LLM推理优化技术(三)

5. 解码优化 5.1 Speculative Decoding 投机解码(推测解码)1是一种非常成熟的优化技术,并被吸收进各开源大模型推理引擎项目中。它的基本原理非常简单:由于decoding阶段是内存带宽瓶颈限制,LLM输入一个token前向推理一次花费的时间,和批量输入N个token前向推理一次的时间基本一致。那么就有个比较巧妙的办法是,通过某种方法让一次前向推理输出N个token作为草稿(draft),然后批量输入这N个draft token并行前向推理,比较draft token和对应位置的LLM输出token,如果一致则直接跳过推理,如果不支持则从这个位置重新开始下一轮推理。如果猜测的N个draft token准确率足够高,那么整个推理过程将会从每次推理1个token,提升到多个token,推理速度显著提升。 思想很简单,但到具体实现,需要考虑的是如何解决一次推理能猜测N个后续token,并保证一定的准确率。这里就有两种常见的方法: 通过一个小模型来快速预测后续N个token。这个小模型可以是一个参数量更小的LLM,例如Llama 7B作为Llama 70B的猜测模型,也可以是一个更加轻量的n-gram的统计模型,可以根据实际需求挑选。这种方法的好处是,不需要重新训练模型,只需要升级推理过程,即可享受解码加速。缺点是需要两个模型配合,可能会浪费一些内存和算力。 通过修改LLM网络结构,增加多个推测头(speculative head),使得模型一次推理可以同时输出多个token。典型有Medusa2和Multi-token Prediction3。这种方法的好处是比较节省算力和内存资源,缺点也很明显,需要后训练模型,增加网络训练参数。 一个经典的,通过小模型作为draft model的投机解码算法如下图所示: 在实际落地过程中,投机解码中的draft model,也可以是一个n-gram统计模型,这样可以极大减少draft model的开销,而且适应性更强,比较适合输入和输出有较多重复内容的场景,例如文本总结场景。 应用投机解码过程中,还有一个绕不开的话题是投机解码是否对模型效果无损。投机解码影响模型效果主要有三个方面: 浮点数精度影响。由于硬件对于浮点数运算过程中,还是有可能引入精度误差,最终导致结果差异 算法实现影响。不同推理引擎在实现投机解码时,对于sampling阶段的算法,如果无法保证和原模型的分布一致,则会产生结果的差异 随机因素影响。当批量大小不同,GPU数值计算精度将会有细微差别,这个在pytorch等深度学习框架都有类似问题。这个不稳定性累计下来会影响logprobs结果,最终导致输出的差异。 综合上述原因,投机解码还是会或多或少影响LLM的输出效果。需要实际应用时充分完成效果的评测,才能确保该优化是否可使用。 5.2 MoE(Mixture of Experts) LLM在训练时遵循scaling law的规律,即参数量越大,计算量越大,训练token量越大,模型的效果越好。但这种scaling law对推理并不友好。随着参数量的增长,推理的计算量也随之增长,导致推理成本的上升。在深度学习时代,MoE技术就已经被深入研究,可以有效解决训练和推理算力需求不平等问题。 MoE是一种稀疏模型结构。它通过在网络中增加一个门结构来路由多个子网络,在推理过程中动态选择部分子网络参与推理计算,而训练时则是将所有子网络都参与训练参数中。这样既可以增加训练时的模型参数量,也可以有效降低推理时参与计算的参数量。 MoE的典型网络结构,可以参考DeepSeek-V3的结构4,如下图所示: LLM MoE一般将FFN结构替换为多个子FFN网络,在Multi Head Attention结构之后,增加一个门算子,决定路由到哪几个子FFN网络进一步计算。一般子专家网络分为共享专家和路由专家,共享专家是每次推理都会参与计算的子网络,而路由专家则是根据门算子决定选择其中几路专家网络参与计算。 对于数百B量级的MoE大模型的推理部署,是天然适合多GPU并行部署的。例如著名的DeepSeek-V3模型4,每个MoE层有1个共享专家网络,256个子专家网络,每个token推理将会激活8路专家网络和1路共享专家网络。 在部署的时候,Prefilling集群最小部署套餐是4台节点32张H100。每个GPU卡部署8个专家网络,为了避免不同专家计算量的不平衡,实际的Prefilling集群部署的时候,每个GPU卡在8个专家网络之外,还额外部署了一个冗余专家,这样每个token推理激活9个专家网络。通过动态跨节点迁移这个冗余专家网络,来尽量实现计算量的动态平衡。 而V3模型的Decoding集群,最小部署套餐是40个节点320张H100,其中256个GPU卡,每卡部署1个专家网络,其余64个GPU卡,每卡部署冗余专家以及共享专家网络。所有卡间通过直接点到点的IB网络来通信。整个调度需要精巧的设计,来降低通信耗时。 MoE的网络结构天然只会部分激活参数,因此对于推理更加友好。特别是随着DeepSeek的大火,这种网络结构也受到越来越多的关注和重视。 5.3 算子融合 算子融合是一种常见的成熟模型推理优化技术。它将模型网络计算图中的多个算子或者多层,进行编译期融合,来降低中间数据交换,降低计算开销,从而达到提升推理性能的目标。 自从深度学习迅速发展以来,算子融合就已经成为推理优化方向成熟的技术。著名的TVM5开源项目,实现全自动化的编译期算子识别和融合,覆盖经典的深度学习模型。 然而进入大语言模型时代,特别是以decoding-only模式大行其道的今天,专门针对decoding网络的优化更加适合当前业界的需要。著名的FlashAttention6,FlashAttention27,FlashDecoding8,FlashDecoding++9算法,将attension的多步算子计算,融合为一个算子。这样极大减少了读写attention矩阵的开销,提升了LLM推理计算中最重要的算子的性能。 开源项目DeepSpeed-inference10提出了Deep-Fusion融合技术,实现了: QKV矩阵计算和输入层归一化的融合 转置和attention算子的融合 后attention层归一化和中间矩阵计算的融合 偏置叠加和残差网络的融合 xFormers11 提供了各种可以增强Transformer网络结构性能的融合内核。这些包括融合 softmax算子,融合线性层、融合层归一化,以及融合SwiGLU。 TensorRT-LLM 12 是NVidia开发的提供各种高性能融合内核的框架。它集成了一个强大的模式匹配算法,可以检测各种 LLM 中的潜在融合。由于TensorRT-LLM和NVidia GPU紧密结合,使之成为NVidia GPU上推理服务的重要优化工具,深受NVidia GPU开发者的喜爱。 5.3 MQA, GQA, MLA 解码优化的另一个方向,就是在多头注意力模型的attention结构中进行优化。这也需要和训练相配合,而不是纯粹的推理优化。 经典的多头注意力算法(Multiple Head Attention)13,如下图所示: 可以明显看出,QKV矩阵计算,每个头分别计算,但Keys和Values矩阵需要占用大量的显存存储KV Cache。一个自然的想法是,是否可以在多个Queries矩阵中共享一个K和V矩阵,这就是MQA(Multi-query Attention)14的基本思想,其结构如下所示: 然而,MQA虽然节省了KV Cache的存储开销,但影响了大语言模型的效果。为此,Google的研究人员综合了MHA和MQA两种方法,提出了中间方案GQA(Grouped-query Attention)15,即多个Queries矩阵共享一组K和V矩阵,结构如下图所示:...

February 19, 2025 · Skyan

LLM推理优化技术(二)

4. 系统优化 4.1 Iteration-level Scheduling 传统上的模型推理批量计算都是将一批请求合并到一起,然后一起发送到GPU批量推理计算,完成后返回结果。但这会引起两个问题: 大语言模型请求到达时间不固定,这样先到的请求得等待后到的请求集齐一个批量,并且等待上一批量计算完成之后,才能一起发送到GPU进行批量推理计算,这对于先到的请求而言,浪费了等待时间 大语言模型每次输入和输出序列的长度不定,一般会采用padding的方法插入一些空白token用于对齐。这种批量计算对于较短的序列并不公平,它虽然已经完成,但仍然等待长序列完成之后才能返回,而且空白token用于padding计算也是浪费,GPU整体利用率也很低。 为此,2022年Orca论文1提出了iteration-level scheduling方法,将每次批量decoding作为一个迭代(iteration),每次批量decoding输出一批token之后,检查有没有完成输出的序列,如果有则从批量token序列中删除,而从排队的请求中挑选一个请求序列插入到空出的序列位置。 通过这种方法,可以有效节省等待时间,只要一个迭代中有完成的请求,就可以加入新请求继续批量decoding,而且还无需特别处理长度不一致导致的padding。这种方法将会极大提升GPU利用率,并在各个主流LLM引擎中得到了广泛应用,例如vLLM和Huggingface TGI的continuous batching,TensorRT-LLM的In-flight Batching,都是这种技术的实际应用。 4.2 Chunked Prefills Iteration-level scheduling可以极大提升GPU利用率,但还未能将GPU利用率压榨到极致。主要有两点问题: 如前所述,推理中的Prefill阶段是计算密集型,Decoding阶段是内存密集型。GPU执行prefill阶段任务时,由于大部分计算都是矩阵和矩阵乘法,因此GPU利用率可以达到最大。但当GPU在执行decoding计算时,由于大部分计算都是向量和矩阵乘法,计算受到内存带宽瓶颈限制,整体利用率很难达到最大化。 由于prefill和decoding阶段分别批量计算,存在两个阶段调度互相抢占问题。如果优先decoding,则会影响首token延迟(TTFT)。如果优先prefill,则会影响生成token间耗时(ITL)。这些调度方法都对整体的延迟长尾不友好。 Chunked prefill技术2通过将prefill拆分为多段,和decoding的序列拼在一起批量计算,来提升GPU吞吐和利用率,而且对整体服务的延迟长尾能有较好的提升。拆分主要有如下两种: 长prompt拆分为多段,调度到多次迭代批量计算中,只有最后一个段才真正使用生成的token 短prompt和decode token一起拼凑成一次批量计算,但是prompt和decode token在attention计算时分开计算。这种可以充分利用GPU算力。 Chunked Prefill的好处是将访存密集型的decode预算通过和prefill融合,从而转换为算力密集型。将decode效率得到较大提升。一些测试报告显示,chunked prefill调度相对vLLM的continuous batching调度,吞吐提升2.3倍,延迟降低50%。 该项技术已经成熟,已经被引入到vLLM,DeepSpeed等项目中,成为可以配置开启的调度类型。 4.3 PD分离 除了chunked prefill调度优化,另外一种提升GPU利用率的方法就是将prefill和decoding分别运行在不同的GPU集群3 4。这种优化可以针对算力瓶颈不同的两阶段,分配不同的GPU算力,甚至不同型号的GPU,来最大化整个集群的利用率。 典型的架构可以参考MoonCake4架构图,如下所示: 这种调度方法原理上比较直观。在prefill集群只运行prefill计算,将计算完成后得到的KV Cache传输到decoding集群,decoding集群自回归式计算输出token,完成文本生成。整个过程可以发生在一台机器中的多卡之间,通过NVLink完成卡间通讯。也可以发生在多机之间,通过IB或者RDMA网卡来通讯传输KV Cache数据。 为什么这种调度会提升GPU利用率,节省整体的GPU资源呢。可以这样模拟计算一下: 假设prefill的最大吞吐为5.6 RPS(request per second),decoding最大吞吐为10 RPS,那么如果放在一起,平均每卡吞吐最大为min(5.6, 10)/2=2.8 RPS。而将prefill阶段放在两张GPU运行,decoding阶段放在一张GPU,这样平均每卡吞吐最大为min(5.6 * 2, 10)/3=3.3 RPS,相对运行在一张卡,吞吐提升了18%。 更进一步,prefill和decoding可以采用不同的GPU型号,例如prefill集群采用算力较强的GPU,而decoding阶段采用内存带宽更大的型号,整体利用率还可以进一步提升。 PD分离带来的优势有: 可以分别优化首token延迟(TTFT)和token间延迟(ITL),由于PD分离,可以针对P和D分别采用不同的并行策略(TP或者PP),两种延迟之间不互相影响 有效控制ITL的长尾延迟。由于单卡调度Prefill和decoding,会导致prefill和decoding互相抢占GPU资源,导致最坏情况下,输出token发生严重的长尾延迟。 当然,PD分离带来的性能提升,也是建立在保证SLO目标基础上。如果不考虑SLO,PD分离带来的收益并不显著,相反,还会导致运维复杂性提高,P和D集群资源规划更加复杂。这些都是需要考虑的因素。目前PD分离也作为实验功能,进入vLLM等开源项目中。 4.4 多GPU并行推理 对于参数规模在数百B量级以上的大语言模型而言,单GPU的显存大小已经无法承载如此数量的参数和KV Cache了,这必然依赖多GPU共同加载模型,实现并行推理服务。Google在这个领域很早就开始布局5,PaLM的540B大模型就是成功部署在64块TPU v4芯片上。 多GPU并行推理,核心的难题是如何拆分模型,使得推理延迟,MFU(model FLOPS utilization),以及显存使用量同时达到帕累托最优。这个拆分还依赖模型结构和GPU的体系结构特点。例如MHA和MQA下需要考虑不同的分片方法。 模型网络每个阶段,可以采用不同的分片方法,例如在前馈神经网络层(feedforward layer)可以精巧的设计tensor的拆分,通过all-gather操作实现并行推理,在attention层则可以通过batch维度拆分,来降低显存消耗,同时降低卡间通信量,提升MFU。通过这类优化,PaLM 540B大模型的Prefill MFU可以达到76%,Decoding MFU可以达到33%。...

February 18, 2025 · Skyan

LLM推理优化技术(一)

1. 前言 随着2022年底以ChatGPT为代表的LLM(大语言模型)爆发式发展,LLM成为智能时代新的增长引擎,受到学术和工业界广泛的关注。业界对于LLM的深度研究极其火热,从训练、推理、可解释性、数据集、评估方法,甚至神经科学的交叉方向都有丰富的研究成果。 作为大模型应用领域最为关心的话题,还是如何能进一步降低大模型的成本,降低响应延迟,在不影响模型效果的前提下,提升模型推理性能。这方面的工作自从2023年以来,已有诸多新技术新思想的出现,而且已经迅速成熟,成为「开箱即用」的开源组件。本文主要介绍一些工业界成熟落地的推理优化技术,作为LLM推理技术的阶段性总结。 2. LLM推理技术原理 现代主流的大语言模型都是基于decoder-only的自回归transformer模型结构。这种模型预测方式是:已知一个token序列,预测下一个token的概率。整个模型的计算非常简洁,只需前向执行多层堆叠的transformer结构,经过抽样(sampling)计算,输出下一个token。而且现代服务一般采用GPU等专用AI芯片用于推理加速计算。 模型执行一次推理分为两个阶段: 第一阶段称为prefill,将输入的文本token序列执行一遍前向计算,填充内部每一个transformer层的key-value cache,实现初始化内部KV Cache的目的,准备下一阶段的计算。此时KV Cache缓存在GPU的HBM高速缓存中。 第二阶段称为decoding,这是一个循环计算,模型使用prefill阶段填充好的KV Cache,预测下一个token,将下一个token加入输入序列的尾部,重新执行一遍前向计算并更新KV Cache,再预测下一个token,更新KV Cache,再将新生成的token加入输入序列的尾部,如此循环反复,直到遇到结尾token<EOS>或者最大输出长度限制停止,此时将生成的文本序列返回。 整个流程如下图所示: graph LR subgraph Prefill Phase A1["'世界'"] --> A2([Iterator 1]) A2 --> A3["'人民'"] end subgraph Decoding Phase B1([Iteration 2]) --> B2["'大'"] B2 --> B3([Iteration 3]) B3 --> B4["'团结'"] B4 --> B5([Iteration 4]) B5 --> B6["&lt;EOS&gt;"] end subgraph KV Cache KV[KV-Cache] end A3 --> B1 %% KV-Cache as a shared block A2 --> |Update| KV KV -->|Shared| B1 B1 --> |Update| KV KV -->|Shared| B3 B3 --> |Update| KV KV -->|Shared| B5 B5 --> |Update| KV 从上面的推理流程可以看出,prefill阶段和decoding阶段是完全不同的两个阶段。prefill阶段主要是批量计算,由于整个序列可以一次输入计算,并行度更高,所需要的GPU算力也更高,所以属于计算密集型,GPU的算力(FLOPS)越高,运算越快,模型的首token耗时(TTFT)也就越低。...

January 13, 2025 · Skyan