# 開発コマンド (Development Commands)

日常の開発で使うコマンドの一覧．**コマンドを推測せず必ず本ファイルを参照する**（新しく確定・変更された時は本ファイルに反映する）．

※ Git Bash ではログの日本語が文字化けする．先頭に `PYTHONIOENCODING=utf-8` を付けると正しく表示される．

## 環境 (Environment)

| 目的 | コマンド | 備考 |
| --- | --- | --- |
| 依存の同期 | `uv sync` | 初回・`pyproject.toml` 変更後．手元には CPU 版 PyTorch が入る |
| 依存の追加 | `uv add <パッケージ>` | `uv.lock` が更新されるのでコミットする |
| 開発用依存の追加 | `uv add --dev <パッケージ>` | pytest・ruff 等 |
| Python の実行 | `uv run python <スクリプト>` | 仮想環境を明示的に有効化しなくてよい |

## データ (Data)

| 目的 | コマンド | 備考 |
| --- | --- | --- |
| 合成データの生成 | `uv run python scripts/make_synthetic_dataset.py` | 出力は `data/synthetic/`（`images/<label>_<severity>/` と `manifest.csv`）．既定は 1 ディレクトリ 10 枚・seed 0 |
| 合成データの作り直し | `uv run python scripts/make_synthetic_dataset.py --overwrite` | 目印ファイル `.synthetic_dataset` がある出力先だけを削除して作り直す（実データの誤削除を防ぐため） |
| 枚数・seed の指定 | `uv run python scripts/make_synthetic_dataset.py --per-dir 50 --seed 1` | 出力先は `--out` で変更できる |
| manifest の生成 | `uv run tias-dataset build-manifest --config <設定>` | `images/` を走査して `manifest.csv` を書く．既存があれば `--overwrite` が必要 |
| データセットの集計 | `uv run tias-dataset survey --config <設定>` | `runs/<実験ID>/` に集計値だけを書く．最後に実験 ID を出力する（[SPEC_01](../04_SPEC/SPEC_01_アーキテクチャ設計.md)「データセット集計の出力」） |

**実データ（サーバ上）での実行例**（GPU を使わないので `--cpu`）:

```bash
uv run tias-remote run --name manifest --cpu --server Newton -- tias-dataset build-manifest --config configs/newton.yaml
uv run tias-remote run --name survey --cpu --server Newton -- tias-dataset survey --config configs/newton.yaml
uv run tias-remote logs survey          # 最後の行に実験 ID が出る
uv run tias-remote pull <実験ID>          # 集計値と図だけが手元の runs/ に届く
```

設定ファイルは `configs/synthetic.yaml`（手元の合成データ）と `configs/newton.yaml`（サーバの実データ）．環境変数 `TIAS_DATA_ROOT` を設定すると `data.root` より優先される．

## リモート実行 (Remote Execution)

研究室の GPU サーバ（Newton・Archimedes）で計算するときは `tias-remote` を使う．コマンドはすべて手元で実行する．空いている GPU を両サーバから自動で選ぶ（**未使用の GPU を最優先**．仕様は [SPEC_03](../04_SPEC/SPEC_03_リモート実行仕様.md)）．サーバ設定は `configs/remote.yaml`．

| 目的 | コマンド |
| --- | --- |
| GPU の状況と `run` が選ぶ GPU | `uv run tias-remote gpus` |
| 実行中ジョブと GPU の状況 | `uv run tias-remote status` |
| コードを送る（全サーバ） | `uv run tias-remote push` |
| 送る一覧だけ見る | `uv run tias-remote push --dry-run` |
| ジョブを起動（GPU 自動選択） | `uv run tias-remote run --name exp1 -- python scripts/xxx.py` |
| GPU を指定して起動 | `uv run tias-remote run --name exp2 --server Newton --gpu 1 -- python ...` |
| 選ばれる GPU だけ確かめる | `uv run tias-remote run --name exp1 --dry-run -- python ...` |
| GPU を使わないジョブ | `uv run tias-remote run --name job --cpu [--server Newton] -- ...`（GPU の空きを待たない．`CUDA_VISIBLE_DEVICES` は空） |
| ログの末尾・追従 | `uv run tias-remote logs exp1`・`uv run tias-remote logs exp1 -f` |
| ジョブを止める | `uv run tias-remote kill exp1` |
| 実験結果を持ち帰る | `uv run tias-remote pull <実験ID>`（重みも要るときは `--with-checkpoints`） |

- `gpus`・`run`・`status` は GPU を **10 秒観測してから**判定するため，1 回に 13 秒ほどかかる．急ぐときは `--observe 0`（瞬間値のみ．約 2 秒．`gpus`・`run` のみ）
- `run` は起動前に選んだサーバへ自動でコードを送る（`--no-push` で省略）．ジョブには `CUDA_VISIBLE_DEVICES`・`TIAS_DATA_ROOT`（そのサーバのデータの場所）が渡る
- `pull` は[回収ホワイトリスト](../04_SPEC/SPEC_01_アーキテクチャ設計.md)に名前が一致するファイルだけを `runs/<実験ID>/` に持ち帰る．回収しなかったファイルは件数だけ表示される
- ジョブログはサーバ上の `runs/_remote_logs/<ジョブ名>.log`．末尾に `=== [日時] exit <終了コード>` の行が付く
- **研究室 LAN 内にいるとき**は踏み台が不要なので，環境変数 `TIAS_REMOTE_JUMP` を空文字にすると速い（Git Bash: `TIAS_REMOTE_JUMP= uv run tias-remote gpus`．PowerShell: `$env:TIAS_REMOTE_JUMP = ""`）
- **ジョブの実行中に同じサーバへ push しない**（上書き展開なので，実行中のジョブが新旧のコードを混ぜて読むおそれがある．実行中なら警告が出る）
- 各サブコマンドの詳細は `uv run tias-remote <サブコマンド> --help`

## 学習・交差検証 (Training)

| 目的 | コマンド | 備考 |
| --- | --- | --- |
| 5-fold 交差検証 | `uv run tias-train cv --config <設定>` | 学習・評価して `runs/<実験ID>/` に書き出す．最後に実験 ID を出力する（[SPEC_02](../04_SPEC/SPEC_02_学習・評価仕様.md)「交差検証の実行」） |
| 手元での試運転 | `uv run tias-train cv --config configs/cv_synthetic.yaml` | 合成データ・小さなモデル・事前学習なし．CPU で十数秒 |
| 色特徴分類器の交差検証 | `uv run tias-train color-cv --config <設定>` | CNN と同じ分割で色特徴＋ロジスティック回帰／勾配ブースティングを評価する（[SPEC_02](../04_SPEC/SPEC_02_学習・評価仕様.md)「色特徴分類器」）．GPU 不要．手元の試運転は `configs/color_synthetic.yaml` |
| 判定モデルの書き出し | `uv run tias-train color-export --config <設定>` | 全データの患者単位 5-fold で C を選び，全データで学習した色特徴＋ロジスティック回帰を `runs/<実験ID>/color_model.json` に書き出す（回収対象）．GPU 不要．手元の試運転は `configs/export/color_synthetic.yaml` |
| 回収した結果の集計 | `uv run python scripts/summarize_cv.py runs` | `runs/*_cv_*` を読み，モデル × 学習率 × 不均衡対策 × 条件ごとの表と，「除外 − 込み」「対策あり − 対策なし」の対応比較を Markdown で出す（[TEST_03](../06_TEST/TEST_03_交差検証結果.md) の表） |

設定ファイル:

| 設定 | 内容 |
| --- | --- |
| `configs/cv_with_mild.yaml`・`configs/cv_without_mild.yaml` | ConvNeXt-Tiny・ややあり込み／除外（サーバの実データ） |
| `configs/cv_<effb0 \| resnet50 \| vits>_<with_mild \| without_mild>.yaml` | モデル比較用（モデル名以外は上と同一） |
| `configs/repeat/*_s43.yaml`・`*_s44.yaml` | 分割 seed を変えた繰り返し（seed 以外は元の設定と同一） |
| `configs/lr1e-3/*.yaml` | ResNet-50・EfficientNet-B0 を学習率 1e-3 で回す設定（1e-4 では学習不足だったため．TEST_03） |
| `configs/imbalance/*.yaml` | クラス不均衡の対策（`_cwinv`: 重み inverse・`_cwsqrt`: 重み sqrt_inverse・`_balanced`: バランス・サンプリング）．元の設定（ConvNeXt-Tiny・ResNet-50 lr 1e-3 の各 6 本）から対策のキーだけを変えたもの |
| `configs/hparam/*.yaml` | ハイパーパラメータの比較（`cv_hp_<convnext_cwinv \| resnet50>_<変更>[_s43 \| _s44]`）．基準の設定（ConvNeXt-Tiny・重み inverse／ResNet-50 lr 1e-3．ややあり除外）から 1 項目だけを変えたもの（[TEST_06](../06_TEST/TEST_06_ハイパーパラメータの比較.md)） |
| `configs/color/*.yaml` | 色特徴分類器（`cv_color_<logistic \| hist_gb>_<with_mild \| without_mild>[_s43 \| _s44][_cwinv]`）．分割・程度の設定は同名の CNN の設定と同一 |
| `configs/export/*.yaml` | 判定モデルの書き出し（`color_logistic_<with_mild \| without_mild>`．特徴・候補は `configs/color/` と同じ．`color_synthetic` は手元用） |

**サーバでの実行例**:

```bash
# 1 本だけ（空いている GPU を自動で選ぶ）
uv run tias-remote run --name cv1 -- tias-train cv --config configs/cv_with_mild.yaml

# 複数本を同じ GPU で順に回す（キュー）．; で区切るので 1 本が失敗しても次へ進む
uv run tias-remote run --name q1 --server Archimedes --gpu 1 -- bash -c "tias-train cv --config configs/cv_with_mild.yaml; tias-train cv --config configs/cv_effb0_with_mild.yaml;"

uv run tias-remote logs q1              # 各実験の最後の行に実験 ID が出る
uv run tias-remote pull <実験ID>         # 指標・図・ログだけが手元の runs/ に届く
```

- 色特徴分類器は GPU を使わないので `--cpu` で回す（例: `uv run tias-remote run --name color1 --cpu --server Archimedes -- bash -c "tias-train color-cv --config configs/color/cv_color_logistic_with_mild.yaml;"`）．1 本は Archimedes で約 1 分・Newton で約 2 分（大半が画像の読み込みと特徴抽出．2026-09-28 実測）
- ConvNeXt-Tiny の 5-fold 交差検証 1 本は Archimedes の RTX A6000 で約 2.5 分（2026-09-28 実測．画像の読み込み約 8 秒を含む）
- 事前学習の重みは初回にサーバが Hugging Face からダウンロードする（`~/.cache/huggingface`）
- ログに出る `lr_scheduler.step() before optimizer.step()` の警告は，混合精度で最初の数ステップの勾配がオーバーフローして捨てられたときに出るもので無害

## セグメンテーションの評価 (Segmentation)

DeepTIAS 2.7 の手順（検出 → ResUNet → 後処理）を Python（onnxruntime・OpenCV）で再現したものを，正解マスク付きデータで評価する．データ・モデルの場所は設定の `data.root`・`models.root`（環境変数 `TIAS_SEG_DATA_ROOT`・`TIAS_SEG_MODEL_ROOT` で上書き．`tias-remote run` が渡す `TIAS_DATA_ROOT` は使わない）．

| 目的 | コマンド | 備考 |
| --- | --- | --- |
| 合成データの生成 | `uv run python scripts/make_synthetic_segmentation.py` | 出力は `data/synthetic_seg/input/`（`train`・`test/cropped`・`test_extra/cropped`・`test/fullsize` の `sample/`・`label/`）．作り直しは `--overwrite` |
| ダミーの ONNX の生成 | `uv run python scripts/make_dummy_seg_models.py` | 出力は `data/synthetic_seg/models/`（入出力の形だけを合わせた ResUNet・検出モデル．`onnx` は開発用の依存） |
| 評価 | `uv run tias-seg eval --config <設定>` | `runs/<実験ID>/` に `metrics.json`（集計値）・`figures/`（IoU のヒストグラム）を書く．手元の試運転は `configs/seg/eval_synthetic.yaml`（CPU で数秒） |
| 検出モデルの ONNX 変換 | `uv run --with tensorflow --with tf2onnx python scripts/convert_detection_to_onnx.py --pb <Detection_Normal.pb> --out <Detection_Normal.onnx>` | サーバで一時的な依存を入れて実行する（本体の依存には入れない）．入出力の候補は `--list-nodes` |

**サーバでの実行例**（モデルは `~/models/TongueSegmentation/` に `ResUNet.onnx`（と変換した `Detection_Normal.onnx`）を置く）:

```bash
uv run tias-remote run --name seg1 --cpu --server Newton -- tias-seg eval --config configs/seg/eval_newton.yaml
uv run tias-remote pull <実験ID>
```

- 検出モデルの ONNX が無ければ `detector` の方式を省いて（警告を出して）続ける

## テスト (Test)

| 目的 | コマンド |
| --- | --- |
| 全テスト | `uv run pytest` |
| 特定ファイル | `uv run pytest tests/data/test_split.py` |
| 詳細表示 | `uv run pytest -v` |

臨床データに依存するテストは書かない（合成データで動くテストのみ）．

## Lint / Format

| 目的 | コマンド |
| --- | --- |
| Lint | `uv run ruff check .` |
| Lint（自動修正） | `uv run ruff check --fix .` |
| Format | `uv run ruff format .` |

※ `.claude/` はテンプレート所有のため ruff の対象外（`pyproject.toml` の `extend-exclude`）．テンプレート由来のフックのテストは `uv run pytest .claude/hooks/tests` で実行する．

## フック (Hooks)

| 目的 | コマンド | 備考 |
| --- | --- | --- |
| フックのテスト | `bash .claude/hooks/tests/test_hooks.py` 相当を `uv run pytest .claude/hooks/tests` | テンプレート由来．`.claude/` の変更時に確認する |
