Google TensorFlow学习笔记之Deep MNIST for Experts

Deep MNIST for Experts学习笔记


今天看了TensorFlow的Deep MNIST for Experts的部分,为了加深理解用中文的翻译一下。英文原文请参考:
https://www.tensorflow.org/versions/r0.9/tutorials/mnist/pros/index.html#deep-mnist-for-experts

第一步要做的就是设置(setup),这一步主要有两个操作,首先是加载  MNIST数据,然后开始一个tensorflow的会话(session)。


加载mnist数据

为了方便,使用了一个可以自动下载并且导入MNIST数据集的脚本,这个脚本将会创建一个MNIST_data的目录来存储数据,脚本文件如下:
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

在这里,mnist是一个作为NumPy数组的轻量级类,用来存储训练数据集,评价数据集和测试数据集,此外它还提供了一个迭代小批量数据的迭代函数。这个稍后我们会用到。


开始tensorflow会话

tensorflow依靠搞笑的C++后台进行计算,连接后台的就是会话。在tensorflow程序中最常见的用法就是,首先创建一个图然后把图加载到一个会话中。这里我们用了一个很方便的交互会话(InteractiveSession)类,它会让你更灵活的构建程序。这样你可以交错的进行构建一个运算图的操作。当使用像IPython那样的交互上下文的时候这个会话类非常方便。如果你不用交互会话的话,就需要在开始会话和加载图之前创建一个完整的图然。代码如下:
import tensorflow as tf
sess = tf.InteractiveSession()


运算图

在Python中,为了高效地进行大规模计算,经常会用到Python之外的库,比如可以处理诸如矩阵乘那样的昂贵的操作的NumPy。但是即便如此每个操作返回到python仍然会有很大的消耗。尤其是当想在GPU上计算或者分布式计算的时候,转换数据的代价非常大。
TensorFlow在python之外也需要做大量的操作。为了避免这些操作代价,TensorFlow没有单独地执行每个操作,而是让我们创建一个完全独立于python的表示相互关系的图。这种方法同样用在Theano和Torch中。因此可以说python的角色是创建这种外部的运算图,然后指挥图的哪一部分去执行。关于运算图的详细内容可以参考基本应用的运算图那一部分。

创建softmax回归模型

本节中我们会用一个线性层来创建一个softmax回归。下一节中我们会将其扩展为用多层卷积网络创建softmax回归。


占位符(Placeholders)

首先我们通过为输入图像和目标输出图像创建创建节点来开始创建运算图。

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

在这里x和y_并非什么特别的变量,只是单纯的占位符。所谓占位符就是我们执行计算时要输入的值。

输入图像x由2次元浮点数的张量构成。这里我们把它指派给一个[None, 784]的形状(shape),784是一个扁平化的MNIST图像的维数,而None则意味着和patch大小相关的第一个次元可以是任何的大小。输出类y_也是有2次元的张量组成,它的每行是一个独热(one-hot)10次元向量,这个向量表示MNIST图表示的是哪个数字。原文中关于独热(one-hot)在MNIST For ML Beginners中有介绍。这里简要说明一下。独热就是状态向量中只有一位是1其余位是0的向量。比如在MNIST这个例子中,001000000表示3,000000010表示8。
shape参数在这里是一个可选项,但是在这里它可以让TensorFlow自动的获取阻止不一致张量形状bug。


变量(Variables)

现在我们开始为我们的模型定义权重W和偏移量b,它们都可以被看作是额外的输入。TensorFlow用变量(Variables)来处理它们。每个变量都表示运算图里的一个值,它们都可以在运算中使用或者更新,这和编程语言里的变量可能没有区别(?)。在机器学习应用中,通常都会把模型参数作为变量。

W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))

上面的代码,我们用tf.Variable把变量W和b定义为全是零的张量。W是784×10的矩阵(因为我们有784个输入特征和10个输出),b是10次元的变量(因为有10个类)。

在变量被用到会话(session)之前,他们必须用会话进行初始化。在这一步,初始值已经被定义为全是零的张量并把它们出给了张量。在tensorflow中,一次就可以把所有的变量进行初始化。

sess.run(tf.initialize_all_variables())

预测类和代价函数(Predicted Class and Cost Function)

现在我们可以执行回归模型,这只需要一行代码就可以完成。我们把向量化的输入图像乘以权重W,加上偏移量b,然后计算分配到每个类的softmax概率就OK了。

y = tf.nn.softmax(tf.matmul(x,W) + b)

在训练中需要最小化的代价函数也是很容易被指定的。代价函数就是目标值和预测值的熵。

cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))


这里tf.reduce_sum是所有类的和,tf.reduce_mean取和的平均值。(这里边我的理解是:对每个类(0,1,2,...8,9),用输入图像来求y_ * tf.log(y),然后相加。然后对每个类的和求平均?)


训练模型

刚才我们创建了模型和训练代价函数。在TensorFlow里,执行训练非常简单。TensorFlow已经知道了运算图,所以为了找到关于每个变量的代价梯度,可以用自动差分。TensorFlow有很多内置优化算法,在这个例子中我们使用了步长为0.5的最速下降法(steepest gradient descent)来下降熵。

train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)


这很简单的一行是把一些新的操作加到了运算图中。这些操作包括了计算梯度的操作,计算参数更新步长并把步长更新到参数中的操作。返回操作train_step运行的时候,将会把梯度步长更新应用到参数中。因此通过反复执行train_step操作就可以完成训练模型。


for i in range(1000):
  batch = mnist.train.next_batch(50)
  train_step.run(feed_dict={x: batch[0], y_: batch[1]})

每次迭代中我们加载50个样本,然后执行train_step操作。使用feed_dict就可以用训练模型替换掉占位符张量x和y_。其实除了占位符张量,你还可用feed_dict替换运算图中的任何张量。


评价模型

在这一步我们的模型会做什么呢 ?

首先,我们要清楚我们在哪里预测正确的标签。tf.argmax是一个非常有用的函数,因为它能给你一个张量中最高实体的索引。比如,对每个输入来说,tf.argmax(y,1)是一个我们的模型认为最有可能的标签。而tf.argmax(y_,1)是一个真正的标签,我们可以用tf.equal来检测预测是否为真。

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))


上边的操作会给我们一个布尔值的列表。为了确定什么分数(fraction)是正确的,我们将其转换为浮点数并取均值,比如,[True, False, True, True]将变成[1,0,1,1]然后编程0.75 。

accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))


最终,我们可以用测试数据来评价我们的模型的精度。这个例子应该是92%。


print(accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels}))



构建多层卷积网络


在MNIST例子中,92%的精度是很差的。在本节中我们将会对其进行优化,从一个简单的模型到一个中等复杂的小型的卷积神经网络。这可以让我们的精度提高到99.2%,这虽然算不上最好的。


权重初始化


为了创建模型,我们需要创建大量的权重和偏移量。为了对称破缺(symmetry breaking)防止0梯度,通常会用噪点来初始化权重(这个地方不太理解)。由于我们用了ReLU神经元,可以尝试用小的初始的正偏移量来对他们进行初始化,这样就可以避免死神经元(dead neurons)。在创建模型时不用重复的做同样的操作,我们可以创建两个方便的函数。

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)



卷积和池化


TensorFlow可以让我们灵活的使用卷积和池化操作。我们如何控制边界,步长大小是多少?在这个例子中,我们选择使用vanilla版本。使用步长为1,边距为0的卷积这样输入和输出就可以保持同样的大小。池化操作使用块大小为2×2的最大池化(max pooling)。为了让代码简洁,我们把这些操作放到一个函数里。

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')


第一层卷积


现在我们实现的第一层包括了卷积和卷积之后的池化。卷积将会为5×5的patch计算32个特征。权重张量的形状是[5, 5, 1, 32],前边的2个维数是patch的大小,接下来是通道数,最后是输出的通道数。对于每个输出通道,都会有一个偏移量。

W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])


为了应用这一层,首先我们要把变量x重置成4次元张量,其中第2,3维是输入图像的宽和高,最后一个维数是颜色的通道数。

x_image = tf.reshape(x, [-1,28,28,1])


接下来我们用权重张量对x_image,再加上偏置量,然后用ReLU函数激活,最后进行最大池化。

h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)


第二层卷积


为了创建深层网络,我们要做若干个这样的层。第二层将会为每个5×5的patch创建64个特征。

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)


密集连接层


现在图像大小变成了7×7,我们添加有1024个神经元的全连接层来处理整个图片。我们把来自池化层的张量变成一些向量,然后乘以权重矩阵,加上偏置,然后用ReLU激活。


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)


退出(Dropout)

为了减少过度拟合,在readout层之前我们用了退出操作。在dropout过程中我们为神经元输出的概率创建了占位符。这可以上我们在训练时开启dropout并且在测试时关闭dropout。tf.nn.dropout操作除了可以隐蔽神经元的输出外,还可以自动处理神经元的输出的尺度(scale)。所以dropout执行时不用考虑尺度。

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


输出层(readout layer)


最后我们添加一个softmax层,就像前面的单层softmax回归一样。


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)


训练和评价模型



我们的模型效果怎么样?为了训练和评价模型,我们使用了和上边单层softmax网络几乎一样的代码。不同的是,我们不用最陡梯度下降优化器,而是使用更加复杂的ADAM优化器。另外还有feed_dict中的keep_prob来控制dropout比例。在训练中每100个迭代添加一个日志。


cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y_conv), reduction_indices=[1]))
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, tf.float32))
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})
    print("step %d, training accuracy %g"%(i, train_accuracy))
  train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})

print("test accuracy %g"%accuracy.eval(feed_dict={
    x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))


代码执行之后,测试集的精度应该在99.2%左右。

到此,我们已经学习了使用tensorFlow来创建,训练和评价比较复杂的深度神经网络。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值