pytorch初试:CNN实现


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分类

  1. 定义网络

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()

1.png

    最终的训练精度达到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

上一篇:
下一篇:

首页 所有文章 机器人 计算机视觉 自然语言处理 机器学习 编程随笔 关于