自首次发布以来,Llama.cpp 已得到扩展,不仅支持各种模型、量化等,还支持多个后端,包括支持 NVIDIA CUDA 的 GPU。在撰写本文之时,
Llama.cpp 在所有 GitHub 库中排名第 123 位
,在所有 C++ GitHub 库中排名第 11 位。
在 NVIDIA GPU 上使用 Llama.cpp 执行 AI 推理已经带来了显著的优势,因为它们能够以极高的性能和能效执行基础 AI 推理的计算,同时在消费设备和数据中心中也很普遍。NVIDIA 和 Llama.cpp 开发者社区继续合作,以进一步提高性能。本文介绍了最近通过在 Llama.cpp 中引入 CUDA Graphs 功能而实现的改进。
CUDA Graphs
GPU 会随着每一代产品的推出而不断加速,而且通常情况下,GPU 上的每个事件(例如内核或内存复制)都会很快完成。过去,每个事件都必须由 CPU 单独调度(启动),相关的开销可能会累积成为性能瓶颈。
CUDA Graphs 工具通过将多个 GPU 活动调度为单个计算图形来解决此问题。在上一篇文章“
Getting Started with CUDA Graphs
”中,我介绍了 CUDA Graphs 并演示了入门方法。在后续的博文“
A Guide to CUDA Graphs in GROMACS 2023
”中,我将介绍如何将 CUDA Graphs 成功应用于 GROMACS 生物分子模拟科学软件包。
使用传统流模型时,每个 GPU 活动都是单独调度的,而 CUDA Graphs 支持对多个 GPU 活动进行一致调度。这减少了调度开销。调整现有基于流的代码以使用图形相对简单。该功能通过几次额外的 CUDA API 调用将流执行“捕获”到图形中。
本文将介绍如何利用此工具,使用图形(而非流)来执行预先存在的 llama.cpp 代码。
在 Llama.cpp 中实现 CUDA Graphs
本节重点介绍现有代码中的开销,并描述如何引入 CUDA Graphs 来减少这些开销。
现有代码中的开销
图 1 显示了在引入 CUDA Graphs 之前,使用 Linux 在 NVIDIA A100 GPU 上执行 Llama 7B Q4 推理的现有代码的配置文件片段。它是通过
NVIDIA Nsight Systems
获得的。图中顶部配置文件中的每个 GPU 活动块都对应于对单个令牌的评估,其中缩放设置为显示正在评估的两个完整令牌。可以看到,每个令牌的评估(对应于与采样和计算图形准备相关的 CPU 活动)之间存在间隙。(我将在博文结束后返回到这一点)
计算图形也有频繁但非常微小的更改,其中每个令牌的某些节点(与 KV 缓存相关)的内核参数会发生变化。NVIDIA 开发了一种机制,仅在可重复使用的 CUDA Graphs 中更新这些参数。在启动每个图形之前,我们利用 CUDA Graphs API 功能来识别图形中需要更新的部分,并手动替换相关参数。