AMD Ryzen AI MAX+ 395 上部署 llama.cpp:从 Vulkan 切换到 ROCm 的完整记录

本文记录在 Ubuntu 24.04 LTS、AMD Ryzen AI MAX+ 395(Radeon 8060S)上部署 llama.cpp 的过程,重点包括 ROCm 运行环境、设备识别失败排查、启动参数、上下文长度与显存分配,以及 Vulkan 和 ROCm 的实际体验差异。

一、硬件与软件环境

这次测试使用的是 AMD Ryzen AI MAX+ 395 平台,集成 Radeon 8060S 显卡,运行 Ubuntu 24.04 LTS。推理引擎为 llama.cpp,模型采用 GGUF 分片量化格式。

|
项目

|

环境

操作系统

|

Ubuntu 24.04 LTS

|
|

处理器

|

AMD Ryzen AI MAX+ 395

|
|

GPU

|

Radeon 8060S Graphics

|
|

GPU 架构标识

|

gfx1151

|
|

内存

|

128GB 统一内存配置

|
|

推理引擎

|

llama.cpp

|
|

ROCm 版本

|

ROCm 10.0 环境

|
|

llama.cpp ROCm 预编译包

|

b11173

|
|

模型

|

Qwen3.8-Flash-Next-Uncensored-Q5_K_M-GGUF

|
|

服务端口

|

8080

|

测试模型的主分片文件:

/data/models/orcarouter/Qwen3.8-Flash-Next-Uncensored-Q5_K_M-guff/Qwen3.8-Flash-Next-Uncensored-Q5_K_M-00001-of-00003.gguf

注意:模型是分片 GGUF 文件,启动时应指定第一个分片文件,确保其余分片也在同一目录下且文件名、编号完整。

二、为什么从 Vulkan 尝试切换到 ROCm

最初使用 Vulkan 版 llama.cpp,设备能够被识别,也能正常运行模型。但在较长上下文和本地 Agent 场景中,仍希望尝试 ROCm 后端,观察其显存管理、运行稳定性与生成速度。

需要先说明:ROCm 不保证在所有 AMD 集成显卡上都比 Vulkan 快。 实际表现取决于 GPU 架构支持情况、构建版本、算子实现、模型结构、量化格式、上下文长度及推理参数。切换后应以设备识别、服务日志和实际速度测试为准,不宜仅凭后端名称判断性能。

三、安装 ROCm 版 llama.cpp

本次使用 llama.cpp 官方发布的 Ubuntu ROCm 10.0 预编译包:

https://github.com/ggml-org/llama.cpp/releases/download/b11173/llama-b11173-bin-ubuntu-rocm-10.0-x64.tar.gz

建议把推理工具放在单独的软件目录中,模型放在数据盘或统一模型目录,避免将大型模型文件与程序混放。

示例安装流程:

Bash

sudo mkdir -p /opt/tools
cd /opt/tools

# 将下载的压缩包解压到单独目录
sudo mkdir -p /opt/tools/llama-b11173
sudo tar -xzf llama-b11173-bin-ubuntu-rocm-10.0-x64.tar.gz \
  -C /opt/tools/llama-b11173

如果压缩包已经下载到其他目录,需先进入实际文件所在位置,或在 tar 命令中使用完整路径。解压后先查看目录内容:

Bash

ls -lah /opt/tools/llama-b11173

确认其中存在 llama-server 和相关后端动态库,再继续排查运行环境。

四、排查 ROCm 设备识别失败

1. 初次运行 --list-devices 没有列出 GPU

最初运行 ROCm 版的设备列表命令时,曾出现没有可用设备的情况。随后检查 ROCm 自身的设备枚举,rocminfo 已经能够看到 Radeon 8060S,架构为 gfx1151。

检查命令:

Bash

rocminfo

可筛选关键行:

Bash

rocminfo | grep -E 'Agent|Name:|gfx'

设备识别后,再检查 llama.cpp:

Bash

cd /opt/tools/llama-b11173
./llama-server --list-devices

最终识别结果为:

Available devices:
  ROCm0: AMD Radeon 8060S Graphics (98304 MiB, 98148 MiB free)

这一步很关键:rocminfo 能看到 GPU,说明 ROCm runtime 的设备枚举可用;llama-server --list-devices 也列出 ROCm0,才说明当前这份 llama.cpp 程序已经发现了 ROCm 设备。后续启动脚本应使用实际列出的设备名称,而不是凭经验猜测。

2. ROCm 动态库路径与 LD_LIBRARY_PATH

ROCm 版 llama.cpp 需要在运行时找到 ROCm 相关动态库。AMD 的 llama.cpp ROCm 文档指出,系统安装的 ROCm 库通常位于 /opt/rocm/lib,而该目录未必默认加入动态库搜索路径;因此需要根据本机安装路径配置 LD_LIBRARY_PATH。

AMD ROCm AI Ecosystem

先确认实际目录:

Bash

ls -ld /opt/rocm
ls -lah /opt/rocm/lib

如果本机 ROCm 安装在 /opt/rocm,可在当前终端临时设置:

Bash

export LD_LIBRARY_PATH="/opt/rocm/lib:${LD_LIBRARY_PATH}"

然后在同一个终端执行设备检查和服务启动:

Bash

cd /opt/tools/llama-b11173
./llama-server --list-devices

如果 ROCm 安装路径不是 /opt/rocm,应将上面的路径替换为本机实际目录。不要在没有确认路径的情况下,把某个虚构目录写入环境变量。

如果希望每次登录终端都生效,可以把经过确认的 export 行加入用户的 ~/.bashrc,然后重新加载:

Bash

source ~/.bashrc

但对于服务脚本,建议在脚本中明确设置所需环境变量,而不是完全依赖交互式 Shell 的配置。

3. 排查可能干扰设备枚举的变量

ROCm/HIP 环境中可能存在用于设备可见性或架构兼容性处理的变量。例如 HIP_VISIBLE_DEVICES 可限制进程可见的 GPU;HSA_OVERRIDE_GFX_VERSION 用于覆盖 GPU 架构识别,在某些特定兼容性场景下才需要。llama.cpp 文档也提到了这些变量的用途。

GitHub

对于本次已经能被 rocminfo 识别为 gfx1151、并最终被 llama.cpp 列为 ROCm0 的设备,不要为了“试试看”而随意覆盖架构版本。尤其不要把其他显卡的架构值照搬过来。

可以先检查当前终端是否残留了相关设置:

Bash

env | grep -E '^(LD_LIBRARY_PATH|HIP_VISIBLE_DEVICES|HSA_OVERRIDE_GFX_VERSION|ROCR_VISIBLE_DEVICES)='

如果发现以前调试时设置过不确定的覆盖值,可在当前终端临时清除,再重新检查:

Bash

unset HSA_OVERRIDE_GFX_VERSION
unset HIP_VISIBLE_DEVICES
unset ROCR_VISIBLE_DEVICES

./llama-server --list-devices

这只是用于排除环境变量干扰的测试步骤,并不意味着所有机器都应该永久清除这些变量。如果系统有意使用设备隔离或特定兼容性设置,应保留并核对其配置。

4. 检查程序依赖

若设备列表仍为空,或启动时提示找不到共享库,可以检查二进制文件的动态依赖:

Bash

cd /opt/tools/llama-b11173
ldd ./llama-server | grep -E 'not found|hip|roc'

如果出现 not found,应先修复相应依赖库路径或安装问题,再进行模型加载测试。不要通过随意复制其他版本的 ROCm 库来“补齐”依赖,因为不同版本的运行库混用可能引入更难定位的问题。

五、先做最小化 GPU 验证,再加载大模型

设备识别成功后,建议先确认服务端启动参数与本机版本兼容,再逐步增加上下文长度和批处理参数。尤其是大模型,不能把“GPU 可见”与“模型已完整卸载到 GPU”视为同一件事。

启动前可检查当前版本支持哪些参数:

Bash

cd /opt/tools/llama-b11173
./llama-server --help

本机设备名称已确认是 ROCm0,因此后续启动时可显式指定:

Bash

--device ROCm0

对于 GPU 卸载参数,使用当前版本帮助中实际列出的名称。不要将其他版本的参数拼写直接照搬到本机版本。

六、ROCm 启动脚本

下面给出一个适合当前目录布局的基准脚本。它显式指定 ROCm 设备、模型路径和动态库路径,先用相对保守的上下文与批处理参数验证稳定性。之后再根据实际请求长度和显存情况调整。

创建脚本:

Bash

sudo nano /opt/tools/llama-b11173/start-qwen38-rocm.sh

写入:

Bash

#!/usr/bin/env bash
set -euo pipefail

# llama.cpp 程序目录
LLAMA_DIR="/opt/tools/llama-b11173"

# 模型第一个 GGUF 分片
MODEL="/data/models/orcarouter/Qwen3.8-Flash-Next-Uncensored-Q5_K_M-guff/Qwen3.8-Flash-Next-Uncensored-Q5_K_M-00001-of-00003.gguf"

# ROCm 动态库路径:按本机实际安装位置确认
ROCM_LIB="/opt/rocm/lib"

# 服务监听地址与端口
HOST="0.0.0.0"
PORT="8080"

# 基准参数:先确认模型稳定加载,再逐项调大
CTX_SIZE="35000"
PARALLEL="1"
BATCH_SIZE="512"
UBATCH_SIZE="256"

# 明确指定本机已识别的 ROCm 设备
DEVICE="ROCm0"

# 加入 ROCm 动态库搜索路径
export LD_LIBRARY_PATH="${ROCM_LIB}:${LD_LIBRARY_PATH:-}"

# 避免继承未知的架构覆盖设置。
# 若本机确实需要设备隔离或架构覆盖,请按实际需求调整。
unset HSA_OVERRIDE_GFX_VERSION
unset HIP_VISIBLE_DEVICES
unset ROCR_VISIBLE_DEVICES

cd "$LLAMA_DIR"

exec ./llama-server \
  --model "$MODEL" \
  --alias "qwen38" \
  --host "$HOST" \
  --port "$PORT" \
  --device "$DEVICE" \
  --n-gpu-layers all \
  --ctx-size "$CTX_SIZE" \
  --parallel "$PARALLEL" \
  --batch-size "$BATCH_SIZE" \
  --ubatch-size "$UBATCH_SIZE" \
  --flash-attn on \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --jinja

赋予执行权限并启动:

Bash

sudo chmod +x /opt/tools/llama-b11173/start-qwen38-rocm.sh
/opt/tools/llama-b11173/start-qwen38-rocm.sh

启动参数说明

|
参数

|

用途

|

本次配置

--model

|

指定 GGUF 模型文件

|

第一个分片路径

|
|

--alias

|

设置 API 使用的模型别名

|

qwen38

|
|

--host

|

监听地址

|

0.0.0.0,允许局域网访问

|
|

--port

|

服务端口

|

8080

|
|

--device

|

指定推理设备

|

ROCm0

|
|

--n-gpu-layers all

|

尽可能将模型层卸载到 GPU

|

all

|
|

--ctx-size

|

服务上下文容量

|

基准 35000

|
|

--parallel

|

并行槽位数量

|

1

|
|

--batch-size

|

逻辑批处理大小

|

512

|
|

--ubatch-size

|

物理微批处理大小

|

256

|
|

--flash-attn on

|

启用 Flash Attention

|

on

|
|

--cache-type-k/v

|

KV Cache 的 K/V 缓存类型

|

q8_0

|
|

--jinja

|

启用 Jinja 模板处理

|

开启

|

参数是否受支持,以当前解压版本的 ./llama-server --help 为准。若某个参数在该构建中不存在,应先核对版本与帮助输出,而不是直接删改一串参数后盲目尝试。

为什么基准脚本没有加 --fit on

本次排障过程中曾出现参数拟合失败提示,指出 GPU 层数参数已被用户显式设置,导致拟合过程无法再自动调整。为了让启动行为更可预测,基准脚本选择明确指定 GPU 层数与上下文等参数,不同时启用自动拟合。

如果要测试自动拟合,应先按本机 --help 确认当前版本的拟合参数语义,再避免与手动设置的参数冲突。自动拟合并不是必需项,不能代替对内存需求的估算。

七、上下文长度过大导致 KV Cache 分配失败

本次最明显的一次启动失败,是把上下文长度设置为 512000。日志出现了两类重要信息:

n_ctx_seq (512000) > n_ctx_train (262144) -- possible training context overflow

以及:

cudaMalloc failed: out of memory
failed to allocate buffer for KV cache

这里的 cudaMalloc 是后端日志中出现的分配失败信息,不能据此认为当前运行的是 NVIDIA CUDA。关键问题是:当前配置下设备内存不足以完成所需的 KV Cache 分配。

1. 模型训练上下文与服务上下文不是一回事

日志显示模型训练上下文为 262144,即 256K tokens。将服务上下文设为 512K,超过模型记录的训练上下文长度,llama.cpp 因而给出 overflow 警告。

需要区分:

  • 模型训练上下文长度:模型训练或配置所记录的上下文窗口。
  • 服务上下文长度:推理服务为请求预留或允许使用的上下文容量。
  • 实际请求 token 数:某次请求真正传入模型的提示词与历史记录长度。

设置更大的服务上下文,并不意味着模型原生支持该长度,也不意味着硬件一定能分配对应 KV Cache。超过训练上下文的运行还涉及 RoPE 外推等设置及模型效果问题,不能只靠增大 --ctx-size 解决。

2. 上下文会明显影响 KV Cache 内存

KV Cache 的内存需求会随上下文长度、并行槽位、模型层数、KV 头配置和缓存精度等因素变化。即使模型权重能够装入 GPU,也不代表任意上下文长度都能启动。

本次 512K 配置不仅出现训练上下文超限警告,还在 KV Cache 分配阶段 OOM。实际使用时应从较小上下文开始,确认启动和生成正常,再按真实工作负载逐步提高。

3. OpenClaw 历史记录超过 256K 的处理思路

如果 OpenClaw 界面显示某段对话历史已经超过 256K tokens,需要先确认该数字代表什么:它可能是会话累计记录的总量,不一定等于单次发给模型的完整提示词长度。

排查时可重点确认:

  1. OpenClaw 是否会在请求前压缩、摘要或裁剪历史。
  2. 实际发送给 llama.cpp 的请求中,是否包含全部历史消息。
  3. 单次请求的提示词 token 数是否超过当前服务上下文容量。
  4. 超长历史是否需要由 Agent 层进行摘要或分段管理。

如果确实要把超过 256K 的完整内容一次性传给模型,需要另行验证模型长上下文配置、RoPE 方案和实际 KV Cache 容量,不能简单地把 --ctx-size 提高到 512K。

八、验证是否真正使用 ROCm GPU

服务成功启动后,还应确认它实际使用的是 ROCm 后端,而不是仅仅成功运行了 CPU 推理。

建议从以下几方面验证:

1. 再次检查设备列表

Bash

cd /opt/tools/llama-b11173
./llama-server --list-devices

确认输出包含:

ROCm0: AMD Radeon 8060S Graphics

2. 查看启动日志

启动时留意日志中是否出现 ROCm 设备选择、模型层卸载和 GPU buffer 分配等信息。只看到“服务启动成功”还不够,最好同时确认模型是否按预期卸载到 GPU。

3. 对照空闲与推理期间的系统资源

可以在模型空闲待机和生成回复期间分别查看系统资源、温度及可用的 GPU 监控信息。由于不同 AMD 平台与驱动版本提供的监控字段不完全相同,不建议仅用一个占用率字段判断 GPU 是否工作。

同时记录模型启动时间、首 token 延迟、生成速度和运行时内存变化。对比 Vulkan 与 ROCm 时,应保持模型、量化、上下文长度、批处理大小和并发设置尽量一致。

九、实际运行体验:速度、内存与声音

本次切换到 ROCm 版之后,模型可以成功启动并正常生成。测试中观察到的生成速度约为 25 tokens/s,而此前 Vulkan 测试约为 27 tokens/s。这属于当前这套软件版本、模型与参数下的实际观测,不应直接推广为所有 395 Max 设备的固定性能结论。

另一个变化是运行期间内存占用减少了约 6–7GB。这说明在本次测试配置中,ROCm 与 Vulkan 的内存使用表现存在差异,但还不能单凭这一点推断某个后端普遍更省内存。

声音表现的差异

在生成回复时,Vulkan 主要听到持续时间较长的风扇声;ROCm 则会短暂出现尖锐的高频电流声,听起来像电流啸叫。

这类短促高频声可能与负载变化引起的电感啸叫有关,但仅凭声音无法确认具体声源,也不能单独判定为驱动或硬件故障。建议在相同模型和参数下,分别比较空闲、模型待机、生成和停止生成时的声音,并观察是否伴随异常发热、异味、死机、重启或掉电。

如果出现异味、异常发热或系统不稳定,应停止推理负载并检查设备;不要为了消除声音而贸然调整电压或带电拆机。

十、常见问题与排查顺序

|
现象

|

优先检查

--list-devices 没有 ROCm 设备

|

先运行 rocminfo,确认系统层面是否能识别 GPU

|
|

rocminfo 能识别,llama.cpp 不能识别

|

检查是否为 ROCm 构建、动态库路径及继承的设备环境变量

|
|

启动时报找不到共享库

|

检查 LD_LIBRARY_PATH、实际 ROCm 安装路径及 ldd 输出

|
|

能识别 GPU,但加载模型失败

|

检查模型分片是否完整、GPU 层卸载设置和内存余量

|
|

KV Cache 分配失败

|

减小上下文、并发或批处理参数,逐项测试

|
|

服务启动成功但速度很慢

|

检查启动日志、GPU 卸载情况、实际请求长度及参数配置

|
|

OpenClaw 传入长历史后失败

|

核实单次请求 token 数、上下文上限及历史压缩策略

|
|

生成时出现短促高频声

|

做后端对照测试,观察是否与负载变化同步,并留意异常温度或系统状态

|

十一、总结

这次在 AMD Ryzen AI MAX+ 395 上尝试 ROCm 版 llama.cpp,核心经验可以归纳为:

  1. 先验证系统层面的设备识别,再验证 llama.cpp 的设备识别。rocminfo 和 llama-server --list-devices 是两层不同的检查。
  2. 确认 ROCm 动态库路径。如果运行时找不到依赖,先核实实际安装目录和 LD_LIBRARY_PATH,不要盲目混用不同版本的库。
  3. 不要随意覆盖 GPU 架构。本机已能识别 gfx1151,不应无故套用其他显卡的 HSA_OVERRIDE_GFX_VERSION 值。
  4. 先用保守参数启动,再逐步提高上下文和批处理。本次 512K 上下文配置在 KV Cache 分配阶段 OOM,说明模型权重能加载并不代表任意上下文都能运行。
  5. 实际性能必须通过同条件测试比较。本次 ROCm 约 25 tokens/s、Vulkan 约 27 tokens/s,且 ROCm 内存占用少约 6–7GB;这些是当前测试观察,不是普遍结论。
  6. 声音差异应作为观察线索,而不是故障结论。Vulkan 的持续风扇声与 ROCm 的短促高频声可能对应不同负载表现,需结合温度、系统稳定性和对照测试进一步判断。

对于需要长对话历史的 OpenClaw 本地 Agent,除了推理后端本身,还应把单次请求 token 数、上下文窗口、历史压缩策略和 KV Cache 内存一起纳入设计。这样才能避免模型看似已成功启动,却在实际长会话中因上下文或内存需求而失败。

参考资料

标签: AMD Ryzen AI MAX+ 395, ROCm, Vulkan

添加新评论