<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>第 7 章 循环神经网络 on 《从零学AI指南手册》</title>
		<link>https://mlwithme.github.io/dl/chapter07/</link>
		<description>Recent content in 第 7 章 循环神经网络 on 《从零学AI指南手册》</description>
		<generator>Hugo</generator>
		<language>zh_CN</language>
		
		
		
		
			<atom:link href="https://mlwithme.github.io/dl/chapter07/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>7.1 RNN网络</title>
				<link>https://mlwithme.github.io/dl/chapter07/88ba4e03337b4233/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter07/88ba4e03337b4233/</guid>
				<description>&lt;h1 id=&#34;第-7-章-循环神经网络&#34;&gt;第 7 章 循环神经网络&lt;a class=&#34;anchor&#34; href=&#34;#%e7%ac%ac-7-%e7%ab%a0-%e5%be%aa%e7%8e%af%e7%a5%9e%e7%bb%8f%e7%bd%91%e7%bb%9c&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;经过第3章和第4章内容的介绍，我们知道深度学习的本质可以总结为通过设计合理的网络结构来对输入进行特征提取，然后再利用提取得到的抽象特征完成后续下游任务。同时，在介绍卷积操作时我们说到，卷积的核心思想是通过共享权重来实现对在相邻空间位置上具有依赖关系的数据进行特征提取，但现实情况中还存在一类在时间维度上具有前后依赖关系的数据，我们称这样的数据为时间序列（Time Serial ）数据，也叫做时序数据，如音频信号、文本序列等。因此，在本章内容中我们将介绍一种全新的网络结构——循环神经网络（Recurrent Neural Network, RNN）及其各类变体——来专门对时序数据进行特征提取。&lt;/p&gt;&#xA;&lt;h1 id=&#34;71-rnn网络&#34;&gt;7.1 RNN网络&lt;a class=&#34;anchor&#34; href=&#34;#71-rnn%e7%bd%91%e7%bb%9c&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在正式介绍循环神经网络之前，我们先简单看一下RNN模型背后的思想和动机，然后再介绍它的相关原理和使用场景。&lt;/p&gt;&#xA;&lt;h2 id=&#34;711-rnn动机&#34;&gt;7.1.1 RNN动机&lt;a class=&#34;anchor&#34; href=&#34;#711-rnn%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;尽管在图像处理中卷积神经网络有着广泛的应用，但是它却不适用于对时序类的数据进行特征提取，其原因在于对于时序数据来说当前时刻的状态信息往往会依赖于之前多个时刻的输出结果。例如在语言模型中，一个单词的含义往往会依赖于它前面出现的多个单词。因此我们便需要一种具备“记忆”功能的网络模型来对这类数据进行特征提取。基于这样的想法，1990年埃尔曼（Elman）等人提出了一种具有短期记忆能力网络模型循环神经网络Elman Network [1]。需要指出的是，RNN的概念是逐步发展的，很多研究者对其理论和应用做出了贡献，因此很难将其归功于某一位或几位特定的发明者，这里我们介绍的是现在最常使用的一种RNN模型结构。&lt;/p&gt;&#xA;&lt;h2 id=&#34;712-rnn原理&#34;&gt;7.1.2 RNN原理&lt;a class=&#34;anchor&#34; href=&#34;#712-rnn%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;循环神经网络是深度学习中一种典型的反馈神经网络，和前馈神经网络相比较反馈神经网络之所以具有一定的记忆功能，因为反馈神经网络在不同时刻的状态是根据历史所有时刻的信息及当前时刻的输入计算而来。在 RNN 中，神经元不仅可以接受到其他神经元的输出信息，也可以接受自己的输出信息从而形成一个具有环路的网络拓扑结构，因此RNN也成为了处理序列数据的重要工具之一。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/dl/23050443919.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 7-1. RNN模型示意图&lt;/center&gt;&#xA;&lt;p&gt;如图7-1(a)所示就是一种最基本的RNN网络结构，可以明显地看到其具有循环结构，而也恰好是这一“闭环”使得 RNN 具有了记忆功能，因为它将历史信息带入到了当前时刻的计算过程中。同时，图7-1(b)为RNN模型在时间维度展开的示意图，每一个时刻称之为一个记忆单元（Cell），其中$x_t$和$h_t$分别表示第$t$个时刻模型的输入和输出，每个时刻在计算时共享同一组模型参数。此时可以看出，第$t$时刻的输出不仅依赖于第$t$时刻的输入$x_t$同时也依赖于第$t-1$时刻的输出结果$h_{t-1}$，而这也揭示了循环神经网络天然地适合用于处理具有时序关系的数据。同时由图7-1可知，对于RNN模型来说其输入应该有3个维度，即批大小、时间步长和输入维度。&lt;/p&gt;&#xA;&lt;p&gt;进一步，RNN模型的内部详细情况如图7-2所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;550&#34; src=&#34;https://mlwithme.github.io/images/dl/23051039022.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 7-2. RNN模型细节图&lt;/center&gt;&#xA;&lt;p&gt;根据图7-2所示，RNN在沿时间维度展开时会先将上一时刻的输出和当前时刻输入分别进行一次线性变换并相加到一起，然后再经过一次非线性变换得到当前时刻的输出结果，具体计算过程如式(7-1)所示&#xA;&lt;/p&gt;&#xA;$$&#xA;h_t=f(x_tU+h_{t-1}W+b)\tag{7-1}&#xA;$$&lt;p&gt;&#xA;其中$x_t$的形状为&lt;code&gt;[batch_size,input_size]&lt;/code&gt;，$h_{t-1}$的形状为&lt;code&gt;[batch_size,hidden_size]&lt;/code&gt;；$U,W,b$分别为模型的3个权重参数，形状分别为 &lt;code&gt;[input_size,hidden_size]&lt;/code&gt;、&lt;code&gt;[hidden_size,hidden_size]&lt;/code&gt;和&lt;code&gt;[hidden_size]&lt;/code&gt;。同时，式(7-1)中的激活函数$f(\cdot)$可以是Tanh或ReLU等，并且这里需要再次提醒的是$U,W,b$这3个参数在每个时刻中共享。对于第1个时刻来说，通常其上一个时刻的输出将会被初始化为全0状态。&lt;/p&gt;&#xA;&lt;h2 id=&#34;713-rnn计算示例&#34;&gt;7.1.3 RNN计算示例&lt;a class=&#34;anchor&#34; href=&#34;#713-rnn%e8%ae%a1%e7%ae%97%e7%a4%ba%e4%be%8b&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在清楚了RNN模型的相关原理后，我们来通过一个实际的示例来体会RNN的计算过程。假定现在某个序列样本一共有3个时刻，每个时刻为一个4维向量，即&#xA;&lt;/p&gt;&#xA;$$&#xA;X=&#xA;\begin{bmatrix}&#xA;x_1\\x_2\\x_3&#xA;\end{bmatrix}=&#xA;\begin{bmatrix}&#xA;0.4&amp;0.2&amp;0.5&amp;0.1\\&#xA;0.1&amp;0.3&amp;0.2&amp;0.0\\&#xA;0.0&amp;0.2&amp;0.4&amp;0.2&#xA;\end{bmatrix}_{1\times3\times4}\tag{7-2}&#xA;$$&lt;p&gt;&#xA;同时设隐含状态的向量维度为2，初始状态$h_0$，权重参数$U,W$和$b$分别为&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;h_0=\begin{bmatrix}&#xA;0.0&amp;0.0&#xA;\end{bmatrix}_{1\times2}, \; \;&#xA;U=\begin{bmatrix}&#xA;0.2&amp;0.5\\&#xA;0.1&amp;0.1\\&#xA;0.0&amp;0.2\\&#xA;0.3&amp;0.3\\&#xA;\end{bmatrix}_{4\times2}, \; \;&#xA;W=\begin{bmatrix}&#xA;0.1&amp;0.1\\&#xA;0.0&amp;0.2&#xA;\end{bmatrix}_{2\times2},\;\;b=\begin{bmatrix}&#xA;0.5&amp;0.5&#xA;\end{bmatrix}_{1\times2}&#xA;\end{aligned}\tag{7-3}&#xA;$$&lt;p&gt;&#xA;根据式(7-1)~式(7-3)可得&#xA;&lt;/p&gt;</description>
			</item>
			<item>
				<title>7.2 时序数据</title>
				<link>https://mlwithme.github.io/dl/chapter07/ec8ff069aadc49b9/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter07/ec8ff069aadc49b9/</guid>
				<description>&lt;h1 id=&#34;72-时序数据&#34;&gt;7.2 时序数据&lt;a class=&#34;anchor&#34; href=&#34;#72-%e6%97%b6%e5%ba%8f%e6%95%b0%e6%8d%ae&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/88ba4e03337b4233&#34;&gt;7.1节&lt;/a&gt;内容中，我们详细介绍了RNN模型的原理及使用场景，即对时序特征进行特征提取，因此在本节内容中我们将通过两个实际的案例来介绍RNN的具体使用方式。不过在正式介绍之前我们需要明白一点的是，所谓时序数据并不是一定要具有时间上的概念，只要是包含前后的先后顺序并且打乱这个顺序就改变了样本的属性，那么这样的数据便都可以被称之为时序数据。&lt;/p&gt;&#xA;&lt;h2 id=&#34;721-时序图片&#34;&gt;7.2.1 时序图片&lt;a class=&#34;anchor&#34; href=&#34;#721-%e6%97%b6%e5%ba%8f%e5%9b%be%e7%89%87&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;虽然对于图像处理来说采用卷积操作是最合理的一种方式，但我们仍旧可以将一张图片看成是时序数据并通过RNN来对其进行特征提取并完成后续的分类任务，而构造成时序数据的方法便是将其按照行或列进行分割。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;350&#34; src=&#34;https://mlwithme.github.io/images/dl/23050521820.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 7-5. 时序图片示意图&lt;/center&gt;&#xA;&lt;p&gt;如图7-5所示，左侧为原始图片，右侧为被垂直分割成4部分后的图片。此时我们可以发现，对于图7-5右侧的图片来说，其分割后的每一列都可以看成是每个时刻对应的状态，并且如果列与列之间的顺序发生了改变，那么将会改变该图片对应的原始属性。因此，在按照这样的分割方式操作后，每张图片均可以看成是一个序列样本。当然，除了以垂直的方式进行分割外也可以按照水平的方式进行分割。&lt;/p&gt;&#xA;&lt;p&gt;以FashionMNIST数据集为例，其原始形状为$28\times28$，如果我们以垂直方式对其进行分割，那么便可以通过一个包含有28个时刻，每个时刻为一个28维的向量来对其进行表示。&lt;/p&gt;&#xA;&lt;h2 id=&#34;722-基于rnn的图片分类&#34;&gt;7.2.2 基于RNN的图片分类&lt;a class=&#34;anchor&#34; href=&#34;#722-%e5%9f%ba%e4%ba%8ernn%e7%9a%84%e5%9b%be%e7%89%87%e5%88%86%e7%b1%bb&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在清楚了时序图片的构造方式后，下面我们再来介绍如何通过RNN来完成FashionMNIST数据集的分类任务。以下完整示例代码可以参见&lt;code&gt;Code/Chapter07/C02_RNNImgCla/FashionMNISTRNN.py&lt;/code&gt;文件。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 前向传播&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;由于&lt;code&gt;torchvision&lt;/code&gt;中的&lt;code&gt;datasets&lt;/code&gt;模块已经将FashionMNIST数据集处理成了&lt;code&gt;[batch_size, 1, width, high]&lt;/code&gt;的形式，所以我们只需要压缩掉通道这个维度，然后将width和high分别理解成步长和输入维度即可，并不需要进行特殊处理。因此我们直接定义相应的前向传播过程，示例代码如下所示：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;FashionMNISTRNN&lt;/span&gt;(nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Module):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;__init__&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;, input_size&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;28&lt;/span&gt;, hidden_size&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;128&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;                  num_layers&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;, num_classes&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;10&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;super&lt;/span&gt;(FashionMNISTRNN, &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;)&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;__init__&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;rnn &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;RNN(input_size, hidden_size,nonlinearity&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;relu&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;                           num_layers&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;num_layers, batch_first&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;True&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;classifier &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Sequential(LayerNormalization(hidden_size),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;                     nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Linear(hidden_size, hidden_size),nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;ReLU(inplace&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;True&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;9&lt;/span&gt;                     nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Linear(hidden_size, num_classes))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;10&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;11&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;forward&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;, x, labels&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;None&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;12&lt;/span&gt;         x &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; x&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;squeeze(&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;)  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;13&lt;/span&gt;         x, _ &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;rnn(x)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;14&lt;/span&gt;         logits &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;classifier(x[:, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;]&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;squeeze(&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;15&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; labels &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;None&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;16&lt;/span&gt;             loss_fct &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;CrossEntropyLoss(reduction&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;mean&amp;#39;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;17&lt;/span&gt;             loss &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; loss_fct(logits, labels)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;18&lt;/span&gt;             &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; loss, logits&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;19&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;else&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;20&lt;/span&gt;             &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; logits&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第2~3行用于指定相关的模型参数。第5~6行为实例化一个RNN模型，其中&lt;code&gt;nonlinearity&lt;/code&gt;用于指定RNN中的激活函数。第7~9行为最后的分类层，其中&lt;code&gt;LayerNormalization&lt;/code&gt;为&lt;a href=&#34;https://mlwithme.github.io/dl/chapter06/fdd5ba4b41f74a0e&#34;&gt;6.4节&lt;/a&gt;中介绍到的层归一化方法。第11~20行便是整个前向传播计算过程，其中第12行表示将&lt;code&gt;[batch_size, 1, width, high]&lt;/code&gt;压缩成&lt;code&gt;[batch_size, width, high]&lt;/code&gt;，第13行是RNN的计算结果此时&lt;code&gt;x&lt;/code&gt;的形状为&lt;code&gt;[batch_size, time_steps, hidden_size]&lt;/code&gt;，第14行是取最后一个时刻的输出并压缩成&lt;code&gt;[batch_size, hidden_size]&lt;/code&gt;的形状。&lt;/p&gt;</description>
			</item>
			<item>
				<title>7.3 LSTM网络</title>
				<link>https://mlwithme.github.io/dl/chapter07/b4c5ddcc9e904238/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter07/b4c5ddcc9e904238/</guid>
				<description>&lt;h1 id=&#34;73-lstm网络&#34;&gt;7.3 LSTM网络&lt;a class=&#34;anchor&#34; href=&#34;#73-lstm%e7%bd%91%e7%bb%9c&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面两节内容中，我们详细介绍了RNN模型的原理以及在PyTorch框架中的使用方法。虽然理论上RNN模型在处理序列数据方面具有着很好的效果，但在处理长序列数据时RNN模型可能会出现梯度消失或爆炸的情况，进而导致模型无法学习到长期依赖的关系。在这样的背景下，基于RNN模型改进的长短期记忆网络（Long Short-Term Memory, LSTM）[1]便应运而生了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;731-lstm动机&#34;&gt;7.3.1 LSTM动机&lt;a class=&#34;anchor&#34; href=&#34;#731-lstm%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;根据&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/88ba4e03337b4233&#34;&gt;7.1节&lt;/a&gt;内容可知，RNN模型出现的动机便是为了解决时序数据的特征编码问题，但在实际情况中由于时序数据的时间步长较多因而又导致了新问题的出现。例如模型在对一个时序长度为50的序列进行特征提取时，第50个时刻的隐含向量$h_{50}$便会依赖之前所有时刻的信息。在这样的情景下，一方面由&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/88ba4e03337b4233&#34;&gt;7.1.6节&lt;/a&gt;内容可知模型在训练过程中极易出现梯度消失或爆炸的情况；另一方面由于历史时刻和当前时刻的状态信息得不到有效筛选，使得模型难以学到真正对下游任务有用的信息，而这也被称之为长期依赖（Long-Term Dependencies）问题。&lt;/p&gt;&#xA;&lt;p&gt;基于这样的动机， 霍赫赖特等人在1997年提出了基于门控单元的长短期记忆网络。LSTM模型的设计思想在于通过引入门控机制（Gating）和记忆状态（Memory State）来解决上述两个问题。门控机制可以控制信息的流动决定哪些信息应该被保留，哪些应该被遗忘，以及哪些信息应该输入给下一个记忆单元以便模型可以更好地捕捉序列的长期依赖关系。同时，记忆状态则是类似于残差模块中的连接，使得经过筛选后的记忆状态能够直接输入到下一个记忆单元，从而缓解了RNN中的梯度消失或爆炸问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;732-lstm结构&#34;&gt;7.3.2 LSTM结构&lt;a class=&#34;anchor&#34; href=&#34;#732-lstm%e7%bb%93%e6%9e%84&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;同RNN模型类似，LSTM模型也是一个在时间维度进行展开的循环结构。在原始的RNN模型中，每个重复的记忆单元内只包含一个简单的网络层，而对于LSTM模型来说每个记忆单元包含有4个不同的网络层，并通过不同的方式进行相互作用以此得到当前时候的输出结果。如图7-6所示便是LSTM模型的网络结构示意图。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;850&#34; src=&#34;https://mlwithme.github.io/images/dl/23051172221.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 7-6 LSTM网络结构图&lt;/center&gt;&#xA;&lt;p&gt;在图7-6中，上方贯穿每个记忆单元的便是LSTM中引入的记忆状态$C_t$，同时$f_t$ 、$i_t$、$o_t$和$\tilde{C_t}$ 分别表示遗忘门（Forget Gate）、输入门（Input Gate）、输出门（Output Gate）和输入层对应的输出结果，$h_t$表示当前时候的输出结果。从图7-6可以看出，LSTM中的每个记忆单元都会通过3个门控结构（$f_t$、$i_t$和$o_t$）来完成对信息流动的控制与筛选。每个门控结构都是根据同样的输入经Sigmoid函数作用后得到一系列取值在区间$[0,1]$ 里的值，其中0表示将流经的所有信息进行完全抑制，而1则表示对流经的信息不做任何处理。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 遗忘门&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;遗忘门主要用于对历史记忆状态$C_{t-1}$进行筛选，选择性的遗忘或者保留部分历史信息，使得真正有用的信息能够贯穿LSTM 网络。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;350&#34; src=&#34;https://mlwithme.github.io/images/dl/23051188721.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 7-7 LSTM遗忘门&lt;/center&gt;&#xA;&lt;p&gt;如图7-7所示，在LSTM中第1步需要做的就是确定应该丢弃哪些信息，$t-1$时刻的输出$h_{t-1}$和当前时刻的输入$x_t$经过遗忘门之后，后续再通过按位乘作用于$C_{t-1}$便完成了对历史记忆状态的筛选，其具体计算过程为&#xA;&lt;/p&gt;&#xA;$$&#xA;f_t=\sigma([h_{t-1},x_t]W_f+b_f)\tag{7-9}&#xA;$$&lt;p&gt;&#xA;其中$\sigma$为Sigmoid函数，$[a,b]$ 表示将$a,b$两个向量进行堆叠组合，$x_t$的形状为&lt;code&gt;[batch_size,input_size]&lt;/code&gt;，$h_{t-1}$的形状为&lt;code&gt;[batch_size,hidden_size]&lt;/code&gt;，$[h_{t-1},x_t]$的形状为&lt;code&gt;[batch_size,input_size+hidden_size]&lt;/code&gt;，$W_f$的形状为&lt;code&gt;[input_size+hidden_size,hidden_size]&lt;/code&gt;，$b_f$的形状为&lt;code&gt;[hidden_size]&lt;/code&gt;，$f_t$的形状为&lt;code&gt;[batch_size,hidden_size]&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2.输入门&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;输入门主要用于对输入信息$\tilde{C_t}$进行筛选，仅让其中部分信息流入到当前时刻，然后再与历史记忆状态融合形成新的记忆状态$C_t$。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;350&#34; src=&#34;https://mlwithme.github.io/images/dl/23051119020.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 7-8 LSTM输入门&lt;/center&gt;&#xA;&lt;p&gt;如图7-8所示，在LSTM中第2步需要做的便是通过输入门对当前时刻的输入信息进行筛选，其具体计算过程为&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;i_t&amp;=\sigma([h_{t-1},x_t]W_i+b_i)\\[2ex]&#xA;\tilde{C_t}&amp;=\tanh([h_{t-1},x_t]W_c+b_c)\\[2ex]&#xA;\end{aligned}\tag{7-10}&#xA;$$&lt;p&gt;&#xA;其中$W_i$和$W_c$的形状均为&lt;code&gt;[input_size+hidden_size,hidden_size]&lt;/code&gt;，$b_i$和$b_c$的形状均为&lt;code&gt;[hidden_size]&lt;/code&gt;，$i_t$和$\tilde{C}_t$的形状均为&lt;code&gt;[batch_size,hidden_size]&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;进一步对历史记忆状态$C_{t-1}$进行更新，计算过程为&#xA;&lt;/p&gt;&#xA;$$&#xA;C_t=f_t\odot C_{t-1}\oplus  i_t\odot\tilde{C_t}\tag{7-11}&#xA;$$&lt;p&gt;&#xA;其中$\odot$表示按位乘，$\oplus$表示按位加，$C_{t-1}$的形状为&lt;code&gt;[batch_size,hidden_size]&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;3. 输出门&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;subscribe&gt;55&lt;/subscribe&gt;&lt;/p&gt;&#xA;&lt;br&gt;&#xA;&lt;br&gt;&#xA;&lt;br&gt;</description>
			</item>
			<item>
				<title>7.4 GRU网络</title>
				<link>https://mlwithme.github.io/dl/chapter07/4112672112224dc1/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter07/4112672112224dc1/</guid>
				<description>&lt;h1 id=&#34;74-gru网络&#34;&gt;7.4 GRU网络&lt;a class=&#34;anchor&#34; href=&#34;#74-gru%e7%bd%91%e7%bb%9c&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在上一节内容中，我们详细介绍了LSTM模型的相关原理，其动机主要是为了解决RNN模型中的长期依赖以及梯度消失或爆炸的问题。在接下来的这篇文章中我们将继续介绍另外一个同样是为了解决上述两个问题的基于门控循环单元（Gated Recurrent Unit, GRU）的时序模型[1]。&lt;/p&gt;&#xA;&lt;h2 id=&#34;741-gru动机&#34;&gt;7.4.1 GRU动机&lt;a class=&#34;anchor&#34; href=&#34;#741-gru%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;如同LSTM一样，GRU提出的动机同样是为了解决传统RNN的长距离依赖等问题。同时，受到LSTM中门控机制的启发曹庆贤等人在2014年也提出了一种基于门控循环单元的循环结构。与LSTM相比，GRU通过精简LSTM中输入门和输出门减少了模型的参数量从而使得计算速度更快，并同时使用了更新门和重置门来控制信息的流动。GRU既解决了LSTM中的复杂性和计算成本问题，同时又保留了LSTM在处理长序列数据时对梯度消失问题的有效应对，是一种更加简化和高效的RNN变体。&lt;/p&gt;&#xA;&lt;h2 id=&#34;742-gru结构&#34;&gt;7.4.2 GRU结构&lt;a class=&#34;anchor&#34; href=&#34;#742-gru%e7%bb%93%e6%9e%84&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;经过&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/b4c5ddcc9e904238&#34;&gt;7.3节&lt;/a&gt;对LSTM模型的介绍，GRU模型理解起来就十分容易了。在LSTM门中，每个记忆单元通过3个不同的门控结构来对输入当前时刻的信息进行筛选，而在GRU模型中则是将其精简到了两个门控结构，并通过一种巧妙的方式实现了对历史信息和当前信息的互补结合。如图7-10所示便是GRU模型的结构示意图。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;400&#34; src=&#34;https://mlwithme.github.io/images/dl/23051380910.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 7-10 GRU网络结构图&lt;/center&gt;&#xA;&lt;p&gt;从图7-10可以一眼看出GRU中去掉了LSTM中存在的隐含状态，转而只留下了直接贯穿所有时刻的记忆状态。在GRU中，首先是根据当前时刻的输入$x_t$和历史记忆状态$h_{t-1}$计算得到重置门$r_t$，并用于后续对历史记忆状态进行筛选，其具体计算过程为&#xA;&lt;/p&gt;&#xA;$$&#xA;r_t=\sigma([h_{t-1},x_t]W_r) &#xA;\tag{7-14}&#xA;$$&lt;p&gt;其中$\sigma$为Sigmoid函数，$[a,b]$示将$a,b$两个向量进行堆叠组合，$x_t$的形状为&lt;code&gt;[batch_size,input_size]&lt;/code&gt;，$h_{t-1}$的形状为&lt;code&gt;[batch_size,hidden_size]&lt;/code&gt;，$[h_{t-1},x_t]$的形状为&lt;code&gt;[batch_size,input_size+hidden_size]&lt;/code&gt;，$W_r$的形状为&lt;code&gt;[input_size+hidden_size,hidden_size]&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;接着，同样根据当前时刻的输入$x_t$和历史记忆状态$h_{t-1}$计算得到更新门$z_t$。可以看出，此时更新门的输出结果将同时作用于对历史信息和当前时刻信息的筛选，只是两者为互补关系，即$z_t$将直接作用于输出$\tilde{h}_t$，而$1-z_t$作用于历史记忆状态$h_{t-1}$。这样的设计也十分巧妙，一部占比分来自于历史状态，而另一部分占比则来自于当前状态，但总的信息占比量固定为1。当然，这里我们还可以把$z_t$看做是输出门，而$1-z_t$看作是遗忘门，详见第7.4.4节内容。进一步，更新门的具体计算过程为&#xA;&lt;/p&gt;&#xA;$$&#xA;z_t=\sigma([h_{t-1},x_t]W_z) &#xA;\tag{7-15}&#xA;$$&lt;p&gt;&#xA;其中$W_z$的形状为&lt;code&gt;[input_size+hidden_size,hidden_size]&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;最后，当前时刻的输入同经过重置门处理后的历史记忆状态组合，经过一个$\text{tanh}$非线性层后便得到了当前时刻的新输入信息；进一步再将更新门作用后的两个结果相加便得到了当前时刻GRU的输出$h_t$，其具体计算过程为&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;\tilde{h}_t=\tanh([r_t\odot h_{t-1},x_t]W)\\[2ex]&#xA;h_t=z_t\odot\tilde{h}_t+(1-z_t)\odot h_{t-1}&#xA;\end{aligned}\tag{7-16}&#xA;$$&lt;p&gt;&#xA;其中$W$的形状为&lt;code&gt;[input_size+hidden_size,hidden_size]&lt;/code&gt;，$h_t$的形状为&lt;code&gt;[batch_size,hidden_size]&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;743-gru实现&#34;&gt;7.4.3 GRU实现&lt;a class=&#34;anchor&#34; href=&#34;#743-gru%e5%ae%9e%e7%8e%b0&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在清楚GRU模型的相关原理之后，我们再来看如何借助PyTorch快速实现GRU模型，示例代码如下所示：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;test_GRU&lt;/span&gt;():&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;     batch_size, time_step &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;     input_size, hidden_size &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;     x &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;rand([batch_size, time_step, input_size])  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;     gru &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;GRU(input_size, hidden_size, num_layers&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;, batch_first&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;True&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;     output, hn &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; gru(x)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;     &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(output)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;     &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(hn)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从上述代码可以看出，PyTorch中&lt;code&gt;GRU&lt;/code&gt;的使用方式和&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/88ba4e03337b4233&#34;&gt;7.1.6节&lt;/a&gt;中介绍的&lt;code&gt;RNN&lt;/code&gt;的使用方式一致，因此这里我们就不再赘述。以上完整示例代码可以参见&lt;code&gt;Code/Chapter07/C05_GRU/main.py&lt;/code&gt;内容。&lt;/p&gt;&#xA;&lt;h2 id=&#34;744-gru与lstm对比&#34;&gt;7.4.4 GRU与LSTM对比&lt;a class=&#34;anchor&#34; href=&#34;#744-gru%e4%b8%8elstm%e5%af%b9%e6%af%94&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在介绍完GRU的相关原理及在PyTorch中的使用方法以后，我们再来将其与LSTM模型对比一下，看看两者有何异同之处。为了更好地从直观上来将两者进行对比，我们将图7-10中的结构换了一种绘制方式，如图7-11所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;550&#34; src=&#34;https://mlwithme.github.io/images/dl/240310104824.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 7-11 GRU与LSTM网络结构对比图&lt;/center&gt;&#xA;&lt;p&gt;如图7-11所示，左侧为LSTM的网络结构图，右侧则为重新绘制的GRU网络结构图，各位读者可以先对比其与图7-10的差别，然后再回过头来看这里的内容。首先，在LSTM中记忆状态$C_t$经非线性变换$\text{tanh}$作用后，再经过输出门作用后便得到当前时刻的输出$h_t$；而在GRU中，融入新信息后的记忆状态就直接作为了当前时刻的输出$h_t$。因此在LSTM中输出$h_t$可以看成是对记忆状态$C_t$的再次筛选，而在GRU中去掉了这一步。其次，虽然在LSTM和GRU中遗忘门（GRU中的$1-z_t$）都是通过第$t-1$时刻的输出$h_{t-1}$与当前时刻的输入$x_t$训练得到，但是不同点在于LSTM&lt;/p&gt;</description>
			</item>
			<item>
				<title>7.5 BiRNN网络</title>
				<link>https://mlwithme.github.io/dl/chapter07/b6e5ccb6cd064f74/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter07/b6e5ccb6cd064f74/</guid>
				<description>&lt;h1 id=&#34;75-birnn网络&#34;&gt;7.5 BiRNN网络&lt;a class=&#34;anchor&#34; href=&#34;#75-birnn%e7%bd%91%e7%bb%9c&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;经过前面几节内容的介绍，我们对于循环神经网络这一类模型已经有了清晰的认识。可以发现，不管是原始的RNN还是后续改进的LSTM和GRU等模型，它们在对输入序列进行特征编码时都是从左往右依次进行，也即在对当前时刻的信息进行编码时只能依赖于当前时刻之前的历史信息。然而，在实际情况中当前时刻之后的信息对于当前时刻的输出结果可能同样有用，例如在类似命名体识别这样的任务中。在这样的背景下，Mike Schuster等人[1]于1997年提出双向循环神经网络结构（Bidirectional Recurrent Neural Networks, BRNN），也简称为BiRNN，来解决这一问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;751-birnn动机&#34;&gt;7.5.1 BiRNN动机&lt;a class=&#34;anchor&#34; href=&#34;#751-birnn%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;传统的RNN模型在处理文本序列时都只能利用当前时刻之前的上下文信息而无法获得其后的上下文信息；相反，如果将文本序列反向输入到RNN模型中则又只能利用到当前位置之后的上下文信息而无法获取其之前的上下文信息。为了能够充分利用文本序列正反两个方向上的语义信息，BiRNN模型通过同时使用正向和反向RNN对输入序列进行特征提取，以便能够同时获得这两个方向上的上下文信息。&lt;/p&gt;&#xA;&lt;p&gt;由于BiRNN可以分别从正反两个方向上获得文本序列的上下文语义，因此它能够更好地理解序列中的上下文依赖关系，将全局语义信息传递到序列中的每一个位置从而提供更加准确的特征表示；并且由于BiRNN这种特有的正反结构，它还能够更好地处理序列中的长期依赖关系，对长文本序列的处理也有着较好的效果。不过也正是因为BiRNN需要从正反两个方向来依次计算每个时刻的输出结果，这导致其计算速度非常缓慢，因此它也只是常用于一些特定的场景中，如命名实体识别和语言翻译这类需要依靠全局信息的任务[2]。&lt;/p&gt;&#xA;&lt;h2 id=&#34;752-birnn结构&#34;&gt;7.5.2 BiRNN结构&lt;a class=&#34;anchor&#34; href=&#34;#752-birnn%e7%bb%93%e6%9e%84&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;总的来说BiRNN的模型结构并不复杂，它本质上就是由两个RNN所构成，只是分别将原始序列的正反两个方向作为各自的输入，如图7-13所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;380&#34; src=&#34;https://mlwithme.github.io/images/dl/23051511420.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;  图 7-13 BiRNN网络结构图&lt;/center&gt;&#xA;&lt;p&gt;如图7-13所示便是一个单层的BiRNN网络结构，下面的RNN1从正向（Forward）对输入序列进行特征提取，上面的RNN2从反向（Backward）对输入序列进行特征提取，对于两者每个时刻的输出结果既可以再次输入到下一层BiRNN中也可以进行组合直接作为特征使用，而对于正反两个方向的计算过程均与式(7-1)相同。同时，图7-13中的RNN记忆单元也可以替换成LSTM或GRU等。&lt;/p&gt;&#xA;&lt;h2 id=&#34;753-birnn实现&#34;&gt;7.5.3 BiRNN实现&lt;a class=&#34;anchor&#34; href=&#34;#753-birnn%e5%ae%9e%e7%8e%b0&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在清楚双向循环神经网络模型的相关原理之后，我们再来看如何借助PyTorch快速实现模型，示例代码如下所示：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;test_BiLSTM&lt;/span&gt;():&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;     batch_size,time_step &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;     input_size,hidden_size &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;     x &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;rand([batch_size, time_step, input_size])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;     lstm &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;LSTM(input_size, hidden_size, num_layers&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;                    batch_first&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;True&lt;/span&gt;, bidirectional&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;True&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;     output, (hn, cn) &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; lstm(x)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从上述代码可以看出，PyTorch中双向循环神经网络的使用方式和&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/88ba4e03337b4233&#34;&gt;7.1.6节&lt;/a&gt;中介绍的&lt;code&gt;RNN&lt;/code&gt;的使用方式一致，只需要将&lt;code&gt;bidirectional&lt;/code&gt;设置为&lt;code&gt;True&lt;/code&gt;即可（默认为&lt;code&gt;False&lt;/code&gt;)，因此这里我们就不再赘述。这里需要仔细介绍一下最后输出&lt;code&gt;output&lt;/code&gt;和&lt;code&gt;hn&lt;/code&gt;的形状。在上述第7行代码中，&lt;code&gt;output&lt;/code&gt;的形状为&lt;code&gt;[3,5,8]&lt;/code&gt;，即&lt;code&gt;[batch_size, time_step, 2*hidden_size]&lt;/code&gt;，其中第3个维度的前面4列为正向LSTM提取得到的输出结果，后4列为反向LSTM提取得到的输出结果。&lt;/p&gt;&#xA;&lt;p&gt;如下便是第1个样本的输出结果：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; tensor([[[ &lt;span style=&#34;color:#40a070&#34;&gt;0.0322&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1162&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0091&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0761&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1878&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0995&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.4181&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1844&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;          [ &lt;span style=&#34;color:#40a070&#34;&gt;0.0509&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1594&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0122&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1520&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1246&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0768&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.3270&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0915&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;          [ &lt;span style=&#34;color:#40a070&#34;&gt;0.0054&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1520&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0167&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.2036&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1360&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0494&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.3670&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1104&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;          [&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0456&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1496&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0269&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.2669&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0534&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0301&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.2054&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1105&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;          [ &lt;span style=&#34;color:#40a070&#34;&gt;0.0211&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1875&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0312&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.2397&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0353&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0387&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.1633&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1326&lt;/span&gt;]]])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述结果中，左边的5行4列便是正向LSTM各个时刻的输出结果，且第5行为最后一个时刻的输出结果；右边的5行4列便是反向LSTM各个时刻的输出结果，且第1行才是最后一个时刻的输出结果。&lt;/p&gt;&#xA;&lt;p&gt;进一步，&lt;code&gt;hn&lt;/code&gt;和&lt;code&gt;cn&lt;/code&gt;的输出形状均为&lt;code&gt;[2,3,4]&lt;/code&gt;，即&lt;code&gt;[num_layers*2, batch_size, hidden_size]&lt;/code&gt;，因为是双向所以第1个维度乘以了2，其中第1个维度的每两个切片均表示图7-13所示的最后一个时刻正反两个方向的输出结果。&lt;/p&gt;&#xA;&lt;p&gt;如下便是上述代码中&lt;code&gt;hn&lt;/code&gt;的输出结果：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; tensor([[[ &lt;span style=&#34;color:#40a070&#34;&gt;0.0211&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1875&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0312&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.2397&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;          [&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0113&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1713&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0314&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.2340&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;          [ &lt;span style=&#34;color:#40a070&#34;&gt;0.0190&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1552&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0424&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.2485&lt;/span&gt;]],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;         [[&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1878&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0995&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.4181&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1844&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;          [&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1409&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0749&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.3836&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1914&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;          [&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1214&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0129&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.3164&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1672&lt;/span&gt;]]])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述结果中，第1~3行表示正向LSTM最后一个时刻的输出结果。第5~7行表示反向LSTM最后一个时刻的输出结果，各位读者可以将其与上面&lt;code&gt;output&lt;/code&gt;的输出结果进行对比。以上完整示例代码可以参见&lt;code&gt;Code/Chapter07/C06_BiLSTM/main.py&lt;/code&gt;内容。&lt;/p&gt;</description>
			</item>
			<item>
				<title>7.6 CharRNN网络</title>
				<link>https://mlwithme.github.io/dl/chapter07/4bf3ecf7b21e45fb/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter07/4bf3ecf7b21e45fb/</guid>
				<description>&lt;h1 id=&#34;76-charrnn网络&#34;&gt;7.6 CharRNN网络&lt;a class=&#34;anchor&#34; href=&#34;#76-charrnn%e7%bd%91%e7%bb%9c&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;经过前面几节内容的介绍，我们已经清楚了RNN模型及其变体的相关原理，并且在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/ec8ff069aadc49b9&#34;&gt;7.2节&lt;/a&gt;内容中我们也通过两个实例详细介绍了RNN中多对一任务的构建流程。在本节内容中，我们将会以古诗词生成为例来介绍了RNN中的多对多任务类型，即图7-3中的第3种情况。&lt;/p&gt;&#xA;&lt;h2 id=&#34;761-任务构造原理&#34;&gt;7.6.1 任务构造原理&lt;a class=&#34;anchor&#34; href=&#34;#761-%e4%bb%bb%e5%8a%a1%e6%9e%84%e9%80%a0%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;对于接下来要介绍的古诗生成模型其本质上就是一个简单的RNN模型，也被称为字符级循环神经网络CharRNN[1]。CharRNN通过将序列$t_1,t_2,...,t_{n-1},t_n$作为模型输入，将$t_2,t_3,...,t_n,t_{n+1}$作为标签来训练模型，整个网络结构如图7-14所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;580&#34; src=&#34;https://mlwithme.github.io/images/dl/231214145644.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;  图 7-14 古诗生成模型网络结构图&lt;/center&gt;&#xA;&lt;p&gt;如图7-14所示，最下面为原始输入（Src Input），在转换为词表中的索引后便输入到词嵌入层（Embedding Layer）中。简单来讲，词嵌入层是一个包含有$m$行$n$列的网络层，其中$m$表示词表中词的数量，$n$表示向量的维度，即词嵌入层的作用是将词表中的每个词通过一个$n$维向量来进行表示。更多关于词嵌入层的内容将在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/c6aa1405b8cf46d8&#34;&gt;9.5节&lt;/a&gt;中进行介绍。&lt;/p&gt;&#xA;&lt;p&gt;在经过词嵌入层的处理之后再将该结果输入到循环神经网络中；然后再将循环神经网络输出结果中的每个时刻进行分类处理，并且因为这里的预测结果是词表中的其中一个词，所以其分类类别数便是词表的长度；最后将模型的预测结果同正确标签进行损失计算并完成整个模型的训练。&lt;/p&gt;&#xA;&lt;p&gt;当模型训练完成之后，可以通过给模型输入一个序列片段来循环完成固定长度序列的生成任务，整个预测过程原理如图7-15所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;580&#34; src=&#34;https://mlwithme.github.io/images/dl/23052114118.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;  图 7-15 古诗生成预测网络结构图&lt;/center&gt;&#xA;如图7-15所示便是整个模型的预测过程。在图7-15的最左侧为预测的第1个时刻，输入为“墙”预测结果为“角”；中间为第2个时刻，输入为“墙”以及第1个时刻的预测结果“角”组成的序列，预测结果只取最后一个时刻的“数”；最右侧为第3个时刻，输入为“墙”以及第1个和第2个时刻各自的预测结果组成的序列，预测结果同样只取最后一个时刻“枝”。最后继续迭代循环，直到预测生成的整个序列长度满足预设条件为止。&#xA;&lt;h2 id=&#34;762-数据预处理&#34;&gt;7.6.2 数据预处理&lt;a class=&#34;anchor&#34; href=&#34;#762-%e6%95%b0%e6%8d%ae%e9%a2%84%e5%a4%84%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 数据集介绍&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在清楚整个模型的训练和预测过程后，我们再来如何从零构建模型训练所需要的数据集。这里我们所使用到的是一个全唐诗[2]的数据集，一共有58个&lt;code&gt;json&lt;/code&gt;文件共计大约5.8万余首古诗。在每个&lt;code&gt;json&lt;/code&gt;文件中，文本内容的存储形式如下所示。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; [{&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;author&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;王安石&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;   &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;paragraphs&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;墙角数枝梅，凌寒独自开。&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;遥知不是雪，为有暗香来。&amp;#34;&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;   &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;梅花&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;   &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;ae7391fc-aef5-4f59-ae25-a7e7a9ee0858&amp;#34;&lt;/span&gt;},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;  {&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;author&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;佚名&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;   &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;paragraphs&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;自伯东去，首如飞蓬。&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;岂无膏沐，谁适为容。&amp;#34;&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;   &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;诗经·国风·卫风&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;   &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;0f0b345d-c074-4ec7-bde1-e28438712b7b&amp;#34;&lt;/span&gt;}]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从上述结果可以看出，整个&lt;code&gt;json&lt;/code&gt;文件的最外层是一个列表，列表中的每个元素便是一个包含有一首古诗的字段，后续我们将只取每首古诗中的&lt;code&gt;paragraphs&lt;/code&gt;来构建数据集。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 预处理流程&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在正式介绍如何构建数据集之前我们先通过一张图了解一下整体的构建流程。假如现在有两个样本构成了一个小批量，那么其整个数据的处理流程如图7-16所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;480&#34; src=&#34;https://mlwithme.github.io/images/dl/231214153252.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt; 图 7-16 数据集构建流程图&lt;/center&gt;&#xA;&lt;p&gt;注：图7-16中的词表是以整个训练集为语料构建而成，并非只由上述两个样本构建，其中0表示&lt;code&gt;[&#39;UNK&#39;]&lt;/code&gt;，1表示&lt;code&gt;[&#39;PAD&#39;]&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;如图7-16所示，首先我们需要将原始&lt;code&gt;json&lt;/code&gt;格式的语料抽取出出来；然后再以此为基础对句子进行分词（字）并构建词表；接着再将样本句子中的每个词转换为词表中对应的索引序号得到原始输入Src，并同时将原始输入向左平移一位得到真实标签Tgt；最后在输入模型之前再对其进行填充处理以使得每个小批量中所有样本的长度一致。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;3. 格式化样本和 Tokenize&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;首先，我们定义一个类&lt;code&gt;TangShi&lt;/code&gt;并继承自在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/ec8ff069aadc49b9&#34;&gt;7.2.4节&lt;/a&gt;中介绍的&lt;code&gt;TouTiaoNews&lt;/code&gt;类以复用其中的部分方法，同时初始化原始数据的相关存储路径，示例代码如下所示：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;TangShi&lt;/span&gt;(TouTiaoNews):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;     DATA_DIR &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; os&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;join(DATA_HOME, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;peotry_tang&amp;#39;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;     FILE_PATH &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; [os&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;join(DATA_DIR, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;poet.tang.0-55.json&amp;#39;&lt;/span&gt;),  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;                  os&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;join(DATA_DIR, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;poet.tang.56-56.json&amp;#39;&lt;/span&gt;), &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;                  os&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;join(DATA_DIR, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;poet.tang.57-57.json&amp;#39;&lt;/span&gt;)] &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;__init__&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;args, &lt;span style=&#34;color:#666&#34;&gt;**&lt;/span&gt;kwargs):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;super&lt;/span&gt;(TangShi, &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;)&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;__init__&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;args, &lt;span style=&#34;color:#666&#34;&gt;**&lt;/span&gt;kwargs)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;ends &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; [&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;vocab&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;stoi[&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;。&amp;#34;&lt;/span&gt;], &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;vocab&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;stoi[&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;？&amp;#34;&lt;/span&gt;]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第2行用来指定原始数据存储路径。第3~5行用来指定文件名并同时划分了训练集（&lt;code&gt;poet.tang.0.json&lt;/code&gt;~&lt;code&gt;poet.tang.55000.json&lt;/code&gt;)、验证集（&lt;code&gt;poet.tang.56000.json&lt;/code&gt;~&lt;code&gt;poet.tang.56000.json&lt;/code&gt;)和测试集（&lt;code&gt;poet.tang.57000.json&lt;/code&gt;~&lt;code&gt;poet.tang.57000.json&lt;/code&gt;)，后续将解析其中的序号来读取相应的原始文件。第8行用来指定可能的结束符，用于生成序列时的停止条件之一。&lt;/p&gt;&#xA;&lt;p&gt;进一步，定义&lt;code&gt;load_raw_data&lt;/code&gt;方法来完成原始所有数据的载入，示例代码如下所示：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;load_raw_data&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;, file_path&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;None&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;read_json_data&lt;/span&gt;(file_path):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;             samples, labels &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; [], []&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;             &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;open&lt;/span&gt;(file_path, encoding&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;as&lt;/span&gt; f:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;                 data &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; json&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;loads(f&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;read())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;                 &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; item &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; data:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;                     content &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;join(item[&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;paragraphs&amp;#39;&lt;/span&gt;])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;9&lt;/span&gt;                     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;not&lt;/span&gt; skip(content):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;10&lt;/span&gt;                         samples&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;append(content[:&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;]) &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;11&lt;/span&gt;                         labels&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;append(content[&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;:])  &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# 向左平移 &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;12&lt;/span&gt;             &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; samples, labels&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;13&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;14&lt;/span&gt;         file_name &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; file_path&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;split(os&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;sep)[&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;15&lt;/span&gt;         start, end &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; file_name&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;split(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;.&amp;#39;&lt;/span&gt;)[&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;]&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;split(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;-&amp;#39;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;16&lt;/span&gt;         all_samples, all_labels &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; [], []&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;17&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;range&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;int&lt;/span&gt;(start), &lt;span style=&#34;color:#007020&#34;&gt;int&lt;/span&gt;(end) &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;18&lt;/span&gt;             file_path &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; os&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;join(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;DATA_DIR, &lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;poet.tang.&lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;i &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1000&lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;.json&amp;#39;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;19&lt;/span&gt;             samples, labels &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; read_json_data(file_path)  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;20&lt;/span&gt;             all_samples &lt;span style=&#34;color:#666&#34;&gt;+=&lt;/span&gt; samples  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;21&lt;/span&gt;             all_labels &lt;span style=&#34;color:#666&#34;&gt;+=&lt;/span&gt; labels&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;22&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; all_samples, all_labels&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第3~12行是定义一个辅助函数来读取单个的原始&lt;code&gt;json&lt;/code&gt;文件，其中第9行为根据相应条件来判断是否将部分内容过滤，第10~11行是构造对应的输入和标签。第14~16行为根据传入的参数提取文件对应序号。第17~21行为根据拼接的文件名循环读取原始&lt;code&gt;json&lt;/code&gt;文件。第22行为返回所有格式化后的结果。&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
