恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
GPU还是NPU?不如按负载切片做异构协同调度
首页
资讯中心
/
GPU还是NPU?不如按负载切片做异构协同调度
GPU还是NPU?不如按负载切片做异构协同调度
发布时间:2026/10/20 16:26:52
做了几年推理服务被人问得最多的问题就是你这个场景到底用GPU还是NPU这个问题背后往往是预算有限、功耗受限、又要按期交付的普遍焦虑。我最初也死磕这个二选一结果两次都踩了坑一次是纯GPU方案被电费和散热账单教育了另一次是纯NPU方案被算子和精度问题拖到临近上线才临时补救。后来我把思路反转先问自己为什么不能先看负载长什么样再决定硬件阵容慢慢才形成今天想分享的这套东西。这篇文章要聊的是GPU和NPU之外的第三个答案按负载切片、异构协同、统一调度。它不是某个硬件而是一套让不同算力引擎各跑一段的工程方法。适合正在做模型上线、推理服务优化或者刚拿到一块NPU评估板准备做验证的同学参考。1. 两个热门选项的真实底细1.1 GPU算力高光掩不住三笔隐形账单GPU为什么这么火因为它的架构天生适合大规模并行矩阵运算。核心数多、访存带宽大、软件生态成熟主流框架基本都优先支持GPU。这三点加在一起让它成为模型推理默认的标准答案。但生产环境不是跑个验收报告。GPU有至少三笔账单评测指标里看不见。第一笔是功耗与散热。高端加速卡的标称功耗动辄几百瓦跑起来加上服务器整体散热一个机柜的功率密度很快就到上限。有些机房条件差的团队卡还没买先得解决供电和空调这不是段子。第二笔是采购成本与折旧。GPU价格贵而且迭代快两三年就要考虑淘汰换新折旧摊到每个请求上小业务的成本压力很大。第三笔是利用率问题。推理服务的流量有明显波峰波谷白天在线API高峰夜里批量任务低迷GPU很难始终满负荷。我见过不少团队GPU平均利用率不到30%但还是得按满配电力预留资源。我不是说GPU不好而是说如果只看峰值算力就下单后续会有很多超出预算的意外支出。这也是很多人开始看NPU的契机能不能用更低的功耗、更便宜的价格把同样的模型跑起来。NPU确实能但它有另一套问题。1.2 NPU能效漂亮但好用和好用是两回事NPU的算力逻辑和GPU不一样。它把乘法累加阵列、片上缓存和低精度计算做成专用电路跑特定类型的算子时能效比相当夸张。同样一个INT8卷积NPU的每瓦性能可能做到GPU的好几倍。对于边缘盒子、摄像头这类功耗受限的设备NPU几乎是唯一可行解。但问题也出在特定两个字上。第一算子兼容性。把模型从GPU格式转换到NPU格式时某个算子不支持是常态。一旦遇到不支持的算子要么改网络结构要么把这个子图留在CPU或GPU上执行复杂度一下就上来。第二精度不一致。NPU集群习惯上使用INT8量化量化误差会累积。同一个模型在GPU上用FP16跑精度达标转到NPU上可能某些类别掉点需要逐层排查、校准。第三动态Shape支持弱。NPU为了极致性能很多内部存储结构是静态规划的输入尺寸一变化就要重新编译。遇到检测类模型那种后处理阶段动态逻辑一多NPU反而施展不开。另外不同NPU厂商的SDK、模型格式、量化工具各搞一套迁移成本不低。这不是某一家的毛病是整个生态还在成熟的正常状态。所以NPU的真实定位不是GPU的全面替代而是特定负载下的能效补充。明白这一点后面整套思路才顺理成章。1.3 顺便说说CPU和FPGA为什么它们也不是标准的第三答案聊选型时常有人提CPU和FPGA。CPU在低延迟、小Batch场景其实很有价值单独的CPU节点也能承担不少推理任务。但大规模矩阵运算和GPU比性能和单位成本都不占优。业务量一大CPU方案算下来的总成本反而更高。FPGA则走到另一个极端可重配置、功耗可控、时延可以做到很确定特别适合一些专用信号处理场景。但它的开发周期和调试难度都不是普通算法团队能长期承担的。你不仅要懂硬件描述语言还要处理时序、布局布线一堆硬件层面的问题。模型还经常要改每次迭代都要重新综合实现收益和成本往往不成比例。所以真正能作为第三答案的不是某种单一的替代硬件而是编排——把一次推理拆开来看哪些阶段适合GPU、哪些阶段适合NPU、哪些阶段留在CPU再由一层调度逻辑把它们组合起来。这套组合拳就是我这篇文章想展开的核心思路。2. 第三个答案的底层逻辑负载形状决定硬件阵容2.1 从一维算力到四维目标延迟、吞吐、Batch和功耗很多硬件选型评测只喜欢报一个指标比如多少T算力。但对生产推理服务来说光看算力等于没看。真正决定选型的是四个可量化的目标延迟、吞吐、Batch特性和功耗预算。先说话延迟。在线推荐、智能客服这类场景用户等不起P95延迟超过几百毫秒就是事故。这类服务请求往往是小Batch甚至Batch等于1每次请求还有动态输入长度。算力再高如果启动开销大、流水线切不深延迟依然上不来。再说吞吐。离线批量任务完全不同比如一批图片要批量质检一晚处理十万张单个任务跑慢几秒没关系只关心总吞吐量和每张图的成本。Batch在这里可以压得很高对算力密集型硬件非常友好。第三个维度是Batch分布。我接触过的很多服务平均Batch只有2到4但峰值能达到32以上。这种波动对GPU最不友好因为大算力卡在低Batch下发挥不出优势对NPU倒是相对合适因为它的静态特性在小Batch下效率不低。第四个维度是功耗预算。机房供电上限是多少边缘设备是电池还是太阳能这些不是技术团队能谈判的物理约束。把这四个维度列成一张表很多问题的答案会自己浮现。比如在线APIBatch小、延迟敏感适合GPU或CPU离线批量Batch大、延迟无所谓CPU加NPU组合也行成本优先边缘摄像头功耗受限NPU基本是必须项大模型服务Prefill和Decode分化明显异构方案天然有优势。2.2 把一次推理拆成流水线让不同硬件各跑一段大多数团队把模型当成一个不可分割的整体要么整张卡要么整颗NPU。实际上一次推理是由多个阶段组成的流水线阶段之间差异很大。拿一个典型的工业质检视觉模型举例。输入是工业相机拍的原始图像处理流程大致是图像解码、尺寸缩放、归一化然后进入一个骨干卷积网络做特征提取最后是一个检测头加一堆后处理逻辑比如NMS。这三个阶段的负载特征完全不一样。前处理是密集型数据搬运图像解码对算力没要求但对数据带宽和格式转换有要求适合在CPU上跑或者走专门的硬件解码通道。骨干卷积网络是规则的矩阵乘加输入尺寸固定、网络层结构固定最适合NPU这类专用阵列。到了检测头和后处理阶段牵扯到坐标解码、阈值筛选、NMS这些都是动态Shape和控制流操作NPU最怕这种负载GPU的灵活性在这里更有优势。语言模型也有类似的分化。Prefill阶段要并行处理整个输入序列计算密度高适合算力大的部件Decode阶段是逐Token生成访存带宽受限纯算力不再是唯一瓶颈这时候硬件的功耗差异会被放大。所谓Prefill和Decode分离本质上就是这个思路在语言模型场景的应用。当然这个方案要求高速互联和成熟的通信实现不然中间状态来回搬运的成本会吃掉收益团队要有足够的系统能力才建议碰。所以第三个答案的第一步不是先选卡而是先画流水线请求进来之后每一个阶段分别是什么负载消耗多少时间占多大比例。画完之后切分方案基本就出来了。2.3 调度层这才是整套架构的第三个答案不同引擎解决了算力问题真正让它们协作的是一层调度逻辑。这也是很多做NPU的朋友容易忽略的点把模型转好、性能跑起来却缺一个把请求分给谁的决策者。没有调度层异构只是一堆各自运行的孤岛。调度的职责可以概括为三件事。第一是路由根据当前请求的形状、优先级和排队情况决定它进GPU、NPU还是CPU引擎。第二是配额给每个引擎设置最大并发上限保护引擎不被打爆也保护整个系统不互相挤占。第三是熔断当某个引擎排队时间超过阈值时快速失败或者降级到备用引擎而不是让请求无限堆积。打个比方这个调度层很像快递分拣中心的中控台。大件重货走干线运输小件快件走城际专线异常件进人工窗口中控台负责实时调配。你不会把所有快递都塞给一种车同样也不该让所有请求都落在一种卡上。这套思路的好处在于它是可生长的。今天只有GPU就只在GPU一个引擎上做路由明天加了NPU板卡无非是多插一个引擎路由规则加两行配置。硬件选型从一次性拍板变成了渐进式扩展这正是我认为的第三个答案最核心的价值。3. 实操落地一套异构推理服务是怎么搭起来的3.1 第一步给模型做一次负载体检别急着转模型、买机器先给现有服务做一次体检。我见过最典型的失败路径拿到一款NPU开发板跑通一个Demo立刻立项要替换GPU结果上线第一周就发现吞吐没上去、延迟还超了。原因很简单Demo和真实流量根本不是一回事。体检要收集几类数据。第一请求量曲线。把一周的请求按小时统计找出波峰时段、波谷时段、峰值是平均值的几倍。第二单请求时延构成。在服务里埋点分别统计预处理、模型推理、后处理三个阶段的耗时占比。这一步很关键因为如果预处理占了一半时间换再强的NPU也只能优化推理那部分。第三Batch分布。把一周所有请求的Batch大小记录下来看平均Batch和P99 Batch。第四资源使用率。当前GPU的算力利用率、显存占用、功耗曲线全部拉出来判断瓶颈到底是算力、显存还是IO。埋点不需要多复杂就是几个计数器加耗时直方图跑三到五天数据就够用了。拿到数据后把负载画像填进一张表格这样后面每一步决策都有依据而不是拍脑袋。这个体检动作本身往往就能暴露很多还以为不是瓶颈的问题。3.2 第二步确定引擎分工和路由规则体检完成之后就可以画分工图了。还是用前面那个工业质检项目来说最后定下来的分工是这样CPU负责图像解码、缩放和最后的坐标结果透传NPU负责骨干卷积网络输入固定为640乘640Batch固定为4统一走INT8GPU负责检测头、NMS和动态后处理这部分就吃灵活性和动态Shape。为什么这么分骨干网络在NPU上静态编译后性能最稳定能效比最高。而NMS这类逻辑控制密集的操作在NPU上要么不支持、要么性能很差留在GPU上反而省心。这样一来每次请求先是CPU做预处理然后进入NPU做重计算最后到GPU收尾三个引擎各干各最擅长的活。引擎分工和路由规则确定之后最好把它们统一成一份配置文件让基础设施团队不用每次改判断逻辑。我习惯用一种类YAML的结构来描述整条流水线字段包含阶段、引擎类型、输入约束、超时和回退条件比如下面这个简化示例pipeline: preprocess: engine: cpu decode: hw_decoder backbone: engine: npu input_info: width: 640 height: 640 batch: 4 precision: int8 timeout_ms: 120 head: engine: gpu min_batch: 1 max_batch: 8 timeout_ms: 80这个配置文件的含义是把请求按阶段路由预处理走CPU骨干网络走NPU并限定输入格式后处理走GPU。如果NPU阶段超时超过120毫秒调度器要按下一小节设计的策略做回退。3.3 第三步设计回退、超时和动态Batch策略引擎分工定好之后最见功力的其实是异常路径设计。很多人踩坑就踩在这里NPU排队排到崩溃调度器把流量全甩给GPU结果GPU也崩整个服务雪崩。一个稳妥的思路是设置百分比配额而不是简单的超过就全切。例如NPU队列长度超过阈值时只把增量请求的30%切到GPU剩下70%继续排队或者直接快速失败。这个比例要根据压测结果调。另外每个引擎必须设置最大并发数GPU也要设置上限超了就直接返回降级响应而不是让请求无限堆积。动态Batch也要按引擎区别设置。NPU适合固定小Batch好处是延迟稳定GPU可以适当把小块合并成大Batch提高吞吐。调度器可以维护一个小型合并窗口例如攒够4个请求再发给NPU攒够8个再发给GPU。合并窗口不能设太大否则在线请求的延迟就上去了。调度器本身不复杂但回退比例、最大并发和动态Batch窗口这几个参数必须做成可配置项而不是写死在代码里。我会用一个极简的伪代码把核心逻辑固化下来方便后续压测时反复调整参数def route_request(req): if queue_len(npu) npu_max_queue: if failover_ratio(gpu) 0.3: return dispatch_to(gpu, flatten_batch(req)) else: return reject_with_capacity_hint(req) if req.is_dynamic_shape or req.requires_fp16: return dispatch_to(gpu, req) return dispatch_to(npu, gather_batch(req, targetnpu_batch_size))这段代码里最关键的是failover_ratio它控制回退流量比例把雪崩的概率压到最低。这个指标要看全局而不是单个请求建议做成一个原子计数器避免并发误判。3.4 第四步验证、灰度与压测功能跑通后不要直接切全量流量。先把三种方案放在同一份回放流量下对比纯GPU、纯NPU、异构混合。用压测工具把线上录制的真实请求回放一遍分别记录P50和P95延迟、每分钟请求数、功耗和错误率。数据出来后你会看到很有趣的结果纯GPU方案延迟最低但不便宜纯NPU方案能效最好但在动态请求上P95很糟糕混合方案单看延迟不是第一名但综合成本和稳定性往往最平衡。灰度放量也讲究节奏。先切5%的流量到混合方案观察一周确认没有精度事故和时延毛刺再逐步扩大。每一步都要对比业务侧的核心指标这些指标只有业务方最清楚上线窗口要留足。还有一个必须做的环节精度对齐。GPU跑FP16NPU跑INT8两边出来的结果要抽样比对。方法是对同一批测试样本先让GPU方案输出作为基准再让NPU方案输出算一下各类别的误差分布。如果某个类别的指标掉得厉害就得回查是哪一层量化出了问题然后在配置里对该层单独保持高精度。4. 常见问题速查与避坑实录4.1 NPU转换阶段的老三样问题把模型转到NPU的过程绕不开三个问题我挨个说。第一算子不支持。某款NPU的SDK只支持有限算子集合模型里遇到不支持的算子最常见的解决办法是算子剥离把不支持的部分拆出来放到CPU或GPU上作为一个子图运行。听起来简单但子图之间的张量传输是额外开销拆得太碎反而更慢。我的经验是能改网络结构解决的优先改网络比如用一个更通用的算子替换自定义层。第二动态Shape被固定。NPU编译器为了做极致优化会把输入尺寸固定下来你传一张不同尺寸的图它要么报错要么重新编译延迟直接爆炸。解决办法是校准输入分布项目里绝大多数图落在什么尺寸区间就固定在那个区间其余尺寸走回退路径。第三INT8量化精度掉落。之前说的逐层排查方法这里具体说一下先在测试集上跑一遍INT8和FP16的中间结果逐层算特征分布差异把误差放大最多的那一两层保留FP16其余继续用INT8。这样大部分精度损失可以找回来代价是这两层速度稍慢但可接受。4.2 异构调度里的时延雪崩问题我在项目里遇到过两次比较严重的雪崩都是同一种模式某个引擎出现慢请求客户端超时重试重试又把对端压垮然后所有引擎一起变慢。排查路径有迹可循。先看监控图哪个引擎的队列长度最先抬头哪个引擎的错误率在雪崩前就开始爬升。然后检查超时配置很多服务超时时间设成固定值超出就重试重试其实是最危险的它会把一个故障放大好几倍。解决方向是给每个阶段设置独立超时重试要带全局的速率限制雪崩前让队列自然溢出而不是无限存积。调度器要主动丢弃最低优先级的请求保证核心请求的P95稳定。这个取舍需要产品侧提前对齐但架构上必须预留。这里有一张问题速查表按症状排查比较快症状优先排查方向常规解决手段NPU转换报算子不支持日志里的算子名改结构或子图回退避免碎片化INT8精度掉点逐层特征分布对比误差大的层保留FP16输入尺寸变化延迟暴涨检查是否触发重新编译统一固定尺寸超范围走回退某引擎队列无限堆积队列长度和重试计数设最大并发超限快速失败混合方案P95抖动阶段间数据拷贝时间共享内存或零拷贝减少跨引擎搬运4.3 成本模型怎么算才对最后算一笔总账。很多团队选型只看单卡价格这是个误区。真正的成本要摊开看硬件采购、机房供电和散热改造、折旧周期、开发人力迁移成本、模型重新调优的维护成本。我按一套中等规模服务粗略算过纯GPU方案和混合方案的采购价差大约15%到20%但运行两年算上电费和迁移人力混合方案往往能省下30%以上。这个数字会随地区电价浮动但趋势是稳定的。当然规模太小的团队我不建议一上来就搞混合架构。模型只有一个、QPS不到几十直接买一台GPU服务器是最省心的起步方式。异构协同是在你有稳定流量、明确的瓶颈和足够工程人力之后再做减法优化成本的手段。顺序不能反。5. 一些真实体会5.1 关于硬件选型的三个心态转变第一不要迷信任何一家厂商给的Benchmark。官方评测用的是动手环境精心调过的确定性负载你的线上流量是动态度、随机的、各式各样都有。拿真实流量回放测出来的数字才算数。第二异构协同的复杂度是真实存在的。每多接入一个引擎就多一套依赖、多一群兼容性问题需要投入的维护成本常常被低估。如果你团队只有两三个人我建议先从一个引擎做到极致开始等瓶颈确凿了再引入第二个引擎不要为了技术炫酷去搞复杂架构。第三我踩过最大的坑是让引擎之间互相等待。不同引擎处理速度天然不一样流水线设计时一定要用解耦队列把各阶段隔开否则一个阶段抖动就会拖垮全链路。队列长度要有上限积压时要优先处理最关键的请求。5.2 监控先行比硬件选型更优先最后再分享一个小技巧把所有引擎的监控指标统一成一个标准格式无论GPU、NPU还是CPU都上报排队长度、处理时延、错误率、利用率这四类指标。未来哪怕换芯片、加新板卡也只是插一套监控接口的事不用重新造轮子。把选型问题从该买谁变成怎么编排整个系统反而更好维护。这套思路我至今还在用希望对正在纠结要不要买NPU、或者刚被GPU账单吓到的你有帮助。