写《从零训练一个大语言模型》写到第五篇,后台私信里出现频率最高的不再是具体的训练报错,而是一个更“大”的问题:明明训练目标只是让模型预测下一个字,它凭什么能翻译、写代码、做逻辑推理?这个问题问得多了,我越觉得应该专门写一篇把它讲透。
这个系列的读者里,有刚入门的学生,也有做AI应用开发的工程师。大家起点不同,但通常会在某个深夜盯着loss曲线发呆:数字确实在往下掉,可模型真的“变聪明”了吗?这篇文章不打算堆公式,只想讲清楚三件事:为什么偏偏是“预测下一个字”孕育了智能,训练过程中模型内部大致发生了什么,以及这种智能的边界到底在哪里。如果你也在从零训练大语言模型,这篇读起来应该比纯论文推导舒服得多。
1. “预测下一个字”的本质不是语文题,而是信息压缩题
1.1 一个被低估的目标函数:交叉熵到底在算什么
先回到训练的最基本动作。所谓“预测下一个字”,在工程上对应的是“下一个token预测”,配合交叉熵损失。训练时,模型读取一段文本的前面部分,对“下一个token”输出一个覆盖整个词表的概率分布;正确的token概率越高,损失越低。这个动作看起来人畜无害,但它的数学含义非常深:它等价于你在用模型把一段文本编码成尽量短的比特序列。
香农信息论告诉我们,一个事件携带的信息量等于它出现概率的负对数。一个不容易猜到的词,一旦被猜中,说明模型对上下文的解释力很强;一个经常出现却总也猜不对的词,则说明模型还有信息没吸收。所以模型训练的整个过程,其实是在做“压缩”:把海量文本里的规律,一点点转移进模型参数里。参数是压缩后的字典,前向传播是解压过程。这个角度看过去,大语言模型和zip压缩本质是同一类数学问题。
1.2 想猜中“下一个字”,你必须先“理解世界”
我经常用一个例子来跟人解释这件事。给你一句话:“她推开门,一阵风吹过来,桌上的纸突然____。”要让模型合理地填出“飞”或“飘起来”,它至少得知道:风能对轻物体施加力,纸是轻的,桌面不是一个封闭盒子。这些知识并非被显式写进代码,而是从海量文本中统计出来的。再比如“他体温三十九度,医生建议先____”,合理的续写依赖医疗常识;“铁块在太阳下晒一天会变得更____”,涉及基础物理直觉。模型对每个位置都做预测,就相当于被一个极其严苛的老师按着头要求:如果你不想一直得低分,就必须把文本背后的物理规律、因果链条、空间关系、社会惯例,全部内化到参数里。
这里有一个需要澄清的误区:模型并不是像人一样真有一个世界模拟器,而是为了降低预测误差,被迫寻找一个“统计意义上够用”的内部表征。当这个表征越能预测语料,它就越像一个可用的世界模型。“世界模型”不是说它脑子里真的在渲染画面,而是说在行为上,它能正确预判大部分事件的结果。
1.3 为什么“随便猜一个高频词”不行
有人可能会说:那我干脆每次都猜“的”“是”“了”这类高频词,是不是也能拿低损失?答案是不行。语言里信息量最大的部分往往集中在低频、强上下文相关的词上。高频功能词占比很大,但每个词携带的熵极少;“线粒体”“司法解释”“量子纠缠”这类词出现频率低,可一旦出现,对预测的约束力就极强。交叉熵是对所有位置预测质量的综合打分,你猜对一百个“的”,也弥补不了猜错一个“线粒体”。这也在相当程度上解释了为什么数据规模和数据多样性如此重要:一个只会复读高频词的模型,在信息论上毫无价值。
1.4 为什么不需要人工标注也能学:自监督的妙处
“预测下一个字”还有一个经常被低估的好处:它不需要人工标注。传统机器学习要花大力气标数据,而自然语言本身就自带标签——任何一个“上文”都是下一个词的提示,任何一个词都可以成为前文的答案。训练用的语料有多大,“免费标签”就有多少。这个特性让语言模型可以从互联网级别的文本里吸收知识,这是它最后能变得“聪明”的规模前提。一个需要人工标注的任务,规模撑死到百万级;自监督任务,规模可以轻松到千亿token级。所谓智能,很多时候就藏在规模门槛的另一边。
2. 训练路线图:一个 token 一个 token 地逼出“世界模型”
2.1 从随机噪声到能说话的模型:训练阶段长什么样
我手头跑过的小规模复现(参数规模在千万到十亿之间),让我对“智能如何长出来”有了很具体的体感。说实话,“智能时刻”不会像烟花一样在某一个迭代突然炸开,它更像一层一层地长出来。为了讲清楚,我把它拆成四个阶段:
| 阶段 | 损失曲线形态 | 生成效果 |
|---|---|---|
| 词频复读期 | 快速下降 | 只会复读“的”“是”“了”,句子断裂 |
| 语法习得期 | 下降放缓 | 能生成通顺短句,但内容空洞、经常跑题 |
| 话题稳定期 | 缓慢下降 | 能在同一话题内保持连贯,常识错误减少 |
| 规则沉淀期 | 逼近数据熵下界 | 对没见过的新组合也能给出合理延续 |
这张表也对应了一个训练规律:前期损失下降靠的是背下高频搭配,后期损失下降主要靠抽象规则。这也是为什么数据质量在后期比数据数量更重要的原因。看loss曲线时别只盯着数值,要看生成样本的结构复杂度。
2.2 数据分布是隐藏的课程表:语料顺序的现实影响
从零训练一个模型的人,经常把注意力全放在模型结构和学习率上,对数据分布配比不够敏感。我自己踩过坑:把高质量长文全部堆在前面,早期模型会显得很“木讷”;把大量低质量网络文本混进早期语料,模型又会花更长的步数才能把基础语言能力打牢。比较稳的做法是把数据排成一个从通用到专业的顺序:通用网页和书籍垫底,代码和专业语料按比例混入,指令数据放到最后的收尾阶段。这样安排的逻辑很简单——先学语言本身,再学事实,最后学交互格式。课程学习听上去很高级,但小规模训练里简单的分层排序已经够用,复杂策略的收益并不明显,调试成本反而更高。
另外,去重这件事别偷懒。我在一次小规模实验里只是对语料做了模糊去重,最后阶段的验证损失就降了一截,生成里的重复套话也明显减少。数据工程做得如何,直接决定后面能走多远,这在前几篇里反复强调过,这里旧事重提,是因为它和“理解”的形成关系实在太密切。
2.3 教师强迫和自回归生成:两个模式的关键差异
一个容易被新手忽略的细节:训练时和推理时,模型的工作方式完全不同。训练用的是teacher forcing,把整段真实文本一次性喂进去,在每个位置都做预测;不管模型在这个位置猜得对不对,下一个位置看到的仍然是真实文本。推理时则变成自回归,模型自己预测出的token,作为下一次预测的输入。也就是说,训练时它一直在“看标准答案上下文”,推理时却要面对“自己瞎编的上下文”。误差会随着生成逐步累积,这也就是生成文本越写越离谱的原因之一。理解了这一点,你就会明白为什么第四章里的解码策略那么重要,也能理解“让模型看着自己的输出训练”这类技巧为什么会有效。
3. 它是在“记忆”还是在“理解”:两个实验能看出分水岭
3.1 实验一:把训练集里的段落改一个词,看模型怎么反应
我评估模型时常用一个便宜但有效的测试:取一段训练数据里确实出现过的文本,把其中一个关键名词换成同类的另一个词,然后让模型续写。如果模型真的背诵了这段文字,续写时它会自动把原来的名词补回来,驴唇不对马嘴;如果模型学到的是更抽象的概念,它会顺着新词给出一个语义上还讲得通的新续写。
这个现象在小参数量模型上极其明显,几乎等于复读机。参数量上去之后,即使loss差不多,模型“修补”能力也会显著增强,更倾向于理解式重建。当然,这里没有一条绝对的分界线,本质上“记忆”和“理解”在这类系统里是混在一起的。但如果你只能选一个指标,这个测试可能是最便宜的判断方式。
注意:做这种测试时,要确保改写后的句子在语法上完全通顺。如果新词和原词在语法位置上不一致,模型续写跑偏,就不能算作测试结果的有效证据。
3.2 实验二:问一个反事实问题,看模型会不会“顺着规则走”
比改词更苛刻的是反事实测试。比如把“猫喜欢吃鱼”改成“猫喜欢吃石头”,再追问“如果猫真的改吃石头,它们在生态系统里的角色会怎样变?”纯靠统计搭配的模型会当场懵掉,因为训练数据里根本没出现过这种组合;具备一定规则抽象能力的模型则会尝试在“食性变化影响生态位”的框架下推导。
实测下来,小模型经常把反事实条件当成普通事实来复述,稍大一点的模型能部分利用条件约束,看似在推理,但往往在第二个转折点上泄气。这说明所谓“理解”在模型里是分层出现的:简单规则容易沉淀,复杂因果链非常不稳定。这也是为什么学术界对“模型究竟理不理解”争论不休的原因——它确实在不同层次上都展现出了理解的影子。
3.3 记忆与理解之间,其实是一片连续谱
我们习惯把“记忆”和“理解”当成两种截然不同的能力,但在神经网络里,它们更像同一个压缩过程的两个端点。模型会优先尝试直接存储;当存储空间不足,或者数据本身存在很强的规律时,它才会被“逼”出抽象规则。参数规模增大,不等于说它背诵的东西更多,而是它能容纳更多规则性的描述,因此对没见过的新输入也能做出合理反应。把模型训练到接近数据熵下界时,它几乎是在用一套抽象模式去复现数据,而不是逐字背诵。我在从零训练时最深的体会就是:不要只盯着loss值,定期做这类对比测试,比什么都可靠。
3.4 小心评估集污染:别把“见过”误判成“理解”
做这类实验最容易犯的错,是评估集和训练集存在重叠。如果你设计的补全测试,其中的句式或关键词在你训练语料里频繁出现,那么模型给出的漂亮回答,很可能只是“见过”而非“理解”。我自己的做法是专门留一部分样本,训练过程中绝对不看、不用,甚至刻意构造训练语料里没有的句式来测试。只有当你拿着这种“隔离评估集”去测,还观察到稳定的规律性反应,才说明规则真正沉淀进了参数。否则,你感受到的智能可能只是记忆的回声。
4. 采样温度与解码策略:把“预测概率”翻译成“智能表现”的最后一步
4.1 greedy解码为什么会让人觉得“呆”
训练完模型后,很多人直接拿贪婪解码去生成,结果发现输出死板、重复、像复读机,就怀疑训练出了问题。实际上,greedy解码每一步都选概率最高的token,表面看是最优选择,实际却很容易让整个句子滑向平庸甚至循环的套路。打个比方:一个人永远只做最有把握的事,短期内无风险,但长期会把自己的路越走越窄。语言生成也是如此,局部最高概率的选择,往往会把后面带进一个低质量的沟里。
大模型推理时,真正该做的是“从合理分布中采样”,而不是“挑最大概率”。这个认知对从零训练的人尤其重要,因为你还没有做偏好对齐,直接greedy出来的观感通常会非常差,而这不代表模型没训练好。
4.2 temperature、top-k、top-p到底在改什么
temperature这个参数,数学上就是先把logits除以一个温度值,然后再做softmax。温度越低,概率分布越尖锐,输出越保守;温度越高,分布越平,低概率词被选中的机会越大。top-k是保留概率最高的k个词作为候选,top-p是保留累计概率达到阈值p的最小候选集合。两者都是截断策略,目的是把尾部那些又低又离谱的词挡在门外。
实操区间我整理成了一张表:
| 参数 | 作用 | 常用区间 | 备注 |
|---|---|---|---|
| temperature | 缩放logits | 0.2-1.1 | 低=保守,高=发散 |
| top-k | 候选数量截断 | 50-100 | 过小容易呆板 |
| top-p | 累计概率截断 | 0.9-0.99 | 过小会丢失多样性 |
| repetition penalty | 重复惩罚 | 1.0-1.2 | 过大会导致输出破碎 |
具体场景上,代码生成我一般用temperature 0.2-0.4、top-p 0.9;通用对话用temperature 0.7-0.9、top-p 0.95;创意写作才敢放到0.9-1.1。这几个参数是组合生效的,先改温度,再截断,最后采样。我见过不少新手只调temperature不调top-p,结果生成质量飘忽不定。建议固定一组基准确认,再各自微调。
提示:temperature不是越高越好。超过1.2之后,大多数场景下模型只是在随机组织词句,并不会变得更“有创意”。
4.3 同一个checkpoint,两种解码策略,体验像两个模型
我做过一个很直观的对比:用同一个模型、同一个提示词,分别用greedy和temperature=0.9+top-p=0.95。我给过一句“夜晚的城市总是让人______”,greedy输出直接是“让人想起夜晚的城市总是让人想起夜晚的……”;换成temperature=0.9、top-p=0.95后,输出变成“夜晚的城市总是让人想起白天看不见的那层秩序,路灯、车流和玻璃幕墙里的灯光各怀心事”。后者明显更像“懂了一些什么”,尽管底层参数一模一样。
这个对比残酷地说明了一件事:我们感知到的“智能程度”,有很大一部分根本不在模型上,而在推理时怎么用模型。你训出一个底座模型,先别急着骂“不够聪明”,把解码参数来回扫一遍,往往能发现它比你想的能打很多。这也是我在这个系列里坚持给新手强调“先调解码器,再下结论”的原因。
5. “下一个字”路径的已知边界:能涌现什么,又缺什么
5.1 通过“预测下一个字”拿到手的能力清单
到目前为止,用“下一个token预测”训练出来的模型,已经被验证能做很多事:跨语言翻译、摘要、改写、代码补全、常识问答,以及部分推理痕迹。这些能力有一个共同特点,就是都有大量文本样本可供学习,并且都能被简化成“给定上文,预测下文”。翻译靠的是平行语料里两种语言的交替出现,代码补全靠的是仓库里海量的“上文-下文”结构。预测目标本身并不关心输入是数学题还是闲聊,它只关心统计一致性。而统计一致性恰好覆盖了数量惊人的智能行为。
5.2 还没有拿到手的东西:可靠推理、自我纠错、事实一致性
这条路也有清晰的天花板。“预测下一个字”只在文本表面工作,它不会直接惩罚“生成一句流畅但错误的话”,只要这句话在语言统计上说得通,损失就不会升高。幻觉问题有一半的根源就埋在这个目标函数里。同样,模型在推理时更倾向于“把话说顺”,而不是“把题做对”。你让它算一道数学题,它可能给出像模像样的推导步骤,但结果就是错的。可靠的推理要求模型在中间步骤里反复验证,这不是“预测下一个字”的直接优化目标。自我纠错也是一样,除非“发现错-修正”的文本模式大量存在于训练语料里,否则模型即使推理跑偏了,也完全意识不到。
5.3 目标函数不是终点,但它是一切后续工作的地基
正因为边界清晰,现在业界才会在预训练底座上加各种对齐技术,比如偏好优化、带验证的奖励函数、推理时计算。这些方法本质上都是在“预测下一个字”得到的底座上,加一层额外的挑选和修正机制。底座负责海量语言知识和模式的压缩,后续的对齐负责告诉它“在什么场景下更多输出哪种风格”。我的看法是:“预测下一个字”不是大模型的终点,但它是所有后续工作的地基。你把它理解透,再去看微调、对齐、推理优化里的各种反直觉现象,会清醒很多。这也是我愿意花一整个连载篇幅来写这个“简单问题”的原因。
最后说点个人体会。我训练这类小规模模型的那段时间,最深的感受是:所谓的“智能感”,不是某一个组件单独给的,而是数据质量、参数规模、解码策略三者相乘的结果。你单独调结构,收益有限;你把数据质量提上去,loss会有实质性的下降;你再把解码参数调对,生成体验立刻上一个大台阶。这个世界并不存在“因为目标简单所以做不出智能”的诅咒,真正稀缺的是你愿不愿意把“填词游戏”背后的压缩逻辑吃透。如果你也正在从零训练自己的模型,建议先别急着追更复杂的目标函数,把你手头这个“猜下一个字”的玩法练到极致,很多困惑会自己解开。