Commit Graph
19 Commits
Author SHA1 Message Date
Shaun ZhouandClaude Opus 5 6e543660ce feat(configs): 新增 resnet101 的自监督聚类配置
resnet101 此前不在 TorchvisionBackbone 的支持列表里,先补进 _SUPPORTED
(out_channels 2048),随后被既有的参数化测试自动覆盖:能前向、声明维度与实际一致。

configs/cluster/film_simclr_resnet101.yaml 仿照 resnet18/50 两份,只改骨架与
batch_size,其余超参一致以便横向对比:
- 42.5M 参数(resnet18 11.2M / resnet50 23.5M),layer2+3 仍是 1536 维,
  与 resnet50 相同,差别在深度(layer3 有 23 个 block 而非 6 个)
- batch_size 取 128:MPS 上 resnet50 在 1024 已 OOM,resnet101 约重 1.8 倍故再降一档;
  注释里说明该数字来自 MPS,16 GB 独显上可往上调
- pretrained 首次使用会下载约 171 MB 权重

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 20:51:16 +08:00
xzhou c9e7e4104c fix(configs): update dataset root path in film.yaml 2026-09-07 12:36:51 +00:00
Shaun ZhouandClaude Opus 5 92c88b785c fix(config): --set 拦下不存在的键,并支持续训时重开学习率曲线
用户反馈"聚类配置里改不了 lr/weight_decay",实测是两件事:

1. --set 的键打错字母会凭空造出一个谁也不读的键,训练照跑但改动无效。
   实例:simclr.optmizer.weight_decay=0.0(optimizer 少个 i)被静默接受。
   现在 apply_overrides 默认只允许覆盖已存在的键,报错时给出同级可用键
   与最接近的拼写("是不是想写 'optimizer'?")。需要新增键时可 strict=False。

2. lr 其实生效了,但从 2229/2500 续训时 cosine 只剩满值的 3%,
   新设的 1e-3 落到 2.87e-5。新增 restart_schedule 开关:按剩余轮数重开曲线,
   新 lr 从满值开始;SimCLR 与检测训练都支持。续训日志补上调度进度,
   并在 lr 不足 initial_lr 的 10% 时警告并给出两种解法。

顺带:严格校验立刻暴露出 configs/cluster/film.yaml 里根本没有 scatter 段
(代码 cfg.get("scatter", {}) 兜底走默认值,所以功能正常但配置项形同虚设),已补上。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 19:30:17 +08:00
xzhou 01cfff9b02 fix(configs): update optimizer settings and add projection parameters in film_simclr_resnet50.yaml 2026-09-07 06:25:54 +00:00
Shaun ZhouandClaude Opus 5 5d395b7c25 chore: 数据迁到 data/raw/ 后同步所有路径引用
原始数据从 data/<数据集> 移到了 data/raw/<数据集>。

- 聚类配置的 dataset.root:film / pearlescent 均改为 data/raw/ 下
- 检测配置的 img_dir 与 label_dir 注释同步
- README、data/README、算法文档、流程图(含重新渲染的 PNG)与各脚本
  docstring 里的路径示例一并更新
- data/README 补充目录约定:原始数据只读放 data/raw/,
  export_clusters.py 的派生数据集放在 data/ 下与 raw/ 平级
- 顺手把 unlabeled 数据集加进 datasets/__init__.py:此前它没在包初始化时注册,
  build_dataset({"name": "unlabeled"}) 只有在别处先 import 过该模块时才可用

迁移后重跑全量聚类,结果与迁移前逐项一致(轮廓 0.3255、稳定性 0.9641、
簇大小 [4507, 3795, 4849, 1428])。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 11:19:42 +08:00
Shaun ZhouandClaude Opus 5 5f31ed0a92 feat(configs): 新增 resnet50 的自监督聚类配置
仿照 film_simclr_resnet18.yaml,只改骨架与 batch_size,其余超参保持一致以便对比。

batch_size 取 256 而非照抄 resnet18 的 1024:实测 resnet50 在 Apple MPS 上
batch 1024 直接 OOM(需 18.7 GiB),batch 128 时 604 MB。每 epoch 耗时与 batch
基本无关(约 155 秒,算力受限),所以调小 batch 不花额外时间,只是负样本变少。

配置注释里记下了实测数据与降级路径(显存不够继续调到 128 / 64),
并说明 resnet50 的 layer2+3 是 1536 维(resnet18 为 384 维)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 11:07:55 +08:00
xzhou 7f13ec5d18 fix(configs): update training epochs and optimizer settings in film_simclr_resnet18.yaml 2026-09-06 05:05:47 +00:00
xzhou 703ba7076b fix(configs): update num_clusters and training parameters in film_simclr_resnet18.yaml 2026-09-04 13:41:41 +00:00
xzhou 6b11128357 fix(configs): update film_simclr_resnet18.yaml with new clustering parameters and optimizer settings 2026-09-04 09:19:15 +00:00
Shaun ZhouandClaude Opus 5 6f00074199 feat(cluster): 新增 resnet18 自监督聚类配置,并修复 --set 的 YAML 标量解析
- 新增 configs/cluster/film_simclr_resnet18.yaml:用 resnet18 做域内自监督后聚类。
  backbone 块带 _replace_,避免 base 里 tiny_conv 的 widths/depths 残留
- parse_override 此前只用 ast.literal_eval,不认 YAML 风格的 null/true/false:
  `--set xxx.enabled=false` 会得到字符串 "false",而非空字符串是真值,开关反被打开。
  改为先试 Python 字面量(保住 1e-3 这类),再退回 YAML 标量解析
- feature_stages 默认由 null 改为 [5, 6]:实测 1 epoch 自监督后 layer2+3 的轮廓
  0.243/稳定性 0.997,明显优于 layer4 的 0.156/0.528。原注释里"自监督后 layer4
  已是域内特征"的推断被数据推翻
- README 补充三种方案的实测对比与成本

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 15:51:28 +08:00
Shaun ZhouandClaude Opus 5 47fb0f1125 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>
2026-09-04 15:42:14 +08:00
xzhou 4e6c8aa2ea fix: update work directory in film.yaml and add pearlescent.yaml configuration 2026-09-04 06:54:06 +00:00
Shaun Zhou 4550fdfa8e feat(cluster): add ImageNet pre-trained model section and adjust batch sizes 2026-09-03 15:47:37 +08:00
Shaun ZhouandClaude Opus 5 345dee50da feat(simclr): 支持断点续训,恢复优化器与调度器状态
此前 simclr.checkpoint 的语义是"有权重就跳过训练",没有真正的续训:
中途停掉再启动只能从头再来,或者放弃已训的轮次。

- 新增 simclr_last.pth:骨架 + 投影头 + 优化器 + 调度器 + scaler + epoch + step,
  与给下游用的 simclr_backbone.pth 并存,两者在同一时机落盘
- 新增 simclr.resume:载入完整状态从下一个 epoch 接着练。只恢复权重不恢复动量与
  cosine 进度的话,续训时损失会先反弹一段
- resume 与 checkpoint 互斥(同时给直接报错);拿只含骨架的 simclr_backbone.pth
  去 resume 会给出可操作的报错,提示改用 checkpoint
- 续训轮数已达计划值时不再训练,只打警告

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 09:34:55 +08:00
Shaun ZhouandClaude Opus 5 be6173c746 feat(simclr): 接入 SwanLab 可视化,并补上本地看板缺失的依赖
- SimCLRTrainer 记录 simclr/loss、loss_avg、lr(按 step)与 epoch_loss、
  epoch_seconds、gpu_mem_peak_mb(按 epoch),超参为完整 yaml 配置;
  正常结束与 KeyboardInterrupt 两条路径都会 finish()
- 配置新增 simclr.swanlab(字段同 train.swanlab),默认 mode: local,
  不需要登录,日志写到 <work_dir>/swanlog
- 依赖改为 swanlab[dashboard]:此前 `swanlab watch` 在干净环境里会报
  "Please install the swanboard package",README 里检测训练那节的看板命令
  同样受影响,现已随 uv sync 装好
- README 补齐本地看板/云端/离线补传三种用法与端口、局域网参数

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 09:24:39 +08:00
Shaun ZhouandClaude Opus 5 b6f83fcad0 fix(simclr): 周期性落盘,中途中断不再丢失训练成果
此前 fit() 只在全部 epoch 跑完后才保存骨架,一次跑到 epoch 12 被停掉后
13 分钟的训练全部作废。

- 每 save_interval(默认 5)个 epoch 保存一次骨架
- 捕获 KeyboardInterrupt,中断时先落盘再返回
- 聚类脚本改用 resolve_device,自监督分支不再有 GPU 守卫

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 21:43:35 +08:00
Shaun ZhouandClaude Opus 5 141cb907f2 feat: 支持 cuda / mps / cpu 三后端,Mac 上可用 MPS 训练
移除"训练必须有 Nvidia GPU"的硬性守卫,改为按后端能力分派。

- utils/device: resolve_device("auto") 按 cuda > mps > cpu 挑最快的可用后端;
  显式指定不可用的后端时直接报错,不会悄悄退回 CPU——训练慢几十倍却不吭声是最坏的情况
- AMP 随后端取默认值:CUDA 开、MPS 关。MPS 上 autocast 数值正常但实测更慢
  (tiny_conv @128²:fp32 76 ms/步、fp16 90 ms、bf16 108 ms),需要时 amp: true 可强开
- PeakMemory 统一显存峰值统计:CUDA 读内置计数器,MPS 无峰值 API 改用逐 step 采样
  (是下界,日志与产出里已标注)
- profile_inference 支持 MPS,并提示 torch.profiler 没有 MPS 的 ProfilerActivity,
  算子明细只反映 CPU 侧下发耗时
- train.py / eval.py 新增 --device,配置默认改为 auto
- check_env 改为列出全部可用后端与 auto 的选择结果

实测:tiny_conv 训练在 MPS 上比 CPU 快约 32 倍。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 21:43:35 +08:00
Shaun ZhouandClaude Opus 5 f433e5cf59 feat: 未分类样本的无监督聚类(多 stage 特征 + KMeans,可选 SimCLR)
把 data/film 下所有图片拉平做聚类,不使用任何目录名,簇数由 num_clusters 决定。

预处理针对该批数据的实际情况(14.5k 张已裁好的缺陷小图,中位 152x113,
宽高比 0.24~39.9):尺寸与亮度都是 ROI 裁剪和光照的产物、不是缺陷属性,
因此拉伸到 128x128(不用 letterbox,其填充比例等价于编码了宽高比)并逐图 z-score。

- cluster: torch 实现的 kmeans++/Lloyd(含空簇处理与 n_init)、PCA、轮廓系数、
  NMI 稳定性、多 stage 特征提取;不引 scikit-learn
- 白化默认关闭:CNN 特征谱极陡(λ1/λ32≈165x),白化会把噪声方向抬到与信号同权,
  实测最大簇一度吃掉 96% 的样本
- simclr: NT-Xent 自监督预训练,用项目自己的卷积骨架,权重可直接初始化 DefectNet;
  属于训练,走 require_cuda() 守卫
- 产出 assignments.csv、summary.json、按簇的软链目录与代表样本拼图,供人工核对

全量 14,579 张:轮廓系数 0.326、换种子稳定性 0.964,CPU 约 100 秒。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 17:55:47 +08:00
Shaun ZhouandClaude Opus 5 b0d0dfffbb feat: 训练与评估入口及 yaml 配置
- train.py: 先过 require_cuda() 守卫再建模型/数据,支持 --resume 与 --set 覆盖
- eval.py: 允许 CPU,输出定位与分类指标并可写 json
- configs: model/dataset/train/eval 四类,通过 `_base_` 组合;
  classes 既可直接写列表,也可指向 YOLO data.yaml 由框架读 names

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 17:55:20 +08:00