# Tương thích ngược

## Chuyển đổi Chuẩn hóa Chính sách (PR #1452)

**Thay đổi lớn**: Các chính sách LeRobot không còn có các lớp chuẩn hóa tích hợp sẵn trong trọng số của chúng. Việc chuẩn hóa hiện được xử lý bởi các thành phần `PolicyProcessorPipeline` bên ngoài.

### Có gì thay đổi?

|                            | Trước PR #1452                                  | Sau PR #1452                                               |
| -------------------------- | ------------------------------------------------ | ------------------------------------------------------------ |
| **Vị trí chuẩn hóa** | Được nhúng trong trọng số mô hình (`normalize_inputs.*`) | Các thành phần `PolicyProcessorPipeline` bên ngoài                |
| **Model State Dict**       | Chứa các thống kê chuẩn hóa                | **Chỉ trọng số sạch** - không có tham số chuẩn hóa         |
| **Cách sử dụng**                  | `policy(batch)` xử lý mọi thứ               | `preprocessor(batch)` → `policy(...)` → `postprocessor(...)` |

### Tác động đến các mô hình hiện có

- Các mô hình được huấn luyện **trước** PR #1452 có chuẩn hóa được nhúng trong trọng số của chúng
- Các mô hình này cần được di chuyển để hoạt động với hệ thống `PolicyProcessorPipeline` mới
- Quá trình di trú trích xuất các thống kê chuẩn hóa và tạo ra các đường ống xử lý riêng biệt

### Chuyển đổi các mô hình cũ

Sử dụng script di chuyển để chuyển đổi các mô hình có chuẩn hóa nhúng:

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

Tệp kịch bản:

1. **Extracts** thống kê chuẩn hóa từ trọng số mô hình
2. **Tạo** các pipeline tiền xử lý và hậu xử lý bên ngoài
3. **Loại bỏ** các lớp chuẩn hóa khỏi trọng số mô hình
4. **Lưu** các pipeline mô hình + bộ xử lý sạch
5. **Pushes** lên Hub với tạo PR tự động

### Sử dụng các mô hình đã di chuyển

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

## Thiết kế lại API phần cứng

PR [#777](https://github.com/huggingface/lerobot/pull/777) cải thiện việc hiệu chuẩn LeRobot nhưng **không tương thích ngược**. Dưới đây là tổng quan về những thay đổi và cách bạn có thể tiếp tục làm việc với các bộ dữ liệu được tạo trước pull request này.

### Có gì thay đổi?

|                                   | Trước PR #777                                    | Sau PR #777                                                |
| --------------------------------- | ------------------------------------------------- | ------------------------------------------------------------ |
| **Phạm vi chung**                   | Độ `-180...180°`                             | **Phạm vi đã chuẩn hóa** Khớp: `–100...100` Kẹp: `0...100` |
| **Vị trí zero (SO100 / SO101)** | Cánh tay duỗi thẳng hoàn toàn theo phương ngang                   | **Ở giữa khoảng cho mỗi khớp**                    |
| **Xử lý biên**             | Các biện pháp bảo vệ phần mềm để phát hiện các lần quay vòng ±180 ° | Không cần logic bao quanh do giá trị zero ở giữa            |

---

### Tác động đến các bộ dữ liệu hiện có

- Các quỹ đạo được ghi lại **trước** PR #777 sẽ phát lại không chính xác nếu được tải trực tiếp:
  - Góc khớp bị lệch và được chuẩn hóa không chính xác.
- Bất kỳ mô hình nào được tinh chỉnh hoặc huấn luyện trực tiếp trên dữ liệu cũ sẽ cần chuyển đổi đầu vào và đầu ra của chúng.

### Sử dụng các bộ dữ liệu được tạo bằng hệ thống hiệu chuẩn trước đó

Chúng tôi cung cấp một kịch bản ví dụ để di chuyển, cho phép phát lại một tập dữ liệu (episode) được ghi lại với hiệu chuẩn trước đó tại đây: `examples/backward_compatibility/replay.py`. Dưới đây, chúng tôi sẽ hướng dẫn bạn qua các thay đổi được thực hiện trong kịch bản ví dụ để các bộ dữ liệu hiệu chuẩn trước đó có thể hoạt động.

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

Hãy phân tích điều này. Codebase mới sử dụng hậu tố `.pos` cho các quan sát vị trí và chúng tôi đã bỏ tiền tố `main_`:

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

Với `"shoulder_lift"` (id = 2), vị trí 0 được thay đổi -90 độ và hướng bị đảo ngược so với hiệu chuẩn/mã cũ.

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

Với `"elbow_flex"` (id = 3), vị trí 0 được thay đổi -90 độ so với hiệu chuẩn/mã cũ.

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

Để sử dụng chuẩn hóa theo độ, chúng ta đặt tùy chọn `--robot.use_degrees` thành `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
```

### Sử dụng các chính sách được huấn luyện với hệ thống hiệu chuẩn trước đó

Policies xuất ra các hành động ở cùng định dạng với các dataset (`torch.Tensors`). Do đó, các phép biến đổi tương tự cũng nên được áp dụng.

Để tìm các phép biến đổi này, chúng tôi khuyên bạn nên đầu tiên chạy lại một tập dữ liệu (episode) của bộ dữ liệu mà chính sách của bạn đã được huấn luyện, bằng cách sử dụng phần ở trên. Sau đó, thêm các phép biến đổi tương tự này vào script suy luận của bạn (được minh họa ở đây cho một script gọi `predict_action`, giống như các ví dụ trong `evaluate.py` ở `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)
```

Nếu bạn có câu hỏi hoặc gặp sự cố trong quá trình di chuyển, hãy thoải mái đặt câu hỏi trên [Discord](https://discord.gg/s3KuuzsPFb)

