一、背景认知:为什么 Transformer 是 AI 时代的基石

1.1 传统模型的致命缺陷

在 Transformer 出现之前(2017 年以前),自然语言处理(NLP)主要依赖RNN(循环神经网络)和它的改进版LSTM/GRU。它们的工作原理是:逐字串行处理文本,就像人读书一样一个字一个字看。

但这带来了两个无法解决的核心问题:

  • 计算速度极慢:必须等前一个字处理完才能处理下一个字,无法利用现代 GPU 的并行计算能力
  • 长距离依赖丢失:处理长文本时,前面的信息会被逐渐 "遗忘"(比如读一本 1000 页的书,看到最后已经忘了开头讲了什么)

1.2 Transformer 的诞生与革命

  • 诞生时间:2017 年 6 月,谷歌团队发表论文《Attention Is All You Need》(注意力就是你需要的一切)
  • 核心创新完全抛弃了循环结构,只使用注意力机制
  • 革命性突破
    1. 支持全文并行计算,速度比 LSTM 快 100 倍以上
    2. 完美解决长距离依赖问题,可以同时关注文本中任意位置的词
    3. 架构极其灵活,可扩展到几乎所有 AI 任务(文本、图像、音频、视频)

1.3 历史地位与应用

  • 所有现代大模型的唯一基础架构:GPT 系列、Llama 系列、Qwen 系列、BERT、Gemini 全部基于 Transformer
  • 开启了大模型时代:没有 Transformer 就没有今天的 ChatGPT 和生成式 AI
  • 跨领域通用:现在已经扩展到计算机视觉(ViT)、语音识别(Whisper)、蛋白质结构预测(AlphaFold)等领域

二、核心配置:Transformer 架构逐模块拆解

Transformer 整体采用 ** 编码器 - 解码器(Encoder-Decoder)** 架构,就像一个 "翻译官":

  • 编码器:负责 "读懂" 输入文本,提取语义信息
  • 解码器:负责 "生成" 输出文本,根据编码器的理解逐字生成结果
输入文本 → 编码器(×6) → 语义向量 → 解码器(×6) → 输出文本

2.1 输入处理:让计算机能 "看懂" 文字

计算机只能处理数字,不能直接处理文字,所以第一步要把文字转换成数字向量。

2.1.1 词嵌入(Word Embedding)
  • 作用:把每个词转换成一个固定长度的向量,向量中包含了词的语义信息
  • 直观理解:意思相近的词,它们的向量在空间中距离也近
    • 比如:"猫" 的向量和 "狗" 的向量很接近,和 "汽车" 的向量距离很远
  • 实现:通常是一个大的查找表,每个词对应表中的一行向量
  • 常见维度:小模型 128 维,大模型 4096 维(GPT-3.5)、8192 维(GPT-4)
2.1.2 位置编码(Positional Encoding)
  • 为什么需要:Transformer 没有循环结构,不知道词的顺序。如果没有位置编码,"我爱你" 和 "你爱我" 对它来说是完全一样的
  • 实现方式:使用正弦和余弦函数生成位置向量,然后和词嵌入向量相加
  • 公式(不用死记,理解即可):
    PE(pos, 2i) = sin(pos / 10000^(2i/d_model))
    PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))
    
    • pos:词在句子中的位置(0,1,2...)
    • i:向量的维度索引
    • d_model:词嵌入的总维度

2.2 编码器层:提取语义信息

每个编码器层由两个核心子层组成:多头自注意力机制前馈神经网络,每个子层后面都跟着残差连接 + 层归一化

2.2.1 核心中的核心:自注意力机制(Self-Attention)
  • 直观理解:当我们理解一个词的意思时,会自动关注句子中其他相关的词。
    • 比如句子:"动物没有穿过街道,因为它太累了"
    • 当我们看到 "它" 时,会自动关注前面的 "动物",而不是 "街道"
  • 自注意力机制就是让计算机也具备这种能力:计算每个词和句子中所有其他词的 "关联程度",然后根据关联程度加权求和,得到这个词的新表示。

自注意力计算三步法(必须掌握):

  1. 生成 Q、K、V 三个向量
    • 对每个词的嵌入向量,分别乘以三个不同的权重矩阵,得到三个向量:
      • Q(Query 查询):我要找什么
      • K(Key 键):我有什么
      • V(Value 值):我实际的内容
  2. 计算注意力分数
    • 用 Q 和 K 做点积,得到两个词之间的关联程度
    • 除以√d_k(缩放因子,防止点积结果太大)
  3. 加权求和
    • 对注意力分数做 softmax,转换成 0-1 之间的概率(所有分数加起来等于 1)
    • 用 softmax 后的分数乘以对应的 V 向量,然后相加,得到最终的注意力输出
2.2.2 多头自注意力(Multi-Head Attention)
  • 为什么需要多头:单头注意力只能从一个角度关注信息,多头注意力可以同时从多个不同角度关注信息。
  • 直观理解:就像我们看一幅画,有的人关注颜色,有的人关注形状,有的人关注构图,多头注意力就是把这些不同角度的观察结果综合起来。
  • 实现
    1. 把 Q、K、V 分别分成 h 个 "头"(h 通常是 8)
    2. 每个头独立计算自注意力
    3. 把所有头的结果拼接起来,得到最终的多头注意力输出
2.2.3 残差连接 + 层归一化(Add & Norm)
  • 残差连接:把输入直接加到输出上,解决深度网络的 "退化问题"(网络越深,效果越差)
  • 层归一化:把每一层的输出标准化,让训练更稳定
  • 公式输出 = LayerNorm(输入 + 子层输出)
2.2.4 前馈神经网络(FFN)
  • 作用:对每个位置的向量进行独立的非线性变换,增强模型的表达能力
  • 结构:两个线性层,中间加一个 ReLU 激活函数
  • 公式FFN(x) = max(0, xW1 + b1)W2 + b2

2.3 解码器层:生成输出文本

解码器层比编码器层多了一个掩码多头自注意力层和一个交叉注意力层

2.3.1 掩码多头自注意力(Masked Multi-Head Attention)
  • 为什么需要掩码:生成文本是逐字进行的,当生成第 n 个词时,不能看到第 n+1 个及以后的词(否则就作弊了)
  • 实现:在计算注意力分数时,把未来位置的分数设置为负无穷,这样 softmax 后这些位置的权重就变成 0 了
2.3.2 交叉注意力(Cross-Attention)
  • 作用:让解码器在生成每个词时,都能关注编码器输出的语义信息
  • 和自注意力的区别:Q 来自解码器的上一层输出,K 和 V 来自编码器的最终输出

2.4 输出层

  • 把解码器的输出向量通过一个线性层,转换成词汇表大小的向量
  • 经过 softmax 函数,得到每个词的生成概率
  • 选择概率最大的词作为下一个输出词

三、基础实操:用 PyTorch 实现迷你 Transformer

我们将从零开始实现一个最简单的 Transformer,让你亲手验证每个模块的工作原理。

3.1 环境准备

# 安装PyTorch(如果还没装)
pip install torch

3.2 导入必要的库

import torch
import torch.nn as nn
import torch.nn.functional as F
import math

3.3 实现位置编码

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_len=5000):
        super().__init__()
        # 创建位置编码矩阵
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        # 计算分母项
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        
        # 偶数维度用sin,奇数维度用cos
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        
        # 增加batch维度,方便后续广播
        pe = pe.unsqueeze(0)
        # 注册为缓冲区(不需要训练的参数)
        self.register_buffer('pe', pe)
    
    def forward(self, x):
        # x的形状:[batch_size, seq_len, d_model]
        x = x + self.pe[:, :x.size(1)]
        return x

3.4 实现多头自注意力

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super().__init__()
        assert d_model % num_heads == 0, "d_model必须能被num_heads整除"
        
        self.d_model = d_model
        self.num_heads = num_heads
        self.d_k = d_model // num_heads  # 每个头的维度
        
        # 定义Q、K、V的线性变换层
        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 scaled_dot_product_attention(self, q, k, v, mask=None):
        # 计算注意力分数
        scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(self.d_k)
        
        # 如果有掩码,把掩码位置的分数设为负无穷
        if mask is not None:
            scores = scores.masked_fill(mask == 0, -1e9)
        
        # 计算softmax
        attn_weights = F.softmax(scores, dim=-1)
        
        # 加权求和
        output = torch.matmul(attn_weights, v)
        return output, attn_weights
    
    def forward(self, q, k, v, mask=None):
        batch_size = q.size(0)
        
        # 线性变换
        q = self.w_q(q)
        k = self.w_k(k)
        v = self.w_v(v)
        
        # 分成多个头:[batch_size, seq_len, d_model] → [batch_size, num_heads, seq_len, d_k]
        q = q.view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        k = k.view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        v = v.view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        
        # 计算自注意力
        output, attn_weights = self.scaled_dot_product_attention(q, k, v, mask)
        
        # 拼接所有头:[batch_size, num_heads, seq_len, d_k] → [batch_size, seq_len, d_model]
        output = output.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)
        
        # 最终线性变换
        output = self.w_o(output)
        return output, attn_weights

3.5 实现前馈神经网络

class FeedForward(nn.Module):
    def __init__(self, d_model, d_ff, dropout=0.1):
        super().__init__()
        self.fc1 = nn.Linear(d_model, d_ff)
        self.fc2 = nn.Linear(d_ff, d_model)
        self.dropout = nn.Dropout(dropout)
    
    def forward(self, x):
        x = self.dropout(F.relu(self.fc1(x)))
        x = self.fc2(x)
        return x

3.6 实现编码器层

class EncoderLayer(nn.Module):
    def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
        super().__init__()
        self.self_attn = MultiHeadAttention(d_model, num_heads)
        self.ffn = FeedForward(d_model, d_ff, dropout)
        
        # 层归一化
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        
        # Dropout
        self.dropout1 = nn.Dropout(dropout)
        self.dropout2 = nn.Dropout(dropout)
    
    def forward(self, x, mask=None):
        # 自注意力子层
        attn_output, _ = self.self_attn(x, x, x, mask)
        x = self.norm1(x + self.dropout1(attn_output))
        
        # 前馈神经网络子层
        ffn_output = self.ffn(x)
        x = self.norm2(x + self.dropout2(ffn_output))
        
        return x

3.7 实现解码器层

class DecoderLayer(nn.Module):
    def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
        super().__init__()
        self.self_attn = MultiHeadAttention(d_model, num_heads)
        self.cross_attn = MultiHeadAttention(d_model, num_heads)
        self.ffn = FeedForward(d_model, d_ff, dropout)
        
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.norm3 = nn.LayerNorm(d_model)
        
        self.dropout1 = nn.Dropout(dropout)
        self.dropout2 = nn.Dropout(dropout)
        self.dropout3 = nn.Dropout(dropout)
    
    def forward(self, x, enc_output, src_mask=None, tgt_mask=None):
        # 掩码自注意力子层
        attn_output, _ = self.self_attn(x, x, x, tgt_mask)
        x = self.norm1(x + self.dropout1(attn_output))
        
        # 交叉注意力子层
        cross_attn_output, _ = self.cross_attn(x, enc_output, enc_output, src_mask)
        x = self.norm2(x + self.dropout2(cross_attn_output))
        
        # 前馈神经网络子层
        ffn_output = self.ffn(x)
        x = self.norm3(x + self.dropout3(ffn_output))
        
        return x

3.8 实现完整的 Transformer

class Transformer(nn.Module):
    def __init__(self, src_vocab_size, tgt_vocab_size, d_model=512, num_layers=6, 
                 num_heads=8, d_ff=2048, max_len=5000, dropout=0.1):
        super().__init__()
        
        # 编码器部分
        self.src_embedding = nn.Embedding(src_vocab_size, d_model)
        self.pos_encoding = PositionalEncoding(d_model, max_len)
        self.encoder_layers = nn.ModuleList([
            EncoderLayer(d_model, num_heads, d_ff, dropout) for _ in range(num_layers)
        ])
        
        # 解码器部分
        self.tgt_embedding = nn.Embedding(tgt_vocab_size, d_model)
        self.decoder_layers = nn.ModuleList([
            DecoderLayer(d_model, num_heads, d_ff, dropout) for _ in range(num_layers)
        ])
        
        # 输出层
        self.fc = nn.Linear(d_model, tgt_vocab_size)
        
        # 初始化参数
        self._init_weights()
    
    def _init_weights(self):
        for p in self.parameters():
            if p.dim() > 1:
                nn.init.xavier_uniform_(p)
    
    def generate_mask(self, src, tgt):
        # 源掩码:屏蔽padding位置
        src_mask = (src != 0).unsqueeze(1).unsqueeze(2)
        
        # 目标掩码:屏蔽padding和未来位置
        tgt_pad_mask = (tgt != 0).unsqueeze(1).unsqueeze(2)
        tgt_len = tgt.size(1)
        tgt_sub_mask = torch.tril(torch.ones(tgt_len, tgt_len)).bool().to(tgt.device)
        tgt_mask = tgt_pad_mask & tgt_sub_mask
        
        return src_mask, tgt_mask
    
    def forward(self, src, tgt):
        # 生成掩码
        src_mask, tgt_mask = self.generate_mask(src, tgt)
        
        # 编码器前向传播
        enc_output = self.src_embedding(src)
        enc_output = self.pos_encoding(enc_output)
        for layer in self.encoder_layers:
            enc_output = layer(enc_output, src_mask)
        
        # 解码器前向传播
        dec_output = self.tgt_embedding(tgt)
        dec_output = self.pos_encoding(dec_output)
        for layer in self.decoder_layers:
            dec_output = layer(dec_output, enc_output, src_mask, tgt_mask)
        
        # 输出层
        output = self.fc(dec_output)
        return output

3.9 测试我们的迷你 Transformer

# 定义超参数
src_vocab_size = 1000  # 源语言词汇表大小
tgt_vocab_size = 1000  # 目标语言词汇表大小
d_model = 128          # 模型维度(小模型用128,方便测试)
num_layers = 2         # 编码器和解码器层数
num_heads = 4          # 注意力头数
d_ff = 512             # 前馈神经网络隐藏层维度

# 创建模型
model = Transformer(
    src_vocab_size=src_vocab_size,
    tgt_vocab_size=tgt_vocab_size,
    d_model=d_model,
    num_layers=num_layers,
    num_heads=num_heads,
    d_ff=d_ff
)

# 创建测试数据
batch_size = 2
src_seq_len = 10
tgt_seq_len = 8

src = torch.randint(1, src_vocab_size, (batch_size, src_seq_len))  # 源序列
tgt = torch.randint(1, tgt_vocab_size, (batch_size, tgt_seq_len))  # 目标序列

# 前向传播
output = model(src, tgt)

# 打印输出形状
print(f"输入源序列形状: {src.shape}")
print(f"输入目标序列形状: {tgt.shape}")
print(f"模型输出形状: {output.shape}")
print("恭喜!迷你Transformer运行成功!")

运行结果应该是:

输入源序列形状: torch.Size([2, 10])
输入目标序列形状: torch.Size([2, 8])
模型输出形状: torch.Size([2, 8, 1000])
恭喜!迷你Transformer运行成功!

四、高阶用法:从基础 Transformer 到大模型

4.1 三大主流 Transformer 架构变体

架构类型 代表模型 核心特点 主要应用
编码器 - 解码器 原始 Transformer、T5、BART 完整的编码器和解码器 机器翻译、文本摘要、对话生成
编码器 - only BERT、RoBERTa、ALBERT 只有编码器部分 文本分类、命名实体识别、情感分析(理解类任务)
解码器 - only GPT 系列、Llama 系列、Qwen 系列 只有解码器部分 文本生成、代码生成、大语言模型(生成类任务)

4.2 大模型的核心优化技术

  1. 因果注意力(Causal Attention)

    • 解码器 - only 模型使用的注意力机制
    • 每个词只能关注它前面的词,不能关注后面的词
    • 这就是为什么 GPT 能逐字生成文本的原因
  2. 参数共享

    • 让不同层的权重共享,大大减少模型参数数量
    • 比如 GPT-2 就使用了参数共享技术
  3. 混合精度训练

    • 同时使用 16 位和 32 位浮点数进行训练
    • 速度提升 2 倍,内存占用减少一半,几乎不影响精度
  4. LoRA(低秩适配)

    • 大模型微调的主流技术
    • 只训练模型中很小一部分参数(通常不到 1%)
    • 速度快、内存占用小、效果好

4.3 注意力机制的计算复杂度

  • 自注意力的计算复杂度是O(n²d),其中 n 是序列长度,d 是模型维度
  • 这是大模型的主要性能瓶颈:序列长度越长,计算量呈平方增长
  • 这就是为什么早期大模型的上下文窗口都很小(GPT-3 只有 2048)
  • 现在的大模型通过各种优化技术(如稀疏注意力、FlashAttention)把上下文窗口提升到了几十万甚至上百万

五、拓展建议:初学者后续学习路径

5.1 学习资源推荐

  1. 必看论文:《Attention Is All You Need》(Transformer 开山之作)
  2. 视频教程:李宏毅《机器学习》Transformer 部分(讲得最通俗易懂)
  3. 书籍:《动手学深度学习》(有 PyTorch 和 TensorFlow 代码实现)
  4. 官方文档:Hugging Face Transformers 库文档(工业界标准)

5.2 循序渐进的实践步骤

  1. 第一步:把上面的迷你 Transformer 代码跑通,尝试修改参数(如增加层数、头数),观察输出变化
  2. 第二步:用 Hugging Face Transformers 库调用预训练模型(如 bert-base-uncased、gpt2),完成简单的文本分类和生成任务
  3. 第三步:学习 LoRA 微调技术,用自己的数据集微调一个小模型
  4. 第四步:学习 Ollama 本地部署大模型,理解大模型的推理过程
  5. 第五步:结合云原生技术,把大模型打包成 Docker 镜像,用 K8s 进行部署和调度

5.3 重点关注方向(结合你的云原生 AI 架构师目标)

  1. 大模型推理优化:量化、剪枝、蒸馏,这些是部署大模型的关键技术
  2. GPU 资源调度:理解 Transformer 的计算特点,优化 K8s 上的 GPU 资源分配
  3. 分布式训练与推理:大模型无法在单张 GPU 上运行,必须掌握分布式技术
  4. 信创适配:学习在 openEuler 等信创系统上部署和优化大模型

5.4 常见误区提醒

  1. 不要一开始就陷入复杂的数学推导:先建立直观理解,再逐步深入数学细节
  2. 不要只看不动手:Transformer 是一个工程性很强的技术,必须亲手写代码才能真正理解
  3. 不要追求大而全:先掌握基础 Transformer,再学习各种变体和优化技术
  4. 不要脱离实际应用:始终结合部署和工程化来学习,这是云原生 AI 架构师的核心竞争力
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐