Введение
Сверточные нейронные сети (CNN) стали основой для обработки изображений и компьютерного зрения. Однако их обучение требует тщательной настройки архитектуры и гиперпараметров, что может быть сложной задачей, особенно при работе с большими наборами данных. В этой статье мы подробно рассмотрим несколько методов оптимизации, используемых для повышения производительности CNN на примере набора данных CIFAR-10, и покажем, как различные техники влияют на потери и точность модели. Мы протестируем аугментацию данных, различные архитектурные решения, такие как Batch Normalization и Dropout, и адаптивные подходы к обучению.
Набор данных CIFAR-10 и предобработка
CIFAR-10 — это один из самых популярных наборов данных для обучения моделей компьютерного зрения. Он содержит 60,000 изображений размером 32×32 пикселя, разделенных на 10 классов, что делает его отличным кандидатом для тестирования эффективности различных методов оптимизации.
import torch from torch.utils.data import DataLoader from torchvision import datasets, transforms # Определение преобразований для набора данных CIFAR-10 transform_cifar = transforms.Compose([ transforms.RandomHorizontalFlip(), transforms.RandomCrop(32, padding=4), transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ]) # Загрузка набора данных cifar10_train = datasets.CIFAR10(root='data', train=True, transform=transform_cifar, download=True) cifar10_loader_train = DataLoader(cifar10_train, batch_size=32, shuffle=True)
Для эксперимента мы применили несколько различных преобразований, включая аугментацию с предобработкой на основе наборов данных Fashion-MNIST и SVHN.
# Загрузка каждого набора данных с предобработкой cifar10_loader = DataLoader(cifar10_train, batch_size=32, shuffle=True) fmnist_loader = DataLoader(fmnist_train, batch_size=32, shuffle=True) svhn_loader = DataLoader(svhn_train, batch_size=32, shuffle=True) # Добавляем трансформацию для повторения канала в Fashion-MNIST transform_fmnist_rgb = transforms.Compose([ transform_fmnist, # Текущие трансформации для FMNIST Lambda(lambda x: x.repeat(3, 1, 1)) # Повторяем канал 3 раза ]) # Загрузка данных Fashion-MNIST с трансформацией повторения каналов fmnist_cifar_transform = DataLoader( datasets.FashionMNIST(root='data', train=True, transform=transform_fmnist_rgb, download=True), batch_size=32, shuffle=True ) svhn_loader = DataLoader(svhn_train, batch_size=32, shuffle=True) # Загрузка CIFAR-10 с альтернативной предобработкой cifar10_fmnist_transform = DataLoader(datasets.CIFAR10(root='data', train=True, transform=transform_fmnist, download=True), batch_size=32, shuffle=True) cifar10_svhn_transform = DataLoader(datasets.CIFAR10(root='data', train=True, transform=transform_svhn, download=True), batch_size=32, shuffle=True) # Загрузка Fashion-MNIST с альтернативной предобработкой #fmnist_cifar_transform = DataLoader(datasets.FashionMNIST(root='data', train=True, transform=transform_cifar, download=True), batch_size=32, shuffle=True) fmnist_svhn_transform = DataLoader(datasets.FashionMNIST(root='data', train=True, transform=transform_svhn, download=True), batch_size=32, shuffle=True) # Загрузка SVHN с альтернативной предобработкой svhn_cifar_transform = DataLoader(datasets.SVHN(root='data', split='train', transform=transform_cifar, download=True), batch_size=32, shuffle=True) svhn_fmnist_transform = DataLoader(datasets.SVHN(root='data', split='train', transform=transform_fmnist, download=True), batch_size=32, shuffle=True)
Эксперимент 1: Влияние предобработки данных
Различные методы предобработки могут влиять на то, какие особенности изображений извлекает модель. Мы протестировали несколько вариантов, включая стандартную предобработку CIFAR-10, а также трансформации, адаптированные из других наборов данных:
-
Оригинальная предобработка CIFAR-10
-
Предобработка, основанная на Fashion-MNIST
-
Предобработка на основе SVHN
Обучение CIFAR-10 с собственной предобработкой: |
||
Эпоха 1 |
Потери: 1.6969 |
Точность: 37.90% |
… |
… |
… |
Эпоха 5 |
Потери: 1.1355 |
Точность: 59.95% |
Обучение CIFAR-10 с предобработкой Fashion-MNIST |
||
Эпоха 1 |
Потери: 1.4984 |
Точность: 46.54% |
… |
… |
… |
Эпоха 5 |
Потери: 0.9440 |
Точность: 66.95% |
Обучение CIFAR-10 с предобработкой SVHN |
||
Эпоха 1 |
Потери: 1.6444 |
Точность: 39.83% |
… |
… |
… |
Эпоха 5 |
Потери: 1.0892 |
Точность: 61.49% |
Результаты: Предобработка, основанная на Fashion-MNIST, продемонстрировала лучшие результаты, обеспечив потерю в 0.9440 и точность 66.95%. Это позволяет предположить, что некоторые преобразования могут быть лучше адаптированы для задач классификации изображений, несмотря на различия в данных.
Эксперимент 2: Оптимизация архитектуры — выбор фильтров и пуллинга
Следующим шагом было изучение того, как количество фильтров и метод пуллинга влияет на результаты. Мы тестировали три варианта с разным количеством фильтров (16, 32 и 64), а также несколько типов пуллинга.
Пример конфигурации фильтров:
import torch.nn as nn class CNNVariant1(nn.Module): def __init__(self): super(CNNVariant1, self).__init__() self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1) self.pool = nn.MaxPool2d(2, 2) self.fc1 = nn.Linear(16 * 16 * 16, 10) def forward(self, x): x = self.pool(torch.relu(self.conv1(x))) x = x.view(-1, 16 * 16 * 16) x = self.fc1(x) return x
Результаты: Среднее количество фильтров (32 фильтра) и Max Pooling 2×2 оказались оптимальными, обеспечив 57.33% точности и потерю в 1.2018. Использование большого количества фильтров привело к переобучению, а использование Average Pooling показало менее хорошие результаты.
Эксперимент 3: Batch Normalization и Dropout
Batch Normalization и Dropout — это техники, которые помогают улучшить стабильность и обобщающую способность модели. Мы тестировали Batch Normalization после каждого сверточного слоя и только в начале и в конце, а также различные значения Dropout.
Пример использования Batch Normalization и Dropout:
class CNNBatchNorm(nn.Module): def __init__(self): super(CNNBatchNorm, self).__init__() self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1) self.bn1 = nn.BatchNorm2d(32) self.dropout = nn.Dropout(0.2) self.fc1 = nn.Linear(32 * 16 * 16, 10) def forward(self, x): x = self.dropout(self.bn1(torch.relu(self.conv1(x)))) x = x.view(-1, 32 * 16 * 16) x = self.fc1(x) return x
Результаты: Batch Normalization после каждого слоя обеспечил лучшую стабильность обучения и точность 60.25%. Умеренный Dropout (0.2) оказался наиболее эффективным и достиг 63.79% точности, тогда как сильный Dropout (0.5) привел к ухудшению результатов.
Эксперимент 4: Адаптивные стратегии темпа обучения и динамический размер пакета
Использование адаптивного темпа обучения и динамического изменения размера пакета — это современные подходы, которые помогают улучшить обучение модели.
Cyclic Learning Rate:
from torch.optim.lr_scheduler import CyclicLR optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9) scheduler = CyclicLR(optimizer, base_lr=0.001, max_lr=0.01, step_size_up=5)
Результаты: Оптимизатор Adam показал лучшие результаты по сравнению с Cyclic Learning Rate, с потерей 1.2331 и точностью 57.42%. Dynamic Batch Size и Gradient Accumulation продемонстрировали схожие результаты, но Gradient Accumulation позволил несколько улучшить точность при ограниченных вычислительных ресурсах.
Эксперимент 5: Progressive Layer Growth и Pruning
Мы протестировали Progressive Layer Growth и Random Filter Pruning для регулировки сложности модели.
Пример Progressive Layer Growth:
class SimpleCNN(nn.Module): def __init__(self): super(SimpleCNN, self).__init__() self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1) self.fc1 = nn.Linear(16 * 16 * 16, 10) # После нескольких эпох добавляем слои class ExtendedCNN(SimpleCNN): def __init__(self): super(ExtendedCNN, self).__init__() self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1) self.fc2 = nn.Linear(32 * 8 * 8, 10)
Результаты: Progressive Layer Growth улучшил точность модели до 60.87%, а Random Filter Pruning обеспечил точность в 64.80%, что доказывает его эффективность для предотвращения переобучения.
Заключение
Результаты экспериментов подтверждают, что оптимизация архитектуры и гиперпараметров CNN требует комплексного подхода, включающего различные методы.
-
Наилучшие результаты были достигнуты при использовании предобработки на основе Fashion-MNIST, Batch Normalization после каждого слоя, Dropout с вероятностью 0.2 и оптимизатора Adam. Эти методы в совокупности обеспечили улучшение точности, минимизацию потерь и повышение стабильности модели.
-
Адаптивные стратегии темпа обучения и размера пакета также показали хорошие результаты, особенно Gradient Accumulation для ограниченных вычислительных ресурсов.
-
Progressive Layer Growth и Pruning оказались полезными для регулировки сложности модели, помогая избежать переобучения и улучшить обобщающую способность.
Эти методы могут быть полезны при обучении сверточных нейронных сетей для более сложных задач и наборов данных. Надеемся, что эта статья поможет вам глубже понять процесс оптимизации CNN и применять его на практике.
Спасибо за внимание!
P.S. Пишите в комментариях, какие методы вы используете для улучшения моделей, и делитесь своими результатами!
ссылка на оригинал статьи https://habr.com/ru/articles/857620/
Добавить комментарий