解码器 | 基于 Transformers 的编码器-解码器模型

这篇具有很好参考价值的文章主要介绍了解码器 | 基于 Transformers 的编码器-解码器模型。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

基于 transformer 的编码器-解码器模型是 表征学习模型架构 这两个领域多年研究成果的结晶。本文简要介绍了神经编码器-解码器模型的历史,更多背景知识,建议读者阅读由 Sebastion Ruder 撰写的这篇精彩 博文。此外,建议读者对 自注意力 (self-attention) 架构 有一个基本了解,可以阅读 Jay Alammar 的 这篇博文 复习一下原始 transformer 模型。

本文分 4 个部分:

  • 背景 - 简要回顾了神经编码器-解码器模型的历史,重点关注基于 RNN 的模型。
  • 编码器-解码器 - 阐述基于 transformer 的编码器-解码器模型,并阐述如何使用该模型进行推理。
  • 编码器 - 阐述模型的编码器部分。
  • 解码器 - 阐述模型的解码器部分。

每个部分都建立在前一部分的基础上,但也可以单独阅读。这篇分享是最后一部分 解码器

解码器

编码器-解码器 部分所述, 基于 transformer 的解码器定义了给定上下文编码序列条件下目标序列的条件概率分布:

\[p_{\theta_{dec}}(\mathbf{Y}_{1: m} | \mathbf{\overline{X}}_{1:n}) \]

根据贝叶斯法则,在给定上下文编码序列和每个目标变量的所有前驱目标向量的条件下,可将上述分布分解为每个目标向量的条件分布的乘积:

\[p_{\theta_{dec}}(\mathbf{Y}_{1:m} | \mathbf{\overline{X}}_{1:n}) = \prod_{i=1}^{m} p_{\theta_{dec}}(\mathbf{y}_i | \mathbf{Y}_{0: i-1}, \mathbf{\overline{X}}_{1:n}) \]

我们首先了解一下基于 transformer 的解码器如何定义概率分布。基于 transformer 的解码器由很多 解码器模块 堆叠而成,最后再加一个线性层 (即 “LM 头”)。这些解码器模块的堆叠将上下文相关的编码序列 \(\mathbf{\overline{X}}_{1:n}\) 和每个目标向量的前驱输入 \(\mathbf{Y}_{0:i-1}\) (这里 \(\mathbf{y}_0\) 为 BOS) 映射为目标向量的编码序列 \(\mathbf{\overline{Y} }_{0:i-1}\)。然后,“LM 头”将目标向量的编码序列 \(\mathbf{\overline{Y}}_{0:i-1}\) 映射到 logit 向量序列 \(\mathbf {L}_{1:n} = \mathbf{l}_1, \ldots, \mathbf{l}_n\), 而每个 logit 向量\(\mathbf{l}_i\) 的维度即为词表的词汇量。这样,对于每个 \(i \in {1, \ldots, n}\),其在整个词汇表上的概率分布可以通过对 \(\mathbf{l}_i\) 取 softmax 获得。公式如下:

\[p_{\theta_{dec}}(\mathbf{y}_i | \mathbf{Y}_{0: i-1}, \mathbf{\overline{X}}_{1:n}), \forall i \in {1, \ldots, n} \]

“LM 头” 即为词嵌入矩阵的转置, \(\mathbf{W}_{\text{emb}}^{\intercal} = \left[\mathbf{ y}^1, \ldots, \mathbf{y}^{\text{vocab}}\right]^{​​T}\) \({}^1\)。直观上来讲,这意味着对于所有 \(i \in {0, \ldots, n - 1}\) “LM 头” 层会将 \(\mathbf{\overline{y }}_i\) 与词汇表 \(\mathbf{y}^1, \ldots, \mathbf{y}^{\text{vocab}}\) 中的所有词嵌入一一比较,输出的 logit 向量 \(\mathbf{l}_{i+1}\) 即表示 \(\mathbf{\overline{y }}_i\) 与每个词嵌入之间的相似度。Softmax 操作只是将相似度转换为概率分布。对于每个 \(i \in {1, \ldots, n}\),以下等式成立:

\[p_{\theta_{dec}}(\mathbf{y} | \mathbf{\overline{X}}_{1:n}, \mathbf{Y}_{0:i-1}) \]
\[= \text{Softmax}(f_{\theta_{\text{dec}}}(\mathbf{\overline{X}}_{1:n}, \mathbf{Y}_{0:i-1})) \]
\[= \text{Softmax}(\mathbf{W}_{\text{emb}}^{\intercal} \mathbf{\overline{y}}_{i-1}) \]
\[= \text{Softmax}(\mathbf{l}_i) \]

总结一下,为了对目标向量序列 \(\mathbf{Y}_{1: m}\) 的条件分布建模,先在目标向量 \(\mathbf{Y}_{1: m-1}\) 前面加上特殊的 \(\text{BOS}\) 向量 ( \(\mathbf{y}_0\)),并将其与上下文相关的编码序列 \(\mathbf{\overline{X}}_{1:n}\) 一起映射到 logit 向量序列 \(\mathbf{L}_{1:m}\)。然后,使用 softmax 操作将每个 logit 目标向量 \(\mathbf{l}_i\) 转换为目标向量 \(\mathbf{y}_i\) 的条件概率分布。最后,将所有目标向量的条件概率 \(\mathbf{y}_1, \ldots, \mathbf{y}_m\) 相乘得到完整目标向量序列的条件概率:

\[p_{\theta_{dec}}(\mathbf{Y}_{1:m} | \mathbf{\overline{X}}_{1:n}) = \prod_{i=1}^{m} p_{\theta_{dec}}(\mathbf{y}_i | \mathbf{Y}_{0: i-1}, \mathbf{\overline{X}}_{1:n}). \]

与基于 transformer 的编码器不同,在基于 transformer 的解码器中,其输出向量 \(\mathbf{\overline{y}}_{i-1}\) 应该能很好地表征 下一个 目标向量 (即 \(\mathbf{y}_i\)),而不是输入向量本身 (即 \(\mathbf{y}_{i-1}\))。此外,输出向量 \(\mathbf{\overline{y}}_{i-1}\) 应基于编码器的整个输出序列 \(\mathbf{\overline{X}}_{1:n}\)。为了满足这些要求,每个解码器块都包含一个 单向自注意层,紧接着是一个 交叉注意层,最后是两个前馈层\({}^2\)。单向自注意层将其每个输入向量 \(\mathbf{y'}_j\) 仅与其前驱输入向量 \(\mathbf{y'}_i\) (其中 \(i \le j\),且 \(j \in {1, \ldots, n}\)) 相关联,来模拟下一个目标向量的概率分布。交叉注意层将其每个输入向量 \(\mathbf{y''}_j\) 与编码器输出的所有向量 \(\mathbf{\overline{X}}_{1:n}\) 相关联,来根据编码器输入预测下一个目标向量的概率分布。

好,我们仍以英语到德语翻译为例可视化一下 基于 transformer 的解码器。

我们可以看到解码器将 \(\mathbf{Y}_{0:5}\): “BOS”、“Ich”、“will”、“ein”、“Auto”、“kaufen” (图中以浅红色显示) 和 “I”、“want”、“to”、“buy”、“a”、“car”、“EOS” ( \(\mathbf{\overline{X}}_{1:7}\) (图中以深绿色显示)) 映射到 logit 向量 \(\mathbf{L}_{1:6}\) (图中以深红色显示)。

因此,对每个 \(\mathbf{l}_1、\mathbf{l}_2、\ldots、\mathbf{l}_6\) 使用 softmax 操作可以定义下列条件概率分布:

\[p_{\theta_{dec}}(\mathbf{y} | \text{BOS}, \mathbf{\overline{X}}_{1:7}), \]
\[p_{\theta_{dec}}(\mathbf{y} | \text{BOS Ich}, \mathbf{\overline{X}}_{1:7}), \]
\[\ldots, \]
\[p_{\theta_{dec}}(\mathbf{y} | \text{BOS Ich will ein Auto kaufen}, \mathbf{\overline{X}}_{1:7}) \]

总条件概率如下:

\[p_{\theta_{dec}}(\text{Ich will ein Auto kaufen EOS} | \mathbf{\overline{X}}_{1:n}) \]

其可表示为以下乘积形式:

\[p_{\theta_{dec}}(\text{Ich} | \text{BOS}, \mathbf{\overline{X}}_{1:7}) \times \ldots \times p_{\theta_{dec}}(\text{EOS} | \text{BOS Ich will ein Auto kaufen}, \mathbf{\overline{X}}_{1:7}) \]

图右侧的红框显示了前三个目标向量 \(\mathbf{y}_0\)\(\mathbf{y}_1\)\(\mathbf{y}_2\) 在一个解码器模块中的行为。下半部分说明了单向自注意机制,中间说明了交叉注意机制。我们首先关注单向自注意力。

与双向自注意一样,在单向自注意中, query 向量 \(\mathbf{q}_0, \ldots, \mathbf{q}_{m-1}\) (如下图紫色所示), key 向量 \(\mathbf{k}_0, \ldots, \mathbf{k}_{m-1}\) (如下图橙色所示),和 value 向量 \(\mathbf{v }_0, \ldots, \mathbf{v}_{m-1}\) (如下图蓝色所示) 均由输入向量 \(\mathbf{y'}_0, \ldots, \mathbf{ y'}_{m-1}\) (如下图浅红色所示) 映射而来。然而,在单向自注意力中,每个 query 向量 \(\mathbf{q}_i\) 与当前及之前的 key 向量进行比较 (即 \(\mathbf{k}_0 , \ldots, \mathbf{k}_i\)) 并生成各自的 注意力权重 。这可以防止输出向量 \(\mathbf{y''}_j\) (如下图深红色所示) 包含未来向量 (\(\mathbf{y}_i\),其中 \(i > j\)\(j \in {0, \ldots, m - 1 }\)) 的任何信息 。与双向自注意力的情况一样,得到的注意力权重会乘以它们各自的 value 向量并加权求和。

我们将单向自注意力总结如下:

\[\mathbf{y''}_i = \mathbf{V}_{0: i} \textbf{Softmax}(\mathbf{K}_{0: i}^\intercal \mathbf{q}_i) + \mathbf{y'}_i \]

请注意, keyvalue 向量的索引范围都是 \(0:i\) 而不是 \(0: m-1\)\(0: m-1\) 是双向自注意力中 key 向量的索引范围。

下图显示了上例中输入向量 \(\mathbf{y'}_1\) 的单向自注意力。

可以看出 \(\mathbf{y''}_1\) 只依赖于 \(\mathbf{y'}_0\)\(\mathbf{y'}_1\)。因此,单词 “Ich” 的向量表征 ( \(\mathbf{y'}_1\)) 仅与其自身及 “BOS” 目标向量 ( \(\mathbf{y'}_0\)) 相关联,而 与 “will” 的向量表征 ( \(\mathbf{y'}_2\)) 相关联。

那么,为什么解码器使用单向自注意力而不是双向自注意力这件事很重要呢?如前所述,基于 transformer 的解码器定义了从输入向量序列 \(\mathbf{Y}_{0: m-1}\) 到其 下一个 解码器输入的 logit 向量的映射,即 \(\mathbf{L}_{1:m}\)。举个例子,输入向量 \(\mathbf{y}_1\) = “Ich” 会映射到 logit 向量 \(\mathbf{l}_2\),并用于预测下一个输入向量 \(\mathbf{y}_2\)。因此,如果 \(\mathbf{y'}_1\) 可以获取后续输入向量 \(\mathbf{Y'}_{2:5}\)的信息,解码器将会简单地复制向量 “will” 的向量表征 ( \(\mathbf{y'}_2\)) 作为其输出 \(\mathbf{y''}_1\),并就这样一直传播到最后一层,所以最终的输出向量 \(\mathbf{\overline{y}}_1\) 基本上就只对应于 \(\mathbf{y}_2\) 的向量表征,并没有起到预测的作用。

这显然是不对的,因为这样的话,基于 transformer 的解码器永远不会学到在给定所有前驱词的情况下预测下一个词,而只是对所有 \(i \in {1, \ldots, m }\),通过网络将目标向量 \(\mathbf{y}_i\) 复制到 \(\mathbf {\overline{y}}_{i-1}\)。以下一个目标变量本身为条件去定义下一个目标向量,即从 \(p(\mathbf{y} | \mathbf{Y}_{0:i}, \mathbf{\overline{ X}})\) 中预测 \(\mathbf{y}_i\), 显然是不对的。因此,单向自注意力架构允许我们定义一个 因果的 概率分布,这对有效建模下一个目标向量的条件分布而言是必要的。

太棒了!现在我们可以转到连接编码器和解码器的层 - 交叉注意力 机制!

交叉注意层将两个向量序列作为输入: 单向自注意层的输出 \(\mathbf{Y''}_{0: m-1}\) 和编码器的输出 \(\mathbf{\overline{X}}_{1:n}\)。与自注意力层一样, query 向量 \(\mathbf{q}_0, \ldots, \mathbf{q}_{m-1}\) 是上一层输出向量 \(\mathbf{Y''}_{0: m-1}\) 的投影。而 keyvalue 向量 \(\mathbf{k}_0, \ldots, \mathbf{k}_{n-1}\)\(\mathbf{v}_0, \ldots, \mathbf {v}_{n-1}\) 是编码器输出向量 \(\mathbf{\overline{X}}_{1:n}\) 的投影。定义完 keyvaluequery 向量后,将 query 向量 \(\mathbf{q}_i\)所有 key 向量进行比较,并用各自的得分对相应的 value 向量进行加权求和。这个过程与 双向 自注意力对所有 \(i \in {0, \ldots, m-1}\)\(\mathbf{y'''}_i\) 是一样的。交叉注意力可以概括如下:

\[\mathbf{y'''}_i = \mathbf{V}_{1:n} \textbf{Softmax}(\mathbf{K}_{1: n}^\intercal \mathbf{q}_i) + \mathbf{y''}_i \]

注意,keyvalue 向量的索引范围是 \(1:n\),对应于编码器输入向量的数目。

我们用上例中输入向量 \(\mathbf{y''}_1\) 来图解一下交叉注意力机制。

我们可以看到 query 向量 \(\mathbf{q}_1\)(紫色)源自 \(\mathbf{y''}_1\)(红色),因此其依赖于单词 "Ich" 的向量表征。然后将 query 向量 \(\mathbf{q}_1\) 与对应的 key 向量 \(\mathbf{k}_1, \ldots, \mathbf{k}_7\)(黄色)进行比较,这里的 key 向量对应于编码器对其输入 \(\mathbf{X}_{1:n}\) = "I want to buy a car EOS" 的上下文相关向量表征。这将 "Ich" 的向量表征与所有编码器输入向量直接关联起来。最后,将注意力权重乘以 value 向量 \(\mathbf{v}_1, \ldots, \mathbf{v}_7\)(青绿色)并加上输入向量 \(\mathbf{y''}_1\) 最终得到输出向量 \(\mathbf{y'''}_1\)(深红色)。

所以,直观而言,到底发生了什么?每个输出向量 \(\mathbf{y'''}_i\) 是由所有从编码器来的 value 向量(\(\mathbf{v}_{1}, \ldots, \mathbf{v}_7\) )的加权和与输入向量本身 \(\mathbf{y''}_i\) 相加而得(参见上图所示的公式)。其关键思想是: 来自解码器的 \(\mathbf{q}_i\)query 投影与 来自编码器的 \(\mathbf{k}_j\) 越相关,其对应的 \(\mathbf{v}_j\) 对输出的影响越大。

酷!现在我们可以看到这种架构的每个输出向量 \(\mathbf{y'''}_i\) 取决于其来自编码器的输入向量 \(\mathbf{\overline{X}}_{1 :n}\) 及其自身的输入向量 \(\mathbf{y''}_i\)。这里有一个重要的点,在该架构中,虽然输出向量 \(\mathbf{y'''}_i\) 依赖来自编码器的输入向量 \(\mathbf{\overline{X}}_{1:n}\),但其完全独立于该向量的数量 \(n\)。所有生成 key 向量 \(\mathbf{k}_1, \ldots, \mathbf{k}_n\)value 向量 $\mathbf{v}_1, \ldots, \mathbf{v}_n $ 的投影矩阵 \(\mathbf{W}^{\text{cross}}_{k}\)\(\mathbf{W}^{\text{cross}}_{v}\) 都是与 \(n\) 无关的,所有 \(n\) 共享同一个投影矩阵。且对每个 \(\mathbf{y'''}_i\),所有 value 向量 \(\mathbf{v}_1, \ldots, \mathbf{v}_n\) 被加权求和至一个向量。至此,关于为什么基于 transformer 的解码器没有远程依赖问题而基于 RNN 的解码器有这一问题的答案已经很显然了。因为每个解码器 logit 向量 直接 依赖于每个编码后的输出向量,因此比较第一个编码输出向量和最后一个解码器 logit 向量只需一次操作,而不像 RNN 需要很多次。

总而言之,单向自注意力层负责基于当前及之前的所有解码器输入向量建模每个输出向量,而交叉注意力层则负责进一步基于编码器的所有输入向量建模每个输出向量。

为了验证我们对该理论的理解,我们继续上面编码器部分的代码,完成解码器部分。


\({}^1\) 词嵌入矩阵 \(\mathbf{W}_{\text{emb}}\) 为每个输入词提供唯一的 上下文无关 向量表示。这个矩阵通常也被用作 “LM 头”,此时 “LM 头”可以很好地完成“编码向量到 logit” 的映射。

\({}^2\) 与编码器部分一样,本文不会详细解释前馈层在基于 transformer 的模型中的作用。Yun 等 (2017) 的工作认为前馈层对于将每个上下文相关向量 \(\mathbf{x'}_i\) 映射到所需的输出空间至关重要,仅靠自注意力层无法完成。这里应该注意,每个输出词元 \(\mathbf{x'}\) 对应的前馈层是相同的。有关更多详细信息,建议读者阅读论文。

from transformers import MarianMTModel, MarianTokenizer
import torch

tokenizer = MarianTokenizer.from_pretrained("Helsinki-NLP/opus-mt-en-de")
model = MarianMTModel.from_pretrained("Helsinki-NLP/opus-mt-en-de")
embeddings = model.get_input_embeddings()

# create token ids for encoder input
input_ids = tokenizer("I want to buy a car", return_tensors="pt").input_ids

# pass input token ids to encoder
encoder_output_vectors = model.base_model.encoder(input_ids, return_dict=True).last_hidden_state

# create token ids for decoder input
decoder_input_ids = tokenizer("<pad> Ich will ein", return_tensors="pt", add_special_tokens=False).input_ids

# pass decoder input ids and encoded input vectors to decoder
decoder_output_vectors = model.base_model.decoder(decoder_input_ids, encoder_hidden_states=encoder_output_vectors).last_hidden_state

# derive embeddings by multiplying decoder outputs with embedding weights
lm_logits = torch.nn.functional.linear(decoder_output_vectors, embeddings.weight, bias=model.final_logits_bias)

# change the decoder input slightly
decoder_input_ids_perturbed = tokenizer("<pad> Ich will das", return_tensors="pt", add_special_tokens=False).input_ids
decoder_output_vectors_perturbed = model.base_model.decoder(decoder_input_ids_perturbed, encoder_hidden_states=encoder_output_vectors).last_hidden_state
lm_logits_perturbed = torch.nn.functional.linear(decoder_output_vectors_perturbed, embeddings.weight, bias=model.final_logits_bias)

# compare shape and encoding of first vector
print(f"Shape of decoder input vectors {embeddings(decoder_input_ids).shape}. Shape of decoder logits {lm_logits.shape}")

# compare values of word embedding of "I" for input_ids and perturbed input_ids
print("Is encoding for `Ich` equal to its perturbed version?: ", torch.allclose(lm_logits[0, 0], lm_logits_perturbed[0, 0], atol=1e-3))

输出:

    Shape of decoder input vectors torch.Size([1, 5, 512]). Shape of decoder logits torch.Size([1, 5, 58101])
    Is encoding for `Ich` equal to its perturbed version?: True

我们首先比较解码器词嵌入层的输出维度 embeddings(decoder_input_ids) (对应于 \(\mathbf{Y}_{0: 4}\),这里 <pad> 对应于 BOS 且 "Ich will das" 被分为 4 个词) 和 lm_logits (对应于 \(\mathbf{L}_{1:5}\)) 的维度。此外,我们还通过解码器将单词序列 “<pad> Ich will ein” 和其轻微改编版 “<pad> Ich will das” 与 encoder_output_vectors 一起传递给解码器,以检查对应于 “Ich” 的第二个 lm_logit 在仅改变输入序列中的最后一个单词 (“ein” -> “das”) 时是否会有所不同。

正如预期的那样,解码器输入词嵌入和 lm_logits 的输出, \(\mathbf{Y}_{0: 4}\)\(\mathbf{L}_{ 1:5}\) 的最后一个维度不同。虽然序列长度相同 (=5),但解码器输入词嵌入的维度对应于 model.config.hidden_​​size,而 lm_logit 的维数对应于词汇表大小 model.config.vocab_size。其次,可以注意到,当将最后一个单词从 “ein” 变为 “das”,\(\mathbf{l}_1 = \text{“Ich”}\) 的输出向量的值不变。鉴于我们已经理解了单向自注意力,这就不足为奇了。

最后一点, 自回归 模型,如 GPT2,与删除了交叉注意力层的 基于 transformer 的解码器模型架构是相同的,因为纯自回归模型不依赖任何编码器的输出。因此,自回归模型本质上与 自编码 模型相同,只是用单向注意力代替了双向注意力。这些模型还可以在大量开放域文本数据上进行预训练,以在自然语言生成 (NLG) 任务中表现出令人印象深刻的性能。在 Radford 等 (2019) 的工作中,作者表明预训练的 GPT2 模型无需太多微调即可在多种 NLG 任务上取得达到 SOTA 或接近 SOTA 的结果。你可以在 此处 获取所有 🤗 transformers 支持的 自回归 模型的信息。

好了!至此,你应该已经很好地理解了 基于 transforemr 的编码器-解码器模型以及如何在 🤗 transformers 库中使用它们。

非常感谢 Victor Sanh、Sasha Rush、Sam Shleifer、Oliver Åstrand、Ted Moskovitz 和 Kristian Kyvik 提供的宝贵反馈。

附录

如上所述,以下代码片段展示了如何为 基于 transformer 的编码器-解码器模型编写一个简单的生成方法。在这里,我们使用 torch.argmax 实现了一个简单的 贪心 解码法来对目标向量进行采样。

from transformers import MarianMTModel, MarianTokenizer
import torch

tokenizer = MarianTokenizer.from_pretrained("Helsinki-NLP/opus-mt-en-de")
model = MarianMTModel.from_pretrained("Helsinki-NLP/opus-mt-en-de")

# create ids of encoded input vectors
input_ids = tokenizer("I want to buy a car", return_tensors="pt").input_ids

# create BOS token
decoder_input_ids = tokenizer("<pad>", add_special_tokens=False, return_tensors="pt").input_ids

assert decoder_input_ids[0, 0].item() == model.config.decoder_start_token_id, "`decoder_input_ids` should correspond to `model.config.decoder_start_token_id`"

# STEP 1

# pass input_ids to encoder and to decoder and pass BOS token to decoder to retrieve first logit
outputs = model(input_ids, decoder_input_ids=decoder_input_ids, return_dict=True)

# get encoded sequence
encoded_sequence = (outputs.encoder_last_hidden_state,)
# get logits
lm_logits = outputs.logits

# sample last token with highest prob
next_decoder_input_ids = torch.argmax(lm_logits[:, -1:], axis=-1)

# concat
decoder_input_ids = torch.cat([decoder_input_ids, next_decoder_input_ids], axis=-1)

# STEP 2

# reuse encoded_inputs and pass BOS + "Ich" to decoder to second logit
lm_logits = model(None, encoder_outputs=encoded_sequence, decoder_input_ids=decoder_input_ids, return_dict=True).logits

# sample last token with highest prob again
next_decoder_input_ids = torch.argmax(lm_logits[:, -1:], axis=-1)

# concat again
decoder_input_ids = torch.cat([decoder_input_ids, next_decoder_input_ids], axis=-1)

# STEP 3
lm_logits = model(None, encoder_outputs=encoded_sequence, decoder_input_ids=decoder_input_ids, return_dict=True).logits
next_decoder_input_ids = torch.argmax(lm_logits[:, -1:], axis=-1)
decoder_input_ids = torch.cat([decoder_input_ids, next_decoder_input_ids], axis=-1)

# let's see what we have generated so far!
print(f"Generated so far: {tokenizer.decode(decoder_input_ids[0], skip_special_tokens=True)}")

# This can be written in a loop as well.

输出:

    Generated so far: Ich will ein

在这个示例代码中,我们准确地展示了正文中描述的内容。我们在输入 “I want to buy a car” 前面加上 \(\text{BOS}\) ,然后一起传给编码器-解码器模型,并对第一个 logit $\mathbf{l}_1 $ (对应代码中第一次出现 lm_logits 的部分) 进行采样。这里,我们的采样策略很简单: 贪心地选择概率最高的词作为下一个解码器输入向量。然后,我们以自回归方式将采样得的解码器输入向量与先前的输入一起传递给编码器-解码器模型并再次采样。重复 3 次后,该模型生成了 “Ich will ein”。结果没问题,开了个好头。

在实践中,我们会使用更复杂的解码方法来采样 lm_logits。你可以参考 这篇博文 了解更多的解码方法。

至此,《基于 Transformers 的编码器-解码器模型》的四个部分就全部分享完啦,欢迎大家阅读其他分享 🤗!


英文原文: https://hf.co/blog/encoder-decoder

原文作者: Patrick von Platen

译者: Matrix Yao (姚伟峰),英特尔深度学习工程师,工作方向为 transformer-family 模型在各模态数据上的应用及大规模模型的训练推理。

审校/排版: zhongdongy (阿东)文章来源地址https://www.toymoban.com/news/detail-473785.html

到了这里,关于解码器 | 基于 Transformers 的编码器-解码器模型的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【计算机视觉 | 目标检测】术语理解9:AIGC的理解,对比学习,解码器,Mask解码器,耦合蒸馏,半耦合,图像编码器和组合解码器的耦合优化

    AIGC指的是使用人工智能技术自动生成的各类数字内容,包括文本、图像、音频、视频等。它利用机器学习模型进行智能化内容生成。 主要的技术手段包括: 自然语言生成(NLG):使用RNN、GPT等语言模型生成文本。 生成对抗网络(GAN):使用GAN生成高质量图片。 自动语音合成(TTS):使用

    2024年02月04日
    浏览(70)
  • 深入了解Transformer:从编码器到解码器的神经网络之旅

    自2017年问世以来,Transformer模型在自然语言处理(NLP)领域引发了一场革命。它的独特设计和高效性能使其成为了解决复杂语言任务的关键工具。 (1)自注意力机制 Transformer的核心在于自注意力机制。它允许模型在处理每个词时考虑句子中的所有其他词,从而有效捕获长距离依

    2024年01月17日
    浏览(52)
  • LeViT-UNet:transformer 编码器和CNN解码器的有效整合

    levi - unet[2]是一种新的医学图像分割架构,它使用transformer 作为编码器,这使得它能够更有效地学习远程依赖关系。levi - unet[2]比传统的U-Nets更快,同时仍然实现了最先进的分割性能。 levi - unet[2]在几个具有挑战性的医学图像分割基准上取得了比其他法更好的性能,包括Synap

    2024年02月12日
    浏览(46)
  • SpringBoot项目整合OpenFeign、实现动态IP+URL请求、自定义(编码器\解码器)

    OpenFeign 是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中. 启动类加上注解: @EnableDiscoveryClient 动态URL 工具类: FeignUtils.class

    2024年02月02日
    浏览(54)
  • 机器学习&&深度学习——从编码器-解码器架构到seq2seq(机器翻译)

    👨‍🎓作者简介:一位即将上大四,正专攻机器学习的保研er 🌌上期文章:机器学习深度学习——注意力提示、注意力池化(核回归) 📚订阅专栏:机器学习深度学习 希望文章对你们有所帮助 接下来就要慢慢开始实战了,把这边过了,我们接下来就要进行机器翻译的实战

    2024年02月13日
    浏览(42)
  • RK3399Pro-硬件编解码器MPP库快速上手--(二)MPP编码入门

    整个编码分为mpp_create,mpp_init, 再通过mpp的接口mpi-control接口来进行参数设置.一般需要配置三类信息: 码率控制方式(MPPEncRcCfg),通过命令MPP_ENC_RC_CFG配置; 输入控制配置(MppEncPrepCfg),通过命令MPP_ENC_SET_PREP_CFG配置; 协议控制配置(MppEncCodecCfg),通过命令MPP_ENC_SET_CO

    2024年02月02日
    浏览(36)
  • 利用第三方解码器ffmpeg让群晖DSM6.2.4版本的Video Station支持DTS视频编码和EAC3音频编码

    截至2022年5月6日,此方法可用! 本文章可以解决群晖版本6.2.4-25556 Update5(Video Station版本2.5.0-1656)在播放dts、eac3音频编码的视频时提示不支持的问题。 对于群晖6.2.3版本,Video Station版本2.4.9,网上随便搜的方法都可以使用,但是用在6.2.4未必可行。原因在于Video Station版本2

    2023年04月08日
    浏览(42)
  • 基于扩散模型的图像压缩:创建基于Stable Diffusion的有损压缩编解码器

    Stable Diffusion是最近在图像生成领域大火的模型,在对他研究的时候我发现它可以作为非常强大的有损图像压缩编解码器。在介绍之前,我们先看看它与高压缩率下的JPG和WebP相比的而结果,所有都是512x512像素的分辨率为单位: 上面这图的细节如下: 这是JPG压缩结果大小为5

    2024年02月12日
    浏览(46)
  • 自然语言处理(七):来自Transformers的双向编码器表示(BERT)

    BERT(Bidirectional Encoder Representations from Transformers)是一种预训练的自然语言处理模型,由Google于2018年提出。它是基于Transformer模型架构的深度双向(双向指同时考虑上下文信息)表示学习模型。 BERT的目标是通过在大规模文本语料上进行自监督学习来学习通用的语言表示。在预

    2024年02月09日
    浏览(44)
  • BERT:来自 Transformers 的双向编码器表示 – 释放深度上下文化词嵌入的力量

    BERT是 Transformers 双向编码器表示 的缩写,是 2018 年推出的改变游戏规则的 NLP 模型之一。BERT 的情感分类、文本摘要和问答功能使其看起来像是一站式 NLP 模型。尽管更新和更大的语言模型已经出现,但 BERT 仍然具有相关性,并且值得学习它的架构、方法和功能。  这篇综合文

    2024年02月05日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包