fix(configs): 修复 resnet18 训练配置无法构建,并补上对应的评估配置

- configs/train/resnet18.yaml 此前直接报错:它同时继承 tiny_conv 与 resnet18 的模型
  配置,深度合并后 backbone 混了两边字段。在 configs/model/resnet18.yaml 的 backbone
  上加 _replace_: true 整块替换
- _replace_ 标记此前不生效:_load_raw 对每个 base 都会先 deep_merge({}, data),
  标记在参与替换判断之前就被剥掉了。改为合并期间保留、load_config 末尾统一剥除
- 新增 configs/eval/resnet18.yaml:评估必须与训练用同一套模型配置,否则构建出的
  骨架与权重对不上,而此前只有 baseline 一个评估配置
- 新增参数化测试:仓库里每个配置都要能真的构建出组件(片段自动跳过),
  且训练/评估配置对的 model 段必须一致
- README 补充骨架与配置对的对应表

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Shaun Zhou
2026-09-04 15:42:14 +08:00
co-authored by Claude Opus 5
parent e581d9b3d7
commit 47fb0f1125
5 changed files with 99 additions and 9 deletions
+14 -9
View File
@@ -64,21 +64,25 @@ def deep_merge(base: Mapping, override: Mapping) -> dict:
merged = dict(base)
for key, value in override.items():
if isinstance(value, Mapping) and value.get(REPLACE_KEY):
merged[key] = _strip_replace_key(value)
merged[key] = dict(value) # 整块替换;标记本身留到最后统一剥掉
elif key in merged and isinstance(merged[key], Mapping) and isinstance(value, Mapping):
merged[key] = deep_merge(merged[key], value)
else:
merged[key] = _strip_replace_key(value) if isinstance(value, Mapping) else value
merged[key] = value
return merged
def _strip_replace_key(value: Mapping) -> dict:
"""去掉 `_replace_` 标记本身,避免它漏进组件的构造参数。"""
return {
k: (_strip_replace_key(v) if isinstance(v, Mapping) else v)
for k, v in value.items()
if k != REPLACE_KEY
}
def strip_replace_keys(value: Any) -> Any:
"""剥掉所有 `_replace_` 标记,避免它漏进组件的构造参数。
必须等**全部合并做完**再剥:`_load_raw` 对每个 base 都会先 `deep_merge({}, data)`
一次,若在那时就剥掉,标记还没来得及参与真正的替换判断就没了。
"""
if isinstance(value, Mapping):
return {k: strip_replace_keys(v) for k, v in value.items() if k != REPLACE_KEY}
if isinstance(value, list):
return [strip_replace_keys(v) for v in value]
return value
def _load_raw(path: Path, seen: set[Path]) -> dict:
@@ -132,5 +136,6 @@ def apply_overrides(cfg: dict, overrides: Iterable[str]) -> dict:
def load_config(path: str | Path, overrides: Iterable[str] = ()) -> Config:
cfg = _load_raw(Path(path), set())
cfg = apply_overrides(cfg, overrides)
cfg = strip_replace_keys(cfg)
cfg.setdefault("config_path", str(Path(path).resolve()))
return Config(cfg)