# 通知設計書 11-ReduceLROnPlateau

## 概要

本ドキュメントは、TensorFlow Kerasの`ReduceLROnPlateau`コールバックの通知設計について記載する。このコールバックは、監視対象メトリクスの改善が停滞した場合に学習率を自動的に低減し、その変更をログおよびコンソールを通じて通知する仕組みである。

### 本通知の処理概要

`ReduceLROnPlateau`は、モデルトレーニング中にメトリクス（デフォルトでは`val_loss`）を監視し、一定エポック数（`patience`）にわたって改善が見られない場合に学習率を`factor`倍に低減する。低減後はクールダウン期間を設けることも可能であり、学習率が`min_lr`を下回らないよう制御される。

**業務上の目的・背景**：ディープラーニングモデルのトレーニングにおいて、学習が停滞（プラトー）した際に学習率を適切に低減することで、損失関数の局所的最適解からの脱出や収束の改善を図る。手動での学習率調整は非効率であり、自動化によりトレーニングの効率性と再現性を向上させる。

**通知の送信タイミング**：各エポック終了時（`on_epoch_end`フック）に監視メトリクスを評価し、`patience`回のエポックで改善が見られず、かつクールダウン期間外であり、現在の学習率が`min_lr`を超えている場合に学習率低減を実行し通知する。

**通知の受信者**：トレーニングを実行している開発者・研究者。`verbose > 0`が設定されている場合、標準出力（コンソール）に学習率変更メッセージが表示される。また、`logging.warning`を通じてモニタリング対象メトリクスが利用不可の場合にも警告が通知される。

**通知内容の概要**：学習率が低減された場合、エポック番号と新しい学習率の値がコンソールに出力される。形式は `Epoch XXXXX: ReduceLROnPlateau reducing learning rate to Y.` である。

**期待されるアクション**：受信者はトレーニングログを確認し、学習率の変更が適切であるかを判断する。必要に応じて`factor`や`patience`、`min_lr`などのハイパーパラメータを調整し、再トレーニングを行う。

## 通知種別

コンソール出力（標準出力 `print`） / Pythonロギング（`tf_logging.warning`）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（エポック終了時のコールバック内で即時実行） |
| 優先度 | 中（トレーニングの進行に直接影響するが、即時対応は不要） |
| リトライ | 無し（コンソール出力のためリトライ不要） |

### 送信先決定ロジック

- `verbose > 0` の場合：`print`関数により標準出力へ学習率変更メッセージを出力
- 監視メトリクスが利用不可の場合：`logging.warning`により警告メッセージを出力（verboseフラグに関係なく常に出力）

## 通知テンプレート

### コンソール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元 | ReduceLROnPlateauコールバック |
| 出力先 | 標準出力（stdout） |
| 形式 | テキスト |

### 本文テンプレート

```
Epoch {epoch+1:05d}: ReduceLROnPlateau reducing learning rate to {new_lr}.
```

警告メッセージ（メトリクス未取得時）:
```
Learning rate reduction is conditioned on metric `{monitor}` which is not available. Available metrics are: {available_keys}
```

### 添付ファイル

該当なし（コンソール出力のため添付ファイルは存在しない）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| epoch | 現在のエポック番号（0始まり、表示時+1） | `on_epoch_end`の引数 | Yes |
| new_lr | 低減後の新しい学習率 | `old_lr * factor`（`min_lr`でクリップ） | Yes |
| monitor | 監視対象メトリクス名 | `self.monitor`（デフォルト: `val_loss`） | Yes |
| available_keys | 利用可能なメトリクス一覧 | `logs.keys()` | No（警告時のみ） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| コールバック | `on_epoch_end` | patience回改善なし AND クールダウン外 AND lr > min_lr AND verbose > 0 | 学習率低減時にコンソールへ通知 |
| コールバック | `on_epoch_end` | 監視メトリクスがlogsに存在しない | メトリクス未取得警告をloggingへ出力 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| verbose == 0 | 学習率低減通知が抑止される（ただし低減処理自体は実行される） |
| クールダウン期間中 | `cooldown_counter > 0` の間は改善判定が行われず通知も発生しない |
| lr <= min_lr | 学習率が最小値以下の場合、低減処理自体がスキップされる |
| メトリクス改善あり | `monitor_op(current, best)` が True の場合、低減せず通知なし |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[on_epoch_end発火] --> B[logsからmonitorメトリクス取得]
    B --> C{メトリクス取得成功?}
    C -->|No| D[logging.warning出力]
    C -->|Yes| E{クールダウン中?}
    E -->|Yes| F[cooldown_counter減算, wait=0]
    E -->|No| G{改善あり?}
    G -->|Yes| H[best更新, wait=0]
    G -->|No| I[wait += 1]
    I --> J{wait >= patience?}
    J -->|No| K[終了]
    J -->|Yes| L{lr > min_lr?}
    L -->|No| K
    L -->|Yes| M[new_lr = old_lr * factor]
    M --> N[backend.set_value でlr更新]
    N --> O{verbose > 0?}
    O -->|Yes| P[print で通知出力]
    O -->|No| Q[通知スキップ]
    P --> R[cooldown_counter設定, wait=0]
    Q --> R
    R --> K
    D --> K
    F --> K
    H --> K
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（データベースを使用しない。インメモリでのメトリクス監視のみ）

### 更新テーブル一覧

該当なし（学習率はオプティマイザオブジェクトのインメモリ状態として更新される）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ValueError | `factor >= 1.0`で初期化した場合 | コンストラクタで即座に例外を送出（行2634-2635） |
| メトリクス未取得 | `logs.get(self.monitor)`がNone | `logging.warning`で警告を出力し、学習率変更をスキップ（行2677-2680） |
| モード不正 | `mode`が`auto`/`min`/`max`以外 | `logging.warning`で警告し`auto`にフォールバック（行2656-2659） |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| エポックあたり上限 | 最大1回（エポック終了時に1度だけ評価） |
| クールダウン制御 | `cooldown`パラメータにより低減後の再低減を抑止 |

### 配信時間帯

制限なし（トレーニング実行中に随時動作）

## セキュリティ考慮事項

- 個人情報の取り扱い：該当なし（メトリクス値と学習率のみを出力）
- 認証：不要（ローカルプロセス内の標準出力への書き込みのみ）

## 備考

- `epsilon`引数は非推奨であり、`min_delta`に置き換えられている（行2636-2639）
- `mode='auto'`の場合、メトリクス名に`acc`が含まれるかどうかで自動的に最大化/最小化を判定する（行2660-2666）
- `logs['lr']`として現在の学習率をログ辞書に追加する副作用がある（行2675）

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

Kerasコールバックの基底クラスとライフサイクルフックの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | callbacks.py | `tensorflow/python/keras/callbacks.py` | Callbackクラス（行591-670）の基本構造とフックメソッド一覧を理解する |

**読解のコツ**: `Callback`クラスは`on_epoch_begin`, `on_epoch_end`, `on_batch_begin`, `on_batch_end`, `on_train_begin`, `on_train_end`の各フックを提供する。`model`属性を通じてトレーニング中のモデルにアクセスできる。

#### Step 2: エントリーポイントを理解する

ReduceLROnPlateauのコンストラクタと初期化処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | callbacks.py | `tensorflow/python/keras/callbacks.py` | `ReduceLROnPlateau.__init__`（行2621-2651）でパラメータ設定と`_reset()`呼び出しを確認 |

**主要処理フロー**:
1. **行2621-2630**: コンストラクタ引数の受け取り（monitor, factor, patience, verbose, mode, min_delta, cooldown, min_lr）
2. **行2634-2635**: factorが1.0以上の場合のバリデーション
3. **行2636-2639**: 非推奨epsilon引数の互換処理
4. **行2651**: `_reset()`メソッド呼び出しによる内部状態初期化

#### Step 3: 状態リセットロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | callbacks.py | `tensorflow/python/keras/callbacks.py` | `_reset()`メソッド（行2653-2668）でmode判定とmonitor_op設定を確認 |

**主要処理フロー**:
- **行2656-2659**: 不正なmode値のフォールバック処理
- **行2660-2666**: mode/autoに基づくmonitor_op（比較関数）とbest値の設定

#### Step 4: 通知トリガーロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | callbacks.py | `tensorflow/python/keras/callbacks.py` | `on_epoch_end`メソッド（行2673-2702）の改善判定・学習率低減・通知出力ロジック |

**主要処理フロー**:
- **行2675**: 現在の学習率をlogsに追加
- **行2676-2680**: 監視メトリクスの取得と未取得時の警告
- **行2683-2685**: クールダウン処理
- **行2687-2689**: 改善判定
- **行2692-2702**: patience超過時の学習率低減と通知出力

### プログラム呼び出し階層図

```
model.fit() [Kerasトレーニングループ]
    │
    ├─ CallbackList.on_train_begin()
    │      └─ ReduceLROnPlateau.on_train_begin() [行2670-2671]
    │             └─ _reset() [行2653-2668]
    │
    └─ [各エポックのループ]
           └─ CallbackList.on_epoch_end()
                  └─ ReduceLROnPlateau.on_epoch_end() [行2673-2702]
                         ├─ backend.get_value(model.optimizer.lr) [行2675]
                         ├─ logs.get(self.monitor) [行2676]
                         ├─ self.monitor_op(current, self.best) [行2687]
                         ├─ backend.set_value(model.optimizer.lr, new_lr) [行2697]
                         └─ print() [行2699-2700] ※verbose > 0の場合
```

### データフロー図

```
[入力]                     [処理]                           [出力]

logs (メトリクス辞書)  ───▶ on_epoch_end()              ───▶ stdout (学習率変更通知)
                           │                                │
model.optimizer.lr     ───▶ ├─ メトリクス評価               ├─ logging.warning (警告)
                           ├─ 改善判定                      │
                           ├─ patience判定                  └─ model.optimizer.lr (更新)
                           └─ 学習率低減
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| callbacks.py | `tensorflow/python/keras/callbacks.py` | ソース | ReduceLROnPlateauクラス定義（行2585-2705） |
| callbacks.py | `tensorflow/python/keras/callbacks.py` | ソース | Callback基底クラス（行591-670） |
| backend.py | `tensorflow/python/keras/backend.py` | ソース | `get_value`/`set_value`による学習率の読み書き |
