Fine-tuning и веса · Fine-tuning and weights · урок 3 · 13 мин
Данные для SFT: форматы, chat template, чистка
SFT data: formats, chat templates, cleaning
Зачем
После урока ты соберёшь набор данных для SFT в правильном формате, поймёшь, что делает chat template и почему из-за него модель «не умеет остановиться», и опишешь чистку данных до обучения. На собеседовании это вопрос «walk me through the data pipeline», а на работе — та часть проекта, которая съедает больше всего времени и решает качество.
Набор данных — главный актив
SFT (supervised fine-tuning, обучение на парах «запрос → эталонный ответ») учит модель подражать примерам, включая их ошибки. Если в наборе половина ответов неудачна, модель выучит и неудачи. Авторы LIMA получили сильную модель всего на 1 000 тщательно отобранных пар. Отсюда правило: 500 ответов, написанных или вычитанных лучшими операторами, ценнее 50 000 сырых журналов чата. Для стиля и формата обычно хватает сотен – низких тысяч хороших пар. Adapter (обученную добавку) можно переобучить за час, а потерянные или грязные данные быстро не восстановишь, поэтому версионируют в первую очередь данные.
Форматы, которые понимает TRL
Библиотека TRL (Hugging Face, post-training; документация v1.15.0, открыта 10.10.2026) принимает четыре вида примеров:
- language modeling, сырой текст: {"text": "..."} — для continued pretraining;
- conversational: {"messages": [{"role": "user", ...}, {"role": "assistant", ...}]} — диалог с ролями;
- prompt-completion: {"prompt": "...", "completion": "..."};
- conversational prompt-completion: те же поля, но в каждом список сообщений.
Для tool calling (вызова инструментов) в сообщениях есть tool_calls и роль tool, а в отдельной колонке tools лежат JSON-схемы доступных функций. Файл обычно JSONL: один пример на строку. Пример строки для ассистента банка:
{"messages": [
{"role": "system", "content": "Ты ассистент банка. Сначала ответ, потом условия."},
{"role": "user", "content": "Сколько стоит перевод на карту другого банка?"},
{"role": "assistant", "content": "Сейчас проверю действующий тариф.", "tool_calls": [{"type": "function", "function": {"name": "get_fee", "arguments": {"product": "card_transfer_external"}}}]}
]}
Обрати внимание: в эталоне нет цифры тарифа, есть вызов tool. Иначе модель выучит сегодняшнюю комиссию как часть стиля и будет называть её через год.
Chat template: как роли превращаются в tokens
Модель не видит ролей, она видит последовательность tokens (кусочков текста). Chat template (шаблон диалога) превращает список сообщений в строку со служебными special tokens (зарезервированными tokens разметки). У Qwen это формат ChatML: каждая реплика начинается с <|im_start|>user или <|im_start|>assistant и заканчивается <|im_end|>. У других семейств свои маркеры. Документация Transformers предупреждает: с чужими маркерами модели работают «drastically worse».
Четыре правила, на которых ломаются новички:
1. Один шаблон в обучении и в inference (работе модели на запросах). Сервер вроде vLLM применяет шаблон из tokenizer модели; если ты учил на другом, поведение поплывёт.
2. При подготовке обучающих данных add_generation_prompt=False: маркер «теперь отвечает ассистент» нужен только при генерации.
3. Не дублировать special tokens. Если ты сделал apply_chat_template(..., tokenize=False), а потом сам переводишь строку в tokens, ставь add_special_tokens=False, иначе в начале окажутся два служебных tokens.
4. EOS-token (token конца последовательности) должен совпадать с концом реплики в шаблоне. Если модель учили, что реплика кончается <|im_end|>, а trainer считает концом другой token, модель не научится останавливаться и будет писать бесконечно. Документация TRL прямо пишет: для базовой Qwen/Qwen2.5-1.5B задать eos_token="<|im_end|>".
Loss только на ответе
Loss (ошибка, которую минимизирует обучение) в SFT — token-level cross-entropy: насколько модель «удивлена» каждым следующим token эталона. Считать её нужно на ответе ассистента, а не на вопросе пользователя и не на system prompt: иначе модель учится сочинять вопросы клиентов и заучивает повторяющийся system prompt. В TRL для prompt-completion так и сделано по умолчанию (completion_only_loss). Для диалогов нужно assistant_only_loss=True; это требует в шаблоне маркеров {% generation %}, и для известных семейств вроде Qwen3 TRL дописывает их сам. Гайд Unsloth отмечает, что обучение только на ответах может поднять точность на несколько процентных пунктов, особенно в многоходовых диалогах.
Чистка до обучения
- Отбор. Только ответы, которые не исправлялись и получили хорошую оценку. Устаревшие тарифы — удалить или заменить вызовом tool.
- Dedup (удаление дублей) — точных и почти точных. Статья «Deduplicating Training Data Makes Language Models Better» показала: в популярных наборах много почти-дублей; после чистки модель выдаёт заученный текст в 10 раз реже, а пересечение обучающих и проверочных данных затрагивало более 4 % проверочных наборов.
- Нормализация. Одинаковая запись цифр, Unicode, букв — так же, как на входе в production.
- PII (personally identifiable information, персональные данные) удаляются до обучения, а не после. Работа «Extracting Training Data from Large Language Models» извлекла из GPT-2 сотни дословных фрагментов обучающих данных, включая имена, телефоны и почту, даже когда фрагмент встречался в одном документе; большие модели уязвимее малых. Замена — согласованными метками (
CUSTOMER_A,ACCOUNT_1), а не пустым[REDACTED], чтобы модель учила структуру диалога. Полноту redaction (удаления PII) меряют на своих данных: казахские падежные формы и транслитерированные фамилии готовый инструмент может не видеть вовсе. - Длина. В TRL
max_lengthпо умолчанию 1 024 tokens, длинные примеры обрезаются с конца (keep_start). Если ответ ассистента стоит в конце длинного диалога, обрезается именно он. Посчитай распределение длин до запуска.
Разбиение, разметка и синтетика
Три части: train, validation (для выбора момента остановки) и test, который открывают один раз. Test — это новые обращения, пришедшие после сбора train, разбитые по клиенту или теме, а не по случайным строкам: иначе почти одинаковые диалоги одного клиента попадут и туда, и туда, и ты измеришь память вместо обобщения. Разметке нужны письменные правила с пограничными случаями и два разметчика на общей части; их согласие меряют Cohen's κ (каппа Коэна, согласие с поправкой на случайность). Синтетика от сильной модели быстра, но однообразна, содержит непроверенные ошибки и предубеждения модели-учителя, а лицензия учителя может ограничивать такое использование. Человек проверяет выборку, а test собирают только из реальных данных.
Схема
Термины · Key terms
- SFT (supervised fine-tuning)
- обучение на парах «запрос → эталонный ответ»
- chat template
- шаблон, превращающий сообщения с ролями в строку tokens
- special tokens
- служебные tokens разметки диалога, например
<|im_end|> - EOS token
- token конца последовательности, по которому модель останавливается
- assistant-only loss
- ошибка считается только на ответах ассистента
- JSONL
- файл, где каждая строка — отдельный JSON-пример
- dedup
- удаление точных и почти точных дублей
- PII redaction
- замена персональных данных метками до обучения
- held-out test
- запечатанный набор новых примеров для итоговой оценки
- Cohen's kappa
- согласие двух разметчиков с поправкой на случайность
Сделай сам
Напиши в заметке две строки JSONL в формате messages для ассистента банка с правилом «сначала ответ, потом условия». В первой — обычный ответ без цифр. Во второй — вопрос про комиссию, где ассистент вызывает tool вместо того, чтобы назвать сумму. Под строками перечисли три проверки, которые ты запустишь по всему набору до обучения.
Обсуди с тьютором: покажи свои строки и спроси, на какой из них модель скорее выучит что-то нежелательное и почему; попроси тьютора найти в твоих примерах скрытую PII или изменчивый факт.
Проверь себя · ответ под вопросом
1Почему после SFT модель может не останавливаться и писать бесконечно?
eos_token, например <|im_end|> для Qwen, и одним шаблоном в обучении и inference.2Зачем считать loss только на ответе ассистента?
completion_only_loss для prompt-completion и assistant_only_loss=True для диалогов.3Почему test нельзя делить случайными строками из того же журнала?
Interview questions · US / UK
1We want to fine-tune on 18 months of chat transcripts. Walk me through the data pipeline.
2After fine-tuning, the model never stops generating. What went wrong?
3Security asks how you guarantee the model won't repeat a customer's account number. What do you say?
Ключевые фразы · Say it aloud
- The dataset is the asset; the adapter is cheap to retrain.Актив — набор данных; adapter переобучить дёшево.
- Quality beats volume for style and format.Для стиля и формата качество важнее объёма.
- Use the model's own chat template in training and serving.Один chat template модели и в обучении, и в работе.
- Loss goes on the assistant's tokens only.Loss считаем только на tokens ассистента.
- Redact before trainingmodels memorise. — Удаляй PII до обучения: модели запоминают.
- Test on new conversations, split by customer, not by row.Тест на новых диалогах, деление по клиенту, а не по строкам.
Материалы
- TRL — SFT Trainer — разделы «Expected dataset type and format», «Train on assistant messages only» (10 мин)
- Transformers — Chat templates —
apply_chat_template,add_generation_prompt, предупреждение о дублях special tokens (8 мин) - Deduplicating Training Data Makes Language Models Better (arXiv 2107.06499) — abstract: почти-дубли и запоминание (2 мин)
- Extracting Training Data from Large Language Models (arXiv 2012.07805) — abstract: извлечение PII из GPT-2 (2 мин)