本文模型为tensorflow官方文档中,构建多层CNN完成MNIST训练的模型,通过复现模型来讲解用到的API以及对CNN进行一个简单的梳理。
权重初始化
tf.truncated_normal() 截断正态分布API
https://www.tensorflow.org/versions/r1.4/api_docs/python/tf/truncated_normal
首先使用正态分布,加入高斯噪声,打破对称性。然后使用截断正态分布是为了限制权重大小,不会太大。
所谓截断正态分布,就是只在我截断的区域里面取值,官方文档说是将取值限制在离均值2倍标准差的范围内。一旦超过这个范围,就重新取值。
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
卷积与池化
卷积
tf.nn.conv2d(input,filter,strides,padding,use_cudnn_on_gpu=None,data_format=None,name=None)
二维卷积API
https://www.tensorflow.org/api_docs/python/tf/nn/conv2d
首先讲述data_format,只有在规范了数据格式的情况下,才能更好的进行讨论。
data_format是该API的一个带有默认参数的输入,它的意义在于规范卷积的输入输出的数据格式,一般不需要定义。默认为"NHWC",即[batch, height, width, channels]。
input自然是我们的输入,对于第一层,就是我们的图片,格式为[mini_batch_size, 图片高度,图片宽度,图片通道数]
filter卷积核,它的格式是[filter_height, filter_width, in_channels, out_channels]。
strides步长,是配合卷积核在图片上进行卷积时,移动的步长,它的数据格式对应于input,对于二维卷积来说,strides[0] = strides[3] = 1, 在batch和channel方向上不存在跳步移动的。那么strides[1]就代表卷积核在图片高度上的移动,strides[2]就代表卷积核在图片宽度上的移动。
padding填充,有两种padding方式,'VALID’表示不进行padding,'SAME’表示进行zero padding。这两种padding方式要仔细讲一下,因为它们决定了我们输出的feature map的高度和宽度。
- VALID
不进行padding,卷积核在图片上通过strides进行滑动直到卷积核超出图片,卷积结束,无法卷积到的部分会被丢弃。那么输出的图像大小是多少呢,我们来计算一下。(我们只计算宽度方向,高度方向相似)
filter_width+n×stride≤in_width<filter_width+(n+1)×stridein_width−filter_widthstride<n+1≤in_width−filter_width+stridestride\text{filter\_width} + n \times \text{stride} \le \text{in\_width}< \text{filter\_width} + (n+1) \times \text{stride} \\ \frac{\text{in\_width} - \text{filter\_width}}{\text{stride}} < n+1 \le \frac{\text{in\_width} - \text{filter\_width} + \text{stride}}{\text{stride}} filter_width+n×stride≤in_width<filter_width+(n+1)×stridestridein_width−filter_width<n+1≤stride