一个简单的 PyTorch 图像分类器
学习了 PyTorch 官方教程中文版后跟着敲了一个图像分类器,能实现 10 中类别的图像分类任务
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torch
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
class Net(nn.Module):
def __init__(self):
super(Net, self).__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 = x.view(-1, 16 * 5 * 5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
def imshow(img):
img = img / 2 + 0.5
npimg = img.numpy() # 转化成 numpy 数组
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()
def main():
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
# 下载并构造训练集对象
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=transform)
# 把 trainset 包装成 数据加载器,训练时用它来一批一批取数据。
# trainset 是刚才的数据集
# batch_size=4 :一次取 4 张图片组成一个 mini-batch。
# shuffle=True :每个 epoch 都打乱训练数据,避免模型记住顺序。
# num_workers=2 :用 2 个子进程并行加载数据,加快读取速度。
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
shuffle=True, num_workers=2)
# 和 trainset 类似,不过这里 train=False,所以加载的是 测试集(10000 张图片)。
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
download=True, transform=transform)
# 把测试集封装成迭代器。
testloader = torch.utils.data.DataLoader(testset, batch_size=4,
shuffle=False, num_workers=2)
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
net = Net()
# 定义损失函数为交叉墒损失
criterion = nn.CrossEntropyLoss()
# 自定义优化器
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
for epoch in range(10): # 训练两个完整的 epoch running_loss = 0.0
for i, data in enumerate(trainloader, 0): # 获取一个 mini-batch inputs, labels = data
optimizer.zero_grad() # 梯度清零
outputs = net(inputs) # 得到神经网络的输出
loss = criterion(outputs, labels) # 获取损失函数
loss.backward() # 反向传播
optimizer.step() # 使用 SGD 优化器来更新参数
# 打印训练进度
running_loss += loss.item() # 累积损失到 running_loss 中
if i % 2000 == 1999:
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0 # 清零
print('Finished Training') # 结束训练
# dataiter = iter(trainloader)
# images, labels = next(dataiter) # # imshow(torchvision.utils.make_grid(images)) # print('Ground truth labels: ', ' '.join('%5s' % classes[labels[j]] for j in range(4))) # # outputs = net(images) # _, predicted = torch.max(outputs.data, 1) # 通过已经训练好的神经网络进行预测
# print('Predicted ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))
# 验证数据预测准确性
correct, total = 0, 0
with torch.no_grad(): # 不计算梯度的上下文环境
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs.data, 1) # 找到最大类别的标签就是预测值
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))
if __name__ == '__main__':
main()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110