# Kompatibilitas mundur

## Migrasi Normalisasi Kebijakan (PR #1452)

**Perubahan Besar**: Kebijakan LeRobot tidak lagi memiliki lapisan normalisasi bawaan yang tertanam dalam bobotnya. Normalisasi sekarang ditangani oleh komponen eksternal `PolicyProcessorPipeline`.

### Apa yang berubah?

|                            | Sebelum PR #1452                                  | Setelah PR #1452                                               |
| -------------------------- | ------------------------------------------------ | ------------------------------------------------------------ |
| **Lokasi Normalisasi** | Tersemat dalam bobot model (`normalize_inputs.*`) | Komponen `PolicyProcessorPipeline` eksternal                |
| **Model State Dict**       | Berisi statistik normalisasi                | **Hanya bobot bersih** - tanpa parameter normalisasi         |
| **Penggunaan**                  | `policy(batch)` menangani semuanya               | `preprocessor(batch)` → `policy(...)` → `postprocessor(...)` |

### Dampak pada model yang ada

- Model yang dilatih **sebelum** PR #1452 memiliki normalisasi yang tertanam di dalam bobotnya
- Model-model ini memerlukan migrasi agar dapat bekerja dengan sistem `PolicyProcessorPipeline` baru
- Migrasi mengekstrak statistik normalisasi dan membuat pipeline pemroses yang terpisah

### Migrasi model lama

Gunakan skrip migrasi untuk mengonversi model dengan normalisasi tertanam:

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

Skripnya:

1. **Extracts** statistik normalisasi dari bobot model
2. **Membuat** pipeline preprocessor dan postprocessor eksternal
3. **Menghapus** lapisan normalisasi dari bobot model
4. **Menyimpan** pipeline model + processor yang bersih
5. **Pushes** ke Hub dengan pembuatan PR otomatis

### Menggunakan model yang dimigrasi

```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)
```

## Redesain API Perangkat Keras

PR [#777](https://github.com/huggingface/lerobot/pull/777) meningkatkan kalibrasi LeRobot tetapi **tidak kompatibel mundur**. Berikut adalah ringkasan tentang apa yang berubah dan bagaimana Anda dapat terus bekerja dengan dataset yang dibuat sebelum pull request ini.

### Apa yang berubah?

|                                   | Sebelum PR #777                                    | Setelah PR #777                                                |
| --------------------------------- | ------------------------------------------------- | ------------------------------------------------------------ |
| **Range gabungan**                   | Derajat `-180...180°`                             | **Range ternormalisasi** Sendi: `–100...100` Gripper: `0...100` |
| **Posisi nol (SO100 / SO101)** | Lengan sepenuhnya diperpanjang secara horizontal                   | **Di tengah rentang untuk setiap sendi**                    |
| **Penanganan batas**             | Lindung perangkat lunak untuk mendeteksi pembalikan ±180 ° | Tidak diperlukan logika wrap-around karena nol berada di rentang tengah            |

---

### Dampak pada dataset yang ada

- Trajektori yang direkam yang dibuat **sebelum** PR #777 akan diputar ulang secara tidak benar jika dimuat secara langsung:
  - Sudut sendi mengalami pergeseran dan dinormalisasi secara tidak benar.
- Semua model yang dilatih ulang atau dilatih langsung pada data lama akan memerlukan konversi pada input dan output-nya.

### Menggunakan dataset yang dibuat dengan sistem kalibrasi sebelumnya

Kami menyediakan skrip contoh migrasi untuk memutar ulang episode yang direkam dengan kalibrasi sebelumnya di sini: `examples/backward_compatibility/replay.py`. Di bawah ini, kami akan memandu Anda melalui modifikasi yang dilakukan dalam skrip contoh agar dataset kalibrasi sebelumnya dapat berfungsi.

```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
```

Mari kita uraikan ini. Basis kode baru menggunakan akhiran `.pos` untuk observasi posisi dan kami telah menghapus prefiks `main_`:

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

Untuk `"shoulder_lift"` (id = 2), posisi 0 diubah sebesar -90 derajat dan arahnya dibalik dibandingkan dengan kalibrasi/kode lama.

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

Untuk `"elbow_flex"` (id = 3), posisi 0 diubah sebesar -90 derajat dibandingkan kalibrasi/kode lama.

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

Untuk menggunakan normalisasi derajat, kami kemudian mengatur opsi `--robot.use_degrees` menjadi `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
```

### Menggunakan kebijakan yang dilatih dengan sistem kalibrasi sebelumnya

Policies menghasilkan aksi dalam format yang sama dengan dataset (`torch.Tensors`). Oleh karena itu, transformasi yang sama harus diterapkan.

Untuk menemukan transformasi ini, kami merekomendasikan untuk pertama kali memutar ulang satu episode dari dataset yang digunakan untuk melatih kebijakan Anda menggunakan bagian di atas. Kemudian, tambahkan transformasi yang sama ini ke skrip inferensi Anda (ditampilkan di sini untuk skrip yang memanggil `predict_action`, seperti contoh `evaluate.py` di `examples/`):

```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)
```

Jika Anda memiliki pertanyaan atau mengalami masalah migrasi, silakan ajukan di [Discord](https://discord.gg/s3KuuzsPFb)

