Files
ModelTrainEval/figures/kmeans-lloyd.md
T
Shaun ZhouandClaude Opus 5 4fc0fa5353 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>
2026-09-02 17:55:48 +08:00

2.6 KiB
Raw Blame History

K-Means:k-means++ 初始化 + Lloyd 迭代

engine/cluster.py 里 kmeans() 与 cluster_features() 的完整控制流:空簇处理、收敛判据、多次重启取最优,以及子集拟合 + 全量指派。 虚线是各阶段内部的循环回边。

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&nbsp;&nbsp;(可先随机抽子集拟合:fit_max_samples)<br/>目标 &nbsp; min_{C,μ} J(C,μ) = Σᵢ ‖yᵢ − μ_{c(i)}‖²&nbsp;&nbsp;— NP-hard,只求局部最优"]:::start

    subgraph INIT["① k-means++ 初始化&nbsp;&nbsp;(期望近似比 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 迭代&nbsp;&nbsp;(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["③ 以上 ①②&nbsp;整体重复 n_init = 10 次<br/>每次换随机种子 seed + r"]:::step
    best["④ 取 10 次里 J 最小的一次 (C*, μ*)<br/>缓解 Lloyd 只保证局部最优"]:::done
    final["⑤ 全量指派&nbsp;&nbsp;cᵢ = argminⱼ ‖yᵢ − μ*ⱼ‖,i = 1…N<br/>并记录到质心的距离 dᵢ,供排序与离群检查"]:::done

    input --> INIT
    kdone ==>|"是,得到初值 μ⁽⁰⁾"| assign
    conv ==>|"是,本次收敛"| repeat
    repeat --> best --> final