В этом блоге мы будем использовать набор данных CIFAR10, определим модель CNN, затем обучим модель и, наконец, протестируем модель на тестовых данных.
Импорт библиотек
import torch import torchvision import torchvision.transforms as transforms
Проверьте версию torchvision
torchvision.__version__
Вывод: ‘0.9.1+cu102’
Загрузите набор данных CIFAR10
Создайте преобразование изображений
Выходными данными наборов данных torchvision являются изображения PILImage диапазона [0, 1]. Мы преобразуем их в тензоры нормализованного диапазона [-1, 1].
transform = transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
Загрузите данные и создайте загрузчик данных
batch_size = 5 train_data = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform) train_data_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size, shuffle=True, num_workers=2)
Вывод:
test_data = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform) test_data_loader = torch.utils.data.DataLoader(test_data, batch_size=batch_size, shuffle=False, num_workers=2)
Вывод:
Создайте список классов
class_names = ['plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
Повторите и просмотрите train_data_loader
sample = next(iter(train_data_loader)) imgs, lbls = sample print(lbls)
Вывод: тензор([9, 0, 8, 1, 8])
Визуализируйте набор данных поезда
import matplotlib.pyplot as plt import numpy as np
..
def imshow(img): img = img / 2 + 0.5 # unnormalize npimg = img.numpy() plt.imshow(np.transpose(npimg, (1, 2, 0))) plt.show() # get some random training images #dataiter = iter(train_data_loader) images, labels = iter(train_data_loader).next() # show images imshow(torchvision.utils.make_grid(images)) # print labels print(' '.join(f'{class_names[labels[j]]:5s}' for j in range(batch_size)))
Вывод:
Определите свёрточную нейронную сеть
import torch.nn as nn import torch.nn.functional as F
класс
torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1,bias=True, padding_mode='zeros', device=None, dtype=None): применяет 2D свертка над входным сигналом, состоящим из нескольких входных плоскостей.
Параметры:
in_channels (int) — количество каналов во входном изображении.
out_channels (int) — количество каналов, созданных сверткой
kernel_size (целое число или кортеж) — размер свертывающегося ядра.
шаг (целое число или кортеж, необязательно) — шаг свертки. По умолчанию: 1
padding (int, tuple или str, необязательно) — заполнение добавляется ко всем четырем сторонам ввода. По умолчанию: 0
padding_mode (строка, необязательно) — «нули», «отражать», «реплицировать» или «круговой». По умолчанию: «нули»
dilation (int или tuple, необязательно) — интервал между элементами ядра. По умолчанию: 1
groups (целое число, необязательно) — количество заблокированных подключений от входных каналов к выходным каналам. По умолчанию: 1
bias (bool, необязательный) — если значение равно True, к выходным данным добавляется обучаемое смещение. По умолчанию: Истина
class MyModel(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(3, 6, 5) self.pool = nn.MaxPool2d(2, 2) self.conv2 = nn.Conv2d(6, 16, 5) self.fc1 = nn.Linear(16 * 5 * 5, 120) self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 10) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = torch.flatten(x, 1) # flatten all dimensions except batch x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x model = MyModel()
Определите функцию потерь и оптимизатор
import torch.optim as optim loss_function = nn.CrossEntropyLoss() optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
Обучите сеть
for epoch in range(2): # loop over the dataset multiple times running_loss = 0.0 for i, data in enumerate(train_data_loader, 0): # get the inputs; data is a list of [inputs, labels] inputs, labels = data # zero the parameter gradients optimizer.zero_grad() # forward + backward + optimize outputs = model(inputs) loss = loss_function(outputs, labels) loss.backward() optimizer.step() # print statistics running_loss += loss.item() if i % 2000 == 1999: # print every 2000 mini-batches print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 2000:.3f}') running_loss = 0.0 print('Finished Training')
Выход:
Сохраните модель
PATH = './conv2d_model.sav' torch.save(model.state_dict(), PATH)
Протестируйте сеть на тестовых данных
Мы обучили сеть за 2 прохода по обучающему набору данных. Но нам нужно проверить, научилась ли сеть вообще чему-нибудь.
Мы проверим это, предсказав метку класса, которую выдает нейронная сеть, и проверим ее на соответствие действительности. Если прогноз правильный, мы добавляем образец в список правильных прогнозов.
Хорошо, первый шаг. Давайте покажем изображение из тестового набора, чтобы ознакомиться.
dataiter = iter(test_data_loader) images, labels = dataiter.next() # print images imshow(torchvision.utils.make_grid(images)) print('GroundTruth: ', ' '.join(f'{class_names[labels[j]]:5s}' for j in range(4)))
Вывод:
Загрузите сохраненную модель
trained_model = MyModel() trained_model.load_state_dict(torch.load(PATH))
Вывод: ‹Все ключи успешно подобраны›
Предсказывать
outputs = trained_model(images)
Результатом являются энергии для 10 классов. Чем выше энергия для класса, тем больше сеть считает, что изображение относится к определенному классу. Итак, получим индекс наибольшей энергии:
_, predicted = torch.max(outputs, 1) print('Predicted: ', ' '.join(f'{class_names[predicted[j]]:5s}' for j in range(4)))
Вывод: предсказано: корабль-корабль-самолет
Прогнозировать весь набор тестовых данных
correct = 0 total = 0 # we are not training, we don't need to calculate the gradients for our outputs with torch.no_grad(): for data in test_data_loader: images, labels = data # calculate outputs by running images through the network outputs = trained_model(images) # the class with the highest energy is what we choose as prediction _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print(f'Accuracy of the network on the 10000 test images: {100 * correct // total} %')
Вывод: Точность сети на 10 000 тестовых изображений: 53 %
Давайте посмотрим, какие классы показали хорошие результаты, а какие — нет.
Подготовьтесь к подсчету прогнозов для каждого класса
correct_pred = {class_name: 0 for class_name in class_names} print(correct_pred) total_pred = {class_name: 0 for class_name in class_names} print(total_pred)
Вывод:
Прогнозировать все тестовые данные
# again no gradients needed with torch.no_grad(): for data in test_data_loader: images, labels = data outputs = trained_model(images) #get the maximum of tensor _, predictions = torch.max(outputs, 1) # collect the correct predictions for each class for label, prediction in zip(labels, predictions): if label == prediction: correct_pred[class_names[label]] += 1 total_pred[class_names[label]] += 1 pass pass pass
Вывести правильный и общий прогноз
print(correct_pred) print(total_pred)
Вывод:
Точность печати для каждого класса
for class_name, correct_count in correct_pred.items(): accuracy = 100 * float(correct_count) / total_pred[class_name] print(f'Accuracy for class: {class_name:5s} is {accuracy:.1f} %') pass
Вывод:
Мы можем видеть точность каждого класса. Спасибо за прочтение.