个人博客:http://www.chenjianqu.com/
原文链接:http://www.chenjianqu.com/show-66.html
PyTorch
1.Pytorch介绍
Torch是一个有大量机器学习算法支持的科学计算框架,其诞生已有十年之久,但是真正起势得益于Facebook开源了大量Torch的深度学习模块和扩展。Torch的特点在于特别灵活,但是另一个特殊之处是采用了编程语言Lua,在深度学习大部分以Python为编程语言的大环境之下,一个以Lua为编程语言的框架有着更多的劣势,这一项小众的语言增加了学习使用Torch这个框架的成本。
PyTorch的前身便是Torch,其底层和Torch框架一样,但是使用Python重新写了很多内容,不仅更加灵活,支持动态图,而且提供了Python接口。它是由Torch7团队开发,是一个以Python优先的深度学习框架,不仅能够实现强大的GPU加速,同时还支持动态神经网络,这是很多主流深度学习框架比如Tensorflow等都不支持的。PyTorch既可以看作加入了GPU支持的numpy,同时也可以看成一个拥有自动求导功能的强大的深度神经网络。除了Facebook外,它已经被Twitter、CMU和Salesforce等机构采用。
2.基本概念
Tensor
PyTorch 里最基本的操作对象,表示的是一个多维的矩阵。可以和 numpy的ndarray相互转换,唯一不同的是 PyTorch可以在GPU上运行,而 numpy 的 ndarray只能在 CPU 上运行。
import torch as t
#默认是float的矩阵
a=t.Tensor([[2,3],[4,7],[3,2]])
print(a)
print('size={}'.format(a.size()))
常用的不同数据类型的 Tensor,有
32 位浮点型 torch.Float Tensor
64 位浮点型 torch.DoubleTensor
16 位整型 torch.ShortTensor
32 位整型 torch.lntTensor
64 位整型 torch.LongTensor
b = t.LongTensor([[2,3],[4,7],[3,2]])#创建长整型张量
print(b.type())
fb=b.float()#数据类型转换
print(fb.type())
b[0,0]=100
print(fb)
c=t.zeros((3,2))#创建张量
d=t.ones((3,2))
e=t.randn((3,2))
print(c)
print(d)
print(e)
import numpy as np
bb=b.numpy()#与numpy交互
print(bb)
n=np.ones((2,2))
nt=t.from_numpy(n)
print(nt)
print(t.cuda.is_available())#判断是否支持GPU
if(t.cuda.is_available()):
a_cuda=a.cuda()#放入GPU中运行
print(a_cuda)
变量
是神经网络计算图里特有的一个概念,Variable 提供了自动求导的功能,神经网络在做运算的时候需要先构造一个计算图,然后在里面进行前向传播和反向传播。Variable 和 Tensor本质上没有区别,不过 Variable 会被放入一个计算图中,然后进行前向传播,反向传播,自动求导。Variable 是在torch.autograd.Variable 中的。
变量求导:
from torch.autograd import Variable
#创建变量
x=Variable(t.Tensor([1]),requires_grad=True)
w=Variable(t.Tensor([2]),requires_grad=True)
b=Variable(t.Tensor([3]),requires_grad=True)
#构建计算图
y=w*x+b
#计算梯度
y.backward()
print(x.grad) #y对x求导
print(w.grad) #y对w求导
print(b.grad) #y对b求导
对矩阵求导:
x=t.randn(3)
x=Variable(x,requires_grad=True)
y=x*2
print(y)
#y对x求导,需要系数矩阵,得到的梯度是原本的每个分量的梯度分别乘以系数
y.backward(t.FloatTensor([1,0.1,0.01]))
print(x.grad)
数据集
在处理任何机器学习 问题之前都需要数据读取, 并进行预处理。 PyTorch 提供了很多工具使得数据的读取和预处理变得很容易 。
torch.utils.data.Dataset 是代表这一数据的抽象类,你可以 自 己定义你的数据类继 承和重写这个抽象类 ,非常简单,只需要定义__len__和__getitem__这两个函数
nn.Module(模组)
在 PyTorch 里面编写神经网络,所有的层结构和损失函数都来自于 torch.nn,所 有的模型构建都是从这个基类 nn.Module 继承的,于是有了下面这个模板:
class net_name(t.nn.Module):
def __init__(self,other_argument):
super(net_name,self).__init__()
self.conv=t.nn.Conv2d(in_channels,out_channels,kernel_size)
def forward(self,x):
x=self.conv1(x)
return x
模型的加载和保存
保存模型的结构和参数: torch.save(model,'./model.pth ' )
保存模型的参数: torch.save(model.state_dict(),'./model_state.pth')
加载模型的结构和参数: load model = torch.load('model.pth' )
加载模型的参数 model.load state_dic(torch.load('model state.pth'))
CNN实现MNIST分类
-
定义网络
import torch as t from torch import nn,optim from torch.autograd import Variable from torch.utils.data import DataLoader from torchvision import datasets,transforms class MyCNN(nn.Module): def __init__(self): super(MyCNN,self).__init__() layer=nn.Sequential() layer.add_module('conv1',nn.Conv2d(1,16,3,stride=1,padding=0)) layer.add_module('conv1_bn',nn.BatchNorm2d(16)) layer.add_module('conv1_relu',nn.ReLU(True)) layer.add_module('conv2',nn.Conv2d(16,32,3,stride=1,padding=0)) layer.add_module('conv2_bn',nn.BatchNorm2d(32)) layer.add_module('conv2_relu',nn.ReLU(True)) layer.add_module('pool1',nn.MaxPool2d(2,2,padding=0)) layer.add_module('conv3',nn.Conv2d(32,64,3,stride=1,padding=0)) layer.add_module('conv3_bn',nn.BatchNorm2d(64)) layer.add_module('conv3_relu',nn.ReLU(True)) layer.add_module('conv4',nn.Conv2d(64,128,3,stride=1,padding=0)) layer.add_module('conv4_bn',nn.BatchNorm2d(128)) layer.add_module('conv4_relu',nn.ReLU(True)) layer.add_module('pool2',nn.MaxPool2d(2,2,padding=0)) self.cnn=layer linear=nn.Sequential() linear.add_module('fc1',nn.Linear(128*4*4,1024)) linear.add_module('fc1_relu',nn.ReLU(True)) linear.add_module('fc1_dropout',nn.Dropout()) linear.add_module('fc2',nn.Linear(1024,128)) linear.add_module('fc2_relu',nn.ReLU(True)) linear.add_module('fc2_dropout',nn.Dropout()) linear.add_module('fc3',nn.Linear(128,10)) self.linear=linear def forward(self,x): x=self.cnn(x) x=x.view(x.size(0),-1) x=self.linear(x) return x
2.载入数据集
batch_size=128 learning_rate=1e-2 epoch=20 #定义数据预处理 data_tf=transforms.Compose(#将各个预处理操作组合在一起 [transforms.ToTensor(),#将图片转换为Tensor,转化过程中自动将图片转换为0-1范围 transforms.Normalize([0.5],[0.5]) #标准化,参数:均值、方差。这样图片转换为[-1,1]之间 #transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5]) #如果是RGB图像的话 ] ) #导数数据集 train_dataset=datasets.MNIST( root='./data', train=True, transform=data_tf,#预处理 download=True ) test_dataset=datasets.MNIST( root='./data', train=False, transform=data_tf ) #定义数据迭代器 train_loader=DataLoader(train_dataset,batch_size=batch_size,shuffle=True) test_loader=DataLoader(test_dataset,batch_size=batch_size,shuffle=True)
3.训练模型
acc_history=[] loss_history=[] model=MyCNN() model=model.cuda() batch_epoch=int(len(train_loader)/batch_size) criterion=nn.CrossEntropyLoss() sgd=optim.SGD(model.parameters(),lr=learning_rate) for e in range(epoch): sum_loss=0.0 sum_acc=0 for i,data in enumerate(train_loader) : img,label=data #img=img.view(img.size(0),-1) #返回一个有相同数据但大小不同的tensor。 img=Variable(img).cuda() label=Variable(label).cuda() y=model(img) loss=criterion(y,label) #反向传播 sgd.zero_grad() loss.backward() #计算梯度 sgd.step() #更新参数 sum_loss+=loss.item() _,pred=t.max(y,1) num_correct=(pred==label).sum() sum_acc+=num_correct.item() loss_v=sum_loss/len(train_loader) acc_v=sum_acc/len(train_dataset) acc_history.append(acc_v) loss_history.append(loss_v) print('epoch:%d,loss:%f,acc:%f'%(e,loss_v,acc_v))
画出训练过程的acc和Loss曲线:
%matplotlib inline import matplotlib.pyplot as plt x_epoch = range(0, epoch) plt.subplot(2, 1, 1) plt.plot(x_epoch, acc_history, '.-') plt.title('acc') plt.ylabel('acc') plt.xlabel('epoch') plt.subplot(2, 1, 2) plt.plot(x_epoch,loss_history , '.-') plt.ylabel('loss') plt.xlabel('epoch') plt.show()
最终的训练精度达到99.3%
4.测试模型
model.eval() eval_loss=0 eval_acc=0 for data in test_loader: img,label=data img=Variable(img,volatile=True).cuda() label=Variable(label,volatile=True).cuda() y=model(img) loss=criterion(y,label) eval_loss+=loss.item()*label.size(0) _,pred=t.max(y,1) num_correct=(pred==label).sum() eval_acc+=num_correct.item() print('test loss:%f \ntest acc:%f'%( eval_loss/len(test_dataset), eval_acc/len(test_dataset)))
测试精度同样达到99.3%
参考文献
[1] 廖星宇.深度学习入门之PyTorch