【2023Q4】再谈Long-Context LLM
0、前言
从我个人来说,确实有一段时间的思考重点不在这个方向了。但最近两件事触发了我再写一下目前对于Long-Context LLM的一些判断:
前一段时间还有人认真地问过我做原生Long Context能力的LLM的(我个人的)思路
Moonshot/月之暗面 预发布了他们的首个产品,主要卖点之一就是Long Context
1、一些基础知识
为了方便不太熟悉技术细节的读者理解全文,这里插入一节说明一些相关的基础知识。
1.1 Token与Tokenizer
从模型的角度来说,原生支持的上下文长度(context window)是以token数计算的,token是对文本序列进行离散化后的一个最小单元。Token翻译成Web3中的代币不太合适,就当成一个NLP领域自己的术语就好。
token和具体文字的对应关系由tokenizer算法根据设置参数和语料数据共同决定,tokenizer的优化目标是用尽可能少的token数量表达训练语料中的所有文本。
这导致不同的成品LLM的token到文本的对应关系是不同的,所以以下都默认一个训练得到的LLM(以下简称为成品LLM)都绑定有一个自己的tokenzier生成的token映射词表,不再特意区分LLM、token词表、tokenizer。
从目前来看,大多数成品LLM的token到文本的映射特性主要与以下因素相关:
训练语料中,各个语言的占比。例如,以英文为主体的语料得到的成品LLM需要使用更多的token才能表达同样长度的中文文字。对于更符合语料的文本则只需要更少的token。
Tokenizer中设置的词表大小,目前不同LLM默认设置有差异,但整体差距不算太大。
对这方面感兴趣的同学可以参考我之前的文章 《LLM场景的Tokenizer设计》 (文章发表于知乎)。
1.2 Token与文本长度
以token数计算的context window是从模型实现层面来说的,反应模型的核心能力和团队的炼丹能力。严格来说这里还是要看具体效果的,毕竟开源界Context window虚胖但效果不好的模型已经够多了。
而从应用的角度来说,更有意义的是模型能够实际处理的文本长度,这方面就非常受到token到文本的映射的影响,简单来说,有一个平均每token能够表达的字数(或者字符数)的折算系数。这个系数非常粗糙,严格来说跟语言和文本所属的领域都是有关的。
那么基于不同语言语料训练的成品LLM在这方面差异可能是很大的,例如:
英语文化圈中训练的成品LLM一般需要2-3个token才能表示1个汉字。
中文原生训练的成品LLM每个token能够表达1-2个汉字。
所以即使模型能力完全没变,使用同样的LLM模型架构、同样的tokenizer设置,仅仅语料从英语换成中文。处理中文时候的实际context window就可能0成本的提升了3-5倍。
2、目前方案回顾
2.1、原生能力的模型/产品:
Claude,全球最早的Long Context LLM产品,提供API,宣称能力100K,实际有报告说可以超额进行请求。
Moonshot,国内首个主打该方向的产品,公司定位2C,不确定将来是否能够开放API,暂时没有公开它所支持的以token数计算的context window大小。
Moonshot的官方介绍是:
Kimi Chat在中文上具备显著优势,实际使用效果能够支持约 20 万汉字的上下文,2.5 倍于 Anthropic 公司的 Claude-100k(实测约8万字),8 倍于 OpenAI 公司的 GPT-4-32k(实测约2.5万字)。
考虑到前面提到的中文原生训练模型的天生优势,我目前猜测Moonshot的能力大概也在100k context token附近。虽然并没有显著超过Claude,但能够追上Claude,并在中文场景有实际更大的上下文长度支持已经是很有竞争力的差异化特性了。
也不能排除Moonshot也通过显著拉大了词表大小来增加实际context长度。
毕竟GPT-4拖了这么久,也仍然在32k context的层面停留,Sam Altman年中所说的要推出更长context能力的计划目前还没有实现。
Moonshot目前的近似100k能力是否是虚胖还有待其开放试用之后大家进行评价,但我目前相信他们既然已经作为了主要卖点,那么应该是明显超过开源方案的。
2.2、微调方案
目前例如ChatGLM2-6b-32k这样的后期微调实现Long Context的开源模型或者方案我目前都没有那么看好。
它们作为阶段性的、低成本的Long Context能力入门实现方案是有价值的,但我认为它们在效果上应该无法跟原生设计和训练的Long Context模型能力相比。
我也无意讨论这类方案,我认为目前的不少方式在1-2年之后可能不少都会被淘汰。而原生Long Context的模型设计经验的“半衰期”(有一半经验过时所需要的时间)应该会长的多。
3、构建原生Long Context LLM的一些思路
本节的一些想法我早就在各种地方提过了,但似乎没有系统性的整理,所以还是借此机会汇总一下。
另外本节的内容比较鸡肋,因为:
能用上这些想法的团队,只有能自己炼基座LLM的团队,他们自己能想到这些方式。
想不到这些方式的团队自己大概率只能做微调,无法利用这些方式,因为这些方式大都意味着完整的重新训练。
所以大概也就只剩对于行业分析师有一些用了(捂脸)
3.1、位置编码
在位置编码方面已经有了不少论文,但我的思路是与主流不同的。
考虑以下观点/事实:
目前的位置编码大多仍然需要一个不能被量化太多方式,与LLM其他部分有着明显的差异。
有一个常见思路认为:从实际训练DL角度上,无法在固定长度的向量中压缩进任意多的信息。
我自己的模型sense认为:Long-Context的原生模型结构需要一个可以被高度量化的,非固定维度的位置编码方式。
我认为这个方向是可行的,虽然我尚未构造出一个结构。因为我自己也没有重新训练LLM的资源,等1-2年之后训练成本大幅降低之后大概会来继续思考这方面。
3.2、模型结构
从总体来说,需要考虑Long Context的问题是否能够通过简单的分治方式进行解决,例如一轮Map-Reduce。
我个人的看法是,严格意义上的全能力Long Context问题无法通过这种简单的方式来解决,或者说需要对于所有子问题的组合进行指数级别的枚举遍历才行。但在一般常见的问题中,并不需要保持这么强的能力,或者说LLM还有其他短板导致这方面的制约并没有那么强。
但也并不是随便分治一下就可以的,例如:
NBCE(NaiveBayes-basedContextExtension)这样仅在最后token概率层面进行reduce
在网络前部试图对于token子串进行固定比例压缩的思路
大体的结构类似于:
Reduce-Network( Chunk-Network(Chunk_i), i=1....k )
这样的结构,其中:
Chunk-Network和Reduce-Network都是两个比较复杂的网络
Chunk-Network输出的结果会附加一个Chunk级别的位置编码设计
Chunk-Network输出结果并不是一个简单的固定维度的embedding,而是仍然类似某种变长序列的中间表示
Reduce-Network可能是在输入段有某种类似传统Pooling的结构,也可能不是。
整个网络需要重新从头训练,光靠已有LLM进行迁移微调应该是不太行的。
这个分治的结构也可能并不只有一层,也可能是需要叠加几层,每层对于token序列的长度进行一定程度的压缩。
3.3、Token相关的一些trick
从实用性角度来说,也可以采用超大词表的思路来扩展实际context长度能力。
虽然靠扩展词表对于context长度的拓展在渐进角度上来说是很不划算的,扩展速度为Log(V)的水平。但考虑到目前词表embedding部分结构还比较简单,以及占用显存并不那么大。所以我认为在这个方面还是有空间可以挤得,例如提高到1M token词表来实现增加10-20%的等效长度。
当然这需要一些数据tokenizer过程和训练方式上的针对性优化来针对低频率token的训练效果提升,我目前认为这并不是做不了的,而且工作跟模型本身的结构是独立的。
以及在这条线可以采用类似多层embedding的网络结构来扩展更大的等效词表。
但终究这些方式并不改变渐进意义上的模型context能力,所以我只将其称之为trick。
4、一种 序列压缩的网络结构 与 中间表示设计
本节的内容是全新的,而且我认为是很多基座模型团队也很难想到的。本节的内容基于小波变换的建模思路,有兴趣的同学可以考虑找一些小波变换的录像课程来看,该方向的科普内容仍然比较少。
本节有一个基础假设:变长序列对象中包含的信息量可能有很大差异。压缩到固定长度的序列/维数并非最优方案,要么会浪费,要么会损失太多信息。那么就需要一种自适应压缩序列的方式。
LLM本身就可以作为一个压缩工具,从序列中剔除可以大概率被预测到的token即可。但这种压缩方式的数学性质还不足够好,不是本节讨论的思路,不过这条线确实也可以做一些工作。
这里我们借鉴小波变换的思路:
1维的单轮小波变换可以看成是把信号序列成为低频信息和高频信息两个子信号序列的方式,对于每个子序列都还可以反复应用这个变换来对其做一个类似二叉树结构的分解。
2维图像的小波变化也是类似的,将图像在2维方向做类似的分解,每次将原图像按照频率性质分解为4个子图像,则对一个图像两次分解后的示例如下:
从信号处理和数据压缩的角度上来说,我们可以丢弃这个分解的N叉树中的某些分支,或者只对于这些主要分支的特征进行建模。
回到token序列的问题,虽然token是离散的,但可以通过embedding对其进行连续化。这样我们就有可能使用类似的思路将序列分解为低频和高频的成分,并递归分解多层。具体小波的选择还需要进行考量甚至重新创造,但我觉得应该是可行的。
如果序列中含有的信息不多,那么可以做到在某种小波的分解下实现某些高频分支上的信息可以被忽略,只保留部分信息喂进下级网络。也可以对于各种频率分量以软性加权或其他合成方式进行部分合成(不是缩减为固定维度)后喂入下级网络,甚至说这个类似pooling的子网络参数也是可以端到端学习的。
这样对于每个chunk就可以分解为若干个频率子成分,另外chunk还是位置信息,有一个位置编码。这位置和频率可以联合在一起设计一个“位置-频率联合编码方式”,对于频率部分,越高频率的部分等效权重越小。
总体思路就是对序列进行分解,将主要信息(低频信息)分解出来送入下级网络,高频信息一般是不重要的,以次要的通道送入后续,或干脆忽略。
也可以把这个过程视为一种压缩感知的方式。其实具体叫什么不重要,总之都是对于变换后的更紧凑的表示直接进行后续建模。
5、应用价值
虽然目前全球范围内,成熟的Long-Context LLM还不够多,但我认为这条线对于上层应用来说是重要的。
上层应用只能用一些效果比较差或重复计算很多的方式来模拟一个较强能力的Long-Context能力。这个问题还是应该由基座LLM层面进行解决。
而且确实在一些复杂场景下,缺乏好的替代性方案,应用构建被LLM的context能力所卡住。
OpenAI虽然在0613之后再没有Long Context上的动作,但Sam Altman确实说过他们要做更长的context能力。我认为该feature的应用价值是确实的,虽然并不是所有场景都需要。
历史相关文章
以下文章都发表于知乎:
【2023.6】产品视角看LLM:开源LLM进展 简评
【2023.5】基于LLM的程序开发:LLM的Context Window 与 短期发展展望
【2023H1】漫谈ChatGPT系列(7):谈LLM能处理的最大 有效上下文长度
交流与合作
如果希望和我交流讨论,或参与相关的讨论群,或者建立合作,请私信联系,见 联系方式。
希望留言可以到知乎对应文章下留言。
本文于2023.10.11首发于微信公众号与知乎。
知乎链接 https://zhuanlan.zhihu.com/p/660660723