<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>第10章 现代神经网络 on 《从零学AI指南手册》</title>
		<link>https://mlwithme.github.io/dl/chapter10/</link>
		<description>Recent content in 第10章 现代神经网络 on 《从零学AI指南手册》</description>
		<generator>Hugo</generator>
		<language>zh_CN</language>
		
		
		
		
			<atom:link href="https://mlwithme.github.io/dl/chapter10/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>10.1 ELMo网络</title>
				<link>https://mlwithme.github.io/dl/chapter10/7523731afc0241c0/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/7523731afc0241c0/</guid>
				<description>&lt;h1 id=&#34;第10章-现代神经网络&#34;&gt;第10章 现代神经网络&lt;a class=&#34;anchor&#34; href=&#34;#%e7%ac%ac10%e7%ab%a0-%e7%8e%b0%e4%bb%a3%e7%a5%9e%e7%bb%8f%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/chapter05/211b26bdd8f248ac&#34;&gt;5.4节&lt;/a&gt;内容中，我们初次接触到了预训练（Pre-trained）模型这个概念。预训练模型的主要思想是模型通过在大规模数据集上学习得到通用特征的抽取能力，然后再将其迁移到其他任务中以加速新任务的学习和提高模型性能。预训练模型最早大规模应用于图像处理领域，而其中最具代表性的便是深度卷积神经网络预训练模型，例如AlexNet、VGG和ResNet等[1]。这些模型首先在大规模图像数据集（如ImageNet）上进行预训练以捕获图像的低级或中级特征（如边缘、纹理和形状等），然后再将其迁移到其他图像处理任务，如目标检测、图像生成和分割等。预训练模型的优点在于它们能够从大规模数据中学习到通用的特征表示并在多个下游任务上共享，这种方法既减少了对大量标注数据的需求也加速了模型的训练和收敛过程。&lt;/p&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;内容中介绍到的词向量从某种程度上来讲也可以看作是一种简单的预训练模型，但是它并没有掀起自然语言处理领域中迁移学习的浪潮，因为它并没有给下游任务带来实质上的提升。直到2018年ELMo模型的出现才使得研究人员又开始将迁移学习聚焦到自然语言处理领域中[2]。紧接着，自然语言处理领域便先后出现了一系列有着重要影响的预训练模型，例如BERT和GPT系列。从某种程度上来说这两个技术流派正在引领者当前自然语言处理研究的主要方向。在本章内容中，我们将会逐一对这些模型的思想原理及其实战案例进行详细的介绍，包括ELMo、Transformer、BERET和GPT系列模型等。&lt;/p&gt;&#xA;&lt;h1 id=&#34;101-elmo网络&#34;&gt;10.1 ELMo网络&lt;a class=&#34;anchor&#34; href=&#34;#101-elmo%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章&lt;/a&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模型。在本节内容中我们将介绍另外一种新的动态词向量模型ELMo。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1011-elmo动机&#34;&gt;10.1.1 ELMo动机&lt;a class=&#34;anchor&#34; href=&#34;#1011-elmo%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在传统的静态词向量中每个词都将被映射为一个固定的向量表示，词向量在构建过程中也只使用了局部的上下文信息，因此难以准确地表示词语在复杂语境中的依赖关系。同时，静态词向量并没有考虑词义随上下文语境变化所产生的不同含义，即无法解决一词多义的问题。例如文章中出现了“苹果”一词，它到底是指代科技公司“苹果”还是水果中的“苹果”静态词向量无法解决，因为这需要根据上下文来确定。在这样的背景下有学者开始研究基于上下文环境的词向量表示方法[3] [4]。在这类方法中，词向量的表示通常都不再只是一个固定的权重向量而是整个网络模型根据输入的上下文计算得到的词向量表示，即对于同一个词来说上下文语境的变化也会导致词向量表示的变化。&lt;/p&gt;&#xA;&lt;p&gt;基于这样的动机， 马修（Matthew）等人[2]于2018年提出了一种基于LSTM的深度双向语言模型（Embeddings from Language Models, ELMo）来学习词向量的动态表示。ELMo模型通过将每个词表示为其在不同层次上下文中隐含状态的线性组合，使得每个词的向量表示不仅能够包含更为丰富的语义信息同时也能够捕捉到不同语境下的语义信息。最终，基于ELMo动态词向量的下游模型在6个流行的NLP任务中都取得了显著的效果提升。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1012-elmo结构&#34;&gt;10.1.2 ELMo结构&lt;a class=&#34;anchor&#34; href=&#34;#1012-elmo%e7%bb%93%e6%9e%84&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在以往的研究中研究者们发现，将每个单词拆分成子词（Subword）的形式[5] [6]以及通过将不同网络深度输入的向量表示组合起来[7]均能够在一定程度上提高词向量的表达能力。受此启发，ELMo模型首先利用基于字符级的卷积神经网络CharCNN来学习得到每个词与上下文无关（Context-Independent）的向量表示；然后再通过一个带有残差连接的两层双向循环神经网络（相关内容可参见&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/88ba4e03337b4233?id=_715-%e5%a4%9a%e5%b1%82rnn&#34;&gt;7.1.5节&lt;/a&gt;内容）来学习得到不同网络深度中每个词与上下文相关（Context-Dependent ）的向量表示；最后再将三部分的输出以线性组合的方式得到每个词的向量表示。如图10-1所示便是ELMo模型的整体网络结构图。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;550&#34; src=&#34;https://mlwithme.github.io/images/dl/230827165359.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图10-1 ELMo网络结构图&lt;/center&gt;&#xA;&lt;p&gt;如图10-1所示便是ELMo模型的整体网络结构。ELMo模型整体上包括字符级的卷积神经网络和带残差连接的双向循环神经网络两大部分，分别用于学习得到不同粒度的词向量表示。接下来分别就各部分进行介绍。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 字符级卷积网络&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在字符级卷积神经网络中，每个单词首先将会被切分成字符形式，并且对于每个单词来说其最大长度为50，不足部分需进行填充；然后再将其以不同窗口大小的一维卷积操作进行特征提取；最后经过最大池化操作并将池化后的结果进行拼接得到整个单词的词嵌入表示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/dl/230828211141.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图10-2 1D卷积示意图&lt;/center&gt;&#xA;&lt;p&gt;如图10-2所示便是一维卷积操作的示意图，其中左侧矩阵中：每一列表示每个字符对应的向量表示，在一维卷积中称其为通道数；每一行表示同一个特征通道中不同字符对应的特征。同时，在一维卷积中卷积核有3个参数，分别是输入通道数&lt;code&gt;in_hannels&lt;/code&gt;、宽度&lt;code&gt;width&lt;/code&gt;和输出通道数&lt;code&gt;out_channels&lt;/code&gt;。在ELMo模型中，每个单词的最大长度&lt;code&gt;max_characters_per_token&lt;/code&gt;为50；字符嵌入维度&lt;code&gt;char_embed_dim&lt;/code&gt;为16，即图10-2中的&lt;code&gt;channels&lt;/code&gt;为16；并且采用了宽度分别为1、2、3、4、5、6、7的卷积核，其中卷积核的数量分别为32、32、64、128、256、512、1024，即卷积操作结束后每个词向量的维度为2048。最后，再通过一个两层的高速连接（Highway )[8]和全连接层将每个词向量映射到了512维，即图10-1中的$E_i$。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;300&#34; src=&#34;https://mlwithme.github.io/images/dl/230829200811.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图10-3 Highway网络结构图&lt;/center&gt;&#xA;&lt;p&gt;如图10-3所示便是高速连接层的结构示意图，其主要思想也是借鉴于LSTM中的单元记忆状态，使得网络每加深一层都能够同时融合当前层和上一层的历史信息。可以看出，此处的门控单元同时充当了遗忘门和输入门的角色。具体地，其计算过程为&#xA;&lt;/p&gt;&#xA;$$&#xA;y=\sigma(xW_f)\odot x\oplus(1-\sigma(xW_f))\odot g(xW_i)\tag{10-1}&#xA;$$&lt;p&gt;&lt;strong&gt;2. 双向循环神经网络&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在循环神经网络中不同网络深度的输出结果能够分别从上下文依赖、语法信息等角度来丰富词语的向量化表示，因而对于不同的下游任务有着不同的性能提升。例如在一个基于两层LSTM的编码器-解码器翻译模型中，编码器第1层的输出向量相比于第2层来说更加有利于进行词性标记（Part-Of-Speech Tags)任务。因此ELMo模型同样采用了两层的双向循环神经网络来获取得到不同粒度的词向量表示，并且在循环神经网络之间还采用了残差连接。如图10-1上半部分所示表示整个双向LSTM部分。&lt;/p&gt;&#xA;&lt;p&gt;在ELMo模型中，对于给定序列$t_1,t_2,...,t_N$正向LSTM需要根据给定的前$k-1$个词来预测第$k$词，即建模&#xA;&lt;/p&gt;&#xA;$$&#xA;p(t_1,t_2,...,t_N)=\prod_{k=1}^Np(t_k|t_1,t_2,...,t_{k-1})\tag{10-2}&#xA;$$&lt;p&gt;&#xA;并且用$\overrightarrow{h}_{k,j}^{\text{LM}}, j=1,...,L$表示正向LSTM第$j$层第$k$个时刻的输出结果。&lt;/p&gt;&#xA;&lt;p&gt;反向LSTM则恰好相反，需要根据给定的后$N-k$个词来预测第$k$个词，即建模&#xA;&lt;/p&gt;&#xA;$$&#xA;p(t_1,t_2,...,t_N)=\prod_{k=1}^Np(t_k|t_{k+1},t_{k+2},...,t_{N})\tag{10-3}&#xA;$$&lt;p&gt;&#xA;并且用$\overleftarrow{h}^{\text{LM}}_{k,j}, j=1,...,L$表示反向LSTM第$j$层第$k$个时刻的输出结果。&lt;/p&gt;&#xA;&lt;p&gt;最终，通过最大化式(10-4)来求解整个模型参数&#xA;&lt;/p&gt;&#xA;$$&#xA;\sum_{k=1}^N\left(\log p(t_k|t_1,...,t_{k-1};\Theta_x,\overrightarrow{\Theta}_{\text{LSTM}},\Theta_s)+\log p(t_k|t_{k+1},...,t_{N};\Theta_x,\overleftarrow{\Theta}_{\text{LSTM}},\Theta_s)\right)\tag{10-4}&#xA;$$&lt;p&gt;&#xA;其中$\Theta_x$表示CharCNN中的所有权重参数，$\overrightarrow{\Theta}_{\text{LSTM}}$和$\overleftarrow{\Theta}_{\text{LSTM}}$分别表示正向反向LSTM中的权重参数，$\Theta_s$表示每个时刻$\text{Softmax}$分类层的权重参数，且对于正反两个LSTM来说共享一个分类器。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;3. ELMo词向量表示&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;当整个ELMo模型在大规模语料上完成预训练之后，便可以取各部分对应的输出经过线性组合得到每个词最终的向量表示，如图10-4所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;280&#34; src=&#34;https://mlwithme.github.io/images/dl/230827165429.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图10-4 ELMo表示输出&lt;/center&gt;&#xA;&lt;p&gt;&lt;subscribe&gt;52&lt;/subscribe&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.2 Transformer网络</title>
				<link>https://mlwithme.github.io/dl/chapter10/4987d1044939480d/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/4987d1044939480d/</guid>
				<description>&lt;h1 id=&#34;102-transformer网络&#34;&gt;10.2 Transformer网络&lt;a class=&#34;anchor&#34; href=&#34;#102-transformer%e7%bd%91%e7%bb%9c&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面几章内容中，我们陆续介绍了多个传统的经典模型，包括CNN、RNN和LSTM等来处理自然语言领域中的相关任务。但是从整体上来看，在2017年之前相关任务模型的发展仍旧主要集中在各个模块的拼接组合上，而这些基础模型并没有出现本质上的改变。正是在这个时间点，一项突破性的技术——Transformer架构——出现了。Transformer架构的出现是自然语言处理领域的一个重大转折点，它所提出的多头注意力机制为后续的研究和发展开辟了全新的方向。尽管Transformer最初是应用于在文本数据上的序列到序列学习，但现在已经推广到各种现代的深度学习中，例如语言、视觉、语音和强化学习等领域[1]。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1021-transformer动机&#34;&gt;10.2.1 Transformer动机&lt;a class=&#34;anchor&#34; href=&#34;#1021-transformer%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;根据&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/88ba4e03337b4233&#34;&gt;第7章&lt;/a&gt;内容可知，由于传统的Encoder-Decoder架构在建模过程中，下一个时刻的计算过程会依赖于上一个时刻的输出，即整个过程需要按序进行，而这种固有的属性就限制了模型就不能以并行的方式进行计算[2]。尽管相关研究工作已经能够使得传统的循环神经网络在计算效率上有了很大的提升，但是本质的问题依旧没有得到解决。&lt;/p&gt;&#xA;&lt;p&gt;基于这样的动机，阿希什（Vaswani）等人[2]于2017年提出了一种全新的Transformer架构来解决这一问题。Transformer架构的优点在于它完全摈弃了传统的循环结构，取而代之的是只通过注意力机制来计算模型输入与输出的隐含向量表示， 而这种注意力的名字就是大名鼎鼎的自注意力机制（Self-attention）。所谓自注意力机制是指通过某种运算来直接并行计算得到序列每个位置上的注意力权重，然后再以加权和的形式计算得到每个位置上隐含向量表示。最终，Transformer架构就是基于这种自注意力机制所构建形成。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1022-自注意力机制&#34;&gt;10.2.2 自注意力机制&lt;a class=&#34;anchor&#34; href=&#34;#1022-%e8%87%aa%e6%b3%a8%e6%84%8f%e5%8a%9b%e6%9c%ba%e5%88%b6&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;自注意力机制在论文中也被称之为缩放点积注意力（Scaled Dot-Product Attention），它可以描述为将Query和一系列的Key-Value对映射到某个输出的过程，而这个输出的向量就是根据Query和Key计算得到的权重作用于Value上的加权和。此处Query、Key和Value含义同&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/5bcd8b0920414f34&#34;&gt;9.10节&lt;/a&gt;内容中介绍的一致。下面开始分别介绍自注意力机制和多头注意力机制的原理。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 自注意力机制&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;如图10-5所示便是自注意力机制的结构示意图，其核心过程就是通过Q（Query）和K（Value）计算得到注意力权重；然后再作用于V（Value）得到整个权重和输出，即序列中每个位置的向量表示。整个过程依旧如同&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/5bcd8b0920414f34?id=_9103-%e6%b3%a8%e6%84%8f%e5%8a%9b%e8%ae%a1%e7%ae%97%e6%a1%86%e6%9e%b6&#34;&gt;9.10.3节&lt;/a&gt;内容中介绍的一致，查询Q先在键K中依次与其中的每一个键进行匹配计算便得到了一个权重向量，然后再将该向量作用于V便得到了最后的输出。不同点在于此处还引入了权重缩放和注意力掩码。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;230&#34; src=&#34;https://mlwithme.github.io/images/dl/230904230810.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-5 自注意力机制结构图&lt;/center&gt;&#xA;&lt;p&gt;具体地，自注意力机制的计算过程为&#xA;&lt;/p&gt;&#xA;$$&#xA;\text{Attention}(Q,K,V)=\text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V\in\mathbb{R}^{n\times d_v}&#xA;\tag{10-7}&#xA;$$&lt;p&gt;&#xA;其中$Q\in\mathbb{R}^{n\times d_{q}}$，$K\in\mathbb{R}^{n\times d_{k}}$，$V\in\mathbb{R}^{n\times d_{v}}$，三者的每一行均可以看做是一个字符的向量表示。&lt;/p&gt;&#xA;&lt;p&gt;根据式(10-7)可知$d_q=d_k$，而除以$\sqrt{d_k}$的过程就是图10-5中所指的缩放（Scale）过程。之所以要进行缩放一方面是因为，如果两个向量的维度为$d$，且每个维度均是独立的随机变量并都满足均值为0方差为1，那么这两个向量点积的均值则为0方差则为$d$，而除以$\sqrt{d_k}$则可以保证方差仍旧为1；另一方面，$d$越大则$QK^T$的值可能越大，而这便会导致$\text{Softmax}$函数的梯度变得非常小不利于网络训练，因此可以通过缩放来消除这部分影响。&lt;/p&gt;&#xA;&lt;p&gt;同时，对于图10-5中的Mask操作是用于在多个样本并行计算时忽略掉填充位置上的注意力权重，这与&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/5bcd8b0920414f34?id=_9104-%e5%a1%ab%e5%85%85%e6%b3%a8%e6%84%8f%e5%8a%9b%e6%8e%a9%e7%a0%81&#34;&gt;9.10.4节&lt;/a&gt;内容中介绍的一致。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 自注意力计算过程&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在清楚自注意力机制的原理后我们再通过一个实际的计算图示来从直观上理解自注意机制到底是怎么回事。现在，假设输入序列为“我  是  谁”，且已经通过某种方式得到了1个形状为$3\times4$的矩阵来进行表示，即图中的$X$。在通过图10-6所示的过程便能够计算得到$Q$、$K$和$V$这3个矩阵。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;380&#34; src=&#34;https://mlwithme.github.io/images/dl/230905210111.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图10-6 $Q$、$K$和$V$计算示意图&lt;/center&gt;&#xA;&lt;p&gt;从图10-6的计算过程可以看出，$Q$、$K$和$V$ 其实就是输入$X$分别进行3次线性变换而得到，不过这一计算过程仅仅只局限于Encoder和Decoder在各自输入部分利用自注意力机制进行编码时的过程， Encoder和Decoder交互部分的$Q$、$K$和$V$另有指代。此时，对于计算得到的$Q$、$K$和$V$可以理解为这是对于同一个输入不同的3种状态。在计算得到$Q$、$K$和$V$之后便可以根据式(10-7)计算得到注意力权重矩阵，如图10-7所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;350&#34; src=&#34;https://mlwithme.github.io/images/dl/230905210745.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-7 注意力权重矩阵计算过程图（已经$\text{Softmax}$处理）&lt;/center&gt;&#xA;&lt;p&gt;如图10-7所示，在经过上述计算过程后我们便得到了注意力权重矩阵。此时，对于权重矩阵的第1行来说，表示在编码“我”这个位置上的信息时应该将0.7的注意力放在“我”上，0.2的注意力放在“是”上，0.1的注意力放在“谁”上。同理，对于权重矩阵第 3 行来说，表示在编码“谁”这个位置上的信息时应该将 0.2 的注意力放在“我”上，将 0.1 的注意力放在“是”上，将 0.7的注意力放在“谁”上。从这一过程可以看出，通过这个权重矩阵模型在编码对应位置上的信息时，就能够知道应该以何种方式将注意力分配到不同的位置上。&lt;/p&gt;&#xA;&lt;p&gt;在通过图10-7所示的过程计算得到权重矩阵后，便可以将其作用于$V$ ，进而得到自注意力机制的最终编码输出结果，计算过程如图10-8所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;360&#34; src=&#34;https://mlwithme.github.io/images/dl/230905210803.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-8 自注意力输出结果&lt;/center&gt;&#xA;&lt;p&gt;从图10-8可以看出，对于最终输出“是”的编码向量来说，它其实就是原始 “我 是 谁”3 个向量的加权和，而这也就体现了在对“是”进行编码时注意力 权重分配的全过程。可以看出通过这种自注意力机制的方式的确解决了作者所提出 的“传统序列模型在编码过程中都需顺序进行的弊端”的问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1023-多头注意力机制&#34;&gt;10.2.3 多头注意力机制&lt;a class=&#34;anchor&#34; href=&#34;#1023-%e5%a4%9a%e5%a4%b4%e6%b3%a8%e6%84%8f%e5%8a%9b%e6%9c%ba%e5%88%b6&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;从上述计算过程可以发现，自注意力机制在对当前位置的信息进行编码时会将注意力过度集中于自身所在的位置，因为在计算注意力权重时自己与自己所在位置的相似性是最高的，而这可能导致模型忽略了其它位置上的信息。&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.3 Transformer结构</title>
				<link>https://mlwithme.github.io/dl/chapter10/a469ed1a25e1498f/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/a469ed1a25e1498f/</guid>
				<description>&lt;h1 id=&#34;103-transformer结构&#34;&gt;10.3 Transformer结构&lt;a class=&#34;anchor&#34; href=&#34;#103-transformer%e7%bb%93%e6%9e%84&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/4987d1044939480d&#34;&gt;10.2节&lt;/a&gt;内容中我们详细介绍了自注意力机制的动机和原理，在介绍下来的这节内容中我们将继续介绍Transformer的整个网络结构，以及多头注意力机制的实现。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1031-单层transformer结构&#34;&gt;10.3.1 单层Transformer结构&lt;a class=&#34;anchor&#34; href=&#34;#1031-%e5%8d%95%e5%b1%82transformer%e7%bb%93%e6%9e%84&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;整体来看Tansformer模型同样是基于多层的编码器-解码器构造而来，而编码器和解码器又都是基于多头注意力机制构建而来，如图10-18所示便是Transformer网络结构的示意图。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;300&#34; src=&#34;https://mlwithme.github.io/images/dl/230907205739.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-18单层Transformer结构图&lt;/center&gt;&#xA;&lt;p&gt;在图10-18中，左侧为编码器，右侧为解码器。下面，我们分别对其中的各个部分进行介绍。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 编码器&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;对于编码器来说其网络结构如图10-18（左）侧所示。尽管论文中的编码器是由6个相同的编码层结构堆叠而成，但这里我们还是先以堆叠一层时的情况来进行介绍。在每一个编码层中，其内部主要由两部分网络所构成：多头注意力机制和两层前馈神经网络。同时，对于这两部分网络来说都加入了残差连接，并且在残差连接后还进行了层归一化操作。这样，对于每个部分来说其输出均为$\text{LayerNorm}(x+\text{SubLayer}(x))$，并且在都加入了Dropout操作。&lt;/p&gt;&#xA;&lt;p&gt;进一步，为了便于在这些地方使用残差连接，这两部分网络输出向量的维度均相同，默认为$d_{\text{model}}=512$，并且对于第2部分的两层全连接网络来说，其具体计算过程为&#xA;&lt;/p&gt;&#xA;$$&#xA;\text{FFN}(x)=\text{ReLU}(xW_1+b_1)W_2+b_2\tag{10-10}&#xA;$$&lt;p&gt;&#xA;其中输入$x$的维度为$d_{\text{model}}=512$，第1个全连接层的输出维度为$d_{ff}=2048$；第2个全连接层的输出为$d_{\text{model}}=512$。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 解码层&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;同编码器一样，解码器也采用了6个完全相同的网络层堆叠而成，不过这里我们依旧只是先看1层时的情况。对于解码器部分来说整体上与编码器类似，只是多了一个用于与编码器输出进行交互的多头注意力机制， 如图10-18（右）侧所示。&lt;/p&gt;&#xA;&lt;p&gt;不同于编码器部分，在解码器中一共包含有3个部分的网络结构。最上面的前馈神经网络和最下面的掩码多头注意力机制（暂时忽略掩码）与 编码器相同，只是多了中间与编码器输出（Memory）进行交互的部分，称之为“Encoder-Decoder attention”。 对于这一多头注意力机制，Q来自于下方的掩码多头注意力机制的输出，而K和V均是编码器部分的输出经过线性变换后所得到。当然这样设计也是在模仿传统编码器-解码器网络模型的解码过程，即在对当前时刻的状态解码时需要同编码器中每个时刻的隐含状态计算得到对应的注意力权重完成注意力的分配过程，更多具体细节可以参见&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/5bcd8b0920414f34&#34;&gt;9.3节&lt;/a&gt;内容。&lt;/p&gt;&#xA;&lt;p&gt;例如对于编码器输入为”我  是  谁“编码结束后，编码器-解码器交互注意力机制的整个过程便可以通过如图10-19和图10-20所示的过程来进行表示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;350&#34; src=&#34;https://mlwithme.github.io/images/dl/230909142302.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-19 编码器-解码器注意力计算示意图一&lt;/center&gt;&#xA;&lt;p&gt;如图10-19所示，对于左上角待解码向量和编码器的输出结果来说，分别进行对应的线性变换得到$Q$、$K$和$V$。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;300&#34; src=&#34;https://mlwithme.github.io/images/dl/230909142515.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-20 编码器-解码器注意力计算示意图二&lt;/center&gt;&#xA;&lt;p&gt;如图10-20所示，首先$Q$通过与$K$进行交互得到权重向量，此时可以看做是$Q$在 $K$中查询各个位置与$Q$有关的信息；然后将权重向量与$V$进行运算得到解码向量，此时这个解码向量便可以看作是考虑了memory中各个位置编码信息的输出结果。进一步，在得到这个解码向量并经过图10-18（右）中最上面的两层全连接层后，便将其输入到分类层中进行分类得到当前时刻的解码预测输出。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;3. 推理解码过程&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;如同我们在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/03a0166e195f443f&#34;&gt;9.7.2节&lt;/a&gt;内容中介绍的编码器-解码器结构一样，在Transformer解码器的推理过程中，当第1个时刻的解码过程完成之后，解码器便会将解码器第1个时刻的输入，以及解码第1个时刻后的输出均作为解码器的输入来解码预测第2个时刻的输出，后续过程以此类推直到达到指定长度或某个时刻的预测输出为结束符时停止。&lt;/p&gt;&#xA;&lt;p&gt;假设现在需要将&amp;quot; 我  是  谁&amp;quot;翻译成英语&amp;quot;who am i&amp;quot;，且解码预测后前两个时刻的结果为&amp;quot;who am&amp;quot;， 接下来需要对下一时刻的输出&amp;quot;i&amp;quot;进行预测，那么整个过程就可以通过图 10-21来进行表示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;300&#34; src=&#34;https://mlwithme.github.io/images/dl/230909142946.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-21 推理解码过程示意图&lt;/center&gt;&#xA;&lt;p&gt;如图10-21 所示，左上角的矩阵是解码器对输入&lt;code&gt; &amp;quot;&amp;lt;s&amp;gt;  who am&amp;quot;&lt;/code&gt;这 3 个字经过解码器中自注意力机制编码后的结果；左下角是编码器对输入&amp;quot;我 是 谁&amp;quot;这 3 个字编码后的结果；两者分别经过线性变换后便得到了$Q$、$K$和$V$这3个矩阵。此时值得注意的是，左上角矩阵中的每一个向量在经过自注意力机制编码后，每个向量同样也包含了其它位置上的编码信息。&lt;/p&gt;&#xA;&lt;p&gt;进一步，$Q$与$K$作用后便得到了一个权重矩阵；再将其与$V$进行线性组合便得到了编码器-解码器多头注意力机制部分的输出。最后在经过解码器中的两个全连接层后，便得到了解码器最终的输出结果。同时，这里需要注意的是模型在进行实际的预测时，只会取解码器输出的其中一个向量进行分类，然后作为当前时刻的解码输出。例如上述示例中解码器最终会输出一个形状为&lt;code&gt;[3,vocab_len]&lt;/code&gt;的矩阵，那么只用取其最后一行向量输入到分类器中进行分类得到当前时刻的解码输出，具体细节可见后续代码实现。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;4. 训练解码过程&lt;/strong&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.4 Transformer实现</title>
				<link>https://mlwithme.github.io/dl/chapter10/d50c490eef3b4565/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/d50c490eef3b4565/</guid>
				<description>&lt;h1 id=&#34;104-transformer实现&#34;&gt;10.4 Transformer实现&lt;a class=&#34;anchor&#34; href=&#34;#104-transformer%e5%ae%9e%e7%8e%b0&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面两节内容中我们分别详细介绍了Transformer模型的原理与多头注意力机制的实现过程，接下来，我们将会一步一步地来详细介绍如何通过 PyTorch框架实现Transformer的整体网络结构， 包括嵌入层、编码器和解码器等等。下面，首先介绍嵌入层的实现过程。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1041-嵌入层实现&#34;&gt;10.4.1 嵌入层实现&lt;a class=&#34;anchor&#34; href=&#34;#1041-%e5%b5%8c%e5%85%a5%e5%b1%82%e5%ae%9e%e7%8e%b0&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. Token Embedding 实现&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;这里首先要实现的是最基础的字符嵌入层，通过PyTorch框架只需要一行代码便可以得到一个字符嵌入层，如下所示：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;TokenEmbedding&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;, vocab_size, emb_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;         &lt;span style=&#34;color:#007020&#34;&gt;super&lt;/span&gt;(TokenEmbedding, &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;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(vocab_size, emb_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;emb_size &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; emb_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:#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;, tokens):&#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;return&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(tokens&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;long()) &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; math&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;sqrt(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;emb_size)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第4行便是根据指定的词表大小和维度建立一个字符嵌入层。第6~7行是字符嵌入层对应的前向传播过程，即取每个词的索引对应的词向量，其中输入&lt;code&gt;tokens&lt;/code&gt;的形状为&lt;code&gt;[len, batch_size]&lt;/code&gt;，返回结果的形状为&lt;code&gt;[len, batch_size, emb_size]&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. Positional Embedding实现&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/4987d1044939480d?id=_1024-%e8%be%93%e5%85%a5%e7%bc%96%e7%a0%81&#34;&gt;10.2.4节&lt;/a&gt;内容中我们已经详细介绍了位置编码的作用和原理，同时根据式(10-9)我们还能得到&#xA;&lt;/p&gt;&#xA;$$&#xA;1/\left(10000^{\frac{2i}{d_{\text{model}}}}\right)=\exp\left(2i\left(\frac{-\log(10000)}{d_{\text{model}}}\right)\right)\tag{10-11}&#xA;$$&lt;p&gt;&#xA;根据式(10-9)和式(10-11)，位置编码的实现过程如下所示：&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;PositionalEncoding&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;, d_model, dropout&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.1&lt;/span&gt;, max_len&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5000&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;(PositionalEncoding, &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;dropout &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Dropout(p&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;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;5&lt;/span&gt;         pe &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;zeros(max_len, d_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;6&lt;/span&gt;         position &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;arange(&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;, max_len, dtype&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;float)&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;7&lt;/span&gt;         div_term &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;exp(torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;arange(&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;,d_model,&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;)&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;float()&lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt;(&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;math&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;log(&lt;span style=&#34;color:#40a070&#34;&gt;10000.0&lt;/span&gt;)&lt;span style=&#34;color:#666&#34;&gt;/&lt;/span&gt;d_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;8&lt;/span&gt;         pe[:, &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:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;sin(position &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; div_term)  &#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;         pe[:, &lt;span style=&#34;color:#40a070&#34;&gt;1&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; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;cos(position &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; div_term)&#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;         pe &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; pe&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&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;register_buffer(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;pe&amp;#39;&lt;/span&gt;, pe)&#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;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;forward&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;, x): &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;13&lt;/span&gt;         x &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; x &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;pe[:x&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;size(&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;14&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&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(x) &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第1行&lt;code&gt;d_model&lt;/code&gt;表示指定模型的维度，&lt;code&gt;max_len&lt;/code&gt;表示指定最大的位置长度，需要大于最大句子的长度。第5行用于初始化一个全0的位置矩阵来保存位置信息，即图10-17中括号里的第2个矩阵。第6~9行是用来计算每个维度（每一列）的相关位置信息，其中第8行是计算偶数列的位置信息，第9行是计算奇数列的位置信息。第10行是进行维度扩充形状为&lt;code&gt;[max_len, 1, d_model]&lt;/code&gt;。第11行是声明一个不可训练的模型变量，后续可通过以类成员变量的方式进行引用。第12~14行为前向传播计算过程，其中输入&lt;code&gt;x&lt;/code&gt;的形状为&lt;code&gt;[x_len, batch_size, emb_size]&lt;/code&gt;，输出的形状同为&lt;code&gt;[x_len, batch_size, emb_size]&lt;/code&gt;。&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.5 Transformer对联模型</title>
				<link>https://mlwithme.github.io/dl/chapter10/f6c507b3d2d74f03/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/f6c507b3d2d74f03/</guid>
				<description>&lt;h1 id=&#34;105-transformer对联模型&#34;&gt;10.5 Transformer对联模型&lt;a class=&#34;anchor&#34; href=&#34;#105-transformer%e5%af%b9%e8%81%94%e6%a8%a1%e5%9e%8b&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;经过前面几节内容的介绍，相信各位读者对于Transformer的基本原理以及实现过程已经有了一个较为清晰地认识。在接下来的这节内容中我们将通过搭建一个完整的对联生成模型来再次理解Transformer模型的整个工作流程，包括数据的预处理、数据集的构建以及模型的推理部分的实现等。&lt;/p&gt;&#xA;&lt;p&gt;从整体上来看，基于Transformer的对联生成模型在结构上类似于我们在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/fefa60e0bc854a17&#34;&gt;9.9节&lt;/a&gt;内容中介绍到的神经翻译模型，编码器对上联进行编码得到记忆向量；然后解码器在逐时刻对其进行解码得到下联。同时，由于对联的上下联长度都是一致的，所以解码器在解码时的最大长度等于编码器的输入长度。进一步，由于在这一场景下编码器和解码器的输入均为汉字所以还可以共用同一个字符嵌入层来进行处理。&lt;/p&gt;&#xA;&lt;p&gt;本节内容完整示例代码可参见&lt;code&gt;Code/Chapter10/C03_Transformer&lt;/code&gt;文件。下面，我们首先开始介绍整个数据集的构建过程。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1051-数据预处理&#34;&gt;10.5.1 数据预处理&lt;a class=&#34;anchor&#34; href=&#34;#1051-%e6%95%b0%e6%8d%ae%e9%a2%84%e5%a4%84%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;经过前面多节内容的介绍，对于文本数据预处理这部分内容相信各位读者已经比较熟悉了，所以在下面的介绍过程中对于之前已经介绍过的内容就不再赘述，直接参见相关引用即可。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 数据集介绍&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;本次所使用到的数据集是一个网上公开的对联数据集，在GitHub中检索&amp;quot;couplet-dataset”即可找到。整个数据集中一共包含有770491条训练样本和4000条测试样本。与翻译数据集类似，对联数据集也包含上下两句，原文件如下所示：&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:#60a0b0;font-style:italic&#34;&gt;# 上联  in.txt&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt; 晚 风 摇 树 树 还 挺 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt; 愿 景 天 成 无 墨 迹 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt; 丹 枫 江 冷 人 初 去 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt; &#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:#60a0b0;font-style:italic&#34;&gt;# 下联  out.txt&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; 晨 露 润 花 花 更 红 &#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; 万 方 乐 奏 有 于 阗 &#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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如上所示便是3条样本，分别存放在&lt;code&gt;in.txt&lt;/code&gt;和&lt;code&gt;out.txt&lt;/code&gt;这两个文件中。可以看出，原始数据已经做了分字处理这一步，所以后续我们只需要进行简单的分割操作即可。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 建立词表&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;首先根据原始文本构建词表，我们这里直接分别延续使用&lt;a href=&#34;https://mlwithme.github.io/dl/chapter07/ec8ff069aadc49b9?id=_724-%e5%9f%ba%e4%ba%8ernn%e7%9a%84%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb&#34;&gt;7.2.4节&lt;/a&gt;中介绍的&lt;code&gt;tokenize()&lt;/code&gt;函数来将文本切分成字的形式，&lt;code&gt;Vocab()&lt;/code&gt;类来构建整个词表。最终，根据原始语料便可以得到类似如下所示词表：&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.6 BERT网络</title>
				<link>https://mlwithme.github.io/dl/chapter10/3aedea1d3f3e48dd/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/3aedea1d3f3e48dd/</guid>
				<description>&lt;h1 id=&#34;106-bert网络&#34;&gt;10.6 BERT网络&lt;a class=&#34;anchor&#34; href=&#34;#106-bert%e7%bd%91%e7%bb%9c&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;经过前面几节内容的介绍，我们对Transformer模型已经有了清晰地认识。不过说起Transformer模型在它发表之初并没有引起太大的反响，直到它的后继者BERT[1]模型的出现才使得大家再次回过头来仔细研究Transformer模型。在接下来的几节内容中，我们将主要从BERT模型的基本原理、模型实现、预训练模型在下游任务中的运用以及掩码任务和下句预测任务这几个方面来详细介绍BERT模型。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1061-bert动机&#34;&gt;10.6.1 BERT动机&lt;a class=&#34;anchor&#34; href=&#34;#1061-bert%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;虽然预训练语言模型对于很多下游处理任务的性能都有着显著的提升，但现有预训练模型的网络结构却限制了模型自身的表达能力，其中最主要的一点就是模型的单向编码。例如在传统的RNN或者是GPT[2]中，模型在建模时使用的均是从左到右（Left-to-Right）或者从右到左（Right-to-Left）的建模方式，这就使得模型在编码过程中只能够看到当前时刻之前的信息，而不能够同时捕捉到当前时刻之后的信息。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;350&#34; src=&#34;https://mlwithme.github.io/images/dl/230914200254.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图10-25 编码方向图&lt;/center&gt;&#xA;&lt;p&gt;如图10-25所示，对于这句样本来说无论模型采用的是从左到右还是从右到左的编码方，模型在对词“it”进行编码时都不能有效地捕捉到其具体所指代的信息。这就类似于我们人在阅读这句话时一样，在没有看到“tired”这个词之前我们同样也无法判断“it”具体所指代的事物。例如如果我们把“tired”这个词换成“wide”，则“it”指代的就变成了“street”。所以，如果模型采用的是双向编码的方式，那么从理论上来看就能够很好的避免这个问题。&lt;/p&gt;&#xA;&lt;p&gt;基于这样的动机，德夫林（Devlin）等人[1]于2018年10月提出了一种采用双向表示的编码器（Bidirectional Encoder Representations from Transformers, BERT）来实现模型的双向编码学习能力。整体来看BERT模型的整体结构并不复杂，它本质上就等同于Transformer中的编码器，只是模型在预训练的过程中使用了掩码语言模型（Mask Language Model, MLM）和下句预测（Next Sentence Prediction, NSP）这两项任务。下面我们首先开始介绍BERT模型的基本原理。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1062-bert结构&#34;&gt;10.6.2 BERT结构&lt;a class=&#34;anchor&#34; href=&#34;#1062-bert%e7%bb%93%e6%9e%84&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;BERT网络结构整体上是由多层的Transformer编码器所构建，如图10-26所示便是一个详细的BERT模型网络结构图。从图10-26可以发现其上半部分的结构与&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/a469ed1a25e1498f&#34;&gt;10.3节&lt;/a&gt;内容中介绍的Transformer编码器类似，只不过在输入层部分新加入了句子编码（Segment Embedding）。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;300&#34; src=&#34;https://mlwithme.github.io/images/dl/230914200835.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图10-26 BERT网络结构图&lt;/center&gt;&#xA;&lt;p&gt;如图10-26所示，其上半部分便是BERT编码器，其整体由多个BERT编码层（即原文中指代的 Transformer Blocks）所构成。具体地，在论文中作者分别用 $L$来表示编码层的格式，即BERT编码器是由$L$ 个编码层所构成；用$H$来表示模型的维度；用$A$来表示多头注意力中多头的个数。同时，作者分别就$\text{BERT}_{\text{BASE}} (L=12,H =768,A=12)$和$\text{BERT}_{\text{BASE}} (L=24,H =1024,A=16)$这两种尺寸的BERT模型进行了实验对比。由于这部分类似的内容在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/a469ed1a25e1498f&#34;&gt;10.3节&lt;/a&gt;内容中已经进行了详细介绍，所以这里就不再 赘述，细节之处见&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/82a1cd0def084620&#34;&gt;10.7节&lt;/a&gt;代码实现。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1063-bert输入层&#34;&gt;10.6.3 BERT输入层&lt;a class=&#34;anchor&#34; href=&#34;#1063-bert%e8%be%93%e5%85%a5%e5%b1%82&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;如图10-27所示，在BERT中输入层模块中一共包含3个部分：字符嵌入（Token Embedding）、位置编码（Positional Embedding） 和句子编码（Segment Embedding）。虽然前面两部分在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/a469ed1a25e1498f&#34;&gt;10.3节&lt;/a&gt;内容中已经介绍过了，但这里需要注意的是BERT中的位置编码并不是采用公式计算得到，而是类似 普通的嵌入层一样为每一个位置初始化了一个向量然后随着网络一起训练得到。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;360&#34; src=&#34;https://mlwithme.github.io/images/dl/230914200914.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图10-27 输入层结构图&lt;/center&gt;&#xA;&lt;p&gt;同时，最值得注意的一点是BERT开源的预训练模型最大只支持 512个字符的长度，这是因为模型在训练过程中位置编码的词表的最大长度只有512。&lt;/p&gt;&#xA;&lt;p&gt;除此之外，第三部分则是BERT模型中所引入的句子编码。由于BERT模型的主要目的是构建一个通用的预训练模型，因此难免需要兼顾到各种NLP 任务场景下的输入。因此句子编码的作用便是用来区分输入序列中的不同部分，其本质是通过一个普通的嵌入层来区分每一个序列所处的位置。例如在下句预测任务中，对于任意一个输入样本来说均由两个句子构成，而句子编码的作用就是对每个字符进行位置标识，以此来区分哪些字符属于第1个句子哪些字符属于第2个句子，因此也可以看出同一个句子中的编码是一样的。最后，再将这三部分的结果相加并标准化便得到了BERT模型的输入。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/dl/230914203449.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图10-28 输入层细节图&lt;/center&gt;&#xA;&lt;p&gt;如图10-28所示，最上面的Input表示原始的输入序列，其中第1个字符[CLS]是一个特殊的分类标志，如果下游任务是做文本分类的话，那么在 BERT 的输出结果中可以只取[CLS]对应的向量进行分类（不过实验表明，取所有位置向量的均值往往有着更好的效果）；而其中的[SEP]字符则是用来作为将两句话分开的标志。句子编码则同样是用来区分两句话所在的不同位置，对于每句话来说其内部各自的位置向量都是一样的，当然如果原始输入只有一句话，那么句子编码层中对应的每个字符的位置向量均相同。最后，位置编码则是用来标识句子中每个字符各自所在的位置，使得模型能够捕捉到文本“有序”这一特性，具体细节之处可见&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/82a1cd0def084620&#34;&gt;10.7节&lt;/a&gt;代码实现。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1064-预训练任务&#34;&gt;10.6.4 预训练任务&lt;a class=&#34;anchor&#34; href=&#34;#1064-%e9%a2%84%e8%ae%ad%e7%bb%83%e4%bb%bb%e5%8a%a1&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;为了能够更好训练BERT模型，论文引入了MLM和NSP这两个预训练任务来训练网络。对于MLM任务来说，它的做法是随机掩盖掉输入序列中$15\%$​的字符，即用[MASK]替换掉原有的字符，然后在BERT的输出结果中取对应掩盖位置上的向量进行真实值预测。不过由于模型在后续的微调（Fine-tuning)过程中输入序列并不存在 [MASK]这样的字符，因此这将导致模型的预训练和微调之间存在不匹配的问题。为了解决这一问题，可以将原始MLM做相应调整，即先选定15%的字符，然后将其中的80%替换为[MASK]符号、10%随机替换为其它符号、剩下的10%保持不变。最后取这15% 的字符对应的输出来做分类来预测其真实值。&lt;/p&gt;&#xA;&lt;p&gt;对于NSP任务来说，它的做法是在每个有AB两个句子构造的样本中，其中50%的情况下B确实为A上下文的下一句话，此时标签为IsNext；另外50%的情况下B为语料中其它的随机句子， 此时标签为NotNext然；最后模型取[CLS]位置上对应的向量来预测B是否为A的下一句话。这样做的目的便是因为在很多下游任务需要依赖于分析两句话之间的关系来进行建模，例如文本蕴含、问题选择等任务场景。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;330&#34; src=&#34;https://mlwithme.github.io/images/dl/230914201017.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图10-29 NSP和MLM任务网络结构&lt;/center&gt;&#xA;&lt;p&gt;如图10-29所示便是MLM和NSP这两个预训练任务在BERT预训练时的输入输出示意图。在图10-29中，最上层输出的C在训练时用于NSP的分类任务，其它位置上的$T_i$和$T^{\prime}_j$等则用于预测被掩盖掉的字符。&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.7 从零实现BERT</title>
				<link>https://mlwithme.github.io/dl/chapter10/82a1cd0def084620/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/82a1cd0def084620/</guid>
				<description>&lt;h1 id=&#34;107-从零实现bert&#34;&gt;10.7 从零实现BERT&lt;a class=&#34;anchor&#34; href=&#34;#107-%e4%bb%8e%e9%9b%b6%e5%ae%9e%e7%8e%b0bert&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;经过&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/3aedea1d3f3e48dd&#34;&gt;10.6节&lt;/a&gt;内容的介绍，我们对于BERT模型的整体结构已经有了一定的了解。根据图10-26可知，从本质上来说BERT就是由Transformer中的编码器构建而来，同时在输入层部分额外加入了一个句子编码来区分输入的不同部分。在本节内容中，我们将以图10-26中黑色加粗字体所示的部分为一个类来分别构建实现整个BERT模型。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1071-工程结构&#34;&gt;10.7.1 工程结构&lt;a class=&#34;anchor&#34; href=&#34;#1071-%e5%b7%a5%e7%a8%8b%e7%bb%93%e6%9e%84&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;由于整个项目涉及到的代码模块较多，所以我们在这里先进行简单说明， 这样便于各位读者在阅读后续内容时能够快速地定位到相应的代码部分。同时， 这里也建议各位读者在阅读内容的能够同时结合代码一起阅读并动手实践。&lt;/p&gt;&#xA;&lt;p&gt;在整个工程项目中一共包含有6个主要的文件目录，cache、data、model、Tasks、test和uils。其中cache目录用来存放训练过程中所保存下来的模型；data用来存放各类数据集，包括后续将要用到的文本分类、问题回答和训练预料等；model目录中存放的是整个BERT模型的实现代码，以及相关下游任务的构造模型；Tasks目录中存放的是model中各个任务对应的模型训练代码；test目录中存放的是各个模块的测试案例，用于在实现过程中的验证，后续内容中的相关使用示例都能在其中找到；utils目录中存放的是一些辅助工具模块，包括数据集构建和日志模块等。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1072-input-embedding实现&#34;&gt;10.7.2 Input Embedding实现&lt;a class=&#34;anchor&#34; href=&#34;#1072-input-embedding%e5%ae%9e%e7%8e%b0&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;首先，我们先来看Input Embedding的实现过程。由于在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/d50c490eef3b4565&#34;&gt;10.4节&lt;/a&gt;内容中我们已经介绍过了字符嵌入的实现，所以在复用这部分代码之后只需要再实现位置编码和句子编码即可。本节内容及后续多个下游任务的完整示例代码可参见&lt;code&gt;Code/Chapter10/C04_BERT&lt;/code&gt;文件。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. Positional Embedding实现&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;不同于Transformer中位置编码的实现方式，在BERT中位置编码并没有采用固定的变换公式来计算每个位置上的值，而是采用了普通嵌入层的方式来为每个位置生成一个向量然后随着模型一起训练。因此，这也就限制了在使用预训练的中文BERT模型时最大的序列长度只能是512，因为在训练时只初始化了512个位 置向量。示例代码如下所示：&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;PositionalEmbedding&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, max_position_embeddings&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;512&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;                  initializer_range&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.02&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;(PositionalEmbedding, &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 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Embedding(max_position_embeddings, 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;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;, position_ids):&#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;return&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(position_ids)&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;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第7行&lt;code&gt;position_ids&lt;/code&gt;的形状为&lt;code&gt;[1,position_ids_len]&lt;/code&gt;。第8行返回结果的形状为&lt;code&gt;[position_ids_len, 1, hidden_size]&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. Segment Embedding 实现&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;SegmentEmbedding&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;, type_vocab_size, hidden_size, initializer_range&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.02&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;(SegmentEmbedding, &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;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(type_vocab_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; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;forward&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;, token_type_ids):&#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;return&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(token_type_ids)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第2行&lt;code&gt;type_vocab_size&lt;/code&gt;的默认值为 2，即只用于区分两个序列的不同位置。第6行&lt;code&gt;token_type_ids&lt;/code&gt;的形状为&lt;code&gt;[token_type_ids_len, batch_size]&lt;/code&gt;。第7行返回结果的形状为&lt;code&gt;[token_type_ids_len, batch_size, hidden_size]&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;3. Bert Embedding实现&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在完成3个部分的代码实现之后，只需要将每个部分的结果相加便可以得到最终的嵌入层表示作为BERT模型的输入，示例代码如如下所示：&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;BertEmbeddings&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;, config):&#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;()&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;word_embeddings &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; TokenEmbedding(config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;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;5&lt;/span&gt;                                       config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;hidden_size,config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;pad_token_id)&#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;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;position_embeddings &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; PositionalEmbedding(&#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;                            config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;max_position_embeddings,config&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&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;token_type_embeddings &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; SegmentEmbedding(config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;type_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;9&lt;/span&gt;                                  config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;hidden_size,config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;initializer_range)&#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&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;LayerNorm &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;LayerNorm(config&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;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;dropout &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Dropout(config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;hidden_dropout_prob)&#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&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;register_buffer(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;position_ids&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;13&lt;/span&gt;                 torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;arange(config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;max_position_embeddings)&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;expand((&lt;span style=&#34;color:#40a070&#34;&gt;1&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;)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第2行&lt;code&gt;config&lt;/code&gt;是传入的一个配置类，里面各个类成员就是BERT模型中对应的模型参数。第 4~8行是分别用来定义图10-27中的3个编码部分。第12~13行是用来生成一个默认的位置编号，即&lt;code&gt;[0,1,....,511]&lt;/code&gt;。&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.8 BERT文本分类模型</title>
				<link>https://mlwithme.github.io/dl/chapter10/e736d3974ed0484c/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/e736d3974ed0484c/</guid>
				<description>&lt;h1 id=&#34;108-bert文本分类模型&#34;&gt;10.8 BERT文本分类模型&lt;a class=&#34;anchor&#34; href=&#34;#108-bert%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb%e6%a8%a1%e5%9e%8b&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;经过前面两节内容的介绍，我们对于BERT模型的原理及其实现过程已经有了比较清晰的理解。同时，由于BERT是一个强大的预训练模型，因此我们可以直接基于谷歌发布的预训练参数将模型迁移到各个下游任务中进行微调学习。在这节内容中，我们将开始介绍第1个基于BERT预训练模型的下游任务文本分类。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1081-任务构造原理&#34;&gt;10.8.1 任务构造原理&lt;a class=&#34;anchor&#34; href=&#34;#1081-%e4%bb%bb%e5%8a%a1%e6%9e%84%e9%80%a0%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;整体来看基于BERT的文本分类模型就是在原始BERT模型的基础之上添加了一个新的分类层。 同时，对于分类层的输入，即原始BERT模型的输出，默认情况下可以取BERT输出结果中[CLS]位置对应的向量，当然也可以修改为其它方式，例如取所有位置向量的均值等，详见&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/82a1cd0def084620?id=_1073-bert%e6%a8%a1%e5%9e%8b%e5%ae%9e%e7%8e%b0&#34;&gt;10.7.3节&lt;/a&gt;内容。&lt;/p&gt;&#xA;&lt;p&gt;因此，对于基于BERT的文本分类模型来说其输入为一个单句，输出则是每个类别对应的概率值。接下来，我们首先来介绍如何构造文本分类任务中所使用到的数据集。以下完整示例代码可参见&lt;code&gt;Code/Chapter10/C04_BERT&lt;/code&gt;文件。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1082-数据预处理&#34;&gt;10.8.2 数据预处理&lt;a class=&#34;anchor&#34; href=&#34;#1082-%e6%95%b0%e6%8d%ae%e9%a2%84%e5%a4%84%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在构建数据集之前，我们首先需要知道模型应该接收什么样的输入，然后才能构建得到正确的样本形式。由于在文本分类这个任务场景中输入模型的只有一个序列，所以在构建数据集时并不需要构造句子编码这一层，直接默认使用全为0即可。同时，对于位置编码来说在任何场景下都不需要显示地指定输入，因为我们在代码实现时已经做了相应的默认处理逻辑。因此，对于文本分类来说只需要构造原始文本对应的索引序列， 并在首尾分别再加上一个[CLS]符和[SEP]符作为输入即可。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1.  语料介绍&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在这里，我们使用到的是今日头条开源的一个新闻分类数据集[1]， 一共包含有382688个样本，15 个类别。同时我们这里已经将其进行了格式化处理， 以7 : 2 : 1的比例划分成了训练集、验证集和测试集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; 千万不要乱申请网贷&lt;span style=&#34;&#34;&gt;，&lt;/span&gt;否则后果很严重_&lt;span style=&#34;&#34;&gt;!&lt;/span&gt;_4&#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;10&lt;/span&gt;年前的今天&lt;span style=&#34;&#34;&gt;，&lt;/span&gt;纪念 &lt;span style=&#34;color:#40a070&#34;&gt;5.12&lt;/span&gt; 汶川大地震 &lt;span style=&#34;color:#40a070&#34;&gt;10&lt;/span&gt; 周年_&lt;span style=&#34;&#34;&gt;!&lt;/span&gt;_11&#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; 怎么看待杨毅在一 NBA 直播比赛中说詹姆斯的球场统治力已经超过乔丹&lt;span style=&#34;&#34;&gt;、&lt;/span&gt;伯德和科比&lt;span style=&#34;&#34;&gt;?&lt;/span&gt;_&lt;span style=&#34;&#34;&gt;!&lt;/span&gt;_3 &#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;&#34;&gt;?&lt;/span&gt;_&lt;span style=&#34;&#34;&gt;!&lt;/span&gt;_2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述示例中，&lt;code&gt;_!_&lt;/code&gt;左边为新闻标题，即后续需要用到的分类文本，右边为类别标签。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 定义Tokenizer&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在构建数据集之前需要完成的便是将文本序列切分到字符级别，对于中文语料来说主要是将每个字和标点符号都分割开。在这里我们可以借用 &lt;code&gt;transformers&lt;/code&gt;包中的&lt;code&gt;BertTokenizer&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;from&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;transformers&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;import&lt;/span&gt; BertTokenizer&#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; model_config &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; ModelConfig()&#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; tokenize &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; BertTokenizer&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;from_pretrained(model_config&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;pretrained_model_dir)&#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;print&lt;/span&gt;(tokenize&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;tokenizer(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;10年前的今天，纪念 5.12 汶川大地震 10 周年&amp;#34;&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# [&amp;#39;10&amp;#39;, &amp;#39;年&amp;#39;, &amp;#39;前&amp;#39;, &amp;#39;的&amp;#39;, &amp;#39;今&amp;#39;, &amp;#39;天&amp;#39;, &amp;#39;，&amp;#39;, &amp;#39;纪&amp;#39;, &amp;#39;念&amp;#39;, &amp;#39;5&amp;#39;, &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# &amp;#39;.&amp;#39;, &amp;#39;12&amp;#39;, &amp;#39;汶&amp;#39;, &amp;#39;川&amp;#39;, &amp;#39;大&amp;#39;, &amp;#39;地&amp;#39;, &amp;#39;震&amp;#39;, &amp;#39;10&amp;#39;, &amp;#39;周&amp;#39;, &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;在上述代码中，第1行是导入&lt;code&gt;BertTokenizer&lt;/code&gt;模块。第3行是实例化一个&lt;code&gt;BertTokenizer&lt;/code&gt;类对象用于中文序列的分割。第5~6行便是切分后的示例结果。&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.9 BERT问题选择模型</title>
				<link>https://mlwithme.github.io/dl/chapter10/f5076cbadda84d4e/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/f5076cbadda84d4e/</guid>
				<description>&lt;h1 id=&#34;109-bert问题选择模型&#34;&gt;10.9 BERT问题选择模型&lt;a class=&#34;anchor&#34; href=&#34;#109-bert%e9%97%ae%e9%a2%98%e9%80%89%e6%8b%a9%e6%a8%a1%e5%9e%8b&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;经过&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/e736d3974ed0484c&#34;&gt;10.8节&lt;/a&gt;内容介绍之后，我们对于如何在下游任务中使用BERT预训练模型已经有了一定的认识。在本节内容中我们将会介绍如何利用BERT模型来完成推理问答选择任务，同时给模型输入一个问题和若干选项的答案，最后需要模型从给定的选项中选择一个最符合问题逻辑的答案。&lt;/p&gt;&#xA;&lt;p&gt;通常来说，在NLP领域的大多数场景中模型最后本质上完成的都是一个分类任务。例如文本蕴含任务本质就是将两个序列拼接 在一起，然后预测其所属的类别；基于神经网络的序列生成模型（翻译、文本 生成等）本质就是预测词表中下一个最有可能出现的词，此时的分类类别就是词表的大小。因此，从本质上来看本节内容将要介绍的问答选择任务以及在后面将要介绍的问题回答任务其实都是一个分类任务，而关键的地方就在于如何构建模型的输入和输出。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1091-任务构造原理&#34;&gt;10.9.1 任务构造原理&lt;a class=&#34;anchor&#34; href=&#34;#1091-%e4%bb%bb%e5%8a%a1%e6%9e%84%e9%80%a0%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;正如上面所说，对于问答选择这个任务场景来说其本质上依旧可以归结为分类任务，只是关键在于如何构建这一任务以及整个数据集。对于问答选择这 个场景来说，其整体原理如图10-30所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;400&#34; src=&#34;https://mlwithme.github.io/images/dl/230920193259.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-30 问题选择任务构造原理图 &lt;/center&gt;&#xA;&lt;p&gt;如图10-30所示是一个基于BERT预训练模型的4选1问答选择模型的原理图。从图中可以看出原始数据的形式是1个问题和4个选项，模型需要做的是从4个选项中给出一个最合理的答案，于是本质上也就变成了一个4分类任务。同时，构建模型输入的方式就是将原始问题和每一个答案拼接起来构成一个序列并且中间用[SEP]符号隔开；然后再分别输入到BERT模型中进行特征提取得到4个特征向量，此时输出形状为&lt;code&gt;[4,hidden_size]&lt;/code&gt;；最后再经过一个分类层进行分类处理得到预测选项。通常情况下这里的4个特征都是直接取每个序列经BERT编码后的[CLS]向量。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1092-数据预处理&#34;&gt;10.9.2 数据预处理&lt;a class=&#34;anchor&#34; href=&#34;#1092-%e6%95%b0%e6%8d%ae%e9%a2%84%e5%a4%84%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;根据上面的内容可知，对于问答任务来说其接受的输入也分为两个部分：一是由问题和每个选项这两个句子所组成的索引序列，并且需要在两个句子的开始位置加上一个[CLS]符号，以及两个句子之间和结尾分别加上一个[SEP]符号；二是句子编码部分的输入用于确定两个句子的所属部分。最后将两者均作为模型的输入即可。以下完整示例代码可参见&lt;code&gt;Code/Chapter10/C04_BERT&lt;/code&gt;文件。&lt;/p&gt;&#xA;&lt;p&gt;同时，这里需要注意的是虽然对于BERT模型来说“问题 +  1个选项”构成的序列就是一个样本，但是我们在构造数据集的时候还是需要将“问题 + 4个选项”看成一个整体，然后在输入模型之前再变形为对应的形状。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 语料介绍&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在这里我们使用到的是生成对抗场景数据集（The Situations With Adversarial Generations, SWAG）[1] [2]，即给定一个情景（一个问题或一句描述），任务是模型从给定的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; ,video&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#007020&#34;&gt;id&lt;/span&gt;,fold&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;ind,startphrase,sent1,sent2,gold&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;source, ending0,ending1, ending2,ending3,label&#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&lt;/span&gt;,anetv_NttjvRpSdsI,&lt;span style=&#34;color:#40a070&#34;&gt;19391&lt;/span&gt;,The people are &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; robes&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; They,The people are &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; robes&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;,They,gold,are wearing colorful costumes&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;,are doing karate moves on the floor&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;,shake hands on their hips&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;,do a flip to the bag&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:#40a070&#34;&gt;1&lt;/span&gt;,lsmdc3057_ROBIN_HOOD&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;27684&lt;/span&gt;,&lt;span style=&#34;color:#40a070&#34;&gt;16344&lt;/span&gt;,She smirks at someone &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;and&lt;/span&gt; rides off&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; He,She smirks at someone &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;and&lt;/span&gt; rides off&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;,He,gold,smiles &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;and&lt;/span&gt; falls heavily&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;,wears a bashful smile&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;,kneels down behind her&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;,gives him a playful glance&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;,&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述示例中一共有12个字段（第1行）包含两个样本（第2~3行），这里需要用到的是sent1, ending0, ending1, ending2, ending3和label这6个字段。例如对于第1个样本来说，其形式如下：&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.10 BERT问题回答模型</title>
				<link>https://mlwithme.github.io/dl/chapter10/25d9ef3d9b34472a/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/25d9ef3d9b34472a/</guid>
				<description>&lt;h1 id=&#34;1010-bert问题回答模型&#34;&gt;10.10 BERT问题回答模型&lt;a class=&#34;anchor&#34; href=&#34;#1010-bert%e9%97%ae%e9%a2%98%e5%9b%9e%e7%ad%94%e6%a8%a1%e5%9e%8b&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;经过前面几节内容的介绍，我们已经清楚了BERT模型的基本原理以及如何基于BERT预训练模型来完成文本分类和问答选择这些下游微调任务。在接下来的这节内容中，我们将会继续介绍基于BERT预训练模型的第3个下游任务微调场景，问题回答任务。所谓问题回答是指同时给模型输入一个问题和一段描述，最后需要模型从给定的描述中预测出答案所在的位置。&lt;/p&gt;&#xA;&lt;p&gt;例如：&lt;/p&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;描述:苏轼是北宋著名的文学家与政治家，眉州眉山人。&lt;/p&gt;&#xA;&lt;p&gt;问题:苏轼是哪里人?&lt;/p&gt;&#xA;&lt;p&gt;标签:眉州眉山人&lt;/p&gt;&#xA;&lt;/blockquote&gt;&lt;p&gt;在完成这个任务之前首先需要明白的是：①最终问题的答案一定存在于给定的文本描述中；②问题的答案一定是给定描述中的一段连续的字符，即不能有间隔。例如对于上面的描述内容来说，如果给出的问题是“苏轼生活在什么年代以及他是哪里人?”，那么模型最终并不能给出类似“北宋”和“眉州眉山人”这两个分离的答案，最好的情况下便是给出“北宋著名的文学家与政治家，眉州眉山 人”这一段连续的文本序列。&lt;/p&gt;&#xA;&lt;p&gt;在有了这两个限制条件以后，对于这类问答任务其本质也就变成了需要让模型预测得到答案在文本描述中的起始位置（Start Position）和结束位置（End Position），而这也叫做文本片段（Text Span）预测。因此，问题最终就变成了如何在BERT模型的基础之上再构建一个分类器来对BERT最后一层输出的每个位置进行分类，依次判断它们是否属于开始位置或结束位置。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10101-任务构造原理&#34;&gt;10.10.1 任务构造原理&lt;a class=&#34;anchor&#34; href=&#34;#10101-%e4%bb%bb%e5%8a%a1%e6%9e%84%e9%80%a0%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;正如上面所说，尽管问题回答任务看似复杂但其本质依旧可以归结为一个普通的分类任务，只是解决这个问题的关键在于如何构建整个数据集。如图10-32所示便是一个基于BERT预训练模型的问题回答模型的原理图。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/dl/230924091936.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-32 问题回答原理图&lt;/center&gt;&#xA;&lt;p&gt;从图10-32可以看出，构建模型输入的方式就是将原始问题和上下文描述拼接成一个序列中间用[SEP]符号隔开，然后再分别输入到BERT模型中进行特征提取。在BERT编码完成后再取最后一层的输出对每个位置上的向量进行分类即可得到开始位置和结束位置的预测输出。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10102-样本构造与结果筛选&#34;&gt;10.10.2 样本构造与结果筛选&lt;a class=&#34;anchor&#34; href=&#34;#10102-%e6%a0%b7%e6%9c%ac%e6%9e%84%e9%80%a0%e4%b8%8e%e7%bb%93%e6%9e%9c%e7%ad%9b%e9%80%89&#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;在正式介绍如何构建数据集之前我们先来看对于上下文过长时的情况该怎么处理。在问题回答这个任务场景中，当原始上下文的长度超过给定长度或者是512个字符时，可以采取滑动窗口的方法来构造整个模型的输入序列，如图10-33所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/dl/230924092613.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-33 训练时滑动窗口处理流程&lt;/center&gt;&#xA;&lt;p&gt;如图10-33所示，第①步需要是根据指定的最大长度和滑动窗口将原始样本进行滑动窗口处理并得到多个子样本。这里需要注意的是，句子A也就是问题部分不参与滑动处理。同时，图10-33中样本右边的3列数字分别表示在每个子样本中答案的起始位置、结束位置和原始样本对应的编号。紧接着第②步便是将所有原始样本滑动处理后的结果作为训练集来训练模型。&lt;/p&gt;&#xA;&lt;p&gt;总的来说，在这一场景中模型的训练程并不复杂，因为每个子样本也都有其对应的标签值和普通的训练过程并没有什么本质上的差异。因此， 最关键的地方在于如何在推理过程中也使用滑动窗口。&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;p&gt;如图10-34所示，在推理过程中第①步仍旧需要根据指定最大长度和滑动窗口大小将原始样本进行滑动窗口处理。接着第②步是根据模型分类的输出取前K个概率值最大的结果。在图10-34中K=4，因此对于每个子样本来说其开始位置和结束位置分别都有4个候选结果。例如，第②步中第1行的 7:0.41、10:02、9:0.12和2:01分别表示对于第1个子样本来说，开始位置为索引7的概率值为 0.41，其它同理。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/dl/230924092712.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-34 推理时滑动窗口处理流程（一）&lt;/center&gt;&#xA;&lt;p&gt;此时对于每一个子样本来说，在分别得到开始位置和结束位置的前K个候选值后便可以通过组合来得到更多的候选预测结果，然后再根据一些规则来选择最终原始样本对应的预测输出。根据图10-34中样本重构后的结果可以看出：（1）最终的索引预测结果需要大于8，因为句子A的长度已经是7，而答案只可能在上下文中出现；（2）在结果组合中，起始索引必定小于等于结束索引。因此，根据这两个条件在经过步骤③的处理后，便可得到进一步筛选后的结果。例如：对于第1个子样本来说，开始位置中7和2不满足条件（1）所以可以直接去掉，同时为了满足第（2）个条件所以在结束位置中8、6和7均需要去掉。&lt;/p&gt;&#xA;&lt;p&gt;进一步，将第③步处理后的结果在每个子样本内部进行组合，并按照开始位置加结束位置概率值的大小进行排序，便可以得到如图10-35&lt;/p&gt;&#xA;&lt;p&gt;&lt;subscribe&gt;43&lt;/subscribe&gt;&lt;/p&gt;&#xA;&lt;br&gt;&#xA;&lt;br&gt;&#xA;&lt;br&gt;</description>
			</item>
			<item>
				<title>10.11 BERT命名体识别模型</title>
				<link>https://mlwithme.github.io/dl/chapter10/64d3ec5593ec4b94/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/64d3ec5593ec4b94/</guid>
				<description>&lt;h1 id=&#34;1011-bert命名体识别模型&#34;&gt;10.11 BERT命名体识别模型&lt;a class=&#34;anchor&#34; href=&#34;#1011-bert%e5%91%bd%e5%90%8d%e4%bd%93%e8%af%86%e5%88%ab%e6%a8%a1%e5%9e%8b&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面几节内容中我们陆续介绍了3种基于BERT预训练模型的下游任务，包括文本分类、问题选择和问题回答模型。在本节内容中，我们将会介绍最后一个基于BERT预训练模型的下游任务，命名体识别（Named Entity Recognition, NER）。所谓命名体指的是输入模型一句文本，最后需要模型将其中的实体，例如人名、地名、组织等标记出来。&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-shell&#34; data-lang=&#34;shell&#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; 句子:涂伊说，如果有机会他想去黄州赤壁看一看!&#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:#4070a0&#34;&gt;&amp;#39;B-PER&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;I-PER&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;B-LOC&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;I-LOC&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:#4070a0&#34;&gt;&amp;#39;B-LOC&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;I-LOC&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/f5076cbadda84d4e&#34;&gt;10.9节&lt;/a&gt;内容中我们提到，通常来讲几乎对于所有NLP任务来说最后所要完成的本质上都是一个分类任务，因此在NER任务中也不例外。根据上面给出的标签来看，对于原始句子中的每个字符来说其都有一个对应的类别标签，因此对于NER 任务来说只需对原始句子里每个字符进行分类，然后再将预测后的结果进行后处理便能够得到句子中存在的相应实体。这种对BERT最后一层每个字符进行分类的做法也类似于在上一节中介绍到的问题回答任务。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10111-任务构造原理&#34;&gt;10.11.1 任务构造原理&lt;a class=&#34;anchor&#34; href=&#34;#10111-%e4%bb%bb%e5%8a%a1%e6%9e%84%e9%80%a0%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;正如上面所说，对于命名体识别这个任务场景来说其本质上依旧可以归结为分类任务，只是关键在于如何构建这个任务以及整个数据集。对于这个任务场景来说，模型的整体原理如图10-37所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;480&#34; src=&#34;https://mlwithme.github.io/images/dl/230925193830.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-37 命名体识别原理图&lt;/center&gt;&#xA;&lt;p&gt;如图10-37所示便是一个基于BERT预训练模型的NER任务原理图。从图中可以看出原始输入为一个单句，我们只需要在句子的首尾分别加上[CLS]和[SEP]，然后将其输入到模型当中进行特征提取并最终通过一个分类层对输出的每个向量进行分类即可。在推理过程中，只需要对每个位置的预测结果进行后处理便能够实现整个NER任务。&lt;/p&gt;&#xA;&lt;p&gt;到此，对于问答选择整个模型的原理就介绍完了，下面首先来看如何构造数据集。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10112-数据预处理&#34;&gt;10.11.2 数据预处理&lt;a class=&#34;anchor&#34; href=&#34;#10112-%e6%95%b0%e6%8d%ae%e9%a2%84%e5%a4%84%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 语料介绍&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在这里，我们使用到的是一个中文命名体识别数据集[1]，如下所示便是原始数据的存储形式：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; 涂 B&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;PER &#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&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;PER &#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; 说 O &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;...&lt;/span&gt;&#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; 黄 B&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;LOC&#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; 州 I&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;LOC&#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; 赤 B&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;LOC &#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; 壁 I&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;LOC &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中每一行包含一个字符和其所属类别，B-表示该类实体的开始标 志，I-表示该类实体的延续标志。例如对于第5~8行来说分别对应了“黄州”和 “赤壁”这两个实体。同时，对于该数据集来说，其一共包含有3类实体（人名、地名和组织），因此其对应的分类总数便为7，如下所示：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; {&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;B-ORG&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;B-LOC&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;,&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;B-PER&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;I-ORG&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;I-LOC&amp;#39;&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;I-PER&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#40a070&#34;&gt;6&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;p&gt;&lt;strong&gt;2. 数据集构造&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在数据集构造部分同样包含载入原始数据、重构样本、样本填充构造迭代器等过程。由于这些内容我们在前面几节内容中已经多次提及，所以这里我们只对其中的关键部分进行介绍。同样，整体上我们依旧可以继承文本分类处理中的&lt;code&gt;LoadSingleSentenceClassificationDataset&lt;/code&gt;类，然后再稍微修改其中的部分方法。&lt;/p&gt;&#xA;&lt;p&gt;首先是在&lt;code&gt;data_process()&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;data_process&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;, file_path):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;         raw_iter &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;open&lt;/span&gt;(file_path, encoding&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;utf8&amp;#34;&lt;/span&gt;)&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;readlines()&#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;         data, max_len, tmp_token_ids &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;         tmp_sentence,tmp_label, tmp_entity &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, [], []&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; raw &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; tqdm(raw_iter, ncols&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;80&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;             line &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; raw&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;rstrip(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#4070a0;font-weight:bold&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;)&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;split(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;split_sep)&#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;if&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;len&lt;/span&gt;(line) &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;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;len&lt;/span&gt;(tmp_token_ids) &lt;span style=&#34;color:#666&#34;&gt;&amp;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;max_position_embeddings &lt;span style=&#34;color:#666&#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;9&lt;/span&gt;                     tmp_token_ids &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; tmp_token_ids[:&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;max_position_embeddings &lt;span style=&#34;color:#666&#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;10&lt;/span&gt;                     tmp_label &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; tmp_label[:&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;max_position_embeddings &lt;span style=&#34;color:#666&#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;11&lt;/span&gt;                 max_len &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;max&lt;/span&gt;(max_len, &lt;span style=&#34;color:#007020&#34;&gt;len&lt;/span&gt;(tmp_label) &lt;span style=&#34;color:#666&#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;12&lt;/span&gt;                 token_ids &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;tensor([&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;CLS_IDX] &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; tmp_token_ids &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;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;SEP_IDX], dtype&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;long)&#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;                 labels &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;tensor([&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;IGNORE_IDX] &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; tmp_label &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;15&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;IGNORE_IDX], dtype&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;long)&#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;                 data&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;append([tmp_sentence, token_ids, labels])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;17&lt;/span&gt;                 &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;assert&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;len&lt;/span&gt;(tmp_token_ids) &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;len&lt;/span&gt;(tmp_label)&#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;                 tmp_token_ids,tmp_sentence &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; [], &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#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;                 tmp_label,tmp_entity &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;20&lt;/span&gt;                 &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;continue&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;21&lt;/span&gt;             tmp_sentence &lt;span style=&#34;color:#666&#34;&gt;+=&lt;/span&gt; line[&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;22&lt;/span&gt;             tmp_token_ids&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;append(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;vocab[line[&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;23&lt;/span&gt;             tmp_label&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;append(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;entities[line[&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;24&lt;/span&gt;             tmp_entity&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;append(line[&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;25&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; data, max_len&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第2行是一次性读取原始数据中的所有行。第3行分别用于保存预处理结束后的数据、所有样本中的最大长度和每个样本索引。第4行分别用于保存每个原始样本、对应的标签类别和原始标签值，主要用于观察预处理时的中间结果。第5行开始遍历原始数据中的每一行。第7行表示已经将上一个样本处理完毕。第7~10行是判断长度是否超过最大长度。第11行用来记录所有句子的最大长度。第12~15行是用来构造模型输入和正确标签。第21~24行分别是对当前样本中的每个字符进行相应的处理。&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.12 BERT从零训练</title>
				<link>https://mlwithme.github.io/dl/chapter10/90ea8d3e090d48b4/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/90ea8d3e090d48b4/</guid>
				<description>&lt;h1 id=&#34;1012-bert从零训练&#34;&gt;10.12 BERT从零训练&lt;a class=&#34;anchor&#34; href=&#34;#1012-bert%e4%bb%8e%e9%9b%b6%e8%ae%ad%e7%bb%83&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面几节内容中我们已经介绍了几种常见的基于BERT预训练模型的下游任务，在接下来的这节内容中我们将会介绍如何从零实现整个NSP和MLM任务并从头训练BERT模型。通常来说，我们既可以通过MLM和NSP这两个任务来从头训练一个BERT模型，当然也可以在开源预训练模型的基础上再次通过MLM和NSP任务来在特定语料中对模型进行微调，以使得整个模型参数更加符合这一场景，并且一般来说更加倾向于第2种做法。&lt;/p&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/3aedea1d3f3e48dd&#34;&gt;10.6节&lt;/a&gt;内容中我们已经就MLM和NSP这两个任务的原理做了详细介绍，所以这里就不再赘述。一言以蔽之，MLM就是随机掩盖掉部分字符让模型来预测，而NSP则是同时输入模型两句话让模型判断后一句话是否真的为前一句话的下一句话，最终通过这两个任务来训练BERT模型中的权重参数。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10121-构建流程与格式化&#34;&gt;10.12.1 构建流程与格式化&lt;a class=&#34;anchor&#34; href=&#34;#10121-%e6%9e%84%e5%bb%ba%e6%b5%81%e7%a8%8b%e4%b8%8e%e6%a0%bc%e5%bc%8f%e5%8c%96&#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;在正式介绍数据预处理之前，我们依旧先通过一张流程图来了解一下整个数据集的构建流程。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/dl/230925194638.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-38 MLM和NSP数据集构建流程图 &lt;/center&gt;&#xA;&lt;p&gt;如图10-38所示便是整个NSP和MLM任务数据集的构建流程。第①②步是根据原始语料来构造NSP任务所需要的输入和标签。第③步则是随机掩盖掉部分字符来构造MLM任务的输入，并同时进行填充处理。第④步则是根据第③步处理后的结果来构造MLM任务的标签值，其中[P]表示填充的含 义，这样做的目的是为了方面在计算损失时直接忽略那些不需要进行预测的位置。在大致清楚了整个数据集的构建流程后，我们下面就可以一步一步来完成数据集的构建。&lt;/p&gt;&#xA;&lt;p&gt;同时，为了能够使得整个数据预处理代码具有通用性，同时支持构造不同场景语料下的训练数据集，因此我们需要为每一类不同的数据源定义一个格式化函数来完成标准化的输入。这样即使是换了不同的语料只需要重写一个针对该数据集的格式化函数即可，其余部分的代码都不需要进行改动。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 英文数据格式化&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;这里首先以英文维基百科数据wiki2 [1]为例来介绍如何得到格式化后的标准数据。如下所示便是wiki2中的原始文本数据的存储形式：&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; The development of [UNK] powder , based on [UNK] &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;or&lt;/span&gt; [UNK] , by the French inventor Paul [UNK] &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1884&lt;/span&gt; was a     further step allowing smaller charges of propellant &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;with&lt;/span&gt; longer barrels &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; The guns of the pre &lt;span style=&#34;color:#666&#34;&gt;@-@&lt;/span&gt; [UNK]         battleships of the &lt;span style=&#34;color:#40a070&#34;&gt;1890&lt;/span&gt;s tended to be smaller &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; calibre&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; The nature of the projectiles also changed during the ironclad period &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; Initially , the best armor &lt;span style=&#34;color:#666&#34;&gt;@-@&lt;/span&gt;           piercing [UNK] was a solid cast &lt;span style=&#34;color:#666&#34;&gt;@-@&lt;/span&gt; iron shot &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; Later , shot of [UNK] iron , a harder iron alloy , gave better   armor &lt;span style=&#34;color:#666&#34;&gt;@-@&lt;/span&gt; piercing qualities &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; Eventually the armor &lt;span style=&#34;color:#666&#34;&gt;@-@&lt;/span&gt; piercing shell was developed &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;在上述示例数据中，每一行都表示一个段落，其由一句话或多句话组成。此时我们需要在目录utils下新建&lt;code&gt;create_pretraining_data.py&lt;/code&gt;模块，然后定义一个函数来对其进行预处理：&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.13 GPT-1模型</title>
				<link>https://mlwithme.github.io/dl/chapter10/e36878dad7a647d8/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/e36878dad7a647d8/</guid>
				<description>&lt;h1 id=&#34;1013-gpt-1模型&#34;&gt;10.13 GPT-1模型&lt;a class=&#34;anchor&#34; href=&#34;#1013-gpt-1%e6%a8%a1%e5%9e%8b&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;经过&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/4987d1044939480d&#34;&gt;10.2节&lt;/a&gt;和&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/3aedea1d3f3e48dd&#34;&gt;10.6节&lt;/a&gt;内容的介绍，我们对基于多头注意力机制的网络模型已经有了深刻的认识。根据&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/3aedea1d3f3e48dd&#34;&gt;10.6节&lt;/a&gt;内容可知，BERT模型本质上只是一个基于Transformer编码器的网络结构，它通过多层多头注意力机制来对输入序列进行编码并完成后续下游任务。这种通过对整个文本序列同时进行编码理解并完成后续下游任务的过程我们称之为自然语言理解。在接下来几节内容中，我们将会介绍另外一种以自然语言生成方式来进行建模的网络模型。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10131-gpt-1动机&#34;&gt;10.13.1 GPT-1动机&lt;a class=&#34;anchor&#34; href=&#34;#10131-gpt-1%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/e0cb9a7aae814045&#34;&gt;第9章&lt;/a&gt;内容开始我们介绍到自然语言处理可以分为自然语言理解和自然语言生成两大部分。对于自然语言理解来说它包括的场景有文本蕴含、问题回答和文本分类等，并且对于这类任务来说它们都有两个共同的地方——特定任务下的网络结构和高质量的标注数据。在传统的判别式模型训练过程中——例如RNN、CNN这类分类模型——标注数据总是一件成本高昂的事情，但与此同时却又存在着海量的非标注数据却无法有效利用。从BERT模型的预训练过程我们知道，如果能通过合理的预训练任务使用无标签数据来训练一个通用的预训练模型，然后分别在每个特定的下游任务中进行有监督微调将会有效改善标注数据不足的问题。&lt;/p&gt;&#xA;&lt;p&gt;基于这样的动机，2018年6月OpenAI团队拉德福德（Radford）[1]等人以Transformer中解码器为基础提出了一种通过自然语言生成方式来进行建模的预训练语言模型（Generative Pretrained Transformer, GPT），而这也是第1代GPT模型，下称GPT-1。GPT-1模型的核心思想在于它首先使用生成式任务在大规模未标记的文本语料上进行预训练，使模型学习到通用的结构、语法、语义等信息；然后在下游任务上通过有监督的方式进行参数微调以实现模型的迁移运用，并且通过特定的输入方式实现了模型结构调整的最小化。这里需要注意的一点是，GPT-1模型的提出时间要早于BERT模型。最后，实验表明GPT-1在12个任务场景中有9个任务的结果超越了传统完全以有监督方式训练的网络模型。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10132-gpt-1结构&#34;&gt;10.13.2 GPT-1结构&lt;a class=&#34;anchor&#34; href=&#34;#10132-gpt-1%e7%bb%93%e6%9e%84&#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;类似于BERT网络模型，GPT-1模型也分为预训练和微调两个部分，不同的地方在于GPT-1模型是以Transformer中的解码器为基础构建得到的标准语言模型，即在模型预训练过程中通过以前$k$个字符来预测第$k+1$个字符的方式来训练模型。具体地，假设给定语料$\mathcal{U}=\{u_1,...,u_n\}$，则模型将最大化如下目标函数&lt;/p&gt;&#xA;$$&#xA;L_1(\mathcal{U})=\sum_{i=k+1}^n\log P(u_i|u_{i-k},u_{i-k+1},...,u_{i-1};\Theta)&#xA;\tag{10-12}&#xA;$$&lt;p&gt;其中$k$表示预训练任务中构建样本时的窗口大小，$\Theta$表示模型参数，这里相加是因为取$\log$后的缘故。&lt;/p&gt;&#xA;&lt;p&gt;同时，整个模型的前向传播计算过程为&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;h_0&amp;=UW_e+W_p\\[1ex]&#xA;h_l&amp;=\text{transformer\_block}(h_{l-1}), \forall\;l\in[1,L]\\[1ex]&#xA;P(u)&amp;=\text{softmax}(h_L,W^T_e)&#xA;\end{aligned}\tag{10-13}&#xA;$$&lt;p&gt;其中$U$为输入文本序列对应的词表索引形状为&lt;code&gt;[src_len, batch_size]&lt;/code&gt;，$W_e$为字符嵌入层对应的权重参数形状为&lt;code&gt;[vocab_size, hidden_size]&lt;/code&gt;，$W_p$为位置编码层对应的权重参数形状为&lt;code&gt;[max_position_embeddings, hidden_size]&lt;/code&gt;，$L$表示解码器的层数，$h_l$为解码器第$l$层的输出结果形状为&lt;code&gt;[tgt_len, batch_size, hidden_size]&lt;/code&gt;，$h_L$为最后一层的输出结果，而$P(u)$则是对应每个时刻预测结果的概率分布。这里需要注意的是此处的位置编码同样是可训练的模型参数，而非原始Transformer中的公式变换。&lt;/p&gt;&#xA;&lt;p&gt;最后，在大规模语料上根据上述过程利用梯度下降算法便可以训练得到对应的预训练模型。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 微调阶段&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在预训练阶段结束以后，我们便可以通过如下过程来针对特定任务场景进行模型参数的微调。现假设某下游任务的输入序列为$x^1,x^2,...,x^m$，对应标签为集合$\mathcal{C}$，则需最大化如下目标函数&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;&amp;P(y|x^1,x^2,...,x^m)=\text{softmax}(h^m_L,W_y)\\[1ex]&#xA;&amp;L_2(\mathcal{C})=\sum_{(x,y)}\log P(y|x^1,x^2,...,x^m)\\[1ex]&#xA;&amp;L_3(\mathcal{C})=L_2(\mathcal{C})+\lambda*L_1(\mathcal{C})&#xA;\end{aligned}\tag{10-14}&#xA;$$&lt;p&gt;&#xA;其中$h^m_L$表示第$L$层最后一个位置的输出结果，$W_y$为最后分类层对应的权重参数，$\lambda$为平衡目标函数$L_1$和$L_2$的一个超参数。之所以这样构造目标函数一是为了提高模型的泛化性，二是为了加速模型的收敛速度。&lt;/p&gt;&#xA;&lt;p&gt;同时，在传统的深度学习模型中对于不同的下游任务场景均需要修改网络结构以满足不同形式的输入。GPT-1为了解决这一问题采用了一种统一的输入形式，即将所有待输入部分以特殊字符进行分割构造成一个序列作为模型的输入，并且整个序列的首尾以&lt;code&gt;&amp;lt;s&amp;gt;&lt;/code&gt;和&lt;code&gt;&amp;lt;e&amp;gt;&lt;/code&gt;进行标识&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;570&#34; src=&#34;https://mlwithme.github.io/images/dl/231027201249.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-41 GPT下游任务输入构造图&lt;/center&gt;&#xA;&lt;p&gt;如图10-41所示为4种常见下游任务场景的输入构建方式。对于文本分类任务来说可以直接取最后一个时刻的生成结果进行分类即可；对于文本蕴含任务来说可以将描述和假设拼接成一个序列，并且两者之间用特殊分隔符标识，然后再将其输入到GPT-1模型中进行特征提取并取最后一个时刻的生成结果进行分类；对于相似性比较任务来说可以分别以不同的顺序将两个序列拼接到一起，且两者中间同样用分隔符标识，然后分别将两者经GPT-1特征提取后的向量按位相加进行分类即可；对于问题选择任务来说分别将上下文与不同的选项构造形成一个序列，并且上下文与选项之间同样以特殊分隔符标识，然后分别通过GPT-1进行特征提取完成分类即可，细节可以参考&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/25d9ef3d9b34472a&#34;&gt;10.10节&lt;/a&gt;内容。可以看出BERT模型中在构造不同下游任务的输入时也参考借鉴了GPT-1的处理方式。&lt;/p&gt;&#xA;&lt;p&gt;同时，对于问题回答和阅读理解这类任务来说，给定上下文$z$，问题$q$以及一系列答案选项$\{a_k\}$，我们只需要将它们拼接在一起中间用特殊分隔符标识，即$[z;q;a_k]$，然后输入到模型中进行分类。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10133-gpt-1实现&#34;&gt;10.13.3 GPT-1实现&lt;a class=&#34;anchor&#34; href=&#34;#10133-gpt-1%e5%ae%9e%e7%8e%b0&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在介绍完GPT-1的相关原理后我们再来看如何借助PyTorch从零实现一个简单版GPT-1模型。从整体上来看GPT-1模型是基于Transformer解码器的多层网络结构，同时由于没有了与编码器交互的部所以此时解码器中将只有一个带掩码的多头注意力机制模块。基于&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/a469ed1a25e1498f&#34;&gt;10.3节&lt;/a&gt;内容中已经实现的多头注意力机制，我们下面先实现GPT-1中的解码器。本节内容完整示例代码可参见&lt;code&gt;Code/Chapter10/C05_ToyGPT&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;a href=&#34;https://mlwithme.github.io/dl/chapter10/d50c490eef3b4565&#34;&gt;10.4节&lt;/a&gt;内容中实现Transformer解码器逻辑一样，此处解码器我们同样通过&lt;code&gt;MyTransformerDecoder&lt;/code&gt;和&lt;code&gt;MyTransformerDecoderLayer&lt;/code&gt;这两个模块来构建。首先，对于&lt;code&gt;MyTransformerDecoderLayer&lt;/code&gt;模块来说其实现过程如下所示：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;MyTransformerDecoderLayer&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;, d_model, nhead, dim_feedforward&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2048&lt;/span&gt;, dropout&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.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;3&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;super&lt;/span&gt;(MyTransformerDecoderLayer, &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;self_attn &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; MyMultiheadAttention(d_model, nhead, 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;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;linear1 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Linear(d_model, dim_feedforward)&#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;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;linear2 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Linear(dim_feedforward, d_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;7&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;norm1 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;LayerNorm(d_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;8&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;norm2 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;LayerNorm(d_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;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;dropout1 &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;10&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;dropout2 &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;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;dropout3 &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;12&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;activation &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;ReLU()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;13&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;14&lt;/span&gt;     &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, tgt_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;, 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;15&lt;/span&gt;         tgt2 &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;self_attn(tgt, tgt, tgt, attn_mask&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;tgt_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;16&lt;/span&gt;                               key_padding_mask&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;key_padding_mask)[&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;17&lt;/span&gt;         tgt &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;norm1(tgt &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;dropout1(tgt2))&#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;         tgt2 &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;activation(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;linear1(tgt)) &#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;         tgt2 &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;linear2(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;dropout2(tgt2))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;20&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;norm2(tgt &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;dropout3(tgt2))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;subscribe&gt;51&lt;/subscribe&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.14 GPT-2与GPT-3模型</title>
				<link>https://mlwithme.github.io/dl/chapter10/94dda9bbbc994913/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/94dda9bbbc994913/</guid>
				<description>&lt;h1 id=&#34;1014-gpt-2与gpt-3模型&#34;&gt;10.14 GPT-2与GPT-3模型&lt;a class=&#34;anchor&#34; href=&#34;#1014-gpt-2%e4%b8%8egpt-3%e6%a8%a1%e5%9e%8b&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/e36878dad7a647d8&#34;&gt;10.13节&lt;/a&gt;内容中我们详细介绍了GPT-1模型的相关原理。尽管它是基于Transformer中解码器来进行构建的，但是从整个模型的构建流程来看GPT-1似乎仍旧将它当做是“编码器”在使用，并没有用到解码独有的序列生成能力。在本节内容中，我们将从另外一个视角来介绍GPT-1的迭代版本GPT-2模型。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10141-gpt-2动机&#34;&gt;10.14.1 GPT-2动机&lt;a class=&#34;anchor&#34; href=&#34;#10141-gpt-2%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;传统的自然语言模型在面对不同的任务场景时总是需要重新设计网络结构，例如问题回答、机器翻译等。尽管在GPT-1中基于预训练模型的微调方法已经极大限度上减少了对网络结构的修改，但是在不同的下游任务中依旧需要在原有网络的基础上再加入一个线性层。因此，在引入了新的模型参数后还要通过少量标注数据来训练这部分模型参数。&lt;/p&gt;&#xA;&lt;p&gt;基于这样的动机，2019年2月OpenAI团队在GPT-1模型的基础之上提出了GPT-2模型[1] [2]。GPT-2模型最大的一个改进点就是没有再针对每个下游任务进行有监督微调，而是使用同一个预训练语言模型依靠它自身学习到的生成能力来完成不同的下游任务。从一定程度上看，这也标志着自然语言处理领域中一个新流派的出现。尽管最后GPP-2在各项下游任务中的表现还远不如现有的有监督模型，但是OpenAI研究发现随着模型规模的扩大其表现结果有还有明显的增长趋势，而这也为后续的GPT-3埋下了伏笔。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10142-gpt-2结构&#34;&gt;10.14.2 GPT-2结构&lt;a class=&#34;anchor&#34; href=&#34;#10142-gpt-2%e7%bb%93%e6%9e%84&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;从整体上看GPT-2模型依旧延续了GPT-1中的网络结构，仅仅只是对各个模块间的归一化形式和残差连接层里的权重参数缩放进行了修改，同时上下文窗口也从512增加到了1024的长度。GPT-2的训练方法也同GPT-1一样，都是通过以给定前$k$个词来预测第$k+1$个词的形式来进行建模求解得到权重参数。尽管这一目标函数看似简单，但由于训练数据集的多样性——它天然地包含有不同领域、不同场景下的语义环境——使得训练得到的模型在生成能力上同样具有这样的多样性。&lt;/p&gt;&#xA;&lt;p&gt;在GPT-2中，模型的改进主要体现在模型规模和训练数据质与量的扩大上。一方面，为了提高模型的生成能力以适应不同的下游任务，GPT-2设计了4种规格的模型结构，其中具有48个解码层的模型更是拥有超过15亿参数，是GPT-1的10倍。&lt;/p&gt;&#xA;&lt;center&gt;表10-1 GPT-2模型参数规模（原始论文中作者参数量计算有误，已在[2]中进行了修正）&lt;/center&gt;&lt;div align=center&gt;&lt;img width=&#34;300&#34; src=&#34;https://mlwithme.github.io/images/dl/231107205722.jpg&#34;/&gt; &lt;/div&gt;&#xA;&lt;p&gt;注：M表示百万&lt;/p&gt;&#xA;&lt;p&gt;如表10-1所示是GPT-2中4种不同规格模型的配置情况，其中最小的12层用于从模型规模上同GPT-1进行对比，而最大的48层则是用来探索模型的生成能力。&lt;/p&gt;&#xA;&lt;p&gt;另一方面，为了能够训练得到更大规模的GPT-2模型，其对应的数据集也相应扩大了近10倍。在训练GPT-1中所使用到的数据集是包含有超过7000本未出版的电子书籍BookCorpus数据集，总大小接近5G。在GPT-2的训练过程中为了使得生成内容更加准确和多样，模型使用了来自Reddit中的4500万个经过人工筛选过的网页文本，经去重和清理后构建得到了一个近800万篇文档总共近40G的高质量数据集WebText。&lt;/p&gt;&#xA;&lt;p&gt;在GPT-2的工作中之所以如此重视训练数据的质量是因为作者认为，高质量数据集内部本身就可能存在各个任务场景下的自然语言描述，因此如果将这些数据用于训练最终得到的模型便同样能够生成类似的文本内容。&lt;/p&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;In a now-deleted post from Aug. 16, Soheil Eid, Tory candidate in the riding of Joliette, wrote in French: ”&lt;strong&gt;Mentez mentez, il en restera toujours quelque chose&lt;/strong&gt;,” which translates as,”&lt;strong&gt;Lie lie and something will always remain.&lt;/strong&gt;”&lt;/p&gt;&#xA;&lt;p&gt;If listened carefully at 29:55, a conversation can be heard between two guys in French: “-&lt;strong&gt;Comment on fait pour aller de l’autre cote&lt;/strong&gt; ́? -Quel autre cote ́?”, which means “- &lt;strong&gt;How do you get to the other side? - What side?&lt;/strong&gt;”.&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.15 基于GPT-2的中文预训练模型</title>
				<link>https://mlwithme.github.io/dl/chapter10/4af57a29308840de/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/4af57a29308840de/</guid>
				<description>&lt;h1 id=&#34;1015-基于gpt-2的中文预训练模型&#34;&gt;10.15 基于GPT-2的中文预训练模型&lt;a class=&#34;anchor&#34; href=&#34;#1015-%e5%9f%ba%e4%ba%8egpt-2%e7%9a%84%e4%b8%ad%e6%96%87%e9%a2%84%e8%ae%ad%e7%bb%83%e6%a8%a1%e5%9e%8b&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面几节内容中我们陆续介绍了GPT-1到GPT-3的原理和动机，从网络结构上来看三者并没有本质上的差异，都是以Transformer中解码器为基础构建而来。在本节内容中，我们将以一个开源的中文GPT-2中文预训练模型为例，来详细介绍GPT-2模型的训练和推理过程，并训练完成自己的GPT-2模型。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10151-项目介绍&#34;&gt;10.15.1 项目介绍&lt;a class=&#34;anchor&#34; href=&#34;#10151-%e9%a1%b9%e7%9b%ae%e4%bb%8b%e7%bb%8d&#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;在本节内容中我们使用到的是一个用GPT-2为网络结构的开源中文预训练语言模型GPT2-Chinese [1]。基于不同的训练语料，该项目中也包含了不同的预训练模型。例如使用130MB的名家散文、情感散文和散文诗歌所训练得到的散文模型；使用180MB约80万首古诗词训练得到的诗词模型；使用40MB约70万条对联训练得到的对联模型；通过CLUECorpusSmall语料训练得到的通用中文模型；以及本节内容将会示例的使用1.8GB约300万篇文言文训练得到的文言文模型。&lt;/p&gt;&#xA;&lt;p&gt;如下所示便是根据项目中文言文模型以“先帝创业未半而中道崩殂”为开始所生成的示例内容：&lt;/p&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;[CLS] 先帝创业未半而中道崩殂， 故其子孙不能保守社稷，遂为奸臣所误。此事之大，人皆知之。然不知当日之事，果系何人？若果系奸臣所误，亦当据实具奏，以为国家除害。不然，此后奸人必复有所借口，亦不可不防之于早也。至于奸人之所借口，亦不可不防。今既不可得见，而奸臣所指之事，又不可不察。盖奸臣之为人，有如是之大者，而其所托名，则又有如是之重者，故必须详审，乃可得其要领，使其人不敢为奸臣所误，而其子孙不至费绝也。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&lt;p&gt;从上述内容的意思可以看出，GPT-2以为“先帝中道崩殂”是糟奸人所害，所以后续通篇内容都在讨论这件事情。但是总体来说生成的内容似模似样，足以以假乱真。&lt;/p&gt;&#xA;&lt;p&gt;对于上面所提及的各个预训练模型我们都可以在该项目的主页获得相应下载地址，然后直接进行使用。不过遗憾的是大部分预训练模型所使用到的语料并没有公开，因此在后续内容中我们将使用其它公开语料来训练我们自己的GPT-2预训练模型。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 环境安装&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在GitHub主页上该项目一共有两个分支，我们需要选择master主分支进行使用。同时，建议各位读者使用本书所维护的克隆版本[2]，差别在于我们对其中的各行代码进行了详细注释和说明，并且提供了更加完整的环境依赖列表。&lt;/p&gt;&#xA;&lt;p&gt;在完成项目的克隆以后，我们可以看到有若干个文件夹，但是我们这里基本上都不会用到，因为都是一些数据或配置存放目录可以自定义指定。这里主要会使用到两个模块：定义数据预处理、网络结构和训练过程的&lt;code&gt;train.py&lt;/code&gt;模块；定义模型推理和筛选过程的&lt;code&gt;generate.py&lt;/code&gt;模块。首先，我们根据&lt;a href=&#34;https://mlwithme.github.io/dl/chapter02/04f07b9246984577&#34;&gt;2.2.3节&lt;/a&gt;内容所介绍的步骤，根据项目中所提供的&lt;code&gt;requirements.txt&lt;/code&gt;（包含有48个依赖包）文件完成Python环境的安装。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10152-生成结果筛选&#34;&gt;10.15.2 生成结果筛选&lt;a class=&#34;anchor&#34; href=&#34;#10152-%e7%94%9f%e6%88%90%e7%bb%93%e6%9e%9c%e7%ad%9b%e9%80%89&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在正式使用预训练模型进行内容生成之前，我们先来介绍如何根据模型预测的logits值来筛选得到对应的预测结果，这与我们&lt;a href=&#34;https://mlwithme.github.io/dl/chapter09/fefa60e0bc854a17&#34;&gt;9.9节&lt;/a&gt;介绍的内容有些许差异，可以看做是升级版考虑得更加细致。当然，这也是大语言模型中一种比较通用的做法。各位读者也可以暂时跳过这部分内容的相关原理介绍，直接阅读10.15.3节内容使用对应的预训练模型。&lt;/p&gt;&#xA;&lt;p&gt;如图10-44所示便是生成结果筛选的原理示意图。筛选结果筛选结果的整体思路为：①根据预测得到的logits取前Top_k为候选结果，并将剩余部分置为负无穷大。②首先将候选logits进行排序并得排序后的结果sorted_logits和其对应的索引序号sorted_indeces；然后对排序后的结果进行归一化并计算累积概率，再将大于Top_p的位置标记为T（表示后续需要忽略），同时为了避免Top_p设置过小导致所有结果都被忽略所以需要将sorted_indx_to_remove中的结果整体向后移动一位并将第1个位置直接置为F（表示一定会有一个筛选结果剩下）；最后，根据sorted_indx_to_remove和sorted_indeces可知需要将logits中过滤掉的索引序号为3、0、4和5，这样便得到了经过两次筛序后的logits。③将得到的logits根据采样策略得到预测值。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;350&#34; src=&#34;https://mlwithme.github.io/images/dl/231119160048.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-44 结果筛选原理图&lt;/center&gt;&#xA;&lt;p&gt;现在，假设模型已经预测得到了当前时刻的logits输出结果，且形状为&lt;code&gt;[vocab_size,]&lt;/code&gt;，则图10-44过程可通过如下代码进行实现：&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;top_k_top_p_filtering&lt;/span&gt;(logits, top_k&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;, top_p&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.0&lt;/span&gt;, filter_value&lt;span style=&#34;color:#666&#34;&gt;=-&lt;/span&gt;&lt;span style=&#34;color:#007020&#34;&gt;float&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;Inf&amp;#34;&lt;/span&gt;)):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;     top_k &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;min&lt;/span&gt;(top_k, logits&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;size(&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;3&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; top_k &lt;span style=&#34;color:#666&#34;&gt;&amp;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;         indices_to_remove &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; logits &lt;span style=&#34;color:#666&#34;&gt;&amp;lt;&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;topk(logits, top_k)[&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:#666&#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;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;5&lt;/span&gt;         logits[indices_to_remove] &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; filter_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;6&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; top_p &lt;span style=&#34;color:#666&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0.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;7&lt;/span&gt;         sorted_logits, sorted_indices &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;sort(logits, descending&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;8&lt;/span&gt;         cumulative_probs &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;cumsum(F&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;softmax(sorted_logits, dim&lt;span style=&#34;color:#666&#34;&gt;=-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;), 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;9&lt;/span&gt;         sorted_indices_to_remove &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; cumulative_probs &lt;span style=&#34;color:#666&#34;&gt;&amp;gt;&lt;/span&gt; top_p&#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;         sorted_indices_to_remove[&lt;span style=&#34;color:#666&#34;&gt;...&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;:] &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; sorted_indices_to_remove[&lt;span style=&#34;color:#666&#34;&gt;...&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;]&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;clone()&#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;         sorted_indices_to_remove[&lt;span style=&#34;color:#666&#34;&gt;...&lt;/span&gt;, &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;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;12&lt;/span&gt;         indices_to_remove &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; sorted_indices[sorted_indices_to_remove] &#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;         logits[indices_to_remove] &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; filter_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; logits&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第2行是检查&lt;code&gt;top_k&lt;/code&gt;取值是否超过了序列长度，是则直接取序列长度。第3~5行便是图10-44中第①步处理后的结果。第6~13行则是图10-44中第②步中的处理过程，其中第7行表示对原始&lt;code&gt;logits&lt;/code&gt;进行排序并得到排序后的结果以及在原始&lt;code&gt;logits&lt;/code&gt;中的索引。第8~9行是对排序后的&lt;code&gt;sorted_logits&lt;/code&gt;进行归一化处理并计算累积概率，同时得到大于&lt;code&gt;top_p&lt;/code&gt;的位置标记。第10~11行是为了避免当&lt;code&gt;top_p&lt;/code&gt;设置过小导致所有结果都被忽略所考虑的情况。第12~13行是根据&lt;code&gt;indices_to_remove&lt;/code&gt;将&lt;code&gt;logits&lt;/code&gt;中满足条件的值忽略，设置为负无穷大。从这里可以看出，通过调整阈值&lt;code&gt;top_p&lt;/code&gt;可以在不同的生成效果之间找到平衡，较小的阈值将导致模型生成更加集中和确定性的文本，而较大的阈值将产生更加多样和随机的文本。&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.16 InstructGPT与ChatGPT</title>
				<link>https://mlwithme.github.io/dl/chapter10/9f5c00cadde14d31/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/9f5c00cadde14d31/</guid>
				<description>&lt;h1 id=&#34;1016-instructgpt与chatgpt&#34;&gt;10.16 InstructGPT与ChatGPT&lt;a class=&#34;anchor&#34; href=&#34;#1016-instructgpt%e4%b8%8echatgpt&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面几节内容中我们陆续介绍了GPT-1到GPT-3这3个模型的思想和原理。尽管随着模型规模的变大模型的效果也在稳步增长，但是却一直面临着一个重大的问题，那就是模型生成内容的安全性。在接下来的这节内容中我们将会分别介绍一种基于用户指令和对话内容微调而来的GPT模型。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10161-instructgpt动机&#34;&gt;10.16.1 InstructGPT动机&lt;a class=&#34;anchor&#34; href=&#34;#10161-instructgpt%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;由语言模型本身的建模方式可知，它的目标函数是通过前$k$个词来预测第$k+1$个词，而这也就决定了它难以根据用户输入的指令来生成对应有用的内容，因为两者的目标函数显然并不相同。简单来说就是模型知道得很多，但并不能理解用户的真实意图。例如用户输入提示“地球到底是圆的还是平的”，那么模型生成的结果可能是：&lt;/p&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;结果1： 地球到底是圆的还是平的 &lt;strong&gt;，结果很近热：“大约三分之一受访者认为不确定，好在大部分人认为地球是圆的……&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;结果2： 地球到底是圆的还是方的 &lt;strong&gt;。其实，迄今为止，地球上生活的人仍然有人相信地球是方的。在这里，我不讨论的地……&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&lt;p&gt;为什么会出现这样的结果呢？那是因为这样的描述确存在于训练语料中，所以当用户输入“地球到底是圆的还是平的”这个提示时模型并不能理解其背后真实的意图，也就是不知道用户希望得到哪个回答。因此，我们需要将模型的输出和用户的真实意图进行对齐（Alignment）。&lt;/p&gt;&#xA;&lt;p&gt;同时，随着模型生成能力的增强，对于生成内容的安全性和无害性也需要进行加强。基于这样的动机，2022年3月OpenAI团队在GPT-3模型的基础上加入人类反馈强化学习微调得到了InstructGPT模型[1]。从名字也可以看出，它的核心目的就是为了让模型能够理解用户所输入的指令。&lt;/p&gt;&#xA;&lt;p&gt;例如对于指令“Explain the moon landing to a 6 year old in a few sentences.”来说，GPT-3和InstructGPT将会分别生成如下结果：&lt;/p&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;GPT-3:&lt;/p&gt;&#xA;&lt;p&gt;Explain the theory of gravity to a 6 year old.&lt;/p&gt;&#xA;&lt;p&gt;Explain the theory of relativity to a 6 year old in a few sentences.&lt;/p&gt;&#xA;&lt;p&gt;Explain the big bang theory to a 6 year old.&lt;/p&gt;&#xA;&lt;p&gt;Explain evolution to a 6 year old.&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.17 ChatGPT与提示词工程</title>
				<link>https://mlwithme.github.io/dl/chapter10/050b54fd34ca480a/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/050b54fd34ca480a/</guid>
				<description>&lt;h1 id=&#34;1017-chatgpt与提示词工程&#34;&gt;10.17 ChatGPT与提示词工程&lt;a class=&#34;anchor&#34; href=&#34;#1017-chatgpt%e4%b8%8e%e6%8f%90%e7%a4%ba%e8%af%8d%e5%b7%a5%e7%a8%8b&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;经过&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/9f5c00cadde14d31&#34;&gt;10.16节&lt;/a&gt;内容的介绍，我们已经清楚了ChatGPT的基本原理与核心能力，即能够以对话的形式来与用户进行交互，并基于先前的上下文生成连贯的回复。通过大规模的预训练和微调能够理解并生成自然语言文本，这种能力使得ChatGPT在多种应用场景中都能发挥作用，包括但不限于智能助手、编程帮助、创意文本生成等。在本节内容中，我们将详细介绍ChatGPT的使用方式和技巧，并将其用作我们的实际生产力工具。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10171-提示词工程&#34;&gt;10.17.1 提示词工程&lt;a class=&#34;anchor&#34; href=&#34;#10171-%e6%8f%90%e7%a4%ba%e8%af%8d%e5%b7%a5%e7%a8%8b&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;随着ChatGPT的出现以及它所展现出的惊人能力，如何能ChatGPT让生成高质量的回答便成为了所有ChatGPT使用者所共同关注的一个问题。随着研究的进一步加深，研究员们发现能够让ChatGPT产生高质量的、满足用户真实需求的内容的前提就是输入高质量的提示。因为经过大规模预训练和微调后的ChatGPT已经具备了海量的知识内容，而我们要做的就是通过一种恰到的方式从中提取出我们预期的结构化内容。甚至有人曾经调侃，如果ChatGPT生成的结果不正确，那一定是你的提示出了问题。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;330&#34; src=&#34;https://mlwithme.github.io/images/dl/231201085754.jpeg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-53 知识的海洋（由DALL.E3创作）&lt;/center&gt;&#xA;&lt;p&gt;在ChatGPT中，提示词（Prompt）是用户提供给模型的输入文本或问题，旨在以清晰简洁的语言向ChatGPT描述你的问题以生成满足用户预期的结果。在对话式场景中，提示词通常充当启动对话并引导模型生成响应的媒介。有效的提示词对于实现模型输出的准确性和合理性至关重要，因为它们在很大程度上影响模型对用户意图和上下文的理解。因此，良好的提示词能够有效指导模型生成相关、有意义且流畅的回应，同时有助于避免歧义，确保模型能够准确解读用户的问题或请求。所以使用清晰而详细的提示词是与ChatGPT进行有效交互的关键策略，用户通过提供明确的信息和上下文，能够引导模型生成更符合其期望的回答，使其在各种应用场景中更为灵活和强大。&lt;/p&gt;&#xA;&lt;p&gt;首先，我们先使用一个简单的提示词来让ChatGPT生成一篇关于人工智能的科普文章：&lt;/p&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;&lt;strong&gt;User:&lt;/strong&gt; 生成一个科普文章。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;ChatGPT:&lt;/strong&gt;  当我们深入探索人工智能的世界时，ChatGPT（Generative Pre-trained Transformer）涌现为一颗耀眼的明星。ChatGPT是由OpenAI公司推出的大型语言模型，它在自然语言处理领域取得了巨大的成功。本文将为您揭开ChatGPT的神秘面纱，带您了解它的工作原理和影响。&lt;/p&gt;&#xA;&lt;p&gt;首先，ChatGPT的基础是Transformer架构，这是一种创新的深度学习结构，广泛应用于各种自然语言处理任务。该架构采用自注意力机制，使得模型能够更好地理解上下文关系，从而更准确地生成语言。&lt;/p&gt;&#xA;&lt;p&gt;ChatGPT之所以如此强大，得益于其在大规模文本数据上进行的预训练。在这个阶段，模型通过海量的语料库学习语言的模式、结构和语境，使得它在后续任务中具备了出色的表现。这种预训练使得ChatGPT成为一个通用的语言生成工具，可用于回答问题、创作文本，甚至与用户进行自然对话。&lt;/p&gt;&#xA;&lt;p&gt;ChatGPT在生成文本时采用了生成式的方法，这意味着它可以创造性地生成全新的内容。用户只需提供简短的提示，ChatGPT就能够根据上下文和语境生成连贯、有逻辑的回应。这种交互方式让人感觉仿佛在与一个理解力强大的虚拟伙伴对话。&lt;/p&gt;&#xA;&lt;p&gt;然而，尽管ChatGPT在语言生成上取得了显著的进展，但它也面临一些挑战。有时候，模型可能生成不准确或模糊的回答，尤其是在处理复杂或专业性领域的问题时。此外，ChatGPT也可能受到数据偏见的影响，导致生成结果带有一定的倾向性。&lt;/p&gt;&#xA;&lt;p&gt;总体而言，ChatGPT的出现标志着自然语言处理领域的一次飞跃。它为我们提供了一个强大的工具，可以应用于多个领域，从解答问题到辅助创作，展现了人工智能技术在语言理解和生成方面的巨大潜力。在ChatGPT的引领下，我们或许能够更深入地探索语言的奥秘，为人工智能的未来铺平道路。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&lt;p&gt;紧接着，我们再来使用一个稍微精确一点的提示词来让ChatGPT生成一个同样主题的科普文章：&lt;/p&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;&lt;strong&gt;User:&lt;/strong&gt; 你是一名科学杂志编辑，请为最新一期的专题文章创作一篇关于人工智能的科普文章。请涵盖人工智能的基本原理、当前应用领域以及未来发展趋势。确保文章通俗易懂，适合广大读者群体。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;ChatGPT:&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;探索未来科技：人工智能的奇妙世界&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;人工智能（AI）正迅速改变着我们生活的方方面面，从日常工作到娱乐活动。本文将带您深入了解人工智能的基本原理、当前应用领域以及未来发展趋势，让您对这一科技奇迹有更全面的认识。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;基本原理：深度学习的魔法&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;人工智能的核心是深度学习，一种模仿人脑神经网络的技术。这种网络由神经元和层组成，通过学习大量数据来识别模式、理解语言，甚至进行创造性的文本生成。深度学习的魔法在于它让机器能够模拟人类的思维过程，使得机器能够逐渐变得更加聪明和智能。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;当前应用领域：AI改变我们的生活&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;AI已经深入到我们日常生活的方方面面。在医疗领域，它可以帮助医生更快速准确地诊断疾病；在交通领域，自动驾驶技术正在逐步改变着我们的出行方式；在金融领域，智能算法正在提升风险管理和投资决策的效率。此外，AI还在艺术、娱乐等领域展现了独特的创造力，例如生成艺术品和音乐。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;未来发展趋势：AI的辉煌前景&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;随着技术的不断发展，AI的未来看起来更加辉煌。首先，AI将更好地理解自然语言，实现更自然、流畅的人机交互。其次，AI将更广泛地应用于教育领域，为学生提供个性化的学习体验。最重要的是，AI将在医学研究、环境保护和社会问题解决方面发挥更大的作用，为人类创造更美好的未来。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;结语：融入AI的未来&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;人工智能已经不再是遥不可及的未来科技，而是融入我们生活的现实力量。我们要有信心迎接这个变革，同时保持对技术的审慎态度。正是在我们共同的努力下，AI将继续为我们打开科技的新大门，带来更多的惊喜和便利。让我们共同探索这个人工智能的奇妙世界，迎接未来的挑战和机遇。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&lt;p&gt;可以看出，虽然在两个示例中ChatGPT都根据问题生成了对应内容，但是对于第一个示例来说它生成有关于ChatGPT的内容是随机的，因为我们没有告诉它相应的主题。同时，对于整个内容而言也没有看出任何段落之间的逻辑关系。但是反观第二个示例，我们通过提示词明确告诉了ChatGPT应该生成什么样的内容以及它所面向的群体，因此最终生成的内容不管是从逻辑性还是可读性来讲都比第一个更好。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10172-提示词的构成&#34;&gt;10.17.2 提示词的构成&lt;a class=&#34;anchor&#34; href=&#34;#10172-%e6%8f%90%e7%a4%ba%e8%af%8d%e7%9a%84%e6%9e%84%e6%88%90&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;通常来说，在使用ChatGPT时提示词可以通过指令、上下文、输入数据和输出格式这4部分来组成，当然也可以是其中的一部分。具体地：&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;指令：&lt;/strong&gt; 想要模型执行的特定任务或指令，例如生成、翻译、解释、抽取或总结等；&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;上下文：&lt;/strong&gt; 包含外部信息或额外的上下文信息以引导语言模型更好地响应，例如生成内容的面向群体、需要ChatGPT扮演的角色信息等；&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;输入数据：&lt;/strong&gt; 用户输入的内容或问题；&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;输出格式：&lt;/strong&gt; 指定输出的类型或格式。&lt;/p&gt;&#xA;&lt;p&gt;在使用提示词的过程中，输入信息越详细、越精准那么ChatGPT生成的内容同样也会更准确以及更贴合用户的预期。&lt;/p&gt;&#xA;&lt;p&gt;例如：请你解释一下什么是登月，需要注意的是生成结果的面向对象是一个6岁的儿童，并将输出结果以json的格式给出，key为名词，value为该名词对应的解释。&lt;/p&gt;&#xA;&lt;p&gt;在上述提示中，指令为“解释”，输入数据为“什么是登月”，上下文为“生成结果的面向对象是一个6岁的儿童”，输出格式为“以json的格式给出，key为名词，value为该名词对应的解释”。最后，将该提示词输入到ChatGPT中我们将会得到类似如下结果：&lt;/p&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;{&amp;ldquo;登月&amp;rdquo;: &amp;ldquo;登月是一种很棒的冒险，就像坐上宇宙飞船一样，飞到月球上去。在那里，宇航员可以穿上宇航服，走在月球上，看到漂亮的星星和大地球。他们还可以做一些有趣的实验，就像在月球上变成科学家一样。登月就是为了更好地了解月球和宇宙，就像探险一样，发现新奇的事物！&amp;rdquo;}&lt;/p&gt;&#xA;&lt;/blockquote&gt;&lt;p&gt;相反，如果我们直接问“什么是登月？”，那么我们将会得到另外一个具有一定知识储备的人才能看懂的答案，如下所示：&lt;/p&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;登月是指人类使用特殊的飞行器，如宇宙飞船，飞往月球进行探险的过程。宇航员通过宇宙飞船抵达月球表面，可以在月球上行走、探索，并执行科学实验。这个过程旨在增进我们对宇宙和地球之外的空间的认识，推动科学研究和探险活动。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&lt;h2 id=&#34;10173-简单提示词&#34;&gt;10.17.3 简单提示词&lt;a class=&#34;anchor&#34; href=&#34;#10173-%e7%ae%80%e5%8d%95%e6%8f%90%e7%a4%ba%e8%af%8d&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;下面，我们分别就代码生成、文本生成、文本翻译、文本分类和关系抽取等几种常见的简单指令进行介绍，以便各位读者对于ChatGPT的使用能有一个基本的认识。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 代码生成&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;对于代码生成来说，我们可以让ChatGPT根据一段功能性的描述来生成对应的代码内容。&lt;/p&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;&lt;strong&gt;User:&lt;/strong&gt; 请给出基于PyTorch框架LeNet网络模型的实现过程&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;: 当然可以！LeNet是一个经典的卷积神经网络（CNN）模型，适用于手写数字识别等任务。以下是一个简单的基于PyTorch框架的LeNet实现：&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.18 百川大模型使用</title>
				<link>https://mlwithme.github.io/dl/chapter10/a90b0d71389b4d69/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/a90b0d71389b4d69/</guid>
				<description>&lt;h1 id=&#34;1018-百川大模型使用&#34;&gt;10.18 百川大模型使用&lt;a class=&#34;anchor&#34; href=&#34;#1018-%e7%99%be%e5%b7%9d%e5%a4%a7%e6%a8%a1%e5%9e%8b%e4%bd%bf%e7%94%a8&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面几节内容中，我们陆续介绍了GPT系列模的技术原理和使用方法，对于GPT相关模型整体上也有了一定的了解。在本节内容中，我们将以百川大模型为例，先来详细介绍其使用具体使用方法，然后在下一节内容中具体介绍其内部的构建原理。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10181-模型简介&#34;&gt;10.18.1 模型简介&lt;a class=&#34;anchor&#34; href=&#34;#10181-%e6%a8%a1%e5%9e%8b%e7%ae%80%e4%bb%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;百川大模型是由前搜狗公司CEO王小川于2023年4月创立的百川智能所发布的开源可商用的大规模预训练语言模型（ Large Language Model, LLM）。截止到2023年12月，百川智能基于Transformer解码器结构已经陆续发布了Baichuan和Baichuan 2两款大模型，本文将要介绍的便是以Baichuan2大模型为基座的聊天模型[1]。&lt;/p&gt;&#xA;&lt;p&gt;Baichuan2是百川智能推出的新一代开源大语言模型，采用了2.6万亿词元的高质量语料训练 [2]。根据模型的参数规模来看Baichuan2有Baichuan2-7B-Base和Baichuan2-13B-Base这两个基座模型，前者的隐藏层个数和多头个数均为32、隐藏层维度为4096整体相当于表10-2中GPT-3 6.7B的规模，后者的隐藏层个数和多头个数均为40、隐藏层维度为5120整体相当于表10-2中GPT-3 13B的规模。除此以外，百川智能基于这两个基座模型还分别微调得到一个聊天模型，即Baichuan2-7B-Chat和Baichuan2-13B-Chat这两个模型。为了便于加载以及下载预训练模型，后续我们将以Baichuan2-7B-Chat这个模型为例来进行介绍。同时，百川智能还提供了这两个聊天模型对应的4bits量化（Quantize）版本。所谓模型量化是一种用于减少模型大小和提高模型计算速度的技术，它通过将浮点计算转换为低比特（如4bits和8bits）定点计算的方式来降低模型的参数量、计算量和内存消耗，但这种方法也会给模型带来一定的精度损失。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 在线使用&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;如同使用ChatGPT一样，通过百川智能提供的在线服务[3]我们便能够直接使用到百川大模型。相比于ChatGPT，百川智能推出的对话服务还支持在线联网搜索内容，我们可以直接向它提问某个链接里的相关内容。同时，它还能使用到ChatGPT中付费用户才能使用的文件上传功能。下面我们展示几个简单的使用示例。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/dl/231224101454.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-59 百川大模型在线服务（一）&lt;/center&gt;&#xA;&lt;p&gt;如图10-59所示是聊天服务中示例的相关用法。这里我们同样以“请你解释一下什么是登月，需要注意的是生成结果的面向对象是一个6岁的儿童。” 这个问题来测试百川大模型的理解能力。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/dl/231224102406.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-60 百川大模型在线服务（二）&lt;/center&gt;&#xA;&lt;p&gt;如图10-60所示便是百川大模型的生成结果，各位读者可以将其与&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/050b54fd34ca480a&#34;&gt;10.17.2节&lt;/a&gt;中ChatGPT的生成结果对比。进一步，可以针对本地上传的附件使用百川大模型进行分析。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/dl/231224113757.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-61 百川大模型在线服务（三） &lt;/center&gt;&#xA;&lt;p&gt;在图10-61所示的结果便是百川大模型根据上传的PDF总结的内容，同时，我们还可以针对PDF中的内容继续进行提问交&lt;/p&gt;&#xA;&lt;h2 id=&#34;10182-项目介绍&#34;&gt;10.18.2 项目介绍&lt;a class=&#34;anchor&#34; href=&#34;#10182-%e9%a1%b9%e7%9b%ae%e4%bb%8b%e7%bb%8d&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;为了便于学习这个项目的代码，所以我们需要在Huggingface[2]下载整个工程对应的代码文件，并且在使用时需要直接导入对应的模块而不是通过类似&lt;code&gt;AutoModelForCausalLM()&lt;/code&gt;这样的方式来通过模型名称自动下载并加载模型。这里建议各位读者直接使用本书所维护工程下的项目代码[4]，详见&lt;code&gt;Code/Chapter10/C07_BaiChuan2/Baichuan2_7B_Chat&lt;/code&gt;目录。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1.工程结构&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在下载完成后该目录下一共会有11个文件，这里逐一简单介绍一下。&lt;code&gt;config.json&lt;/code&gt;是记录整个模型超参数的配置文件，例如多头数量、隐藏层数量等；&lt;code&gt;tokenizer_config.json&lt;/code&gt;是记录词元切分器的相关配置参数；&lt;code&gt;special_tokens_map.json&lt;/code&gt;是记录特殊词元的相关信息；&lt;code&gt;generation_config.json&lt;/code&gt;是记录推理时模型的相关超参数，例如&lt;code&gt;temperature&lt;/code&gt;、&lt;code&gt;top_k&lt;/code&gt;和&lt;code&gt;top_p&lt;/code&gt;等；&lt;code&gt;tokenizer.model&lt;/code&gt;是一个实例化的模型文件，保存的是原始语料对应的词表；&lt;code&gt;tokenization_baichuan.py&lt;/code&gt;是百川大模型对应词元切分器&lt;code&gt;BaichuanTokenizer&lt;/code&gt;的实现模块；&lt;code&gt;configuration_baichuan.py&lt;/code&gt;是百川大模型对应配置类&lt;code&gt;BaichuanConfig&lt;/code&gt;的实现模块；&lt;code&gt;modeling_baichuan.py&lt;/code&gt;是百川大模型&lt;code&gt;BaichuanModel&lt;/code&gt;相关的实现模块；&lt;code&gt;generation_utils.py&lt;/code&gt;是模型推理时对输入进行预处理的相关功能模块；&lt;code&gt;quantizer.py&lt;/code&gt;是对模型参数进行4bits或8bits量化的功能模块；&lt;code&gt;pytorch_model.bin&lt;/code&gt;则是对应的预训练模型。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 环境安装&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;由于Baichuan2使用到了Pytocrch 2.0版本中的新特性，即一种高效计算多头注意力的模块，所以这里我们这里需要使用2.0版本以上的Pytorch框架。首先，我们根据&lt;a href=&#34;https://mlwithme.github.io/dl/chapter02/04f07b9246984577&#34;&gt;2.2节&lt;/a&gt;内容所介绍的步骤，通过项目中所提供的&lt;code&gt;requirements.txt&lt;/code&gt;（包含有78个依赖包）文件完成Python环境的安装。同时，需要将下载好的预训练模型&lt;code&gt;pytorch_model.bin&lt;/code&gt;（大约15GB）放到工程下的&lt;code&gt;Baichuan2_7B_Chat&lt;/code&gt;目录中。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10183-模型结构&#34;&gt;10.18.3 模型结构&lt;a class=&#34;anchor&#34; href=&#34;#10183-%e6%a8%a1%e5%9e%8b%e7%bb%93%e6%9e%84&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;从整体上来百川大模型也是基于Transformer解码器架构的大语言模型，只是对其中各个小的模块进行了优化和改进，这里我们进行一个简单的介绍。如图10-62所示便是Baichuan2模型对应的网络结构图。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;300&#34; src=&#34;https://mlwithme.github.io/images/dl/231226195049.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-62 百川大模型结构图&lt;/center&gt;&#xA;&lt;p&gt;从图10-62可以看出，相较于原始的Transformer解码器，Baichuan2中最明显的变化在于归一化层、多头注意力层和多层感知机层。在自注意力层中，百川大模型采用了旋转位置编码（Rotary Position Embedding）[5]来对输入序列进行位置编码。简单来说，旋转编码通过引入旋转矩阵来改善模型的位置编码信息，随着输入序列相对长度地增加旋转编码能够灵活地处理各个位置上的依赖关系，以此来提高模型的泛化能力。虽然Baichuan2训练过程中最大长度为4096，但是实际测试中模型可以很好的扩展到5000以上[2]。在解码层的多层感知机中，Baichuan2使用了类似于LSTM中的门控机制来对信息流进行筛选。同时，对于各层之间的归一化方式，Baichuan2采用了更为轻量级的均方根归一化方式（Root Mean Square Normalization），即先对每个神经元计算平方并取均值，然后再将均值的平方根作为系数来归一化对应的神经元。&lt;/p&gt;&#xA;&lt;p&gt;到此，对于Baichuan2模型网络结构部分的内容就介绍完了，下面我们继续从使用的角度来介绍Baichuan2模型。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10184-模型推理&#34;&gt;10.18.4 模型推理&lt;a class=&#34;anchor&#34; href=&#34;#10184-%e6%a8%a1%e5%9e%8b%e6%8e%a8%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在对Baichuan2模型有了一个整体的了解之后，我们再来看如何使用它完成推理过程，即实现完整的对话流程。在官方开源的项目中一共提供两种方式来使用模型进行推理：一个是在命令行终端中进行使用，另一个则是提供了以网页端访问的方式进行使用。下面分别就这两种方式进行介绍。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 命令行终端使用&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;对于命令行终端这一使用方式来说，我们只需要激活上面创建好的虚拟环境并进入到工程根目录中，然后执行&lt;code&gt;python cli_demo.py&lt;/code&gt;命令即可运行该程序。紧接着大约30秒钟后，我们便会看到命令行中出现如下提示：&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;&#34;&gt;，&lt;/span&gt;输入进行对话&lt;span style=&#34;&#34;&gt;，&lt;/span&gt;vim 多行输入&lt;span style=&#34;&#34;&gt;，&lt;/span&gt;clear 清空历史&lt;span style=&#34;&#34;&gt;，&lt;/span&gt;CTRL&lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt;C 中断生成&lt;span style=&#34;&#34;&gt;，&lt;/span&gt;stream 开关流式生成&lt;span style=&#34;&#34;&gt;，&lt;/span&gt;exit 结束&lt;span style=&#34;&#34;&gt;。&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;&#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;</description>
			</item>
			<item>
				<title>10.19 百川大模型实现</title>
				<link>https://mlwithme.github.io/dl/chapter10/40c1c9ade70c4ce7/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/40c1c9ade70c4ce7/</guid>
				<description>&lt;h1 id=&#34;1019-百川大模型实现&#34;&gt;10.19 百川大模型实现&lt;a class=&#34;anchor&#34; href=&#34;#1019-%e7%99%be%e5%b7%9d%e5%a4%a7%e6%a8%a1%e5%9e%8b%e5%ae%9e%e7%8e%b0&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/a90b0d71389b4d69&#34;&gt;10.18节&lt;/a&gt;内容中我们详细介绍了Baichuan2模型的推理使用方法以及如何根据我们自己的需要来对基座模型进行微调。在本节内容中我们将进一步详细介绍Baichuan2模型的内部实现细节。由于百川大模型是基于Transformers框架所实现，因此在正式介绍百川大模型的实现原理之前我们先来看一下Transformers中对于基于Transformer解码器的模型在解码时的Key-Value缓存机制。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10191-解码缓存原理&#34;&gt;10.19.1 解码缓存原理&lt;a class=&#34;anchor&#34; href=&#34;#10191-%e8%a7%a3%e7%a0%81%e7%bc%93%e5%ad%98%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;根据&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/a469ed1a25e1498f&#34;&gt;10.3节&lt;/a&gt;内容可知，解码器在解码预测每个时刻时都涉及计算Query与Key之间的注意力权重，并通过对Value的加权求和来生成输出。为了避免在生成序列时的重复计算，特别是在处理长序列时，缓存机制允许解码器存储并复用先前计算的Key和Value。这样一来，相同的查询Query在不同时间步中便能够直接使用之前计算得到的结果，在减少了计算复杂度同时也提高了序列生成过程的速度。&lt;/p&gt;&#xA;&lt;p&gt;现在假定我们已经训练得到了一个基于Transformer解码器的生成式模型，且模型的原始输入为一个长度为3的序列，那么它在第4个时刻的解码输出过程便可以通过图10-64来进行表示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;400&#34; src=&#34;https://mlwithme.github.io/images/dl/231217162753.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-64 解码器编码图&lt;/center&gt;&#xA;&lt;p&gt;在图10-64中，输入序列在经过两个注意力层以后预测得到了第4个时刻的输出。如果是传统的解码方式，那么在解码第5个时刻时将会把原始的输入序列同第4个时刻的输出拼接在一起作为新的输入进行解码预测，后续过程以此类推。可以发现，在这种解码方式中对第$t$个时刻进行解码输出时，前面第$t-1$个时刻的输入都是重复的，而这就导致在自注意力的计算过程中前面第$t-1$个时刻的计算是重复的。&lt;/p&gt;&#xA;&lt;p&gt;因此，在基于缓存机制的解码过程中，解码器在对第$t$个时刻进行解码时会直接使用前$t-1$个时刻缓存得到的&lt;code&gt;key_states&lt;/code&gt;和&lt;code&gt;value_states&lt;/code&gt;来计算第$t$时刻的输出。例如在图10-64所示的过程中，当解码器对第4个时刻进行解码时将会缓存此时计算得到的&lt;code&gt;key_states&lt;/code&gt;和&lt;code&gt;values_states&lt;/code&gt;并通过一个元组&lt;code&gt;past_key_value&lt;/code&gt;进行表示。进一步，解码器在对第5个时刻进行解码时可以通过图10-65所示的过程表示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/dl/202507031942.png&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-65 缓存机制解码过程图&lt;/center&gt;&#xA;&lt;p&gt;如图10-65所示，解码器在对第5个时刻解码时其输入只有第4个时刻的输出，并且会将当前时刻输入经过线性变换计算得到的&lt;code&gt;key_states&lt;/code&gt;和&lt;code&gt;values_states&lt;/code&gt;同之前缓存的状态拼接起来得到新的&lt;code&gt;key_states&lt;/code&gt;和&lt;code&gt;values_states&lt;/code&gt;，以此同&lt;code&gt;query_states&lt;/code&gt;计算得到第5个时刻的注意力输出。最后，对于第6个时刻的解码输出过程各位读者可以根据图示自行理解，这里就不再赘述。&lt;/p&gt;&#xA;&lt;p&gt;在这里，我们还可以通过如下示例代码来验证Baichuan2模型中解码器的输出结果：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;test_BaichuanModel&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;     config &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; BaichuanConfig&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;from_pretrained(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;./Baichuan2_7B_Chat&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;     model &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; BaichuanModel(config)&#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;     past_key_values &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;5&lt;/span&gt;     inp &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;randint(&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;100&lt;/span&gt;, [&lt;span style=&#34;color:#40a070&#34;&gt;1&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;6&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;range&lt;/span&gt;(&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;,&lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(&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;i&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;8&lt;/span&gt;         result &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; model(inp, past_key_values&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;past_key_values)&#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;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;last_hidden_state的形状: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;result&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;last_hidden_state&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;shape&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;         past_key_values &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; result&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;past_key_values&#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;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;len(past_key_values): &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#007020&#34;&gt;len&lt;/span&gt;(past_key_values)&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;12&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;len(past_key_values[0]: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#007020&#34;&gt;len&lt;/span&gt;(past_key_values[&lt;span style=&#34;color:#40a070&#34;&gt;0&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;13&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;past_key_values[0][0].shape: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;past_key_values[&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:#666&#34;&gt;.&lt;/span&gt;shape&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;14&lt;/span&gt;         inp &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;randint(&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;100&lt;/span&gt;, [&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第2~3行是根据本地配置文件实例化一个&lt;code&gt;BaichuanModel&lt;/code&gt;类对象。第7~14行便是模拟解码器的解码输出过程。上述代码运行结束以后便会得到如下输出内容。&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; 第4个时刻输出&lt;span style=&#34;&#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; last_hidden_state的形状: torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Size([&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;4096&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;len&lt;/span&gt;(past_key_values): &lt;span style=&#34;color:#40a070&#34;&gt;32&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;len&lt;/span&gt;(past_key_values[&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;5&lt;/span&gt; past_key_values[&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:#666&#34;&gt;.&lt;/span&gt;shape: torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Size([&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;32&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;4096&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; 第5个时刻输出&lt;span style=&#34;&#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; last_hidden_state的形状: torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Size([&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;4096&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:#007020&#34;&gt;len&lt;/span&gt;(past_key_values): &lt;span style=&#34;color:#40a070&#34;&gt;32&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;len&lt;/span&gt;(past_key_values[&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;10&lt;/span&gt; past_key_values[&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:#666&#34;&gt;.&lt;/span&gt;shape: torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Size([&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;32&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;4096&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; 第6个时刻输出&lt;span style=&#34;&#34;&gt;：&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;12&lt;/span&gt; last_hidden_state的形状: torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Size([&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;4096&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;len&lt;/span&gt;(past_key_values): &lt;span style=&#34;color:#40a070&#34;&gt;32&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; &lt;span style=&#34;color:#007020&#34;&gt;len&lt;/span&gt;(past_key_values[&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;15&lt;/span&gt; past_key_values[&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:#666&#34;&gt;.&lt;/span&gt;shape: torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Size([&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;32&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;4096&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;[batch_size, seq_len, hidden_size]&lt;/code&gt;，后面再通过一个分类层便可以得到第4个时刻的预测输出。第3~5行分别表示&lt;code&gt;past_key_values&lt;/code&gt;缓存了32个注意力层中每一层的键值对，且形状为&lt;code&gt;[batch_size, num_heads, seq_len, hidden_size]&lt;/code&gt;。第7~10行分别是第5个时刻的输出，以及&lt;code&gt;past_key_values&lt;/code&gt;缓存结果，可以发现对于每一层中的键值序列其长度已经由3增加到了4，因为多了本层键值对的缓存。上述完整示例代码可参见&lt;code&gt;Code/Chapter10/C07_BaiChuan2/main.py&lt;/code&gt;文件。这里需要提醒各位读者的是，当你们在学习运行上述示例代码时，可以把配置文件中的维度、层数、多头个数等设置小一点，这样就能快速验证结果。&lt;/p&gt;</description>
			</item>
			<item>
				<title>10.20 GPT-4与GPTs使用</title>
				<link>https://mlwithme.github.io/dl/chapter10/ea1b4cf8b40c4b05/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter10/ea1b4cf8b40c4b05/</guid>
				<description>&lt;h1 id=&#34;1020-gpt-4与gpts使用&#34;&gt;10.20 GPT-4与GPTs使用&lt;a class=&#34;anchor&#34; href=&#34;#1020-gpt-4%e4%b8%8egpts%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/chapter10/94dda9bbbc994913&#34;&gt;10.14节&lt;/a&gt;和&lt;a href=&#34;https://mlwithme.github.io/dl/chapter10/9f5c00cadde14d31&#34;&gt;10.16节&lt;/a&gt;内容中，我们分别详细介绍了GPT-3系列模型和ChatGPT的原理与使用方法，同时也介绍了当前大模型所存在的局限性，并且从长期来看这些局限也将一直伴随着大模型的发展，因此，OpenAI也在持续地对GPT系列模型进行迭代更新。在接下来的这节内容中，我们将会介绍OpenAI最新发布的GPT-4以及后续迭代的GPT-4 Turbo模型和新引入的GPTs生态应用。&lt;/p&gt;&#xA;&lt;h2 id=&#34;10201-gpt-4介绍&#34;&gt;10.20.1 GPT-4介绍&lt;a class=&#34;anchor&#34; href=&#34;#10201-gpt-4%e4%bb%8b%e7%bb%8d&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在GPT-3模型发布34个月以后，2023年3月15日OpenAI在万众瞩目下发布了其最新一代的大模型GPT-4，同时也发布了基于GPT-4的ChatGPT模型。根据OpenAI发布的技术报告显示 [1]，GPT-4模型早在2022年8月份——第一代ChatGPT发布前的3个月——就已经训练完成，之后的6个多月一直在进行安全性和可靠性等方面的测试。同以往不同的是，在整整100页的技术报告中，OpenAI对于GPT-4模型的技术细节并未提及，例如网络结构信息、训练使用到的数据等等。以至于PyTorch Lightning的首席执行官威廉·福尔肯更是直接将该报告总结成了3个单词：We used Python——我们使用的是Python语言。&lt;/p&gt;&#xA;&lt;p&gt;总体来看，在日常对话中GPT-3.5和GPT-4之间的区别可能并不明显，但当涉及到复杂任务时便有了显著的差异。相比于上一代最强的GPT-3.5模型，GPT-4在理解力、多模态、可靠性、创造力以及处理复杂指令的能力上都有了显著提升。在接下来的内容中我们将会大致对这些部分进行一个简单的介绍。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 更可控的训练过程&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在这份技术报告中，OpenAI仅仅只提到GPT-4是一个基于Transformer结构并通过前$k$个词元来预测第$k+1$个词元进行任务建模的预训练语言模型，使用的是互联网数据和第三方授权的数据，包含数学问题的正确与错误答案数据、强推理与弱推理数据、自相矛盾与陈述一致的数据以及各种意识形态和观点类的数据。进一步，为了将模型与人类意图进行对齐，OpenAI同样也使用了人类反馈的强化学习算法来对预训练模型进行微调。不过后续实验发现，整个大模型的能力似乎主要来自于预训练过程，也就说微调后并没有明显提升模型在各种考试上的效果，并且如果提示词设计不恰当反而会降低模型的效果。不过OpenAI也发现，微调带来的好处是模型能够更容易受到人类意图的引导，而预训练模型则需要通过精心设计提示词才能实现。&lt;/p&gt;&#xA;&lt;p&gt;由于在大规模的模型训练中不可能直接根据每一组超参数来初始化模型并进行训练，因此GPT-4项目在一开始的聚焦点便是如何建立一个可预测和扩展的深度学习框架体系。也就是说，通过这套体系能够准确预判得到当模型扩大多少倍以后，它便能够达到一个什么样的效果。为此，OpenAI开发了一套能对不同模型规模实现可预测的基础性框架和优化方法。为了验证这种扩展性，OpenAI通过分析后使用相同方法但计算量仅为GPT-4 万分之一的模型准确地预测出了GPT-4模型最终的损失值。除了预测模型最终的损失值，OpenAI还提出了一种方法来直接预测相应的评价指标，并成功地通过使用计算量只有GPT-4千分之一的模型预测出了GPT-4在HumanEval数据集的一个子集上的通过率。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 更强的多模态&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;GPT-4最大的不同在于它的多模态（Multimodal）能力。在GPT-4中，我们除了可以将文本作为模型的输入之外同时也可以将图片作为模型的输入，并最终让它理解图片中的内容生成文本。不过在8个月后的2023年11月，OpenAI举办了第一届开发者大会并同时发布了更强的GPT-4 Turbo模型。相较于GPT-4，GPT-4 Turbo在多模态方面更是同时支持将文本、图像、文件作为输入，并支持输出文本和图像 [2] [3]。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;300&#34; src=&#34;https://mlwithme.github.io/images/dl/240102205155.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-68 ChatGPT输入图&lt;/center&gt;&#xA;&lt;p&gt;如图10-68所示，我们可以将其作为ChatGPT的输入，并让ChatGPT告诉我们这张图的有趣之处。&lt;/p&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;User: 这幅图有趣的地方在哪里？请依次告诉我。&lt;/p&gt;&#xA;&lt;p&gt;ChatGPT: 这幅图的幽默之处在于，它展示了一个用于电子设备的普通VGA连接器伪装成能够连接到现代智能手机的Lightning电缆。VGA连接器通常用于连接显示器到电脑，而不是手机，并且它的体积和形状通常不适合用作便携式设备的充电或数据传输。另外，VGA连接器的设计明显比现代的手机充电和数据线要大和过时。&lt;/p&gt;&#xA;&lt;p&gt;图片中还显示了一个包装盒，似乎是这个伪装成Lightning电缆的VGA连接器的包装。这给人一种幽默感，因为包装上的描述与实际产品的功能不符，创造了一种期望与现实不一致的滑稽对比。这个产品的实用性几乎为零，它似乎是专为创造笑话或作为恶搞礼物而设计。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&lt;p&gt;从ChatGPT的反馈结果可以看出，ChatGPT一方面不仅能告我们图里面有什么内容，同时它还能结合常识理解图中内容的不合理之处。进一步，我们还可以让ChatGPT为我们生成类似风格的图片。&lt;/p&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;User: 请生成一张类似有趣的图片&lt;/p&gt;&#xA;&lt;p&gt;ChatGPT: 这是生成的图片，它描绘了一种幽默的技术矛盾：一张古老的软盘配上了现代的USB-C连接器，好像它可以插入当代的智能手机一样。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/dl/240102205605.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 10-69 ChatGPT生成图&lt;/center&gt;&#xA;&lt;p&gt;如图10-69所示便是ChatGPT根据上下文内容生成的两张类似风格的图片，其有趣之处在于左图中一个连屏幕也没有的上世纪手机居然支持无线充电，而右图中则是一张古老的软盘配上了现代的USB-C连接器，好像它可以插入当代的智能手机一样。&lt;/p&gt;&#xA;&lt;p&gt;正是基于这样的能力，GPT-4在多种专业和学术基准测试中表现出了近乎人类水平的结果。例如在美国统一律师资格考试（UBE）的测试结果中GPT-4获得了前10%的成绩，而GPT-3.5模型的表现结果仅为后10%的水平。尽管GPT-4 具备强大的能力，但它目前仍然存在与早期GPT模型类似的局限性，即它可能会产生错误的事实（“幻觉”）和推理逻辑错误。例如当生成内容过长时可能会出现自说自话的情况 [4]。&lt;/p&gt;&#xA;&lt;p&gt;同时，GPT-4 带来的风险与之前的模型类似，比如仍旧生成有害建议、有缺陷的代码或不准确的信息，并且由于多模态的加入还额外引入新的风险。OpenAI为了深入了解这些风险，专门邀请了来自人工智能安全、网络安全、生物风险、信任与安全及国际安全等领域的 50 多名专家，对模型进行了严格的测试，以帮助OpenAI对模型进行改进。例如OpenAI收集了更多的数据来提高GPT-4拒绝提供合成危险化学物质请求的能力。因此，GPT-4模型是一个持续迭代更新的模型，训练数据从发布之初2021年9月的截止时间，到现在（2024年1月）最新GPT-4 Turbo模型的2023年4月截止时间 [5]。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;3. 更长的上下文&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在新发布的GPT-4模型中，模型支持的长下文长度相较于之前的GPT-3系列模型也有了显著的增加。在GPT-4中，支持的通用上下文窗口长度为8192个词元，最大支持长度为32768个词元。在OpenAI开发者大会上发布的最新版GPT-4 Turbo已经支持了最长32768个词元的上下文窗口。&lt;/p&gt;&#xA;&lt;center&gt;表 10-6 GPT-4系列模型信息表&lt;/center&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;400&#34; src=&#34;https://mlwithme.github.io/images/dl/240104153934.jpg&#34;/&gt; &lt;/div&gt;&#xA;&lt;p&gt;如表10-6所示便是目前为止GPT-3.5系列和GPT-4系列各个模型的长下文支持长度和训练日期截止日期情况。值得注意的是，每一代的GPT模型都有不同的分支版本，每个分支版本支持的上下文长度并不相同而且后期也会进行迭代更新，所以对于每个版本最新支持的上下文窗口长度以及训练数据截止日期各位读者可以自行在OpenAI官网进行查询 [5]。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;4. 更精细的控制和输出&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在本次和后续的开发者大会中，OpenAI针对GPT-4系列模型陆续发布了一系列新的功能。从开发者的角度来看，OpenAI允许通过参数来控制模型返回结果的形式，例如指定返回结果类型为JSON对象、支持返回预测结果的对数概率分布、支持设定随机种子来生成固定的结果等。从用户使用的角度来看，我们可以更为精细地控制GPT-4系列模型的输出，比如模型输出语言的风格、话题深度和输出的详细程度。尽管在之前的模型中我们也可以通过设计相应的提示词来引导模型输出我们期望中的结果，但是随着对话会话轮数的增加模型便容易遗忘前面的内容。在此次GPT-4的发布中，OpenAI在原有模型基础上新引入了一个“System”这个角色来引导控制模型的输出结果。&lt;/p&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;System: 你是一位总是采用苏格拉底式教学法的导师。你从不直接告诉学生答案，而是总是试图提出最合适的问题，帮助他们学会独立思考。你应该始终依据学生的兴趣和所掌握的知识来调整你的提问，把问题分解成更简单的部分，直到问题适合他们的认知水平。&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
