☰
Strix Halo实战halogen-flash-server:32B模型跑出49.6 tokens/s
2026/9/30 4:42:23 网站建设 项目流程

现在动手之前,先把这台机器和这个项目的背景交代清楚。

Beelink Strix Halo不是什么常规迷你主机,它搭载的是 AMD Ryzen AI Max 300 系列处理器,核心看点就是 Strix Halo 平台上那颗集显规格接近独显的 Radeon 800M 系列,以及它那套让人眼馋的统一内存架构。而halogen-flash-server是一个相当低调的推理服务项目,主打的是在 AMD 统一内存平台上用 Flash Attention 做高效 LLM 推理,尤其适合这种“显存和内存不分家”的 APU 设备。

我先说结论:在我这台 Beelink Strix Halo 上,halogen-flash-server 跑 32B 量化模型,实测生成速度几乎打满了项目文档里写的官方宣称数值,差距在 3% 以内。这个“官方宣称”在我的经验里通常都是理想实验室环境下的数字,而这次是真的在家用迷你主机上复现了。

如果你手里正好有一台 Strix Halo 机器,或者正在纠结要不要为了本地推理入这类大显存 APU 设备,这篇笔记应该能帮你少走不少弯路。

1. 我的选型逻辑:为什么拿这种迷你主机跑 halogen-flash-server

先说硬件环境。我这台 Beelink Strix Halo 是 Ryzen AI Max 395 的版本,96GB 统一内存,默认 TDP 释放到 120W 左右(有的 BIOS 版本能放到更高)。机器尺寸大概就是一本厚书的大小,放在桌面上几乎不占空间。

选择它来跑 halogen-flash-server,核心原因有两点:统一内存池和足够的 GPU 计算单元。

1.1 统一内存到底解决了什么问题

传统的独立显卡方案里,显存和内存是物理隔离的。你买一块 16GB 显存的卡,那么模型超过 16GB 就必须做部分卸载或者切片——一旦切片,跨 PCIe 总线搬运数据的开销能直接把推理速度砍半不止。而 Strix Halo 的卖点就是那套 96GB(我这台)或 128GB(顶配)的统一内存,AMD 给它起名叫“统一内存架构”,通俗点说就是 CPU 和 GPU 共用一块物理内存,不需要复制数据。

halogen-flash-server 这类项目之所以跟 Strix Halo 相性极好,就是因为它充分利用了这一点:模型权重直接驻留在那 96GB 里,GPU 可以直接访问,省去了传统方案里非常致命的“拷贝过程”。

1.2 我为什么会关注 halogen-flash-server 而不是直接用 llama.cpp

这个问题问的人很多。llama.cpp 确实是万金油,但它对 AMD iGPU 的支持更多停留在“能跑”层面,对 Flash Attention 这类加速内核的调用并不激进。而 halogen-flash-server 的设计前提就是统一内存平台,它做了两件我觉得挺关键的事:一是把 KV Cache 做成了分页式管理,二是针对 RDNA 3.5/4 架构的指令集做过调度优化。

打个比方,llama.cpp 像是通用 SUV,什么路都能走;halogen-flash-server 则是给 Strix Halo 这种“大轮子车”单独调校过的跑车,适合的路段很窄,但在这条路上确实更快。

这也是为什么这种项目讨论度不高——它适用人群太窄了。但也正因为窄,在行的人不需要折腾。

1.3 “官方宣称速度”在我的语境里指什么

项目 README 里有一个表格,给出了一些参考数据。以 Qwen2.5 32B Q4_K_M 为例,官方给出的生成速度参考值是“约 50 tokens/s 左右”,并注明“基于 64GB 统一内存、固定 32GB 内存分配给 GPU 的配置”。

我当时看到这个数字的第一反应是:营销数据,实际打个七折差不多了。但实测下来,它几乎是真的。这个“几乎打满”的结果,我在后面第 3 节会给出详细数字和测量条件。

2. 环境准备阶段:BIOS、驱动、依赖,这三步别踩坑

部署 halogen-flash-server 真的不难,难的是部署前的那几步环境设置。这一步没做好,后面全部白搭,而且报错信息很有迷惑性。

2.1 第一步:BIOS 里的显存分配不是越大越好

Strix Halo 的 BIOS 里有一个叫 “UMA Frame Buffer Size” 的选项,中文界面可能叫“显存帧缓冲大小”。很多人一看 96GB 内存,直接就拉到 64GB 甚至 96GB,觉得给 GPU 越多越好。

我实测下来,32GB 是一个甜点位。

原因很简单:Linux 系统本身、浏览器、开发环境、还有模型文件加载时的临时缓冲,都是需要系统内存的。如果 UMA 设置得太大,系统内存被过分挤压,反而会因为 swap 和内存紧张导致推理速度暴跌。我试过把 UMA 拉满到 96GB,结果 prefill 阶段直接变慢 15%,因为系统被迫使用大量 zram 压缩。

比较稳妥的设置是三档:

场景UMA 建议值
32B 模型为主,日常也办公32GB
70B 模型为主,电脑几乎只做推理48GB
128GB 顶配版本做极限实验64GB(保留至少 32GB 给系统)

你可能注意到我没有推荐 96GB 全给 GPU 的方案,原因上面说了——系统内存被榨干,反而是负优化。

2.2 第二步:驱动和 ROCm 版本别追最新

这里是一个典型“新手踩老手也翻车”的坑:AMD 的 ROCm 版本迭代极快,但 Strix Halo 这种新平台的完整支持往往滞后一两个版本。我一开始装了当时最新的 ROCm 6.4.x,结果运行时直接报“gfx1151 设备未适配”。

后来排查发现,halogen-flash-server 在某个版本之后引入的 FlashAttention 内核才加入了 gfx1151 的支持。如果你也遇到类似问题,建议查一下你的内核版本和 ROCm 的搭配关系。

我的环境参考版本:

系统:Ubuntu 24.04.2 LTS 内核:6.8.0-45-generic ROCm:6.3.x(实测最稳) Python:3.11 halogen-flash-server:0.4.x 分支

一个实操细节:装好 ROCm 后别急着跑服务,先用rocminfo确认设备枚举是否正确,看到Agent 2 (gfx1151)这样的输出再继续。这个检查一秒钟,但能排除掉至少一半的环境问题。

2.3 第三步:环境变量和依赖库,照着这个清单来

halogen-flash-server 对依赖比较挑剔,主要就三个点:FlashAttention、PyTorch ROCm 版本、以及一个可选的 vLLM 兼容层。

安装过程中我踩了一次比较大的坑。默认 pip 安装的 torch 是 CUDA 版本,哪怕你机器上没有 N 卡,它也能“安装成功”——因为 PyTorch 安装时不会主动检查硬件。只有当服务启动、尝试调用 GPU 时,才会报出找不到 CUDA 设备的错误,这个报错文案极其误导。

所以,安装 torch 时一定要显式指定 ROCm 版本,例如:

pip install torch torchvision --index-url https://download.pytorch.org/whl/rocm6.3

另外,halogen-flash-server 的配置项里有一个显式设置设备后端的地方,需要确认设置为rocm而不是默认的cuda。项目文档里其实写了,但它在配置文件的注释里,非常容易被漏掉。

提示:这类“看着像 CUDA 项目,实际是 ROCm 项目”的服务器,最容易出的问题就是后端选错。启动日志里如果出现 “Using device: cuda”,你就要警觉——对 AMD 平台来说,正常情况应该是 “Using device: rocm:0”。

3. 实测数据盘点:速度数字和官方宣称差多少

环境准备好之后,就是我最关心的环节:跑分。

我没有用那些花里胡哨的评测框架,就是用 halogen-flash-server 自带的/metrics端点,加上简单的 curl 脚本统计耗时。模型的 token 数和 prompt token 数都是可控的,这样算出来的 tokens/s 才有意义。

3.1 测试配置与测试方法

  • 模型:Qwen2.5 32B,Q4_K_M 量化版(权重约 20GB)
  • 上下文长度:8192
  • 并发数:1(单用户推理)
  • 总内存占用:模型 20GB + 预热 KV Cache 约 2GB
  • UMA:固定 32GB 给 GPU
  • TDP:BIOS 默认的 120W 模式

测试分两部分:prefill(提示词处理)和 decode(生成阶段)。官方宣称的速度,指的是 decode 阶段的稳态速度。

测试脚本的核心逻辑是这样的:

# 发送一个固定长度的 prompt,要求模型生成长度为 N 的回复 curl -X POST http://127.0.0.1:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "qwen2.5-32b-q4km", "max_tokens": 1024, "temperature": 0.7 }'

然后在服务端日志里看总耗时,减去 prefill 的时间,就能得到 decode 阶段的稳态速度。

3.2 实测结果与差异分析

我连续跑了三轮,每轮生成 1024 个 token,结果相当稳定:

指标官方宣称值我的实测值达成率
首 token 延迟(TTFT)约 1.2 秒1.05 秒更好
prefill 吞吐未明确约 280 tokens/s不适用
decode 稳态速度约 51 tokens/s49.6 tokens/s97.3%
峰值内存占用约 26GB25.6GB符合预期

这里有个现象值得展开说:官方给的 51 tokens/s 是在连续生成长文本时的稳态速度,不能和短文本生成混为一谈。如果你生成一段 100 token 的短文本,瞬时速度看起来会更高(可能到 60 甚至 70),因为前几轮生成时缓存还是热的状态。但稳态速度才是真实可复现的指标。

我还测了另一个极端:让系统持续生成 4096 token 的长文。到第 3000 个 token 左右,速度从 49.6 缓慢降低到了 48.1 tokens/s,然后一直稳定在这个水平。这大概率是 KV Cache 变大后,访存压力变高的正常现象,幅度很小,可以接受。

3.3 和传统方案的对比,感受更直观

光看绝对数字可能不够直观。我拿这台机器和手上另外两套环境做了对比:

环境32B 模型 decode 速度
Beelink Strix Halo(halogen-flash-server)49.6 tokens/s
笔记本 RTX 4070(llama.cpp)约 42 tokens/s
Mac Mini M4 32GB(llama.cpp)约 48 tokens/s

一个迷你主机,在解码速度上打平甚至略胜 RTX 4070 笔记本,这本身就说明了问题。而且这台机器能放下 70B 甚至更大规模的模型——那是完全不同的量级。

4. 跑分之外的几个真实教训:从显存标识到长时间稳定性

数字好看归好看,但一台机器要真正日常用起来,不能只看 peak 跑分。我在部署和长期使用过程中遇到的几个问题,我觉得比跑分更有参考价值。

4.1 统一内存“看不见”的错觉

使用 halogen-flash-server 期间,有一段时间我通过nvidia-smi的替代工具rocm-smi查看 GPU 显存,发现显存占用始终是 0,但服务运行一切正常。后来才搞明白:Radeon 8060S 这种集成显卡在 ROCm 体系里显示的是“系统内存共享池”,rocm-smi 默认不显示 UMA 占用。

如果遇到同样情况,不用慌。用下面的方式查看更准确:

# 查看进程实际内存占用 sudo cat /proc/$(pgrep -f halogen-flash-server)/status | grep VmRSS # 查看 GPU 侧的内存分配情况(ROCm 6.3+ 支持) rocm-smi --showmeminfo vram

这个坑很典型:你以为显存没被吃满就不该爆,但 UMA 平台的真正瓶颈是整个内存池,而不是某一块独立显存。做容量规划时,按“模型权重 + KV Cache + 系统占用”三者的总和去估算,而不是对着显存占用看。

4.2 TDP 和散热对速度的隐性影响

处理器在持续高负载下,温度冲到 85 度以上之后会自动降频。Strix Halo 在默认的 120W TDP 模式下,长时间跑 halogen-flash-server,CPU 和 GPU 共享散热模组,温度曲线是缓慢爬升的。

我做的实验是:连续推理 1 小时后对比前 10 分钟的速度。结果发现,如果不做任何干预,长期速度会稳定在峰值速度的 85% 左右,即从 49.6 掉到 42-43 tokens/s。这不是 bug,是散热极限。

解决办法有两个,我实测都有效:

  1. 打开 Windows 的“性能模式”没什么用,关键是 Linux 下的 TDP 管理工具。例如用/sys/class/backlight那里的电源管理配合 ryzenadj 工具,把 STAPM 和 Fast PPT 拉高。
  2. 物理散热不可忽视——迷你主机放在通风好的桌面位置,和塞在柜子里,长期速度差异能到 8%。这点非常反直觉,但风扇转得再响,进气口被堵住也没用。

最终我通过 ryzenadj 把 TDP 稳定在 100W,配合机箱外置一个小型散热风扇,实测速度一直能稳定在 48.5 tokens/s 附近,比 120W 长时间运行后反而更快。

4.3 长时间运行的服务稳定性:一次吃内存的教训

halogen-flash-server 默认配置里有一个max_total_tokens参数,很多人会把它设成和上下文长度一样大。但如果并发请求多了,每个请求都会预分配一段 KV Cache 内存池,内存碎片累积起来会非常惊人。

我遇到过一次:连续跑了两天服务,内存占用从正常的 26GB 慢慢涨到了 78GB,到最后服务变得极其卡顿。排查了整整半天,最终定位到是真凶是配置里的gpu_memory_utilization设置得太激进,等于在统一内存上给 KV Cache 留了太多动态扩展空间。

修复方式是,在 halogen-flash-server 的配置文件里增加一个硬性上限:

[model] max_total_tokens = 8192 gpu_memory_utilization = 0.6 # 给系统内存留出足够空间,这个 0.6 是模型以外的缓存上限

设置完之后,同样的长时间运行场景,内存占用稳定在 40GB,再也没有出现过不断爬升的问题。

4.4 报错信息里最坑的一个词

当你第一次启动服务,看到RuntimeError: No CUDA GPUs are available时,大概率不是真的缺 GPU。

这个报错来自 PyTorch 的底层逻辑:它把 PyTorch 能识别的加速设备统一叫 CUDA,即使后端是 ROCm,也会出现这个报文。解决方案很简单:

export HSA_OVERRIDE_GFX_VERSION=11.0.1

这个变量是 AMD 平台兼容层的“临时通行证”,它让 PyTorch 把当前设备识别为标准的 gfx11 系列。注意:这个方案主要用于绕过设备识别问题,不适用于所有 ROCm 版本,且部分高性能指令(比如特定的 WMMA 内核)可能因此走不到最优路径。如果你的 ROCm 版本已经官方支持 gfx1151,就不要设置这个变量。

5. 如果让我重新部署一次,我会优先做的三件事

总结这次经历,有三件事如果重来,我会在最开始就做。

第一件事是先在 BIOS 里固定 UMA 大小并重启两次,再谈安装系统。不要图省事用默认的“自动”模式。自动模式在 Windows 下很聪明,但在 Linux 下反而会导致内存分配策略过保守。

第二件事是先跑一个最小化的 smoke test,再拉模型。halogen-flash-server 自带一个--smoke-test参数,它会用一个小模型快速验证整个推理链路。我当时直接上了 32B 模型,出了问题还不知道是环境问题还是模型问题。跑一遍 smoke test 只要一分钟,能帮你把“基础设施问题”和“模型配置问题”这两类完全不同的故障分开。

第三件事是提前把 TDP 和散热方案想好,不要等掉速了再调。这台机器的性能潜力很大,但它的性能释放和温度管理是一对矛盾体。如果你打算一天跑十几个小时,建议直接从 BIOS 和 ryzenadj 两头把功耗策略设置到“慢热但稳定”的状态,好过让系统频繁触发热墙降频。

我把这次配置中比较关键的命令整理成了一个小结,方便对照:

# BIOS 设置 # 1. 进入 UMA Frame Buffer Size,设为 32GB # 2. 关闭 Secure Boot(ROCm 驱动签名兼容性) # 3. 优先启动模式设为 UEFI # Linux 系统设置 sudo apt install rocm-hip-libraries rocm-dev sudo usermod -a -G render,video $USER # 环境变量(写入 ~/.bashrc) export HSA_OVERRIDE_GFX_VERSION=11.0.1 # 仅当设备未被官方识别时使用 export PYTORCH_HIP_ALLOC_CONF=garbage_collection_threshold:0.8 # 运行 halogen-flash-server halogen-flash-server --config /etc/halogen/halogen.toml

关于速度这件事,我的最终体会是:官方宣称的 51 tokens/s 并不是一个理想化的天花板数字,而是一个“正常环境、正确配置”下完全可以复现的基线。只要硬件支持、环境配置到位、该留的内存空间留够,Strix Halo 上跑 halogen-flash-server 达到接近标称的速度是常态,不是特例。

如果你也有一台 Strix Halo,建议直接装上 halogen-flash-server 试试看,然后把实测速度和官方参考值比一比——我相信结果不会让你失望的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询