Что такое transfer learning?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Transfer Learning (Трансфертное обучение)
Transfer Learning — это техника машинного обучения, при которой модель, обученная на одной задаче или датасете, переиспользуется для другой, часто связанной задачи. Основная идея: знания, полученные при решении одной проблемы, помогают быстрее и точнее решить другую проблему. Это экономит время обучения и улучшает результаты, особенно когда данных для целевой задачи мало.
Основная интуиция
Вместо обучения модели с нуля на маленьком датасете (что ведёт к переобучению), мы берём модель, которая уже выучила полезные признаки на большом датасете, и адаптируем её к нашей задаче.
┌─────────────────────────────────────────────────────┐
│ Классический подход: Обучение с нуля │
├─────────────────────────────────────────────────────┤
│ Маленький датасет + случайные веса = переобучение │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ Transfer Learning: Переиспользование знаний │
├─────────────────────────────────────────────────────┤
│ Большой датасет -> Модель с полезными весами │
│ + маленький датасет -> Адаптация │
└─────────────────────────────────────────────────────┘
Основные сценарии transfer learning
1. Feature Extraction (Извлечение признаков)
Используем предобученную модель как "чёрный ящик" для получения признаков, затем обучаем новый классификатор:
import torch
import torch.nn as nn
from torchvision import models, transforms
from PIL import Image
# Загружаем предобученный ResNet50
resnet50 = models.resnet50(pretrained=True)
# Удаляем последний слой (классификационный)
feature_extractor = nn.Sequential(*list(resnet50.children())[:-1])
# Замораживаем все слои предобученной модели
for param in feature_extractor.parameters():
param.requires_grad = False
# Добавляем новый классификационный слой для нашей задачи
model = nn.Sequential(
feature_extractor,
nn.Flatten(),
nn.Linear(2048, 256),
nn.ReLU(),
nn.Linear(256, 10) # 10 классов в нашей задаче
)
# Обучаем только новый слой
optimizer = torch.optim.Adam(
filter(lambda p: p.requires_grad, model.parameters()),
lr=0.001
)
2. Fine-tuning (Тонкая настройка)
Разморозим верхние слои предобученной модели и обучаем их на новых данных:
import torch
from torchvision import models
# Загружаем предобученный ResNet50
resnet = models.resnet50(pretrained=True)
# Сначала замораживаем все слои
for param in resnet.parameters():
param.requires_grad = False
# Разморозим последние слои для fine-tuning
for param in resnet.layer4.parameters():
param.requires_grad = True
for param in resnet.fc.parameters():
param.requires_grad = True
# Заменяем последний слой на нашу задачу
resnet.fc = torch.nn.Linear(2048, 10)
# Используем более низкий learning rate для fine-tuning
optimizer = torch.optim.Adam(
filter(lambda p: p.requires_grad, resnet.parameters()),
lr=1e-4 # Ниже, чем при обучении с нуля
)
Как работает transfer learning
Иерархия признаков в CNN:
Слои 1-2: Low-level признаки (края, текстуры, цвета)
|-> Полезны для любой визуальной задачи
Слои 3-5: Mid-level признаки (углы, части объектов)
|-> Довольно общие
Слои 6-8: High-level признаки (лица, животные, объекты)
|-> Специфичны для исходной задачи
При transfer learning:
- Нижние слои обычно оставляют заморозанными (они уже полезны)
- Верхние слои разморозивают и обучают на новых данных
Практический пример: Классификация кошек и собак
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset
from torchvision import models, transforms
from sklearn.model_selection import train_test_split
# Загружаем и обучаем
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 1. Загружаем предобученную модель
model = models.resnet18(pretrained=True)
# 2. Заменяем последний слой
model.fc = nn.Linear(512, 2) # 2 класса: кот и собака
model.to(device)
# 3. Замораживаем ранние слои
for param in model.layer1.parameters():
param.requires_grad = False
for param in model.layer2.parameters():
param.requires_grad = False
# 4. Обучаем только layer3, layer4 и fc
params_to_train = [
{'params': model.layer3.parameters(), 'lr': 1e-4},
{'params': model.layer4.parameters(), 'lr': 1e-4},
{'params': model.fc.parameters(), 'lr': 1e-3}
]
optimizer = optim.Adam(params_to_train)
criterion = nn.CrossEntropyLoss()
# 5. Обучение
epochs = 5
for epoch in range(epochs):
model.train()
total_loss = 0
for images, labels in train_loader:
images, labels = images.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
total_loss += loss.item()
print(f"Epoch {epoch + 1}, Loss: {total_loss / len(train_loader):.4f}")
Когда использовать transfer learning?
1. Маленький датасет целевой задачи
# У вас есть только 500 картинок кошек
# Transfer learning спасает, потому что:
# - Модель уже знает, что такое текстуры, края
# - Не нужно 1M картинок для обучения с нуля
2. Похожие домены
# Классификация котов -> Классификация собак (очень похожие)
# Классификация животных -> Классификация растений (менее похожие)
# Классификация естественных картинок -> Медицинские снимки (совсем другие)
3. Предобученная модель существует
# ImageNet -> 1.2M изображений, 1000 классов
# BERT -> 3 миллиарда слов текста
# GPT -> 45 TB текста
# Эти модели дорогие в обучении, но бесплатно доступны
from torchvision import models
model = models.resnet50(pretrained=True) # Скачиваем предобученную
Стратегии transfer learning по размеру датасета
| Размер датасета | Стратегия | Почему |
|---|---|---|
| Очень маленький (<1000) | Feature extraction | Избегаем переобучения, используем как признаки |
| Маленький (1000-10000) | Fine-tune верхние слои | Достаточно данных для адаптации, но нижние слои замороз |
| Средний (10000-100000) | Fine-tune все слои | Размораживаем больше слоёв, низкий learning rate |
| Большой (>100000) | Можно обучать с нуля | Достаточно данных, можно не использовать transfer |
Техника: Discriminative Learning Rates
Чем ближе слой к исходному обучению, тем меньше learning rate:
param_groups = [
{'params': model.layer1.parameters(), 'lr': 1e-5},
{'params': model.layer2.parameters(), 'lr': 1e-4},
{'params': model.layer3.parameters(), 'lr': 1e-3},
{'params': model.layer4.parameters(), 'lr': 1e-3},
{'params': model.fc.parameters(), 'lr': 1e-2}
]
optimizer = optim.Adam(param_groups)
Примеры transfer learning в реальности
1. Медицина: Детекция рака на рентгене
ImageNet (естественные картинки)
|
v
CheXpert (500K рентгеновских снимков)
|
v
Ваш датасет (100 снимков с раком)
2. NLP: Классификация тональности
Common Crawl (178GB текста)
|
v
BERT (предобучение)
|
v
Ваш датасет (1000 твитов)
3. Audio: Распознавание эмоций
Large audio corpus (10000+ часов)
|
v
WaveNet (предобучение)
|
v
Ваш датасет (100 часов речи)
Техника: Progressive Unfreezing
Разморозиваем слои постепенно, начиная с верхних:
import torch
def unfreeze_layers(model, num_layers_to_unfreeze):
# Получаем все слои в порядке от конца к началу
layers = list(model.children())
# Размораживаем последние num_layers_to_unfreeze слоёв
for layer in layers[-num_layers_to_unfreeze:]:
for param in layer.parameters():
param.requires_grad = True
# Пример: постепенное разморозивание
for phase, lr in [(1, 1e-3), (2, 1e-3), (3, 1e-4)]:
unfreeze_layers(model, num_layers_to_unfreeze=phase)
optimizer = optim.Adam(
filter(lambda p: p.requires_grad, model.parameters()),
lr=lr
)
# Обучаем на несколько эпох
Domain Adaptation
Когда домены сильно различаются, используют специальные техники:
# Adversarial Domain Adaptation
class DomainAdaptationModel(nn.Module):
def __init__(self, num_classes):
super().__init__()
self.feature_extractor = models.resnet50(pretrained=True)
self.classifier = nn.Linear(2048, num_classes)
self.domain_discriminator = nn.Sequential(
nn.Linear(2048, 256),
nn.ReLU(),
nn.Linear(256, 1),
nn.Sigmoid()
)
def forward(self, x):
features = self.feature_extractor(x)
class_pred = self.classifier(features)
domain_pred = self.domain_discriminator(features)
return class_pred, domain_pred
Инструменты для transfer learning
# PyTorch
from torchvision import models
model = models.resnet50(pretrained=True)
# TensorFlow/Keras
import tensorflow as tf
model = tf.keras.applications.ResNet50(weights='imagenet')
# Hugging Face (для NLP)
from transformers import BertModel
model = BertModel.from_pretrained('bert-base-uncased')
# Fast.ai
from fastai import *
learn = cnn_learner(dls, resnet50, metrics=accuracy)
Лучшие практики
- Всегда замораживай ранние слои — они содержат универсальные признаки
- Используй более низкие learning rates — не хотим «забыть» предобучение
- Проверяй на валидации — убедись, что transfer помогает
- Используй Discriminative Learning Rates — разные слои требуют разных скоростей
- Визуализируй веса — убедись, что слои обновляются правильно
Заключение
Transfer Learning — это одна из самых мощных и практичных техник в современном машинном обучении. Позволяет использовать знания, полученные на больших датасетах, для решения специализированных задач с малым количеством данных. Это особенно критично в глубоком обучении, где обучение больших моделей требует массивных датасетов и вычислительных ресурсов.