pytorch学习【训练分类器】

说明:此博客内容来源于pytorch官方文档英文版,链接:pytorch.org

对于计算机视觉,我们已经创建了一个名为torchvision的包,该包含有支持加载类似Imagenet、CIFAR10,MNIST等公共数据集的数据加载模块torchvision.datasets和支持加载图像数据转换模块torch.utils.data.DataLoader.
对于本教程,我们使用公共数据集CIFAR10,它包含10个类别:airplane、automobile、bird、cat、deer、dog、frog、horse、ship、truck。CIFAR10的图像尺寸在33232,其中3为RGB三个颜色通道,每个通道内图像尺寸为32*32.

训练一个图像分类器的步骤:1.使用torchvision加载并且归一化CIFAR10的训练集和测试集;2.定义一个卷积神经网络;3.定义一个损失函数;4.在训练样本上训练神经网络;5.在测试样本上测试网络。

1.加载数据并归一化

import torch
import torchvision
import torchvision.transforms as transforms

#transforms.ToTensor()会将像素值转换为范围为[0,1]的tensor。Normalize两个参数分别为均值和方差,将像素值减掉均值后除以标准差差,得到标准化像素值范围为[-1,1]
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))])
#加载训练集。root为路径;train为True表示该数据集为训练集;download为True表示下载数据集,由于本人数据集已下载,因此设置为False。
trainset = torchvision.datasets.CIFAR10(root='.data',train=True,download=False,transform=transform)
#shuffle=True表示打乱数据集顺序,一般设置为True
trainloader = torch.utils.data.DataLoader(trainset,batch_size=4,shuffle=True)
testset = torchvision.datasets.CIFAR10(root='.data',train=False,download=False,transform=transform)
testloader=torch.utils.data.DataLoader(testset,batch_size=10,shuffle=True)

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

显示一下训练集

import numpy as np
import matplotlib.pyplot as plt

def imshow(img):
    #首先去归一化,因为前面对图像进行了归一化,即减掉均值后除以标准差(均值标准差均为0.5),因此去归一化需要乘以0.5再加0.5.
    img = img/2+0.5
    npimg = img.numpy()
    #由于输入图像格式为(C,W,H)形式,而numpy可以读取的形式为(W,H,C),因此需要将三个维度顺序转换一下
    plt.imshow(np.transpose(npimg,(1,2,0)))
    plt.show()
#定义一个迭代器,每次运行会显示下一组图像
detaiter = iter(trainloader)
images,labels=detaiter.next()

imshow(torchvision.utils.make_grid(images))
print(''.join('%5s'%classes[labels[j]] for j in range(4)))

2.定义神经网络

import torch
import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__()
        #定义两个卷积层,Conv2d为二维卷积。3,6,5分别为输入通道,输出通道,卷积核大小
        self.conv1 = nn.Conv2d(3,6,5)
        self.conv2 = nn.Conv2d(6,16,5)
        #定义三个全连接层,两个参数分别为输入单元数和输出单元数,由于CIFAR10有10中类别,因此最后一层输出单元个数为10。
        self.fc1 = nn.Linear(16*5*5,120)
        self.fc2 = nn.Linear(120,84)
        self.fc3 = nn.Linear(84,10)
    #定义好网络结构,开始前向传播
    def forward(self,x):
        #F.max_pool2d表示二维最大池化,(2,2)表示filter大小为2,如果filter为矩形,可以省略一个2。F.relu为relu激活函数
        x = F.max_pool2d(F.relu(self.conv1(x)),(2,2))
        x = F.max_pool2d(F.relu(self.conv2(x)),2)
        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()

3.定义损失函数和优化器

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(net.parameters(),lr=0.001,momentum=0.9)

4.训练神经网络

for epoch in range(2):
    running_loss = 0
    #enumerate两个参数(序列,起始位置),返回值为枚举对象
    for i,data in enumerate(trainloader,0):
        inputs,labels = data
        #由于pytorch计算梯度会累积,因此每次反向传播之前需要清空梯度
        optimizer.zero_grad()
        #获取输出
        outputs = net(inputs)
        #定义损失函数
        loss = criterion(outputs,labels)
        #反向传播
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if i%2000 == 1999:
            print('[%d,%5d]loss:%.3f'%(epoch+1,i+1,running_loss/2000))
            running_loss =0.0
print("finish training")

我们可以保存已训练好的模型

PATH='./cifar_net.pth'
torch.save(net.state_dict(),PATH)
#读取已保存的模型
net = Net()
net.load_state_dict(torch.load(PATH))

5.测试数据集

net.eval()
with torch.no_grad():
    total_correct = 0
    total_num = 0
    for x,label in testloader:
        out = net(x)
        pred = out.argmax(dim=1)
        total_correct += torch.eq(pred,label).float().sum().item()
        total_num += x.size(0)

    acc = total_correct /total_num
    print(epoch,acc)

测试每一类的分类精度

class_correct = list(0. for i in range(10))  #记住这个表达,生成10个0的列表
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, 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 %%' % (classes[i], 100 * class_correct[i] / class_total[i]))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值