NETBYTE
启动项目

研究

Helix 第一部分:训练一个欧洲语言模型

我们正在训练自己的语言模型。它很小——只有 3.2 亿参数——却能读懂欧盟全部 24 种官方语言,并且在为游戏打造的显卡上训练。第一部分讲述我们如何走到今天;训练结束后会推出第二部分。

作者:Marcus Weitschat 阅读约 8 分钟

点阵图,展示 Helix 中每个 token 能关注的范围:蓝色条带代表局部窗口,黄色圆点代表所在的块,零散的橙色圆点代表远距离检索。

一家游戏工作室为什么要训练语言模型

NETBYTE 制作游戏、应用和网站。语言模型越来越多地出现在这类产品里:会回话的角色、能听懂问题的帮助、能动手办事的工具。大多数开放模型首先是用英语思考的;爱沙尼亚语、爱尔兰语或马耳他语只是捎带。我们想亲手弄懂整条链路——数据、分词器、架构、训练——并搞清楚钱究竟花在了哪里。

参数
3.2 亿
种欧盟官方语言
24
训练 token
65 亿
租用 GPU 的费用
≈ 12 美元

Helix 最初是一个研究原型。下面的每一条都是塑造它的决定,每个决定都有测量数据支撑——还有那些最耗费我们时间的错误。

四个想法,只留下一个

这个原型针对当今文本生成器的四个已知弱点。它以 16 个 token 为一块来写,而不是一次一个 token;它可以多次循环通过一组共享的核心层;它为每个块预测一个紧凑的“计划”;它还把廉价的局部注意力与处理远距离的线性注意力结合起来。

分块写作立刻见效:一个小型测试模型只用 13 次网络前向就写出了 64 个 token,而传统模型每个 token 都要跑一次——工作量大约只有五分之一。另外三个想法没能通过一项更难的测试。我们设计了答案远在局部窗口之外的任务,模型必须回看整段文本。

图 1 远距离检索 在线索位于局部窗口之外的检索任务中的正确率。小型参考模型,每个变体预算相同。
  1. 仅局部窗口 23.1%
  2. + 线性注意力、计划和循环 23.1%
  3. + 2 个精确全局注意力头 49.4%
  4. 完整注意力(对照) 49.0%
查看数据
变体正确率
仅局部窗口23.1%
+ 线性注意力、计划和循环23.1%
+ 2 个精确全局注意力头49.4%
完整注意力(对照)49.0%
随机(25%)25.0%

只有覆盖全程的精确注意力解决了这些任务。线性注意力、计划和循环都停留在随机水平;优化器甚至把线性记忆的半衰期压到了不足一个 token。两个精确的全局注意力头就足以追平完整注意力。

因此,最终模型在每一层保留八个窗口为 256 个 token 的局部注意力头,并每隔一层加入两个精确的全局注意力头;中间的层保留两个门控线性注意力头。计划和循环已关闭。它们仍在代码里并有测试覆盖,但在真实文本上不值它们的开销。

图 2 每一层在看什么 每层 10 个注意力头,共 12 层。每层都有 8 个局部注意力头;奇数层再加 2 个精确全局注意力头,偶数层加 2 个门控线性注意力头。
  • 局部,窗口 256 个 token
  • 精确全局注意力
  • 门控线性注意力
查看数据
注意力头类型层每层头数
局部,窗口 256 个 token1–128
精确全局注意力1, 3, 5, 7, 9, 112
门控线性注意力2, 4, 6, 8, 10, 122

靠测量,不靠猜

每一个训练技巧,我们都在一个 9400 万参数的模型上测试,每次运行预算相同:2950 万个 token、相同的随机种子、相同的数据顺序。同一配置跑两次的差异为 ±0.03,所以比这更小的差别都是噪声。

图 3 哪些有用,哪些只是噪声 相对 AdamW 基线的验证损失变化。9400 万参数模型,每次运行 2950 万个 token。低于零更好;灰色带为运行之间的噪声(±0.03)。
  1. Muon + WSD 调度 -0.587
  2. Muon 优化器 -0.347
  3. 更深更窄的网络 -0.099
  4. WSD 调度 -0.080
  5. 值残差 -0.007
  6. z-loss +0.029
  7. 分组查询注意力 +0.088
查看数据
改动Δ 损失(奈特)
Muon + WSD 调度-0.587
Muon 优化器-0.347
更深更窄的网络-0.099
WSD 调度-0.080
值残差-0.007
z-loss+0.029
分组查询注意力+0.088

Muon 优化器是唯一的大杠杆,并且可以与 warmup-stable-decay 学习率调度叠加。按照 Muon 作者的建议,把嵌入层和输出层交回 AdamW,又改善了 0.12,训练也快了 5%。组合并不是简单相加:更深更窄的网络在 AdamW 下有帮助,在 Muon 下却有害。所以每个有希望的组合都单独跑了一次。

24 种语言,65 亿 token

Helix 读取的网络文本中,英语来自 FineWeb-Edu,其余 23 种语言来自 FineWeb-2——较大的语言取其按质量筛选后的前十分之一。代码、数学和一小股合成对话数据补全了配比。英语占三分之一。其他语言按现有文本量加权,并做了平滑,以免爱尔兰语和马耳他语被淹没;任何来源重复都不超过四次——在这个次数以内,重复数据几乎和新数据一样好。

图 4 Helix 读什么 各来源组在训练 token 中的占比。语料共 65 亿 token,分 34 个数据流;代码与标记语言包括 Python、JavaScript、C、C++、Java、HTML、CSS 和 Markdown。
  1. 其他 23 种欧盟语言 51.6%
  2. 英语 33.0%
  3. 代码与标记语言 10.0%
  4. 数学 3.0%
  5. 合成对话与工具 2.4%
查看数据
来源占比
其他 23 种欧盟语言51.6%
英语33.0%
代码与标记语言10.0%
数学3.0%
合成对话与工具2.4%

对话数据是抽取式的:回答摘自真实段落,工具结果是计算出来的而不是编造的。它教的是格式,不是知识。分词器是一个有 64,000 个词条的字节级 BPE;对每种拉丁字母书写的语言,它都能把 3.3 到 4 个字节的文本装进一个 token。

三个值得一说的 bug

  • 偷看答案的模型。 在某条代码路径里,全局注意力头忽略了因果掩码,能看到未来的 token。损失在 75 步内从 6.85 降到 1.71,一次 16 小时的运行白费了。好得可疑的损失就是一份 bug 报告;现在有一个回归测试专门守着这一点。
  • 字符不等于字节。 压缩率是按字符而不是按 UTF-8 字节计算的。这凭空造出了中文的“弱点”,还让希腊语和保加利亚语看起来比实际差了将近一倍。
  • 在每个空行处被切断的文档。 编码器在每个空行处切分文档——而几乎每个源代码文件中间都有空行。代码和数学文本最多丢失了 35%。我们修好了分隔符,并在 10 月 31 日重建了整个语料库,用时 2 小时 12 分钟。

从办公桌到租来的机器

最初的 16.6 亿个 token 是在一块 AMD Radeon RX 7800 XT 上跑的。有两件事让它变得可用:一个默认关闭的注意力内核开关(没有它,注意力要慢 12 倍),以及用 torch.compile 编译每一层。按每秒 11,800 个 token 的中位数计算,剩下的部分还要将近五天。

于是我们写了一个自动驾驶程序。它在 Vast.ai 上租用 GPU,上传代码、语料和检查点,开始训练,每三小时把检查点取回本地,并在额度用完前停下。11 月 2 日,它先后碰上三台提供方始终没能启动的机器,最后选定了德国的两块 RTX 4070 Ti Super,每小时 0.363 美元。15.4 GiB 的上传用了 40 分钟。

图 5 训练速度 3.2 亿参数模型在序列长度 1,024 下每秒处理的 token 数(中位数)。本地:一块 AMD Radeon RX 7800 XT。租用:两块 NVIDIA RTX 4070 Ti Super。
  1. 本地,优化前 8,319
  2. 本地,编译后 11,830
  3. 租用,2 块 GPU 41,367
查看数据
配置token/秒
本地,优化前8,319
本地,编译后11,830
租用,2 块 GPU41,367

每秒 41,400 个 token 是办公桌那台机器的 3.5 倍。租用的部分——约 33 小时、48 亿个 token——花费大约 12 美元。

Helix 目前的进展

图 6 迄今为止的训练 每 token 的损失(奈特),越低越好。留出:模型从不训练的文本。训练:每 5000 万 token 取平均;在冷却阶段下降更快,部分原因是数据配比改变了。坐标轴止于计划的 65 亿 token。
  • 留出
  • 训练

损失(奈特/token)

已读 token(十亿)

查看数据
已读 token(十亿)留出训练
0.064.5714.261
0.553.7763.574
1.043.6943.469
1.543.5963.421
2.033.4263.238
2.523.3293.143
3.013.2913.113
3.503.2633.076
3.993.2253.079
4.493.2443.076
4.983.2183.036
5.353.1232.884

截至 2026 年 11 月 3 日,Helix 已读完 65 亿个 token 中的 53.5 亿个。从 52 亿开始进入冷却阶段:学习率逐步下降,数据配比转向数学、代码和对话。在所有数据流的留出文本上,损失为每 token 3.12 奈特。

图 7 各语言的情况 训练 53.5 亿 token 后,留出文本上的每字节比特数,越低越好。希腊语和保加利亚语看起来更好,部分是因为它们的每个字母占两个字节。
  1. 希腊语 0.721
  2. 保加利亚语 0.844
  3. 法语 1.065
  4. 英语 1.086
  5. 西班牙语 1.135
  6. 葡萄牙语 1.219
  7. 德语 1.257
  8. 荷兰语 1.268
  9. 意大利语 1.277
  10. 波兰语 1.355
  11. 丹麦语 1.364
  12. 匈牙利语 1.407
  13. 斯洛伐克语 1.412
  14. 马耳他语 1.415
  15. 罗马尼亚语 1.416
  16. 瑞典语 1.418
  17. 爱尔兰语 1.422
  18. 斯洛文尼亚语 1.431
  19. 捷克语 1.444
  20. 立陶宛语 1.450
  21. 拉脱维亚语 1.451
  22. 克罗地亚语 1.507
  23. 芬兰语 1.508
  24. 爱沙尼亚语 1.727
查看数据
语言每字节比特
希腊语0.721
保加利亚语0.844
法语1.065
英语1.086
西班牙语1.135
葡萄牙语1.219
德语1.257
荷兰语1.268
意大利语1.277
波兰语1.355
丹麦语1.364
匈牙利语1.407
斯洛伐克语1.412
马耳他语1.415
罗马尼亚语1.416
瑞典语1.418
爱尔兰语1.422
斯洛文尼亚语1.431
捷克语1.444
立陶宛语1.450
拉脱维亚语1.451
克罗地亚语1.507
芬兰语1.508
爱沙尼亚语1.727

这在实践中意味着什么,最好看一段未经修改的样本,取自约 49 亿 token 时的检查点。开头是我们写的,其余由 Helix 续写:

英语样本,49 亿 token 时的检查点,未经修改

开头: The history of the printing press begins in the fifteenth century, when Johannes Gutenberg introduced movable type to Europe. Before that, books 模型输出: for printing were usually in the form of texts, usually in the format of illustrations. In its introduction to the printing press, Gutenberg uses one line-of-action model to illustrate a series of printed pieces of a book.

语法、用词和主题都站得住,事实却不行。这大致就是 3.2 亿参数、65 亿 token 所能期待的水平:一个流畅但会编造内容的模型。

接下来

预训练将在几小时内结束。之后是长上下文阶段,使用 Project Gutenberg 的书籍和 EUR-Lex 的欧盟法律文本;然后是面向对话和工具使用的微调,以及一个加快生成速度的小型草稿模型。

返回全部文章

下一步

接下来想创造什么?

请告诉我们您的游戏、应用、网站或 AI 项目。一条简短的消息就足以开始。