
在自然语言处理领域,从序列到序列的建模曾长期被RNN、LSTM等循环神经网络主导。然而,这些模型在处理长序列时,普遍面临梯度消失/爆炸和难以并行计算的瓶颈。2017年,一篇名为《Attention Is All You Need》的论文横空出世,彻底改变了这一格局。Transformer架构摒弃了循环结构,完全依赖自注意力机制来捕捉序列内部的依赖关系,不仅在机器翻译任务上取得了突破性进展,其强大的并行能力和对长距离依赖的建模能力,更使其成为当今深度学习,特别是大语言模型(LLM)和视觉Transformer(ViT)的基石。无论你是希望理解ChatGPT、GPT-4等大模型背后核心思想的学生和研究者,还是计划在项目中应用或微调Transformer相关模型的工程师,掌握其原理都至关重要。本文将系统性地拆解Transformer的每一个核心组件,从最基础的自注意力机制到完整的编码器-解码器架构,并结合代码示例和数学直觉,帮助你从零开始构建对Transformer的深刻理解,最终能够“手撕”出其前向传播过程。1. Transformer核心思想与整体架构在深入细节之前,我们首先需要理解Transformer要解决的根本问题以及它的宏观设计。1.1 从序列建模的挑战到“注意力”的崛起传统的RNN及其变体(如LSTM)按时间步顺序处理序列。对于第t个时间步,其隐藏状态h_t依赖于当前输入x_t和前一时间步的隐藏状态h_{t-1}。这种串行特性导致:计算效率低:无法充分利用GPU等硬件的并行计算能力。长程依赖建模困难:尽管LSTM通过门控机制有所缓解,但信息在长序列中传递仍会衰减。位置信息隐式编码:RNN通过处理顺序隐含了位置信息,但这并不直接和明确。注意力机制的引入是关键的转折点。其核心思想是:当模型处理序列中的某个元素(如一个词)时,它可以直接“关注”序列中任何其他位置的元素,并动态地为这些元素分配不同的重要性权重,而不是仅仅依赖上一个隐藏状态。Transformer将这种思想推向极致,提出了“自注意力”(Self-Attention),让序列中的每个元素都与其他所有元素进行交互,从而一次性捕获全局上下文。1.2 Transformer架构总览Transformer是一个典型的编码器-解码器(Encoder-Decoder)架构,最初用于序列到序列的任务,如机器翻译。输入序列 - [编码器] - 中间表示 - [解码器] - 输出序列其整体结构如下图所示(此处用文字描述,建议读者搜索“Transformer架构图”辅助理解):编码器(Encoder):由N个(原论文中N=6)完全相同的层堆叠而成。每一层包含两个子层:多头自注意力机制(Multi-Head Self-Attention)前馈神经网络(Position-wise Feed-Forward Network)每个子层周围都应用了残差连接(Residual Connection)和层归一化(Layer Normalization)。即,每个子层的输出是LayerNorm(x + Sublayer(x))。解码器(Decoder):同样由N个相同的层堆叠而成。每一层包含三个子层:掩码多头自注意力机制(Masked Multi-Head Self-Attention):确保在预测第t个位置时,只能看到t时刻及之前的信息,防止信息泄露。多头交叉注意力机制(Multi-Head Cross-Attention):其Query来自解码器上一层的输出,而Key和Value来自编码器的最终输出。这使得解码器可以“关注”输入序列的相关部分。前馈神经网络(Position-wise Feed-Forward Network)同样,每个子层都应用了残差连接和层归一化。此外,架构的输入和输出端还涉及位置编码(Positional Encoding)和线性层+Softmax输出层。2. 核心组件深度拆解理解了整体框架后,我们来逐一攻克其核心组件。2.1 自注意力机制(Self-Attention)这是Transformer的灵魂。其目的是计算序列中每个元素相对于所有元素的表示。计算过程(缩放点积注意力):输入表示:假设我们有一个输入序列矩阵X,形状为[seq_len, d_model](seq_len是序列长度,d_model是模型维度,如512)。线性变换:通过三个不同的权重矩阵 W^Q, W^K, W^V(形状均为[d_model, d_k]或[d_model, d_v],通常d_k = d_v),将每个输入向量转换为三个向量:查询(Query)、键(Key)、值(Value)。Q = X * W^Q # [seq_len, d_k] K = X * W^K # [seq_len, d_k] V = X * W^V # [seq_len, d_v]计算注意力分数:对于序列中的每个位置i(对应Q的第i行),我们计算它与序列中所有位置j(对应K的所有行)的相似度。论文中使用点积(Dot-Product)作为相似度度量。scores = Q * K^T # [seq_len, seq_len]分数矩阵scores[i, j] 表示位置i对位置j的关注程度。缩放(Scale):为了防止点积结果过大导致Softmax梯度消失,将分数除以sqrt(d_k)。scores = scores / sqrt(d_k)应用Softmax:对每一行(即每个Query)的分数应用Softmax,将其转化为概率分布,即注意力权重(和为1)。attention_weights = softmax(scores, dim=-1) # [seq_len, seq_len]加权求和:用注意力权重对Value向量进行加权求和,得到该位置的输出。Z = attention_weights * V # [seq_len, d_v]输出矩阵Z的每一行都是原始序列所有位置值的加权组合,包含了全局上下文信息。为什么有效?自注意力允许模型直接建立任意两个位置间的联系,无论它们相距多远。计算Q*K^T的过程是高度并行的,因为所有位置对的计算是独立的。2.2 多头注意力(Multi-Head Attention)单一的自注意力机制可能只关注到一种模式的依赖关系(例如语法依赖)。为了增强模型捕捉不同子空间信息的能力,Transformer采用了“多头”机制。操作流程:将Q, K, V通过不同的线性投影矩阵,分别投影h次(h是头数,如8次),得到h组不同的Q_i, K_i, V_i。每次投影的维度降为d_k = d_v = d_model / h。对每一组(Q_i, K_i, V_i)并行地执行缩放点积注意力,得到h个输出矩阵Z_i,形状为[seq_len, d_v]。将h个输出矩阵在特征维度上拼接(Concat)起来,形状变为[seq_len, h * d_v](即[seq_len, d_model])。最后通过一个线性投影矩阵W^O将拼接后的结果映射回