TensorFlow官方教程学习笔记(三)——MNIST入门(续)

22 篇文章 1 订阅
13 篇文章 1 订阅

教程地址:TensorFlow官方文档中文版


上一篇文章中,我们使用了一个简单的SoftMax的回归模型对MNIST手写数字数据集进行训练,经过1000次的跌代后,识别精度达到了91%,但这是远远不够的。

在本章中,我们使用一个稍微复杂的模型,其实也不是很复杂,一个含有两个卷积层的卷积神经网络,来测试它的识别效果。


同样的,mnist数据集的四个文件放在\tutorials\mnist\目录下的MNIST_data文件夹中,在Python中cd到\tutorials\mnist\的目录下,使用以下代码:

import input_data  
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) 

数据集就被提取为三个部分:mnist.train、mnist.test和mnist.validation,每个部分包含有images和labels。train、test和validation中样本的数量分别为55000、10000和5000。

在这里,教程中使用了一个交互的环境(InteractiveSession)来构建Session,这样的好处是,不需要在指定的会话中运行变量,即不需要使用 sess.run()的形式,而是定义好会话对象后,每次执行tensor时,调用tensor.eval()即可,这样使得操作起来更加灵活、高效。但是值得注意的是,使用Session()时,可以用with..as..来定义,后面可以不使用close()关闭对话,而InteractiveSession不能通过with..as..来定义,并且需要在最后调用close()。代码如下:

import tensorflow as tf
sess = tf.InteractiveSession()

接下来,我们定义权值和偏执两个变量的初始化函数,因为在这个模型中,我们将用到多组weight和bias:

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)

这里weight使用一个标准方差为0.1的正态分布来初始化,bias使用常量0.1来初始化,在教程中,提到这样做的目的是使用一个较小的正数来初始化偏置项,可以避免ReLU神经元节点输出恒为0的问题(dead neurons),ReLU的激活函数是:max(0,x),使用ReLU的好处是既可以保证稀疏性,也可以避免梯度消失。


然后我们定义卷积和池化操作:

def conv2d(x, W):
  return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

def max_pool_2x2(x):
  return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                        strides=[1, 2, 2, 1], padding='SAME')

卷积层的作用是提取局部特征,池化的作用是降维,了解卷积神经网络的应该清楚,因此不再赘述。在这里,x代表输入,W代表卷积核,即weight,卷积的步长(stride)为1,padding='SAME'的意思是在输入矩阵的上下左右分别扩充值为0的边,输出矩阵的尺寸根据以下方式进行计算:

out_height = ceil(float(in_height) / float(strides[1]))
out_width = ceil(float(in_width) / float(strides[2]))
padding还有一个参数'VALID',表示对输入矩阵不进行扩充,输出矩阵尺寸的计算方式如下:

out_height = ceil(float(in_height - filter_height + 1) / float(strides1))
out_width = ceil(float(in_width - filter_width + 1) / float(strides[2]))

这里使用2*2的最大化池化(max pooling),输出矩阵的尺寸为输入矩阵尺寸的一半。


构建占位符:

x = tf.placeholder("float", shape=[None, 784])
y_ = tf.placeholder("float", shape=[None, 10])

x和y_分别代表样本图片和标签真值,None表示样本的数量可以使任意的。


然后我们就可以来构建模型的第一层了,这一层包含一个卷积层和一个max pooling层,代码如下:

x_image = tf.reshape(x, [-1,28,28,1])
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)

首先将输入x变换成一个4D的数据,维度为[-1, 28, 28, 1],第一维-1代表x中样本的总数,第二、第三维对应图片的宽、高,第四维代表图片的通道数,灰度图像为1,彩色图像为3。W_conv1为第一个卷积层的卷积核,[5, 5, 1, 32]表示卷积核的大小为5*5,输入通道数为1,输出通道数为32,也代表提取的32个特征。h_conv1为第一个卷积层的输出,激活函数为ReLU,输出的尺寸和输入的尺寸一致,为28*28,然后紧接了一个2*2的max pooling层,输出的尺寸为14*14。

接下来,模型的第二层,同样也是一个卷积层和一个max pooling层:

W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)


第二个卷积层的卷积核大小依然是5*5,输入通道数为32,输出通道数为64,表示64个特征,其余的和第一层类似。卷积层输出的尺寸为14*14,max pooling的输出尺寸为7*7。


接下来是模型的第三层,这一层是一个全连接层,全连接层的目的是提取全局特征:

W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

因为处理的是全局的信息,所以将输入又reshape成了一个7*7*64的向量。该层的激活函数是ReLU,输出的尺寸为1*1024。


接下来,教程中还使用了一个dropout层,使用dropout,使得在每一次迭代中,都有部分神经元在输出时关闭,即不输出,这样做的好处是在训练时减少过拟合,代码如下:

keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

keep_prob为不关闭的概率,在训练阶段,这个值一般为0.5,即关闭50%的神经元,而在评估阶段,我们不需要关闭神经元,即将这个值设为1.0即可。


最后一层,输出层,为一个softMax层,和前一篇文章一样,该层的目的是将输出转换成概率,输入尺寸为1*1024,输出尺寸为1*10,代表将输入分类为0~9这10个数字的概率:

W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

之后的步骤就和前一篇文章中的类似了,使用交叉熵的代价函数,并用Adam的最速梯度下降方法来最小化这个代价函数,对模型进行训练。代码如下:

cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
sess.run(tf.initialize_all_variables())
for i in range(20000):
  batch = mnist.train.next_batch(50)
  if i%100 == 0:                                
    train_accuracy = accuracy.eval(feed_dict={
        x:batch[0], y_: batch[1], keep_prob: 1.0})                                      #评估阶段不使用dropout
    print("step %d, training accuracy %f"%(i, train_accuracy))                          #每隔100次迭代打印一次训练信息
  train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})                 #训练阶段使用50%的dropout

print("test accuracy %f"%accuracy.eval(feed_dict={
    x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))                      #打印测试信息

最终在测试集上的识别精度达到了99%以上,比单一的softMax模型效果要好得多。

在本章中,我们使用了一个浅层的卷积神经网络,就达到了一个非常高的识别精度,也证明了深度学习的效果。在这里,我们需要着重理解每一层的含义,每一层参数的设置也会对训练的结果造成很大的影响,如何选定一个合适的参数,就是根据经验以及不断的调试来确定了。






  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值