Lenet5 论文学习,特点,代码实现

目录

 

LeNet5 论文

I Introduction

II 卷积神经网络在文字识别中的应用

A 卷积神经网络

B LeNet-5

III 实验结果及与其他分类方法 比较

​    

二、特点

三、代码实现


LeNet5 论文

论文:Gradient-Based Learning Applied to Document Recognition

          Lecun Y, Bottou L. Gradient-based learning applied to document recognition[J]. Proceedings of the                    IEEE,1998,86(11):2278-2324.

I Introduction

     在过去的几年中, 机器学习技术, 特别是在神经网络中的应用, 在模式识别系统的设计中发挥着越来越重要的作用。事实上, 可以说, 学习技术的可用性是近年来模式识别应用 (如连续语音识别和手写识别) 成功的关键因素。

     以文档理解为个案研究, 我们展示了通过手工集成单独设计的模块来构建识别系统的传统方法, 可以用统一的、原则性好的设计范式代替, 称为图形转换器网络, 允许训练所有模块以优化全局性能标准。

     在本研究中, 我们考虑了手写体字符识别的任务(第一和第二部分), 并将几种学习技术在基准数据集上的性能与手写数字识别(第三部分)进行了比较。虽然更多的自动学习是有益的, 没有学习技术可以成功, 而没有少量的先验知识的任务。在多层神经网络的情况下, 融合知识的一个好方法是将其结构调整为任务。第二部分中介绍的卷积神经网络是专门的神经网络体系结构的一个例子, 它通过使用局部连接模式和对权重施加约束, 将2D 形状的不变性知识结合起来。第三部分对几种独立手写体数字识别方法进行了比较。从对个别字符的识别到对文档中单词和句子的识别。第四五六部分提出了几种问题的解决方法,现在已经不被使用。

II 卷积神经网络在文字识别中的应用

      使用梯度下降法的多层网络可以从大量的数据中学习复杂的,高纬,非线性的映射,这使得他们成为图像识别任务的首选。

      对于字符识别,可以将图像作为行向量作为输入输入到网络中。虽然这些任务(比如字符识别)可以使用传统的前向全连接网络完成。但是还存在一些问题:

  1. 没有结构的网络的主要缺点是,多于图像或者音频这些应用来说,不具备平移,形变扭曲的不变性。在输入到固定大小输入的网络前,字符图像的大小必须归一化,并且放在输入的中间,不幸的是,没有哪种预处理能够达到如此完美。在下面描述的卷积神经网络中,位移不变性(shift invariance)可以通过权值共享实现。
  2. 全连接的网络的另一个缺点就是完全忽略了输入的拓扑结构。在不影响训练的结果的情况下,输入图像可以是任意的顺序。然而,图像具有很强的二维局部结构:空间相邻的像素具有高度相关性。局部相关性对于提取局部特征来说具有巨大优势,因为相邻像素的权值可以分成几类。CNN通过将隐藏结点的感受野限制在局部来提取特征。

A 卷积神经网络

      CNN通过局部感受野(local receptive fields),权值共享(shared weights),下采样(sub-sampling)实现位移,缩放,和形变的不变性(shift,scale,distortion invariance)。

       每一层的每个神经元(each unit)接受上一层中一组局部领域的神经元的输入(就是局部感受野)。利用图像的局部相关性

       我们可以将局部感受野位于图像不同位置的一组神经元设置为相同的权值(这就是权值共享)。减少了参数数量

       在特征图中降低特征位置的精度的方式是降低特征图的空间分辨率,这个可以通过下采样层达到,下采样层通过求局部平均降低特征图的分辨率,并且降低了输出对平移和形变的敏感度。卷积层和下采样层是交替出现的,这种形式形成一个金字塔:每一层,特征图的分辨率逐渐减低,而特征图的数量逐渐增加。降低特征位置的精度

B LeNet-5

    

          LeNet-5共有7层,不包含输入,输入图像为32*32大小的灰度图像

          C1卷积层,这一层的输入就是原始的图像,输入层接受图片的输入大小为32*32*1。卷积层的核(过滤器)尺寸为5*5,深度为6,不使用0进行填充,步长为1。卷积层总共的参数有5*5*1*6+6 =156个参数

          S2池化层。本层的输入是C1层的输出,它接受一个28*28*6的节点矩阵。所使用的核大小为2*2,长和宽的步长都是2,6*2 = 12个参数。

           C3卷积层,输入是一个14*14*6的矩阵,C3层一共有16卷积核,每一个卷积核的大小为5*5,输出是10*10*16。

           S4池化层, S4层的池化方式与S2层相同,输入是10*10*16,输出是5*5*16。

           F6全连接层,使用Sigmoid函数

           输出层,是由欧式径向基函数(RBF)组成。每一个输出对应一个RBF函数,每一个RBF函数都有84维的输入向量,RBF的函数公式如下。每一个RBF函数都会有一个输出,最后输出层会输出一个10维的向量。

III 实验结果及与其他分类方法 比较

   

二、特点

LeNet5特征能够总结为如下几点:
    1)卷积神经网络使用三个层作为一个系列: 卷积,池化,非线性
    2)使用卷积提取空间特征
    3)使用映射到空间均值下采样(subsample) 
    4)双曲线(tanh)或S型(sigmoid)形式的非线性
    6)层与层之间的稀疏连接矩阵避免大的计算成本

三、代码实现

Lenet5 的pytorch代码实现如下:

import torch
import os
import time
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from torchvision import transforms
from torch import optim
import torch.nn as nn
from torchvision.datasets import ImageFolder
from torchvision import transforms as T
from com.product.selftraining.zk import ZkUtil
from torchsummary import summary
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import json;
import cv2;
from PIL import Image;

# MINIST数据集
def loadMNIST():
    data_train = MNIST('./data/mnist',
                       download=True,
                       transform=transforms.Compose([
                           transforms.Resize((32, 32)),
                           transforms.ToTensor()]))
    # print(data_train.classes);
    size= len(data_train.class_to_idx);
    # print(data_train.class_to_idx);
    data_test = MNIST('./data/mnist',
                      download=True,
                      train=False,
                      transform=transforms.Compose([
                          # transforms.Resize((32, 32)),
                          transforms.ToTensor()]))
    # 并行处理数据
    data_train_loader = DataLoader(data_train, batch_size=256, shuffle=True, num_workers=8)
    data_test_loader = DataLoader(data_train, batch_size=1024, num_workers=8)
    return data_train, data_train, data_train_loader, data_test_loader

# Load data,从ImageFolder加载数据
def loadImage(batch_size, trainSetPath, testSetPath):
    transform = transforms.Compose([
        transforms.Resize((32, 32)),
        transforms.Grayscale(),
        transforms.ToTensor(),
    ]);

    trainset = ImageFolder(trainSetPath, transform=transform)
    testset = ImageFolder(testSetPath, transform=transform)
    size = len(trainset.class_to_idx);
    # device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    trainloader = DataLoader(trainset, batch_size=4, shuffle=True, num_workers=10)
    testloader = DataLoader(testset, batch_size=4, shuffle=False, num_workers=10)
    return trainset, testset, trainloader, testloader


# build network
class LeNet(nn.Module):
    size = 0;
    def __init__(self,size):
        super(LeNet, self).__init__()
        self.size = size;
        self.conv = nn.Sequential(
            # stride 步长  padding填充
            # (n+2*padding-f)/stride+1 向下取整
            # 输入32*32*1
            # 卷积层,输入32*32*1,输出28*28*6
            nn.Conv2d(1, 6, kernel_size=(5,5), stride=1),
            # 激活函数
            nn.ReLU(),
            # 池化层,输入28*28*6,输出14*14*6
            nn.MaxPool2d(kernel_size=(2, 2),stride=2),
            # 卷积层,输入14 * 14 * 6,输出10*10*16
            nn.Conv2d(6, 16, kernel_size=(5,5), stride=1),
            # 激活函数
            nn.ReLU(),
            # 池化层,输入10*10*16,输出5*5*16
            nn.MaxPool2d(kernel_size=(2, 2),stride=2),
            # 卷积层,输入5*5*16,输出1*1*120
            nn.Conv2d(16, 120, kernel_size=(5,5), stride=1),
            nn.ReLU()
        )
        self.fc = nn.Sequential(
            # 卷积层,输入120,输出84
            nn.Linear(120, 84),
            nn.ReLU(),
            # 卷积层,输入84,输出2
            nn.Linear(84, self.size),
            nn.Sigmoid(),
        )
    def forward(self, x):
        # 卷积运算
        out = self.conv(x)
        # Convert multidimensional data to 2D data
        out = out.view(out.size(0), -1)
        # 全连接运算
        out = self.fc(out)
        return out


def LeNetTrain():
    learning_rate = 1e-2
    batch_size = 199
    epoches = 50
    try:
    # trainset, testset, trainloader, testloader = loadMNIST(batch_size,trainSetPath,testSetPath)  # data
        start = time.time();
        trainset, testset, trainloader, testloader = loadMNIST();
        lenet = LeNet(len(trainset.class_to_idx))  # network
        print(summary(lenet,(1,32,32)));
        criterian = nn.CrossEntropyLoss(reduction='sum')
        for i in range(epoches):
            optimizer = optim.SGD(lenet.parameters(), lr=learning_rate)
            learning_rate= learning_rate*0.95
            running_loss = 0.
            running_acc = 0.
            for (img, label) in trainloader:
                optimizer.zero_grad()  #
                output = lenet(img)
                loss = criterian(output, label)
                loss.backward()
                optimizer.step()
                running_loss += loss.item()
                valu, predict = torch.max(output, 1)
                correct_num = (predict == label).sum()
                running_acc += correct_num.item()
            running_loss /= len(trainset)
            running_acc /= len(trainset)
            print("[%d/%d] Loss: %.5f, Acc: %.2f" % (i + 1, epoches, running_loss,
                                                     100 * running_acc));
        end = time.time();
        print(end-start);
        modelUrl = path + "/" + realName + ".pth";
        # only save the parameter of model
        torch.save(lenet, modelUrl);
    except(BaseException):
        print(BaseException);


if __name__ == '__main__':
     LeNetTrain()

 实现了两种加载训练集的方式,MINIST数据集下载较慢,可以自行下载数据集,之后更改配置文件加载本地数据集:

本地加载mnist数据集的方法

ImageFolder使用:ImageFolder

 

 

 

 

 

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值