# 学習・評価仕様 (Training & Evaluation)

## 前処理 (Preprocessing)

| 項目 | 方針 |
| --- | --- |
| リサイズ | アスペクト比を保って 224×224 に収め，余白は黒で埋める（元画像は幅 449〜900・高さ 279〜1025 でばらつく） |
| 正規化 | ImageNet の mean / std（事前学習の統計に合わせる） |
| マスク外領域 | **黒 (0, 0, 0)**（実データで確認済み．[TEST_01](../06_TEST/TEST_01_データセット構成調査.md)）．リサイズ時のパディングも黒で統一する |

## データ拡張 (Augmentation)

**色を変える拡張は既定で無効にする．** 舌の色そのものが正解ラベルであり，color jitter・彩度変更・ホワイトバランス変更はラベルを壊す．

| 使う | 使わない（既定） |
| --- | --- |
| 左右反転・微小回転・微小スケール・ランダムクロップ | 色相・彩度・明度ジッタ・グレースケール化・強い正規化 |

※ 撮影条件差の吸収のために色系の拡張を試す場合は，**独立した実験**として効果を測る．

## モデル (Model)

| 項目 | 初期設定 |
| --- | --- |
| アーキテクチャ | ConvNeXt-Tiny（timm・ImageNet 事前学習） |
| 出力 | 5 クラス |
| 学習方式 | 全層ファインチューニング（データが少ないと判断した場合は段階的凍結を試す） |
| 最適化 | AdamW ＋ cosine annealing（warmup 付き） |
| 早期終了 | 検証セットの macro F1 を基準にする |

まず 1 本を通すことを優先し，比較は timm での差し替えで後から行う．

## データ分割 (Data Split)

**すべての分割は患者単位で行う．** 同一患者の画像が複数の分割に跨ってはならない．

現在のデータセットは **1 患者 1 枚**であることを確認済みのため（2026-09-27．[TEST_01](../06_TEST/TEST_01_データセット構成調査.md)），画像単位の分割が患者単位の分割と一致する．ただし実装は常に `patient_id` 単位で分割し，将来同一患者の複数枚が追加されても正しく動くようにする．

| 局面 | 方式 |
| --- | --- |
| 日常の試行 | 患者単位の単一分割（train / val / test）．クラス分布を層化する |
| 結論を出すとき | 患者単位の 5-fold 交差検証 |

- 分割は `patient_id` と seed から決定的に生成し，`config.yaml` に記録する
- **test セットはモデル選択に使わない**（val で選び，test は最後に一度だけ見る）
- 層化はクラス（5 分類）で行う．`severity` は層化の条件に含めない（分割が細分化されすぎるため）が，分割後に `severity` の偏りを確認する
- **実装方式**: 1 患者は 1 つの label しか持たない（manifest の検証で保証）ため，患者の一覧をクラスで層化して分ければ「患者単位」と「クラス層化」が同時に成り立つ
  - 単一分割: クラスごとに患者を seed で並べ替え，「患者数 × 比率」の四捨五入で test・val の人数を取り，残りを train とする．train に患者が残らないクラスがあれば停止する
  - K-fold: 患者の一覧に scikit-learn の `StratifiedKFold`（shuffle あり・seed 指定）を使う．評価側を `held_out` と呼ぶ（fold 内でさらに val を取るかは Step 4・5 で決める）．患者数が fold 数に満たないクラスがあれば停止する
  - どちらも最初に患者 ID を並べ替えるため，manifest の行順に依存しない
- 分割結果（各分割の患者 ID）は**個票に当たるため手元へ回収しない**（サーバ上の `runs/` にのみ保存する．[SPEC_01](SPEC_01_アーキテクチャ設計.md)「回収ホワイトリスト」）

## クラス不均衡 (Class Imbalance)

実データのクラス分布は最大 / 最小 = 380 / 104 ≒ **3.7 倍**（[TEST_01](../06_TEST/TEST_01_データセット構成調査.md)）．中程度の不均衡であり，初回は対策を入れずに素の結果を見る．混同行列でどのクラスが落ちているかを確認してから，クラス重み付き損失等を**独立した実験**として追加し，効果を切り分けて評価する．

程度ラベル（`severity`）を含めた 9 クラス分類は採らない（最小クラス 51 枚・不均衡 6.6 倍となり学習が不安定になる．目的は TIASjudge の 5 分類の置き換えであるため）．

## 評価指標 (Metrics)

| 指標 | 役割 |
| --- | --- |
| **macro F1** | 主指標（クラス不均衡下で少数クラスを無視できないため） |
| accuracy | 参考（クラス分布に引っ張られる） |
| クラス別 precision / recall | どのクラスが弱いかの特定 |
| 混同行列 | 誤りの方向（隣接クラスとの混同か，飛んだ誤りか）の確認 |

- 舌色が順序尺度として扱える（淡白 → 淡紅 → 紅 → 暗赤紅 → 紫 のような並び）なら，**quadratic weighted kappa** を追加する．順序の妥当性は TIASjudge の定義と医学的な解釈を確認してから決める（未確定）
- **程度別の層別評価**: `severity` ごと（`strong` / `mild`）にクラス別 recall を出す．「ややあり」（`mild`）は境界例であり誤りが集中すると予想されるため，全体の指標だけでは改善の効果が見えない
- 医師ラベルの評価者間一致率が分かる場合は，モデル性能の上限の目安として併記する

## ベースライン (Baseline)

既存 TIASjudge のルールベース診断を同一テストセットで実行し，同じ指標で並べる．実装の取り込み方（移植 / 別リポジトリ参照）は未定とし，ベースライン実装に着手する時点で決める．

## 再現性 (Reproducibility)

- seed を設定ファイルで固定し，`config.yaml` に git コミットハッシュとともに記録する
- 完全なビット再現性（`torch.use_deterministic_algorithms`）は速度とのトレードオフのため求めない．代わりに**同一設定で複数 seed を回して振れ幅を確認する**
- 共用サーバのため，使用する GPU は明示的に指定する

## 未確定事項 (Open Items)

- 舌色 5 分類を順序尺度として扱えるか（quadratic weighted kappa の採用可否）
- 入力解像度 224 で足りるか（元画像は平均 675×614 で，約 1/3 に縮小することになる）
- 黒背景が面積の大半を占めるため，正規化・統計を画像全体で取るか舌領域内のみで取るか
- ルールベース診断の取り込み方
- 医師ラベルの評価者間一致率（分かれば性能の上限の目安になる）
