可复现实验从数据版本和度量口径开始
可复现实验从数据版本和度量口径开始
复现实验最怕“代码没变,结果变了”。通常不是玄学,而是数据切分、依赖、随机状态或度量实现没有一起版本化。下面把这些变量收进一份可复核记录。
1. 把实验状态视为一个整体
机器学习工程化的重点是让一次结论能够被独立复核。数据版本、配置、随机状态和产物位置应当一同记录;任何缺项都应视为结论的边界,而不是用经验补齐。
实验结论要注明适用数据和未覆盖项。数据、依赖或执行路径变化后,旧结果只能作为历史记录,不能直接沿用。
2. 从单一断言逐步扩展
可先把问题缩小为固定输入上的单一断言,再逐步加入数据切分、训练和服务环节。比较不同方案时,保持其余条件不变,并把失败样本作为下一轮检查材料。
每一步都留下能失败的断言,只保存输入摘要、配置和结果摘要。这样既能定位差异,也不必在排障材料中复制原始数据。
3. 稳定切分的示意实现
以下片段保留原有技术结构。运行前请替换为本地的非敏感示例,并根据依赖版本核对接口。
全量原始数据 (按时间戳严格排序 T_0 -> T_N) └── [T_0 ---------> T_train_end] ──> 训练集 (80%) └── [T_train_end --> T_val_end] ──> 验证集 (10%) └── [T_val_end ----> T_N] ──> 独立测试集 (10%)import hashlib def assign_bucket_by_hash(entity_id: str, salt: str = "exp_0813") -> float: """ 根据实体ID的哈希值映射到 [0, 1) 区间,实现稳定不漂移的数据切分 """ raw_str = f"{entity_id}_{salt}" hash_hex = hashlib.md5(raw_str.encode('utf-8')).hexdigest() # 截取前8位十六进制转为整数并归一化 hash_int = int(hash_hex[:8], 16) return hash_int / 0xFFFFFFFF # 示例:同一脱敏记录标识在相同 salt 下映射值恒定 bucket_val = assign_bucket_by_hash("record_example") train_flag = bucket_val < 0.8 # 80% 归入训练集4. 复跑前逐项核对
- 数据切分是否由版本化规则生成,而不是手工复制。
- 随机种子、依赖锁文件和硬件信息是否随结果保存。
- 比较双方是否使用同一数据范围与度量实现。
- 失败样本能否用最小脚本重新触发。
总结
可复现不等于每次浮点值都逐位相同,而是差异有来源、条件能还原、结论可再次检验。