纸上得来终觉浅,须知此事要躬行

“低成本实践”这个名字有两个来由。一是前阵子和孩子看了一部电视剧,叫《低智商犯罪》,觉得这个名字挺有意思;二是这些实验确实是在有限资源下完成的。这里的低成本,不只是少用几张 GPU,也包括尽量利用开源模型、开源语料和公开论文,把一个原本只有大公司才能做的项目,缩小到个人也能跑起来的程度。

训练 GPT 选择的任务是中英机器翻译。

机器翻译大概经历过三个时期。第一代是统计机器翻译,核心可以写成 P(T|S) ∝ P(S|T) × P(T):一边是翻译模型,一边是目标语言模型。第二代是以 RNN、Seq2Seq 和 Transformer 为代表的神经机器翻译,模型能力提高了,但需要海量双语平行语料。第三代则是大语言模型:先通过 Next Token Prediction 学习语言,再通过 Prompt、SFT 和偏好训练,让一个通用模型完成翻译。

前两代机器翻译流行的时候,也都没有真正做过。统计时代在训练 LDA,神经机器翻译时代主要做了 Word2Vec,后来又做了一些 BERT。机器翻译一直更偏 Research,既没有机会做,也确实不会做。到了大语言模型时代,开源模型、训练框架和数据都已经比较成熟,反而给了个人一次补课的机会。

把评估搞明白

机器翻译过去最常用的指标是 BLEU。它大致计算预测译文与参考译文之间的 N-gram 重合度。这个指标简单、稳定,也用了很多年,但它更关心字面是否相似。一个意思正确、甚至表达更自然的译文,只要和参考答案写得不一样,也可能得到较低的分数。

COMET 则是一个学习出来的翻译评估模型。它同时读取源句、参考译文和模型译文,再给出质量分数。到了大语言模型时代,翻译结果越来越多样,仅靠字面重合已经不够,COMET 这类指标的重要性也越来越高。

评估方式并不是实验结束后才补上的报表,它会反过来决定训练方向。CPO 需要从多个候选中选择更好的译文,GRPO 也需要奖励信号。如果没有一个相对可信的自动指标,偏好训练和强化学习就无从谈起。

Interpreter:由 Qwen3 开始

第一条路线放在 Interpreter 仓库里。我参考了 ALMA 的做法,但把任务收缩到中英互译,底座也换成了 Qwen3-1.7B-Base。Qwen3 本身已经见过大量中英文语料,1.7B 的规模又能放进消费级显卡,适合作为低成本实验的起点。

训练分为三个阶段:

  1. SFT:使用约 3.68 万条清洗后的 ALMA/X-ALMA 平行数据,让模型稳定理解翻译指令。
  2. CPO:让 SFT 模型为同一源句生成多个候选,再用 COMET 选出较好和较差的译文,构造约 4.4 万条偏好数据。
  3. GRPO:以 COMET 作为主要奖励,对模型继续做全参数强化学习。

最终在 WMT23 上得到下面的结果:

StageZh→En BLEUZh→En COMETEn→Zh BLEUEn→Zh COMET
Qwen3-1.7B-Base(5-Shot)21.830.795041.150.8490
+ SFT19.650.786340.740.8384
+ CPO19.160.801732.690.8507
+ GRPO20.310.805333.690.8540
SFT → GRPO(跳过 CPO)22.850.800341.970.8540
HY-MT1.5-1.8B(参考)17.840.805231.740.8669

亲手跑过以后,能很清楚地看到所谓的 Alignment Tax。SFT 之后,模型在四项指标上反而都不如 Base 的 5-Shot;CPO 明显提高了 COMET,却损失了不少 BLEU;GRPO 又把效果往前推了一步。另一个意外结论是,CPO 并不是必需的。调好参数以后,直接走 SFT → GRPO,既能保持较高 BLEU,也能取得相当的 COMET。

这套训练不能说没有成本,但整个流程可以在单张 RTX 4090 上完成。它和大规模预训练当然无法相比,却已经足够让我把 SFT、偏好数据构造、CPO、GRPO 和多测试集评估完整走一遍,而不只是停留在论文和代码片段里。

Summer:动一下底座模型

后训练做完以后,问题又回到了预训练。Qwen3 使用 119 种语言、36T Token 训练,这显然不属于个人能够复现的“低成本”。但底座模型也不是完全没有可以动手的地方。

如果任务只有中英互译,Qwen3 原生词表会显得有些冗余。于是又做了 Summer:把 Qwen3 的原生 Tokenizer 换成面向中英文的 Piece Tokenizer,再通过继续预训练恢复模型能力。这类工作通常叫 ReTok。

ReTok 大概分为三步。第一步,用旧 Tokenizer 拆解新词,用旧词 Embedding 的平均值初始化新词;第二步,冻结 Transformer 主体,先训练新的 Embedding 和 LM Head;第三步,放开全部参数,使用混合语料继续预训练。最终的 v18 模型使用约 10 亿 Token 做第一阶段恢复,再用约 2 亿高质量 Token 退火。

这个实验没有得到一个“换了 Tokenizer 就全面变强”的漂亮结论。换词表会直接破坏底座模型已经学到的能力,恢复过程比预想中困难。ReTok 底座的 5-Shot 翻译明显弱于原始 Qwen3;但继续执行同样的 SFT、CPO 和 GRPO 后,差距又被追回了大半:

StageZh→En BLEU / COMETEn→Zh BLEU / COMET
ReTok Base(5-Shot)17.44 / 0.758238.10 / 0.8255
+ SFT19.34 / 0.776240.09 / 0.8392
+ CPO18.11 / 0.794131.38 / 0.8480
+ GRPO18.43 / 0.796731.79 / 0.8511

这至少说明两件事。第一,Tokenizer 并不是一个可以随便替换的前处理组件,它已经和模型参数深度绑定;第二,底座模型只要还在某个基本门槛之上,后训练确实能够重新塑造它的任务能力。ReTok 没有超过原始 Qwen3,但它让我真正碰到了预训练中的词表、Embedding 初始化、数据配比、冻结恢复和全参数继续训练。

为什么还要做

其实也经常怀疑这些项目的意义。现在的大语言模型写代码、写文章的能力已经超过绝大多数人,很多用户需求也直接交给模型了。那为什么还要自己训练一个翻译模型?是为了弥补当年没有做过机器翻译的遗憾,还是为了弄清大语言模型的技术细节?

后来觉得,人还是有非理性的一面。机器可以天然地 Loop 下去,但人会怀疑、会厌倦,也会因为不认输而再试一次。也许正是这种不够理性的部分,才会让人去做一些明明不合算、也不一定成功的事情。

项目与模型