124M参数模型崩溃分析 | AI生成和翻译

Home 2026.06

你的124M模型在当前的规模和训练预算下表现完全符合预期:它能很好地处理分布内的前缀,然后迅速退化为token级别的退化

实际发生了什么

输出中有两个明显不同的阶段:

1. 连贯区域(BST部分): 这是你提示词的延续。模型生成了语法完美、地道的Java代码——正确的insertRec递归、合适的空值处理、平衡的花括号。这是一种接近记忆的泛化:BST实现是GitHub-Java训练数据中极为常见的模式,因此模型从一个尖锐、低熵的分布中采样。几乎每个下一个token都有很高的概率。这是简单模式。

2. 退化(从boolean search开始): 来看看确切的失败点:

boolean search(int key) {
    return;        // ← 第一个错误:布尔方法中出现了void返回
}

一旦模型生成了语义无效的token,它就会在训练数据中不存在的上下文上进行条件化。没有真实的Java文件会包含boolean search(int key) { return; }。因此条件分布P(x_t | x_<t)变得平坦——模型对于接下来应该出现什么没有清晰的信号,因为它已经偏离了数据流形。从那时起就进入了一个反馈循环:垃圾上下文→平坦分布→垃圾token→更多垃圾上下文。

.S.S.S.S重复是典型的标志。在top_k=200temp=0.8的情况下,一旦分布变平坦,.S很可能位于一个局部概率峰值(句点加大写S在this.S...这样的标识符中很常见),所以采样器不断选择进入同一个吸引子盆地。这就是Holtzman等人描述的退化现象——即使在采样(而非贪心解码)时也会发生。

为什么这已经是预期上限

在受限代码语料上训练的124M参数模型,其容量足以学习:

不足以维持:

前向传递一旦提交了一个糟糕的token,就没有任何机制可以“撤出”——自回归解码本质上是贪婪的,因为它没有前视或回溯。GPT-2-small仅仅缺乏足够的表示深度,无法在约30-50个新奇结构token之后保持语义状态向量的连贯性。

实际应该怎么做

首先进行诊断——量化退化程度。sample.py中添加每个token的对数概率/熵日志记录:

# 在model.py的generate()中,计算logits之后
probs = F.softmax(logits, dim=-1)
entropy = -(probs * probs.clamp_min(1e-9).log()).sum(-1)
# 每一步记录entropy[0].item()

绘制熵值相对于位置的曲线。你会看到它在return;这个token处急剧上升。这个峰值正是模型在告诉你它失去了方向。这是最值得添加的一个功能。

然后,按优先级顺序尝试以下杠杆:

  1. 降低top_k/增加top_p 对于代码而言top_k=200太大了——它保留了200个候选token,即使只有2-3个是有效的。尝试top_k=40或核采样top_p=0.95。这不能修复潜在的漂移,但能削减那些播种退化的尾部token。

  2. 重复惩罚。 nanoGPT没有自带这一功能。将其插入generate()

for tok in set(idx[0].tolist()):
    logits[0, tok] /= 1.15

这直接打破了.S.S.S吸引子。

  1. 更多训练/更多数据。 诚实的答案。检查你的train.py损失曲线——如果验证损失仍在下降,说明你训练不足。124M模型需要数十亿个代码token才能超越教科书级别的能力。你的MI300X(192GB)可以容纳比4070大得多的批次——向那个方向推进。

  2. 扩大规模。 这本质上是一个容量问题。从124M→350M→760M(你的GPT-2 760M运行)将显著延长连贯窗口。你已经知道这一点;从BST→垃圾的过渡正是你训练760M模型这一行为的直观证明

对你来说有趣的是:这种退化正是生产模型中KV缓存、更好的采样和规模扩展所要解决的问题。亲眼看着自己的模型以这种方式崩溃,比任何相关论文都能带来更好的直觉。

参考文献:


Back Donate