跳转至

09 - Scaling Laws 与训练资源规划

学习目标:理解大模型缩放定律的核心公式,掌握计算最优训练策略,学会训练资源估算与规划。 前置知识:大模型预训练基础(03-大模型预训练)、训练基础设施(02-训练基础设施


目录

  1. Scaling Laws 概述
  2. Kaplan Scaling Laws (2020)
  3. Chinchilla Scaling Laws (2022)
  4. 计算最优训练策略
  5. 训练资源估算
  6. 前沿 Scaling 研究与争议

1. Scaling Laws 概述

1.1 什么是 Scaling Laws

Scaling Laws(缩放定律)描述了模型性能如何随模型参数量 (N)训练数据量 (D)计算预算 (C) 的变化而变化。这些经验规律为训练大模型提供了科学指导。

graph TD
    A[Scaling Laws 三要素] --> B[模型参数量 N]
    A --> C[训练数据量 D<br/>token 数]
    A --> D[计算预算 C<br/>FLOPs]
    B --> E[交叉熵损失 L]
    C --> E
    D --> E

1.2 为什么 Scaling Laws 重要

用途 说明
训练预算规划 预估需要多少 GPU、多长时间
模型规模决策 给定预算下选择最优模型大小
数据量决策 确定需要多少训练 token
小规模预测 用小模型实验预测大模型性能
架构对比 不同架构的 scaling 效率

2. Kaplan Scaling Laws (2020)

2.1 核心发现

OpenAI 的 Kaplan 等人在 2020 年发现,语言模型的交叉熵损失与三个因素呈幂律关系

\[L(N) = \left(\frac{N_c}{N}\right)^{\alpha_N}\]
\[L(D) = \left(\frac{D_c}{D}\right)^{\alpha_D}\]
\[L(C) = \left(\frac{C_c}{C}\right)^{\alpha_C}\]

其中: - \(L\) 是交叉熵损失 - \(N\) 是模型参数量(不含 embedding) - \(D\) 是训练数据量(token 数) - \(C\) 是总计算量(FLOPs) - \(N_c, D_c, C_c\) 是常数 - \(\alpha_N \approx 0.076\), \(\alpha_D \approx 0.095\), \(\alpha_C \approx 0.050\)

2.2 关键结论

Python
import numpy as np
import matplotlib.pyplot as plt

# Kaplan Scaling Laws 参数
N_c = 8.8e13   # 参数量常数
D_c = 5.4e13   # 数据量常数
alpha_N = 0.076
alpha_D = 0.095

def kaplan_loss_N(N):
    """模型参数量与损失的关系"""
    return (N_c / N) ** alpha_N

def kaplan_loss_D(D):
    """数据量与损失的关系"""
    return (D_c / D) ** alpha_D

# 可视化
Ns = np.logspace(7, 12, 100)  # 10M 到 1T 参数
Ds = np.logspace(9, 13, 100)  # 1B 到 10T tokens

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))

ax1.loglog(Ns, kaplan_loss_N(Ns))
ax1.set_xlabel('Parameters (N)')
ax1.set_ylabel('Loss L(N)')
ax1.set_title('Kaplan: Loss vs Model Size')
ax1.grid(True, alpha=0.3)

ax2.loglog(Ds, kaplan_loss_D(Ds))
ax2.set_xlabel('Data (D tokens)')
ax2.set_ylabel('Loss L(D)')
ax2.set_title('Kaplan: Loss vs Data Size')
ax2.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('scaling_laws_kaplan.png', dpi=150)

2.3 Kaplan 的核心观点

"更大的模型更高效" — 在固定计算预算下,训练一个更大的模型但训练步数更少,比训练一个小模型更多步数更有效。

这意味着:优先增大模型规模,而非训练更多数据。这个结论后来被 Chinchilla 推翻。


3. Chinchilla Scaling Laws (2022)

3.1 Chinchilla 的修正

DeepMind 的 Hoffmann 等人在 2022 年重新审视了 Scaling Laws,发现 Kaplan 的结论有偏差:

\[L(N, D) = \frac{A}{N^\alpha} + \frac{B}{D^\beta} + E\]

其中: - \(E\) 是不可约损失(数据的固有熵) - \(\alpha \approx 0.34\), \(\beta \approx 0.28\) - \(A \approx 406.4\), \(B \approx 410.7\)

3.2 Chinchilla 的核心结论

Python
import numpy as np

# Chinchilla 参数
E = 1.69      # 不可约损失
A = 406.4
B = 410.7
alpha = 0.34
beta = 0.28

def chinchilla_loss(N, D):
    """Chinchilla 缩放定律"""
    return A / N**alpha + B / D**beta + E

# 计算最优分配:给定计算预算 C,求最优 N 和 D
# C ≈ 6 * N * D (训练 FLOPs)
def optimal_allocation(C):
    """给定计算预算,求最优参数量和数据量"""
    # Chinchilla 推导的最优解
    # N_opt = G * C^a
    # D_opt = G^{-1} * C^b
    a = alpha / (alpha + beta)  # ≈ 0.548
    b = beta / (alpha + beta)   # ≈ 0.452

    G = (alpha * A / beta / B) ** (1 / (alpha + beta))

    N_opt = G * (C / 6) ** a
    D_opt = G**(-1) * (C / 6) ** b

    return N_opt, D_opt

# 不同计算预算下的最优分配
budgets = {
    "GPT-2 (1.5B)":  1.5e9 * 1e9 * 6,       # ~9e18 FLOPs
    "GPT-3 (175B)":  175e9 * 300e9 * 6,      # ~3.15e23 FLOPs
    "Chinchilla (70B)": 70e9 * 1.4e12 * 6,   # ~5.88e23 FLOPs
}

print("=" * 60)
print(f"{'模型':<25} {'计算量 (FLOPs)':<20} {'最优N':<12} {'最优D':<12}")
print("=" * 60)
for name, C in budgets.items():
    N_opt, D_opt = optimal_allocation(C)
    print(f"{name:<25} {C:<20.2e} {N_opt/1e9:<12.1f}B {D_opt/1e9:<12.1f}B tokens")

3.3 Kaplan vs Chinchilla 对比

维度 Kaplan (2020) Chinchilla (2022)
最优策略 更大的模型 模型和数据等比例增长
N:D 比例 N >> D N ≈ D/20
GPT-3 策略 175B 参数, 300B tokens 应该用 ~70B 参数, 1.4T tokens
核心观点 模型优先 数据同等重要
实验基础 有限数据量 更大范围数据量

3.4 Chinchilla 实验验证

Python
# Chinchilla 的关键实验结果
results = {
    "Gopher (280B, 300B tokens)": {"loss": 1.91, "params": "280B"},
    "Chinchilla (70B, 1.4T tokens)": {"loss": 1.79, "params": "70B"},
}

# Chinchilla 用 1/4 的参数量,但 4.7x 的数据量,获得了更低的损失
# 证明:在相同计算预算下,更多数据 + 适中模型 > 更大模型 + 更少数据
print("Chinchilla 实验结论:")
print(f"  Gopher:    280B 参数 × 300B tokens = 损失 1.91")
print(f"  Chinchilla: 70B 参数 × 1.4T tokens = 损失 1.79")
print(f"  → 用更小的模型但更多数据,效果更好!")

4. 计算最优训练策略

4.1 FLOPs 估算

Python
def estimate_training_flops(
    num_params: float,
    num_tokens: float,
    forward_flops_per_param: float = 2.0,
    backward_flops_per_param: float = 4.0,
) -> float:
    """估算训练总 FLOPs

    前向传播:约 2 * N * D FLOPs
    反向传播:约 4 * N * D FLOPs
    总计:约 6 * N * D FLOPs

    Args:
        num_params: 模型参数量
        num_tokens: 训练 token 总数
        forward_flops_per_param: 每个参数每 token 的前向 FLOPs
        backward_flops_per_param: 每个参数每 token 的反向 FLOPs
    """
    flops_per_token = num_params * (forward_flops_per_param + backward_flops_per_param)
    total_flops = flops_per_token * num_tokens
    return total_flops

# 示例:估算 LLaMA-2 7B 的训练 FLOPs
N = 7e9         # 7B 参数
D = 2e12        # 2T tokens
C = estimate_training_flops(N, D)
print(f"LLaMA-2 7B 训练 FLOPs: {C:.2e}")
# ≈ 6 * 7e9 * 2e12 = 8.4e22 FLOPs

4.2 GPU 时间估算

Python
def estimate_training_time(
    num_params: float,
    num_tokens: float,
    gpu_type: str = "A100",
    num_gpus: int = 1,
    model_flops_utilization: float = 0.5,
) -> dict:
    """估算训练时间

    Args:
        num_params: 模型参数量
        num_tokens: 训练 token 总数
        gpu_type: GPU 型号
        num_gpus: GPU 数量
        model_flops_utilization: MFU(模型 FLOPs 利用率)
    """
    # GPU 理论算力 (BF16 TFLOPS)
    gpu_flops = {
        "A100-40GB": 312e12,
        "A100-80GB": 312e12,
        "H100-SXM": 990e12,
        "H200": 990e12,
        "B200": 2250e12,  # 估计值
        "V100-32GB": 125e12,
        "RTX4090": 165e12,
    }

    peak_flops = gpu_flops.get(gpu_type, 312e12)  # 修复:gpu_fpus → gpu_flops
    effective_flops = peak_flops * model_flops_utilization * num_gpus

    total_flops = estimate_training_flops(num_params, num_tokens)
    time_seconds = total_flops / effective_flops

    return {
        "total_flops": total_flops,
        "effective_flops_per_sec": effective_flops,
        "time_seconds": time_seconds,
        "time_hours": time_seconds / 3600,
        "time_days": time_seconds / 86400,
        "gpu_type": gpu_type,
        "num_gpus": num_gpus,
        "mfu": model_flops_utilization,
    }

# 示例:LLaMA-2 70B 训练时间估算
result = estimate_training_time(
    num_params=70e9,
    num_tokens=1.4e12,
    gpu_type="A100-80GB",
    num_gpus=2048,
    model_flops_utilization=0.45,
)
print(f"LLaMA-2 70B 训练估算:")
print(f"  总 FLOPs: {result['total_flops']:.2e}")
print(f"  GPU: {result['num_gpus']} × {result['gpu_type']}")
print(f"  MFU: {result['mfu']:.0%}")
print(f"  预计时间: {result['time_days']:.1f} 天 ({result['time_hours']:.0f} 小时)")

4.3 显存估算

Python
def estimate_memory(
    num_params: float,
    precision_bytes: int = 2,  # BF16 = 2 bytes
    optimizer_type: str = "adam",
    batch_size: int = 1,
    seq_length: int = 4096,
    hidden_dim: int = 4096,
    num_layers: int = 32,
    activation_memory_factor: float = 2.0,
) -> dict:
    """估算 GPU 显存需求

    Args:
        num_params: 模型参数量
        precision_bytes: 每个参数的字节数
        optimizer_type: 优化器类型
    """
    # 模型参数
    param_memory = num_params * precision_bytes

    # 优化器状态
    if optimizer_type == "adam":
        # Adam: momentum (FP32) + variance (FP32) + master params (FP32)
        optimizer_memory = num_params * 4 * 2 + num_params * 4  # = 12 bytes/param
    elif optimizer_type == "adamw":
        optimizer_memory = num_params * 12  # 同 Adam
    elif optimizer_type == "sgd":
        optimizer_memory = num_params * 4  # 只需 momentum
    else:
        optimizer_memory = num_params * 12

    # 梯度
    gradient_memory = num_params * precision_bytes

    # 激活值(粗略估计)
    activation_memory = (
        batch_size * seq_length * hidden_dim * num_layers 
        * precision_bytes * activation_memory_factor
    )

    total = param_memory + optimizer_memory + gradient_memory + activation_memory

    return {
        "param_memory_GB": param_memory / 1e9,
        "optimizer_memory_GB": optimizer_memory / 1e9,
        "gradient_memory_GB": gradient_memory / 1e9,
        "activation_memory_GB": activation_memory / 1e9,
        "total_memory_GB": total / 1e9,
        "recommended_GPU_memory_GB": total / 1e9 * 1.2,  # 20% 余量
    }

# 示例:LLaMA-2 7B 显存估算
mem = estimate_memory(
    num_params=7e9,
    precision_bytes=2,  # BF16
    optimizer_type="adamw",
    batch_size=4,
    seq_length=4096,
    hidden_dim=4096,
    num_layers=32,
)
print("LLaMA-2 7B 显存估算:")
for k, v in mem.items():
    print(f"  {k}: {v:.1f} GB")

4.4 最优模型规模选择

Python
def compute_optimal_model_size(compute_budget_flops: float) -> dict:
    """Chinchilla 最优模型规模

    给定计算预算,返回最优参数量和数据量
    """
    # Chinchilla 最优比例: N ∝ C^0.5, D ∝ C^0.5
    # 具体系数来自 Hoffmann et al. 2022
    # N_opt ≈ 0.06 * C^0.5 (参数)
    # D_opt ≈ C / (6 * N_opt) (tokens)

    N_opt = 0.06 * compute_budget_flops**0.5
    D_opt = compute_budget_flops / (6 * N_opt)

    return {
        "compute_budget_flops": compute_budget_flops,
        "optimal_params": N_opt,
        "optimal_tokens": D_opt,
        "tokens_per_param": D_opt / N_opt,
    }

# 不同预算下的最优规模
print("=" * 70)
print(f"{'计算预算 (FLOPs)':<20} {'最优参数量':<15} {'最优token数':<15} {'D/N比':<10}")
print("=" * 70)

budgets = [1e20, 1e21, 1e22, 1e23, 1e24, 1e25]
for C in budgets:
    result = compute_optimal_model_size(C)
    N = result['optimal_params']
    D = result['optimal_tokens']
    print(f"{C:<20.0e} {N/1e9:<15.1f}B {D/1e9:<15.1f}B {D/N:<10.0f}")

5. 训练资源规划

5.1 训练规划决策树

graph TD
    A[确定训练目标] --> B{可用 GPU 显存}
    B -->|≤ 24GB| C[小模型 ≤ 7B<br/>使用 LoRA/QLoRA]
    B -->|≤ 80GB| D[中等模型 ≤ 30B<br/>使用 DeepSpeed ZeRO-2]
    B -->|≥ 80GB × N| E[大模型 ≤ 70B+<br/>使用 3D 并行]

    C --> F[确定数据量<br/>Chinchilla: 20× 参数量]
    D --> F
    E --> F

    F --> G[估算训练时间<br/>FLOPs / GPU算力 / MFU]
    G --> H[确定训练方案]

5.2 常见模型训练配置参考

模型 参数量 训练 Token GPU 配置 训练时间 估算成本
GPT-2 1.5B 40B 8× V100 ~1 天 ~$100
GPT-3 175B 300B 1024× A100 ~34 天 ~$4.6M
Chinchilla 70B 1.4T 2048× TPUv4 ~30 天 ~$5M
LLaMA-2 7B 7B 2T 64× A100 ~7 天 ~$50K
LLaMA-2 70B 70B 1.4T 2048× A100 ~21 天 ~$2M
LLaMA-3 8B 8B 15T 8192× H100 ~30 天 ~$5M

5.3 完整训练规划模板

Python
class TrainingPlanner:
    """大模型训练资源规划器"""

    GPU_SPECS = {
        "A100-80GB": {"memory": 80, "bf16_tflops": 312, "cost_per_hour": 1.5},
        "H100-SXM": {"memory": 80, "bf16_tflops": 990, "cost_per_hour": 3.0},
        "H200":     {"memory": 141, "bf16_tflops": 990, "cost_per_hour": 4.0},
        "B200":     {"memory": 192, "bf16_tflops": 2250, "cost_per_hour": 6.0},
    }

    def __init__(self, num_params_B: float, num_tokens_T: float):
        self.N = num_params_B * 1e9
        self.D = num_tokens_T * 1e12

    def plan(self, gpu_type: str = "A100-80GB", mfu: float = 0.45, 
             max_gpus: int = 2048) -> dict:
        """生成训练计划"""
        gpu = self.GPU_SPECS[gpu_type]

        # 总 FLOPs
        total_flops = 6 * self.N * self.D

        # 单 GPU 有效算力
        effective_flops_per_gpu = gpu["bf16_tflops"] * 1e12 * mfu

        # 最少 GPU 数(基于显存)
        model_memory_GB = self.N * 2 / 1e9  # BF16 参数
        min_gpus_memory = max(1, int(model_memory_GB / gpu["memory"] * 3))  # 3x for optimizer

        # 使用 GPU 数
        num_gpus = min(max(min_gpus_memory, 8), max_gpus)

        # 训练时间
        total_effective_flops = effective_flops_per_gpu * num_gpus
        time_seconds = total_flops / total_effective_flops

        # 成本估算
        cost = time_seconds / 3600 * gpu["cost_per_hour"] * num_gpus

        return {
            "model_params": f"{self.N/1e9:.1f}B",
            "training_tokens": f"{self.D/1e12:.1f}T",
            "total_flops": f"{total_flops:.2e}",
            "gpu_type": gpu_type,
            "num_gpus": num_gpus,
            "mfu": f"{mfu:.0%}",
            "training_days": time_seconds / 86400,
            "estimated_cost_usd": cost,
            "tokens_per_param": self.D / self.N,
        }

# 使用示例
planner = TrainingPlanner(num_params_B=7, num_tokens_T=2)
plan = planner.plan(gpu_type="A100-80GB", mfu=0.45, max_gpus=64)
print(f"训练计划:")
for k, v in plan.items():
    print(f"  {k}: {v}")

6. 前沿 Scaling 研究与争议

6.1 Beyond Chinchilla

研究 年份 核心发现
Kaplan 2020 幂律关系,模型优先
Chinchilla 2022 数据同等重要,N ∝ D
LLaMA-3 2024 过度训练(over-training)在推理时更高效
DeepSeek 2024 MoE 架构打破传统 scaling 规律
MiniCPM 2024 小模型通过密集数据可以超越大模型

6.2 过度训练(Over-training)

LLaMA-3 的策略与 Chinchilla 相反:用远超最优比例的数据训练模型。

Python
# Chinchilla 最优: D ≈ 20 * N
# LLaMA-3 实际: D ≈ 1875 * N (8B 模型训练 15T tokens)

# 为什么过度训练?
# 1. 推理成本 >> 训练成本(模型被部署后服务大量请求)
# 2. 更小的模型推理更快、更便宜
# 3. 用训练成本换取推理效率

# 过度训练的 trade-off
print("过度训练策略对比:")
print(f"  Chinchilla 最优: 70B × 1.4T tokens → 推理成本高")
print(f"  LLaMA-3 策略:    8B × 15T tokens  → 推理成本低,性能接近")
print(f"  → 当模型需要长期部署服务时,过度训练更经济")

6.3 MoE 的 Scaling 特性

Python
# MoE (Mixture of Experts) 改变了传统 Scaling Laws
# DeepSeek-V3: 671B 总参数, 37B 激活参数

# 传统 Dense 模型: FLOPs = 6 * N_total * D
# MoE 模型: FLOPs = 6 * N_active * D (只计算激活参数)

# 这意味着 MoE 可以用更少的计算获得更大的模型容量
# Scaling Laws 需要针对 MoE 重新校准

moe_comparison = {
    "DeepSeek-V3": {
        "total_params": "671B",
        "active_params": "37B",
        "training_tokens": "14.8T",
        "effective_flops": "6 * 37B * 14.8T",  # 等效于 37B dense 模型
        "performance": "接近 GPT-4 水平",
    },
    "LLaMA-3 70B": {
        "total_params": "70B",
        "active_params": "70B",
        "training_tokens": "15T",
        "effective_flops": "6 * 70B * 15T",
        "performance": "接近但略低于 DeepSeek-V3",
    },
}

6.4 μP(Maximal Update Parameterization)

参考来源:本节内容参考了 diy-llm 第九章( Scaling Laws )对 μP 的详细分析,以及 Yang et al. (2022) 的原始论文。

μP( Maximal Update Parameterization ,最大更新参数化)是一种超参数迁移方法,允许在小模型上搜索最优超参数,然后直接迁移到大模型上使用。

核心问题:传统方法中,模型规模变化时,最优学习率、初始化方差等超参数也需要重新调整。μP 通过理论分析确定了超参数应该如何随模型规模缩放。

Text Only
标准参数化(SP)vs 最大更新参数化(μP)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

标准参数化(Standard Parameterization):
├── 所有层的初始化方差相同
├── 所有层使用相同的学习率
├── 问题:模型规模变化时,训练动态不稳定
└── 大模型需要昂贵的超参数搜索

μP 的核心思想:
├── 不同层的参数应该有不同的缩放规则
├── 嵌入层:学习率 ∝ 1/√d(d 为隐藏层维度)
├── 隐藏层:学习率 ∝ 1/d
├── 输出层:学习率 ∝ 1/√d
└── 初始化方差也按相应规则缩放

μP 的优势:
├── 小模型上搜索的超参数可直接迁移到大模型
├── 训练曲线更稳定、更可预测
├── 显著降低大模型训练的超参数调优成本
└── MiniCPM 等模型验证了 μP 的有效性
Python
# μP 参数化实现示例
def get_mup_scaling_rules(hidden_size, base_hidden_size=256):
    """
    计算 μP 的缩放规则

    Args:
        hidden_size: 目标模型的隐藏层维度
        base_hidden_size: 基准小模型的隐藏层维度
    """
    import math

    # 宽度缩放因子
    width_ratio = hidden_size / base_hidden_size

    scaling_rules = {
        "嵌入层": {
            "学习率缩放": f"1/√d → {1/math.sqrt(width_ratio):.4f}x",
            "初始化缩放": "标准正态(不变)",
        },
        "隐藏层(Attention/FFN)": {
            "学习率缩放": f"1/d → {1/width_ratio:.4f}x",
            "初始化缩放": f"1/√d → {1/math.sqrt(width_ratio):.4f}x",
        },
        "输出层(LM Head)": {
            "学习率缩放": f"1/√d → {1/math.sqrt(width_ratio):.4f}x",
            "初始化缩放": "标准正态(不变)",
        },
        "残差连接": {
            "缩放因子": f"1/√(num_layers) → 随深度调整",
        },
    }

    return scaling_rules

# 示例:从 256 维小模型迁移到 4096 维大模型
rules = get_mup_scaling_rules(hidden_size=4096, base_hidden_size=256)
print("μP 缩放规则(256 → 4096):")
for layer, rule in rules.items():
    print(f"\n  {layer}:")
    for key, value in rule.items():
        print(f"    {key}: {value}")
Text Only
MiniCPM 的 μP 实践验证(参考 diy-llm 第九章)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. 在小模型(约 100M 参数)上进行随机超参数搜索
2. 使用 μP 将最优超参数迁移到 1.2B/2.4B 模型
3. 结果:
   ├── 训练损失曲线更稳定
   ├── 不同规模模型的缩放曲线更可预测
   ├── 学习率无需在大模型上重新搜索
   └── MiniCPM 在同等参数规模下超越其他开源模型

使用 mup 库实现 μP

Python
# pip install mup
import mup
import torch.nn as nn

# 1. 定义基础模型(小模型,如 hidden_size=256)
class TransformerBlock(nn.Module):
    def __init__(self, hidden_size, n_heads):
        super().__init__()
        self.attn = nn.MultiheadAttention(hidden_size, n_heads)
        self.ffn = nn.Sequential(
            nn.Linear(hidden_size, 4 * hidden_size),
            nn.GELU(),
            nn.Linear(4 * hidden_size, hidden_size),
        )
        self.norm = nn.LayerNorm(hidden_size)

# 2. 使用 mup 初始化
base_dim = 256
target_dim = 4096

base_model = TransformerBlock(base_dim, n_heads=4)
delta_model = TransformerBlock(target_dim, n_heads=32)

# mup 会自动处理初始化缩放和学习率缩放
mup.set_base_shapes(delta_model, base_model)

# 3. 使用 mup 的 MuReadiness 检查器验证
# 确保 μP 参数化正确应用

💡 μP 实践建议:对于小规模实验(<1B),μP 的收益有限;但在训练 >10B 模型时,μP 可以节省数十次昂贵的超参数搜索,显著降低训练成本。Cohere、MiniCPM 等团队已在大规模训练中验证了其有效性。

6.5 数据墙(Data Wall)问题

Python
# 高质量人类文本数据的总量估计
total_human_text_tokens = {
    "Common Crawl (过滤后)": "~10T tokens",
    "书籍": "~1T tokens",
    "学术论文": "~500B tokens",
    "代码 (GitHub)": "~500B tokens",
    "维基百科": "~10B tokens",
    "合计高质量数据": "~15-20T tokens",
}

# 按当前最大模型的训练速度,高质量数据可能在 2026-2027 年耗尽
# 解决方案:
solutions = [
    "1. 合成数据(用强模型生成训练数据)",
    "2. 多模态数据(图像/视频/音频作为额外数据源)",
    "3. 数据高效训练(更好的数据选择和课程学习)",
    "4. 自我改进(模型生成数据 → 过滤 → 再训练)",
    "5. RL from environment(从环境交互中学习)",
]

📝 本章小结

概念 核心公式/结论
Kaplan Laws \(L \propto N^{-0.076}\), 模型优先
Chinchilla Laws \(L = A/N^\alpha + B/D^\beta + E\), 数据同等重要
训练 FLOPs \(C \approx 6ND\)
最优分配 \(N_{opt} \propto C^{0.5}\), \(D_{opt} \propto C^{0.5}\)
过度训练 推理密集场景下用更多数据训练更小模型
MoE Scaling FLOPs 由激活参数决定,非总参数

🤔 思考题

💡 思考题参考解答 **Q1: LLaMA 系列为什么选择"过度训练"(Over-training)而非遵循 Chinchilla 最优?** Chinchilla 的最优是**训练计算量最优**(给定 FLOPs 预算,如何分配 N 和 D 使 loss 最低)。但 LLaMA 的考量是**推理成本最优**: - 一个模型训练一次,但推理数十亿次 - 训练一个更小的模型(如 7B)用更多数据(1T tokens),推理成本远低于训练 13B 模型用 0.5T tokens - LLaMA-2 7B 训练了 2T tokens(远超 Chinchilla 最优的 ~140B tokens),但在推理时比 13B 模型便宜近一半 **Q2: 如何用 Scaling Laws 估算"我的预算能训练多大的模型"?** 步骤: 1. 确定计算预算 $C$(GPU 数 × 训练天数 × 单卡算力) 2. Chinchilla 最优:$N_{opt} \approx 0.6 \times C^{0.5}$,$D_{opt} \approx 20 \times C^{0.5}$ 3. 验证显存是否足够($M \approx 20N$ bytes for Adam + 模型 + 梯度 + 激活值) 示例:8 × A100 (80GB) 训练 30 天 - 总 FLOPs:$8 \times 312 \text{TFLOPS} \times 30 \times 86400 \approx 6.5 \times 10^{21}$ FLOPs - $N_{opt} \approx 0.6 \times \sqrt{6.5 \times 10^{21}} \approx 4.8 \times 10^{10}$ ≈ 48B 参数 - $D_{opt} \approx 20 \times \sqrt{6.5 \times 10^{21}} \approx 1.6 \times 10^{12}$ ≈ 1.6T tokens - 但 48B 模型在 8 × A100 上可能显存不够(需要 ZeRO-3),实际可能选 13B + 更多数据 **Q3: MoE 模型的 Scaling Laws 与 Dense 模型有何不同?** 关键区别: - **FLOPs 由激活参数决定**:MoE 的总参数可能是 100B,但每次只激活 10B(top-2 路由),实际计算量与 10B Dense 模型相当 - **Scaling Laws 需要重新校准**:Chinchilla 的 $N$ 应替换为激活参数 $N_{active}$,但总参数 $N_{total}$ 影响显存 - **数据需求可能不同**:MoE 的专家需要足够数据来分化,可能需要比 Dense 模型更多的训练数据 - **通信开销**:All-to-All 通信是 MoE 的额外瓶颈,Dense 模型不需要考虑 **Q4: μP(Maximal Update Parameterization)解决了什么问题?** **问题**:传统参数初始化中,超参数(如学习率、初始化标准差)需要针对每个模型规模单独调优。小模型上找到的最优 lr 放到大模型上可能完全不对。 **μP 的解决方案**:通过数学分析,设计一种参数化方式,使得: - 在小模型(如 256 维)上调优的超参数可以直接迁移到大模型(如 4096 维) - 避免了大模型上昂贵的超参数搜索 - 训练初期的 loss 曲线在不同规模下表现一致 **实际价值**:DeepSeek-V3 等大模型训练已采用 μP,节省了大量调参成本。

🔗 参考资料