标签(空格分隔): 王小草Tensorflow笔记
笔记整理者:王小草
笔记整理时间:2017年2月25日
官方文档原文地址:https://www.tensorflow.org/get_started/mnist/pros
官方文档最近更新时间:2017年2月15日
欢迎机器学习,深度学习爱好者一起交流。
也欢迎关注我的喜马拉雅账号:”好吧我真的叫王草”。分享由集智俱乐部推出的两本好书:《科学的极致:漫谈人工智能》与《走进2050,注意力,互联网与人工智能》。
在上一篇笔记中介绍了用softmax去识别手写数字的图片,正确率只有92%。这篇笔记,仍然聚焦于同一个案例,但使用一个更复杂一点的模型来做训练:卷积神经网络(简称CNN)。从而正确率会到达99.2%。
关于卷积神经网络CNN在我之前的深度学习系列笔记中有详细介绍,欢迎阅读,在这里就不再赘述了。
1.数据准备
前面的过程与上一篇笔记一样:
1.导入tensorflow包
2.下载数据
3.创建会话
4.为输入的样本特征x与标签y建立占位符
代码如下,不再解释,不懂的可以看上一篇笔记
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
# 加载数据
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
# 创建会话
sess = tf.InteractiveSession()
# 设置占位符
x = tf.placeholder(tf.float32, shape=[None, 784])
y_ = tf.placeholder(tf.float32, shape=[None, 10])
2.初始化参数的方法封装
参数在训练中是会不断变更与优化的,所有为参数创建一组变量。因为在神经网络中每层都会有参数,一个一个去创建显然不科学,最好的方式是写一个function去封装创建参数变量的过程。在神经网络里涉及的参数仍然是2类:w,b.
# 创建w参数
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
# 创建b参数
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
以上代码中,tf.truncated_normal函数使得w呈正太分布,
stddev设置标准差为0.1。也就是说输入形状大小shape,输出标准差为0.1的正太分布的随机参数作为权重变量矩阵
对于参数b,使用了tf.constant()来创建一组指定大小的常数,常数值为0.1
在方法def中都分别初始化了这两个参数。
注意:在初始化参数的时候,也不是随便给一个值作为初始值的哈。模型对初始的参数是很敏感的,如果参数都很大,那么经过wx+b这个线性函数时,输出的值也会很大,若是经过tanh这个激活函数,输出的结果绝对值都几乎接近于1,也就是说每个神经元的输出都几乎相同,这完全违背了神经网络的初衷,事实上我们希望每个神经网络都能去学习一个不同的特征,他们的输出值应该是有差异的。另一方面,如果w值设置地太小了,经过线性函数wx+b的时候,wx可以忽略不计,于是线性函数的输出都约等于b,经过激活函数后的输出也几乎相同,又造成了神经元彼此雷同的尴尬局面呢。
对于参数b, 因为这里要使用的是RELU这个激活函数,所以最好设置成小一点的正数,从而来避免“神经元死亡”。RELU激活函数是,当输入大于0,则输出=输入值;若输入值小于0,则输出=0,想想,要是b是太大的负数,线性函数的输出也很有可能是负数,经过RELU之后就都变成0了。。。
3.创建卷积层与池化层的方法封装
Tensorflow也在卷积层与池化层给了很多灵活的操作。卷积层与池化层都需要设置一些超参数,比如步长,窗口大小,补全的边界等。那么我们该如何去定义边界,如何去选择步长呢?在这里我们选择使用步长为1,用0补全边界,故卷积层的输出与输入的数据大小是一致的。
在池化层中,使用2*2的窗口选取窗口中的最大值作为输出。
同样,一个神经网络会有很多个卷积层与池化层,我们不可能去一层一层写,为了使代码更简洁,最好将卷积层与池化层的创建封装成两个方法。如下:
# 创建卷积层,步长为1,周围补0,输入与输出的数据大小一样(可得到补全的圈数)
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
# 创建池化层,kernel大小为2,步长为2,周围补0,输入与输出的数据大小一样(可得到补全的圈数)
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
strides=[1, 2, 2, 1], padding=