赞
踩
如何利用TensorFlow使用(经典)MNIST数据集训练并评估一个用于识别手写数字的简易前馈神经网络(feed-forward neural network),从中我们可以学习到tensorflow的运行原理与结构
TensorFlow 是一款用于数值计算的强大的开源软件库,特别适用于大规模机器学习的微调。 它的基本原理很简单:首先在 Python 中定义要执行的
计算图 (如图)
首先我们需要导入tensorflow库。 然后我们必须指定输入和输出的数量,并设置每个层中隐藏的神经元数量,n_inputs为根据输入数据的维度设定为28*28,其他隐藏层参数为随意设置,n_outpus为所需输出的类别值:
import tensorflow as tf
n_inputs = 28*28
n_hidden1 = 300
n_hidden2 = 100
n_outputs = 10
我们可以使用占位符节点来表示训练数据和目标。X的形状仅有部分被定义。
我们知道它将是一个 2D 张量(即一个矩阵),沿着第一个维度的实例和第二个维度的特征,我们知道特征的数量将是28×28(每像素一个特征) 但是我们不知道每个训练批次将包含多少个实例。 所以X的形状是(None, n_inputs)
X = tf.placeholder(tf.float32, shape=(None, n_inputs), name="X")
y = tf.placeholder(tf.int64, shape=(None), name="y")
现在让我们创建一个实际的神经网络。 占位符X
将作为输入层; 在执行阶段,它将一次更换一个训练批次(注意训练批中的所有实例将由神经网络同时处理)。 现在您需要创建两个隐藏层和输出层。 两个隐藏的层几乎相同:它们只是它们所连接的输入和它们包含的神经元的数量不同。 输出层也非常相似,但它使用 softmax 激活函数而不是 ReLU 激活函数。 所以让我们创建一个neuron_layer()
函数,我们将一次创建一个图层。 它将需要参数来指定输入,神经元数量,激活函数和图层的名称:
def neuron_layer(X, n_neurons, name, activation=None):
with tf.name_scope(name):
n_inputs = int(X.get_shape()[1])
stddev = 2 / np.sqrt(n_inputs)
init = tf.truncated_normal((n_inputs, n_neurons), stddev=stddev)
W = tf.Variable(init, name="weights")
b = tf.Variable(tf.zeros([n_neurons]), name="biases")
z = tf.matmul(X, W) + b
if activation == "relu":
return tf.nn.relu(z)
else:
return z
我们逐行浏览这个代码:
n_inputs, n_neurons
)。它将被随机初始化,使用具有标准差为2/√n
的截断的正态(高斯)分布(使用截断的正态分布而不是常规正态分布确保不会有任何大的权重,这可能会减慢训练。).使用这个特定的标准差有助于算法的收敛速度更快(我们将在第11章中进一步讨论这一点),这是对神经网络的微小调整之一,对它们的效率产生了巨大的影响)。0
,则所有神经元将输出0
,并且给定隐藏层中的所有神经元的误差梯度将相同。 然后,梯度下降步骤将在每个层中以相同的方式更新所有权重,因此它们将保持相等。b
变量,初始化为 0
(在这种情况下无对称问题),每个神经元有一个偏置参数。z = X·W + b
。relu(z)
(即max(0,z)
),否则它只返回z
。好了,现在你有一个很好的函数来创建一个神经元层。 让我们用它来创建深层神经网络! 第一个隐藏层以X为输入。 第二个将第一个隐藏层的输出作为其输入。 最后,输出层将第二个隐藏层的输出作为其输入。
with tf.name_scope("dnn"):
hidden1 = neuron_layer(X, n_hidden1, "hidden1", activation="relu")
hidden2 = neuron_layer(hidden1, n_hidden2, "hidden2", activation="relu")
logits = neuron_layer(hidden2, n_outputs, "outputs")
正如你所期望的,TensorFlow 有许多方便的功能来创建标准的神经网络层,所以通常不需要像我们刚才那样定义你自己的neuron_layer()
函数。 例如,TensorFlow 的dense()
函数创建一个完全连接的层,其中所有输入都连接到图层中的所有神经元。
with tf.name_scope("dnn"):
hidden1 = tf.layers.dense(X, n_hidden1, name="hidden1",
activation=tf.nn.relu)
hidden2 = tf.layers.dense(hidden1, n_hidden2, name="hidden2",
activation=tf.nn.relu)
logits = tf.layers.dense(hidden2, n_outputs, name="outputs")
现在我们已经有了神经网络模型,我们需要定义我们用来训练的损失函数。我们将使用交叉熵。 正如我们之前讨论的,交叉熵将惩罚估计目标类的概率较低的模型。 TensorFlow 提供了几种计算交叉熵的功能。 我们将使用sparse_softmax_cross_entropy_with_logits():
它根据logit
计算交叉熵(即,在通过 softmax
激活函数之前的网络输出),并且期望以 0 到 -1 数量的整数形式的标签(在我们的例子中,从 0 到 9)。 这将给我们一个包含每个实例的交叉熵的 1D 张量。 然后,我们可以使用 TensorFlow 的reduce_mean()
函数来计算所有实例的平均交叉熵。
with tf.name_scope("loss"):
xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=logits)
loss = tf.reduce_mean(xentropy, name="loss")
我们有神经网络模型,我们有损失函数,现在我们需要定义一个GradientDescentOptimizer来调整模型参数以最小化损失函数
learning_rate = 0.01
with tf.name_scope("train"):
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
training_op = optimizer.minimize(loss)
我们将简单地将精度用作我们的绩效指标。 首先,对于每个实例,通过检查最高 logit
是否对应于目标类别来确定神经网络的预测是否正确。 为此,您可以使用in_top_k()
函数。 这返回一个充满布尔值的 1D 张量,因此我们需要将这些布尔值转换为浮点数,然后计算平均值。 这将给我们网络的整体准确性.
with tf.name_scope("eval"):
correct = tf.nn.in_top_k(logits, y, 1)
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))
我们还将创建一个Saver
来将我们训练有素的模型参数保存到磁盘中
init = tf.global_variables_initializer()
saver = tf.train.Saver()
我们为输入和目标创建占位符,我们创建了一个构建神经元层的函数,我们用它来创建DNN
,我们定义了损失函数,我们 创建了一个优化器,最后定义了性能指标。 现在到执行阶段。
首先,我们加载 MNIST
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("/tmp/data/")
现在我们定义我们要运行的迭代数,以及小批量的大小然后训练模型:
n_epochs = 10001
batch_size = 50
with tf.Session() as sess:
init.run()
for epoch in range(n_epochs):
for iteration in range(mnist.train.num_examples // batch_size):
X_batch, y_batch = mnist.train.next_batch(batch_size)
sess.run(training_op, feed_dict={X: X_batch, y: y_batch})
acc_train = accuracy.eval(feed_dict={X: X_batch, y: y_batch})
acc_test = accuracy.eval(feed_dict={X: mnist.test.images, y: mnist.test.labels})
print(epoch, "Train accuracy:", acc_train, "Test accuracy:", acc_test)
save_path = saver.save(sess, "./my_model_final.ckpt")
该代码打开一个 TensorFlow
会话,并运行初始化所有变量的init
节点。 然后它运行的主要训练循环:在每个时期,通过一些小批次的对应于训练集的大小的代码进行迭代。 每个小批量通过next_batch()
方法获取,然后代码简单地运行训练操作,为当前的小批量输入数据和目标提供。 接下来,在每个时期结束时,代码评估最后一个小批量和完整训练集上的模型,并打印出结果。 最后,模型参数保存到磁盘。
现在神经网络被训练了,你可以用它进行预测。 为此,您可以重复使用相同的建模阶段,但是更改执行阶段,如下所示:
with tf.Session() as sess:
saver.restore(sess, "./my_model_final.ckpt") # or better, use save_path
X_new_scaled = mnist.test.images[:20]
Z = logits.eval(feed_dict={X: X_new_scaled})
y_pred = np.argmax(Z, axis=1)
首先,代码从磁盘加载模型参数。 然后加载一些您想要分类的新图像。 记住应用与训练数据相同的特征缩放(在这种情况下,将其从0
缩放到 1
)。 然后代码评估对数点节点。 如果您想知道所有估计的类概率,则需要将softmax()
函数应用于对数,但如果您只想预测一个类,则可以简单地选择具有最高 logit
值的类(使用argmax()
函数做的伎俩)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。