当前位置: 首页 > news >正文

7. 解码器层(DecoderLayer):Transformer的“目标序列生成器”

解码器层是Transformer生成目标序列的核心单元——整个解码器由N个完全相同的解码器层堆叠而成(原论文N=6),它的任务是:接收目标序列(如翻译任务中的中文句子)和编码器输出的上下文特征(memory),通过“自约束+跨交互+细加工”逐步生成高质量的目标序列特征,最终传给线性层预测每个位置的词。

相比于编码器层(2个子层),解码器层多了1个子层——这是因为它要处理两个关键关系:目标序列内部的依赖(需防“偷看”)目标序列与输入序列的关联(需“对齐”)

一、解码器层的“定位与核心差异”

先明确解码器层在整个Transformer中的位置和作用:
「目标序列→嵌入层+位置编码→解码器层1→解码器层2→…→解码器层6→线性层→预测词」
同时,每个解码器层还需要接收编码器的输出(memory) ——这是解码器与编码器交互的唯一途径。

解码器层与编码器层的核心差异:

对比维度编码器层(EncoderLayer)解码器层(DecoderLayer)
子层数量2个(自注意力+前馈网络)3个(掩码自注意力+交叉注意力+前馈网络)
注意力类型仅自注意力(无掩码)2种(掩码自注意力+交叉注意力)
依赖外部输入无(仅依赖自身输入x)有(依赖编码器的memory)
核心任务提取输入序列特征生成目标序列特征(需对齐输入)

二、代码逐行解析:从初始化到前向传播

class DecoderLayer(nn.Module):def __init__(self, d_model, self_atten, cross_atten, feed_forward, dropout):super(DecoderLayer, self).__init__()# 1. 接收3个核心模块实例(适配3个子层)self.self_atten = self_atten        # 👉 掩码自注意力(防止偷看未来词)self.cross_atten = cross_atten      # 👉 交叉注意力(连接编码器与解码器)self.feed_forward = feed_forward    # 👉 前馈网络(局部特征加工)# 2. 3个AddNorm模块:对应3个子层,确保每层训练稳定(防梯度消失+稳分布)self.sublayer = nn.ModuleList([AddNorm(d_model, dropout),  # 对应「掩码自注意力子层」AddNorm(d_model, dropout),  # 对应「交叉注意力子层」AddNorm(d_model, dropout)   # 对应「前馈网络子层」])

1. __init__方法关键参数解读

参数名作用说明
d_model词向量维度(如512),确保所有模块维度一致,数据顺畅流动
self_atten多头自注意力实例(同编码器的MultiHeadAttention),但需传入未来掩码,防止偷看
cross_atten多头注意力实例(同MultiHeadAttention),用于“解码器→编码器”的交叉交互
feed_forward前馈网络实例(同EncoderLayer的FeedForward),逐位置加工特征
dropoutDropout概率(如0.1),传给AddNorm防止过拟合

⚠️ 注意点1:为什么需要两个注意力模块?

  • self_atten:处理目标序列内部的依赖(如“猫吃鱼”中“吃”与“猫”“鱼”的关系),但必须加“未来掩码”,避免生成时“偷看”后面的词;
  • cross_atten:处理解码器与编码器的跨序列依赖(如“吃”对应输入序列的“eats”),是两者信息交互的唯一通道。
    def forward(self, x, memory, src_mask, tag_mask):# x:解码器输入(目标序列的嵌入+位置编码,或上一层解码器输出),形状[batch_size, tag_seq_len, d_model]# memory:编码器输出的上下文特征,形状[batch_size, src_seq_len, d_model]# src_mask:源序列掩码(遮挡输入序列的<PAD>),形状[batch_size, 1, 1, src_seq_len]# tag_mask:目标序列掩码(遮挡目标序列的<PAD> + 未来词),形状[batch_size, 1, tag_seq_len, tag_seq_len]# 子层1:掩码自注意力(处理目标序列内部依赖,防偷看未来词)x = self.sublayer[0](x, lambda y: self.self_atten(y, y, y, tag_mask))# 子层2:交叉注意力(连接编码器,对齐输入与目标序列)x = self.sublayer[1](x, lambda y: self.cross_atten(y, memory, memory, src_mask))# 子层3:前馈网络(局部特征细加工)x = self.sublayer[2](x, lambda y: self.feed_forward(y))return x  # 输出形状不变:[batch_size, tag_seq_len, d_model],特征更适配目标序列生成

2. forward方法核心逻辑拆解(结合翻译例子)

我们用英语→中文翻译任务举例(输入序列:“cat eats fish”,目标序列:“猫吃鱼”),逐个解释每个步骤:

(1)先明确4个输入的作用(小白必懂)
输入参数具体例子(batch_size=1)核心作用
x目标序列“猫吃鱼”的嵌入+位置编码,形状[1,3,512]解码器当前要处理的目标序列特征
memory编码器处理“cat eats fish”后的输出,形状[1,3,512]输入序列的上下文特征,供解码器对齐使用
src_mask若输入无PAD,则全1,形状[1,1,1,3]遮挡输入序列的,避免交叉注意力关注无效词
tag_mask未来掩码+PAD掩码,形状[1,1,3,3](下三角全1,上三角0)① 遮挡目标序列的;② 防止生成时偷看未来词
(2)子层1:掩码自注意力——“目标序列自己关注自己,但不能偷看”

这是解码器层最特殊的子层,核心是**“掩码”**,解决“自回归生成”的关键问题:

  • 自回归生成:解码器生成目标序列时,是“逐词生成”的(先生成“猫”,再生成“吃”,最后生成“鱼”),生成第i个词时,只能用前i-1个词的信息,不能“偷看”第i个及以后的词。

📌 重点:掩码如何工作?
以目标序列“猫吃鱼”(长度3)为例,tag_mask的形状是[1,1,3,3],值为:

[[[[1, 0, 0],  # 生成“猫”(第0个词)时,只能看自己(第0个),不能看“吃”“鱼”[1, 1, 0],  # 生成“吃”(第1个词)时,能看“猫”“吃”,不能看“鱼”[1, 1, 1]]]]# 生成“鱼”(第2个词)时,能看所有前词

当计算注意力分数时,tag_mask中为0的位置会被设为负无穷,softmax后权重为0,相当于“完全不关注”。

同时,self.self_atten(y, y, y, tag_mask)query=key=value=y(y是归一化后的x),说明是“目标序列自注意力”,但通过tag_mask限制了关注范围。

lambda函数的作用和编码器层一致:适配AddNorm的接口,将“归一化后的y”传入自注意力,并带上tag_mask

(3)子层2:交叉注意力——“解码器向编码器‘提问’,找对应关系”

这是解码器与编码器“沟通”的唯一桥梁,核心是**“query来自解码器,key/value来自编码器”**,实现“目标序列与输入序列的对齐”。

用翻译例子解释:

  • query:解码器当前的特征y(归一化后的x,如“吃”的向量)——相当于“解码器的提问:我现在处理‘吃’,输入序列里哪个词和我对应?”;
  • key:编码器的memory(如“eats”的向量)——相当于“编码器的回答候选:这是输入里的‘eats’,你看看是不是对应?”;
  • value:编码器的memory(和key相同)——相当于“编码器的详细信息:如果‘吃’对应‘eats’,就用我的向量来更新你的特征”;
  • src_mask:遮挡输入序列的(如输入无PAD,全1)——确保解码器只关注输入序列中的有效词(“cat”“eats”“fish”)。

通过交叉注意力,“吃”的向量会被更新为“融合了‘eats’上下文的特征”,实现“输入与目标的对齐”——这就是翻译任务中“词对齐”的核心原理。

(4)子层3:前馈网络——“细加工对齐后的特征”

和编码器层的前馈网络功能完全一致:逐位置独立处理每个词的向量,通过“升维(512→2048)→ReLU激活→降维(2048→512)”提炼细节特征。

比如经过交叉注意力后,“吃”的向量已经对齐了“eats”的信息,前馈网络会进一步加工这个向量,提取更细的特征(如“‘吃’是动词,对应输入的‘eats’,主语是‘猫’,宾语是‘鱼’”),为后续预测词做准备。

三、关键注意点(换色突出,小白必记)

1. 两个掩码的区别:不要混淆src_mask和tag_mask!

掩码类型作用范围遮挡内容形状示例(seq_len=3)
src_mask源序列(输入)仅遮挡符号[1,1,1,3](全1,无PAD时)
tag_mask目标序列(输出)① 遮挡;② 遮挡未来词[1,1,3,3](下三角1,上三角0)
核心目的保护输入有效信息① 保护目标有效信息;② 保证自回归——

2. 三个子层的顺序不能乱!必须是“掩码自注意力→交叉注意力→前馈网络”

顺序设计的逻辑:

  1. 先处理目标序列内部依赖(掩码自注意力):先搞清楚“猫”和“吃”的关系,再去对齐输入;
  2. 再对齐输入与目标的关系(交叉注意力):基于内部依赖的结果,找输入里对应的词,避免对齐混乱;
  3. 最后细加工特征(前馈网络):在对齐的基础上提炼细节,确保特征质量。
    如果顺序颠倒(如先交叉注意力再掩码自注意力),会导致“目标序列内部关系没理清就去对齐输入”,生成的序列逻辑混乱(如翻译出“吃猫鱼”)。

3. 交叉注意力的query/key/value来源是固定的!

永远是:query=解码器特征(y),key=编码器memory,value=编码器memory
这是因为:解码器需要“主动向编码器提问”(用自己的query找编码器的key),而不是编码器向解码器提问——如果key/value来自解码器,就失去了“对齐输入”的意义。

四、知识拓展:为什么解码器层也要堆叠N=6层?

和编码器层类似,单层解码器只能处理简单的依赖和对齐:

  • 底层(1-2层):只能捕捉目标序列的局部依赖(如“猫”和“吃”),对齐输入的局部词(如“猫”对应“cat”);
  • 中层(3-4层):能捕捉目标序列的短语级依赖(如“猫吃”),对齐输入的短语(如“猫吃”对应“cat eats”);
  • 高层(5-6层):能捕捉目标序列的全局依赖(如“猫吃鱼”的整体逻辑),对齐输入的全局语义(如“猫吃鱼”对应“cat eats fish”)。

N=6层是“生成质量”和“计算效率”的平衡——层数太少,生成的序列可能逻辑混乱(如“鱼吃猫”);层数太多,训练慢且容易过拟合。

五、总结:解码器层的核心价值

解码器层通过“掩码自注意力(约束自身)+ 交叉注意力(对齐输入)+ 前馈网络(加工特征) ”的三步流程,实现了“在不偷看未来词的前提下,结合输入序列信息,逐步生成高质量目标序列特征”的核心任务。

用一句话记住:解码器层=“自约束”(掩码自注意力)+“跨对齐”(交叉注意力)+“细加工”(前馈网络),堆叠起来就是Transformer的“目标序列生成引擎”

http://www.dtcms.com/a/509672.html

相关文章:

  • 网站报价页做一款app需要什么技术
  • 没有英文网站怎么做外贸只做水果的网站
  • 网站流量怎么变现呢南阳定制网站制作价格低
  • 品牌网站开发策划书曲靖网站微信建设
  • 网站开发的一次性收益做微信公众号第三网站
  • 自己做的网站上传手机做电商怎么赚钱
  • 【GESP】C++五级考试大纲知识点梳理, (5) 算法复杂度估算(多项式、对数)
  • 微商城手机网站制作公司网站设计手机版为什么那么多背景
  • 省建设厅网站安徽怎么做新网站上线通稿
  • 江西建设银行分行网站手机交互网站
  • 昌都网站建设西安找工作哪个网站好
  • 万网 网站 ip低价网站建设教程
  • 营销型网站制作培训多少钱昆明市建设局官方网站
  • 银川建设局网站温州网站制作软件
  • 自己做网站有什么意义新手如何做网站推广
  • 原创网站源码网站内容添加
  • vs2015做网站如何添加控件wordpress设置付费
  • 下载软件网站程序员40岁以后出路
  • 胶州网站建设 网络推广合肥知名网站制作公司
  • 网站 关键词 地区医院官方网站建设
  • 网站 维护 费用广州冼村街道办事处电话
  • 西宁建设公司网站房地产最新消息政策代表了什么
  • 扁平化网站首页广州动画制作公司
  • 网站用的横幅广告怎么做做维修广告效最好是哪个网站吗
  • 本地网站建设公司国外做gif的网站
  • 做网站后台教程视频课题组网站建设
  • 广元专业高端网站建设广东的互联网公司有哪些
  • 北京网站开发网站建设报价怎么查到网站是谁做的
  • 网站文章的作用网站设计技能
  • 建视频网站需要多少钱竞价代运营厂家