在“开席”之前,咱们先来热热身!看看下面大模型推理调度的“高频面试题”,你能答上来几道?
1.调度策略有哪些?各有什么优缺点
2.什么时候会触发调度?
3.Continuous batch 下 prefill batch 里 prompt 长度各不相同时需要 Padding 吗?为什么
很多人以为加速推理只能靠更快的芯片、量化算法或更高效的 CUDA kernel。但在 LLM 推理场景中,调度策略也是加速利器!去年,Anyscale 在 vLLM 中推出的 Continuous Batching 策略,就让推理速度直接提升了十倍以上!
Continuous Batching,又叫 Dynamic Batching,是一种按 iteration(每次前向推理)来调度的方式。这个想法最早出现在 2022 年的 Orca 推理框架中,但由于缺少实际应用,如今已经不太被提起了。反观 vLLM 在 Chatbot Arena 和 LMSys.org 上有真实流量,逐渐成为大模型推理的事实标准。
Static Batch
在 Continuous Batch 之前,最常见的调度方式是 Static Batch。下面动图展示了它的基本原理:
Static Batch 的特点是按请求分批推理,早到的请求要等晚到的(S1要等S4),“要走一起走”。它好像老家火车站的黑车。即便某个请求早完成(S3最早结束),它也得等所有请求完成后才能释放资源。这种方式导致 GPU 资源浪费且请求延迟高。不过,它的实现简单,调度器只要静态规划好当前请求的批次,等模型运行完后再继续调度下一个批次就行。
Continuous Batch
顾名思义就是“持续组 batch” 的策略,它的工作原理如下动图所示:
可以看到调度器现在很忙,模型每完成一个批次的 prefill 或者 decode 阶段,调度器就立即干活,尽量把下次推理的 batch 搞大 —— GPU 特别擅长大批量推理。这样早到的请求能快速开始,早结束的也能及时释放资源。和Static Batch 一对比,KV Cache 利用率明显提高了!
细心的朋友可能已经注意到:上面动图中,调度器优先执行 prefill 阶段。这样一来,当有 decode 请求时,可以最大化批次的规模,提高推理效率!
这里再贴出一张 vLLM 的请求处理流程图:
每次在 ModelExecutor 执行一个前向步骤前,LLMEngine都会让调度干活。调度器会根据当前请求的 KV Cache 情况决定是否需要抢占一些请求,腾出显存以满足当前推理需求。
如果还想在调度这里压榨性能,那还能做哪些事情来提高吞吐呢?
如果你对调度器的具体实现细节感兴趣,欢迎留言或者关注公众号《vLLM 深入浅出》!有朋友正在梳理源码流程图,整理好之后可以分享给大家。