# 通知設計書 17-CheckpointSaverListener

## 概要

本ドキュメントは、TensorFlowの`CheckpointSaverListener`の通知設計について記載する。これはチェックポイント保存イベントの前後に通知を受け取るリスナーインターフェースであり、`CheckpointSaverHook`と連携して動作する。

### 本通知の処理概要

`CheckpointSaverListener`は、チェックポイント保存イベントに対するオブザーバー（リスナー）パターンを実装する抽象インターフェースである。`begin`、`before_save`、`after_save`、`end`の4つのフックメソッドを提供し、`CheckpointSaverHook`から呼び出される。ユーザはこのクラスを継承してカスタムリスナーを実装する。

**業務上の目的・背景**：チェックポイント保存という重要なイベントに対して、カスタム処理を注入するための拡張ポイントを提供する。モデル評価、外部通知、データベース更新、モデルデプロイなど、保存イベントに連動した多様な業務処理を実装可能にする。

**通知の送信タイミング**：(1) セッション使用前（`begin`）、(2) チェックポイント保存直前（`before_save`）、(3) チェックポイント保存直後（`after_save`）、(4) セッション終了時（`end`）。これらのタイミングは`CheckpointSaverHook`のトリガーに依存する。

**通知の受信者**：`CheckpointSaverListener`を継承したユーザ定義クラスのインスタンス。`CheckpointSaverHook`のコンストラクタに`listeners`引数として渡される。

**通知内容の概要**：`before_save`と`after_save`にはセッションオブジェクトとグローバルステップ値が渡される。`end`にもセッションとグローバルステップ値が渡される。`begin`は引数なし。

**期待されるアクション**：リスナー実装者が定義する任意のアクション。`after_save`からTrueを返すことでトレーニング停止を要求可能（分散トレーニングではチーフのみで使用すべき）。

## 通知種別

プログラム内部通知（インターフェースコールバック / オブザーバーパターン）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（CheckpointSaverHookから直接呼び出し） |
| 優先度 | 高（チェックポイント保存に連動する重要イベント） |
| リトライ | 無し |

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

- `CheckpointSaverHook`のコンストラクタに渡された`listeners`リストの全リスナーに順次通知
- リスナーの実行順序はリストの順序に従う

## 通知テンプレート

### コールバック通知の場合

リスナーインターフェースのメソッドシグネチャ：

| メソッド | 引数 | 戻り値 |
|---------|------|--------|
| `begin()` | なし | なし |
| `before_save(session, global_step_value)` | セッション, グローバルステップ | なし |
| `after_save(session, global_step_value)` | セッション, グローバルステップ | True: 停止要求 / None: 継続 |
| `end(session, global_step_value)` | セッション, グローバルステップ | なし |

### 本文テンプレート

該当なし（インターフェース定義のみ。実装はユーザに委ねられる）

使用例（docstringより）:
```python
class ExampleCheckpointSaverListener(CheckpointSaverListener):
    def begin(self):
        print('Starting the session.')
        self.your_tensor = ...

    def before_save(self, session, global_step_value):
        print('About to write a checkpoint')

    def after_save(self, session, global_step_value):
        print('Done writing checkpoint.')
        if decided_to_stop_training():
            return True

    def end(self, session, global_step_value):
        print('Done with the session.')
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| session | TensorFlowセッションオブジェクト | MonitoredSession | Yes（before_save/after_save/end） |
| global_step_value | 現在のグローバルステップ値 | `session.run(_global_step_tensor)` | Yes（before_save/after_save/end） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| CheckpointSaverHook | `begin` | CheckpointSaverHook.begin()が呼ばれた時 | セッション使用前の初期化フック |
| CheckpointSaverHook | `_save` | Saver.save()呼出の直前 | `before_save(session, step)` |
| CheckpointSaverHook | `_save` | Saver.save()呼出の直後 | `after_save(session, step)` |
| CheckpointSaverHook | `end` | セッション終了時 | `end(session, last_step)` |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| CheckpointSaverHookのトリガー条件 | チェックポイント保存が発生しない場合、before_save/after_saveは呼ばれない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[CheckpointSaverHook.begin] --> B[listener.begin]
    B --> C[トレーニング開始]
    C --> D{保存トリガー?}
    D -->|Yes| E[listener.before_save]
    D -->|No| C
    E --> F[Saver.save実行]
    F --> G[listener.after_save]
    G --> H{戻り値=True?}
    H -->|Yes| I[トレーニング停止要求]
    H -->|No| C
    I --> J[listener.end]
    J --> K[終了]
```

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

### 参照テーブル一覧

該当なし（インターフェース定義のみ。ユーザ実装に依存）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| リスナー内例外 | ユーザ実装のリスナーメソッド内で例外発生 | 例外はCheckpointSaverHookを経由してトレーニングループに伝播 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限 | CheckpointSaverHookの保存頻度に従う |

### 配信時間帯

制限なし

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

- `session`オブジェクトがリスナーに渡されるため、リスナー実装内で任意のテンソル評価が可能。信頼できるリスナー実装のみを使用すべき
- `after_save`のTrue返却による停止要求は、分散トレーニングではチーフワーカーのみで使用すべき（各ワーカーで独立に評価すると無駄なリソース消費が発生する可能性）

## 備考

- デフォルト実装はすべてno-op（`pass`）であり、必要なフックのみオーバーライドすれば良い（行510-520）
- リスナーは独自のスケジュールで動作可能（例：`global_step_value`に基づいて一部の保存イベントのみ処理）
- `end()`は最後のチェックポイント保存に関連するアクションを処理するために使用。`after_save()`で既に処理済みの場合は重複処理しないよう注意が必要

---

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

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

### 推奨読解順序

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

CheckpointSaverListenerインターフェースの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | basic_session_run_hooks.py | `tensorflow/python/training/basic_session_run_hooks.py` | CheckpointSaverListenerクラス（行457-520）の4つのフックメソッド |

**読解のコツ**: このクラスはSessionRunHookを継承していない独立したリスナーインターフェースである。CheckpointSaverHookの`listeners`引数として渡され、保存イベント前後に呼び出される。

#### Step 2: 呼び出し元を理解する

CheckpointSaverHookからの呼び出しパターンを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | basic_session_run_hooks.py | `tensorflow/python/training/basic_session_run_hooks.py` | CheckpointSaverHook.begin（行582-583）でのlistener.begin()呼び出し |
| 2-2 | basic_session_run_hooks.py | `tensorflow/python/training/basic_session_run_hooks.py` | CheckpointSaverHook._save（行625-648）でのbefore_save/after_save呼び出し |
| 2-3 | basic_session_run_hooks.py | `tensorflow/python/training/basic_session_run_hooks.py` | CheckpointSaverHook.end（行622-623）でのlistener.end()呼び出し |

**主要処理フロー**:
- **行582-583**: `begin` - リスナーリストを順次呼び出し
- **行629-630**: `before_save` - 保存前に全リスナーを順次呼び出し
- **行641-648**: `after_save` - 保存後に全リスナーを順次呼び出し、True返却で停止要求
- **行622-623**: `end` - セッション終了時に全リスナーを呼び出し

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

```
CheckpointSaverHook
    │
    ├─ begin() [行576-583]
    │      └─ for l in listeners: l.begin() [行582-583]
    │
    ├─ _save() [行625-648]
    │      ├─ for l in listeners: l.before_save(session, step) [行629-630]
    │      ├─ saver.save() [行633-634]
    │      └─ for l in listeners: l.after_save(session, step) [行641-648]
    │             └─ if True returned: should_stop = True
    │
    └─ end() [行618-623]
           └─ for l in listeners: l.end(session, last_step) [行622-623]
```

### データフロー図

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

CheckpointSaverHook        ───▶ listener.begin()            ───▶ ユーザ定義処理
session                    ───▶ listener.before_save()      ───▶ ユーザ定義処理
global_step_value          ───▶ listener.after_save()       ───▶ ユーザ定義処理 + 停止要求(optional)
                                listener.end()              ───▶ ユーザ定義処理
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| basic_session_run_hooks.py | `tensorflow/python/training/basic_session_run_hooks.py` | ソース | CheckpointSaverListenerクラス定義（行457-520） |
| basic_session_run_hooks.py | `tensorflow/python/training/basic_session_run_hooks.py` | ソース | CheckpointSaverHookクラス（行524-670）-- リスナー呼び出し元 |
