卷积神经网络CNN(LeNet-5算法的tensorflow实现)

一、LeNet-5算法原理


      LeNet-5模型诞生于1998年,是Yann LeCun教授在论文Gradient-based learning applied to document recognition中提出的,它是第一个成功应用于数字识别问题的卷积神经网络,麻雀虽小五脏俱全,它包含了深度学习的基本模块:卷积层,池化层,全连接层。是其他深度学习模型的基础。
1998论文:http://pdfs.semanticscholar.org/162d/958ff885f1462aeda91cd72582323fd6a1f4.pdf

LeNet-5网络模型详解:https://blog.csdn.net/sinat_24143931/article/details/78958931

LeNet除了输入层,总共有7层。输入是32*32大小的图像

  1. C1是卷积层,卷积层的过滤器尺寸大小为5*5,深度为6,不使用全0补充,步长为1,所以这一层的输出尺寸为32-5+1=28,深度为6。
  2. S2层是一个池化层,这一层的输入是C1层的输出,是一个28286的结点矩阵,过滤器大小为22,步长为2,所以本层的输出为1414*6
  3. C3层也是一个卷积层,本层的输入矩阵为14146,过滤器大小为55,深度为16,不使用全0补充,步长为1,故输出为1010*16
  4. S4层是一个池化层 ,输入矩阵大小为101016,过滤器大小为22,步长为2,故输出矩阵大小为55*16
  5. C5层是一个卷积层,过滤器大小为55,和全连接层没有区别,这里可看做全连接层。输入为5516矩阵,将其拉直为一个长度为55*16的向量,即将一个三维矩阵拉直到一维向量空间中,输出结点为120。
  6. F6层是全连接层 ,输入结点为120个,输出结点为84个
  7. 输出层也是全连接层,输入结点为84个,输出节点个数为10。

                                   LeNet-5识别数字3的过程

通过对LeNet-5的网络结构的分析,可以直观地了解一个卷积神经网络的构建方法,为分析、构建更复杂、更多层的卷积神经网络做准备。

二、tensorflow框架实现

LeNet-5.py

import tensorflow as tf
from tensorflow.contrib.layers import flatten  #注释1

#定义LeNet网络
def LeNet(input_tensor):
    #C1是卷积层。 conv Input=32*32*1,Output=28*28*6,卷积层的过滤器尺寸大小为5*5,深度为6,不使用全0补充,步长为1
    conv1_w=tf.Variable(tf.truncated_normal(shape=[5,5,1,6],mean=1,stddev=0.1))#注释2
    conv1_b=tf.Variable(tf.zeros(6))#注释3
    conv1=tf.nn.conv2d(input_tensor,conv1_w,strides=[1,1,1,1],padding='VALID')+conv1_b#注释4
    conv1=tf.nn.relu(conv1)
    
    #S2是池化层 Pooling  Input=28*28*6 Output=14*14*6,过滤器大小为2*2,步长为2。
    pool_1=tf.nn.max_pool(conv1,ksize=[1,2,2,1],strides=[1,2,2,1],padding='VALID')#注释5
    
    #C3卷积层 conv Input=14*14*6 Output=10*10*6,过滤器大小为5*5,深度为16,不使用全0补充,步长为1
    conv2_w=tf.Variable(tf.truncated_normal(shape=[5,5,6,16],mean=1,stddev=0.1))
    conv2_b=tf.Variable(tf.zeros(16))
    conv2=tf.nn.conv2d(pool_1,conv2_w,strides=[1,1,1,1],padding='VALID')+conv2_b
    conv2=tf.relu(conv2)
    
    #S4池化层 Pooling Input=10*10*6, OutPut=5*5*16,过滤器大小为2*2,步长为2
    pool_2=tf.nn.max_pool(conv2,ksize=[1,2,2,1],strides=[1,2,2,1],padding='VALID')
    
    # Flatten Input=5*5*16 Output=400
    fc1=flatten(pool_2)
    
    #C5层是一个卷积层,过滤器大小为55,和全连接层没有区别,这里可看做全连接层。 Input=5*5*16=400 Output=120
    fc1_w=tf.Variable(tf.truncated_normal(shape=(400,120),mean=1,stddev=0.1))
    fc1_b=tf.Variable(tf.zeros(120))
    fc1=tf.matmul(fc1,fc1_w)+fc1_b
    
    #F6 Input=120 OutPut=84
    fc2_w = tf.Variable(tf.truncated_normal(shape=(120, 84), mean=0, stddev=0.1))
    fc2_b = tf.Variable(tf.zeros(84))
    fc2 = tf.matmul(fc1, fc2_w)+fc2_b
    fc2 = tf.nn.relu(fc2)

    # F7 Input=84  Output=10
    fc3_w = tf.Variable(tf.truncated_normal(shape=(84, 10), mean=0, stddev=0.1))
    fc3_b = tf.Variable(tf.zeros(10))
    logits = tf.matmul(fc2, fc3_w) + fc3_b
    return logits

注释:

1、tensorflow.contrib.layers.flatten

(1)TensorFlow层(contrib):https://www.w3cschool.cn/tensorflow_python/tensorflow_python-ugo128uh.html

建立神经网络层的高级操作,此包提供了一些操作,它们负责在内部创建以一致方式使用的变量,并为许多常见的机器学习算法提供构建块。包含用于构建神经网络层,正则化,摘要等的操作。

(2)tf API 研读1:tf.nn,tf.layers, tf.contrib概述

我们在使用tensorflow时,会发现tf.nn,tf.layers, tf.contrib模块有很多功能是重复的,尤其是卷积操作,在使用的时候,我们可以根据需要现在不同的模块。但有些时候可以一起混用。

        下面是对三个模块的简述:

  •  tf.nn :提供神经网络相关操作的支持,包括卷积操作(conv)、池化操作(pooling)、归一化、loss、分类操作、embedding、RNN、Evaluation。

        TensorFlow层(nn):https://www.w3cschool.cn/tensorflow_python/tensorflow_python-kd5h28vo.html

  •  tf.layers:主要提供的高层的神经网络,主要和卷积相关的,个人感觉是对tf.nn的进一步封装,tf.nn会更底层一些。
  •  tf.contrib:tf.contrib.layers提供够将计算图中的  网络层、正则化、摘要操作、是构建计算图的高级操作,但是tf.contrib包含不稳定和实验代码,有可能以后API会改变。

        TensorFlow层(contrib):https://www.w3cschool.cn/tensorflow_python/tensorflow_python-ugo128uh.html

以上三个模块的封装程度是逐个递进的。 

 1) 如果只是想快速了解一下大概,不建议使用tf.nn.conv2d类似的函数,可以使用tf.layers和tf.contrib.layers高级函数

 2) 当有了一定的基础后,如果想在该领域进行深入学习,建议使用tf.nn.conv2d搭建神经网络,此时会帮助你深入理解网络中参数的具体功能与作用,而且对于loss函数需要进行正则化的时候很便于修改。

且能很清晰地知道修改的地方。而如果采用tf.layers和tf.contrib.layers高级函数,由于函数内部有正则项,此时,不利于深入理解。而且如果编写者想自定义loss,此时比较困难,如如果读者想共享参数时,此时计算loss函数中的正则项时,应该只计算一次,如果采用高级函数可能不清楚到底如何计算的。

(3)Tensorflow contrib.layers 模块介绍

在tf.contrib.layers内部,有许多产生layer操作及其相关权重和偏差变量的函数。这些大部分都是用来构建不同深度学习架构的。也有些函数是提供归一化,卷积层,dropout层(注:Dropout是在训练过程中以一定概率1-p将隐含层节点的输出值清0),‘one-hot’编码等。下面来粗略浏览一下:

  • tf.contrib.layers.optimizers模块:tf.contrib.layers.optimizers包括的优化器有Adagrad,SGD,Momentum等。它们用来解决数值分析的优化问题,比如,优化参数空间寻找最优模型;
  • tf.contrib.layers.regularizers模块:tf.contrib.layers.regularizers包括的正则化有L1规则化和L2规则化。规则化经常被用来抑制模型训练时特征数过大导致的过拟合(overfitting)问题;有时也作为Lasso回归和Ridge回归的构建模块;
  • tf.contrib.layers.initializers模块:tf.contrib.layers.initializers一般用来做模型初始化。包括深度学习在内的许多算法都要求计算梯度来优化模型。随机初始化模型参数有助于在参数空间中找到最优参数解。TensorFlow提供的有Xavier初始化器,用来在所有层中保持梯度大体相同;
  • tf.contrib.layers.feature_column模块:tf.contrib.layers.feature_column提供函数(比如,bucketing/binning,crossing/compostion,和embedding)来转换连续特征和离散特征;
     

(4)tf.contrib.layers.flatten()和tf.contrib.layers.fully_connection()

  • tf.contrib.layers.flatten(P)这个函数就是把P保留第一个维度,把第一个维度包含的每一子张量展开成一个行向量,返回张量是一个二维的, shape=(batch_size,….),一般用于卷积神经网络全链接层前的预处理 
  • t f.contrib.layers.fully_connection(F,num_output,activation_fn)这个函数就是全链接成层,F是输入,num_output是下一层单元的个数,activation_fn是激活函数

2、tf.truncated_normal函数

(1)从截断的正态分布中输出随机值。

生成的值遵循具有指定平均值和标准偏差的正态分布,不同之处在于其平均值大于 2 个标准差的值将被丢弃并重新选择。

random_normal(
    shape,
    mean=0.0,
    stddev=1.0,
    dtype=tf.float32,
    seed=None,
    name=None
)

参数:

  • shape:一维整数张量或 Python 数组.输出张量的形状.
  • mean:dtype 类型的0-D张量或 Python 值.正态分布的均值.
  • stddev:dtype 类型的0-D张量或 Python 值.正态分布的标准差.
  • dtype:输出的类型.
  • seed:一个 Python 整数.用于为分发创建一个随机种子.查看 tf.set_random_seed 行为.
  • name:操作的名称(可选).

返回:

将返回一个指定形状的张量,通过随机的正常值填充。

(2)TensorFlow生成常量,序列和随机值

https://www.w3cschool.cn/tensorflow_python/tensorflow_python-efts28tw.html

随机张量

函数作用参数返回
tf.random_normal从正态分布中输出随机值. random_normal( shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None )将返回一个指定形状的张量,通过随机的正常值填充.
tf.truncated_normal

从截断的正态分布中输出随机值. 

生成的值遵循具有指定平均值和标准偏差的正态分布,不同之处在于其平均值大于 2 个标准差的值将被丢弃并重新选择.

tf.truncated_normal( shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None )将返回一个指定形状的张量,通过随机的正常值填充。

tf.random_uniform

从均匀分布中输出随机值。

生成的值在该 [minval, maxval) 范围内遵循均匀分布。对于浮点数,默认范围是 [0, 1)。对于整数,至少 maxval 必须明确地指定。

random_uniform( shape, minval=0, maxval=None, dtype=tf.float32, seed=None, name=None )用于填充随机均匀值的指定形状的张量。

tf.random_shuffle

随机地将张量沿其第一维度打乱.

张量沿着维度0被重新打乱,使得每个 value[j] 被映射到唯一一个 output[i]。

random_shuffle( value, seed=None, name=None )与 value 具有相同的形状和类型的张量,沿着它的第一个维度打乱。
tf.random_crop

随机地将张量裁剪为给定的大小. 

以一致选择的偏移量将一个形状 size 部分从 value 中切出.需要的条件:value.shape >= size.

random_crop( value, size, seed=None, name=None )与 value 具有相同的秩并且与 size 具有相同形状的裁剪张量.
tf.random_gamma

从每个给定的 Gamma distribution(s) 中绘制 shape 样本.

alpha 是描述 distribution(s) 的形状参数,并且 beta 是反比例参数(s).

random_gamma( shape, alpha, beta=None, dtype=tf.float32, seed=None, name=None )

samples:具有 dtype 类型值的带有形状 tf.concat(shape, tf.shape(alpha + beta)) 的 Tensor.

(3)TensorFlow随机张量:tf.set_random_seed函数

https://www.w3cschool.cn/tensorflow_python/tensorflow_python-fqc42jvo.html

3、tf.Variable函数

tf.Variable(initializer,name),参数initializer是初始化参数,name是可自定义的变量名称。

4、tf.nn.conv2d函数

tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)

函数作用:对输入数据进行二维卷积操作

参数说明:

  • input:输入,A 4-D tensor,shape为[batch_size, input_height, input_width, input_channels],数据类型必须为float32或者float64
  • filter: 卷积核,A 4-D tensor,shape为[filter_height, filter_width, input_channels, output_channels], 和input有相同的数据类型
  • strides: 步长,一个长度为4的一维列表,每一位对应input中每一位对应的移动步长,在使用中,由于input的第一维和第四维不参与卷积运算,所以strides一般为[1, X, X, 1]
  • padding: 填充方式,一个字符串,取值‘SAME’或者‘VALID’. 当padding = ‘SAME’时,tensorflow会自动对原图像进行补零操作,从而使得输入和输出的图像大小一致;当padding = ‘VALID’时, 采用不填充的方式,会根据计算公式缩小原图像的大小,计算公式为(W-F+2P)/S+1, W是图像大小,F为卷积核大小,P是填充数量,S是步长。
  • use_cudnn_on_gpu=None : 可选布尔值,默认为True
     

4、tf.nn.max_pool函数

池化:池化层的主要目的是通过降采样的方式,在不影响图像质量的情况下,压缩图片,减少参数。子采样有两种形式,一种是均值子采样,即是对一个区域里的元素求平均值;另一种就是最大值采样,即是在一个区域中寻找最大值,如下图所示。

 

# 平均池化
tf.nn.avg_pool(value, ksize, strides, padding, name=None)
# 最大化池化
tf.nn.max_pool(value, ksize, strides, padding, name=None)


函数作用:对输入进行池化操作

参数说明:

  • value:池化输入,A 4-D tensor,shape为[batch_size, input_height, input_width, input_channels],数据类型为float32,float64,qint8,quint8,qint32
  • ksize:池化窗口大小,A 4-D tensor,一般为[1, X, X, 1]
  • strides:步长,一般为[1, X, X, 1],同上述卷积运算的strides
  • padding:填充,一个字符串取值‘SAME’或者‘VALID’,同上述卷积运算的padding
     

 

 

 

参考博客:

tf API 研读1:tf.nn,tf.layers, tf.contrib概述:https://blog.csdn.net/u014365862/article/details/77833481

Tensorflow contrib.layers 模块介绍:https://blog.csdn.net/hengxingheng/article/details/80431693

MachineLP博客目录:https://blog.csdn.net/u014365862/article/details/78422372

tensorflow学习(一)——有关tensorflow不同层的使用(tf.nn 和tf.layers以及tf.contrib.layers)的简单区别:https://blog.csdn.net/holmes_MX/article/details/82317742

tf.contrib.layers.flatten()和tf.contrib.layers.fully_connection():https://blog.csdn.net/CZ505632696/article/details/79389694

tensorflow mnist实战笔记(一)了解官方mnist数据格式:https://blog.csdn.net/hjxu2016/article/details/73613671

详解 MNIST 数据集:https://blog.csdn.net/simple_the_best/article/details/75267863

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值