ResNet50 в задачах компьютерного зрения: обучение и настройка

Раздел: Машинное обучение и ИИ -> Глубокое обучение

ResNet50 - популярная архитектура для классификации изображений. Перенос обучения позволяет эффективно применять ее на новых наборах. Рассмотрим основные подходы.

Основной подход: тонкая настройка предобученной ResNet50

При решении задачи классификации изображений на небольшом наборе данных эффективно использовать модель ResNet50, предобученную на ImageNet. Основной метод - тонкая настройка (fine-tuning) нескольких верхних слоев после замены классификатора. Это позволяет адаптировать признаки к новому набору без потери ранее изученных.

Пример реализации на Keras:


import tensorflow as tf
from tensorflow.keras.applications import ResNet50
from tensorflow.keras.layers import GlobalAveragePooling2D, Dense
from tensorflow.keras.models import Model

base_model = ResNet50(include_top=False, weights='imagenet', input_shape=(224,224,3))
base_model.trainable = False

x = GlobalAveragePooling2D()(base_model.output)
x = Dense(256, activation='relu')(x)
output = Dense(num_classes, activation='softmax')(x)
model = Model(inputs=base_model.input, outputs=output)
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

Torch python (фреймворк pytorch)

После этого модель обучается на своих данных. Затем можно разморозить несколько верхних слоев и продолжить обучение с меньшей скоростью.

Типичные ошибки: неправильный размер входных изображений (не 224x224), отсутствие нормализации (требуется preprocess_input из resnet50). При разморозке слоев возможна потеря предыдущего обучения, если скорость обучения слишком велика.

Как использовать ResNet50 как экстрактор признаков?

Если объем данных очень мал, целесообразно заморозить всю базовую модель и обучить только новый классификатор. Веса ResNet50 не изменяются. Этот вариант подходит, когда новый набор похож на ImageNet.


base_model.trainable = False
model.fit(...)

библиотека torch python (библиотека pytorch в python)

Проблема: если новый набор сильно отличается, признаки могут быть нерелевантными. В таком случае лучше применить тонкую настройку.

Как улучшить точность, разморозив верхние слои ResNet50?

После начального обучения с замороженной базой, разморозьте последние N слоев (например, 20) и обучите с низкой скоростью (например, 1e-5).


base_model.trainable = True
for layer in base_model.layers[:-20]:
    layer.trainable = False
model.compile(optimizer=tf.keras.optimizers.Adam(1e-5), loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(...)

классификация изображений python с использованием resnet50 (классификация изображений с resnet50)

Ошибка: разморозка слишком большого числа слоев может привести к переобучению. Следует начинать с небольшого числа слоев и постепенно увеличивать.

Можно ли обучить ResNet50 с нуля на собственном наборе данных?

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


model = ResNet50(weights=None, include_top=True, classes=num_classes)

Главная проблема - отсутствие предобученных весов, что требует намного больше данных и времени. Градиенты могут быстро затухать или взрываться.

Расширенные примеры реализации ResNet50

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

Пример

import tensorflow as tf
from tensorflow.keras.applications import ResNet50
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.layers import GlobalAveragePooling2D, Dense, Dropout
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.applications.resnet50 import preprocess_input

# Параметры
img_size = (224, 224)
batch_size = 32
num_classes = 10
epochs_first = 10
epochs_finetune = 20

# Аугментация (только для обучения)
train_datagen = ImageDataGenerator(
    preprocessing_function=preprocess_input,
    rotation_range=30,
    zoom_range=0.2,
    horizontal_flip=True,
    validation_split=0.2
)

train_generator = train_datagen.flow_from_directory(
    'data/train',
    target_size=img_size,
    batch_size=batch_size,
    class_mode='categorical',
    subset='training'
)
val_generator = train_datagen.flow_from_directory(
    'data/train',
    target_size=img_size,
    batch_size=batch_size,
    class_mode='categorical',
    subset='validation'
)

# Базовая модель
base_model = ResNet50(include_top=False, weights='imagenet', input_shape=(224,224,3))
base_model.trainable = False

x = GlobalAveragePooling2D()(base_model.output)
x = Dense(256, activation='relu')(x)
x = Dropout(0.5)(x)
output = Dense(num_classes, activation='softmax')(x)
model = Model(inputs=base_model.input, outputs=output)

model.compile(optimizer=Adam(learning_rate=0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# Первый этап: обучение классификатора
history = model.fit(
    train_generator,
    validation_data=val_generator,
    epochs=epochs_first
)

# Второй этап: тонкая настройка
base_model.trainable = True
for layer in base_model.layers[:-30]:
    layer.trainable = False

model.compile(optimizer=Adam(learning_rate=1e-5),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

history_fine = model.fit(
    train_generator,
    validation_data=val_generator,
    epochs=epochs_finetune
)

# Оценка на тестовом наборе
test_datagen = ImageDataGenerator(preprocessing_function=preprocess_input)
test_generator = test_datagen.flow_from_directory(
    'data/test',
    target_size=img_size,
    batch_size=batch_size,
    class_mode='categorical',
    shuffle=False
)

loss, acc = model.evaluate(test_generator)
print(f'Test Accuracy: {acc:.4f}')
Found 800 images belonging to 10 classes.
Found 200 images belonging to 10 classes.
Epoch 1/10 ...
...
Test Accuracy: 0.9350

Второй пример на PyTorch демонстрирует загрузку предобученной модели, замену классификатора и fine-tuning.

Пример

import torch
import torch.nn as nn
from torchvision import datasets, transforms, models
from torch.utils.data import DataLoader

# Трансформации
train_transform = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
train_dataset = datasets.ImageFolder('data/train', transform=train_transform)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)

# Модель
model = models.resnet50(pretrained=True)
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, num_classes)

# Заморозка слоев
for param in model.parameters():
    param.requires_grad = False
for param in model.fc.parameters():
    param.requires_grad = True

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.fc.parameters(), lr=0.001)

# Обучение
for epoch in range(10):
    for inputs, labels in train_loader:
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
print('Training complete')
Training complete
Loss: 0.2356

Классификация изображений с ResNet50 - comments

En
классификация изображений python с использованием resnet50 (python)