上一章我们停在哪里
上一篇里,我们聊了怎么读取 GPU 功耗、怎么设计一个基本实验、怎么避免三个最常见的坑。读完之后,你应该能跑通一条测量链路:写脚本、采数据、画曲线、算能耗。
但"能测"和"测得可信"之间,还隔着一段距离。
这段距离不是技术问题,是协议问题。你需要回答:这次测量的条件是什么?哪些参数真的生效了?环境状态记录了吗?如果失败了,失败是显式的还是被静默吞掉了?三个月后有人想复现你的结果,他凭什么相信你报告里的数字?
这篇文章聊的就是这件事:**怎么把你的测量脚本升级成一套测量协议**——一套让数据可复现、可比较、可审计的规则。
第一个教训:参数必须真的生效
测量协议的第一条原则听起来像废话:**你报告里写的参数,必须和实际执行的一致。**
但它不是废话。因为这个问题在我自己的测量容器里真实存在过,而且存在了很长时间才被发现。
具体来说:容器接受一个 `context_length` 参数,报告里也会写上 `context_length: 2048`。但实际执行时,prompt 始终只有约 20 个 token——参数是装饰性的。这意味着所有标注 `context_length = 2048` 的报告,其实际输入长度与标称值不符。
这个问题的可怕之处在于:**它不会报错。** 测量流程正常走完,输出格式完全正确,数字看起来合理。如果你不去对照实际 prompt 长度和标称值,你永远不会发现。
修复之后,容器会把 prompt 平铺或截断到参数指定的精确长度。但修复带来了一个新问题:**r4 之前和之后的报告不可直接比较**,即使它们都标注 2048。因为一个实际是 20 token,一个是真正的 2048 token。
解决方案是在提交系统里加一条分类规则:
- **Qualified submission**:`context_length = 2048`,与 v1.1.0 基线直接可比
- **Exploratory submission**:`context_length ≠ 2048`,形成独立可比类,不与 v1.1.0 直接比较
这不是技术限制,是诚实性要求。一个名义 2048 实际 20 的数据点,和一个真正 2048 的数据点,不该出现在同一张表里。
**协议设计的第一条规则:每一个写入报告的参数,都必须有对应的执行时校验。如果参数没生效,报告必须标注,而不是假装它生效了。**
第二个教训:环境状态必须记录
GPU 功耗不是一个孤立数字,它依赖于环境条件。其中最重要的一个条件是**温度**。
同一张卡、同一个模型、同一个精度,在 32°C 冷态和 65°C 稳态下的功耗读数会有系统性偏差。如果你不记录测量时的温度状态,你就无法判断两次测量之间的差异是来自配置变化,还是来自温度漂移。
我的 schema v1.2 就定义了 `temperature_start_c`、`temperature_end_c`、`temperature_peak_c` 等字段。但容器从未输出过它们——报告里的 thermal block 一直是空壳,schema 描述里甚至自己承认 "the container does not yet emit it (tracked issue)"。
这意味着已发布的 42 个种子测量没有 thermal 记录。它们的热状态是"未知",不是"冷态"。当你看到一份报告没有温度数据时,你不能假设它是标准条件——你只能假设你不知道条件是什么。
修复后,容器在测量窗口内通过 NVML 读取 GPU 温度并填充完整的 thermal block。同时新增 `--thermal_mode` 参数:
- **cold**(默认):冷却到空闲、固定 warmup 后测量
- **steady**:持续加温直至连续读数波动小于 2°C 再测量
对于 AMD/ROCm 主机和 dry-run 模式,thermal block 标注 `basis: "unavailable"` 而非编造数值。
**协议设计的第二条规则:每一个可能影响读数的环境条件,都必须有对应的记录字段。如果条件未知,报告必须显式标注"未知",而不是留空或省略。**
第三个教训:失败必须是显式的
测量系统会失败。硬件不支持、驱动不兼容、参数越界、超时、进程被杀——失败的方式有无数种。
问题不是"会不会失败",而是"失败的时候系统怎么表现"。
在添加 AMD GPU 检测之前,我的容器在 ROCm 主机上运行时会尝试调用 NVML、失败、然后报一个不透明的错误。用户看到的是一个崩溃的进程和一段看不懂的堆栈跟踪。他不知道是硬件不支持,还是配置错了,还是 bug。
更糟糕的是,有些用户可能会尝试"修复"这个问题——比如用 NVIDIA 的功耗拟合曲线去估算 AMD GPU 的能耗。这种跨架构外推比没有数字更糟,因为它给你一个看起来合理但实际上毫无根据的值。
修复后(PR #20,由贡献者 @amarjithkumar2007-wq 提交),容器检测到 AMD 设备后会明确报告:
```
measurement_source: "ecocompute-dataset (AMD GPU detected, NVML is NVIDIA-only)"
energy_per_token_j: unavailable
```
能耗值报告为 `unavailable`——不借用、不估算、不外推。原生 ROCm 功耗遥测(`rocm-smi` / `rocprof`)是后续工作,但在它落地之前,诚实的"我不知道"比虚假的"大约是 X"更有价值。
**协议设计的第三条规则:当测量无法完成时,系统必须显式报告失败原因和缺失字段,而不是静默崩溃或编造数值。**
第四个教训:可复现性需要追踪机制
测量协议的最终目的是让数据可复现。但"可复现"不是一个二元属性,它是一个程度——你需要追踪哪些信息才能让另一个人复现你的结果?
最低限度,你需要:
1. **代码版本**:测量脚本的 commit hash 或版本号
2. **环境配置**:GPU 型号、驱动版本、CUDA 版本、关键库版本
3. **执行参数**:所有影响测量结果的输入参数
4. **原始数据**:完整的功耗时间序列,而不仅仅是聚合后的均值
但光有这些还不够。你还需要一个机制来追踪**谁在什么时候做了什么修改**,以及这些修改对数据可比性的影响。
这就是为什么我们在这一周里不仅修了 bug,还建立了贡献者系统。具体来说:
- 新增 `/contribute/` 页面,列出五条具体贡献路径(跑测量、写代码、报 bug、改进协议、传播)
- About 页面添加致谢部分,公开感谢贡献者
- `CONTRIBUTING.md` 里新增作者政策:
- ≥ 2 个合并的代码 PR,或
- ≥ 1 次合格数据提交(protocol-conformant 的 energy.json 被接收)
满足条件者受邀列入论文/数据集的作者名单。单次 bug 修复和 typo 更正在 release notes 中致谢,但不构成作者资格。
这不是形式主义。一个依赖社区贡献的开放数据集,如果贡献者的名字只出现在 git log 里而不出现在论文上,就不会有足够多的人愿意花时间跑测量。这条政策意味着:外部开发者合并的第 3 个 PR,已经使他具备论文共同作者资格。
**协议设计的第四条规则:你必须追踪数据的来源、修改历史和贡献者,否则"可复现"只是一句空话。**
从规则到检查清单
把上面四条规则汇总,你可以得到一个测量协议的最低检查清单:
参数校验
- [ ] 报告中的每个参数,是否在执行时真的被使用?
- [ ] 如果参数未生效,是否有显式标注?
- [ ] 参数变化是否会导致数据不可比?如果是,是否有分类机制?
环境记录
- [ ] 是否记录了所有可能影响读数的环境条件(温度、湿度、负载状态)?
- [ ] 如果某个条件未知,是否显式标注为"未知"而非留空?
- [ ] 是否有标准化的环境控制流程(如冷启动 vs. 稳态)?
失败处理
- [ ] 测量失败时,是否显式报告失败原因?
- [ ] 缺失字段是否标注为 `unavailable` 而非省略或编造?
- [ ] 是否避免了跨架构/跨硬件的外推估算?
可复现性追踪
- [ ] 是否记录了代码版本(commit hash 或版本号)?
- [ ] 是否记录了完整的环境配置?
- [ ] 是否保存了原始数据(时间序列),而不仅仅是聚合结果?
- [ ] 是否追踪了数据的修改历史和贡献者?
不可比声明:诚实的代价
当你按照这套协议运行一段时间后,你会遇到一个尴尬的问题:**历史数据和当前数据不可比。**
比如我的例子里,r4 之前的 `context_length` 报告实际 prompt 长度与标称值不符,与 r4+ 不可直接比较;thermal 落地之前的报告无热状态记录,无法判断测量温度条件;AMD 主机的报告能耗值为 `unavailable`,不是测量结果。
这时候你有两个选择:
1. **假装它们可比**,把它们放在同一张表里,不标注差异。这样你的数据集看起来更完整、更有说服力。
2. **显式声明不可比**,给每份报告标注 `schema_version`,让读者自己判断哪些数据可以放在一起比较。
我选了第二个。因为第一个选项的代价是:一旦有人发现你的数据不可比(而他们会发现),你的整个数据集的可信度都会崩塌。
所有已发布报告都标注了 `schema_version`,读者可据此判断可比性。完整变更史见 changelog——每条都链接到其证据。
**这不是完美主义,是长期主义。一个有明确局限性的数据集,比一个看起来完美但经不起追问的数据集更有价值。**
下一步
这篇聊的是测量协议的设计原则。下一篇我们会进入更具体的话题:**怎么做跨 GPU 的对比实验**——当你的测量协议已经能保证单 GPU 数据的可信度之后,如何让不同 GPU 之间的数据也可比、可复现。
---
*这是"GPU 能耗测量入门"系列的第二章。第一章讲了怎么测,这一章讲了怎么让测出来的数据可信。系列文章:*
- *第零章:写给非硬件背景开发者的 GPU 功耗测量入门*
- *第一章:从一次测量到一组可信数据:测量协议设计入门(本文)*
- *第二章(预告):跨 GPU 对比实验的设计与陷阱*
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。