docs: 无监督聚类的数学说明、mermaid 图与 README
- docs/unsupervised-clustering.md: 逐图标准化对仿射光照群的不变性证明、 多 stage 特征的取舍、PCA 白化失效的谱分析、KMeans 收敛性与 kmeans++ 近似比、 轮廓系数与 NMI 稳定性的定义、NT-Xent 与 InfoNCE 下界,附全部消融数据与代码对照表 - figures/: 四张 mermaid 图(流水线、KMeans 控制流、SimCLR、主成分谱), 含 .mmd 源、.md 预览与渲染好的 .png - README: 数据准备、训练评估、多类/单类、SwanLab、Profiler、聚类与自监督的运行说明 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
d6adea5b05
commit
4fc0fa5353
@@ -0,0 +1,80 @@
|
||||
# 无监督聚类流水线
|
||||
|
||||
从 `data/film` 的原始图片到可人工核对的分组结果:六个阶段的数据流、张量形状与每步的数学操作。
|
||||
虚线是可选的 SimCLR 自监督分支(`method: simclr`,需要 Nvidia GPU)。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
classDef input fill:#D1FAE5,stroke:#10B981,stroke-width:2px,color:#064E3B
|
||||
classDef prep fill:#DBEAFE,stroke:#2563EB,stroke-width:2px,color:#1E3A8A
|
||||
classDef feat fill:#DBEAFE,stroke:#2563EB,stroke-width:2px,color:#1E3A8A
|
||||
classDef reduce fill:#EDE9FE,stroke:#7C3AED,stroke-width:2px,color:#4C1D95
|
||||
classDef cluster fill:#EDE9FE,stroke:#7C3AED,stroke-width:2px,color:#4C1D95
|
||||
classDef out fill:#FFEDD5,stroke:#EA580C,stroke-width:2px,color:#7C2D12
|
||||
classDef metric fill:#FEF3C7,stroke:#D97706,stroke-width:2px,color:#78350F
|
||||
|
||||
scan["data/film 递归扫描<br/>N = 14,579 张 PNG<br/>尺寸各异 84×83 ~ 4464×1139"]:::input
|
||||
|
||||
subgraph PRE["① 预处理 — 抹掉采集因子"]
|
||||
direction LR
|
||||
resize["双线性拉伸<br/>H×W → 128×128<br/>不保长宽比"]:::prep
|
||||
tensor["转张量 + RGBA/L → RGB<br/>x ∈ ℝ³ˣ¹²⁸ˣ¹²⁸"]:::prep
|
||||
zscore["逐图标准化<br/>x̃ = (x − μₓ) / σₓ<br/>抹掉亮度 μ 与对比度 σ"]:::prep
|
||||
resize --> tensor --> zscore
|
||||
end
|
||||
|
||||
subgraph FEAT["② 特征提取 — 纹理优先"]
|
||||
direction LR
|
||||
stem["resnet18 stem<br/>conv1 → bn → relu → maxpool"]:::feat
|
||||
l1["layer1<br/>64ch, stride 4"]:::feat
|
||||
l2["layer2<br/>128ch, stride 8"]:::feat
|
||||
l3["layer3<br/>256ch, stride 16"]:::feat
|
||||
gap2["GAP → ℓ₂ 归一化<br/>u⁽²⁾ ∈ S¹²⁷"]:::feat
|
||||
gap3["GAP → ℓ₂ 归一化<br/>u⁽³⁾ ∈ S²⁵⁵"]:::feat
|
||||
concat["拼接<br/>z = [u⁽²⁾; u⁽³⁾] ∈ ℝ³⁸⁴"]:::feat
|
||||
stem --> l1 --> l2 --> l3
|
||||
l2 --> gap2 --> concat
|
||||
l3 --> gap3 --> concat
|
||||
end
|
||||
|
||||
subgraph RED["③ 降维"]
|
||||
direction LR
|
||||
norm["ℓ₂ 归一化<br/>ẑ = z / ‖z‖₂"]:::reduce
|
||||
pca["PCA 投影 384 → 32<br/>y = Uᵀ(ẑ − z̄)<br/>不白化:保留 λ 谱"]:::reduce
|
||||
norm --> pca
|
||||
end
|
||||
|
||||
subgraph CLU["④ 聚类 K-Means"]
|
||||
direction LR
|
||||
init["k-means++ 初始化<br/>p(xᵢ) ∝ D(xᵢ)²"]:::cluster
|
||||
lloyd["Lloyd 迭代<br/>指派 ↔ 更新质心"]:::cluster
|
||||
best["n_init = 10<br/>取 inertia 最小的一次"]:::cluster
|
||||
assign["全量指派<br/>cᵢ = argminⱼ ‖yᵢ − μⱼ‖₂"]:::cluster
|
||||
init --> lloyd --> best --> assign
|
||||
end
|
||||
|
||||
subgraph EVAL["⑤ 无标签评估"]
|
||||
direction LR
|
||||
sil["轮廓系数 s̄<br/>簇是否紧致"]:::metric
|
||||
stab["换种子稳定性<br/>NMI(C_seed0, C_seed7)"]:::metric
|
||||
end
|
||||
|
||||
subgraph OUT["⑥ 产出"]
|
||||
direction LR
|
||||
csv["assignments.csv<br/>路径 / 簇号 / 距质心"]:::out
|
||||
links["clusters/cluster_XX/<br/>软链目录,按距质心排序"]:::out
|
||||
prev["cluster_XX_preview.png<br/>代表样本拼图"]:::out
|
||||
summ["summary.json<br/>簇大小 / 轮廓 / 稳定性"]:::out
|
||||
end
|
||||
|
||||
simclr["可选:SimCLR 自监督<br/>method = simclr<br/>需 Nvidia GPU"]:::feat
|
||||
|
||||
scan --> PRE
|
||||
PRE -->|"x̃ᵢ"| FEAT
|
||||
scan -.->|"双视图增强"| simclr
|
||||
simclr -.->|"域内骨架权重"| FEAT
|
||||
FEAT -->|"z ∈ ℝᴺˣ³⁸⁴"| RED
|
||||
RED -->|"y ∈ ℝᴺˣ³²"| CLU
|
||||
CLU -->|"标签 c"| EVAL
|
||||
CLU -->|"标签 c + 距离 d"| OUT
|
||||
```
|
||||
@@ -0,0 +1,73 @@
|
||||
flowchart TB
|
||||
classDef input fill:#D1FAE5,stroke:#10B981,stroke-width:2px,color:#064E3B
|
||||
classDef prep fill:#DBEAFE,stroke:#2563EB,stroke-width:2px,color:#1E3A8A
|
||||
classDef feat fill:#DBEAFE,stroke:#2563EB,stroke-width:2px,color:#1E3A8A
|
||||
classDef reduce fill:#EDE9FE,stroke:#7C3AED,stroke-width:2px,color:#4C1D95
|
||||
classDef cluster fill:#EDE9FE,stroke:#7C3AED,stroke-width:2px,color:#4C1D95
|
||||
classDef out fill:#FFEDD5,stroke:#EA580C,stroke-width:2px,color:#7C2D12
|
||||
classDef metric fill:#FEF3C7,stroke:#D97706,stroke-width:2px,color:#78350F
|
||||
|
||||
scan["data/film 递归扫描<br/>N = 14,579 张 PNG<br/>尺寸各异 84×83 ~ 4464×1139"]:::input
|
||||
|
||||
subgraph PRE["① 预处理 — 抹掉采集因子"]
|
||||
direction LR
|
||||
resize["双线性拉伸<br/>H×W → 128×128<br/>不保长宽比"]:::prep
|
||||
tensor["转张量 + RGBA/L → RGB<br/>x ∈ ℝ³ˣ¹²⁸ˣ¹²⁸"]:::prep
|
||||
zscore["逐图标准化<br/>x̃ = (x − μₓ) / σₓ<br/>抹掉亮度 μ 与对比度 σ"]:::prep
|
||||
resize --> tensor --> zscore
|
||||
end
|
||||
|
||||
subgraph FEAT["② 特征提取 — 纹理优先"]
|
||||
direction LR
|
||||
stem["resnet18 stem<br/>conv1 → bn → relu → maxpool"]:::feat
|
||||
l1["layer1<br/>64ch, stride 4"]:::feat
|
||||
l2["layer2<br/>128ch, stride 8"]:::feat
|
||||
l3["layer3<br/>256ch, stride 16"]:::feat
|
||||
gap2["GAP → ℓ₂ 归一化<br/>u⁽²⁾ ∈ S¹²⁷"]:::feat
|
||||
gap3["GAP → ℓ₂ 归一化<br/>u⁽³⁾ ∈ S²⁵⁵"]:::feat
|
||||
concat["拼接<br/>z = [u⁽²⁾; u⁽³⁾] ∈ ℝ³⁸⁴"]:::feat
|
||||
stem --> l1 --> l2 --> l3
|
||||
l2 --> gap2 --> concat
|
||||
l3 --> gap3 --> concat
|
||||
end
|
||||
|
||||
subgraph RED["③ 降维"]
|
||||
direction LR
|
||||
norm["ℓ₂ 归一化<br/>ẑ = z / ‖z‖₂"]:::reduce
|
||||
pca["PCA 投影 384 → 32<br/>y = Uᵀ(ẑ − z̄)<br/>不白化:保留 λ 谱"]:::reduce
|
||||
norm --> pca
|
||||
end
|
||||
|
||||
subgraph CLU["④ 聚类 K-Means"]
|
||||
direction LR
|
||||
init["k-means++ 初始化<br/>p(xᵢ) ∝ D(xᵢ)²"]:::cluster
|
||||
lloyd["Lloyd 迭代<br/>指派 ↔ 更新质心"]:::cluster
|
||||
best["n_init = 10<br/>取 inertia 最小的一次"]:::cluster
|
||||
assign["全量指派<br/>cᵢ = argminⱼ ‖yᵢ − μⱼ‖₂"]:::cluster
|
||||
init --> lloyd --> best --> assign
|
||||
end
|
||||
|
||||
subgraph EVAL["⑤ 无标签评估"]
|
||||
direction LR
|
||||
sil["轮廓系数 s̄<br/>簇是否紧致"]:::metric
|
||||
stab["换种子稳定性<br/>NMI(C_seed0, C_seed7)"]:::metric
|
||||
end
|
||||
|
||||
subgraph OUT["⑥ 产出"]
|
||||
direction LR
|
||||
csv["assignments.csv<br/>路径 / 簇号 / 距质心"]:::out
|
||||
links["clusters/cluster_XX/<br/>软链目录,按距质心排序"]:::out
|
||||
prev["cluster_XX_preview.png<br/>代表样本拼图"]:::out
|
||||
summ["summary.json<br/>簇大小 / 轮廓 / 稳定性"]:::out
|
||||
end
|
||||
|
||||
simclr["可选:SimCLR 自监督<br/>method = simclr<br/>需 Nvidia GPU"]:::feat
|
||||
|
||||
scan --> PRE
|
||||
PRE -->|"x̃ᵢ"| FEAT
|
||||
scan -.->|"双视图增强"| simclr
|
||||
simclr -.->|"域内骨架权重"| FEAT
|
||||
FEAT -->|"z ∈ ℝᴺˣ³⁸⁴"| RED
|
||||
RED -->|"y ∈ ℝᴺˣ³²"| CLU
|
||||
CLU -->|"标签 c"| EVAL
|
||||
CLU -->|"标签 c + 距离 d"| OUT
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 193 KiB |
@@ -0,0 +1,47 @@
|
||||
# K-Means:k-means++ 初始化 + Lloyd 迭代
|
||||
|
||||
`engine/cluster.py` 里 `kmeans()` 与 `cluster_features()` 的完整控制流:空簇处理、收敛判据、多次重启取最优,以及子集拟合 + 全量指派。
|
||||
虚线是各阶段内部的循环回边。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
classDef start fill:#D1FAE5,stroke:#10B981,stroke-width:2px,color:#064E3B
|
||||
classDef step fill:#DBEAFE,stroke:#2563EB,stroke-width:2px,color:#1E3A8A
|
||||
classDef decide fill:#FEF3C7,stroke:#D97706,stroke-width:2px,color:#78350F
|
||||
classDef guard fill:#FFE4E6,stroke:#BE123C,stroke-width:2px,color:#881337
|
||||
classDef done fill:#FFEDD5,stroke:#EA580C,stroke-width:2px,color:#7C2D12
|
||||
|
||||
input["输入 Y = { yᵢ } ⊂ ℝ³², i = 1…N (可先随机抽子集拟合:fit_max_samples)<br/>目标 min_{C,μ} J(C,μ) = Σᵢ ‖yᵢ − μ_{c(i)}‖² — NP-hard,只求局部最优"]:::start
|
||||
|
||||
subgraph INIT["① k-means++ 初始化 (期望近似比 E[J] ≤ 8(ln k + 2)·J_opt)"]
|
||||
direction LR
|
||||
pick1["均匀随机取 μ₁"]:::step
|
||||
dist["D(y) = min_{j≤t} ‖y − μⱼ‖"]:::step
|
||||
sample["按 p(y) ∝ D(y)² 采样 μ_{t+1}<br/>离已有质心越远越易被选中"]:::step
|
||||
kdone{"够 k 个?"}:::decide
|
||||
pick1 --> dist --> sample --> kdone
|
||||
kdone -.->|"否,继续挑"| dist
|
||||
end
|
||||
|
||||
subgraph LLOYD["② Lloyd 迭代 (J 单调不增且有下界,故必收敛)"]
|
||||
direction LR
|
||||
assign["指派步<br/>c(i) = argminⱼ ‖yᵢ − μⱼ‖²<br/>一次 cdist 算完 N×k 距离"]:::step
|
||||
update["更新步<br/>μⱼ ← mean{ yᵢ : c(i) = j }<br/>均值是簇内平方距离的唯一最小点"]:::step
|
||||
empty{"有空簇?"}:::decide
|
||||
steal["把离自身质心最远的点<br/>提为该空簇的新质心<br/>保证簇数不缩水"]:::guard
|
||||
conv{"|J_prev − J| ≤ tol·J_prev<br/>或迭代满 100 次?"}:::decide
|
||||
assign --> update --> empty
|
||||
empty -->|"否"| conv
|
||||
empty -->|"是"| steal --> conv
|
||||
conv -.->|"否,回到指派步"| assign
|
||||
end
|
||||
|
||||
repeat["③ 以上 ①② 整体重复 n_init = 10 次<br/>每次换随机种子 seed + r"]:::step
|
||||
best["④ 取 10 次里 J 最小的一次 (C*, μ*)<br/>缓解 Lloyd 只保证局部最优"]:::done
|
||||
final["⑤ 全量指派 cᵢ = argminⱼ ‖yᵢ − μ*ⱼ‖,i = 1…N<br/>并记录到质心的距离 dᵢ,供排序与离群检查"]:::done
|
||||
|
||||
input --> INIT
|
||||
kdone ==>|"是,得到初值 μ⁽⁰⁾"| assign
|
||||
conv ==>|"是,本次收敛"| repeat
|
||||
repeat --> best --> final
|
||||
```
|
||||
@@ -0,0 +1,40 @@
|
||||
flowchart TB
|
||||
classDef start fill:#D1FAE5,stroke:#10B981,stroke-width:2px,color:#064E3B
|
||||
classDef step fill:#DBEAFE,stroke:#2563EB,stroke-width:2px,color:#1E3A8A
|
||||
classDef decide fill:#FEF3C7,stroke:#D97706,stroke-width:2px,color:#78350F
|
||||
classDef guard fill:#FFE4E6,stroke:#BE123C,stroke-width:2px,color:#881337
|
||||
classDef done fill:#FFEDD5,stroke:#EA580C,stroke-width:2px,color:#7C2D12
|
||||
|
||||
input["输入 Y = { yᵢ } ⊂ ℝ³², i = 1…N (可先随机抽子集拟合:fit_max_samples)<br/>目标 min_{C,μ} J(C,μ) = Σᵢ ‖yᵢ − μ_{c(i)}‖² — NP-hard,只求局部最优"]:::start
|
||||
|
||||
subgraph INIT["① k-means++ 初始化 (期望近似比 E[J] ≤ 8(ln k + 2)·J_opt)"]
|
||||
direction LR
|
||||
pick1["均匀随机取 μ₁"]:::step
|
||||
dist["D(y) = min_{j≤t} ‖y − μⱼ‖"]:::step
|
||||
sample["按 p(y) ∝ D(y)² 采样 μ_{t+1}<br/>离已有质心越远越易被选中"]:::step
|
||||
kdone{"够 k 个?"}:::decide
|
||||
pick1 --> dist --> sample --> kdone
|
||||
kdone -.->|"否,继续挑"| dist
|
||||
end
|
||||
|
||||
subgraph LLOYD["② Lloyd 迭代 (J 单调不增且有下界,故必收敛)"]
|
||||
direction LR
|
||||
assign["指派步<br/>c(i) = argminⱼ ‖yᵢ − μⱼ‖²<br/>一次 cdist 算完 N×k 距离"]:::step
|
||||
update["更新步<br/>μⱼ ← mean{ yᵢ : c(i) = j }<br/>均值是簇内平方距离的唯一最小点"]:::step
|
||||
empty{"有空簇?"}:::decide
|
||||
steal["把离自身质心最远的点<br/>提为该空簇的新质心<br/>保证簇数不缩水"]:::guard
|
||||
conv{"|J_prev − J| ≤ tol·J_prev<br/>或迭代满 100 次?"}:::decide
|
||||
assign --> update --> empty
|
||||
empty -->|"否"| conv
|
||||
empty -->|"是"| steal --> conv
|
||||
conv -.->|"否,回到指派步"| assign
|
||||
end
|
||||
|
||||
repeat["③ 以上 ①② 整体重复 n_init = 10 次<br/>每次换随机种子 seed + r"]:::step
|
||||
best["④ 取 10 次里 J 最小的一次 (C*, μ*)<br/>缓解 Lloyd 只保证局部最优"]:::done
|
||||
final["⑤ 全量指派 cᵢ = argminⱼ ‖yᵢ − μ*ⱼ‖,i = 1…N<br/>并记录到质心的距离 dᵢ,供排序与离群检查"]:::done
|
||||
|
||||
input --> INIT
|
||||
kdone ==>|"是,得到初值 μ⁽⁰⁾"| assign
|
||||
conv ==>|"是,本次收敛"| repeat
|
||||
repeat --> best --> final
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 172 KiB |
@@ -0,0 +1,29 @@
|
||||
# PCA 主成分谱与白化的失效
|
||||
|
||||
**蓝柱**:真实特征在各主成分上的方差占比 λⱼ/Σλ(2000 张随机样本,layer2+3,384 维)。
|
||||
前 4 个成分占 68.7%,λ₁/λ₃₂ ≈ 165×。
|
||||
|
||||
**橙线**:白化后所有方向被强制拉平到 1/32 = 3.1%。
|
||||
|
||||
PC1 被压掉约 12 倍、PC32 被放大约 14 倍——K-Means 的欧氏距离于是主要由末尾那些
|
||||
近乎噪声的方向决定。实测开白化时最大簇吃掉 96% 的样本,关掉后降到 38%。
|
||||
|
||||
```mermaid
|
||||
---
|
||||
config:
|
||||
xyChart:
|
||||
width: 1250
|
||||
height: 520
|
||||
titlePadding: 16
|
||||
themeVariables:
|
||||
xyChart:
|
||||
titleColor: "#1F2937"
|
||||
plotColorPalette: "#2563EB, #EA580C"
|
||||
---
|
||||
xychart
|
||||
title "主成分方差谱:白化会把末尾的噪声方向抬到与信号同权"
|
||||
x-axis "主成分序号 j (PCA 降到 32 维)" [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
|
||||
y-axis "方差占比 (%)" 0 --> 40
|
||||
bar [38.2, 13.0, 10.8, 6.7, 4.5, 3.6, 3.4, 2.3, 2.0, 1.6, 1.5, 1.3, 1.2, 1.0, 0.9, 0.8, 0.7, 0.7, 0.7, 0.7, 0.5, 0.5, 0.5, 0.4, 0.4, 0.4, 0.3, 0.3, 0.3, 0.3, 0.3, 0.2]
|
||||
line [3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1]
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
config:
|
||||
xyChart:
|
||||
width: 1250
|
||||
height: 520
|
||||
titlePadding: 16
|
||||
themeVariables:
|
||||
xyChart:
|
||||
titleColor: "#1F2937"
|
||||
plotColorPalette: "#2563EB, #EA580C"
|
||||
---
|
||||
xychart
|
||||
title "主成分方差谱:白化会把末尾的噪声方向抬到与信号同权"
|
||||
x-axis "主成分序号 j (PCA 降到 32 维)" [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
|
||||
y-axis "方差占比 (%)" 0 --> 40
|
||||
bar [38.2, 13.0, 10.8, 6.7, 4.5, 3.6, 3.4, 2.3, 2.0, 1.6, 1.5, 1.3, 1.2, 1.0, 0.9, 0.8, 0.7, 0.7, 0.7, 0.7, 0.5, 0.5, 0.5, 0.4, 0.4, 0.4, 0.3, 0.3, 0.3, 0.3, 0.3, 0.2]
|
||||
line [3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1, 3.1]
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,56 @@
|
||||
# SimCLR 自监督对比学习
|
||||
|
||||
同一张图的两个随机增强视图互为正样本,batch 内其余 2B−2 个视图全是负样本。
|
||||
训练完只保留卷积骨架 f_θ,投影头 g_φ 丢弃。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
classDef data fill:#D1FAE5,stroke:#10B981,stroke-width:2px,color:#064E3B
|
||||
classDef aug fill:#DBEAFE,stroke:#2563EB,stroke-width:2px,color:#1E3A8A
|
||||
classDef net fill:#EDE9FE,stroke:#7C3AED,stroke-width:2px,color:#4C1D95
|
||||
classDef loss fill:#FFEDD5,stroke:#EA580C,stroke-width:2px,color:#7C2D12
|
||||
classDef note fill:#FEF3C7,stroke:#D97706,stroke-width:2px,color:#78350F
|
||||
|
||||
batch["一个 batch:B 张无标注图 { Iᵢ }, i = 1…B"]:::data
|
||||
|
||||
aug["随机增强分布 𝒯:RandomResizedCrop 0.5~1.0 · 水平/垂直翻转 · 高斯模糊<br/>对每张图独立采样两次 t, t′ ~ 𝒯"]:::aug
|
||||
|
||||
v1["视图 1 x⁽¹⁾ᵢ = t(Iᵢ)"]:::aug
|
||||
v2["视图 2 x⁽²⁾ᵢ = t′(Iᵢ)"]:::aug
|
||||
|
||||
bb1["卷积骨架 f_θ"]:::net
|
||||
bb2["卷积骨架 f_θ (共享同一份参数)"]:::net
|
||||
|
||||
h1["h⁽¹⁾ᵢ = f_θ(x⁽¹⁾ᵢ) ∈ ℝᴰ"]:::net
|
||||
h2["h⁽²⁾ᵢ = f_θ(x⁽²⁾ᵢ) ∈ ℝᴰ"]:::net
|
||||
|
||||
g1["投影头 g_φ<br/>Linear → BN → ReLU → Linear"]:::net
|
||||
g2["投影头 g_φ (共享参数)"]:::net
|
||||
|
||||
z1["z⁽¹⁾ᵢ = g_φ(h⁽¹⁾ᵢ) ∈ ℝ¹²⁸"]:::net
|
||||
z2["z⁽²⁾ᵢ = g_φ(h⁽²⁾ᵢ) ∈ ℝ¹²⁸"]:::net
|
||||
|
||||
sim["ℓ₂ 归一化后拼成 Z ∈ ℝ²ᴮˣ¹²⁸<br/>相似度矩阵 S = ZZᵀ / τ ∈ ℝ²ᴮˣ²ᴮ,τ = 0.2<br/>对角线置 −∞,排除自己和自己"]:::loss
|
||||
|
||||
nt["NT-Xent 损失<br/>ℒ = − (1/2B) Σₖ log [ exp(S_{k,π(k)}) / Σ_{m≠k} exp(S_{k,m}) ]<br/>π(k):同一张图的另一个视图"]:::loss
|
||||
|
||||
pos["分子 = 正样本对(1 个)<br/>同图另一视图 π(k)"]:::note
|
||||
neg["分母 = 全部 2B−2 个负样本<br/>batch 内其他所有视图"]:::note
|
||||
|
||||
step["反向传播同时更新 θ 与 φ<br/>AdamW + cosine,AMP"]:::loss
|
||||
|
||||
ckpt["训练收敛后只保存骨架<br/>simclr_backbone.pth<br/>投影头 g_φ 丢弃"]:::data
|
||||
|
||||
use["聚类阶段用 h = f_θ(x),不用 z<br/>投影头会滤掉对比任务用不上、<br/>但下游有用的信息"]:::note
|
||||
|
||||
batch --> aug
|
||||
aug --> v1
|
||||
aug --> v2
|
||||
v1 --> bb1 --> h1 --> g1 --> z1
|
||||
v2 --> bb2 --> h2 --> g2 --> z2
|
||||
z1 --> sim
|
||||
z2 --> sim
|
||||
pos -.-> nt
|
||||
neg -.-> nt
|
||||
sim --> nt --> step --> ckpt --> use
|
||||
```
|
||||
@@ -0,0 +1,49 @@
|
||||
flowchart TB
|
||||
classDef data fill:#D1FAE5,stroke:#10B981,stroke-width:2px,color:#064E3B
|
||||
classDef aug fill:#DBEAFE,stroke:#2563EB,stroke-width:2px,color:#1E3A8A
|
||||
classDef net fill:#EDE9FE,stroke:#7C3AED,stroke-width:2px,color:#4C1D95
|
||||
classDef loss fill:#FFEDD5,stroke:#EA580C,stroke-width:2px,color:#7C2D12
|
||||
classDef note fill:#FEF3C7,stroke:#D97706,stroke-width:2px,color:#78350F
|
||||
|
||||
batch["一个 batch:B 张无标注图 { Iᵢ }, i = 1…B"]:::data
|
||||
|
||||
aug["随机增强分布 𝒯:RandomResizedCrop 0.5~1.0 · 水平/垂直翻转 · 高斯模糊<br/>对每张图独立采样两次 t, t′ ~ 𝒯"]:::aug
|
||||
|
||||
v1["视图 1 x⁽¹⁾ᵢ = t(Iᵢ)"]:::aug
|
||||
v2["视图 2 x⁽²⁾ᵢ = t′(Iᵢ)"]:::aug
|
||||
|
||||
bb1["卷积骨架 f_θ"]:::net
|
||||
bb2["卷积骨架 f_θ (共享同一份参数)"]:::net
|
||||
|
||||
h1["h⁽¹⁾ᵢ = f_θ(x⁽¹⁾ᵢ) ∈ ℝᴰ"]:::net
|
||||
h2["h⁽²⁾ᵢ = f_θ(x⁽²⁾ᵢ) ∈ ℝᴰ"]:::net
|
||||
|
||||
g1["投影头 g_φ<br/>Linear → BN → ReLU → Linear"]:::net
|
||||
g2["投影头 g_φ (共享参数)"]:::net
|
||||
|
||||
z1["z⁽¹⁾ᵢ = g_φ(h⁽¹⁾ᵢ) ∈ ℝ¹²⁸"]:::net
|
||||
z2["z⁽²⁾ᵢ = g_φ(h⁽²⁾ᵢ) ∈ ℝ¹²⁸"]:::net
|
||||
|
||||
sim["ℓ₂ 归一化后拼成 Z ∈ ℝ²ᴮˣ¹²⁸<br/>相似度矩阵 S = ZZᵀ / τ ∈ ℝ²ᴮˣ²ᴮ,τ = 0.2<br/>对角线置 −∞,排除自己和自己"]:::loss
|
||||
|
||||
nt["NT-Xent 损失<br/>ℒ = − (1/2B) Σₖ log [ exp(S_{k,π(k)}) / Σ_{m≠k} exp(S_{k,m}) ]<br/>π(k):同一张图的另一个视图"]:::loss
|
||||
|
||||
pos["分子 = 正样本对(1 个)<br/>同图另一视图 π(k)"]:::note
|
||||
neg["分母 = 全部 2B−2 个负样本<br/>batch 内其他所有视图"]:::note
|
||||
|
||||
step["反向传播同时更新 θ 与 φ<br/>AdamW + cosine,AMP"]:::loss
|
||||
|
||||
ckpt["训练收敛后只保存骨架<br/>simclr_backbone.pth<br/>投影头 g_φ 丢弃"]:::data
|
||||
|
||||
use["聚类阶段用 h = f_θ(x),不用 z<br/>投影头会滤掉对比任务用不上、<br/>但下游有用的信息"]:::note
|
||||
|
||||
batch --> aug
|
||||
aug --> v1
|
||||
aug --> v2
|
||||
v1 --> bb1 --> h1 --> g1 --> z1
|
||||
v2 --> bb2 --> h2 --> g2 --> z2
|
||||
z1 --> sim
|
||||
z2 --> sim
|
||||
pos -.-> nt
|
||||
neg -.-> nt
|
||||
sim --> nt --> step --> ckpt --> use
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
Reference in New Issue
Block a user