逆元装置 ▍ INVERSION

丽·芙

CONSTRUCT — LIV
▍
意识海深度 · 回廊稳定
逆元装置 · 待机中
指挥官链接 · 未认证

深入Transformer:从注意力机制到LLM底层原理

Published 2025-03-12 00:00 847 words 5 min read

This post is not yet available in English. Showing the original.
逐层剖析Transformer架构,理解自注意力、多头注意力、位置编码与残差连接的设计思路。

为什么要理解 Transformer?

2017 年《Attention Is All You Need》这篇论文颠覆了 NLP 领域。在它之前,机器翻译主要依赖 RNN/LSTM,存在”长距离依赖消失”和”无法并行计算”两个痛点。Transformer 通过自注意力机制同时解决了这两个问题,并成为 GPT、BERT、Claude 等所有现代 LLM 的基石。

自注意力机制(Self-Attention)

直观理解

假设有一句话:“丽芙敲代码到深夜,她真的热爱编程。” 当模型处理”她”这个字时,它需要知道”她”指的是”丽芙”而非”代码”。自注意力的作用就是让每个词都去”看”句子中的所有词,并给相关度打分。

数学原理

每个词被映射为三个向量:

  • Query(查询):我要找什么?
  • Key(键):我有什么?
  • Value(值):我的实际内容?

这三个向量通过输入词向量乘以三个权重矩阵得到:

Q=X⋅WQ,K=X⋅WK,V=X⋅WVQ = X \cdot W^Q, \quad K = X \cdot W^K, \quad V = X \cdot W^V

自注意力分数的计算:

Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V

关键点:

  • QKTQK^T:计算所有词两两之间的相似度,得到一个「注意力矩阵」
  • \sqrt:缩放因子,防止点积过大导致 softmax 进入梯度消失区域
  • \text:将分数转化为概率分布
  • 左乘 VV:按注意力权重加权求和

代码实现

import torch
import torch.nn.functional as F

def self_attention(Q, K, V):
    d_k = Q.size(-1)
    scores = torch.matmul(Q, K.transpose(-2, -1)) / torch.sqrt(torch.tensor(d_k, dtype=torch.float32))
    attention_weights = F.softmax(scores, dim=-1)
    return torch.matmul(attention_weights, V)

多头注意力(Multi-Head Attention)

单头注意力只能捕获一种关系模式。多头注意力让模型同时关注不同表示子空间中的信息:

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model=512, num_heads=8):
        super().__init__()
        self.d_k = d_model // num_heads
        self.num_heads = num_heads
        self.W_Q = nn.Linear(d_model, d_model)
        self.W_K = nn.Linear(d_model, d_model)
        self.W_V = nn.Linear(d_model, d_model)
        self.W_O = nn.Linear(d_model, d_model)

    def forward(self, x):
        # x: (batch, seq_len, d_model)
        batch, seq_len, _ = x.size()
        Q = self.W_Q(x).view(batch, seq_len, self.num_heads, self.d_k).transpose(1, 2)
        K = self.W_K(x).view(batch, seq_len, self.num_heads, self.d_k).transpose(1, 2)
        V = self.W_V(x).view(batch, seq_len, self.num_heads, self.d_k).transpose(1, 2)

        attn_output = self_attention(Q, K, V)
        attn_output = attn_output.transpose(1, 2).contiguous().view(batch, seq_len, -1)
        return self.W_O(attn_output)

位置编码

Transformer 不像 RNN 那样天然知道词的先后顺序。位置编码的任务就是给模型注入位置信息。

原始论文使用正弦位置编码:

PE(pos,2i)=sin⁡(pos100002i/dmodel)PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right)

PE(pos,2i+1)=cos⁡(pos100002i/dmodel)PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right)

不同频率的正弦波使得模型可以轻易学习到相对位置信息——因为任意两个位置的 PE 之间存在线性关系。

现代的 LLM(如 GPT-4)大多使用可学习的位置嵌入(Learned Positional Embedding)或 RoPE(旋转位置编码),效果更好。

残差连接与层归一化

每个子层(自注意力 / 前馈网络)的输出都会加上输入(残差连接),然后做 Layer Normalization:

Output=LayerNorm(x+Sublayer(x))\text{Output} = \text{LayerNorm}(x + \text{Sublayer}(x))

残差连接让梯度可以毫不衰减地传播到底层,使得训练极深的网络成为可能——这也是 GPT-4 能有上百层的原因。

小结

组件作用
自注意力全局上下文建模
多头注意力多角度语义捕捉
位置编码注入序列顺序
残差连接梯度长距离传播
层归一化训练稳定性

理解了这些,GPT 和 BERT 的区别就一目了然了:GPT 用了因果掩码(只看上文),BERT 用了双向注意力(同时看上下文)。下一篇我们会进入 GPT 的实现细节。