# 全体パイプライン 詳細仕様

作成日: 2026-06-19

> **更新注記（§9: `reports/精度改善レポート_20260619.md` 参照）**
> - 本番入力を **濃度＋動画＋時間(slot)** に拡張。後段は `visual_plus_brix_slot` を採用・再学習済み。
> - [1]代表フレーム抽出は既存リゾルバが**最良フレームを選択済み**（LLMはbest版を評価していた）。
> - [5]判定可否ゲートは**2段**（上流RF-DETR可読性 `readable` → 採点直前 LLM `assessable`）に強化。
> - visual_density のLLM出力は将来外す方針（精度中立・設計整合のため。LLM再実行を伴うため別タイミング）。

ラーメン豚山のスープ動画から、人間評価に近いスコアを算出するまでの全工程の詳細仕様。
`（LLM）` はLLMを使う工程、`（ルール）` は通常処理、`（学習）` は学習モデルを示す。

---

## 0. 全体フロー俯瞰

```text
┌─────────────┐
│  入力: 動画 ＋ (任意)実測濃度Brix          │
└──────┬──────────────────────────────────┘
       ▼
[1] 代表フレーム抽出 （ルール / OpenCV）
       │  3〜5枚の良質フレーム
       ▼
[2] 画像評価AI （LLM）
       │  スープ表面状態の固定JSON
       ▼
[3] 濃度入力の確認 （ルール）
       ├─ 実測濃度あり → 実測Brixを使用
       └─ 実測濃度なし → [3a]スープ領域抽出（学習）→ [3b]濃度推定AI（学習）→ 推定濃度を使用
       ▼
[4] 特徴量生成 （ルール）
       │  LLM評価＋濃度＋付帯情報 → 数値特徴量
       ▼
[5] 評価可否の分岐 （ルール）★今回の改修ポイント
       ├─ assessable=0 → 「要確認/撮り直し」（スコアしない）→ [7]へ
       └─ assessable=1 → [6]へ
       ▼
[6] 後段モデル （学習）
       ├─ スコア回帰（線形回帰）
       │     ├─ total（human_total_score）: feature_set=visual_plus_brix
       │     └─ soup （human_soup_score） : feature_set=visual_only
       │  → グレード付与（A/B/C/D）
       └─ 要注意判定（将来: ルール→軽量分類）
       ▼
[7] 最終出力生成 （LLM）
       │  スコア・グレード・要確認理由を人間向け説明文に整形
       ▼
┌─────────────┐
│  出力: スコア / グレード / 状態(scored・要確認) / 説明文 │
└─────────────┘
```

`★[5] 評価可否の分岐` と `[6]スコア回帰` を本プロジェクト（`精度改善_20260619/pipeline/`）で恒久化済み。
それ以外の工程は既存資産・将来実装。各工程の詳細を以下に示す。

---

## 1. 代表フレーム抽出 （ルール / OpenCV）

| 項目 | 内容 |
|---|---|
| 入力 | スープ動画（.MOV） |
| 出力 | 代表フレーム画像 3〜5枚（.jpg） |
| 技術 | OpenCVベースのルール処理（LLMは使わない） |
| 処理 | 白飛び・ブレ・湯気過多・鍋外が多いフレームを除外し、スープ表面が広く見えるフレームを優先 |
| 実装状況 | 既存（`local_batch_api/` 配下に抽出済みフレームあり） |

**改善余地**: 現状は単枚依存になりがち。3〜5枚を統合判定（中央値・多数決・信頼度加重）し、
フレーム間で判定が割れる動画は「要確認」に回すと、フレーム起因の大外しを削減できる。

---

## 2. 画像評価AI （LLM）

| 項目 | 内容 |
|---|---|
| 入力 | 代表フレーム画像 |
| 出力 | スープ表面状態の固定JSON |
| 対象 | 完成丼ではなく、寸胴・大鍋・スープ釜の中の**スープ表面のみ** |
| 方針ソース | `APIテスト/豚山スープ画像評価プロンプト方針.md`（固定） |
| 同期対象 | プロンプト変更時は `APIテスト/index.html` と方針.md を同期 |

### 主な出力項目（JSON）

| 項目 | 意味 |
|---|---|
| `assessable` | 画像から評価可能か（不可なら true→評価不能） |
| `retake_recommended` | 撮り直し推奨か |
| `image_condition_score` | 画質スコア |
| `visual_density` | 見た目の濃度（10/11/12/13/14/判定不可） |
| `water_level` | 水位（水位良好/水位不足/判定不可） |
| `oil_emulsification` | 油感・乳化（良い/乳化進行/油感強い/乳化しすぎ/判定不可） |
| `boiling_heat_state` | 火力状態（良い/弱い/強すぎる/判定不可） |
| `photo_quality` | 撮影品質（良い/湯気が多い/白飛び/暗い/角度不良/不良/判定不可） |
| `deduction_reasons` / `craftsperson_check_points` / `summary` | 減点理由・職人確認点・要約 |

**重要な注意**: 味・香り・塩分・Brixは画像から推定しない（Brixは別入力）。
`visual_density` の 11/12 境界が特に重要で、**白泡・湯気・脂膜・白い膜・具材表面の白さだけで濃度を上げない**。

**改善余地（今後の最優先）**: 大外しの42%がこの工程の濃度過大評価に起因。
プロンプトの濃度境界説明を補強する（ただしLLM再実行＝追加コストを伴う）。

---

## 3. 濃度入力の確認 （ルール）

| 項目 | 内容 |
|---|---|
| 入力 | 実測Brix（任意）、LLMの `visual_density` |
| 出力 | 採用濃度値＋濃度メタ情報 |
| 処理 | 実測濃度があれば優先採用。無ければ [3a][3b] で推定 |

後段モデルへ渡す濃度関連の情報:

| 項目 | 内容 |
|---|---|
| `density_value` | 採用した濃度値 |
| `density_source` | `measured`（実測）/ `estimated`（推定）/ `missing`（なし） |
| `density_confidence` | 濃度の信頼度 |
| `visual_density` と濃度値の差分 | 見た目と数値の矛盾検出用 |

**実測濃度と推定濃度は同じものとして扱わない**（必ず `density_source` を特徴量に含める想定）。

### 3a. スープ領域抽出 （学習） — 実測濃度なしの場合のみ

| 項目 | 内容 |
|---|---|
| 入力 | フレーム画像 |
| 出力 | スープ領域を切り出した画像 |
| 役割 | 画像評価AIの代替ではなく、**濃度推定AIに渡す領域を切り出す**ため |
| 実装状況 | 既存モデル（以前開発） |

### 3b. 濃度推定AI （学習） — 実測濃度なしの場合のみ

| 項目 | 内容 |
|---|---|
| 入力 | スープ領域抽出済み画像 |
| 出力 | 推定濃度値＋信頼度 |
| 実装状況 | 既存モデル（以前開発） |

**運用上の推奨**: 実測濃度がある期間も裏で推定濃度を併走出力しておくと、
将来実測がなくなった際の性能劣化を事前に測定できる。
（参考: 5-fold CVでは「濃度なし」でも後段MAEの劣化は total +0.06 と軽微。`04_cross_validation/` 参照）

---

## 4. 特徴量生成 （ルール）

| 項目 | 内容 |
|---|---|
| 入力 | LLM評価JSON ＋ 濃度値 ＋ 付帯情報（slot/store等） |
| 出力 | 後段モデル用の数値特徴量 |
| 実装 | `soup_scoring.py: prepare()` |

### 主な生成特徴量

| 種別 | 特徴量 |
|---|---|
| 濃度系 | `visual_density_num`, `brix`, `density_brix_abs_diff`, `density_brix_signed_diff`, `density_below_brix`, `density_match_score` |
| 状態スコア化 | `water_score`, `oil_score`, `boiling_score`, `photo_score`（カテゴリ→0〜1へマッピング） |
| 評価可否 | `assessable`, `retake_recommended`, `visual_density_assessable`, `unassessable_axis_count` |
| 画質 | `image_condition_score`, `low_quality_flag` |
| 時間帯 | `slot_is_opening`, `slot_is_evening` |
| カテゴリ | `visual_density`, `water_level`, `oil_emulsification`, `boiling_heat_state`, `photo_quality`（OneHot） |

`assessable` は4軸（visual_density / water_level / oil_emulsification / boiling_heat_state）が
**全て「判定不可」でないか**で導出（LLM出力のassessableに依存せず、学習時と同じ規則で再計算）。

---

## 5. 評価可否の分岐 （ルール）★今回の改修

| 項目 | 内容 |
|---|---|
| 入力 | 特徴量（特に `assessable`） |
| 出力 | `scored`（スコア対象）/ `要確認`（スコア対象外） |
| 実装 | `soup_scoring.py: score_batch() / score_record()` |

```text
assessable == 1 → status="scored"  → [6] 後段スコア回帰へ
assessable == 0 → status="要確認"   → スコアせず、撮り直し/職人確認へ（reason付き）
```

**改修の根拠**: 改修前は判断不能画像にも後段が一律約77〜80点を付け、大外しの約1/4を生んでいた。
分岐導入でグレード一致率が total 76%→89% / soup 69%→88% へ改善（`05_branch_comparison/`）。

**設計判断**: `retake_recommended=1` での分岐は不採用。
これは「photo_quality≠良い」で広く立ち（全体の63%）、これで切るとデータが激減してMAEが改善せず不安定化したため、
分岐基準は `assessable=0` のみとした。

---

## 6. 後段モデル （学習）

### 6.1 スコア回帰

| 項目 | 内容 |
|---|---|
| 入力 | 評価可能（assessable=1）サンプルの特徴量 |
| 出力 | スコア（0〜100にクリップ）＋グレード |
| 学習対象 | assessable=1 の行のみ（346件） |
| 実装 | `soup_scoring.py` / 学習済み `models/*.pkl` |

| target | 出力 | 採用モデル | 特徴量セット |
|---|---|---|---|
| `human_total_score` | 総合スコア（濃度込み・主対象） | 線形回帰 | visual_plus_brix |
| `human_soup_score` | スープ単体スコア（画像評価の品質確認用） | 線形回帰 | visual_only |

グレード定義: **A ≥ 80 / B 60–79 / C 21–59 / D < 21**

**メイン／サブ構成**（継続比較）:
- メイン: 線形回帰 / Ridge回帰（精度上位＋最も安定＋説明しやすい）
- サブ: Random Forest（MAE最良）/ LightGBM（相関最良）/ XGBoost（BytePlus提案比較軸）

### 6.2 要注意判定（将来）

| 項目 | 内容 |
|---|---|
| 目的 | 60点未満など低評価の要確認対象を拾う |
| 現状 | 低評価データが全体の2.3%しかなく検出力が弱い（要注意検出率 ≈0） |
| 方針 | まずルール、低評価サンプルが増えたら軽量分類モデルへ。スコア回帰とは別建て |
| 実装状況 | 未実装（今後の改善点） |

---

## 7. 最終出力生成 （LLM）

| 項目 | 内容 |
|---|---|
| 入力 | 後段スコア / 要確認判定 / 画像評価JSON / 濃度情報 |
| 出力 | 人間向けの説明文 |
| 制約 | **LLMにスコアを自由に決めさせない**（スコアは後段モデルが確定） |

LLMの役割: 判定理由の文章化 / 職人確認ポイントの整理 / 撮り直し推奨理由の説明 /
濃度値が実測か推定かの明示。

---

## 8. 入出力データ仕様（実装済み区間 [4]〜[6]）

### 入力レコード（1件）

| キー | 必須 | 内容 |
|---|---|---|
| `visual_density` / `water_level` / `oil_emulsification` / `boiling_heat_state` / `photo_quality` | ◯ | LLM評価（文字列、評価不能は「判定不可」） |
| `image_condition_score` | ◯ | LLM画質スコア |
| `brix_raw` | △ | 実測濃度（無ければ空。将来は推定濃度を投入） |
| `slot` / `store` / `video_path` / `frame_path` | △ | 補助情報 |

### 出力レコード（1件）

| キー | 内容 |
|---|---|
| `status` | `scored` / `要確認` |
| `reason` | 要確認の理由（assessable=0時） |
| `total_score` / `total_grade` | 総合スコアとグレード（要確認時はnull） |
| `soup_score` / `soup_grade` | スープスコアとグレード（要確認時はnull） |
| `assessable` / `retake_recommended` | 判定フラグ |

---

## 9. 実装状況サマリ

| 工程 | 実装状況 |
|---|---|
| [1] 代表フレーム抽出 | 既存（改善余地: 複数枚統合） |
| [2] 画像評価AI（LLM） | 既存（改善最優先: 濃度境界補強） |
| [3] 濃度確認 | 既存ルール |
| [3a][3b] スープ抽出・濃度推定 | 既存モデル（実測なし時のみ起動） |
| **[4] 特徴量生成** | **本PJで恒久化（`soup_scoring.py`）** |
| **[5] 評価可否分岐** | **本PJで恒久化（今回の改修）** |
| **[6] スコア回帰** | **本PJで恒久化（学習済みモデル）** |
| [6] 要注意判定 | 未実装（今後） |
| [7] 最終出力生成（LLM） | 既存方針 |

---

## 関連ファイル

- 恒久化パイプライン本体: `精度改善_20260619/pipeline/`（`soup_scoring.py` / `train_model.py` / `predict.py`）
- 評価方針（固定ソース）: `APIテスト/豚山スープ画像評価プロンプト方針.md`
- 後段比較: `reports/後段モデル比較レポート_20260619.md`、`精度改善_20260619/05_branch_comparison/`
- 大外し分析: `精度改善_20260619/01_error_analysis/findings_一次分類.md`
- 精度改善レポート: `reports/精度改善レポート_20260619.md`
