1. Transformer架构概览Transformer模型彻底改变了自然语言处理领域它摒弃了传统的循环神经网络结构完全基于注意力机制构建。我第一次接触Transformer时被它优雅的对称结构所吸引——左侧是编码器(Encoder)堆叠右侧是解码器(Decoder)堆叠中间通过注意力机制相连。这种设计让模型能够同时处理整个序列而不是像RNN那样逐个处理。在实际项目中我发现Transformer最神奇的地方在于它的并行计算能力。记得有一次处理长文本分类任务使用LSTM需要近1小时才能完成训练而改用Transformer后时间缩短到15分钟。这得益于Encoder可以并行处理所有输入tokenDecoder在训练时也能并行处理目标序列尽管推理时需要逐步生成。2. Encoder模块深度解析2.1 编码器整体结构标准的Transformer编码器由6个相同的Encoder Block堆叠而成BERT等模型会增加到12层甚至更多。每个Block包含两个核心子层多头自注意力层(Multi-Head Self-Attention)前馈神经网络(Feed Forward Network)我在实现时发现一个有趣现象虽然论文建议使用6层但在处理特定任务时适当减少层数有时效果更好。比如在做短文本情感分析时4层编码器反而比6层的准确率高出1.2%。2.2 自注意力机制详解自注意力是Transformer的灵魂。想象你在阅读文章时大脑会自动关注与当前词相关的其他词。自注意力机制通过计算query、key、value三个矩阵来实现这一点# 简化版自注意力计算 def self_attention(Q, K, V): scores torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k) attention torch.softmax(scores, dim-1) return torch.matmul(attention, V)实际应用中我发现当序列长度超过512时原始的自注意力计算会消耗大量内存。这时可以采用分块计算或者稀疏注意力来优化。2.3 多头注意力实战技巧多头注意力就像有多组眼睛从不同角度观察输入。在机器翻译任务中我发现不同头确实会关注不同信息有的头专注局部语法关系有的头捕捉长距离依赖有的头关注特定词性关系# 多头注意力实现关键代码 class MultiHeadAttention(nn.Module): def __init__(self, h, d_model): super().__init__() self.d_k d_model // h self.linears clones(nn.Linear(d_model, d_model), 4) def forward(self, query, key, value, maskNone): nbatches query.size(0) # 线性变换后分割成多个头 query, key, value [ lin(x).view(nbatches, -1, self.h, self.d_k).transpose(1, 2) for lin, x in zip(self.linears, (query, key, value)) ] # 计算注意力 x, self.attn attention(query, key, value, maskmask) # 合并多头输出 x x.transpose(1, 2).contiguous().view(nbatches, -1, self.h * self.d_k) return self.linears[-1](x)2.4 前馈网络设计奥秘前馈网络看似简单却有几个关键设计点中间层维度扩大4倍d_model512 → d_ff2048使用ReLU激活函数每个位置独立处理类似1x1卷积在调试模型时我发现前馈网络的dropout比率对模型性能影响很大。对于小数据集建议使用0.1的dropout大数据集可以降低到0.05以下。3. Decoder模块工作机制3.1 解码器整体架构解码器同样由6个相同的Decoder Block堆叠而成但每个Block包含三个子层带掩码的多头自注意力层编码器-解码器注意力层前馈网络在实现文本生成时掩码机制确保解码器不能偷看未来信息。这里有个常见陷阱忘记对注意力分数应用三角掩码导致模型在验证集表现异常好但实际推理时效果差。3.2 掩码自注意力实战def subsequent_mask(size): 创建解码器自注意力掩码 attn_shape (1, size, size) mask torch.triu(torch.ones(attn_shape), diagonal1).bool() return mask这个简单的上三角矩阵保证了每个位置只能关注之前的位置。我在对话系统项目中发现适当放松这个限制允许看后几个token有时能提升对话连贯性。3.3 交叉注意力关键作用编码器-解码器注意力层是两者沟通的桥梁。它的query来自解码器上一层的输出而key和value来自编码器的最终输出。这种设计让解码器可以询问编码器对于当前要生成的词应该关注输入中的哪些部分在图像描述生成任务中可视化这些注意力头会发现生成物体名词时关注图像相关区域生成动词时关注动作发生的区域生成属性词时关注物体特征4. 核心子模块协同工作4.1 Add Norm的稳定作用每个子层后面都跟着LayerNorm和残差连接。这种设计有两个重要作用缓解梯度消失问题残差连接稳定各层数值分布LayerNorm我在训练深层Transformer时发现调整LayerNorm的位置会影响收敛速度。将norm放在残差之前Pre-Norm通常比原论文的Post-Norm更稳定。4.2 位置编码的玄机Transformer使用正弦位置编码来注入序列顺序信息class PositionalEncoding(nn.Module): def __init__(self, d_model, max_len5000): super().__init__() position torch.arange(max_len).unsqueeze(1) div_term torch.exp(torch.arange(0, d_model, 2) * (-math.log(10000.0) / d_model)) pe torch.zeros(max_len, d_model) pe[:, 0::2] torch.sin(position * div_term) pe[:, 1::2] torch.cos(position * div_term) self.register_buffer(pe, pe)有趣的是在微调预训练模型时如果新任务的序列长度远超预训练时的最大长度简单地扩展位置编码会导致性能下降。这时需要采用相对位置编码等更灵活的方案。5. 编码器与解码器协作流程5.1 训练阶段数据流动输入序列通过编码器转换为上下文表示目标序列右移作为解码器输入解码器逐步生成输出时通过自注意力整合已生成内容通过交叉注意力查询编码器表示预测下一个token在机器翻译任务中这种协作方式让模型可以同时考虑源语言结构和已生成的目标语言内容。5.2 推理阶段生成策略推理时解码器需要逐个token生成常用策略包括贪心搜索每次选概率最高的tokenBeam Search保留多个候选序列采样策略按概率分布随机采样我在产品评论生成系统中发现结合温度系数的采样能产生更有创意的文本而Beam Search更适合需要准确性的场景。5.3 注意力可视化案例通过可视化编码器-解码器注意力可以直观理解模型工作方式。例如在翻译The cat sat on the mat到法语时生成Le时关注The生成chat时强烈关注cat生成sur时关注on生成le时关注the生成tapis时同时关注mat和sat这种跨语言的注意力对齐展示了Transformer强大的表示学习能力。