1. 为什么两张 300I Duo 跑 32B 模型是个值得认真对待的方案
把两张 300I Duo 凑在一起跑 Qwen3.5-32B,这个组合乍一看有点"非主流"——毕竟现在大家聊本地部署,张口就是消费级显卡或者整机方案。但如果你手头正好有这两张卡,或者正在为团队选一套性价比可控的推理硬件,这个配置其实相当能打。我先说结论:两张 300I Duo 的显存叠加后,跑 32B 级别的模型在显存容量上是够用的,真正的挑战不在"能不能装下",而在"怎么把两张卡用起来、怎么把吞吐和延迟调到可接受的范围"。
300I Duo 这类加速卡的特点是单卡显存不小,但单卡算力相对克制,所以它的定位天然适合"显存优先"的场景——也就是模型权重占大头、并发不算特别夸张的推理任务。Qwen3.5-32B 这个体量的模型,如果按 FP16 存权重,光权重就要 60GB 以上,单张卡基本没戏;即便上 INT8 量化,也要 30GB 出头。两张卡叠加之后,显存池子一下子宽裕了,这才让 32B 模型有了落地的可能。
这篇文章面向的是这样几类人:手里有 300I Duo 但不清楚怎么组多卡推理的;想跑 32B 级别模型但预算有限、不想上高端整机的;以及已经尝试过单卡部署、被显存卡住想扩展的。我会把整个流程拆成"硬件与显存账怎么算""环境怎么搭""模型怎么切分到两张卡""推理服务怎么起""性能怎么调"这几块,每一块都给出我实际踩过的坑和验证过的做法。
需要提前说明的是,多卡推理这件事,软件栈的匹配度比硬件本身更决定成败。同样的两张卡,用不同的推理框架、不同的并行策略,出来的效果可能差一倍。所以下面我会重点讲清楚"为什么这么选",而不是只丢一堆命令。
2. 先把显存账算清楚:32B 模型到底吃多少
2.1 权重的显存占用不是简单按参数量乘位宽
很多人算显存就一句话:"32B 参数,FP16 就是 64GB"。这个算法方向没错,但太粗糙,实际部署时会发现对不上。原因在于几个容易被忽略的部分。
第一,参数量本身有水分。Qwen3.5-32B 的"32B"是总参数量,但其中可能包含嵌入层、输出层这些占用较大但计算模式不同的部分。真正决定显存的是所有权重张量的总和,通常和标称参数量接近,但不会完全等于 32×10⁹。
第二,量化方式直接改变量级。FP16 每参数 2 字节,INT8 每参数 1 字节,INT4 每参数 0.5 字节。32B 模型在 INT8 下大约 32GB,INT4 下大约 16GB。这是决定你能不能塞进两张卡的关键变量。
第三,KV Cache 是隐形大户。这部分和模型权重无关,只和你的并发数、上下文长度挂钩。公式大致是:
KV Cache 显存 ≈ 2 × 层数 × 注意力头数 × 头维度 × 序列长度 × 并发数 × 数据类型字节数对于 32B 级别的模型,如果上下文开到 8K、并发开到 8,KV Cache 轻松吃掉十几 GB。很多人部署完发现"权重明明装下了,一跑就 OOM",八成是 KV Cache 没算进去。
2.2 两张 300I Duo 的显存池怎么分配
假设单张 300I Duo 的可用显存是 X GB,两张就是 2X。但这里有个关键认知:多卡的显存不是自动合并成一个池子的。你要么用张量并行把模型切开分到两张卡,要么用流水线并行按层切分,要么干脆一张卡放权重、另一张卡放 KV Cache(这种比较少见)。不同的切分方式,显存利用率和通信开销完全不同。
我一般建议先做一张表,把预算列清楚:
| 项目 | FP16 | INT8 | INT4 |
|---|---|---|---|
| 模型权重 | ~64GB | ~32GB | ~16GB |
| KV Cache(8K上下文,并发4) | ~8-12GB | ~8-12GB | ~8-12GB |
| 框架运行时开销 | ~2-4GB | ~2-4GB | ~2-4GB |
| 合计 | ~74-80GB | ~42-48GB | ~26-32GB |
从这张表能直接看出:FP16 基本要三张卡才稳,INT8 是两张卡的主流选择,INT4 则留出了较大余量。所以如果你只有两张 300I Duo,INT8 量化是最现实的起点,INT4 可以作为追求更高并发时的备选。
提示:量化不是免费的午餐。INT8 通常精度损失很小,INT4 在部分任务上会有可感知的下降。建议先用 INT8 跑通,再根据实际效果决定要不要降到 INT4。
2.3 一个容易翻车的点:显存碎片
即便账面上显存够,实际跑起来也可能因为显存碎片而分配失败。尤其是长时间运行、反复加载卸载模型的服务,碎片会越来越严重。我的做法是:服务启动时一次性把显存池预留好,避免运行中动态申请大块显存。很多推理框架有类似gpu_memory_utilization或memory_fraction的参数,把它设成 0.9 左右,留一点余量给碎片和临时张量,比设成 1.0 更稳。
3. 环境搭建:驱动、工具链和框架的匹配顺序
3.1 先确认驱动和固件版本,别急着装框架
多卡部署翻车,十次里有三次是驱动和固件版本不匹配。300I Duo 这类加速卡对驱动版本比较敏感,两张卡如果固件版本不一致,可能出现其中一张识别不到、或者通信带宽跑不满的情况。
我的标准流程是:
- 先用厂商提供的设备管理工具查看两张卡的型号、固件版本、驱动版本,确认完全一致。
- 如果不一致,先统一固件,再统一驱动,顺序不能反。
- 确认系统能同时看到两张卡,并且能读到各自的显存容量。
这一步看起来啰嗦,但能省掉后面一大堆"玄学问题"。我见过有人卡在"模型加载到第二张卡就报错",折腾两天最后发现是两张卡固件差了一个小版本。
3.2 推理框架的选择逻辑
跑 32B 模型的多卡推理,主流选择有几类:通用推理框架、厂商自带推理套件、以及通用深度学习框架自己写并行。我的建议是优先用支持张量并行的成熟推理框架,原因很简单:32B 模型单卡放不下,必须切分,而手写张量并行的通信逻辑非常容易出错,成熟框架已经把 all-reduce、all-gather 这些通信原语调优过了。
选框架时重点看三个能力:
- 是否支持张量并行(TP):这是把单层权重切到多卡的核心机制。
- 是否支持量化加载:INT8/INT4 直接决定显存够不够。
- 是否支持连续批处理(continuous batching):决定并发吞吐。
如果框架只支持数据并行(DP),那对"单模型放不下"这个场景是没用的——数据并行是每张卡放一份完整模型,显存需求反而翻倍。
3.3 依赖安装的坑:别让版本冲突毁掉一切
安装推理框架时,最容易出问题的是底层计算库和框架版本不匹配。我的经验是:
- 先装框架官方推荐的底层库版本,不要盲目升级到最新。
- 用虚拟环境隔离,避免和系统里已有的其他深度学习环境打架。
- 装完后立刻跑一个最小推理测试,确认两张卡都能被框架识别。
一个具体的检查动作:加载模型前,先让框架打印它识别到的设备列表和每张卡的可用显存。如果只识别到一张,或者显存数字明显不对,先别往下走,回头查驱动。
4. 把 32B 模型切到两张卡:并行策略怎么定
4.1 张量并行是首选,但要理解它的代价
张量并行的思路是把每一层的权重矩阵按维度切开,两张卡各算一半,然后通过通信把结果拼起来。它的好处是显存和计算都分摊了,单卡压力小;代价是每层都要通信,对卡间带宽要求高。
对于 32B 这种层数多、每层矩阵大的模型,张量并行度设为 2(也就是两张卡)是比较自然的。切分维度通常选隐藏维度,因为这样每张卡拿到的计算量均衡。
这里有个实操细节:张量并行度最好能整除模型的注意力头数。比如模型有 40 个注意力头,TP=2 就是每卡 20 个头,很干净;如果模型有 33 个头,TP=2 就会有一张卡多一个头,负载不均。部署前查一下模型的头数配置,能避免不必要的性能损失。
4.2 流水线并行作为备选,什么时候用
流水线并行是按层切分,前几层放第一张卡,后几层放第二张卡。它的优点是通信量小(只在层边界通信),缺点是同一时刻只有一张卡在干活,除非你同时跑多个微批次来填满流水线。
对于两张卡的场景,如果卡间带宽不理想,流水线并行反而可能比张量并行更稳。但它的显存分摊不如张量并行均匀——如果模型前半部分层参数多、后半部分少,就会出现一张卡吃紧一张卡空闲。所以我的建议是:优先试张量并行,如果通信成为瓶颈再考虑流水线并行。
4.3 切分后的显存分布验证
模型加载完之后,一定要做一次显存分布检查。理想情况下两张卡的显存占用应该接近,如果差得很多,说明切分策略有问题。
我通常会在加载后打印每张卡的显存使用量,然后跑一次前向推理,再打印一次。两次对比能看出 KV Cache 和临时激活占了多少。如果某张卡在推理时显存飙升,可能是那一侧承担了额外的通信缓冲或输出层计算。
注意:输出层(lm_head)和嵌入层(embedding)在很多框架里默认不切分,会完整放在某一张卡上。对于 32B 模型,这两层加起来可能有好几个 GB,足以让那张卡成为瓶颈。如果框架支持,把这两层也纳入切分范围。
5. 起服务:从能跑到跑得好的关键参数
5.1 上下文长度和并发数的权衡
这是部署里最需要动脑子的地方。上下文长度和并发数都吃 KV Cache,而 KV Cache 是显存里最灵活也最容易失控的部分。
我的调参思路是先定业务需求,再倒推参数:
- 如果业务是单轮问答,上下文 2K-4K 足够,可以把并发开高。
- 如果是长文档处理,上下文要 8K 甚至 16K,那并发就得压下来。
- 如果两者都要,考虑用分页注意力(paged attention)这类机制,把 KV Cache 按块管理,减少碎片。
一个实测经验:把最大上下文设成业务实际需要的 1.2 倍左右,不要盲目开大。很多人习惯性设成 32K,结果显存被 KV Cache 吃掉一大半,并发上不去,吞吐反而低。
5.2 批处理策略对吞吐的影响
连续批处理(continuous batching)是提升吞吐的关键。它的核心思想是:不等一个批次里所有请求都结束,只要有请求完成就立刻塞新请求进来,让计算单元始终饱和。
开启连续批处理后,吞吐通常能提升数倍。但它对显存管理要求更高,因为同时活跃的序列数变多了。所以连续批处理要和 KV Cache 上限配合调:先设一个保守的并发上限,观察显存,再逐步往上加。
5.3 一个完整的启动参数示例
下面是一个基于常见推理框架的启动配置思路(具体参数名因框架而异,这里给的是逻辑结构):
# 伪代码示意,参数名需按实际框架调整 python -m infer_server \ --model /path/to/qwen3.5-32b \ --tensor-parallel-size 2 \ --dtype int8 \ --max-model-len 8192 \ --max-num-seqs 8 \ --gpu-memory-utilization 0.9 \ --enable-continuous-batching \ --port 8000几个参数的解释:
--tensor-parallel-size 2:两张卡做张量并行。--dtype int8:权重量化到 INT8,显存减半。--max-model-len 8192:最大上下文 8K,按业务定。--max-num-seqs 8:最大同时处理的序列数,控制 KV Cache。--gpu-memory-utilization 0.9:预留 10% 显存给碎片和临时张量。
启动后不要急着压测,先发几个请求确认输出正常,再看显存占用是否稳定。
6. 性能调优与常见故障的排查链路
6.1 吞吐上不去,先看是不是卡在通信
两张卡做张量并行,如果卡间通信带宽不够,每层都要等通信,吞吐会被拖死。判断方法很简单:对比单卡跑小模型和双卡跑大模型的每秒处理 token 数,如果双卡的效率远低于线性预期,通信很可能是瓶颈。
缓解手段有几个:确认卡间连接方式是否用了高带宽通道;如果框架支持,调整通信和计算的重叠策略,让通信在计算的同时进行;实在不行,退回到流水线并行,牺牲一点显存均衡换通信量下降。
6.2 OOM 的三种典型场景和对策
OOM 是部署里最常见的报错,但原因各不相同:
| 场景 | 表现 | 对策 |
|---|---|---|
| 加载时 OOM | 模型还没跑起来就报错 | 降量化精度,或检查是否有层没被切分 |
| 推理时 OOM | 跑几个请求后报错 | 降并发数或上下文长度,检查 KV Cache 上限 |
| 长时间运行后 OOM | 跑一段时间才报错 | 显存碎片,重启服务或启用分页显存管理 |
我遇到最多的是第二种。很多人把并发设得很高,前几个请求没事,一上量就崩。解决办法是把max-num-seqs调低,观察稳定后再慢慢加。
6.3 输出质量异常:先怀疑量化,再怀疑并行
如果模型能跑但输出质量明显不对——比如重复、乱码、答非所问——排查顺序是:
- 先换回 FP16 或更高精度跑同样的输入。如果质量恢复,说明是量化损失,考虑换量化方案或提高精度。
- 如果高精度也有问题,检查并行切分是否正确。切分错误会导致某些层的权重对不上,输出必然乱。
- 最后检查输入格式。对话模板、特殊 token 的处理在不同框架里可能不一样,格式错了模型也会答非所问。
6.4 监控:别等出问题才看指标
服务跑起来之后,至少要盯这几个指标:每张卡的显存占用、卡间通信带宽、每秒处理 token 数、请求排队长度。显存占用持续上涨通常意味着 KV Cache 没释放干净;排队长度持续大于零说明并发不够或计算太慢。
有条件的话把这些指标接到监控系统里,设个阈值告警。我吃过亏——服务半夜 OOM 挂了,第二天才发现,中间几个小时的请求全丢了。
7. 我在两张 300I Duo 上跑 32B 模型的几点实际体会
先说量化选择。我一开始图省事直接上 INT4,显存确实宽裕,但在一部分需要精确推理的任务上,输出质量下降能明显感觉到。后来换回 INT8,显存刚好够用,质量也回来了。所以我的建议是能用 INT8 就别急着上 INT4,除非你确实需要更高的并发或者更长的上下文。
再说并行策略。我最初用张量并行,吞吐不错但延迟波动大,后来发现是通信和计算没重叠好。调整之后稳定了很多。如果你的框架支持通信计算重叠,一定要开。
还有一个细节是模型加载时间。32B 模型从磁盘加载到显存,即便有量化,也要几分钟。如果服务需要频繁重启,这个时间很折磨人。我的做法是把量化后的模型权重缓存到本地高速存储上,重启时直接加载缓存,能省不少时间。
最后提醒一句:多卡部署的稳定性高度依赖环境一致性。两张卡的驱动、固件、框架版本、甚至系统内核参数,任何一处不一致都可能埋雷。我现在的习惯是部署前把所有版本信息记一份,出问题时第一时间对照,能快速定位是不是环境漂移导致的。
这套配置不是性能最强的方案,但在"显存够用、成本可控、能稳定跑 32B"这个目标下,两张 300I Duo 是个务实的选择。关键是把量化、并行、KV Cache 这三件事的账算清楚,剩下的就是耐心调参和盯监控了。