0%

pytorch学习笔记1

pytorch 快速入门

参考自《深度学习框架PyTorch入门与实践》

Tensor

Tensor是pytorch里最基础的数据结构,可以认为是一个高级数组。它可以包含一个数,一个一维数组,一个二维矩阵或更高维的数组。

Tensor的创建

创建一个Tensor的方法:

1
2
3
import torch as t
x=t.Tensor(5,3)
x

这种情况下,会生成一个内容全为0的Tensor:
image.png

随机生成Tensor的方法:

1
2
x=t.rand(2,3)
x

这样,Tensor里的每一个值都是一个0到1之间的随机数:
image.png

用t.ones()能生成全为1的Tensor,用t.zeros()能生成全为0的Tensor:

1
2
3
4
x=t.ones(2,3)
y=t.zeros(5,2)
print(x)
print(y)

image.png

得到Tensor的大小:

1
2
print(x.size())
x.size(0),x.size(1)

image.png

Tensor运算

Tensor之间的运算可以用 ‘+’、’-‘、’*’、’/‘等符号实现,也可以用add,sub等函数实现。

1
2
3
4
5
6
7
x=t.rand(2,3)
y=t.rand(2,3)
print(x)
print(y)
print(x+y)
print(x.add(y))
print(x)

image.png

值得注意的是,add函数并不会修改x的值,要实现x+=y,要用add_()函数:

1
2
3
4
5
6
7
x=t.rand(2,3)
y=t.rand(2,3)
print(x)
print(y)
print(x+y)
print(x.add_(y))
print(x)

image.png

Tensor与numpy的关系

Tensor的很多操作跟numpy差不多,它们也可以互相转换:

1
2
3
4
5
6
import numpy as np
x=np.ones(3)
y=t.from_numpy(x)
print(y)
z=y.numpy()
print(z)

image.png

值得注意的是,Tensor与nump对象的内存是共享的,因此其中一个改变的时候,另一个也会改变:
image.png

将Tensor转移到cuda上

可以通过.cuda方法把Tensor转移到GPU上:
image.png

Autograd

pytorch的Autograd模块提供了反向传播的功能。

autograd.Variable是Autograd中的核心类,它可以理解为Tensor的升级版。它的backward()方法能够自动计算梯度,提供了反向传播的功能。
image.png
image.png

由于y对x的每一个元素的偏导数都是1,所以x.grad是一个2*2的全为1的矩阵。
如果我们在调用一次y.backward(),会怎么样?
image.png

我们发现grad在反向传播的过程中是累加的,所以我们要将grad清零:
image.png

神经网络

torch.nn是专门为神经网络设计的模块化接口,可以用来定义和运行神经网络。nn.Module是nn中最重要的类,可以看成是神经网络的封装。

定义网络

一个网络需要继承nn.Module,并实现它的forward方法,并把具有可学习参数的层放在构造函数init中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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(1,6,5)#第一个参数是输入通道数,
#第二个参数是输出通道数,第三个参数是卷积核的大小。
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=F.max_pool2d(F.relu(self.conv1(x)),(2,2))
x=F.max_pool2d(F.relu(self.conv1(x)),2)# 这里的2跟(2,2)的效果是一样的
x=x.view(x.size()[0],-1)
x=F.relu(self.fc1(x))
x=F.relu(self.fc2(x))
x=self.fc3(x)
return x

net=Net()
print(net)

image.png

只要实现了forward方法,backward方法就会被自动实现。
网络的可学习参数可以通过net.parameters()得到:
image.png

image.png

forward函数的输入和输出都是Variable,因此在输入的时候要把Tensor变成Variable:
image.png

注意,input是一个4维的向量,其中第一维是batch的大小,神经网络的输入是一个batch,里面可以有很多张图像。第二维是图像的通道数。第三维第四维是图像的大小。

损失函数

nn里定义了很多损失函数,如MSELoss用来计算均方误差,CrossEntropyLoss用来计算交叉熵损失。
image.png

优化器

torch.optim 中实现了很多优化方法,可以用它们来对网络的参数进行更新:

1
2
3
4
5
6
7
import torch.optim as optim
optimizer=optim.SGD(net.parameters(),lr=0.01)
optimizer.zero_grad()
output=net(input)
loss=criterion(output,target)
loss.backward()
optimizer.step()

CIFAR-10 分类

CIFAR-10是一个常用的彩色图片数据集,共有10个类别,每张图片的大小都是33232。
我们利用torchvision提供的CIFAR-10数据集来训练一个神经网络,并让它对测试图片进行预测。

首先进行一些准备工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import torch as t
import torchvision as tv
import torchvision.transforms as transforms
from torchvision.transforms import ToPILImage
show=ToPILImage()
#show用于将Tensor对象转化为图片,以便于观察结果
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))])
#transform 用于对输入图像进行预处理
trainset=tv.datasets.CIFAR10(root='/home/cy/data/',train=True,download=True,transform=transform)
trainloader=t.utils.data.DataLoader(trainset,batch_size=4,shuffle=True,num_workers=2)
#用trainloader加载训练数据,batch_size=4说明一个batch是4张图片,num_worker=2说明用两个线程
testset=tv.datasets.CIFAR10('/home/cy/data/',train=False,download=True,transform=transform)
testloader=t.utils.data.DataLoader(testset,batch_size=4,shuffle=False,num_workers=2)
classes=('plane','car','bird','cat','deer','dog','frog','horse','ship','truck')

查看某一张照片:

1
2
3
(data,label)=trainset[100]
print(classes[label])
show((data+1)/2).resize((100,100))

image.png

定义一个网络:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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.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=F.max_pool2d(F.relu(self.conv1(x)),(2,2))
x=F.max_pool2d(F.relu(self.conv2(x)),2)# 这里的2跟(2,2)的效果是一样的
x=x.view(x.size()[0],-1)
x=F.relu(self.fc1(x))
x=F.relu(self.fc2(x))
x=self.fc3(x)
return x

net=Net()
print(net)

定义一个损失函数和优化器

1
2
3
from torch import optim
criterion = nn.CrossEntropyLoss()
optimizer=optim.SGD(net.parameters(),lr=0.001,momentum=0.9)

开始训练:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from torch.autograd import Variable
for epoch in range(2):
runnint_loss=0.0
for i,data in enumerate(trainloader,0):
inputs,labels=data
inputs,labels=Variable(inputs),Variable(labels)
#注意要将输入数据转化成Variable类型,不然无法训练
optimizer.zero_grad()
outputs=net(inputs)
loss=criterion(outputs,labels)
loss.backward()
optimizer.step()
runnint_loss+=loss.item()
if i%2000==1999:
print("[%d,%5d] loss: %3f"%(epoch+1,i+1,runnint_loss/2000))
runnint_loss=0.0
print("Finish trainning")

查看第一个batch的数据和标签:

1
2
3
4
dataiter=iter(testloader)
images,labels=dataiter.next()
print("实际的label:"," ".join("%08s"%classes[labels[j]] for j in range(4)))
show(tv.utils.make_grid(images/2-0.5)).resize((400,100))

image.png

查看它们的预测结果:

1
2
3
outputs=net(Variable(images))
_,predicted=t.max(outputs.data,1)
print("预测结果:","".join("%8s"%classes[predicted[j]] for j in range(4)))

查看总正确率:

1
2
3
4
5
6
7
8
9
10
11
correct=0
total=0
for data in testloader:
images,labels=data
outputs=net(Variable(images))
_,predicted=t.max(outputs.data,1)
#output.data是一个数组,max返回两个值,第一个是最大值,第二个是最大值所在的位置
total+=labels.size(0)
correct+=(predicted==labels).sum()
#根据最大值所在的位置是否跟labels相等可以判断分类是否正确
print("正确率为:%d %%"%(100*correct/total))