预算有限如何用A卡跑大模型:ROCm部署与推理微调实战
大模型跑起来到底有多烧钱我们团队年初立项的时候财务给的答复是预算有限你们自己想办法。一开始所有人想的都是N卡结果一问价格直接沉默了——一张24GB显存的N卡报价能顶上两个月的服务器托管账单。一个做过嵌入式的同事嘀咕了一句A卡是不是也能跑我嘴上说试试心里其实在想AMD的驱动和CUDA生态差了十万八千里这坑怕是踩不完。现在项目跑了大半年我可以负责任地说A卡方案在预算紧张的小团队里是一条值得认真计算的路但它绝对不是零成本的坦途。这篇文章把我们这趟“氪金之旅”从选卡、装机、搭ROCm环境到推理部署、微调、多机互联的全部记录都整理了出来。如果你手里预算有限又需要跑几十B参数级别的大模型或者正在纠结要不要上AMD显卡这篇文章应该能帮你省下不少查资料的功夫。1. 为什么最后把宝押在A卡上1.1 显存才是大模型硬件的“硬通货”入门大模型最容易犯的错是盯着算力看。结果买回来一张FP16算力很高的卡跑个7B模型才发现显存不够只能把一半层丢给CPU生成速度直接从每秒几十token掉到个位数。大模型推理时权重、KV Cache、激活值全部要住在显存里。我习惯用下面这张表来估算模型规模加载精度估算显存需求典型场景7B ~ 8BFP1614 ~ 16 GB单卡顺畅推理7B ~ 8BQ4量化5 ~ 7 GB消费级卡无压力14B ~ 32BQ4量化10 ~ 20 GB需要中高端卡70B ~ 72BQ4量化38 ~ 42 GB单卡基本无解70B ~ 72BFP16140 GB基本是服务器级别也就是说在选卡这个环节显存容量和显存带宽比所谓“TOPS”重要得多。A卡吸引我们的第一点就在这里同样24GB显存N卡要贵一大截同样价位A卡往往能给你更大的显存。1.2 三笔账单价、带宽、供货量我们当时的候选卡是RX 7900 XTX和RTX 4090。单看规格两者都是24GB、带宽都在960GB/s到1TB/s这个量级但价格差距非常明显。以那段时间的市场行情为例一张流通性较好的4090报价能到1.5万以上而7900 XTX新卡只要六千多二手甚至能压到五千出头。三笔账算下来单价同样24GB显存A卡只要三分之一到一半的钱。带宽7900 XTX的960GB/s和4090的1008GB/s差距不到5%跑大模型不至于产生代差。供货量4090在市场上经常缺货或者被炒价A卡渠道反而稳定说买就能买到。当然我们也看过Radeon PRO W7900这种48GB工作站卡但价格奔着四万去足够买两张7900 XTX了。48GB单卡固然省心但两张24GB卡在灵活性上更好小模型可以分开跑大模型可以拼起来明显更符合小团队“一块钱掰成两半花”的需求。1.3 A卡的天然短板生态绑定不是开玩笑的踩坑之前必须冷静地说一句A卡便宜是有原因的。AMD的ROCm生态比CUDA慢了不是一点半点很多教程默认你是N卡用户随便找个开源项目拉下来就是“CUDA error”。在大模型这个圈子新框架、新量化算法基本都是N卡优先A卡用户只能等项目适配。所以A卡方案的真实画像应该是团队里有熟悉Linux、愿意翻GitHub issue、能自己编译依赖的人。如果你们希望拿到硬件当天就能跑通 demo或者要给客户做“开箱即用”的交付那还是老老实实加预算上N卡。我们自己能走通这条路很大程度上是因为团队里有做过嵌入式Linux的老手对驱动和内核倒腾这件事有心理准备。2. 选卡与装机锁定了7900 XTX顺带劝退了几个人2.1 用显存和带宽筛掉了一大半A卡AMD消费级显卡家族里能正经跑大模型的其实没几张。我把市面上主流选项按显存和带宽排了一下显卡显存带宽我们的判断RX 6900 XT / 6950 XT16GB512GB/s跑14B还行32B就吃力RX 7900 GRE16GB576GB/s性价比尴尬显存是硬伤RX 7900 XT20GB800GB/s第二选择带宽比XTX低RX 7900 XTX24GB960GB/s最终选择显存和带宽均衡Radeon PRO W790048GB864GB/s好但贵性价比不划算这里多说一句显存带宽对大模型速度的影响比很多人想象的大。模型推理时每个token都要把权重从头到尾过一遍带宽直接决定上限。7900 XTX能跑得动核心就是24GB显存加960GB/s带宽这个组合在当时的A卡里没有更好的替代品。2.2 装机细节PCIe通道、电源、风道一个都不能省买卡只花了一半功夫装机才是真正踩坑的开始。PCIe通道我们用的是X670E主板加7950X处理器。消费级平台的PCIe通道本来就紧张第二根PCIe插槽到底走CPU还是芯片组、能不能拆成x8必须在买主板前查清楚。我们最后确认了双卡可以跑在PCIe 4.0 x8 x8才敢往下走。如果第二槽只能跑x4多卡之间的通信带宽直接腰斩跑分布式推理会很难受。电源7900 XTX的整卡功耗在355W左右两张卡加CPU和其余配件850W电源必然不够。我们直接上了1200W白金电源显卡供电老老实实用了三根独立8pin线。这里有个经验不要用那种一根线串两个头的显卡供电线A卡瞬时功耗很猛线材老化之后最容易出问题。风道两块三风扇卡紧挨着放上面那张卡进风直接被下面那张卡的热尾气挡住。我们最开始正面进风、背面出风的常规布局上卡温度轻松到95度后来把机箱侧板换成冲孔网、加了两把向下吹的风扇温度才压到85度以内。如果预算允许双卡直接上水冷是最省心的方案。2.3 驱动签名与注册表报错Windows下A卡的第一道坎群里有人问就为了省钱能不能在Windows上装A卡凑合跑我们试过结果遇到了一个很典型的报错设备管理器里显卡带黄色感叹号提示“Windows 无法验证此设备所需的驱动程序的数字签名”。还有一台机器直接报“Windows 无法启动这个硬件设备由于其配置信息注册表中的不完整或已损坏”。这两个错误基本可以锁定两个方向数字签名错误大概率是驱动没装对。要么装的是非WHQL签名版本要么驱动和卡不匹配。我们这批卡里有一张是二手收来的BIOS被刷过原版驱动签名对不上死活装不上。后来刷回官方BIOS、用DDU把旧驱动卸干净再装AMD官网的正式版驱动才恢复正常。注册表配置信息损坏一般是上一次驱动没卸载干净就强装新版注册表里留下了坏掉的设备配置项。办法是在设备管理器里把所有显卡相关设备连同“隐藏设备”全部删掉再用DDU进安全模式清理最后重新插卡。如果是正经想用A卡跑大模型我的建议是别在Windows上恋战。ROCm的完整生态主要在Linux上Windows下很多功能要么缺失要么不稳定。反正最终都要迁移不如直接从Linux开始。2.4 Linux下装机后的第一轮验证机器装好后先进BIOS开启“Above 4G Decoding”和Resizable BAR这对A卡显存寻址和性能都有帮助。然后登录Ubuntu先确认系统认卡lspci | grep -i radeon正常情况下能看到两张卡的信息。接着装上ROCm之后用rocm-smi看一眼rocm-smi能看到两张卡的型号、驱动版本、温度和显存占用说明硬件链路基本没问题。如果这里只显示一张卡先去查PCIe插槽和显卡供电线别急着怪系统。3. ROCm环境搭建从安装到自检3.1 为什么直接以Linux为基准ROCm对Windows的支持一直很有限很多组件只有Linux版本。我们统一使用Ubuntu 22.04 LTS理由是官方文档写得最全、PyTorch的ROCm轮子最齐全、Ollama和vLLM的AMD支持也是优先照顾这个版本。另外ROCm在Linux下对显卡的识别更“透传”不会像Windows那样频繁被驱动签名问题卡住。我们之后所有部署和微调都以Linux为基准Windows那台机器彻底沦为办公机。3.2 安装ROCm 6.x的完整步骤这里给一份我们当时能稳定复现的安装流程版本号以你拉取时的最新6.x为准# 1. 先装内核头文件和额外模块缺了后面编译必炸 sudo apt update sudo apt install linux-headers-$(uname -r) linux-modules-extra-$(uname -r) # 2. 下载amdgpu-install安装包 # 在 https://repo.radeon.com/amdgpu-install/ 下找到对应Ubuntu版本的deb wget repo.radeon.com/amdgpu-install对应的deb链接 # 3. 安装并执行部署 sudo apt install ./amdgpu-install_*_all.deb sudo amdgpu-install --usecaserocm # 4. 重启之后把用户加进render和video组 sudo usermod -aG render,video $USER注意--usecaserocm而不是--usecasegraphics后者会把桌面图形栈也装上纯计算节点没必要。装完一定要重启不然内核模块加载不完整。3.3 PyTorch的ROCm轮子版本必须对齐PyTorch官方的下载源里其实是有ROCm版本的wheel的关键是要让PyTorch、ROCm驱动的大版本一致。我们是ROCm 6.2配PyTorch的rocm6.2轮子pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/rocm6.2这里有一个特别容易误导人的点ROCm版的PyTorch里torch.cuda.is_available()返回的也是True。很多新手看到这个以为装的是N卡版其实底层走的是HIPPyTorch为了兼容把接口都包装成了CUDA风格。判断你是不是真的用上了A卡要看torch.version.hippython3 -c import torch; print(torch.__version__); print(torch.version.hip); print(torch.cuda.get_device_name(0))能打印出类似6.2.0的HIP版本号并且设备名是AMD显卡才算真正跑在ROCm上。3.4 环境自检三板斧每次换驱动、换PyTorch版本我都会按这个顺序排查rocminfo | grep -E Agent|Marketing Name rocm-smi python3 -c import torch; print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0))第一句看系统认不认卡第二句看驱动和温度第三句看PyTorch能不能分配显存。三步都过了再往上跑模型基本就不会是环境问题。还有个偷懒的办法直接用官方容器docker run -it --rm --device/dev/kfd --device/dev/dri --group-add video \ --ipchost rocm/pytorch:latest容器里的环境官方都配好了适合不想折腾的团队。但我们后来还是回退到裸机装因为容器里调Ollama和vLLM的GPU映射偶尔会出奇怪问题裸机排查起来更直接。4. 推理部署实测Ollama与vLLM的上手记录4.1 Ollama零门槛跑通指令微调模型Ollama对AMD的支持比我想象的好安装脚本一条命令就完事curl -fsSL https://ollama.com/install.sh | sh systemctl start ollama ollama run qwen2.5:14b第一次跑的时候我盯着显存占用看了半天确认模型确实加载到了7900 XTX上才放心。实测下来Qwen2.5-14B的GGUF Q4版本生成速度稳定在35到45 token/s之间已经能勉强满足我们内部测试的交互需求。如果ollama报“GPU not supported”之类的错多半是ROCm版本太老不认RDNA3核心。老版本驱动下可以临时指定一个兼容的GFX版本HSA_OVERRIDE_GFX_VERSION10.3.0 ollama run qwen2.5:14b新版本驱动下不建议乱设这个环境变量否则性能会下降。Ollama还支持把监听地址改成0.0.0.0这样局域网内其他同事的电脑都能直接访问不用给每台机器都装显卡。4.2 vLLM高吞吐场景的ROCm兼容性Ollama适合单机内部用真要做并发服务还得上vLLM。vLLM在ROCm上的支持已经进主线了但安装时有两个前提一是必须先生成好对应版本的ROCm版PyTorch二是vLLM、torch、ROCm三者的版本必须严格匹配。我们一开始图省事直接pip install vllm结果用的是CUDA版wheel启动模型就报错。后来老老实实按vLLM文档里的AMD安装说明走用带rocm后缀的wheel重新装问题才解决。启动参数和CUDA环境下的差别不大python -m vllm.entrypoints.openai.api_server \ --model Qwen/Qwen2.5-7B-Instruct \ --dtype float16 \ --gpu-memory-utilization 0.9要提醒的是--gpu-memory-utilization不要设1.0ROCm下显存碎片化比CUDA更明显设太高容易在长上下文下OOM。我们实测0.9是最稳的。还有一点vLLM的某些新算子比如部分FlashAttention变体在ROCm下需要AOTriton的版本和torch匹配否则会出现“算子不存在”的报错。这种问题没有技巧就是去GitHub issue里翻对应版本的解法或者等下一个release。4.3 显存不够时的组合拳量化加CPU offload两卡24GB听起来不少但碰到70B级别照样抓瞎。这时候就得靠量化。用Ollama/llama.cpp生态首选GGUF格式Q4_K_M量化后70B模型大约38到42GB两张24GB卡勉强能拼着跑。用vLLM生态则考虑AWQ或GPTQ这种整数量化吞吐比GGUF高一些。如果显存还是不够可以把模型的最后几层扔到CPU上用Ollama的num_gpu参数或llama.cpp的--n-gpu-layers来控。但CPU offload只适合应急一旦超过一半层在CPU上生成速度会急剧下滑还不如直接换小一号的模型。4.4 实测数据一张7900 XTX上的参考数字下面是我们压测时记录的大致数据受温度、量化版本、输入长度影响会有浮动但量级可以参考模型精度/量化速率参考Qwen2.5-7B-InstructGGUF Q470 ~ 90 token/sQwen2.5-14B-InstructGGUF Q435 ~ 45 token/sQwen2.5-32B-InstructGGUF Q415 ~ 20 token/sQwen2.5-7B (vLLM)FP16并发4路时约40 token/s单独一张7900 XTX跑7B模型是绰绰有余的跑32B属于“能跑但不算快”。如果要服务化7B配vLLM是性价比最高的组合。5. 微调实战QLoRA在A卡上的九九八十一难5.1 为什么全参微调第一轮就被否了团队最初的想法是对一个70B模型做领域微调结果预算一算就放弃了70B全参微调动辄需要8张A100级别显卡就算租云都肉疼。于是回到现实先做7B和14B模型的LoRA/QLoRA微调。LoRA的思路是冻结原模型权重只训练一小部分低秩矩阵显存需求直接降一个数量级这才是小团队用消费卡微调的正确姿势。5.2 bitsandbytes的ROCm补丁是头号拦路虎QLoRA之所以省显存靠的是把模型权重4-bit量化后加载这就离不开bitsandbytes库。问题是bitsandbytes官方repo默认只出CUDA轮子ROCm下直接装会报“CUDA error: no kernel image is available for execution on the device”这类错。我们当时的解决办法是改用社区维护的bitsandbytes ROCm分支。网上有专门的fork会针对ROCm版本编译出对应wheel找对版本pip install进去就能替代。这个坑花了我们整整一天期间还试过自己编译源码结果被一连串依赖问题劝退。如果你的ROCm是6.2务必装标注了rocm6.2的bitsandbytes轮子版本差一个字母都跑不起来。5.3 微调参数与显存优化细节分支搞定之后训练参数反而没什么神秘。我们最终稳定运行的LoRA配置是LoRA rank 16alpha 32目标模块为q/k/v/obatch size 1梯度累积 32等效batch size 32序列长度512到1024过长会让激活值暴涨开启gradient checkpointing显存能省出将近一半优化器用AdamW精度用FP16这里有个A卡特有的坑ROCm下FP16比BF16稳定得多。我们试过BF16某些算子在RDNA3上会随机崩掉跑几小时训练直接中断FP16就没这个问题。虽然BF16在理论上更稳但实际以稳定为先。训练7B模型QLoRA的显存峰值大概在10GB以内单张7900 XTX就能跑训练速度大约每步2秒左右一整个晚上能跑完一个epoch。我们用rocm-smi实时监控显存和核心温度发现训练时的热点主要集中在显存控制器核心利用率反而不高这也印证了大模型训练对带宽的需求。5.4 效果验收别只看loss微调结束之后验证环节更容易翻车。我们当时用过一段固定测试集包含领域问答、格式要求、拒绝回答三类样本用vLLM搭的OpenAI兼容接口批量做推理评估。这里有个经验只看训练loss下降不可靠必须看验证集上的生成质量。我们有一次训练loss降得漂亮结果发现模型在格式要求上全部翻车后来一查是训练数据里格式标签写得不统一模型学歪了。数据清洗这一关比调参更重要。把原始文本统一成同一种对话模板答案里不该出现的标点和换行全部清理掉模型效果会立刻上一个台阶。6. 多卡多机A卡集群是省钱还是烧钱6.1 RDNA卡的互联短板没有xGMIP2P基本是摆设买了两张7900 XTX之后我们理所当然地想搞多卡并行。结果一查资料心凉了半截RDNA系列没有xGMI互联两张卡之间走的是PCIe总线而且ROCm下RDNA卡的P2P点对点支持很有限。我们用rocm-bandwidth-test测了一下跨卡通信带宽只有正常PCIe水平和Instinct系列那种动辄几百GB/s的互联完全不是一个量级。这带来的直接后果是张量并行Tensor Parallelism这种需要频繁AllReduce的并行方式在RDNA双卡上基本跑不出好效果通信时间比计算时间还长。我们试过一次vLLM的tensor parallel2吞吐不升反降最后只能放弃。6.2 多机推理llama.cpp RPC反而成了实用方案既然卡间通信不行我们就把思路转到机器间。llama.cpp新版本把RPC功能合并进来了可以在第二台机器上起一个RPC服务主节点负责加载模型并把不同层分派到不同机器。每台机器只处理自己那几层的计算机器之间传的只是中间激活值。算一笔账就明白了假设模型hidden size是8192FP16每个数占2字节每过一个机器边界每个token只需要传8192×216KB的激活数据。哪怕每秒生成上百token网络流量也只有几MB/s千兆内网都能扛住。我们就是用一台旧工作站加一张二手A卡和主节点组成双机把70B Q4模型拼起来跑速度大概8到12 token/s。群里同事说“能用但着急的时候想砸键盘”。具体启动方式每个版本不太一样拉取代码后先看--help主节点和RPC从节点之间要用同一版本编译产物否则协议对不上会直接握手失败。6.3 多卡微调的窘境数据并行可以张量并行很难微调环节我们也尝试过多卡。PyTorch在ROCm下的分布式后端虽然写的是nccl底层实际走的是AMD的RCCL实现所以torchrun --nproc_per_node2这套命令在ROCm下能用。我们把7B LoRA的数据切成两份两张卡各训一份然后用梯度累积同步相当于数据并行。效果还算可以训练吞吐相比单卡提升不到1.6倍毕竟通信开销在那里。但张量并行是不敢想了除非你愿意花大钱上Instinct系列或者等ROCm对RDNA互联做更多优化——后者目前看不到时间表。7. 最后盘一下账7.1 我们最终花了多少钱列一张不算精细但真实的账单项目配置估算费用显卡RX 7900 XTX × 2约1.3万CPU/主板7950X X670E约6000内存DDR5 128GB约3000电源/散热/机箱1200W白金 风道改造约3000存储4TB NVMe约2600粗算下来不到3万。如果换成一张正经能跑70B的N卡光显卡就不止这个数。A卡方案省下来的钱足够我们再买一台同配置的机器做多机测试。7.2 给后续团队的六条建议项目收尾的时候我把踩过的坑整理成六条建议希望后面的人少走弯路先确定模型量级再买卡。只跑7B一张16GB的A卡就够要跑32B以上24GB起步。团队里至少得有一个熟悉Linux的人。A卡方案的大多数坑都在环境层面纯Windows用户会痛不欲生。不要在Windows上死磕ROCm。装个双系统或者直接用Ubuntu服务器效率翻倍。买新卡优先二手卡一定要查BIOS和驱动签名否则“Code 52”能卡你一下午。RDNA多卡只做数据并行或者层拆分别指望张量并行能救性能。预算里至少留10%给电源、散热和线材这几样在长时间训练时比显卡本身还关键。最后再分享一个小技巧装机时就把每张卡的PCIe Bus ID和rocm-smi里显示的编号对应记录下来贴一张纸条在机箱上。双卡机器一旦出现显存OOM或者温度异常你能立刻定位是哪张卡的锅省下的排查时间比什么都值钱。这趟A卡氪金之旅钱是省了一些时间和头发也搭进去不少但至少现在团队每个人都能在自己工位上安安稳稳地调一个7B模型了。