Запуск процесса Supervised Fine-Tuning через API

50 минут Урок 23

Введение: Переходим от подготовки данных к обучению

Добро пожаловать на урок, где магия становится реальностью. В предыдущих частях модуля мы скрупулезно собирали данные, чистили их и форматировали в JSONL. Это была, пожалуй, самая трудоемкая часть работы. Теперь мы переходим к самому интересному — запуску процесса Supervised Fine-Tuning (SFT) через API.

Почему мы фокусируемся на API, а не на графическом интерфейсе Google AI Studio? Интерфейс прекрасен для экспериментов и прототипов. Но когда речь заходит о Enterprise-решениях — автоматизации, CI/CD пайплайнах, регулярном переобучении моделей на свежих данных — без кода не обойтись. Вы же не будете каждый понедельник вручную кликать кнопки в браузере, чтобы обновить модель поддержки клиентов?

В этом уроке мы разберем процесс запуска обучения шаг за шагом, углубимся в настройки гиперпараметров (те самые рычаги, которые определяют качество модели) и научимся программно отслеживать статус выполнения задачи.

Шаг 1: Подготовка окружения и загрузка данных

Прежде чем модель начнет учиться, она должна получить доступ к учебникам — вашим данным. В экосистеме Gemini API процесс обучения разделен на два этапа: загрузка файла и создание задачи обучения (Tuning Job).

Мы будем использовать Google GenAI SDK. Предполагается, что у вас уже настроен API ключ и установлен пакет.

Важный нюанс: Данные загружаются через специальный File API. Это временное хранилище, оптимизированное для быстрой передачи данных в обучающий кластер. Файл должен быть в формате JSONL, где каждая строка — это валидный JSON объект с примерами диалогов.

python
import google.generativeai as genai
import time
import os

# Настройка API ключа
# В реальном проекте используйте переменные окружения для безопасности
genai.configure(api_key=os.environ["GOOGLE_API_KEY"])

# Путь к вашему подготовленному файлу данных
file_path = "training_data_v1.jsonl"
display_name = "support_tickets_dataset_jan2024"

print(f"Загружаем файл {file_path}...")

# 1. Загрузка файла в File API
training_file = genai.upload_file(
    path=file_path,
    display_name=display_name,
    mime_type="application/json"
)

print(f"Файл загружен. URI: {training_file.uri}")
print(f"Состояние: {training_file.state.name}")

Шаг 2: Анатомия Tuning Job и Гиперпараметры

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

Давайте разберем ключевые настройки (гиперпараметры), которые вам доступны:

  • Epochs (Эпохи): Сколько раз модель «прочитает» весь ваш набор данных.
    • Слишком мало: Модель не запомнит паттерны (Underfitting).
    • Слишком много: Модель просто зазубрит примеры и потеряет гибкость (Overfitting). Для наборов данных среднего размера (50-500 примеров) обычно начинают с 3-5 эпох.
  • Batch Size (Размер батча): Сколько примеров модель обрабатывает за один шаг обновления весов. Больший батч дает более стабильное, но усредненное обучение. Меньший батч — более шумное, но иногда более точное. API часто подбирает это автоматически, но вы можете задать его вручную.
  • Learning Rate Multiplier (Множитель скорости обучения): Насколько сильно модель меняет свои внутренние веса в ответ на ошибку. Если представить обучение как спуск с горы, то это длина шага. Слишком большой шаг — перепрыгнете низину. Слишком маленький — будете спускаться вечность.

Для Gemini 3 мы будем использовать базовую модель (например, gemini-3.0-flash-001) как фундамент.

python
# Конфигурация задачи обучения
base_model = "models/gemini-3.0-flash-001"
tuned_model_id = "my-specialized-support-bot-v1"

print("Запуск задачи Fine-Tuning...")

# 2. Создание задачи обучения
operation = genai.create_tuned_model(
    # Уникальный ID для вашей новой модели
    tuned_model_id=tuned_model_id,
    
    # Базовая модель
    source_model=base_model,
    
    # Ссылка на файл с данными (объект, который мы получили на шаге 1)
    training_data=training_file,
    
    # Гиперпараметры
    epoch_count=5, # Проходим датасет 5 раз
    batch_size=4,  # Обрабатываем по 4 примера за раз
    learning_rate=0.001, # Скорость обучения
    
    display_name="Customer Support Bot - Fine Tuned"
)

print("Задача создана. Модель обучается в фоновом режиме.")

Шаг 3: Мониторинг и Ожидание

Fine-tuning — это не мгновенный процесс. В зависимости от объема данных и загруженности кластера Google, это может занять от 10 минут до нескольких часов.

После вызова create_tuned_model, вы получаете объект операции. Процесс происходит асинхронно. Ваша задача как инженера — не просто ждать, а контролировать процесс. API возвращает статус задачи, который может принимать значения:

  • CREATING: Задача инициализируется.
  • ACTIVE: Модель готова к использованию (обучение завершено).
  • FAILED: Что-то пошло не так (обычно проблема в данных).

Ниже приведен паттерн поллинга (опроса) статуса, который часто используется в скриптах автоматизации.

python
import time

model_name = f"tunedModels/{tuned_model_id}"

print(f"Ожидание завершения обучения для модели: {model_name}")

while True:
    # Получаем актуальный статус модели
    model_info = genai.get_tuned_model(model_name)
    status = model_info.state.name
    
    if status == 'ACTIVE':
        print("\nУСПЕХ! Модель обучена и готова к работе.")
        break
    elif status == 'FAILED':
        print(f"\nОШИБКА: Обучение не удалось. Детали: {model_info.tuning_task.description}")
        break
    else:
        # Статус CREATING или обучение в процессе
        print(".", end="", flush=True)
        time.sleep(10) # Проверяем каждые 10 секунд

Шаг 4: Инференс (Использование обученной модели)

Поздравляю! Если статус сменился на ACTIVE, у вас теперь есть собственная версия Gemini 3, заточенная под ваши задачи. Она больше не просто "умная модель", она — эксперт в вашем домене.

Использование fine-tuned модели практически не отличается от использования обычной, за исключением одного нюанса: вы обращаетесь к ней по ее новому, уникальному имени (ресурсу), который начинается с tunedModels/.

Давайте проверим, как наша новая модель справляется с запросом, используя те же методы генерации контента, что и раньше.

python
# Использование дообученной модели

# Инициализируем модель по её ID
my_model = genai.GenerativeModel(model_name=f"tunedModels/{tuned_model_id}")

# Тестовый промпт, релевантный вашим данным
test_prompt = "Клиент жалуется на ошибку 503 при оплате. Как ответить вежливо?"

response = my_model.generate_content(test_prompt)

print("Ответ дообученной модели:")
print("-" * 30)
print(response.text)
print("-" * 30)

Лучшие практики и Советы

Запуск скрипта — это только половина дела. Вот несколько советов из «полей» для создания Enterprise-решений:

  1. Валидация данных перед загрузкой: API вернет ошибку, если JSONL битый, но лучше проверить это локально скриптом. Это сэкономит время.
  2. Кривые обучения (Loss Curves): В консоли Google Cloud или через объект метаданных модели можно посмотреть график функции потерь (loss). Если линия падает — модель учится. Если скачет или стоит на месте — проверьте Learning Rate или качество данных.
  3. Версионирование: Всегда добавляйте суффиксы к tuned_model_id (например, -v1, -date). Вы будете переобучать модель много раз, и важно не запутаться в версиях.
  4. Квоты: Помните, что на Fine-Tuning действуют отдельные квоты API. Если вы планируете обучать много моделей параллельно, запросите увеличение лимитов заранее.

Упражнение

Сценарий: Вы работаете в финтех-стартапе. Вам нужно обучить модель классифицировать транзакции на 'Подозрительные' и 'Нормальные' на основе JSON-логов. У вас есть файл 'finance_logs.jsonl'. <br><br>Напишите фрагмент кода, который:<br>1. Задает базовую модель как 'models/gemini-3.0-flash-001'.<br>2. Устанавливает жесткий лимит обучения: всего 2 эпохи (чтобы избежать переобучения на малом датасете).<br>3. Задает идентификатор модели 'fintech-guard-v1'.<br><br>(Код загрузки файла можно пропустить, начните с вызова create_tuned_model).

Вопрос

Вы запустили процесс Fine-Tuning, и видите, что значение функции потерь (Loss) на графике не уменьшается в течение нескольких эпох, а колеблется на одном уровне. Какое действие с гиперпараметрами будет наиболее логичным для следующей попытки?