为什么会有那么多大模型答错「9.9 和 9.11 哪个大」?
省流:不是tokenizer的问题,也不是注意力错误,也不是语义建模错误。我不知道为什么,这简直是这几天最令我困惑的事情了。
最简单的回答是归咎于tokenizer,但这很可能是过度简化了问题。
对于其他答主提及的gpt4o等模型,其tokenizer可以从openai的网站或tiktoken获得,其将 11 分词为一个token并不能证明是直接导致该现象的原因。
我们可以很简单地找到反例。如llama系列,从第一代开始其tokenizer就将单个数字作为分词。baichuan等开源模型也采用了同样的策略。见之于其技术报告,你也可以很简单地如下代码验证。
但是我们注意到,哪怕是baichuan3,也会错误的回答这一问题。这个简单的消融实验表明tokenizer并非该问题的真正罪魁祸首。
第一个简单的怀疑是9.11作为一个特殊的日期可能导致模型存在bias,这干扰了模型的分析。因此我换成别的数字,如7.11和7.9,模型依然有错误输出。
事情开始变得有趣了起来。我首先用贪婪采样来避免随机性,这样模型的输出应该就代表模型学到的语言分布。
outputs = model.generate(tokens, max_length=100, do_sample=False, pad_token_id=tokenizer.eos_token_id, eos_token_id=tokenizer.eos_token_id)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
-----------------
['[INST] 9.11和9.9哪个大? [/INST] Both 9.11 and 9.9 are numbers, but they represent different quantities.\n\n9.11 is a decimal number that represents the number 9 and 11/10, or 9.11.\n\n9.9 is also a decimal number that represents the number 9 and 9/10, or ']
这下太有趣了,llama2-7b-chat-hf居然认为9.11中的小数为代表11/10。我尝试在此处截断输出,并修改为正确的内容(将11/10改为11/100)让模型继续自回归推理。我使用的代码和输出如下:
import re
prompt = ""
match = re.search(r'\[INST\].*?10',tokenizer.decode(outputs[0],skip_special_tokens=True), re.DOTALL)
if match:
prompt = match.group().replace("10","100")
output = model.generate(tokenizer.encode(prompt, return_tensors="pt"), max_length=200, do_sample=False, pad_token_id=tokenizer.eos_token_id, eos_token_id=tokenizer.eos_token_id)
tokenizer.batch_decode(output, skip_special_tokens=True)
---------------
['[INST] 9.11和9.9哪个大? [/INST] Both 9.11 and 9.9 are numbers, but they represent different quantities.\n\n9.11 is a decimal number that represents the number 9 and 11/100, or 0.0911 in decimal form.\n\n9.9, on the other hand, is also a decimal number that represents the number 9 and 9/100, or 0.099 in decimal form.\n\nSo, in summary, 9.11 is greater than 9.9.']
这下给我震惊了。我原先预期这只是简单的幻觉而已,但llama2-7b-chat-hf似乎真的不理解9.11的含义。考虑到语言模型的训练目标本质上是一个language modeling任务,我们现在似乎很有必要探究为什么在这个问题上语言建模很糟糕了。
发生这个现象,最简单的理由是模型attention到了奇怪的token上去,导致模型不能很好地区分数字11在小数点后。
我抽取了模型最后一层的注意力矩阵,关注模型在输出"represents the number 9 and 11/10"中的and后的空格时的注意力值。因为接下来,模型即将把9.11的.11误解为11/10。观察这里的注意力机制有助于我们理解llama2-7b-chat-hf在即将误解时,它在关注哪些词元。
Index Values
40 ▁but 0.001243
41 ▁they 0.001257
42 ▁represent 0.001447
43 ▁different 0.001335
44 ▁quantities 0.003305
45 . 0.001761
46 <0x0A> 0.002079
47 <0x0A> 0.001947
48 9 0.002113
49 . 0.008446
50 1 0.004066
51 1 0.003441
52 ▁is 0.002958
53 ▁a 0.003151
54 ▁decimal 0.010345
55 ▁number 0.003771
56 ▁that 0.003202
57 ▁represents 0.007748
58 ▁the 0.005733
59 ▁number 0.009140
60 ▁ 0.016815
61 9 0.027405
62 ▁and 0.062378
63 ▁ 0.050323
64 1 0.000000
65 1 0.000000
66 / 0.000000
67 1 0.000000
68 0 0.000000
69 , 0.000000
结果非常地amazing啊!我原先预计模型忽略了小数点的存在,因此才把.11误解为11/10。但事实于预计相反:模型在小数点上的注意力明显大于9和11,它其实是有注意到的!那么,到底是什么导致了模型误解呢?
已经排除了是错误的attention,现在我怀疑是语义建模错误。让我们试着可视化模型注意力,这将有助于我们找到答案。
我们可以观察到,除了截止部分的特殊token(<s>)以外,模型还在其他几个地方有特别高的注意力。第一个是"and",这不奇怪,因为我们接下来即将输出关于小数位的解释,这在上下文中有特别重要的语义。还有一个比较大的注意力是"decimal",这就是关键的语义token了。有没有可能是"decimal"的语义建模有问题呢?
我们不妨做一个实验。我将其中的"decimal"换成"fractional",然后再做一次前向传播。如果模型对这个近义词的注意力行为和"decimal"不一致,并自回归地输出了正确答案,那就说明是小数的语义建模有问题;如果不是,那就是更深入的原因。
Index Values
40 ▁but 0.001758
41 ▁they 0.002245
42 ▁represent 0.001986
43 ▁different 0.001574
44 ▁quantities 0.003105
45 . 0.001535
46 <0x0A> 0.001220
47 <0x0A> 0.001457
48 9 0.002367
49 . 0.003555
50 1 0.002571
51 1 0.002995
52 ▁is 0.003519
53 ▁a 0.004395
54 ▁fraction 0.020554
55 al 0.009804
56 ▁number 0.007782
57 ▁that 0.006435
58 ▁represents 0.010178
59 ▁the 0.008095
60 ▁number 0.014618
61 ▁ 0.019104
62 9 0.037598
63 ▁and 0.051178
64 ▁ 0.000000
65 1 0.000000
66 1 0.000000
67 / 0.000000
68 1 0.000000
69 0 0.000000
结果非常的amazing啊!在替换后,模型对这个fraction的注意力与decimal几乎差不太多。并且输出同样是错误的答案。
['[INST] 9.11和9.9哪个大? [/INST] Both 9.11 and 9.9 are numbers, but they represent different quantities.\n\n9.11 is a fractional number that represents the result of dividing 11 by 9. It is equal to 1.222222222.\n\n9.9 is also a fractional number that represents the result of dividing 9 by 9. It is equal to 1.000000000.\n\nSo, in summary, 9.11 is greater than 9.9.']
现在我们已经把显而易见的可能性排除掉了。研究进入了深水区。现在种种证据指向llama2-7b-chat-hf在该情况下无法正确建模小数,如果不是meta训练的bad case的原因,那可能是模型更底层的问题,如位置编码等。(我相信既然这么多模型都有类似的问题,应该不是单纯的训练数据缺陷)