HYGON DCU上运行Ollama 70B大模型:量化策略与部署实践
1. 项目拆解70B模型不是不能跑是策略不对最近一直在折腾 HYGON DCU 跑 Ollama 70B 模型这件事先说结论能跑而且跑通之后稳定性比我预期要好。但入手之前得先把几个门槛认识清楚不然上来就ollama pull一个 70B大概率会卡在显存不足或者驱动识别不了设备这些地方。先说门槛。70B 级别模型如果直接以 FP16/FP32 精度加载光权重文件就是 140GB 到 280GB这不是一张加速卡能解决的问题。所以思路必须换不追求满血精度而是走 GGUF 量化路线用 4-bit、5-bit 量化把模型压到 40GB 到 50GB 的区间这样才能塞进大显存 DCU 卡里。这也是为什么圈子里常说“没有跑不了的模型只有放不下的显存”。第二个门槛是生态。HYGON DCU 的软件栈很特殊它并不是 CUDA 那一套而是走的 HIP/ROCm 兼容路线也就是说能用 AMD ROCm 生态的推理框架往往在 DCU 上也能编译运行。Ollama 底层核心是 llama.cpp 的推理引擎而 llama.cpp 的 HIP 后端恰好可以用在 ROCm 兼容设备上。这层兼容关系是整个项目的立足点少了它后面所有操作都无从谈起。第三个门槛是性能预期。DCU 的显存带宽和主流计算卡相比有差距70B 推理时是纯显存带宽敏感型负载所以生成速度不会像 A100 那样动辄几十 token/s实测下来在个位数到十几 token/s 都是正常范围。如果一开始预期拉得太高很容易误判为配置失败。把这三个门槛想清楚剩下的事情就顺理成章了。1.1 为什么选 Ollama 而不是直接上推理框架有人会问既然底层是 llama.cpp为什么不直接用 llama.cpp 命令行跑非要绕一圈用 Ollama我自己的体会是Ollama 在模型管理和对外服务上做了很多省事的封装。模型管理Ollama 有ollama list / pull / create这类命令还可以把本地 GGUF 文件打包成自定义模型后期换量化版本时不需要手动重编推理二进制。服务化装好之后自带 API 服务默认监听 11434 端口给内部工具、Web 页面、客户端做集成非常方便不用自己再去写一套 FastAPI 包装层。上下文管理keep_alive、num_ctx、num_parallel这些参数可以直接通过环境变量或 API 请求控制省掉手动传参的麻烦。多模型共存同一台机器可以同时登记多个模型按需加载不用每次换模型都重来一遍编译和路径配置。当然Ollama 并非没有毛病它对非白名单设备的兼容性检查有时比原始 llama.cpp 更严格必要时还是要回到底层命令行做排查。下文我会把两条路都写出来但重点放在 Ollama 这条最终跑通的路线上。1.2 你适合看这篇文章吗如果你手头正好有 DCU 加速卡且想跑 70B 这个量级的模型本文的操作步骤可以直接照抄。如果你想跑的是 7B、13B 这类小模型也能参考前面的环境搭建部分只是显存规划和量化策略会更宽松。如果你只是好奇国产加速卡到底能不能干这种活那本文的性能实测数据和踩坑记录也可以给你一个相对客观的参考。2. 环境准备驱动、编译与关键环境变量2.1 驱动与 ROCm 工具链安装第一件事是确认驱动和 ROCm 运行环境。DCU 卡虽然硬件上由厂商提供驱动但 Ollama 和 llama.cpp 感知到的是 ROCm 运行时所以二者必须同时存在且版本对齐。我实际踩过的坑是驱动装好了rocm-smi能看到设备但 Ollama 启动日志里依然报no device found。后来发现是 ROCm 用户态库和驱动版本不匹配相当于驱动是门卫ROCm 运行库是门卡二者不配套门卫就不认你。安装时注意从厂商官方仓库或技术支持渠道获取驱动和 ROCm 包不要直接用 AMD 官网的通用 ROCm因为 DCU 通常有定制版本需求。安装完成后依次验证三件事rocm-smi # 能看到设备列表和显存占用 which hipcc # 确认 HIP 编译器在 PATH 里 ls /opt/rocm/lib # 确认 librocblas.so、libamdhip64.so 等库文件存在如果系统里同时存在多个 ROCm 版本建议把/opt/rocm软链接到实际使用的版本目录避免编译时链接到错误版本。2.2 llama.cpp 编译Ollama 底层引擎的准备Ollama 官方发行版的预编译二进制通常在主流芯片上有较好的兼容性但在 DCU 上不一定能直接识别。我自己遇到的情况是官方包能装上但一加载模型就报设备初始化失败。这个问题的根源在于 Ollama 内置的 llama.cpp 二进制没有包含针对该 DCU 架构的编译分支。解决方案有两种一是直接使用支持 ROCm 的 Ollama 版本通常社区有适配过的构建包。二是自己编译一个 llama.cpp先用命令行验证设备可用性再用 Ollama 的 GGUF 导入功能管理模型。第二种方案虽然多几步但排查问题会更可控。编译命令如下git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build -DGGML_HIPON -DCMAKE_HIP_COMPILER/opt/rocm/bin/hipcc -DCMAKE_C_COMPILERgcc -DCMAKE_CXX_COMPILERg cmake --build build --config Release -j $(nproc)注意-DGGML_HIPON是让编译走 HIP 后端不是默认的 CUDA 后端。编译时如果提示找不到 hipcc检查一下/opt/rocm是否已经纳入 PATH或者直接用-DCMAKE_HIP_COMPILER指定全路径。2.3 三个必须掌握的环境变量在整个折腾过程中有三个环境变量几乎是绕不开的我按优先级顺一遍。第一个是HSA_OVERRIDE_GFX_VERSION。这是 ROCm 生态里专门给非官方支持 GPU 用的兼容开关。DCU 的架构版本不一定在 llama.cpp 的白名单里运行时可能会提示gfx架构不支持这时需要根据你的板卡实际架构设置一个兼容值。常见做法是设置成9.0.6或9.0.8具体以厂商文档或社区实测为准。注意这个值设错了会导致模型加载后输出乱码或直接崩溃所以验证环境时建议先用小模型试跑一次。第二个是OLLAMA_MAX_LOADED_MODELS和OLLAMA_NUM_PARALLEL。前者控制同时驻留内存的模型数量后者控制同一模型的最大并发请求数。70B 这种大模型加载一次要一两分钟如果keep_alive设得太短用一次就卸载体验会非常糟糕。第三个是HIP_VISIBLE_DEVICES。多卡环境下用它指定 Ollama 使用哪张卡避免模型被分配到没有足够显存的设备上导致 OOM。如果系统里还有其他 ROCm 设备这个变量一定要设置。我建议把这些环境变量统一写进/etc/systemd/system/ollama.service.d/override.conf或者当前用户的 shell profile 里避免每次启动 Ollama 都手动 export既容易漏也不利于后来人接手。3. 模型选择与显存规划没算清楚之前别急着开跑3.1 70B 模型有哪些档位“70B”并不是特指某一个模型而是一个参数量级。常见的有 Llama 3 70B、Qwen 2.5 72B 这类开源模型。它们的精度档位和文件体积差别很大选错档位直接决定你手里的显卡能不能放得下。以 70B 量级模型为例各精度的粗略体积如下精度/量化文件体积说明FP16约 140GB几乎不可能单卡跑需要多卡或大内存服务器Q8_0约 75GB8-bit 量化质量高但体积大64GB 显存放不下Q6_K约 56GB6-bit 量化质量和体积的均衡点Q5_K_M约 49GB5-bit 混合量化社区常用档位Q4_K_M约 43GB4-bit 混合量化跑 70B 的首选Q3_K_M约 35GB3-bit 量化质量下降明显一般不建议这里要特别提醒上面是量化后权重大小实际运行时显存占用还要加上 KV cache 和运行时开销。所以并不是“模型 43GB 显卡 48GB”就能刚好跑我见过不少人在这上面翻车。3.2 KV cache 的显存占用怎么算KV cache 是大模型推理时存储中间注意力状态的缓存区它的体积和模型层数、注意力头数、上下文长度直接相关。对于 70B 模型粗略估算公式是KV cache 字节数 2 × 层数 × KV 头数 × 头维度 × 2字节 × 上下文长度举个例子某 70B 模型有 80 层8 个 KV 头头维度 128上下文长度 81922 × 80 × 8 × 128 × 2 × 8192 ≈ 268MB × 8 2.1GB也就是说把上下文拉长到 8192 tokens 时KV cache 大约会占 2GB 左右显存。如果设成 32768就会膨胀到 8GB 以上。显存吃紧的时候第一个应该砍的就是上下文长度而不是急着换更低的量化档位。3.3 业务场景下的量化档位取舍我的选择逻辑是这样的如果显卡显存不超过 48GB直接上 Q4_K_M上下文控制在 8192 以内这是最稳的组合。如果显存有 64GB可以先试 Q5_K_M上下文可以放到 16384日常对话质量比 Q4 有明显提升。至于 Q3 和 Q2我强烈不建议在 70B 上使用。大模型量化到 3-bit 以下后虽然体积小了但输出质量崩塌得非常快出现重复、胡言乱语、中英文混杂的概率显著上升。省下来的那几 GB 显存远不够弥补质量损失。另外下载 GGUF 文件时请确认它是针对你的模型版本生成的不要只看文件名。同一个量化名不同上下文归一化方式或不同分片方式都会影响 ollama 导入时的兼容性。认准来源一致的模型仓库能少很多奇怪的报错。4. 从拉模型到跑通完整操作记录4.1 方案一直接用 Ollama 官方仓库拉取如果你的 DCU 兼容性状态良好官方仓库里也有对应的模型操作最简ollama pull llama3:70b ollama run llama3:70b但实际操作中官方仓库对 70B 模型通常只提供特定精度的默认标签不一定有我们需要的 GGUF 量化版本。另外直接ollama pull下来的模型在 DCU 上经常出现加载阶段失败因为二进制里的设备兼容性检查比较严格。所以这个方案可以作为验证 Ollama 服务是否正常的路径但 70B 正式落地我推荐走第二种方案。4.2 方案二本地 GGUF 手动导入最推荐这个思路是把 Ollama 当成推理服务和模型管理器模型本体全部用本地 GGUF 文件控制。步骤拆开看并不复杂。第一步准备 GGUF 文件从 HuggingFace 或其他模型仓库下载目标模型的 GGUF 版本。下载时看清量化标识70B 推荐 Q4_K_M。文件较大建议用aria2c这类支持断点续传的工具避免下载一半中断再重来。第二步编写 Modelfile创建Modelfile内容大约是这样FROM /data/models/qwen2.5-72b-instruct-q4_K_M.gguf TEMPLATE {{- if .System }} System: {{ .System }} {{- end }} User: {{ .Prompt }} Assistant: PARAMETER temperature 0.7 PARAMETER top_p 0.8 PARAMETER num_ctx 8192 PARAMETER stop |im_end|这里有几个细节FROM路径必须是容器或本机可访问的绝对路径PARAMETER num_ctx直接决定 KV cache 大小显存不宽裕时优先调低TEMPLATE和stop要跟模型本身的对话格式匹配否则会出现模型回答串味或者不知道何时停止的情况。第三步创建并运行模型ollama create qwen2.5-72b-q4 -f Modelfile ollama run qwen2.5-72b-q4创建过程会把 GGUF 文件复制到 Ollama 的模型目录耗时取决于磁盘速度。模型创建成功后后面就跟普通 Ollama 模型一样使用了。4.3 启动参数与服务化配置单次交互没问题后把它变成长期服务需要额外处理几件事。首先是保持模型驻留避免对话间隙自动卸载设置OLLAMA_KEEP_ALIVE30m或调成-1表示永久驻留。然后确认对外 APIcurl http://127.0.0.1:11434/api/generate -d { model: qwen2.5-72b-q4, prompt: 用一句话介绍你自己, stream: false }如果要在局域网内提供服务设置OLLAMA_HOST0.0.0.0:11434但要注意这时 Ollama 没有任何鉴权机制在内网也不能裸奔最好前面挂一层简单的反向代理加密钥校验。4.4 加载日志与状态确认模型启动后不要急着问问题先确认状态。ollama ps会显示当前驻留模型、显存占用和上下文长度。日志里重点看两个信息一是设备是否成功初始化二是是否显示模型全部层都加载到了 GPU。如果日志里出现了类似“部分层加载到内存RAM”的字样需要检查显存是否足够或者num_gpu参数是否被自动调低。这个阶段不仔细看日志后续的性能问题会很难排查。5. 性能实测与参数调优5.1 不虚报的实测数据跑通是一回事跑得动是另一回事。我在一块 64GB 显存、带宽在 1TB/s 附近的中高端 DCU 卡上做了几组测试模型是 70B 量级量化档位和上下文不同结果如下模型配置上下文长度Prompt 处理速度生成速度Q4_K_M4096约 45 token/s约 11 token/sQ4_K_M16384约 40 token/s约 10.5 token/sQ5_K_M8192约 32 token/s约 8.5 token/sQ6_K4096约 25 token/s约 7 token/s可以看到量化越重、模型体积越小速度越快上下文长度对生成速度的影响主要体现在 KV cache 膨胀后的访存压力上但不如量化档位影响那么明显。10 token/s 这个数字直观感受是“能等但不快”。适合对话、批量离线生成、内部知识问答这类场景不适合需要实时流式输出的高并发前端。5.2 三个真正值得调的参数第一个是上下文长度。70B 模型在 DCU 上跑的时候KV cache 是最容易被忽视的显存黑洞。我建议先用num_ctx 4096验证稳定运行再逐步往上加。如果你处理的文本普遍超过 8192再考虑是否值得牺牲缓存空间。第二个是并行数。Ollama 默认串行处理请求如果只是单用户使用问题不大。多人共用时可以设置OLLAMA_NUM_PARALLEL2但注意这只是允许同时塞进两个请求吞吐提升有限每个人的响应延迟反而会被拉长。实测下来70B 模型保持单并发是体验最优解超过 2 并发后显存带宽会成为硬瓶颈所有用户都变慢。第三个是批处理大小。llama.cpp 推理时的 prompt 处理阶段是批量计算适当调大 batch 可以提升长文本处理速度。但这和并行数是两码事不要搞混。batch 增大后显存占用也会涨DCU 上建议从 512 开始尝试超过 1024 收益就不明显了。5.3 哪些场景真正适合这套方案跑通后的 DCU Ollama 70B我认为最合适的场景是私有化部署和敏感数据本地处理。模型文件全部落在自己机器里不经过外部 API也不需要担心数据出境问题。同时对于国产化适配有要求的项目这套方案在技术栈上是完整的可以作为一个可交付的推理底座。相反如果你追求的是高并发、低延迟、大规模用户在线推理那 DCU 单卡跑 70B 不是好选择。这种场景应该考虑多卡并行或换更小的模型而不是硬顶一个 70B 在单卡上挣扎。6. 踩坑实录与排查技巧6.1 高频报错速查表我在实际运行中遇到并解决的问题整理成一张表你可以按图索骥报错/现象可能原因解决办法no device found驱动与 ROCm 运行库版本不匹配或设备未探测确认rocm-smi能看到设备重装匹配的驱动与 ROCm必要时设置HSA_OVERRIDE_GFX_VERSION模型加载后输出乱码gfx架构兼容值设置错误换其他HSA_OVERRIDE_GFX_VERSION数值反复验证至输出正常out of memoryKV cache 过大或量化档位过高降低num_ctx换 Q4_K_M 量化检查是否有其他进程占用显存加载极慢磁盘 IO 慢或每次重新加载模型使用 SSD 存放 GGUF增加OLLAMA_KEEP_ALIVE驻留时长生成速度只有 2-3 token/s部分层被卸载到系统内存检查日志确认层是否全部加载到 GPU释放显存或降低上下文API 请求超时模型加载期间新请求被阻塞预加载模型或用ollama run先发一次空对话完成加载创建模型时提示Modelfile not found路径写错或格式错误检查FROM路径是否为绝对路径确保Modelfile文件名大小写正确6.2 启动前必须检查的三个命令每次重启机器后我心里有一套固定的“三连查”rocm-smi ollama ps dmesg | grep -i fail第一查设备是否正常上电和识别第二查模型是否驻留以及显存占用第三查内核层面有没有隐藏的驱动报错。做项目最怕的不是机器有问题而是机器有问题但没被发现等模型跑起来后才被各种诡异现象拖着走。6.3 几条保命级别的避坑经验有几个经验是我折腾完之后最想提前告诉后来人的。永远先拿小模型验证环境再上 70B。不要一上来就跑 70B环境变量、驱动兼容、MODfile 模板这些问题用 7B 模型几分钟就能验证完毕70B 光加载就要几分钟。大体积模型只适合用来做最后的性能验证不适合做环境调试。一次只改一个参数。这是排查问题的黄金法则。改量化档位和改上下文长度要分开测试否则出了问题你根本不知道是哪一步导致的。我见过同事一口气把num_ctx、num_parallel、量化档位全换了跑崩了之后三个人排查了一下午。学会看日志而不是看现象。Ollama 的日志默认输出在journalctl -u ollama里llama.cpp 的日志则直接打在终端。这里写的每一句几乎都有价值。很多时候你看到“模型回答不完整”翻日志发现是 KV cache 不够被截断这种问题凭肉眼永远猜不出来。磁盘空间要留够。一个 43GB 的 GGUF 文件导入 Ollama 时还会复制一份所以要预留至少两倍的模型体积空间。这个坑我踩得特别实在跑得好好的突然提示导入失败一看是磁盘满了非常尴尬。最后分享一个小技巧这套环境跑稳之后我养成了一个习惯把常用的模型加载脚本写成固定命令包含环境变量、模型名、上下文长度和保活时间而不是手动一个个设置。比如export OLLAMA_KEEP_ALIVE30m export OLLAMA_NUM_PARALLEL1 ollama run qwen2.5-72b-q4 --verbose这样每次重启服务后一行命令就能把环境恢复到自己熟悉的状态。折腾 DCU 跑 70B 模型最终能收获的不只是“能跑”这个结果而是对显存规划、量化取舍、ROCm 兼容链路都建立起完整的直觉。这套经验不仅适用于这一块卡换到其他非主流加速卡上排查思路也是一样的。