# Дообучение LLM

Обучите собственную кастомную LLM, используя эффективные техники дообучения на GPU CLORE.AI.

{% hint style="success" %}
Все примеры можно запускать на GPU-серверах, арендованных через [маркетплейс CLORE.AI](https://clore.ai/marketplace).
{% endhint %}

## Аренда на CLORE.AI

1. Посетите [маркетплейс CLORE.AI](https://clore.ai/marketplace)
2. Фильтруйте по типу GPU, VRAM и цене
3. Выберите **On-Demand** (фиксированная ставка) или **Spot** (цена ставки)
4. Настройте ваш заказ:
   * Выберите Docker-образ
   * Укажите порты (TCP для SSH, HTTP для веб-интерфейсов)
   * Добавьте переменные окружения при необходимости
   * Введите команду запуска
5. Выберите оплату: **CLORE**, **BTC**, или **USDT/USDC**
6. Создайте заказ и дождитесь развертывания

### Получите доступ к вашему серверу

* Данные для подключения найдите в **Мои заказы**
* Веб-интерфейсы: используйте URL HTTP-порта
* SSH: `ssh -p <port> root@<proxy-address>`

## Что такое LoRA/QLoRA?

* **LoRA** (Low-Rank Adaptation) — обучайте небольшие адаптерные слои вместо всей модели
* **QLoRA** — LoRA с квантизацией для ещё меньшего объёма VRAM
* Обучение модели 7B на одной RTX 3090
* Обучение модели 70B на одном A100

## Требования

| Модель | Метод       | Мин. VRAM | Рекомендуется                                                                                            |
| ------ | ----------- | --------- | -------------------------------------------------------------------------------------------------------- |
| 7B     | QLoRA       | 12 ГБ     | [RTX 3090](https://clore.ai/rent-3090.html?utm_source=docs\&utm_medium=guide\&utm_campaign=finetune-llm) |
| 13B    | QLoRA       | 20 ГБ     | [RTX 4090](https://clore.ai/rent-4090.html?utm_source=docs\&utm_medium=guide\&utm_campaign=finetune-llm) |
| 70B    | QLoRA       | 48 ГБ     | A100 80GB                                                                                                |
| 7B     | Полная LoRA | 24 ГБ     | RTX 4090                                                                                                 |

## Быстрое развертывание

**Docker-образ:**

```
pytorch/pytorch:2.5.1-cuda12.4-cudnn9-devel
```

**Порты:**

```
22/tcp
8888/http
6006/http
```

**Команда:**

```bash
pip install "transformers>=4.45" "datasets>=2.20" accelerate "peft>=0.14" \
    bitsandbytes "trl>=0.12" wandb jupyterlab && \
jupyter lab --ip=0.0.0.0 --port=8888 --allow-root
```

## Доступ к вашему сервису

После развертывания найдите свой `http_pub` URL в **Мои заказы**:

1. Перейдите на **Мои заказы** страницу
2. Нажмите на ваш заказ
3. Найдите `http_pub` URL (например, `abc123.clorecloud.net`)

Используйте `https://YOUR_HTTP_PUB_URL` вместо `localhost` в примерах ниже.

## Подготовка датасета

### Формат чата (рекомендуется)

```json
[
  {
    "messages": [
      {"role": "system", "content": "Вы — полезный помощник."},
      {"role": "user", "content": "Что такое Python?"},
      {"role": "assistant", "content": "Python — это язык программирования..."}
    ]
  }
]
```

### Формат инструкций

```json
[
  {
    "instruction": "Переведи на французский",
    "input": "Привет, как дела?",
    "output": "Bonjour, comment allez-vous?"
  }
]
```

### Формат Alpaca

```json
[
  {
    "instruction": "Дайте три совета по сохранению здоровья.",
    "input": "",
    "output": "1. Ешьте сбалансированную пищу..."
  }
]
```

## Поддерживаемые современные модели (2025)

| Модель                      | HF ID                                     | Мин. VRAM (QLoRA) |
| --------------------------- | ----------------------------------------- | ----------------- |
| Llama 3.1 / 3.3 8B          | `meta-llama/Llama-3.1-8B-Instruct`        | 12 ГБ             |
| Qwen 2.5 7B / 14B           | `Qwen/Qwen2.5-7B-Instruct`                | 12 ГБ / 20 ГБ     |
| DeepSeek-R1-Distill (7B/8B) | `deepseek-ai/DeepSeek-R1-Distill-Qwen-7B` | 12 ГБ             |
| Mistral 7B v0.3             | `mistralai/Mistral-7B-Instruct-v0.3`      | 12 ГБ             |
| Gemma 2 9B                  | `google/gemma-2-9b-it`                    | 14 ГБ             |
| Phi-4 14B                   | `microsoft/phi-4`                         | 20 ГБ             |

## Скрипт дообучения QLoRA

Современный пример с PEFT 0.14+, Flash Attention 2, поддержкой DoRA и совместимостью с Qwen2.5 / DeepSeek-R1:

```python
import torch
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    BitsAndBytesConfig,
    TrainingArguments,
)
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from datasets import load_dataset
from trl import SFTTrainer, SFTConfig

# === Конфигурация ===
# Выберите одну из: Qwen2.5, DeepSeek-R1-Distill, Llama 3.1, Mistral и т. д.
MODEL_NAME = "Qwen/Qwen2.5-7B-Instruct"
# MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B"
# MODEL_NAME = "meta-llama/Llama-3.1-8B-Instruct"

DATASET = "your_dataset.json"  # или имя датасета HuggingFace
OUTPUT_DIR = "./output"
MAX_SEQ_LENGTH = 4096           # Qwen2.5 поддерживает контекст до 32K
USE_DORA = True                 # DoRA улучшает качество по сравнению со стандартной LoRA
USE_FLASH_ATTN = True           # Flash Attention 2 экономит VRAM и ускоряет работу

# === Загрузка модели с 4-битной квантизацией ===
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
)

model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,  # требуется для Qwen2.5 и DeepSeek
    # Flash Attention 2: требует GPU архитектуры Ampere+ (RTX 30/40, A100)
    attn_implementation="flash_attention_2" if USE_FLASH_ATTN else "eager",
)

tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
if tokenizer.pad_token is None:
    tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

# === Настройка LoRA с необязательной DoRA ===
# DoRA (Weight-Decomposed Low-Rank Adaptation) — требуется PEFT >= 0.14
# use_dora=True раскладывает веса на величину + направление для лучшего качества
lora_config = LoraConfig(
    r=64,                    # Ранг (выше = больше возможностей, больше VRAM)
    lora_alpha=16,           # Коэффициент масштабирования (держите равным r или половине r)
    target_modules=[
        "q_proj", "k_proj", "v_proj", "o_proj",  # Слои внимания
        "gate_proj", "up_proj", "down_proj",      # Слои MLP
    ],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
    use_dora=USE_DORA,        # DoRA: улучшенное качество (PEFT 0.14+)
    # use_rslora=True,        # Необязательно: Rank-Stabilized LoRA
)

# Подготовка модели к обучению QLoRA
model = prepare_model_for_kbit_training(
    model,
    use_gradient_checkpointing=True,
    gradient_checkpointing_kwargs={"use_reentrant": False},
)
model = get_peft_model(model, lora_config)

# Вывод сводки обучаемых параметров
model.print_trainable_parameters()
# Пример вывода: trainable params: 42,991,616 || all params: 7,284,891,648 || trainable%: 0.59

# === Загрузка датасета ===
dataset = load_dataset("json", data_files=DATASET)
# Или используйте публичный датасет:
# dataset = load_dataset("HuggingFaceH4/ultrachat_200k")

# === Форматирование датасета для Qwen2.5 / формата ChatML ===
def format_chat_qwen(example):
    """Формат для Qwen2.5 с использованием шаблона ChatML."""
    messages = example.get("messages", [])
    if not messages:
        # Обработка данных в стиле Alpaca
        text = f"<|im_start|>system\nВы — полезный помощник.<|im_end|>\n"
        text += f"<|im_start|>user\n{example['instruction']}"
        if example.get("input"):
            text += f"\n{example['input']}"
        text += f"<|im_end|>\n<|im_start|>assistant\n{example['output']}<|im_end|>"
    else:
        # Обработка формата messages (ChatML)
        text = tokenizer.apply_chat_template(
            messages,
            tokenize=False,
            add_generation_prompt=False,
        )
    return {"text": text}

dataset = dataset.map(format_chat_qwen, remove_columns=dataset["train"].column_names)

# === Параметры обучения (PEFT 0.14+ / TRL 0.12+) ===
training_args = SFTConfig(
    output_dir=OUTPUT_DIR,
    num_train_epochs=3,
    per_device_train_batch_size=2,
    gradient_accumulation_steps=8,         # Эффективный batch = 2 * 8 = 16
    learning_rate=2e-4,
    weight_decay=0.001,
    warmup_ratio=0.03,
    lr_scheduler_type="cosine",
    logging_steps=10,
    save_steps=100,
    save_total_limit=3,
    bf16=True,                             # Используйте bf16 для современных GPU (A100, RTX 30/40)
    # fp16=True,                           # Используйте fp16 для более старых GPU
    optim="paged_adamw_8bit",
    max_grad_norm=0.3,
    group_by_length=True,
    report_to="wandb",                     # или "tensorboard"
    # Специфично для SFTConfig:
    max_seq_length=MAX_SEQ_LENGTH,
    dataset_text_field="text",
    packing=True,                          # Упаковывает несколько примеров для эффективности
)

# === Обучение ===
trainer = SFTTrainer(
    model=model,
    train_dataset=dataset["train"],
    tokenizer=tokenizer,
    args=training_args,
)

trainer.train()

# === Сохранение адаптера LoRA ===
trainer.save_model(f"{OUTPUT_DIR}/final")
tokenizer.save_pretrained(f"{OUTPUT_DIR}/final")
print(f"Модель сохранена в {OUTPUT_DIR}/final")
```

## Flash Attention 2

Flash Attention 2 снижает использование VRAM и значительно ускоряет обучение. Требует GPU архитектуры Ampere+ (RTX 3090, RTX 4090, A100).

```bash
# Установить Flash Attention 2
pip install flash-attn --no-build-isolation
```

```python
# Включить при загрузке модели:
model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    attn_implementation="flash_attention_2",  # <-- добавьте это
    torch_dtype=torch.bfloat16,               # FA2 требует bf16 или fp16
    device_map="auto",
)
```

| Параметр                    | VRAM (7B) | Скорость        |
| --------------------------- | --------- | --------------- |
| Стандартное внимание (fp16) | \~22 ГБ   | базовый уровень |
| Flash Attention 2 (bf16)    | \~16 ГБ   | +30%            |
| Flash Attention 2 + QLoRA   | \~12 ГБ   | +30%            |

## DoRA (Weight-Decomposed LoRA)

DoRA (PEFT >= 0.14) раскладывает предобученные веса на компоненты величины и направления. Это улучшает качество дообучения, особенно при меньших рангах.

```python
from peft import LoraConfig

# Стандартная LoRA
lora_config = LoraConfig(r=64, lora_alpha=16, use_dora=False, ...)

# DoRA — те же параметры, лучшее качество
lora_config = LoraConfig(r=64, lora_alpha=16, use_dora=True, ...)
# Примечание: DoRA добавляет ~5-10% накладных расходов VRAM по сравнению со стандартной LoRA
# Примечание: не совместимо со всеми квантованными моделями (4-bit/8-bit) во всех случаях
```

## Примеры Qwen2.5 и DeepSeek-R1-Distill

### Дообучение Qwen2.5

```python
MODEL_NAME = "Qwen/Qwen2.5-7B-Instruct"
# Для 14B: "Qwen/Qwen2.5-14B-Instruct" (нужно 20GB+ VRAM с QLoRA)

model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,          # требуется для Qwen2.5
    attn_implementation="flash_attention_2",
)
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)

# Qwen2.5 использует формат ChatML — применяйте apply_chat_template
messages = [
    {"role": "system", "content": "Вы — полезный помощник."},
    {"role": "user", "content": "Привет!"},
    {"role": "assistant", "content": "Привет! Чем я могу помочь?"},
]
text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False)
```

### Дообучение DeepSeek-R1-Distill

Модели DeepSeek-R1-Distill (Qwen-7B, Qwen-14B, Llama-8B, Llama-70B) ориентированы на рассуждения. Дообучайте их, чтобы адаптировать стиль chain-of-thought под вашу область.

```python
# Варианты DeepSeek-R1-Distill
MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B"   # 7B на базе Qwen2.5
# MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Llama-8B" # 8B на базе Llama3
# MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B" # 14B (нужен A100)

model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,
    attn_implementation="flash_attention_2",
)

# DeepSeek-R1 использует теги <think>...</think> для рассуждений
# Сохраняйте это в обучающих данных, чтобы сохранить способность к chain-of-thought
example_format = """<|im_start|>user
Решите: чему равно 15 * 23?<|im_end|>
<|im_start|>assistant
<think>
15 * 23 = 15 * 20 + 15 * 3 = 300 + 45 = 345
</think>
Ответ: 345.<|im_end|>"""

# Целевые модули LoRA для DeepSeek-R1-Distill (база Qwen2.5)
lora_config = LoraConfig(
    r=32,
    lora_alpha=16,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                    "gate_proj", "up_proj", "down_proj"],
    use_dora=True,
    task_type="CAUSAL_LM",
)
```

## Использование Axolotl (проще)

Axolotl упрощает дообучение с YAML-конфигами:

```bash
pip install axolotl

# Создать конфиг
cat > config.yml << 'EOF'
base_model: mistralai/Mistral-7B-v0.1
model_type: MistralForCausalLM
tokenizer_type: LlamaTokenizer

load_in_4bit: true
adapter: qlora
lora_r: 32
lora_alpha: 16

datasets:
  - path: your_data.json
    type: alpaca

sequence_len: 4096
sample_packing: true

gradient_accumulation_steps: 4
micro_batch_size: 2
num_epochs: 3
learning_rate: 2e-4

output_dir: ./output
EOF

# Обучение
accelerate launch -m axolotl.cli.train config.yml
```

## Примеры конфигов Axolotl

### Чат-модель

```yaml
base_model: mistralai/Mistral-7B-Instruct-v0.2
load_in_4bit: true
adapter: qlora

datasets:
  - path: data.json
    type: sharegpt

chat_template: mistral
```

### Кодовая модель

```yaml
base_model: codellama/CodeLlama-7b-hf
load_in_4bit: true
adapter: qlora

datasets:
  - path: code_data.json
    type: alpaca

sequence_len: 8192  # Более длинный контекст для кода
```

## Объединение весов LoRA

После обучения объедините LoRA обратно с базовой моделью:

```python
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer

# Загрузить базовую модель
base_model = AutoModelForCausalLM.from_pretrained(
    "mistralai/Mistral-7B-v0.1",
    torch_dtype=torch.float16,
    device_map="auto",
)

# Загрузить LoRA
model = PeftModel.from_pretrained(base_model, "./output/final")

# Объединить
merged_model = model.merge_and_unload()

# Сохранить объединённую модель
merged_model.save_pretrained("./merged_model")
tokenizer.save_pretrained("./merged_model")
```

## Преобразование в GGUF

Для использования с llama.cpp/Ollama:

```bash

# Клонировать llama.cpp
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp

# Преобразовать
python convert.py ../merged_model --outtype f16 --outfile model-f16.gguf

# Квантовать
./quantize model-f16.gguf model-q4_k_m.gguf q4_k_m
```

## Мониторинг обучения

### Weights & Biases

```python
import wandb
wandb.init(project="llm-finetune", name="mistral-7b-lora")
```

### TensorBoard

```python

# В аргументах обучения
report_to="tensorboard"
logging_dir="./logs"

# Просмотр
tensorboard --logdir ./logs --port 6006 --bind_all
```

## Лучшие практики

### Гиперпараметры

| Параметр    | Модель 7B | Модель 13B | Модель 70B |
| ----------- | --------- | ---------- | ---------- |
| batch\_size | 4         | 2          | 1          |
| grad\_accum | 4         | 8          | 16         |
| lr          | 2e-4      | 1e-4       | 5e-5       |
| lora\_r     | 64        | 32         | 16         |
| epochs      | 3         | 2-3        | 1-2        |

### Размер датасета

* Минимум: 1 000 примеров
* Хорошо: 10 000+ примеров
* Качество > количество

### Как избежать переобучения

```python
training_args = TrainingArguments(
    ...
    weight_decay=0.01,
    warmup_ratio=0.03,
    save_total_limit=3,
    load_best_model_at_end=True,
    evaluation_strategy="steps",
    eval_steps=100,
)
```

## Обучение на нескольких GPU

```bash

# С accelerate
accelerate launch --multi_gpu --num_processes 4 train.py

# С DeepSpeed
accelerate launch --use_deepspeed --num_processes 4 train.py
```

Конфиг DeepSpeed:

```json
{
  "bf16": {"enabled": true},
  "zero_optimization": {
    "stage": 2,
    "offload_optimizer": {"device": "cpu"}
  }
}
```

## Сохранение и экспорт

```bash

# Сохранить адаптер LoRA
trainer.save_model("./lora_adapter")

# Сохранить объединённую модель
merged_model.save_pretrained("./full_model")

# Загрузить на HuggingFace
huggingface-cli login
merged_model.push_to_hub("username/my-model")
```

## Устранение неполадок

### Ошибки OOM

* Уменьшите размер batch
* Увеличьте gradient accumulation
* Используйте `gradient_checkpointing=True`
* Уменьшите lora\_r

### Потери обучения не уменьшаются

* Проверьте формат данных
* Увеличьте скорость обучения
* Проверьте наличие проблем с данными

### Потеря NaN

* Уменьшите скорость обучения
* Используйте fp32 вместо fp16
* Проверьте данные на повреждения

## Оценка стоимости

Типичные тарифы маркетплейса CLORE.AI (по состоянию на 2026 год):

| GPU       | Почасовая ставка | Дневная ставка | 4-часовая сессия |
| --------- | ---------------- | -------------- | ---------------- |
| RTX 3060  | \~$0.03          | \~$0.70        | \~$0.12          |
| RTX 3090  | \~$0.06          | \~$1.50        | \~$0.25          |
| RTX 4090  | \~$0.10          | \~$2.30        | \~$0.40          |
| A100 40GB | \~$0.17          | \~$4.00        | \~$0.70          |
| A100 80GB | \~$0.25          | \~$6.00        | \~$1.00          |

*Цены зависят от провайдера и спроса. Проверьте* [*маркетплейс CLORE.AI*](https://clore.ai/marketplace) *актуальные тарифы.*

> 📚 См. также: [Как дообучить LLaMA 3 на облачном GPU — пошаговое руководство](https://blog.clore.ai/how-to-fine-tune-llama-3-cloud-gpu/)

**Экономьте деньги:**

* Используйте **Spot** рынок для гибких рабочих нагрузок (часто на 30-50% дешевле)
* Оплатите **CLORE** токенами
* Сравните цены у разных провайдеров


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.clore.ai/guides/guides_v2-ru/obuchenie/finetune-llm.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
