pytorch深度学习笔记(2)------手写数字识别(卷积)

(小白笔记,有问题请指正)
手写数字识别可以说是学习深度学习的第一个代码了,相当于我们学习其他语言时的Hello World。在这里,我们要利用卷积来构建神经网络去完成手写数字识别案例。

卷积CNN
在我们使用卷积神经网络去完成手写数字识别案例时,我们要首先了解什么是卷积(CNN)。

传统神经网络层之间都采用全连接方式,但这种方式,如果输入的层数较多,输入又是高纬度的话,那么其参数将会很多很多以至于难以计算。例如训练一张1000×1000像素的灰色图片,如果隐层节点是100,那么参数就是1000×1000×100。因此机器学习在一段时间内一直处于停滞期,直到卷积的出现。

卷积神经网络由一个或多个卷积层和顶端的全连通层组成,同时也包括关联权重和池化层。卷积层就是卷积神经网络的核心层,而卷积又是卷积层的核心。简单的说,卷积就是两个函数的一种运算。
例如:输入一个2×2的矩阵[[1,2],[3,4]],卷积核设为2,那么输出为[[2,4],[6,8]]。那么我们再把输入和卷积核维度提高,输入变为5×5,卷积核变为3×3,那么这个卷积核将会在输入的矩阵上遍历,并提取特征,那么这些不同的特征可作为输出的不同通道,因此可扩展更高维度。
那如果我们处理的数据是多通道呢?其实我们输入的矩阵在图形角度是灰色的,没有考虑彩色图片的情况,但我们实际应用时输入的数据往往是多通道的,彩色图片就有三个通道(R,G,B),而多通道的计算和单通道基本一样的。无非是将每个单通道与卷积核进行卷积运算,并把3通道的和相加,得到输出图片的一个像素值。

池化
通过卷积层获得图像的特征后,理论上可以直接使用这些特征训练分类器,但是,这样计算量过大,并且容易出现过拟合。因此,为了进一步降低网络训练参数及模型的过拟合程度,就要对卷积层进行池化处理。

池化层在卷积神经网络中可以用来减小尺寸,提高运算速度及减小噪声影响,让各特征更具有健壮性。

手写数字识别

  1. 导库,定义超参数。
import numpy as np
import torch
import torchvision
import torch.utils.data as Data
from  torch import nn
from torch.autograd import Variable
import matplotlib.pyplot as plt

#定义超参数
EPOCH = 1 #因为用的是cpu 所以这里只训练1次
BATCH_SIZE = 50#定义每50个数据为1块
LR = 0.001# 学习率
DOWNLOAD_MNIST = False#看是否有数据

2.获取数据(从MNIST数据集中下载数据)

train_data = torchvision.datasets.MNIST(
    root='./minst',#根目录,如果没有数据则创建目录并下载,如果有则直接获取
    train=True,#是训练数据
    transform=torchvision.transforms.ToTensor(),#把下载的数据改成Tensor的格式  数据的值都会被压缩到(0,1)
    download=DOWNLOAD_MNIST #如果以及下载好数据,设置为False 没有则为True
)

train_loader = Data.DataLoader(dataset=train_data,batch_size=BATCH_SIZE,shuffle=True,num_workers=0)

test_data = torchvision.datasets.MNIST(root='./minst',train=False)
#提取test_data中的test_data,用unsqueeze加上维度,用Variable包裹一下
# 这里的归一化用的是除以255,因为RGB大小是在0到255之间的,我们把他压缩到0到1
test_x = Variable(torch.unsqueeze(test_data.test_data,dim=1),volatile=True).type(torch.FloatTensor)[:2000]/255.
test_y = test_data.test_labels[:2000]

3.定义神经网络,选取优化器和损失函数。
其中经历了两次卷积,两次池化和一次全连接

class CNN(nn.Module):
    def __init__(self):
        super(CNN,self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d( #图片维度是(1,28,28)
                in_channels=1,#这个参数是这个图片有多高(也就是有多少层),因为图片是灰的,有一层
                out_channels=16,#在一个位置提取16个特征,是16个卷积核,分别对图片进行卷积
                kernel_size=5,#过滤器是5*5的,在扫描图片时一次扫描5×5的区域
                stride=1,#是扫描时每隔几个跳一下 比如现在扫描的是12345  下次就是23456
                padding=2,#在原始的图片周围围上一圈0,因为过滤器扫描到边上时可能会多出来一部分
            ),#卷积像是一个过滤器,他有长宽高,长和宽决定了在图片上一次能搜集多少信息
            #高度决定了在这一地方提取的特征值
            #在卷积后维度变成了(16,28,28)
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2),#在进行一次卷积后会生成一张更厚(很多层)的图片,但此时长和宽也没有改变,
            # 因此要用池化筛选,相当与1个2×2的过滤器对他进行裁剪,
            #在池化后维度变成了(16,14,14)
        )
        self.conv2 = nn.Sequential(#此时的输入维度是(16,14,14)
            nn.Conv2d(16,32,5,1,2),#此时进行卷积变为了(32,14,14)
            nn.ReLU(),
            nn.MaxPool2d(2)#再次池化变为了(32,7,7)
        )
        self.out = nn.Linear(32*7*7,10)#因为图片要展开。因为图片是0-9有十个分类  所以输出10个分类

    def forward(self,x):
        x = self.conv1(x)
        x = self.conv2(x) #此时考虑了batch  为(batch,32,7,7)
        x = x.view(x.size(0),-1)    #保留batch维度(batch,32*7*7)  -1的作用就是把这些维度变一起
        output = self.out(x)
        return output

cnn = CNN()
# print(cnn)
optimizer = torch.optim.Adam(cnn.parameters(),lr=LR)#使用Adam过滤器
loss_func = nn.CrossEntropyLoss()

4.开始训练测试。

for epoch in range(EPOCH):
    train_loss = 0
    for step,(x,y) in enumerate(train_loader):
        b_x = Variable(x)
        b_y = Variable(y)#放入Variable中  可省略

        output = cnn(b_x)#向前传播
        loss = loss_func(output,b_y)#得到损失值
        optimizer.zero_grad()#设梯度为0
        loss.backward()#反向传播
        optimizer.step()#优化

        # train_loss += loss.item()
        if step%50 == 0:
            test_output = cnn(test_x)
            pred_y = torch.max(test_output,1)[1].data.squeeze()
            accuracy = float(sum(pred_y == test_y)) / float(test_y.size(0))
            # accuracy = float((pred_y == test_y.data.numpy()).astype(int).sum())/float(test_y.size(0))
            print('Epoch:',epoch,'| train loss :{:.4f}'.format(loss.item()),'| test accuracy:%.2f' % accuracy)
#loss.item()
test_output = cnn(test_x[:10])
pred_y = torch.max(test_output,1)[1].data.numpy().squeeze()
print(pred_y,'prediction number')
print(test_y[:10].numpy(),'real number')

5.运行结果

在这里插入图片描述
6.总源码

import numpy as np
import torch
import torchvision
import torch.utils.data as Data
from  torch import nn
from torch.autograd import Variable
import matplotlib.pyplot as plt

#定义超参数
EPOCH = 1 #因为用的是cpu 所以这里只训练1次
BATCH_SIZE = 50#定义每50个数据为1块
LR = 0.001# 学习率
DOWNLOAD_MNIST = False#看是否有数据

train_data = torchvision.datasets.MNIST(
    root='./minst',#根目录,如果没有数据则创建目录并下载,如果有则直接获取
    train=True,#是训练数据
    transform=torchvision.transforms.ToTensor(),#把下载的数据改成Tensor的格式  数据的值都会被压缩到(0,1)
    download=DOWNLOAD_MNIST #如果以及下载好数据,设置为False 没有则为True
)

# print(train_data.train_data.size())
# print(train_data.train_labels.size())
# plt.imshow(train_data.train_data[0].numpy(),cmap='gray')#显示train_data的第一张图片
# plt.title('%i'% train_data.train_labels[0])
# plt.show()

train_loader = Data.DataLoader(dataset=train_data,batch_size=BATCH_SIZE,shuffle=True,num_workers=0)

test_data = torchvision.datasets.MNIST(root='./minst',train=False)
#提取test_data中的test_data,用unsqueeze加上维度,用Variable包裹一下
# 这里的归一化用的是除以255,因为RGB大小是在0到255之间的,我们把他压缩到0到1
test_x = Variable(torch.unsqueeze(test_data.test_data,dim=1),volatile=True).type(torch.FloatTensor)[:2000]/255.
test_y = test_data.test_labels[:2000]

class CNN(nn.Module):
    def __init__(self):
        super(CNN,self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d( #图片维度是(1,28,28)
                in_channels=1,#这个参数是这个图片有多高(也就是有多少层),因为图片是灰的,有一层
                out_channels=16,#在一个位置提取16个特征,是16个卷积核,分别对图片进行卷积
                kernel_size=5,#过滤器是5*5的,在扫描图片时一次扫描5×5的区域
                stride=1,#是扫描时每隔几个跳一下 比如现在扫描的是12345  下次就是23456
                padding=2,#在原始的图片周围围上一圈0,因为过滤器扫描到边上时可能会多出来一部分
            ),#卷积像是一个过滤器,他有长宽高,长和宽决定了在图片上一次能搜集多少信息
            #高度决定了在这一地方提取的特征值
            #在卷积后维度变成了(16,28,28)
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2),#在进行一次卷积后会生成一张更厚(很多层)的图片,但此时长和宽也没有改变,
            # 因此要用池化筛选,相当与1个2×2的过滤器对他进行裁剪,
            #在池化后维度变成了(16,14,14)
        )
        self.conv2 = nn.Sequential(#此时的输入维度是(16,14,14)
            nn.Conv2d(16,32,5,1,2),#此时进行卷积变为了(32,14,14)
            nn.ReLU(),
            nn.MaxPool2d(2)#再次池化变为了(32,7,7)
        )
        self.out = nn.Linear(32*7*7,10)#因为图片要展开。因为图片是0-9有十个分类  所以输出10个分类

    def forward(self,x):
        x = self.conv1(x)
        x = self.conv2(x) #此时考虑了batch  为(batch,32,7,7)
        x = x.view(x.size(0),-1)    #保留batch维度(batch,32*7*7)  -1的作用就是把这些维度变一起
        output = self.out(x)
        return output

cnn = CNN()
# print(cnn)
optimizer = torch.optim.Adam(cnn.parameters(),lr=LR)#使用Adam过滤器
loss_func = nn.CrossEntropyLoss()

for epoch in range(EPOCH):
    train_loss = 0
    for step,(x,y) in enumerate(train_loader):
        b_x = Variable(x)
        b_y = Variable(y)#放入Variable中  可省略

        output = cnn(b_x)#向前传播
        loss = loss_func(output,b_y)#得到损失值
        optimizer.zero_grad()#设梯度为0
        loss.backward()#反向传播
        optimizer.step()#优化

        # train_loss += loss.item()
        if step%50 == 0:
            test_output = cnn(test_x)
            pred_y = torch.max(test_output,1)[1].data.squeeze()
            accuracy = float(sum(pred_y == test_y)) / float(test_y.size(0))
            # accuracy = float((pred_y == test_y.data.numpy()).astype(int).sum())/float(test_y.size(0))
            print('Epoch:',epoch,'| train loss :{:.4f}'.format(loss.item()),'| test accuracy:%.2f' % accuracy)
#loss.item()
test_output = cnn(test_x[:10])
pred_y = torch.max(test_output,1)[1].data.numpy().squeeze()
print(pred_y,'prediction number')
print(test_y[:10].numpy(),'real number')
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值