<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>第 9 章 自然语言处理 on 《从零学AI指南手册》</title>
		<link>https://mlwithme.github.io/dl/chapter09/</link>
		<description>Recent content in 第 9 章 自然语言处理 on 《从零学AI指南手册》</description>
		<generator>Hugo</generator>
		<language>zh_CN</language>
		
		
		
		
			<atom:link href="https://mlwithme.github.io/dl/chapter09/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>9.1 自然语言处理介绍</title>
				<link>https://mlwithme.github.io/dl/chapter09/e0cb9a7aae814045/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter09/e0cb9a7aae814045/</guid>
				<description>&lt;h1 id=&#34;第-9-章-自然语言处理&#34;&gt;第 9 章 自然语言处理&lt;a class=&#34;anchor&#34; href=&#34;#%e7%ac%ac-9-%e7%ab%a0-%e8%87%aa%e7%84%b6%e8%af%ad%e8%a8%80%e5%a4%84%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面两章内容中我们已经初步接触了与文本处理相关的任务模型，例如&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/ec8ff069aadc49b9&#34;&gt;7.2节&lt;/a&gt;和&lt;a href=&#34;https://mlwithme.github.io/dl/chapter08/2be88fbc08a5418f&#34;&gt;8.1节&lt;/a&gt;中介绍的文本分类任务、&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/4bf3ecf7b21e45fb&#34;&gt;7.6节&lt;/a&gt;中介绍的文本生成任务以及后续将会介绍到的机器翻译、问答模型和命名体识别任务等，而这些任务场景在人工智能领域也有一个特定的称谓——自然语言处理（Natural Language Processing, NLP）。自然语言处理是人工智能的一个子领域，它涉及计算机对人类自然语言的理解和生成，即自然语言理解（Natural Language Understanding, NLU）和自然语言生成（Natural Language Generation, NLG），其目标是使计算机能够理解、分析、生成语言并且能够实现与人类语言进行交互。在本章内容中，我们将会以整个自然语言处理的发展路线为主干来梳理其中几项关键技术出现的动机和相关原理。&lt;/p&gt;&#xA;&lt;h1 id=&#34;91-自然语言处理介绍&#34;&gt;9.1 自然语言处理介绍&lt;a class=&#34;anchor&#34; href=&#34;#91-%e8%87%aa%e7%84%b6%e8%af%ad%e8%a8%80%e5%a4%84%e7%90%86%e4%bb%8b%e7%bb%8d&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;自然语言处理起源于 20 世纪 50 年代。 早在 1950 年，计算机科学与人工智能之父艾伦·图灵（Alan Turing）就发表了一篇名为“计算机器与智能”的文章，并提出了著名的图灵测试，即一个是正常思维的人（代号B）、一个是机器（代号A），如果经过若干询问以后C不能得出实质的区别来分辨A与B的不同，则此机器B通过图灵测试[1]。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/dl/230703204115.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 9-1 图灵测试&lt;/center&gt;&#xA;&lt;p&gt;可以看出，如果需要实现机器和人类的交互，那么首先需要实现的便是机器对于人类自然语言的理解，因此一般认为自然语言处理的历史可以追溯到那个时候，至今已经过去了70多年[2]。&lt;/p&gt;&#xA;&lt;p&gt;从自然语言处理整个技术路线的发展来看大致可以分为3个阶段：20世纪50年代至20世纪90年代早期主要是基于规则的语言模型，20世纪90年代至21世纪早期主要是基于统计的语言模型，21世纪早期到现在主要是基于神经网络的语言模型 [3]。&lt;/p&gt;&#xA;&lt;h2 id=&#34;911-语言模型&#34;&gt;9.1.1 语言模型&lt;a class=&#34;anchor&#34; href=&#34;#911-%e8%af%ad%e8%a8%80%e6%a8%a1%e5%9e%8b&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;自然语言处理的本质是理解并生成语言，而对于计算机来说理解的本质便是根据语料训练得到文本序列的概率分布 [4]。因此，所谓语言模型便是根据给定文本序列来估计序列的联合概率，即对于任意长度为$T$的序列来说，语言模型的目的便是用来估计联合概率$P(x^{(1)},...,x^{(T)})$，如式(9-1)所示[4] [5] [6]&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;P(x^{(1)},...x^{(T)})=&amp;P(x^{(1)})\times P(x^{(2)}|x^{(1)})\times P(x^{(3)}|x^{(2)},x^{(1)})\times\cdots\times P(x^{(T)}|x^{(T-1)},...,x^{(1)})\\[2ex]&#xA;=&amp; \prod_{t=1}^TP(x^{(t)}|x^{(t-1)},...,x^{(1)})&#xA;\end{aligned}\tag{9-1}&#xA;$$&lt;p&gt;&#xA;其中等式右边的条件概率便是根据语料训练得到的语言模型。&lt;/p&gt;&#xA;&lt;p&gt;语言模型可以用来衡量一个句子或文本序列在语言中的合理性或流畅度，因此广泛应用于自动语音识别、机器翻译、文本生成和文本补全等自然语言处理任务中，例如常见的搜索引擎关键词联想功能，如图9-2所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/dl/230705153145.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 9-2 搜索引擎关键词联想&lt;/center&gt;&#xA;&lt;p&gt;在图9-2中，我们输入序列“Natural Language”之后，搜索引擎便自动给出了若干种（这里只给出了前3种）可能的联想结果，而这一过程便可以通过分别计算各个序列对应的联合概率再以概率降序排序得到[5]。例如对于图9-2中这3种情况来说，其联合该分别为&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;P(\text{&#39;N&#39;},\text{&#39;L&#39;},\text{&#39;P&#39;})&amp;=P(\text{&#39;N&#39;})\times P(\text{&#39;L&#39;}|\text{&#39;N&#39;})\times P(\text{&#39;P&#39;}|\text{&#39;N&#39;},\text{&#39;L&#39;})\\[2ex]&#xA;P(\text{&#39;N&#39;},\text{&#39;L&#39;},\text{&#39;I&#39;})&amp;=P(\text{&#39;N&#39;})\times P(\text{&#39;L&#39;}|\text{&#39;N&#39;})\times P(\text{&#39;I&#39;}|\text{&#39;N&#39;},\text{&#39;L&#39;})\\[2ex]&#xA;P(\text{&#39;N&#39;},\text{&#39;L&#39;},\text{&#39;U&#39;})&amp;=P(\text{&#39;N&#39;})\times P(\text{&#39;L&#39;}|\text{&#39;N&#39;})\times P(\text{&#39;U&#39;}|\text{&#39;N&#39;},\text{&#39;L&#39;})&#xA;\end{aligned}\tag{9-2}&#xA;$$&lt;p&gt;&#xA;其中$\text{&#39;N&#39;},\text{&#39;L&#39;},\text{&#39;P&#39;},\text{&#39;I&#39;},\text{&#39;U&#39;}$分别指Natural、Language、processing、inference和understanding这5个单词。&lt;/p&gt;</description>
			</item>
			<item>
				<title>9.2 Word2Vec词向量</title>
				<link>https://mlwithme.github.io/dl/chapter09/d4703d990f8d4fed/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter09/d4703d990f8d4fed/</guid>
				<description>&lt;h1 id=&#34;92-word2vec词向量&#34;&gt;9.2 Word2Vec词向量&lt;a class=&#34;anchor&#34; href=&#34;#92-word2vec%e8%af%8d%e5%90%91%e9%87%8f&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/e0cb9a7aae814045&#34;&gt;9.1节&lt;/a&gt;内容中，我们详细梳理了自然语言处理发展时所经历的3个核心阶段，并且同时提到目前主流的是基于深度学习的语言模型。在本节内容中我们将会介绍第1种基于神经网络的将单词表示为连续向量的自然语言处理技术——Word2Vec。&lt;/p&gt;&#xA;&lt;h2 id=&#34;921-word2vec动机&#34;&gt;9.2.1 Word2Vec动机&lt;a class=&#34;anchor&#34; href=&#34;#921-word2vec%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在基于深度学习的语言模型中一个关键的问题就是如何有效地表示文本信息。在早期的建模方法中通常都是使用基于手工设计的特征表示来表示文本，例如词袋模型中的词频或TF-IDF权重、独热编码等方法。但这些特征通常都是离散且稀疏的，难以捕捉到词与词之间的语义关系。例如独热编码就没有任何相似性或者其它关系上的概念，如果我们将点积作为相似性的衡量方法那么此时任意两个向量之间的相似度都将是0。因此，研究人员开始寻求一种更有效的文本表示方法，并且希望能够利用神经网络的能力来自动学习词的向量化表示。&lt;/p&gt;&#xA;&lt;p&gt;基于这样的动机，谷歌公司托马斯[1]等人于2013年提出了一种基于神经网络技术的Word2Vec模型来生成词向量（Word Embedding）或（Word Vector）。Word2Vec通过使用浅层神经网络模型来学习词的分布式表示（Distributed Representations），其核心思想是基于大量文本语料库的统计信息，将每个词分别映射到一个低维连续的向量空间中，使得具有相似语义的词在向量空间中的距离更近。这种分布式表示可以更好地捕捉词之间的语义关系，使得近义词之间的相似性和词之间的语义类比能够通过计算得到。例如计算&amp;quot;king&amp;quot; - &amp;ldquo;man&amp;rdquo; + &amp;ldquo;woman&amp;rdquo;，可以得到一个向量表示&amp;quot;queen&amp;quot;，即实现了词之间的类比关系[2]。&lt;/p&gt;&#xA;&lt;h2 id=&#34;922-word2vec模型&#34;&gt;9.2.2 Word2Vec模型&lt;a class=&#34;anchor&#34; href=&#34;#922-word2vec%e6%a8%a1%e5%9e%8b&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;整体来看Word2Vec模型的网络结构主要有两种：连续词袋模型（Continuous Bag of Words，CBOW）和跳元（Skip-gram）模型。CBOW模型的目标是在固定滑动窗口内根据第$t$个词的上下文词来预测第$t$个词对应的概率分布，即第$t$个词；Skip-gram模型则刚好与CBOW模型相反，它的目标是根据第$t$个词来预测其上下文各个词的概率分布。从这里我们可以看出，不管是CBOW模型还是Skip-gram模型都不需要人工额外标注数据，因此它们都属于自监督模型，下面开始分别进行介绍。&lt;/p&gt;&#xA;&lt;h2 id=&#34;923-连续词袋模型&#34;&gt;9.2.3 连续词袋模型&lt;a class=&#34;anchor&#34; href=&#34;#923-%e8%bf%9e%e7%bb%ad%e8%af%8d%e8%a2%8b%e6%a8%a1%e5%9e%8b&#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;如图9-4所示便是CBOW的原理示意图，此时滑动窗口的长度为$m=2$，CBOW的原理是文本序列$S$在所有滑动窗口下，通过已知的上下文词来最大化中心词出现的条件概率。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/dl/230708195923.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt; 图9-4 CBOW原理示意图&lt;/center&gt;&#xA;&lt;p&gt;在文本序列$S$中，对于每个位置$t=1,2,...,T$来说，在滑动窗口长度为$m$的情况下，CBOW模型的目标便是最大化所有给定上下文词$w_{t-m},..,w_{t-1},w_{t+1},...,w_{t+m}$时，中心词$w_t$对应的条件概率，如式(9-6)所示便是CBOW模型需要最大化的似然函数&#xA;&lt;/p&gt;&#xA;$$&#xA;\mathcal{L}(\theta)=\prod_{t=1}^TP(w_{t}|w_{t-m},...,w_{t-1},w_{t+1},...,w_{t+m};\theta)\tag{9-6}&#xA;$$&lt;p&gt;&#xA;其中$\theta$便是需要求解的模型参数。&lt;/p&gt;&#xA;&lt;p&gt;进一步，同时对式(9-6)两边取自然对数，且令$\hat{w}=\{w_{t-m},...,w_{t-1},w_{t+1},...,w_{t+m}\}$有&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;J(\theta)=-\frac{1}{T}\log \mathcal{L}(\theta) &amp;=-\frac{1}{T}\sum_{t=1}^T\log P(w_t|w_{t-m},...,w_{t-1},w_{t+1},...,w_{t+m};\theta)\\[3ex]&#xA;&amp;=-\frac{1}{T}\sum_{t=1}^T\log P(w_t|\hat{w};\theta)&#xA;\end{aligned}&#xA;\tag{9-7}&#xA;$$&lt;p&gt;&#xA;此时$J(\theta)$便是我们需要最小化的目标函数，而接下来的问题便是如何计算条件概率$P(w_{t}|\hat{w};\theta)$。&lt;/p&gt;&#xA;&lt;p&gt;现在假设$p_w$和$q_w$分别为词$w$作为中心词和上下文词时各自对应的词向量，则在给定上下文词$o$的情况下中心词$c$的条件概率为&#xA;&lt;/p&gt;&#xA;$$&#xA;P(c|o)=\frac{\exp(q_o^Tp_c)}{\sum\limits_{w\in \mathcal{V}}\exp(q^T_op_w)}\in \mathbb{R}\tag{9-8}&#xA;$$&lt;p&gt;&#xA;其中$\mathcal{V}$表示词表中所有的词。&lt;/p&gt;&#xA;&lt;p&gt;之所以可以通过式(9-8)来建模此时的条件概率是因为离得越近的两个词总体上语义应该越相似，而点积的大小在一定程度上则可以反映两个向量的相似性，点积越大则表示两个向量越相似[2]。因此，在建模上述条件概率时本质上可以看做是对于已知上下文词时，模型需要在词表中找到与之尽可能相似的词。&lt;/p&gt;&#xA;&lt;p&gt;此时，由式(9-7)和式(9-8)可得&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;J(\theta)&amp;=-\frac{1}{T}\sum_{t=1}^T\log \frac{\exp(q_{\hat{w}}^Tp_{w_t})}{\sum\limits_{w\in\mathcal{V}}\exp(q^T_{\hat{w}}p_w)}=-\frac{1}{T}\sum_{t=1}^T\left(q_{\hat{w}}^Tp_{w_t}-\log\sum\limits_{w\in\mathcal{V}}\exp(q^T_{\hat{w}}p_w)\right)&#xA;\end{aligned}&#xA;\tag{9-9}&#xA;$$&lt;p&gt;&#xA;因为在CBOW模型中，待预测的中心词有多个上下文词，因此在实际处理时式(9-9)中的$q_{\hat{w}}$一般取滑动窗口中所有上下文词词向量的均值。最终，式(9-9)便是模型需要最小化的目标函数，虽然看起来略显复杂但是本质上它就是$\text{Softmax}$和交叉熵的组合。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 连续词袋模型建模&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在实际模型构建过程中，CBOW模型将首先取上下文中每个词$w_i$对应词向量$v_i\in \mathbb{R}^n$的均值；然后再与隐藏层权重参数$U\in \mathbb{R}^{n\times|\mathcal{V}|}$作用并取$\text{Softmax}$后得到对应的条件概率分布；最后使用交叉熵损失函数来完成模型的训练过程，整体结构如图9-5所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;550&#34; src=&#34;https://mlwithme.github.io/images/dl/231226095208.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 9-5 CBOW模型结构图&lt;/center&gt;&#xA;&lt;p&gt;在图9-5中，左侧输入层为上下文词的独热编码表示形式，其中$|\mathcal{V}|$表示词表的长度；中间为隐藏层，每一行表示根据对应上下文词独热编码索引得到的输入词向量表示，这也被形象的称为词嵌入（Word Embedding）；输入层和隐藏层之间的权重矩阵$V\in \mathbb{R}^{|\mathcal{V}|\times n}$为输入词向量矩阵，其中第$i$行$v_i$表示词表中第$i$个词$w_i$对应的输入词向量，而这也模型训练完毕后每个词真正的词向量表示；隐藏层与输出层之间的权重矩阵$U\in \mathbb{R}^{n\times |\mathcal{V}|}$为输出词向量矩阵，其中第$i$列$u_i$表示词表中第$i$个词$w_i$对应的输出词向量，用于同$v_i$计算得到对应的条件概率分布。&lt;/p&gt;</description>
			</item>
			<item>
				<title>9.3 Word2Vec训练与使用</title>
				<link>https://mlwithme.github.io/dl/chapter09/1bb6351b01a2479b/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter09/1bb6351b01a2479b/</guid>
				<description>&lt;h1 id=&#34;93-word2vec训练与使用&#34;&gt;9.3 Word2Vec训练与使用&lt;a class=&#34;anchor&#34; href=&#34;#93-word2vec%e8%ae%ad%e7%bb%83%e4%b8%8e%e4%bd%bf%e7%94%a8&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/d4703d990f8d4fed&#34;&gt;9.2节&lt;/a&gt;内容中，我们详细介绍了Word2Vec中CBOW和Skip-gram这两种建模语言模型来训练词向量的方法。根据式(9-8)和式(9-13)可知，由于目标词（在CBOW中指中心词，在Skip-gram中指上下文词）可以是词表$\mathcal{V}$中的任意一个，因此在计算条件概率时需要计算每个目标词与所有其他词之间的相似度，这就导致模型在计算梯度时同样需要计算大量的求和项（项数同词表长度一致）。但是由于在实际情况中词表的长度通常可以达到几十万或数百万，所以直接采取这样的方法来训练模型开销巨大[1]。&lt;/p&gt;&#xA;&lt;h2 id=&#34;931-近似训练&#34;&gt;9.3.1 近似训练&lt;a class=&#34;anchor&#34; href=&#34;#931-%e8%bf%91%e4%bc%bc%e8%ae%ad%e7%bb%83&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;为了降低模型训练在计算梯度时的复杂度提高模型的训练效率，托马斯（Tomas）等人[2]又提出了两种近似训练方法分层Softmax（Hierarchical Softmax）和负采样（Negative Sampling）来解决这一问题。&lt;/p&gt;&#xA;&lt;p&gt;分层Softmax的核心思想在于利用霍夫曼树的结构来表示词表中词之间的概率关系，树中的每个叶子节点表示词表中的一个词，每条路径则通过每个词的词频进行构建（频率越高的词离根节点越近），同时每个非叶子节点都对应着一个二分类器用于判断目标词在该节点左孩子或者右孩子中的概率，最终通过依次计算路径上各二分类器概率的乘积得到目标词与上下文词之间的条件概率。&lt;/p&gt;&#xA;&lt;p&gt;负采样的思想是将滑动窗口中的非目标词看做是正样本，并同时在整个词表中（不包括滑动窗口中的词）随机采样部分词作为负样本，而负采样方法的目标则是最大化目标词与正样本一同出现的概率，并同时最小化目标词与负样本一同出现的概率[1]。由于这部分内容过于繁杂我们这里就暂不做介绍，下面我们直接使用开源工具库Gensim来构建相应模型。&lt;/p&gt;&#xA;&lt;h2 id=&#34;932-载入预训练词向量&#34;&gt;9.3.2 载入预训练词向量&lt;a class=&#34;anchor&#34; href=&#34;#932-%e8%bd%bd%e5%85%a5%e9%a2%84%e8%ae%ad%e7%bb%83%e8%af%8d%e5%90%91%e9%87%8f&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. Gensim介绍&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;Gensim是Generate Similar的简称，它是一个免费开源的Python库，主要用于高效地将文本转换为向量表示等自然语言处理任务，并且Gensim还提供了一套简单而强大的API，使得处理大规模语料库和构建语言模型变得更加简单便捷[3]。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;430&#34; src=&#34;https://mlwithme.github.io/images/dl/230712193328.jpg&#34;/&gt; &lt;/div&gt; &lt;center&gt; 图9-8 Gensim库&lt;/center&gt;&#xA;&lt;p&gt;Gensim中的核心功能包括&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/d4703d990f8d4fed&#34;&gt;9.2节&lt;/a&gt;内容中介绍的Word2Vec模型以及在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/40a8a1146d934c55&#34;&gt;9.4节&lt;/a&gt;中将要介绍的FastText模型和LDA模型等。通过Gensim我们可以轻松地进行文本数据的预处理、特征提取和模型训练，从而支持各种与文本分析和语义相关的任务。由于其简洁易用的设计和高效的性能使得Gensim成为了自然语言处理领域中广泛应用的工具之一。&lt;/p&gt;&#xA;&lt;p&gt;在使用Gensim之前首先需要通过命令&lt;code&gt;pip install --upgrade gensim&lt;/code&gt;完成Gensim库的安装。接下来我们来看如何使用Gensim载入已经持久化到本地的词向量文件。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 英文词向量&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在这里，我们首先以Word2Vec论文中谷歌开源的词向量为例进行介绍。首先需要去谷歌官网下载该文件[4]，下载完成后将会得到一个名为&lt;code&gt;GoogleNews-vectors-negative300.bin.gz&lt;/code&gt;的文件。&lt;/p&gt;&#xA;&lt;p&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;from&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;gensim.models&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;import&lt;/span&gt; KeyedVectors&#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;load_third_part_wv_en&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;     path_to_model &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;Pretrained&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;                                  &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;GoogleNews-vectors-negative300.bin.gz&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;     model &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; KeyedVectors&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;load_word2vec_format(path_to_model, binary&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;     vec_king &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; model[&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;king&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;8&lt;/span&gt;     vec_queen &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; model[&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;queen&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;     logging&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;info(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;vec_king: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;vec_king&lt;span style=&#34;color:#70a0d0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&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;10&lt;/span&gt;     logging&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;info(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;vec_queen: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;vec_queen&lt;span style=&#34;color:#70a0d0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第1行便是从Gensim中导入&lt;code&gt;KeyedVectors&lt;/code&gt;类来加载本地词向量文件。第4~5行是构造词向量文件的路径。第6行便是用于载入本地的词向量文件，其中&lt;code&gt;binary&lt;/code&gt;用于指定该文件为一个二进制文件。第7~8行是取单词king和queen对应的词向量。&lt;/p&gt;&#xA;&lt;p&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; KeyedVectors lifecycle event {&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;msg&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;loaded (3000000, 300) matrix of type float32&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;2&lt;/span&gt; [ &lt;span style=&#34;color:#40a070&#34;&gt;0.12597656&lt;/span&gt;    &lt;span style=&#34;color:#40a070&#34;&gt;0.02978515&lt;/span&gt;   &lt;span style=&#34;color:#40a070&#34;&gt;0.00860595&lt;/span&gt;  &lt;span style=&#34;color:#40a070&#34;&gt;0.13964843&lt;/span&gt;&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;3&lt;/span&gt; [ &lt;span style=&#34;color:#40a070&#34;&gt;0.00524902&lt;/span&gt; &#x9; &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.14355469&lt;/span&gt;  &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.06933594&lt;/span&gt;  &lt;span style=&#34;color:#40a070&#34;&gt;0.12353516&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;....&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从上述输出信息可以知道，词向量文件中一共包含有300万个词，每个词向量的维度为300维。第2~3行则是单词king和queen对应词向量的部分结果输出。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;3. 常见用法&lt;/strong&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>9.4 GloVe词向量</title>
				<link>https://mlwithme.github.io/dl/chapter09/40a8a1146d934c55/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter09/40a8a1146d934c55/</guid>
				<description>&lt;h1 id=&#34;94-glove词向量&#34;&gt;9.4 GloVe词向量&lt;a class=&#34;anchor&#34; href=&#34;#94-glove%e8%af%8d%e5%90%91%e9%87%8f&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/d4703d990f8d4fed&#34;&gt;9.2节&lt;/a&gt;内容中，我们详细介绍了Word2Vec中两训练词向量的模型CBOW和Skip-gram背后的思想与原理，即在固定窗口中通过中心词来预测上下文或上下文来预测中心词的思想来捕捉词与词之间的语义关系，从而学习得到词的向量表示。在接下来的这节内容中，我们将会介绍另外一种同时考虑全局信息的词向量模型。&lt;/p&gt;&#xA;&lt;h2 id=&#34;941-glove动机&#34;&gt;9.4.1 GloVe动机&lt;a class=&#34;anchor&#34; href=&#34;#941-glove%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;由CBOW和Skip-gram这两种模型的原理可知，本质上它们都是通过固定窗口中的局部上下文信息来学词的全局向量表示，即没有考虑到词在整个语料中的全局信息对最终词向量的影响。对于一个庞大的语料来说，如果两个词频繁地出现在同一个上下文环境中，那么则说明这两个词具有更强的关联程度，因此模型在训练词向量的过程中就应该需要将这部分信息考虑进去。&lt;/p&gt;&#xA;&lt;p&gt;基于这样的动机，斯坦福大学彭宁顿（Pennington）[1]等人于2014年提出了一种基于全局角度考虑词与词之间共现信息的词向量训练方法—— 全局向量的词嵌入（ Global Vectors for Word Representation, GloVe）。GloVe模型的核心思想是首先通过全局共现矩阵（Co-occurrence Matrix）来统计词与词之间在不同上下文环境中的共现频次，然后再将其作用于原有的条件概率中来调整词向量的关联程度，从而辅以全局的角度来捕捉词与词之间的语义关系。&lt;/p&gt;&#xA;&lt;h2 id=&#34;942-共现矩阵&#34;&gt;9.4.2 共现矩阵&lt;a class=&#34;anchor&#34; href=&#34;#942-%e5%85%b1%e7%8e%b0%e7%9f%a9%e9%98%b5&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在建模GloVe模型时整个过程大致可以分为两步：首先根据训练语料计算得到共现矩阵$X$；然后再将模型的预测值同贡献矩阵进行损失计算进而训练得到包含全局统计信息的词向量。下面开始先对共现矩阵进行介绍。&lt;/p&gt;&#xA;&lt;p&gt;共现矩阵是一个对称方阵，其大小为词表中所有词的总数，矩阵中的每个元素表示两个词在上下文中共同出现的次数。具体地，设$X$表示共现矩阵，则$X_{ij}$表示在所有文档中词$w_j$出现在词$w_i$的上下文环境中的次数，$X_i=\sum_{k}X_{ik}$表示所有词出现在词$w_i$上下文环境中的总次数。最后，在词$w_i$的上下文环境中词$w_j$出现的概率可以定义为&#xA;&lt;/p&gt;&#xA;$$&#xA;P_{ij}=P(w_j|w_i)=\frac{X_{ij}}{X_i}\tag{9-15}&#xA;$$&lt;p&gt;&#xA;进一步，为了构建共现矩阵首先需要定义一个窗口来考虑词$w_i$的上下文范围；然后再遍历语料库中的每个句子，并针对每个词$w_j$将词$w_i$上下文窗口内的其它词与$w_j$进行比较，如果与$w_j$相同则$X_{ij}$的值加一。&lt;/p&gt;&#xA;&lt;p&gt;假定现在有如下3条语料：&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; I like deep learning&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;2&lt;/span&gt; I like NLP&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;3&lt;/span&gt; I enjoy flying&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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; vocab &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; [&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;I&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;like&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;enjoy&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;deep&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;learning&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;NLP&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;flying&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;.&amp;#39;&lt;/span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此时假定窗口长度$m=1$，则最后便可以得到如下共现矩阵$X_{8\times8}$&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/dl/230715200545.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 9-10 共现矩阵图&lt;/center&gt;&#xA;&lt;p&gt;在图9-10中，第0行第1列（忽略表头）中2的含义为词&amp;rsquo;like&amp;rsquo;出现在词&amp;rsquo;I&amp;rsquo;的上下文环境中的次数为2，即第1条和第2条语料中的&amp;rsquo;I like&amp;rsquo;；同理，第0行第2列中1的含义为词&amp;rsquo;enjoy&amp;rsquo;出现在词&amp;rsquo;I&amp;rsquo;的上下文环境中的次数为1，即第3条语料中的&amp;rsquo;I enjoy&amp;rsquo;；第1行第0列中2的含义为词&amp;rsquo;I&amp;rsquo;出现在词&amp;rsquo;like&amp;rsquo;的上下文环境中的次数为2，即第1条语料中的&amp;rsquo;I like deep&amp;rsquo;和第2条语料中的&amp;rsquo;I like NLP&amp;rsquo;。&lt;/p&gt;&#xA;&lt;p&gt;从共现矩阵的构建过程可以看出，共现矩阵能够有效地对词$w_j$所处词$w_i$上下文环境的情况进行量化，即$X_{ij}$越大则表示词$w_j$出现在词$w_i$的上下文中越频繁，词$w_j$与词$w_i$联系程度越紧密。同时，共现矩阵$X$的对角线全为0也表示在正常情况下同一个词不可能连续出现两次。&lt;/p&gt;&#xA;&lt;p&gt;根据图9-10中的共现矩阵和式(9-15)可以进一步计算得到共现矩阵对应的条件概率分布&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/dl/230716095342.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 9-11 条件概率分布图&lt;/center&gt;&#xA;&lt;p&gt;从图9-11可以得出，词&amp;rsquo;enjoy&amp;rsquo;出现在词&amp;rsquo;I&amp;rsquo;的上下文中的概率为0.3333；词&amp;rsquo;deep&amp;rsquo;出现在词&amp;rsquo;like&amp;rsquo;的上下文中的概率为0.25。&lt;/p&gt;&#xA;&lt;h2 id=&#34;943-glove原理&#34;&gt;9.4.3 GloVe原理&lt;a class=&#34;anchor&#34; href=&#34;#943-glove%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. GloVe思想&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;根据&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/d4703d990f8d4fed&#34;&gt;9.4.2节&lt;/a&gt;内容我们知道了共现矩阵$X$的基本原理以及如何将计算得到对应的上下文条件矩阵概率$P$。下面我们通过一个简单的示例来介绍GloVe模型背后的思想。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;550&#34; src=&#34;https://mlwithme.github.io/images/dl/230716155517.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图9-12 共现矩阵条件概率图[1]&lt;/center&gt;&#xA;&lt;p&gt;如图9-12所示是大语料下部分词所出现的条件概率及相应的比值结果，例如对于第1列中$1.9\times10^{-4}$来说它表示在词&amp;rsquo;ice&amp;rsquo;的上线文环境中词&amp;rsquo;solid&amp;rsquo;出现的概率，$2.2\times10^{-5}$表示在词&amp;rsquo;steam&amp;rsquo;的上线文环境中词&amp;rsquo;solid&amp;rsquo;出现的概率，而8.9则表示前者比后者的比值。在构建GloVe模型时，作者认为：&lt;/p&gt;&#xA;&lt;p&gt;①如果词$k$与词$i$相关而与词$j$不太相关，那么$P(k|i)/P(k|j)$就应该有更大的共现比率值，例如图9-12中的第1列；&lt;/p&gt;&#xA;&lt;p&gt;②如果词$k$与词$i$不太相关而与词$j$相关，那么$P(k|i)/P(k|j)$就应该有更小的共现比率值，例如图9-12中的第2列；&lt;/p&gt;&#xA;&lt;p&gt;③如果词$k$与词$i$和词$j$均相关，那么$P(k|i)/P(k|j)$就应该有接近于1的共现比率值，例如图9-12中的第3、4两列。&lt;/p&gt;</description>
			</item>
			<item>
				<title>9.5 词向量的微调使用</title>
				<link>https://mlwithme.github.io/dl/chapter09/c6aa1405b8cf46d8/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter09/c6aa1405b8cf46d8/</guid>
				<description>&lt;h1 id=&#34;95-词向量的微调使用&#34;&gt;9.5 词向量的微调使用&lt;a class=&#34;anchor&#34; href=&#34;#95-%e8%af%8d%e5%90%91%e9%87%8f%e7%9a%84%e5%be%ae%e8%b0%83%e4%bd%bf%e7%94%a8&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面几节内容中，我们分别介绍了两种词向量模型的原理和使用方法，不过这些方法也仅仅是停留在单一词向量计算和推理方面，而它更常见的一种用法是作为网络中的词嵌入层进行使用。在本节内容中，我们将会详细介绍如何将预训练的词向量作为网络模型的词嵌入层进行使用。&lt;/p&gt;&#xA;&lt;h2 id=&#34;951-词嵌入层介绍&#34;&gt;9.5.1 词嵌入层介绍&lt;a class=&#34;anchor&#34; href=&#34;#951-%e8%af%8d%e5%b5%8c%e5%85%a5%e5%b1%82%e4%bb%8b%e7%bb%8d&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;词嵌入层（Word Embedding Layer）是自然语言处理任务中常用的组件之一，它的作用是将离散的词转换为连续的向量表示以便计算机可以更好地理解和处理自然语言。本书中首次提及词嵌入这个概念是在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/4bf3ecf7b21e45fb&#34;&gt;7.6节&lt;/a&gt;内容中，我们通过一个词嵌入层将原始的词转换为了一个稠密的向量表示，其原理如图9-13所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/dl/230718225028.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 9-13 词嵌入层示意图&lt;/center&gt;&#xA;&lt;p&gt;如图9-13所示，最左侧为该任务词表中每个词对应的索引，此时一共有2个样本，每个样本由6个词构成；中间部分为一个词嵌入层，其权重为一个$m\times n$的矩阵，其中$m$表示词表的长度，第$i$行表示词表中第$i$个词的词向量表示，$n$表示词向量的维度；最左侧则是输入的索引在词嵌入层中索引得到的结果。例如对于第1个样本来说它是有词表中第1、3、4、0、1和0个词构成，而词嵌入层则会取权重矩阵的对应行来得到该样本的稠密向量表示。&lt;/p&gt;&#xA;&lt;p&gt;在自然语言处理中对于原始的文本输入通常都会经过这样一个词嵌入层将其转换为稠密向量表示，其中不同的策略在于词嵌入层中的权重矩阵是随机初始化的还是第三方预训练模型，例如GloVe词向量。&lt;/p&gt;&#xA;&lt;h2 id=&#34;952-词嵌入层使用&#34;&gt;9.5.2 词嵌入层使用&lt;a class=&#34;anchor&#34; href=&#34;#952-%e8%af%8d%e5%b5%8c%e5%85%a5%e5%b1%82%e4%bd%bf%e7%94%a8&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;不管是哪种策略下的词嵌入层都可以通过PyTorch中的&lt;code&gt;nn.Embedding()&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;/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;if&lt;/span&gt; &lt;span style=&#34;color:#bb60d5&#34;&gt;__name__&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;__main__&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;2&lt;/span&gt;     embedding &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Embedding(num_embeddings&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;20&lt;/span&gt;, embedding_dim&lt;span style=&#34;color:#666&#34;&gt;=&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;     x &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;LongTensor([[&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;], [&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;2&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;, &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0&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;     embedded_input &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; embedding(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;5&lt;/span&gt;     &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;词嵌入层权重: &amp;#34;&lt;/span&gt;, embedding&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;weight[:&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;6&lt;/span&gt;     &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;词嵌入后输入的形状: &amp;#34;&lt;/span&gt;, embedded_input&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;shape)&#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;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;词嵌入后输入的结果: &amp;#34;&lt;/span&gt;, embedded_input[&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第2行是初始化一个词嵌入层，其中&lt;code&gt;num_embeddings&lt;/code&gt;和&lt;code&gt;embedding_dim&lt;/code&gt;分别表示词表长度和词向量维度。第3行是样本中每个词在词表中的索引。第4行便是经过词嵌入后的结果。&lt;/p&gt;&#xA;&lt;p&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.9658&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.4774&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;1.7705&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;1.3563&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;1.8367&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.6297&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.0833&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.6767&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.2838&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:#40a070&#34;&gt;0.2031&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0171&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.7267&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.7138&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.3275&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.8566&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; 词嵌入后输入的形状:  torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Size([&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;6&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;7&lt;/span&gt; 词嵌入后输入的结果: tensor([[&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1.3563&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;1.8367&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.6297&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:#40a070&#34;&gt;0.2031&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0171&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.7267&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:#40a070&#34;&gt;0.7138&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.3275&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.8566&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;10&lt;/span&gt;                         [ &lt;span style=&#34;color:#40a070&#34;&gt;0.9658&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.4774&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;1.7705&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:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1.3563&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;1.8367&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.6297&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:#40a070&#34;&gt;0.9658&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.4774&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;1.7705&lt;/span&gt;]])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述结果中，第2~5行是随机初始化的词嵌入层权重的前5行。第7~12行便是第1个样本经过词嵌入层后的输出结果。&lt;/p&gt;</description>
			</item>
			<item>
				<title>9.6 fastText网络</title>
				<link>https://mlwithme.github.io/dl/chapter09/48c26d04b342452d/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter09/48c26d04b342452d/</guid>
				<description>&lt;h1 id=&#34;96-fasttext网络&#34;&gt;9.6 fastText网络&lt;a class=&#34;anchor&#34; href=&#34;#96-fasttext%e7%bd%91%e7%bb%9c&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/d4703d990f8d4fed&#34;&gt;9.2节&lt;/a&gt;和&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/40a8a1146d934c55&#34;&gt;9.4节&lt;/a&gt;内容中我们分介绍了Word2Vec和GloVe这两种词向量模型的原理，可以发现它们有一个共同的特点就是都是以词为粒度来训练其对应的词向量。在接下来的这节内容中，我们将会介绍另外一种从此的形态学来训练词向量的模型。&lt;/p&gt;&#xA;&lt;h2 id=&#34;961-fasttext动机&#34;&gt;9.6.1 fastText动机&lt;a class=&#34;anchor&#34; href=&#34;#961-fasttext%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;尽管同一个词根可以派生得到不同词，但是在Word2Vec和GloVe这两种模型中并没有从形态学的角度来考虑词向量的生成。例如对于interesting和interested这两个词来说，虽然它们都有共同的词根interest，但是在Word2Vec和GloVe中却将这三者看成了完全不同的3个词来对待，而这将导致如果某些词在语料中出现的频次过低，那么模型将难以准确学到这些词对应的词嵌入表示。&lt;/p&gt;&#xA;&lt;p&gt;基于这样的动机，元宇宙公司研究院（Facebook AI Research, FAIR）博扬诺夫斯基（Bojanowski）等人[1]于2017年基于&lt;a href=&#34;Ch09.2_Word2Vec?id=_924-%e8%b7%b3%e5%85%83%e6%a8%a1%e5%9e%8b%e8%b7%b3&#34;&gt;9.2.4节&lt;/a&gt;˙中的跳元模型提出了一种从形态学角度来考虑词向量的子词（Subword）嵌入模型——fastText。fastText模型的核心思想是将一个词以N-gram的形式分割成若干字词部分，然后利用跳元模型的思想为每个子词学习得到一个嵌入式表示，最后将每个词各个子词对应的向量累加起来作为该词的向量化表示。通过这样的方式让具有相似结构的词之间共享来自子词的向量表示，fastText便可以捕捉到更加细粒度的语义信息从而提高了词向量的表达能力，同时对于词表中未出现的词也可以通过子词间的组合得到该词的词向量表示。&lt;/p&gt;&#xA;&lt;h2 id=&#34;962-fasttext原理&#34;&gt;9.6.2 fastText原理&lt;a class=&#34;anchor&#34; href=&#34;#962-fasttext%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;整体上来说fastText的原理是在跳元模型的基础上引入了字符级别的$N$-gram子词嵌入策略，即将一个词以$N$-gram($3\leq N \leq 6$)的方式划分成若干子词，然后采用模型为每个子词训练得到一个词向两，最后将该词所有子词的词向量求和得到最终的词向量表示。&lt;/p&gt;&#xA;&lt;p&gt;对于语料中的每个词来说，首先需要在其首尾分别加上&lt;code&gt;&amp;lt;&lt;/code&gt;和&lt;code&gt;&amp;gt;&lt;/code&gt;符以区分与其它单词的前后缀；然后再以不同取值$N$将其划分为$N$-gram子词并同该词本身构成整个语料对应的词表。以单词&lt;code&gt;where&lt;/code&gt;为例，首先在首尾分别加上&lt;code&gt;&amp;lt;&lt;/code&gt;和&lt;code&gt;&amp;gt;&lt;/code&gt;即&lt;code&gt;&amp;lt;where&amp;gt;&lt;/code&gt;；然后分别构建当$N=3$时其对应的子词集&lt;code&gt;&amp;lt;wh&lt;/code&gt;、&lt;code&gt;whe&lt;/code&gt;、&lt;code&gt;her&lt;/code&gt;、&lt;code&gt;ere&lt;/code&gt;、&lt;code&gt;re&amp;gt;&lt;/code&gt;，当$N=4$时的子词集&lt;code&gt;&amp;lt;whe&lt;/code&gt;、&lt;code&gt;wher&lt;/code&gt;、&lt;code&gt;here&lt;/code&gt;、&lt;code&gt;ere&amp;gt;&lt;/code&gt;，当$N=5$时的子词集&lt;code&gt;&amp;lt;wher&lt;/code&gt;、&lt;code&gt;where&lt;/code&gt;、&lt;code&gt;here&amp;gt;&lt;/code&gt;，当$N=6$时的子词集&lt;code&gt;&amp;lt;where&lt;/code&gt;、&lt;code&gt;where&amp;gt;&lt;/code&gt;，以及特殊子词&lt;code&gt;&amp;lt;where&amp;gt;&lt;/code&gt;。这样便得到了单词&lt;code&gt;where&lt;/code&gt;的子词集。最后以同样的方式构造得到所有单词的子词集便形成了最终的词表。&lt;/p&gt;&#xA;&lt;p&gt;在fastText中对于任意词$w$来说，用$\mathcal{G}_w$表示其对应的$N$-gram子词及其对应的特殊子词的合集，并假设$z_g$是词表中子词$g$对应的向量，则在跳元模型模型中，词$w$的词向量$v_w$是其所有子词向量的和[2]&#xA;&lt;/p&gt;&#xA;$$&#xA;v_w=\sum_{g\in\mathcal{G_w}}z_g\tag{9-25}&#xA;$$&lt;p&gt;&#xA;对于其它部分的建模过程fastText与&lt;a href=&#34;Ch09.2_Word2Vec?id=_924-%e8%b7%b3%e5%85%83%e6%a8%a1%e5%9e%8b&#34;&gt;9.2.4节&lt;/a&gt;中介绍的跳元模型模型一致，这里就不再赘述。&lt;/p&gt;&#xA;&lt;p&gt;同时，对于中文语料来说fastText模型会先使用斯坦福大学开源的斯坦福分词模型（Stanford Word Segmenter）[3] [4]进行普通的分词处理；然后同样也在每个词的首尾加上符号&lt;code&gt;&amp;lt;&lt;/code&gt;和 &lt;code&gt;&amp;gt;&lt;/code&gt; ；最后对于每个词来说以$N$-gram构建子词集，例如当$N=6$时，词&lt;code&gt;&amp;lt;跟我一起学深度学习&amp;gt;&lt;/code&gt;的子词有&lt;code&gt;&amp;lt;跟我一起学&lt;/code&gt;、&lt;code&gt;跟我一起学深&lt;/code&gt;、&lt;code&gt;我一起学深度&lt;/code&gt;、&lt;code&gt;一起学深度学&lt;/code&gt;、&lt;code&gt;起学深度学习&lt;/code&gt;和&lt;code&gt;学深度学习&amp;gt;&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;963-fasttext库介绍&#34;&gt;9.6.3 fastText库介绍&lt;a class=&#34;anchor&#34; href=&#34;#963-fasttext%e5%ba%93%e4%bb%8b%e7%bb%8d&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;对于fastText模型的使用有两种途径，第1种是借助Gensim库中的&lt;code&gt;gensim.models.FastText&lt;/code&gt;模块，其包括预训练词向量的载入和训练等，使用方法同&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/1bb6351b01a2479b&#34;&gt;9.3节&lt;/a&gt;类似这里就不再赘述，各位读者可以直接查阅官方文档[5]；第2种则是借助Facebook AI研究院开源的&lt;code&gt;fastText&lt;/code&gt;库[6]。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/dl/230721194421.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 9-14 fastText库&lt;/center&gt;&#xA;&lt;p&gt;fastText是由FAIR开发的一个用于文本分类和词向量学习的开源库，支持多语言文本处理并且在低资源情况下的文本分类任务中有良好的性能。除此之外fastText库还提供了简单易用的API和命令行工具，使得模型的训练和预测非常方便。在大规模数据集上，fastText具有高效的训练和推理速度，使其成为处理大规模文本数据的强大工具。&lt;/p&gt;&#xA;&lt;h2 id=&#34;964-词向量的使用与训练&#34;&gt;9.6.4 词向量的使用与训练&lt;a class=&#34;anchor&#34; href=&#34;#964-%e8%af%8d%e5%90%91%e9%87%8f%e7%9a%84%e4%bd%bf%e7%94%a8%e4%b8%8e%e8%ae%ad%e7%bb%83&#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;在fastText官网[6]中一共开源了157种语言的预训练模型，且均包含&lt;code&gt;txt&lt;/code&gt;和&lt;code&gt;bin&lt;/code&gt;两种格式，前者同&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/1bb6351b01a2479b&#34;&gt;9.3节&lt;/a&gt;中Word2Vec一样因此也可以通过Gensim库里的&lt;code&gt;KeyedVectors.load_word2vec_format()&lt;/code&gt;函数载入，后者则只能通过&lt;code&gt;fastText&lt;/code&gt;库中的&lt;code&gt;fasttext.load_model()&lt;/code&gt;函数载入使用。在使用之前需要通过命令&lt;code&gt;pip install --upgrade fasttext&lt;/code&gt;安装&lt;code&gt;fastText&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_fasttext_model&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;     path_to_model &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;Pretrained&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;fasttext&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;cc.zh.300.bin&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;     ft &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; fasttext&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;load_model(path_to_model)&#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;     logging&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;info(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;词向量的维度: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;ft&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;get_dimension()&lt;span style=&#34;color:#70a0d0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&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;     logging&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;info(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;中国: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;ft&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;get_word_vector(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;中国&amp;#39;&lt;/span&gt;)&lt;span style=&#34;color:#70a0d0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&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;     logging&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;info(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;与中国最相似的5个词为: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;ft&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;get_nearest_neighbors(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;中国&amp;#39;&lt;/span&gt;, k&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;)&lt;span style=&#34;color:#70a0d0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&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;     reduce_model(ft, &lt;span style=&#34;color:#40a070&#34;&gt;100&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;     logging&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;info(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;词向量的维度: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;ft&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;get_dimension()&lt;span style=&#34;color:#70a0d0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&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;9&lt;/span&gt;     path_to_model &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;Pretrained&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;fasttext&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;cc.zh.100.bin&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;10&lt;/span&gt;     ft&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;save_model(path_to_model)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;subscribe&gt;57&lt;/subscribe&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>9.7 Seq2Seq网络</title>
				<link>https://mlwithme.github.io/dl/chapter09/03a0166e195f443f/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter09/03a0166e195f443f/</guid>
				<description>&lt;h1 id=&#34;97-seq2seq网络&#34;&gt;9.7 Seq2Seq网络&lt;a class=&#34;anchor&#34; href=&#34;#97-seq2seq%e7%bd%91%e7%bb%9c&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/e0cb9a7aae814045&#34;&gt;9.1节&lt;/a&gt;内容中，我们探讨了自然语言处理的核心概念，即理解与生成。其中，自然语言理解可以看作是自然语言生成的前置任务。在自然语言理解任务中，主要目标是对原始输入文本进行编码（Encode）操作，即将文本转换为特征向量表示，然再将其应用于文本分类、命名实体识别或信息抽取等场景中以完成对文本语义的理解。对于自然语言生成来说则是根据自然语言理解阶段得到的特征向量表示来完成特定场景下的自然语言文本生成任务，典型的应用包括文本摘要、语音识别、机器翻译等。此时可以看出，在这个过程中自然语言生成类似于一个解码（Decode）操作，将编码阶段得到的特征向量转换为人类可理解的文本内容。&lt;/p&gt;&#xA;&lt;p&gt;尽管在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/4bf3ecf7b21e45fb&#34;&gt;7.6节&lt;/a&gt;内容中我们已经介绍了基于RNN结构的文本生成模型，但其编码和解码阶段使用的是相同的网络权重。然而，在类似翻译模型这样的场景下，这种方法是不适用的，因为翻译模型的输入和输出属于不同的语义空间，它们之间存在着显著的语言差异和词汇表的不同，因此需要采用不同的网络权重来编码和解码不同的语言特征。在本节及本章接下来的内容中，我们将会介绍另外一种新的网络架构编码器（Encoder）-解码器（Decoder），并围绕这一结构来介绍其它相关技术。&lt;/p&gt;&#xA;&lt;h2 id=&#34;971-seq2seq动机&#34;&gt;9.7.1 Seq2Seq动机&lt;a class=&#34;anchor&#34; href=&#34;#971-seq2seq%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在传统的深度神经网络中，由于输入和输出必须具有固定长度的限制，像机器翻译这样输入输出序列长度不固定的任务受到了极大的限制[1]。虽然RNN网络模型在一定程度上解决了序列长度固定的问题，但又面临着模型输入输出在同一个语义空间的限制。为了解决这一问题，我们需要考虑使用更加复杂但灵活又能同时解决上述两个问题的网络结构。&lt;/p&gt;&#xA;&lt;p&gt;基于这样的动机，谷歌公司苏茨克维尔（Sutskever）等人于2014年提出了一种基于LSTM的序列到序列（Sequence to Sequence, Seq2Seq）神经网络机器翻译模型（Neural Machine Translation, NMT）[1]，即输入和输出均为一个序列。Seq2Seq模型使用Encoder-Decoder架构来处理不同语义空间下的序列生成任务，其中编码器和解码器分别采用不同的网络权重以适应不同语义空间中的特征映射和转换。在模型训练过程中，它可以学习到输入和输出序列之间的复杂映射关系，从而实现有效的序列转换任务。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;400&#34; src=&#34;https://mlwithme.github.io/images/dl/230724230139.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt; 图9-15 Seq2Seq网络结构图&lt;/center&gt;&#xA;&lt;p&gt;如图9-15所示便是基于Encoder-Decoder架构的Seq2Seq模型，其中编码器和解码器分别由一个LSTM网络所构成。在Seq2Seq模型中，Encoder先将一个可变长度的序列编码成一个固定维度的中间向量，然后Decoder再将这个中间向量解码成一个可变长度的目标序列。&lt;/p&gt;&#xA;&lt;p&gt;此时我们需要明白的是，Seq2Seq其实是一类任务的总称，即根据源序列生成目标序列的场景，而Encoder-Decoder则是一种技术架构的总称。因此，对于Encoder和Decoder来说两者的网络结构并没有任何限制，可以分别采用不同的神经网络结构来满足实际的任务需求。所以在Encoder和Decoder中，除了可以是RNN、LSTM、GRU之外，也可以是之前已经介绍过的DNN、CNN和ConvLSTM等。例如对于&lt;a href=&#34;https://mlwithme.github.io/dl/chapter08/5f426a9190e7454b&#34;&gt;8.6节&lt;/a&gt;中的流量预测任务来说，如果我们想要预测未来多个时刻的流量分布情况，那么Encoder-Decoder便可以采样ConvLSTM来进行建模。&lt;/p&gt;&#xA;&lt;h2 id=&#34;972-seq2seq结构&#34;&gt;9.7.2 Seq2Seq结构&lt;a class=&#34;anchor&#34; href=&#34;#972-seq2seq%e7%bb%93%e6%9e%84&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;根据图9-15可知，Seq2Seq模型整体分为两个部分，编码器和解码器。编码器将不定长的输入序列转换为一个固定长度的上下文向量（Context Vector），然后解码器根据这个上下文向量逐步生成不定长的输出序列。如图9-16所示便是基于Seq2Seq的NMT翻译模型。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;480&#34; src=&#34;https://mlwithme.github.io/images/dl/230724210617.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt; 图9-16 Seq2Seq翻译模型网络结构图&lt;/center&gt;&#xA;&lt;p&gt;在图9-16中，左侧为编码器，论文中采用了4层LSTM来捕捉输入序列中的语义信息，然后再将编码器最后一个时间步长的隐含状态作上下文向量。右侧为解码器，同样也采用了4层LSTM结构，接收编码器产生的上下文向量作为初始隐含状态，并结合先前多个时刻的输出结果来逐步生成下一个时刻的输出概率分布，最终根据该概率分布采样生成实际的输出。可以看出，对于每个时刻的预测过程来说本质上都是一个分类任务，而分类类别数则是整个词表的大小，因此整个模型在计算损失时是以所有时刻的交叉熵损失来进行衡量。&lt;/p&gt;&#xA;&lt;p&gt;具体地，对于图9-16˙中的示例来说，编码器接受4个时刻的输出&amp;quot;I am a stuednt&amp;quot;，然后将其编码成一个固定维度的上下文向量$\mathcal{c}$，即第4个时刻对应的隐含状态。在解码器中，第1个时刻分别以上下文向量$\mathcal{c}$和&lt;code&gt;&amp;lt;bos&amp;gt;&lt;/code&gt;作为输入，然后得到第1个时刻的预测结果“我”；第2个时刻再以上下文向量、&lt;code&gt;&amp;lt;bos&amp;gt;&lt;/code&gt;和第1个时刻的输出作为输入来预测第2个时刻的输出，即此时将以$\mathcal{c}$、&lt;code&gt;&amp;lt;bos&amp;gt;&lt;/code&gt;和“我”作为输入；同理，第3个时刻将以$\mathcal{c}$、&lt;code&gt;&amp;lt;bos&amp;gt;&lt;/code&gt;、“我”和“是”作输入来预测第3个时刻的输出；以此循环，直到预测结果为&lt;code&gt;&amp;lt;eos&amp;gt;&lt;/code&gt;或达到指定长度后停止。&lt;/p&gt;&#xA;&lt;p&gt;这里需要注意的是，上述过程仅仅是Seq2Seq模型在推理阶段时的计算过程，对于训练过程来说在不同的场景下还会有不同的技巧。在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/fefa60e0bc854a17&#34;&gt;9.9节&lt;/a&gt;内容中我们将以一个实际的翻译模型为例来详细介绍整个过程。同时，此处的&lt;code&gt;&amp;lt;bos&amp;gt;&lt;/code&gt;和&lt;code&gt;&amp;lt;eos&amp;gt;&lt;/code&gt;分别表示起始符（begin of sentence）和结束符（end of sentence）。&lt;/p&gt;&#xA;&lt;h2 id=&#34;973-搜索策略&#34;&gt;9.7.3 搜索策略&lt;a class=&#34;anchor&#34; href=&#34;#973-%e6%90%9c%e7%b4%a2%e7%ad%96%e7%95%a5&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;根据&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/03a0166e195f443f?id=_972-seq2seq%e5%8e%9f%e7%90%86&#34;&gt;9.7.2节&lt;/a&gt;内容的介绍可知，解码器在对每个时刻的输出进行预测时我们都需要选择其中一个分类类别作为当前时刻的预测值。同时，通过前面几个章节的介绍可知，对于分类任务来说通常我们可以选择概率分布中概率值最大的类标作为分类结果。但是对于序列生成任务来说，由于第$t+1$时刻的预测结果会依赖于第$t$个时刻的预测结果，因此如果在每个时刻中均选择当前概率分布中概率值最大的类标并不能保证整个生成序列的条件概率值最大[2]。&lt;/p&gt;&#xA;&lt;p&gt;具体地，在序列生成任务中模型需要根据输入值$(x_1,...x_T)$来预测目标值$(y_1,...,y_{T^{\prime}})$，即最大化条件概率$p(y_1,...,y_{T^{\prime}}|x_1,...,x_T)$。在计算这一条件概率时，编码器首先需要根据输入值$(x_1,...x_T)$来编码得到上下文向量$\mathcal{c}$，然后再依次计算得到预测值$(y_1,...,y_{T^{\prime}})$对应的概率分布，即想要得到最优生成序列则需要最大化式(9-26)&#xA;&lt;/p&gt;&#xA;$$&#xA;p(y_1,...,y_{T^{\prime}}|x_1,...,x_T)=\prod_{t=1}^{T^{\prime}}p(y_t|\mathcal{c},y_1,...,y_{t-1})&#xA;\tag{9-26}&#xA;$$&lt;p&gt;&#xA;其中条件$p(y_t|\mathcal{c},y_1,...,y_{t-1})$的分布是解码时每个时刻输出的$\text{Softmax}$结果。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 贪婪搜索&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;贪婪搜索（Greedy Search）的基本原理是在解码每个时刻时，都选择概率分布中概率值最大的类标作为当前时刻的预测输出，一直持续到遇到终止符号或达到预先设定的输出序列长度时结束。虽然贪婪搜索简单高效且易于计算和实现，但是贪婪搜索也存在着一定的局限性。由于每次只考虑当前时刻的输出概率分布，并选择最大概率的输出，因此它可能无法得到全局最优的输出序列。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/dl/230725203810.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图9-17 （非）贪婪搜索示意图&lt;/center&gt;&#xA;&lt;p&gt;如图9-17所示是解码器在解码图9-16中输入“I am a student”时可能的两种搜索方式。对于图9-17(a)来说，解码器在每个时刻都选择了当前概率值最大结果，使得最终生成的序列“我  是  一位  老师”并不是正确的结果，此时对应的条件概率为$0.4\times0.45\times0.32\times0.48\times0.5\approx0.0138$。在图9-17(b)中，在解码第3个时刻时解码器选择了当前概率第二大的结果，并在前3个时刻输出结果的条件下依次得到后续两个时刻的输出，最终得到了最优学序列“我  是  一个  学生”，此时对应的条件概率为$0.4\times0.45\times0.3\times0.5\times0.52\approx0.0140$。通过这个例子也就说明了采用贪婪搜索并不能保证生成得到最优序列。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 穷举搜索&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;穷举搜索（Exhaustive Search），也被称为暴力搜索或完全搜索，它是一种简单而直接的搜索策略，通过枚举所有可能的发生情况来寻找问题的最优解。&lt;/p&gt;&#xA;&lt;p&gt;在穷举搜索中，解码器在解码当前时刻时会考虑所有生成的结果，而在解码下一个时刻时又会基于上一个时刻的所有结果来生成当前时刻的结果并依旧考虑当前时刻的所有结果，以此循环直到预测结束。可以看出，穷举搜索的生成结果会随着时间步长而成指数增长，因此在复杂问题中穷举搜索将会变得非常耗时，尤其是当问题的规模很大时。例如在机器翻译或文本摘要中穷举搜索往往不可行，在这些情况下就需要使用更高级的搜索算法来寻找更优的解决方案。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;3. 束搜索&lt;/strong&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>9.8 序列模型评价指标</title>
				<link>https://mlwithme.github.io/dl/chapter09/271bda16904544af/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter09/271bda16904544af/</guid>
				<description>&lt;h1 id=&#34;98-序列模型评价指标&#34;&gt;9.8 序列模型评价指标&lt;a class=&#34;anchor&#34; href=&#34;#98-%e5%ba%8f%e5%88%97%e6%a8%a1%e5%9e%8b%e8%af%84%e4%bb%b7%e6%8c%87%e6%a0%87&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/4bf3ecf7b21e45fb&#34;&gt;7.6节&lt;/a&gt;内容中我们首次接触了序列生成模型，并以准确率来作为序列生成的评价指标。虽然准确率在一定程度上能够评估模型的优劣，但是对于语言模型来说它并不是一个好的选择。例如对于翻译模型来说，生成的序列并不需要完全与目标序列一样对应，只需要在$N$-gram角度满足一定的重合度即可。在本节内容中，我们将会学习语言模型中两种较为常见的模型评价指标：困惑度（Perplexity）和双语评估辅助（BLEU）。&lt;/p&gt;&#xA;&lt;h2 id=&#34;981-困惑度&#34;&gt;9.8.1 困惑度&lt;a class=&#34;anchor&#34; href=&#34;#981-%e5%9b%b0%e6%83%91%e5%ba%a6&#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;关于如何定量地来描述信息，几千年来都没有人给出很好的解答。直到1948年，香农在他著名的论文《通信的数学原理》中提出了信息熵（Information Entropy）的概念，这才解决了信息的度量问题并且还量化出了信息的作用[1]。&lt;/p&gt;&#xA;&lt;p&gt;对于任意离散型随机变量$X\in\mathcal{X}$，且服从概率分布$\mathcal{X}\sim p(x)$，则随机变量$X$的信息熵定义为&#xA;&lt;/p&gt;&#xA;$$&#xA;H(X)=-\sum_{x\in\mathcal{X}}p(x)\log{p(x)}=\mathbb{E}[-\log p(X)]=\mathbb{E}\left[\log {\frac{1}{p(X)}} \right]&#xA;\tag{9-27}&#xA;$$&lt;p&gt;其中当$\log$取2为底时$H(X)$的单位为比特（Bit），取$e$为底的时候称之为纳特（Nat），此时$H(X)$表示的含义便是随机变量$X$所携带信息量的多少，也即编码该信息所需比特（纳特）数的期望。&lt;/p&gt;&#xA;&lt;p&gt;现在假设有8只球队进行比赛，每只球队获胜的概率都是$\frac{1}{8}$，那么对于“哪只球队能够获胜”这句描述来说，其信息量为&#xA;&lt;/p&gt;&#xA;$$&#xA;H(X)=-8\times(\frac{1}{8}\log{\frac{1}{8}})=3\text{ (Bit)}\tag{9-28}&#xA;$$&lt;p&gt;根据式(9-28)的计算结果可知，“哪只球队能够获胜”这句描述包含有3比特的信息，也就是说如果我们想要将哪只球队获得了冠军这一消息传递出去需要使用3个比特进行编码，即&lt;code&gt;000&lt;/code&gt;、&lt;code&gt;001&lt;/code&gt;一直到&lt;code&gt;111&lt;/code&gt;这8种情况。&lt;/p&gt;&#xA;&lt;p&gt;进一步，我们将式(9-27)的表达形式重写为&#xA;&lt;/p&gt;&#xA;$$&#xA;H(X)=\sum_{x\in\mathcal{X}}p(x)\log{\frac{1}{p(x)}}&#xA;\tag{9-29}&#xA;$$&lt;p&gt;由式(9-29)可知，$p(x)$表示的是随机事件$x$发生的概率，而$\log{\frac{1}{p(x)}}$ 表示的正是编码事件$x$所包含信息需要的比特数，因此$H(X)$则表示编码整个随机事件所有信息需要比特数的期望。&lt;/p&gt;&#xA;&lt;p&gt;例如假定明天下雨的概率是$\frac{1}{4}$，不下雨的概率是$\frac{3}{4}$，那么对于“明天可能下雨”这句描述来说，编码该信息所需比特数的期望为&#xA;&lt;/p&gt;&#xA;$$&#xA;H(X)=(\frac{1}{4}\log{\frac{4}{1}}+\frac{3}{4}\log{\frac{4}{3}})\approx0.8113 \text{ (Bit)}\tag{9-30}&#xA;$$&lt;p&gt;&lt;strong&gt;2. 困惑度&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;困惑度（Perplexity）是一种用于衡量语言模型性能的指标。具体来说，它衡量了模型对未知文本的困惑程度或不确定性，困惑度越低表示模型对测试集的预测越准确，即模型能够更好地对未知文本进行预测。在比较不同的语言模型时，较低的困惑度通常意味着更好的性能。&lt;/p&gt;&#xA;&lt;p&gt;具体地，对于离散型随机变量$X\in\mathcal{X}$且服从概率分布$\mathcal{X}\sim p(x)$来说，则其困惑度定义为[4] [5]&#xA;&lt;/p&gt;&#xA;$$&#xA;PP(X)=2^{H(X)}=2^{-\sum_{x}p(x)\log_2p(x)}\tag{9-31}&#xA;$$&lt;p&gt;根据式(9-31)可以看出，困惑度实际上计算的是随机变量$X$所有可能情况信息的总量，越低也就表示信息的确定性越高。&lt;/p&gt;&#xA;&lt;p&gt;进一步，在语言模型中式(9-31)可以改写为&#xA;&lt;/p&gt;&#xA;$$&#xA;PP(X)=\exp\left(H(X)\right)=\exp\left(-\frac{1}{N}\sum_{t=1}^N\ln p(x_t)\right)\tag{9-32}&#xA;$$&lt;p&gt;其中$p(x_t)$表示第$t$个时刻对应的条件概率，幂次$-\frac{1}{N}\sum_{t=1}^N\ln p(x_t)$可以看做是编码序列 $x_1,...x_N$ 所有信息需要纳特数的均值，同时在形式上也可以理解为交叉熵损失函数。&lt;/p&gt;&#xA;&lt;p&gt;根据式(9-32)可知，当模型在测试集上预测值和真实值越接近，那么此时模型的困惑度也将会越趋近于1；而在最坏的情况下，模型的困惑度将达到无穷大。&lt;/p&gt;&#xA;&lt;h2 id=&#34;982-双语评估辅助&#34;&gt;9.8.2 双语评估辅助&lt;a class=&#34;anchor&#34; href=&#34;#982-%e5%8f%8c%e8%af%ad%e8%af%84%e4%bc%b0%e8%be%85%e5%8a%a9&#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;双语评估辅助（Bilingual Evaluation Understudy, BLEU）是一种用于评估机器翻译质量的指标，它是由帕皮内尼（Papineni）等人于2002年所提出。BLEU通过比较机器翻译输出与参考翻译之间的$N$-gram匹配度来评估翻译质量，较高的BLEU分数则表示机器翻译系统的输出与参考译文之间有更多的重叠[6]。具体地，BLEU的计算方式定义如下[2] [6]&#xA;&lt;/p&gt;&#xA;$$&#xA;\text{BLEU}=\exp\left(\min\left(0,1-\frac{\text{len}_\text{label}}{\text{len}_\text{pred}}\right)\right)\prod_{n=1}^Np_n^{\frac{1}{N}}\tag{9-33}&#xA;$$&lt;p&gt;其中$\text{len}_\text{label}$和$\text{len}_\text{pred}$分别表示目标序列和预测序列的长度，$N$表示使用$N$-gram中的$N$值，$p_n$表示每个$N$-gram中预测序列里正确$N$-gram片段的数量除以整个$N$-gram片段的数量。&lt;/p&gt;&#xA;&lt;p&gt;根据式(9-33)可知，当目标序列与预测序列完全相同时BLEU的取值为1，即此时$p_n=1$；当目标序列与预测序列差异越大时BLEU将越接近于0。可以看出，BLEU不仅可以用于对机器翻译的结果进行评估，任何序列生成任务都可以将其作为评价指标。&lt;/p&gt;&#xA;&lt;p&gt;为了理解式(9-33)中的含义我们可以进一步对等式两边取对数，此时有&#xA;&lt;/p&gt;&#xA;$$&#xA;\log \text{BLEU}=\min\left(0,1-\frac{\text{len}_\text{label}}{\text{len}_\text{pred}}\right)+\sum_{n=1}^Nw_n\log p_n;\;\;w_n=\frac{1}{N}&#xA;\tag{9-34}&#xA;$$&lt;p&gt;其中$w_n$为每个$n$-gram中$\log p_n$对应的加权值，在原始论文中$w_n=\frac{1}{N}$，而在文献[2]中作者取值为$\frac{1}{2^n}$。这是因为随着$n$的增大则重叠片段的匹配难度就越大，所以可以给更大的$n$赋予更高的权重。同时，由于预测越短越容易获得较大的$p_n$，所以式(9-34)中的第1项可以作为惩罚项来对整个结果进行惩罚。例如当$N=2$时，对于目标序列A、B、C、D、E、F和预测序列A、B来说，尽管$p_1=p_2=1$，但是此时惩罚项$\exp(1-6/2)\approx0.14$会降低整个BLEU值。&lt;/p&gt;</description>
			</item>
			<item>
				<title>9.9 NMT网络</title>
				<link>https://mlwithme.github.io/dl/chapter09/fefa60e0bc854a17/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter09/fefa60e0bc854a17/</guid>
				<description>&lt;h1 id=&#34;99-nmt网络&#34;&gt;9.9 NMT网络&lt;a class=&#34;anchor&#34; href=&#34;#99-nmt%e7%bd%91%e7%bb%9c&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/03a0166e195f443f&#34;&gt;9.7节&lt;/a&gt;内容中，我们大致介绍了Seq2Seq架构的思想和基本原理，它通过编码器将源输入编码成一个固定维度的中间向量，然后再依靠解码器将这一中间向量解码成任务需要的目标序列。同时，这种序列到序列的网络架构也使得我们可以采用不同的网络模型来作为编码器和解码器使用，例如除了到目前为止我们已经介绍过的DNN、CNN和RNN之外，也可以是在第10章中将要介绍的自注意力模块等。在接下来的这节内容中，我们将会探索以LSTM模型为编码器和解码器的神经机器翻译模型（Neural Machine Translation, NMT）背后的原理及其实现过程。本节内容的完整示例代码可参见&lt;code&gt;Code/Chapter09/C07_NMT&lt;/code&gt;文件夹。&lt;/p&gt;&#xA;&lt;h2 id=&#34;991-谷歌翻译简介&#34;&gt;9.9.1 谷歌翻译简介&lt;a class=&#34;anchor&#34; href=&#34;#991-%e8%b0%b7%e6%ad%8c%e7%bf%bb%e8%af%91%e7%ae%80%e4%bb%8b&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;为了让每一个人都能访问世界上的所有信息，谷歌公司在2006年4月推出了一项基于统计机器方法的语言翻译模型（Statistical Machine Translation, SMT）。在SMT模型中，输入文本必须要先翻译成英语作为中转，然后再将其翻译成对应的目标语言，因此这也导致在不同语言中翻译结果的准确性差异很大[1]。&lt;/p&gt;&#xA;&lt;p&gt;随着深度学习技术的迅猛发展，谷歌公司于2014年提出了一种基于Seq2Seq架构的序列学习模型，并且尝试将其应用于NMT这一任务中[2]。但是由于该模型在翻译质量、推理速度和处理低频词等方面的效果并没有得到显著提升，因此并没有将其运用于实际的翻译服务中[3]。不过由于Seq2Seq模型在网络结构上的独特优势——编码器直接将源输入编码成一个向量，然后解码器再将其解码为对应的目标序列，从而避免了事先将源输入分割成不同粒度的短语而导致的翻译结果不流畅的问题——研究人员一直在尝试通过各种方法提高NMT模型的效果。直到2016年，谷歌公司又基于Seq2Seq的NMT模型提出了GNMT模型来解决上述问题，并将其运用在了谷歌翻译服务中[4]。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;550&#34; src=&#34;https://mlwithme.github.io/images/dl/230806155847.jpg&#34;/&gt; &lt;/div&gt; &lt;center&gt;图 9-19 谷歌翻译示例图&lt;/center&gt;&#xA;&lt;p&gt;值得一提的是随着自注意力机制（Self-Attention）的出现以及其强大的编码能力，谷歌公司也于2020年将其翻译服务中Seq2Seq的编码器部替换成了Transform中的Encoder模块（相关内容将在第10章中进行详细介绍），而解码器部分则依旧使用的是RNN模块，其主要原因在于使用RNN作为解码器在推理时的速度要远快于Transform中的Decoder模块[5]。&lt;/p&gt;&#xA;&lt;p&gt;谷歌神经机器翻译作为一种先进的机器翻译技术，对于改进跨语言交流和信息传播有着重要的作用。它使得机器翻译在很多情况下能够产生更流畅、准确的翻译结果，同时也是深度学习在自然语言处理领域成功应用的一个典型案例。截至2023 年8 月，谷歌翻译已经提供了超过133种语言的翻译服务，每天服务用户超5亿人[1]。&lt;/p&gt;&#xA;&lt;h2 id=&#34;992-统计翻译模型弊端&#34;&gt;9.9.2 统计翻译模型弊端&lt;a class=&#34;anchor&#34; href=&#34;#992-%e7%bb%9f%e8%ae%a1%e7%bf%bb%e8%af%91%e6%a8%a1%e5%9e%8b%e5%bc%8a%e7%ab%af&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;尽管传统基于短语的统计翻译模型在翻译任务中有着不错的表现，但是却一直存在着一些难以克服的弊端。由于这类模型需要将输入划分成不同粒度的短语进行翻译，所以会导致最后翻译的结果在语义上并不连贯，同时也会使得在长文本翻译过程中无法解决上下文的长依赖问题容易出现局部翻译化的现象[6]。同时，这类模型需要人工设计和提取大量的特征，例如词频、短语对齐等，这些过程比较繁琐且依赖于专业知识因此并不具有良好的可扩展性，每换一种翻译场景都需要重新开始构建统计模型。&lt;/p&gt;&#xA;&lt;p&gt;鉴于上述原因，基于神经网络的机器翻译模型开始引起了研究人员的注意，而谷歌公司苏茨克维尔（Sutskever）等人于2014年也提出了一种基于LSTM的神经网络机器翻译模型[2]。在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/03a0166e195f443f&#34;&gt;9.7节&lt;/a&gt;内容中我们已经大致介绍了这一模型的思想和基本原理，接下来我们再以一个真实的翻译任务为例来详细介绍NMT模型的具体工作原理。&lt;/p&gt;&#xA;&lt;h2 id=&#34;993-nmt数据集构建&#34;&gt;9.9.3 NMT数据集构建&lt;a class=&#34;anchor&#34; href=&#34;#993-nmt%e6%95%b0%e6%8d%ae%e9%9b%86%e6%9e%84%e5%bb%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在这里我们使用到的是一组英德翻译平行语料，一共包含有 6 个文件&lt;code&gt;train.de&lt;/code&gt;、&lt;code&gt;train.en&lt;/code&gt;、&lt;code&gt;val.de&lt;/code&gt;、 &lt;code&gt;val.en&lt;/code&gt;、&lt;code&gt;test_2016_flickr.de &lt;/code&gt;和&lt;code&gt;test_2016_flickr.en&lt;/code&gt;，其分别为德语训练语料、英语训练语料、德语验证语料、英语验证语料、德语测试语料和英语测试语料。同时， 这三部分的样本量分别为 29000、1014 和 1000 条。&lt;/p&gt;&#xA;&lt;p&gt;如下所示便是一条平行预料数据，其中第 1 行为德语，第 2 行为英语，后续我们需要完成的是搭建一个翻译模型将德语翻译为英语。&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; Zwei junge weiße Männer sind im, Freien &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; der Nähe vieler Büsche&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;2&lt;/span&gt; Two young, White males are outside near many bushes&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;1. 数据集预览&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在正式介绍如何构建数据集之前，我们先通过一张图来简单了解一下整个构建流程，以便更加清楚后续的构建流程及代码实现。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/dl/230807211814.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt; 图9-20 英德翻译语料数据集构建图&lt;/center&gt;&#xA;&lt;p&gt;如图9-20所示，左边部分为源序列，右边部分为目标序列。从图9-20可以看出，第①步需要对原始语料进行切分（Tokenize）处理，如果是对类似英文这样的语料进行处理，最简单的就是直接按空格切分即可，但注意的一点是要把其中的标点符号也切分出来。第②步则是根据源语料和目标语料切分后的字符分别构建一个词表。第③步是将切分后的字符根据词表中的索引将其转换成对应的索引序列。第④步是对同一个小批量中的样本进行填充（Padding）处理，通常情况下以最长样本的长度进行填充，如果是对目标序列进行处理则还需要在首尾分别加上&lt;code&gt;&amp;lt;BOS&amp;gt;&lt;/code&gt;和&lt;code&gt;&amp;lt;EOS&amp;gt;&lt;/code&gt;特殊符。第⑤步则是分别得到编码器的源输入、解码器的目标输入和目标输出，其中目标输入和目标输出是分别取前$n-1$个字符和后$n-1$个字符（$n$表示目标序列长度）。&lt;/p&gt;</description>
			</item>
			<item>
				<title>9.10 注意力机制</title>
				<link>https://mlwithme.github.io/dl/chapter09/5bcd8b0920414f34/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter09/5bcd8b0920414f34/</guid>
				<description>&lt;h1 id=&#34;910-注意力机制&#34;&gt;9.10 注意力机制&lt;a class=&#34;anchor&#34; href=&#34;#910-%e6%b3%a8%e6%84%8f%e5%8a%9b%e6%9c%ba%e5%88%b6&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/fefa60e0bc854a17&#34;&gt;9.9节&lt;/a&gt;内容中，解码器在解码时我们直接取了编码器最后一个时刻的输出进行循环解码，然而随着输入序列长度的增加这样的处理方式将会成为一种信息瓶颈（ Information Bottleneck）[1] [2] [3]，即使得解码器无法记住和区分源序列中各个时刻的编码信息。在本节内容中，我们将会学习到一种新的深度学习技术——注意力机制（Attention Mechanism）——来解决类似问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;9101-注意力的起源&#34;&gt;9.10.1 注意力的起源&lt;a class=&#34;anchor&#34; href=&#34;#9101-%e6%b3%a8%e6%84%8f%e5%8a%9b%e7%9a%84%e8%b5%b7%e6%ba%90&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;关于对人类注意力机制的研究最早大致可以追溯至19世纪下半叶。有着世纪之交最有影响力心理学家之称的威廉·詹姆斯在他的主要作品《心理学原理》中说到[4]：每个人都知道什么是注意力，注意力其实就是大脑以一种清晰生动的方式在多个同时存在的对象中选择占据其中一个的过程，即意识的集中和聚焦。所以，注意力也被形象的描述为根据有限认知处理和分配大脑资源的过程[5]。&lt;/p&gt;&#xA;&lt;p&gt;例如在视觉注意力（ Visual Attention ）中，人类的视觉系统在处理视觉信息时会根据特定任务或环境选择性地集中关注某些区域，从而提高对这些区域的感知，使得我们能够在复杂的视觉场景中更有效地捕获重要信息[6]。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/dl/230817211900.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 9-23 视觉注意力示意图[7]&lt;/center&gt;&#xA;&lt;p&gt;如图9-23所示，当我们注视于湖边的这只白鹭时，我们的大脑便会将更多的注意力分配到这只白鹭身上而减少对其周边环境的注意力。&lt;/p&gt;&#xA;&lt;p&gt;正是受到人类注意力机制的启发，研究人员开始将这一思想运用于深度学习领域中。2014年姆尼赫等人[8]开始将注意力机制运用在基于循环神经网络的图像和视频分类模型中；2014年巴赫达瑙等人[1]第一次将注意力运用于机器翻译模型中；进一步，注意力机制的应用也开始出现在语音识别、图像描述、图像描述、摘要总结和文本分类等领域[9]。&lt;/p&gt;&#xA;&lt;h2 id=&#34;9102-注意力机制思想&#34;&gt;9.10.2 注意力机制思想&lt;a class=&#34;anchor&#34; href=&#34;#9102-%e6%b3%a8%e6%84%8f%e5%8a%9b%e6%9c%ba%e5%88%b6%e6%80%9d%e6%83%b3&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在Seq2Seq任务中，源输入序列的不同部分通常都具有不同的重要性，然而传统Encoder-Decoder模型在处理这一过程时并没有考虑到这种情况，因为它仅仅只是依靠上一个时刻的解码输出来对当前时刻进行解码。所以通过将源序列编码压缩得到一个固定维度的中间向量并直接进行解码的做法并不能有效地区分源序列中每个时刻的重要性，进而准确地预测每个时刻的输出结果。理想情况下，解码器在对不同时刻的输出进行解码时都应该将关注点放在编码器对应的不同时刻上。&lt;/p&gt;&#xA;&lt;p&gt;例如在图9-22中，当解码器对第3个时刻“是”进行解码时，理论上模型应该更加专注于编码器中第2个时刻“am”对应的位置。同时，实验结果也表明当推理过程中输入序列的长度远大于训练集中的序列长度时，这种影响将会更加明显[1] [2]。&lt;/p&gt;&#xA;&lt;p&gt;基于这样的动机，巴赫达瑙（Bahdanau）等人[1]在2014年首次提出了一种基于Seq2Seq架构的加法形式（Additive Style）注意力学习机制，其核心思想是对于解码器每个时刻的输出，模型可以对源输入序列的不同部分动态地分配注意力权重，使得模型可以更聚焦于编码序列中与当前输出时间步最相关的部分[3]。进一步，基于巴赫达瑙所提出的注意力框架，卢翁（Luong）等人[10]2015年又提出了一种乘法形式（Multiplicative Style）的注意力机制。&lt;/p&gt;&#xA;&lt;p&gt;通过引入注意力机制，模型可以根据输入的上下文动态地将注意力权重分配到序列的不同位置上，而这也意味着模型可以更加灵活地关注重要位置上的信息，从而提高模型的预测能力。&lt;/p&gt;&#xA;&lt;h2 id=&#34;9103-注意力计算框架&#34;&gt;9.10.3 注意力计算框架&lt;a class=&#34;anchor&#34; href=&#34;#9103-%e6%b3%a8%e6%84%8f%e5%8a%9b%e8%ae%a1%e7%ae%97%e6%a1%86%e6%9e%b6&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;根据上面两个小节内容的介绍我们从直观上了解了什么是注意力机制以及注意力机制的主要作用，因此接下来我们需要知道在深度学习中如何表示注意力以及如何设计一个通用的注意力计算框架。由于注意力的本质就是对有限资源的一个分配过程，自然而然我们可以通过一个权重向量来表示注意力的分配情况，权重越大的位置便给予更高的注意力。所以，如何设计一个有效的框架来计算注意力权重向量便成了我们接下来需要解决的问题。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 计算框架&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在信息检索系统中，通常我们可以根据关键字在数据库中检索得到离我们期望结果最相似的输出结果，而这样一个过程便可以作为注意力计算框架的灵感来源。例如对于一个视频网站来说，用户可以通过关键字（Query）在标题表（Keys）中检索得到与之最为匹配的标题，然后再通过标题从视频库（Values）中检索得到对应视频并返回给用户，整个结构如图9-24所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;400&#34; src=&#34;https://mlwithme.github.io/images/dl/230818201616.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 9-24 视频检索示意图&lt;/center&gt;&#xA;&lt;p&gt;在图9-24中，视频检索系统首先根据用户输入的关键词Query同视频标题Keys中的每个标题进行相似性计算并得到一个权重向量$\alpha$ ，其中$\alpha_i$表示Query与第$i$个标题的相似程度；最后根据$\alpha$便可以从Values中返回相应的视频内容。此时，权重向量$\alpha$便可以理解为当输入关键词为Query时检索系统应该如何将注意力分配到各个视频内容上的度量。进一步，如果将$\alpha$限制为One-hot编码形式则被称之为硬注意力（Hard Attention），此时将只会返回Values中的一个值；通常情况下$\alpha$将会被归一化成一个概率分布称之为软注意力（Soft Attention），此时将会返回所有Values的加权结果。&lt;/p&gt;&#xA;&lt;p&gt;同时，对于不同的模型来说Query、Keys和Values都不尽相同，并且需要注意的是Keys和Values一一对应出现。例如在Seq2Seq架构中Query通常取自目标序列编码后的隐含状态，Keys和Values则都取自源序列编码后的隐含状态。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 计算流程&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;根据上述注意力计算框架，含有注意力机制的NMT模型在对每个时刻进行解码时，其注意力计算过程可以通过图9-25进行表示 [2] [3] [11]。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/dl/230818203313.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 9-25 解码过程注意力计算原理图&lt;/center&gt;&#xA;&lt;p&gt;如图9-25所示便是解码器解码时注意力机制的计算原理图，其中Query表示第$t$时刻解码器的隐含状态$h_t$，Keys表示编码器中所有时刻的隐含状态$\overline{h}_1,\overline{h}_2,..\overline{h}_S$，此时Values与Keys相同。进一步，整个含注意力的解码过程可以表示为如下4步。&lt;/p&gt;&#xA;&lt;p&gt;①将第$t$时刻的隐含状态同编码器中所有时刻的隐含状态进行比较，根据式(9-37)计算得到注意力权重（Attention Weights）。&#xA;&lt;/p&gt;&#xA;$$&#xA;\alpha_{ts}=\frac{\exp\left(\text{score}(h_t,\overline{h}_s)\right)}{\sum_{s^{\prime}=1}^S\exp\left(\text{score}(h_t,\overline{h}_{s^{\prime}})\right)}\in\mathbb{R}\tag{9-37}&#xA;$$&lt;p&gt;&lt;subscribe&gt;53&lt;/subscribe&gt;&lt;/p&gt;&#xA;&lt;br&gt;&#xA;&lt;br&gt;&#xA;&lt;br&gt;</description>
			</item>
			<item>
				<title>9.11 含注意力的NMT网络</title>
				<link>https://mlwithme.github.io/dl/chapter09/8a78e8213ee04aac/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter09/8a78e8213ee04aac/</guid>
				<description>&lt;h1 id=&#34;911-含注意力的nmt网络&#34;&gt;9.11 含注意力的NMT网络&lt;a class=&#34;anchor&#34; href=&#34;#911-%e5%90%ab%e6%b3%a8%e6%84%8f%e5%8a%9b%e7%9a%84nmt%e7%bd%91%e7%bb%9c&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/fefa60e0bc854a17&#34;&gt;9.9节&lt;/a&gt;和&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/5bcd8b0920414f34&#34;&gt;9.10节&lt;/a&gt;内容中我们分别介绍了NMT模型和注意力机制的原理和实现。在本节内容中，我们将会结合NMT和注意力机制来实现一个完整的含注意力的神经网络翻译模型。&lt;/p&gt;&#xA;&lt;h2 id=&#34;9111-含注意力的nmt结构&#34;&gt;9.11.1 含注意力的NMT结构&lt;a class=&#34;anchor&#34; href=&#34;#9111-%e5%90%ab%e6%b3%a8%e6%84%8f%e5%8a%9b%e7%9a%84nmt%e7%bb%93%e6%9e%84&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在Seq2Seq任务中，源输入序列的不同部分通常都具有不同的重要性，然而传统Encoder-Decoder模型在处理这一过程时并没有考虑到这种情况。然而在理想情况下，解码器在对不同时刻的输出进行解码时都应该将注意力聚焦在编码器对应的不同时刻上。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/dl/240711104757.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图9-27 含注意力的NMT模型网络结构图&lt;/center&gt;&#xA;&lt;p&gt;如图9-27所示便是含注意力机制的NMT模型网络结构图。从图中可以看出，解码器在解码第2个时刻时，其输入除了上一个时刻的预测结果“我”之外，还有根据第1个时刻计算得到的上下文向量$c_1$。根据图9-27可知，在解码第2个时刻时应该将更多的注意力集中到编码器&amp;rsquo;am&amp;rsquo;对应的隐含向量上，因此理想状态下应该给予该时刻更多的注意力关注。此时，模型将首先取解码器第2层第1个时刻对应的隐含向量$h_1$同编码器第2层所有的隐含向量$\overline{h}_1,...\overline{h}_4$来计算得到对应的上下文向量$c_1$；然后再将$[c_1;\hat{y}_1]$一同作为第2个时刻的输入计算得到$a_2$；最后根据$a_2$分类得到第2个时刻的预测结果$\hat{y}_2$。&lt;/p&gt;&#xA;&lt;h2 id=&#34;9112-含注意力的nmt实现&#34;&gt;9.11.2 含注意力的NMT实现&lt;a class=&#34;anchor&#34; href=&#34;#9112-%e5%90%ab%e6%b3%a8%e6%84%8f%e5%8a%9b%e7%9a%84nmt%e5%ae%9e%e7%8e%b0&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在清楚NMT及注意力机制的相关原理后，接下来我们再来看如何实现整个基于注意力机制的解码过程。下面我们基于&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/fefa60e0bc854a17&#34;&gt;9.9节&lt;/a&gt;所实现的NMT模型进行改进。由于注意力机制只是作用于解码过程，因此我们只需要对解码器部分的代码进行改造即可，其余部分不需要进行任何改动。具体地，我们只需要修改类&lt;code&gt;DecoderWrapper&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;/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;DecoderWrapper&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;, embedding_size, hidden_size, num_layers, vocab_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;3&lt;/span&gt;         cell_type&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;LSTM&amp;#39;&lt;/span&gt;, attention_type&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;standard&amp;#39;&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;, dropout&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.&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;(DecoderWrapper, &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;embedding_size &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; embedding_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;6&lt;/span&gt;         &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;7&lt;/span&gt;         input_size &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;embedding_size &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;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;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&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;attention_type &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;standard&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&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;attention, input_size &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;, &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;embedding_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;10&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;elif&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;attention_type &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;luong&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;11&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;attention &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; LuongAttention(hidden_size, dropout)&#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;elif&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;attention_type &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;bahdanau&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;13&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;attention &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; BahdanauAttention(hidden_size, dropout)&#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;         &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; rnn_cell(input_size, &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;hidden_size, &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;num_layers,&#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;                             batch_first&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;batch_first, dropout&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;dropout)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第7行是初始化RNN的输入维度，因为如果使用到注意力机制的话，RNN的输入还包含有上下文向量$c_t$。第8~13行是根据不同的超参数选择使用不同的注意力机制进行解码。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 改造前向传播方法&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&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;forward&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;, tgt_input&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;, decoder_state&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;                 encoder_output&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;, src_key_padding_mask&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;3&lt;/span&gt;         tgt_input &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;token_embedding(tgt_input)&#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;font-weight:bold&#34;&gt;if&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;attention_type &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;standard&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;             outputs, decoder_state &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(tgt_input, decoder_state)&#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;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;7&lt;/span&gt;             tgt_input &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; tgt_input&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;permute(&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0&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;8&lt;/span&gt;             outputs, &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;_attention_weights &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;9&lt;/span&gt;             &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; tgt_in &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; tgt_input:  &#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;                 tgt_in &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; tgt_in&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;unsqueeze(&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;                 &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;isinstance&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, nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;LSTM):&#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;                     query &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; decoder_state[&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;][&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;13&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;14&lt;/span&gt;                     query &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; decoder_state[&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;                 con_vect, attn_weights &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;attention(query, encoder_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;16&lt;/span&gt;                                        encoder_output, src_key_padding_mask)&#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;                 tgt_in &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;cat((tgt_in, con_vect), dim&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;                 attn_vector, decoder_state &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(tgt_in, decoder_state)&#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;                 outputs&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;append(attn_vector) &#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&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;_attention_weights&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;append(attn_weights)  &#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;             outputs &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;cat(outputs, dim&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;22&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; outputs, decoder_state&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第1~2行&lt;code&gt;tgt_input&lt;/code&gt;是每个时刻解码器的输入形状为&lt;code&gt;[batch_size, tgt_len]&lt;/code&gt;，&lt;code&gt;decoder_state&lt;/code&gt;为解码器上一个时刻的状态，如果是解码第1个时刻则其为编码器最后一个时刻的状态，&lt;code&gt;encoder_output&lt;/code&gt;为编码器所有时刻的输出形状为&lt;code&gt;[batch_size, src_len, hidden_size]&lt;/code&gt;，&lt;code&gt;src_key_padding_mask&lt;/code&gt;为注意力掩码用于忽略编码器中填充部分的输出结果形状为&lt;code&gt;[batch_size, src_len]&lt;/code&gt;。第3行是词嵌入操作。第4~5行不使用注意力机制。第7行是交互&lt;code&gt;tgt_input&lt;/code&gt;的维度，因为后续是逐时刻进行解码，其形状为&lt;code&gt;[tgt_len, batch_size, embedding_size]&lt;/code&gt;。第8行用于保存每个时刻的解码输出和注意力权重矩阵。第9行开始逐时刻进行解码，此时&lt;code&gt;tgt_in&lt;/code&gt;的形状为&lt;code&gt;[batch_size, embedding_size]&lt;/code&gt;。第10行是扩张维度，将变成&lt;code&gt;[batch_size, 1, embedding_size]&lt;/code&gt;。第11~14行是判断RNN的类型，因为LSTM的状态包括$h_t$和$C_t$两部分（详见&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/b4c5ddcc9e904238&#34;&gt;7.3节&lt;/a&gt;内容）而 GUR 中只有 $h_t$，进一步取最后一层，此时&lt;code&gt;query&lt;/code&gt;的形状为&lt;code&gt;[batch_size, hidden_size]&lt;/code&gt;。第15~16行是计算上下文向量和注意力权重，在推理阶段时&lt;code&gt;src_key_padding_mask&lt;/code&gt;的传入值将为&lt;code&gt;None&lt;/code&gt;，此时&lt;code&gt;con_vect&lt;/code&gt;的形状为&lt;code&gt;[batch_size, 1, hidden_size]&lt;/code&gt;，&lt;code&gt;attn_weights&lt;/code&gt;的形状为&lt;code&gt;[batch_size, src_len]&lt;/code&gt;。第17~18行则是先将输入和上下文向量组合，然后输入到RNN中进行解码，此时&lt;code&gt;tgt_in&lt;/code&gt;的形状为&lt;code&gt;[batch_size, 1, hidden_size+embedding_size]&lt;/code&gt;，&lt;code&gt;attn_vector&lt;/code&gt;的形状为&lt;code&gt;[batch_size, 1, hidden_size]&lt;/code&gt;。第19~20行是分别保存注意力向量和注意力权重矩阵。第21行是堆叠得到所有注意力向量，用于后续分类得到所有时刻的预测结果，其形状为&lt;code&gt;[batch_size, tgt_len, hidden_size]&lt;/code&gt;。&lt;/p&gt;</description>
			</item>
			<item>
				<title>9.12 含注意力的RNN网络</title>
				<link>https://mlwithme.github.io/dl/chapter09/474ac7a1867d4b5e/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter09/474ac7a1867d4b5e/</guid>
				<description>&lt;h1 id=&#34;912-含注意力的rnn网络&#34;&gt;9.12 含注意力的RNN网络&lt;a class=&#34;anchor&#34; href=&#34;#912-%e5%90%ab%e6%b3%a8%e6%84%8f%e5%8a%9b%e7%9a%84rnn%e7%bd%91%e7%bb%9c&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/5bcd8b0920414f34&#34;&gt;9.10节&lt;/a&gt;和&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/8a78e8213ee04aac&#34;&gt;9.1节&lt;/a&gt;内容中我们分别介绍了注意力机制的原理以及它在Seq2Seq翻译模型中的具体应用。在Seq2Seq这个翻译场景中，我们明确地知道在解码器在解码每一个时刻时，query来自于当前解码时刻对应的隐含向量，并且这样做的动机也十分合理。但是，在某些场景中尽管我们也想引入注意力这一机制，但是却不存在对应的query向量。&lt;/p&gt;&#xA;&lt;p&gt;例如在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter08/9023d1f822a54226&#34;&gt;8.2节&lt;/a&gt;内容中介绍的使用RNN进行文本分类的场景中，我们完全可以利用注意力机制的思想来得到一个注意力权重，然后作用于每个时刻的隐含状态并得到一个上下文向量，最后再利用上下文向量完成后续的分类任务。&lt;/p&gt;&#xA;&lt;h2 id=&#34;9121-含注意力的rnn结构&#34;&gt;9.12.1 含注意力的RNN结构&lt;a class=&#34;anchor&#34; href=&#34;#9121-%e5%90%ab%e6%b3%a8%e6%84%8f%e5%8a%9b%e7%9a%84rnn%e7%bb%93%e6%9e%84&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;对于这种不存在query向量的场景中，我们可以自己定义一个全局的query向量来完成注意力权重的计算过程，然后再将其作用于RNN输出的每个时刻的向量上，进而得到上下文向量。值得注意的是，这里定义的全局query向量也是一个可训练的模型参数。整个网络结构如图9-28所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/dl/240224230133.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 9-28 含注意力的RNN网络结构图&lt;/center&gt;&#xA;&lt;p&gt;如图9-28所示便是含有注意力机制的RNN网络结构图，其中右侧的 global query便是我们自己定义的全局query向量。输入文本”I really like this moive“在经过RNN编码后便会得到5个时刻的输出向量。此时，global query 将会同这个5个向量分别计算得到一个注意力值并进行归一化。同时，在这里计算注意力值的时候可以是任何一种你认为合理的方式，例如可以是最简单两个向量的内积、也可以是一次线性变换后的内积等等，后续我们将以&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/5bcd8b0920414f34&#34;&gt;9.10节&lt;/a&gt;中的Luong注意力计算法来进行实现。在计算得到每个时刻对应的注意力权重以后，再将其作用于每个时刻的隐含向量便可以得到最终的上下文向量。最后，使用一个分类层对上下文向量进行分类即可。&lt;/p&gt;&#xA;&lt;h2 id=&#34;9122-含注意力的rnn实现&#34;&gt;9.12.2 含注意力的RNN实现&lt;a class=&#34;anchor&#34; href=&#34;#9122-%e5%90%ab%e6%b3%a8%e6%84%8f%e5%8a%9b%e7%9a%84rnn%e5%ae%9e%e7%8e%b0&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;这里我们以&lt;a href=&#34;https://mlwithme.github.io/dl/chapter08/9023d1f822a54226&#34;&gt;8.2节&lt;/a&gt;内容中实现的TextRNN模型为基础进行改造，我们只需要在原有RNN编码结束以后再加上一个注意力层即可。以下完整示例代码可参见&lt;code&gt;Code/Chapter09/C08_TextRNNAtt/TextRNN.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;由于此时的 global query是一个固定的向量，不会随着样本数量的变化而变化，所以我们在实现Luong注意力机制时需要做一点小的改动，实现代码如下所示：&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;LuongAttention&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;, hidden_size, dropout&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.&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&#34;&gt;super&lt;/span&gt;(LuongAttention, &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;4&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;linear &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Linear(hidden_size, 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;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;drop &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Dropout(dropout)&#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; &#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;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;, query, key, value, src_key_padding_mask&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;8&lt;/span&gt;         scores &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;matmul(key, &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;linear(query)&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;transpose(&lt;span style=&#34;color:#40a070&#34;&gt;0&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;9&lt;/span&gt;         scores &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; scores&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;squeeze(&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;10&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; src_key_padding_mask &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;11&lt;/span&gt;             scores &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; scores&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;masked_fill(src_key_padding_mask, &lt;span style=&#34;color:#007020&#34;&gt;float&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;-inf&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;12&lt;/span&gt;         attention_weights &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;softmax(scores, dim&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;13&lt;/span&gt;         context_vec &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;bmm(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;drop(attention_weights)&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;unsqueeze(&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;), value)&#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;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; context_vec, attention_weights&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第7行&lt;code&gt;query&lt;/code&gt;便是上面的我们定义的global query，形状为&lt;code&gt;[1, hidden_size]&lt;/code&gt;；&lt;code&gt;key&lt;/code&gt;和&lt;code&gt;value&lt;/code&gt;则均是RNN编码完成后每个时刻对应的隐含状态，形状为&lt;code&gt;[batch_size, src_len, hidden_size]&lt;/code&gt;；&lt;code&gt;src_key_padding_mask&lt;/code&gt;则是输入序列的填充情况，形状为&lt;code&gt;[batch_size, src_len]&lt;/code&gt;。在第8行中，&lt;code&gt;query&lt;/code&gt;经过线性变换且转置后的形状为&lt;code&gt;[hidden_size,1]&lt;/code&gt;，&lt;code&gt;scores&lt;/code&gt;的形状为&lt;code&gt;[batch_size, src_len, 1]&lt;/code&gt;。第9行是进行维度压缩，之后&lt;code&gt;scores&lt;/code&gt;的形状为&lt;code&gt;[batch_size, src_len]&lt;/code&gt;。第10~11行则是将填充部分的注意力权重置为负无穷大。第12~13行则是分别对注意力权重进行归一化并计算得到上下文向量，形状为&lt;code&gt;[batch_size, 1, hidden_size]&lt;/code&gt;。&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
