# 通知設計書 21-GlobalStepWaiterHook

## 概要

本ドキュメントは、TensorFlowの`tf.train.GlobalStepWaiterHook`の通知設計について記載する。本フックは、分散トレーニング環境においてワーカーの起動タイミングを制御するためのSessionRunHookである。

### 本通知の処理概要

GlobalStepWaiterHookは、グローバルステップが指定された値に到達するまでワーカーの実行を遅延させるフックである。分散トレーニング環境において、全ワーカーが同時に開始するのではなく、段階的に参加させるために使用される。

**業務上の目的・背景**：分散トレーニングにおいて、複数のワーカーが同時にトレーニングを開始すると、パラメータサーバーへの負荷集中やモデルの不安定性が生じる場合がある。GlobalStepWaiterHookは、チーフワーカーがある程度のステップを進めた後に他のワーカーを段階的に参加させることで、トレーニングの安定性と効率性を確保する。典型的な使用例は`wait_until_step=int(K*log(task_id+1))`のようにtask_idに応じて待機ステップを設定するパターンである。

**通知の送信タイミング**：`before_run()`フック内で、`session.run()`が呼ばれる前に毎回グローバルステップを確認する。グローバルステップが`wait_until_step`に到達していない場合は0.5秒間隔でポーリングを行い、到達するまでブロッキングで待機する。到達した時点でワーカーの実行を開始する旨をログに出力する。

**通知の受信者**：このフックを設定したワーカープロセス自身が受信者である。フック内部でワーカーの開始状態（`_worker_is_started`フラグ）を管理し、他のプロセスやシステムへの明示的な通知は行わない。ログ出力を通じて運用者にも待機状態が通知される。

**通知内容の概要**：待機中はログレベルINFOで「Waiting for global step N before starting training. Current step is M.」というメッセージを1000ステップごとに出力する。グローバルステップが目標値に到達した時点でブロッキングを解除し、通常のトレーニングループに処理を返す。

**期待されるアクション**：運用者はログを監視し、各ワーカーが適切なタイミングで開始されていることを確認する。異常に長い待機が発生した場合は、チーフワーカーの状態やネットワーク接続を確認する必要がある。

## 通知種別

ログ出力（tf_logging INFO）/ プロセス内状態通知（フラグ制御）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（ブロッキングポーリング） |
| 優先度 | 高（トレーニング開始を制御するため） |
| リトライ | 無し（ポーリングにより継続的に確認） |

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

送信先は固定で、フックを設定したワーカープロセス自身である。`MonitoredTrainingSession`または`MonitoredSession`を通じて`before_run()`が呼ばれるたびに、内部状態`_worker_is_started`をチェックし、未開始の場合のみ待機ロジックが実行される。

## 通知テンプレート

### ログ出力の場合

| 項目 | 内容 |
|-----|------|
| 送信元 | `tf.train.GlobalStepWaiterHook` |
| ログレベル | INFO |
| 形式 | テキスト |

### 本文テンプレート

```
Waiting for global step {wait_until_step} before starting training.
Waiting for global step {wait_until_step} before starting training. Current step is {current_step}.
```

### 添付ファイル

なし（ログ出力のみ）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| wait_until_step | 待機目標ステップ数 | コンストラクタ引数 | Yes |
| current_step | 現在のグローバルステップ | session.run(global_step_tensor) | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| SessionRunフック | before_run()呼び出し | `_worker_is_started == False` かつ `wait_until_step > 0` | MonitoredSessionのrun()が呼ばれるたびにbefore_run()が実行される |
| ポーリング | 0.5秒間隔のsession.run() | `current_step < wait_until_step` | 待機中は0.5秒ごとにグローバルステップを確認 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| `_worker_is_started == True` | 既にワーカーが開始済みの場合、before_run()は即座にNoneを返す |
| `wait_until_step <= 0` | 待機ステップが0以下の場合、即座にワーカーを開始する |
| ログ出力間隔 | 前回のログ出力から1000ステップ以上進んだ場合のみ進捗ログを出力する |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[MonitoredSession.run呼び出し] --> B[before_run発火]
    B --> C{_worker_is_started?}
    C -->|True| D[None返却 - 通常実行]
    C -->|False| E{wait_until_step <= 0?}
    E -->|True| F[_worker_is_started = True]
    E -->|False| G[INFO: Waiting for global step...]
    G --> H[ポーリングループ開始]
    H --> I[session.run global_step_tensor]
    I --> J{current_step >= wait_until_step?}
    J -->|Yes| F
    J -->|No| K{1000ステップ以上経過?}
    K -->|Yes| L[INFO: Waiting... Current step is...]
    K -->|No| M[time.sleep 0.5秒]
    L --> M
    M --> I
    F --> D
```

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

### 参照テーブル一覧

本フックはデータベースを直接参照しない。TensorFlowセッション内のグローバルステップテンソルを参照する。

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| （なし） | - | TFグラフ内のglobal_stepテンソルを使用 |

### テーブル別参照項目詳細

#### グローバルステップテンソル

| 参照項目 | 用途 | 取得条件 |
|---------|------|---------|
| global_step | 現在のトレーニングステップ数 | `training_util._get_or_create_global_step_read()` |

### 更新テーブル一覧

本フックはデータの更新を行わない。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| RuntimeError | グローバルステップが作成されていない場合（begin()内） | "Global step should be created to use _GlobalStepWaiterHook."メッセージを出力しRuntimeErrorを送出 |
| セッション切断 | ポーリング中にセッションが切断された場合 | MonitoredSessionの例外処理に委譲 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 無制限（ポーリングベース） |
| リトライ間隔 | 0.5秒 |
| リトライ対象エラー | グローバルステップ未到達 |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| ポーリング間隔 | 0.5秒（time.sleep(0.5)） |
| ログ出力間隔 | 1000ステップごと |

### 配信時間帯

制限なし。トレーニング開始時に動作する。

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

- 本フックはプロセス内でのみ動作し、外部通信を行わない
- グローバルステップの取得はTensorFlowセッション経由で行われ、セッションのアクセス制御に従う
- 分散環境ではgRPC等を通じてパラメータサーバーからグローバルステップを取得するため、通信経路の暗号化はTensorFlowの分散設定に依存する

## 備考

- TensorFlow v1 APIに属する。TF2ではEstimatorとの組み合わせで使用される
- `tf.estimator`名前空間にもエクスポートされている
- チーフワーカー（task_id=0）では`wait_until_step=0`を設定することが一般的

---

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

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

### 推奨読解順序

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

まず、SessionRunHookのインターフェースとライフサイクルを理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | session_run_hook.py | `tensorflow/python/training/session_run_hook.py` | SessionRunHookの基底クラス定義。begin(), before_run(), after_run(), end()の各フックメソッドの契約を理解する（行97-182） |
| 1-2 | session_run_hook.py | `tensorflow/python/training/session_run_hook.py` | SessionRunArgs, SessionRunContext, SessionRunValuesのデータ構造（行186-284） |

**読解のコツ**: SessionRunHookはオブザーバーパターンで実装されており、MonitoredSessionが各フックメソッドを適切なタイミングで呼び出す。

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

GlobalStepWaiterHookの実装本体を読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | basic_session_run_hooks.py | `tensorflow/python/training/basic_session_run_hooks.py` | GlobalStepWaiterHookクラス定義（行901-948） |

**主要処理フロー**:
1. **行911-917**: `__init__()` - `wait_until_step`の保持
2. **行919-924**: `begin()` - `_worker_is_started`フラグの初期化とグローバルステップテンソルの取得
3. **行926-947**: `before_run()` - 待機ロジックの本体。ポーリングループで0.5秒間隔でグローバルステップを確認

#### Step 3: トレーニングユーティリティを理解する

グローバルステップの取得メカニズムを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | training_util.py | `tensorflow/python/training/training_util.py` | `_get_or_create_global_step_read()`関数の実装 |

**主要処理フロー**:
- グローバルステップ変数の読み取りオペレーションを取得または作成する

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

```
MonitoredSession.run()
    |
    +-- GlobalStepWaiterHook.begin()
    |       +-- training_util._get_or_create_global_step_read()
    |
    +-- GlobalStepWaiterHook.before_run(run_context)
            |
            +-- [_worker_is_started == True] --> return None
            |
            +-- [_worker_is_started == False]
                    +-- logging.info("Waiting for global step...")
                    +-- while True:
                            +-- run_context.session.run(global_step_tensor)
                            +-- [current_step >= wait_until_step]
                            |       +-- _worker_is_started = True
                            |       +-- return None
                            +-- [current_step < wait_until_step]
                                    +-- logging.info(進捗) [1000ステップごと]
                                    +-- time.sleep(0.5)
```

### データフロー図

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

wait_until_step ---------> GlobalStepWaiterHook ----------> ログ出力（INFO）
(コンストラクタ引数)         .before_run()                    _worker_is_startedフラグ

global_step_tensor ------> session.run() -----------------> current_step値
(TFグラフ)                  (ポーリング0.5秒間隔)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| basic_session_run_hooks.py | `tensorflow/python/training/basic_session_run_hooks.py` | ソース | GlobalStepWaiterHookの実装（行901-948） |
| session_run_hook.py | `tensorflow/python/training/session_run_hook.py` | ソース | SessionRunHook基底クラス定義 |
| training_util.py | `tensorflow/python/training/training_util.py` | ソース | グローバルステップテンソルの取得ユーティリティ |
| tf_logging.py | `tensorflow/python/platform/tf_logging.py` | ソース | ログ出力モジュール |
