LLM 无法准确运算数字的底层原因分析
在探讨大语言模型(LLM)迈向通用人工智能(AGI)的过程中,一个常被质疑的痛点是:为何看似智能的模型连简单的多位数加法都无法准确完成?这一现象并非偶然,而是由 LLM 的底层架构机制决定的。目前学界与业界已基本理清其主要原因,并提出了相应的解决方案。
一、Tokenizer 对数字的切分问题
早期的大语言模型 Tokenizer 通常采用字节对编码(BPE)或 WordPiece 等通用策略,不会对数字进行特殊处理。这导致连续的若干数字可能被切分成不同的 Token。例如,数字'13579'可能被切分为'13'、'57'、'9'三个 Token。这种切分方式取决于训练数据中的统计分布,具有不确定性。
在这种不确定的 Token 组合下,LLM 很难建立数字数值与 Token 序列之间的精确映射关系。要想做对多位数字的数值计算,模型必须理解每个 Token 代表的数值及其位置权重,这在非数字专用的 Tokenizer 中极难实现。
解决方案: 现代主流大模型已普遍采用针对数字优化的 Tokenizer 策略。自 2023 年初起,许多技术报告建议将每个数字单独切分为一个 Token。例如,'13579'应被切分为'1'、'3'、'5'、'7'、'9'。这使得模型能够更清晰地识别数位,是实现准确计算的基础必要条件。
二、数字序列输入顺序问题
通常我们让 LLM 做数学题时,习惯正向输入,即高位在前、低位在后(如'13579+24680')。然而,从 LLM 的运行机制来看,这种方式存在显著缺陷。
LLM 基于 Next Token Prediction(下一个词元预测)机制生成结果,即一次输出一个 Token。如果按照'13579+24680='的顺序输入,模型需要预测的结果最高位是 3。这意味着模型必须在内部先计算出完整的正确结果(38259),并将中间状态存储起来,然后才能输出第一个 Token'3'。这违背了 LLM'边说边想'的自回归特性,人为增加了学习难度。
相比之下,人类计算多位数加法时,也是先将两个数值串从低位到高位对齐,然后从右向左依次计算,处理进位。
解决方案: 正确的做法是将数字逆序输入,即低位在前、高位在后。例如将'13579+24680'转换为'97531+08642'。经过此改造,LLM 可以逐位生成结果,从最低位开始计算,若有进位则向下一位传递。这极大地降低了学习难度,将一个复杂的多步推理问题分解为连续的单位数加法问题。单位数加法的组合空间有限(仅 100 种组合),加上进位情况共 200 种可能性,模型更容易掌握。
三、数字对齐问题
即使采用逆序输入,整体效果虽有提升,但仍不够完美。研究发现,LLM 在进行数学运算时,经常无法正确对齐相应位置的数字。例如在'13579+24680'中,个位的 9 应对齐 0,但模型可能错误地对齐到 8 或其他数字上。
这种对齐失败主要归因于 Transformer 架构中的 Self-Attention 机制。标准的注意力机制并不天然具备列对齐能力,且位置编码(Position Embedding)在处理长序列时可能存在精度损失。
解决方案: 目前有两种有效的解决思路:
- 加入位置提示符(Hint Tokens): 在每个数字前加入特定的位置标记字符。例如将'13579+24680'转换为'a1b3c5d7e9+a2b4c6d8e0'。相同位置的数字拥有共同的提示字符,利用 Induction Head 机制帮助模型识别对应关系。
- 引入专用位置编码(Abacus Embedding): 对每个数字块单独引入新的位置编码。对于每个数字块,第一个字符引入位置编码 1,后续数字依次递增。这样,相同数位的数字拥有相同的位置编码,从而强制模型关注对应位置的关系。
四、长度外推能力弱
LLM 的长度外推能力较弱,表现为:若训练数据中见过的最长数字串长度为 10 位,模型能较好地完成 10 位数以内的加法;但若要求计算 20 位长度的数字,准确率会大幅下降。这是因为模型未见过类似长度的位置编码模式。
这一问题的根源在于 Transformer 中的位置编码设计。传统的绝对位置编码难以泛化到未见过的长度。
解决方案:
- FIRE (Functional Interpolation for Relative Position Embeddings): 这是一种相对位置编码方案,研究表明其在数值运算场景下的长度外推能力最强。即使不改变输入顺序,FIRE 也能提供较好的外推性能。
- Randomized Position Encodings(随机化位置编码): 在训练过程中配合使用此技巧可大幅增加外推能力。具体做法是:假设训练数据最大长度为 10,希望外推到 100 位。在训练时,数值块中第一个数字的 Abacus 位置索引不从 1 开始,而是在 [0, 100] 之间随机取值,后续数字在此基础上递增。同一个加法运算涉及的两个数需使用相同的起始编号。训练时随机抽取,实际使用时恢复从 1 开始的编号。这使得模型在训练阶段就'学会'了未见过的长位置编码,从而在实际应用中不怕遇到超长数字。


