Llama-2 的推理特性
Llama-2-70B 是 gpt-3.5 的一个诱人替代方案,但如果要寻找便宜的语言模型,那么偏离 OpenAI 的 API 可能并不值得。
在考虑价格和延迟时
相反,Llama 最适合以提示为主的任务,例如分类。Llama-2可能也适用于以下情况
- 你的工作负载没有提示 token(不直观,但我们稍后会解释)
- 你正在执行批处理作业
否则,gpt-3.5 应该更便宜、更快。
快速声明一下,使用 Llama 而不是 gpt-3.5 的一个原因是微调1。但在这篇文章中,我们只探讨成本和延迟。我没有将 Llama-2 与 GPT-4 进行比较,因为它更接近 3.5 级别的模型。基准测试性能也支持这一说法

图 1:GPT-3.5 在此处的所有基准测试中都优于 llama 2
我将通过比较在大致相似的延迟下服务 Llama-2-70B 与 gpt-3.5-turbo 的成本来证明这些断言。我们在 2 个 80GB 的 A100 GPU 上运行 Llama,因为这是将 Llama 放入内存所需的最低配置(使用 16 位精度)3。
在 2 个 A100 上,我们发现 Llama 的完成 token 价格比 gpt-3.5 更高。我们推测在 8 个 A100 上的价格具有竞争力,但代价是高得无法接受的延迟。
另一方面,对于提示 token,Llama 比 gpt-3.5 便宜 倍。
Transformer 数学入门
通过一些简单的数学计算,我们将展示 Llama-2 的以下内容。对于序列长度 和批量大小
来自模型参数数量的两倍,320 KB/s 是通过一些算术推导出来的。在下一节中,我们将解释如何得到这些数字。
还有其他论文和/或博客文章很好地解释了 Transformer 数学。对于推理,Kipply 的文章 4 是一个很好的参考。而且,我相信缩放定律 5 推广了用于 Transformer FLOPs 的简化方程。
为了验证这些数字,我们从 Llama 的架构细节开始。隐藏维度为 4096,注意力头数为 64,层数为 80,每个注意力头的维度为 128
计算模型 Flops
前向传递的 FLOPs 数量为 ,其中 是模型中参数的数量。我们模型中的每个参数都属于某个权重矩阵 。对于每个输入 token,每个矩阵在与表示该 token 的向量的矩阵乘法中只使用一次。
对于每个 ,我们将其左乘一个维度为 的向量 。此向量-矩阵乘法的总 FLOPs 为 6,即权重矩阵中条目数的两倍。Transformer 中所有权重矩阵的条目总数是参数总数 ,这使得总 FLOPs 为 (不计注意力机制)。
对于像 Llama 这样具有(相对)短序列的大型模型,注意力机制对 FLOPs 的贡献可以忽略不计。对于每一层和每个注意力头,注意力操作为
需要将一个 向量乘以一个 矩阵,即 flops。缩放因子和 Softmax 可以忽略不计。最后,将注意力向量乘以 V 需要额外的 FLOPs。将所有注意力头和层加起来,我们得到 MFLOPs。因此,对于我们最大的 8192 序列,注意力机制仍然只占总共 GFLOPs 中的 GFLOPs。它足够小,为了简单起见,我们忽略它。
完成比提示的内存需求更高
在生成token时,我们需要重新读取模型的所有权重和 KV 缓存来生成**每个**token。这意味着什么?要执行任何矩阵乘法,我们需要将每个矩阵的权重从 RAM 加载到 GPU 的寄存器中。如果有足够多的唯一矩阵,权重的实际加载将成为瓶颈,而不是矩阵乘法本身。因此,让我们比较token通过模型的路径,分别针对提示和完成。
通过 Transformer 生成 token 的内存路径
为了说明这一点,我们可以遵循一个简单的单层 Transformer 生成一批 token 的(非常粗略的)路径
- 我们读取输入嵌入矩阵 并计算批次中每个输入的相应嵌入向量。
- 我们从内存中读取每个 矩阵来计算每个输入的 (向量)。
- 我们执行注意力操作——这需要读取缓存的键和值。这会为每个输入返回一个向量。
- 我们从内存中读取 并将其与上一步的输出相乘。
- 我们将步骤 1 的输出与步骤 4 的输出相加,然后执行层归一化。
- 我们读取 并相乘得到第一个前馈层的输出。
- 我们读取 并相乘得到第二个前馈层的输出。
- 我们将步骤 5 的输出与步骤 7 的输出相加,然后执行层归一化。
- 我们读取非嵌入层,,然后进行矩阵乘法,得到批次中每个输入的词元对数概率。
- 我们对下一个词元进行采样,并将其反馈回步骤 1。
让我们计算内存需求。在步骤 1、2、4、6、7 和 9 中,我们读取了模型的所有参数大约一次。7 在步骤 3 中,我们读取了每个批次元素的 KV 缓存。在所有步骤中,我们读取的中间激活与模型大小相比可以忽略不计。因此,内存带宽需求是模型权重 + KV 缓存。随着我们增加批次大小,除了 KV 缓存之外,内存需求大致保持不变!我们稍后会回到这一点。请注意,这是**每个词元**的内存需求。
通过 Transformer 处理提示词元的内存路径。
在处理提示词元时,我们读取模型的所有权重一次,但会产生注意力机制的内存成本。考虑一批序列通过同一 Transformer 的大致路径。
- 我们读取输入嵌入矩阵 ,并计算批次中每个序列的相应嵌入矩阵。
- 我们从内存中读取每个 矩阵,以计算 (它们是矩阵)。
- 我们执行注意力操作。
- 我们从内存中读取 并将其与上一步的输出相乘。
- 我们将步骤 1 的输出与步骤 4 的输出相加,然后执行层归一化。
- 我们读取 并相乘得到第一个前馈层的输出。
- 我们读取 并相乘得到第二个前馈层的输出。
- 我们将步骤 5 的输出与步骤 7 的输出相加,然后执行层归一化。
- 我们读取非嵌入层 ,然后进行乘法运算,得到提示序列的词元对数概率。
在步骤 1、2、4、6、7 中,我们读取了模型的所有参数。在步骤 3 中,我们执行了注意力操作,使用 FlashAttention,所需的内存带宽远小于读取模型权重(对于合理的序列长度和批次大小)。在所有步骤中,我们读取激活,它们是与模型大小相比可以忽略不计的矩阵(对于合理的序列长度和/或批次大小也是如此)。8 请注意,这是**所有词元**的内存需求。
总之,提示处理的每个词元的内存需求明显小于生成词元,因为我们对提示的序列维度进行了矩阵乘法批处理!
模型权重所需的内存带宽。
使用 16 位精度的模型权重占用 GB 的内存。
KV 缓存所需的内存带宽。
KV 缓存的大小是神经网络中所有层的所有先前词元的所有头的所有键和值的大小,每个词元和批次元素为 MB。
Llama 2 决定移除多头注意力。但他们没有使用多查询注意力,而是使用了分组查询注意力,这提高了性能。这导致键和值的头部(或组)数量为 8 个(),而不是多头注意力的常规 128 个和多查询注意力的 1 个。
对于 个词元,KV 缓存的大小将是 。使用 16 位精度,即 KB。给定批次大小 ,我们得到 KB。
对于补全,这给出了每个词元的内存需求:
对于较短的序列/小批次,第一项占主导地位。否则,第二项要大得多。然而,由于我们只有 160GB 的内存,而模型占用了 140GB,因此在我们的实验中,KV 缓存对内存带宽的影响很小。
提示的内存带宽约为:
通信开销
为简单起见,我们忽略了通信成本,因为考虑模型并行会使事情变得非常复杂。我们可以合理地假设,它不会对我们的任何计算增加太大的减速(尤其是在我们只将 Llama 分布在 2 个 GPU 上的情况下)。
提示处理成本非常低
提示处理或*首个词元时间*是 Transformer 推理中最有效的部分,您应该预期价格会比 gpt-3.5 **降低 3 倍**。
对于一个具有 个参数和 长度提示的模型,处理提示的内存需求约为 字节,而计算需求为 FLOPs。由于 A100 可以处理 312 TFLOPs 的矩阵乘法和 2 TB/s 的内存带宽,因此对于序列长度 ,我们是受计算限制的。9
在 A100 上,FLOPs 利用率可能会在略低于 70% MFU 时达到最大值。这相当于大约 200TFLOPs。两张 80GB 的 A100 的成本约为 4.42 美元/小时10,即 美元/秒。Llama 的 FLOPs 需求为 TFLOPs/token。根据 2 个 A100 的总 FLOPs,我们可以计算每秒的 token 数。
价格为
与 gpt-3.5 的 **0.0015 美元** 相比,这简直是太便宜了!准确地说,价格降低了近 4 倍!
延迟也相当不错!在我们的 2 个 GPU 上,批量大小为 1,我们应该能够在 170 毫秒内处理 512 个 token,在 530 毫秒内处理 1536 个 token。
让我们用实际数字来验证这些说法。我们使用 huggingface 的 text-generation-inference 仓库的内部分支来测量 Llama-2 的成本和延迟。

正如我们所看到的,价格比 gpt-3.5 的 0.0015 美元/1k token *明显* 更好!看起来我们在较长序列的第一个 token 生成时间上略微落后,但解决方案非常简单。将 llama 并行化到 8 个 GPU(而不是 2 个)将使我们的速度提高近 4 倍,这意味着 llama-2 在提示方面优于 gpt-3.5!
生成 token 速度慢且成本非常高
理论上,在补全方面可以获得与 gpt-3.5 *竞争性的价格*,但在实践中,你可能会做得更差。
在生成 token 时,我们从受计算限制变为受内存限制。11 假设批量大小为 1,让我们确定可以实现的吞吐量。
每个 80GB A100 的峰值内存带宽为每个 GPU 2TB/s。然而,与 FLOPs 利用率一样,在推理工作负载中,你可能预计接近 1.3 TB/s(60-70%)。由于 KV 缓存对小批量来说可以忽略不计,因此我们在 2 个 A100 上的吞吐量将是
我们的新价格要差得多。以 0.0012 美元/秒 计算,我们的成本是……
对于 gpt-3.5 级别的模型来说,这个价格和速度太糟糕了!但请记住前面关于批量大小的说明。我们受到内存瓶颈的限制,因此可以增加批量大小而不会降低生成速度。批量越大,成本越低。
我们不能无限增加,因为我们的 KV 缓存最终会占用所有 GPU RAM。幸运的是,分组查询注意力有助于缓解这个问题。对于 个 token,批量大小为 ,16 位精度,我们的缓存将是 字节。在 4096 个 token 的情况下,批量大小为 1 时,这相当于 1.3GB 的内存。我们的 2 个 A100 的机器上有 160GB 的空间。我们的模型占用了其中的 135GB,只剩下 25GB 的空间用于 KV 缓存。由于内存存储方面还有一些其他低效问题,因此对于较长的序列长度,我们的最大批量大小约为 8。
考虑到(大约)8 倍的加速,我们可以预期价格为 **0.00825 美元/ 1K token**。这仍然比 gpt-3.5-turbo 差,但更接近了。对于较短的序列长度(总共 1k 个 token),我们应该能够将批量大小增加到 32,这意味着价格为 **0.00206 美元/ 1K token**。理论上,这与 gpt-3.5-turbo 具有竞争力。
另一个解决方案是增加 GPU 的数量。通过租用 8 个 80GB A100,我们获得 1.28TB 的内存。去除模型权重后,我们还有超过 1TB 的内存剩余用于 KV 缓存,这意味着批量大小可以大于 512 个 token。请注意,我们实际上不会看到成本降低 512 倍,因为 KV 缓存现在占用的内存带宽是模型大小的 8 倍,这意味着成本降低更接近 64 倍。
使用更多计算资源也可以解决延迟问题。GPT-3.5 的速度达到约 70 TPS。将模型分布在 8 个 GPU 上而不是 2 个 GPU 上应该会使我们的速度达到 token/秒。
我们在运行此实验时没有 8 个 A100,但让我们看一下 2 个 80GB A100 上的数据。
测量的生成性能

这些数字与根据内存带宽计算得出的预期值非常接近。
正如我们所看到的,增加批量大小会直接导致每 1K token 的价格几乎线性下降。然而,我们仍然与 GPT-3.5 的 0.002 美元/1K token 的定价相差甚远,尤其是在较长的序列长度下。
大批量大小意味着不可接受的延迟
使用大批量大小进行生成意味着价格与 gpt-3.5 具有竞争力,但它会增加第一个 token 的生成时间。随着我们增加批量大小,成本线性下降,但第一个 token 的生成时间也线性增加。
批量大小为 64 使我们的定价优于 gpt-4。但是,批量大小为 64 会给我们带来……
仅 512 个 token,首个 token 的时间就接近 3 秒!12 批大小为 64,3596 个 token 需要 20.1 秒。13 因此,Llama-2 相对于 OpenAI API 更合适的负载类型是
-
大型提示,几乎没有或没有生成的 token —— 处理纯提示非常简单。
-
使用少量或没有提示生成 token —— 我们可以将批大小调整到 ,并在不牺牲延迟的情况下获得与 gpt-3.5-turbo 相当的价格。
-
对延迟不敏感的离线批处理作业。
增加批大小需要持续的大负载,而大多数初创公司都不会有!对于大多数用户和大多数工作负载,使用量非常突发。当然,一个候选解决方案是按需自动扩展 GPU,但即便如此,您可能平均每个 GPU 预计只有 50% 的最大吞吐量——尤其是考虑到冷启动时间。
我们的建议是将开源模型用于提示繁重的任务,并将生成繁重的任务留给 gpt-3.5 等闭源模型。
量化
大多数量化方法都是有损的,这意味着性能会有一定程度的下降。我们很可能通过 8 位量化实现与之相当的性能,从而使所有计算出的数字降低 2 倍的价格!量化和不完美的利用率相互抵消,这意味着考虑到这两者,我们预计价格与我们测量的价格相似!
然而,大多数开源量化方法的目标是在少量/小型消费级 GPU 上轻松部署,而不是大规模优化吞吐量。
有几个开源库可以优化更低精度的量化,同时保持性能。然而,这些库针对在少量/小型非数据中心 GPU 上提供这些模型而不是大规模吞吐量进行了优化。具体来说,它们针对低批量推理情况(主要是批大小为 1)进行了优化。尽管提供了(最多)3-4 倍的加速,但这仍然相当于每 1k 个 token 0.017 美元的价格。
Bits and Bytes
Bits and Bytes 提供(实际上)无损量化,这意味着性能没有差异。然而,它的主要好处是减少内存使用而不是提高速度。例如,最近 NF4 表示的加速仅体现在矩阵乘法速度上,而不是推理吞吐量上。根据经验,人们似乎没有在这方面测量加速。 14
目前还不清楚它如何扩展到更大的批次。
llama.cpp
我认为 Llama.cpp 主要针对 Apple 硬件进行了优化。它们也支持 CUDA,并支持快速 4 位精度推理,但我怀疑这里的简单量化会导致性能显著下降。
此外,该库针对低批量情况进行了优化。
GPT-Q
GPT-Q 是另一个量化库。我还没有测试 GPT-Q,但计划这样做。希望我们能在这里看到价格降低 2 倍!
此外,该实现针对低批量情况进行了优化。此外,论文中报告的 >3 倍加速仅适用于 3 位量化,这对于我们的用例来说损失太大。
闭源模型究竟是如何更便宜的?
闭源模型使用多种方法来显著加快推理速度
量化
如前所述,有几种可靠的开源量化方法——但我怀疑 OpenAI 的量化实现针对更大的批次进行了更好的优化。
混合专家模型 (MoE)
人们普遍推测 GPT-4 使用了混合专家模型 15。如果 gpt-3.5-turbo 也使用了 MoE,那么为了获得相同级别的性能,您可以提供一个更小(因此更快)的模型
推测性采样
推测性采样是另一个有趣的技巧,它通过让一个较小的模型连续起草多个 token 来绕过语言模型的慢解码时间。 16。请注意,在极限情况下,这不会显着提高 吞吐量,但可以大幅减少延迟。作为参考,这个 仓库 实现了它的简化版本。
大规模推理的巧妙技巧
在大规模运行推理时,OpenAI 可能会做一些巧妙的事情,例如分配几个 8-GPU 节点来预填充一批请求,然后分配一个 8-GPU 节点来为该批请求生成 token。这将使他们两全其美,既可以使用 > 64 的批大小,又能看到极低的首个 token 时间。
总结
我们已经使用这些发现来指导我们何时/如何决定在 Anysphere 使用开源模型。
总而言之,我们发现将开源模型用于提示繁重的任务(例如 分类 或 重新排序)最有用
来 Anysphere 和我们一起工作吧!
我们正在构建 Cursor,一个 AI 优先的代码编辑器。从根本上重新构想开发环境时,我们必须解决许多非常有趣的问题。例如,以 OpenAI API 价格的一小部分微调和提供模型。17 或使用 OpenAI 的 API 设计 新的抽象 来创建复杂的链和代理。
我们是一个由 9 人组成的位于旧金山的小团队,并由 OpenAI 提供支持。如有兴趣,请通过 [email protected] 联系我们。
或者,如果您想讨论语言模型,请在 Twitter 上私信我。
附录
下表是 Llama-2-70B 延迟测量数据点以及一些其他计算指标的表格