
电力成本正在变成一个训练团队最早撞上的墙而不是最后才考虑的事。我在几个不同规模的项目里都遇到过同一种情况模型结构还没调明白机房那边先来问为什么这个月的用电量翻了一倍。很多团队在能耗优化上做的第一件事是换硬件或者上液冷但实测下来这两个动作的边际收益往往排不进前三真正吃掉电量的地方藏在并行配置、数据流水线和检查点策略里这些地方改一行配置的效果可能比换一批设备更直接。这篇内容想讲清楚一件具体的事大型模型训练中的能耗到底怎么量化、怎么归因、怎么在不牺牲模型效果的前提下压下来。适合正在跑或准备跑多机多卡训练、并且已经开始被电费和散热问题追着跑的工程师看。不涉及任何具体的硬件采购建议只讲方法论和可复现的调优路径包括我在实际项目里踩过的坑以及那些看起来很省、实际不省甚至更费的反直觉操作。1. 先把电费换算成“每 token 成本”能耗账本的建模方法1.1 从机柜功率到焦耳三条必须打通的换算链大部分团队对能耗的认知停留在“这个月电费多少”这个粒度做不了任何优化决策。要能优化必须把电费一路换算到“每处理一百万 token 消耗多少焦耳”这个量级中间要打通三条链路。第一条是从加速卡功率到整机墙插功率。管理接口读出来的板卡功耗只覆盖板卡本身CPU、内存、本地盘、风扇、网卡全都不在里面。一台典型的高密度训练整机板卡部分占整机功耗的七成到八成剩下的部分是实打实的开销。第二条是从整机功率到机房总功率这里要乘 PUE也就是机房总用电与 IT 设备用电的比值风冷机房常见在 1.2 到 1.5 之间这个系数直接决定了你在计算侧省下来的每一瓦最终能从电表上省下多少。第三条是从总功率到有效工作量也就是这段时间里真正完成了多少个有效 token 的前向反向计算。这三条链路里最容易出错的是第一条。我曾经在一个项目里用板卡功耗做基线算出某次改造省了 8% 的电后来接上机柜级电表一测实际只省了 5% 左右因为改造同时改变了风扇转速曲线整机其他部分的功耗占比变了。后来我的做法是日常调优用板卡功率做相对比较只要前后对比口径一致就能看出趋势但凡要对外汇报绝对节能数字一律以机柜级或列头柜电表为准。1.2 计算、搬运、散热功耗被谁吃掉把一台训练整机的功耗拆开看大致是三块计算单元的动态功耗、数据搬运带来的功耗、以及散热和供电转换的损耗。计算单元在满载跑矩阵乘的时候功耗最高但当它因为等数据、等通信而空转时功耗并不会掉到零通常还在峰值的三四成。这个特性非常关键它意味着“空转”是纯浪费而且是很难被监控发现的那种浪费——从任务视角看训练还在跑从电表视角看电一直在花但有效工作量是零。数据搬运这块的功耗经常被低估。显存带宽打满的场景下比如注意力的中间矩阵反复读写、大范围的 all-reduce、频繁的检查点落盘搬运功耗在整机功耗里的占比可以到两成以上。这也是为什么算子融合这类看起来只是“性能优化”的手段在能耗上收益往往比预期更大——它减少的不是计算量而是搬运量。散热和供电转换属于“乘法系数”。风扇转速跟着进风温度走供电机组的转换效率在五成负载附近最高、低载时明显下降。有个很实际的现象一批机器如果长期跑在三成负载以下电源效率会比额定值低好几个百分点这部分损失平时根本看不见但它确确实实计入了电费。1.3 一张可以直接套用的估算表下面这张表是我自己在做前期评估时用的模板参数按常见配置填实际项目里替换成自己的数字就行。假设规模是一千张加速卡单卡板卡功耗取一个中间值整机功耗按板卡功耗的一点三倍估PUE 取 1.2。项目取值说明加速卡数量1000训练集群规模单卡板卡功耗700 W满载训练态典型值整机功耗约 1.0 kW板卡功耗 × 1.3 后取整IT 侧总功率约 1.0 MW整机功耗 × 卡数机房总功率约 1.2 MWIT 功率 × PUE 1.2单日耗电约 28.8 MWh1.2 MW × 24 h单月耗电约 864 MWh按 30 天计有效算力约 160 PFLOPS峰值 400 PFLOPS × MFU 40%单 token 计算量约 4.2e11 FLOPs70B 参数模型按 6N 估算吞吐约 3.8e5 token/s有效算力 ÷ 单 token 计算量能耗强度约 0.32 token/J吞吐 ÷ 总功率这张表最有价值的地方不是那些绝对值而是它把“改一个参数会怎样”变得可算。比如 MFU 从 40% 提到 50%其他不变吞吐涨 25%能耗强度从 0.32 涨到 0.40同样的训练任务时间缩短两成总能耗同比下降两成。这个换算关系比任何定性描述都更有说服力也更容易让非技术背景的人理解为什么优化 MFU 就是在省电。不过这里有个陷阱要提醒单 token 计算量用 6N 估算在短序列下够用序列长度上到几万 token 之后注意力部分的计算量占比会显著上升实际单 token 计算量可能是 6N 的一点几倍。做长上下文训练时如果还按 6N 算吞吐会被高估能耗强度的分母就虚高了。2. 度量体系没建好所有节能动作都是自我安慰2.1 MFU、tokens/J、PUE三个不能互相替代的指标这三个指标经常被混着用实际上它们回答的是完全不同的问题。MFU模型浮点利用率回答的是“硬件的计算能力被用起来多少”它只看计算侧完全不管机房效率tokens/J 回答的是“每焦耳电换来多少有效工作量”它把计算效率和机房效率一起打包了PUE 回答的是“IT 设备用的电有多少被机房自己吃掉了”它跟模型、跟并行策略一点关系都没有。混用会导致很荒唐的结论。我见过一个团队报告说 MFU 提升了 15%同时期 tokens/J 只涨了 3%原因是他们同时把机柜密度提上去了风冷压不住风扇功耗吃掉了大部分收益。如果只看 MFU这个改造会被判定为成功如果看 tokens/J结论会完全不同。我自己的习惯是把这三个指标放在一张看板上按天采集MFU 用来定位训练内部的问题tokens/J 用来做跨项目、跨集群的比较和对外汇报PUE 用来判断机房侧还有没有优化空间。三者出现背离的时候就是排查最需要投入的地方。2.2 功耗采样本身的误差来源功耗数据的可信度比很多人想象的低。板卡管理接口的采样频率通常在几十毫秒到几百毫秒量级如果采样间隔大于训练步长的波动周期就会把峰值抹平算出来的平均值偏低。这在流水线并行场景下特别明显——流水线气泡期的功耗会掉一个台阶采样点稀疏的时候很容易全部落在高功耗段上导致基线虚高后续任何改动都显得“有收益”。另一个误差来源是读数口径。管理接口报的功耗包含哪些部分不同厂商、不同型号之间并不一致有的含显存有的不含混用不同型号的机器做集群级统计会引入系统性偏差。我一般的处理方式是集群里只保留一种型号做基准节点所有对比实验都在基准节点上跑跨型号的汇总数据只用来做量级判断不做精细归因。还有一个容易被忽略的点待机功耗。训练任务之间的间隙、检查点落盘的等待期、数据加载的阻塞期加速卡并不是零功耗。一批机器如果调度不紧凑每天累计几小时的待机一个月下来的浪费相当可观而这部分功耗在任务级的统计里通常是看不见的。2.3 基线怎么建才算可信建基线这件事做扎实比做得快重要得多。我的做法是固定三件事再开始测固定的数据子集、固定的并行配置、固定的检查点间隔。然后至少跑够几百个 step跳过前几十个 step 的预热期取稳定段的平均值。预热期必须跳过的原因是显存分配、通信组建立、数据流水线填充这些都集中在前几十步功耗特征和稳态完全不同。有一次我偷懒把整段数据一起平均结果基线比真实稳态低了 6%后续所有优化看起来都打了折扣排查了两天才发现是自己基线算错了。还有一点是记录环境温度。风冷机房里进风温度每变化几度风扇功耗就会跟着变这部分变化会直接体现在机柜电表上。跨天、跨季节做对比的时候如果不记录温度很容易把季节性变化误判成优化效果。我的习惯是在采集脚本里直接带上机房进风温度的时间序列事后做归因时会省很多事。3. 计算侧让每一焦耳多算几次乘加3.1 低精度训练的收益边界在哪里降低计算精度是收益最直接的手段BF16 相对 FP32 几乎已经是默认选择真正的讨论空间在更进一步的低精度格式上。收益的来源有两块一是计算单元的吞吐提升同样的时间能算更多二是显存占用和带宽占用下降搬运功耗跟着降。两块叠加理论上能带来相当可观的能耗改善。但收益有明确的边界而且这个边界往往被低估。低精度格式的表示范围窄遇到数值分布极端的层比如某些归一化层前后的激活值、或者训练早期的嵌入梯度容易出现溢出或下溢。处理方式通常是加缩放因子但缩放因子本身需要统计统计不准就会出现损失尖峰。我在一个项目里遇到过这种情况切到低精度后训练损失在第两千步左右突然跳了一下当时以为是数据问题排查了很久最后定位到是某一层的缩放因子在特定 batch 下失效。这个坑的代价不只是排查时间。损失尖峰出现后标准做法是回滚到上一个检查点重跑重跑那一段的能耗是纯浪费而且往往比正常训练更费——因为回滚后通常会降低学习率、开梯度裁剪收敛更慢。所以低精度这件事我的建议是先在小规模上把数值稳定性验证充分逐层灰度开启并且准备好“哪几层必须保持高精度”的白名单。拿着白名单再上大规模比一把梭要稳得多。3.2 重算换显存这笔账大多数团队算错了激活重算是用计算换显存的经典手段原理是不保存中间激活反向传播时重新算一遍。从计算量上看标准的一前向加两反向大致是三个单位的工作量加上一次完整重算就变成四个单位计算量增加约三分之一。看起来这是拿能耗换显存不算节能手段。但实际账不是这么算的。省下来的显存可以换成更大的批大小、更少的模型并行切分、更少的流水线阶段这些变化会直接减少通信量和流水线气泡。在通信成为瓶颈的配置里重算带来的净效果经常是正的——计算多花了三分之一但通信等待时间减少得更多整体吞吐反而上升。我自己总结的判断标准是看瓶颈在哪。如果监控显示计算单元长期接近满载、通信占比很低那重算大概率是负收益应该尽量少用如果计算单元有明显空转、通信或数据加载在等重算往往能换来净收益。中间地带则要实测因为不同并行配置下的拐点位置差别很大。选择性重算只重算显存占用大的那几层比如注意力部分通常是个不错的折中增加的计算量明显小于全量重算省下的显存却接近全量重算的效果。3.3 算子融合与内核选择的隐性收益融合内核的价值经常被当成纯性能优化来看其实它在能耗上的意义可能更大。原因在于很多操作的瓶颈不在算力而在显存带宽把多个小算子合成一个减少的是中间结果的落盘和重读而这部分搬运的能耗占比在带宽受限的场景下相当高。注意力部分是最典型的例子。朴素的实现会把注意力分数矩阵完整写回显存再读出来做归一化序列长度上去之后这个中间矩阵的体积非常可观读写它的能耗可能超过计算本身。融合实现把整个过程放在片上完成显存读写量能降一个数量级。长序列场景下这个改动带来的吞吐提升经常是翻倍级别的能耗强度自然跟着大幅改善。选择内核时有个实际问题要注意不同实现的最优区间不一样。有的实现在中等序列长度下表现最好超长序列下因为分块策略的原因反而不如朴素实现。我的做法是在自己的实际序列长度分布上做一次基准测试而不是直接采用公开数据里的结论。测试的时候别忘了把端到端的墙钟时间和机柜功率一起记录只看单算子延迟容易做出错误判断。3.4 全局批大小的甜点区不在最大处这是一个非常反直觉的点把批大小拉满通常能让硬件利用率看起来更漂亮但不一定让总能耗下降。原因是样本效率。批大小增大到一定程度后达到同样损失水平需要的总 token 数会增加也就是每个 token 带来的梯度信息变少了。这时候你虽然单位时间处理得更快但总工作量变多了乘起来的总能耗可能是上升的。临界点的位置跟模型规模、数据质量、优化器配置都有关系。经验上在学习率没有相应放大的情况下批大小翻倍带来的样本效率损失可能达到百分之几到十几这个量级已经足以抵消掉吞吐提升带来的收益。所以做批大小调优时必须把“达到目标损失所需的总 token 数”作为约束条件一起看而不是只盯着每秒处理的 token 数。我自己的做法是跑三条曲线横轴是批大小纵轴分别是单步时间、每 token 能耗、以及达到验证集目标指标所需的总 token 数。三条曲线放在一起看甜点区通常在中间偏右的位置而不是最右端。这个测试成本不高通常几天能跑完但它能避免后面几周的训练全部跑在错误的工作点上。4. 搬运侧真正的大头常常不在算力单元里4.1 并行策略组合的能耗差异并行策略的选择直接决定了通信量而通信是纯开销——它不产生任何有效计算却要消耗网络设备、光模块和主机侧的功率。常见组合里数据并行在梯度同步时做全量规约通信量跟参数规模成正比张量并行在层内切分每层前后都要做激活的规约通信频繁但单次数据量小流水线并行通信量最小但会引入气泡气泡期间计算单元空转。从能耗角度评估这几种方案要看的不是通信总量而是“通信期间计算单元空转的比例”。张量并行的通信可以跟计算部分重叠实际影响较小流水线并行的气泡是硬等待期间功耗掉不下去但也没有产出这部分是纯浪费。所以在节点内带宽充裕的情况下适当多用张量并行、少用流水线并行往往能同时改善吞吐和能耗。序列维度的切分在长上下文训练里值得单独考虑。序列切分把注意力的计算分散到多个设备减少的是单个设备上的激活显存和中间矩阵体积通信量比张量并行小效果在超长序列下很明显。我参与过一个长上下文项目把部分张量并行换成序列并行之后通信时间占比从接近三成降到一成多机柜功率没变但吞吐涨了不少能耗强度改善明显。4.2 通信压缩与梯度累积的性价比梯度压缩是常见的降通信手段把梯度量化到低精度或者做稀疏化再传。收益很直观通信量能降一半甚至更多。代价是压缩和解压本身要消耗计算而且压缩带来的噪声可能影响收敛需要配合误差补偿之类的机制。实际收益要看通信在总时间里的占比。如果通信只占一成把它压缩一半端到端时间最多改善五个点但压缩解压的开销可能吃掉两三个点净收益很薄还要承担收敛变差的风险。我的经验是通信占比超过两成再考虑压缩低于这个线不如去优化拓扑或者调整并行切分。梯度累积经常被误认为能省通信这是个常见误解。梯度累积减少的是优化器更新频率梯度规约的次数并不会减少每一步累积仍然要做通信。它真正省下的是优化器状态更新的计算和显存开销以及可能的检查点体积。把它当成通信优化手段来用方向就错了。4.3 数据流水线空转最容易被忽略的浪费数据加载导致的空转是我见过最普遍也最容易被忽视的浪费。表现是加速卡利用率周期性地掉下去监控上看平均利用率还有七八成但掉下去的那些时段功耗并不低——板卡在等数据功率维持在三成到五成产出为零。原因通常是 CPU 侧的预处理跟不上。大规模训练的数据管道里往往有解码、增强、分词、打包这些步骤单看每一步都不慢串起来在高压并发下就会成为瓶颈。而且很多实现默认用较少的进程做预处理没有跟着加速卡数量一起扩。处理方式有几种把重预处理离线做掉训练时只读已经处理好的中间格式增加预处理进程数并做预取把数据打包packing做充分减少 padding 带来的无效计算。第三条对能耗的影响经常被低估——padding 部分照样参与计算照样耗电但不产生任何有效梯度。如果打包做得不好padding 占比到两成那就是两成的电白花了。还有一个细节本地盘和对象存储的读取策略。频繁的小文件随机读会拉高 CPU 等待和 IO 功耗改成顺序读大文件、配合内存缓存对整机功耗的影响比想象中明显。4.4 放置策略让通信留在机柜内部拓扑感知的任务放置是个低成本高产出的优化。同样的并行配置把通信密集的进程组放在同一个高带宽域内跨域通信量能降一个量级。这件事不需要改任何模型代码只是调度层的亲和性配置但很多团队没做。我在一个项目里做过对比同一套训练脚本随机放置和拓扑感知放置端到端吞吐差了接近两成。功率上倒没太大变化但因为时间短了两成总能耗同比下降。这类优化的性价比极高属于“先做这个再做别的”的序列。要注意的是放置策略跟并行配置是耦合的。张量并行要求同组进程之间带宽最高所以必须放在同一高带宽域内数据并行的规约可以跨域放在带宽较低的位置也能接受。换了并行配置就要重新检查放置规则否则原本最优的放置可能变成次优的。5. 机房侧的电PUE 之外的三个漏点5.1 风冷与液冷的分界线液冷经常被当成能耗优化的万能答案但它的收益高度依赖机柜功率密度。低密度场景下风冷的制冷能耗占比本来就不高上液冷的主要收益来自风扇功耗的消除而那部分在整机功耗里只占几个点投入产出比很差。密度上去之后情况反过来风冷需要极高的风量才能把热带走风扇功耗和冷机功耗同时飙升这时候液冷的优势才真正显现。判断分界线的一个粗略方法是看风扇功耗占整机功耗的比例。如果这个比例低于一成液冷的改造收益很有限超过一成半就值得认真评估了。当然这只是技术判断还要看改造条件和运维能力液冷对运维的要求比风冷高不少漏液风险和接头可靠性都是实际问题。5.2 供配电与制冷的低载低效区机房侧有两个效率洼地经常被忽略。一个是供配电链路变压器和 UPS 在低载时效率明显下降一批机器如果长期跑在低负载链路损耗的占比会显著上升。解决办法不是提高效率而是提高负载率——把任务集中到部分机柜跑满让其他机柜彻底下电这比让所有机柜都跑在三成负载要省得多。另一个是制冷系统的部分负载特性。冷水机组在低载时效率下降明显而且很多机房是按峰值负载配置制冷能力的实际长期跑在低载效率一直不在最优点。把冷机的出水温度适当提高在设备允许范围内、把机房内的气流组织理顺减少冷热混合这些操作的收益往往比换设备更快见效。5.3 余热回收到底能不能回本余热回收在宣传材料里看起来很美实际算账要谨慎。训练机房的余热品味不高液冷系统能拿到的热水温度通常在几十度这个量级这个温度能用的场景有限供暖、生活热水、部分工艺预热是比较现实的方向。但回收需要加装换热设备、铺设管路改造投入不小。能不能回本取决于三件事热源是否稳定、用热需求是否与供热的时空分布匹配、以及当地能源价格的对比关系。如果机房附近恰好有稳定的用热需求回收是有账可算的如果只是理论上能回收、实际上热量白白散掉那这笔投入就很难收回。我见过的比较务实的做法是先在新建项目里预留接口等用热侧的需求明确了再上设备而不是一步到位。6. 调度侧把“空等”变成“停机”6.1 检查点频率的能耗最优解检查点间隔是个典型的能耗权衡问题存得太频繁落盘消耗的 IO 和计算不少而且落盘期间训练往往要暂停存得太稀疏一旦故障回滚重跑的那段时间全是浪费。这个权衡有解析解最优间隔大致正比于“单次保存开销 × 平均无故障间隔”的平方根。这个公式不用记但它给出的直觉很有用故障率越高、保存越贵间隔应该越短但缩短的幅度是平方根关系不是线性关系。实际项目里更常见的错误是间隔设得太长。我见过设成每几小时一次的一次故障回滚重跑二十分钟一个月下来浪费的时间相当可观。也见过走另一个极端、每十几分钟存一次的落盘本身占掉了可观的吞吐。我的做法是先测出单次保存的实际耗时再结合集群的实际故障频率这个数据运维那边一般有套一下公式通常能得到一个比拍脑袋靠谱得多的值。另一个优化点是异步保存。把检查点先写到本地高速盘再在后台异步搬到长期存储这样训练不会被 IO 阻塞。这个改动看起来只是工程细节但能显著缩短落盘造成的停顿进而降低那部分空转功耗。6.2 弹性伸缩与故障恢复的隐性开销弹性训练听起来对能耗很友好——任务少了就缩容有资源就扩容。但伸缩本身有成本重新建立通信组、重新分片模型、重新预热数据流水线这些都发生在没有有效产出的时段。如果伸缩太频繁反复的重建开销可能超过弹性带来的收益。我的经验是给伸缩加一个迟滞窗口规模变化不超过一定比例就不触发重建同时尽量把伸缩点对齐到检查点让重建复用已有的分片状态。这两条能把弹性伸缩的隐性开销压下去一大半。故障恢复也是类似。大规模训练里单点故障是常态恢复时间的长短直接决定了浪费多少电。优化方向包括把检查点分布到多个存储节点避免单点瓶颈、预热阶段并行做健康检查、以及把恢复流程脚本化减少人工介入。这些都不难但需要提前设计事到临头再补往往来不及。6.3 任务整形把非紧急训练挪到空闲时段集群里跑的任务不是都紧急。实验性的、调参的、跑基线复现的这些任务对完成时间不敏感完全可以让它们填充到紧急任务的间隙里或者集中在某些时段跑。这样做的好处不只是提高利用率还能让机房在低峰期把部分机柜彻底下电避免长时间低载运行带来的效率损失。实现这件事需要调度器支持优先级和资源预留还需要团队形成习惯——把“这个实验什么时候要结果”写进任务描述里。听起来是管理问题实际对能耗的影响不小。一个跑满但负载率只有三成的集群能耗强度可能比一个负载率七成的集群差一倍以上。7. 一次真实改造的收益归因复盘7.1 改造前的基线数据说一个我参与过的改造过程规模是几百张卡的中等集群跑的是几十亿参数级别的模型预训练。改造前的基线MFU 在三成出头机柜侧统计的能耗强度大约是 0.2 token/J 的量级训练任务经常因为数据加载跟不上出现周期性掉利用率检查点间隔设得偏长一个月里发生过若干次故障回滚。当时团队的第一反应是换硬件但预算周期长先做了软件侧的排查。排查方式很简单把一次完整训练切成若干段每段记录加速卡利用率、通信占比、数据加载等待时间、以及机柜功率的时间序列然后人肉看曲线找规律。7.2 六项改动的逐项上线顺序第一项是修数据流水线。把重预处理离线化预处理进程数翻倍打开预取。这一项做完周期性掉利用率的现象基本消失MFU 从三成出头涨到接近四成。这一步没有改任何模型代码纯工程改动收益却最大。第二项是拓扑感知放置。按并行组的通信需求重新编排进程位置跨域通信量降下来端到端吞吐又涨了一截。第三项是调整并行配置把部分流水线并行换成序列并行气泡明显减少。第四项是把部分层的激活重算打开换来更大的批大小和更少的切分。第五项是异步检查点加间隔重算把落盘停顿压下去。第六项才是低精度而且只在前几层和输出层保留了高精度白名单。顺序很重要。前两项做完MFU 已经涨到四成五左右这时候再上低精度收益就变得很难归因——因为前面几项已经把明显的瓶颈消掉了。事后复盘时我们讨论过如果一开始就上低精度很可能因为数值不稳定反复回滚把时间耗在排查上而真正的瓶颈数据加载一直没被发现。7.3 踩过的三个坑第一个坑是重算的误判。我们一开始把全量重算打开结果吞吐反而掉了因为那个配置的瓶颈已经不在通信上了纯粹是计算量增加。后来改成只重算注意力部分才拿到正收益。这件事的教训是任何“节省资源”的手段都要在瓶颈分析之后再用。第二个坑是把梯度累积当成通信优化。有一版配置加大了累积步数期望减少通信实测通信时间一点没变反而因为有效批大小变大导致收敛需要更多步。这个误解很常见值得单独强调。第三个坑是基线口径不一致。中间有一版数据是用板卡功耗统计的跟前面的机柜功耗混在一张表里对比得出了“某项改动收益 12%”的结论后来统一口径重算只有 5%。口径这件事必须在开始前定死中途改口径等于把所有结论作废。最后分享一个我自己一直在用的小习惯在训练脚本的日志里固定输出每百步的吞吐、加速卡利用率均值、以及从管理接口读到的平均板卡功率三行就够。这些数据跟着实验记录一起存事后做归因的时候不用再去翻监控系统直接看日志就能还原当时的状况。这个习惯不花什么成本但省下来的排查时间相当可观。