Вход на сайт

Просмотр новости

Найдите то, что Вас интересует

habrGPT. Обучим LLM 0.5B с нуля на статьях Хабра с помощью nanochat от Карпатого. Обучение fp8 дома и сравнение с bf16

Дата публикации: 08-07-2026 17:25:08

Раскрученный проект nanochat обещает "за $100 обучите свой ChatGPT". В оригинале обучение на 8xH100 80Gb, но никто не мешает обучить его на домашнем и более слабом железе. Попробуем обучить LLM с нуля на статьях Хабра, чтобы посмотреть хватит ли там материала, чтобы модель хотя бы смогла связать пару слов. Читать далее

Основное содержимое страницы с новостью.

0d37f82ebde63da7de7bca3b2eb6f701.png

Раскрученный проект nanochat обещает "за $100 обучите свой ChatGPT". В оригинале обучение на 8xH100 80Gb, но никто не мешает обучить его на домашнем и более слабом железе. Попробуем обучить LLM с нуля на статьях Хабра, чтобы посмотреть хватит ли там материала, чтобы модель хотя бы смогла связать пару слов.

Этапы обучения LLM с нуля

Классические этапы обучения LLM:

  • pretrain - это base модель. Дают неразмеченный сырой текст, модель учится продолжать.

  • SFT - это instruct модель. Дают качественный, размеченный датасет.

  • RL, DPO - выравнивание модели, датасет с парами хороший-плохой ответ.

Обучение с нуля начинается со случайных параметров, на вход необученной модели подается неразмеченный текст и модель шаг за шагом пытается предсказать следующие токены на основе предыдущего контекста. Вначале модель осваивает простые паттерны, такие как орфография и пунктуация, после начинается выявление более сложных связей, где происходит аппроксимация не только коротких связей, но и полных документов, например, идея которая озвучена в 1 главе получает развитие в 3 главе, и такие длинные связи тоже начинают выявляться.

Цель настроить параметры так, чтобы модель могла уверенно продолжать текст, где начало, середина и конец связаны друг с другом. Упрощенно можно на это посмотреть так, из случайного распределения параметров начинают проявляться структуры, эти структуры означают, что паттерны найдены и знание усвоено:

8d584d30cbfdf5f4907ee2a1741cd94f.pngАнимация упрощенного процесса подбора параметров модели
Анимация процесса подбора параметров модели

Анимация (webp) процесса подбора параметров модели

Модель работает с токенами. Слова, перед тем как попадут в модель, разбиваются на токены, токены в свою очередь преобразуются в вектора, эти вектора можно назвать как "вектора сути". Такие вектора тоже обучаются, и после обучения начинают передавать смысл слова.

То, что имеет похожие смыслы или близкие сущности - они начинают располагаться всё ближе и ближе друг к другу в многомерном пространстве, формируя кластер семантической близости. Чем лучше обучена нейросеть, тем точнее будет их расположение в таком многомерном пространстве с огромной размерностью (размерность от 512 до 8192 и более). Это называют эмбеддингами.

Эмбеддинги

Эмбеддинги

Эмбеддинги несут суть слова в многомерном пространстве, а не само слово, и так как это вектора, то с ними можно проводить различные операции через геометрию пространства.

Например, есть Вектора "Король", "Мужчина", "Женщина". Каждый вектор содержит в себе какую-то определённую суть:

Вектор("Король") = [Мужчина] + [Монарх]
Вектор("Мужчина") = [Мужчина] + [Человек]
Вектор("Женщина") = [Женщина] + [Человек]

Если из Вектор("Король") вычесть Вектор("Мужчина"), получится чистый признак [Монарх]

Если пока нет готового понятия, его можно создавать:

Вектор("Король") - Вектор("Мужчина") + Вектор("Женщина") = Вектор("Королева")

По сути работа нейросети заключается в том, чтобы перемножать эмбеддинги с векторами положений слова, вычислять значимость слова в контексте, создавая новые вектора, новые вектора прогоняются дальше слой за слоем, всё усложняя признаки.

На выходе нейросети вычисленные вероятности для всех токенов нейросети, количество вероятностей равно vocab_size, обычно от 32к до 256к, но большинство их них будут иметь значение ниже 0.01 и только top-k токенов будут иметь какую-то значимость.

Нейросеть не выбирает какой токен из предложенных выбрать. Выбором занимается внешний от нейросети процесс - семплинг. Семплинг это не интеллектуальная сущность, тут нет накопленной статистики, нет обучения, и он предназначен чтобы добавить случайности и разнообразия в ответ, это делает модель более интересной, но выбор неудачного токена может увести даже большую модель в ошибочное направление.

Можно выделить основные параметры семплирования:

  • Greedy (Жадный поиск) - всегда берется самый вероятный токен, самый первый.

  • Top-K - отсекает хвосты, оставляя только N верхних по вероятности токенов.

  • Top-P - оставляет токены, пока их сумма вероятностей не достигает порога.

  • Temperature - масштабирует логиты до softmax, сглаживает или заостряет распределение.

семплинг

семплинг

Когда pretrain создан, он умеет только продолжать фразы и нужно научить его следовать инструкциям. Модели показывают как выглядят инструкции, шаблон, структуру, служебные токены для разделения user и assistant, чтобы модель могла правильно отделять свои ответы от запросов пользователя.

Всё это делается на основе множества размеченных примеров, из которых будут выявляться паттерны. Происходит процесс подбора параметров так, чтобы шаблон сходился.

SFT

SFT

После того как модель научилась следовать шаблону, можно её дополнительно настроить или выровнять, усилить сигнал хороших ответов и ослабить у плохих. Для этого нужен датасет где будет пара хороший-плохой ответы, и по ходу дообучения расхождение между этими парами должно усиливаться.

DPO

DPO

Nanochat, закон Шиншиллы, PLE, домашние GPU, win vs linux

Обучать будем на nanochat, это позволит создать современную LLM без погружения в конфигурации, настройки, подбор параметров обучения.

Nanochat от Andrej Karpathy построен по принципу "укажите 1 параметр, остальные будут подобраны автоматически" - нужно указать depth или количество слоев трансформера. Остальные параметры будут подобраны согласно закону Шиншиллы.

В nanochat свежие подходы к обучению, вместо AdamW используют гибрид с новым эффективным Muon, вместо GELU более качественный SwiGLU, пробуют различные новые архитектурные решения вроде PLE, обучение в fp8, компиляция torch.compile triton ядер для ускорения в 2 раза и т.д.

Возможно, вместо adamw+muon можно перейти на новый оптимизатор gefen, который заявляет, что можно сэкономить до x8 памяти: https://github.com/ndvbd/Gefen

Что такое PLE?

Размер модели d16 составляет 0.5B, но эффективных ~0.25B, остальное это PLE.

Архитектура PLE (Per-Layer Embeddings), это к каждому, или через один, слою добавляется слои эмбеддингов, которые по сути является ассоциативной памятью. Этот слой обучают вместе с моделью, но он почти не требует FLOPs ни на обучение, ни на инференс. Идея в чем-то похожа на MoE, только тут получается статичный слой PLE, который увеличивает емкость данных у модели в 2 раза, не тратя ресурсы на вычисления.

В Gemma4 есть 2 модели E2B и E4B, которые работают на этой архитектуре. В теории Gemma4 E4B обучается и запускается как 4B модель, но работает как "умная" 8B модель.

Что такое закон Шиншиллы?

Исследователи из DeepMind в 2022 году представили работу Chinchilla Scaling Laws (Закон Шиншиллы), в которой вывели эмпирические правила, что на 1 параметр модели нужно 20-25 токенов обучения. Так же они внесли корректировки в Warmup и пиковый LR.

В nanochat из этого scaling laws исключаются эмбеддинги, поэтому в nanochat, где эмбединги PLE занимают почти половину модели, Chinchilla ratio составляет 12. Другие параметры будут вычислены на основе этих факторов.

Например, вычисление общего размера батча:

B∝D ^{0.383}

Где B - оптимальный размер батча, а D - размер датасета. Степень 0.383 тоже выведена эмпирически DeepMind и OpenAI, отвечающая на вопрос как сильно надо увеличить размер батча, если увеличивается объем датасета, чтобы обучение шло оптимально.

Для d16 размер батча оптимален в 512к, для d24 будет 1кк. Вместить такой размер физически на GPU тяжело, чтобы это компенсировать используют Gradient accumulation.

Total\_Batch\_Size = Device\_Batch\_Size \times Gradient\_Accumulation

На домашнем GPU физический размер батча будет где-то в диапазоне 4-16, но за счет накапливания через Gradient accumulation, итоговый батч будет иметь нужный размер. И математически это почти равнозначно физическому батчу.

5090 это урезанный Blackwell, поэтому поддержки fa3 нет

Nanochat рассчитан на работу с серверными картами уровня H100 и выше, потому что тут используется flash-attention 3, который ускоряет обучение и тратит меньше памяти. FA3 работает на архитектурах Blackwell и Hopper.

Я буду обучать на 5090, и это как раз архитектура Blackwell, но в ходе обучения возникла первая проблема, расход памяти был слишком большой, и снижалась скорость обучения, MFU показывал не эффективное использование карты.

Проблема в том, что в nanochat используется скользящее окно внимания SSSL (S - 1/4 от полного внимания, L - полное), это ускоряет обучение и экономит память. SSSL эффективно только в fa3, для этого паттерна нужно оптимально маскировать урезанное внимание, чтобы не тратить полную память и вычисления на операция с такими слоями.

Изучение вопроса как работает FA3 привело к тому, что тут нужны физические блоки тензорной памяти TMEM, если их нет, будет откат на старые регистры HMMA (уровень Volta/Ampere), которые не могут оптимально работать с SSSL и тратят лишнюю память и время на обработку, что приводит к тому, что скорость обучения падает. Оказалось, что TMEM физически присутствует только в корпоративном сегменте Blackwell, на картах типа B200, на домашних картах этих блоков нет. Подробнее про fa3 и отсутствие TMEM на 5090: https://gist.github.com/solatticus/aab6ec3a0436748b021cbbdd12e8c739

В итоге на домашних GPU придется откатиться на SDPA, где под капотом используется FA2 (в Linux, под Windows скорее всего придется установить fa2 вручную), который не может нормально работать с SSSL. FA2 это тоже быстро, но не так эффективно как FA3/FA4, и придётся переключиться на полный L.

Возможно, есть какой-то эффективный способ обучать со скользящим окном внимания на потребительских GPU, вроде FlexAttention. Ещё какая-то работа представлена тут: https://github.com/MaxLSB/flash-attn2

Обучение на Windows или на Linux

Под Windows нужно установить pip install triton-windows - это позволит запустить обучение и скомпилировать triton ядра, но вопрос скорости остается открытым.

Под Linux скорость обучения выше, чем под Windows. В чем именно проблема, не понятно. Возможно проблема моей сборки, возможно медленный fa2 под Windows, или из-за Win10, а на Win11 будет нормально.

Под Windows скорость 85к t/s:

Windows 10, обучение d16, TDP 450, 85617 t/s

Windows 10, обучение d16, TDP 450, 85617 t/s

Утилизация GPU 100%, что с учетом скорости, не эффективно:

Windows 10, TDP 450

Windows 10, TDP 450

Под Linux 132к t/s, на ~60% выше при той же утилизации 100%:

Manjaro Linux, обучение d16, TDP 450, 132498 t/s

Manjaro Linux, обучение d16, TDP 450, 132498 t/s

В обоих случаях nvidia-smi -i 0 -pl 450, чтобы GPU оставалась тихой во время работы, это снижает эффективность всего на ~7%, но шум вентиляторов тише в 2 раза.

При TDP 575 результат не сильно лучше, но ощутимо шумнее. Windows 10, обучение d16, 91396 t/s

При TDP 575 результат не сильно лучше, но ощутимо шумнее. Windows 10, обучение d16, 91396 t/s

Обучение. Токенизатор

Обучение начинается с обучения токенизатора. В качестве датасета IlyaGusev/habr.

Обучение токенизатора проходит на тех же статьях, он ищет зависимости языка, выявляет частые слоги, корни слов, различные сочетания символов, создает словарь, чтобы эффективно сжимать русский текст в токены.

393f9d3ac3b0b8754dbbd7ee924315cc.png

После обучения токенизатора, можно подсчитать точное число токенов Хабра, получилось на 302к статей всего 508M токенов.

2479bf1f03cdbadf1ab07c0cc17ef4c6.png

Комментарии это ещё +0.6B. Но их не будем учитывать, так как обучение на статьях, хотя комментарии могли бы внести живости в общение модели и расширить её знания.

aeb4250106db15069501faaf508f6769.png

Обучение pretrain. Параметры d16

Скрипт обучения рассчитан на 80Гб VRAM, по умолчанию batch-size равен 32, чтобы влезть в меньший объем VRAM, нужно его снизить. Если памяти совсем не хватает, можно включить Gradient checkpointing, который кардинально снижает расход памяти за счёт скорости.

Обучать будем в fp8, размер d16, для размера 0.5B нужен датасет в 6-10B, у нас есть только 508M. Вместо SSSL используем L, сохраняем чекпоинт каждые 500 шагов, размер физического батча 16 или меньше, чтобы влезало в VRAM.

python -m scripts.base_train --depth=16 --fp8 --window-pattern L --save-every=500 --device-batch-size 16

После запуска, скрипт произведет все необходимые расчёты по автоматическому выставлению параметров. Размер d16 составляет 0.5B (размер PLE указан как value_embeds и составляет 0.25B, размер матриц трансформера 0.19B и общий размер 0.5B), суммарный размер батча 512к, количество голов внимания 8.

С учетом Закона Шиншиллы и PLE скрипт рассчитал, что для d16 нужно 2.8B токенов, чтобы достигнуть это число обучение будет в несколько эпох, пока не будет пройдено заданное количество токенов. Из-за множества эпох возможно переобучение (overfitting).

e65cf2fe9d8ca5d310871e58b4f57cc7.png

Малый размер датасета и BOS-aligned best-fit packing

По умолчанию в nanochat максимальная длина последовательности 2048 токенов. Но я выставил её в 512, чтобы сэкономить память, и тут же столкнулся с первой проблемой обучения.

Обучение шло не плохо, loss уверенно снижался, но эпохи слишком быстро сменяли друг друга.

По расчётам должно было быть 5.5 эпох, но первые эпохи прошли слишком быстро, а потом пошли эпохи 6, 7, 8, чего быть не должно. Вернувшись к анализу кода, и внимательнее посмотрев на предупреждение в файле dataloader.py о том, что "Original Streams tokens" отключен, теперь вместо него BOS-aligned bestfit который "~35% tokens cropped at T=2048", стало понятно, что датасет кропается по какому-то алгоритму.

Старый способ создавал плоский буфер токенов из 100% датасета, который шли друг за другом, в таком режиме обрезки старой статьи попадали в новую, получалось много шумных данных. Вместо этого новый алгоритм ищет статьи которые влезают в заданную последовательность, если таких нет, берутся длинные и обрезаются, обрезки выбрасываются.

При bestfit модель видит более чистые данные, каждое начало это BOS токен и начало документа, структура и весь контекст статьи в одном месте. Но при размере контекста в 512 токенов, хвосты выбрасываются и это составляют львиную долю датасета.

В итоге в обучение попало только 170M вместо 508M при ctx 512.

Обучаем pretrain. 1 попытка. Контекст 2048

Вернемся к стандартному значению в 2048. При таком варианте из датасете берется 370M. Потери в районе обещанных 35%, поэтому попробуем обучить так.

Численным показателем хода обучения выступает функция потерь cross-entropy loss. Модель выдает распределение вероятностей по всему словарю, настоящий следующий токен известен из обучающих данных, и кросс-энтропия измеряет расстояние между тем, что выдает модель и тем, что должно быть. На первых шагах loss максимальный и вычисляется как натуральный логаритм от размера словаря, в нашем случае это 32к, все 32к токенов имеют равную вероятность.

\text{loss} = \ln(\text{vocabsize}) = \ln(32768) = 10.39

Базовые паттерны будут очень быстро усваивается, поэтому дойти до loss 6 будет просто, в районе 3 будут усвоены все основные принципы языка, орфография, пунктуация, опуститься ниже 3 будет сложно, так как там будут выявляться уже какие-то конкретные факты, тонкости.

Размер d16, fp8, 5090, датасет 370M с BOS bestfit, целевое количество токенов 2.8B, ожидаемое время обучения 6 часов. Размер контекста в 2048, хвосты длинных статей обрезаются, 63% датасета. Обучение потребует ~9 эпох.

8c6414070e1d9ecea9e24b8344eae11d.png

loss 10.39. Шаг 1. Loss совпадает с расчётным, все 32к токена равновероятны при выборе моделью. Посмотрим как это выглядит.

Токены просто хаотично слипаются, есть какие-то слова, но это либо случайность, либо целый токен слова, текст представляет собой неразборчивое месиво:

loss 10, 1 шаг

loss 10, 1 шаг

loss 6. Шаг 40. Происходит быстрое снижение с 10 до 6. Базовые паттерны языка выявляются, смысла в фразах нет, но теперь это уже не мешанина токенов:

loss 6, 40 шагов

loss 6, 40 шагов

loss 3.3. Шаг 500. Примерно 10% обучения, эпоха ещё не пройдена. До loss 3 добраться просто, нейросеть быстро аппроксимирует язык и PPL равняется 20, у модели есть 20 вариантов следующих токенов, которые она считает подходящими.

8699366629f544fe1036d652a2db5ac9.png

PPL 20 означает, что ответы уже начинают походить на настоящие, модель выучила частоту токенов, простые сочетания, базовую грамматику, в фразах начинает проявляться смысл:

loss 3.3, 500 шагов, 10%, датасет 370M

loss 3.3, 500 шагов, 10%, датасет 370M

loss 2.6. Шаг 3000. 55% обучения. 2 эпохи. Опуститься ниже loss 3 занимает много времени.

Тут можно заметить bpb 0.56, который я пока не учитываю.

de194a32accf9ac6fa6a95677f4d5b79.png

loss ниже 3 изучает семантические связи, длинные зависимости, набор фактических знаний. PPL опустился до 13, текст становится более связным:

loss 2.6, 3000 шагов, 55%, датасет 370M

loss 2.6, 3000 шагов, 55%, датасет 370M

loss 1.8. Шаг 5376. bpb 0.7, 9 эпох. Пройдено 2.8B токенов, цель достигнута.

Завершал обучение под Win10, поэтому цифры отличаются

Завершал обучение под Win10, поэтому цифры отличаются

Проверка pretrain 1. Первая проблема обучения на fp8

Можно посмотреть какие паттерны удалось выявить.

В целом текст получается связным, ответ по промпту, орфография соблюдена. Модель пытается что-то выжать и придумать какой-то ответ, даже если ей не известно ничего:

6f7c9a5040cf2f08845fc1835be9a36c.png

Проверим, как модель усвоила тонкости языка. Если начать как мужской, то модель продолжает писать в мужском роде, если начать как женский, то модель следует этому:

eaf4a4f15f2abebff2c915bbf1bf29af.png

Списки стандартный, буквенный, римский и ненумерованный. У модели не получилось аппроксимировать этот навык:

Провал со списками

Провал со списками

И это первое проявление проблемы fp8 против bf16. Точнее их было больше, но модель постепенно, но не идеально, выправляла их по ходу обучения.

Для сравнения fp8 vs bf16 пример старого чекпоинта d16, который обучался только на статьях Хабра, но обучался в bf16. Такой чекпоинт не только вывел как правильно составлять все варианты списков, но и усвоил последовательность планет до Марса:

73d30dd6471112dd7a1828656f76445f.png

Но в целом pretrain обучился и в fp8, и возможно ему просто не хватило токенов.

pretrain. 2 попытка. Попробуем контекст в 8192

Чтобы увеличить количество токенов, и прежде чем отказываться от BOS bestfit, попробуем обучить модель в 8192. Это увеличивает до 450M токенов, примерно 85%.

Обучать сразу в 8192 не рекомендуется, так как стабильность хуже, матрица внимания слишком большая на первых шагах из-за чего сходимость будет плохая.

Скорость обучения просела в 2 раза (и дополнительно от того, что под Win10):

e3d7089762ea1d8ce7c94793c781b3ab.png

На 500 шагах loss упал до 3.2, в целом работает:

c4745bf5b97094ac5709077fb0ac28f7.png

Качество для loss 3 имеет слишком много зацикливаний и повторений:

93eef299d18bea3dd5c56484f1393f65.pngf2e83730af75245d5e53a5af3b728ad9.png

Поэтому попробуем вариант поэтапного обучения. Можно взять предыдущий чекпоинт в контексте 2048, который прошел 5376 шагов и дообучить его как Continued Pre-Training (CPT). Если немного модифицировать код nanochat, можно продолжать обучение не с конкретного шага, а инициировать новое обучение, но не с нуля, а весами с другого шага.

python -m scripts.base_train --depth=16 --fp8 --window-pattern L --save-every=500 --device-batch-size 4 --max-seq-len 8192 --model-tag d16-8192 --load-weights-from 5376

Модель уже видела 370M токенов, поэтому сразу loss 3.1 и быстро падает до 2.3, адаптация к 8192 проходит на первых шагах нормально:

216b6f377f85d6c4223b0d743cfabe2c.png

А дальше loss начал плавно расти до 2.7 и не собирался останавливаться. Модель обучается слишком большим шагом LR и вылетает из своего минимума.

1b9249a7542c7b8b53bf1e6323d28ac1.png

Нужно снизить LR, увеличить warmup:

python -m scripts.base_train --depth=16 --fp8 --window-pattern L --save-every=500 --device-batch-size 4 --max-seq-len 8192 --model-tag d16-8192 --load-weights-from 500 --matrix-lr 0.005 --embedding-lr 0.075 --unembedding-lr 0.002 --scalar-lr 0.125 --warmup-steps 200

После этого loss снижается, в ходе адаптации плавает от 2.4 до 2.1. Итоговый loss стал ниже даже 1.7, у 2048 версии было 1.8. Но при этом val bpb остался тем же, стал 0.71, а был 0.70:

cc9689528be49ead8b9fbd9e8e63f0ec.png

И это странно, если посмотреть лог, то минимальный bpb составлял 0.55, но в конце обучения он вырос до 0.7, хотя loss упал:

31f9c9356ce8c4453c7e536dc5ce8e93.png

Всё это указывает на переобучение. Для CPT надо было задать меньше эпох, так как в обучение добавилось только 80M дополнительных токенов, но чекпоинт на 2048 имел аналогичные показатели, минимальный был 0.55, а итоговый 0.70. Так что проблема была и с первым чекпоинтом.

Не сохранилась 0.55 версия, но можно сравнить bpb 0.65 vs 0.71:

1f89769291c443ca018b304f471a7c95.png

Версия 0.65 дает правильный код и структуру ответа, версия на 0.71 зацикливается. Видимо на 0.55 было бы ещё лучше. Переобучение ощутимо снижает качество, но оба чекпоинты были переобучены, так как val bpb был 0.7, потенциал датасета не раскрыт.

BPB, Loss и PPL

Простая и быстрая оценка LLM это показатель перплексии PPL.

PPL показывает степень уверенности модели в её ответе. PPL равный 10 означает, что у модели на выбор 10 вариантов, и она не уверена какой из них лучше, модель колеблется между этими 10 вариантами. Loss и PPL математически связаны:

PPL = e^{loss}

Loss 3 дает PPL равную 2^3 = 8, loss 1.8 = PPL 3.5. Если Loss снижается, а val Loss растет, значит модель от обобщения перешла к запоминанию, модель переобучается (overfitting).

В nanochat для валидации используют BPB, более универсальную метрику, которую можно сравнивать на разных датасетах и токенизаторах. BPB не зависит от того, токенизатор разбил слово на 3 токена или на 1 токен, так как нормализует значение. BPB - сколько бит информации требуется модели, чтобы закодировать один байт текста:

\text{BPB} = \frac{\mathcal{loss}}{{\text{bytes}} \cdot \ln(2)}

SFT для pretrain

Пока продолжим с тем, что получилось. Pretrain умеет только продолжать текст, чтобы раскрыть этот потенциал нужно дообучение на другом датасете, который покажет модели:

  • Шаблон Assistant - User

  • Примеры вопросов и качественных ответов

  • Примеры где нужно останавливать генерацию, чтобы не генерировать до отсечки

Найти хороший датасет не тривиальная задача. Я нашел несколько вариантов:

Возможно, имеет смысл создать SFT датасет по статьям хабра в формате вопрос-ответ, чтобы знания у модели лучше усвоились. Например, создать что-то такое, для каждой статьи создать от 2 до 10 ответов, это позволит научиться отвечать на вопрос не целой статьей, а коротким ответом, и позволит лучше усвоить знания из статей:

091318e6b4126dfc5a67940880052d7f.png

saiga_preferences это DPO датасет, но если взять только chosen, и игнорировать rejected, то получится SFT. Но это маленький датасет на 30к записей, который не включает в себя многие сценарии. Дообучение на нем займет не много времени, как проверка концепции подойдет.

Я не сохранял промежуточные чекпоинты, поэтому версии с bpb 0.55 не осталось. Попробуем дообучить 0.71 версию, посмотрим, что получиться с переобученным pretrain. Запускаем SFT и смотрим, что показатели loss тут отличаются. Они ниже 1, но это нормально, так как датасет маленький, и показатель val bpb не показывает переобучение:

0b2631c567f175b2f88e031e21411e40.png

Свободный режим общения с моделью. Уже не плохо, модель ведет диалог, ответы короткие:

d16 8192, sft saiga

d16 8192, sft saiga

Подберет занятия, чтобы развеять скуку (конечно, если вам подходит вариант с путешествиями по времени или в космосе):

ece582442fb59a962b2f4b3f56be3777.png

Если задавать вопросы, то ответы уже становиться длинными, но модель научилась выполнять инструкции и отвечать на вопросы по теме:

67b823d42cae2dd5e0158bcb7519c8fd.png

У pretrain размер генерации без остановки доходил до лимита в 8к, теперь же модель останавливается сама:

f7203099adc1be60742db4e22338c970.png

Можно попробовать написать статью, так как обучение было на статьях, то она не должна потерять навык генерировать очень длинный текст, сохраняя оформление:

f7117772b54ca180ec43fe2344072d7d.png

Попытка написать стих. Всплывает проблема зацикливания:

80892bd47df2a71dc8e972aad279c924.png

Как концепция - всё работает.

После SFT выравнивание через DPO

В датасете DPO есть хорошие и отвергнутые ответы, увеличивая разрыв между ними, можно выровнять веса модели так, чтобы у неё был перевес в нужную сторону.

Тут сталкиваемся с той же проблемой обучения. Вначале у DPO loss всегда равен ~0.693, PPL 2 - cлучайное угадывание между 2 вариантами. При нормальном обучении DPO loss должен плавно снижаться, показывая, что модель учиться выбирать хорошие варианты. И вначале всё идет не плохо, loss снижается:

5b763c75132fef93671ebf443c0c025e.png

Но после 25% loss резко растет выше 0.69, что в целом не нормально для DPO:

c7042611ce4afc3776b6b40467fd8a4f.png

Попробуем тот же способ как выше, снизим LR:

python -m scripts.chat_dpo --model-tag d16-8192 --beta 0.1 --dataset saiga_preferences --matrix-lr 0.00001 --embedding-lr 0.00001 --unembedding-lr 0.00001

Теперь нормально, loss плавал от 0.33 до 0.56, но не выходил выше 0.69:

70278ee2eb7991ba12967dc2438a86a6.png

Посмотрим, дало ли это хоть что-то.

Начало генерации в обоих случая одинаковое, перегенерирован только последний ответ:

d462c6ead74c15f076dd98928c04e768.png

Так как SFT версия получилась не достаточно хорошей, сложно сказать это случайность или действительно какой-то значимый эффект есть. Ответ стал лучше, DPO версия хотя бы сгенерировала код, а не впала в рассуждения, но код не того качества, как ожидалось.

Исследование. fp8 против bf16, 100% датасет без BOS best-fit

Первые попытки не стали полным провалом, но было видно, что они работают хуже, чем могли бы, и это заставляет искать другие стратегии обучения. Проверим несколько гипотез на микро модели размером d8, сравним загрузку датасета по стратегии bestfit с 100% flat, fp8 vs bf16.

У d8 размер 124M (как у базовой GPT-2 Small 124M). Для обучения 124M с учетом PLE нужно как раз 0.5B, что совпадает с размером датасета Хабра без bestfit.

Скрипт показывает, что обучение влезает в ~1 эпоху:

01e32d58aa9962043dfe30f5cd9a54c2.png

d8 это маленькая модель, модели такого размера почти сразу скатываются в повторы и зацикливание:

01ffa212c6235e0acc3e381bf8381a61.png

Поэтому сразу добавим штраф за повтор в размере 1.1. В целом ответы тут буду глупее чем на d16, так как размер совсем крохотный, хотя и d16 очень маленькая.

1 вариант. Размер d8, обучение fp8, контекст 2048 с 100% загрузкой датасета:

d8 124M, fp8, ctx 2048 100%, bpb 0.61

d8 124M, fp8, ctx 2048 100%, bpb 0.61

bpb 0.61:

15fd9ff3b467294e5f08494206c2c828.png

2 вариант. Размер d8, обучение fp8, контекст 8192 с bestfit:

d8 124M, fp8, ctx 8192 bestfit, bpb 0.58

d8 124M, fp8, ctx 8192 bestfit, bpb 0.58

bpb 0.58:

388e6df1305d58f23beac588dab07ead.pngb432ef822029b668104de80e3750db8a.png

3 вариант. Размер d8, обучение bf16, контекст 2048 с 100%:

d8 124M, bf16, ctx 2048 100%, bpb 0.61

d8 124M, bf16, ctx 2048 100%, bpb 0.61

bpb 0.61:

02012c82cba78dda0085e0fd006c43dc.png

4 вариант. Размер d8, обучение bf16, контекст 8192 с bestfit:

d8 124M, bf16, ctx 8198 bestfit, bf16, bpb 0.58

d8 124M, bf16, ctx 8198 bestfit, bf16, bpb 0.58

bpb 0.58:

8afd7190affe21184047fc1f7acab6e0.png

Ответы моделей слабые, но даже так можно сделать какие-то выводы:

  • даже при одинаковых loss и bpb связность ответа отличается.

  • ответы bf16 лучше согласованы

  • разница между bestfit и 100% загрузкой незначительная

Обучать в fp8 сложно, в случае обучения в bf16 это тоже самое, что fp32 и поэтому переход от bf16 к fp8 снижает диапазон в 4 раза и требует различных хаков с масштабированием. Для таких маленьких моделей это приводит к тому, что модели не имеют достаточно простора, чтобы сделать обобщение быстро и переобучаются раньше, чем обобщают. Требуется определенный опыт для обучения в fp8 и в условиях ограниченного датасета это не лучший вариант.

Что касается загрузки датасета, показатели loss и bpb - это усреднение ошибки на млн токенах, они не показывают качество усвоенных данных. И потеря 37% критична на таком размере, поэтому имеет смысл переключиться на полную загрузку. Как вариант, можно попробовать разбивать статьи длиннее T=2048 по абзацам, чтобы лучше влезать в besfit.

Нужно всё переделать и сделать правильно

Попробуем всё переделать. Обучение в bf16, ctx 2048, непрерывный 100% датасет.

На половине обучения bpb 0.54:

435cb8ed4d8e6ec146b42fd604ed9d3f.png

46%, обучение ещё не завершено, но pretrain уже ведет себя стабильнее:

337c86c8c375e60ee9ef9b682756c6f4.png

Модель начала усваивать списки, что указывает на то, что диапазона хватает, и модель может извлекать более сложные признаки и паттерны, чем это получалось в fp8:

d16 bf16

d16 bf16

83%, 4500 шаг, bpb остается 0.54, модель не переобучается и продолжает выявлять паттерны:

f7d1b08bda80e3033061328e08e80279.png

К этому шагу модель освоила простой перевод, чего версия на fp8 не смогла:

cat = кошка, dog = собака, keyboard =

cat = кошка, dog = собака, keyboard =

Более сложные фразы удаются:

95a2b67391b13b90bd8b5aa9c10f7e56.png

Обучение завершено на val bpb 0.55, loss 2.12. Пройдено 2.8B без bestfit, плоским списком с 100% загрузкой всех токенов. Переобучение минимальное, val bpb близок к лучшему значению.

d16 bf16

d16 bf16

Результат bf16

pretrain усвоил порядок планет до Нептуна:

83db622c94f2c1ed8d9ac835513fdcc8.png

Свободный чат:

e79bc7dbed80ac6ffdfaf0a525ecc25f.png

Вопрос-ответ:

6fe8252799118e931d3a2ad9c72b96da.png

Генерация простого кода:

f4f7d0c5ba288d697ccffb57eb1872c7.png

Написать корректный json это тоже навык:

fc857e6723ba3c4d790a8b5fcc5e0b51.png

Где будет провал

Модель не может знать как чинить кран на кухне, и что вообще такое кран на кухне, так как такой информации не было на Хабре.

37752da3378b751fca11b437bba1ce42.png

Но зато смогла каким-то образом понять, что вообще такое "Кухня":

9aeafe1b27458a3e6d6d9f6fb1f61a88.png

У модели нет знаний из Wiki, и встречая незнакомые сущности навык галлюцинаций выкручивается на 500%:

bfa29fdafad1a871c0f2ebf691402ed3.png

Но знает эмодзи, так как они встречались:

cbd926fc2325cab2c69c6c45b538e116.png

Сложность со следованием какой-то точной инструкции, например "не писать комментарии", просить перечислить точное количество чего-то, написать сложный код и тому подобное.

f881668583d7166e7327bdf3b35dff06.png

Более простые задания с небольшой конкретикой даются лучше:

6f49c65fead24fd2a21d30cd20c8c00b.png

Если pretrain мог переводить с помощью правильно составленного запроса, то SFT версия почти не умеет, так как не было или мало примеров такого сценария в SFT датасете. Вместо перевода начинает общение с текстом, при этом понимает смысл текста на английском.

9267f9ded37046f9a1a5fa4ed1bb8db5.png

Но простые примеры иногда получаются:

38042697e0d71e0e46f7634339a0b47e.png

Потенциал не раскрыт

Как концепция - работает, но можно лучше. Если пройтись циклом дообучения:

Saiga SFT → Habr SFT → Vikhr SFT → Saiga DPO

Можно получить более интересную модель:

Файлы моделей

Чекпоинты: https://huggingface.co/shannonkun/nanochat-d16-habrgpt

Для запуска нужно использовать https://github.com/karpathy/nanochat

python -m scripts.chat_web --source sft --model-tag d16-dpo-step2-bf16

Поддержки gguf пока нет.

Заключение

Модель habrGPT 0.5B научилась связно говорить, соблюдать орфографию, пунктуацию, давать ответы на вопросы, писать статьи, выполнять задания, генерировать простой код, писать что-то похожее на стихи, немного переводить, несмотря на то, что английского языка было мало.

Первая GPT-2 124M обучалась на 10B токенов, Gemma3 1B обучалась на 2T (2048B) токенов. Датасет Хабра содержит всего 508M (0.49B) узкоспециализированных токенов и всё равно что-то получилось.

Возможно, вместо 0.5B стоит называть эту модель E0.25B, хоть тут и есть 0.5B, но вместо трансформных +0.25B тут легковесные +0.25B PLE, и на сколько они хороши и компенсируют качество - непонятно. Возможно, честные 0.5B были бы даже лучше.

Обучение в fp8 частично провалилось, частично удалось. Обучить такую маленькую модель в fp8 можно и какой-то результат достигнут, но результат хуже чем на bf16.

Схожие новости

#Наименование новостиТональностьИнформативностьДата публикации
1[Перевод] Как на самом деле работают LLM0707-07-2026
2LLM (ИИ) - О СЕРЬЕЗНОМ И НЕМНОГО ЮМОРА, КАК ОБЫЧНО ...2601-07-2026
3Я устал писать одноразовые скрипты для бенчмарков LLM и собрал харнесс, который сам считает Pareto-front0727-06-2026
4Нейросеть-автопилот вместо 400 Playwright-тестов0707-07-2026
5Настройка AI-агентов для ускорения бизнес процессов компании0703-07-2026
6130 новых пользователей и ни одной покупки: как один промпт чуть не убил бота, который уже принес $12005702-07-2026
7Анализ: популярные ИИ-агенты тратят в 136 раз больше электричества, чем ChatGPT0706-07-2026
8Носители данных — «игра на выбывание» (2026.07)0504-07-2026
9Как заставить ИИ соблюдать закон, не трогая веса. Выкладываем в открытый доступ внешний фильтр для LLM5707-07-2026
10Google Launches Nano Banana 2 Lite for Low-Cost, High-Throughput AI Image Generation0502-07-2026

Классификация: Наука. Схожих патентов: 0. Схожих новостей: 10. Тональность: 0. Информативность: 5. Источник: habr.com.