Зачем вам 0.5 миллиарда?
Когда речь заходит об обучении LLM, в головах сразу всплывают картинки гигантских кластеров по 100500 H100 и бюджеты, сопоставимые с ВВП небольшой страны. Но реальность такова: абсолютному большинству нишевых задач (чат-бот для поддержки, генерация отчетов, автоматизация переписки) модель на 0.5 млрд параметров даёт 95% результата десятикратно большей Llama-70B, при этом жрёт в 50 раз меньше железа и времени.
Я решил проверить это на практике: обучить LLM 0.5B с нуля на русскоязычном датасете с Хабра. Зачем? Во-первых, хабровский контент — уникальная смесь технического языка, жаргона и кода. Во-вторых, чтобы ответить на главный вопрос: можно ли сделать это на одной домашней видеокарте, используя современные форматы вроде fp8, и не сойти с ума?
Спойлер: можно, но без пары трюков с Unsloth и правильной организации пайплайна не обойтись. Если вы уже пробовали бесплатную тонкую настройку — здесь будет сложнее, но интереснее.
Битва форматов: почему fp8 может убить вашу модель
Главная интрига — что выбрать: fp8 или bf16? В теории bf16 даёт больше точности, но требует вдвое больше памяти. fp8 — экономия VRAM, но риск потерять градиенты на эпохе. На практике для модели 0.5B кажется, что bf16 — безопасный выбор. Но давайте честно: при обучении с нуля на датасете из 500 тысяч постов Хабра (около 2 млрд токенов) fp8 позволил мне уместить батч размером 8 на RTX 4090 24 ГБ против 4 на bf16. Скорость — не две копейки: 40% прироста токенов в секунду.
Я сделал замеры после первой эпохи претрейна. Результаты — в таблице.
| Метрика | fp8 | bf16 |
|---|---|---|
| Perplexity (val) | 8.15 | 8.07 |
| Loss (val) | 2.12 | 2.08 |
| VRAM, ГБ | 16.2 | 22.5 |
| Токенов/с | 3500 | 2500 |
Внимание: fp8 очень чувствителен к scale-факторам. Если loss не падает первые 500 шагов — переключайтесь на bf16, иначе модель уйдёт в NaN. Я наступил на эти грабли дважды, потеряв 6 часов вычислений.
Мой вердикт: для претрейна с нуля используйте bf16 как базовый, а fp8 — только если VRAM упирается в потолок, и вы готовы следить за loss каждые 10 шагов. Для последующих стадий (SFT, DPO) fp8 уже не так критичен — можно смело ставить bf16, дообучение менее требовательно к разрядности.
Три круга ада: претрейн, SFT и DPO
Обучение LLM с нуля — это не одна команда python train.py. Это три последовательных этапа, каждый со своими граблями. Разберем по косточкам.
1 Претрейн (Causal LM на датасете Хабра)
Скармливаем модели сырые тексты статей, чтобы она научилась предсказывать следующее слово. Я использовал датасет habr_posts_2026 (~500K статей, 2.3B токенов). Архитектура — миниатюрный GPT-style: 12 слоев, 8 голов, embedding 1024. Код на базе PyTorch + Hugging Face Transformers.
from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments, Trainer
import torch
model = AutoModelForCausalLM.from_config(
config={
"vocab_size": 32000,
"n_positions": 2048,
"n_embd": 1024,
"n_layer": 12,
"n_head": 8,
"use_cache": False,
"torch_dtype": torch.bfloat16 # или fp8 через bitsandbytes
}
)
tokenizer = AutoTokenizer.from_pretrained("google/mt5-small")
tokenizer.pad_token = tokenizer.eos_token
# Data collator для Causal LM
...
training_args = TrainingArguments(
output_dir="./habr-0.5b-pretrain",
per_device_train_batch_size=4,
gradient_accumulation_steps=2,
learning_rate=3e-4,
num_train_epochs=3,
fp8=True, # или bf16=True
optim="adamw_bnb_8bit",
ddp_find_unused_parameters=False if torch.cuda.device_count() > 1 else None
)
Важный нюанс: при train from scratch не забудьте use_cache=False, иначе вылезет ошибка с градиентами. Ещё один трюк — warmup_steps = 1000, иначе модель сразу улетает в loss=11.
2 SFT (Supervised Fine-Tuning) — учим отвечать на вопросы
После претрейна модель умеет продолжать текст, но не умеет отвечать на вопросы в формате “Вопрос-Ответ”. Я собрал SFT-датасет из первых 10K статей Хабра, сгенерировав пары (текст статьи, краткий пересказ-ответ) через GPT-4o-mini — да, это дорого, но в итоге модель научилась реферировать хабровские посты.
Для SFT использовал Unsloth — библиотека, которая ускоряет дообучение в 2 раза без потери качества. Как бесплатно дообучить свою LLM — там детали, а здесь скажу главное: для SFT не надо заморачиваться с fp8, bf16 хватает за глаза.
from unsloth import FastLanguageModel
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="./habr-0.5b-pretrain",
max_seq_length=2048,
dtype=torch.bfloat16,
load_in_4bit=False, # 8bit для экономии, но bf16 лучше
)
model = FastLanguageModel.get_peft_model(
model,
r=16,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
lora_alpha=16,
lora_dropout=0.1,
use_rslora=True
)
# Trainer тот же, но learning_rate ниже: 2e-5
3 DPO (Direct Preference Optimization) — полируем до блеска
Последний этап — учим модель выбирать “правильный” ответ из пары. Без DPO модель часто галлюцинирует и выдает откровенную чушь. Я нагенерировал 5K пар (выбранный ответ vs отвергнутый) с помощью rule-based системы (проверка фактов по статье) и обучил DPO через trl.
from trl import DPOTrainer
dpo_trainer = DPOTrainer(
model=model,
ref_model=None, # если null — берется копия model
beta=0.1,
train_dataset=dpo_dataset,
tokenizer=tokenizer,
args=TrainingArguments(
output_dir="./habr-0.5b-dpo",
per_device_train_batch_size=2,
gradient_accumulation_steps=4,
num_train_epochs=2,
fp8=False, # DPO с fp8 крайне нестабилен
bf16=True
)
)
Здесь fp8 — табу! Даже с bf16 loss иногда прыгает. Если видите, что accuracy выбора падает на 10% за эпоху — уменьшите learning rate до 1e-6.
Железо, которое выжмет из RTX 4090 всё
Вся магия произошла на моей домашней станции: RTX 4090 24GB, Ryzen 9 7950X, 64GB RAM, NVMe SSD 2TB. Если у вас меньше — читайте как собрать локальную рабочую станцию или как втиснуть 7 маленьких LLM на ноутбук с 16 ГБ. Моя конфигурация позволила завершить претрейн за 5 дней (3 эпохи, 2.3B токенов) — приемлемо для эксперимента. SFT — 8 часов, DPO — 4 часа.
Ошибка новичка: не используйте CPU offloading, если у вас больше 32 ГБ RAM. На Ryzen это убивает производительность — лучше купить еще одну 4090, если есть бюджет. Но для 0.5B хватает одной.
Грабли, на которые я наступил (и вы наступите тоже)
- Забыл добавить EOS токен в датасет. Модель генерировала бесконечный поток текста. Проверяйте, что каждый пример заканчивается
. - Перепутал порядок этапов. Сначала сделал DPO на сырой модели — результаты были хуже рандома. DPO — только после SFT.
- Использовал fp8 в DPO. Три раза получил NaN на 500 шаге. Перешел на bf16 — loss стабилен.
- Не сохранял чекпоинты на Google Drive. После случайного отключения питания потерял 2 дня. Теперь крон-скрипт каждые 30 минут пушит на HF Hub.
- Выбрал слишком большой learning rate для претрейна. 1e-3 привел к loss=11 и остановке. Стартуйте с 3e-4, постепенно увеличивайте.
Если вы хотите упростить визуализацию процесса — попробуйте NTTuner: GUI для тонкой настройки LLM. Для экспериментов с кастомными ядрами — эта статья поможет понять, стоит ли овчинка выделки. Спойлер: для 0.5B не стоит, стандартные оптимизации дают 90% прироста.
Что в итоге?
Финальная модель habr-0.5b-instruct (hub: myname/habr-0.5b) отвечает на вопросы о технологиях на уровне junior-специалиста. Perplexity на тестовой выборке — 7.8. Сравнение с LFM2.5-1.2B показало, что моя модель проигрывает по глубине ответов, но выигрывает по скорости генерации (50 мс против 120 мс на токен). Для чат-бота в техподдержке — идеально.
Совет напоследок: не гонитесь за версиями — для большинства проектов 0.5B достаточно. Если нужно качество выше — не учите с нуля, возьмите дообучение Qwen3.5-27B или заточьте под медицинские протоколы. А начинать — с малого. И да, не забудьте сохранить чекпоинт через 5 минут после запуска. Я серьезно.