# 機能設計書 111-クリッピング操作

## 概要

本ドキュメントは、TensorFlowにおけるテンソル値のクリッピング（値域制限）機能の設計を記述する。勾配クリッピングや重みの値域制限を行うための各種API群を対象とする。

### 本機能の処理概要

テンソルの値を指定した最小値・最大値の範囲に制限する操作を提供する。勾配爆発の防止やモデルの安定的な学習に不可欠な機能群である。

**業務上の目的・背景**：深層学習の学習過程では勾配爆発（gradient explosion）が発生しやすく、特にRNNやTransformerなどの深いネットワークにおいて顕著である。勾配クリッピングはこの問題に対する標準的な解決策であり、学習の安定性と収束性を確保する。また、重みやバイアスの値を一定範囲に制限することで、モデルのロバスト性を向上させる。

**機能の利用シーン**：オプティマイザに勾配を適用する前段階での勾配クリッピング、推論値の範囲制限（例：画像ピクセル値を0-255に制限）、正則化手法としての重みクリッピングなどで利用される。

**主要な処理内容**：
1. `clip_by_value` - テンソル要素を指定した最小値・最大値で個別にクリップ
2. `clip_by_norm` - テンソルのL2ノルムが指定値以下となるよう正規化
3. `clip_by_global_norm` - 複数テンソルのグローバルL2ノルムに基づくクリッピング
4. `global_norm` - 複数テンソルのグローバルL2ノルム計算
5. `clip_by_average_norm` - 平均L2ノルムによるクリッピング（非推奨）

**関連システム・外部連携**：TensorFlowの数学演算（math_ops）、配列操作（array_ops）、ニューラルネットワーク操作（gen_nn_ops）と内部連携する。各種オプティマイザから勾配クリッピングとして呼び出される。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本機能はバックエンドAPI機能であり、直接的な画面関連はない |

## 機能種別

計算処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| t | Tensor / IndexedSlices | Yes | クリッピング対象のテンソル | clip_by_normの場合はfloat型のみ |
| clip_value_min | Tensor（スカラーまたはブロードキャスト可能） | Yes（clip_by_value） | クリップ最小値 | clip_value_min <= clip_value_max |
| clip_value_max | Tensor（スカラーまたはブロードキャスト可能） | Yes（clip_by_value） | クリップ最大値 | clip_value_min <= clip_value_max |
| clip_norm | Tensor（0-Dスカラー） | Yes（clip_by_norm/clip_by_global_norm） | 最大ノルム値（> 0） | 負値の場合は0として扱われる |
| t_list | list/tuple of Tensor | Yes（clip_by_global_norm/global_norm） | テンソルのリスト | Sequence型であること |
| axes | Tensor（1-D int32） | No | L2ノルム計算に使用する次元 | None時は全次元 |
| use_norm | Tensor（0-Dスカラー float） | No | 事前計算済みグローバルノルム | clip_by_global_normでのみ使用 |

### 入力データソース

Python API呼び出し（tf.clip_by_value, tf.clip_by_norm, tf.clip_by_global_norm, tf.linalg.global_norm）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| clipped_tensor | Tensor / IndexedSlices | クリッピング後のテンソル（入力と同じ型・形状） |
| global_norm | Tensor（0-Dスカラー float） | グローバルノルム値（clip_by_global_normの場合のみ） |
| list_clipped | list of Tensor | クリッピング後のテンソルリスト（clip_by_global_normの場合） |

### 出力先

呼び出し元への戻り値として返却

## 処理フロー

### 処理シーケンス

```
1. clip_by_value
   └─ math_ops.minimum(values, clip_value_max) でまず上限をクリップ
   └─ math_ops.maximum(t_min, clip_value_min) で下限をクリップ
   └─ IndexedSlicesの場合はvaluesを更新してIndexedSlicesとして再構築

2. clip_by_norm
   └─ L2ノルムの二乗を計算: l2sum = reduce_sum(values * values, axes)
   └─ ゼロ除算防止のためのsafe値計算
   └─ L2ノルム計算: sqrt(l2sum_safe)
   └─ スケーリング: values * clip_norm / max(l2norm, clip_norm)

3. clip_by_global_norm
   └─ use_normが未指定の場合はglobal_norm()を呼び出し
   └─ スケール計算: clip_norm * min(1/use_norm, 1/clip_norm)
   └─ inf/NaN対応のスケール調整
   └─ 各テンソルにスケールを乗算

4. global_norm
   └─ 各テンソルのL2損失を計算: gen_nn_ops.l2_loss(v)
   └─ 全テンソルのL2損失を合算
   └─ sqrt(2 * half_squared_norm) でグローバルノルムを算出
```

### フローチャート

```mermaid
flowchart TD
    A[入力テンソル] --> B{クリップ方式}
    B -->|clip_by_value| C[minimum/maximumで値域制限]
    B -->|clip_by_norm| D[L2ノルム計算]
    B -->|clip_by_global_norm| E[グローバルL2ノルム計算]
    D --> F{L2norm > clip_norm?}
    F -->|Yes| G[t * clip_norm / l2norm]
    F -->|No| H[値を変更せず返却]
    E --> I[スケール計算]
    I --> J[各テンソルにスケール適用]
    C --> K[出力テンソル]
    G --> K
    H --> K
    J --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-111-01 | 値域制限順序 | clip_by_valueではmin→maxの順で適用 | clip_by_value呼び出し時 |
| BR-111-02 | ブロードキャスト制限 | 入力テンソルの次元を拡張するブロードキャストは禁止 | clip_by_value呼び出し時 |
| BR-111-03 | 型一致 | 整数型テンソルにfloat型のクリップ値は使用不可 | clip_by_value呼び出し時 |
| BR-111-04 | 負値clip_norm | clip_normが負の場合は0として扱う | clip_by_norm呼び出し時 |
| BR-111-05 | 無限大ノルム | global_normが無限大の場合、結果はNaN | clip_by_global_norm呼び出し時 |
| BR-111-06 | Noneスキップ | t_list内のNone要素は無視 | global_norm/clip_by_global_norm呼び出し時 |

### 計算ロジック

- **clip_by_value**: `max(clip_value_min, min(t, clip_value_max))`
- **clip_by_norm**: `t * clip_norm / max(l2norm(t), clip_norm)`
- **global_norm**: `sqrt(sum([l2norm(t)**2 for t in t_list]))`
- **clip_by_global_norm**: `t_list[i] * clip_norm / max(global_norm, clip_norm)`

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

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

該当なし（データベースへのアクセスは行わない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| InvalidArgumentError | ブロードキャストエラー | clip値のブロードキャストで入力テンソルより大きくなる場合 | clip値の形状を確認 |
| TypeError | 型不一致 | int32テンソルにfloat32のclip値を指定 | tf.castで型を統一 |
| ValueError | 不正なclip_norm | clip_normが0-Dスカラーでない場合 | スカラー値を指定 |
| TypeError | 不正なt_list | t_listがSequence型でない場合 | リストまたはタプルを渡す |

### リトライ仕様

該当なし（同期的な演算処理のためリトライ不要）

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

該当なし（ステートレスな計算操作）

## パフォーマンス要件

各クリッピング操作はテンソルサイズに対しO(n)の計算量。clip_by_global_normは全テンソルのノルム計算が必要なため、clip_by_normより遅い。

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

特になし。数値演算のみで外部通信やデータ保存は行わない。

## 備考

- `clip_by_average_norm`はTensorFlow 2.0で非推奨。代替として`clip_by_norm(t, clip_norm * tf.cast(tf.size(t), tf.float32), name)`を使用。
- Pascanu et al., 2012の勾配クリッピング手法に基づくclip_by_global_normが推奨される。

---

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

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

### 推奨読解順序

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

IndexedSlicesの理解が重要。クリッピング操作はTensorだけでなくIndexedSlices（スパース勾配表現）にも対応している。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | indexed_slices.py | `tensorflow/python/framework/indexed_slices.py` | IndexedSlicesの構造（values, indices, dense_shape）を理解する |

**読解のコツ**: IndexedSlicesはスパーステンソルの一種で、`values`（非ゼロ値）、`indices`（非ゼロ値のインデックス）、`dense_shape`（元のテンソル形状）の3つの属性を持つ。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | clip_ops.py | `tensorflow/python/ops/clip_ops.py` | 全クリッピング関数の定義場所 |

**主要処理フロー**:
1. **34-122行目**: `clip_by_value` - `@tf_export("clip_by_value")`デコレータでAPIとして公開。minimum→maximum の順で値をクリップし、IndexedSlicesの場合はvaluesのみ処理して再構築する
2. **128-149行目**: `_clip_by_value_grad` - ClipByValueの勾配関数。クリップ範囲内外でマスクを作成し、勾配を振り分ける
3. **152-242行目**: `clip_by_norm` - L2ノルムベースのクリッピング。ゼロ除算防止のためのTwo-tap trick（230行目）に注目
4. **245-295行目**: `global_norm` - `gen_nn_ops.l2_loss`を使用して効率的にL2ノルムの二乗を計算
5. **298-392行目**: `clip_by_global_norm` - グローバルノルムベースのクリッピング。inf/NaN対応のため`scale_for_finite + (use_norm - use_norm)`という手法を使用（365行目）

#### Step 3: 依存する数学演算を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | math_ops.py | `tensorflow/python/ops/math_ops.py` | minimum, maximum, reduce_sum, sqrt等の基本演算 |
| 3-2 | gen_nn_ops.py | 自動生成 | l2_loss関数（テンソルのL2ノルム二乗の半分を計算） |

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

```
tf.clip_by_value()
    ├─ ops.convert_to_tensor()
    ├─ math_ops.minimum(values, clip_value_max)
    ├─ math_ops.maximum(t_min, clip_value_min)
    └─ IndexedSlices再構築（必要時）

tf.clip_by_norm()
    ├─ ops.convert_to_tensor()
    ├─ math_ops.reduce_sum(values * values)
    ├─ math_ops.sqrt()
    └─ values * clip_norm / max(l2norm, clip_norm)

tf.clip_by_global_norm()
    ├─ global_norm()
    │       ├─ gen_nn_ops.l2_loss(v)  [各テンソル]
    │       ├─ math_ops.reduce_sum()
    │       └─ math_ops.sqrt()
    ├─ scale計算
    └─ 各テンソル × scale
```

### データフロー図

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

Tensor/IndexedSlices ──▶ clip_by_value ──────────────▶ Clipped Tensor
clip_value_min/max   ──▶   minimum → maximum

Tensor/IndexedSlices ──▶ clip_by_norm ───────────────▶ Normalized Tensor
clip_norm            ──▶   L2norm計算 → スケーリング

List[Tensor]         ──▶ clip_by_global_norm ─────── ▶ List[Clipped Tensor]
clip_norm            ──▶   global_norm → scale → 適用     + global_norm値
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| clip_ops.py | `tensorflow/python/ops/clip_ops.py` | ソース | クリッピング操作の全関数定義 |
| math_ops.py | `tensorflow/python/ops/math_ops.py` | ソース | 基本数学演算（minimum, maximum, reduce_sum, sqrt等） |
| array_ops.py | `tensorflow/python/ops/array_ops.py` | ソース | テンソル操作（shape, where, identity, ones_like等） |
| gen_nn_ops.py | `tensorflow/python/ops/gen_nn_ops.py` | 自動生成 | l2_loss関数の定義 |
| indexed_slices.py | `tensorflow/python/framework/indexed_slices.py` | ソース | IndexedSlicesデータ構造の定義 |
| constant_op.py | `tensorflow/python/framework/constant_op.py` | ソース | 定数テンソル生成 |
| dtypes.py | `tensorflow/python/framework/dtypes.py` | ソース | データ型定義 |
