TRAINING A CLASSIFIER
数据加载
torchvision
torchvision.datasets
torch.utils.data.DataLoader
训练图像分类器
- 使用torchvision加载及标准化CIFAR10训练、测试数据集
- 定义卷积神经网络
- 定义损失函数
- 训练网络
- 测试网络
1. 加载及标准化CIFAR10训练、测试数据集
import torch
import torchvision
import torchvision.transforms as transforms
torchvision数据集输出为PILImage图像,其取值范围为 [ 0 , 1 ] [0, 1] [0,1],将其转化为取值范围为 [ − 1 , 1 ] [-1, 1] [−1,1]的标准化张量。
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))])
trainset = torchvision.datasets.CIFAR10(root="../../../datasets", train=True,
download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
shuffle=True, num_workers=2)
testset = torchvision.datasets.CIFAR10(root="../../../datasets", 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")
Files already downloaded and verified
Files already downloaded and verified
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
# functions to show an image
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(trainloader)
images, labels = dataiter.next()
# show images
imshow(torchvision.utils.make_grid(images))
# print labels
print(" ".join(["{:5s}".format(classes[labels[j]]) for j in range(4)]))
plane ship deer ship
2 定义卷积神经网络
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(in_channels=3, out_channels=6, kernel_size=5)
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
self.conv2 = nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5)
self.fc1 = nn.Linear(in_features=16 * 5 * 5, out_features=120)
self.fc2 = nn.Linear(in_features=120, out_features=84)
self.fc3 = nn.Linear(in_features=84, out_features=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
net = Net()
print(net)
Net(
(conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
(fc1): Linear(in_features=400, out_features=120, bias=True)
(fc2): Linear(in_features=120, out_features=84, bias=True)
(fc3): Linear(in_features=84, out_features=10, bias=True)
)
3 定义损失函数
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
4 训练网络
for epoch in range(2): # loop over the dataset multiple times
running_loss = 0
for i, data in enumerate(trainloader, start=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 = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# print statistics
running_loss += loss.item()
if i % 2000 == 1999: # print every 2000 mini-batches
print("[{:d}, {:5d}] loss: {:.3f}"
.format(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0
print("Finishe Training")
[1, 2000] loss: 2.225
[1, 4000] loss: 1.892
[1, 6000] loss: 1.692
[1, 8000] loss: 1.583
[1, 10000] loss: 1.506
[1, 12000] loss: 1.482
[2, 2000] loss: 1.402
[2, 4000] loss: 1.367
[2, 6000] loss: 1.338
[2, 8000] loss: 1.330
[2, 10000] loss: 1.311
[2, 12000] loss: 1.308
Finishe Training
5 测试网络
dataiter = iter(testloader)
images, labels = dataiter.next()
# print images
imshow(torchvision.utils.make_grid(images))
print("GroundTruth: {}".format(
" ".join(["{:5s}".format(classes[labels[j]]) for j in range(4)])))
GroundTruth: cat ship ship plane
outputs = net(images)
_, predicted = torch.max(outputs, dim=1)
print("Predicted: {}".format(" ".join(["{:5s}".format(classes[predicted[j]])
for j in range(4)])))
Predicted: cat ship ship ship
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs, dim=1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print("Accuracy of the network on the 10000 test images: {}%".format(100 * correct / total))
Accuracy of the network on the 10000 test images: 55.81%
class_correct = [0] * 10
class_total = list(0 for i in range(10))
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs, dim=1)
c = (predicted == labels).squeeze()
for i in range(4):
label = labels[i]
class_correct[label] += c[i].item()
class_total[label] += 1
for i in range(10):
print("Accuracy of {:5s} : {:2d} %".format(
classes[i], 100 * class_correct[i] // class_total[i]))
Accuracy of plane : 59 %
Accuracy of car : 75 %
Accuracy of bird : 40 %
Accuracy of cat : 17 %
Accuracy of deer : 32 %
Accuracy of dog : 63 %
Accuracy of frog : 70 %
Accuracy of horse : 59 %
Accuracy of ship : 79 %
Accuracy of truck : 59 %
使用GPU训练
查询GPU是否可用
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# Assuming that we are on a CUDA machine, this should print a CUDA device:
print(device)
cuda:0
将网络参数和缓存转为CUDA张量
net.to(device)
Net(
(conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
(fc1): Linear(in_features=400, out_features=120, bias=True)
(fc2): Linear(in_features=120, out_features=84, bias=True)
(fc3): Linear(in_features=84, out_features=10, bias=True)
)
训练中,每一步都需将输入和目标转为CUDA张量
inputs, labels = data[0].to(device), data[1].to(device)
使用多GPU训练
删除数据迭代器
del dataiter