主要分为下面5个步骤:

  1. Load and normalizing the CIFAR10 training and test datasets using torchvision 加载数据
  2. Define a Convolutional Neural Network 定义卷积神经网络类
  3. Define a loss function 定义损失函数
  4. Train the network on the training data 训练模型
  5. Test the network on the test data 测试模型

相比官网上面添加了一些注释,并将一些object输出来便于理解。


另外官网上在文章末尾包含了将模型放在GPU上面运行的方法,这一部分没有被本篇包含。

ps:本文从jupyter中导出,引用部分代表jupyter上面的输出

1. 加载数据

import torch
import torchvision
import torchvision.transforms as transforms #tansforms包对图片进行变换
# 定义transform,首先将图像变换为tensor,然后将其正则化
transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
# 下载训练集到当前目录下到data文件中
trainset = torchvision.datasets.CIFAR10(root='./data',train=True,download=True,transform=transform)

Files already downloaded and verified

# 下载测试集到当前目录下到data文件中
testset = torchvision.datasets.CIFAR10(root='./data',train=False,download=True,transform=transform)

Files already downloaded and verified

trainset
Dataset CIFAR10
 Number of datapoints: 50000
 Root location: ./data
 Split: Train
 StandardTransform
 Transform: Compose(
 ToTensor()
 Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
 )
testset
Dataset CIFAR10
 Number of datapoints: 10000
 Root location: ./data
 Split: Test
 StandardTransform
 Transform: Compose(
 ToTensor()
 Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
 )
# 数据集加载器
trainloader = torch.utils.data.DataLoader(trainset,batch_size=4,shuffle=True,num_workers=2)# num_workers表示进程数处理laod
testloader = torch.utils.data.DataLoader(testset, batch_size=4,
                                         shuffle=False, num_workers=2)
trainloader

<torch.utils.data.dataloader.DataLoader at 0x7fed838b2610>

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

可选-查看图片

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' % classes[labels[j]] for j in range(4)))

pytorch 训练L1损失nan_神经网络

ship car dog frog

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(3,6,5) # 3表示通道数,6表示卷积核个数,5表示kernel_size
        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)# tensor.view()调整tensor的形状,view不会修改自身的数据,返回的新tensor与原tensor共享内存。
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x
net = Net()
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)
 )
net.parameters()

<generator object Module.parameters at 0x7fed8843aad0>

3. 定义损失函数和优化方法

import torch.optim as optim
criterion = nn.CrossEntropyLoss() # 交叉熵损失函数
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9) # 学习率为0.001,动量为0.9

4. 训练模型

# 多次循环train训练集
for epoch in range(2):
    running_loss = 0.0
    for i,data in enumerate(trainloader,0): #enumerate对迭代器使用时,可以获得迭代器索引,后面的0指,“从0开始计数”
        # 每一个batch的数据, data is a list of [inputs, labels]
        inputs, labels = data
        
        # 清空上一批次的grad
        optimizer.zero_grad()
        
        # 正向传播
        outputs = net(inputs)
        loss = criterion(outputs,labels)
        
        # 反向传播(求梯度)
        loss.backward()
        
        # 迭代优化
        optimizer.step()
        
        running_loss += loss.item()
        # 每个epoch中,每2000打印一些信息
        if i%2000 == 1999:
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0
print('Finished Training')

[1, 2000] loss: 2.192
[1, 4000] loss: 1.842
[1, 6000] loss: 1.676
[1, 8000] loss: 1.585
[1, 10000] loss: 1.510
[1, 12000] loss: 1.493
[2, 2000] loss: 1.429
[2, 4000] loss: 1.390
[2, 6000] loss: 1.364
[2, 8000] loss: 1.338
[2, 10000] loss: 1.317
[2, 12000] loss: 1.297
Finished Training

# 存储训练后所得的模型, 通过python自带的pickle存下其参数(tensor)
torch.save(net.state_dict(),"./the_first_net.pth")

5. 测试模型

# reload
# net = Net()
# net.load_state_dict(torch.load(PATH))

5.1 一批次图片测试

# 一批次图片测试
dataiter = iter(testloader)
images, labels = dataiter.next()
images.shape # 一次按照batch_size的个数进行load

torch.Size([4, 3, 32, 32])

output = net(images)
output.shape

torch.Size([4, 10])

output

tensor([[-0.9346, -2.7493, 1.2818, 3.6521, -1.5410, 2.4433, 0.6683, -1.0054,
-0.7376, -2.0586],
[ 4.5771, 5.9592, -1.0427, -2.6354, -2.7411, -3.2669, -4.4034, -3.0291,
3.7823, 3.8982],
[ 2.2086, 4.1630, -0.3639, -0.9545, -2.9833, -1.7351, -2.9355, -2.1742,
2.0145, 2.9517],
[ 4.6543, 1.2111, 1.2452, -1.8118, -0.2649, -2.6369, -3.2264, -3.2120,
5.6315, -0.2643]], grad_fn=)

val, predicted = torch.max(output,1) #torch.max(input, dim),dim=0每行最大值,dim=1每列最大值
val

tensor([3.6521, 5.9592, 4.1630, 5.6315], grad_fn=)

predicted

tensor([3, 1, 1, 8])

print('GroundTruth',' '.join('%5s' % classes[labels[j]]
                              for j in range(4)))
print('Predicted',' '.join('%5s' % classes[predicted[j]]
                              for j in range(4)))

GroundTruth cat ship ship plane
Predicted cat car car ship

5.2 整体数据集测试

correct = 0
total = 0
for i, data in enumerate(testloader,0):
    inputs, labels = data
    outputs = net(inputs)
    _,predicted = torch.max(outputs,1)
    
    # preticted与labels比较
    correct += (predicted == labels).sum().item() # 调用sum()函数返回一个一维tensor如:tensor(1),使用item()将其转化为标量
    
    total += labels.size()[0] # 也可以写为labels.size(0)
print('正确个数为:%d,全部个数为:%d'%(correct,total),'准确率为:%f'%(correct/total))

正确个数为:5568,全部个数为:10000 准确率为:0.556800

# 观察每个类的准确率

class_correct = [0. for i in range(10)] # 一个列表表示每个类正确的个数
class_total = [0. for i in range(10)]

for data in testloader:
    inputs, labels = data
    outputs = net(inputs)
    _,predicted = torch.max(outputs,1)
    
    temp = predicted == labels # 返回一个true,false张量
    for i in range(temp.size(0)):
        class_total[labels[i]]+=1
        if temp[i]:
            class_correct[labels[i]]+=1

for i in range(10):
    print('Accuracy of %5s : %2d %%' % (
        classes[i], 100 * class_correct[i] / class_total[i]))

Accuracy of plane : 70 %
Accuracy of car : 76 %
Accuracy of bird : 43 %
Accuracy of cat : 34 %
Accuracy of deer : 53 %
Accuracy of dog : 42 %
Accuracy of frog : 66 %
Accuracy of horse : 62 %
Accuracy of ship : 60 %
Accuracy of truck : 47 %