# 後方互換性

## Policy Normalization Migration (PR #1452)

**破壊的変更**: LeRobot のポリシーには、重みに正規化レイヤーが組み込まれなくなりました。正規化は、外部の `PolicyProcessorPipeline` コンポーネントによって処理されるようになりました。

### 何が変更されましたか？

|                            | PR #1452 以前                                  | PR #1452以降                                               |
| -------------------------- | ------------------------------------------------ | ------------------------------------------------------------ |
| **正規化の位置** | モデルの重みに埋め込まれた(`normalize_inputs.*`) | 外部`PolicyProcessorPipeline`コンポーネント                |
| **モデルステートディクト**       | 正規化統計情報を含む                | **重みのみのクリーンな形式** - 正規化パラメータなし         |
| **使用方法**                  | `policy(batch)` がすべてを処理します               | `preprocessor(batch)` → `policy(...)` → `postprocessor(...)` |

### 既存のモデルへの影響

- PR #1452 **以前**に学習されたモデルは、重みに正規化が組み込まれています
- これらのモデルは、新しい`PolicyProcessorPipeline`システムで動作させるために移行が必要です
- 移行処理では、正規化統計情報を抽出し、個別のプロセッサパイプラインを作成します。

### 旧モデルの移行

移行スクリプトを使用して、埋め込み正規化を持つモデルを変換します:

```shell
python src/lerobot/processor/migrate_policy_normalization.py \
    --pretrained-path lerobot/act_aloha_sim_transfer_cube_human \
    --push-to-hub \
    --branch migrated
```

スクリプト:

1. **Extracts** はモデルの重みから正規化統計量を抽出します
2. **作成**外部のプリプロセッサおよびポストプロセッサのパイプライン
3. モデルの重みから**正規化**レイヤーを削除します
4. **Saves** クリーンなモデルとプロセッサのパイプライン
5. Hubへの**Pushes**と自動PR作成

### 移行済みモデルの使用

```python
# New usage pattern (after migration)
from lerobot.policies import make_policy, make_pre_post_processors

# Load model and processors separately
policy = make_policy(config, ds_meta=dataset.meta)
preprocessor, postprocessor = make_pre_post_processors(
    policy_cfg=config,
    dataset_stats=dataset.meta.stats
)

# Process data through pipeline
processed_batch = preprocessor(raw_batch)
action = policy.select_action(processed_batch)
final_action = postprocessor(action)
```

## ハードウェアAPIの再設計

PR [#777](https://github.com/huggingface/lerobot/pull/777) は LeRobot のキャリブレーションを改善していますが、**後方互換性はありません**。以下に、変更点と、このプルリクエスト以前に作成されたデータセットで引き続き作業する方法を概説します。

### 何が変更されましたか？

|                                   | PR #777 以前                                    | PR #777 以降                                                |
| --------------------------------- | ------------------------------------------------- | ------------------------------------------------------------ |
| **共通範囲**                   | 度数 `-180...180°`                             | **正規化された範囲** 関節: `–100...100` グリッパー: `0...100` |
| **ゼロポジション（SO100 / SO101）** | 腕を完全に水平に伸ばした状態                   | **各関節の範囲の中央**                    |
| **境界の処理**             | ±180°のラップアラウンドを検出するためのソフトウェアの安全対策 | 中間範囲のゼロにより、ラップアラウンドロジックは不要です            |

---

### 既存のデータセットへの影響

- PR #777 **以前**に作成された記録済み軌道は、直接読み込むと正しく再生されません:
  - 関節角度がオフセットされており、正しく正規化されていません。
- 旧データで直接ファインチューニングまたは学習されたモデルは、入力と出力の変換が必要です。

### 以前のキャリブレーションシステムで作成されたデータセットを使用する

以前のキャリブレーションで記録されたエピソードを再生するための移行例スクリプトを、こちらに提供しています: `examples/backward_compatibility/replay.py`。以下では、以前のキャリブレーションデータセットを動作させるために、例スクリプトで行われている変更点について説明します。

```diff
+   key = f"{name.removeprefix('main_')}.pos"
    action[key] = action_array[i].item()
+   action["shoulder_lift.pos"] = -(action["shoulder_lift.pos"] - 90)
+   action["elbow_flex.pos"] -= 90
```

分解していきましょう。新しいコードベースでは、位置の観測値に`.pos`サフィックスを使用し、`main_`プレフィックスを削除しました:

```python
key = f"{name.removeprefix('main_')}.pos"
```

`"shoulder_lift"`（id = 2）の場合、旧キャリブレーション/コードと比較して、0 の位置が -90 度変更され、方向が反転します。

```python
action["shoulder_lift.pos"] = -(action["shoulder_lift.pos"] - 90)
```

`"elbow_flex"`（id = 3）については、0 の位置が、従来のキャリブレーション/コードと比較して -90 度に変更されています。

```python
action["elbow_flex.pos"] -= 90
```

degrees正規化を使用するには、`--robot.use_degrees`オプションを`true`に設定します。

```diff
python examples/backward_compatibility/replay.py \
    --robot.type=so101_follower \
    --robot.port=/dev/tty.usbmodem5A460814411 \
    --robot.id=blue \
+   --robot.use_degrees=true \
    --dataset.repo_id=my_dataset_id \
    --dataset.episode=0
```

### 以前のキャリブレーションシステムで学習されたポリシーを使用する

Policiesは、データセットと同じ形式(`torch.Tensors`)でアクションを出力します。したがって、同じ変換を適用する必要があります。

これらの変換を見つけるには、まず上記のセクションに従って、ポリシーが学習されたデータセットのエピソードを再生することをお勧めします。その後、推論スクリプトに同じ変換を追加します（ここでは、`examples/` の `evaluate.py` の例のように、`predict_action` を呼び出すスクリプトを示しています）：

```diff
action_values = predict_action(
    observation_frame,
    policy,
    get_safe_torch_device(policy.config.device),
    preprocessor,
    postprocessor,
    policy.config.use_amp,
    task=single_task,
    robot_type=robot.robot_type,
    )
    action = {key: action_values[i].item() for i, key in enumerate(robot.action_features)}

+   action["shoulder_lift.pos"] = -(action["shoulder_lift.pos"] - 90)
+   action["elbow_flex.pos"] -= 90
    robot.send_action(action)
```

ご質問や移行に関する問題が発生した場合は、[Discord](https://discord.gg/s3KuuzsPFb)でお気軽にご質問ください。

