Использование LoRA адаптеров для мультизадачности

45 минут Урок 23

Введение: Почему один гигантский мозг хуже сотни маленьких экспертов?

Добро пожаловать в пятый модуль. До этого момента мы рассматривали модель Gemini 3 как монолит — мощный, универсальный, но статичный инструмент. Однако в реальном продакшене универсальность часто проигрывает специализации. Если вы строите юридического ассистента, вам нужно, чтобы модель знала тонкости прецедентного права, а не рецепты лазаньи.

Традиционный подход (Full Fine-Tuning) предполагал обновление всех весов модели. Для моделей масштаба Gemini это катастрофически дорого и медленно. Более того, это убивает мультизадачность: под каждого клиента вам пришлось бы разворачивать отдельную копию огромной модели.

Сегодня мы изучим LoRA (Low-Rank Adaptation) — технологию, которая меняет правила игры. Представьте, что вместо того, чтобы учить человека заново ходить и говорить, мы просто надеваем на него очки дополненной реальности для конкретной задачи. LoRA — это эти «очки». Это небольшие, легковесные слои адаптеров, которые накладываются на замороженную базовую модель Gemini 3.

Что вы узнаете в этом уроке:

  • Как математически работает LoRA и почему это экономит 98% ресурсов.
  • Как переключать «личности» модели (адаптеры) на лету без перезагрузки сервера.
  • Паттерн архитектуры «Router-Adapter» для сложных мультизадачных систем.

Анатомия LoRA: Как это работает «под капотом»

Давайте спустимся на уровень матриц, но без лишней академической сухости. В нейронных сетях веса хранятся в огромных матрицах. При обычном обучении мы обновляем матрицу весов $W$. Изменение весов можно обозначить как $\Delta W$.

В полном файн-тюнинге матрица $\Delta W$ имеет тот же размер, что и исходная $W$. Это миллиарды параметров.

Идея LoRA: Авторы метода заметили, что при адаптации к конкретным задачам изменения весов имеют «низкий ранг» (low intrinsic rank). Это значит, что огромную матрицу изменений $\Delta W$ можно представить как произведение двух крошечных матриц $A$ и $B$.

Формула LoRA:
W_new = W_frozen + (A × B)

Где:

  • W_frozen: Веса базовой модели Gemini 3 (мы их не трогаем, они заморожены).
  • A и B: Матрицы адаптера. Они очень маленькие. Если размерность модели $d=4096$, а ранг адаптера $r=8$, то вместо $4096 \times 4096$ (16 млн параметров) мы обучаем $4096 \times 8 + 8 \times 4096$ (всего 65 тыс. параметров).

Результат: Адаптер весит мегабайты, а не гигабайты. Вы можете хранить сотни таких адаптеров на одном диске и загружать их в оперативную память мгновенно.

python
# Концептуальная визуализация разницы в объемах данных

base_model_params = 100_000_000_000  # Условно 100 млрд параметров
full_finetune_params = 100_000_000_000 # При полном тюнинге обновляем всё

# Параметры LoRA
dimension = 12288  # Размерность скрытого слоя Gemini 3 (примерная)
rank = 16          # Ранг адаптера (r)

lora_params = 2 * (dimension * rank)

ratio = (lora_params / base_model_params) * 100

print(f"Параметров в базовой модели: {base_model_params:,}")
print(f"Обучаемых параметров LoRA: {lora_params:,}")
print(f"Экономия ресурсов: мы обучаем всего {ratio:.6f}% от объема модели!")

# Вывод:
# Параметров в базовой модели: 100,000,000,000
# Обучаемых параметров LoRA: 393,216
# Экономия ресурсов: мы обучаем всего 0.000393% от объема модели!

Паттерн мультизадачности: Hot-Swapping

Главная фишка Gemini 3 API — поддержка горячей замены (Hot-Swapping) адаптеров. В старых архитектурах для каждой дообученной модели требовался отдельный endpoint и отдельный GPU. Это было невероятно дорого.

В Gemini 3 архитектура выглядит так:

  1. Базовый слой (Base Layer): Один гигантский инстанс модели, загруженный в память GPU. Он обрабатывает общие знания языка и логику.
  2. Слой адаптеров (Adapter Layer): При каждом запросе API вы передаете параметр adapter_id. Система на лету подмешивает матрицы $A \times B$ к вычислениям.

Это позволяет одному серверу обрабатывать запрос от юриста (используя legal-adapter-v1), а следующий запрос — от программиста (используя python-expert-v2) без задержек на переключение контекста.

python
import google.generativeai as genai
import os

# Предварительная настройка API (используем гипотетический синтаксис Gemini 3 SDK)
genai.configure(api_key=os.environ["GEMINI_API_KEY"])

# Задача: У нас есть интернет-магазин.
# Нам нужно генерировать описание товара (SEO) и ответ техподдержки.
# Мы обучили два разных LoRA адаптера для этих задач.

product_context = "Смарфон X-Phone 5, 256GB, камера 200MP, батарея 5000mAh."

# 1. Вызов с SEO-адаптером (стиль: продающий, с ключевыми словами)
seo_response = genai.GenerativeModel("gemini-3-pro").generate_content(
    f"Создай описание товара: {product_context}",
    request_options={"adapter_id": "adapters/ecommerce-seo-v4"}
)

print(f"SEO Описание:\n{seo_response.text}")

# 2. Вызов с Support-адаптером (стиль: вежливый, технический, эмпатичный)
support_response = genai.GenerativeModel("gemini-3-pro").generate_content(
    f"Клиент спрашивает, сколько держит заряд: {product_context}",
    request_options={"adapter_id": "adapters/customer-support-polite-v2"}
)

print(f"Ответ поддержки:\n{support_response.text}")

# Обратите внимание: мы используем одну и ту же базовую модель 'gemini-3-pro',
# просто меняя 'линзу', через которую она смотрит на данные.

Процесс создания LoRA адаптера

Давайте пройдем путь от сырых данных до рабочего адаптера. В отличие от промпт-инжиниринга, здесь качество данных критичнее, чем их количество. Для хорошего LoRA часто достаточно 50-100 качественных пар «вход-выход».

Этап 1: Подготовка данных

Данные должны быть в формате JSONL. Для специализации модели важна консистентность стиля. Если вы учите модель отвечать как пират, все ответы в датасете должны быть в стиле пирата.

Формат обычно выглядит так:

{"messages": [{"role": "user", "content": "Привет"}, {"role": "model", "content": "Якорь мне в бухту! Чего хотел, сухопутная крыса?"}]}

Этап 2: Выбор гиперпараметров

При запуске create_tuned_model ключевые параметры это:

  • Rank (r): Обычно 4, 8 или 16. Чем выше ранг, тем сложнее паттерны может выучить адаптер, но тем выше риск переобучения (модель начнет просто цитировать примеры). Для стилизации текста обычно хватает r=4. Для новых знаний (например, специфический синтаксис языка программирования) может потребоваться r=16.
  • Epochs: Сколько раз модель увидит данные. Для малых датасетов (100 примеров) ставьте 5-10 эпох.
  • Learning Rate Multiplier: Коэффициент скорости обучения. В LoRA он часто выше, чем при полном тюнинге.

python
# Пример скрипта для запуска обучения адаптера
import time

base_model = "models/gemini-3-pro-001"
training_file_id = "files/dataset-legal-contracts.jsonl"

operation = genai.create_tuned_model(
    # Уникальный ID для вашего адаптера
    id="tuned-models/gemini-3-legal-expert-v1",
    source_model=base_model,
    training_data=training_file_id,
    # Конфигурация LoRA
    tuning_task_options={
        "hyperparameters": {
            "batch_size": 8,
            "learning_rate_multiplier": 0.001,
            "epoch_count": 5,
            # В некоторых API параметр rank может быть скрыт или настраиваем через advanced конфиг
            # Но концептуально вы управляете именно им
        }
    },
    display_name="Legal Contract Analyzer"
)

print(f"Запущено обучение: {operation.name}")

# Ожидание завершения
while not operation.done():
    print("Обучение в процессе...")
    time.sleep(60)

result = operation.result()
print(f"Обучение завершено. Адаптер доступен как: {result.name}")

Архитектурный паттерн: Интеллектуальный Роутер

Теперь самое интересное. Как автоматизировать выбор адаптера? Пользователь не будет вручную выбирать «режим юриста». Ваше приложение должно делать это за него.

Мы используем двухуровневую архитектуру:

  1. Роутер (Router): Легковесный вызов (например, Gemini 3 Flash без адаптеров), который классифицирует интент пользователя.
  2. Исполнитель (Worker): Вызов Gemini 3 Pro с конкретным LoRA адаптером, выбранным Роутером.

Этот подход позволяет создавать невероятно мощные «швейцарские ножи» для бизнеса, где один чат-бот может квалифицированно консультировать по налогам, писать код и сочинять стихи, просто переключая внутренние модули.

Упражнение

Реализуйте функцию `smart_reply(user_query)`, которая автоматически выбирает нужный адаптер. <br><br>Условия:<br>1. Есть два адаптера: `adapters/tech-support` (для технических проблем) и `adapters/sales` (для вопросов о цене и покупке).<br>2. Сначала используйте `gemini-3-flash` чтобы классифицировать запрос пользователя на категорию 'TECHNICAL' или 'SALES'.<br>3. Затем сделайте вызов `gemini-3-pro` с соответствующим адаптером.<br>4. Если категория не ясна, используйте базовую модель без адаптера.

Вопрос

В чем заключается главное преимущество использования LoRA по сравнению с полным файн-тюнингом (Full Fine-Tuning) в контексте мультизадачности?