使用神经网络
现在神经网络被训练了,你可以用它进行预测。 为此,您可以重复使用相同的建模阶段,但是更改执行阶段,如下所示:
with tf.Session() as sess:
saver.restore(sess, "./my_model_final.ckpt") # or better, use save_path
X_new_scaled = mnist.test.images[:20]
y_pred = np.argmax(Z, axis=1)
Z = logits.eval(feed_dict={X: X_new_scaled})
首先,代码从磁盘加载模型参数。 然后加载一些您想要分类的新图像。 记住应用与训练数据相同的特征缩放(在这种情况下,将其从 0 缩放到 1)。 然后代码评估对数点节点。 如果您想知道所有估计的类概率,则需要将softmax()
函数应用于对数,但如果您只想预测一个类,则可以简单地选择具有最高 logit 值的类(使用argmax()
函数做的伎俩)。
微调神经网络超参数
神经网络的灵活性也是其主要缺点之一:有很多超参数要进行调整。 不仅可以使用任何可想象的网络拓扑(如何神经元互连),而且即使在简单的 MLP 中,您可以更改层数,每层神经元数,每层使用的激活函数类型,权重初始化逻辑等等。 你怎么知道什么组合的超参数是最适合你的任务?
当然,您可以使用具有交叉验证的网格搜索来查找正确的超参数,就像您在前几章中所做的那样,但是由于要调整许多超参数,并且由于在大型数据集上训练神经网络需要很多时间, 您只能在合理的时间内探索超参数空间的一小部分。 正如我们在第2章中讨论的那样,使用随机搜索要好得多。另一个选择是使用诸如 Oscar 之类的工具,它可以实现更复杂的算法,以帮助您快速找到一组好的超参数.
它有助于了解每个超级参数的值是合理的,因此您可以限制搜索空间。 我们从隐藏层数开始。
隐藏层数量
对于许多问题,您只需从单个隐藏层开始,您将获得合理的结果。 实际上已经表明,只有一个隐藏层的 MLP 可以建模甚至最复杂的功能,只要它具有足够的神经元。 长期以来,这些事实说服了研究人员,没有必要调查任何更深层次的神经网络。 但是他们忽略了这样一个事实:深层网络具有比浅层网络更高的参数效率:他们可以使用比浅网格更少的神经元来建模复杂的函数,使得训练更快。
要了解为什么,假设您被要求使用一些绘图软件绘制一个森林,但是您被禁止使用复制/粘贴。 你必须单独绘制每棵树,每枝分枝,每叶叶。 如果你可以画一个叶,复制/粘贴它来绘制一个分支,然后复制/粘贴该分支来创建一个树,最后复制/粘贴这个树来制作一个林,你将很快完成。 现实世界的数据通常以这样一种分层的方式进行结构化,DNN 自动利用这一事实:较低的隐藏层模拟低级结构(例如,各种形状和方向的线段),中间隐藏层将这些低级结构组合到 模型中级结构(例如,正方形,圆形)和最高隐藏层和输出层将这些中间结构组合在一起,以模拟高级结构(如面)。
这种分层架构不仅可以帮助 DNN 更快地融合到一个很好的解决方案,而且还可以提高其将其推广到新数据集的能力。 例如,如果您已经训练了模型以识别图片中的脸部,并且您现在想要训练一个新的神经网络来识别发型,那么您可以通过重新使用第一个网络的较低层次来启动训练。 而不是随机初始化新神经网络的前几层的权重和偏置,您可以将其初始化为第一个网络的较低层的权重和偏置的值。这样,网络将不必从大多数图片中低结构中从头学习;它只需要学习更高层次的结构(例如发型)。
总而言之,对于许多问题,您可以从一个或两个隐藏层开始,它可以正常工作(例如,您可以使用只有一个隐藏层和几百个神经元,在 MNIST 数据集上容易达到 97% 以上的准确度使用两个具有相同总神经元数量的隐藏层,在大致相同的训练时间量中精确度为 98%)。对于更复杂的问题,您可以逐渐增加隐藏层的数量,直到您开始覆盖训练集。非常复杂的任务,例如大型图像分类或语音识别,通常需要具有数十个层(或甚至数百个但不完全相连的网络)的网络,正如我们将在第 13 章中看到的那样),并且需要大量的训练数据。但是,您将很少从头开始训练这样的网络:重用预先训练的最先进的网络执行类似任务的部分更为常见。训练将会更快,需要更少的数据(我们将在第 11 章中进行讨论)
每层隐藏层的神经元数量
显然,输入和输出层中神经元的数量由您的任务需要的输入和输出类型决定。例如,MNIST 任务需要28×28 = 784
个输入神经元和 10 个输出神经元。对于隐藏的层次来说,通常的做法是将其设置为形成一个漏斗,每个层面上的神经元越来越少,原因在于许多低级别功能可以合并成更少的高级功能。例如,MNIST 的典型神经网络可能具有两个隐藏层,第一个具有 300 个神经元,第二个具有 100 个。但是,这种做法现在并不常见,您可以为所有隐藏层使用相同的大小 - 例如,所有隐藏的层与 150 个神经元:这样只用调整一次超参数而不是每层都需要调整(因为如果每层一样,比如 150,之后调就每层都调成 160)。就像层数一样,您可以尝试逐渐增加神经元的数量,直到网络开始过度拟合。一般来说,通过增加每层的神经元数量,可以增加层数,从而获得更多的消耗。不幸的是,正如你所看到的,找到完美的神经元数量仍然是黑色的艺术.
一个更简单的方法是选择一个具有比实际需要的更多层次和神经元的模型,然后使用早期停止来防止它过度拟合(以及其他正则化技术,特别是 drop out,我们将在第 11 章中看到)。 这被称为“拉伸裤”的方法:而不是浪费时间寻找完美匹配您的大小的裤子,只需使用大型伸缩裤,缩小到合适的尺寸。
激活函数
在大多数情况下,您可以在隐藏层中使用 ReLU 激活函数(或其中一个变体,我们将在第 11 章中看到)。 与其他激活函数相比,计算速度要快一些,而梯度下降在局部最高点上并不会被卡住,因为它不会对大的输入值饱和(与逻辑函数或双曲正切函数相反, 他们容易在 1 饱和)
对于输出层,softmax 激活函数通常是分类任务的良好选择(当这些类是互斥的时)。 对于回归任务,您完全可以不使用激活函数。
这就是人造神经网络的这个介绍。 在接下来的章节中,我们将讨论训练非常深的网络的技术,并分发多个服务器和 GPU 的训练。 然后我们将探讨一些其他流行的神经网络架构:卷积神经网络,循环神经网络和自动编码器。
完整代码
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
import numpy as np
from sklearn.metrics import accuracy_score
n_hidden2 = 100
if __name__ == '__main__': n_inputs = 28 * 28 n_hidden1 = 300
X_train = mnist.train.images
n_outputs = 10 mnist = input_data.read_data_sets("/tmp/data/")
y_test = mnist.test.labels.astype("int")
X_test = mnist.test.images y_train = mnist.train.labels.astype("int")
y = tf.placeholder(tf.int64, shape=(None), name = 'y')
X = tf.placeholder(tf.float32, shape= (None, n_inputs), name='X') with tf.name_scope('dnn'):
hidden2 = tf.layers.dense(hidden1, n_hidden2, name='hidden2',
hidden1 = tf.layers.dense(X, n_hidden1, activation=tf.nn.relu ,name= 'hidden1') activation= tf.nn.relu)
xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels = y,
logits = tf.layers.dense(hidden2, n_outputs, name='outputs') with tf.name_scope('loss'): logits = logits) loss = tf.reduce_mean(xentropy, name='loss')#所有值求平均
with tf.name_scope('eval'):
learning_rate = 0.01 with tf.name_scope('train'): optimizer = tf.train.GradientDescentOptimizer(learning_rate) training_op = optimizer.minimize(loss)
n_epochs = 20
correct = tf.nn.in_top_k(logits ,y ,1)#是否与真值一致 返回布尔值 accuracy = tf.reduce_mean(tf.cast(correct, tf.float32)) #tf.cast将数据转化为0,1序列 init = tf.global_variables_initializer() batch_size = 50
sess.run(training_op,feed_dict={X:X_batch,
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) y: y_batch})
print(epoch, "Train accuracy:", acc_train, "Test accuracy:", acc_test)
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})
练习
使用原始的人工神经元(如图 10-3 中的一个)来计算神经网络,计算A ⊕ B
(
⊕
表示 XOR 运算)。提示:
A ⊕ B = (A ∧ ¬ B) ∨ (¬ A ∧ B)
。
为什么通常使用逻辑斯蒂回归分类器而不是经典感知器(即使用感知器训练算法训练单层的线性阈值单元)?你如何调整感知器使之等同于逻辑回归分类器?
为什么激活函数是训练第一个 MLP 的关键因素?
说出三种流行的激活函数。你能画出它们吗?
假设有一个 MLP 有一个 10 个神经元组成的输入层,接着是一个 50 个神经元的隐藏层,最后一个 3 个神经元输出层。所有人工神经元使用 Relu 激活函数。
-
输入矩阵
X
的形状是什么? -
隐藏层的权重向量的形状以及它的偏置向量的形状如何?
-
输出层的权重向量和它的偏置向量的形状是什么?
-
网络的输出矩阵
Y
是什么形状? -
写出计算网络输出矩阵的方程
什么是反向传播,它是如何工作的?反向传播与反向自动微分有什么区别?
你能列出所有可以在 MLP 中调整的超参数吗?如果 MLP 与训练数据相匹配,你如何调整这些超参数来解决这个问题?
在 MNIST 数据集上训练一个深层 MLP 并查看是否可以超过 98% 的精度。就像在第 9 章的最后一次练习中,尝试添加所有的铃声和哨子(即,保存检查点,在中断的情况下恢复最后一个检查点,添加摘要,使用 TensorBoard 绘制学习曲线,等等)。
原文发布时间为:2018-06-23
本文作者:ApacheCN【翻译
本文来自云栖社区合作伙伴“Python爱好者社区”,了解相关信息可以关注“Python爱好者社区”。