随着 ChatGPT、AI 代理和视频生成等人工智能技术的快速发展,现代移动系统已开始在本地设备上集成这些 AI 能力,以增强隐私保护并减少响应延迟。
为了满足 AI 任务的计算需求,当前的移动 SoC 配备了多样化的 AI 加速器,包括 GPU 和神经处理单元(NPU)。然而,这些异构处理器尚未得到全面的性能合理使用,通常仅利用单个 AI 加速器进行 LLM 推理,导致计算资源和内存带宽的使用效率低下。
在本文中,我们首先总结了移动 SoC 的关键性能特征,包括异构处理器、统一内存、同步机制等。基于这些观察,我们提出了不同的张量划分策略,以满足预填充(prefill)和解码(decoding)阶段的不同需求。我们进一步利用移动 SoC 提供的统一内存地址空间,设计了一种快速同步机制。
通过采用这些技术,我们推出了 HeteroLLM,这是移动设备上最快的 LLM 推理引擎,支持层级和张量级的异构执行。评估结果表明,HeteroLLM 相比其他移动端 LLM 推理引擎(MLC 和 MNN)实现了 9.99 倍和 4.36 倍的性能提升。
交流
一、引言
在大型语言模型(LLM)快速发展的推动下,ChatGPT[4,14,37,43]、AI 代理[17,54,55,66]和视频生成[6,16,56,64,69]等技术已得到广泛应用。与此同时,随着用户越来越重视个人数据隐私,在智能手机等本地设备上执行模型推理的趋势日益增长。为了在这些移动平台上实现大型语言模型的高效计算,现代移动片上系统(SoC)制造商集成了各种 AI 加速器,包括 GPU 和神经处理单元(NPU)。这些加速器[11,18,26,28,42,60-62]增强了向量和矩阵计算能力,符合 AI 应用的计算需求。例如,高通的智能手机集成了 Adreno GPU 和 Hexagon NPU,以满足边缘 AI 应用的计算需求。此外,通过在单个 SoC 内集成不同的计算单元,这些处理器可以利用统一的物理内存,从而避免显式的数据拷贝。
为了充分利用异构系统中的计算资源,先前的研究[19,20,25]提出了针对异构处理器的推理引擎。然而,这些解决方案与当前的移动平台不兼容。
- 首先,GPU 和 NPU 的传统同步方法在 LLM 推理期间可能产生显著开销,尤其是在解码阶段,每个内核仅执行数百微秒。
- 其次,NPU 的性能显著高于 GPU。例如,高通 8 Gen 3[46]平台的 GPU 实际计算能力约为 1 TFLOPS(理论值 2.8 TFLOPS),而其 NPU 的实际性能可达 10 TFLOPS。
如先前方法所建议的强制 GPU 和 NPU 并行执行,实际上可能降低端到端性能。我们还注意到,一些先前的研究[12,58,59,63]利用模型稀疏性和混合精度技术,将高精度但有限的操作分配给 CPU,同时将低精度、高批量的操作卸载到 NPU。
这些方法的性能和准确性在很大程度上依赖于激活和权重的稀疏性,而最近的研究[27,57]指出,LLM 正越来越呈现密集特性。因此,为现实移动设备中的所有异构处理器(即 CPU、GPU 和 NPU)设计一个高效的推理引擎仍然是一个重大挑战。
通过对移动 SoC 内异构处理器的深入分析,我们基于其硬件架构发现了几个显著的性能特征:
- 张量敏感的 NPU 性能:尽管 NPU 在最佳条件下可以表现出卓越性能,但其效率高度依赖于张量因子,如阶数、大小和形状。如果张量与 NPU 的硬件结构不匹配,“权重停滞”(weight-stall)计算的性能优势无法充分实现,可能导致性能回退到 GPU 水平。
- 高生成成本的静态 NPU 图:现有的移动 NPU 仅支持静态计算图,这与 LLM 的动态工作负载不兼容。由于 NPU 架构的固有约束,为 NPU 生成最优图比为 GPU 生成更复杂。此外,图生成的开销不可忽视,且与每个张量的大小相关,这使得在运行时生成 NPU 图变得不切实际。
- 单个处理器的内存带宽限制:单个处理单元不足以完全饱和 SoC 的内存带宽。例如,在内存密集型工作负载中,仅 GPU 可利用 40~45 GB/s 的内存带宽。相比之下,同时使用两个处理单元可实现约 60 GB/s 的内存带宽(SoC 的最大内存带宽为 68 GB/s)。
这些独特的性能特征为增强 GPU 和 NPU 的并行性开辟了新机会:通过策略性地利用 GPU,可以在特定场景中弥补 NPU 的性能限制。
在本文中,我们介绍 HeteroLLM,这是最快的移动推理引擎,旨在高效利用移动 SoC 中的所有异构处理单元。
CPU 被用作同步和 GPU 内核调度的控制平面,因其能效低不适合 LLM 任务。NPU 作为主要计算单元,处理大部分计算任务,而 GPU 作为辅助计算单元,提升 NPU 性能下限。
为了高效利用这些异构计算资源,HeteroLLM 全面考虑了 GPU 和 NPU 的性能特征,如阶段性能、顺序敏感性能和形状敏感性能。为了在现实移动设备上实现层级和张量级的 GPU-NPU 并行性,HeteroLLM 进一步引入了三项技术:
- 首先,HeteroLLM 在预填充和解码阶段应用不同的张量划分策略,以促进张量级异构执行;
- 其次,HeteroLLM 基于可预测的内核等待时间实现了一种快速同步机制,以实现微秒级同步;
- 第三,HeteroLLM 集成了张量划分求解器,利用硬件性能分析器和运行时决策器生成最优划分方案。
我们在高通 8 Gen 3 SoC(最先进的移动平台之一,集成了 Arm CPU、GPU 和 NPU)上实现了 HeteroLLM 原型。我们的系统基于 PPL[50](一种支持 CPU 和 GPU 的先进 LLM 推理引擎)构建。为了纳入 NPU,我们将高通 QNN[48]提供的 NPU 算子集成到我们的框架中。关于推理准确性,我们避免使用激活量化和稀疏技术,因为这些技术与我们的方法正交。
HeteroLLM 是首个在移动设备上使用 FLOAT 计算使十亿级 LLM 的预填充阶段超过每秒 1000 个 Token 的 LLM 引擎。
- 在预填充阶段,与其他 SOTA 推理引擎相比,仅使用层级异构执行就可比 MLC[40]提速 7.27 倍,比 MNN[36]提速 3.18 倍。此外,张量级异构执行比层级执行带来近 40%的性能提升。当序列长度与 NPU 图的形状不匹配时,张量级方法比填充方法实现高达 2.12 倍的提升。
- 在解码阶段,HeteroLLM 生成的 Token 比仅使用 GPU 时多 23.4%。当与 GPU 密集型工作负载并发运行时,HeteroLLM 将 LLM 推理与渲染任务之间的干扰降至最低(无 FPS 下降),LLM 任务仅减慢 7.26%。
二、背景与相关工作
2.1 LLM 推理
大型语言模型(LLM)推理指使用预训练模型基于新输入数据生成预测或输出的过程。通常包括两个不同阶段:预填充阶段和解码阶段。
- 在预填充阶段,LLM 以单批次处理用户输入,生成第一个 Token。由于用户输入的序列长度可能较长,此阶段依赖矩阵乘法操作,计算量密集。
- 相反,解码阶段以顺序自回归方式逐一生成后续 Token。由于支持 KV 缓存[3,30,30,35],此阶段需要矩阵向量乘法,属于内存密集型工作负载。
与云端 LLM 推理(如 vLLMs[29]、orca[67]等[2,10,32,45,51,68,71,73])注重高吞吐量和满足不同推理工作负载的响应时间服务级别目标(SLO)不同,移动端 LLM 推理更强调最小化端到端延迟。
延迟可进一步分为两部分:首 Token 生成时间(TTFT)和每输出 Token 时间(TPOT)。
- 前者表示生成第一个 Token 的延迟,主要受预填充阶段处理速度影响;
- 后者表示生成每个后续 Token 所需的时间,与解码阶段的 Token 生成速度相关。
2.2 移动端异构 SoC
出于个人隐私和安全考虑,用户越来越倾向于在本地移动设备上部署 LLM,而非将个人数据传输至云服务。因此,主流厂商正积极推动边缘 AI 平台的演进,包括高通骁龙 8 Gen 3[46]、苹果 A18[5]、联发科天玑 9300[5]、华为麒麟 9000[21]等移动平台。
表 1 列出了几种主流移动 SoC 平台的参数规格。为支持 LLM 所需的巨大计算能力,移动平台正向异构 SoC 发展。除了传统的 CPU 和 GPU,NPU 在这些平台中愈发关键。
通常,这些异构处理单元可共享统一物理内存,这与离散异构系统有显著区别。
2.3 移动端推理引擎
随着对 LLM 需求的增长,先前研究已开发了移动端推理引擎,如 ONNXRuntime[39]、Llama.cpp[13]、MNN[36]、NCNN[53]、OpenVino[23]、TFLite[15]、MLC[40]、PPL[50]等[24,34]。考虑到移动设备的复杂性、多样性和不兼容性,建立统一全面的软件生态系统具有挑战性。为应对这些挑战,这些移动端推理引擎通常以 ONNX 格式[39]为输入,然后执行一系列优化(如图优化和算子融合)以构建模型的运行时图。
为支持各种设备,推理引擎通常将移动加速器抽象为不同后端(如 CPU、GPU 和 NPU),并进一步利用指令集和编程语言(如 CPU:NEON、SVE2 和 AVX;GPU:OpenCL、Vulkan 和 CUDA;NPU:QNN、HIAI 和 CoreML)在运行时图中实现相应的底层算子。图 1 展示了推理引擎的通用框架:PPL,其被选为本文的基线。
如图 1 所示,HeteroLLM 参考的推理引擎总体框架包括 API 接口(Python/C++)、模型解析器、优化器、序列化器、全局图(ONNX/CAFFE)、运行时调度器、分区器、内存管理器、统一中间图表示库以及后端引擎(CPU/ARM、GPU/OpenCL/Cuda、NPU/QNN 等)。
如 2.2 节所述,现代移动 SoC 通常具有多个异构处理器,这意味着单个移动设备上可同时利用多个处理单元执行 AI 任务。一些研究已注意到这一现象,如表 2 所示。
- Qualcomm-AI[47]仅利用 NPU 的 INT 计算进行矩阵乘法,这显著牺牲了推理精度[27,57]。
- MLLM-NPU[65]设计用于通过 NPU 卸载实现高效的设备端 LLM 推理,其优化了提示处理、张量离群值处理和乱序块调度,以显著提升性能和能效,但仅利用 NPU 提供的 INT 操作,并严重依赖模型激活稀疏性和量化,这两种机制均可能降低模型精度。
- MLC[40]和 MNN[36]利用 CPU 和 GPU 进行 LLM 推理。
- Onnxruntime[39]利用 CPU 和 NPU 进行计算,但这些研究均未涉及张量级的异构并行性。
此外,所有先前工作均未解决 GPU-NPU 并行性,而这对移动设备而言是更强的组合。
三、性能特征
为有效利用异构处理器,我们首先分析 GPU、NPU 和内存系统的性能。这些加速器因其独特的硬件架构而表现出多样的性能特征。特别是 NPU 在不同张量类型和算子间的性能差异显著。因此,我们全面分析这些异构加速器的架构差异,然后总结其性能特征。
3.1 GPU 特征
移动 GPU 与桌面级离散 GPU 具有相似的计算架构,包括单指令多线程(SIMT)指令、片上共享内存和流式多处理器或计算单元(SM/CU)。
不同之处在于,移动 GPU 采用与系统内存集成的统一内存地址空间(UMA)的独特内存层次结构。离散 GPU 中必要的 CPU 端与 GPU 端内存之间的数据传输操作,在移动 GPU 中变得冗余。然而,传统 GPU 框架(如 OpenCL)并非为这些 UMA GPU 设计,仍遵循为移动 GPU 抽象专用 GPU 内存的方式。
特征 1:线性性能
图 2 展示了移动 GPU 在不同张量大小下的性能。
- 当张量较小时,GPU 计算受内存限制;随着张量大小增加,总 FLOPS 线性增加;
- 一旦大小超过特定阈值,GPU 计算转为受计算限制,总 FLOPS 保持稳定。
特征 2:高成本同步
移动 GPU 存在两种主要同步开销:
- 第一种源于数据拷贝,现有 GPU 框架仍为移动 GPU 维护独立内存空间,开发者必须使用“clEnqueueWriteBuffer”等 API 将数据从 CPU 端缓冲区传输至 GPU 内存,此传输过程会产生固定延迟(在我们的平台上约为 400 微秒),与数据大小无关;
- 第二种开销与内核提交相关,由于 GPU 采用异步编程模型,当前内核执行时可对后续内核进行排队,提交开销可忽略(约 10-20 微秒),但同步后 GPU 队列变空,由于内核排队和提交开销,会导致额外 50-100 微秒的延迟。
3.2 NPU 特征
尽管 NPU 实现多样,但矩阵计算单元(如脉动阵列)是 NPU 内部最关键的组件。其利用矩阵计算的内在数据流特性,从而最小化模型权重和激活的冗余加载/存储操作。
图 3 展示了经典的脉动阵列设计。
- 在脉动阵列的计算流程中,权重在计算前预加载到每个处理单元(PE);
- 计算阶段采用“权重停滞”模式,权重保持不动,输入或激活被馈入脉动阵列;
- 最终计算结果从脉动阵列输出,存储于片上 SRAM 或直接转发至后续脉动阵列单元。
由于这种 NPU 计算范式,NPU 表现出三种不同的计算特征:阶段性能、顺序敏感性能和形状敏感性能。
特征 1:阶段性能
由于 NPU 内部硬件计算阵列(如脉动阵列)的大小固定,用于矩阵乘法(Matmul)算子的张量维度可能与硬件计算单元的大小不匹配,导致计算资源利用效率低下。
如图 4 所示,这种不匹配导致不同张量大小下的“阶段性能”现象。例如,对于采用 32×32 脉动阵列的 NPU 矩阵计算单元,任何维度小于 32 的计算张量将表现出相同的计算延迟,导致特定张量形状下的性能显著下降。为充分利用 NPU 的计算资源,编译器将张量划分为与矩阵计算单元硬件配置对齐的分块。当张量维度无法被矩阵计算单元的大小整除时,NPU 编译器必须引入内部填充以对齐所需计算大小,这导致 NPU 计算期间的阶段性能效应。
特征 2:顺序敏感性能
除阶段性能外,NPU 还表现出顺序敏感的计算行为。考虑两个维度为[M, N]和[N, K]的张量(M>N>K),常规矩阵乘法(MatMul)操作需要 2×M×N×K 次运算;若反转张量顺序(即[K, N]×[N, M]),总计算操作数不变,但可能导致 NPU 性能显著下降,我们将此现象称为顺序敏感性能。
图 5 给出了一个具体示例,[14336,4096]×[4096,K]的矩阵乘法操作相比[K,4096]×[4096,14336]实现了 6 倍的性能提升。
顺序敏感性能的主要原因是 NPU 利用权重停滞计算最小化内存加载/存储开销。
- 理想情况下,权重张量完全适配硬件矩阵计算单元,无需额外内存操作;
- 但当权重张量显著大于输入张量时,需要更频繁地将权重张量从内存加载至矩阵计算单元,增加 NPU 执行期间的内存开销。
因此,即使[K, N]×[N, M]和[M, N]×[N, K]的计算操作数相同,[N, M]相比[N, K]的更大尺寸会因涉及的额外内存操作导致性能更差。在 NPU 计算的最坏情况下,若输入张量为[M, N]且权重张量假设为[N, 无限],矩阵计算单元无法利用权重停滞计算范式,NPU 性能将回退至 GPU 水平。
特征 3:形状敏感性能
除顺序敏感性能外,NPU 还表现出形状敏感性能特征。即使输入张量大于权重张量,NPU 的效率仍受行和列大小比例影响。
具体而言,当输入张量的行大小超过列大小,NPU 表现出更好的性能(比较图 5 中的蓝线和紫线)。这主要是因为输入张量的列大小与权重张量的行大小相同,输入张量列大小较大导致权重张量较大,削弱了权重停滞计算范式的优势。
3.3 SoC 内存带宽
特征 1:单处理器内存带宽未充分利用。尽管移动 SoC 为多个异构处理器采用统一内存地址空间,但我们观察到,在解码工作负载下,单一处理器无法充分利用 SoC 的总内存带宽。
如图 6 所示,在高通骁龙 8 Gen 3 平台上,SoC 的最大可用内存带宽约为 68 GB/s(图中黑色虚线),但使用单个处理器(如 CPU、GPU 或 NPU)在解码工作负载下仅能达到 40-45 GB/s。当 NPU 和 GPU 任务并发执行时,总内存带宽利用率提升至约 60 GB/s,非常接近理论带宽极限。
因此,鉴于 Token 生成速率与可用内存带宽呈线性相关,GPU-NPU 并行性为提升 LLM 解码阶段性能提供了新机会。
四、设计
鉴于移动系统的功耗限制和其他应用的存在,我们避免为 LLM 任务耗尽异构处理器的所有可用功率。例如,CPU 由于能效低且忙于通用任务,不适合作为 LLM 任务的专用后端。因此,HeteroLLM 仅将 CPU 用作同步、GPU 内核调度和处理非计算密集型任务(如反量化)的控制平面。至于其他处理器,NPU 在大多数情况下性能优于 GPU,但在执行某些计算时可能出现显著性能下降。
因此,我们的系统将 NPU 指定为主要计算单元,同时利用 GPU 在特定情况下提升 NPU 的性能下限。
图 7 展示了 HeteroLLM 在典型 LLM 中的整体执行流程。
HeteroLLM 采用两种 GPU-NPU 并行方法:层级异构执行和张量级异构执行。
- 层级方法包含两项关键优化:
- 首先,将不同算子分配给最合适的后端(例如,将矩阵乘法算子导向 NPU 后端,而 RMSNorm/SwiGLU 算子由 GPU 后端更高效地处理);
- 其次,由于典型 LLM 模型的权重张量尺寸大于用户输入张量,输入和权重张量会从[M, N]×[N, K]置换为[[K, N]×[N, M]]^T,以满足 NPU 的顺序敏感性能要求。
- 对于张量级方法,HeteroLLM 针对不同后端引入各种张量划分策略(4.1 节),并设计求解器以确定最佳划分方案(4.3 节)。两种方法均采用新型同步技术以减少 NPU 与 GPU 之间的同步开销(4.2 节介绍)。
4.1 张量划分策略
HeteroLLM 通过三种不同的划分策略引入张量级异构执行:行切分、序列长度切分和混合切分。这些策略解决了【仅】使用 NPU 执行时的三个关键缺陷:
(1)特定张量形状导致的性能下降;
(2)高图生成成本的静态计算图;
(3)SoC 内存带宽和异构处理器计算能力的未充分利用。
4.1.1 预填充阶段的张量划分
行切分
在预填充阶段,尽管 NPU 在理想情况下性能可比 GPU 高一个数量级,但其性能显著受输入和权重张量的形状影响。
- 首先,当序列长度较短时,由于 NPU 的阶段性能,NPU 无法利用所有可用计算资源,导致性能与 GPU 相近;
- 其次,由于前馈网络向下投影层(FFN-down)固有的降维矩阵,该矩阵的列大小在转置后大于行大小,即使在序列长度较大的情况下,这种配置对 NPU 执行也非最优(归因于 NPU 的形状敏感性能)。
在此类场景中,由于 NPU 在该张量形状下的计算效率极低,其性能仅比 GPU 提升 0.5× 至 1.5×,而该张量上的矩阵乘法占预填充总执行时间的近一半。
在这两种情况下,我们提出用于 GPU 和 NPU 并行的行切分策略。如图 8 所示,行切分基于行维度将第一个张量划分为子张量,将部分计算负载从 NPU 调度至 GPU。为确保下一层开始执行前可获取最后一层的所有激活(即输入),HeteroLLM 在计算图中显式引入同步点,并管理不同后端间中间结果的拆分与合并。对于理想划分,GPU 和 NPU 将同时完成计算,从而减少端到端延迟。
序列长度切分
除 NPU 的性能波动外,移动端 NPU 还存在另一限制:仅支持静态图执行。运行时张量的形状和大小需在内核初始化阶段确定,这一限制源于当前移动 NPU 广泛采用的数据流图编译[1,7,52]方法。此外,如图 9 所示,NPU 的内核优化成本高度依赖张量大小,更大的张量会扩大优化的搜索空间[49,70,72]。相比之下,GPU 框架提供一组内核实现,每个实现可适配多种张量形状,便于运行时动态形状的内核执行。
为支持 NPU 引擎的动态输入形状,标准方法是选择一组预定义张量形状(如 128、256 和 512),然后将输入数据填充至这些形状。例如,若输入 Token 的序列长度为 300,推理引擎会将其填充至对齐大小 512,以避免为新张量大小生成 NPU 图的开销。但这种填充会引入额外计算开销。为解决此问题,我们提出序列长度切分策略,以支持动态张量形状,同时最小化冗余填充开销。
如图 10 所示,HeteroLLM 将涉及动态形状张量的计算任务卸载至 GPU(根据 GPU 的线性性能特征),同时将固定大小的张量计算保留在 NPU。例如,对于输入序列长度 300,我们将张量划分为 44 和 256 两个段:256 是标准张量形状,其计算图预先生成,可由 NPU 处理;大小为 44 的段(非预定义形状)由 GPU 后端与 NPU 并发执行。理想情况下,NPU 执行与 GPU 执行重叠,从而消除额外开销。
多序列长度切分和混合切分
由于 GPU 性能通常弱于 NPU,当序列长度超过特定阈值时,其计算会成为瓶颈。
为缓解此问题,我们进一步沿序列长度维度将输入张量划分为多个子张量(每个子张量具有预定义形状)和一个任意形状的子张量(多序列长度切分)。
所有预定义形状的子张量在 NPU 上顺序执行。例如,若输入张量的序列长度为 600,可划分为 512、32 和 56 的子张量:512 和 32 是预定义张量形状,可在 NPU 上顺序执行,动态大小 56 的子张量卸载至 GPU。
除多序列长度切分外,HeteroLLM 还可采用混合方法,结合行切分和序列长度切分(混合切分)。在此配置中,HeteroLLM 继续对 NPU 计算使用填充,同时基于行维度将部分计算负载卸载至 GPU 后端。
通过这些精心设计的张量划分方法,HeteroLLM 可重叠 GPU 和 NPU 的执行时间,并根据不同序列长度进一步选择最佳划分策略。
4.1.2 解码阶段的张量划分
在解码阶段,主要瓶颈从计算转向内存带宽。GPU 和 NPU 的并行执行可利用 SoC 的全部内存带宽(大于单个处理器的内存带宽)。在解码阶段,输入 Token 的序列长度固定(标准解码通常为 1,推测解码[38]为 n)。我们可使用指定的解码张量形状预生成 NPU 图,并采用行切分策略进行张量划分。与预填充阶段旨在平衡 GPU 和 NPU 计算负载的行切分策略不同,解码阶段的方法侧重于最大化 SoC 内存带宽并最小化潜在内存竞争。为实现最佳划分,我们采用划分求解器(4.3 节介绍)确定 NPU 和 GPU 之间的最佳划分比例。
4.2 快速同步
尽管 GPU-NPU 并行可减少某些算子的执行时间,但可能因 GPU 和 NPU 同步引入新开销(GPU 的高成本同步特征)。这种同步开销在解码阶段更为显著,此时单个操作(如矩阵乘法)的执行时间缩短至数百微秒,而一次同步操作的开销至少为 400 微秒。
为缓解此开销,我们采用两种策略:
首先,移动 SoC 提供统一地址空间,允许将内存缓冲区映射到主机和设备地址空间,无需额外数据传输。在 HeteroLLM 运行时,预留专用内存池用于分配每个算子的输入和输出张量。由于 LLM 中的不同层共享相同的解码器块,该内存池仅需几个缓冲区插槽,可在不同层之间重复使用。此外,这些缓冲区插槽不会被 GPU/NPU 驱动回收,确保 CPU 与 GPU/NPU 地址空间之间的映射在整个模型推理过程中保持不变。
其次,我们利用 GPU 内核的可预测等待时间实现快速同步。鉴于 LLM 在每层执行相同操作,GPU 内核的等待时间在不同层间趋于一致且可预测。我们允许同步线程按预测的等待时间睡眠,随后通过轮询机制实现精确同步。由于移动 SoC 中“usleep”的最小粒度约为 80-100 微秒,无法作为精确的同步机制,因此同步线程唤醒后,会利用小/中型 CPU 核心持续监控最后一层的输出张量。输出张量旁添加标志位,输出张量填充完成后更新该标志位。CPU 核心只需轮询该标志位几微秒,一旦 GPU 内核完成,即可立即通知 NPU 进行后续执行。
尽管预填充和解码阶段均利用带快速同步的 GPU 和 NPU 并行性,但两者存在若干区别,如图 11 所示。
- 在预填充阶段,NPU 计算能力更强,属于 NPU 主导型。HeteroLLM 有效将 GPU 执行时间隐藏在 NPU 执行中,但需延迟提交下一个 GPU 内核直至 NPU 执行完成。尽管这会在 GPU-NPU 同步期间引入任务提交开销(约数十微秒),但在预填充阶段可忽略。
- 相反,在解码阶段,由于 GPU 内核实现更稳定高效的内存带宽,GPU 性能优于 NPU,属于 GPU 主导型。在此阶段,我们将 NPU 执行与 GPU 执行重叠:NPU 任务完成后,立即将下一个 GPU 内核提交至 GPU 队列。队列的固有顺序确保 GPU 内核的同步,消除解码阶段的额外 GPU 提交开销。
4.3 整体整合
图 12 展示了 HeteroLLM 的整体架构。给定大型语言模型,我们的张量划分求解器首先识别模型在若干预定义序列长度下使用的各种张量形状,然后与性能分析器协作确定每个张量的划分策略,接着以最适当的比例划分每个张量,最后为不同后端生成计算图,在运行时执行推理引擎。
性能分析器
为确定最佳划分方案,求解器与专为异构处理器设计的性能分析器协作。我们的分析器有两种模式:真实执行和预测。
- 在真实执行模式下,分析器在实际硬件上对各种张量形状执行目标算子,收集 GPU 和 NPU 的精确性能指标。尽管此模式耗时,但可离线进行。此外,NPU 的阶段性能特征有助于有效修剪张量划分搜索空间(约束行划分需对齐至 256,序列长度划分需对齐至 32),从而减少候选划分数量。除真实执行模式外,我们还提供预测模式。由于硬件性能的固有波动,不同后端的性能结果允许 minor 不精确。我们使用传统机器学习技术(如决策树回归)预测不同张量形状下的 NPU 性能;
- 鉴于 GPU 性能更稳定且较少依赖张量形状,我们可在计算密集型场景中使用固定 TFLOPS 速率轻松估算 GPU 执行时间。
张量划分求解器
获取各种张量形状的硬件性能结果后,求解器必须确定最佳划分策略(考虑仅 GPU、仅 NPU 和 GPU-NPU 并行)。求解器优化的目标函数如下式所示:
在 GPU-NPU 并行场景中,求解器遍历 GPU 和 NPU 的所有可能划分方案,并从分析器获取性能结果。
通常,GPU 和 NPU 的执行时间无法完美重叠,因此求解器使用这两个后端的最大执行时间作为实际计算时间。除计算时间外,求解器还考虑同步开销(包括内核提交和 GPU 与 NPU 内存间的激活传输)。内核提交成本还受执行是 GPU 主导还是 NPU 主导的影响。对于 GPU-NPU 并行无法带来性能提升的某些张量大小,求解器选择不划分张量,而是选择最佳后端执行。
推理引擎
执行期间,控制平面决策器根据推理阶段和序列长度,确定内核在 NPU 后端、GPU 后端还是使用 GPU-NPU 并行执行。当两个相邻内核分配至不同后端时,HeteroLLM 引擎采用快速同步机制确保数据一致性。两后端内核执行完成后,引擎根据需要合并中间结果。
此外,HeteroLLM 引擎还管理主机-设备共享缓冲区的内存池,这些缓冲区作为每个 GPU/NPU 内核的输入和输出张量分配或回收,绕过设备驱动的组织。
五、评估
5.1 实验设置
我们基于 PPL[50](一种支持 CPU 和 GPU 的 SOTA 移动端推理引擎)实现了 HeteroLLM 原型。HeteroLLM 通过集成 NPU 支持(使用 QNN-NPU 库)扩展了 PPL,并实现了 GPU 和 NPU 之间的层级及张量级异构执行。
关于模型量化,HeteroLLM 采用 W4A16(仅权重)量化[8,9,31,33,44],平衡模型精度(FLOAT 计算)和存储开销(权重存储为 INT4)。我们在最强大的移动 SoC 之一——高通 8 Gen 3 上评估 HeteroLLM 的性能。即使与利用模型/激活稀疏性或依赖仅 INT 的 NPU 计算(可能损害模型精度)的推理引擎[47,59,63]相比,HeteroLLM 通过更高效的 NPU 利用和 GPU-NPU 并行性展现出可比性能,且不牺牲任何精度。此外,我们相信我们的技术还可提升稀疏推理的性能,这与我们的工作属于正交方向。
在评估中,我们主要与使用密集计算且不牺牲推理精度的推理引擎进行比较,如 llama.cpp(CPU)、MLC(GPU)和 MNN(GPU)。
- HeteroLLM 通过预填充阶段的层级异构执行(Hetero-layer)实现显著性能提升,相比上述推理引擎分别提升 25.1 倍、7.27 倍和 3.18 倍。
- 此外,HeteroLLM 通过张量级异构执行(Hetero-tensor)进一步提升 40%。
在解码阶段,HeteroLLM 通过充分利用 SoC 的内存带宽实现高达 23.4%的性能提升。
5.2 预填充性能
我们首先评估 HeteroLLM 的预填充性能。由于移动 NPU 仅支持静态图执行,评估从两个角度进行:适配预定义图的规则序列长度,以及与 NPU 静态图不匹配的任意序列长度。
5.2.1 对齐序列长度
我们在序列长度为 64、256、1024 时,将 HeteroLLM 的预填充性能与 MNN-OpenCL、llama.cpp、MLC 和 PPL-OpenCL 进行比较。
如图 13 所示,在序列长度为 256 时运行 W4A16 量化的 Llama-8B 模型,Hetero-layer 相比上述框架实现 5.85 倍、24.9 倍、5.64 倍、2.99 倍的加速。对于序列长度 64 和 1024,Hetero-layer 分别可加速 3.67-14.36 倍和 3.17-25.12 倍。
这些性能提升源于使用 NPU 替代 GPU 执行计算密集型算子(如 Matmul),因为优化良好的 NPU 在大多数场景中使用更合适的张量顺序时显著优于 GPU。
基于此,Hetero-tensor 更进一步,平均比 Hetero-layer 高出 30.2%(序列长度为 32 时最高达 40.8%)。在序列长度为 1024 时,Hetero-tensor 相比 llama.cpp、MLC 和 MNN-OpenCL 分别实现 34.5 倍、9.99 倍和 4.36 倍的性能提升。Hetero-tensor 在 Llama-8B 上的预填充速度达到 247.9 tokens/秒,在 InternLM-1.8B 上高达 1092 tokens/秒。
这是因为 Hetero-tensor 同时考虑了 GPU 和 NPU 的性能特征,允许 GPU 弥补 NPU 在特定张量形状(如 FFN-down)下的性能下降,从而释放 GPU 和 NPU 异构执行的潜力。
此外,Hetero-tensor 还利用快速同步机制克服 GPU 和 NPU 之间的同步开销,我们将在 5.4 节评估这一点。对于其他模型,Hetero-layer 和 Hetero-tensor 也表现出显著的性能提升。在 Llama-7B 上,Hetero-tensor 平均比 MNN-OpenCL 快 6.05 倍,比 MLC 快 6.63 倍。类似地,在 Llama-3B 模型上,Hetero-tensor 相比 MNN-OpenCL 平均加速 10.2 倍,相比 PPL-OpenCL 加速 3.51 倍。
与仅利用 NPU 进行稀疏计算(INT)的其他推理引擎[59,63]相比,HeteroLLM 利用 NPU 的密集计算能力(FLOAT)。得益于 GPU 的参与,HeteroLLM 甚至比这些工作表现更好。例如,Hetero-tensor 在 InternLM-1.8B 上序列长度为 256 的预填充阶段实现 1092 tokens/s,而 MLLM-npu[59]在相同模型规模下仅达到 564 tokens/s(依赖稀疏激活)。
5.2.2 未对齐序列长度
由于当前移动 NPU 仅支持静态计算图,无法提前为每个序列长度准备图。
- 一种直观方法是在运行时为每个不同序列长度的请求创建新图(称为“Online-prepare”)。
- 另一种方法是预加载几个标准尺寸的图(如 128、256、512),并将未对齐的输入填充至最接近的标准尺寸。
此外,未对齐的输入还可使用多序列长度切分方法(4.1.1 节描述)分割为多个部分,超过标准尺寸的部分(称为边缘部分)使用较小的标准尺寸图处理,并在 NPU 上顺序执行。这两种方法分别称为“Padding”和“Pipe”。
MLLM-NPU 通过将输入序列分割为固定大小的块(称为“Chunked Prefill”)解决 NPU 上静态计算图的挑战。块大小必须谨慎选择以充分利用 NPU 的计算能力并避免不必要的开销。例如,Chunked Prefill 仅在序列长度为 1024 时达到最大预填充性能,当序列长度缩短至 256 时性能下降至一半[59]。相比之下,Pipe(即无 GPU 支持的多序列长度切分)动态选择不同的标准尺寸,图加载开销更小。我们将 Pipe 作为仅 NPU 预填充的最佳方案。
图 14 展示了 Hetero-tensor 在运行 Llama-8B 时未对齐序列长度下的性能,并与上述三种方法比较。标准尺寸设置为 32 至 1024 之间的 2 的幂。我们记录 Online-prepare 的图准备时间和计算时间。
结果表明,Hetero-tensor 在每个序列长度下均优于其他方法,
- 在未对齐序列长度为 525 时,相比 Online-prepare、Padding 和 Pipe 分别实现 2.24 倍、2.21 倍和 1.35 倍的加速。Online-prepare 在大多数情况下延迟最长,因为图准备时间随序列长度增加,且与图的数量相关(通常为 4 个图)。
- 在序列长度为 135 时,准备时间为 408.4 ms,占总延迟的 34.6%;
- 当序列长度延长至 1000 时,该开销增加至 2050 ms。
Padding 的延迟呈阶梯式而非线性增加,其引入额外延迟并导致计算资源浪费。当未对齐序列长度略超过标准尺寸时,Padding 的延迟平均比 Hetero-tensor 长 1.91 倍。Pipe 通过将边缘部分适配到较小的图中补偿 Padding 的开销,添加的填充更少。相比 Pipe,Hetero-tensor 仍能够将延迟降低 13.2%-30.1%。
Hetero-tensor 的性能提升归因于其跨异构加速器并行计算的能力,以及采用各种张量划分策略的灵活性。
对于每个尺寸未对齐的矩阵乘法,Hetero-tensor 根据 NPU 和 GPU 的计算能力决定划分策略:
- 当边缘部分与标准尺寸的比例接近 GPU 与 NPU 计算能力的比例时,计算按序列长度在 GPU 和 NPU 之间划分;
- 如果边缘部分太小而无法充分利用 GPU 的计算能力,Hetero-tensor 应用混合切分在行和序列长度上划分乘法。
5.3 解码性能
图 16 展示了 Hetero-tensor 和其他推理引擎的解码速度。Hetero-tensor 在 Llama-8B 上达到 14.01 tokens/s,在 Llama-3B 上达到 29.9 tokens/s,在 InternLM-1.8B 上达到 51.12 tokens/s。
- 在 Llama-8B 上,Hetero-tensor 相比 MNN-OpenCL、llama.cpp、MLC 分别实现 1.50 倍、2.53 倍、1.52 倍的加速;
- 在 InternLM-1.8B 上,相比 MNN-OpenCL 和 MLC 分别实现 1.94 倍和 2.62 倍的加速。
对于 Hetero-layer,由于 NPU 计算在序列长度较小时通常慢于 GPU,其在解码层始终选择 GPU,表现与 PPL-OpenCL 类似。
Hetero-tensor 是唯一在解码阶段同时利用 GPU 和 NPU 的框架。
当 NPU 和 GPU 并发运行时,内存带宽从 43.3 GB/s(仅 GPU)增加至 59.1 GB/s。Hetero-tensor 使用行切分策略划分计算并最大化 SoC 内存带宽,因此在 Llama-8B 上比 PPL-OpenCL 快 23.4%,在 Llama-3B 上快 8.52%,在 InternLM-1.8B 上快 13.38%。
5.4 快速同步的影响
预填充性能:图 15 展示了 Hetero-layer 和 Hetero-tensor 在有无快速同步时,在不同模型、序列长度 64、256 和 1024 下的预填充性能。
- 在 Llama-8B 上,使用快速同步使 Hetero-layer 和 Hetero-tensor 的性能平均提升 15.8%和 24.3%;
- 在序列长度为 256 时,Hetero-tensor 的预填充速度从 196.44 tokens/s 提升至 236.92 tokens/s。
对于 Llama-7B 和 InternLM-1.8B,Hetero-tensor 实现 49.0%和 34.5%的性能提升,Hetero-layer 实现 31.7%和 26.7%的性能提升。Hetero-tensor 对同步成本更敏感,这可能破坏 GPU 和 NPU 之间的计算平衡。
解码性能:图 17 展示了 Hetero-tensor 在有无快速同步时的解码性能。
- 在 Llama-8B 上,Hetero-tensor 的解码速率通过快速同步提升至 4.01 倍;
- 在其他模型上,我们观察到可比的提升(2.2 倍加速)。
解码阶段的加速远高于预填充阶段,因为解码阶段每个内核的执行时间更短,因此同步和 GPU 内核提交的开销不可忽视。
5.5 GPU 性能干扰
为评估 HeteroLLM 对系统级图像渲染以及与其他 GPU 应用的干扰,我们通过与高性能移动游戏(《英雄联盟:激斗峡谷》)并发运行 PPL-OpenCL、Hetero-layer 和 Hetero-tensor 进行实验,游戏内所有图形设置保持默认值。
如图 18 所示,与游戏并发运行时,Hetero-layer 和 Hetero-tensor 的预填充速度分别下降 9.57%和 7.26%,而 Hetero-tensor(带游戏)甚至比 Hetero-layer(不带游戏)仍快 15.3%。游戏的帧率(FPS)不受 Hetero-layer 和 Hetero-tensor 执行的影响,稳定保持在 60 FPS,游戏内所有操作仍流畅。
相比之下,与 PPL-OpenCL 并发运行时,游戏的 FPS 显著下降(降至零),这是因为 PPL 运行时启动的 GPU 内核完全占用 GPU 提交队列,导致游戏的渲染任务无法在指定时间内完成。相比之下,Hetero-layer 和 Hetero-tensor 仅将一小部分计算负载分配给 GPU,为 GPU 留出足够能力及时处理游戏的渲染任务。
5.6 能耗
图 19 展示了 PPL-OpenCL、Hetero-layer 和 Hetero-tensor 在序列长度为 256 的 Llama-8B 预填充阶段的功耗和能耗。
- Hetero-layer 功耗最低,为 2.23W,主要因其大部分计算依赖 NPU。
- Hetero-tensor 的功耗仅比 Hetero-layer 高 23.2%,比 PPL-OpenCL 低 36.7%。
预填充阶段的总能耗由功耗和执行时间的乘积决定,Hetero-tensor 的预填充速度比 Hetero-layer 快 24.4%,比 PPL-OpenCL 快 2.72 倍。因此,Hetero-tensor 的能耗仅比 Hetero-layer 高 3.3%,而能效比 PPL-OpenCL 高 5.87 倍。
六、讨论
模型量化
HeteroLLM 采用 W4A16(仅权重)量化,在内存占用和计算精度之间取得平衡。W4A16 量化是实际部署中最广泛使用的方法,它在存储时对模型权重进行量化(INT4),计算时将其反量化为 FLOAT。相比之下,其他方法[47,59,63]需要将激活和权重从 FLOAT 量化为 INT,这可能会影响推理精度。
GPU 与 NPU 的共享内存
当前的移动 SoC(如苹果 M/A 系列、高通骁龙系列)支持 CPU、GPU 和 NPU 的统一地址空间。
在我们的实现中,已通过 OpenCL 成功建立 CPU 与 GPU 之间的共享内存,并通过 QNN API 建立 CPU 与 NPU 之间的共享内存。此外,通过使用“CL_MEM_USE_HOST_PTR”标志,我们还可以将 NPU 的共享内存映射到 GPU,从而建立 GPU 与 NPU 之间的共享内存。
我们建议移动 SoC 厂商提供原生 API,为所有异构处理器分配统一内存。
七、结论
本文介绍了 HeteroLLM,这是针对现代移动 SoC 中的异构处理器优化的最快 LLM 推理引擎。
我们深入分析了 GPU 和 NPU 的硬件架构,强调了 NPU 对张量形状敏感的性能特征。遗憾的是,现代 LLM 中的某些层(如 FFN-down 层)无法被 NPU 高效处理,形成显著瓶颈。
HeteroLLM 通过利用 GPU 弥补 NPU 的计算限制,缓解了这些效率问题,同时解决了 SoC 内存带宽未充分利用和静态图约束等挑战。此外,本文为设计更高效的边缘 AI 加速器和异构 SoC 提供了新见解。
参考文献
END
作者:SJTU、THU
来源:NeuralTalk
推荐阅读
- 图解Vllm V1系列6:KVCacheManager与PrefixCaching
- 【博客转载】C++/CUDA Data Alignment
- 【博客转载】CUDA Kernel Execution Overlap
- GigaTok借语义正则化统一视觉分词器,3B参数完胜VQ-GAN,刷新ImageNet纪录
欢迎大家点赞留言,更多 Arm 技术文章动态请关注极术社区嵌入式AI专栏欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。