Данная статья – это основа для практики, благодаря которой вы сможете построить рабочую нейросеть с нуля. Большая часть математических концепций и научных решений мы пропустим.
Вы научитесь программировать и создавать нейронную сеть прямого распространения (feedforward neural networks FNN или FF) уже сегодня при помощи PyTorch. Здесь изложена кодовая база jupyter для FNN.
FNN: https://github.com/yhuag/neural-network-lab
Отличная статья для старта: Шпаргалка по разновидностям нейронных сетей
Приступим к работе
1. Убедитесь, что на вашем компьютере установлены PyTorch и Python 3.6;
2. Проверьте корректность установки Python, используя данную команду в консоли:
1 |
python -V |
На выходе должна быть версия Python 3.6.3 или выше.
3. Откройте хранилище (папку) и создайте свой первый файл нейросети:
1 2 3 |
mkdir fnn-tuto cd fnn-tuto touch fnn.py |
Есть вопросы по Python?
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Паблик VK
Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!
Начинаем писать код
Все изложенные коды должны быть написаны в файле fnn.py
Импорт PyTorch
1 2 3 4 5 |
import torch import torch.nn as nn import torchvision.datasets as dsets import torchvision.transforms as transforms from torch.autograd import Variable |
Так мы загрузим PyTorch в скрипт. Отлично! Мы уже на полпути.
Инициализация Гипер-параметров
Гипер-параметры – это мощные аргументы с предварительной настройкой и не будут обновляться в ходе изучения нейронной сети.
1 2 3 4 5 6 |
input_size = 784 # Размеры изображения = 28 x 28 = 784 hidden_size = 500 # Количество узлов на скрытом слое num_classes = 10 # Число классов на выходе. В этом случае от 0 до 9 num_epochs = 5 # Количество тренировок всего набора данных batch_size = 100 # Размер входных данных для одной итерации learning_rate = 0.001 # Скорость конвергенции |
Загрузка набора данных MNIST
MNIST – это огромная база данных с тоннами прописанных чисел (т.е. от 0 до 9), которая направлена на обработку изображений.
1 2 3 4 5 6 7 8 9 10 11 12 |
train_dataset = dsets.MNIST( root='./data', train=True, transform=transforms.ToTensor(), download=True ) test_dataset = dsets.MNIST( root='./data', train=False, transform=transforms.ToTensor() ) |
Загрузка набора данных. После загрузки MNIST, мы загружаем набор данных в наш код:
1 2 3 4 5 6 7 8 9 10 11 |
train_loader = torch.utils.data.DataLoader( dataset=train_dataset, batch_size=batch_size, shuffle=True ) test_loader = torch.utils.data.DataLoader( dataset=test_dataset, batch_size=batch_size, shuffle=False ) |
Обратите внимание: мы перемешиваем процесс загрузки train_dataset, чтобы процесс обучения не зависел от порядка данных, однако порядок test_loader остается неизменным, чтобы понять, когда мы можем обработать неопределенный порядок входов.
Создаем нейронную сеть Feedforward
Сейчас наши наборы данных готовы. Можно приступить к созданию нейронной сети. Можете взглянуть на изображение концепции работы нейросети внизу:
Структура модели нейросети
Нейронная сеть включает в себя два полностью соединенных слоя (т.е. fc1 и fc2) и нелинейный слой ReLU между ними. Как правило, мы называем эту структуру 1-скрытый слой нейросети, отбрасывая слой вывода (fc2).
Запустив следующий код, указанные изображения (х) могут пройти через нейронную сеть и сгенерировать вывод (out), показывая, как именно соответствие принадлежит каждому из 10 классов. Например, изображение кошки соответствует изображению собаки на 0.8, в то врем я как соответствие изображению самолета – 0.3.
1 2 3 4 5 6 7 8 9 10 11 12 |
class Net(nn.Module): def __init__(self, input_size, hidden_size, num_classes): super(Net, self).__init__() # Наследуемый родительским классом nn.Module self.fc1 = nn.Linear(input_size, hidden_size) # 1й связанный слой: 784 (данные входа) -> 500 (скрытый узел) self.relu = nn.ReLU() # Нелинейный слой ReLU max(0,x) self.fc2 = nn.Linear(hidden_size, num_classes) # 2й связанный слой: 500 (скрытый узел) -> 10 (класс вывода) def forward(self, x): # Передний пропуск: складывание каждого слоя вместе out = self.fc1(x) out = self.relu(out) out = self.fc2(out) return out |
Демонстрация нейросети
Мы только что создали настоящую нейронную сеть по нашей структуре.
1 |
net = Net(input_size, hidden_size, num_classes) |
Включаем графический процессор (GPU)
Обратите внимание: вы можете включить эту строку для запуска кодов на GPU
1 |
net.cuda() # Вы можете прокомментировать (#) эту строку для отключения GPU |
Выбираем функцию потерь и оптимизатор
Функция потерь (критерий) выбирает, как выходные данные могут быть сопоставлены с классом. Это определяет, как хорошо или плохо работает нейросеть. Оптимизатор выбирает способ обновления веса, чтобы найти область, в которой будет найден лучшие параметры в конкретной нейросети.
1 2 |
criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(net.parameters(), lr=learning_rate) |
Тренируем нейросеть
Этот процесс займет примерно 3-5 минут, в зависимости от работоспособности вашего компьютера. Подробные инструкции находятся в комментариях (после #) в следующих примерах.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
for epoch in range(num_epochs): for i, (images, labels) in enumerate(train_loader): # Загрузка партии изображений с индексом, данными, классом images = Variable(images.view(-1, 28*28)) # Конвертация тензора в переменную: изменяем изображение с вектора, размером 784 на матрицу 28 x 28 labels = Variable(labels) optimizer.zero_grad() # Инициализация скрытых масс до нулей outputs = net(images) # Передний пропуск: определение выходного класса, данного изображения loss = criterion(outputs, labels) # Определение потерь: разница между выходным классом и предварительно заданной меткой loss.backward() # Обратный проход: определение параметра weight optimizer.step() # Оптимизатор: обновление параметров веса в скрытых узлах if (i+1) % 100 == 0: # Логирование print('Epoch [%d/%d], Step [%d/%d], Loss: %.4f' %(epoch+1, num_epochs, i+1, len(train_dataset)//batch_size, loss.data[0])) |
Тестируем модель нейросети
Также как и с тренировкой нейронной сети, нам также нужно загрузить пачки тестируемых изображений и собрать выходные данные. Отличия теста от тренировки:
- Проходит без подсчета потерь и веса;
- Нет обновления веса;
- Корректный расчет прогноза
1 2 3 4 5 6 7 8 9 10 11 |
correct = 0 total = 0 for images, labels in test_loader: images = Variable(images.view(-1, 28*28)) outputs = net(images) _, predicted = torch.max(outputs.data, 1) # Выбор лучшего класса из выходных данных: класс с лучшим счетом total += labels.size(0) # Увеличиваем суммарный счет correct += (predicted == labels).sum() # Увеличиваем корректный счет print('Accuracy of the network on the 10K test images: %d %%' % (100 * correct / total)) |
Мы сохраняем тренированную модель как pickle. Таким образом, ее можно будет загрузить и использовать в будущем.
1 |
torch.save(net.state_dict(), 'fnn_model.pkl') |
Поздравляем! Вы создали вашу первую рабочую нейронную сеть прямого распространения (Feedforward).
Что дальше?
Сохраняем и закрываем файл. Запускаем файл в консоли:
1 |
python fnn.py |
Процесс тренировки будет выглядеть следующим образом:
Спасибо, что уделили время. Надеюсь, вам понравилась данная статья. Весь код из статьи можно найти на github тут.
Данная статья была основана на разработки пользователя Yunjey у которого отличная библиотека примеров.
Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.
E-mail: vasile.buldumac@ati.utm.md
Образование
Universitatea Tehnică a Moldovei (utm.md)
- 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»