Author image

作者Aman

Llama-2 的推理特性

Llama-2 比你想象的要昂贵。在这篇文章中,我们将探讨为什么它通常比 gpt-3.5-turbo 更贵。

Llama-2-70B 是 gpt-3.5 的一个诱人替代方案,但如果要寻找便宜的语言模型,那么偏离 OpenAI 的 API 可能并不值得。

在考虑价格和延迟时

你不应该将 Llama-2 用于完成量大的工作负载

相反,Llama 最适合以提示为主的任务,例如分类。Llama-2可能也适用于以下情况

  1. 你的工作负载没有提示 token(不直观,但我们稍后会解释)
  2. 你正在执行批处理作业

否则,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 便宜 >3>3 倍。

Transformer 数学入门

通过一些简单的数学计算,我们将展示 Llama-2 的以下内容。对于序列长度 NN 和批量大小 BB

每个 token 的 FLOPS=140109FLOPs\text{每个 token 的 FLOPS} = 140 \cdot 10^9 \text{FLOPs}
内存带宽 / token=140GB/s+320NBKB/s\text{内存带宽 / token } = 140 \text{ GB/s} + 320\cdot N\cdot B \text{ KB/s}

140140 来自模型参数数量的两倍,320 KB/s 是通过一些算术推导出来的。在下一节中,我们将解释如何得到这些数字。

还有其他论文和/或博客文章很好地解释了 Transformer 数学。对于推理,Kipply 的文章 4 是一个很好的参考。而且,我相信缩放定律 5 推广了用于 Transformer FLOPs 的简化方程。

为了验证这些数字,我们从 Llama 的架构细节开始。隐藏维度为 4096,注意力头数为 64,层数为 80,每个注意力头的维度为 128

dmodel=4096 d_\text{model} = 4096 nh=64n_h = 64 nl=80n_l=80 dhead=128d_\text{head} =128

计算模型 Flops

前向传递的 FLOPs 数量为 2P\approx 2P,其中 PP 是模型中参数的数量。我们模型中的每个参数都属于某个权重矩阵 MRm×nM \in \mathbb{R}^{m \times n}。对于每个输入 token,每个矩阵在与表示该 token 的向量的矩阵乘法中只使用一次

对于每个 MM,我们将其左乘一个维度为 mm 的向量 xx。此向量-矩阵乘法的总 FLOPs 为 2mn2mn6,即权重矩阵中条目数的两倍。Transformer 中所有权重矩阵的条目总数是参数总数 PP,这使得总 FLOPs 为 2P2P(不计注意力机制)。

对于像 Llama 这样具有(相对)短序列的大型模型,注意力机制对 FLOPs 的贡献可以忽略不计。对于每一层和每个注意力头,注意力操作为

softmax(QTKdhead)V\text{softmax}\Biggl(\frac{Q^TK}{\sqrt{d_\text{head}}}\Biggr)V

QTKQ^TK 需要将一个 dheadd_\text{head} 向量乘以一个 dhead×Nd_\text{head} \times N 矩阵,即 2dheadN2d_\text{head}N flops。缩放因子和 Softmax 可以忽略不计。最后,将注意力向量乘以 V 需要额外的 2dheadN2d_\text{head}N FLOPs。将所有注意力头和层加起来,我们得到 4dmodelnlN=1.3N4\cdot d_\text{model}\cdot n_l\cdot N = 1.3 \cdot N MFLOPs。因此,对于我们最大的 8192 序列,注意力机制仍然只占总共 140140 GFLOPs 中的 10.510.5 GFLOPs。它足够小,为了简单起见,我们忽略它。

完成比提示的内存需求更高

在生成token时,我们需要重新读取模型的所有权重和 KV 缓存来生成**每个**token。这意味着什么?要执行任何矩阵乘法,我们需要将每个矩阵的权重从 RAM 加载到 GPU 的寄存器中。如果有足够多的唯一矩阵,权重的实际加载将成为瓶颈,而不是矩阵乘法本身。因此,让我们比较token通过模型的路径,分别针对提示和完成。

通过 Transformer 生成 token 的内存路径

为了说明这一点,我们可以遵循一个简单的单层 Transformer 生成一批 token 的(非常粗略的)路径

  1. 我们读取输入嵌入矩阵 WeW_e 并计算批次中每个输入的相应嵌入向量。
  2. 我们从内存中读取每个 Wq,Wk,WvW_q, W_k, W_v 矩阵来计算每个输入的 qi,ki,viq_i, k_i, v_i(向量)。
  3. 我们执行注意力操作——这需要读取缓存的键和值。这会为每个输入返回一个向量。
  4. 我们从内存中读取 WoW_o 并将其与上一步的输出相乘。
  5. 我们将步骤 1 的输出与步骤 4 的输出相加,然后执行层归一化。
  6. 我们读取 Wff1W_{ff_1} 并相乘得到第一个前馈层的输出。
  7. 我们读取 Wff2W_{ff_2} 并相乘得到第二个前馈层的输出。
  8. 我们将步骤 5 的输出与步骤 7 的输出相加,然后执行层归一化。
  9. 我们读取非嵌入层,WeTW_e^T,然后进行矩阵乘法,得到批次中每个输入的词元对数概率。
  10. 我们对下一个词元进行采样,并将其反馈回步骤 1。

让我们计算内存需求。在步骤 1、2、4、6、7 和 9 中,我们读取了模型的所有参数大约一次。7 在步骤 3 中,我们读取了每个批次元素的 KV 缓存。在所有步骤中,我们读取的中间激活与模型大小相比可以忽略不计。因此,内存带宽需求是模型权重 + KV 缓存。随着我们增加批次大小,除了 KV 缓存之外,内存需求大致保持不变!我们稍后会回到这一点。请注意,这是**每个词元**的内存需求。

通过 Transformer 处理提示词元的内存路径。

在处理提示词元时,我们读取模型的所有权重一次,但会产生注意力机制的内存成本。考虑一批序列通过同一 Transformer 的大致路径。

  1. 我们读取输入嵌入矩阵 WeW_e,并计算批次中每个序列的相应嵌入矩阵。
  2. 我们从内存中读取每个 Wq,Wk,WvW_q, W_k, W_v 矩阵,以计算 Qi,Ki,ViQ_i, K_i, V_i(它们是矩阵)。
  3. 我们执行注意力操作。
  4. 我们从内存中读取 WoW_o 并将其与上一步的输出相乘。
  5. 我们将步骤 1 的输出与步骤 4 的输出相加,然后执行层归一化。
  6. 我们读取 Wff1W_{ff_1} 并相乘得到第一个前馈层的输出。
  7. 我们读取 Wff2W_{ff_2} 并相乘得到第二个前馈层的输出。
  8. 我们将步骤 5 的输出与步骤 7 的输出相加,然后执行层归一化。
  9. 我们读取非嵌入层 Wu=WeTW_u = W_e^T,然后进行乘法运算,得到提示序列的词元对数概率。

在步骤 1、2、4、6、7 中,我们读取了模型的所有参数。在步骤 3 中,我们执行了注意力操作,使用 FlashAttention,所需的内存带宽远小于读取模型权重(对于合理的序列长度和批次大小)。在所有步骤中,我们读取激活,它们是与模型大小相比可以忽略不计的矩阵(对于合理的序列长度和/或批次大小也是如此)。8 请注意,这是**所有词元**的内存需求。

总之,提示处理的每个词元的内存需求明显小于生成词元,因为我们对提示的序列维度进行了矩阵乘法批处理!

模型权重所需的内存带宽。

使用 16 位精度的模型权重占用 270=1402 \cdot 70 = 140 GB 的内存。

KV 缓存所需的内存带宽。

KV 缓存的大小是神经网络中所有层的所有先前词元的所有头的所有键和值的大小,每个词元和批次元素为 320320 MB。

Llama 2 决定移除多头注意力。但他们没有使用多查询注意力,而是使用了分组查询注意力,这提高了性能。这导致键和值的头部(或组)数量为 8 个(ngn_g),而不是多头注意力的常规 128 个和多查询注意力的 1 个。

对于 NN 个词元,KV 缓存的大小将是 2ngnldheadN=1.6N1052n_gn_ld_\text{head} N = 1.6N \cdot 10^5。使用 16 位精度,即 320N320N KB。给定批次大小 BB,我们得到 320NB320\cdot NB KB。

对于补全,这给出了每个词元的内存需求:

内存/词元=140GB+320NBKB\text{内存 / 词元 } = 140 \text{ GB} + 320\cdot N\cdot B \text{ KB}

对于较短的序列/小批次,第一项占主导地位。否则,第二项要大得多。然而,由于我们只有 160GB 的内存,而模型占用了 140GB,因此在我们的实验中,KV 缓存对内存带宽的影响很小。

提示的内存带宽约为:

内存/词元=140NGB\text{内存 / 词元 } = \frac{140}{N} \text{ GB}

通信开销

为简单起见,我们忽略了通信成本,因为考虑模型并行会使事情变得非常复杂。我们可以合理地假设,它不会对我们的任何计算增加太大的减速(尤其是在我们只将 Llama 分布在 2 个 GPU 上的情况下)。

提示处理成本非常低

提示处理或*首个词元时间*是 Transformer 推理中最有效的部分,您应该预期价格会比 gpt-3.5 **降低 3 倍**。

对于一个具有 PP 个参数和 NN 长度提示的模型,处理提示的内存需求约为 2P2P 字节,而计算需求为 2PN2PN FLOPs。由于 A100 可以处理 312 TFLOPs 的矩阵乘法和 2 TB/s 的内存带宽,因此对于序列长度 N>156N > 156,我们是受计算限制的。9

在 A100 上,FLOPs 利用率可能会在略低于 70% MFU 时达到最大值。这相当于大约 200TFLOPs。两张 80GB 的 A100 的成本约为 4.42 美元/小时10,即 0.00120.0012 美元/秒。Llama 的 FLOPs 需求为 140140 TFLOPs/token。根据 2 个 A100 的总 FLOPs,我们可以计算每秒的 token 数。

22001012/140109=2.86103 token/秒2 * 200 * 10¹² / 140 * 10⁹ = 2.86 * 10³ token/秒

价格为

0.00042 美元/ 1K token

与 gpt-3.5 的 **0.0015 美元** 相比,这简直是太便宜了!准确地说,价格降低了近 4 倍!

延迟也相当不错!在我们的 2 个 GPU 上,批量大小为 1,我们应该能够在 170 毫秒内处理 512 个 token,在 530 毫秒内处理 1536 个 token。

让我们用实际数字来验证这些说法。我们使用 huggingface 的 text-generation-inference 仓库的内部分支来测量 Llama-2 的成本和延迟。

图 2:每个数据点代表不同的批量大小。对于提示 token,我们的定价总是比 gpt-3.5 好得多,但在延迟方面略微落后于 gpt-3.5 处理 3.6K token 的 0.4 秒。

正如我们所看到的,价格比 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 上的吞吐量将是

21.31012 字节/秒140109 字节/token=18.6 token/秒\frac{2 * 1.3 * 10¹² 字节/秒}{140 * 10⁹ 字节/token} = 18.6 token/秒

我们的新价格要差得多。以 0.0012 美元/秒 计算,我们的成本是……

0.066 美元/ 1K token

对于 gpt-3.5 级别的模型来说,这个价格和速度太糟糕了!但请记住前面关于批量大小的说明。我们受到内存瓶颈的限制,因此可以增加批量大小而不会降低生成速度。批量越大,成本越低。

我们不能无限增加,因为我们的 KV 缓存最终会占用所有 GPU RAM。幸运的是,分组查询注意力有助于缓解这个问题。对于 NN 个 token,批量大小为 BB,16 位精度,我们的缓存将是 3.2NB1053.2 \cdot N\cdot B \cdot 10^5 字节。在 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 上应该会使我们的速度达到 74.474.4 token/秒。

我们在运行此实验时没有 8 个 A100,但让我们看一下 2 个 80GB A100 上的数据。

测量的生成性能

图 3:对于所有数据点,我们测量生成 512 个 token 时的每个生成 token 的价格。

这些数字与根据内存带宽计算得出的预期值非常接近。

正如我们所看到的,增加批量大小会直接导致每 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 更合适的负载类型是

  1. 大型提示,几乎没有或没有生成的 token —— 处理纯提示非常简单。

  2. 使用少量或没有提示生成 token —— 我们可以将批大小调整到 >64>64,并在不牺牲延迟的情况下获得与 gpt-3.5-turbo 相当的价格。

  3. 对延迟不敏感的离线批处理作业。

增加批大小需要持续的大负载,而大多数初创公司都不会有!对于大多数用户和大多数工作负载,使用量非常突发。当然,一个候选解决方案是按需自动扩展 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 延迟测量数据点以及一些其他计算指标的表格

批大小提示 Token完成 Token首个 token 的时间完成时间Token/秒提示 TFLOPs/GPU提示内存带宽 / GPU提示 FLOPS 利用率提示内存利用率每 1k 提示 token 的价格每 1k 完成 token 的价格
11282420.08412.63619.151106.1561.3410.3400.894$0.00081$0.06412
21285120.11627.75118.450154.4781.2910.4950.861$0.00056$0.03328
41285120.21628.15418.186165.7061.2730.5310.849$0.00052$0.01688
11282420.08412.66119.114106.1221.3380.3400.892$0.00081$0.06425
21285120.11627.82418.402154.1961.2880.4940.859$0.00056$0.03337
41285120.21528.20518.153167.0741.2710.5350.847$0.00051$0.01691
15125120.21727.75218.449164.9961.2910.5290.861$0.00052$0.06656
25125120.39228.54317.938183.0681.2560.5870.837$0.00047$0.03423
45125120.73429.04217.630195.3451.2340.6260.823$0.00044$0.01741
15123040.22516.39318.545158.9401.2980.5090.865$0.00054$0.06622
85125121.44529.75317.208198.4021.2050.6360.803$0.00043$0.00892
85125121.46029.74017.216196.3441.2050.6290.803$0.00044$0.00892
165125123.08132.70815.654186.1491.0960.5970.731$0.00046$0.00490
165125123.03832.66115.676188.7761.0970.6050.732$0.00046$0.00490
165125123.06832.70815.654186.8871.0960.5990.730$0.00046$0.00490
325125126.36341.30212.396180.2560.8680.5780.578$0.00048$0.00310
325125126.63241.09912.458172.9310.8720.5540.581$0.00050$0.00308
110245120.39728.96117.679180.7271.2380.5790.825$0.00048$0.06946
110245120.39628.98217.666181.0171.2370.5800.824$0.00047$0.06951
210245120.73229.67417.254195.7591.2080.6270.805$0.00044$0.03559
410245121.47130.15916.977194.9041.1880.6250.792$0.00044$0.01808
810245123.01531.16716.428190.2231.1500.6100.767$0.00045$0.00934
1610245126.54135.11114.582175.3251.0210.5620.681$0.00049$0.00526
135955121.43034.21014.966175.9291.0480.5640.698$0.00049$0.08205
235955122.84134.96414.644177.1681.0250.5680.683$0.00049$0.04193
435955125.84635.79514.304172.1991.0010.5520.667$0.00050$0.02146
175841663.08113.64112.170172.3300.8520.5520.568$0.00050$0.10091
275845126.29643.48211.775168.6420.8240.5410.550$0.00051$0.05214
Anysphere制作
SOC 2 认证