# 通知設計書 12-CSVLogger

## 概要

本ドキュメントは、TensorFlow Kerasの`CSVLogger`コールバックの通知設計について記載する。このコールバックは、トレーニング中の各エポックにおけるメトリクス結果をCSVファイルにストリーミング出力し、トレーニングの進捗をファイルベースで記録・通知する仕組みである。

### 本通知の処理概要

`CSVLogger`は、各エポック終了時にトレーニングメトリクス（loss、accuracy等）をCSV形式でファイルに書き出す。追記モード（`append=True`）と上書きモード（`append=False`）を切り替え可能であり、トレーニング終了時にファイルを適切にクローズする。

**業務上の目的・背景**：モデルトレーニングの結果を永続的に記録し、後から分析・可視化するための基盤を提供する。コンソール出力は揮発性があるが、CSVファイルに記録することでトレーニング履歴の再現性を確保し、複数実験の比較やレポート作成が容易になる。

**通知の送信タイミング**：各エポック終了時（`on_epoch_end`フック）にメトリクスをCSVファイルに書き出す。トレーニング開始時（`on_train_begin`）にファイルをオープンし、トレーニング終了時（`on_train_end`）にファイルをクローズする。

**通知の受信者**：CSVファイルを参照する開発者・研究者・データ分析ツール。ファイルベースの非同期的な通知であり、トレーニング中でも外部ツールから参照可能（`flush()`により即座にディスクに書き出される）。

**通知内容の概要**：エポック番号と各メトリクス値（loss、各種accuracy等）がCSV形式で記録される。ヘッダー行にはフィールド名が出力され、各行がエポックごとの結果に対応する。

**期待されるアクション**：受信者はCSVファイルを読み込み、トレーニングの推移を分析する。Excel、pandas、可視化ツールなどでメトリクスの推移グラフを作成し、モデルの性能を評価する。

## 通知種別

ファイル出力（CSV形式ファイル）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（エポック終了時のコールバック内でファイル書き込みを実行） |
| 優先度 | 低（記録目的であり、即時対応は不要） |
| リトライ | 無し（ファイル書き込み失敗時のリトライ機構はない） |

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

- コンストラクタで指定された`filename`パスにCSVファイルを出力
- `append=True`の場合、既存ファイルに追記（ヘッダーの有無を自動判定）
- `append=False`の場合、既存ファイルを上書き

## 通知テンプレート

### CSVファイル出力の場合

| 項目 | 内容 |
|-----|------|
| 出力先 | ユーザ指定のファイルパス（`filename`引数） |
| 区切り文字 | デフォルト `,`（`separator`引数で変更可能） |
| 形式 | CSV（ヘッダー行付き） |

### 本文テンプレート

```
epoch,loss,accuracy,val_loss,val_accuracy
0,0.5234,0.7812,0.4567,0.8125
1,0.3456,0.8594,0.3210,0.8750
...
```

### 添付ファイル

該当なし（本コールバック自体がCSVファイルを生成する）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| epoch | 現在のエポック番号 | `on_epoch_end`の引数 | Yes |
| keys | メトリクス名一覧 | `sorted(logs.keys())`（初回エポックで確定） | Yes |
| logs[key] | 各メトリクスの値 | `on_epoch_end`のlogs辞書 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| コールバック | `on_train_begin` | 常に発火 | CSVファイルをオープン（追記or上書き） |
| コールバック | `on_epoch_end` | 常に発火 | メトリクスをCSV行として書き出し、flush |
| コールバック | `on_train_end` | 常に発火 | CSVファイルをクローズ |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| なし | エポック終了時に常にCSVファイルへ書き出しが行われる |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[on_train_begin発火] --> B{append=True?}
    B -->|Yes| C[既存ファイル確認]
    C --> D{ファイル存在?}
    D -->|Yes| E[ヘッダー有無判定]
    D -->|No| F[append_header=True]
    E --> G[mode='a'でオープン]
    B -->|No| H[mode='w'でオープン]
    F --> G
    G --> I[ファイルオープン完了]
    H --> I
    I --> J[on_epoch_end発火]
    J --> K{writerが未作成?}
    K -->|Yes| L[DictWriter作成]
    L --> M{append_header?}
    M -->|Yes| N[ヘッダー行書き出し]
    M -->|No| O[ヘッダースキップ]
    N --> P[行データ書き出し]
    O --> P
    K -->|No| P
    P --> Q[flush実行]
    Q --> R{トレーニング継続?}
    R -->|Yes| J
    R -->|No| S[on_train_end発火]
    S --> T[ファイルクローズ]
```

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

### 参照テーブル一覧

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

### 更新テーブル一覧

該当なし（ファイルシステムへの書き出しのみ）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ファイルI/Oエラー | 指定パスに書き込み権限がない場合 | 例外がそのまま伝播する（明示的なエラーハンドリングなし） |
| stop_training時のNA値 | `model.stop_training=True`の場合 | 欠損メトリクスに'NA'を設定しCSVパーサーの失敗を防止（行2762-2764） |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| エポックあたり上限 | 1回（エポック終了時に1行書き出し） |
| 書き出し頻度 | エポック単位（バッチ単位の書き出しは行わない） |

### 配信時間帯

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

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

- ファイル出力先パスはユーザ指定であり、パストラバーサル等のバリデーションは行われない
- 出力内容はメトリクス値のみで個人情報を含まない

## 備考

- `gfile.GFile`を使用しているため、ローカルファイルシステムだけでなくGCS等のリモートファイルシステムにも対応可能
- 1Dイテラブル（`np.ndarray`等）は`"[v1, v2, ...]"`形式の文字列に変換される（行2751-2757）
- カスタムダイアレクトにより区切り文字を`separator`引数で変更可能（行2768-2769）
- 各エポック後に`flush()`を呼び出すことで、バッファリングによるデータ損失を防止（行2783）

---

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

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

### 推奨読解順序

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

CSVLoggerが扱うデータ構造（logs辞書、CSV形式）を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | callbacks.py | `tensorflow/python/keras/callbacks.py` | Callbackクラス（行591-670）のlogsパラメータの構造を理解する |

**読解のコツ**: `logs`は`dict`型であり、キーがメトリクス名、値がそのメトリクスの数値となる。`on_epoch_end`では1エポック分の集約メトリクスが渡される。

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

CSVLoggerのコンストラクタとファイル操作を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | callbacks.py | `tensorflow/python/keras/callbacks.py` | `CSVLogger.__init__`（行2728-2735）でファイル名、区切り文字、追記モードの設定を確認 |

**主要処理フロー**:
1. **行2728-2735**: コンストラクタ引数の設定（filename, separator, append）
2. **行2732-2734**: writer, keys, append_headerの初期化

#### Step 3: ファイルオープン処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | callbacks.py | `tensorflow/python/keras/callbacks.py` | `on_train_begin`（行2737-2745）でのファイルオープン処理 |

**主要処理フロー**:
- **行2738-2742**: append=Trueの場合、既存ファイルの有無とヘッダー存在を確認
- **行2745**: `gfile.GFile`でファイルをオープン

#### Step 4: CSV書き出し処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | callbacks.py | `tensorflow/python/keras/callbacks.py` | `on_epoch_end`（行2747-2783）のCSV行書き出しロジック |

**主要処理フロー**:
- **行2750-2757**: `handle_value`ヘルパー関数による値のフォーマット
- **行2759-2760**: 初回エポックでkeysを確定
- **行2762-2764**: stop_training時のNA値補完
- **行2766-2778**: DictWriter作成とヘッダー出力
- **行2780-2783**: 行書き出しとflush

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

```
model.fit() [Kerasトレーニングループ]
    │
    ├─ CallbackList.on_train_begin()
    │      └─ CSVLogger.on_train_begin() [行2737-2745]
    │             └─ gfile.GFile(filename, mode) [行2745]
    │
    ├─ [各エポックのループ]
    │      └─ CallbackList.on_epoch_end()
    │             └─ CSVLogger.on_epoch_end() [行2747-2783]
    │                    ├─ handle_value() [行2750-2757]
    │                    ├─ csv.DictWriter() [行2773-2776]
    │                    ├─ writer.writeheader() [行2778]
    │                    ├─ writer.writerow() [行2782]
    │                    └─ csv_file.flush() [行2783]
    │
    └─ CallbackList.on_train_end()
           └─ CSVLogger.on_train_end() [行2785-2787]
                  └─ csv_file.close() [行2786]
```

### データフロー図

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

logs (メトリクス辞書)  ───▶ on_epoch_end()              ───▶ CSVファイル（filename）
                           │
epoch (エポック番号)   ───▶ ├─ handle_value()               ├─ ヘッダー行
                           ├─ DictWriter作成                └─ データ行（エポックごと）
                           └─ writerow() + flush()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| callbacks.py | `tensorflow/python/keras/callbacks.py` | ソース | CSVLoggerクラス定義（行2708-2787） |
| callbacks.py | `tensorflow/python/keras/callbacks.py` | ソース | Callback基底クラス（行591-670） |
| gfile | `tensorflow/python/platform/gfile.py` | ソース | GFileによるファイルI/O抽象化レイヤー |
