Newer
Older
TIASJudgeModel / docs / 04_SPEC / SPEC_01_アーキテクチャ設計.md

アーキテクチャ設計 (Architecture)

基本方針 (Principles)

  1. 実データに触るコードはサーバでしか動かさない.手元では合成データで同じコードパスを流す
  2. 手元への回収はホワイトリスト方式.回収対象を明示的に列挙し,列挙外(画像・manifest・患者 ID)は持ち帰れないようにする
  3. 設定は YAML に集約し,pydantic で検証する.コードに絶対パス・閾値を書かない
  4. 実験は runs/<実験ID>/ に閉じる.同じ設定と seed で同じ結果に辿れるようにする

ディレクトリ構成 (Directory Layout)

TIASJudgeModel/
├── configs/                      # 実験設定 YAML
├── src/tias_judge_model/
│   ├── schema.py                 # pydantic 設定スキーマ
│   ├── data/                     # manifest 読み込み・Dataset・分割・前処理
│   ├── models/                   # timm ラッパ(アーキテクチャ差し替え点)
│   ├── training/                 # 学習ループ・損失・スケジューラ
│   ├── evaluation/               # 指標・混同行列・レポート生成
│   ├── baseline/                 # ルールベース比較(扱いは未定)
│   ├── remote/                   # リモート実行(tar over ssh・tmux・回収)
│   ├── segmentation/             # 舌のセグメンテーション(DeepTIAS 2.7 の手順の Python 版)
│   ├── deploy/                   # 配布用の参照実装(TIASjudge にコピーする単一ファイル.NumPy のみ)
│   └── cli/                      # エントリポイント
├── scripts/                      # 合成データ生成・manifest 生成
├── tests/
├── data/                         # .gitignore(合成データ.実データは置かない)
└── runs/                         # .gitignore(実験結果)

依存方向は cli → training / evaluation → data / models の一方向とする.data と models は CLI・学習ループを import しない.

データ契約 (Data Contract)

元データは研究室 PC の C:\Users\Papin\clinical-data\TIASJudgeModel\ にラベルごとの 9 フォルダとして置かれている(ENV_03).サーバへコピーした後の配置(~/data/TIASJudgeModel/):

~/data/TIASJudgeModel/
├── images/
│   ├── light_red_normal/    # ラベル_程度のスラッグごとのディレクトリ
│   ├── dark_red_strong/
│   ├── dark_red_mild/
│   ├── purple_strong/
│   ├── purple_mild/
│   ├── red_strong/
│   ├── red_mild/
│   ├── pale_strong/
│   └── pale_mild/
└── manifest.csv             # 学習が読む唯一の入口

ディレクトリ名は <label>_<severity> のスラッグとする(研究室 PC 側の日本語フォルダ名との対応は ENV_03.日本語名のまま転送すると文字コード差で壊れるため).

manifest.csv の列:

列名内容備考
image_pathimages/ からの相対パス—
patient_id患者を一意に識別する ID必須.分割の単位になる
label舌色 5 分類のいずれか元データのフォルダ名に由来
severity程度(strong / mild / normal)学習には使わず,評価の層別分析に使う
note任意の備考除外理由等
  • manifest はサーバ上の生成スクリプトで作る.元データはラベルごとのフォルダに分かれているため,フォルダ名から label と severity を決める(対応表は TEST_01 データセット構成調査)
  • patient_id について: 現在のデータセットは 1 患者 1 枚であることを確認済み(2026-09-27).したがって画像 ID をそのまま patient_id とする.この前提が崩れる(同一患者の複数枚が追加される)場合は,実際の患者 ID を入れ直す必要がある(同一患者が分割を跨ぐと評価が壊れるため).分割処理は常に patient_id 単位で行い,前提が変わってもコードを変えずに済むようにする
  • 前提が確認できない新規データに対しては,画像 ID を患者 ID と見なす代替を自動では行わない.生成を止めて人間が判断する

manifest の検証規則 (Validation Rules)

読み込み時・生成時とも,問題があれば黙って除外せず ValueError で停止する(.claude/rules/error-handling.md).メッセージは行番号・件数・クラス名のみで示し,患者 ID・ファイル名を含めない.

対象停止する条件
読み込み必須列(image_path・patient_id・label・severity)の欠落,patient_id が空,未知の label / severity,無効な組み合わせ,image_path の重複,同一 patient_id に異なる label,image_path が絶対パス・.. を含む・区切りが \
生成images/ 直下の想定外のディレクトリ名・ファイル,クラスディレクトリ内のサブディレクトリ・PNG 以外のファイル,画像が 0 枚のクラスディレクトリ(クラスが欠けたまま学習が進むのを防ぐため),ファイル名の stem の重複(患者 ID と見なせなくなるため)
  • note 列は読み込み時に省略できる(無ければ空文字)
  • 同一 patient_id で同じ label の複数行は許す(1 患者複数枚に備える)

設定ファイル (Configuration)

実験条件は configs/*.yaml に置き,pydantic で検証する(未知のキーは拒否する).

キー内容既定値
data.rootデータのルート(images/ と manifest を含む).~ を展開する.相対パスはカレントディレクトリ基準なし(必須)
data.manifestmanifest のパス.相対パスは data.root 基準manifest.csv
data.severities学習・評価に使う程度(strong・mild・normal の部分集合).空・重複・未知の値は不可.分割の後に適用する(SPEC_02「程度(ややあり)の扱い」)[strong, mild, normal]
split.seed分割の seed42
split.val_ratio・split.test_ratio単一分割の比率.各 0 より大きく,合計 1 未満0.15・0.15
split.n_folds交差検証の fold 数(2 以上)5
  • 環境変数 TIAS_DATA_ROOT が設定されていれば data.root より優先する(サーバと手元で同じ設定ファイルを使い回せるようにするため)
  • 学習・モデル関連の設定は model・train 節に置く(キーと既定値は SPEC_02「学習の設定」).学習しないコマンド(tias-dataset)では省略できる

クラス定義 (Class Definition)

内部表現は英字 slug,表示は日本語とし,整数 ID を固定して混同行列の軸をぶらさない.

IDslug表示
0pale淡白
1light_red淡紅
2red紅
3dark_red暗赤紅
4purple紫

※ 表示名は元データのフォルダ名に合わせている(「暗赤紅」).順序尺度として扱えるかは未確定(SPEC_02 参照).

実験の出力 (Run Artifacts)

runs/<実験ID>/
├── config.yaml            # 解決済み設定 + git コミットハッシュ + seed
├── history.csv            # エポックごとの損失・指標
├── metrics.json           # 最終指標(macro F1・accuracy・クラス別)
├── confusion_matrix.csv   # 混同行列の数値
├── log.txt
├── figures/               # 図専用(学習曲線・混同行列等).症例画像は書き込まない
│   └── confusion_matrix.png
├── dataset_summary.json   # データセット集計の結果(集計値のみ.データセット集計の実行時)
├── split.json             # 分割結果(患者 ID を含む.回収しない)
└── checkpoints/best.pt

実験 ID の書式: YYYYmmdd-HHMMSS_<名前>_<git短縮ハッシュ>(<名前> は学習なら設定ファイル名,データセット集計なら survey)

  • サーバには .git を送らないため,git のハッシュは手元で求めて tias-remote run が環境変数 TIAS_GIT_COMMIT で渡す(SPEC_03).未コミットの変更(未追跡ファイルを含む.git status --porcelain が空でない)があるときは末尾に -dirty が付く.値は英数字で始まり英数字・_・- の 64 文字以内でなければ拒否する.環境変数が無い場合(手元での直接実行等)は nogit とする

  • figures/ には図だけを置き,症例画像(舌画像そのもの・切り出し・誤分類例の画像)を書き込まない.回収ホワイトリストが figures/*.png を回収対象にしているため

  • 患者 ID・画像ファイル名を含む出力(分割結果・個票の予測)は上記の回収対象外の名前で保存する

回収ホワイトリスト (Pull Whitelist)

手元へ回収できるのは以下の名前が一致するファイルのみ.列挙外のファイルは回収しない(拡張子や中身での判断はしない).リモート実行ツール(SPEC_03)がこの制約を実装する.

回収する(runs/<実験ID>/ 配下)回収しない
config.yaml・history.csv・metrics.json・confusion_matrix.csv・log.txt・dataset_summary.json・color_model.json上記以外のすべて(split.json・個票の予測(predictions.csv)・画像・manifest 等)
figures/*.pngfigures/ 以外にある *.png
checkpoints/*.pt(明示的に指定したときのみ)指定が無いときの checkpoints/
  • ジョブのログ(runs/_remote_logs/<ジョブ名>.log)はファイルとしては回収せず,tias-remote logs で表示して確認する(ログに個人情報を出さない規則が前提..claude/rules/coding-style.md)
  • color_model.json は tias-train color-export が書き出す判定モデル(特徴の定義・標準化の平均と尺度・係数・切片・クラス・学習条件)で,患者 ID・ファイル名・画像単位の値を含まない
  • データディレクトリ(~/data/TIASJudgeModel/)からは何も回収しない
  • 個票(画像ごとの予測)が必要な分析はサーバ上で行い,集計結果だけを上記の名前で書き出して持ち帰る

CLI (Entry Points)

コマンド役割実行場所
tias-dataset build-manifestimages/ を走査して manifest.csv を書き出す(既存があれば --overwrite が必要)サーバ
tias-train cv --config PATH5-fold 交差検証で学習・評価し,runs/<実験ID>/ に書き出す(SPEC_02「交差検証の実行」).最後に実験 ID を出力するサーバ(GPU)
tias-train color-cv --config PATH色特徴分類器(SPEC_02「色特徴分類器」)を同じ分割で交差検証し,同じ形式で書き出す(学習曲線・重みは出さない).最後に実験 ID を出力するサーバ(CPU)
tias-train color-export --config PATH色特徴+ロジスティック回帰の最終モデルを全データ(data.severities 適用後)で学習し,TIASjudge 用の color_model.json と C の選択の記録(metrics.json)を書き出す.NumPy だけの参照実装は src/tias_judge_model/deploy/color_model.pyサーバ(CPU)
tias-seg eval --config PATHPython 版セグメンテーション(DeepTIAS 2.7 の再現.onnxruntime・OpenCV)を正解マスク付きデータで評価し,IoU・Dice の集計値を metrics.json に書き出す(画像ごとの値はサーバ上の predictions.csv)サーバ(CPU)
tias-dataset surveyデータセットを集計して runs/<実験ID>/ に集計値だけを書き出す(下記)サーバ(結果の要約のみ手元へ)
学習設定 YAML を受け取って学習するサーバ
評価学習済み run の評価・レポート生成サーバ
リモート実行コード送信・ジョブ実行・結果回収・GPU 空き確認(複数サーバ.SPEC_03)手元

コマンド名は実装時に確定し,ENV_04 開発コマンドに記載する.

データセット集計の出力 (Dataset Survey Output)

tias-dataset survey は manifest と画像を読み,集計値だけを runs/<実験ID>/dataset_summary.json と runs/<実験ID>/figures/ に書き出す.画像単位の値・患者 ID・ファイル名は出力しない(ログも同様).集計の単位は <label>_<severity> の 9 グループと,クラス(5)・全体.

項目内容
件数グループ・クラス・程度ごとの画像数と患者数.条件ごと(data.severities の 2 条件)の件数
読み込み読めなかった画像の件数,RGB 以外のモード・アルファチャンネル付きの件数
サイズ幅・高さの最小・最大・平均・中央値
舌領域の割合画像に占める舌領域(背景でない画素)の割合の最小・平均・最大
舌領域の色(Lab)画像ごとに舌領域の L*・a*・b* の平均を求め,グループごとにその平均・標準偏差・中央値・10/90 パーセンタイルを出す
グループ間の色差グループ平均どうしの色差 ΔE(CIE76).特に各 mild グループについて「淡紅(light_red_normal)との ΔE」と「同じクラスの strong との ΔE」を並べる
分割の確認既定の設定で分割したときの,各分割・グループの件数(患者 ID は出さない)
  • 背景の定義: RGB がすべて 0 の画素を背景(マスク外)とし,それ以外を舌領域とする(TEST_01.マスク外は黒 (0,0,0))
  • Lab の計算: sRGB(ガンマ補正を外して線形化)→ XYZ(D65)→ CIE L*a*b*(D65 白色点).新しい依存を増やさず NumPy で計算する.画像の平均 Lab は,画素ごとに Lab へ変換してから舌領域で平均する(平均 RGB を変換するのではない)
  • RGBA 等のアルファ付き画像は「RGB 以外のモード」と「アルファ付き」の両方に数え,RGB に変換してから測る
  • 図(figures/): グループごとの L*・a*・b* の分布(箱ひげ図等).画像そのもの・画像の切り出しは描かない
  • 読めない画像があっても集計は止めず,件数として報告する(集計は現状把握のためであり,学習時の fail fast とは目的が異なる).ただし manifest の検証エラーは従来どおり停止する