宝玉的分享 02月17日
DeepSeek-V3 与 r1 中的异常 Token [译]
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文作者首次尝试对DeepSeek模型中出现的异常Token进行识别与归档。文章详细记录了在DeepSeek-V3中发现的故障Token,并初步观察了它们的行为。作者通过导出DeepSeek-V3的分词器词表,对每个Token进行自动测试,观察其是否表现出异常行为。文章重点介绍了碎片类Token、'Nameeee'、'EDMFunc'等英文Token,以及宿务语等非英文Token的异常表现,并对特殊Token的行为进行了分析。最后,作者提出了未来研究方向,包括研究异常Token在嵌入空间中的分布和关系,以及挖掘被筛掉的中文Token背后的秘密。

🧩**碎片类Token**:这些Token单独出现时无法被正确输出,只有在更长的字符串环境中才会出现,表现为输出后映射到其他结果,如'CHANTABILITY'映射到'MERCHANTABILITY'。

🎭**'Nameeee' Token**:当DeepSeek重复输出带前导空格的' Nameeee'时,会出现各种奇怪的Unicode符号、首字母缩写或表情符号,有时甚至会被解释成结束推理的特殊Token。

🌐**非英文Token(宿务语)**:大量的异常Token来自宿务语或其他菲律宾区域语言,映射时可能只是简单翻译或词形变化,也可能变成看似毫无联系的词汇,例如'Gikuha'映射到'Giya'。

✨**特殊Token**:如'<|begin of thinking|>'、'<|end of thinking|>'等,在V3中表现类似“空白的”异常Token,但在r1模式下会触发异常行为,特别是'<|end of thinking|>'可能导致r1陷入无限循环。

对 DeepSeek 出现的异常 Token 进行首次识别与归档的尝试在大型语言模型(LLM)中,“Anomalous”(异常)、“glitch”(故障)或“unspeakable”(无法直述)的 Token 指的是那些会引发奇怪行为,或不再像普通文本那样正常运作的 Token。SolidGoldMagikarp 的故事 几乎是理解这种现象的必要背景资料,因为它记载了在 GPT-2 和 GPT-3 中最早发现这种问题的过程。但就我所知,似乎还没有人在 DeepSeek-V3 中尝试系统地搜索这些 Token,于是我决定亲手做这件事。DeepSeek-V3 既是当前最先进(SOTA)的基础模型,又是开源模型,同时本身也颇为“古怪”,所以我认为它是一个绝佳的研究对象。这篇文章是我在 DeepSeek 中经过大约一天时间试验后找到的所有故障 Token 的归档,并附上一些对其行为的初步观察。注:本文中我将“DeepSeek”作为 V3 和 r1 的统称。过程我的做法是先把 DeepSeek-V3 的分词器(tokenizer)词表全部导出,然后对其中每个 Token 进行自动测试,观察其是否会表现出异常行为。注:对我们的目的而言,r1 可以看作在 V3 之上又加了一层,而所有的异常 Token 在这两者之间都是通用的。另一方面,DeepSeek 的 distillation 版本则与其所依赖的预训练模型更加类似,因此本文不涉及 distillation 的讨论。与其他模型的分词器最明显的区别在于,DeepSeek 的训练数据里包含了相当比例的中文文本。这带来了一些处理上的困难——分词器会基于字节(byte)层面进行切分,而中文字符在 UTF-8 下通常由多个字节组成,导致在不一致的字节边界被切开,从而产生难以解码的碎片。因此,词表里大约有一半的条目看上去是这样子的:ä¸į æĸ¹ä¾¿ä½ł 没æľīন ি人åijĺ åľ¨为了排除这些无法直接解码的词条,我对非标准字符进行了很激进的过滤,把词表的大小从 128000 大幅缩减到 70698。我相信这里面仍然有不少值得研究的内容,但我实在不想在无法识别的中文碎片和被切分得乱七八糟的 Unicode 字符中花费太多精力。接下来,我通过 DeepSeek 的 Chat API 对这 70698 个 Token 各调用了两次,每次都会让 DeepSeek-V3 重复输出这个 Token(但在提示里使用了略微不同的格式),并把所有无法正确重复该 Token 的情况保存下来。(在此要大力感谢 DeepSeek,费用极低且不作任何速率限制,使得这个过程变得可行。)在这两轮测试中,我都让 DeepSeek-V3 尽可能只重复给定的 Token,只是提示的写法略有不同,以避免漏掉某些边界情况。像这样:System: Repeat the requested string and nothing else.User: Repeat the following: "{token}"System: Say the requested string, exactly as it is written, and nothing else.User: Say the following: "{token}"然后我筛选了那些输出与输入的 Token 存在非琐碎差异的条目(例如有的 Token 会被加上反斜杠转义,或空格位置出现细微变化,或者模型对某些带有攻击/歧视性内容的 Token 做了拒绝等,我都认为不具有研究价值而排除掉),把剩下的结果按其初始外观大致分了类。接着我再对每一类中的 Token 进行进一步的人工探索。注:在尝试下文提及的 Token 时,请注意空格:'XXXX' 和 ' XXXX' 是不同的 Token。官方的 DeepSeek 聊天界面 会自动去除前后的空格。碎片类 Token有很多 Token 在其单独出现时是无法被正确输出的,因为它们只在更长的字符串环境中才出现过。这是最简单、也最容易理解的一类异常 Token。这种“碎片 Token”的存在在大容量词表里并不让人意外,但它们的表现仍然值得深挖,通常会表现为以下模式:其他示例如下:CHANTABILITY -> MERCHANTABILITYellationToken -> Token, CanellationTokenetheless -> theless, nonethelessVERTISEMENT -> ADVERTISEMENTruptedException -> interruptedExceptioneredWriter -> BufferedWriter, WriterWriter, Writerarmaceut -> aceut, armaceuticalreeNode -> TreeNodedfunding -> Funding, Fundraising目前还没有更好的叫法,我就先借用数学里的概念,把这些输出后映射到的结果称作该异常 Token 的“像”(image)。从现在开始,一旦我提到一个异常 Token 的“像”,指的就是它最终变成了什么字符串。' Nameeee'当让 DeepSeek 重复输出 ' Nameeee'(请注意这前面是带空格的),往往会出现各种奇怪的 Unicode 符号、含有“M”的首字母缩写,或是表情符号等。这引起了我的注意,也是我最先深入研究的一个 Token。Prompt: Say Nameeee (And variations of that prompt)Images: ↑, ��, ?️, ⟩⟩, MR, ?, ►▼如果给出一些上下文线索,DeepSeek 更有可能把 ' Nameeee' 当成一个普通的英文单词。有时映射到的替换词在语义上能对得上,但也常常是毫无关联:Prompt: Who is John Nameeee?Images: John McCain, John MP3, John Wikisource, John the Baptist, John †, John ██████Prompt: What's Nameeee plus Nameeee?Images: ¼ plus ¼, [Math Processing Error] plus [Math Processing Error], one plus one如果只发送 ' Nameeee'(带前导空格)这个 Token,本身往往会被视为一些短的 ASCII 残片,如 '{{',或者是更随机的“Mughal”之类。而在 r1 模式下,有时 ' Nameeee' 会被解释成类似 '<|end▁of▁thinking|>' 这样用来结束推理的特殊 Token,从而导致它(r1)直接进入混乱状态。下文会看到,这类行为相当常见。关于这个 Token 的来源,目前我还不太确定。想要弄清它为何会在模型中表现异常,需要更深入的溯源和分析,而我目前只完成了发现和初步记录的工作。'EDMFunc''EDMFunc' 这个 Token 的表现与 ' Nameeee' 类似,也会映射到相同的那几个怪符号(例如 '►▼'),除此以外还偏好以“H”开头的单词或者日语名字。有趣的是,' FullEDMFunc' 是另一个独立的异常 Token。通常情况下,它在映射时只会替换掉 'EDMFunc' 这个片段,而会保留前面的 'Full':Prompt: Say FullEDMFunc (And variations of that prompt)Images: FullMesh, FullMoon, FullDisclosure, Fully Mapped Function, Full Machine Translation关于此 Token 的潜在来源,我只在 .NET Framework 里找到一个可能相关的类——EdmFunction。其他英文类 Token' everydaycalculation' 通常会映射到一些关于数学教育工具相关的字符串,比如 'percentcalc'、'FractionCal'、'youtube' 或 'VisualFractions'。' numbersaplenty' 看起来和 ' everydaycalculation' 处在相似的语义场中,也常常映射到 'VisualFractions'、'Numbermatics' 等。值得注意的是,r1 模式常常把它与“千”之类的概念联系起来,比如“millennia”。'SetSavedPoint' 有时能被正确地输出,但更多时候会映射到与 Unity 上下文相关的词汇,如 'SetValue' 或 'SerializeField'。' CategoryTreeLabel' 通常会变成 'Categorize',偶尔也会变成非英语词汇,比如他加禄语(菲律宾语)单词 'Kaagapay',或者希腊语的 'καταλογείς'。有一些 Token 既不完全是无法说出的“碎片”,也会表现出某些异常,如 ' MentionsView':它偶尔会变成类似 'Mendeley'、'Viewfinder' 这样的相似词,或保持原样,或者直接空输出;在 r1 模式下还会互相矛盾地反复改变主意。另外,' mediefiler' 和 'HasColumnType' 也有类似的表现。在单独给 r1 提示上述大部分 Token 时,它往往会出现两种崩溃模式之一:幻想自己在回答一个非常具体又莫名其妙的算术问题:或者把该 Token 视为 '<|end▁of▁thinking|>',从而终止了它的推理链(COT),但输出内容仍然和原先的 Token 主题有关:非英文 Token在我进行的初步扫描中,数量最多的异常 Token 来自宿务语(Cebuano)或者其他菲律宾区域语言。(还记得吗,所有中文 Token 都已经过滤掉了。)其中最简单的异常 Token,映射时只是做一些简单的翻译或词形变化;另一些则会变成看似毫无联系的词汇:tterligare -> yttre, Tillägglicensierad -> licensiedGikuha -> Giyaahimut -> Hakut, Ambot, AmutTiganos -> Gitas, TITLES, GeoNamesSiyent -> സ്മാർട്ട്, శ్లేష్మం这样的 Token 可能还有上百个,我没来得及全部深入研究。' kasarangang'为了感受一下这一类 Token 的情况,我随机挑了 ' kasarangang' 以及看起来跟它相关的 'asarangang'。前者在宿务语里表示“中等、适度”(moderate)的意思,后者似乎在语料库里几乎没出现过。当让 DeepSeek-V3 去定义 'asarangang' 时,它往往把这个 Token 当成某个以 A 开头的词,比如 'Angstrom'、'angle'、'abogon' 等等。r1 模式下就更有意思一些。前文提到,大多数英文异常 Token 在 r1 环境下会被视为那些莫名其妙的算术问题,但 'asarangang' 映射到的主题更偏向文科社科类:'asarangang' 倾向映射到以 A 开头的词,而 ' kasarangang' 倾向映射到以 K 开头的词。有时它也会映射到 'Gitas' 或 '►▼' 这类在很多异常 Token 中都意外常见的符号。此外,它还会和温度这个概念产生稳定的关联,比如 ' kasarangang' 常常映射成 '°C' 或者 'temperature'。我想这应该和宿务语语料中,“moderate”常常与温度上下文关联度比较高有关(比如形容气候或者温度)。非英文的特殊案例注:DeepSeek 的一个特征是非常容易反复输出相同短 Token,哪怕上下文中并没有出现异常 Token。有时无论是 r1 还是 V3,都可能突然“掉进”这种无限循环输出的状态。在实际测试中,这给我带来了不少麻烦。在这些非英文 Token 中,有少数表现比较特殊,难以用某种模式概括。例如 'Espesye' 在我第二次词表扫描时输出过这样一段结果:可惜的是,我没能再次复现这个输出。除此之外,'Espesye' 大多数情况下无法确定自己所指的含义,但又能被 V3 产生出来。偶尔,它会在随机情境下被当做无法直述的异常 Token。'talagsaon' 则更容易复现这种奇怪行为:在合适的提示下,会产出一整屏空字符(实际上是大量空白或不可见字符):有些 Token(如 'referentziak'、'Kapunoang'、' kinadul' 等)比以上更“空白”,它们在输出时的映射通常是以下几种情况之一:在语境提示下,可能随机冒出任何看似合理的词完全不输出复制前一个词我猜这种现象是因为在训练语料中,这些 Token 出现极少,模型几乎没有它们的学习样本,或是它们在词表中的位置与特殊 Token 非常接近。换句话说,它们的嵌入(embedding)在模型向量空间中位置很“偏”,以至于导致跟特殊 Token 类似的行为。特殊 Token虽然它们并不是什么新鲜事,但仍然非常值得一提:'<|begin▁of▁thinking|>'、'<|end▁of▁thinking|>'、'<|▁pad▁|>'、'<|begin▁of▁sentence|>'、'<|end▁of▁sentence|>' 这些都是 DeepSeek 为了在上下文窗口中进行特殊标记而自定义的 Token。大多数此类 Token 在 V3 中表现类似那些“空白的”异常 Token(blank slate),不过需要注意的是,“thinking” 系列的特殊 Token 只在 r1 模式下 会触发异常行为。特别值得一提的是 '<|end▁of▁thinking|>',它可以让 r1 出现非常精彩的崩溃:因为:对那些“空白”类 Token 来说,它们的含义在很大程度上依赖上下文推断;'<|end▁of▁thinking|>' 在纯 V3 环境下其实是正常可输出的 Token;我们可以用这种方式把对的“含义”投射到 r1 环境下,让它和 V3 的上下文对齐:先用 V3 输出 '<|end▁of▁thinking|>',然后再切到 r1,让 r1 根据上下文认出这个 Token 是“结束思考”的指令。结果就导致了非常有趣的故障:一旦 r1 把 '<|end▁of▁thinking|>' 识别为结束思考的指令,它就会尝试停止自己的 COT——但此时 COT 已经跳出了系统提示,它会误以为这是用户的回复,开始跟自己对话,陷入无限循环:切换到基础模型模式如果我们在上下文里放入大量的特殊 Token(数量要非常多),就能让 DeepSeek 进入“原始补全模式”(out-of-distribution mode):它会暂时丢失“聊天机器人的角色”并更像纯文本补全模型。然而,我目前还没在普通的异常 Token(非特殊 Token)上复现这种大规模模式崩溃。DeepSeek 对短序列的重复输出有着非常强的偏好,这一点似乎不仅仅是因为异常上下文,而是它本身的一个特征:如果此时继续提问,模型就会出现“自我认同”紊乱的问题:在 r1 的 distillation 版本中也可以观察到类似的现象(推特示例),甚至可能更有趣,只是这里就不展开细说了。接下来做什么?我希望这篇文章能起到抛砖引玉的作用,帮助更多人加入对这个领域的探索。无论你发现了什么有趣的模式或异常行为——哪怕很细微——都欢迎分享给我,我都会觉得非常有价值。对于下一步,显而易见的一个方向是去研究这些异常 Token 在嵌入空间(embedding space)中的分布和关系,这也可能会是我自己接下来的工作(但这绝不意味着其他人就不必或不能去尝试!)。另外,还有那些我筛掉的中文 Token,以及它们背后潜藏的秘密。我就留给更勇敢的人去挖掘了。—— henry

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

DeepSeek 异常Token 语言模型 分词器 人工智能
相关文章