Зачем платить за облако, если M3 Max в рюкзаке уже всё умеет
Ситуация знакома: у вас есть идея для кастомного AI-ассистента, датасет подготовлен, а в голове уже рисуются графики потерь. Вы открываете консоль AWS или Lambda, смотрите на цену за час A100 – и идея медленно уползает в долгий ящик. Потому что прототипирование вслепую, без уверенности в результате, это сжигание денег. В 2026 году это уже не проблема.
mlx-tune – это не просто ещё одна библиотека для fine-tuning. Это ваш личный пропуск в мир локального прототипирования больших языковых и мультимодальных моделей на Apple Silicon. Пока остальные арендуют кластеры, вы запускаете SFT (Supervised Fine-Tuning) на Qwen2.5-Coder 7B, пока пьёте кофе. Параметризуете DPO (Direct Preference Optimization) для RLHF, смотря сериал. А потом одним скриптом экспортируете всё в GGUF и запускаете в LM Studio. Это не магия, а просто правильный инструмент.
Забудьте про "попробую на Google Colab". На M3 Pro с 36 ГБ памяти mlx-tune жуёт 7B-параметрические модели за часы, а не дни. Это не сопоставимо с арендой H100, но для понимания, сработает ли ваша идея по настройке, – этого более чем достаточно. Прототип должен быть дешёвым и быстрым.
Что ломает mlx-tune: от SFT до Vision, нативный Metal и Unsloth под капотом
Библиотека построена на MLX 26.2 – нативном фреймворке Apple для машинного обучения на их чипах. Это ключ к скорости. В отличие от переводных слоёв PyTorch через mps, MLX говорит с Metal API напрямую. Результат? Полное использование Unified Memory и нейронных движков. Вы не теряете 30% производительности на конверсиях.
| Метод настройки | Что делает | Поддержка в mlx-tune |
|---|---|---|
| Full Fine-Tuning | Обновление всех весов модели. Требует тонны памяти. | Есть, но не для слабых Mac |
| LoRA (Low-Rank Adaptation) | Добавляет крошечные адаптеры к слоям. Основной метод. | Полная (r=16, alpha=32) |
| SFT (Supervised Fine-Tuning) | Базовая настройка на парных "вопрос-ответ". | Нативно, форматы JSONL, Alpaca |
| DPO (Direct Preference Optimization) | Настройка на предпочтениях (chosen/rejected). Для выравнивания. | Полная, с кастомными лоссами |
| GRPO (Group Relative Policy Optimization) | Новый метод 2025 года, эффективнее DPO для длинных ответов. | Экспериментальная, но стабильная |
| Vision Models (LLaVA-стиль) | Настройка связки ViT + LLM для описания изображений. | Через mlx-vision, требует отдельной сборки |
Самый жирный плюс – совместимость с Unsloth API. Unsloth, как вы помните из наших статей, это не библиотека, а набор низкоуровневых ядер, ускоряющих тренировку в 2-3 раза. mlx-tune умеет загружать модели, уже прошедшие через слоевую хирургию и оптимизацию от Unsloth. Это как установить турбонаддув на уже быстрый двигатель.
1 Голая установка: никакого Docker, только чистый Metal
Забудьте про Conda и виртуальные среды, которые ломаются после обновления macOS. mlx-tune живёт в изоляции через uv – новый пакетный менеджер, который не конфликтует с системным Python. Откройте Terminal и вбейте:
curl -LsSf https://astral.sh/uv/install.sh | sh
uv tool install mlx-tune
Проверяем, что всё встало:
mlx-tune --version
# mlx-tune 0.8.3 (17 Mar 2026) with MLX 26.2.1 backend
Если увидите ошибку про metallib, не паникуйте. Это значит, что MLX не нашёл скомпилированные шейдеры Metal. Просто выполните python -c "import mlx.core; print(mlx.core.metal.is_available())". Если вернёт True – всё в порядке. Если False, переустановите MLX через uv pip install --force-reinstall mlx.
2 Подготовка датасета: почему JSONL победил CSV
mlx-tune ждёт данные в формате JSON Lines. Каждая строка – отдельный JSON-объект. Для SFT хватит полей instruction, input (опционально), output. Для DPO добавьте chosen и rejected. Пример dataset.jsonl:
{"instruction": "Напиши приветственное письмо клиенту.", "input": "Имя клиента: Алексей", "output": "Уважаемый Алексей! Мы рады приветствовать вас..."}
{"instruction": "Объясни квантовую суперпозицию.", "input": "", "output": "Квантовая суперпозиция — это состояние, когда частица существует в нескольких состояниях одновременно..."}
Скрипт для конвертации вашего CSV в JSONL за минуту:
import pandas as pd
import json
df = pd.read_csv('your_data.csv')
with open('dataset.jsonl', 'w') as f:
for _, row in df.iterrows():
record = {
"instruction": row['prompt'],
"input": "",
"output": row['completion']
}
f.write(json.dumps(record, ensure_ascii=False) + '\n')
3 Костяк конфига: какие параметры решают всё
Создайте config.yaml. Вот минимальный рабочий вариант для LoRA SFT на Llama 3.1 8B:
model: "mlx-community/Llama-3.1-8B"
data:
train: "dataset.jsonl"
eval: null # если нет валидации
lora:
r: 16
alpha: 32
dropout: 0.05
target_modules: ["q_proj", "v_proj"] # только эти слои адаптируем
training:
batch_size: 4 # для 16 ГБ RAM
num_epochs: 3
learning_rate: 2e-4
warmup_steps: 50
logging_steps: 10
save_steps: 200
optimizer: "adamw"
weight_decay: 0.01
output_dir: "./lora-llama-3.1-8b-finetuned"
А вот где собака зарыта: параметр target_modules. Для разных моделей названия слоёв разные. Для Qwen2.5 это часто "c_attn", "c_proj". Смотрите в исходниках модели. Если указать неверно – LoRA просто не прицепится, а вы будете гадать, почему модель не обучается.
Запуск: когда тишина в терминале – это хорошо
Команда для старта тривиальна:
mlx-tune train config.yaml
Если всё настроено верно, вы увидите прогресс-бар и падающий loss. На MacBook Pro M2 Max (64 ГБ) одна эпоха на датасете в 1000 примеров займёт около 25 минут. На MacBook Air M3 (16 ГБ) – вдвое дольше, и возможно, придётся уменьшить batch_size до 2.
caffeinate -s в отдельном окне.4 DPO и GRPO: где ваш датасет предпочтений и почему его нет
Самая частая ошибка – пытаться запустить DPO на том же датасете, что и SFT. DPO нужны пары: хороший ответ (chosen) и плохой (rejected). Где их взять? Варианты:
- Сгенерировать два ответа через сырую модель и вручную разметить (долго).
- Взять готовые датасеты вроде Anthropic/hh-rlhf (тяжело найти русские).
- Использовать синтетику: сгенерировать через GPT-4o 2026, а отвергнутые ответы исказить.
Конфиг для DPO отличается одним блоком:
# ... остальное как в SFT конфиге
training:
method: "dpo" # ключевая строка!
beta: 0.1 # температура для DPO loss, default 0.1
loss_type: "sigmoid" # или "hinge"
# ...
GRPO – более новая фича. Она требует группировки ответов по рангам, но в mlx-tune пока реализована базово. Если видите в логах "GRPO is experimental" – это не ошибка, а предупреждение. Работает, но может быть нестабильной на больших батчах.
5 Экспорт в GGUF: мост между прототипом и продакшеном
Вот ради этого многие и используют mlx-tune. Вы натренировали LoRA-адаптеры, они лежат в output_dir как adapter_model.safetensors. Теперь нужно наложить их на базовую модель и сконвертировать в GGUF – формат, который жрут LM Studio, llama.cpp и другие рантаймы.
mlx-tune export \
--base-model mlx-community/Llama-3.1-8B \
--adapter-path ./lora-llama-3.1-8b-finetuned \
--export-path ./exported-model \
--quantize q4_k_m # или q8_0 для большей точности
Через 10-20 минут (в зависимости от размера модели) в папке exported-model появится файл ggml-model-q4_k_m.gguf. Тащите его в LM Studio и тестируйте. Если ответы кажутся странными, проверьте, что при экспорте не потерялась токенизатор. В папке должны быть tokenizer.json и config.json.
Тихие грабли, на которые наступают все
• Ошибка: "Killed: 9". Знакомо? Mac просто убивает процесс, потому что не хватило памяти. Решение: уменьшайте batch_size, включайте gradient checkpointing в конфиг (gradient_checkpointing: true), или… купите больше RAM. Серьёзно, 16 ГБ в 2026 – это ничто для LLM.
• LoRA не обучается, loss почти не двигается. Скорее всего, target_modules указаны неверно. Загрузите модель в скрипте и выведите названия модулей: print([n for n, p in model.named_modules()]). Ищите что-то вроде q_proj, v_proj.
• После экспорта модель молчит или генерирует абракадабру. Вы забыли добавить токенизатор при экспорте. Убедитесь, что в папке с адаптером есть tokenizer.json. Если нет, скопируйте его из исходной модели вручную.
• Тренировка работает, но невероятно медленно. Возможно, у вас включён macOS Sonoma 14.5 с багом в Metal Performance Shaders. Откатитесь на 14.4 или обновитесь до 14.6. Да, такое до сих пор случается.
Зачем это всё, если есть Longcat-Flash-Lite?
Справедливый вопрос. После нашей статьи про Longcat-Flash-Lite кажется, что n-gram модели решают все задачи. Но нет. Longcat – это хаммер, он забивает гвозди (простые запросы) со скоростью света. А mlx-tune – это хирургический скальпель для тонкой настройки рассуждений, тона, специализированных знаний. Вы не сделаете из n-gram модели юридического ассистента, который понимает контекст договора. А из Llama 3.3 – сделаете. И проверите это на своём MacBook, прежде чем заливать в облако.
mlx-tune не заменит кластер из H100. Но он даёт то, что дороже денег – быструю обратную связь. Идея умирает не от сложности, а от времени ожидания. С этой библиотекой у вас нет оправданий.