查看原文
其他

【翻译】Sklearn与TensorFlow机器学习实用指南 —— 第13章 循环神经网络(中)

ApacheCN【翻译】 Python爱好者社区 2019-04-07

作者:ApacheCN【翻译】   Python机器学习爱好者
Python爱好者社区专栏作者
GitHub:https://github.com/apachecn/hands_on_Ml_with_Sklearn_and_TF


前文传送门:


【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— Chapter 0.前言

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第1章 机器学习概览(上)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第1章 机器学习概览(下)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第2章  一个完整的机器学习项目(上)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第2章 一个完整的机器学习项目(中)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第2章 一个完整的机器学习项目(中二)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第2章 一个完整的机器学习项目(下)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第3章 分类(上)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第3章 分类(中)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第3章 分类(下)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第4章( 上) 训练模型

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第4章( 中) 训练模型

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第4章( 下) 训练模型

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第5章( 上)支持向量机

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第5章( 中)支持向量机

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第5章( 中)支持向量机

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第5章( 下)支持向量机

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第6章 决策树

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第7章 集成学习和随机森林(上)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第7章 集成学习和随机森林 (中)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第7章 集成学习和随机森林 (下)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第8章 降维(上)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第8章 降维(下)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 ——  第9章 (上)启动并运行TensorFlow

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第9章 (中)启动并运行TensorFlow

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第9章 (下)启动并运行TensorFlow

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第10章 人工神经网络介绍(上)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第10章 人工神经网络介绍(中)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第10章 人工神经网络介绍(下)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第11章 训练深层神经网络(上)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第11章 训练深层神经网络(中)

【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第11章 训练深层神经网络(下)

【翻译】Sklearn与TensorFlow机器学习实用指南 —— 第12章 卷积神经网络(上)

【翻译】Sklearn与TensorFlow机器学习实用指南 —— 第12章 卷积神经网络(下)

【翻译】Sklearn与TensorFlow机器学习实用指南 —— 第13章 循环神经网络(上)


处理变长输入序列


到目前为止,我们只使用固定大小的输入序列(全部正好两个步长)。 如果输入序列具有可变长度(例如,像句子)呢? 在这种情况下,你应该在调用dynamic_rnn()(或static_rnn())函数时设置sequence_length参数;它必须是一维张量,表示每个实例的输入序列的长度。 例如:

n_steps = 2 n_inputs = 3 n_neurons = 5 reset_graph() X = tf.placeholder(tf.float32, [None, n_steps, n_inputs]) basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons) seq_length = tf.placeholder(tf.int32, [None]) outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32,                                    sequence_length=seq_length)

例如,假设第二个输入序列只包含一个输入而不是两个输入。 为了适应输入张量X,必须填充零向量(因为输入张量的第二维是最长序列的大小,即 2)

X_batch = np.array([        # step 0     step 1        [[0, 1, 2], [9, 8, 7]], # instance 1        [[3, 4, 5], [0, 0, 0]], # instance 2 (padded with zero vectors)        [[6, 7, 8], [6, 5, 4]], # instance 3        [[9, 0, 1], [3, 2, 1]], # instance 4    ]) seq_length_batch = np.array([2, 1, 2, 2])

当然,你现在需要为两个占位符Xseq_length提供值:

with tf.Session() as sess:    init.run()    outputs_val, states_val = sess.run(        [outputs, states], feed_dict={X: X_batch, seq_length: seq_length_batch})

现在,RNN 输出序列长度的每个时间步都会输出零向量(查看第二个时间步的第二个输出):



此外,状态张量包含每个单元的最终状态(不包括零向量):




处理变长输出序列


如果输出序列长度不一样呢? 如果事先知道每个序列的长度(例如,如果知道长度与输入序列的长度相同),那么可以按照上面所述设置sequence_length参数。 不幸的是,通常这是不可能的:例如,翻译后的句子的长度通常与输入句子的长度不同。 在这种情况下,最常见的解决方案是定义一个称为序列结束标记(EOS 标记)的特殊输出。 任何在 EOS 后面的输出应该被忽略(我们将在本章稍后讨论)。


好,现在你知道如何建立一个 RNN 网络(或者更准确地说是一个随着时间的推移而展开的 RNN 网络)。 但是你怎么训练呢?


训练 RNN


为了训练一个 RNN,诀窍是在时间上展开(就像我们刚刚做的那样),然后简单地使用常规反向传播(见图 14-5)。 这个策略被称为时间上的反向传播(BPTT)。




训练序列分类器


我们训练一个 RNN 来分类 MNIST 图像。 卷积神经网络将更适合于图像分类(见第 13 章),但这是一个你已经熟悉的简单例子。 我们将把每个图像视为 28 行 28 像素的序列(因为每个MNIST图像是28×28像素)。 我们将使用 150 个循环神经元的单元,再加上一个全连接层,其中包含连接到上一个时间步的输出的 10 个神经元(每个类一个),然后是一个 softmax 层(见图 14-6)。



建模阶段非常简单, 它和我们在第 10 章中建立的 MNIST 分类器几乎是一样的,只是展开的 RNN 替换了隐层。 注意,全连接层连接到状态张量,其仅包含 RNN 的最终状态(即,第 28 个输出)。 另请注意,y是目标类的占位符。

n_steps = 28 n_inputs = 28 n_neurons = 150 n_outputs = 10 learning_rate = 0.001 X = tf.placeholder(tf.float32, [None, n_steps, n_inputs]) y = tf.placeholder(tf.int32, [None]) basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons) outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32) logits = tf.layers.dense(states, n_outputs) xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y,                                                          logits=logits) loss = tf.reduce_mean(xentropy) optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate) training_op = optimizer.minimize(loss) correct = tf.nn.in_top_k(logits, y, 1) accuracy = tf.reduce_mean(tf.cast(correct, tf.float32)) init = tf.global_variables_initializer()

现在让我们加载 MNIST 数据,并按照网络的预期方式将测试数据重塑为[batch_size, n_steps, n_inputs]。 我们之后会关注训练数据的重塑。

from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets("/tmp/data/") X_test = mnist.test.images.reshape((-1, n_steps, n_inputs)) y_test = mnist.test.labels

现在我们准备训练 RNN 了。 执行阶段与第 10 章中 MNIST 分类器的执行阶段完全相同,不同之处在于我们在将每个训练的批量提供给网络之前要重新调整。

batch_size = 150 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)            X_batch = X_batch.reshape((-1, n_steps, n_inputs))            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: X_test, y: y_test})        print(epoch, "Train accuracy:", acc_train, "Test accuracy:", acc_test)

输出应该是这样的:


我们获得了超过 98% 的准确性 - 不错! 另外,通过调整超参数,使用 He 初始化初始化 RNN 权重,更长时间训练或添加一些正则化(例如,droupout),你肯定会获得更好的结果。


你可以通过将其构造代码包装在一个变量作用域内(例如,使用variable_scope("rnn", initializer = variance_scaling_initializer())来使用 He 初始化)来为 RNN 指定初始化器。


为预测时间序列而训练


现在让我们来看看如何处理时间序列,如股价,气温,脑电波模式等等。 在本节中,我们将训练一个 RNN 来预测生成的时间序列中的下一个值。 每个训练实例是从时间序列中随机选取的 20 个连续值的序列,目标序列与输入序列相同,除了向后移动一个时间步(参见图14-7)。


首先,我们来创建一个 RNN。 它将包含 100 个循环神经元,并且我们将在 20 个时间步骤上展开它,因为每个训练实例将是 20 个输入那么长。 每个输入将仅包含一个特征(在该时间的值)。 目标也是 20 个输入的序列,每个输入包含一个值。 代码与之前几乎相同:



一般来说,你将不只有一个输入功能。 例如,如果你试图预测股票价格,则你可能在每个时间步骤都会有许多其他输入功能,例如竞争股票的价格,分析师的评级或可能帮助系统进行预测的任何其他功能。


在每个时间步,我们现在有一个大小为 100 的输出向量。但是我们实际需要的是每个时间步的单个输出值。 最简单的解决方法是将单元包装在OutputProjectionWrapper中。 单元包装器就像一个普通的单元,代理每个方法调用一个底层单元,但是它也增加了一些功能。Out putProjectionWrapper在每个输出之上添加一个完全连接的线性神经元层(即没有任何激活函数)(但不影响单元状态)。 所有这些完全连接的层共享相同(可训练)的权重和偏差项。 结果 RNN 如图 14-8 所示。



包装单元是相当容易的。 让我们通过将BasicRNNCell包装到OutputProjectionWrapper中来调整前面的代码:

cell =tf.contrib.rnn.OutputProjectionWrapper(    tf.contrib.rnn.BasicRNNCell(num_units=n_neurons,activation=tf.nn.relu),    output_size=n_outputs)

到现在为止还挺好。 现在我们需要定义损失函数。 我们将使用均方误差(MSE),就像我们在之前的回归任务中所做的那样。 接下来,我们将像往常一样创建一个 Adam 优化器,训练操作和变量初始化操作:


生成 RNN


到现在为止,我们已经训练了一个能够预测未来时刻样本值的模型,正如前文所述,可以用模型来生成新的序列。


为模型提供 长度为n_steps的种子序列, 比如全零序列,然后通过模型预测下一时刻的值;把该预测值添加到种子序列的末尾,用最后面 长度为n_steps的序列做为新的种子序列,做下一次预测,以此类推生成预测序列。


如图 14-11 所示,这个过程产生的序列会跟原始时间序列相似。



如果你试图把约翰·列侬的唱片塞给一个 RNN 模型,看它能不能生成下一张《想象》专辑。


约翰·列侬 有一张专辑《Imagine》(1971),这里取其双关的意思


也许你需要一个更强大的 RNN 网络,它有更多的神经元,层数也更多。下面来探究一下深度 RNN。


深度 RNN


一个朴素的想法就是把一层层神经元堆叠起来,正如图 14-12 所示的那样,它呈现了一种深度 RNN。


为了用 TensorFlow 实现深度 RNN,可先创建一些神经单元,然后堆叠进MultiRNNCell


以下代码中创建了 3 个相同的神经单元(当然也可以用不同类别的、包含不同不同数量神经元的单元)

n_neurons = 100 n_layers = 3 basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons) multi_layer_cell = tf.contrib.rnn.MultiRNNCell([basic_cell] * n_layers) outputs, states = tf.nn.dynamic_rnn(multi_layer_cell, X, dtype=tf.float32)

这些代码就完成了这部分堆叠工作。status变量包含了每层的一个张量,这个张量就代表了该层神经单元的最终状态(维度为[batch_size, n_neurons])。

如果在创建MultiRNNCell时设置了state_is_tuple=False,那么status变量就变成了单个张量,它包含了每一层的状态,其在列的方向上进行了聚合,维度为[batch_size, n_layers*n_neurons]


注意在 TensorFlow 版本 0.11.0 之前,status是单个张量是默认设置。

Python爱好者社区历史文章大合集

Python爱好者社区历史文章列表(每周append更新一次)

福利:文末扫码立刻关注公众号,“Python爱好者社区”,开始学习Python课程:

关注后在公众号内回复“课程”即可获取:

小编的Python入门免费视频课程!!!

【最新免费微课】小编的Python快速上手matplotlib可视化库!!!

崔老师爬虫实战案例免费学习视频。

陈老师数据分析报告制作免费学习视频。

玩转大数据分析!Spark2.X+Python 精华实战课程免费学习视频。


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存