为什么会有那么多大模型答错「9.9 和 9.11 哪个大」?

发布时间:
2024-07-18 12:36
阅读量:
27

省流:不是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的原因,那可能是模型更底层的问题,如位置编码等。(我相信既然这么多模型都有类似的问题,应该不是单纯的训练数据缺陷)

END