Зачем дообучать, если есть ChatGPT?
Допустим, вам нужно, чтобы модель писала код в стиле вашей команды, отвечала на вопросы по внутренней документации или генерировала мемы в корпоративном стиле. Промпты-инженеринг — это круто, но он не научит модель вашим специфическим паттернам. Полноценное дообучение (fine-tuning) позволяет адаптировать поведение LLM под вашу задачу.
Раньше это требовало кластеров A100. В 2026 году QLoRA + Unsloth на 12GB карте — реальность. Причём не «собачья сборка», а стабильный процесс, которым пользуются SRE в проде. Рассказываю, как.
💡 Для кого это? DevOps, ML-инженеры, энтузиасты. Если у вас есть NVIDIA с 12+ GB VRAM (RTX 3060, 4070, A4000) — вы уже можете дообучать модели до 7B параметров. Для 13B+ понадобится 24GB, но мы покажем, как выжать максимум из малого.
QLoRA и Unsloth: дуэт, рвущий лимиты
QLoRA — это техника, сочетающая 4-битную квантизацию основной модели (с помощью bitsandbytes) и низкоранговые адаптеры (LoRA). Вместо обновления 7 миллиардов весов мы тренируем крошечную матрицу ранга 8-64. Это снижает потребление памяти в 4-5 раз без существенной потери качества.
Unsloth — библиотека, которая переписывает внутренние вычисления в Transformers/Hugging Face на CUDA-ядрышки так, что обучение ускоряется на 2-3x, а памяти жрёт ещё на 30-40% меньше. В апреле 2026 вышла версия 2026.4.0, которая добавила поддержку Llama 4 и DeepSeek V3. В основе — оптимизированное ядро для Flash Attention 2 и смешанной точности.
⚠️ Засада: Unsloth работает только с определёнными архитектурами (Llama, Mistral, Qwen, DeepSeek). Если ваша модель — какой-нибудь экспериментальный BLOOM — забудьте. Зато для популярных моделей — идеально.
Шаг 1: поднимаем окружение
Всё запускаем в изолированном conda-окружении. Никаких global pip install — только сломанные нервы потом.
conda create -n finetune python=3.11 -y
conda activate finetune
# CUDA Toolkit 12.4 — обязательно совпадает с драйвером nvidia-smi
conda install cudatoolkit-dev=12.4 -c conda-forge
pip install torch==2.5.1+cu124 --index-url https://download.pytorch.org/whl/cu124
pip install "unsloth[cu124]"
pip install transformers datasets accelerate bitsandbytes wandb
Проверьте, что CUDA видится:
python -c "import torch; print(torch.cuda.is_available())"
Если False — начинайте танцы с бубнами вокруг драйверов. Вероятно у вас установлен драйвер, несовместимый с вашим CUDA тулчейном. Каноничный ответ смеха ради.
Шаг 2: выбираем базовую модель
На конец апреля 2026 лучший выбор для 12GB — Llama 3.2 8B или Qwen 2.5 7B. Обе имеют сильную англоязычную и растущую русскоязычную поддержку. Unsloth их поддерживает out-of-the-box.
Если хочется попробовать 13B — берите Mistral 7B v0.3 (на самом деле 7B, но обманутый мозг радуется). Для русского языка — Saiga Llama 3.1 8B (дообученная на русских инструкциях). Но про неё отдельный разговор.
Если вам нужны не только генерация, но и вызов инструментов — советую глянуть наш обзор лучших Tool Calling моделей — там как раз разбираем, какая база лучше для дообучения под агентов.
Шаг 3: готовим датасет
Самый частый способ — формат ShareGPT (список сообщений с ролями). Unsloth умеет его парсить напрямую. Вот пример для задачи «напиши краткую документацию»:
[
{
"conversations": [
{"from": "human", "value": "Напиши документацию для функции calculate_entropy()"},
{"from": "gpt", "value": "## `calculate_entropy(data)`\n\n**Описание:** Вычисляет энтропию Шеннона для переданного списка значений.\n\n**Параметры:**\n- `data`: список чисел или строк.\n\n**Возвращает:** float — значение энтропии в битах.\n\n**Пример:**\n```python\n>>> calculate_entropy([1,1,1,0,0])\n0.971\n```"}
]
}
]
Можно использовать и старый датасет alpaca в CSV, но ShareGPT удобнее для диалогов. Важно: следите за длиной контекста — обрезайте до 2048 токенов, иначе модель переполнится.
Шаг 4: пишем скрипт обучения
Теперь самое интересное. Создаём файл train.py. Я привожу рабочий шаблон для Unsloth 2026.4.0.
from unsloth import FastLanguageModel
import torch
from datasets import load_dataset
from transformers import TrainingArguments
from trl import SFTTrainer
# 1. Загрузка модели с 4-битной квантизацией
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="unsloth/Llama-3.2-8B-Instruct-bnb-4bit", # пред-квантованный бинарник
max_seq_length=2048,
dtype=torch.bfloat16,
load_in_4bit=True,
# token="hf_..." # если модель под gated
)
# 2. Подключение LoRA адаптеров
model = FastLanguageModel.get_peft_model(
model,
r=16, # ранг LoRA
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"], # все линейные слои
lora_alpha=32, # масштаб обновлений
lora_dropout=0.1, # дропаут для регуляризации
bias="none",
use_gradient_checkpointing=True, # экономим память
random_state=42,
)
# 3. Датасет
dataset = load_dataset("json", data_files="my_data.json", split="train")
# предполагаем, что колонка "conversations"
# 4. Тренировочные аргументы
training_args = TrainingArguments(
output_dir="./llama32-doc-finetune",
per_device_train_batch_size=2, # для 12GB пробуйте 2-4
gradient_accumulation_steps=4, # эффективный batch = 8
warmup_steps=20,
num_train_epochs=3,
learning_rate=2e-4,
fp16=False, # bfloat16 уже выше
bf16=True,
logging_steps=10,
save_steps=100,
evaluation_strategy="no",
save_total_limit=2,
report_to="wandb", # логируем в Weights & Biases
)
# 5. Trainer
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
train_dataset=dataset,
args=training_args,
dataset_text_field="text", # если датасет без колонки диалогов
# formatting_func=... можно заюзать для ShareGPT
max_seq_length=2048,
)
trainer.train()
# 6. Сохраняем только адаптер (слияние не обязательно)
model.save_pretrained("my-finetuned-adapter")
tokenizer.save_pretrained("my-finetuned-adapter")
Разбор параметров
r=16 — золотая середина. При r=32 качество чуть выше, но память растёт. Для 12GB — 16. lora_alpha=32 — общепринятое значение alpha=2*r. Меньше — меньше влияние адаптера, больше — риск переобучения.
batch_size=2 + gradient_accumulation_steps=4 дают эффективный batch 8. Если VRAM позволяет, увеличьте batch до 4. Для 7B моделей можно и 8.
learning_rate=2e-4 стандарт для LoRA. Если loss скачет — уменьшите до 1e-4.
save_steps — сохраняйте каждый 100-200 шагов, чтобы не потерять дни работы.
Запуск и мониторинг
Запускаем: python train.py. Если включили report_to="wandb", смотрите в веб-интерфейс.
Типичная картинка: loss плавно снижается. На эпохах 3-5 обычно достигает плато. Если loss вдруг начинает расти — переобучение. Останавливайте, уменьшайте эпохи или добавляйте dropout.
❌ Ошибка OOM (Out of Memory). Решения: уменьшите batch size, отключите gradient checkpointing (наоборот — включите, я же написал). Ещё попробуйте model.gradient_checkpointing_enable(). Unsloth часто выигрывает 20-30% памяти благодаря собственным оптимизациям — не забывайте использовать FastLanguageModel.
Сохранение и инференс
После обучения у вас папка с адаптерами. Чтобы использовать обученную модель, загружайте базовую + адаптер:
from unsloth import FastLanguageModel
import torch
base_model, tokenizer = FastLanguageModel.from_pretrained(
model_name="unsloth/Llama-3.2-8B-Instruct-bnb-4bit",
max_seq_length=2048,
dtype=torch.bfloat16,
load_in_4bit=True,
)
# Применяем адаптер
base_model.load_adapter("my-finetuned-adapter")
# Генерация
inputs = tokenizer("Напиши документацию для функции calculate_entropy()", return_tensors="pt").to("cuda")
outputs = base_model.generate(**inputs, max_new_tokens=200)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
Если хотите «слить» адаптер в одну модель (merge) для ускорения инференса, используйте model.merge_and_unload(). Но это займёт дополнительное время и место на диске.
Типичные грабли
- Датасет из интернета — мусор. Не качайте все подряд. Лучше 500 качественных примеров, чем 5000 шумных.
- Забыли установить
tokenдля gated моделей. Llama, Gemma, DeepSeek требуют лицензионного соглашения. - Loss не снижается. Проверьте, что датасет правильно токенизирован. Иногда модель не понимает формат ShareGPT.
- После дообучения модель стала глупее. Вы, вероятно, переобучили на слишком узкой выборке. Добавьте в датасет 10-20% общеинтеллектуальных примеров (например, из OpenHermes).
- Проблемы с русским алфавитом. Убедитесь, что токенизатор корректно обрабатывает кириллицу. Qwen 2.5 и Llama 3.1 — норм, DeepSeek V3 — отлично.
Если хотите глубже понять эволюцию техник дообучения и то, как мы пришли к QLoRA/Unsloth, почитайте историю локальных LLM. Там рассказывается про LoRA, Alpaca, и почему Unsloth — это демократизация.
FAQ
use_gradient_checkpointing обязательна.Неочевидный совет напоследок
После дообучения не проверяйте модель только на тех примерах, что были в трейне. Сделайте отдельный тестовый набор — но не из того же распределения, а слегка смещённый (например, про документирование на другом языке или незнакомый код). Если модель справится — вы победили. Если начнёт галлюцинировать — пересмотрите diversity датасета.
Кстати, если вам нужно обкатывать много разных экспериментов с быстрым инференсом, посмотрите сравнение LM Studio и llama.cpp — они тоже умеют и квантование, и загрузку адаптеров.
Главное — не бойтесь эксперементировать. Комбинация Unsloth + QLoRA — это вертолёт, который поднимет любую локальную модель до уровня вашей задачи. Пробуйте, ломайте, чините. И помните: модель — это просто инструмент. Хороший инструмент — это дообученный инструмент.