中文翻译暂不可用,显示俄语原文。
Fine-tune QLoRA на 1 GPU
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Fine-tune QLoRA на 1 GPU
1. Цель задачи
Научиться эффективно fine-tune'ить большие языковые модели (70B параметров) на одном GPU с помощью QLoRA (Quantized Low-Rank Adaptation). Используя 4-битную квантизацию и LoRA-адаптеры, вы сможете дообучить модель 70B на 500 примерах, потребляя менее 48 ГБ видеопамяти. Задача демонстрирует практические навыки работы с bitsandbytes, PEFT, Hugging Face Transformers и техниками снижения потребления памяти.
Ключевой результат Рабочий checkpoint адаптированной модели 70B (LoRA-адаптеры + базовая модель в 4-bit), обученной на 500 примерах, с измеренным loss < 1.5 на валидации.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Базовая модель 70B (например, LLaMA-2-70B или Mistral-70B) | Hugging Face Model Hub (с доступом по лицензии) |
| Датасет из 500 примеров (инструкции + ответы) | Сгенерировать самостоятельно или взять из HF (databricks/databricks-dolly-15k, первые 500 записей) |
| GPU с ≥ 24 ГБ VRAM (например, A10, A100, RTX 4090) | Локально, облако (Colab Pro, RunPod, Vast.ai) или симуляция на CPU (только для отладки) |
| Python 3.10+ и базовая среда | Установка через conda / pip |
Если нет реального GPU — симулируем:
- Используйте ту же конфигурацию в Google Colab (бесплатный T4 — 16 ГБ не хватит для 70B, но подойдёт для 7B/8B). Для 70B нужен A100 или подобный — арендуйте через RunPod ($0.50/ч).
- Если бюджет ограничен, замените модель на meta-llama/Llama-3.1-8B и отработайте все шаги с той же конфигурацией QLoRA — навыки переносятся.
- Скачайте и закешируйте модель локально, чтобы не тратить время на повторные загрузки.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Base model | Hugging Face Transformers, AutoModelForCausalLM | Загрузка и квантизация модели 70B |
| 4-bit quantization | bitsandbytes (>=0.43.0) | Сжатие весов до 4 бит (NF4) |
| LoRA / QLoRA | peft (>=0.12.0) | Создание и обучение низкоранговых адаптеров |
| Training loop | transformers.Trainer + trl.SFTTrainer | Обучение с оптимизацией памяти (gradient checkpointing) |
| Dataset | datasets (Hugging Face) | Загрузка и токенизация 500 примеров |
| Управление памятью | accelerate + deepspeed (опционально) | Распределение, offload |
| Мониторинг | wandb или tensorboard | Логирование loss, градиентов, использования памяти |
| Система | CUDA 12.x, PyTorch 2.4+, Linux | Среда выполнения |
4. Этапы выполнения
Этап 1: Подготовка окружения и данных (30 минут)
Действия
-
Создайте виртуальное окружение и установите зависимости:
conda create -n qlora70b python=3.10 -y conda activate qlora70b pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124 pip install transformers accelerate bitsandbytes peft trl datasets wandb -
Получите доступ к модели 70B (если закрытая):
- Запросите доступ на Hugging Face для
meta-llama/Llama-2-70b-hf. - Авторизуйтесь: huggingface-cli login.
- Запросите доступ на Hugging Face для
-
Подготовьте датасет (500 примеров):
- Загрузите Dolly-15k и выберите первые 500:
from datasets import load_dataset ds = load_dataset("databricks/databricks-dolly-15k", split="train") ds = ds.select(range(500)) ds = ds.train_test_split(test_size=0.1, seed=42) # Формат: {"instruction": str, "context": str, "response": str} - Конвертируйте в формат для causal LM (instruction -> response):
def format_example(example): return {"text": f"### Instruction:\n{example['instruction']}\n\n### Response:\n{example['response']}"} ds = ds.map(format_example)
- Загрузите Dolly-15k и выберите первые 500:
-
Проверьте, сколько занимает модель в 4-bit:
Ожидаемый результат этапа Среда установлена, модель загружена (хотя бы проверка доступа), датасет готов и разбит на train/val.
Этап 2: Загрузка модели и настройка QLoRA (1 час)
Действия
-
Загрузите модель в 4-bit с помощью bitsandbytes:
import torch from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_use_double_quant=True, # Double Quantization bnb_4bit_compute_dtype=torch.bfloat16 # или float16, bfloat16 стабильнее ) model = AutoModelForCausalLM.from_pretrained( "meta-llama/Llama-2-70b-hf", quantization_config=bnb_config, device_map="auto", torch_dtype=torch.bfloat16, trust_remote_code=True ) tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-70b-hf") tokenizer.pad_token = tokenizer.eos_token -
Настройте LoRA-адаптеры (PEFT):
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training model = prepare_model_for_kbit_training(model) lora_config = LoraConfig( r=8, # ранг адаптера lora_alpha=32, target_modules=["q_proj", "v_proj", "k_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], lora_dropout=0.05, bias="none", task_type="CAUSAL_LM" ) model = get_peft_model(model, lora_config) model.print_trainable_parameters() # должно быть ~0.1% от всех параметров (~70M из 70B) -
Проверьте потребление памяти
- torch.cuda.memory_summary() до и после загрузки.
- Ожидается: ~40-45 ГБ на загрузку, + буфер для градиентов (~10 ГБ) → всего ~50-55 ГБ. Если не хватает, включите
gradient_checkpointing_enable().
Ожидаемый результат этапа Модель загружена в 4-bit, LoRA адаптеры добавлены, параметры trainable показаны, память в пределах доступной.
Этап 3: Конфигурация обучения и запуск (1 час)
Действия
-
Настройте Trainer с оптимизацией памяти
from transformers import TrainingArguments from trl import SFTTrainer training_args = TrainingArguments( output_dir="./qlora-70b-checkpoints", per_device_train_batch_size=2, # маленький batch из-за 70B per_device_eval_batch_size=2, gradient_accumulation_steps=4, # эффективный batch = 8 learning_rate=2e-4, warmup_steps=10, max_steps=50, # 500 примеров, batch 8 → ~63 шага, возьмём 50 logging_steps=5, eval_steps=10, save_strategy="steps", save_steps=10, evaluation_strategy="steps", fp16=False, # используем bf16, если поддерживается bf16=True, optim="paged_adamw_8bit", # экономит память gradient_checkpointing=True, gradient_checkpointing_kwargs={"use_reentrant": False}, report_to="wandb" # или "tensorboard" ) -
Создайте коллатор данных и запустите обучение:
trainer = SFTTrainer( model=model, tokenizer=tokenizer, args=training_args, train_dataset=ds["train"], eval_dataset=ds["test"], dataset_text_field="text", max_seq_length=512, # обрезаем длинные примеры до 512 токенов packing=False # для простоты ) # Перед обучением проверьте, что trainer может разместить data в память trainer.train() -
Мониторинг в WandB
- Следите за train_loss, eval_loss, grad_norm.
- Цель: loss < 1.5 на валидации после 50 шагов.
Ожидаемый результат этапа Обучение завершено без Out-of-Memory, в папке ./qlora-70b-checkpoints сохранены чекпоинты.
Этап 4: Оценка и сохранение финальной модели (30 минут)
Действия
-
Загрузите лучший чекпоинт и оцените на тесте:
from peft import PeftModel from transformers import pipeline base_model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-70b-hf", quantization_config=bnb_config, device_map="auto") model = PeftModel.from_pretrained(base_model, "./qlora-70b-checkpoints/checkpoint-50") pipe = pipeline("text-generation", model=model, tokenizer=tokenizer, max_new_tokens=100) # Пример запроса test_prompt = "### Instruction:\nExplain quantum entanglement in simple terms.\n\n### Response:\n" print(pipe(test_prompt)[0]["generated_text"]) -
Сохраните только адаптеры (они весят ~140 МБ):
model.save_pretrained("./qlora-70b-final-adapter") tokenizer.save_pretrained("./qlora-70b-final-adapter") -
Сравните loss на тесте с baseline (модель без fine-tune):
- Если eval_loss < 1.5 — задача выполнена.
Ожидаемый результат этапа Сохранённые LoRA-адаптеры, пример генерации, лог eval_loss.
Этап 5: Документирование и анализ (30 минут)
Действия
- Зафиксируйте все метрики и конфигурацию создайте markdown-файл
report.mdс таблицами. - Сравните время обучения и используемую память: запишите peak memory из
nvidia-smi. - Сделайте выводы как QLoRA позволила обучить 70B на одном GPU? Что можно улучшить (больше данных, больше шагов, rank адаптера).
Ожидаемый результат этапа Файл report.md с анализом, метриками, рекомендациями.
5. Критерии приемки (Definition of Done)
- Обучение QLoRA запущено и завершено без ошибок OOM.
- Peak GPU memory не превышает 90% от доступной (например, < 72 ГБ для A100 80GB).
- Финальный eval loss (perplexity) ≤ 1.5 (или улучшение относительно базовой модели).
- LoRA-адаптеры сохранены в отдельной папке (размер < 200 МБ).
- Модель генерирует осмысленные ответы на примерах из датасета.
- Подготовлен файл
report.mdс конфигурацией, метриками и наблюдениями. - Воспроизводимость: указаны версии пакетов (pip freeze > requirements.txt).
6. Ожидаемый результат
- Основной артефакт папка
qlora-70b-final-adapterсadapter_config.json,adapter_model.safetensorsиtokenizer. - Содержание LoRA веса (~140 МБ) и конфигурация, которые можно загрузить на базовую 70B модель для инференса.
- Дополнительно
report.mdс метриками (train loss, eval loss, память, скорость),requirements.txt, скриншот WandB.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| CUDA Out-of-Memory при загрузке модели | Уменьшить max_memory в device_map, использовать from_pretrained(..., device_map="sequential"), включить CPU offload или арендовать GPU с большей памятью (A100 80GB). |
Ошибка bitsandbytes не совместим с CUDA | Установить bitsandbytes для конкретной версии CUDA (pip install bitsandbytes==0.43.2), проверить import bitsandbytes и torch.cuda.is_available(). |
| Медленное обучение (больше 4 часов) | Уменьшить max_steps до 30, увеличить batch size (если позволяет память), отключить eval на каждом шагу. |
| Плохая сходимость на 500 примерах | Использовать больший learning_rate (3e-4), увеличить lora_alpha (64), добавить больше шагов (100) или увеличить рангов (r=16). |
| Генерация повторяющихся/бессмысленных ответов | Увеличить температуру при инференсе, проверить датасет на качество, увеличить max_seq_length. |
Проблемы с transformers и accelerate | Обновить библиотеки до последних версий, использовать pip install --upgrade transformers accelerate. |
8. Бюджет времени (оценка)
| Этап | Время |
|---|---|
| Этап 1: Подготовка окружения и данных | 30 мин |
| Этап 2: Загрузка модели и QLoRA | 1 ч |
| Этап 3: Обучение | 2-3 ч |
| Этап 4: Оценка и сохранение | 30 мин |
| Этап 5: Документирование | 30 мин |
| Итого | ~5-6 часов |
Примечание для первого раза: Время обучения сильно зависит от GPU. На A100 80GB 50 шагов с batch 8 занимает ~40 минут. На RTX 4090 (24 ГБ) 70B не поместится — используйте 8B модель для теста.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 101 | Как настроить bitsandbytes для 4-bit? |
| 205 | Разница между LoRA и QLoRA |
| 310 | Оптимизация VRAM: gradient checkpointing |
| 415 | Выбор ранга LoRA для больших моделей |
| 520 | Как провести fine-tune инструкционных моделей |
| 623 | Настройка SFTTrainer из TRL |
| 730 | Мониторинг обучения с WandB |
| 835 | Устранение OOM при загрузке моделей |
| 899 | Бенчмарк памяти: 4-bit vs 8-bit |
10. Чек-лист самопроверки
- Я корректно загрузил(а) модель в 4-bit с
BitsAndBytesConfig. - Я проверил(а), что trainable параметры < 0.2% от общего числа.
- Я включил(а) gradient checkpointing и paged optimizer.
- Я сохранил(а) только LoRA-адаптеры, а не полную модель.
- Я убедился(ась), что eval loss снизился относительно начального значения.