卷积神经⽹络(CNN)mnist⼿写字python源代码详解⾸先介绍下卷积神经⽹络
输⼊层我就不讲了,我主要根据代码讲下卷积层,池化层,全连接层。
(⼀)
卷积层
'''
-1代表着矩阵⾏不确定我这⾥⽤n表⽰,[-1,28,28,1]的意思是n⾏28列,
它的⼦元素是⼀个28⾏1列的矩阵,例如
[[[[1]], [[1]], [[1]], [[1]]],
[[[1]], [[1]], [[1]], [[1]]]]
可以表⽰为【2,4,1,1】它的⼦元素[[1]]为1⾏1列。在这⾥这个1也可以理解为通道数为1
'''
x_image = tf.reshape(x, [-1, 28, 28, 1])
'''
w_conv1代表着filter【5,5】为卷积核⼤⼩,1为通道数,32为卷积核的个数,卷积核个
数的选取需要凭经验,也许有⼤神知道⼀定的规律,这⾥我讲⼀下卷积核的通道数为什么需
要和输⼊的通道数⼀样,其实原理很简单,我们需要x_image和w_conv1相乘,也就需要它们两
个的⼦元素相乘,上边已经说过x_image的⼦元素为【28,1】,要想两者相乘,则w_conv1
⼦元素必须为【1,n]
'''
w_conv1 = weight_variable([5, 5, 1, 32])
卷积的计算包括两部分,输⼊和filter
卷积的计算(注意,下⾯蓝⾊矩阵周围有⼀圈灰⾊的框,那些就是上⾯所说到的填充值)
蓝⾊的矩阵(输⼊图像)对粉⾊的矩阵(filter)进⾏矩阵内积计算并将三个内积运算的结果与偏置值b相加(⽐如上⾯图的计算:2+(-2+1-2)+(1-2-2) + 1= 2 - 3 - 3 + 1 = -3),计算后的值就是绿框矩阵的⼀个元素。下⾯的动态图形象地展⽰了卷积层的计算过程:
代码中我们需要定义⼀个⽅法,来实现卷积
def conv2d(x, w):
b = v2d(x, w, strides=[1, 1, 1, 1], padding='SAME')
return b
卷积运算后,输出图⽚尺⼨缩⼩;
越是边缘的像素点,对于输出的影响越⼩,因为卷积运算在移动的时候到边缘就结束了。中间的像素点有可能会参与多次计算,但是边缘像素点可能只参与⼀次。所以我们的结果可能会丢失边缘信息。
  那么为了解决这个问题,我们引⼊padding, 什么是padding呢,就是我们认为的扩充图⽚, 在图⽚外围补充⼀些像素点,把这些像素点初始化为0.
① SAME
输出⼤⼩等于输⼊⼤⼩除以步长向上取整,s是步长⼤⼩;
我们这⾥的输⼊⼤⼩为2828的图像,filter ⼤⼩为55, 步长strides 为1所以输出⼤⼩也为2828,下⾯给出图解
假设我们输⼊矩阵为
我们先把矩阵扩充为
然后再与filter进⾏卷积运算,这样做是为了保留边界信息,否则的话我们的边界只进⾏了⼀次运算,⽽内部进⾏了多次
② VALUE
python代码转换输出⼤⼩等于输⼊⼤⼩减去滤波器⼤⼩加上1,最后再除以步长(f为滤波器的⼤⼩,s是步长⼤⼩)。假设我们输⼊⼤⼩为2828,步长为1,filter为55,那么输出⼤⼩为2424,图⽚有所缩⼩。
**(⼆)**激励层
把卷积层输出结果做⾮线性映射。
主要是增强输⼊输出之间的拟合性,
CNN采⽤的激励函数⼀般为ReLU(The Rectified Linear Unit/修正线性单元),它的特点是收敛快,求梯度简单,但较脆弱。代码如下
h_conv1 = lu(conv2d(x_image, W_conv1) + b_conv1)
**(三)**池化层
池化层夹在连续的卷积层中间, ⽤于压缩数据和参数的量,减⼩过拟合。
简⽽⾔之,如果输⼊是图像的话,那么池化层的最主要作⽤就是压缩图像。
这⾥再展开叙述池化层的具体作⽤。
1. 特征不变性,也就是我们在图像处理中经常提到的特征的尺度不变性,池化操作就是图像的resize,平时⼀张狗的图像被缩⼩了⼀倍
我们还能认出这是⼀张狗的照⽚,这说明这张图像中仍保留着狗最重要的特征,我们⼀看就能判断图像中画的是⼀只狗,图像压缩时去掉的信息只是⼀些⽆关紧要的信息,⽽留下的信息则是具有尺度不变性的特征,是最能表达图像的特征。
2. 特征降维,我们知道⼀幅图像含有的信息是很⼤的,特征也很多,但是有些信息对于我们做图像任务时没有太多⽤途或者有重复,我
们可以把这类冗余信息去除,把最重要的特征抽取出来,这也是池化操作的⼀⼤作⽤。
3. 在⼀定程度上防⽌过拟合,更⽅便优化。
池化层⽤的⽅法有Max pooling 和 average pooling,⽽实际⽤的较多的是Max pooling。
这⾥就说⼀下Max pooling,其实思想⾮常简单。
对于每个22的窗⼝选出最⼤的数作为输出矩阵的相应元素的值,⽐如输⼊矩阵第⼀个22窗⼝中最⼤的数是6,那么输出矩阵的第⼀个元素就是6,如此类推。
(四)全连接层
全连接层在我看来不⼤好理解,下⾯给出我⾃⼰的理解,全连接层的⽬的是将⽹络学习到的特征映射
到样本的标记空间中。全连接层会把卷积输出的⼆维特征图(featureMap)转化成⼀个⼀维的向量。本案例中我们进⾏了2次卷积,最后得到了64个77的⼆维特征图(featureMap),我们需要把它转化为⼀维的,即77*64,代码如下
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])              #reshape成向量
W_fc1 = weight_variable([7 * 7 * 64, 1024]) #1024代表卷积个数,我们可以任意取
b_fc1 = bias_variable([1024])
h_fc1 = lu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
这⾥我给个例⼦帮助你们理解tf.reshape(),请看代码
import numpy as np
import tensorflow as tf
input = tf.Variable([[[[1]], [[1]], [[1]], [[1]]],
[[[1]], [[1]], [[1]], [[1]]]], dtype=float)
b = tf.reshape(input, [1, 8])
print(np.shape(input))
print(np.shape(b))
运⾏结果为, 从结果中我们可以看出,转换规则为,2411=18
同理,因为我们全连接层的输⼊,就是卷积层的输出,我们经过两次卷积后的输出为h_pool2= [-1, 7, 7, 64],为什么是-1,是因为我们最初的输⼊x_image = [-1, 28, 28, 1] , -1 代表着⾏数不确定。
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])              #reshape成向量
我们就把 [-1, 7, 7, 64]转换为 [-1, 7764]。
谨记,全连接层不是卷积层,所以这⾥是
h_fc1 = lu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
我们⽤tf.matmul()只是把得到的特征值与权重w相乘再加上偏执b。
最后我们需要加上,
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
最后给出我们整个运算过程并附上代码。
代码
import tensorflow as tf

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。