
1. 算法与 infra 的协同为什么这是当下最值得投入的方向最近这半年我明显感觉到一个趋势单纯把算法模型调好已经越来越不够用了。你模型精度涨了 0.5 个点但线上推理延时翻了 3 倍你在单机脚本里跑得好好的流程一上分布式就各种卡死你的训练任务和别人的推理任务抢 GPU谁都没跑痛快。这些问题单靠算法侧优化是解决不了的单靠 infra 侧堆机器也解决不了真正的出路就四个字协同配合。我把这个方向叫“算法-infra协同”核心就一句话算法工程师和基础设施工程师在同一个系统里为了同一个目标各自发力并且互相理解对方的约束条件。今天这篇内容我把自己在这条路上踩过的坑、总结出的方法、以及实际跑通的方案整理出来希望能给同样在算法和工程夹缝中求生存的同学一些参考。先说清楚这篇内容适合谁看算法工程师尤其是那些模型代码写得好、但一上生产环境就头疼的人infra/平台工程师想理解算法同学的真实需求而不是自己闷头造轮子的人技术管理者和架构师正在为团队效能和资源利用率发愁的人还有刚入行、想搞清楚算法和工程边界到底在哪的初级开发者。我保证这篇内容不搞“高屋建瓴”的废话全是我们实际干过、验证过、踩过坑之后沉淀下来的东西。那些热词榜上的排序算法、PID、A*、深度学习这类内容在这个协同体系里都有自己的位置后面我会逐一串起来讲。2. 算法-infra协同到底在解决什么问题2.1 先算一笔账你的 GPU 到底用到了百分之几聊协同之前我们先把问题量化。很多团队领导喜欢直接拍板“再买 100 张卡”但真正的问题往往不是卡不够而是卡的利用率太低。我做了一个简单的测算模型。假设你们团队有 8 张 A100每张卡的采购成本按 15 万算这就是 120 万的固定资产。如果训练任务平均 GPU 利用率只有 30%意味着每天有价值 84 万的算力在空转。这还不算电费、机柜、散热和人力成本。我实测过一些团队的训练任务发现 GPU 利用率低的原因通常不是模型不够复杂而是 infra 层面的设计出了漏洞数据加载线程卡在磁盘 IO 上GPU 只能干等着分布式训练的参数同步效率太低通信时间占到了总时长的 40% 以上训练脚本里到处是同步阻塞点不同 GPU 之间算力浪费严重任务排队策略不合理小任务排队时间比训练时间还长。这些问题全部落在算法和 infra 的交叉地带。算法同学往往盯着 loss 曲线不会注意到 GPU 空转infra 同学盯着监控大盘却看不懂模型训练的阶段变化。两边都觉得自己没问题但整体效率就是上不去。2.2 算法和 infra 各自的边界在哪协同的前提是搞清楚分工。我见过太多团队在这里翻车要么算法工程师既写模型又搞运维要么 infra 工程师不懂模型结构就乱调参数。我们团队最终把边界划得很清楚算法侧负责的内容模型结构设计和精度调优数据预处理和增强策略训练超参数的实验管理推理阶段的性能评估延迟、吞吐量、准确率。infra 侧负责的内容底层资源管理GPU、CPU、内存、磁盘分布式训练框架的搭建和调优数据管道的构建和性能优化推理服务的部署、扩缩容和监控故障恢复和容灾策略。但边界清晰不等于各干各的。真正的协同发生在边界两侧的“接口”上。比如算法工程师决定用多大的 batch size、用什么样的数据加载顺序直接决定 infra 侧要准备多大的缓存、配多少 IO 带宽infra 侧选择的通信框架和并行策略也反过来影响算法侧能跑多大规模的数据和模型。接口设计是协同的核心。我们用一句话总结算法侧管“做什么”infra 侧管“怎么做”但双方必须通过统一的配置、计量和监控体系来对齐信息否则协同就是一句空话。2.3 为什么经典算法反而更容易得到 infra 的歧视这里我想专门说一个有意思的现象。热词榜上的冒泡排序、堆排序、贪心算法、粒子群优化、PID 控制等经典算法在很多团队里被当成“面试题”“课程作业”反而没有享受到 infra 的优化待遇。有一次我问一个 infra 组的同学为什么你们对 PyTorch 的训练任务做了专门的调度和通信优化但对内部一个用粒子群算法做参数标定的任务不管不问他的回答很直接“那个任务就单机跑跑又不占多少资源不用管。”这个回答暴露了一个典型的认知偏差。经典算法虽然计算量小但它们往往是实时性要求极高、调用频率极高的模块。拿 PID 算法来说在自动化控制场景里它每秒可能执行几百上千次每次延迟波动都会被下游无限放大。再拿排序算法来说如果它是某个在线服务热路径上的关键步骤一个低效的实现就会拖垮整个接口的 P99 延迟。所以我的观点是infra 优化的优先级不应该只看计算量大小而应该看算法在系统边界上的位置和影响面。传统算法规格小、调用密对调度延迟、缓存命中、I/O 模式反而更敏感。这一点算法的同学和 infra 的同学都需要重新认识。3. 协同底座怎么搭我们选型和踩坑的完整记录3.1 核心诉求可观测、可容量、可控制动手搭建之前我先理清楚协同底座必须满足的三大诉求这也决定了后续一系列选型的方向。第一个诉求是可观测。没有数据就没有协同的依据。算法和 infra 各说各话的时候唯一能让大家闭嘴的就是监控数据。我们要能回答每个任务占了多少 GPU、多少内存、网络带宽用了多少、数据加载耗时多少、训练和推理的资源竞争情况如何。第二个诉求是可容量。这就是热词里那个“容量评估”的问题只是比“把东西装进背包”复杂多了。我们经常遇到的情况是算法同学提了一个新模型说需要多少资源但没人能确认这个估算是准的。所以要建立一个容量评估流程用 profiling 数据说话而不是靠拍脑袋。第三个诉求是可控制。光看得到、估得准还不够还要能管得住。任务优先级怎么排、资源怎么限制、故障怎么自动恢复这些都是协同底座必须提供的控制能力。3.2 存储选型分布式文件系统 vs 对象存储很多人以为存储选型跟算法关系不大我吃过这个亏才明白存储是整个数据管道的第一道关卡直接影响算法训练的数据供给效率。我们团队最初用的是传统的 NFS理由很朴素简单熟大家都用过。但跑起来发现三个问题元数据操作在高并发场景下延迟飙升几百个文件同时读写就卡壳数据吞吐量受限无法支撑大 batch 的快速加载扩容需要停机严重影响训练任务的连续性。后来我们把训练数据的存储整体迁到了并行文件系统上配套加上缓存层。这里有个关键经验训练数据的热度差异极大不是所有数据都需要同等的高速存储。我们按数据的访问频率分了三层热数据放高速本地 NVMe 缓存命中率超过 90%温数据放并行文件系统吞吐量中上等冷数据放对象存储成本低、冗余强训练前再拉取。这套分层存储方案上线后数据加载时间从平均 4.3 秒降到了 1.1 秒训练吞吐提升了 31%。算法的同学终于不用在每次启动任务时干等半小时去拉数据了。3.3 调度系统队列、优先级和抢占调度是算法-infra协同里最微妙的一环。因为它直接涉及“谁先用资源”的利益分配处理不好团队内部就要闹矛盾。我们用的是 Kubernetes 加自定义调度策略核心是解决两个问题任务排队和资源抢占。先说说任务排队。以前是简单的 FIFO 队列后来发现这会导致大任务堵车、小任务饿死。我们改造后维护了多个优先级队列并给每个队列设置了资源配额。高优在线推理任务永远优先训练任务按项目紧急程度分档离线跑批任务放在最低优先级。再说资源抢占。这里是大坑。我们最开始用的抢占策略是“新任务到达后直接杀低优先级任务”结果低优任务还没做 checkpoint几百个小时的算力白白浪费。踩过这次坑之后我们改成了优雅抢占先给低优任务发迁移信号等它把状态存好再回收资源同时靠 infra 侧的自动 checkpoint 机制兜底每 15 分钟记录一次进度。这个机制上线后因为抢占导致的算力浪费降了接近 90%。3.4 通信与同步多机训练的性能关键如果你是做深度学习的就知道多机训练最大的瓶颈往往不在计算而在通信。热词里的“3DCNN 和 C3D 是一种算法吗”“反向传播算法”这些内容落实到工程上最终都逃不过通信开销这个问题。我们最初用 PyTorch 分布式训练默认的参数同步方式是 AllReduce。但随着模型规模增大AllReduce 的通信量成倍增长训练效率直线下降。后来引入了分层通信策略同一机架内用 NVLink 做 GPU 到 GPU 的高速通信跨机架用 RDMA 网卡传输参数参数更新改用局部 AllReduce 加全局参数服务器的混合模式。这套组合拳的效果很直接8 卡扩展到 32 卡时加速比从原来的线性区掉到 60%提升回 88%。关键是通信时间在训练总时长中的占比从 37% 降到了 14%。另外给想试混合精度的同学一个建议fp16 不仅能省显存还能把通信量整体减半因为梯度传输的数据量直接少了 50%。但前提是得做好损失缩放loss scaling不然模型训练初期特别容易数值溢出。这个坑我一开始没注意连续三次训练直接发散到 NaN排查了整整两天。4. 实操过程从零搭建算法-infra协同体系4.1 第一步先做全链路的性能剖析Profiling这一步是整个协同体系的基础也是最容易被跳过的一步。我见过太多团队一上来就讨论用什么框架、买多少卡结果连自己的瓶颈在哪都不知道。我们的建议是先花一到两周时间把现有算法的全链路性能剖析做扎实。具体拆成三块计算侧 profiling用性能分析工具抓取模型每个算子的执行时间、GPU 利用率和显存占用。这里我推荐重点看两个指标GPU 计算利用率和显存带宽利用率。前者告诉你 GPU 在不在干活后者告诉你硬件资源有没有吃透。数据侧 profiling统计数据加载的平均耗时、峰值耗时、缓存命中率、磁盘 IO 延迟。通常最容易出问题的就是这里因为数据的读取路径特别长涉及存储、网络、缓存、解码、增强等多个环节每一环都可能成为隐性瓶颈。通信侧 profiling多机训练时抓取通信耗时占总耗时的比例、通信带宽利用率、同步等待时间分布。如果同步等待占比过高说明集群负载不均衡或者网络配置有问题。做完 profiling 之后你会拿到一张清晰的瓶颈分布图后续所有的优化动作都有了明确靶点。我见过做得最细致的团队把 profiling 结果做成了可持续追踪的趋势图每两周对比一次优化进度一目了然。4.2 第二步计算资源与数据加载的协同设计拿到压测数据之后就可以开始真正的协同设计。这里面最经典的就是“计算-数据”流水线的设计。简单说训练过程就是循环执行取数据、算前向、算反向、更新参数。如果数据加载是阻塞式的GPU 就不可避免会空转。我们的解法是引入预取队列机制循环过程伪代码 1. 队列中有足够的数据 否 - 触发异步数据加载线程预取下一批 2. 从队列取训练数据 3. GPU 执行前向 反向 4. 更新参数 5. 回到步骤 1但单纯加预取队列还不够真正的坑在数据增强环节。我们曾经在 CPU 上做图像增强结果 CPU 直接成了瓶颈GPU 依旧吃不满。后来把图像增强操作拆成两部分一部分留在 CPU 上做轻量变换翻转、裁剪一部分下沉到拼装和内处理阶段做 GPU 增强最终把 GPU 利用率从 61% 拉到了 87%。4.3 第三步算法侧的“可运行”设计算法-infra协同不是单向的算法侧也需要迁就 infra 的节奏否则协同搭不起来。我这里说的“可运行”设计主要包括三点第一训练任务必须支持随时断点续跑。这不是可选项是硬性要求。我们要求所有的训练脚本至少每 15 分钟做一次带权重的 checkpoint 保存模型结构配置、优化器状态、随机种子、数据迭代器位置全部记录。这样不管是机器宕机还是主动抢占最多只需要回退 15 分钟的训练进度。第二超参配置必须和资源预算绑定。算法同学常犯的毛病是一次实验吃满所有资源结果两三个任务一跑整个集群就堵了。现在我们在配置系统里加了一个“资源预算”字段每个实验在提交时必须声明预计消耗多少 GPU 小时超出预算的任务自动告警。这个机制让资源使用变得可见、可管、可审计。第三模型服务和训练任务要隔离。在线推理和离线训练放在同一个资源池里互相踩踏的后果我之前已经领教过。现在我们给在线推理任务设置了最高优先级并且做了独立的资源预留池保证即使训练任务再重线上服务也不受影响。4.4 第四步监控、告警和反馈闭环协同体系的最后一公里是完善的监控告警和反馈闭环。没有监控的协同就是摸着黑走路早晚掉坑里。我们最终搭建的监控体系包含三个层次基础设施监控层GPU 利用率、显存占用、CPU 负载、内存压力、磁盘 IO、网络带宽全部按 1 分钟粒度采集保留 30 天。任务执行监控层每个训练任务的实时进度、GPU 闲置率、数据加载等待时间、通信等待时间。这里有一个关键的复合指标叫“有效计算时间占比”它能直观反映一个任务到底有多少时间真正花在计算上。业务效果监控层模型在验证集上的准确率、线上推理的延迟和吞吐、以及数据分布的漂移检测。这些数据最终反馈给算法团队指导下一轮模型的迭代方向。告警策略我也分享一个踩坑后的经验别大而全地所有指标都配告警那只会造成告警疲劳。我们最终只保留了 5 类核心告警GPU 持续闲置超过 10 分钟、任务失败或退出、显存溢出、训练发散loss 出现 NaN、服务延迟超过 P99 线。每一条告警都对应一个明确的响应负责人和处置预案。5. 常见问题与排查技巧实录5.1 问题一GPU 利用率上不去但不知道卡在哪这是最典型、也最让人头疼的问题。我总结了一条排查路径按性价比排优先级先看数据加载线程。把 PyTorch DataLoader 的 num_workers 调成 0如果 GPU 利用率反而上升了说明瓶颈在 CPU 数据预处理。这时候应该加 worker 数、加大预取长度或者把部分增强操作转移到 GPU 上做。再看批大小。有些同学 batch size 设置偏小GPU 每次要等数据导致利用率上不去。适当增大 batch size前提是显存装得下一般有立竿见影的效果。再看通信同步。多机训练用得特别多跑一下通信耗时统计确认 Overlap 是否开了。没开的话无论如何利用率都很难超过 70%。最后才看算子效率。如果以上都排查完还是不行那才算到算子级别的优化对应热词里的“剪枝算法”“模型压减”这些方向。5.2 问题二任务一多就互相拖垮典型场景三个训练任务和一个在线服务同时跑结果谁都没跑舒服。我们的解法是三层组合第一层是资源配额每个队列有硬性资源上限谁都不能超额申请第二层是优先级抢占在线服务最高优先训练任务按业务紧急程度排序第三层是弹性伸缩推理服务晚高峰扩容、凌晨低谷缩容把空闲资源动态释放出来给训练任务。这套策略跑了一个季度后集群整体利用率从 41% 提高到了 66%训练任务的平均排队时间从 53 分钟缩短到 11 分钟在线推理的 P99 延迟保持稳定没有明显波动。5.3 问题三找不到“背锅侠”出了问题两边互相甩锅这可能是协同体系里最难治的问题比技术问题难多了。我们的经验是建立一个联合值班和故障定位机制每当出现线上故障不管最终定位到哪一侧算法和 infra 两边必须同时在群里由当周值班的人牵头。避免了互相推诿的低效损耗。故障复盘的时候不追责个人只追流程缺口。回答三个问题为什么没被监控到为什么监控到了没告警为什么告警了没及时处置每个问题都必须给出流程层面的整改项。这样搞了小半年团队里“边界争执”少了很多。大家慢慢意识到算法和 infra 本就是一个系统的两端只有协同好交付才能稳。5.4 问题四经典算法无人优化拖慢线上接口前面说了经典算法容易被忽略这里给一个我们实际处理的案例。我们内部有一个排序模块服务于某个在线推荐接口的热路径每天被调用上亿次。最初的实现是标准冒泡排序逻辑没毛病但问题是数据量级上来之后耗时明显超出预算。我把问题抛给算法组让他们评估要不要换更快的排序实现。算法同学一算数据规模 n 大约在 150 左右冒泡排序平均要做 10000 次比较这个量级单次耗时只有几十微秒按理说不是瓶颈。但后端的延迟统计暴露了另一个问题由于数据分布不平衡最坏情况下冒泡排序要跑 20000 次比较加上缓存缺失P99 延迟比 P50 高出 3 倍多。这正好印证了我前面说的观点经典算法的问题往往不在于“算得慢”而在于“延迟波动大”对在线服务特别不友好。后来我们把排序段换成了对小数组有优化的算法配合提前退出的机制延迟的稳定性好了很多。这个案例启发我们在内部建立了一个“算法体检清单”专门审查那些高频小算法在在线路径上的表现看看有没有延迟尾部和资源分配不均问题。6. 团队协同层面比技术更重要的几个认知技术做到后面你会发现真正卡住协同推进的往往不是技术债而是团队的认知和运作方式。我在这里总结几个判断不一定对但都是实际经历换来的。第一个认知算法工程师不要只会“调模型”。如果你的算法同学连基本的 profiling 都不会、不懂 GPU 利用率意味着什么、不知道 checkpoint 为什么重要那他写出来的模型再漂亮上线也是灾难。这意味着你在招人、带人的时候要把“工程素养”放进能力模型里。第二个认知infra 工程师不要只盯着“硬件利用率”。如果只追求资源 100% 打满那必然会牺牲任务的稳定性和算法的实验效率。协同的目标不是让所有资源都跑满而是让关键任务在关键时间用上关键资源。这个“关键”的标准要和算法同学一起讨论并且每季度复盘调整。第三个认知رارmeworks 和工具只是载体真正黏住算法和 infra 的是配置、监控、模型版本管理和实验记录的标准化。我们最终沉淀了一套统一的“任务卡片”每个任务跑之前必须填清楚模型结构、数据集版本、超参集合、预计资源消耗、负责人。这套卡片让所有协同动作都有了明确的对象和上下文。第四个认知技术债要用“慢债快还”的方式处理。协同体系的搭建不是一蹴而就的如果你一开始就想搞一个覆盖全部场景的大平台大概率会烂尾。我们的做法是每两周一个迭代每次只接一个痛点场景先解决数据加载慢再解决通信瓶颈再解决资源抢占最后搞监控。一步一个脚印反而比大跨步的方案落地得更快。7. 结尾最后再分享一个关于“算法-infra协同”的小观察我的实际经验是很多人以为“协同”就是一个技术问题搞定了架构就万事大吉。但真正跑起来协同的瓶颈经常出在人和信息的流通上。算法同学不知道 infra 的容量上限infra 同学不知道算法的性能目标。我们内部后来每周固定有一个 30 分钟的“边界对齐会”算法和 infra 各出一个人把近期的资源变化、任务优化、疑难问题摆到台面上过一遍。就这么一个小习惯省去了太多私下扯皮的成本。另外一个小技巧是遇到跨领域的性能问题别急着在群里 对方先自己花 15 分钟看监控数据再带着数据和方案去找对方沟通。你会发现绝大多数看似对方的问题最后都能在协同中找到解法。这些经验不复杂但都是真金白银换来的希望能帮到正在走这条路的你。