# 通知設計書 1-BaseLogger

## 概要

本ドキュメントは、TensorFlow Kerasの`BaseLogger`コールバックに関する通知設計書である。`BaseLogger`はエポックごとのメトリクス平均値を蓄積し、後続コールバックへ通知する基盤コールバックである。

### 本通知の処理概要

`BaseLogger`は、Kerasモデルのトレーニングにおいて、各エポック内の全バッチにわたるメトリクス値を蓄積し、エポック終了時に平均値を計算して`logs`辞書に書き戻すことで、後続のコールバック（`History`や`ProgbarLogger`など）が正確なエポック単位のメトリクスを取得できるようにする。

**業務上の目的・背景**：機械学習モデルのトレーニングでは、バッチ単位のメトリクス値はノイズが多く、エポック単位の平均値がモデルの学習進捗を把握するために重要である。`BaseLogger`はこのメトリクス平均化処理を自動的に行い、他のコールバックが正確な値を利用できるようにする基盤的役割を担う。

**通知の送信タイミング**：エポック開始時（`on_epoch_begin`）にカウンタと蓄積値をリセットし、各バッチ終了時（`on_batch_end`）にメトリクス値を蓄積し、エポック終了時（`on_epoch_end`）に平均値を計算して`logs`辞書に反映する。

**通知の受信者**：`CallbackList`に登録された後続のコールバック全て。`BaseLogger`はコールバックリストの先頭に配置されるため、`on_epoch_end`で`logs`辞書を更新した結果を後続コールバックが参照する。

**通知内容の概要**：エポック内の全バッチにおけるメトリクス（loss、accuracy等）の平均値。`stateful_metrics`に指定されたメトリクスは平均化されず、最後の値がそのまま通知される。

**期待されるアクション**：後続コールバック（`History`、`ProgbarLogger`、`EarlyStopping`等）がエポック単位の正確なメトリクス値を取得し、それぞれの処理（履歴記録、進捗表示、早期停止判定等）を行う。

## 通知種別

アプリ内通知（Kerasコールバックフレームワーク内部の`logs`辞書更新による通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高（全Kerasモデルに自動適用） |
| リトライ | 無し |

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

`CallbackList`内で`BaseLogger`より後に登録されている全てのコールバックが受信者となる。`configure_callbacks`関数（行74-133）において、`BaseLogger`はコールバックリストの先頭に挿入され（行112）、後続コールバックが更新済みの`logs`を参照する。

## 通知テンプレート

### メール通知の場合

該当なし（アプリ内通知のため）

### 本文テンプレート

```
logs辞書のキーと値のペア:
{
  "loss": <エポック平均loss値>,
  "<metric_name>": <エポック平均metric値>,
  ...
}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| loss | 損失関数の平均値 | バッチごとのlogs['loss']の蓄積平均 | Yes |
| metrics | 各メトリクスの平均値 | self.params['metrics']に登録されたメトリクス名 | No |
| stateful_metrics | 平均化しないメトリクス | コンストラクタ引数またはset_callback_parameters設定 | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| エポック開始 | on_epoch_begin | 常に発火 | カウンタ・蓄積値リセット |
| バッチ終了 | on_batch_end | 常に発火 | メトリクス値蓄積 |
| エポック終了 | on_epoch_end | logs is not None | 平均値計算・logs更新 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| logs is None | on_epoch_endでlogsがNoneの場合、メトリクス値の更新をスキップ |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[on_epoch_begin: カウンタリセット] --> B[on_batch_end: メトリクス蓄積]
    B --> B
    B --> C[on_epoch_end: 平均値計算]
    C --> D{logs is not None?}
    D -->|Yes| E[logsにメトリクス平均値を書き戻し]
    D -->|No| F[スキップ]
    E --> G[後続コールバックが更新済みlogsを参照]
    F --> G
```

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

### 参照テーブル一覧

該当なし（インメモリ処理のみ）

### 更新テーブル一覧

該当なし（インメモリ処理のみ）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ZeroDivisionError | self.seenが0の場合 | バッチが実行されないエポックでは0除算が発生する可能性（通常は発生しない） |
| KeyError | params['metrics']にないメトリクス名 | self.totalsに存在するキーのみ処理 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

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

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

特になし。メトリクス値のみを扱い、個人情報や機密データは含まない。

## 備考

- `BaseLogger`はすべてのKerasモデルのトレーニングに自動的に適用される（`configure_callbacks`関数で自動挿入）
- `stateful_metrics`に指定されたメトリクスは平均化されず、最後のバッチの値がそのまま使用される
- TF2のデフォルトでは`CallbackList`の`add_history`/`add_progbar`パラメータ経由で追加される

---

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

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

### 推奨読解順序

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

まず、`BaseLogger`が扱うデータ構造（`logs`辞書、`stateful_metrics`、`totals`等）を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | callbacks.py | `tensorflow/python/keras/callbacks.py` | `BaseLogger`クラス定義（行902-948）。`stateful_metrics`、`seen`、`totals`の3つのインスタンス変数を確認 |

**読解のコツ**: `stateful_metrics`は「平均化しないメトリクス」を指定するセットであり、これに含まれるメトリクスは最後のバッチの値がそのまま使われる。

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

`BaseLogger`がどのようにコールバックリストに組み込まれるかを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | callbacks.py | `tensorflow/python/keras/callbacks.py` | `configure_callbacks`関数（行74-133）。BaseLoggerの自動挿入ロジックを確認 |
| 2-2 | callbacks.py | `tensorflow/python/keras/callbacks.py` | `CallbackList.__init__`（行204-261）及び`_add_default_callbacks`（行263-280）。TF2パスでのコールバック追加 |

**主要処理フロー**:
1. **行112**: `callbacks = [BaseLogger()] + (callbacks or []) + [model.history]` でBaseLoggerをリスト先頭に挿入
2. **行160-162**: `set_callback_parameters`で`stateful_metrics`をmodel.metrics_names[1:]に設定

#### Step 3: メトリクス蓄積処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | callbacks.py | `tensorflow/python/keras/callbacks.py` | `on_epoch_begin`（行918-920）。`seen`と`totals`のリセット |
| 3-2 | callbacks.py | `tensorflow/python/keras/callbacks.py` | `on_batch_end`（行922-937）。バッチサイズ加算とメトリクス蓄積ロジック |
| 3-3 | callbacks.py | `tensorflow/python/keras/callbacks.py` | `on_epoch_end`（行939-947）。平均値計算とlogs辞書への書き戻し |

**主要処理フロー**:
- **行924**: `batch_size = logs.get('size', 0)` でバッチサイズを取得
- **行927-928**: `num_steps`を考慮した`seen`カウンタの更新
- **行930-937**: `stateful_metrics`に含まれるかどうかで蓄積方法を分岐
- **行942-947**: `self.params['metrics']`に含まれるメトリクスについて平均値を計算

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

```
model.fit()
    |
    +-- CallbackList.on_epoch_begin()
    |       +-- BaseLogger.on_epoch_begin()  # seen=0, totals={} にリセット
    |
    +-- [バッチループ]
    |       +-- CallbackList.on_batch_end()
    |               +-- BaseLogger.on_batch_end()  # メトリクス蓄積
    |
    +-- CallbackList.on_epoch_end()
            +-- BaseLogger.on_epoch_end()  # 平均値計算、logs更新
            +-- History.on_epoch_end()     # 更新済みlogsを記録
            +-- ProgbarLogger.on_epoch_end()  # 更新済みlogsを表示
```

### データフロー図

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

バッチごとのlogs     ---> BaseLogger.on_batch_end()   ---> self.totals（蓄積値）
  {loss: 0.5,              メトリクス値 * batch_size         self.seen（サンプル数）
   accuracy: 0.8}          を蓄積

self.totals          ---> BaseLogger.on_epoch_end()   ---> logs辞書（平均値更新済み）
self.seen                  totals[k] / seen                  {loss: 0.45,
                           を計算                              accuracy: 0.82}
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| callbacks.py | `tensorflow/python/keras/callbacks.py` | ソース | BaseLoggerクラス定義、CallbackList、configure_callbacks |
| generic_utils.py | `tensorflow/python/keras/utils/generic_utils.py` | ソース | Progbarクラス（ProgbarLoggerが使用） |
| tf_utils.py | `tensorflow/python/keras/utils/tf_utils.py` | ソース | sync_to_numpy_or_python_type関数 |
