Eval bug: Using llama.cpp with ROCm produces garbage output with –split-mode layer

在多卡 ROCm/HIP 环境下用 llama.cpp 加载跨卡模型(尤其是 --split-mode layer )时出现乱码输出,问题通常不在模型本身,而在于多卡间的数据拷贝或 GPU 间通信路径。优先排查两项:一是主机 PCIe P2P/IOMMU(VT-d)是否干扰跨卡拷贝;二是 GPU 时

快速结论:在多卡 ROCm/HIP 环境下用 llama.cpp 加载跨卡模型(尤其是 --split-mode layer)时出现乱码输出,问题通常不在模型本身,而在于多卡间的数据拷贝或 GPU 间通信路径。优先排查两项:一是主机 PCIe P2P/IOMMU(VT-d)是否干扰跨卡拷贝;二是 GPU 时钟是否在层分割计算中频繁升降导致计算异常。

适用环境:Ubuntu 24.04.3 LTS、ROCm 6.4.3、llama.cpp build 6688 (898acba6)、HIP 后端、3× AMD Instinct MI50/MI60(gfx906)、2× Intel Xeon E5-2683 v4。另一反馈环境为 AlmaLinux 10.1、kernel 6.12 + ROCm 7.1 amdgpu 驱动、2× MI50(gfx906)、2× Xeon E5-2680 v4、llama.cpp 容器镜像 b9549/b8209/b11669。

最快修复方案:暂无确认的一步修复方案。Issue 中有两条被报告有效的路径:其一是在编译时加 -DGGML_CUDA_NO_PEER_COPY=On(会降低性能的规避手段,或直接关闭内核 PCIe P2P);其二是报告者在 BIOS 中关闭 VT-d 后乱码消失(另一反馈者关闭 VT-d 仅减轻未完全修复)。

注意事项:该问题被描述为部分 ROCm 主机平台上的已知缺陷,可能与主板 PCIe 实现或 GPU 电源状态相关,并非 llama.cpp 自身的 bug。关闭 VT-d 会影响虚拟化与设备直通;GGML_CUDA_NO_PEER_COPY 有性能代价;GPU 时钟锁定属于硬件层规避,重启后失效,需自行确认对功耗与稳定性的影响。

问题场景

用户在 ROCm/HIP 后端下用 llama-cli 加载跨多张 GPU 的大模型(如 gpt-oss-120b GGUF,--n-gpu-layers 999、--split-mode layer),期望获得正常生成结果,但输入 prompt 后直接输出乱码。同一用户反馈:当模型小到能放进单张卡、并设置 --split-mode none 时一切正常。

报错原文

Eval bug: Using llama.cpp with ROCm produces garbage output with --split-mode layer

# 附带的运行日志关键片段
ggml_cuda_init: found 3 ROCm devices:
  Device 0: AMD Instinct MI50/MI60, gfx906:sramecc+:xnack- (0x906), VMM: no, Wave Size: 64
  Device 1: AMD Instinct MI50/MI60, gfx906:sramecc+:xnack- (0x906), VMM: no, Wave Size: 64
  Device 2: AMD Instinct MI50/MI60, gfx906:sramecc+:xnack- (0x906), VMM: no, Wave Size: 64

原因分析

按 Issue 讨论,这属于影响部分 ROCm 平台的已知问题。有证据指向主机系统的 PCIe 硬件实现存在缺陷(另有反馈者定位到 VT-d/IOMMU 干扰),但确切根因尚未完全确定,结论是这并非 llama.cpp 本身的 bug。

另一名使用 2× MI50 的反馈者给出不同定位:其乱码源于 GPU DPM 电源状态。在层分割(layer split)模式下,两张卡交替空闲并计算,空闲卡会掉到低 DPM 状态(925 MHz),每生成一个 token 又切回高 P-state(1725 MHz),这一升降循环导致计算结果被破坏;把时钟固定在任意稳定档位后乱码消失。该反馈也指出 -sm row 的崩溃可能是另一种失败模式。

环境排查

  • 确认 ROCm 版本(本例 6.4.3,反馈环境另见 6.3.3 / 7.1.4)与 HIP 后端是否启用。
  • 确认 GPU 型号与架构(gfx906)、卡数及是否跨 PCIe root port、是否处于 PCIe bridge 芯片之后。
  • 确认 BIOS 中 VT-d/IOMMU 状态,以及内核是否启用了 PCIe P2P。
  • 确认 --split-mode 取值(layer / row / none)与 --tensor-split 配置。
  • 确认是否设置了 GGML_CUDA_NO_PEER_COPY、HSA_ENABLE_SDMA 等环境变量。
  • 观察多卡层分割时各卡的 pp_dpm_sclk 时钟是否在空闲与计算之间反复升降。

解决步骤

  1. 先用单卡运行验证基线:将模型放到单张卡并设 --split-mode none,确认单卡输出正常,以排除模型与构建问题。
  2. 可优先尝试:编译 llama.cpp 时加 -DGGML_CUDA_NO_PEER_COPY=On,或在系统中关闭内核 PCIe P2P,避开有缺陷的跨卡 P2P 拷贝路径。
  3. 可优先尝试:在 BIOS 中关闭 VT-d/IOMMU,然后重新运行并对比输出(反馈称可消除乱码,但另一环境仅部分缓解)。
  4. 检查 GPU 拓扑:若某些 GPU 位于 PCIe bridge 芯片之后,可尝试更换插槽使其不再经过该芯片。
  5. 排查 GPU 时钟(针对另一反馈者的 MI50 场景):以 root 将两张卡的 power_dpm_force_performance_level 设为 manual,并把 pp_dpm_sclk 限制到较低档位(如 0–7 或 0–6),使时钟在层分割时保持稳定,观察是否仍出现乱码。
  6. 层分割模式下若出现 “Memory access fault by GPU node” 类错误,注意该错误与乱码可能是不同失效模式;--split-mode row 在本例中始终失败,暂不作为可行方案。

验证方法

使用同一模型、同一 prompt、--temp 0 连续运行多次(反馈者用 20 次以上串行请求),检查输出是否仍有乱码、错字或 token 崩坏。同时对比单卡运行、独立双卡并行、倾斜 --tensor-split(如 30,1)等配置的结果;若调整后多次运行输出均正常,视为问题已规避。若输出仍异常,需继续排查 PCIe 拓扑与电源状态。

参考来源

ggml-org/llama.cpp #16424

lemonade-sdk/llamacpp-rocm #75

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 30393

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注