Учебник по PyTorch CNN: Создание и обучение сверточных нейронных сетей на Python

Сверточные нейронные сети (CNN) являются основой современного компьютерного зрения, позволяя создавать приложения, такие как распознавание изображений, обнаружение лиц и автономные автомобили. Эти сети разработаны для автоматического извлечения узоров и особенностей из изображений, что делает их более мощными, чем традиционные методы машинного обучения для визуальных задач.

В этом учебнике мы реализуем CNN с использованием PyTorch, фреймворка глубокого обучения, который одновременно удобен для пользователей и высокоэффективен для исследований и производственных приложений.

Предварительные требования: Глубокое обучение и PyTorch

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

Глубокое обучение – это подмножество машинного обучения, где основная структура модели представляет собой сеть входов, скрытых слоев и выходов. Такая сеть может иметь один или несколько скрытых слоев. Исходная идея глубокого обучения заключалась в создании моделей, вдохновленных тем, как учится человеческий мозг: через взаимосвязанные клетки, называемые нейронами. Поэтому мы продолжаем называть модели глубокого обучения “нейронными” сетями. Эти сложные структуры моделей требуют гораздо больше данных для обучения, чем другие модели обучения с учителем, чтобы извлечь узоры из неструктурированных данных. Обычно речь идет о как минимум сотнях тысяч данных.

В то время как существует несколько фреймворков и пакетов для реализации алгоритмов глубокого обучения, мы сосредоточимся на PyTorch, одном из самых популярных и хорошо поддерживаемых фреймворков. Помимо использования инженерами глубокого обучения в индустрии, PyTorch является предпочтительным инструментом среди исследователей. Многие научные статьи по глубокому обучению публикуются с использованием PyTorch. Он разработан таким образом, чтобы быть интуитивно понятным и удобным для пользователя, имея много общего с библиотекой Python NumPy.

Если вам нужно введение в эти концепции, рассмотрите возможность записи на курс Глубокое обучение с PyTorch уже сегодня.

Что такое сверточная нейронная сеть (CNN)?

Сверточные нейронные сети, обычно называемые CNN или ConvNet, представляют собой конкретный вид глубоких нейронных сетей, хорошо подходящий для задач компьютерного зрения. Изобретение CNN уходит в 1980-е годы. Однако они стали широко распространены в 2010-х годах, в результате прорывов в вычислениях, которые произошли благодаря применению графических процессоров (GPU). Действительно, быстрая популяризация CNN помогла области нейронных сетей вернуть себе престиж, приведя к так называемой “третьей волне нейронных сетей”, в которой мы все еще находимся.

CNN специально вдохновлены биологической зрительной корой. Кора имеет небольшие области клеток, которые чувствительны к конкретным областям зрительного поля. Эта идея была расширена захватывающим экспериментом Хубеля и Визеля в 1962 году.

Сверточные нейронные сети пытаются воссоздать эту особенность, создавая сложные нейронные сети, состоящие из различных слоев, специфичных для задачи. CNN называются “прямыми” потому, что информация проходит прямо через модель. Нет обратных связей, при которых выводы модели обратно подаются на вход, в отличие от других моделей, использующих техники, такие как обратное распространение ошибки.

В частности, CNN обычно состоит из следующих слоев:

Слой свертки

Это первый строительный блок CNN. Как подразумевает название, основная математическая операция, выполняемая здесь, называется сверткой, которая представляет собой применение функции скользящего окна к матрице пикселей, представляющей изображение. Функция скольжения, применяемая к матрице, называется ядром или фильтром. В слое свертки применяется несколько фильтров одинакового размера, и каждый фильтр используется для распознавания определенного узора изображения, такого как изгиб цифр, края, общая форма цифр и другое. 

Функция активации

Обычно после каждой операции свертки применяется функция активации ReLU. Эта функция помогает сети изучать нелинейные взаимосвязи между признаками на изображении, делая сеть более надежной для идентификации различных узоров. Она также помогает уменьшить проблемы с затухающим градиентом. 

Слой пулинга

Цель слоя подвыборки заключается в извлечении наиболее значимых признаков из свёрнутой матрицы. Это достигается путём применения некоторых агрегирующих операций, которые уменьшают размерность карты признаков (свёрнутой матрицы), тем самым уменьшая объем памяти, используемой при обучении сети. Подвыборка также важна для снижения переобучения.

Полносвязные слои

Эти слои находятся в последнем слое свёрточной нейронной сети, и их входы соответствуют развернутой одномерной матрице, созданной последним слоем подвыборки. К ним применяются функции активации ReLU для введения нелинейности.

Архитектура свёрточной нейронной сети. Источник: DataCamp

Вы можете прочитать более подробное объяснение математики, лежащей в основе CNN, в нашем учебном пособии, Свёрточные нейронные сети на Python.

Почему использовать CNN для классификации изображений?

Сверточные нейронные сети стали одним из наиболее влиятельных инноваций в области компьютерного зрения. Они показали гораздо лучшие результаты, чем традиционные модели машинного обучения, такие как SVMs и деревья принятия решений, и продемонстрировали передовые результаты.

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

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

  • классификация изображений, обнаружение объектов, сегментация, распознавание лиц;
  • автомобили с функцией автопилота, использующие системы компьютерного зрения на основе CNN;
  • классификация кристаллической структуры с использованием сверточной нейронной сети;
  • системы видеонаблюдения.

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

Реализация CNN с помощью PyTorch

Теперь, когда вы ознакомились с теорией CNN, мы готовы приступить к делу. В этом разделе мы создадим и обучим простую CNN с помощью PyTorch. Наша цель – построить модель для классификации цифр на изображениях. Для обучения и тестирования нашей модели мы будем использовать известный набор данных MNIST, содержащий 70 000 изображений в оттенках серого размером 28×28 пикселей с рукописными цифрами.

1. Импорт необходимых библиотек

Ниже вы можете найти библиотеки, которые мы будем использовать в этом учебнике. В основном мы воспользуемся PyTorch для создания нашей CNN, а также модулем компьютерного зрения PyTorch torchvision, чтобы загрузить и загрузить набор данных MNIST. Наконец, мы также воспользуемся torchmetrics для оценки производительности нашей модели.

import numpy as np import pandas as pd import matplotlib.pyplot as plt import torch from torch import optim from torch import nn from torch.utils.data import DataLoader from tqdm import tqdm # !pip install torchvision import torchvision import torch.nn.functional as F import torchvision.datasets as datasets import torchvision.transforms as transforms # !pip install torchmetrics import torchmetrics

2. Загрузка и предварительная обработка набора данных

PyTorch также поставляется с обширной экосистемой инструментов и расширений, включая torchvision, модуль для компьютерного зрения. Torchvision включает несколько наборов данных изображений, которые могут быть использованы для обучения и тестирования нейронных сетей. В нашем учебнике мы будем использовать набор данных MNIST. 

Сначала мы загрузим и преобразуем набор данных MNIST в тензор, основную структуру данных в PyTorch, аналогичную массивам NumPy, но с возможностями ускорения на GPU.

Затем мы также будем использовать DataLoader для обработки пакетирования и перемешивания как для обучающего, так и для тестовых наборов данных. Объект DataLoader PyTorch может быть создан из Dataset для загрузки данных, разделения их на пакеты и выполнения преобразований данных при необходимости. Затем он возвращает готовый к обучению образец данных. В приведенном ниже коде мы загружаем данные и сохраняем их в DataLoaders с размером пакета из 60 изображений:

batch_size = 60 train_dataset = datasets.MNIST(root="dataset/", download=True, train=True, transform=transforms.ToTensor()) train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True) test_dataset = datasets.MNIST(root="dataset/", download=True, train=False, transform=transforms.ToTensor()) test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)

По желанию, набор данных для обучения может быть дополнительно разделен на две части: обучающую и валидационную. Валидация – это техника, используемая в глубоком обучении для оценки производительности модели во время обучения. Она помогает выявить потенциальное переобучение и недообучение наших моделей, и особенно полезна для оптимизации гиперпараметров. Однако для простоты мы не будем использовать валидацию в этом учебнике. Если вы хотите узнать больше о валидации, вы можете ознакомиться с полным объяснением в нашем Курсе по глубокому обучению с PyTorch.

Теперь, когда у нас есть наши данные, давайте посмотрим, как выглядит случайный пакет цифр:

def imshow(img): npimg = img.numpy() plt.imshow(np.transpose(npimg, (1, 2, 0))) plt.show() # получаем некоторые случайные обучающие изображения dataiter = iter(dataloader_train) images, labels = next(dataiter) labels # показываем изображения imshow(torchvision.utils.make_grid(images))

3. Определение архитектуры CNN

Для решения задачи классификации мы будем использовать класс nn.Module, строительный блок PyTorch для интуитивного создания сложных архитектур нейронных сетей.

В приведенном ниже коде мы создаем класс с именем CNN, который наследует свойства класса nn.Module. Класс CNN будет являться чертежом CNN с двумя сверточными слоями, за которыми следует полносвязанный слой.

В PyTorch мы используем nn.Conv2d для определения сверточного слоя. Мы передаем ему количество входных и выходных карт признаков. Мы также устанавливаем некоторые параметры для работы сверточного слоя, включая размер ядра или фильтра и заполнение.

Затем мы добавляем слой максимальной пулинга с помощью nn.MaxPool2d. В нем мы перемещаем неперекрывающееся окно по выводу предыдущего сверточного слоя. На каждой позиции мы выбираем максимальное значение из окна для передачи вперед. Эта операция уменьшает пространственные размеры карт признаков, уменьшая количество параметров и вычислительную сложность в сети. Наконец, мы добавляем полносвязанный линейный слой.

Функция forward() определяет, как различные слои соединены, добавляя несколько активационных функций ReLU после каждого сверточного слоя.

class CNN(nn.Module): def __init__(self, in_channels, num_classes): """ Building blocks of convolutional neural network. Parameters: * in_channels: Number of channels in the input image (for grayscale images, 1) * num_classes: Number of classes to predict. In our problem, 10 (i.e digits from 0 to 9). """ super(CNN, self).__init__() # 1-й сверточный слой self.conv1 = nn.Conv2d(in_channels=in_channels, out_channels=8, kernel_size=3, padding=1) # Слой максимального объединения self.pool = nn.MaxPool2d(kernel_size=2, stride=2) # 2-й сверточный слой self.conv2 = nn.Conv2d(in_channels=8, out_channels=16, kernel_size=3, padding=1) # Полносвязанный слой self.fc1 = nn.Linear(16 * 7 * 7, num_classes) def forward(self, x): """ Define the forward pass of the neural network. Parameters: x: Input tensor. Returns: torch.Tensor The output tensor after passing through the network. """ x = F.relu(self.conv1(x)) # Применить первую свертку и активацию ReLU x = self.pool(x) # Применить максимальное объединение x = F.relu(self.conv2(x)) # Применить вторую свертку и активацию ReLU x = self.pool(x) # Применить максимальное объединение x = x.reshape(x.shape[0], -1) # Выровнять тензор x = self.fc1(x) # Применить полносвязанный слой return x x = x.reshape(x.shape[0], -1) # Выровнять тензор x = self.fc1(x) # Применить полносвязанный слой return x

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

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

device = "cuda" if torch.cuda.is_available() else "cpu" model = CNN(in_channels=1, num_classes=10).to(device) print(model) >>> CNN( (conv1): Conv2d(1, 8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (conv2): Conv2d(8, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (fc1): Linear(in_features=784, out_features=10, bias=True) )

4. Обучение модели CNN

Теперь, когда у нас есть наша модель, пришло время её обучить. Для этого сначала нам нужно определить, как мы будем измерять производительность модели. Поскольку мы имеем дело с задачей классификации с несколькими классами, мы будем использовать функцию потерь cross-entropy, доступную в PyTorch как nn.CrossEntropyLoss. Мы также будем использовать оптимизатор Adam, один из наиболее популярных алгоритмов оптимизации.

# Определите функцию потерь criterion = nn.CrossEntropyLoss() # Определите оптимизатор optimizer = optim.Adam(model.parameters(), lr=0.001)

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

num_epochs=10 for epoch in range(num_epochs): # Итерация по обучающим пакетам print(f"Epoch [{epoch + 1}/{num_epochs}]") for batch_index, (data, targets) in enumerate(tqdm(dataloader_train)): data = data.to(device) targets = targets.to(device) scores = model(data) loss = criterion(scores, targets) optimizer.zero_grad() loss.backward() optimizer.step()
Epoch [1/10] 100%|██████████| 1000/1000 [00:13<00:00, 72.94it/s] Epoch [2/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.27it/s] Epoch [3/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.16it/s] Epoch [4/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.00it/s] Epoch [5/10] 100%|██████████| 1000/1000 [00:13<00:00, 75.69it/s] Epoch [6/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.24it/s] Epoch [7/10] 100%|██████████| 1000/1000 [00:12<00:00, 78.23it/s] Epoch [8/10] 100%|██████████| 1000/1000 [00:12<00:00, 78.16it/s] Epoch [9/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.96it/s] Epoch [10/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.93it/s]

5. Оценка модели

После обучения модели мы можем оценить её производительность на тестовом наборе данных. Мы будем использовать метрику точности, популярную метрику для задач классификации. Точность измеряет долю правильно классифицированных случаев от общего количества объектов в наборе данных. Она вычисляется путем деления количества правильных предсказаний на общее количество предсказаний, сделанных моделью.

Сначала мы настраиваем метрику точности из torchmetrics. Затем мы используем метод .eval модели, чтобы перевести модель в режим оценки, потому что некоторые слои в моделях PyTorch ведут себя по-разному на этапах обучения и тестирования. Мы также добавляем контекст Python с torch.no_grad, указывая, что не будем выполнять вычисление градиента.

Затем мы итерируемся по примерам теста без вычисления градиента. Для каждой тестовой партии мы получаем выводы модели, выбираем наиболее вероятный класс и передаем его в функцию точности вместе с метками. Наконец, мы вычисляем метрики и выводим результаты. Мы получили оценку точности 0.98, что означает, что наша модель правильно классифицировала 98% цифр. Неплохо!

# Настройка метрики точности для многоклассовой классификации acc = Accuracy(task="multiclass",num_classes=10) # Итерация по партиям набора данных model.eval() with torch.no_grad(): for images, labels in dataloader_test: # Получение предсказанных вероятностей для тестовой партии данных outputs = model(images) _, preds = torch.max(outputs, 1) acc(preds, labels) precision(preds, labels) recall(preds, labels) # Вычисление общей точности теста test_accuracy = acc.compute() print(f"Test accuracy: {test_accuracy}") >>> Test accuracy: 0.9857000112533569

Вы также можете использовать другие популярные метрики классификации, включая полноту и точность. Мы расскажем вам об этих метриках с практическими примерами в нашем Курсе по промежуточному глубокому обучению с PyTorch.

Улучшение производительности модели

Хотя наша модель CNN достигает высокой производительности, существуют несколько стратегий, которые мы можем использовать для дальнейшего улучшения ее точности, надежности и обобщения на новые данные.

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

Техники аугментации данных

Аугментация данных – это техника, используемая для улучшения точности нашей модели путем случайного создания новых обучающих данных. Например, во время загрузки можно применить преобразования к обучающим изображениям, такие как изменение размера, горизонтальное или вертикальное отражение, случайное вращение и т. д. Таким образом, можно создавать аугментированные изображения и присваивать им тот же ярлык, что и оригинальному изображению, тем самым увеличивая размер обучающего набора.

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

Однако важно быть осторожными с аугментацией данных, потому что иногда она может нанести вред процессу обучения. Например, в нашей задаче, если мы применим вертикальное отражение к цифре “6”, она будет похожа на цифру “9”. Передача ее модели с ярлыком “6” сбивает модель с толку и затрудняет обучение. Эти примеры показывают, что иногда конкретные аугментации могут повлиять на ярлык.

Настройка гиперпараметров

Другая стратегия для улучшения производительности нашей модели – изменить значения гиперпараметров, участвующих в различных слоях модели. Эта настройка гиперпараметров требует глубокого понимания математики нейронных сетей и значения различных гиперпараметров.

Например, вы можете настраивать свои слои CNN, изменяя размер фильтров или увеличивая отступ. Вы также можете установить другое значение для начальных весов нейронов.

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

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

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

Вы можете узнать больше о настройке гиперпараметров в нашем Курсе по введению в глубокое обучение с помощью PyTorch.

Использование предварительно обученных моделей

Обучение моделей глубокого обучения с нуля – это длительный и трудоемкий процесс, который typично требует большого объема обучающих данных. Вместо этого мы часто можем использовать предварительно обученные модели, то есть модели, которые уже были обучены на некоторой задаче.

Иногда мы можем напрямую использовать предварительно обученную модель, если она уже способна решить задачу, которая нас интересует. В других случаях нам может потребоваться настроить предварительно обученную модель под новую задачу. Это известно как перенос обучения.

Использование предварительно обученных моделей в PyTorch довольно просто. Torchvision предоставляет коллекцию предварительно обученных моделей для различных задач, связанных с изображениями. Эти модели предварительно обучены на крупных наборах данных изображений и легко доступны. Ознакомьтесь с нашим Курсом по Глубокому Обучению для изображений с использованием PyTorch, чтобы узнать все, что вам нужно о них.

Развертывание модели CNN

Обучив свою высокоточную классификационную модель в PyTorch, вы теперь можете сохранить модель и ее предварительно обученные веса для будущего использования и совместного использования с вашей командой, убедившись, что они могут без проблем ее загрузить.

Для сохранения модели мы можем использовать torch.save. Обычным расширением файла для моделей torch является либо pt, либо pth. Чтобы сохранить веса модели, мы передаем model.state_dict в torch.save, указывая имя выходного файла, например, MulticlassCNN.pth.

Чтобы загрузить сохраненную модель, мы инициализируем новую модель с той же архитектурой. Затем мы используем метод загрузки состояния dict вместе с torch.load для загрузки параметров в новую модель.

# Сохранение модели torch.save(model.state_dict(), 'MulticlassCNN.pth') # Создание новой модели loaded_model = CNN(in_channels=1, num_classes=10) # Загрузка сохраненной модели loaded_model.load_state_dict(torch.load('MulticlassCNN.pth')) print(loaded_model) CNN( (conv1): Conv2d(1, 8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (conv2): Conv2d(8, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (fc1): Linear(in_features=784, out_features=10, bias=True) )

Заключение

Мы рассмотрели полный обзор CNN, предоставив детали о каждом слое архитектуры CNN. Кроме того, мы предоставили руководство по реализации CNN в PyTorch, охватывая основные этапы, от загрузки данных и проектирования модели до обучения и оценки модели. Наконец, мы также проанализировали несколько стратегий для улучшения производительности нашей модели. Мы применили все эти навыки к реальной ситуации, связанной с задачей многоклассовой классификации. 

Есть многое, что можно изучить о глубоком обучении, возможно, одном из самых захватывающих и требовательных направлений в области ИИ. К счастью, DataCamp здесь, чтобы помочь. Ознакомьтесь с нашими специализированными материалами и курсами и станьте экспертом по нейронным сетям:

Source:
https://www.datacamp.com/tutorial/pytorch-cnn-tutorial