CUDA 报告文档索引
CUDA 训练器知道它采样的文档
每个训练步从 .btok 二进制文件中拉取一个序列,该文件将许多文档端到端打包。CUDA 在损失旁记录文档索引:step 47213, source=gutenberg, doc=128407, loss=2.81。代理收集这些报告并维护每个来源见到的唯一文档索引集合。
从计数到覆盖率
源的覆盖率 = unique_docs_seen / n_docs。几个示例:
| 源 | n_docs | unique seen | 覆盖率 |
|---|---|---|---|
| gutenberg | 512,000 | 154,000 | 30.1% |
| hermes3-general | 67,395 | 47,176 | 70.0% |
| dictionary | 88,000 | 88,000 | 100.0% |
| synthetic-chat | 1,400 | 1,400 | 100.0% |
小型来源很快就会饱和。大型来源的覆盖率会持续数周低于 50%。覆盖率奖励鼓励 bandit 访问来源中尚未采样的文档。
奖励公式
覆盖率奖励从 0% 覆盖率时的 1.3 倍线性缩放到 50% 覆盖率时的 1.0 倍,然后在 50% 以上保持 1.0 倍不变:
if coverage < 0.5:
bonus = 1.0 + 0.3 * (1.0 - coverage / 0.5)
else:
bonus = 1.0
覆盖率为 0% 的源代码获得 1.3 倍加成;覆盖率为 25% 的源代码获得 1.15 倍加成;覆盖率为 50% 的源代码降至 1.0 倍。超过 50% 后,不再有加成。
计算奖励加成
两个不同的新鲜度信号
相同目标,不同粒度
ANDREA 有两种机制来防止过度训练单一来源。它们听起来相似;它们测量不同的东西。
Epoch 惩罚。 跟踪总体的过度拉取。当 lifetime_pulls / n_docs > 1.0 时,一个来源理论上已经至少遍历了每个文档一次。惩罚 = 1 / (1 + epochs)。一个拥有 1.4K 文档的 synthetic-chat 来源,在 5,600 次终身拉取(epochs = 4)时,获得惩罚 1/5 = 0.2x。Epoch 计数在重启间持久化;它们从不衰减。
覆盖率奖励。 跟踪来源内每个文档的新鲜度。CUDA 报告文档索引;代理为每个来源维护一个集合。唯一文档覆盖率低于 50% 的来源可获得高达 1.3x 的奖励。覆盖率奖励探索来源的尾部;epoch 惩罚惩罚耗尽它。
为什么两者都重要
| 信号 | 跟踪 | 方向 | 上限 | 重启后持续 |
|---|---|---|---|---|
| Epoch 惩罚 | 聚合过度拉取 | 降低 | 1/(1+e) | 是 |
| 覆盖加成 | 每文档新鲜度 | 提升 | 1.3x | 是 |
一个包含 500K 文档的 gutenberg 来源可以在整个 200K 训练运行中保持低于 50% 的覆盖率,同时从未接近 epoch=1。Epoch 惩罚忽略它;覆盖加成主动将 bandit 拉向 gutenberg 未探索的 70% 尾部。
相反,一个 1.4K 合成聊天来源会在几千次拉取内达到饱和覆盖(100%);覆盖加成保持在 1.0x,而 epoch 惩罚则增长。
区分两者
覆盖奖励为 ANDREA 带来的益处
它防止的失败模式
没有文档级跟踪的情况下,基于每步奖励选择的 bandit 会贪婪地挑选 .btok 序列。一个包含 500K 文档的 gutenberg 语料库中有几千个低交叉熵的序列(一致的散文、常见词汇)。仅基于奖励的 bandit 会反复返回这些序列,因为它们持续产生强烈的奖励信号。
结果:一个 500K 文档的语料库在 200K 训练步骤中仅采样大约 2K-5K 个不同的序列。模型记住这些序列,却从未见过其余部分。容量浪费;覆盖率停留在 1% 以下。
覆盖率奖励带来的好处
在 0% 覆盖率时为 1.3x,在 50% 时缩减到 1.0x。这种推动通过 UCB1 选择传播:覆盖率低的臂即使单次拉取奖励下降,也保持竞争力。bandit 通过设计而非偶然探索尾部。
在一个 500K 文档 gutenberg 上的 200K 步运行中,覆盖率奖励通常将观察到的覆盖率从 ~3%(无奖励)提高到 ~25-30%(有奖励)。相同计算量,触及的文档数量增加八到十倍。
跟踪信息的位置
| 组件 | 职责 |
|---|---|
microgpt_cuda.cu | 每个训练步骤报告文档索引 |
training_proxy.py | 每个源维护 seen_docs 集合 |
training_proxy.py | 计算覆盖率,向 bandit 奖励应用加成 |
training_proxy.py | 在重启间将 seen_docs 持久化到 .state.json |