CS336 · 第 11 课

Scaling Laws:深入拟合、外推与决策

第 9 课建立了 scaling law 的宏观图景;这一课深入实际工程问题:如何从噪声数据中稳健拟合幂律?如何量化外推的不确定性?如何用 scaling law 在真实约束下做最优决策?

授课:Tatsu Hashimoto 预计用时:80 分钟 难度:中等 → 较高

Spring 2026 官方来源:Lecture 11 PDF · 课程日程

本页是中文学习导读;讲次主题、教师与材料版本以 Stanford 官方页面和讲义为准。

本讲问题:第 9 课给出了 scaling law 的结论;本讲进一步处理真正困难的部分:有限、带噪声的实验怎样支持对更大训练规模的外推和决策。

30 秒知识地图

选择函数形式 → 设计小规模 runs → 拟合参数与置信区间 → 检查 residual / regime shift → 外推候选规模 → 用敏感性分析做决策。

问题与 prerequisite refresher

本课把“曲线看起来像直线”升级为可审计预测。Parameter 是模型中待拟合的系数,hyperparameter 是训练设置,两者不要混淆;residual = observation − fitted prediction,它的结构比单个 \(R^2\) 更能暴露模型错在哪里。

一次可信外推的证据链

run design → observations → fit parameters
                         ├→ held-out residuals
                         ├→ bootstrap / uncertainty
                         └→ regime-shift checks
                                  ↓
candidate extrapolation → sensitivity analysis → decision

point estimate ≠ confidence interval ≠ guarantee

为什么 1B→1T 不是“多一点”

参数规模从 \(10^9\) 到 \(10^{12}\) 是 1000×。即使 log-space 只向右移动 3 个 decade,任何很小的 exponent 或 floor 偏差都会被外推放大。用 runs 拟合后,应故意留出最大的若干规模做 pseudo-extrapolation:如果连已知的大 run 都预测不好,就没有理由信任更远预测。

为什么不是选训练误差最低的函数

更灵活的函数可追噪声并给出荒谬 asymptote;随机 split 也可能让相邻规模泄漏趋势。反例:所有 residual 在小 \(N\) 为正、大 \(N\) 为负,即使平均 residual 为零,也说明函数形式存在系统偏差。


从第 9 课说起

第 9 课的核心结论:

这一课的核心问题:这些结论是从拟合得到的。拟合本身有噪声,外推有风险,实际决策有更多约束。我们需要理解这些机制才能安全地使用 scaling law。

回顾:幂律形式

# 参数 vs 损失(固定数据量)
L(N) = (N_c / N)^α_N

# 数据 vs 损失(固定参数量)
L(D) = (D_c / D)^α_D

# 联合形式(Chinchilla 论文)
L(N, D) = E + (N_c / N)^α + (D_c / D)^β
# 其中 E 是不可约损失(irreducible loss)

如何拟合 Scaling Law

方法 1:对数线性回归(简单但不稳健)

对幂律 L = (N_c / N)^α 取对数,得到:

log L = α log N_c − α log N
      = a − α × log N     (关于 log N 的线性函数)

# 算法:
# 1. 训练多个不同大小的模型(固定其他超参)
# 2. 记录 (log N, log L)
# 3. 做线性回归
# 4. 斜率 = −α,截距 = α log N_c

问题:在 log-log 图上,小模型的 loss 变化更剧烈,大模型变化平缓。简单线性回归对所有点等权对待,会被小模型区域主导。而且 log 变换会让小 loss 区域的噪声被放大。

方法 2:非线性最小二乘(NLLS)

直接拟合原始幂律形式,避免 log 变换的偏差:

import numpy as np
from scipy.optimize import curve_fit

def scaling_law(N, N_c, alpha, L_inf):
    """带不可约损失的幂律"""
    return (N_c / N) ** alpha + L_inf

# 数据:多个模型的参数量和验证 loss
N_values = np.array([1e6, 3e6, 1e7, 3e7, 1e8, 3e8, 1e9])
losses = np.array([4.2, 3.8, 3.5, 3.2, 2.9, 2.7, 2.5])

# 拟合
popt, pcov = curve_fit(scaling_law, N_values, losses,
                       p0=[1e5, 0.1, 2.0],
                       bounds=([0, 0, 0], [np.inf, 1, np.inf]))
N_c, alpha, L_inf = popt

print(f"α = {alpha:.3f}")
print(f"N_c = {N_c:.2e}")
print(f"L_∞ = {L_inf:.3f}")

方法 3:考虑数据量的联合拟合(Chinchilla 方法)

Chinchilla 论文使用的是同时变化 N 和 D 的联合拟合:

def chinchilla_law(N, D, E, alpha, beta, N_c, D_c):
    """
    Chinchilla 论文的参数化形式
    L(N, D) = E + A/N^α + B/D^β
    其中 A = N_c^α, B = D_c^β
    """
    return E + (N_c / N) ** alpha + (D_c / D) ** beta

# 实验设计:
# - 变化 N: 70M, 160M, 400M, 1B, 14B 等
# - 变化 D: 对应每个 N 训练不同步数
# - 总数据点:几百个 (N, D, L) 三元组

方法 4:Isoflop 曲线拟合(Hoffmann 2022)

Chinchilla 论文采用的更精细策略:

  1. 选择几个固定的算力预算 C(如 1e18, 1e19, 1e20 FLOPs)
  2. 对每个 C,训练多个 (N, D) 组合(满足 6ND = C)
  3. 画出 Isoflop 曲线:x 轴 = N,y 轴 = L
  4. 找到每条曲线的最优点 N_opt(C)
  5. 拟合 N_opt(C) 和 D_opt(C) 与 C 的关系

Chinchilla 论文的三种拟合策略对比:

策略 1: 固定 D,变化 N → L(N)
策略 2: 固定 N,变化 D → L(D)
策略 3: Isoflop 曲线 → 找最优 (N, D)

策略 3 最可靠,因为:
- 直接在目标算力约束下优化
- 避免了外推到未探索区域
- N_opt(C) 和 D_opt(C) 可以直接读出

超参数的影响

Scaling law 的拟合结果依赖于训练超参数:

超参数影响建议
Learning rate太小→收敛慢,太大→噪声大对每个 N 做 lr sweep
Batch size影响梯度噪声随 N 增大而增大
Training tokens太少→欠拟合确保每个模型都收敛
Architecture影响 α 和 N_c固定架构(只变宽度)
Warmup/cooldown影响训练稳定性固定 schedule 形式

关键洞察:Scaling law 不是物理定律,而是在特定超参选择下的经验拟合。改变 optimizer 或 architecture,幂律指数 α 会变化。所以拟合时除了变 N 和 D,其他一切都要固定。


噪声、方差与置信区间

损失的随机性来源

同一个 (N, D) 配置,多次训练可能得到不同的 loss:

# 估计噪声水平的实验:
# 固定 N=1B, D=20B,训练 5 次

seeds = [42, 123, 456, 789, 1024]
losses = []
for seed in seeds:
    model = train(N=1e9, D=20e9, seed=seed)
    losses.append(evaluate(model, val_set))

# 例: losses = [2.81, 2.79, 2.83, 2.80, 2.82]
# 均值 = 2.81, 标准差 = 0.015
# 这个噪声虽然小,但在拟合时不可忽略

Bootstrap 置信区间

给定拟合结果,如何量化不确定性?

from scipy.optimize import curve_fit
import numpy as np

def bootstrap_ci(N_data, loss_data, n_bootstrap=1000, alpha=0.05):
    """用 bootstrap 估计拟合参数的置信区间"""
    params_list = []
    n = len(N_data)

    for _ in range(n_bootstrap):
        # 有放回抽样
        indices = np.random.choice(n, size=n, replace=True)
        N_boot = N_data[indices]
        loss_boot = loss_data[indices]

        try:
            popt, _ = curve_fit(scaling_law, N_boot, loss_boot,
                                p0=[1e5, 0.1, 2.0])
            params_list.append(popt)
        except RuntimeError:
            continue  # 拟合失败则跳过

    params_array = np.array(params_list)
    # 计算每个参数的置信区间
    lower = np.percentile(params_array, 100 * alpha/2, axis=0)
    upper = np.percentile(params_array, 100 * (1 - alpha/2), axis=0)

    return lower, upper

外推的不确定性

外推(预测未训练过的尺度)的不确定性会指数增长:

外推距离不确定性风险
1 倍(拟合范围内)低安全
3 倍中等可用
10 倍高谨慎
100 倍极高不可靠

实际案例:Chinchilla 用 70M-16B 范围的数据拟合,预测 70B 最优配置。这是 ~4 倍外推,尚可接受。但如果用 1M-1M 数据预测 1T 模型,那是 10^6 倍外推——完全不可靠。

幂律弯曲(Bend in the power law)

幂律假设 L ∝ N^{-α} 在所有尺度成立。但实际上:

# 检测幂律弯曲的方法:
# 1. 拟合后看残差(residuals)
# 2. 如果残差有系统性模式 → 幂律不完全成立

predicted = scaling_law(N_values, *popt)
residuals = losses - predicted

# 如果残差在某个 N 范围内系统性为正或负
# 说明该区域的实际 α 与拟合值不同

外推挑战

为什么要外推?

训练 70B 模型需要数百万美元。我们不可能训练 100 个不同大小的 70B 模型来找最优配置。所以必须:

  1. 训练小模型(1M - 1B 范围,便宜)
  2. 拟合 scaling law
  3. 外推预测大模型(70B - 1T)的最优配置

外推的风险

风险原因后果
幂律弯曲大尺度时 α 变化预测的配置不是真正的最优
架构差异小模型最优架构 ≠ 大模型最优拟合的 N_c 不适用于大模型
优化困难大模型训练更不稳定实际 loss 高于预测
数据质量大数据集质量可能下降预测的 D 不够

降低外推风险的策略

策略 1:覆盖足够宽的尺度范围

好的实验设计:
- 训练 10+ 个模型
- 覆盖至少 2 个数量级的 N(如 1M 到 1B)
- 每个 N 尝试多个 D
- 外推距离控制在 10 倍以内

不好的实验设计:
- 只训练 3-4 个模型
- 只覆盖 1 个数量级
- 外推到 100 倍

策略 2:保守预测 + 区间估计

不要只给一个点估计,给出置信区间:

例:预测 70B 模型的最优 D
点估计: D_opt = 1.4T tokens
95% 置信区间: [1.0T, 2.0T]

实际决策:选择区间的保守端
因为 undertraining 比 overtraining 代价更高
(overtraining 只是多花训练钱,undertraining 是模型能力不足)

策略 3:中间验证

在拟合范围和外推目标之间,训练一个中等规模模型验证:

拟合范围: 1M - 1B 参数
外推目标: 70B 参数
中间验证: 训练一个 7B 模型,检查预测是否准确

如果 7B 的预测准确 → 外推到 70B 更可信
如果 7B 有偏差 → 修正模型后再外推


用 Scaling Law 做决策

场景 1:固定算力预算,最大化模型性能

这是 Chinchilla 论文解决的问题:

已知: 总 FLOPs = C = 6ND
目标: 最小化 L(N, D)
方法: 用拟合的 L(N, D) 代入约束,求最优

如果 L(N) = (N_c/N)^α_N, L(D) = (D_c/D)^α_D
且 C = 6ND → D = C/(6N)
代入: L(N) = (N_c/N)^α_N + (6N D_c/C)^α_D

对 N 求导 = 0,得最优条件:
α_N × N_c^α_N × N^(-α_N-1) = α_D × (D_c × 6 / C)^α_D × α_D × N

化简: N_opt ∝ C^(α_N / (α_N + α_D))
D_opt ∝ C^(α_D / (α_N + α_D))

Chinchilla 的拟合结果:
α_N ≈ 0.46, α_D ≈ 0.54 (近似)
所以 N_opt ∝ C^0.46, D_opt ∝ C^0.54
比例: D_opt / N_opt ≈ 20

场景 2:考虑推理成本

Chinchilla 只优化了训练 loss,但实际部署时推理成本也很重要:

推理成本 ∝ N(每个 token 的计算量)
总成本 = 训练成本 + 推理成本 × 推理次数

训练成本 ∝ 6ND
推理成本 ∝ N × num_inferences

关键洞察:
如果推理次数 >> 训练次数 → 推理成本主导
→ 应该用更小的 N(推理更便宜),用更多的 D 补偿

Llama 2 的实际选择:
- 训练成本 ≈ 数百万美元
- 推理次数 ≈ 数十亿次
→ 推理成本 >> 训练成本
→ 选择 D ≈ 27.5N(而非 Chinchilla 的 20N)

场景最优 D/N原因
只关心训练损失20NChinchilla 最优
推理次数多25-40N推理成本主导,选更小 N
推理次数极少10-15N训练成本主导,选更大 N

场景 3:固定时间,选择模型大小

实际约束往往是时间 + 硬件,而非 FLOPs:

已知约束:
- T 天时间
- K 张 GPU(每张峰值算力 P FLOP/s)
- MFU(模型算力利用率,通常 0.3-0.5)
- 每张 GPU 内存 M GB

总 FLOPs = K × P × MFU × T × 86400
所以: 6ND = K × P × MFU × T × 86400

内存约束: 模型大小 + optimizer states ≤ K × M
对于 AdamW: 内存 ≈ 12N bytes (fp32 param + m + v)
所以: N ≤ K × M / 12

求解满足两个约束的 (N, D):
先由内存约束确定 N_max
然后 D = C / (6 × N_max)

场景 4:多目标权衡

实际决策需要同时考虑多个目标:

目标函数可以扩展为:
min L(N, D) + λ × inference_cost(N)

或者更复杂的形式:
min α × training_cost(N, D) + β × inference_cost(N) + γ × L(N, D)

其中 α, β, γ 是根据业务需求设定的权重

例:一个 API 服务
- 训练成本: 100 万美元(一次性)
- 推理成本: 0.002 美元/1K tokens
- 日活: 10M 用户 × 1000 tokens = 10B tokens/天
- 推理日成本: 20,000 美元/天
→ 推理成本在 ~50 天内超过训练成本
→ 应该选择更小 N + 更多 D


Beyond Chinchilla:数据质量与 Overtraining

Chinchilla 的核心假设

Chinchilla 假设所有 token 等价——每个 token 对降低 loss 的贡献相同。但这个假设在现实中不成立:

假设现实影响
所有 token 等价高质量 token 价值 >> 低质量实际最优 D/N 可能更低
Token 独立重复 token 边际价值递减去重后需要的 D 更少
数据无限高质量数据有限可能需要在低质量数据上 overtrain
幂律在所有尺度成立大尺度可能弯曲外推可能高估大模型收益

数据质量的影响

DCLM (DataComp-LM) 等研究表明,经过严格质量过滤的数据上训练,可以用更少的 token 达到相同 loss:

例:在原始 Common Crawl 上
7B 模型 + 140B tokens → loss = 2.5

在 DCLM(高质量过滤)上
7B 模型 + 50B tokens → loss = 2.5

结论: 高质量数据打破了 D=20N 的比例
实际最优 D/N 取决于数据质量

Overtraining 的合理性

有时故意 overtrain(D > 20N)也有好处:

关键洞察:Chinchilla 的 D=20N 是在特定数据质量和特定目标(最小化验证 loss)下的最优。实际决策需要考虑数据质量、推理成本、下游任务需求等多个因素。

Overtraining 的风险

Overtrain 过多也有代价:

实际的数据策略

现代 LLM 训练的数据策略(综合 Chinchilla 和后续研究):

1. 预训练阶段
- 使用 D ≈ 20-30N tokens
- 优先使用高质量数据
- 后期混入更多低质量数据(课程学习)

2. Mid-training(可选)
- 切换到更高质量/更相关的数据
- 训练额外的 5-10% tokens
- 用于增强特定能力(长上下文、推理)

3. Post-training
- SFT: 数万到数十万个高质量样本
- RLHF/DPO: 数千到数万个偏好对


拟合实战:完整流程

Step 1:实验设计

# 确定要变化的范围
# - N: 至少 10 个值,覆盖 2-3 个数量级
# - D: 每个 N 至少 3 个值(不同训练步数)
# - 其他超参:全部固定

model_sizes = [1e6, 3e6, 1e7, 3e7, 1e8, 3e8, 1e9, 3e9]
tokens_per_size = {
    1e6: [2e7, 5e7, 1e8],
    1e7: [2e8, 5e8, 1e9],
    # ... 每个 N 对应多个 D
}

# 总实验数: 8 × 3 = 24 个模型
# 如果每个模型训练成本 100 美元 → 总成本 2400 美元
# 这比训练一个 70B 模型便宜得多

Step 2:训练与记录

import json

results = []
for N in model_sizes:
    for D in tokens_per_size[N]:
        # 训练模型
        model = train_model(N=N, D=D, seed=42)

        # 记录结果
        results.append({
            "N": N,
            "D": D,
            "val_loss": evaluate(model, val_set),
            "train_loss": evaluate(model, train_set),
            "training_time": get_training_time(),
        })

# 保存结果
with open("scaling_results.json", "w") as f:
    json.dump(results, f, indent=2)

Step 3:拟合与验证

# 加载数据
results = json.load(open("scaling_results.json"))
N_data = np.array([r["N"] for r in results])
D_data = np.array([r["D"] for r in results])
loss_data = np.array([r["val_loss"] for r in results])

# 拟合联合模型
def joint_law(N, D, E, alpha, beta, A, B):
    return E + A * N ** (-alpha) + B * D ** (-beta)

popt, pcov = curve_fit(
    lambda x, E, alpha, beta, A, B: joint_law(x[0], x[1], E, alpha, beta, A, B),
    (N_data, D_data),
    loss_data,
    p0=[2.0, 0.1, 0.1, 10.0, 10.0]
)

# 检查拟合质量
predicted = joint_law(N_data, D_data, *popt)
r_squared = 1 - np.sum((loss_data - predicted)**2) / np.sum((loss_data - loss_data.mean())**2)
print(f"R² = {r_squared:.4f}")  # 希望 > 0.99

Step 4:预测最优配置

from scipy.optimize import minimize

C_target = 6 * 70e9 * 1.4e12  # 目标: 70B 模型, Chinchilla 推荐 1.4T tokens

def loss_at_optimal_D(N):
    """给定 N,计算最优 D 和对应 loss"""
    D_opt = C_target / (6 * N)  # 满足算力约束
    return joint_law(N, D_opt, *popt)

# 在合理范围内搜索最优 N
result = minimize(loss_at_optimal_D, x0=[70e9], bounds=[(1e9, 200e9)])
N_optimal = result.x[0]
D_optimal = C_target / (6 * N_optimal)

print(f"最优配置: N = {N_optimal:.2e}, D = {D_optimal:.2e}")
print(f"预测 loss: {result.fun:.4f}")

Scaling Laws 的深层局限

1. 只捕捉训练 loss,不捕捉能力

验证 loss 是连续、平滑的,但下游能力可能是"涌现"的——在某个尺度突然变得可用。Scaling law 无法预测这种相变。

2. 假设架构不变

拟合的 α 和 N_c 是针对特定架构的。如果改变 attention 类型(如 GQA)、使用 MoE、或改变激活函数,整个 scaling law 会变化。

3. 忽略推理效率

Chinchilla 的 70B 模型训练成本低于 GPT-3 175B,但推理成本更高(更多 tokens 需要处理)。对于推理密集型应用,Chinchilla 配置可能不是最优。

4. 数据质量不可控

Scaling law 假设我们可以获得任意多的高质量数据。但现实中高质量数据有限,低质量数据可能引入噪声或偏见。

5. 评估指标单一

只优化验证 loss,但实际关心的是下游任务表现(MMLU、HumanEval 等)。Loss 和下游任务之间有关联但不是完美相关。


知识检查

问题 1:对幂律 L = (N_c / N)^α 取对数后得到什么形式?

问题 2:如果你用 1M-1B 参数范围的数据拟合 scaling law,预测 1T 参数模型,外推距离是多少?

问题 3:如果一个模型会被调用数十亿次做推理,应该如何调整 D/N 比例?

问题 4:如果数据质量极高(如全部是教科书级别的数据),Chinchilla 的 D=20N 比例会如何变化?

问题 5:如何用 Bootstrap 方法估计 scaling law 拟合的不确定性?


Concept Check · residual 平均为零够不够

小模型 residual 全为正、大模型全为负,但整体平均为零。Fit 是否可信?

答案:不可信;残差随规模有系统结构,说明函数形式或 regime 假设错误。

若只看均值,你把“误差互相抵消”错当成了“误差是无结构噪声”。

你现在应该能够解释

通往第 12 课

Scaling law 预测的是某个测量量;下一课追问这个量是否真的代表我们关心的能力,以及 tokenizer、prompt、judge 和 contamination 如何改变测量。

如果只能记住 5 件事

拟合方法

对数线性回归简单但不稳健;NLLS 更可靠;Isoflop 曲线最精确

外推风险

不确定性随距离指数增长;保守预测 + 中间验证

决策框架

算力 + 内存 + 推理成本联合优化,不是单目标

Beyond Chinchilla

数据质量打破 token 等价假设;overtrain 有时合理


延伸阅读

Reference · 延伸阅读与一手资料