Руководство по файн-тюнингу LLM: LoRA, QLoRA, Unsloth, Axolotl
Автоматический перевод Эта статья была автоматически переведена с оригинальной английской версии.
Большинство неудач при файн-тюнинге — это ошибки выбора подхода. Команда начинает обучение, не доказав, что промптинг, retrieval или constrained decoding не решают задачу. Другая команда оценивает модель на распределении, совпадающем с обучающим, или обнаруживает уже после обучения, что получившийся артефакт неудобно использовать в сервинге.
В этом руководстве адаптация рассматривается как эксперимент с заранее определённым операционным выходом. Сначала мы определим границу выбора подхода, а затем пройдём путь через данные, LoRA или QLoRA, оценку на целевой задаче, экспорт и сервинг.
Краткое руководство по выбору подхода см. в статье Fine-Tuning vs RAG vs Prompting.
Нужно ли вообще выполнять файн-тюнинг?
Прежде чем тратить часы GPU, решите, действительно ли файн-тюнинг — подходящий инструмент для вашей задачи.
Файн-тюнинг и RAG
Файн-тюнинг может изменить то, как модель использует доменный язык, но плохо подходит для обновления фактов, которые меняются или должны сопровождаться ссылками. Retrieval и файн-тюнинг решают разные части задачи и часто должны использоваться в одной системе.
| Возможность | Файн-тюнинг | RAG (Retrieval-Augmented Generation) |
|---|---|---|
| Основная функция | Изменяет внутренние веса, обучая навыкам, стилю или поведению | Передаёт внешний актуальный контекст во время инференса |
| Лучше всего подходит | • Специфический стиль диалога • Сложное следование инструкциям • Доменно-ориентированный ризонинг | • Быстро меняющиеся данные (новости, цены акций) • Снижение галлюцинаций (граундинг) • Цитирование источников |
| Работа со знаниями | Меняет статистическое поведение в весах; точное воспроизведение не гарантируется | Извлекает записи или фрагменты, которые можно обновлять и цитировать |
| Частота обновлений | Для обновлений требуется повторное обучение | Обновляется сразу после добавления новых документов |
Файн-тюнинг и промпт-инжиниринг
Современные LLM хорошо реагируют на ясные промпты и примеры. Проверьте эти варианты, прежде чем вкладываться в файн-тюнинг.
| Аспект | Файн-тюнинг | Промпт-инжиниринг |
|---|---|---|
| Стоимость запуска | Высокая (подготовка данных, вычисления на GPU, итерации) | Низкая (итеративная доработка промпта) |
| Гибкость | Требует нового цикла обучения и релиза | Меняется вместе с промптом |
| Формат/стиль | Повышает вероятность повторяющегося поведения | Часто достаточен для стиля и простых форматов |
| Латентность | Может сократить повторяющиеся инструкции | Зависит от длины промпта и кэширования провайдера |
| Лучше всего подходит | Сложное поведение, дистилляция, снижение стоимости в масштабе | Быстрые итерации, меняющиеся требования |
[!TIP] Сначала попробуйте промптинг Начните с промпта и репрезентативных примеров. Если ненадёжен только синтаксис ответа, добавьте constrained decoding, прежде чем менять веса.
Файн-тюнинг и constrained decoding
Библиотеки вроде xgrammar и outlines ограничивают генерацию JSON Schema, регулярным выражением или грамматикой. В зависимости от ограничения и бэкенда они компилируют автомат или грамматику и маскируют недопустимые следующие токены. Обновление весов не требуется.
Это гарантирует принадлежность результата поддерживаемому языку вывода. Но гарантия ничего не говорит о том, будут ли значения истинными, полными или семантически корректными. Синтаксически валидный tool call всё равно может содержать неверный ID клиента.
| Аспект | Constrained Decoding | Файн-тюнинг |
|---|---|---|
| Настройка | Немедленная — определить схему и задеплоить | Требует подготовки данных, вычислений на GPU и итераций |
| Гарантия | Валидный синтаксис для поддерживаемого ограничения | Выученное поведение; соответствие схеме может различаться |
| Гибкость | Схему можно менять в любой момент без повторного обучения | Фиксируется после обучения |
| Латентность | Небольшие накладные расходы (модель может «бороться» со схемой) | Ниже (модель естественно выдаёт нужный формат) |
| Лучше всего подходит | JSON, варианты выбора, грамматики, синтаксис tool call | Повторяющееся поведение задачи, которого не хватает базовой модели |
Практический порядок:
- Начните с промптинга и few-shot-примеров для базового форматирования.
- Добавьте constrained decoding (
xgrammarилиoutlines), если синтаксис нестабилен. - Выполняйте файн-тюнинг только при необходимости изменить поведение, которое нельзя зафиксировать схемой.
Краткая шпаргалка: сопоставление проблем и решений
| Проблема | Первый механизм для проверки | Почему? |
|---|---|---|
| Недостающие знания | RAG | Модели галлюцинируют факты. Retrieval даёт заземлённый актуальный контекст |
| Неверный формат или тон | Промпт-инжиниринг | Современные модели хорошо следуют указаниям по стилю через few-shot-примеры |
| Невалидный синтаксис вывода | Constrained decoding | Во время генерации принудительно соблюдает поддерживаемую схему или грамматику |
| Повторяющаяся ошибка в задаче | Файн-тюнинг (SFT) | Обучается на подготовленных парах вход/выход |
| Несоответствие парных предпочтений | Preference optimization | Использует примеры chosen/rejected после того, как поведение задачи стало измеримым |
| Латентность или стоимость в масштабе | Дистилляция (SFT) | Обучает меньшую student-модель на ответах большей teacher-модели |
| Уменьшение размера модели | Квантизация | Обучение не требуется — веса сжимаются (FP16→INT4) для ускорения инференса |
Сделайте бизнес-кейс измеримым
Файн-тюнинг может сократить регулярное число токенов в промптах или позволить меньшей модели достичь целевого уровня, но ни одна из этих выгод не возникает автоматически. Рассчитайте точку безубыточности на основе собственного трафика и цен:
[ \text{количество запросов до безубыточности} = \frac{\text{стоимость обучения + оценки + деплоя}} {\text{стоимость запроса baseline} - \text{стоимость запроса tuned-модели}} ]
Если знаменатель мал, отрицателен или основан на неподтверждённом предположении о качестве, у проекта пока нет экономического обоснования.
[!TIP] Гибридная конфигурация Распространённая архитектура — меньшая модель, адаптированная под задачу, плюс retrieval для изменяющихся фактов. Используйте большую модель с промптингом как baseline и оставляйте меньшую модель только в том случае, если она достигает тех же порогов качества и безопасности на целевой задаче.
Виды файн-тюнинга
Файн-тюнинг может принимать три основные формы. Они различаются тем, какие данные требуют и чему обучают модель.
1. Continued pre-training (self-supervised)
Вы обучаете базовую модель на дополнительном необработанном тексте, используя следующий токен каждой последовательности как target для обучения. Это self-supervised learning: текст сам предоставляет target — так же, как в исходном претрейнинге.
Когда использовать:
- В домене есть лексика, которой базовая модель никогда не видела (медицина, право, внутренние кодовые базы).
- У вас много доменного текста, но нет размеченных пар (input, output).
- Базовая модель плохо справляется с доменной терминологией.
Пример: обучение на миллионах клинических записей, чтобы модель освоила медицинские сокращения, названия препаратов и клинические рабочие процессы.
2. Supervised fine-tuning (SFT)
SFT обучается на размеченных парах (input, output). Для каждого input вы показываете модели точный output, который хотите получить.
Когда использовать:
- У вас есть конкретная задача с чистым форматом input/output.
- У вас есть качественные размеченные данные, пусть даже в небольшом объёме.
- Вам нужно предсказуемое поведение на известной форме входных данных.
Пример: обучение на парах (описание SQL-запроса, SQL-код) для задачи text-to-SQL.
{
"input": "Get all users who signed up last month",
"output": "SELECT * FROM users WHERE signup_date >= DATE_SUB(NOW(), INTERVAL 1 MONTH)"
}
3. Instruction tuning
Instruction tuning — частный случай SFT, предназначенный для того, чтобы модели следовали широкому набору инструкций на естественном языке. Датасет содержит пары (instruction, response) для множества разных задач.
Когда использовать:
- Вы создаёте ассистента общего назначения (например, ChatGPT или Claude).
- Модель должна обрабатывать разнообразные открытые запросы.
- Вы создаёте чат-интерфейс.
Пример: обучение на тысячах разнообразных инструкций вроде «Суммируй эту статью», «Напиши стихотворение о X», «Объясни Y простыми словами».
Сравнение
| Аспект | Continued Pre-training | SFT | Instruction Tuning |
|---|---|---|---|
| Данные | Необработанный текст | Пары (input, output) | Пары (instruction, response) |
| Разметка | Нет (unsupervised) | Специфичная для задачи | Разные задачи |
| Цель | Доменные знания | Поведение в конкретной задаче | Следование любой инструкции |
| Объём данных | Обычно самый большой корпус | Определяется покрытием задачи и разнообразием ошибок | Обычно шире, чем task-specific SFT |
[!NOTE] Что делают на практике SFT и instruction tuning используют одну и ту же objective-функцию для следующего токена; различие — в широте и построении датасета. Continued pre-training — отдельный эксперимент, после которого нужно проверить как прирост в домене, так и регресс общих способностей.
Пайплайн файн-тюнинга из 7 этапов
Файн-тюнинг — это пайплайн, а не одна команда. У каждого этапа свои режимы отказа, и пропуск одного из них обычно проявляется позже в виде проблем с моделью.
Каждый этап опирается на предыдущий:
- Подготовка данных — определите единицу оценки, разделите данные, затем очистите и отформатируйте их
- Выбор модели — выберите подходящую базовую модель и загрузите веса
- Настройка обучения — сконфигурируйте оборудование, гиперпараметры и стратегию оптимизации
- Файн-тюнинг — запустите обучение SFT, DPO или ORPO
- Оценка — измерьте качество на бенчмарках и проверьте качество
- Деплой — экспортируйте модель и запустите её сервинг
- Мониторинг — отслеживайте качество, сопровождайте модель и выполняйте итерации
[!WARNING] Данные — фундамент Обучение воспроизводит систематические дефекты примеров. Проверьте labels, утечки, покрытие и соответствие политикам до того, как тратить время на перебор конфигураций оптимизатора.
Этап 1: подготовка данных
Многие проекты файн-тюнинга проваливаются именно здесь, а не на обучении. Современная подготовка данных — это больше, чем запуск regex по CSV.
Пайплайн данных из 5 этапов
Инструменты вроде DataTrove и Distilabel помогают обрабатывать данные в масштабе. Проектируйте пайплайн на основе таксономии ошибок и data contract; выбор инструмента должен быть следствием этих требований.
1. Загрузка и фильтрация
- Действие: удалите отказы («I cannot answer that»), повреждённый UTF-8 и тексты нецелевых языков.
- Инструменты: Trafilatura для извлечения и модели идентификации языка fastText для language ID; распределённые модели
lid.176распознают 176 языков.
2. Политика работы с чувствительными данными
- Действие: определите, чему модели разрешено обучаться, затем при необходимости замаскируйте, токенизируйте или исключите персональные и конфиденциальные поля.
- Инструменты: Microsoft Presidio или scrubadub.
- Зачем: детектор — лишь один из механизмов контроля; требования к происхождению данных, согласию, сроку хранения, доступу и удалению по-прежнему действуют.
3. Дедупликация (MinHash LSH)
- Действие: удалите почти дубликаты, чтобы модель их не запоминала.
- Инструменты: DataTrove хорошо подходит для обработки данных терабайтного масштаба.
4. Синтетическое расширение, если необходимо
- Действие: используйте более сильную teacher-модель (GPT-4o, DeepSeek-V3), чтобы преобразовать необработанные данные в чистые пары instruction-response.
- Инструменты: Distilabel.
- Валидация: выберите примеры ответов teacher-модели, проверьте их по той же rubric, что и human labels, и держите синтетические и написанные людьми срезы раздельно при оценке.
5. Форматирование
- Действие: преобразуйте данные в стандартный формат (Alpaca или ShareGPT).
Примеры форматов данных
Формат Alpaca (следование инструкциям):
{
"instruction": "Summarize the following text.",
"input": "The text to be summarized...",
"output": "This is the summary."
}
Формат ShareGPT/ChatML (диалоговый):
{
"conversations": [
{ "from": "user", "value": "Hello, who are you?" },
{ "from": "assistant", "value": "I am a helpful AI assistant." }
]
}
Что действительно важно
- Покрытие важнее объёма. Добавляйте примеры, представляющие различные режимы отказа, а не повторы простого большинства.
- Чистота. Удаляйте нерелевантный текст, нормализуйте пробелы и сохраняйте единообразное форматирование.
- Баланс. Сохраняйте важные редкие случаи и отчитывайтесь о качестве по каждому срезу.
- Разделение. Делите данные по источнику, пользователю, документу или времени, если случайное разделение строк создаёт утечки почти дубликатов.
- Происхождение. Для каждой версии датасета фиксируйте источник, лицензию или разрешение, историю преобразований и путь удаления данных.
Этап 2: выбор модели и оборудования
Выбор базовой модели и понимание минимальных требований к GPU определяют, что вы реально сможете обучить.
Начните с наименьшей базовой модели, которая уже проходит обязательные проверки baseline. Подтвердите:
- лицензионные условия и правила распространения для предполагаемого продукта;
- поведение в нужных языках, домене, tool use и безопасности до адаптации;
- совместимость токенизатора и chat template с датасетом;
- максимальное контекстное окно и поведение при truncation, необходимые для реальных примеров;
- поддержку как в training framework, так и в целевом serving engine.
Файн-тюнинг — это этап адаптации, а не способ исправить неподходящую базовую модель. Если модель не справляется со способностями, которые датасет не покрывает, выберите другую базу, прежде чем запускать дополнительные эпохи.
Оценивайте конкретный запуск, а не маркетинговый класс модели
Универсальной таблицы «размер модели → GPU» не существует. Пиковое потребление памяти меняется в зависимости от precision весов, состояния trainable-параметров, длины последовательности, размера micro-batch, activation checkpointing, реализации attention и накладных расходов фреймворка. Начните с оценки памяти, затем выполните короткий smoke test на максимальной длине в точном стеке, который будете использовать.
| Компонент памяти | Полный файн-тюнинг | LoRA | QLoRA |
|---|---|---|---|
| Веса базовой модели | Training precision | Заморожены, обычно BF16/FP16 | Заморожены, обычно 4-bit NF4 |
| Градиенты | Все trainable-веса | Веса адаптера | Веса адаптера |
| Состояния оптимизатора | Все trainable-веса | Веса адаптера | Веса адаптера |
| Активации | Зависят от batch и длины последовательности в любом методе | Та же зависимость | Та же зависимость |
Оригинальная статья о QLoRA показывает, как в конкретной конфигурации разместить модель LLaMA 65B на одной GPU с 48 GB. Это полезная нижняя граница, но не обещание, что любая современная архитектура 70B, длина контекста, kernel или trainer поместятся на том же устройстве.
Расчёт памяти
Для модели с параметрами только на веса потребуется примерно байт в BF16/FP16 или байт при четырёх битах — до учёта метаданных квантизации и буферов рантайма. Полное обучение в стиле Adam добавляет градиенты, состояния оптимизатора и часто master-веса повышенной точности. LoRA позволяет избежать большей части памяти под trainable-состояния; QLoRA дополнительно уменьшает объём памяти под замороженные веса базовой модели. На длинных последовательностях доминировать всё равно могут активации.
Используйте следующий процесс:
- Выберите максимальную длину последовательности и micro-batch, которые обязаны поддерживаться.
- Оцените объём весов и trainable-состояний, оставив запас под активации и kernels.
- Выполните один шаг forward/backward на максимальной длине.
- Зафиксируйте пиковый объём выделенной и зарезервированной памяти.
- Только после этого увеличивайте размер batch, rank, длину последовательности или число GPU.
Этап 3: методы обучения (PEFT и LoRA)
Полный файн-тюнинг и PEFT
Полный файн-тюнинг (FFT) обновляет каждый вес, поэтому объём градиентов и состояний оптимизатора масштабируется вместе со всей моделью. Пиковое потребление нельзя вывести только из числа параметров, но оно значительно превышает память, необходимую для загрузки весов при инференсе.
Parameter-efficient fine-tuning (PEFT) обучает только небольшое подмножество параметров, замораживая остальные. Математика становится гораздо проще.
LoRA: отправная точка
LoRA (Low-Rank Adaptation) замораживает предобученную матрицу и представляет её выученное обновление двумя меньшими матрицами. В оригинальной статье это мотивируется гипотезой о том, что полезные обновления при адаптации имеют низкий intrinsic rank.
Для замороженной матрицы LoRA обучает:
Адаптированный слой:
Для этой матрицы адаптер имеет trainable-параметров вместо . Для квадратной матрицы шириной 4 096 при rank 16 это сокращение в 128 раз для конкретной матрицы, а не в 10 000 раз для произвольной модели. Указанное в статье LoRA сокращение в 10 000 раз относится к конкретной конфигурации GPT-3 175B с адаптацией выбранных матриц.
Сравнение PEFT-методов
| Метод | Что меняется | Когда выбирать |
|---|---|---|
| LoRA | Замороженная база плюс trainable-обновления низкого ранга | Базовая модель уверенно помещается в память и нужны небольшие артефакты под задачу |
| QLoRA | LoRA с замороженной базой, хранящейся в 4-bit формате | Память под веса базовой модели — ограничивающий фактор |
| DoRA | Разделяет magnitude веса и направление, обновляемое LoRA | Измеренный baseline LoRA оставляет разрыв в качестве, оправдывающий дополнительную сложность |
| Полный файн-тюнинг | Все веса модели | PEFT не достигает цели, а прирост качества оправдывает распределённое обучение и полные чекпоинты |
Когда что выбирать
- LoRA: начните с него. Быстро, экономно по памяти, хорошо поддерживается.
- QLoRA: когда тот же эксперимент с LoRA не помещается из-за замороженных весов базовой модели.
- DoRA: после сравнения LoRA один к одному, показавшего полезный прирост.
- Полный файн-тюнинг: только когда PEFT стал измеренным боттлнеком, а не предположением.
DoRA: LoRA с декомпозицией весов
DoRA (Weight-Decomposed Low-Rank Adaptation) разделяет magnitude каждого вектора весов и его направление. В статье о DoRA обновление LoRA применяется к направленной компоненте, а magnitude обучается отдельно.
Как это работает:
Вместо того чтобы рассматривать веса как единое целое, DoRA разбивает предобученные веса на две компоненты:
- Magnitude — trainable-значение для каждого вектора весов.
- Направление — нормализованный вектор, обновляемый с помощью матриц низкого ранга.
В компактной column-wise нотации:
где:
m= magnitude (trainable)- = замороженная матрица направлений
- = выученное low-rank-обновление направлений
- = нормализация по столбцам
Что даёт эта дополнительная структура:
- Больше степеней свободы, чем у стандартной LoRA, поскольку magnitude может меняться независимо.
- Более высокое качество по сравнению с LoRA в нескольких конфигурациях, о которых сообщают авторы статьи.
- Дополнительные параметры и вычисления, поэтому прирост нужно проверять на своей задаче и serving path.
Слияние адаптеров для multi-task learning
Отдельные адаптеры позволяют одной замороженной базе поддерживать несколько задач. Можно направлять запросы к нужному адаптеру, обслуживать несколько адаптеров одним движком, если это поддерживается, или создать offline-кандидат после слияния. Слияние может привести к интерференции, поэтому оценивайте объединённый артефакт, а не предполагайте, что исходные адаптеры корректно компонуются.
Распространённые методы слияния:
- Concatenation — объединение параметров адаптеров с увеличением effective rank. Быстро и просто.
- Linear combination — взвешенная сумма адаптеров. Даёт дополнительные рычаги настройки.
- SVD — разложение матрицы для слияния. Гибче, но медленнее.
Пример: один адаптер для суммаризации, другой для перевода, объединённые в единую multi-task-модель.
Этап 4: файн-тюнинг и выравнивание предпочтений
SFT обучает на демонстрациях. Preference optimization обучает на сравнениях вроде «chosen response A лучше, чем rejected response B». Используйте его только тогда, когда парные предпочтения действительно подходят как labels для ошибки; фактическую корректность и соответствие политикам часто нужно проверять более сильными эвалуаторами, чем одной общей оценкой предпочтений.
RLHF на основе PPO
Исходный рецепт представлял собой пайплайн из трёх этапов:
- SFT — обучение задаче.
- Reward model — обучение на человеческих предпочтениях (chosen против rejected).
- PPO (Proximal Policy Optimization) — reinforcement learning для оптимизации policy.
Операционная стоимость возникает из-за множества компонентов:
- Сложно реализовывать и сопровождать.
- Дорого: нужно обучать несколько моделей.
- On-policy sampling и оптимизация reward требуют тщательного контроля стабильности и проверок reward hacking.
DPO
DPO (Direct Preference Optimization) отказывается от явной reward model и RL-цикла. В статье о DPO выводится перепараметризованная objective-функция для максимизации reward с ограничением KL-дивергенции, поэтому оптимизацию можно выполнять на preference pairs вместо reinforcement learning:
{
"prompt": "Explain quantum computing",
"chosen": "Quantum computing uses qubits...", # Preferred response
"rejected": "Well, it's complicated..." # Non-preferred response
}
Что меняется с операционной точки зрения:
- Более простой code path (нет отдельной reward model и RL-цикла).
- Offline objective на preference pairs вместо on-policy reinforcement learning.
- Reference policy или эквивалентные reference log probabilities в стандартной формулировке.
DPO проще прототипировать, чем полноценный пайплайн PPO, но это не автоматическое улучшение качества. Результаты зависят от исходной policy, качества пар, настроек loss, эффектов длины и протокола оценки. Сравнивайте DPO с SFT-чекпоинтом на одном и том же наборе отложенных preference- и task-тестов.
ORPO
ORPO (Odds-Ratio Preference Optimization) объединяет SFT-loss отрицательного логарифмического правдоподобия со штрафом odds ratio для rejected-ответов. Он устраняет отдельную reference model и может объединить обучение задаче и preference optimization в одном запуске.
Как это работает: ORPO использует комбинированный loss, который одновременно делает две вещи:
- Максимизирует likelihood chosen-ответа (обучает задаче).
- Штрафует rejected-ответ с помощью odds-ratio-компоненты (обучает предпочтениям).
Гиперпараметры, которые стоит знать:
from trl import ORPOConfig
config = ORPOConfig(
learning_rate=8e-6, # Very low, as recommended by the ORPO paper
beta=0.1, # Controls strength of preference penalty
# ... other params
)
- Learning rate: в экспериментах статьи использовались низкие значения; настраивайте его под свою модель, batch и данные, а не копируйте одно значение как универсальное правило.
- Beta: определяет вклад preference-компоненты относительно SFT-компоненты.
Компромиссы:
- Один этап обучения вместо двух.
- Reward model не требуется.
- Forward pass reference model не требуется.
- Связанный запуск: если обучение задаче или preference-поведение деградирует, в этом пайплайне нет промежуточного SFT-чекпоинта для анализа.
Выбирайте метод на основе дизайна данных и оценки:
- Используйте DPO, если у вас уже есть удовлетворительный SFT-чекпоинт и нужен более простой offline-эксперимент с предпочтениями.
- Тестируйте ORPO, если вашим данным и операционным ограничениям подходит reference-free objective в один этап.
- Используйте RLHF на основе PPO, если online sampling с явным обученным reward является требованием и вы можете отслеживать эксплуатацию reward.
Ни один метод не является универсальным default. Сохраняйте baseline только с SFT и отчитывайтесь как о task-метриках, так и о preference-метриках.
Фреймворки для файн-тюнинга
Фреймворки пересекаются по возможностям и быстро меняются. Выбирайте их под execution path, который обязаны поддерживать, фиксируйте версии и храните конфигурацию обучения в достаточно переносимом виде, чтобы воспроизводить запуск вне ноутбука.
Unsloth — скорость и эффективность использования памяти
Unsloth интегрируется с Hugging Face trl и transformers и предоставляет оптимизированные kernels, checkpointing и квантизированные пайплайны файн-тюнинга для поддерживаемых моделей.
- Пользовательские Triton GPU kernels для attention, RoPE и cross-entropy, которые обходят накладные расходы PyTorch.
- Эффективный по памяти backprop: активации пересчитываются во время backward pass вместо хранения в памяти.
- Fused operations, объединяющие несколько шагов (layer norm + linear и аналогичные) в единые вызовы GPU.
- 4-bit квантизация, напрямую встроенная в QLoRA path, с оптимизированной деквантизацией.
[!IMPORTANT] Порядок импорта важен Следуйте порядку импорта из примера Unsloth для зафиксированной вами версии. Unsloth применяет patches во время импорта, поэтому импорт до
trlиtransformersпомогает избежать потери оптимизаций и version-specific ошибок.
# Correct order
from unsloth import FastLanguageModel # Must be first!
from trl import SFTTrainer
from transformers import TrainingArguments
# Avoid this order with Unsloth's patched path
from trl import SFTTrainer
from unsloth import FastLanguageModel
Лучше всего подходит для: обучения на одной GPU, прототипирования, Colab-ноутбуков и всех, кто следит за счётом за GPU.
Опубликованные показатели скорости и памяти зависят от модели, длины последовательности, batch, precision и оборудования. Измеряйте tokens per second и пиковое потребление памяти на собственном запуске, а не воспринимайте рекламное соотношение как свойство фреймворка.
Axolotl — обучение через конфигурацию
# config.yaml - no code required
base_model: meta-llama/Meta-Llama-3-8B
adapter: qlora
lora_r: 32
lora_alpha: 16
datasets:
- path: data/my_data.jsonl
type: alpaca
sample_packing: true
Запуск: accelerate launch -m axolotl.cli.train config.yaml
Лучше всего подходит для: декларативных воспроизводимых запусков и встроенных launcher-опций для распределённого обучения. Конфигурацию можно ревьюить, версионировать и повторно использовать в локальных и распределённых запусках.
Сравнение фреймворков
| Инструмент | Когда полезен | Что проверить до выбора |
|---|---|---|
| Unsloth | Нужен оптимизированный путь для поддерживаемой модели с краткими примерами | Матрицу совместимости модели, GPU, квантизации и distributed-support |
| Axolotl | Нужны декларативные конфигурации и встроенные distributed-рецепты | Точную схему конфигурации и launcher для зафиксированного релиза |
| TRL | Нужен прямой доступ к SFT- и preference-трейнерам Hugging Face | Формат датасета, chat template, loss masking и интеграцию с PEFT |
| Torchtune | Нужны PyTorch-native-рецепты и компоненты | Покрытие модельных рецептов и совместимость экспорта |
Практический пример: файн-тюнинг с Unsloth
Ниже приведён показательный фрагмент обучения из моего репозитория unsloth-finetune-demo. В демо выполняется файн-тюнинг Nemotron-Nano для function calling. До этого фрагмента src/unsloth_demo/data.py демо загружает и форматирует датасет, а затем training path создаёт версионируемые объекты train_dataset и eval_dataset.
Быстрый старт
# Clone and setup
git clone https://github.com/slavadubrov/unsloth-finetune-demo.git
cd unsloth-finetune-demo
# Install with uv (recommended)
uv sync
# Run fine-tuning (quick test)
uv run finetune --max-samples 1000
Конфигурация
Основные настройки находятся в config.py:
# Model & Dataset
MODEL_NAME = "nvidia/Llama-3.1-Nemotron-Nano-4B-v1.1" # 4B params, 128K context
DATASET_NAME = "glaiveai/glaive-function-calling-v2" # 113K examples
# LoRA Configuration
LORA_R = 16 # Adapter capacity; tune against held-out results
LORA_ALPHA = 32 # Update scaling; alpha/r is the classic LoRA scale
MAX_SEQ_LENGTH = 4096
# Candidate modules for this Llama-family model
LORA_TARGET_MODULES = [
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",
]
[!NOTE] Соотношение alpha и rank
alpha/rмасштабирует классическое обновление LoRA.alpha = 2r— распространённая стартовая эвристика в документации некоторых инструментов, а не гарантия стабильности. Перебирайте rank, alpha, learning rate и target modules только после того, как зафиксированы данные и baseline.
Основной код обучения
from unsloth import FastLanguageModel
from trl import SFTConfig, SFTTrainer
# Load model with 4-bit quantization
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="nvidia/Llama-3.1-Nemotron-Nano-4B-v1.1",
max_seq_length=4096,
load_in_4bit=True,
)
# Add LoRA adapters
model = FastLanguageModel.get_peft_model(
model,
r=16,
lora_alpha=32,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
use_gradient_checkpointing="unsloth", # Lower activation memory; extra compute
)
# The preceding data step must create these versioned dataset objects.
# Each row has the chat messages and tool schemas expected by current TRL.
# Train with the current TRL configuration surface.
trainer = SFTTrainer(
model=model,
processing_class=tokenizer,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
args=SFTConfig(
output_dir="outputs/nemotron-function-calling",
max_length=4096,
packing=True,
per_device_train_batch_size=2,
gradient_accumulation_steps=4,
learning_rate=2e-4,
num_train_epochs=3,
bf16=True,
),
)
trainer.train()
Файн-тюнинг с Axolotl
[!NOTE] Демо готовится Я работаю над практическим демо для Axolotl. Пока оно не готово, хорошим справочным материалом по стратегиям обучения на нескольких GPU будет Accelerate n-D Parallelism Guide от Hugging Face.
Для конфигураций, ориентированных на config-first подход, и распределённых setup-ов Axolotl делает workflow воспроизводимым:
# axolotl_config.yaml
base_model: meta-llama/Meta-Llama-3-8B
model_type: LlamaForCausalLM
# QLoRA configuration
load_in_4bit: true
adapter: qlora
lora_r: 32
lora_alpha: 16
lora_dropout: 0.05
lora_target_modules:
- q_proj
- k_proj
- v_proj
- o_proj
- gate_proj
- up_proj
- down_proj
# Dataset
datasets:
- path: data/training_data.jsonl
type: alpaca
# Training settings
sequence_len: 4096
sample_packing: true # Benchmark with your length distribution
micro_batch_size: 2
gradient_accumulation_steps: 4
learning_rate: 0.0002
num_epochs: 3
# Current Axolotl key; verify support on the pinned release
bf16: true
attn_implementation: flash_attention_2
Запуск обучения:
axolotl train axolotl_config.yaml
Этап 5: оценка
Зафиксируйте evaluation contract до первого запуска. Как минимум сравнивайте tuned-чекпоинт с точной untuned-базой при одинаковых промпте, настройках декодирования и окружении инструментов. Сводное качество публикуйте только после проверки failure slices, которые должен был улучшить проект.
Отслеживайте четыре группы:
- Целевая задача: exact match, успешность выполнения, human rubric или другой результат, связанный с use case.
- Регрессии: общие способности и ранее поддерживаемые срезы задач, которые может ухудшить адаптация.
- Безопасность и политики: отказы, утечки данных, prompt injection или доменные ограничения.
- Операционные показатели: латентность, throughput, память, размер артефакта и стоимость в целевой serving-конфигурации.
Автоматизированные бенчмарки
Используйте lm-evaluation-harness для релевантных стандартизированных задач, но не как замену продуктовой оценке:
lm_eval --model hf \
--model_args pretrained=./outputs/merged-model \
--tasks hellaswag,arc_easy,mmlu \
--batch_size 8
LLM-as-judge
Для субъективного качества большая модель может помогать с оценкой, но откалибруйте её на примерах, проверенных людьми, и скрывайте identity кандидата:
judge_prompt = """
Rate this response from 1-5 on:
- Relevance
- Accuracy
- Formatting
Response: {model_output}
Expected: {ground_truth}
"""
Доменно-ориентированная оценка
Откладывайте реальные примеры по источнику, пользователю, документу или времени, чтобы почти дубликаты не попадали в разные части split. Для function calling проверяйте всю trajectory: выбор инструмента, аргументы, результат выполнения, восстановление после ошибки и финальный ответ. На небольших выборках приводите доверительные интервалы или парные подсчёты побед/поражений и проверяйте каждую регрессию в критичном срезе.
Этап 6: деплой и форматы вывода
Выбирайте артефакт с учётом serving engine и плана rollback, а не только размера файла:
1. LoRA-адаптер
uv run finetune # Saves ~100-500MB adapter
- Размер: пропорционален целевым модулям, rank, числу слоёв и dtype; обычно значительно меньше базовой модели.
- Лучше всего подходит для: разработки, версионируемых task-адаптеров и движков с прямой поддержкой LoRA.
- Дополнительный плюс: адаптеры можно менять без повторной загрузки базовой модели.
2. Слитая модель
uv run finetune --merge # Creates a standalone full model
- Размер: примерно равен полному чекпоинту базовой модели в выбранной output precision.
- Лучше всего подходит для: движков или каналов распространения, которые не поддерживают отдельный адаптер.
- Компромисс: артефакт больше, rollout медленнее, зато загрузка одной модели проще.
3. Формат GGUF
uv run finetune --gguf q4_k_m # Creates ~2-4GB quantized model
- Размер: зависит от модели; для вариантов Q4 примерно соответствует четырёхбитным весам плюс метаданные.
- Лучше всего подходит для: инференса на CPU, Ollama, llama.cpp и edge-деплоя.
- Варианты:
q4_k_m(меньше),q5_k_m(выше fidelity весов),q8_0(больше и выше fidelity). После конвертации измерьте влияние на качество задачи.
Этап 7: сервинг и мониторинг
С vLLM
# Serve the base and expose a PEFT adapter as a model name. This parser and
# template pair is for a Llama 3.1-compatible function-calling adapter.
vllm serve nvidia/Llama-3.1-Nemotron-Nano-4B-v1.1 \
--enable-lora \
--lora-modules function-calling=./outputs/adapter \
--enable-auto-tool-choice \
--tool-call-parser llama3_json \
--chat-template examples/tool_chat_template_llama3.1_json.jinja \
--host 0.0.0.0 \
--port 8000 \
--max-model-len 4096
Запрос через OpenAI-compatible API:
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy")
response = client.chat.completions.create(
model="function-calling",
messages=[{"role": "user", "content": "Book a flight to Tokyo"}],
tools=[
{
"type": "function",
"function": {
"name": "book_flight",
"description": "Book a flight to a city.",
"strict": True,
"parameters": {
"type": "object",
"properties": {
"destination": {"type": "string"},
},
"required": ["destination"],
"additionalProperties": False,
},
},
}
],
tool_choice="auto",
)
Для tool calling guide vLLM требуются auto tool choice и parser, соответствующий модели; используйте совместимый с моделью chat template, если конфигурация её токенизатора не предоставляет. При tool_choice="auto" для constrained arguments также требуется strict: true хотя бы у одной function (при включённой в vLLM настройке strict-tool-calling, которая включена по умолчанию); используйте parameters schema, совместимую с strict-режимом. Без этого opt-in vLLM извлекает calls из raw text, поэтому аргументы могут оказаться malformed или нарушать схему.
С Ollama (локально)
# Create Modelfile
echo 'FROM ./outputs/unsloth-nemotron-function-calling-gguf/model-q4_k_m.gguf' > Modelfile
# Import to Ollama
ollama create my-function-model -f Modelfile
# Run
ollama run my-function-model
С llama.cpp (CPU)
./llama-cli -m ./outputs/model-q4_k_m.gguf \
-p "What's the weather in Tokyo?" \
--ctx-size 4096
Мониторинг выпущенной модели
Жизненный цикл не заканчивается на приемлемом training loss. Фиксируйте revision базовой модели, токенизатор и chat template, hash адаптера, версию датасета, конфигурацию обучения и отчёт об оценке как единую release unit. В продакшене отслеживайте успешность задачи, невалидные ответы, нарушения политик, латентность и drift входных данных по тем же срезам, что и offline. Сохраняйте предыдущий артефакт загружаемым и определите rollback threshold до запуска.
Основные выводы
- Выполняйте файн-тюнинг только после того, как untuned-baseline и таксономия ошибок покажут, что проблема решается адаптацией весов.
- Retrieval управляет изменяющимися источниками; constrained decoding управляет синтаксисом; SFT не заменяет ни один из этих подходов.
- LoRA сокращает объём trainable-состояний. QLoRA дополнительно сжимает замороженные веса базовой модели. Не приписывайте показатели памяти QLoRA методу LoRA.
- Покрытие данных, целостность split, provenance и loss masking важнее копирования модной конфигурации оптимизатора.
- DPO, ORPO и RLHF на основе PPO — разные дизайны экспериментов, а не ступени качества с универсальным default.
- Оценивайте целевое поведение, регрессии, безопасность и операционные характеристики относительно той же базовой модели.
- До обучения выберите adapter, merged или GGUF output на основе требований к сервингу и rollback.
Ссылки
Статьи и исследования
- LoRA: Low-Rank Adaptation of Large Language Models
- QLoRA: Efficient Finetuning of Quantized LLMs
- DoRA: Weight-Decomposed Low-Rank Adaptation
- DPO: Direct Preference Optimization
- ORPO: Odds Ratio Preference Optimization
- PPO: Proximal Policy Optimization Algorithms — OpenAI, 2017
Инструменты обработки данных
- DataTrove — обработка данных Hugging Face в масштабе
- Distilabel — генерация синтетических данных (Argilla)
- Trafilatura — извлечение и краулинг веб-текста
- Идентификация языка fastText — распределённые модели
lid.176для 176 языков - Microsoft Presidio — обнаружение и анонимизация PII
- scrubadub — Python-библиотека для удаления PII
Constrained decoding
Фреймворки обучения
- Unsloth — оптимизированный фреймворк для файн-тюнинга
- Axolotl — обучение через конфигурацию и distributed-launchers
- TRL — библиотека Hugging Face для SFT и обучения на предпочтениях
- Torchtune — PyTorch-native-библиотека для файн-тюнинга
Инференс и деплой
- LoRA-адаптеры vLLM — сервинг одного или нескольких адаптеров с базовой моделью
- Tool calling в vLLM — согласование auto tool choice, parser, chat template и request schema с моделью
- Ollama — локальный LLM runner для Mac/Windows/Linux
- llama.cpp — инференс на CPU/GPU с форматом GGUF
Оценка
- lm-evaluation-harness — стандартизированный LLM-бенчмаркинг от EleutherAI
Руководства и ресурсы
- Репозиторий с демо — практический пример файн-тюнинга
- LLM Fine-Tuning. Theoretical Intuition and Practical Implementation — исследовательский ноутбук NotebookLM
- Accelerate n-D Parallelism Guide — стратегии обучения на нескольких GPU от Hugging Face