
Древняя модель ruGPT-3 XL 1.3B конца 2020 - начала 2021. Модели тех времён не умели выполнять инструкции или вести диалог в чате, они умели только продолжать текст. С помощью современных методов дообучения SFT и DPO можно ли сделать из старого pretrain современную LLM? Получившийся результат сравним с Gemma3 1B, моделью 2025 года. И немного продолжения HabrGPT 0.5B с дообучением на большом датасете.
Содержание
Этапы обучения LLM
Обучение LLM имеет 3 основных этапа:
pretrain - это base модель. Неразмеченный сырой текст, модель учится продолжать.
SFT - это instruct модель. Требует качественный, размеченный датасет.
DPO - выравниваем ответы модели на ещё более качественном датасете.
Pretrain - обучение с нуля начинается со случайных параметров, на вход необученной модели подается сырой текст, модель шаг за шагом пытается предсказать новые токены на основе предыдущего текста - цель настроить параметры так, чтобы модель могла уверенно продолжать текст. Есть различные стратегии как заполнять pretrain для улучшения результата.
Вначале pretrain веса случайны, но по мере обучения начинают проявляться структуры:

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

ruGPT-3. Как было до SFT
Семейство ruGPT-3 это pretrain модели представленные в различных размерах. Версия XL 1.3B обучалась ~10 дней на 256 Tesla V100, размер датасета 80B токенов, 4 эпохи на контексте длиной 512 токенов и 1 эпоха файнтюна, расширяющая контекст до 2048. Умелец @efreelancer проделал работу, чтобы конвертировать старую модель в современный формат, к которому можно применять привычные скрипты. Подробности в его статье: https://habr.com/ru/articles/1016148/
В 2020 году ещё не придумали способ обучение на instruct, SFT появилось только к 2022 году, когда первая SFT-модель InstructGPT, вышедшая в январе 2022 года, продемонстрировала новые горизонты для LLM.
До этого момента модели были тем, что сейчас называют pretrain, они не понимали концепцию вопроса или задания, любой текст они просто продолжали.
Например, вопрос как часть повествования:

Или вопрос как часть диалога:

Pretrain не может понять, что от неё хотят, она умеет только продолжать текст:

Как управлять pretrain-моделью
Можно управлять тем, что и как именно будет продолжать pretrain, для этого нужно начать фразу правильным образом, создать "затравку".
Например, для задачи перевода можно начать перечислять пары слов и последнюю пару оставить без перевода. Или нужно задать вопрос и начать ответ:

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

Чем тут поможет SFT
Если показать pretrain как здороваться, как отвечать на вопросы, как выполнять задания, то модель очень быстро усвоит шаблон. Но у LLM нет возможности работать ни с чем, кроме сплошного текста, поэтому нужно показать модели как отделять свои ответы от запросов пользователя, для этого создают шаблон, например, формат ChatML:
<|im_start|>system Ты — полезный и вежливый AI-ассистент. Отвечай кратко и по делу.<|im_end|> <|im_start|>user Привет! Какое расстояние от Земли до Луны?<|im_end|> <|im_start|>assistant Привет! Среднее расстояние от Земли до Луны составляет около 384 400 километров.<|im_end|> <|im_start|>user А сколько лететь туда на обычном самолете?<|im_end|> <|im_start|>assistant
Для простого понимания шаблона вопрос-ответ достаточно 100-200 примеров, который будут заполнять такой шаблон и отправляться модели на вход. Каждый раз новый ответ или запрос будет добавляться к такому шаблону и модели на вход будет подаваться сформированный новый текст целиком.


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

ruGPT-3. Как стало после SFT
Для создания универсальной LLM не хватит 100-200 примеров, так как датасет должен содержать в себе не только вопрос-ответ, но и весь спектр возможных сценариев. Поэтому возьмём готовый датасет, который хорошо сбалансирован.
DPO датасет IlyaGusev/saiga_preferences от @Takagi имеет 30к записей, они хорошо подобраны, но это DPO датасет, поэтому для SFT он будет не полным, но достаточным для демонстрации. Чтобы из DPO сделать SFT, нужно не учитывать rejected ответы.
Обучение стандартным huggingface SFTTrainer, для ускорения компиляции model = torch.compile(model, ...). Для windows нужно установить triton-windows, возможно flash-attn. Датасет не очень большой, 1 эпоха занимает ~1.5 часа. Можно обучать как full finetune, так и LoRA, DoRA, QLoRA, в зависимости от того, сколько есть VRAM.
Датасет маленький, всего 42M токенов:

Обучение занимает несколько часов, так как датасет маленький, то 2 полные эпохи. Ппо ходу обучения снижается loss, что говорит о том, что шаблоны усваиваются, и вместе с ними усваивается немного новой информации из датасета, но так как это всего 42M токенов, то это не существенно повлияет на pretrain, который обучался на 80B токенах.
Дообучение завершено, и теперь модель отвечает как и ожидается. Понимает вопрос, дает корректный ответ, соблюдает шаблон и форму. Генерация завершается сама, токен EOS генерируется корректно.
Про Чебурашку ответ теперь выглядит нормально:

Чтобы было удобнее, конвертируем модель в gguf и перейдем на llama.cpp.
Дообучение на датасете Сайги, там были записи о том, как модель должна представляться, поэтому в ответ на "кто ты" модель пишет, что она Сайга:

Но при этом в другой раз она уверена, что она создана Claude от Anthropic:

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

В данном SFT не было примеров для перевода, но сама по себе модель может переводить текст, так как в pretrain попадали и англоязычные тексты. Для перевода нужен более полный SFT, и тогда с переводом модель справится:

Тестирование получившейся SFT-модели в llama.cpp
Чтобы оценить на сколько pretrain стал походить на современную LLM, прогоним несколько сценариев. Так как pretrain не обучался на задачах программирования, то проверять будем только творчество, логику, креатив.
Первое, то что модель теперь хорошо распознает вопрос и отвечает ожидаемо:

Усложним задачу. Одновременно и вопрос и инструкция в одном промпте, плохо обученные модели ответят только на вопрос или проигнорируют вопрос и выполнят инструкцию. Другая задача "развесели меня", посмотреть, может ли модель отвечать не только на вопросы.
В обоих случаях модель справилась, ответила кто такой Шекспир, а потом, как и было задано, выдала список его работ. А на скуку предложила варианты, то есть поняла, что от модели ожидается какое-то действие:

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

Негативные инструкции
В целом не плохо, модель уже стала не просто продолжателем текста, а настоящим чат-ботом. И обычно маленькие LLM проваливает тест на "не думай о белом медведе". Проверим как справляется модель.
Просим написать короткий рассказ, в котором нельзя упоминать слово "щенок". Модель не знает, что такое "очень короткий", и про щенка тоже провалила условие:

Но, чтобы убедиться, что модель способа выполнить задание, перегенерируем ответ несколько раз, и, спустя десяток попыток, оба условия выполнены:

Модель может выполнить такую задачу, но не знает как это сделать, она не проходила дообучение на то, чтобы контролировать длину и выполнять негативные инструкции. К модели не применялись никакие штрафы, чтобы понижать сигнал для плохих ответов, и повышать для соответствующих. Для этого применяют выравнивание, например, через DPO.
Но прежде чем перейти к DPO, проверим другую идею - цепочка размышлений CoT (Chain-of-Thought). Добавляя в контекст дополнительную информацию, можно помочь механизму внимания лучше сконцентрировать сигнал вокруг нужного ответа.
Чтобы быстро проверить эту идею, то внедрим CoT мысль вручную. Сначала создадим запрос, но вместо ответа модели подставим текст с мыслью: [Мысль: Мне нужно написать короткий рассказ о маленькой собаке, но я не имею права использовать слово "щенок". Я буду использовать слова "малыш" и "собачка".]

Для модели нет понимания самая она это сгенерировала или нет, так как на каждом шагу она просто получает новый текст от начала до конца, просто там добавляется 1 новый токен. И можно самостоятельно добавить необходимое количество токенов и продолжить генерацию с любого момента. Поэтому добавляем мысль и нажимаем продолжить генерацию.
Частично сработало, вместо "щенок" модель использовала "маленькая собачка", для маленьких моделей режим CoT очень полезен для повышения качества. Но CoT не помогает с длинной ответа, так как модель ещё не получала штрафы за неправильную длину.

Сравним с Gemma3 1B
Перед тем как перейдем к DPO, интересно сравнить получившуюся SFT-модель с чем-то более современным, например, Gemma3 1B 2025 в целом в той же весовой категории. ruGPT3 обучалась на 80B токенах, Gemma3 1B 2025 года обучалась на 2T, что в 26 раз больше.
Скорее всего для Геммы такое перенасыщение идёт в минус, так как 1B не способно вместить такое количество данных, особенно при смене языка с английского на другой.
Сразу зайдем с козырей. Задача про знание отечественных рок групп, у ruGPT3 очевидно с этим будет лучше. В ответ неплохой список у ruGPT3, у Gemma3 1B с этим плохо:

Теперь простой многоходовый чат. Сначала приветствие, дальше сделать вывод по тексту, задание продолжить текст и в конце небольшая загадка. По началу обе модели идут ожидаемо хорошо, но под конец Gemma3 1B проседает, и в конце дает неправильный ответ на загадку, ruGPT3 справляется:

Дальше длинные и сложные вопросы на которые надо дать ответ одной фразой. Первый вопрос про квантовую физику. ruGPT-3 ответила правильно, Gemma3 1B нет:

Второй длинный вопрос, про механику. Gemma3 1B ошибается, ruGPT3 дает правильный ответ:

Простая загадка на пространственное восприятие и запоминание. Несмотря на предложение для Gemma3 1B подумать, она настаивает на ошибочном решении, у ruGPT3 ответ правильный:

Ещё проще: "Что люди делают по ночам? Одним очевидным словом". У Gemma3 1B ответ развернутый, включает многие факторы, которые правильные, но правило про 1 слово не выполнено, у ruGPT3 ответ "Люди спят":

Пока Gemma3 1B ни разу не справилась. Возможно, это совпадение, например, ruGPT в целом не способна давать развернутые ответы и просто пишет 1-2 слова, что выглядит как умный ответ. Попросим дать развернутый ответ на то же самое задание.
Обе модели хорошо и структурированно расписали ночные занятия:

Отыгрыш роли, тут не требуется точных ответов, нужно лишь изменение поведения и стиля ответов. Задание для моделей притвориться собакой и говорить "Гав".
Обе модели как будто бы справились, сложно понять, каждая по своему сработала:

Более сложное, пускай будут линукс-терминалами. И вот тут у ruGPT-3 XL провал, модель вместо имитации терминала начала описывать что делают команды:

Немного DnD. Нужно учитывать сцену, имена участников, расположение персонажей и общий сценарий. Тут уже обе модели плохо справляются, у ruGPT-3 XL ответ поинтереснее, но пошло раздвоение личности, в остальном не выглядит так, что модели справились:

У Gemma3 1B огромное преимущество в технических и комплексных задачах, вроде написать код или извлечь данные в json, на примере с терминалом видно, что ruGPT3 не обучалась на таких данных и не сможет потягаться на этом поле.
SFT навязывает "поведение" для модели
Проблема перехода из pretrain в SFT в том, что какой стиль будет задан в датасете, такой и приобретет модель. Часто можно услышать о том, что интересно посмотреть на чистую модель, как бы она отвечала без навязывания ей какого-то поведения. Но по сути через SFT нельзя получить "чистую модель", будет взят именно тот шаблон, который модели и давали.
Например, тип отказа:

Даже писать грубо отказывается:

При этом если её попросить более явно, то напишет даже матом, так как дообучение было не полным:
Осторожно, мат

Можно даже полностью перевернуть стиль ответов. Например, возьмем датасет Telegram чатов Den4ikAI/russian_dialogues и дообучим на нём. Этот датасет содержит диалоги в свободном стиле общения, и для примера хватит первых 5-10к записей.
Теперь модель пишет "ыыыыы))) да вы шутите) как можно создать искусственный интеллект без полного понимания принципов его работы?)". И дальнейший ответ в таком же стиле:

DPO vs SFT
После SFT идет этап выравнивания. На этапе SFT модель научилась отвечать на вопросы, хорошо ли, плохо ли, но научилась отвечать, поэтому дальше можно научить её отвечать на вопросы хорошо. Для этого нужно показать ей пары, хорошие и плохие варианты ответов, сравнить активации этих ответов, усилить сигнал хороших и снизить плохих.
Обучение через DPOTrainer, в датасете Сайги теперь можно задействовать поле rejected:

После дообучения, первые тесты показывают, что изменение есть, условие про щенка выполняется чаще, модель придумала "маленький коричневый комочек шерсти":

При этом стиль ответов изменился на более свободный, но общее оформление улучшилось:

Сравним DPO и SFT лоб в лоб. При этом надо учесть, что ответы не всегда стабильны, температура может изменить ответ и у первого и у второго как в лучшую, так и в худшую сторону.
Просьба закончить фразу. DPO справился, SFT нет. SFT сделал типичную проблему для SFT без выравнивания, просто повторить фразу. Это случается не каждый раз, но зацикливание и эхо частое явление при не полноценном дообучении:

Прочитать текст и дать ответ. DPO дал правильный ответ, SFT начал сочинять историю:

В целом после DPO качество подросло, но теперь модель общается сама с собой и генерировать токен <|assistant|>. Это явно проблема не DPO, а какая-то проблема скриптов, поэтому попробуем разобраться.

Анализ ошибок обучения DPO
Проблема оказалась в том, что для DPO не был создан шаблон аналогичный тому, что создан для SFT, поэтому произошел рассинхрон. Нужно восстановить согласованность и дообучить заново.
Дообучение с правильным шаблоном прошло успешно, модель почти перестала добавлять токен <|assistant|> в чат, и перестала общаться сама с собой. Но проявилась другая особенность, модель начала отвечать в стиле DnD:

Модель усилила свои веса отыгрыша:

DPO другой датасет
Для сравнения, попробуем другой датасет для DPO, например, перевод одного старого формального датасета d0rj/rlhf-reward-datasets-ru
После 1 эпохи стиль действительно стал более формальным:

В задачах на сочинить историю, стиль не стал сухим, а остался живым:

Негативные подсказки срабатывают чаще в DPO версии:

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

DPO повторила все 3 строки и продолжила с учетом них. При написании песни тоже учла 1 куплет и на его основе продолжила песню:

Проблема с файлами gguf и контекстом длиннее 128 токенов
Модель ruGPT3 обучена со Sparse Attention, настроенная на 128 токенов. Поэтому всё, что выходит за 128 токенов попадает в первое разреженное внимание. На коротких диалогах это не особо заметно, но если нужно сохранять структуру на всей генерации, например, создать корректный html файл, то без рабочего Sparse Attention ничего не выйдет.
Например, попробуем сгенерировать html страницу, вначале всё идет нормально, но под конце генерация сломана:

Если применить патч на Sparse Attention, то тоже задание генерирует полностью рабочу html страницу, даже preview запускается:

Но даже с патчем модель способна писать только очень простой код, так как её не обучали на коде, это сделали только в ruGPT-3.5.
Патч создан @efreelancer, но он не принят в основную ветку llama.cpp, поэтому нельзя создать gguf, который заработает у всех. Подробнее про эту проблему, из-за которой PPL вместо 10 становиться 50, что снижает качество ответов в 5 раз, тут:
gguf
Несмотря на проблему с контекстом длиннее 128 токенов, я собрал gguf, который заработают у всех, но нужно учитывать эту особенность.
Так же я обучал модель такому шаблону чата:
<|user|> Привет.<|assistant|> Привет, я бот.<|endoftext|>
Такой шаблон дает лучшую сходимость и потом работает стабильнее, чем:
Вопрос: Привет.Ответ: Привет, я бот.
В gguf новый шаблон уже вшит, но там нет исправления sparse attention, качество будет резко проседать после 128 токенов, поэтому рассчитывать на многое не стоит. Но проверить концепцию можно, либо использовать safetensors:
safetensors SFT: https://huggingface.co/shannonkun/rugpt3xl-1.3b-sft
gguf SFT: https://huggingface.co/shannonkun/rugpt3xl-1.3b-sft-gguf
gguf DPO: https://huggingface.co/shannonkun/rugpt3xl-1.3b-dpo-gguf
Про загадку с автомойкой и машиной
Такая маленькая модель не может дать правильный ответ осознано, но за счет работы семплинга, за счет добавленной случайности, у модели позволяет выдавать 50/50 правильный ответ, отвечая в ответ то доехать, то прогуляться.
Если уточнить причину, будет понятно, что он ничего не понял:

Больше не значит лучше, наполнение SFT датасета
Причина почему я использую DPO датасет saiga_preferences как SFT (и тут и в статье про habrGPT) в том, что он не плохо сбалансирован и не требует калибровки, но для SFT он не полон, поэтому все возможности pretrain не раскрываются. Но это позволяет получать сразу хорошие результаты при минимальном размере датасета.
Особенность хорошего современно SFT в том, что он не должен быть просто наполнен множеством примеров, нужна определённая стратегия заполнения.
Обычный чат и следование инструкциями должны это основные сценарии для модели, модель должна сохранять стабильную послушность и последовательность. Знания QA на том же уровне с чатом, как одно из основных применений, модель должна иметь актуальные и корректные знания, это и снижает степень галлюцинаций, и сама модель становиться полезной при работе с библиотеками, фактами, рассуждениями и тому подобному.
Для математики и кода не нужного много примеров, нужно чтобы это были хорошо отобранные примеры, просто весь подряд код тут не нужно добавлять, для этого был pretrain.

Если домены распределены хаотично, а само заполнение плохое, то шум будет перебивать сигнал, модель потеряет стабильность, ответы будут то нормальные, то плохие, то хаотичные, если был перекос с каким-то доменом, то модель может на любую тему начать отвечать этим доменом и так далее. Другая проблема - катастрофическое забывание, модель теряет свои навыки, так как перекос в какой-то домен с плохими примерами снизил полезный сигнал.
Для примера, есть огромный датасет ZeroAgency/ru-big-russian-dataset, он имеет 1.8 млн записей, 0.92B токенов, это микс из разных источников.
Датасет большой, отфильтрованный, оцененный GPT-4.1 (что в целом не показатель), но собран из солянки различных источников, включая переводы, перекос в распределении, массовая генерация заглушает сигнал качественных данных.
На дообучение уходит несколько дней:

И этот датасет не подружился с ruGPT-3. Изначальная модель потеряла свои навыки, её ответы потеряли стабильность и может уходить в другие степи, отвечая не по теме.
На вопрос "Сравни трансформеры и рекуррентные нейросети" отвечает про трансформеров как автоботов:

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

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

Возможно проблема дообучения где-то в скриптах или с самой моделью.
Дообучение HabrGPT 0.5B на большом датасете
Даже если датасет ru-big-russian-dataset не самый удачный вариант SFT для ruGPT3, то для пустой модели, которая изначально почти не имела данных, такой датасет дает наполнение, расширяет диапазон возможных задач и общих знаний.
Например, HabrGPT 0.5B, LLM которую я обучал с нуля только на статьях Хабра, тут нет других источников, нет знаний из Wiki, нет книг, имеет только ту информацию, что получилось аппроксимировать из Хабра:

После дообучения на ru-big-russian-dataset, модель получила недостающую информацию:

Модель могла немного переводить в pretrain, но не умела этого после SFT из-за неполного датасета, но теперь даже такая урезанная модель может в перевод:

В отличии от ruGPT3, которая не обучалась на коде, HabrGPT 0.5B лучше работает с кодом, и может даже создать список из пьес Шекспира в html:

Но этого всё равно не хватило, чтобы такая модель, обученная только на статьях Хабра, узнала, что такое батареи и полотенце, не хватает общих знаний:

И энциклопедических знаний в датасете, чтобы восполнить все пробелы, тоже не хватило, что нормально для SFT датасета, так как знания должны были закладываться в pretrain:

Заключение
Из чекпоинта ruGPT3-XL 1.3B при помощи современных методов дообучения получился proof-of-concept переход из base модели в instruct модель. Эта pretrain-модель обучена за 2 года до выхода ChatGPT, и умела только продолжать текст, но научилась вести диалог, выполнять инструкции, отвечать на вопросы, писать стихи, понимать неопределённые просьбы, давать рекомендации, решает простые головоломки.
Получился неплохой тренажер для тех, кому интересна тема обучения LLM дома. Сравнили различные датасеты, посмотрели как меняется поведение модели от содержимого датасета: от свободного неформального общения до формальных фактов. От датасета зависит качество LLM, чем полнее и лучше SFT/DPO, тем лучше результат, поэтому потенциал ruGPT3 не раскрыт. Секрет хорошего SFT не в количестве, а в стратегии заполнения, и тогда SFT может превратить обычную LLM в хорошую LLM. А с помощью DPO из хорошей LLM можно получить отличную.
Но, даже в таком виде, получившая модель смогла обойти Gemma3 1B в части задач.
Комментарии (3)

efreelancer
23.07.2026 07:00Отличная публикация, рад что наработки по ruGPT3XL пригодились.
Кстати по ходу чтения пришла мысль, можно ведь проинициализировать пустую ruGPT3XL, по аналогии с базовой habrGPT, и обучить на полном датасете, а затем сравнить какая модель покзывает более качественные ответы, полагаю что это будет ruGPT3XL, ведь 0.5B меньше чем 1.3B, но всё же.
bethrezen
Привет! Я автор ZeroAgency/ru-big-russian-dataset. Спасибо, что попробовали датасет у себя. Кстати, у нас уже есть расширенные версии ZeroAgency/big-russian-dataset-v2-unfiltered и ZeroAgency/big-russian-dataset-3
Вопрос к вам очень важный. Вы когда SFT делали - маску правильно накладывали? Ну чтобы тренировалось только на ответах ассистента?
Shannon Автор
Да, маска накладывается так же, как и для других датасетов, тренировка только на последнем ответе ассистента: