深度学习——LeNetLeNet解析

前言::LeNet是最早用于数字识别的CNN网络,本文就以数字识别为例,分析下这个最基本的CNN网络。

LeNet解析

网络结构如下图所示:

  • C1层是一个卷积层 6个特征图,每个特征图中的每个神经元与输入中55的邻域相连,特征图大小为2828 每个卷积神经元的参数数目:5*5=25个weight参数和一个bias参数 链接数目:(5*5+1)*6*(28*28)=122304个链接 参数共享:每个特征图内共享参数,因此参数总数:共(5*5*1)*6=156个参 数
  • S2层是一个下采样层 6个1414的特征图,每个图中的每个单元与C1特征图中的一个22邻域相连接, 不重叠。因此,S2中每个特征图的大小是C1中的特征图大小的1/4。 S2层每个单元的4个输入相加,乘以一个可训练参数w,再加上一个可训练偏 置b,结果通过sigmoid函数计算 连接数:(2*2+1)*1*14*14*6=5880个 参数共享:每个特征图内共享参数,因此有2*6=12个可训练参数
  • C3层是一个卷积层 16个卷积核,得到16张特征图,特征图大小为1010 每个特征图中的每个神经元与S2中某几层的多个5*5的邻域相连; 例如:对于C3层第0张特征图,其每一个节点与S2层的第0~2张特征图,总共 3个55个节点相连接。
  • S4层是一个下采样层 由16个5*5大小的特征图构成,特征图中的每个单元与C3中相应特征图的2*2 邻域相连接。 连接数:(2*2+1)*5*5*16=2000个 参数共享:特征图内共享参数,每个特征图中的每个神经元需要1个因子和一 个偏置,因此有2*16个可训练参数。
  • C5层是一个卷积层 120个神经元,可以看作120个特征图,每张特征图的大小为1*1 每个单元与S4层的全部16个单元的5*5邻域相连(S4和C5之间的全连接) 连接数=可训练参数:(5*5*16+1)*120=48120个
  • F6层是一个全连接层 有84个单元(之所以选这个数字的原因来自于输出层的设计),与C5层全连 接。 F6层计算输入向量和权重向量之间的点积,再加上一个偏置。 连接数=可训练参数:(120+1)*84=10164 84:stylized image:7*12 代码来还原上述层次如下:
def le_net(x, y):
    # 1. 输入层
    with tf.variable_scope('input1'):
        # 将输入的x的格式转换为规定的格式
        # [None, input_dim] -> [None, height, weight, channels]
        net = tf.reshape(x, shape=[-1, 28, 28, 1])
    # 2. 卷积层
    with tf.variable_scope('conv2'):
        # 卷积
        # conv2d(input, filter, strides, padding, use_cudnn_on_gpu=True, data_format="NHWC", name=None) => 卷积的API
        # data_format: 表示的是输入的数据格式,两种:NHWC和NCHW,N=>样本数目,H=>Height, W=>Weight, C=>Channels
        # input:输入数据,必须是一个4维格式的图像数据,具体格式和data_format有关,如果data_format是NHWC的时候,input的格式为: [batch_size, height, weight, channels] => [批次中的图片数目,图片的高度,图片的宽度,图片的通道数];如果data_format是NCHW的时候,input的格式为: [batch_size, channels, height, weight] => [批次中的图片数目,图片的通道数,图片的高度,图片的宽度]
        # filter: 卷积核,是一个4维格式的数据,shape: [height, weight, in_channels, out_channels] => [窗口的高度,窗口的宽度,输入的channel通道数(上一层图片的深度),输出的通道数(卷积核数目)]
        # strides:步长,是一个4维的数据,每一维数据必须和data_format格式匹配,表示的是在data_format每一维上的移动步长,当格式为NHWC的时候,strides的格式为: [batch, in_height, in_weight, in_channels] => [样本上的移动大小,高度的移动大小,宽度的移动大小,深度的移动大小],要求在样本上和在深度通道上的移动必须是1;当格式为NCHW的时候,strides的格式为: [batch,in_channels, in_height, in_weight]
        # padding: 只支持两个参数"SAME", "VALID",当取值为SAME的时候,表示进行填充,"在TensorFlow中,如果步长为1,并且padding为SAME的时候,经过卷积之后的图像大小是不变的";当VALID的时候,表示多余的特征会丢弃;
        net = tf.nn.conv2d(input=net, filter=get_variable('w', [5, 5, 1, 20]), strides=[1, 1, 1, 1], padding='SAME')
        net = tf.nn.bias_add(net, get_variable('b', [20]))
        # 激励 ReLu
        # tf.nn.relu => max(fetures, 0)
        # tf.nn.relu6 => min(max(fetures,0), 6)
        net = tf.nn.relu(net)
    # 3. 池化
    with tf.variable_scope('pool3'):
        # 和conv2一样,需要给定窗口大小和步长
        # max_pool(value, ksize, strides, padding, data_format="NHWC", name=None)
        # avg_pool(value, ksize, strides, padding, data_format="NHWC", name=None)
        # 默认格式下:NHWC,value:输入的数据,必须是[batch_size, height, weight, channels]格式
        # 默认格式下:NHWC,ksize:指定窗口大小,必须是[batch, in_height, in_weight, in_channels], 其中batch和in_channels必须为1
        # 默认格式下:NHWC,strides:指定步长大小,必须是[batch, in_height, in_weight, in_channels],其中batch和in_channels必须为1
        # padding: 只支持两个参数"SAME", "VALID",当取值为SAME的时候,表示进行填充,;当VALID的时候,表示多余的特征会丢弃;
        net = tf.nn.max_pool(value=net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    # 4. 卷积
    with tf.variable_scope('conv4'):
        net = tf.nn.conv2d(input=net, filter=get_variable('w', [5, 5, 20, 50]), strides=[1, 1, 1, 1], padding='SAME')
        net = tf.nn.bias_add(net, get_variable('b', [50]))
        net = tf.nn.relu(net)
    # 5. 池化
    with tf.variable_scope('pool5'):
        net = tf.nn.max_pool(value=net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    # 6. 全连接
    with tf.variable_scope('fc6'):
        # 28 -> 14 -> 7(因为此时的卷积不改变图片的大小)
        net = tf.reshape(net, shape=[-1, 7 * 7 * 50])
        net = tf.add(tf.matmul(net, get_variable('w', [7 * 7 * 50, 500])), get_variable('b', [500]))
        net = tf.nn.relu(net)
    # 7. 全连接
    with tf.variable_scope('fc7'):
        net = tf.add(tf.matmul(net, get_variable('w', [500, n_classes])), get_variable('b', [n_classes]))
        act = tf.nn.softmax(net)

    return act

详细代码可以从我的github网站下载:https://github.com/dctongsheng/Lenet/upload

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏人工智能LeadAI

关于numpy mean函数的axis参数

理解多维矩阵的"求和"、"平均"操作确实太恶心了,numpy提供的函数里还有一堆参数,搞得晕头转向的,这里做个笔记,提醒一下自己, 下面是例程 import n...

3407
来自专栏marsggbo

空间金字塔池化(Spatial Pyramid Pooling, SPP)原理和代码实现(Pytorch)

想直接看公式的可跳至第三节 3.公式修正 一、为什么需要SPP 首先需要知道为什么会需要SPP。 我们都知道卷积神经网络(CNN)由卷积层和全连接层组成,其中...

4626
来自专栏null的专栏

简单易学的机器学习算法——在线顺序极限学习机OS-ELM

   这篇文章主要是前面整理的,就直接上图了。 ? ? ? ? ? ? ? 实验: # coding:UTF-8 ################# # OS_...

9375
来自专栏书山有路勤为径

回顾:训练神经网络

我们可以将这些单元神经元组合为层和堆栈,形成神经元网络。一个神经元层的输出变成另一层的输入。对于多个输入单元和输出单元,我们现在需要将权重表示为矩阵。

822
来自专栏智能算法

深度学习三人行(第4期)---- TF训练DNN之进阶

2128
来自专栏机器学习与自然语言处理

Stanford机器学习笔记-5.神经网络Neural Networks (part two)

5 Neural Networks (part two) content:   5 Neural Networks (part two)     5.1 cos...

35410
来自专栏PaddlePaddle

【词向量】Hsigmoid加速词向量训练

导语 PaddlePaddle提供了丰富的运算单元,帮助大家以模块化的方式构建起千变万化的深度学习模型来解决不同的应用问题。这里,我们针对常见的机器学习任务,提...

2718
来自专栏杂七杂八

线性分类器损失函数与最优化(上)

使用正则化一方面的优化参数,另一方面是权衡训练损失和用于测试集的泛化损失。尽管有时候会使训练集上的效果变差,甚至是分类错误,但是对于测试集的训练效果是有很大效果...

932
来自专栏机器学习算法与Python学习

机器学习(4) --神经网络(part two)

content: 5 Neural Networks (part two)     5.1 cost function     5.2 Back Propag...

3015
来自专栏机器之心

教程 | 用数据玩点花样!如何构建skim-gram模型来训练和可视化词向量

3756

扫码关注云+社区