happy-llm 深度解析:结合 PyTorch 源码拆解 Transformer 的 Encoder-Decoder 架构与注意力机制
发布时间:2026/9/10 14:04:01来源:尧图网络
happy-llm 深度解析结合 PyTorch 源码拆解 Transformer 的 Encoder-Decoder 架构与注意力机制【免费下载链接】happy-llm 从零开始构建大模型项目地址: https://gitcode.com/GitHub_Trending/ha/happy-llm本篇技术指南以 happy-llm 仓库中Extra-Chapter/transformer-architecture的扩展内容为主体围绕从整体设计到模块细节的主线讲解 Transformer 的 Encoder-Decoder 结构、位置编码设计原则、PyTorch 顶层nn.Transformer的模块化实现以及注意力机制的核心计算。你将掌握如何阅读 PyTorch 的torch/nn/modules/transformer.py源码来理解 Transformer 的整体设计并将论文公式与仓库中 docs/chapter2/code/transformer.py 的手搓实现一一对应建立起从架构图到可运行代码的完整认知。从经典架构开始Encoder-Decoder 结构让我们先从经典架构图理解 Transformer 的整体设计思路。Transformer 分为两个主要部分左侧的编码器Encoder和右侧的解码器Decoder。那么这两块结构的输入和输出分别是什么Encoder 的职责是接受完整的源序列输入将其转换为一个富含语义信息的表示序列。想象一下如果我们要做机器翻译Encoder 就像是一个深度理解原文的专家它需要充分理解整个句子的含义、语法结构和上下文关系。Decoder 则承担着更复杂的任务它需要接受目标序列和编码器输出的表示序列然后输出词汇/字符的概率分布。这就像是一个翻译专家既要理解原文的含义通过 Encoder 的输出又要根据已经翻译的部分来决定下一个词应该是什么。在仓库主教程 docs/chapter2/第二章 Transformer 架构.md 的 2.2 章节中这一 Encoder-Decoder 结构被用于解决 Seq2Seq 任务如机器翻译输入是自然语言序列输出是另一个可能不等长的序列。本节扩展内容正是对 2.2 章节的补充重点从 PyTorch 源码的角度解释 Transformer 各模块的整体设计。Positional Encoding位置编码设计Transformer 本身对位置信息不敏感。比如我爱你和你爱我这两个句子在没有位置信息的情况下模型无法感知到这是语义完全不同的句子。这就像是一个人失去了对词语顺序的感知能力显然无法正确理解语言。因此我们需要一个带有位置信息的向量将其添加到每个 input embedding 上来对不同位置得到不同的表征。这个模块就是架构图中的Positional Encoding。位置编码的三条设计原则在设计编码模块时有三个重要的前提假设这些假设直接影响了最终的实现方案1. 确定性原则每个位置的编码应该是确定的数字不同序列中相同位置的编码应该相同。为什么这个原则如此重要让我们考虑一个反例如果用等分的设计方法将一个序列从 0~1 之间做均匀划分那么序列长度不一样时每个位置上的编码也就不一样。当序列长度为 5 时位置编码可能是 0、0.2、0.4、0.6、0.8但如果序列长度为 10就变成了 0、0.1、0.2……同样对于第二个位置上的字符在第一个序列中是 0.2在第二个序列中又是 0.1这样的编码就失去了确定性。2. 相对关系一致性不同句子中对于任意两个位置之间的相对距离相对关系应该保持一致。这个目的是为了学习通用的语言关系比如修饰词在被修饰词前 1 个位置是通用模式。以下面的长短句举例- 长句子10个词 位置: 0 1 2 3 4 5 6 7 8 9 词汇: I am learning about transformers today in class now - 短句子6个词 位置: 0 1 2 3 4 5 词汇: I like deep learning models在长句子中位置 1 和位置 4 之间的编码关系应该与短句子中位置 2 和位置 5 之间的编码关系完全相同因为模型需要学会的是通用的相对位置关系。3. 泛化能力位置序列应该能推广到没见过的更长序列。假如训练集中序列长度都是 10 以内的但测试集中可能会有长度为 15 的句子我们希望即使测试集中句子长度更长、在训练中没有见过也能通过这样的位置编码推广过去。三角函数编码基于这些假设Transformer 采用了 sin 和 cos 的组合来表征绝对位置信息- 向量维度为偶数PE(pos, 2i) sin(pos / 10000^(2i/d_model)) - 向量维度为奇数PE(pos, 2i1) cos(pos / 10000^(2i/d_model))通过 sin 和 cos 的组合来表征绝对位置的好处是pe(posk)可以写成pe(pos)的线性组合利用三角函数公式sin(A B) sin(A)cos(B) cos(A)sin(B)。这样做的意义是即使测试集中出现了 posk 这种未见过的位置我们也可以把它写成训练集中见过的位置的线性组合而不用担心测试集中遇到更长的句子无法推广。在仓库的手写实现 PositionalEncoding 中正是用向量化的方式完成了这一编码先用torch.arange(0, args.block_size)构造位置序列再用torch.exp(torch.arange(0, args.n_embd, 2) * -(math.log(10000.0) / args.n_embd))计算不同维度上的频率项最后通过pe[:, 0::2] torch.sin(position * div_term)与pe[:, 1::2] torch.cos(position * div_term)分别填充偶数维和奇数维并注册为模型缓冲区register_buffer(pe, pe)随模型一起保存但不参与梯度更新。位置信息的残差传递机制位置编码在最底层添加会不会在深层网络中丢失这个担心是多余的。通过残差连接位置信息能够充分传递到上层网络。假设有一个 N 层的神经网络输入为 x₀包含位置编码那么- 第1层: x₁ x₀ F₁(x₀) - 第2层: x₂ x₁ F₂(x₁) x₀ F₁(x₀) F₂(x₁) - 第3层: x₃ x₂ F₃(x₂) x₀ F₁(x₀) F₂(x₁) F₃(x₂) - ... - 第N层: xₙ x₀ Σᵢ₌₁ⁿ Fᵢ(xᵢ₋₁)可以看到初始的位置信息 x₀ 始终存在于每一层的输出中这确保了位置信息不会随着网络层数的加深而消失。从 PyTorch 源码 API 理解 Transformer 架构设计通过查看 PyTorch 的源码可以了解 Encoder 和 Decoder 中的架构实现。源码位于 PyTorch 的torch/nn/modules/transformer.py本次解析借助的版本是 v2.5.1仓库中 docs/chapter2/code/requirements.txt 锁定的 torch 版本为 2.7.0核心 API 一致。顶层 Transformer 类与核心参数首先PyTorch 定义了一个顶层的Transformer类我们可以通过torch.nn.Transformer来调用它# 使用示例 transformer_model nn.Transformer(d_model512, nhead8, num_encoder_layers6)在Transformer的__init__函数中主要有 5 个核心参数参数默认值含义与设计考量d_model512整个 Transformer 的特征维度原论文中设置的是 512。这个维度需要足够大以承载丰富的语义信息但太大会导致计算复杂度过高nhead8Multi-head attention 的头数目。多头设计的目的是让模型可以捕捉到更多位置与位置之间的关系num_encoder_layers6Encoder 的 block 数目encoder 的每个 block 包含多头自注意力机制和前馈神经网络默认 6 个num_decoder_layers6Decoder 中 block 数目decoder 的每个 block 包含多头自注意力机制、交叉注意力机制以及前馈神经网络dim_feedforward2048前馈神经网络层中间的特征维度。Multihead attention 输出时会首先映射到 2048 这个大的特征空间然后再映射回 512 这样的空间。必须要保证输出的维度仍然是 512这样就可以进行残差连接对应到仓库的手写实现 Transformer 中这些参数被封装进ModelArgs数据类n_embd、n_heads、dim、dropout、max_seq_len、vocab_size、block_size、n_layer模型通过nn.ModuleDict统一注册了词嵌入wte、位置编码wpe、Dropout、Encoder 和 Decoder最后通过lm_head线性层将隐藏维度映射回词表大小。模块化设计四个核心 classinit函数的作用是实例化模块第一个要实例化的模块就是 encoder。encoder 通过TransformerEncoder的 class 去实现实例在这个 class 中需要传入encoder_layer而在TransformerEncoderLayer的 class 中实现了 Multihead self attention 的调用、残差连接、层归一化、全连接层网络这些共同构成一个 encoder_layer。对于 decoder 部分也是一样传入decoder_layer参数这个 layer 包含了自注意力机制、交叉注意力机制以及前馈神经网络。总体上 Transformer 源码就是由四个 class 所构成TransformerEncoderLayer每一个编码层的实现TransformerEncoder负责把这些编码层串起来TransformerDecoderLayer每一个解码层的实现TransformerDecoder把这些解码层串起来这种模块化的设计体现了软件工程的最佳实践单一职责原则和组合优于继承的思想。在仓库手写实现中同样遵循了这一结构EncoderLayer 与 DecoderLayer 负责单层内部的计算而 Encoder 与 Decoder 通过nn.ModuleList把 N 层串联起来并在末尾追加一个 Layer Norm。Forward 函数编排计算流程在forward函数中Transformer 的计算流程非常清晰。首先 encoder 输入是 source 句子以及 padding_mask。encoder 中的注意力机制不需要掩码因此 mask 及 is_causal 参数不需要传入掩码但需要对样本长度做掩盖即padding_mask。这个 mask 表示每一个样本的长度。当我们做训练时序列长度是不一样的有些短的样本在后面的一些位置上就是无效的通过在 softmax 中把无效位置上的值转成负无穷这样经过归一化后概率就变成 0使得这些没有值的位置变得无效。decoder 输入有四个要素target目标句子memoryencoder 输出因为 memory 会输送到交叉注意力中target mask一个考虑因果的 mask在数学上是一个上三角矩阵memory mask和 source sentence 的长度有关在 batch 训练中 source sentence 每一个样本都不太一样memory mask 就是每个输入源序列样本的长度。因果掩码 mask每次预测时decoder 都会有一个输入句子即 output embedding。但这个 output embedding 不能全部给它——如果全部给它的话那就变成了 identity 映射相当于从 x 到 x的关系直接给出那预测出来的答案肯定是从 x 到 x。我们需要保证 output 每次只根据当前要预测单词的左边所有单词去预测这个单词这个单词本身和它右边的单词都不要输送到 output embedding。这样的操作需要通过 mask 来实现随着预测的字符往右进行我们给到 decoder 中的 output 会越来越多所以它就是一个上三角矩阵。在仓库手写实现的 MultiHeadAttention 中因果掩码的生成逻辑是# 创建一个上三角矩阵用于遮蔽未来信息 # 注意因为是多头注意力Mask 矩阵比单头实现多一个维度 if is_causal: mask torch.full((1, 1, args.max_seq_len, args.max_seq_len), float(-inf)) mask torch.triu(mask, diagonal1) self.register_buffer(mask, mask)torch.triu(mask, diagonal1)使得上三角位置包含对角线右上方全部为-inf、其余位置为 0在注意力分数计算后执行scores scores self.mask[:, :, :seqlen, :seqlen]再经过 Softmax 归一化-inf位置的概率自然变为 0从而遮蔽未来信息。注意到这里对 mask 做了:seqlen的截取因为有些序列可能比max_seq_len短。在forward中只有is_causalTrue即 decoder 的掩码自注意力才应用该 mask。Transformer 整体框架这就是 Transformer class 总体上的构成框架init函数去实例化 encoder 和 decoder在forward函数中基于 source、target、source mask、target mask分别入参到 encoder 和 decoder 中最终得到 output即要预测字符的概率。Transformer 本质上是一个自回归的解码过程不是并行的预测输出而是每次只会预测一个、输出一个然后不断进行解码去预测出整体的 target sentence。仓库手写实现中这一过程也体现在Transformer.forward的推理分支logits self.lm_head(x[:, [-1], :])即只取序列中最后一个位置的输出作为下一步预测。Encoder 编码器层接下来分别看四个 class 的具体实现。首先是单个编码器在TransformerEncoderLayer的__init__函数中需要实例化四个关键组件。先看 init 函数中的参数和 Transformer 中传入的一致d_model是整个 Transformer 的特征维度512nhead是 Multi-head attention 中多头自注意力机制中头的数目。多头注意力的设计为什么是多头目的是让模型可以捕捉到更多的位置与位置之间的关系。多头会分为多组的 query、key 和 value每一组会单独地计算 attention 的上下文向量最后把这个向量拼起来再通过 FFN 得到最终的一个向量。这样做的话embedding 特征向量的维度会降低比如说原来的特征向量维度是 512如果分为 8 个头这时每个头向量的维度就会变成 64这里不是通过压缩而是线性变换重组。每个头独立计算注意力后会得到 8 个 64 维的输出向量然后通过拼接操作concatenation将这 8 个 64 维向量首尾相接重新组合成一个 512 维的向量最后再通过一个输出线性变换层得到最终的 512 维输出。仓库实现 MultiHeadAttention.forward 展示了这一过程的工程技巧通过self.wq / self.wk / self.wv三个nn.Linear组合矩阵一次性完成所有头的线性投影再通过view(bsz, seqlen, self.n_heads, self.head_dim)与transpose(1, 2)把张量重排为(B, n_head, T, head_dim)从而并行计算多头注意力——其核心逻辑在于矩阵内积再拼接等同于拼接矩阵再内积。计算完注意力后再transpose(1, 2).contiguous().view(bsz, seqlen, -1)恢复时间维并合并头最后经wo投影回残差流。源码注释特别提醒由于transpose并不改变底层存储必须先contiguous()再view否则 PyTorch 会报错。前馈神经网络dimension feed forward 是前馈神经网络 FFN 的维度因为需要先从 512 到 2048再从 2048 到 512所以设定了两个全连接层。前馈神经网络对每个单独位置进行建模并且不同位置的参数是共享的。类比 1×1 的 pointwise 卷积——对图像中每个像素位置的特征向量独立进行变换参数共享就是为序列中的每个位置都设计相同的参数目的是希望模型学会如何处理特征的通用能力而不是如何处理第 x 个位置的特征的特定能力。FFN 实际上做的是 embedding 相同位置不同维度间的融合在每个位置内部对该位置的不同特征维度进行融合注意力机制则负责位置间的信息交流。仓库中的 MLP 实现正是两个线性层 ReLU Dropout的结构class MLP(nn.Module): 前馈神经网络 def __init__(self, dim: int, hidden_dim: int, dropout: float): super().__init__() self.w1 nn.Linear(dim, hidden_dim, biasFalse) self.w2 nn.Linear(hidden_dim, dim, biasFalse) self.dropout nn.Dropout(dropout) def forward(self, x): return self.dropout(self.w2(F.relu(self.w1(x))))注意Dropout 层只在训练时开启、推理阶段关闭因此许多 Transformer 结构示意图中不会画出该层。Encoder 层的组件实例化在TransformerEncoderLayer的init函数中需要实例化以下实例首先是 Multi-head attention本节着重整体框架其细节在下一章注意力机制部分展开实例化 FFN 前馈神经网络中的两个 Linear 层第一个 Linear 比较大512→2048第二个 Linear 重新投射回 d_model 的尺度2048→512实例化 layer norm在 self attention 之后会经过层归一化以及在前馈神经网络之后也会经过一个层归一化实例化两个 dropout。dropout 是为了使得这个网络具备集成学习的特点即使我们在训练多个模型时也能提高泛化能力。Encoder 前向传播编排计算流程在forward函数中encoder 层的调用很简单。Transformer encoder layer 的第一部分通过 self attention block 得到一个表征self._sa_block然后再加上一个残差连接就是和 x 加起来最后再经过一个层归一化。self attention 的输入是序列 x 和 padding mask这里的序列 x 既充当了 query又充当了 key 和 value即自注意力的 QKV 同源。第二部分是feed forward block把第一部分输出经过每个位置独立的一个全连接层再进行一个残差连接输送到层归一化中就得到 x。这个就是 Transformer encoder 中每个 layer 的输出。需要特别说明的是层归一化的位置原始论文Post-Norm的设计是层归一化在后先子层、后 Norm而 PyTorch 源码中TransformerEncoderLayer默认走的是norm_firstFalse分支之外的另一条路径即先 Norm 再子层的 Pre-Norm 风格。考虑到目前 LLM 一般采用 Pre-Norm 结构可以使训练 loss 更稳定仓库的手写实现也采用 Pre-Norm 风格见 EncoderLayer.forwarddef forward(self, x): # Layer Norm x self.attention_norm(x) # 自注意力 h x self.attention.forward(x, x, x) # 经过前馈神经网络 out h self.feed_forward.forward(self.fnn_norm(h)) return outEncoder 层的串联TransformerEncoderclass 的作用是将多个编码器层串联起来将上一层的输出作为下一层的输入经过多层处理得到最终的编码器输出。init 主要传入两个参数encoder_layerTransformerEncoderLayerclass 的一个实例num_layerstransformer encoder 有多少层层的含义就是 block。encoder 中自注意力机制 前馈神经网络这两块是一个 block也就是一层。仓库中的 Encoder 通过nn.ModuleList([EncoderLayer(args) for _ in range(args.n_layer)])实现多层串联并在全部层之后追加一个最终的LayerNorm。Decoder 解码器解码器的实现比编码器更复杂因为它包含三个子模块需要处理更多的交互。在TransformerDecoderLayer中我们需要实例化三套组件自注意力 交叉注意力 前馈神经网络。在 init 参数中d_modelTransformer 模型特征大小默认 512nheadTransformer decoder 的多头自注意力机制的头数dim_feedforwarddecoder 中 FFN 前馈神经网络的维度。Decoder 的两种注意力机制init 参数中decoder 和 encoder 不同的地方就是需要实例化两个Multihead attention第一个 Multi-head attention 是自注意力机制它针对 decoder 的输入序列即 target sentence embedding 作为输入序列的自身表征Q、K、V 全部来自目标序列本身第二个 Multi-head attention 是交叉注意力机制。我们想知道 decoder multihead attention 的输出和 encoder 输出状态的关联性用该注意力机制跨越了 encoder 和 decoder 两个不同序列——不是 decoder 内部的自我关注而是让 decoder 去关注 encoder 的信息。于是我们通过用 decoder MHA多头注意力的一个输出作为 query然后用 encoder 的输出作为 key 和 value 来算出一个上下文表征。同样 Decoder 要实现两个 Linear 层第一个 Linear 层比较大把交叉自注意力机制的输出投射到更高维的空间2048然后再投射回低维空间2048→512。由于 Decoder 有三个模块自注意力 交叉注意力 前馈神经网络所以这里要实现 3 个 norm 和 3 个 dropout。仓库的 DecoderLayer 忠实呈现了这一结构三个 LayerNormattention_norm_1、attention_norm_2、ffn_norm、一个is_causalTrue的掩码自注意力、一个is_causalFalse的交叉注意力、一个 MLP。Decoder forward编排流程解码器的forward函数体现了三个模块的协同工作第一个模块会把 target sentence序列 x和 target mask 输入到self._sa_block中对 target 句子做自注意力机制的计算结果放入到残差网络中并且经过层归一化得到输出第二个模块依赖于第一个模块输出的 x再和 encoder 输出的 memory 做交叉注意力的计算得到新的表征后经过残差网络和归一化的 norm 输出把第二个模块的输出输送到 FFN 前馈神经网络再次进行残差网络和归一化的 norm得到 decoder 的输出。可以看下_sa_block和_mha_block各自的调用它们都调用的是 Multihead attention只不过它们的 query、key、value 是不一样的self attention 中query、key、value 都是目标序列是自身对自身的相关性计算交叉注意力机制中query 是 decoder 的输出key 和 value 是 encoder 的输出始终是 memory。仓库中的对应实现DecoderLayer.forward通过函数参数显式区分了两者def forward(self, x, enc_out): # Layer Norm x self.attention_norm_1(x) # 掩码自注意力 x x self.mask_attention.forward(x, x, x) # 多头注意力交叉注意力 x self.attention_norm_2(x) h x self.attention.forward(x, enc_out, enc_out) # 经过前馈神经网络 out h self.feed_forward.forward(self.ffn_norm(h)) return out可以看到掩码自注意力中三个入参都是x而交叉注意力中 query 是x、key 和 value 都是enc_outEncoder 输出。通过多个TransformerDecoderLayer构成TransformerDecoder的方式与TransformerEncoder实现类似。注意力机制的核心计算最后看下注意力机制的核心计算。PyTorch 的实际实现更加复杂和优化但核心思想可以用论文版本来理解。注意力机制的直观理解attention 函数就是将一个 query 和一个由 key 和 value 形成的一对元素建立一个连接最终得到一个输出。比如我们去搜索引擎搜索一个词条这个词条就是 query搜索引擎的数据库里有很多词条信息每个信息自身都有个 keyvalue 就是该词条的具体内容。我们通过这个 query搜索引擎就会返回一个搜索结果。这个结果就可以理解为一个注意力机制——基于 query 和 keyvalue 计算出来的一个上下文。注意力机制的计算结果是Value 的加权求和权重是基于 Query 和 Key 的相似度计算出来的。先算 Query 和每个 Key 的相似度基于这个相似度进行 Softmax 归一化得到权重再把这个权重与每个 Key 所对应的 Value 进行加权求和。Scaled Dot-Product Attention在 Transformer 模型中用的是 Scaled Dot-Product Attention。公式中 QKᵀ 会除以一个根号 d_k这个目的就是为了使得 Softmax 的输入分布会更加稳定一点也就是使得它的方差会更小一点。这个 Attention 由三部分构成分别是 Q、K、V它们都是向量。首先把 query 和 key 进行一个矩阵相乘单个样本来看就是向量内积批量来看就是矩阵相乘。内积过后再除以一个根号 d_K把每个位置上的内积放到一起去做一个归一化。这样就可以得到每个位置上的一个概率表示因为 Softmax 出来的结果总和为 1且每一个值都在 0 到 1 之间。得到这样一个概率后把概率和每个位置上的 value 进行一个加权求和最终得到 attention 的一个输出这就是 scaled dot product attention 的计算逻辑。论文中讲的 Multi-head self attention 其实就是有很多个这样的自注意力机制同时计算算完之后把每一个得到的结果拼起来得到 Multi-head self attention 最终的输出。注意力计算的代码实现下面 attention 代码是论文实现的简单版本输入由 query、key 和 value 构成注意力计算函数论文简化版本 def attention(query, key, value, dropoutNone): args: query: 查询值矩阵 key: 键值矩阵 value: 真值矩阵 # 获取键向量的维度键向量的维度和值向量的维度相同 d_k query.size(-1) # 计算Q与K的内积并除以根号dk # transpose 相当于转置 scores torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(d_k) # Softmax p_attn scores.softmax(dim-1) if dropout is not None: p_attn dropout(p_attn) # 根据计算结果对value进行加权求和 return torch.matmul(p_attn, value), p_attn首先会把 q 跟 k 的转置进行矩阵相乘得到一个 1×T 的向量把这个向量做一个 mask。这里的 mask 就是把等于 0 的位置填充一个非常非常小的数负无穷因为负无穷的数经过 Softmax 归一化之后就会变成 0 的概率目的是希望那些不重要位置上的概率赋为 0。这里只有一个 mask所以你可以理解这是一个自注意力机制的实现如果有两个 mask那就是交叉注意力机制的实现。得到 p_attn 概率分布之后再把这个 p_attn 跟 value 进行加权求和得到最终自注意力机制的输出。这是单个自注意力机制的计算逻辑如果是多头的话最终把单个的输出拼起来就好。不同注意力机制的 QKV 来源在 Transformer 模型中不同的注意力机制有着不同的 QKV 来源和映射方式encoder 层的 query、key 和 value在编码器中都是由 word embedding 加上 position encoding 后通过三个独立的线性映射得到 QKVdecoder 中 self attention 层同样也是通过 target sentence embedding position encoding通过三个独立的线性映射得到 QKV交叉 attention 中query 是由 decoder 的输出经过一个线性映射得到的key 和 value 是编码器的输出 memory 分别经过两个映射得到。仓库手写实现中 MultiHeadAttention.forward 的签名forward(self, q, k, v)正好支持上述三种用法EncoderLayer 中调用attention.forward(x, x, x)实现自注意力DecoderLayer 中掩码自注意力调用mask_attention.forward(x, x, x)交叉注意力调用attention.forward(x, enc_out, enc_out)与论文中 QKV 来源的三种情形一一对应。总结本节从三个层面完整拆解了 Transformer 的 Encoder-Decoder 架构设计层面Encoder 将源序列编码为语义表示Decoder 结合目标序列与 memory 输出概率分布位置编码通过 sin/cos 组合同时满足确定性、相对关系一致性与长度泛化三条设计原则并依靠残差连接逐层传递。源码层面PyTorch 的nn.Transformer由TransformerEncoderLayer、TransformerEncoder、TransformerDecoderLayer、TransformerDecoder四个 class 模块化组合而成其 forward 流程中 padding mask、因果上三角 mask 与 memory mask 各司其职。计算层面注意力本质是基于 Query 与 Key 的相似度对 Value 加权求和除以根号 d_k 的缩放保证 Softmax 输入分布稳定多头机制通过分组计算与拼接捕捉更丰富的位置关系。若希望从零手搓一个完整可运行的 Transformer含 Embedding、位置编码、MultiHeadAttention、LayerNorm、MLP、Encoder/Decoder 组装与训练/推理 forward 分支可以对照仓库中的 docs/chapter2/code/transformer.py 逐步实现其运行依赖见 docs/chapter2/code/requirements.txt完整的主教程讲解可继续阅读 docs/chapter2/第二章 Transformer 架构.md。【免费下载链接】happy-llm 从零开始构建大模型项目地址: https://gitcode.com/GitHub_Trending/ha/happy-llm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网