pytorch初试:CNN实现

个人博客: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分类

  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

发布了74 篇原创文章 · 获赞 33 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_37394634/article/details/103975997