AMD Ryzen AI MAX+ 395 上部署 llama.cpp:从 Vulkan 切换到 ROCm 的完整记录
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,需要先确认该数字代表什么:它可能是会话累计记录的总量,不一定等于单次发给模型的完整提示词长度。
排查时可重点确认:
- OpenClaw 是否会在请求前压缩、摘要或裁剪历史。
- 实际发送给 llama.cpp 的请求中,是否包含全部历史消息。
- 单次请求的提示词 token 数是否超过当前服务上下文容量。
- 超长历史是否需要由 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 Graphics2. 查看启动日志
启动时留意日志中是否出现 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,核心经验可以归纳为:
- 先验证系统层面的设备识别,再验证 llama.cpp 的设备识别。
rocminfo和llama-server --list-devices是两层不同的检查。 - 确认 ROCm 动态库路径。如果运行时找不到依赖,先核实实际安装目录和
LD_LIBRARY_PATH,不要盲目混用不同版本的库。 - 不要随意覆盖 GPU 架构。本机已能识别
gfx1151,不应无故套用其他显卡的HSA_OVERRIDE_GFX_VERSION值。 - 先用保守参数启动,再逐步提高上下文和批处理。本次 512K 上下文配置在 KV Cache 分配阶段 OOM,说明模型权重能加载并不代表任意上下文都能运行。
- 实际性能必须通过同条件测试比较。本次 ROCm 约 25 tokens/s、Vulkan 约 27 tokens/s,且 ROCm 内存占用少约 6–7GB;这些是当前测试观察,不是普遍结论。
- 声音差异应作为观察线索,而不是故障结论。Vulkan 的持续风扇声与 ROCm 的短促高频声可能对应不同负载表现,需结合温度、系统稳定性和对照测试进一步判断。
对于需要长对话历史的 OpenClaw 本地 Agent,除了推理后端本身,还应把单次请求 token 数、上下文窗口、历史压缩策略和 KV Cache 内存一起纳入设计。这样才能避免模型看似已成功启动,却在实际长会话中因上下文或内存需求而失败。
参考资料
llama.cpp 官方构建文档 — ROCm/HIP 后端构建说明、相关环境变量和运行配置。
GitHub
AMD ROCm AI Ecosystem:llama.cpp 推理说明 — Linux 下 ROCm 动态库路径及运行环境配置。
AMD ROCm AI Ecosystem