欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

pytorch入门

程序员文章站 2022-03-17 14:14:03
...

原文链接:https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html

这个教程的目标是:

  • 对PyTorch的张量和神经网络有大致的了解
  • 训练一个小的图片分类的神经网络。

本教程假设你对numpy有一个基础的了解

注意:确保你已经安装了torch和torchvision模块

目录

什么是PyTorch?

入门

张量(Tensors)

运算(Operations)

Numpy Bridge(与Numpy的转换)

Torch的张量到Numpy数组的转换

Numpy数组转换为Torch张量

Autograd:自动微分

Tensor(张量)

梯度

神经网络

定义网络

损失函数

反向传播

更新权重

训练一个分类器

数据怎么来?

训练一个图像分类器

1.加载和规范化CIFAR10

2.定义一个卷积神经网络

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

4.训练网络


什么是PyTorch?

它是一个基于Python的科学计算软件包。主要针对两类受众:

  • 使用GPU运算来取代Numpy
  • 提供最大灵活性和速度的深度学习研究平台

入门

张量(Tensors)

张量和Numpy的ndarray类似。不同的是张量可以在GPU上运行以加速运算。

使用张量构造一个未初始化的5*3的矩阵:

import torch
x=torch.empty(5,3)
print(x)

输出:

tensor([[ 5.3209e-09,  3.0918e-41,  5.3422e-09],
        [ 3.0918e-41,  5.6460e-09,  3.0918e-41],
        [ 5.8182e-09,  3.0918e-41,  2.1418e-39],
        [ 1.6714e-38,  1.7853e-37,  0.0000e+00],
        [ 3.8169e-40,  2.7142e-24,  1.3744e+11]])

构造一个随机数据的矩阵:

x=torch.rand(5,3)
print(x)

输出:

tensor([[ 0.8983,  0.1658,  0.5158],
        [ 0.8509,  0.9362,  0.5348],
        [ 0.5108,  0.8170,  0.6949],
        [ 0.1138,  0.3153,  0.4799],
        [ 0.2695,  0.4061,  0.9428]])

构造一个dtype为long的全0矩阵:

x=torch.zeros(5,3,dtype=torch.long)
print(x)

输出:

tensor([[ 0,  0,  0],
        [ 0,  0,  0],
        [ 0,  0,  0],
        [ 0,  0,  0],
        [ 0,  0,  0]])

直接通过数据来构造张量:

x=torch.tensor([5.5,3])
print(x)

输出:

tensor([ 5.5000,  3.0000])

或基于已有张量来创建张量。除非用户提供新的值,否则这些方法将重用输入张量的属性,例如dtype。

x=x.new_ones(5,3,dtype=torch.double) #方法new_* 的参数是张量的大小
print(x)
x=torch.randn_like(x,dtype=torch.float)#重新定义了dtype
print(x)#保留了原来张量的大小

输出:

tensor([[ 1.,  1.,  1.],
        [ 1.,  1.,  1.],
        [ 1.,  1.,  1.],
        [ 1.,  1.,  1.],
        [ 1.,  1.,  1.]], dtype=torch.float64)
tensor([[ 0.6536, -0.0688, -0.4559],
        [ 0.4712,  1.0297,  0.5794],
        [ 0.7719,  0.5049, -2.1100],
        [-1.0550, -1.3705, -0.7813],
        [-1.2648,  0.5148,  0.2817]])

获取张量的形状:

print(x.size())

输出:

(5, 3)

注意:

torch.size实际上是一个tuple(元组),所以它支持所有元组的运算。

运算(Operations)

运算有很多种语法。接下来的例子我们看下加法运算。

加法:语法1

y=torch.rand(5,3)
print(x+y)

输出(接下来的语法,输出都相同):

tensor([[ 1.3995, -0.4390, -0.2863],
        [ 0.6528,  1.3047, -0.5661],
        [ 1.4773,  0.8449, -1.7209],
        [-0.3371,  1.0313, -0.1698],
        [-0.6412, -0.7284, -0.9708]])

加法:语法2

print(torch.add(x,y))

加法:提供一个输出张量作为参数

result=torch.empty(5,3)
torch.add(x,y,out=result)
print(result)

加法:in-place(不再有输出变量。运算结果直接赋值给调用者)

y.add_(x)
print(y)

注意:

任何运算方法名后面加“_”都代表in-place。例如:x.copy_(y),x.t_(),都会改变x。

你可以使用标准的Numpy风格的索引操作。

print(x[:,1])

输出:

tensor([ 1.0198, -2.2140, -0.3281, -1.1494, -0.9980])

调整大小:如果你想要改变张量的形状,可以使用torch.view:

x=torch.randn(4,4)
y=x.view(16)
z=x.view(-1,8)#-1代表通过其它维度推断获取
print(x.size(),y.size(),z.size())

输出:

((4, 4), (16,), (2, 8))

如果张量只有一个元素,使用.item()可以获取它的Python数字的值,

x=torch.randn(1)
print(x)
print(x.item())

输出:

0.931114792824

Numpy Bridge(与Numpy的转换)

Torch的张量和Numpy的数组将共享底层的内存位置,更改一个另一个也会改变。

Torch的张量到Numpy数组的转换

a=torch.ones(5)
print(a)

b=a.numpy()
print(b)

输出:

tensor([ 1.,  1.,  1.,  1.,  1.])
[1. 1. 1. 1. 1.]

torch的张量改变时numpy数组也随着改变

a.add_(1)
print(a)
print(b)

输出:

tensor([ 2.,  2.,  2.,  2.,  2.])
[2. 2. 2. 2. 2.]

Numpy数组转换为Torch张量

改变Numpy数组时Torch张量也跟着改变

import numpy as np
a=np.ones(5)
b=torch.from_numpy(a)
np.add(a,1,out =a)
print(a)
print(b)

输出:

[2. 2. 2. 2. 2.]
tensor([ 2.,  2.,  2.,  2.,  2.], dtype=torch.float64)

在CPU上所有的张量(CharTensor除外)均支持与Numpy的转换。

Autograd:自动微分

autograd package是PyTorch神经网络的核心。我们先简单看一下,然后开始训练第一个神经网络。

autograd package为张量的所有operations(操作或运算)提供了自动微分。它是一个 define-by-run框架,意思是说你的反向传播(backpropagation)是由 如何运行代码 定义的,并且每一个迭代可以是不同的。

用例子和一些简单的术语来看下:

Tensor(张量)

torch.Tensor是包的核心类。如果你设置它的.requires_grad属性 为 True,它的所有操作都会被跟踪记录。完成计算后可以调用.backward()方法,并自动计算所有的梯度。这个张量的梯度将会被累积到.grad属性。

你可以调用.detach()方法来阻止张量对所有操作的跟踪记录。

阻止跟踪历史的另一种方法是你在代码块外包裹语句 with torch.no_grad(): ,这种方法在模型中训练参数设置了requires_grad=True时依然有效。

实现自动微分的另一个重要的类是Function.(这里function可理解为一个运算。比如加法运算)

Tensor Function相互关联建立了一个非循环图,它记录了完整的计算历史。每一个张量有一个.grad_fn属性,这个属性与创建张量(除了用户自己创建的张量,它们的.grad_fnNone)的Function关联。

如果你想要计算导数,你可以调用张量的.backward()方法。如果张量是一个标量(例如,它只有一个元素),你不需要指定backward()的参数,然而,如果张量有多个元素,你需要指定一个匹配张量大小的gradient参数。

import torch

创建一个张量,并设置requires_grad=True来跟踪计算。

x=torch.ones(2,2,requires_grad=True)
print(x)
print(x.requires_grad)

输出:

tensor([[ 1.,  1.],
        [ 1.,  1.]])
True

对张量做一个运算,这里是+:

y=x+2
print(y)

输出:

tensor([[ 3.,  3.],
        [ 3.,  3.]])

y是被刚刚的运算(+)创建的,所以它有.grad_fn属性:

print(y.grad_fn)

输出:

<AddBackward0 object at 0x7ff0cc6ca050>

对y进行运算:

z=y*y*3
out=z.mean()
print(z,z.grad_fn)
print(out,out.grad_fn)

输出:

(tensor([[ 27.,  27.],
        [ 27.,  27.]]), <MulBackward0 object at 0x7f56c3a85050>)
(tensor(27.), <MeanBackward1 object at 0x7f56c3a85050>)

.requires_grad_(...)函数可以改变张量的requires_grad属性。如果该属性未给出,则默认为False。

a=torch.randn(2,2)
a=((a*3)/(a-1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b=(a*a).sum()
print(b.grad_fn)

输出:

False
True
<SumBackward0 object at 0x7fcd902c2050>

梯度

有了自动微分,现在我们可以反向传播了。因为out只是一个简单的标量,out.backward()等价于out.backward(torch.tensor(1))

out.backward()

打印出导数 d(out)/dx

print(x.grad)

输出:

tensor([[ 4.5000,  4.5000],
        [ 4.5000,  4.5000]])

用下图来解释下为什么对out进行反向传播,x的梯度是4.5的矩阵吧:

pytorch入门

你可以用自动微分做更多有趣的事。之前都是对标量进行backward(),不需要参数。下面看下是向量或矩阵时,gradient参数的值对梯度的影响:

x=torch.randn(3,requires_grad=True)
print(x)
y=x*2
while y.data.norm()<1000:
    y=y*2
#print(y)
gradients = torch.tensor([0.1,1.0,0.0001],dtype=torch.float)
y.backward(gradient=gradients)
print(x.grad)

输出:

tensor([ 0.9283, -0.7296,  0.1258])
tensor([  102.4000,  1024.0000,     0.1024])

如果你不想要跟踪历史并自动微分的时候,你可以在代码块外面包一层:with torch.no_grad():

print(x.requires_grad)
print((x**2).requires_grad)
with torch.no_grad():
    print((x**2).requires_grad)

输出:

True
True
False

神经网络

神经网络可以使用torch.nn package构造。

刚刚我们简单介绍了autogradnn依赖于autograd来定义模型并区分它们。一个nn.Module包括你定义的网络层和一个forward(input)方法,这个方法返回output

我们看下这个数字图片分类的网络的例子:

pytorch入门

它是一个简单的前馈网络。它接受输入,并且每层的输入都是上一层的输出,最后给出输出。

一个典型的神经网络的训练过程如下:

  • 定义具有学习参数(或权重)的神经网络
  • 迭代输入数据集
  • 根据神经网络对输入数据集进行运算
  • 计算损失(输出与真实结果的距离。损失越小说明模型越准确。)
  • 将梯度反向传播给神经网络的参数。
  • 更新网络的权重(或参数)。通常使用一种简单的更新规则:权重=权重-学习率*梯度。

定义网络

来定义一个网络:

#encoding:utf-8
import torch
import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):

    def __init__(self):
        super(Net,self).__init__()
        #定义2个卷积层
        self.conv1=nn.Conv2d(in_channels=1,out_channels=6,kernel_size=5)
        self.conv2=nn.Conv2d(in_channels=6,out_channels=16,kernel_size=5)
        #定义了3个线性层,即y=wx+b
        self.fc1=nn.Linear(in_features=16*5*5,out_features=120)
        self.fc2=nn.Linear(120,84)
        self.fc3=nn.Linear(84,10)

    def forward(self, x):
        #在第一层卷积网络和第二层之间增加了relu**函数和池化层
        x=F.max_pool2d(input=F.relu(input=self.conv1(x)),kernel_size=(2,2))
        #如果池化层是方块形的可以用一个number指定
        x=F.max_pool2d(input=F.relu(input=self.conv2(x)),kernel_size=2)
        x=x.view(-1,self.num_flat_features(x))
        x=F.relu(input=self.fc1(x))
        x=F.relu(self.fc2(x))
        x=self.fc3(x)
        return x

    def num_flat_features(self,x):
        size=x.size()[1:]#切片0里面放的是当前训练batch的number,不是特征信息
        num_features=1
        for s in size:
            num_features*=s
        return num_features
net=Net()
print(net)

输出:

Net(
  (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
  (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)
)

你只需要定义forward方法,后向函数(自动计算微分的函数)就会自动定义,当然你需要设置autograd参数为True。在forward方法中你可以使用张量的任何运算。

模型的学习参数由net.parameters()返回。

params = list(net.parameters())
print(len(params))
print(params[0].size())  #conv1's .weight

输出:

10
(6, 1, 5, 5)

这个网络适合32*32的数据集(1*32*32经过一个核心为5的卷积层,大小变为6*28*28;经过一个核心为2的池化层,大小变为6*14*14;再经过一个核心为5的卷积层,大小变为16*10*10;池化层,16*5*5,正好是下一个线性层的输入特征数),我们随机一个输入数据集,运行一下我们的模型吧:

input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)

输出:

tensor([[ 0.0567,  0.0185,  0.0279, -0.1414,  0.0109,  0.0566,  0.1015,
          0.0602,  0.0469,  0.0734]])

将梯度清0并使用随机梯度进行反向传播:

net.zero_grad()
out.backward(torch.randn(1,10))

注意

torch.nn 只支持对批量数据的处理,不支持单个样本。

例如,nn.Conv2d需要一个4维的张量作为输入:nSamples,nChannels,Height,Width.

如果你只有一个样本,你可以使用input.unsqueeze(0)来增加一个假的batch维。

在继续进行之前,我们回顾下刚学到的几个类。

torch.Tensor:一个支持自动微分(或梯度)操作(例如backward())的多维数组。

nn.Module: 神经网络模型,帮助我们封装参数,移植到GPU,导出,加载等的便捷方式。

nn.Parameter: 张量,当你给Module定义属性时,参数会自动生成。

autograd.Function:实现自动梯度运算的前向后向定义。每一个张量运算,产生至少一个Function节点,连接到创建张量的函数并对其历史进行编码。

在这个基础上,我们已经做了:

定义神经网络

处理输入和调用backward方法

还剩下:

计算损失

更新网络的权重

损失函数

一个损失函数包括两个输入(预测值和实际值),然后返回这两个值的距离。

在nn package里面有不同的损失函数。一个简单的损失函数是:nn.MSELoss,它返回的是均方差,即每一个分量相减的平方累计最后除分量的个数。

output = net(input)
target = torch.arange(1, 11)  # a dummy target, for example
target = target.view(1, -1)  # make it the same shape as output
criterion = nn.MSELoss()

loss = criterion(output, target)
print(loss)

输出:

tensor(38.2002)

如果你沿着loss的反向,用.grad_fn属性查看,你会得到如下的计算图:

input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
      -> view -> linear -> relu -> linear -> relu -> linear
      -> MSELoss
      -> loss

所以,当你调用loss.backward()时,在整个计算图都会进行微分,所有requires_grad=True的张量的.grad属性都会累加。

为了更好的理解它,列出很少的几步:

print(loss.grad_fn)
print(loss.grad_fn.next_functions)
print(loss.grad_fn.next_functions[0][0].next_functions)

输出:

<MseLossBackward object at 0x7f170cbe37d0>
((<AddmmBackward object at 0x7f170cbe3790>, 0L),)
((<ExpandBackward object at 0x7f170cbe3790>, 0L), (<ReluBackward object at 0x7f170cbe3810>, 0L), (<TBackward object at 0x7f170cbe3850>, 0L))

反向传播

为了反向传播误差我们所要做的就只是调用loss.backward()。也需要清除已经存在的梯度,不然梯度会和已经存在的梯度进行累计。

我们调用loss.backward(),看下conv1‘s的bias的梯度在反向传播前后的变化。

net.zero_grad()
print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)

loss.backward()

print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)

输出:

conv1.bias.grad before backward
None
conv1.bias.grad after backward
tensor([ 0.1074,  0.0078,  0.0356,  0.0579,  0.1258,  0.0568])

现在我们已经知道如何使用损失函数了。

稍后阅读:

nn package包含各种深度神经网络的模块和损失函数。这里有一个完整的列表 http://pytorch.org/docs/nn

我们要做的最后一步是:

更新网络模型的权重(参数)

更新权重

实践中常用的最简单的更新规则是Stochastic Gradient Descent(SGD):

weight = weight - learning_rate * gradient

上式用python代码实现:

learning_rate=0.01
for f in net.parameters():
    f.data.sub_(learning_rate*f.grad.data)

然而,在你使用神经网络时,你想要使用各种不同的更新规则例如SGD(随机梯度下降法),Nesterov-SGD,Adam,RMSProp(均方根传播)等。我们实现了所有的这些方法,在库torch.optim中。使用起来也很简单:

import torch.optim as optim
#create your optimizer
optimizer=optim.SGD(net.parameters(),lr=0.01)
#in your training loop:
optimizer.zero_grad() #zero the gradient buffers
output=net(input)
print(output.size())
loss=criterion(output,target)
loss.backward()
optimizer.step() #does the update

注意

观察到我们必须手动的把梯度缓存设置为0,即optimizer.zero_grad(),这是因为我们在反向传播那一节也提到过的,梯度会被累计。

训练一个分类器

刚刚学习了怎么定义神经网络,计算损失和更新参数。现在你可能会想:

数据怎么来?

通常,当你想要处理图片,文本,语音或视频数据,你可以用标准的python库来加载数据到一个numpy的数组中。然后,你可以将这个数组转换为torch.*Tensor.

对于图片,Pillow,OpenCV库很有用

对于语音,scipy和librosa库很有用

对于文本,Python或CPython就可以,当然NLTK和SpaCy也很有用。

比较特别的是对于视觉,我们创建了torchvision包,它包含了一些通用数据集(如Imagenet, CIFAR10, MNIST等)的数据加载,以及对图片的数据转换。即torchvision.datasets torch.utils,data.DataLoader.

这提供了极大的方便,避免了编写公式化的代码。

在本教程中,我们将使用CIFAR10数据集。它有10个类别:‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’. CIFAR10中的图像的大小为3*32*32,即大小为32*32的有3个通道的彩色图像。

pytorch入门

训练一个图像分类器

我们将按以下步骤进行:

  1. 使用torchvision加载和规范化CIFAR10 训练和测试数据集
  2. 定义一个卷积神经网络
  3. 定义一个损失函数
  4. 使用训练数据集训练网络
  5. 使用测试数据集测试网络

1.加载和规范化CIFAR10

使用torchvision,加载CIFAR10非常容易

import torch
import torchvision
import torchvision.transforms as transfroms

torchvison下载的数据集是PILImage类型的图片,每一个点的取值范围为[0,1],我们需要把它规整到取值范围为[-1,1]。

transfrom=transfroms.Compose([transfroms.ToTensor(),
                              transfroms.Normalize(mean=(0.5,0.5,0.5),
                                                   std=(0.5,0.5,0.5))])
trainset=torchvision.datasets.CIFAR10(root='./data',train=True,
                                      download=True,transform=transfrom)
trainloader=torch.utils.data.DataLoader(trainset,batch_size=4,
                                        shuffle=True,num_workers=2)

testset=torchvision.datasets.CIFAR10(root='./data',train=False,
                                     download=True,transform=transfrom)
testloader=torch.utils.data.DataLoader(testset,batch_size=4,
                                       shuffle=False,num_workers=2)

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

输出:

Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data/cifar-10-python.tar.gz
Files already downloaded and verified

我们用matplotlib库来输出一些训练图片。

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(X=np.transpose(npimg,axes=(1,2,0)))

#get some random training images
dataiter=iter(trainloader)
images,labels=dataiter.next()

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

plt.show()

pytorch入门

输出:

 frog plane   dog  bird

2.定义一个卷积神经网络

直接复制之前提到的卷积神经网络,只不过这里输入向量从(1,32,32)变为(3,32,32)

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)
        self.pool=nn.MaxPool2d(kernel_size=2,stride=2)
        self.conv2=nn.Conv2d(6,16,5)
        self.fc1=nn.Linear(16*5*5,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.定义损失函数和优化器

这次我们使用分类的交叉熵损失函数,带有momentum(动量)的SGD优化器。

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):#循环整个数据集多少遍

    running_loss=0.0
    for i,data in enumerate(trainloader,start=0):
        #get the inputs
        inputs, labels = data

        # 梯度清0
        optimizer.zero_grad()

        #forward + backword + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        #打印统计信息
        running_loss += loss.item()
        if i % 2000 == 1999: #每2000个mini-batches打印一次
            print("[%d, %d] loss: %.3f" %
                  (epoch+1, i+1, running_loss/2000))
            running_loss=0.0
print('Finished Training')

输出:

[1, 2000] loss: 2.203
[1, 4000] loss: 1.881
[1, 6000] loss: 1.697
[1, 8000] loss: 1.563
[1, 10000] loss: 1.547
[1, 12000] loss: 1.479
[2, 2000] loss: 1.429
[2, 4000] loss: 1.406
[2, 6000] loss: 1.375
[2, 8000] loss: 1.369
[2, 10000] loss: 1.335
[2, 12000] loss: 1.340
Finished Training

5.使用测试集测试网络

我们使用训练集跑了两遍生成的网络模型,是时候检验一下它到底学了些什么东西了。

我们将通过检验神经网络预测出来的标签,与实际标签是否相同。

第一步,我们先看下测试集的图像

dataiter = iter(testloader)
images, labels = dataiter.next()

#打印图片
imshow(torchvision.utils.make_grid(images))
plt.show()
print('GroundTruth:',' '.join('%5s' %classes[labels[j]] for j in range(4)))

pytorch入门

输出:

('GroundTruth:', '  cat  ship  ship plane')

现在,我们看下神经网络对images的预测结果

outputs=net(images)

这个outputs是一个10*1的向量,分别代表落在10个类别的概率。最高的那个值,就是神经网络预测的类别。所以,我们来看下outputs中最大的那个值是什么:

_, predicted = torch.max(outputs,1)
print('Predictions: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))

输出:

('Predictions: ', '  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, 1)
        total += labels.size(0)
        correct += (labels==predicted).sum().item()#sum得到预测值与实际值相等的数量,
                                                    # 但仍然是一个tensor,item取出这个tensor里面的值。
                                                    # 比如sum后,它为tensor(3);再item,它为3
print('Accuracy of the network on the 10000 test images: %d %%' %(
    100* correct /total
))

输出:

Accuracy of the network on the 10000 test images: 55 %

看起来这个结果很不错。如果完全随机的话准确率应该只会有10%,这个网络似乎学到了点东西。

嗯。在十个类别中,哪个类别的识别率低,哪个高呢?

class_correct = list(0. for i in range(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,1)
        c = (predicted == labels).squeeze()#squeeze可以除去size为1的维度。
                                            #比如size为(1,1,3),应用squeeze之后size为(3)
        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]
    ))

输出:

Accuracy of plane : 52 %
Accuracy of   car : 64 %
Accuracy of  bird : 40 %
Accuracy of   cat : 32 %
Accuracy of  deer : 40 %
Accuracy of   dog : 52 %
Accuracy of  frog : 70 %
Accuracy of horse : 59 %
Accuracy of  ship : 75 %
Accuracy of trunck : 63 %

 

相关标签: pytorch