# 通知設計書 14-LoggingTensorHook

## 概要

本ドキュメントは、TensorFlowの`LoggingTensorHook`（SessionRunHook）の通知設計について記載する。このフックは、指定されたテンソルの値をトレーニング中に定期的にログ出力（`tf_logging.info`）する通知機構である。

### 本通知の処理概要

`LoggingTensorHook`は、Nステップごと、N秒ごと、またはトレーニング終了時に指定テンソルの値を`logging.info`（INFOレベル）で出力する。テンソルは辞書またはリスト形式で指定でき、カスタムフォーマッタによる出力形式のカスタマイズも可能である。

**業務上の目的・背景**：トレーニング中のテンソル値（loss、accuracy、global_step等）をリアルタイムにモニタリングすることで、トレーニングの進行状況を把握し、異常検知やハイパーパラメータ調整の判断材料を提供する。TensorBoardを使わない軽量なモニタリング手段として利用される。

**通知の送信タイミング**：`every_n_iter`ステップごと、`every_n_secs`秒ごと、または`at_end=True`でトレーニング終了時にテンソル値をログに出力する。`SecondOrStepTimer`によりトリガータイミングが管理される。

**通知の受信者**：トレーニングを実行している開発者・運用者。Pythonのloggingフレームワーク（`tf_logging`）を通じてINFOレベルでログが出力され、標準エラー出力やログファイルに記録される。

**通知内容の概要**：指定されたテンソルのタグ名と値が `tag = value` 形式で出力される。前回のトリガーからの経過秒数も付記される。

**期待されるアクション**：受信者はログ出力を確認し、トレーニングの進行状況を把握する。異常な値（過大なloss、急激な変動等）が観測された場合、トレーニングの停止やパラメータ調整を検討する。

## 通知種別

Pythonロギング出力（`tf_logging.info` / INFOレベル）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（session.run後のafter_runフック内で即時実行） |
| 優先度 | 低（情報提供目的のモニタリング） |
| リトライ | 無し |

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

- `tf_logging.info`を使用し、Pythonのloggingフレームワークに委譲
- ログレベルがINFO以上に設定されている場合に出力される

## 通知テンプレート

### ログ出力の場合

| 項目 | 内容 |
|-----|------|
| 出力先 | tf_logging（INFOレベル） |
| 形式 | テキスト |

### 本文テンプレート

標準フォーマット（formatter未指定時）:
```
tag1 = value1, tag2 = value2 (X.XXX sec)
```

初回出力時（elapsed_secsがNone）:
```
tag1 = value1, tag2 = value2
```

カスタムフォーマッタ指定時:
```
{formatter関数の戻り値}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| tag | テンソルのタグ名 | `tensors`辞書のキーまたはテンソル名 | Yes |
| value | テンソルの評価値 | `session.run()`の結果 | Yes |
| elapsed_secs | 前回出力からの経過秒数 | `SecondOrStepTimer.update_last_triggered_step()` | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| SessionRunHook | `after_run` | `_timer.should_trigger_for_step(iter_count)` | Nステップ/N秒経過時にテンソル値をログ出力 |
| SessionRunHook | `end` | `at_end=True` | トレーニング終了時にテンソル値をログ出力 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| タイマー未トリガー | `should_trigger_for_step`がFalseの場合、ログ出力をスキップ |
| at_end=False | トレーニング終了時のログ出力を行わない |
| ログレベルがINFO未満 | Pythonのlogging設定でINFOレベルが抑止されている場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[before_run発火] --> B{timer.should_trigger?}
    B -->|Yes| C[SessionRunArgsにテンソル追加]
    B -->|No| D[SessionRunArgs=None]
    C --> E[session.run実行]
    D --> E
    E --> F[after_run発火]
    F --> G{should_trigger?}
    G -->|Yes| H[_log_tensors実行]
    G -->|No| I[iter_count += 1]
    H --> J[timer.update_last_triggered_step]
    J --> K{formatter指定?}
    K -->|Yes| L[formatter(tensor_values)をlogging.info]
    K -->|No| M[tag=value形式でlogging.info]
    L --> I
    M --> I
    I --> N{トレーニング終了?}
    N -->|Yes and at_end| O[end()でsession.runしてログ出力]
    N -->|No| A
    O --> P[終了]
    N -->|Yes and not at_end| P
```

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

### 参照テーブル一覧

該当なし（データベースを使用しない）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ValueError | `every_n_iter`が非正の値 | コンストラクタで例外送出（行222-223） |
| ValueError | `every_n_iter`と`every_n_secs`のどちらも指定/両方指定 | コンストラクタで例外送出（行217-221） |
| ValueError | テンソルがグラフに属していない | `_as_graph_element`で例外送出（行1097-1118） |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| ステップ単位 | `every_n_iter`で指定（デフォルトなし） |
| 時間単位 | `every_n_secs`で指定（デフォルトなし） |

### 配信時間帯

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

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

- テンソル値にはモデルのパラメータや入力データの統計値が含まれる可能性があるが、通常は集約値であり個別データは含まない
- ログ出力先のセキュリティはPythonのloggingフレームワークの設定に依存

## 備考

- `np.set_printoptions(suppress=True)`により科学記法を抑止してテンソル値を出力（行2253-2254）
- テンソルはdict形式でもリスト/タプル形式でも指定可能。リスト形式の場合、テンソル名がタグとして使用される（行224-228）
- `NeverTriggerTimer`は`at_end=True`かつ`every_n_iter=None, every_n_secs=None`の場合に使用される（行231-233）

---

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

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

### 推奨読解順序

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

SessionRunHookのライフサイクルと、SessionRunArgs/SessionRunValuesの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | session_run_hook.py | `tensorflow/python/training/session_run_hook.py` | SessionRunHook基底クラス（行94-182）のbegin/before_run/after_run/endフック |
| 1-2 | session_run_hook.py | `tensorflow/python/training/session_run_hook.py` | SessionRunArgs（行186-207）とSessionRunValues（行262-283）のデータ構造 |

**読解のコツ**: `before_run`で`SessionRunArgs`を返すことで追加のテンソルをfetchリストに追加でき、`after_run`の`run_values.results`でその結果を受け取れる。

#### Step 2: タイマー機構を理解する

SecondOrStepTimerとNeverTriggerTimerのトリガー判定ロジックを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | basic_session_run_hooks.py | `tensorflow/python/training/basic_session_run_hooks.py` | SecondOrStepTimer（行86-150）のshould_trigger_for_step/update_last_triggered_step |
| 2-2 | basic_session_run_hooks.py | `tensorflow/python/training/basic_session_run_hooks.py` | NeverTriggerTimer（行153-165）のno-op実装 |

**主要処理フロー**:
1. **行109-134**: `should_trigger_for_step` - ステップ数or経過秒数によるトリガー判定
2. **行136-147**: `update_last_triggered_step` - 最終トリガー時刻/ステップの更新と経過情報の返却

#### Step 3: LoggingTensorHookの実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | basic_session_run_hooks.py | `tensorflow/python/training/basic_session_run_hooks.py` | LoggingTensorHookクラス（行169-278）全体のフロー |

**主要処理フロー**:
- **行191-234**: コンストラクタ - テンソル辞書/リストの正規化、タイマー作成
- **行236-243**: `begin` - テンソル名からグラフ要素への変換
- **行245-250**: `before_run` - トリガー判定とSessionRunArgsの返却
- **行252-266**: `_log_tensors` - テンソル値のフォーマットとログ出力
- **行268-273**: `after_run` - トリガー時のログ出力呼び出し
- **行275-278**: `end` - at_end時の最終ログ出力

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

```
MonitoredTrainingSession.run()
    │
    ├─ LoggingTensorHook.begin() [行236-243]
    │      ├─ _timer.reset() [行237]
    │      └─ _as_graph_element() [行241] ※テンソル名→テンソルオブジェクト変換
    │
    ├─ [各ステップのループ]
    │      ├─ LoggingTensorHook.before_run() [行245-250]
    │      │      └─ _timer.should_trigger_for_step() [行246]
    │      │
    │      └─ LoggingTensorHook.after_run() [行268-273]
    │             └─ _log_tensors() [行252-266]
    │                    ├─ _timer.update_last_triggered_step() [行255]
    │                    └─ logging.info() [行257 or 263-265]
    │
    └─ LoggingTensorHook.end() [行275-278]
           └─ session.run() + _log_tensors() ※at_end=Trueの場合
```

### データフロー図

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

tensors (指定テンソル)    ───▶ before_run()               ───▶ SessionRunArgs
                               │
session.run() results     ───▶ after_run()                ───▶ logging.info (テンソル値)
                               └─ _log_tensors()               │
                                   ├─ formatter()               ├─ "tag = value (X.XXX sec)"
                                   └─ デフォルトフォーマット     └─ カスタムフォーマット
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| basic_session_run_hooks.py | `tensorflow/python/training/basic_session_run_hooks.py` | ソース | LoggingTensorHookクラス定義（行169-278） |
| basic_session_run_hooks.py | `tensorflow/python/training/basic_session_run_hooks.py` | ソース | SecondOrStepTimer/NeverTriggerTimer（行49-165） |
| session_run_hook.py | `tensorflow/python/training/session_run_hook.py` | ソース | SessionRunHook基底クラス、SessionRunArgs/Values |
| basic_session_run_hooks.py | `tensorflow/python/training/basic_session_run_hooks.py` | ソース | `_as_graph_element`ヘルパー関数（行1097-1118） |
