FAIRChem Evaluator 深度解析:模型评估中能量力指标的完整计算路径
FAIRChem Evaluator 深度解析模型评估中能量力指标的完整计算路径【免费下载链接】ocpFAIR Chemistrys library of machine learning methods for chemistry项目地址: https://gitcode.com/GitHub_Trending/oc/ocp一、能量误差 0.014 eV 是怎么算出来的训练完一个 MLIP 模型验证日志里跳出 energy MAE 0.014 eV、forces MAE 0.05 eV/Å。数字看着眼熟但每个数到底怎么算的在 FAIRChemocp 仓库里这件事由Evaluator评估模块负责给它 prediction 和 target 两个字典它按任务查表、逐指标求错、跨 batch 累积最后吐出模型评估所需的各项数字。本文以src/fairchem/core/modules/evaluator.py为主线把指标计算、running 累积和接入完整评估流程的路径走一遍让你能独立复现、调试任何一个指标值也能看懂榜单式报告里的口径差异。二、核心概念速览5 个词先分清指标口径术语一句话定义最小示例task选择内置指标表的任务名Evaluator(tasks2ef)property误差计算所针对的数据键forcesmetrics_dict把误差张量包成三件套的装饰器{metric: 0.1, total: 0.2, numel: 2}running 累积结果里的 metric 恒为 total/numel 的全局均值0.2 / 2 0.1threshold 指标满足双阈值条件的 system 占比numel 记系统数力 0.03 且能 0.02容易混的地方在分母均值类指标按元素个数累积threshold 指标按 system 个数累积两者拼到同一个字典里时口径并不一致。另一个隐含概念是 primary metric每个任务有一个被指定的主指标s2ef 用energy_forces_within_thresholdis2re 用energy_mae选最佳 checkpoint 时通常就看它。三、工作原理从两个张量到一行 running 均值整条链路按数据流走不看类结构prediction / target 两个 dict → 按 task 查指标表property → [函数名] → 按名调用指标函数第三个实参传 property → 逐样本误差张量 → 包装成 {metric, total, numel} → update() 累加进 prev_metrics → 返回 running 均值第一站是查表。task_metrics是类变量s2ef 拆成 energy 和 forces 两组is2rs 只有 positionsis2re 只有 energy。传入eval_metrics时整张表被替换不做合并。第二站是按名调用。源码直接用内建eval(fn)从模块全局解析指标函数property 名作为key传进去。这里失败很直白pred/target 缺键就是 KeyError函数名不存在v1 抛 NameErrorv2 的get_metrics_fn对下划线开头的私有名直接 ValueError。第三站是包装与累积。均值类指标走metrics_dict对误差张量取 mean/sum/numelthreshold 指标自己返回三件套内部按 natoms 把 forces 行切成每个 system能量误差和该 system 内的最大力误差同时达标才计一次。update()每轮用 total/numel 重算 metric 字段所以返回值始终是全量 running 均值。average_distance_within_threshold还依赖min_diff做周期边界下的最小镜像位移再对 [0.01, 0.5) 的阈值区间做 AUC 式累加。进一步看 MLIP v2 的路径src/fairchem/core/units/mlip_unit/_metrics.pycompute_metrics在求错前先做三件事——用 output mask 过滤eval_on_free_atoms时按fixed掩掉固定原子、normalizer 反归一化、能量任务撤销 element references然后才调用同一套指标函数累积改用Metrics数据类的__iadd__。四、关键参数怎么选4 个入口加 2 个隐藏阈值参数名默认值作用什么时候需要改taskNone选内置指标表必设取 s2ef / is2rs / is2reeval_metricsNone整体替换内置表只要子集或自定义键时prev_metricsNone接收上一轮累积状态第 2 个 batch 起必传keyNONE_SLICE误差计算的张量切片只算单一分量时p2magnitude_error 的范数阶想要 L1 幅度误差时两个隐藏常量更值得注意energy_forces_within_threshold的 0.03 eV/Å 与 0.02 eV 是硬编码的不开放配置AUC 指标的积分区间 [0.01, 0.5)、步长 0.001 同样写死。想调阈值只能改源码或自己写函数。有三个点反直觉。⚠️ 返回的 metric 是 running 均值不是单 batch 值。update()每轮覆盖 metric 字段单 batch 的结果看起来正常含义却是迄今所有样本的均值。跨 batch 使用时传入的是同一个 dict 对象原地变更别每轮重置。metric 命名藏着特判。键名通常是property_fn但函数名已含 property 时不重复forcesx_mae不加前缀property 为 misc 时也不加。写解析指标名的后处理时不能按第一个下划线切分。文档字符串里的 import 其实是失效的。文件头注释写from fairchem.core.modules import Evaluator但该包的__init__是空的实际必须用from fairchem.core.modules.evaluator import Evaluator。五、实战3 种场景覆盖单 batch 到验证集场景一核对单 batch 能量误差is2repred/target 只需 energy 键from fairchem.core.modules.evaluator import Evaluator import torch evaluator Evaluator(taskis2re) pred {energy: torch.tensor([1.0, 2.0])} target {energy: torch.tensor([1.1, 1.9])} metrics evaluator.eval(pred, target) print(metrics[energy_mae][metric]) # 0.1注意返回字典固定三个键——energy_mae、energy_mse、energy_within_threshold主指标是前者。场景二验证循环里累积数据集级指标prev {} for pred, target in val_batches: # 逐 batch 累积 prev evaluator.eval(pred, target, prev_metricsprev) mae prev[energy_mae][metric] # 全量 running 均值注意prev 必须原样传回它是同一个 dict 被原地更新每轮复制一份再传就会丢累积。场景三用 eval_metrics 裁剪指标表A/B 对比时只留关键指标提速evaluator Evaluator( tasks2ef, eval_metrics{energy: [mae], forces: [mae]}, ) metrics evaluator.eval(pred, target)注意值的函数名必须已存在于模块全局eval(fn)找不到会抛 NameError。完整评估跑法见 docs/core/common_tasks/evaluation.md核心就是一条命令fairchem --config 你的评估配置.yaml。六、进阶接进 MLIP v2 评估闭环与下游 benchmark 模块组合看两个落点。其一是 MLIP v2 评估闭环EvalRunner驱动 dataloaderMLIPEvalUnit每个 batch 调compute_metricsMetrics对象按 task × dataset × metric 三层字典累积epoch 结束在on_eval_epoch_end里跨进程聚合后logger.log。指标列表不写死在配置里而是随 checkpoint 的 task 配置一起由load_tasks读出配置模板见 configs/uma/evaluate/uma_direct.yaml。其二是下游 benchmarkBenchmarkReducer接受一个 evaluator 可调用对象把弛豫、结构搜索这类多步计算的输出和标签喂进去算最终指标力 MAE 这类榜单数字就建立在这套函数之上。组合时的约束有三条threshold 指标要求 forces 行数等于 natoms 之和源码有显式 assert批内 forces 必须是展平布局v2 指标函数名必须是模块全局下划线开头的私有函数被拒cosine_similarity会先转 float32自己写自定义指标时 fp16 下也要先转否则 0/0 出 nan。端到端接线参考from fairchem.core.modules.evaluator import Evaluator evaluator Evaluator(tasks2ef) prev {} for pred, target in val_batches: prev evaluator.eval(pred, target, prev_metricsprev) primary evaluator.task_primary_metric[s2ef] print(primary, prev[primary][metric])七、高频问题排查4 个指标口径的坑为什么 energy_forces_within_threshold 比MAE 已达标的印象低两条件是 AND力看的是系统内最大误差而非均值一个原子偏大就整系统失败。先看逐系统误差分布再下结论。为什么自己累积的 MAE 和最后一批的值对不上metric 恒为 total/numel 的全局 running 均值不是最近 batch。以完整 pass 结束后的 total/numel 为准。混合精度下 cosine_similarity 为什么出 nanfp16 里 0/0 除零所致源码显式转 float32 规避。自定义指标同理先 cast 再算。v2 里自定义指标名为什么抛 ValueErrorget_metrics_fn只查模块全局表且拒绝下划线开头的名字。用公开函数名并保证它注册在_metrics模块内。八、延伸阅读想验证边界行为测试用例里的断言比文档更诚实tests/core/evaluator/test_evaluator.py 用三个 fixture 覆盖了 s2ef / is2rs / is2re 全套指标键的产出。评估配置的写法Hydra defaults 组合、WB 日志在 docs/core/common_tasks/evaluation.md 里有完整说明benchmark 侧的指标复算可对照 benchmarks/omol/force_mae.py。【免费下载链接】ocpFAIR Chemistrys library of machine learning methods for chemistry项目地址: https://gitcode.com/GitHub_Trending/oc/ocp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考