Предобученные модели в torchvision: ResNet, EfficientNet и ViT
Вы загрузите ResNet-50, предварительно обученную на ImageNet, изучите её архитектуру и выполните вывод для нового изображения, чтобы проверить заранее выученные представления.
«Предобученные модели в torchvision: ResNet, EfficientNet и ViT» — бесплатный урок Machine Learning Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Machine Learning Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Machine Learning Academy содержит 4 уроков всего.
Зачем использовать предварительно обученные модели
Обучение глубокой нейронной сети на ImageNet с нуля требует миллионов размеченных изображений и недель вычислений на GPU. Предварительно обученные модели уже выучили общие визуальные признаки — границы, текстуры, формы и части объектов высокого уровня — на основе этого огромного набора данных.
Повторно используя эти веса, Вы получаете пользу от обучения на 1,2 миллиона изображений, не оплачивая вычислительную стоимость обучения. В этом заключается основная идея переноса обучения: признаки, выученные на одной крупной задаче, хорошо переносятся на связанные задачи меньшего масштаба. torchvision.models предоставляет десятки предварительно обученных архитектур, готовых к загрузке и использованию.
import torchvision.models as models
# List some available pre-trained models
print(dir(models)) # Shows resnet50, efficientnet_b0, vit_b_16, etc.
# Loading weights pre-trained on ImageNet-1k
resnet = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)
print('ResNet-50 loaded, parameters:', sum(p.numel() for p in resnet.parameters()))Обзор архитектуры ResNet-50
ResNet-50 (остаточная сеть с 50 слоями) ввела пропускающие соединения, которые напрямую добавляют вход блока к его выходу: output = F(x) + x. Благодаря этому градиенты могут проходить непосредственно через операцию сложения, что позволяет обучать очень глубокие сети без затухания градиентов.
ResNet-50 содержит примерно 25 миллионов параметров и состоит из одного начального свёрточного слоя 7×7, максимального объединения, четырёх остаточных блоков (layer1–layer4) и слоя глобального усредняющего объединения, за которым следует полносвязная голова на 1000 классов для классификации изображений ImageNet. Именно последний слой fc заменяется для пользовательских задач.
import torchvision.models as models
import torch
resnet = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)
print(resnet) # Prints the full architecture
# Key layers
print('Final FC layer:', resnet.fc) # Linear(2048, 1000)
print('Layer4 output channels:', 2048) # Feature dimension before FCВыполнение вывода с ResNet-50
Перед выполнением вывода входные данные должны соответствовать предварительной обработке, использовавшейся при обучении на ImageNet: их нужно изменить до размера не менее 224×224 и нормализовать со средним и стандартным отклонением ImageNet. API torchvision.transforms выполняет эту обработку. Перед выводом всегда вызывайте model.eval(), чтобы отключить прореживание и режим обучения пакетной нормализации.
Модель выдаёт 1000 логитов — по одному на каждый класс ImageNet. Мы применяем softmax, чтобы получить вероятности, и выбираем классы с наибольшими значениями top-k. Теперь torchvision.models включает названия категорий в метаданные весов, поэтому отдельный файл с метками больше не нужен.
import torch
from torchvision import transforms
from PIL import Image
import torchvision.models as models
weights = models.ResNet50_Weights.IMAGENET1K_V1
resnet = models.resnet50(weights=weights)
resnet.eval()
# Preprocessing transforms from the weights metadata
preprocess = weights.transforms()
# Load and preprocess an image
img = Image.open('cat.jpg')
tensor = preprocess(img).unsqueeze(0) # Add batch dimension
with torch.no_grad():
logits = resnet(tensor)
probs = torch.softmax(logits, dim=1)
top5 = torch.topk(probs, 5)
print('Top-5 probabilities:', top5.values)EfficientNet: составное масштабирование
EfficientNet (2019) представила составное масштабирование: систематическое одновременное масштабирование ширины, глубины и разрешения входных данных с использованием одного составного коэффициента. Вместо произвольного увеличения ширины или глубины сети EfficientNet уравновешивает все три измерения, обеспечивая оптимальный компромисс между точностью и эффективностью.
Семейство EfficientNet простирается от efficientnet_b0 (5 млн параметров) до efficientnet_b7 (66 млн параметров). EfficientNet-B0 достигает сопоставимой с ResNet-50 точности, используя в 8 раз меньше параметров и в 6 раз меньше FLOP, поэтому хорошо подходит для развёртывания на мобильных и периферийных устройствах. PyTorch предоставляет все восемь вариантов.
import torchvision.models as models
import torch
# EfficientNet-B0: lightweight but accurate
eff_b0 = models.efficientnet_b0(weights=models.EfficientNet_B0_Weights.IMAGENET1K_V1)
print('EfficientNet-B0 params:', sum(p.numel() for p in eff_b0.parameters()))
print('EfficientNet-B0 classifier:', eff_b0.classifier)
# Compare with ResNet-50
resnet50 = models.resnet50(weights=None) # No weights to count params only
print('ResNet-50 params:', sum(p.numel() for p in resnet50.parameters()))Vision Transformer (ViT): внимание без свёрток
Vision Transformers (ViT) (2020) применяют архитектуру трансформера непосредственно к изображениям, без каких-либо свёрток. Изображение разбивается на сетку фрагментов фиксированного размера (например, 16×16 пикселей), каждый фрагмент разворачивается и проецируется в вектор встраивания. Эти векторы фрагментов обрабатываются подобно токенам слов в NLP.
В начало последовательности фрагментов добавляется токен CLS (классификации). После прохождения через несколько блоков кодировщика трансформера с механизмом самовнимания выход токена CLS используется для классификации. Для превосходства над CNN ViT требует больших обучающих наборов данных, но предварительно обученные модели ViT из torchvision позволяют сразу использовать эту мощь в Ваших задачах.
import torchvision.models as models
import torch
# ViT-B/16: Base model with 16x16 patches
vit = models.vit_b_16(weights=models.ViT_B_16_Weights.IMAGENET1K_V1)
print('ViT-B/16 params:', sum(p.numel() for p in vit.parameters()))
print('ViT patch size: 16x16 pixels')
print('ViT sequence length for 224x224 image:', (224 // 16) ** 2 + 1, '(196 patches + 1 CLS token)')
print('ViT head:', vit.heads) # Linear(768, 1000)Сравнение ResNet, EfficientNet и ViT
Выбор между этими архитектурами зависит от Ваших ограничений и задачи. ResNet-50 — надёжный вариант по умолчанию: хорошо изученная модель, сильная базовая линия, множество руководств и реализаций. EfficientNet-B0/B2 выигрывает, когда важны скорость вывода и размер модели — например, в мобильных приложениях, системах реального времени или периферийном оборудовании.
ViT особенно хорошо показывает себя в крупномасштабных задачах и получает преимущества от самоконтролируемого предварительного обучения (DINO, CLIP). Ей требуется больше вычислительных ресурсов и памяти, чем CNN с сопоставимой точностью. Для большинства пользовательских задач классификации изображений с наборами данных среднего размера начните с EfficientNet-B2 или ResNet-50, а затем попробуйте ViT, если у Вас есть ресурсы для её дообучения.
# Rough comparison on ImageNet top-1 accuracy
comparison = {
'ResNet-50': {'params': '25M', 'top1': '76.1%', 'year': 2015},
'EfficientNet-B0': {'params': '5M', 'top1': '77.7%', 'year': 2019},
'EfficientNet-B4': {'params': '19M', 'top1': '83.4%', 'year': 2019},
'ViT-B/16': {'params': '86M', 'top1': '81.1%', 'year': 2020},
'ViT-L/16': {'params': '307M','top1': '85.1%', 'year': 2020},
}
for name, info in comparison.items():
print(f'{name}: {info["params"]} params, {info["top1"]} top-1')Изучение внутреннего устройства модели
Перед изменением предварительно обученной модели для своей задачи изучите её архитектуру, чтобы понять, какие слои нужно заменить. Используйте print(model), чтобы увидеть дерево слоёв, а для программного перебора — named_modules() или named_children().
Главная идея заключается в следующем: каждая модель torchvision заканчивается классификационной головой, рассчитанной на 1000 классов ImageNet. Чтобы адаптировать модель к задаче с num_classes, отличным от 1000, замените этот последний слой. Извлекатель признаков (всё до головы) сохраняет признаки, выученные на ImageNet.
import torchvision.models as models
resnet = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)
# Find the names of top-level children
for name, module in resnet.named_children():
print(name, '->', type(module).__name__)
# Output:
# conv1 -> Conv2d
# bn1 -> BatchNorm2d
# relu -> ReLU
# maxpool -> MaxPool2d
# layer1 -> Sequential (Residual blocks)
# layer2 -> Sequential
# layer3 -> Sequential
# layer4 -> Sequential
# avgpool -> AdaptiveAvgPool2d
# fc -> Linear <-- This is what we replaceРазмер вектора признаков для каждой архитектуры
При замене классификационной головы необходимо знать размерность признаков, выдаваемых базовой сетью (всем, кроме последнего слоя). Эта размерность является размером входа новой классификационной головы.
Распространённые размерности выхода базовой сети: ResNet-50 выдаёт 2048, EfficientNet-B0 — 1280, а ViT-B/16 — 768. Эти векторы признаков вычисляются с помощью глобального усредняющего объединения пространственных карт признаков, в результате чего для каждого изображения получается один вектор. Ваша заменяемая голова получает этот вектор на вход.
import torch
import torchvision.models as models
# Feature dimensions before the classification head
feature_dims = {
'resnet50': 2048,
'efficientnet_b0': 1280,
'efficientnet_b2': 1408,
'efficientnet_b4': 1792,
'vit_b_16': 768,
'vit_l_16': 1024,
}
# Verify for ResNet-50 by running a dummy forward pass without the head
resnet = models.resnet50(weights=None)
resnet.fc = torch.nn.Identity() # Remove FC layer
x = torch.randn(1, 3, 224, 224)
features = resnet(x)
print('ResNet-50 feature size:', features.shape) # (1, 2048)Проверка качества предварительно обученных весов
Можно быстро проверить корректность весов предварительно обученной модели, запустив её на хорошо известном тестовом изображении и проверив, совпадает ли наиболее вероятное предсказание с ожидаемой меткой. Эта проверка работоспособности подтверждает, что веса загружены правильно, а конвейер предварительной обработки настроен верно.
Помимо этой проверки, рекомендуется всегда сверяться с ожидаемым форматом входных данных в метаданных весов: размером входа (224×224 для большинства моделей), порядком каналов (RGB, а не BGR) и константами нормализации (средним и стандартным отклонением ImageNet). Использование неправильной нормализации — распространённая ошибка, приводящая к плохим результатам переноса обучения.
import torchvision.models as models
weights = models.ResNet50_Weights.IMAGENET1K_V1
print('Expected input size:', weights.meta['min_size']) # (1, 1)
print('Transforms:', weights.transforms())
# Includes Resize(232), CenterCrop(224), Normalize(mean, std)
# ImageNet normalisation constants
IMAGENET_MEAN = [0.485, 0.456, 0.406]
IMAGENET_STD = [0.229, 0.224, 0.225]
# Always use these EXACT values with ImageNet pre-trained modelsПодготовка к дообучению собственной задачи
Типичный рабочий процесс использования предварительно обученных моделей для пользовательских задач таков: (1) загрузить предварительно обученную модель с помощью weights=...IMAGENET1K..., (2) заменить последнюю классификационную голову новой nn.Linear, размер которой соответствует количеству Ваших классов, (3) при необходимости сначала заморозить веса базовой сети и (4) обучать модель с меньшей скоростью обучения, чем при обучении с нуля.
Новая классификационная голова начинает со случайными весами и должна обучиться на Ваших данных. Базовая сеть начинает с превосходными признаками и требует лишь небольших корректировок. Поэтому дифференциальные скорости обучения — очень низкая для базовой сети и более высокая для головы — часто улучшают скорость сходимости и итоговую точность.
import torchvision.models as models
import torch.nn as nn
# Example: Adapt ResNet-50 for 5-class flower classification
model = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)
# Replace the final FC layer
num_classes = 5
model.fc = nn.Linear(model.fc.in_features, num_classes)
# Differential learning rates
optimizer = torch.optim.Adam([
{'params': model.fc.parameters(), 'lr': 1e-3}, # High LR for new head
{'params': [p for n, p in model.named_parameters() if 'fc' not in n], 'lr': 1e-5} # Low LR for backbone
])Быстрая проверка
Проверьте, насколько хорошо Вы поняли работу с предварительно обученными моделями torchvision из этого урока.
Итоги урока
В этом уроке Вы узнали, что ResNet-50 использует пропускающие соединения для обучения очень глубоких сетей и выдаёт признаки размерности 2048; EfficientNet обеспечивает лучший компромисс между точностью и эффективностью благодаря составному масштабированию ширины, глубины и разрешения; а ViT применяет самовнимание трансформера к фрагментам изображений без свёрток. Далее мы изучим извлечение признаков — заморозим предварительно обученную базовую сеть и обучим только новую классификационную голову на пользовательском наборе данных.
Изучай Python с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 30
- Уроки
- 120
Часто задаваемые вопросы
Урок «Предобученные модели в torchvision: ResNet, EfficientNet и ViT» бесплатный?
Да — полный текст урока «Предобученные модели в torchvision: ResNet, EfficientNet и ViT» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Machine Learning Academy, подпишись на CoddyKit PRO. Курс Machine Learning Academy содержит 4 уроков всего.
Чему я научусь в уроке «Предобученные модели в torchvision: ResNet, EfficientNet и ViT»?
Вы загрузите ResNet-50, предварительно обученную на ImageNet, изучите её архитектуру и выполните вывод для нового изображения, чтобы проверить заранее выученные представления. Ты практикуешь Machine Learning Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Machine Learning Academy?
Предыдущий опыт не требуется. Machine Learning Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Предобученные модели в torchvision: ResNet, EfficientNet и ViT»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Machine Learning Academy?
Да. Каждый урок Machine Learning Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Предобученные модели в torchvision: ResNet, EfficientNet и ViT
- Извлечение признаков: заморозка базовой сети
- Дообучение: разморозка и низкая скорость обучения
- Адаптация к предметной области: медицинские изображения при малом числе меток