← Назад к вопросам

Что такое transfer learning?

3.0 Senior🔥 241 комментариев
#Глубокое обучение#Машинное обучение

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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)

Лучшие практики

  1. Всегда замораживай ранние слои — они содержат универсальные признаки
  2. Используй более низкие learning rates — не хотим «забыть» предобучение
  3. Проверяй на валидации — убедись, что transfer помогает
  4. Используй Discriminative Learning Rates — разные слои требуют разных скоростей
  5. Визуализируй веса — убедись, что слои обновляются правильно

Заключение

Transfer Learning — это одна из самых мощных и практичных техник в современном машинном обучении. Позволяет использовать знания, полученные на больших датасетах, для решения специализированных задач с малым количеством данных. Это особенно критично в глубоком обучении, где обучение больших моделей требует массивных датасетов и вычислительных ресурсов.