AI书生大模型:这次怎么落地的
去年开始跟微软那边合作搞 InternLM 的时候,我也想过这个问题:一个国内的模型,为什么微软会感兴趣?
InternLM 是上海人工智能实验室(商汤科技、清华大学等)开源的千亿参数大语言模型,微软在中间主要是提供工程经验和一些基础设施支持。
为什么要做这件事
为什么要参与?
一个现实原因是:微软当时在内部也在找开源模型合作,想看看国内团队的路线跟 OpenAI 有什么不同。另一个更务实的原因是:大模型训练这个活儿,没人敢说自己全搞明白了,多看看别人的实践,总能学到点东西。
但真正的动机是:想搞清楚国内团队做大模型的真实约束条件——算力、数据、工程能力,这些东西跟美国那边完全不一样。这些差异最终会体现在架构选择、工程实现和训练策略上。
架构设计的现实约束
InternLM 的架构不是拍脑袋决定的,每一个选择背后都是现实约束。
最直接的就是算力限制。OpenAI 有足够的 GPU 集群可以堆规模,但国内团队的算力资源相对紧张,所以从一开始就得考虑效率。
InternLM 选择了标准的 Transformer decoder-only 架构,但在具体实现上做了不少优化:
- 使用 SwiGLU 替代 ReLU,激活函数更平滑,训练更稳定
- 用 RoPE(旋转位置编码)替代绝对位置编码,可以更好地处理长序列
- FFN 隐藏层维度是 4/3 倍的模型维度(不是标准的 4 倍),为了节省显存
- 词表大小是 92544,比 LLaMA 的大一些,但比某些千亿模型的词表要小,这个大小是在多语言能力和词表规模之间找的平衡
这些选择的共同点是:不追求绝对最优,而是在资源有限的前提下找到一个相对合理的局部最优。
以 FFN 隐藏层维度为例。标准 Transformer 用 4 倍模型维度,理论上表达能力最强,但显存和计算量都会上来。InternLM 团队发现 4/3 倍在大部分场景下表现差不太多,但能省不少资源,就这么定了。
这种"差不多就行"的取舍,在国内大模型项目里很常见。
数据处理的硬骨头
数据这块,InternLM 踩的坑比我想象的多。
数据源不能只看公开数据集,质量不够。团队自己爬了大量的中文网页,也整合了维基百科、代码仓库、学术论文这些来源。
但爬来的数据很脏,得清洗。
清洗的步骤大致是这样:
- 去重:用 MinHash + LSH 做近似去重,降低相似文档的影响
- 语言过滤:用 fastText 做语言识别,把非中英文的语料去掉(中英文是主要目标)
- 质量过滤:训练一个分类器,识别低质量文本,比如重复片段、乱码、广告
- 去隐私:识别并删除姓名、电话、身份证号等敏感信息
- 长度过滤:过短和过长的文本都不适合训练,要切一个合理的范围
每一步都有坑。
比如语言过滤,fastText 在短文本上表现不好,容易把中文误判为其他语言。团队后来加了一个后处理规则:如果文本中汉字占比超过 50%,强制归类为中文。
数据量的控制也是个头疼事。训练 InternLM 的语料大概用了 1.6T tokens,其中包括 2.2TB 的中文语料、0.5TB 的英文语料、0.3TB 的代码语料。
这个量级不是随便定的,是根据算力和训练效果平衡出来的。算力更多,肯定能训到更多数据,但边际收益会递减。
这张图想说明的是:数据清洗要过多个环节,每个环节有专门的工具和方法,串起来才成。
训练策略的实际考量
训练 InternLM 的策略,大概可以分成三个阶段:
- 预训练:在大量无标注语料上做语言建模
- SFT(监督微调):用高质量指令数据微调
- RLHF(人类反馈强化学习):用人类偏好调整模型行为
预训练阶段是最耗资源的,也是坑最多的地方。
训练用的配置大致是:
- 模型规模:7B 和 20B 两个版本
- 训练步数:7B 版本训了 1.8T tokens,20B 版本训了 1.6T tokens
- batch size:动态调整,根据显存情况和训练稳定性来定
- 学习率:用 cosine decay 衰减,预热阶段用线性 warmup
- 优化器:AdamW,β1=0.9,β2=0.95
一个关键的坑点是训练稳定性。
大模型训练很容易出现 loss 爆炸或者梯度消失,尤其是在早期阶段。InternLM 团队试过很多方法来提高稳定性:
- 梯度裁剪:限制梯度范数,防止数值不稳定
- 学习率预热:前几步用较小的学习率,慢慢调上去
- 混合精度训练:用 FP16 计算梯度,FP32 更新参数
- 权重衰减:L2 正则化,防止过拟合
这些方法组合起来,基本能保证训练的稳定性,但成本也不少。
另一个坑点是显存优化。
20B 模型的参数量很大,如果用标准的并行策略,单卡显存根本放不下。InternLM 用了多种技术来压缩显存占用:
- 张量并行:把模型参数在多卡间切分,每卡只存一部分
- 流水线并行:把模型层拆到多张卡上,形成流水线
- 梯度检查点:只保存部分激活值,其余的重新计算
- ZeRO 优化:把优化器状态、梯度、参数都分散存储
这些技术不是什么新东西,难的是组合在一起还能保持性能。InternLM 团队花了不少时间调参数,找到一种相对平衡的配置。
这张图展示的是多种并行和优化技术的组合使用,目标是把显存占用压下来,同时保持合理的训练速度。
SFT 阶段的工程问题
预训练完成后,模型有了语言理解能力,但不会听从指令,需要 SFT 阶段来微调。
InternLM 的 SFT 数据主要来自几个渠道:
- 公开指令数据集:比如 Alpaca、FLAN、CoT 这些
- 自建指令数据:团队标注的中文指令
- 代码数据:从 GitHub 上筛选的高质量代码
- 多轮对话:模拟真实对话场景的数据
但这些数据质量参差不齐,不能直接用。
团队做了一轮质量筛选,主要是:
- 去掉重复或过于相似的样本
- 检查指令和回答的逻辑一致性
- 去掉明显错误的样本
- 平衡不同类别和难度的样本
SFT 的训练配置跟预训练不太一样:
- 学习率更小:2e-5 左右,防止破坏预训练的知识
- batch size 更小:算力有限,只能用较小 batch
- 训练轮数:通常 1-2 个 epoch,多了容易过拟合
- 数据混洗:每个 epoch 都混洗数据顺序,防止模型记住特定顺序
这里有个坑点是过拟合。
SFT 数据相对较少,如果训练轮数太多,模型容易记死样本,泛化能力会下降。InternLM 团队发现 1 个 epoch 差不多就够了,再往上边际收益递减。
另一个问题是指令遵循能力。
模型要理解指令的意图,不能只是续写文本。团队在 SFT 数据里加入了大量的指令格式,比如"请解释…““列举…““比较…“这些明确的指令格式,让模型学会这种模式。
RLHF 的现实限制
RLHF 是提高模型行为质量的关键步骤,但也是工程复杂度最高的。
标准的 RLHF 流程是:
- 训练奖励模型:用人类标注的数据训练一个 RM,判断回答质量
- 用 PPO 算法:用 RM 提供的奖励信号微调模型
但这个流程在实践中有不少问题。
数据标注成本是第一道坎。人类标注回答质量很慢,而且标注者之间的差异很大。InternLM 团队试过外包标注,但质量很难控制,最后还是主要靠自己团队标注。
PPO 训练稳定性也折腾人。PPO 算法本身就不太稳定,尤其是大模型场景下,很容易出现策略崩溃的问题。团队用了很多技巧来稳定训练:
- KL 散度惩罚:防止策略偏离原始模型太远
- 优势函数裁剪:限制更新步长
- 价值函数裁剪:限制价值估计的范围
- 批归一化:稳定数值计算
即便这样,训练还是经常出问题,得频繁调整参数。
另一个现实问题是算力。RLHF 需要同时跑三个模型(原始模型、奖励模型、策略模型),对算力要求很高。InternLM 团队用的是 20B 模型,资源紧张,只能在较小的 batch size 和较少的训练步数之间找平衡。
最终的效果是:RLHF 确实能提高模型的回答质量,但边际收益不如 SFT 阶段那么明显。如果算力有限,可能优先保证预训练和 SFT 的质量,而不是把资源砸在 RLHF 上。
实践中的判断与取舍
整个过程走下来,技术细节当然重要,但更有意思的是那些需要做判断和取舍的地方。
比如词表大小。92544 这个数字不是标准值,是团队在测试多个方案后选的一个局部最优值。太小,压缩效率不够;太大,词表矩阵占显存太多。这个数字是在多语言能力、压缩效率和显存占用之间找到的一个平衡点。
再比如模型规模。7B 和 20B 两个版本,不是随意选的。7B 版本适合在消费级 GPU 上部署,20B 版本效果更好但需要更多资源。团队很清楚目标场景是什么,所以定了这两个规格。
训练步数的选择也类似。1.6T tokens 这个量级,是算力和效果折中出来的数字。算力更充足可以训更多;算力紧张,就得接受效果差一点。
这些判断没有标准答案,只能根据具体情况来定。不同的团队、不同的资源约束,会做出不同的选择。
踩过的坑
几个印象深刻的坑:
训练崩溃。预训练早期,loss 经常突然爆炸,排查了很久才发现是某个数据批次里有极端异常值。后来加了一层数据过滤,把明显异常的样本删掉,问题才解决。
显存溢出。20B 模型在训练时显存一直很紧张,加一层并行策略就多一点开销,很容易溢出。团队花了很多时间调并行策略和参数,找到一个相对稳定的配置。
梯度消失。某些层在训练过程中梯度越来越小,参数几乎不更新。试过改网络结构、改激活函数、调整初始化策略,最后通过更激进的权重衰减和更保守的学习率策略缓解了问题。
过拟合。SFT 阶段很容易过拟合,模型记住特定样本而不是学习模式。团队通过限制训练轮数、增加数据多样性、加入一些正则化来缓解,但还是很难完全避免。
这些坑没有银弹,只能具体问题具体分析。每个坑都可能花几天甚至几周时间去排查和解决。
结果和边界
折腾了一年多,InternLM 最终的效果怎么样?
在标准评测上,InternLM 7B 在中文场景下表现不错,跟 LLaMA 7B 竞品相当,在中文任务上更有优势。20B 版本在一些推理任务上表现更好,但部署成本也更高。
但评测分数只是一部分,真正的检验是在实际使用中。微软那边用 InternLM 做了一些内部工具,反馈是中文理解和生成能力确实不错,但在复杂推理和长文本处理上还有提升空间。
这个结果并不意外,毕竟训练资源有限,不可能做到样样精通。InternLM 团队很清楚自己的定位:优先保证中文能力,英文和代码能力够用就行。
写在后面
回头看整个项目,模型本身当然重要,但过程里那些判断和取舍更值得记。
每个技术选型背后都有现实约束,每个工程优化都要付代价。没有绝对最优,只有特定条件下相对合理的选择。
大模型这个领域变化很快,今天的选择明天可能就被推翻。但思考问题的方法不会变:先搞清楚约束条件,再找一个合理的平衡点。
“洋为中用"这四个字,在 AI 时代有了新注脚——理解原理,结合自己的算力、数据和工程条件,走一条能落地的路。InternLM 的实践,大概就是这么一个例子。
版权声明: 本文首发于 指尖魔法屋-AI书生大模型:这次怎么落地的(https://blog.thinkmoon.cn/post/412-ai-internlm-internal-external-training-practice/) 转载或引用必须申明原指尖魔法屋来源及源地址!
评论
使用 GitHub 账号登录后即可留言,支持 Markdown。