展望LLM增量输入模式在降低应用延迟上的应用【2024Q1】
作者: 孔某人的低维认知 来源: 孔某人的低维认知
本文讨论的是流式增量【输入】思路,而不是常见的流式输出方式。
####TLDR
- 本文介绍了一种可用于API和私有部署的增量输入模式,及其在降低大参数量LLM在应用中响应延迟的价值。
####1、应用中的低延迟需求
####1.1、人性如此
在不少应用场景中,用户对于低延迟需求是很普遍的。虽然说这个要求客观来说总有些不合理,因为在跟人聊天的时候,一般人是可以接受对方反应没有那么快的,但对于一个系统或者语音电话时,用户的耐心就显著的下降了。
虽然从我的偏好来说,只要给出一个合适的进度展示,就可以容许一个较长的响应时间。但我从客观的角度也确实同意说对低延迟的偏好是人性的一部分,有被满足的价值。并且目前的应用已经在低延迟方面开始竞争,整个应用层生态对于低延迟的追求趋势难以阻挡。
####1.2、现有解决思路
即使不考虑LLM的特性,传统软件开发中也有不少改善响应延迟的思路,例如:1、该并行的部分要并行,缩短整个流程中关键路径的长度;2、设置合适的缓存点和缓存方案,以空间换时间。
考虑到LLM的特性的优化方案就不太多了:
-
期待硬件性能提升和推理基础设施的改善,不过这方面的进展没有那么快。
-
使用更小的模型,加速token的输出。不过这导致能使用的模型能力有限,且可能会需要额外的微调工作来保证效果不下降太多。
-
减少整体流程中关键链路上的LLM调用环节数,能在一次LLM调用中直接解决并以流式的方式直接输出结果是最好的。但这对模型能力的要求变高,且整个流程中很难增加提升效果和可控性的干预方式。
但无论怎样,目前对于依赖大参数量模型、长流程的workflow来说,响应延迟的问题是很大的。
####2、LLM的增量输入模式
####2.1、单次LLM API请求的增量输入模式
在人与人之间对话的时候,听者的思考是可以在他听说者说话的时候同时进行的。而目前LLM的方案上却看不到这种方式的应用,这种方式并非无法实现,只是需要新的输入模式以及更多的算力成本。本节就是描述这种思路的实现思路。
无论是用户通过语音或者打字的方式输入,输入速度都是相对较慢的,已经输入的部分只是单纯的等待一起输入给LLM。最直接的改进思路就是应该先把它们输入给LLM,然后寻找某种能把对这种不完整输入的计算结果用于加速后续完整输入时候LLM推理的方式。
需要注意的是,这时候新增的用户输入未必是直接增加到prompt的末尾,由于不同任务的prompt模板设定,新增的输入经常会出现在prompt中间的某个位置,甚至可能会对中间的多个位置有修改。
直观来想,KV cache类方案就足以在这种场景发挥重复计算复用的功能。只不过KV cache是对于prompt只在末尾新增的场景使用,在中间插入场景下还有问题。
但实际还有一些细节问题,例如位置编码。由于会在prompt中间插入新token,所以会影响到插入位置后面所有的位置编码。不过这个问题是可以解决的,有几种思路:
-
在最开始的时候在prompt中预留一段空白语义的token buffer,后续输入只是不断覆盖了这些空白语义token,而不影响后续token的位置。这种方式虽然会浪费输入token量,但应该是相对实现成本比较低的方案。
-
为该场景重新设计位置编码,例如分成两级:chunk位置编码与chunk内的位置编码,chunk的划分位置由LLM应用中的prompt模板具体指定。或者是像之前 展望LLM与半结构化I/O【2023Q4】 中提到的那样,设计更复杂的输入结构来支持这种动态增量的输入,并最小化对于增量无关部分的位置编码的影响。
这样在具体使用时的模式就是:对于每次LLM API调用,改成创建一个session,应用不断的发送最新的prompt快照,LLM服务端根据新变化到来的情况和自身计算速度对于新内容进行计算,这个预计算的输出token可以较长。
对于不完整输入prompt的输出序列预计算也可以用来加速后续的序列输出,lookahead decoding(https://lmsys.org/blog/2023-11-21-lookahead-decoding/)的方式就是:输出的时候多前瞻计算多个token,然后将后续这些前瞻计算的token n-gram缓存下来,当准确的token生成过程能够匹配到这些n-gram时,可以直接利用这些结果直接进行检验,如果检验成功则可以直接利用这些之前前瞻计算的片段结果。这种方式能够有效的缓存不同次但有些相似请求之间的重复的输出片段、以及对于输出片段的位置平移性也比较好。这种思路在本节的场景也是可以使用的。
由于时间所限这方面的细节我还没有能完整探索,但在我目前来看这个方向应该是较大概率可行的。我相信从事基座LLM模型设计的同学在看了本文之后能够摸索出真正可行的方案。上述的一些细节虽然还值得推敲和优化,但整体思路上应该足够了。
这种方式需要LLM API供应商提供专门的增量请求接口,并且要应用请求者付出更多的计算成本代价。但效果是能够大幅加速在调用较重LLM模型时的响应等待时间。
####2.2、在workflow上多环节的流式预计算
上一节只是讨论了单次LLM请求如何进行流式的不完整预计算方案,这很大程度上依赖于LLM API供应商提供能力,或者是私有LLM部署场景且能够对推理流程做改造,或期待这方面轮子的出现。
但现在的很多应用其实都需要多个LLM调用环节,仅能在第一个LLM调用环节能够进行流式增量计算能够加速一部分,但从总体环节上来说还不够。好在可以进一步把前一步LLM预计算输出的结果直接输入给后续的环节,实现整个流程的流式预计算。虽然这种方式并非没有限制,但应该有较广的适用范围。
如果中间的某个LLM环节的输出的结果并非单纯的非结构化文本,而是一些接近结构化的表示时,由于最前端用户增量输入的过程,可能在用户输入完之前就能够达到稳定输出。这给后续环节的预先计算争取到了时间。当然在用户输入完成之前无法知道这是否是最终结果,只是稳定之后的计算都可以直接命中LLM的缓存和应用内部的缓存,实现快速输出。
对于后续环节的LLM来说,其实并非跟第一个LLM环节一样的用户增量输入,由于前序环节的处理,可能导致在用户增量输入的过程中出现较大的变化。但在不少场景中,后续环节的LLM输出序列中应该也有不少可以命中缓存的计算。以及可以在流程设计和prompt构建时候特意优化这方面,在用户增量输入过程中尽量保持后续环节的输入变化也较小。
####3、总结
看到这里,相信读者能够认同说这并非什么复杂的想法。但确实没有人提的话,可能不容易意识到可以这么做。
我不觉得所有问题都靠小一些参数量的LLM模型是唯一正确的方式,总有些问题还是需要大参数量模型的。而本文就是为此准备的方案。
希望在未来的一年内能在商用LLM API和开源LLM推理库上看到类似的方案。
觉得这个思路不错,想认真在这方面研发的团队,欢迎联系我沟通交流。
交流与合作
如果希望和我交流讨论,或参与相关的讨论群,或者建立合作,请私信联系,见 联系方式。
希望留言可以到知乎对应文章下留言。
本文于2024.1.31首发于微信公众号与知乎
知乎链接 https://zhuanlan.zhihu.com/p/680743630
更多AI工具,参考Github-AiBard123,国内AiBard123