第24章 GPT 系列训推实战

第24章 GPT 系列训推实战

GPT 系列是大语言模型的”起源故事”。从 GPT-1 的”Proof of Concept”到 GPT-4 的”通用智能火花”,OpenAI 用 5 年时间证明了 Scaling Law 的力量。虽然 GPT-4 的内部细节从未公开,但通过技术报告、专利、论文逆向和社区研究,我们仍然可以拼凑出这幅技术全景。

24.1 章节导入

2020 年发布的 GPT-3 是一个大语言模型的分水岭。它不是最强的模型(当时在很多任务上不如 T5),但它证明了一个极其重要的假说:只要模型够大、数据够多, emergent ability 就会自然出现

此后,ChatGPT(基于 GPT-3.5)在 2022 年 11 月引爆了全球 AI 热潮,GPT-4 在 2023 年 3 月展示了多模态理解和推理能力,GPT-4o 在 2024 年 5 月实现了实时的语音/视觉/文本统一交互。

与 LLaMA 不同,GPT 系列是闭源的。本章的技术分析基于 OpenAI 发布的有限技术报告、更早期 GPT-2/GPT-3 的详细论文,以及社区的研究逆向。我们会明确区分”已确认的事实”和”合理的推测”。

24.2 架构演进

24.2.1 GPT 架构演进时间线

graph LR
    GPT1["GPT-1 (2018)<br/>117M params<br/>Decoder-only<br/>12 layers"] --> GPT2["GPT-2 (2019)<br/>1.5B params<br/>48 layers<br/>Byte-level BPE"]
    GPT2 --> GPT3["GPT-3 (2020)<br/>175B params<br/>96 layers<br/>Few-shot learning"]
    GPT3 --> GPT35["GPT-3.5 (2022)<br/>RLHF 对齐<br/>Code trained"]
    GPT35 --> GPT4["GPT-4 (2023)<br/>MoE 架构(推测)<br/>多模态"]
    GPT4 --> GPT4o["GPT-4o (2024)<br/>原生多模态<br/>实时语音"]

24.2.2 GPT-3:奠基之作

GPT-3 的架构在今天看来非常”标准”——标准的 Decoder-only Transformer,标准的多头注意力,标准的 ReLU FFN。但它的关键创新不在架构,而在规模

GPT-3 的关键参数:

配置
参数量 175B
层数 96
隐藏维度 12288
注意力头数 96
上下文长度 2048
词表大小 50,257 (GPT-2 BPE)
训练数据 ~300B tokens (Common Crawl + WebText2 + Books + Wikipedia)

GPT-3 最核心的贡献是发现了 in-context learning(上下文学习)——175B 参数的模型可以在推理时通过 few-shot 示例学会新任务,而不需要任何梯度更新。这种能力在更小的模型(如 GPT-2 1.5B)上不存在,是典型的 emergent ability。

24.2.3 从 GPT-3 到 ChatGPT:对齐的胜利

GPT-3 原始模型其实并不好用——它经常产生有害内容、不遵循指令、风格不自然。从 GPT-3 到 ChatGPT 的转变,技术上是三步:

graph TD
    A["GPT-3 Base Model<br/>(预训练完成)"] --> B["SFT<br/>(指令微调)"]
    B --> C["Reward Model<br/>(训练奖励模型)"]
    C --> D["PPO<br/>(强化学习优化)"]
    D --> E["ChatGPT<br/>(GPT-3.5)"]
    
    style A fill:#f9f,stroke:#333
    style E fill:#bfb,stroke:#333

这三步后来被总结为 RLHF 的标准流程(详见第12章)。但 OpenAI 的关键洞察是:对齐的质量取决于人类标注的质量。他们雇佣了大量专业标注员,并制定了极其详细的标注规范。

24.2.4 GPT-4:MoE 架构的推测

OpenAI 在 GPT-4 技术报告中刻意回避了架构细节,但多种来源的信息指向一个高度可能的结论:GPT-4 是一个 Mixture-of-Experts 模型

主要证据:

  1. George Hotz 的爆料:GPT-4 有 8 个专家(每个 220B 参数),总参数约 1.8T,每次推理激活约 280B
  2. Semianalysis 的分析:基于成本和延迟的逆推,与 8×220B MoE 的模型行为吻合
  3. GPT-4 API 的定价模型:不同 token 的计算时间方差很大,与 MoE 的负载不均衡一致

graph TD
    subgraph "GPT-4 架构(推测)"
        A["Input"] --> B["Shared Attention Layers"]
        B --> C["Router / Gate"]
        C --> D1["Expert 1<br/>~220B"]
        C --> D2["Expert 2<br/>~220B"]
        C --> D3["Expert 3<br/>~220B"]
        C --> D4["..."]
        C --> D8["Expert 8<br/>~220B"]
        D1 --> E["Combine"]
        D2 --> E
        D3 --> E
        D8 --> E
        E --> F["Shared Attention Layers"]
    end

Warning

注意:以上 GPT-4 的架构信息属于社区推测,OpenAI 从未官方确认。将其作为事实引用是不负责任的,但作为技术参考是合理的——MoE 是超大规模模型的必然选择。

24.2.5 GPT-4o:原生多模态

GPT-4o(“o” 代表 omni)的关键突破不是架构,而是训练方式——它从头开始使用统一 tokenizer 处理文本、音频和图像,而不是分别编码后再拼接。

特性 GPT-4 Vision GPT-4o
架构 文本模型 + 视觉编码器 原生多模态
语音延迟 ~3-5 秒(TTS 级联) ~320ms(端到端)
音频输出 文本 → TTS 直接生成音频 token
情感理解 受限于文本 音调、语速、情感

GPT-4o 的音频 tokenizer 将语音压缩到约 12.5 Hz 的 token 速率——这意味着每秒语音只需要 12-13 个 token,远低于文本 tokenizer 的速率。

24.3 训练规模与数据策略

24.3.1 Scaling Law 的实践

OpenAI 的 Scaling Law 论文(Kaplan et al., 2020)揭示了一个关键关系:

\[ L(N) = \left(\frac{N_c}{N}\right)^{\alpha_N} \]

其中 \(L\) 是 loss,\(N\) 是参数量,\(\alpha_N \approx 0.076\)

这个公式告诉我们在计算预算固定时,应该怎么分配参数量和数据量。后来 DeepMind 的 Chinchilla 论文修正了最优比例——模型大小和训练 token 数应该等比例增长(约 20 tokens/parameter)。

GPT-3 的训练数据(~300B tokens)相对于其参数量(175B)来说是不够的——只有约 1.7 tokens/parameter,远低于 Chinchilla 最优的 20。这解释了为什么 LLaMA 2(70B,2T tokens,约 29 tokens/param)在更小参数下超越了 GPT-3。

24.3.2 数据策略推测

基于 GPT-3 的论文和后续社区的逆向分析:

GPT-3 训练数据组成

数据源 权重 (训练采样比) Token 数 (估计)
Common Crawl 60% 410B
WebText2 22% 19B
Books1 8% 12B
Books2 8% 55B
Wikipedia 3% 3B

GPT-4 训练数据(推测)

训练 token 总量: ~13T(比 GPT-3 多 40+ 倍)

数据类型推测:
├── 网页数据(高质量子集)    ~50%
├── 代码数据(GitHub + 代码竞赛) ~20%
├── 多语言数据(100+ 语言)    ~15%
├── 图像/多模态数据            ~10%
├── 数学/科学文献              ~5%
└── 长上下文数据               ~微量

24.3.3 课程学习

OpenAI 据推测使用了课程学习(Curriculum Learning)策略——先训练简单/基础的内容,再逐渐引入更复杂的数据。虽然未官方确认,但以下证据支持这一推测:

  1. GPT-4 在不同难度任务上的表现梯度非常平滑
  2. 训练后期的 checkpoint 突然获得某些能力(如代码能力),暗示数据配比的变化
  3. OpenAI 的论文中提到过”数据混合策略在训练过程中动态调整”

24.4 推理优化

24.4.1 KV Cache

KV Cache 是所有自回归 Transformer 推理的基础优化。核心思想:已计算的 Key 和 Value 不需要重复计算

graph LR
    subgraph "无 KV Cache"
        S1["生成 token 1"] --> S2["重新计算所有 K, V"]
        S2 --> S3["生成 token 2"]
        S3 --> S4["重新计算所有 K, V"]
        S4 --> S5["..."]
    end
    
    subgraph "有 KV Cache"
        C1["生成 token 1"] --> C2["缓存 K1, V1"]
        C2 --> C3["生成 token 2<br/>只需计算 Q2"]
        C3 --> C4["追加 K2, V2 到缓存"]
        C4 --> C5["..."]
    end

KV Cache 的内存占用计算:

\[ \text{KV Cache Size} = 2 \times n_{layers} \times n_{kv\_heads} \times d_{head} \times seq\_len \times batch\_size \times \text{dtype\_size} \]

对于 GPT-3 175B:

n_layers = 96
n_kv_heads = 96  (MHA)
d_head = 128
seq_len = 2048
batch_size = 1
dtype = fp16 (2 bytes)

KV Cache = 2 × 96 × 96 × 128 × 2048 × 1 × 2 = ~9.7 GB

这几乎和模型权重一样大了!这就是为什么 GQA(减少 KV heads)对推理如此重要。

24.4.2 Continuous Batching

传统的静态批处理要求一个 batch 内所有请求同时到达、同时完成。这在 LLM 服务中效率极低——不同请求的长度可能差 10 倍。

Continuous Batching(连续批处理)在每个 token 生成步骤都可以动态调整 batch:

# Continuous Batching 的简化示意
# 每个时间步,新请求可以加入,完成的请求可以离开

# 时间步 t=0: 请求 A, B, C 在 batch 中
# A: "The meaning of life is"  (正在生成)
# B: "def fibonacci(n):"       (正在生成)
# C: "Translate: Hello"        (正在生成)

# 时间步 t=1: C 完成了!D 加入
# A: "The meaning of life is 42"  (继续)
# B: "def fibonacci(n):\n    return" (继续)
# D: "Write a poem about"         (新加入)

Orca(OSDI 2022)论文提出了 this iteration-level scheduling,vLLM、TGI 等推理引擎都实现了类似机制。

24.4.3 Speculative Decoding(推测解码)

推测解码利用一个小模型快速生成候选 token,大模型只需做验证:

graph LR
    A["小模型<br/>(7B)"] -->|"快速生成 5 个 token"| B["大模型<br/>(70B)"]
    B -->|"并行验证 5 个 token"| C{"接受几个?"}
    C -->|"全部接受"| D["5 个 token 完成<br/>(相当于 1 次前向传播)"]
    C -->|"接受前 3 个"| E["3 个 token 完成<br/>+ 1 个修正"]

这在 ChatGPT 的场景中特别有效——因为很多回复(如代码、结构化文本)是高度可预测的,小模型的猜测命中率很高。

# 推测解码的简化实现(使用 transformers)
from transformers import AutoModelForCausalLM, AutoTokenizer

# 大模型(目标模型)
target_model = AutoModelForCausalLM.from_pretrained("meta-llama/Meta-Llama-3-70B")
# 小模型(草稿模型)
draft_model = AutoModelForCatalLM.from_pretrained("meta-llama/Meta-Llama-3-8B")

def speculative_decode(prompt, target_model, draft_model, num_draft_tokens=4):
    input_ids = tokenize(prompt)
    
    while not finished:
        # Step 1: 小模型快速生成 num_draft_tokens 个 token
        draft_tokens = []
        current_ids = input_ids.clone()
        for _ in range(num_draft_tokens):
            logits = draft_model(current_ids)
            next_token = sample(logits)
            draft_tokens.append(next_token)
            current_ids = torch.cat([current_ids, next_token])
        
        # Step 2: 大模型并行验证
        target_logits = target_model(current_ids)  # 一次前向传播
        accepted = 0
        for i, draft_token in enumerate(draft_tokens):
            target_token = sample(target_logits[len(input_ids) + i])
            if draft_token == target_token:
                accepted += 1
            else:
                # 拒绝,从大模型的分布重新采样
                input_ids = torch.cat([input_ids, target_token])
                break
        
        # 接受的 token 直接加入
        input_ids = torch.cat([input_ids, draft_tokens[:accepted]])
    
    return detokenize(input_ids)

24.5 ChatGPT 服务架构推测

ChatGPT 的服务架构从未被 OpenAI 公开,但基于性能特征、延迟分析和行业经验,我们可以合理推测其架构:

graph TD
    subgraph "客户端"
        A["Web / App / API"]
    end
    
    subgraph "CDN / 边缘"
        B["Cloudflare / Azure Front Door"]
    end
    
    subgraph "API Gateway"
        C["请求路由<br/>认证 / 限流"]
        D["模型路由<br/>(GPT-4 vs 3.5 vs 4o)"]
    end
    
    subgraph "推理集群"
        E["推理节点池<br/>(GPU 集群)"]
        F["KV Cache 分布式存储"]
        G["Prefix Cache<br/>(系统提示共享)"]
    end
    
    subgraph "后端服务"
        H["对话管理"]
        I["安全过滤"]
        J["计费 / 日志"]
    end
    
    A --> B --> C --> D --> E
    E <--> F
    E <--> G
    C <--> H
    C <--> I
    C <--> J

24.5.1 关键架构推测

1. 模型路由层

ChatGPT 的不同订阅层级(Free / Plus / Pro)路由到不同的模型实例。这需要一个智能路由层,根据用户层级、请求类型和当前负载选择模型实例。

2. 系统提示 Prefix Cache

ChatGPT 的系统提示通常超过 1000 token(包括安全规则、格式指令等)。如果每个请求都重新计算这些 prefix,成本极高。几乎可以确定 ChatGPT 在所有请求间共享系统提示的 KV Cache。

3. 弹性伸缩

ChatGPT 的流量在 24 小时内波动很大(美东工作时间是高峰)。推测使用 Azure 的虚拟机规模集(VMSS)进行自动伸缩,GPU 实例在低峰期释放。

4. 流量调度

考虑到 GPT-4 推理的成本远高于 GPT-3.5,ChatGPT 可能在简单请求上自动降级到更便宜的模型——这正是 GPT-4o 的设计初衷之一(用单一模型处理所有模态,降低路由复杂度)。

Tip

从 ChatGPT 学习生产 LLM 部署: 即使我们不知道 ChatGPT 的内部细节,它的公开行为告诉了我们很多: - TTFT(Time To First Token)通常在 200-500ms → 说明使用了 Prefix Cache + 高效 batching - 流式输出速度约 30-50 token/s → 对应 batch size 在 16-64 左右 - 高峰期偶尔变慢 → 说明不是无限制弹性,有 GPU 池上限 - GPT-4o 的实时语音延迟 ~320ms → 接近人类对话反应时间的下限

24.6 代码示例:复现 GPT 推理

虽然我们无法复现 ChatGPT 的完整服务,但可以用开源工具搭建一个架构类似的推理服务:

# 使用 vLLM 搭建 OpenAI 兼容的推理服务
# 支持:多模型、Prefix Cache、流式输出、Continuous Batching

"""
vLLM 服务启动:
vllm serve meta-llama/Meta-Llama-3.1-70B-Instruct \
  --tensor-parallel-size 4 \
  --enable-prefix-caching \
  --max-num-batched-tokens 32768 \
  --max-num-seqs 64
"""

from openai import OpenAI
import time

client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy")

# 测试 TTFT(首 token 延迟)
def measure_ttft(prompt, model="meta-llama/Meta-Llama-3.1-8B-Instruct"):
    start = time.time()
    first_token_time = None
    
    stream = client.chat.completions.create(
        model=model,
        messages=[{"role": "user", "content": prompt}],
        stream=True,
        max_tokens=256,
    )
    
    tokens_received = 0
    for chunk in stream:
        if first_token_time is None and chunk.choices[0].delta.content:
            first_token_time = time.time()
        if chunk.choices[0].delta.content:
            tokens_received += 1
    
    total_time = time.time() - start
    ttft = first_token_time - start if first_token_time else 0
    tps = tokens_received / (total_time - ttft) if total_time > ttft else 0
    
    print(f"TTFT: {ttft*1000:.0f}ms | Throughput: {tps:.1f} tok/s | Total: {total_time:.1f}s")

# 测试不同 prompt 长度的 TTFT
measure_ttft("Hello")  # 短 prompt
measure_ttft("Please write a 500-word essay about the history of computing, " * 20)  # 长 prompt

24.6.1 使用推测解码加速推理

# 使用 vLLM 的推测解码功能
# 小模型作为 draft model,大模型作为 target model

vllm serve meta-llama/Meta-Llama-3-70B-Instruct \
  --tensor-parallel-size 4 \
  --speculative-model meta-llama/Meta-Llama-3-8B-Instruct \
  --num-speculative-tokens 5 \
  --enable-prefix-caching

实测加速比取决于任务类型:

任务类型 小模型命中率 实际加速
代码生成 85%+ 2.0-2.5x
事实问答 70-80% 1.5-1.8x
创意写作 50-60% 1.2-1.4x
数学推理 40-50% 1.1-1.2x

24.7 实践建议

Tip

从 GPT 系列学到的工程经验: 1. 数据 > 架构:GPT-3 到 GPT-3.5 的架构变化不大,但数据质量和对齐技术的提升是决定性的 2. RLHF 值得投入:即使预训练模型很强,没有对齐就无法做产品 3. MoE 是规模化的必然:GPT-4 选择 MoE 说明在 1T+ 参数规模上,稠密模型不可行 4. 延迟是产品体验的关键:GPT-4o 的核心改进不是质量,而是速度——320ms 的语音延迟让对话变得自然

Warning

不要盲目模仿 OpenAI: OpenAI 有几千人的团队和海量 GPU 资源。他们的做法不一定适合你: 1. 不要从零训练:使用开源基座模型 + 微调,而不是预训练 2. 不要自己实现 RLHF:使用 DPO 或简单的 SFT,效果在多数场景够用 3. 不要忽视成本:GPT-4 的推理成本是 8B 模型的 100+ 倍,但效果差距在很多任务上不到 2 倍

24.8 小结

GPT 系列的技术演进可以总结为三条主线:

  1. 架构规模化:从 117M 到 1T+,但基本架构变化不大——Scaling Law 的力量远超架构创新
  2. 数据精细化:从”爬全网”到精心设计的多阶段数据管线,数据质量是模型质量的根本决定因素
  3. 对齐工程化:RLHF 从实验性技术变成了产品流程,对齐质量直接决定了模型的产品化程度

虽然 GPT-4 的具体技术细节是闭源的,但它指明了大模型发展的方向——MoE 架构、多模态统一、极致推理优化。开源社区在 LLaMA、DeepSeek、Qwen 等模型上正在快速追赶。

24.9 延伸阅读

  • Brown et al. (2020). Language Models are Few-Shot Learners (GPT-3). NeurIPS 2020
  • Ouyang et al. (2022). Training language models to follow instructions with human feedback (InstructGPT). NeurIPS 2022
  • OpenAI (2023). GPT-4 Technical Report. arXiv:2303.08774
  • OpenAI (2024). GPT-4o System Card
  • Kaplan et al. (2020). Scaling Laws for Neural Language Models. arXiv:2001.08361
  • Semianalysis (2023). GPT-4 Architecture, Infrastructure, Training Dataset, Costs, Vision, MoE. 社区最详细的 GPT-4 逆向分析
  • Orca (OSDI 2022). Orca: A Distributed Serving System for Transformer-Based Generative Models. Continuous Batching 的起源论文
  • Chen et al. (2023). Accelerating Large Language Model Decoding with Speculative Sampling. arXiv:2302.01318