1. 为什么选择 MI50 32G 搭建本地大模型环境
1.1 一张被低估的推理卡
MI50 是 AMD 在 2018 年底推出的数据中心级加速卡,基于 Vega 20 核心,7nm 工艺,16GB 和 32GB 两个版本。当年它的直接竞争对手是英伟达的 V100,但时过境迁,现在二手市场上 32GB 版本的 MI50 价格已经跌到了相当亲民的水平。对于想在家里跑大模型的人来说,这张卡有几个非常实在的优势:32GB 的 HBM2 显存、1TB/s 的显存带宽、支持 FP16 和 INT8 运算,功耗控制在 300W 以内。
我最初注意到这张卡是因为一个很现实的问题:消费级显卡的显存太少了。RTX 4090 有 24GB,已经算是消费级里的天花板,但跑一个 32B 参数的模型做量化推理,上下文稍微长一点就爆显存。而 MI50 的 32GB HBM2 显存,配合合理的量化方案,可以比较从容地跑 32B 甚至 70B 级别的模型。显存带宽 1TB/s 这个指标也很关键,大模型推理的瓶颈往往不在算力,而在显存带宽——模型权重需要从显存里反复读取,带宽越大,token 生成速度越快。
当然,这张卡不是没有代价。它的生态和英伟达的 CUDA 比起来差了一大截,驱动安装、框架适配、工具链支持都需要额外折腾。但如果你愿意花时间搞定这些,MI50 32G 的性价比在本地大模型推理这个场景里几乎没有对手。
1.2 这套方案适合谁
这篇文章面向的是有一定 Linux 基础、想用最低成本搭建本地大模型推理环境的开发者。你不需要是驱动开发专家,但至少得会用命令行、能看懂基本的报错信息、知道怎么查日志。如果你之前只在 Windows 上用过 Ollama 或者 LM Studio 这类一键工具,那这篇文章的内容会让你接触到更底层的东西,但收获也会更大——你会真正理解显卡驱动、计算框架、推理引擎这三层是怎么串起来的。
整个方案的核心链路是这样的:Ubuntu 系统 → AMD 显卡驱动 → ROCm 计算平台 → 推理框架(llama.cpp 或 vLLM)。每一层都有坑,而且坑和坑之间会相互影响。比如驱动没装对,ROCm 就识别不到卡;ROCm 版本和推理框架不匹配,编译就会失败。我会按照实际操作的顺序,把每一步的关键点和容易出问题的地方都讲清楚。
2. 系统准备与硬件检查
2.1 Ubuntu 版本选择
MI50 的驱动和 ROCm 支持对系统版本有比较明确的要求。根据我的实测,Ubuntu 22.04 LTS 是目前最稳妥的选择。ROCm 5.7 和 6.0 对 22.04 的支持最完善,社区里的踩坑记录也最多,遇到问题容易找到参考。Ubuntu 24.04 虽然更新,但 ROCm 的官方支持跟进较慢,有些版本甚至没有对应的 apt 源,需要自己编译,对新手不太友好。
如果你手头只有 Ubuntu 20.04,也可以用,但要注意 ROCm 6.x 已经不再支持 20.04 了,最高只能用到 ROCm 5.7。而 llama.cpp 的新版本对 ROCm 版本有一定要求,太老的版本可能编译不过。所以我的建议是直接上 22.04,省去很多麻烦。
安装系统时有一个细节要注意:不要选择“最小安装”。最小安装会缺少很多编译工具和内核头文件,后面装驱动的时候还得手动补,不如一开始就装完整版。另外,安装时建议勾选“安装第三方软件”,这样一些基础的固件和驱动会自动处理好。
2.2 硬件兼容性检查
在装系统之前,先把卡插好,开机进 BIOS 确认几件事。第一,Above 4G Decoding 必须开启,否则系统可能识别不到大显存设备。第二,Resizable BAR 如果主板支持,建议开启,对显存访问效率有好处。第三,确认 PCIe 插槽的供电能力,MI50 是双 8pin 供电,电源功率要留足余量,整机建议 750W 以上。
进入系统后,先用lspci确认卡被识别到了:
lspci | grep -i amd你应该能看到类似Advanced Micro Devices, Inc. [AMD/ATI] Vega 20 [Radeon Instinct MI50]的输出。如果什么都没看到,那说明硬件层面就有问题,先检查供电和插槽,不要急着装驱动。
还有一个容易被忽略的点:IOMMU 设置。有些主板默认开启 IOMMU,会导致 MI50 在直通或某些计算场景下出现异常。如果你遇到驱动装好了但计算任务报错的情况,可以尝试在 BIOS 里关闭 IOMMU,或者在 GRUB 里加amd_iommu=off参数。
2.3 系统基础配置
装完系统后,先做几件基础的事情。更新系统包:
sudo apt update && sudo apt upgrade -y安装编译工具和内核头文件:
sudo apt install -y build-essential dkms linux-headers-$(uname -r) git cmake这几样东西后面装驱动和编译推理框架都要用到。特别是linux-headers,版本必须和当前运行的内核完全一致,否则 DKMS 编译驱动模块会失败。你可以用uname -r确认当前内核版本,然后检查对应的头文件是否装上了。
另外,建议把用户加入video和render组,这样后面跑计算任务时不需要每次都sudo:
sudo usermod -aG video,render $USER改完组之后需要重新登录才生效。这个操作看起来不起眼,但如果你忘了做,后面跑推理的时候会遇到权限报错,排查起来很浪费时间。
3. AMD 显卡驱动与 ROCm 安装实战
3.1 驱动安装的两种路线
MI50 在 Ubuntu 下的驱动安装有两条路:一条是用 AMD 官方的amdgpu-install脚本,另一条是直接用 apt 安装 ROCm 源里的驱动包。我推荐第一条路,因为amdgpu-install会自动处理依赖关系和内核模块编译,省去很多手动步骤。
首先下载安装脚本。AMD 的官网有各个版本的amdgpu-install,对应不同的 ROCm 版本。对于 MI50,我建议用 ROCm 5.7 或 6.0 对应的安装脚本。下载下来之后:
sudo apt install -y ./amdgpu-install_*.deb sudo apt update然后执行安装。这里有一个关键选择:安装哪些组件。如果你只需要计算功能(跑大模型),不需要图形界面输出,可以用:
sudo amdgpu-install --usecase=rocm --no-dkms但如果你还要用这张卡接显示器,那就得加上graphics:
sudo amdgpu-install --usecase=graphics,rocm--no-dkms这个参数的意思是跳过 DKMS 模块编译。对于 MI50 这种老卡,有时候 DKMS 编译会出问题,跳过它反而更稳。但跳过之后,内核模块需要手动加载,后面会讲。
3.2 内核模块加载与验证
安装完成后,重启系统。重启后检查内核模块是否加载:
lsmod | grep amdgpu如果看到amdgpu相关的模块,说明驱动加载成功了。如果没有,手动加载:
sudo modprobe amdgpu然后检查 ROCm 是否能识别到设备:
rocminfo | grep -i "agent"你应该能看到 MI50 的设备信息,包括显存大小、计算单元数量等。如果rocminfo命令找不到,说明 ROCm 的运行时没装好,检查一下amdgpu-install是否完整执行了。
还有一个命令rocm-smi可以看显卡状态:
rocm-smi这个命令会显示温度、功耗、显存占用等信息。如果它能正常输出,说明驱动和 ROCm 的底层通信没问题。
3.3 环境变量配置
ROCm 装好之后,需要配置一些环境变量,否则后面的推理框架找不到 ROCm 的库。在~/.bashrc里加上:
export PATH=$PATH:/opt/rocm/bin export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/rocm/lib export ROCM_PATH=/opt/rocm然后source ~/.bashrc生效。这几个变量看起来简单,但如果你忘了配,编译 llama.cpp 的时候会报找不到hipcc或者libamdhip64.so,到时候再回头查很麻烦。
另外,如果你用的是 ROCm 6.0 以上版本,可能还需要设置HSA_OVERRIDE_GFX_VERSION。MI50 的 GPU 架构是gfx906,有些新版本的 ROCm 默认不支持这个架构,需要手动指定:
export HSA_OVERRIDE_GFX_VERSION=9.0.6这个变量在跑推理的时候特别重要,不设置的话可能会遇到no kernel image available的错误。
4. 推理框架选型与部署
4.1 llama.cpp 与 vLLM 的取舍
在 MI50 上跑大模型,主流的选择有两个:llama.cpp 和 vLLM。这两个框架的定位不同,适合的场景也不一样。
llama.cpp 的优势是轻量、编译简单、对硬件要求低。它支持 GGUF 格式的量化模型,可以把模型压缩到 4bit 甚至更低,32GB 显存跑 70B 模型也不是不可能。缺点是并发能力弱,适合个人使用或者小规模服务。在 MI50 上编译 llama.cpp 的 ROCm 后端,基本上就是cmake加几个参数的事,踩坑相对少。
vLLM 的优势是并发能力强、吞吐量高,适合做 API 服务。但它对 ROCm 的支持不如 CUDA 那么成熟,在 MI50 这种老架构上编译 vLLM 需要不少折腾。而且 vLLM 对模型格式有要求,通常需要 HuggingFace 格式的模型,显存占用也比 GGUF 量化要高。
我的建议是:如果你是个人使用,想快速跑起来看效果,先用 llama.cpp。如果你要做一个多人使用的 API 服务,再考虑 vLLM。这篇文章会以 llama.cpp 为主线,因为它在 MI50 上的成功率最高。
4.2 llama.cpp 编译与 ROCm 后端配置
从 GitHub 拉取 llama.cpp 的源码:
git clone https://github.com/ggerganov/llama.cpp cd llama.cpp编译的时候要指定 ROCm 后端。关键参数是GGML_HIPBLAS=ON和AMDGPU_TARGETS:
mkdir build && cd build cmake .. -DGGML_HIPBLAS=ON -DAMDGPU_TARGETS=gfx906 -DCMAKE_BUILD_TYPE=Release make -j$(nproc)AMDGPU_TARGETS=gfx906这个参数必须指定,否则编译出来的二进制可能不包含 MI50 的 kernel,运行时会报错。-j$(nproc)是并行编译,加快速度,但如果你内存比较小(比如 16GB),建议改成-j4,否则编译过程可能因为内存不足而中断。
编译完成后,用./bin/llama-cli --version检查一下。如果能看到版本信息,说明编译成功了。然后可以用一个小模型测试一下 GPU 是否被调用:
./bin/llama-cli -m /path/to/model.gguf -p "Hello" -n 32 -ngl 99-ngl 99的意思是把所有层都放到 GPU 上。如果输出正常且速度明显比 CPU 快,说明 ROCm 后端工作正常。
4.3 模型下载与量化选择
MI50 的 32GB 显存给了很大的模型选择空间。以 Q4_K_M 量化为例,不同参数规模的模型显存占用大致如下:
| 模型规模 | Q4_K_M 量化后大小 | 32GB 显存是否够用 | 推荐上下文长度 |
|---|---|---|---|
| 7B | 约 4.5GB | 非常充裕 | 32K |
| 14B | 约 9GB | 充裕 | 16K |
| 32B | 约 20GB | 够用 | 8K |
| 70B | 约 40GB | 不够 | - |
从表里可以看出,32B 模型是 MI50 32G 的甜点区。Q4_K_M 量化下模型占 20GB 左右,剩下的 12GB 可以留给 KV Cache 和上下文。如果你用 Q3_K_M 量化,70B 模型可以压到 30GB 左右,但精度损失会比较明显,适合对质量要求不高的场景。
下载模型推荐用huggingface-cli或者modelscope。国内用户用 modelscope 速度更快:
pip install modelscope modelscope download --model Qwen/Qwen2.5-32B-Instruct-GGUF --local_dir ./models下载完成后,确认文件是 GGUF 格式。如果不是,需要用 llama.cpp 自带的convert_hf_to_gguf.py脚本转换,然后再用llama-quantize量化。
5. 常见问题与避坑指南
5.1 驱动安装后的典型报错
问题一:rocminfo报hsa api call failure
这个错误通常是因为内核模块没加载或者权限不对。先检查lsmod | grep amdgpu,如果没有输出,手动modprobe amdgpu。如果加载失败,看dmesg | grep amdgpu的输出,通常是内核版本和驱动不匹配。解决办法是确认linux-headers版本和uname -r一致,然后重新安装驱动。
问题二:HSA_OVERRIDE_GFX_VERSION不生效
有些教程会让你设置HSA_OVERRIDE_GFX_VERSION=9.0.6,但设了之后还是报错。这时候要检查这个变量是否真的被 export 了。可以在命令行里echo $HSA_OVERRIDE_GFX_VERSION确认。另外,这个变量必须在运行推理程序之前设置,程序启动后再设是没用的。
问题三:编译 llama.cpp 时hipcc找不到
这说明 ROCm 的 bin 目录没在 PATH 里。检查~/.bashrc里的export PATH=$PATH:/opt/rocm/bin是否加了,然后source ~/.bashrc。如果还是不行,用绝对路径/opt/rocm/bin/hipcc试试,确认文件是否存在。
5.2 推理过程中的性能问题
显存够但速度慢
MI50 的算力在 FP16 下大约是 26 TFLOPS,跑 32B 模型的时候,如果 batch size 设得太大,计算会成为瓶颈。可以尝试减小 batch size,或者用--mlock把模型锁在内存里避免换页。另外,确认-ngl参数设成了 99,如果只设了部分层,剩下的层在 CPU 上跑会拖慢整体速度。
上下文一长就崩
这是 KV Cache 爆显存了。llama.cpp 默认的上下文长度可能设得比较大,而 KV Cache 的显存占用和上下文长度成正比。对于 32B 模型,8K 上下文的 KV Cache 大约占 2-3GB,16K 就翻倍。如果显存不够,要么减小上下文长度,要么用--cache-type-k q8_0把 KV Cache 量化到 8bit。
多卡并行的问题
如果你有两张 MI50,想用 tensor parallelism 跑更大的模型,llama.cpp 对多卡的支持比较有限。它可以用--split-mode row做层间拆分,但效率不如 vLLM 的 tensor parallelism。如果要多卡,建议直接上 vLLM,虽然编译麻烦,但多卡效率高很多。
5.3 系统层面的坑
内核自动更新导致驱动失效
Ubuntu 默认会自动更新内核,新内核可能没有对应的驱动模块,导致重启后 ROCm 失效。解决办法是锁定当前内核版本:
sudo apt-mark hold linux-image-$(uname -r) linux-headers-$(uname -r)或者安装dkms版本的驱动,让它在每次内核更新后自动重新编译模块。
电源管理导致降频
MI50 的默认功耗墙是 300W,但有些主板的 PCIe 供电不足或者电源老化,会导致卡在负载高的时候降频。可以用rocm-smi --showpower查看实时功耗,如果远低于 300W 而任务又很重,可能是供电问题。另外,rocm-smi --setperflevel high可以强制高性能模式,避免卡在省电状态。
散热问题
MI50 是被动散热设计,原本是给服务器风道用的。如果你把它装在普通机箱里,必须加装涡轮风扇或者暴力风扇,否则温度会迅速飙升到 90 度以上然后降频。我用的是两个 8cm 的涡轮风扇串联,用扎带固定在卡尾部,温度能控制在 75 度以内。这个投入不能省,否则卡的性能发挥不出来,长期高温还影响寿命。
6. 实际部署效果与调优经验
6.1 实测性能数据
在 MI50 32G 上跑 Qwen2.5-32B-Instruct 的 Q4_K_M 量化版本,我的实测数据如下:
| 指标 | 数值 |
|---|---|
| 模型加载时间 | 约 45 秒 |
| 显存占用(8K 上下文) | 约 23GB |
| 首 token 延迟 | 约 1.2 秒 |
| 生成速度(batch=1) | 约 18 tokens/s |
| 生成速度(batch=4) | 约 35 tokens/s |
| 功耗 | 约 250W |
这个速度对于个人使用来说完全够用。18 tokens/s 意味着生成一段 500 字的回答大约需要 30 秒,比等网页版 API 的响应快不少,而且没有网络延迟和隐私顾虑。
6.2 参数调优的几点经验
-ngl不要无脑设 99
虽然把所有层放 GPU 上通常最快,但如果显存紧张,留一两层在 CPU 上反而能避免爆显存导致的崩溃。具体留几层,可以用--n-gpu-layers逐步调整,观察显存占用和速度的平衡点。
--ctx-size按需设置
上下文长度不是越大越好。设成 32K 虽然能处理长文档,但 KV Cache 会吃掉大量显存,而且 llama.cpp 在超长上下文下的速度会明显下降。我的经验是,日常对话 4K 足够,处理文档 8K 够用,超过 16K 的场景很少。
--threads和--threads-batch
这两个参数控制 CPU 线程数。虽然推理主要在 GPU 上,但数据预处理和后处理还是用 CPU。设成物理核心数就行,不要设成逻辑核心数,超线程在这里帮助不大反而可能增加调度开销。
6.3 长期运行的稳定性建议
如果你打算让这个环境长期跑着做服务,有几个事情要做好。第一,用systemd把推理服务做成开机自启,避免每次手动启动。第二,加一个简单的监控脚本,定期检查rocm-smi的温度和显存,异常时发通知。第三,日志要保留,llama.cpp 的输出重定向到文件,方便出问题的时候回溯。
还有一个我踩过的坑:不要用nohup直接跑。nohup在终端关闭后虽然进程还在,但标准输出可能丢失,而且没法优雅重启。用systemd或者tmux更靠谱。我现在用的是tmux加一个启动脚本,简单直接,出问题的时候 attach 进去就能看日志。
最后说一个 MI50 特有的注意事项:这张卡没有官方的 Windows 驱动支持,所以如果你打算双系统,Windows 那边是用不了这张卡的。另外,MI50 的显示输出接口是 mini-DP,如果你要用它接显示器,需要转接线,而且有些主板在同时使用核显和 MI50 输出时会冲突,建议只用其中一个输出。