# 機能設計書 43-制約（Constraints）

## 概要

本ドキュメントは、TensorFlow/Kerasにおける制約（Constraints）機能の設計を記述する。重みに対するMaxNorm・NonNeg・UnitNorm・MinMaxNorm・RadialConstraintなどの制約を提供し、学習時に重みの値域を制限する。

### 本機能の処理概要

本機能は、ニューラルネットワークの各層の重みパラメータに対して、学習の各ステップ後に所定の制約を適用することで、重みが特定の条件を満たすように強制する。正則化とは異なり、損失関数にペナルティを加えるのではなく、重みの値そのものを投影（projection）する。

**業務上の目的・背景**：ニューラルネットワークの安定した学習を保証するために、重みの値域を制限する必要がある場合がある。例えば、MaxNorm制約はGAN（敵対的生成ネットワーク）の判別器でリプシッツ連続性を確保するために使用され、NonNeg制約は非負行列分解や物理的に意味のある制約を表現するために利用される。

**機能の利用シーン**：（1）Dense層やConv層の`kernel_constraint`引数で重みノルムを制限する場面、（2）`bias_constraint`でバイアスの非負制約を適用する場面、（3）Conv2D層でRadialConstraintによるカーネルの放射対称性を強制する場面。

**主要な処理内容**：
1. Constraintベースクラスによる制約インターフェース定義
2. MaxNorm: 重みノルムを最大値以下に射影
3. NonNeg: 負の重みをゼロにクリップ
4. UnitNorm: 重みノルムを1に正規化
5. MinMaxNorm: 重みノルムを指定範囲に射影
6. RadialConstraint: Conv2Dカーネルの放射対称性を強制

**関連システム・外部連携**：Kerasの各層（Dense、Conv2D等）のkernel_constraint/bias_constraint引数。

**権限による制御**：特になし。

## 関連画面

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

## 機能種別

計算処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| w | Tensor | Yes | 制約対象の重みテンソル | __call__時の入力 |
| max_value | float | No | MaxNormの最大ノルム値 | デフォルト2 |
| min_value | float | No | MinMaxNormの最小ノルム値 | デフォルト0.0 |
| rate | float | No | MinMaxNormの適用率 | デフォルト1.0（完全適用） |
| axis | int | No | ノルム計算の軸 | デフォルト0 |

### 入力データソース

Kerasレイヤーの重みテンソル。optimizer.apply_gradients()の後にConstraint.__call__()が呼ばれる。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| constrained_weight | Tensor | 制約適用後の重みテンソル（入力と同形状） |

### 出力先

レイヤーの重み変数に直接代入される。

## 処理フロー

### 処理シーケンス

```
1. 制約インスタンス生成（__init__）
   └─ パラメータ設定（max_value, axis等）
2. 勾配更新後に__call__(w)が呼ばれる
   └─ ノルム計算: sqrt(reduce_sum(square(w), axis=axis))
   └─ 射影: w * (desired / (epsilon + norms))
3. 射影された重みが変数に代入
```

### フローチャート

```mermaid
flowchart TD
    A[勾配更新完了] --> B[Constraint.__call__ w]
    B --> C{制約タイプ}
    C -->|MaxNorm| D[ノルム計算 → clip → 射影]
    C -->|NonNeg| E[負値をゼロにマスク]
    C -->|UnitNorm| F[ノルムで除算して正規化]
    C -->|MinMaxNorm| G[ノルムをmin-max範囲に射影]
    C -->|RadialConstraint| H[カーネルの放射対称化]
    D --> I[制約済み重みを返却]
    E --> I
    F --> I
    G --> I
    H --> I
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-43-01 | MaxNorm射影 | `w * clip(norms, 0, max_value) / (epsilon + norms)` | MaxNorm使用時 |
| BR-43-02 | NonNeg射影 | `w * cast(w >= 0, floatx)` | NonNeg使用時 |
| BR-43-03 | UnitNorm射影 | `w / (epsilon + sqrt(reduce_sum(square(w), axis)))` | UnitNorm使用時 |
| BR-43-04 | MinMaxNorm射影 | `w * (rate * clip(norms) + (1-rate) * norms) / (epsilon + norms)` | MinMaxNorm使用時 |
| BR-43-05 | RadialConstraint | Conv2Dカーネルの同一半径位置の重みを統一 | RadialConstraint使用時 |

### 計算ロジック

- **MaxNorm**: `norms = sqrt(sum(w^2, axis))`, `w_new = w * clip(norms, 0, max_value) / (epsilon + norms)`
- **UnitNorm**: `w_new = w / (epsilon + sqrt(sum(w^2, axis)))`
- **MinMaxNorm**: `desired = rate * clip(norms, min, max) + (1-rate) * norms`, `w_new = w * desired / (epsilon + norms)`

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし |

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ValueError | 入力エラー | RadialConstraintで重みテンソルがランク4でない | Conv2Dの4次元カーネルのみ使用可能 |

### リトライ仕様

リトライ不要。

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

トランザクション管理なし。

## パフォーマンス要件

- 制約計算はノルム計算と簡単な代数演算のみで、計算コストは低い
- RadialConstraintはmap_fnを使用するため、大きなカーネルサイズでは若干のオーバーヘッドがある

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

特になし。

## 備考

- 制約はステートレスな関数オブジェクトとして実装されている
- get_config()とfrom_config()によるシリアライズ/デシリアライズをサポート
- RadialConstraintはConv2D専用であり、他の次元のConv層では使用できない

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | constraints.py | `tensorflow/python/keras/constraints.py` | Constraintベースクラスの__call__インターフェース |

**読解のコツ**: Constraintはステートレスな関数オブジェクト。__call__(w)で重みテンソルを受取り、制約適用後の重みテンソルを返す。Regularizerと異なり、スカラーではなく重みと同形状のテンソルを返す点に注意。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | constraints.py | `tensorflow/python/keras/constraints.py` | Constraintベースクラス |

**主要処理フロー**:
1. **30-78行目**: Constraintベースクラス。__call__(w)のデフォルトは入力をそのまま返す
2. **69-78行目**: get_config()で空の辞書を返す

#### Step 3: 具体的な制約クラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | constraints.py | `tensorflow/python/keras/constraints.py` | MaxNorm, NonNeg, UnitNorm, MinMaxNorm, RadialConstraint |

**主要処理フロー**:
- **81-118行目**: MaxNorm - ノルム計算 → clip → 射影
- **110-114行目**: MaxNorm.__call__ - `w * (desired / (epsilon + norms))`
- **121-128行目**: NonNeg - `w * cast(w >= 0, floatx)`
- **131-162行目**: UnitNorm - ノルムで除算して正規化
- **165-218行目**: MinMaxNorm - rate付きのmin-max射影
- **221-299行目**: RadialConstraint - Conv2Dカーネルの放射対称性強制

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

```
optimizer.apply_gradients()
    │
    └─ Layer._handle_weight_regularization()
           │
           └─ Constraint.__call__(w)
                  │
                  ├─ MaxNorm.__call__()
                  │      ├─ sqrt(reduce_sum(square(w)))
                  │      ├─ clip(norms, 0, max_value)
                  │      └─ w * desired / (epsilon + norms)
                  │
                  ├─ NonNeg.__call__()
                  │      └─ w * cast(w >= 0, floatx)
                  │
                  ├─ UnitNorm.__call__()
                  │      └─ w / (epsilon + sqrt(reduce_sum(square(w))))
                  │
                  └─ MinMaxNorm.__call__()
                         ├─ rate * clip(norms, min, max) + (1-rate) * norms
                         └─ w * desired / (epsilon + norms)
```

### データフロー図

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

重みテンソル w ──▶ Constraint.__call__(w) ──▶ 制約済み重み w'
                       │
                       ├─ ノルム計算
                       ├─ 射影/クリップ/正規化
                       └─ 制約済みテンソル生成
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| constraints.py | `tensorflow/python/keras/constraints.py` | ソース | 制約クラス群の全実装 |
| base_layer.py | `tensorflow/python/keras/engine/base_layer.py` | ソース | レイヤーへの制約登録・適用処理 |
| generic_utils.py | `tensorflow/python/keras/utils/generic_utils.py` | ソース | serialize/deserializeユーティリティ |
| math_ops.py | `tensorflow/python/ops/math_ops.py` | ソース | reduce_sum, square, abs等の数学演算 |
| backend.py | `tensorflow/python/keras/backend.py` | ソース | sqrt, clip, epsilon, floatx等のバックエンド関数 |
