【阅读原文】
TensorFlow具有强大的计算能力,可以计算大量的数据,其中之一就是可以在实现和训练神经网络上有更为突出的表现。在这篇文章中,我们就会看到一些基本的,用TensorFlow构建深度卷积神经网络分类器。
MNIST数据
首先是载入MNIST数据(Mixed National Institute of Standards and Technology,MNIST数据是供机器学习算法入门使用的数据):
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
这两句命令会自动下载和读取名,读入到变量mnist,里面会有三种数据,测试数据,校验数据和训练数据。这三种数据都是用NumPy的arrays对象来存储的。
启动交互会话
Tensorflow运用运行高效的c++后台来进行数据计算。与后台的链接就叫做session,会话。对于一般TensorFlow的运用方式是首先建立一个图,然后把图放入会话中进行运算。
在这里,我们运用InteractiveSession对象,可以让TensorFlow更灵活地组织你的代码。
import tensorflow as tf
sess = tf.InteractiveSession()
计算图
在Python中更有效率的执行数值计算,我们常见的就是应用像NumPy这样的库,这个库可以在Python之外执行一些开销很大的运算,比如矩阵乘法。但是,在每个操作执行完成之后,切换回Python内时,仍然有许多开销。如果在GPU或者分布式计算时,数据的传输也会有很大的开销。
TensorFlow也把一些繁重的工作放在Python外执行,但是它会需要更多步骤来避免Python执行慢而造成的开销。为了避免在Python外仅仅单独执行一个简单的计算,我们需要描述相互嵌套的操作组成的一整张计算图,然后把这一整张计算图一起放到Python外部进行计算。
所以Python代码的任务就是构建这个计算图,并且指明哪些计算图的哪些部分需要执行。
构建多项回归(softmax Regression)模型
在这一节中,我们建立一个简单的softmax Regression模型,只用一层神经网络。在下一节中,我们会扩展到一个多层卷积网络。
Placeholder(占位符)
首先构建一些用于图像数据输入和识别后数据输出的对象:
x = tf.placeholder(tf.float32, shape=[None, 784])
y_ = tf.placeholder(tf.float32, shape=[None, 10])
X和y_都没有指定特别的值,他们都相当于是一个占位符,在后面需要计算的时候,再把相应的数据"喂"进相应的占位符中。
x就是代表图像数据,定义为2维的浮点数,形状是[None,784],其中784是代表一张图片中所有的像素点(一张图的规格是28*28)。第一维的数据表示可以有任意批量的图片。y_是输出数据的占位符,也是2维浮点数的张量。其中第二维的数字是10,表示(one-hot code)独热码,即代表数字0-9,表示这张图代表的是数字几。类似的第一维数字是None,表示可以有任意批量的图片,与输入的None应该相同。
Variables(变量)
现在来定义我们模型的权重w和偏差b,我们用Tensorflow中的Variable对象来定义他们,他们在计算过程中可以使用,甚至是修改。
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))
我们首先初始化W和b,在调用tf.Variable过程中,我们的都传入了参数。这里我们把他们全部初始化为零。W是一个784*10的矩阵(因为我们用784个特征输入,10个输出),b是10维向量,因为我们有10个不通的分类。这些变量在使用之前,都必须初始化,把这些变量都初始化为零。
sess.run(tf.global_variables_initializer())
Predicted class and Loss Function(预测分类和损失函数)
现在引入我们的回归模型,在TensorFlow中,我们只需要一行代码来表示这个模型。我们把输入的图形数据乘以权重矩阵W,然后在加上偏差b:
y = tf.matmul(x,W) + b
现在就需要定义一个损失函数。损失函数表示这个模型预测出来的值会有多少偏差,我们把这个偏差降得越下,那么这个模型也就越好。在这里,我们的损失函数是真实值和softmax模型估计出来的值之间的交叉熵:
cross_entropy = tf.reduce_mean(
tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))
这里没有很明显的表现出数据的正则化过程,是因为都包含在tf.nn.softmax_cross_entropy_with_logits方法中了,可以参考原文的Implementing the Regression章节。
Train the model(训练模型)
现在我们定义了模型和损失函数,就可以直接用TensorFlow开始训练了。由于之前已经描述了计算图的全部内容,用TensorFlow就可以求出相对于不同变量值对应梯度的差异,TensorFlow也有自己的优化算法库。在这次例子中,用学习率为0.5的梯度下降法降低交叉熵:
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
上面这串代码只是在计算图中加入了新的操作,包括计算梯度,参数调整更新。
进行执行优化的时候就是把上面这个train_step多次执行,多次求梯度及更新参数:
for _ in range(1000):
batch = mnist.train.next_batch(100)
train_step.run(feed_dict={x: batch[0], y_: batch[1]})
每一次训练迭代中,用100个数据样本进行训练,用feed_dict来把占位符x,y_填充上需要的数据。
Evaluate the Model(评估模型)
首先需要确定在什么地方找到预测出来的标签。tf.argmax是一个很有用的函数,可以返回一个张量中某一个维度上最大的数的索引。比如tf.argmax(y,1)返回的是预测模型预测出的每一张图的标签。tf.argmax(y_,1)是代表的真实正确的标签。然后我们再用tf.equal来检测我们的预测是否符合真实的标签,这句命令返回的就是一个布尔类型的列表:
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
将布尔类型的列表转换为准确率:
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
最后,计算图建立好后,我们就可以评估模型在测试数据集上的准确率:
print(accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
计算出来后大概是92%
Build a Multilayer Convolutional Network(建立多层卷积网络)
Weight Initialization(权重初始化)
为了建立这个多层卷积神经网络,我们需要初始化很多的权重W和偏差b,权重需要用一个很小的值来初始化,以便破坏对称性,也可以避免0梯度的出现。由于我们使用的是ReLu神经元,在偏差b上累加上一个适合的值,可以避免无效神经元的出现。
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)
Convolution and Pooling
TensorFlow提供了很多灵活的方法来做convolution和pool,我们需要要指定步长,处理边界。这里我们使用步长为1,不用填充以便让输出和输入的规格一样。
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')
First Convolutional Layer
我们现在引入第一层卷积网络,它是由Convolution和max pool组成,卷积会进行32次5x5大小的区域的计算。那么权重的shape就会变成[5,5,1,32],前两个参数就是提前的小块区域的大小,第三个是输入的通道,最后一个是输出通道的数量。我们也会对每个输出通道附上一个偏差值:
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
在应用这层网络之前,我们需要把输入的图片数据重塑一下,变成4维的张量,第二和第三维对应的是图片的大小,最后一维对应的图片的色彩通道:
x_image = tf.reshape(x, [-1,28,28,1])
然后我们再把x_image张量与权重做卷积并且加上偏差,再经过ReLU函数,最后用max pool。max_pool_2x2函数会让图片大小转换成为14x14。
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
Second Convolutional Layer
为了构建深层次的卷积网络,网上再叠加一层。第二层相对每一个5x5的小块区域会有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)
Densely Connected Layer
现在图片大小已经变成了7x7,现在要加一层1024个神经元组成的全连接网络层,以便处理整张图片。需要再次把图片重新塑形并做相关类似处理:
print(accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
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
为了减轻过拟合,再输出结果之前需要做一个dropout操作。定义一个占位符来代表在训练过程中,输出结果被保留的概率,这个可以在训练过程中打开,在测试过程中关闭。TensorFlow中的tf.nn.dropout方法可以自动的处理这个过程,不会需要多余的扩展:
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
Readout Layer
最后加入一个softmax回归层,就像上一节提到的那样:
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_conv = tf.matmul(h_fc1_drop, W_fc2) + b_fc2
Train and Evaluate the Model
训练和评估模型时,大体上与上一节的代码有很多相似之处,但是不同的是:
用ADAM优化器来优化损失函数,而不是用梯度下降在给计算图输入数据(feed_dict)的时候,会加上一个其他参数(keep_prob)来控制丢失率在训练过程中,每100次迭代记录一次
cross_entropy = tf.reduce_mean(
tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=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, tf.float32))
sess.run(tf.global_variables_initializer())
for i in range(20000):
batch = mnist.train.next_batch(50)
if i0 == 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"