Ответ
LoRA — это метод параметр-эффективного дообучения (fine-tuning) больших моделей, особенно трансформеров. Вместо обновления всех миллиардов параметров исходной модели, LoRA обучает небольшие низкоранговые матрицы, которые добавляются к весам определенных слоев (обычно attention-механизмов). Эти адаптеры затем можно "включить" для конкретной задачи.
Зачем это нужно:
- Резкое снижение вычислительных затрат и потребления памяти. Можно дообучать большие LLM (например, LLaMA 7B) на одном GPU с 24 ГБ памяти.
- Возможность быстрого переключения задач. Обученные адаптеры для разных доменов (медицина, код, юридические тексты) весят несколько мегабайт и подгружаются поверх замороженной базовой модели.
- Снижение риска катастрофического забывания. Так как основные веса заморожены, модель не забывает свои исходные знания.
Техническая суть: Для весового слоя W (размерности d x k) LoRA представляет его обновление как произведение двух низкоранговых матриц: ΔW = B * A, где B (d x r), A (r x k), и ранг r << min(d, k). В прямом проходе используется h = Wx + ΔWx = Wx + BAx.
Пример дообучения модели для генерации кода с использованием библиотеки PEFT:
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, get_peft_model, TaskType
import torch
# Загрузка базовой модели (например, CodeGen)
model_name = "Salesforce/codegen-350M-mono"
tokenizer = AutoTokenizer.from_pretrained(model_name)
base_model = AutoModelForCausalLM.from_pretrained(model_name, load_in_8bit=True, device_map='auto') # Используем 8-битную квантизацию
# Конфигурация LoRA
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=8, # Ранг адаптеров
lora_alpha=32, # Коэффициент масштабирования
lora_dropout=0.1,
target_modules=["q_proj", "v_proj"], # К каким слоям attention добавлять адаптеры
bias="none",
)
# Обертывание модели
model = get_peft_model(base_model, lora_config)
model.print_trainable_parameters() # Выведет: trainable params: 8,388,608 || all params: 350,000,000 || 0.24%
# Далее следует стандартный цикл обучения.
# Будет обновляться менее 1% параметров!
Итог: LoRA — это стандартный де-факто метод для адаптации LLM под конкретные задачи или домены с ограниченными ресурсами, широко используемый в индустрии и research.
Ответ 18+ 🔞
Слушай, а вот есть же такая штука — LoRA. Ну, в общем, если по-простому, то это такой способ доучить большую, ебаную модель, чтобы она не была такой уж общей, а знала что-то конкретное. Представь себе: у тебя есть модель, которая весит, блядь, как слон, и параметров в ней — овердохуища. И чтобы её под себя подогнать, раньше надо было перелопатить все эти миллиарды весов. Это ж пиздец, ёпта! Денег, времени, видеокарт — всё в трубу.
А тут придумали гениальную, хитрожопую идею. Зачем трогать всю эту махину? Да похуй на неё! Мы её заморозим, как мамонта в вечной мерзлоте. А вместо этого прилепим к ней маленькие, лёгкие модульчики — адаптеры. Они, эти адаптеры, и будут учиться под конкретную задачу. Хочешь, чтобы модель код писала — вот тебе один адаптер. Хочешь, чтобы медицинские статьи разбирала — вот тебе другой. А базовая модель остаётся нетронутой, как истукан.
Ну и зачем это всё, спросишь?
- Экономия, мать её, дикая. Раньше для дообучения модели на 7 миллиардов параметров нужен был серверный шкаф. А теперь — одна видюха с 24 гигами памяти, и ты уже король. Ебать мои старые костыли, прогресс!
- Переключаться — раз плюнуть. Обученный адаптер весит пару мегабайт, как картинка с котиком. Захотел перейти с генерации кода на анализ законов — выгрузил один модуль, загрузил другой. Всё, блядь, готово. Удобно же, ёпта?
- Модель не превращается в овощ. Поскольку основные веса не трогаем, модель не забывает всё то, чему её учили изначально. То есть, катастрофического забывания, этой вечной беды, — нет. Доверия к такому подходу, конечно, не ноль, но уже побольше.
А как это, блядь, работает внутри? Ну, смотри. Берём какой-нибудь слой с весами W. Вместо того чтобы его пинать, мы добавляем к его выходу результат работы двух маленьких, низкоранговых матриц: B и A. Их произведение ΔW = B * A и есть наше обновление. Главный фокус в том, что ранг r у них — хуй с горы, очень маленький. И в итоге прямой проход выглядит так: h = Wx + ΔWx = Wx + BAx. Всё гениальное — просто, как три копейки.
Вот, смотри, как это в коде выглядит (используем библиотеку PEFT):
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, get_peft_model, TaskType
import torch
# Берём какую-нибудь модель, которая код генерит
model_name = "Salesforce/codegen-350M-mono"
tokenizer = AutoTokenizer.from_pretrained(model_name)
# Грузим модель, можно даже в 8-битном формате, чтобы ещё легче было
base_model = AutoModelForCausalLM.from_pretrained(model_name, load_in_8bit=True, device_map='auto')
# Настраиваем нашу LoRA
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=8, # Ранжик маленький
lora_alpha=32, # Коэффициент масштабирования
lora_dropout=0.1,
target_modules=["q_proj", "v_proj"], # Куда именно прилепляем наши адаптеры (обычно к слоям attention)
bias="none",
)
# Обматываем базовую модель нашими приблудами
model = get_peft_model(base_model, lora_config)
model.print_trainable_parameters() # Посмотрим, что по параметрам
# Выведет что-то вроде: trainable params: 8,388,608 || all params: 350,000,000 || 0.24%
# Видишь? Обучаемых параметров меньше 1%! Остальные — намертво заморожены.
# Ну а дальше — обычный цикл обучения. Крутишь датасет, считаешь loss.
# Греется и меняется только наша маленькая добавка, а не вся гигантская модель.
Итог, блядь: LoRA — это сейчас, можно сказать, золотой стандарт. Все, кто в теме, используют этот метод, чтобы приспосабливать огромные языковые модели под свои нужды, не разоряясь на аренду дата-центров. Штука реально полезная и, я бы сказал, элегантная. Чистая магия, только на матрицах.