Transfer learning: дообучение готовых моделей

Главный практический приём индустрии: не учить с нуля, а дообучать готовое.

Transfer learning — использование сети, уже обученной на большом наборе данных, как основы для своей задачи с малым числом примеров.

Почему не учить с нуля

Обучить большую сеть с нуля нужны миллионы картинок и дни на мощных GPU — у вас этого обычно нет. Но есть готовые модели (например ResNet), уже обученные на миллионах изображений ImageNet. Они выучили универсальные признаки: первые слои узнают края и текстуры, средние — формы и части объектов. Эти знания полезны почти для любой картиночной задачи. Идея transfer learning: взять эти готовые признаки и приставить к ним свой маленький «классификатор» под вашу задачу.

Как это работает: заморозка и замена головы

План в три шага. Берём предобученную сеть. Замораживаем её веса (запрещаем им обучаться — они уже хороши). Заменяем последний слой («голову») на новый под наше число классов и учим только его. Поскольку учится лишь крошечная голова, хватает сотни примеров и пары минут.

import torch
import torch.nn as nn
import torchvision.models as models

# 1. берём предобученную ResNet18
model = models.resnet18(weights="IMAGENET1K_V1")

# 2. замораживаем все веса — градиенты по ним не считаем
for param in model.parameters():
    param.requires_grad = False

# 3. заменяем голову под свои 3 класса
#    (у нового слоя requires_grad=True по умолчанию)
model.fc = nn.Linear(model.fc.in_features, 3)

Разберём ключевую механику. Установка requires_grad = False всем параметрам — это та самая заморозка из раздела про autograd: по таким весам градиенты не считаются и оптимизатор их не трогает. А новый model.fc создан только что, у него requires_grad=True — значит, учиться будет только он.

Оптимизатор учит только голову

Поскольку у замороженных слоёв градиентов нет, оптимизатору можно отдать вообще все параметры — он обновит только те, у кого requires_grad=True. Но чище отдать явно лишь параметры новой головы:

# учим только новый слой
optimizer = torch.optim.Adam(model.fc.parameters(), lr=0.001)

Дальше — обычный цикл обучения из пяти шагов. Ничего нового: forward → loss → zero_grad → backward → step. Просто backprop дойдёт только до незамороженной головы.

Заморозить или дообучить всё (fine-tuning)

ПодходКогда
заморозить тело, учить головумало данных, задача близка к исходной — быстро и безопасно
дообучить всю сеть (fine-tuning)данных побольше, нужно адаптировать признаки — с маленьким lr

При полном fine-tuning размораживают всю сеть, но берут очень маленький lr, чтобы не разрушить уже выученные признаки. Начинают обычно с заморозки — это проще и часто достаточно.

Почему это так важно

Transfer learning — причина, по которой современный ИИ доступен не только гигантам. Дообучить готовую модель под свою задачу можно на ноутбуке за минуты. Та же идея лежит в основе дообучения языковых моделей: берут предобученную на терабайтах текста сеть и адаптируют под конкретную задачу малым числом примеров.

Итог

  • Transfer learning = взять предобученную сеть и дообучить под свою задачу.
  • Признаки первых слоёв (края, текстуры) универсальны — их незачем учить заново.
  • Базовый рецепт: заморозить тело (requires_grad=False), заменить голову, учить только её.
  • Полный fine-tuning размораживает всё, но с маленьким lr; обычно начинают с заморозки.
Проверьте себя
1. В чём основная идея transfer learning?
AОбучать сеть с нуля, но быстрее
BВзять предобученную сеть и дообучить её под свою задачу
CОбъединить несколько моделей в одну
DУменьшить число классов в датасете
2. Что означает «заморозить» слой при transfer learning?
AПеренести его на CPU
BПоставить его параметрам requires_grad=False, чтобы они не обучались
CУдалить слой из модели
DОбнулить его веса
3. Почему при полном fine-tuning всей сети берут очень маленький learning rate?
AЧтобы обучение шло быстрее
BЧтобы большими шагами не разрушить уже выученные полезные признаки
CПотому что Adam не работает с большим lr
DЧтобы заморозить голову
Поддержать проект