实验生命周期治理概述
实验工作流的治理层:保护破坏性操作,标准化指标,使用门槛对实验进行排名,并审计竞争规则。
三个子系统:
PIN 保护 —— 4 位 PIN 守护取消/停止/删除操作
指标注册表 —— 标准化指标定义和阈值
Compare-Scores —— 多模型排名和门槛
安装
pip install expflow-pde
~/.expflow/pin.hash # 4 位 PIN 的 SHA-256 哈希值(永远不以明文存储)
~/.expflow/experiments.jsonl # 实验注册表(每行 = JSON 记录)
模块设计
# pin.py —— 4 个组件:
# 1. init_pin(pin: str) -> hash # 验证 + 哈希 + 写入
# 2. verify_pin(pin: str) -> bool # 哈希比较
# 3. pin_is_set() -> bool # 检查 PIN 是否配置
# 4. guard(action_description) -> bool # 交互式提示
# sha256 哈希 —— 永远不存储原始 PIN
def _hash_pin(pin: str) -> str:
return hashlib.sha256(pin.encode()).hexdigest()
# 验证确切 4 位数字
def _validate_pin(pin: str) -> None:
if not pin.isdigit() or len(pin) != 4:
raise ValueError("PIN 必须是确切 4 位数字(0-9)")
CLI 命令
expflow pin init 1234 # 设置 PIN(存储 SHA-256 哈希值)
expflow pin check # 交互式验证
expflow pin clear [--force] # 删除 PIN
expflow pin status # 显示 PIN 状态
# 受 PIN 守护的命令(需要 PIN 除非 --force):
expflow run cancel # 交互式 PIN 提示
expflow run cancel --force # 跳过 PIN
STANDARD_METRICS = {
"seg_total": {
"type": "scalar",
"group": "Score",
"higher_is_better": True,
"description": "总分段评分(主要竞争指标)",
},
"pde_mean": {
"type": "scalar",
"group": "PDE",
"higher_is_better": False,
"threshold": 18.09, # 竞争门槛
},
"train_time_min": {
"type": "scalar",
"group": "Time",
"higher_is_better": False,
"threshold": 60, # 竞争限制
},
# ... 13 个指标跨越 Score/Loss/PDE/Time/Model/Training 组
}
report_standard()
def report_standard(task: Any | None = None, **kwargs: float) -> dict[str, float]:
reported = {}
for name, value in kwargs.items():
info = STANDARD_METRICS.get(name)
if info is None:
raise ValueError(f"未知指标 '{name}'...")
reported[name] = float(value)
if task is not None:
task.report_scalar(title=info["group"], series=name, value=float(value), iteration=0)
return reported
CLI
expflow clearml compare-scores \
--project PDEBench --tags task1 \
--sort-by pde_mean --ascending \
--gate pde_mean:lt:18.09 --gate train_time_min:lt:60
门槛格式
门槛使用指标:操作符:值三元组:
pde_mean:lt:18.09 —— PDE 均值 < 18.09
train_time_min:le:60 —— 训练时间 ≤ 60 分钟
seg_total:ge:50 —— 评分 ≥ 50
操作符:lt, le, gt, ge。
CLI
expflow audit validate exp-001 --competition-rules --task-id abc123
Python API
from expflow_pde.audit import validate_competition_rules
result = validate_competition_rules(
task_metrics={"seg_total": 57.09, "pde_mean": 15.0, "train_time_min": 45.5},
task_params={"Args/--sub_step": "5"},
)
print(f"All pass: {result['all_pass']}")
验证检查
检查条件 详细信息
seg_total 主要竞争评分(无门槛) 已报告,不受门槛限制
pde_mean 必须 < 18.09 标准化指标中的阈值
train_time_min 必须 < 60 标准化指标中的阈值
sub_step 参数 必须存在且 > 0 不区分大小写搜索
测试模式
PIN 测试(36 个测试)
哈希一致性:相同输入 → 相同哈希
验证拒绝:错误长度、非数字、空
初始化 → 文件存在且哈希正确
守护模拟:正确 → True,退出 → False
指标测试
注册表结构:每个指标具有类型、组、higher_is_better
report_standard:返回已报告指标的字典
比较测试
_apply_gate:所有 4 个操作符(lt/le/gt/ge)及其通过和失败案例
陷阱
PIN 哈希值必须不在 config.yaml 中(风险为 git 提交)。使用 ~/.expflow/pin.hash。
优先级:pin.hash 文件 > .env EXPFLOW_PIN_HASH > config.yaml pin.hash。
- get_last_scalar_metrics() clearml API
返回嵌套字典:{"Score": {"seg_total": {"last": 57.09, ...}}, ...}。
展平为 {"seg_total": 57.09} 以用于 compare_scores。
始终在 PIN 守护命令中提供 --force / -f 以用于 CI/自动化。
- 交互式 getpass vs 非交互式 getpass
getpass.getpass() 在终端中有效,但在管道命令、CI 或子代理调用中失败。
始终提供 --pin 或 --force 作为替代路径。