关于长上下文
2023年中开始,各大LLM厂商开始关注到长上下文的问题。2023年5月,Claude把长度支持到100k tokens;6、7月的时候,ChatGPT3.5也已经支持16k,而ChatGLM2-B最大长度已经可以到32k。
(插一句,ChatGLM系列做得一直很不错,从基础模型、长窗口、工具调用、Agent都一直保持在比较前沿的水平,个人最近用ChatGLM3、ChatGLM4体验还是很不错的)
差不多同时间还有LM-SYS的LongChat,MosaicLM的MPT也支持16k以及更长的上下文。
今年过年前刚出来的Qwen-1.5系列全家桶也都是32k起步了。还有一些支持超长窗口的模型
大厂商们卷完基础模型效果,把能刷的榜刷完,又盯上了长上下文能力(当然现在长上下文也有榜了)。
为什么要那么长?
长上下文的需求
取决于语言和所使用的tokenizer,每个token对应编码的文本有所不同。以中文为例,大部分模型每个token对应的中文字数都>1.5个字(部分高效的tokenizer可以做到2个字以上)。那么200k的token就能对应处理30w字的上下文了。
最近刚看了刘震云的长篇小说《一句顶一万句》,全书差不多27万字,也就是说现在这些长上下文大模型可以秒读完一部长篇小说,然后和我交流心得,或者告诉我全书的概要,又或者帮我找到一些文中的细节描写。
上面这个场景对应的是大模型的工具化场景。我们可以借助大模型的能力,来阅读论文,总结研报或者阅读代码,这些场景都需要比较长的上下文输入。
另外还有一个也比较火的大模型应用场景,RAG(Retrieval-augmented generation),也对长上下文输入有要求,只是在RAG中,大部分输入文本并不是直接来自于用户输入,而是通过检索得来的。
除了工具化的应用场景,还有一些个性化的场景也会对长上下文有需求。举例来说,就是一些智能助手需要对用户的偏好和设置做长期记忆,这些偏好和设置可以以prompt或者对话的形式持久化存储下来,在进行新的对话的时候就把这些内容连同用户新的输入一起给到模型进行处理。
实际上,哪怕是单次的聊天,也很有可能需要模型处理比较长的上下文。比如我们可能会让模型扮演一个特定的影视角色或者游戏角色和我们进行对话。这时通常会给模型一些设定,比如这是一个什么样的任务,故事背景世界观都是什么样的,以及现在要进行哪些方面的交流等。这些设定都会以prompt的形式在最开始输入给模型。而随着对话的进行,模型如果长文本能力比较差,就有可能忘记了我们之前给的设定,这样体验上就有问题了。
上面这个例子实际引出了对长文本需求更具体的内容:(1)在文本比较长的时候,还能说人话,ppl要低(2)说人话之余,还要能attention到前面提过的细节,不能出现自我矛盾。
模型怎么支持长上下文
看来目前的很多应用场景确实对长上下文有需求,那怎么实现呢?
如果我们直接训练2k/4k长度的模型,然后在推理的时候设定8k或者16k窗口,那么PPL会急剧上升,导致模型直接讲不了人话,原因之一在之前讲RoPE的时候也有提到,对于没有训练过的位置编码,模型不能很好地处理。
直接训练
既然训练的时候用2k/4k不能很好地在8k/16k/32k+的上下文长度下推理,那直接在训练的时候用更长的数据进行训练不就可以了?
这个思路理论上可行,只是实操的时候会遇到一些问题(壕可能觉得不是问题)。
1.训练数据
直观上来说,要训练长上下文的模型,就需要长文本。要达到32k或者更大的长度,基本都只能是书籍。
当然,我们也可以通过把多个中等长度的文本进行拼接,再用来训练。比如筛选4k长度数据,那8条拼在一起也够长了。然后通过attention mask来限制各段文本之间注意力,让它们可以在各自的位置上各训各的,互不干扰。甚至实际上即使不做attention mask,效果也挺好。
总的来说,就是【连续长文本】>【多个中等文本拼接】(也可用)
2.资源消耗
来简单看一下transformer在训练中所消耗的资源。
假设模型有 层,词表大小为 ,hidden size为 ,batch size为 ,训练窗口长度为 ,使用Adam优化器训练(需要存一阶和二阶动量),为简化估算,可以假设注意力头数为1。
(1) 参数量
(2) 计算量
看一下计算量和参数量的关系。忽略参数量和计算量中的低次项,则有