# 機能設計書 31-Adadeltaオプティマイザ

## 概要

本ドキュメントは、TensorFlow/Kerasにおける Adadelta（Adaptive Delta）オプティマイザの機能設計を記載する。Adadeltaは勾配の移動窓に基づく適応的学習率調整アルゴリズムを実装しており、`tf.keras.optimizers.Adadelta` として提供される。

### 本機能の処理概要

**業務上の目的・背景**：Adagradオプティマイザが持つ「学習率の単調減少」および「手動での初期学習率設定の必要性」という2つの問題を解決するために、Adadeltaアルゴリズムが開発された。過去の勾配すべてを蓄積する代わりに、勾配更新の移動窓に基づいて学習率を適応させることで、長期訓練でも学習が継続する。

**機能の利用シーン**：ニューラルネットワークの訓練において、パラメータごとに適応的な学習率を適用したい場合に利用される。特に初期学習率の選択に敏感でないオプティマイザが必要なケースや、Adagradの学習率減衰問題を回避したい場合に適している。

**主要な処理内容**：
1. 各パラメータに対して勾配蓄積スロット（accum_grad）と変数更新蓄積スロット（accum_var）を作成する
2. 密な勾配に対して `ResourceApplyAdadelta` カーネルを呼び出し、変数を更新する
3. スパースな勾配に対して `ResourceSparseApplyAdadelta` カーネルを呼び出し、インデックス指定の部分更新を行う
4. 減衰率（rho）による移動平均を用いて勾配の二乗和とパラメータ更新量の二乗和を追跡する

**関連システム・外部連携**：OptimizerV2基底クラスを継承し、C++で実装された `gen_training_ops` カーネルに更新処理を委譲する。TensorFlowの分散学習フレームワークと連携して分散環境でのパラメータ更新もサポートする。

**権限による制御**：特になし。全てのユーザが利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 画面機能マッピングに関連画面なし |

## 機能種別

計算処理（最適化アルゴリズム）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| learning_rate | float / LearningRateSchedule | No | 初期学習率。デフォルト0.001 | 正の数値 |
| rho | float | No | 減衰率。デフォルト0.95 | 0.0から1.0の範囲 |
| epsilon | float | No | 数値安定性のための微小値。デフォルト1e-7 | 正の数値 |
| name | str | No | オプティマイザ名。デフォルト"Adadelta" | - |
| clipnorm | float | No | 勾配ノルムのクリッピング値 | 正の数値 |
| clipvalue | float | No | 勾配値のクリッピング値 | 正の数値 |

### 入力データソース

- モデルの勾配テンソル（`GradientTape.gradient()` や `optimizer.minimize()` 経由で取得）
- モデルの訓練可能な変数（`model.trainable_variables`）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 更新済み変数 | ResourceVariable | Adadeltaアルゴリズムに従い更新されたモデルパラメータ |
| accum_grad | Tensor | 勾配の二乗の移動平均（各変数ごと） |
| accum_var | Tensor | パラメータ更新量の二乗の移動平均（各変数ごと） |

### 出力先

モデルの訓練可能な変数へインプレース更新。

## 処理フロー

### 処理シーケンス

```
1. __init__: ハイパーパラメータ（learning_rate, rho, epsilon）の設定
   └─ _set_hyperでOptimizerV2の内部状態にハイパーパラメータを登録
2. _create_slots: 各変数に対してスロット変数を作成
   └─ accum_grad（勾配蓄積）とaccum_var（更新量蓄積）を変数ごとに作成
3. _prepare_local: デバイス・データ型ごとの係数を事前計算
   └─ epsilon, rhoをテンソルに変換してapply_stateに格納
4. _resource_apply_dense: 密な勾配の適用
   └─ gen_training_ops.ResourceApplyAdadeltaカーネルを呼び出し
5. _resource_apply_sparse: スパース勾配の適用
   └─ gen_training_ops.ResourceSparseApplyAdadeltaカーネルを呼び出し
```

### フローチャート

```mermaid
flowchart TD
    A[optimizer.minimize / apply_gradients呼び出し] --> B[_create_slots: スロット変数作成]
    B --> C[_prepare_local: 係数の事前計算]
    C --> D{勾配の種別}
    D -->|Dense| E[_resource_apply_dense]
    D -->|Sparse| F[_resource_apply_sparse]
    E --> G[ResourceApplyAdadelta C++ Kernel]
    F --> H[ResourceSparseApplyAdadelta C++ Kernel]
    G --> I[変数更新完了]
    H --> I
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-31-1 | Adadelta更新則 | accum_grad = rho * accum_grad + (1-rho) * grad^2; update = sqrt(accum_var + eps) / sqrt(accum_grad + eps) * grad; accum_var = rho * accum_var + (1-rho) * update^2; var -= lr * update | 全てのパラメータ更新時 |
| BR-31-2 | スロット初期化 | accum_gradとaccum_varは0で初期化 | 最初のトレーニングステップ前 |
| BR-31-3 | Keras V1互換 | set_weightsでイテレーション重みが欠損している場合、先頭に0を追加 | Keras V1からの移行時 |

### 計算ロジック

Adadeltaの更新式（Zeiler, 2012）:
```
E[g^2]_t = rho * E[g^2]_{t-1} + (1 - rho) * g_t^2
RMS[g]_t = sqrt(E[g^2]_t + epsilon)
delta_x_t = - (RMS[delta_x]_{t-1} / RMS[g]_t) * g_t
E[delta_x^2]_t = rho * E[delta_x^2]_{t-1} + (1 - rho) * delta_x_t^2
x_t = x_{t-1} + lr * delta_x_t
```

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし（インメモリ変数操作のみ） |

### テーブル別操作詳細

データベース操作は発生しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ValueError | パラメータエラー | set_weightsで重みリストの長さが不一致 | Keras V1互換モードでイテレーション値を先頭に追加 |
| TypeError | 型エラー | learning_rateに不正な型が指定された | float値またはLearningRateScheduleインスタンスを指定 |

### リトライ仕様

リトライは不要。

## トランザクション仕様

TensorFlowの `use_locking` フラグにより、変数更新時の排他制御が可能。デフォルトはFalse。

## パフォーマンス要件

- 密な勾配適用はC++カーネルに委譲されるため、Pythonオーバーヘッドは最小
- `_HAS_AGGREGATE_GRAD = True` により、勾配の集約が事前に行われ効率的な分散学習をサポート

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

特になし。モデルパラメータの更新処理であり、外部入力の検証は不要。

## 備考

- 参照論文: Zeiler, 2012 (http://arxiv.org/abs/1212.5701)
- 原論文では初期学習率は1.0が推奨されるが、Keras実装ではデフォルト0.001

---

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

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

### 推奨読解順序

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

OptimizerV2基底クラスのスロット変数管理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | optimizer_v2.py | `tensorflow/python/keras/optimizer_v2/optimizer_v2.py` | OptimizerV2基底クラスのadd_slot, get_slot, _set_hyperメソッド |

**読解のコツ**: OptimizerV2は `_set_hyper` でハイパーパラメータを辞書に保存し、`_get_hyper` で取得する。スロット変数は各訓練可能変数に付随する追加変数（モーメンタムなど）。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | adadelta.py | `tensorflow/python/keras/optimizer_v2/adadelta.py` | Adadeltaクラスの全体構造 |

**主要処理フロー**:
1. **67-77行目**: `__init__`でlearning_rate, rho, epsilonを設定
2. **79-84行目**: `_create_slots`でaccum_gradとaccum_varスロットを作成
3. **86-95行目**: `_prepare_local`でepsilonとrhoをテンソルに変換
4. **106-121行目**: `_resource_apply_dense`でResourceApplyAdadeltaカーネルを呼び出し
5. **123-139行目**: `_resource_apply_sparse`でResourceSparseApplyAdadeltaカーネルを呼び出し

#### Step 3: C++カーネル登録を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | training_ops.cc | `tensorflow/core/ops/training_ops.cc` | ApplyAdadelta系Op定義 |

**主要処理フロー**:
- **172-246行目**: ApplyAdadeltaShapeFn関数とREGISTER_OPマクロによるOp定義。var, accum, accum_update, lr, rho, epsilon, gradの入力を受け取る

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

```
tf.keras.optimizers.Adadelta (adadelta.py)
    |
    +-- OptimizerV2.minimize() (optimizer_v2.py)
    |       |
    |       +-- GradientTape.gradient()
    |       +-- OptimizerV2.apply_gradients()
    |               |
    |               +-- Adadelta._create_slots()
    |               +-- Adadelta._prepare_local()
    |               +-- Adadelta._resource_apply_dense()
    |               |       +-- gen_training_ops.ResourceApplyAdadelta (C++ Kernel)
    |               +-- Adadelta._resource_apply_sparse()
    |                       +-- gen_training_ops.ResourceSparseApplyAdadelta (C++ Kernel)
    |
    +-- Adadelta.get_config() -> dict
```

### データフロー図

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

勾配テンソル -------> Adadelta._resource_apply_dense -------> 更新済み変数
                          |                                    更新済みaccum_grad
                          v                                    更新済みaccum_var
                     ResourceApplyAdadelta (C++)
                          |
変数(var) ------------->  |
accum_grad ------------>  |
accum_var ------------->  |
lr, rho, epsilon ------>  |
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| adadelta.py | `tensorflow/python/keras/optimizer_v2/adadelta.py` | ソース | Adadeltaオプティマイザの主実装 |
| optimizer_v2.py | `tensorflow/python/keras/optimizer_v2/optimizer_v2.py` | ソース | OptimizerV2基底クラス |
| training_ops.cc | `tensorflow/core/ops/training_ops.cc` | ソース | C++ Op定義（ApplyAdadelta） |
| backend_config.py | `tensorflow/python/keras/backend_config.py` | ソース | epsilon関数のデフォルト値提供 |
| learning_rate_schedule.py | `tensorflow/python/keras/optimizer_v2/learning_rate_schedule.py` | ソース | 学習率スケジュール（learning_rateに渡す場合） |
