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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
4b1147ed8f
commit
f433e5cf59
@@ -0,0 +1,109 @@
|
||||
# 未分类样本的无监督聚类。
|
||||
#
|
||||
# 预处理决策(针对 data/film 的实际情况:14.5k 张已裁好的缺陷小图,
|
||||
# 中位尺寸 152x113,宽高比 0.24~39.9,尺寸几乎每张都不同):
|
||||
#
|
||||
# 前提:图片的尺寸和宽高比是上游 ROI 裁剪环节的产物,不是缺陷属性。
|
||||
# 所以预处理的目标是**把这个采集噪声抹掉**,只留下缺陷的纹理/形态。
|
||||
#
|
||||
# 1. 直接 Resize 拉伸到 128x128,不用 letterbox —— letterbox 的填充比例
|
||||
# 恰好等价于编码了宽高比,灰边占多少就等于把采集噪声明着喂给网络;
|
||||
# 拉伸则让所有图变成同一个画幅,宽高比不再是可用信号。
|
||||
# 2. use_shape_features 关掉 —— 同理,尺寸不进 embedding。
|
||||
# 3. 逐图标准化(PerImageStandardize)而不是固定的 ImageNet mean/std ——
|
||||
# 整体亮度来自光照和相机增益,同样不是缺陷属性。用固定归一化时,
|
||||
# 4 个簇里有 3 个花在"背景偏亮/偏暗"上;改成逐图 z-score 后,
|
||||
# 簇变成"条纹状 / 团块状 / 弱纹理",轮廓 0.256->0.322,稳定性 0.966->0.995。
|
||||
# 4. 不下采样到 224 —— 这批图本来就小,放大只会糊,128 已经够。
|
||||
#
|
||||
# 代价:拉伸会让纹理各向异性形变(40:1 的长条尤其明显)。如果后续发现
|
||||
# 聚类被形变干扰,可选的替代是在原始分辨率上取固定大小的中心 patch
|
||||
# (不缩放、不填充),配置里把 Resize 换成 CenterCrop 即可。
|
||||
|
||||
work_dir: runs/cluster
|
||||
seed: 42
|
||||
device: cuda # method=pretrained 时可以 --set device=cpu
|
||||
|
||||
num_clusters: 6 # 想分几类改这里(或 --num-clusters 6)
|
||||
|
||||
# pretrained: ImageNet 预训练卷积骨架直接抽特征,不训练,CPU 也能跑,几分钟出结果。
|
||||
# simclr: 在本目录数据上自监督训练项目自己的卷积骨架,域适配更好,需要 Nvidia GPU。
|
||||
method: pretrained
|
||||
|
||||
# method=pretrained 用的骨架(method=simclr 的骨架配在 simclr.backbone,两者字段完全不同,
|
||||
# 各自独立以免 _base_ 合并时串味)
|
||||
backbone:
|
||||
name: torchvision
|
||||
arch: resnet18
|
||||
pretrained: true
|
||||
in_channels: 3
|
||||
|
||||
image_size: [128, 128]
|
||||
use_shape_features: false # 尺寸/宽高比是采集产物,不作为聚类特征;true 仅供对照实验
|
||||
|
||||
# 取哪几个 stage 的特征拼起来(torchvision resnet 的 features 下标:4~7 = layer1~4)。
|
||||
# 实测(2000 张随机样本,k=4):
|
||||
# 只用最后一层 layer4 轮廓 0.191 换种子稳定性 0.410
|
||||
# layer2+3 轮廓 0.256 稳定性 0.989 <- 默认
|
||||
# layer2+3+4 轮廓 0.220 稳定性 0.627
|
||||
# 缺陷之间的差别主要在纹理(颗粒感、条纹方向、边缘锐度),中间层保留得比最后一层好;
|
||||
# 最后一层的 ImageNet 语义("这是猫还是车")对这批图基本是噪声。
|
||||
feature_stages: [5, 6]
|
||||
|
||||
# 特征降维。whiten 默认关闭:CNN 特征只有前若干主成分携带结构,
|
||||
# 白化会把剩下几十个噪声方向抬到同权,簇立刻塌成"一个大簇 + 几个碎簇"
|
||||
# (实测开白化时最大簇占 96%,关掉后降到 38%)。
|
||||
pca_dim: 32
|
||||
whiten: false
|
||||
n_init: 10
|
||||
|
||||
# 只用一部分样本拟合质心以节省时间(0 = 用全部);纯随机抽取,不按目录分层——
|
||||
# 目录名是人工整理的历史产物,不参与聚类。拟合完仍会把全部样本分配到最近的簇。
|
||||
fit_max_samples: 0
|
||||
|
||||
dataset:
|
||||
name: unlabeled
|
||||
root: data/film
|
||||
gray: false
|
||||
exclude: [images, labels] # 跳过已经整理成 YOLO 结构的部分
|
||||
transforms:
|
||||
- {name: Resize, size: [128, 128]} # 拉伸,不保长宽比:见文件开头的说明
|
||||
- {name: ToTensor}
|
||||
- {name: PerImageStandardize} # 逐图 z-score,抹掉整体亮度/对比度
|
||||
|
||||
loader:
|
||||
batch_size: 64
|
||||
num_workers: 8
|
||||
|
||||
# method=simclr 时每个视图各自过一遍的随机增强(正样本对就是同一张图的两个视图)
|
||||
view_transforms:
|
||||
- {name: RandomResizedCrop, size: [128, 128], scale: [0.5, 1.0]}
|
||||
- {name: RandomHorizontalFlip, p: 0.5}
|
||||
- {name: RandomVerticalFlip, p: 0.5}
|
||||
- {name: ColorJitter, brightness: 0.4, contrast: 0.4}
|
||||
- {name: GaussianBlur, p: 0.3}
|
||||
# 注意:主 transforms 里的 PerImageStandardize 会在这些增强之后执行,
|
||||
# 所以 ColorJitter 的亮度扰动最终会被抵消掉,起作用的主要是裁剪/翻转/模糊。
|
||||
|
||||
simclr:
|
||||
# 自监督用项目自己的纯卷积骨架:练出来的权重可以直接拿去初始化 DefectNet 的 backbone
|
||||
backbone:
|
||||
name: tiny_conv
|
||||
in_channels: 3
|
||||
widths: [32, 64, 128, 256]
|
||||
depths: [1, 2, 2, 2]
|
||||
block: dw
|
||||
feature_stages: null # tiny_conv 不是 nn.Sequential,取最终输出
|
||||
epochs: 100
|
||||
batch_size: 256
|
||||
temperature: 0.2 # 越小越关注难负样本
|
||||
amp: true
|
||||
log_interval: 20
|
||||
checkpoint: null # 填已有的 simclr_backbone.pth 可跳过重复训练
|
||||
projection: {hidden_channels: 256, out_channels: 128}
|
||||
optimizer: {name: adamw, lr: 0.001, weight_decay: 0.0001}
|
||||
scheduler: {name: cosine}
|
||||
|
||||
# 输出:每簇软链多少张图 / 预览拼图放多少张
|
||||
link_limit: 300
|
||||
preview_count: 25
|
||||
Reference in New Issue
Block a user