最近在学习《PyTorch官方教程》,跟着教程实现了一个简单的Pytorch图像分类器。
当处理图像数据时,可以使用标准 python 包将数据加载成numpy 数组格式,然后将这个数组转换成 torch.*Tensor。我们已经创建了一个叫做 torchvision 的包,该包含有支持加载类似Imagenet,CIFAR10,MNIST 等公共数据集的数据加载模块 torchvision.datasets 和支持加载图像数据数据转换模块 torch.utils.data.DataLoader。
对于该例,我们将使用CIFAR10数据集,它包含十个类别:‘airplane’, ‘automobile’, ‘bird’, ‘cat’,‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’。CIFAR-10 中的图像尺寸为3*32*32,也就是RGB的3层颜色通道,每层通道内的尺寸为32*32。
训练一个图像分类器,主要步骤如下:
1)使用torchvision加载并且归一化CIFAR10的训练和测试数据集。
2)定义一个卷积神经网络。
3)定义一个损失函数。
4)在训练样本数据上训练网络。
5)在测试样本数据上测试网络。
加载并归一化 CIFAR10 使用 torchvision ,用它来加载 CIFAR10 数据非常简单。
1.import torch
2.import torchvision
3.import torchvision.transforms as transforms
torchvision 数据集的输出是范围在[0,1]之间的 PILImage,我们将他们转换成归一化范围为[-1,1]之间的张量 Tensors。
【注:num_worker表示线程数,我的电脑只能设置0,即主线程工作,否则会报错。】
1.transform = transforms.Compose(
2. [transforms.ToTensor(),
3. transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
4.
5.trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
6. download=True, transform=transform)
7.trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
8. shuffle=True, num_workers=0)
9.
10.testset = torchvision.datasets.CIFAR10(root='./data', train=False,
11. download=True, transform=transform)
12.testloader = torch.utils.data.DataLoader(testset, batch_size=4,
13. shuffle=False, num_workers=0)
14.
15.classes = ('plane', 'car', 'bird', 'cat',
16. 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
定义一个卷积神经网络。从上一篇《Pytorch神经网络》博客中复制神经网络,并修改它为3通道的图片(在此之前它被定义为1通道)。
1.import torch.nn as nn
2.import torch.nn.functional as F
3.
4.class Net(nn.Module):
5. def __init__(self):
6. super(Net, self).__init__()
7. self.conv1 = nn.Conv2d(3, 6, 5)
8. self.pool = nn.MaxPool2d(2, 2)
9. self.conv2 = nn.Conv2d(6, 16, 5)
10. self.fc1 = nn.Linear(16 * 5 * 5, 120)
11. self.fc2 = nn.Linear(120, 84)
12. self.fc3 = nn.Linear(84, 10)
13.
14. def forward(self, x):
15. x = self.pool(F.relu(self.conv1(x)))
16. x = self.pool(F.relu(self.conv2(x)))
17. x = x.view(-1, 16 * 5 * 5)
18. x = F.relu(self.fc1(x))
19. x = F.relu(self.fc2(x))
20. x = self.fc3(x)
21. return x
22.
23.net = Net()
定义一个损失函数和优化器,我们使用分类交叉熵Cross-Entropy 作损失函数,动量SGD做优化器。
1.import torch.optim as optim
2.
3.criterion = nn.CrossEntropyLoss()
4.optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
训练网络。我们只需要在数据迭代器上循环传给网络和优化器输入就可以。
1.for epoch in range(2): # 在整个数据集上训练两次
2.
3. running_loss = 0.0
4. for i, data in enumerate(trainloader, 0):
5. # get the inputs
6. inputs, labels = data
7.
8. # zero the parameter gradients
9. optimizer.zero_grad()
10.
11. # forward + backward + optimize
12. outputs = net(inputs)
13. loss = criterion(outputs, labels)
14. loss.backward()
15. optimizer.step()
16.
17. # print statistics
18. running_loss += loss.item()
19. if i % 2000 == 1999: # print every 2000 mini-batches
20. print('[%d, %5d] loss: %.3f' %
21. (epoch + 1, i + 1, running_loss / 2000))
22. running_loss = 0.0
23.
print('Finished Training')
在测试集上测试网络。
1.correct = 0
2.total = 0
3.with torch.no_grad():
4. for data in testloader:
5. images, labels = data
6. outputs = net(images)
7. _, predicted = torch.max(outputs.data, 1)
8. total += labels.size(0)
9. correct += (predicted == labels).sum().item()
10.
11.print('Accuracy of the network on the 10000 test images: %d %%' % (
12. 100 * correct / total))
【注:由于这里仅做展示过程用,训练次数较少,所以准确率不高,可以多训练几次】
运行结果: