第四章:Golden Data生成:如何生成标准参考数据?
做算子精度对齐,说白了就是拿你的计算结果跟“标准答案”去比。那这个“标准答案”从哪来?这就是我们今天要聊的——Golden Data生成。
我个人习惯把Golden Data叫做“金标准”。它必须是可信的、可复现的。你想想看,如果参考数据本身就有问题,那后面的精度对齐就是白忙活。我在项目中遇到过好几次,团队花了两周查精度问题,最后发现是Golden Data生成脚本里有个类型转换的bug……嗯,从那以后我定了个规矩:Golden Data的生成代码必须单独review。
4.1 三种主流生成方式
生成Golden Data,常用的路子有三条。我按推荐程度排个序:
| 生成方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 随机数 | 单元测试、边界测试 | 覆盖范围广,能发现意外问题 | 不可复现(需固定种子) |
| 固定模式 | 回归测试、性能基线 | 完全可复现,便于调试 | 可能遗漏边界情况 |
| 真实数据 | 端到端验证、上线前测试 | 最贴近实际场景 | 数据量大,依赖外部输入 |
别急着选。我建议你根据算子类型和验证阶段来组合使用。比如我自己做卷积算子对齐时,单元测试用随机数,回归测试用固定模式,上线前再用真实数据跑一遍。
4.2 随机数生成:别让“随机”坑了你
随机数看着简单,其实坑不少。我曾经在生成随机数时没固定种子,结果每次跑出来的Golden Data都不一样,精度对齐根本没法做。
正确的做法是这样:
import numpy as np
# 固定随机种子,保证可复现
np.random.seed(42)
def generate_random_golden(shape, dtype=np.float32):
"""生成随机Golden Data"""
# 使用均匀分布,覆盖正负值
data = np.random.uniform(-1.0, 1.0, shape).astype(dtype)
return data
# 使用示例
golden_input = generate_random_golden((32, 64, 224, 224))
golden_weight = generate_random_golden((64, 64, 3, 3))
这里有个细节:我习惯用均匀分布而不是正态分布。为什么?因为均匀分布能保证每个数值区间都有样本,更容易暴露数值精度问题。我在做量化算子对齐时,就靠这个发现了几个数值饱和的bug。
4.3 固定模式:调试时的好帮手
固定模式说白了就是“我知道输入是什么,我也知道输出应该是什么”。这在调试时特别有用。
我个人常用的固定模式有几种:
- 全零/全一矩阵:最简单的基线,用来验证算子是否正常工作
- 单位矩阵:适合验证矩阵运算类算子
- 等差数列:比如1,2,3,4,...,方便人工验算中间结果
- 特殊数值:比如最大值、最小值、NaN、Inf等边界值
def generate_fixed_golden(mode='identity', shape=(4, 4)):
"""生成固定模式的Golden Data"""
if mode == 'zeros':
return np.zeros(shape, dtype=np.float32)
elif mode == 'ones':
return np.ones(shape, dtype=np.float32)
elif mode == 'identity':
return np.eye(shape[0], dtype=np.float32)
elif mode == 'range':
return np.arange(np.prod(shape), dtype=np.float32).reshape(shape)
elif mode == 'extreme':
data = np.random.randn(*shape).astype(np.float32)
data[0, 0] = np.finfo(np.float32).max # 最大值
data[0, 1] = np.finfo(np.float32).min # 最小值
return data
else:
raise ValueError(f"Unknown mode: {mode}")
4.4 真实数据:最接近实战的验证
真实数据是检验算子的最终标准。但这里有个矛盾:真实数据往往很大,而且涉及数据版权问题。
我的做法是:
- 裁剪数据:从真实数据集中随机抽取小批量,比如100张图片
- 预处理对齐:确保预处理流程(归一化、resize等)与训练时完全一致
- 保存为numpy格式:避免重复加载原始数据
def generate_real_golden(data_loader, num_samples=100):
"""从真实数据集中生成Golden Data"""
golden_data = []
for i, (inputs, _) in enumerate(data_loader):
if i >= num_samples:
break
# 确保数据在CPU上,转为numpy
golden_data.append(inputs.cpu().numpy())
# 合并并保存
golden_array = np.concatenate(golden_data, axis=0)
np.save('golden_real_data.npy', golden_array)
return golden_array
这里要注意:真实数据的分布可能跟随机数完全不同。我在做图像算子的精度对齐时,发现随机数测试全过,但真实图片一跑就出问题。后来查出来是某些像素值接近0时,浮点精度损失被放大了。
4.5 知识体系总览
下面这张图是我自己总结的Golden Data生成决策流程,你可以参考:
4.6 实战中的避坑指南
最后,分享几个我踩过的坑:
坑1:数据类型不一致
我曾经用float64生成Golden Data,但算子内部用的是float32。结果精度对不上,查了两天才发现是类型不匹配。记住:Golden Data的数据类型必须跟算子输入完全一致。
坑2:随机种子没固定
这个前面提过,但值得再说一遍。不固定种子,你的Golden Data就是一次性的,没法复现问题。
坑3:真实数据预处理不一致
真实数据在训练时可能做了归一化、数据增强等操作。如果你生成Golden Data时没做同样的预处理,那结果肯定对不上。我建议把预处理逻辑封装成一个函数,Golden Data生成和算子调用都用同一个函数。
嗯,Golden Data生成这块就聊到这。记住一个原则:你的Golden Data必须可信、可复现、可追溯。下次做精度对齐时,先花10分钟把Golden Data生成流程理清楚,后面能省你好几天的时间。
想要更多资料,联系可可