Ollama vs. llama.cpp实测对比

TOOL Nov 3, 2024

大型语言模型 (LLM) 迅速改变了技术格局,但安全问题依然存在,尤其是在将私人数据发送给外部第三方方面。在这篇博文中,我们深入探讨了在本地和私人(即在自己的计算机上)部署 Llama 模型的选项。

我们在本地运行 Llama 3.1,并调查了不同版本和框架中的关键方面,例如速度、功耗和整体性能。无论你是技术专家还是只是对所涉及的内容感到好奇,都会发现有关本地 LLM 部署的见解。非技术读者可以跳到我们的摘要表进行快速概览,而具有技术背景的读者可能会喜欢深入了解特定工具及其性能。

要点
  • 运行 LLM:可以使用社区中广泛可用的工具和框架下载 LLM 模型并在私人服务器上本地运行。虽然运行最强大的模型需要相当昂贵的硬件,但较小的模型可以在笔记本电脑或台式电脑上运行。
  • 隐私和可定制性:在私人服务器上运行 LLM 可以增强隐私,并更好地控制模型设置和使用策略。
  • 模型大小:开源 Llama 模型有各种大小。例如,Llama 3.1 有 80 亿、700 亿和 4050 亿个参数版本。“参数”粗略定义为网络一个节点上的权重。更多参数可以提高模型性能,但会牺牲内存和磁盘大小。
  • 量化:量化通过将权重“四舍五入”为更少的有效数字来节省内存和磁盘空间——但会牺牲准确性。鉴于 LLM 中的参数数量庞大,量化对于减少内存使用量和加快执行速度非常有价值。
  • 成本:本地实施(参考 GPU 能耗)与基于云的解决方案相比具有成本效益。

1、动机:隐私和可靠性

在我们之前的一篇文章中,我们探讨了 LLM 背后的关键概念,以及如何使用它们通过 Langchain 等框架创建定制的聊天机器人或工具(见图 1)。在这样的方案中,虽然可以使用合成数据或混淆来保护数据,但我们仍然必须将数据发送到第三方外部,并且无法控制模型、其策略甚至其可用性的任何变化。一种解决方案是在私人服务器上运行 LLM(见图 2)。这种方法可确保完全隐私,并减轻对外部服务提供商的依赖。

私下实施 LLM 的担忧包括成本、功耗和速度。在本练习中,我们在改变 1. 框架(工具)和 2. 量化程度的同时运行 LLama 3.1,并比较框架的易用性、速度方面的最终性能和功耗。对于任何希望充分利用人工智能潜力同时保留对数据和资源控制权的人来说,了解这些权衡至关重要。

图 1 图表展示了聊天机器人或工具的典型后端设置,其中 ChatGPT(或类似模型)充当自然语言处理引擎。此设置依赖于快速工程来定制响应。
图 2 完全私有的后端配置图,其中所有组件(包括大型语言模型)都托管在安全服务器上,确保完全控制和隐私

2、量化和 GGUF 文件

在深入了解我们对所探索工具的印象之前,让我们首先讨论量化和 GGUF 格式。

量化是一种通过将权重和偏差从高精度浮点值转换为低精度表示来减小模型大小的技术。鉴于 LLM 拥有大量参数,这种方法对其大有裨益。例如,Llama 3.1 的最大版本包含惊人的 4050 亿个参数。量化可以显著减少内存使用量和执行时间,使这些模型在各种设备上的运行效率更高。有关量化类型的深入解释和命名,请查看此精彩介绍。概念概述也可以在此处找到。

GGUF 格式用于存储 LLM 模型,最近因分发和运行量化模型而广受欢迎。它针对快速加载、读取和保存进行了优化。与仅张量格式不同,GGUF 还以标准化方式存储模型元数据,使框架更容易支持这种格式,甚至将其作为常态。

3、分析的工具和模型

我们探索了四种在本地运行 Llama 模型的工具:

我们的主要重点是 llama.cpp 和 Ollama,因为这些工具允许我们开箱即用并快速高效地部署模型。具体来说,我们探索了它们的速度、能源成本和整体性能。对于模型,我们主要分析了量化的 8B 和 70B Llama 3.1 版本,因为它们在合理的时间范围内运行。

4、第一印象和安装

4.1 HuggingFace

HuggingFace 的 transformers 库和 Hub 在社区中广为人知且被广泛使用。它们提供了广泛的模型和工具,使其成为许多开发人员的热门选择。一旦使用 Python 设置了适当的环境,它的安装通常不会引起重大问题。归根结底,Huggingface 最大的好处是它的在线 hub,它允许轻松访问来自许多不同提供商的量化模型。另一方面,直接使用 transformers 库加载模型,尤其是量化模型,相当棘手。开箱即用,该库似乎直接对模型进行反量化,占用大量内存,使其无法在本地服务器中运行。

尽管 Hugging Face 支持使用 bitsandbytes 进行 4 位和 8 位量化和反量化,但我们最初的印象是需要进一步优化。高效推理可能根本不是它的主要关注点。尽管如此,Hugging Face 提供了出色的文档、庞大的社区和强大的模型训练框架。

4.2 vLLM

与 Hugging Face 类似,vLLM 易于安装,只需正确配置 Python 环境即可。但是,对 GGUF 文件的支持仍处于高度实验阶段。虽然我们能够快速设置它来运行 8B 模型,但尽管文档非常出色,但扩展至此仍然具有挑战性。

总体而言,我们认为 vLLM 具有巨大的潜力。但是,我们最终选择了 llama.cpp 和 Ollama 框架,因为它们具有更直接的兼容性和效率。公平地说,这里可以进行更彻底的调查,但考虑到我们在其他库中发现的直接成功,我们选择专注于这些库。

4.3 Ollama

我们发现 Ollama 非常棒。我们最初的印象是,它是一款用户就绪的工具,用于在本地推断 Llama 模型,易于使用,开箱即用。对于 Mac 和 Linux 用户来说,安装它很简单,Windows 版本目前处于预览阶段。Ollama 会自动检测您的硬件并无缝管理 CPU 和 GPU 之间的模型卸载。它拥有自己的模型库,可以自动下载模型并支持 GGUF 文件。虽然它的速度比 llama.cpp 稍慢,但即使在仅使用 CPU 的设置和笔记本电脑上,它也能很好地运行。

为了快速启动,安装后,运行 ollama run llama3.1:latest 将直接从命令行以对话模式加载最新的 8B 模型。

一个缺点是自定义模型可能有点不切实际,尤其是对于高级开发而言。例如,即使调整温度也需要创建一个新的聊天机器人实例,而该实例又会加载已安装的模型。虽然这是一个小小的不便,但它确实有助于在单个文件中设置自定义聊天机器人(包括其他参数和角色)。总体而言,我们认为 Ollama 是一种有效的本地工具,可以模仿云服务的一些关键功能。

值得注意的是,Ollama 至少在 Linux 机器上以服务形式运行,并提供方便、简单的命令来监控哪些模型正在运行以及它们在哪里卸载,并能够在需要时立即停止它们。社区面临的一个挑战是配置某些方面,例如模型的存储位置,这需要 Linux 系统的技术知识。虽然这对最终用户来说可能不是什么问题,但它可能会稍微损害该工具对于高级开发目的的实用性。

4.4 llama.cpp

llama.cpp 是我们在此分析中最喜欢的工具。正如其存储库中所述,它旨在以最少的设置和尖端性能在大型语言模型上运行推理。与 Ollama 一样,它支持在 CPU 和 GPU 之间卸载模型,尽管这不是开箱即用的。要启用 GPU 支持,您必须使用适当的标志编译该工具 - 具体来说, GGML_CUDA=on。我们建议使用最新版本的 CUDA 工具包,因为旧版本可能不兼容。

该工具可以通过从存储库中提取并编译来独立安装,这为运行模型提供了方便的命令行客户端。例如,你可以执行 llama-cli -p 'you are a helpful assistant' -m Meta-Llama-3-8B-Instruct.Q8_0.gguf -cnv。这里,最后一个标志直接从命令行启用对话模式。llama-cli 提供各种自定义选项,例如调整上下文大小、重复惩罚和温度,它还支持 GPU 卸载选项。

与 Ollama 类似,llama.cpp 有一个 Python 绑定,可以通过 pip install llama-cpp-python 安装。这个 Python 库允许进行大量自定义,使开发人员可以轻松根据特定客户需求定制模型。但是,与独立版本一样,Python 绑定需要使用适当的标志进行编译以启用 GPU 支持。

一个小缺点是该工具尚不支持自动 CPU-GPU 卸载。相反,用户需要手动指定要卸载到 GPU 上的层数,其余的将卸载到 CPU。虽然这需要一些微调,但这是一个简单易行的步骤。

对于像我们这样的具有多个 GPU 的环境,llama.cpp 提供了两种分割模式:行模式和层模式。在行模式下,一个 GPU 处理小张量和中间结果,而在层模式下,层被划分到 GPU 上。在我们的测试中,这两种模式都提供了相当的性能(见下文分析)。

5、我们的分析

从现在开始,结果仅涉及 llama.cpp 和 Ollama。

我们使用 Ollama 和 llama.cpp 对 70B 和 8B Llama 3.1 模型的速度和功耗进行了分析。具体来说,我们在 Quant Factory 中可用的各种量化中检查了每个模型的速度和每个 token 的功耗。

为了进行这项分析,我们开发了一个小型应用程序,在选择工具后对模型进行评估。在推理过程中,我们记录了速度(每秒 token 数)、生成的 token 总数、温度、GPU 上加载的层数以及响应的质量评级等指标。此外,我们在模型执行期间测量了 GPU 的功耗。在生成每个 token 后,立即使用脚本监控 GPU 功耗(通过 nvidia-smi)。推理结束后,我们根据这些读数计算平均功耗。由于我们专注于可以完全适应 GPU 内存的模型,因此我们只测量了 GPU 功耗。

此外,实验是在各种提示下进行的,以确保不同的输出大小,因此数据涵盖了广泛的场景。

6、硬件和软件设置

我们使用了一台相当不错的服务器,具有以下特点:

  • CPU:AMD Ryzen Threadripper PRO 7965WX 24 核 @ 48x 5.362GHz。
  • GPU:2x NVIDIA GeForce RTX 4090。
  • RAM:515276MiB-
  • OS:Pop 22.04 jammy。
  • 内核:x86_64 Linux 6.9.3–76060903-generic。

该设备的零售价约为 15,000 美元。我们之所以选择这样的设置,是因为它是一台不错的服务器,虽然远不及配备 8 个或更多 GPU 的专用高端 AI 服务器那么强大,但仍然功能齐全,代表了我们许多客户可能会选择的功能。我们发现许多客户不愿意一开始就投资高端服务器,而这种设置在成本和性能之间取得了很好的折衷。

7、速度

让我们首先关注速度。下面,我们展示了几个箱线图,描绘了几种量化的速度数据。每个模型的名称都以其量化级别开头;例如,“Q4”表示 4 位量化。同样,较低的量化级别会进行更多的舍入,从而降低尺寸和质量,但提高速度。

技术问题 1(箱线图提醒):箱线图显示中位数、第一和第三四分位数以及最小和最大数据点。晶须延伸到未被归类为异常值的最极端点,而异常值则单独绘制。异常值定义为超出 Q1 − 1.5 × IQR 和 Q3 + 1.5 × IQR 范围的数据点,其中 Q1 和 Q3 分别代表第一和第三四分位数。四分位距 (IQR) 计算为 IQR = Q3 − Q1。

7.1 llama.cpp

以下是 llama.cpp 的图表。图 3 显示了 QuantFactory 中所有具有 70B 参数的 Llama 3.1 模型的结果,而图 4 则描述了此处可用的具有 8B 参数的一些模型。70B 模型可以将最多 81 个层卸载到 GPU 上,而 8B 模型最多可以卸载 33 个层。对于 70B,对于 Q5 量化和更精细的量化,卸载所有层是不可行的。每种量化类型都包括卸载到 GPU 上的层数(括号中)。正如预期的那样,较粗的量化可产生最佳速度性能。由于行分割模式的表现类似,因此我们在此重点介绍层分割模式。

图 3 在 llama.cpp 下运行的具有 70B 参数的 Llama 3.1 模型,采用分割模式层。正如预期的那样,较粗的量化可提供最佳速度。卸载到 GPU 上的层数显示在每个量化类型旁边的括号中。具有 Q5 和更精细量化的模型无法完全适应 VRAM。
图 4 使用分割模式层在 llama.cpp 下运行的具有 8B 参数的 Llama 3.1 模型。在这种情况下,模型适合所有量化类型的 GPU 内存,较粗的量化可实现最快的速度。请注意,高速是异常值,而 Q2_K 的总体趋势徘徊在每秒 20 个令牌左右。

关键观察结果:

  • 在推理过程中,我们观察到一些高速事件(尤其是在 8B Q2_K 中),这是收集数据和了解其分布至关重要的地方,因为事实证明这些事件非常罕见。
  • 正如预期的那样,较粗的量化类型可产生最佳速度性能。这是因为模型大小减小了,从而可以更快地执行。
  • 对于不能完全装入 VRAM 的 70B 模型的结果必须谨慎对待,因为使用 CPU 也可能导致瓶颈。因此,在这些情况下,报告的速度可能不是模型性能的最佳表示。

7.2 Ollama

我们对 Ollama 执行了相同的分析。图 5 显示了 Ollama 自动下载的默认 Llama 3.1 和 3.2 模型的结果。除 405B 模型外,它们都适合 GPU 内存。

图 5 在 Ollama 下运行的 Llama 3.1 和 3.2 模型。这些是使用 Ollama 时的默认模型。所有 3.1 模型(特别是 405B、70B 和 8B(标记为“最新”))都使用 Q4_0 量化,而 3.2 模型使用 Q8_0 (1B) 和 Q4_K_M (3B)

关键观察结果:

  • 我们可以比较 Ollama 和 llama.cpp 上的 70B Q4_0 模型,Ollama 的速度略慢。
  • 同样,8B Q4_0 模型在 Ollama 下的速度比其 llama.cpp 对应模型慢,差异更明显 - llama.cpp 平均每秒处理大约 5 个令牌。

8、分析框架摘要

在讨论功耗和可租用性之前,让我们总结一下到目前为止我们分析的框架。

9、功耗和可租用性

此分析与将所有层放入 GPU 内存的模型特别相关,因为我们仅测量了两张 RTX 4090 卡的功耗。尽管如此,值得注意的是,这些测试中使用的 CPU 的 TDP 为 350 W,这提供了其在最大负载下的功耗估计值。如果将整个模型加载到 GPU 上,则 CPU 可能会将功耗保持在接近空闲水平。

为了估算每个令牌的能耗​​,我们使用以下参数:每秒令牌数 (NT) 和两个 GPU 的功耗 (P),以瓦为单位。通过计算 P/NT,我们得到以瓦秒为单位的每个令牌的能耗​​。将其除以 3600 可得出以 Wh 为单位的每个令牌的能耗​​,这是更常用的参考值。

9.1 llama.cpp

以下是 llama.cpp 的结果。图 6 说明了 70B 模型的能耗,而图 7 则重点介绍了 8B 模型。这些图显示了每种量化类型的能耗数据,图例中显示了平均值。

图 6 llama.cpp 下具有 70B 参数的 Llama 3.1 模型的各种量化的每标记能量。显示了行分割和层分割模式。结果仅与适合 GPU 内存中所有 81 层的模型相关
图 7 llama.cpp 下具有 8B 参数的 Llama 3.1 模型的各种量化的每标记能量。显示了行分割和层分割模式。所有模型都表现出相似的平均消耗

9.2 Ollama

我们还分析了 Ollama 的能耗。图 8 显示了 Llama 3.1 8B(Q4_0 量化)和 Llama 3.2 1B 和 3B(分别为 Q8_0 和 Q4_K_M 量化)的结果。图 9 显示了 70B 和 405B 模型的单独能耗,均采用 Q4_0 量化。

图 8 Ollama 下 Llama 3.1 8B(Q4_0 量化)和 Llama 3.2 1B 和 3B 模型(分别为 Q8_0 和 Q4_K_M 量化)的每令牌能量
图 9 Ollama 下 Llama 3.1 70B(左)和 Llama 3.1 405B(右)的每令牌能量,均使用 Q4_0 量化

10、成本摘要

我们不会单独讨论每个模型,而是重点讨论 llama.cpp 和 Ollama 之间可比较的模型,以及 llama.cpp 下具有 Q2_K 量化的模型,因为这是此处探讨的最粗略的量化。为了让您更好地了解成本,我们在下表中显示了每生成一百万个令牌(1M)的能耗估算值和美元成本。成本是根据德克萨斯州的平均电价计算的,根据该来源,该价格为每千瓦时 0.14 美元。作为参考,GPT-4o 的当前定价至少为每 100 万个代币 5 美元,GPT-o mini 的定价为每 100 万个代币 0.3 美元。

llama.cpp:

Ollama:

关键观察:

  • 使用带有 Q4_0 的 Llama 3.1 70B 模型,llama.cpp 和 Ollama 之间的能耗差别不大。
  • 对于 8B 模型,llama.cpp 比 Ollama 消耗更多的能量。
  • 考虑到此处描述的成本可以看作是运行模型的“裸成本”的下限。其他成本,例如运营、维护、设备成本和利润,不包括在本分析中。
  • 估计表明,与云服务相比,在私人服务器上运行 LLM 可以节省成本。具体来说,在适当的情况下,将 Llama 8B 与 GPT-45o mini 和 Llama 70B 与 GPT-4o 模型进行比较似乎是一笔潜在的好交易。
技术问题 2(成本估算):对于大多数模型,每 100 万个代币的能耗估计(及其变化)由“中位数±IQR”处方给出,其中 IQR 代表四分位距。只有对于 Llama 3.1 8B Q4_0 模型,我们才使用 “平均值±STD”方法,其中STD代表标准差。这些选择不是任意的;除Llama 3.1 8B Q4_0之外的所有模型都表现出异常值,在这些情况下,中位数和IQR的估计量更为稳健。此外,这些选择有助于防止成本出现负值。在大多数情况下,当两种方法产生相同的集中趋势时,它们会提供非常相似的结果。

11、最后的话

对不同模型和工具的速度和功耗的分析只是更广阔图景的一部分。我们观察到,轻量级或高度量化的模型往往难以保证可靠性;随着聊天历史的增长或任务变得重复,幻觉变得更加频繁。这并不出人意料——较小的模型无法捕捉较大模型的广泛复杂性。

为了克服这些限制,重复惩罚和温度调整等设置可以改善输出。另一方面,像70B这样的大型模型始终表现出强劲的性能,幻觉最少。然而,由于即使是最大的模型也并非完全没有不准确性,负责任和值得信赖的使用通常需要将这些模型与其他工具(例如 LangChain 和矢量数据库)集成。虽然我们在这里没有探讨特定的任务性能,但这些集成对于最大限度地减少幻觉和提高模型可靠性至关重要。

总之,在私人服务器上运行 LLM 可以提供 LLM 即服务的竞争性替代方案,具有成本优势和定制机会。


原文链接:Running Large Language Models Privately

汇智网翻译整理,转载请标明出处

Tags