diff --git a/docs/source/zh/_toctree.yml b/docs/source/zh/_toctree.yml new file mode 100644 index 0000000000..71ff7d630b --- /dev/null +++ b/docs/source/zh/_toctree.yml @@ -0,0 +1,20 @@ +- sections: + - local: il_robots + title: 機器人的模仿學習 + - local: bring_your_own_policies + title: 自備策略 + - local: integrate_hardware + title: 自備硬體 + - local: hilserl + title: 使用強化學習訓練機器人 + - local: hilserl_sim + title: 在模擬環境中訓練強化學習 + - local: multi_gpu_training + title: 多 GPU 訓練 + - local: hil_data_collection + title: 人在迴圈中的資料收集 + - local: peft_training + title: 使用 PEFT 訓練(例如 LoRA) + - local: rename_map + title: 使用重新命名映射與空攝影機 + title: "教學" diff --git a/docs/source/zh/bring_your_own_policies.mdx b/docs/source/zh/bring_your_own_policies.mdx new file mode 100644 index 0000000000..41a8134435 --- /dev/null +++ b/docs/source/zh/bring_your_own_policies.mdx @@ -0,0 +1,247 @@ +# 自備策略 + +本教學說明如何將您自訂策略的實作整合到 LeRobot 生態系統中,讓您在使用自己的演算法的同時,能夠運用所有 LeRobot 工具進行訓練、評估和部署。 + +## 步驟 1:建立策略套件 + +您自訂的策略應組織成一個遵循 LeRobot 外掛慣例的可安裝的 Python 套件。 + +### 套件結構 + +建立一個以 `lerobot_policy_` 為前綴(重要!)並在後面加上您的策略名稱的套件: + +```bash +lerobot_policy_my_custom_policy/ +├── pyproject.toml +└── src/ + └── lerobot_policy_my_custom_policy/ + ├── __init__.py + ├── configuration_my_custom_policy.py + ├── modeling_my_custom_policy.py + └── processor_my_custom_policy.py +``` + +### 套件配置 + +設定您的 `pyproject.toml`: + +```toml +[project] +name = "lerobot_policy_my_custom_policy" +version = "0.1.0" +dependencies = [ + # your policy-specific dependencies +] +requires-python = ">= 3.12" + +[build-system] +build-backend = # your-build-backend +requires = # your-build-system +``` + +## 步驟 2:定義策略配置 + +建立一個繼承自 [`PreTrainedConfig`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/configs/policies.py) 的配置類別,並註冊您的策略類型: +以下提供一個起始範本,請依據您的策略架構與訓練需求自行調整參數和方法。 + +```python +# configuration_my_custom_policy.py +from dataclasses import dataclass, field +from lerobot.configs.policies import PreTrainedConfig +from lerobot.optim.optimizers import AdamWConfig +from lerobot.optim.schedulers import CosineDecayWithWarmupSchedulerConfig + +@PreTrainedConfig.register_subclass("my_custom_policy") +@dataclass +class MyCustomPolicyConfig(PreTrainedConfig): + """MyCustomPolicy 的配置類。 + + Args: + n_obs_steps: 作為輸入使用的觀測步數 + horizon: 動作預測範圍 + n_action_steps: 要執行的動作步數 + hidden_dim: 策略網路的隱藏維度 + # 在此新增您的策略特定參數 + """ + + horizon: int = 50 + n_action_steps: int = 50 + hidden_dim: int = 256 + + optimizer_lr: float = 1e-4 + optimizer_weight_decay: float = 1e-4 + + def __post_init__(self): + super().__post_init__() + if self.n_action_steps > self.horizon: + raise ValueError("n_action_steps cannot exceed horizon") + + def validate_features(self) -> None: + """驗證輸入/輸出特徵的相容性""" + if not self.image_features: + raise ValueError("MyCustomPolicy requires at least one image feature.") + if self.action_feature is None: + raise ValueError("MyCustomPolicy requires 'action' in output_features.") + + def get_optimizer_preset(self) -> AdamWConfig: + return AdamWConfig(lr=self.optimizer_lr, weight_decay=self.optimizer_weight_decay) + + def get_scheduler_preset(self): + return None + + @property + def observation_delta_indices(self) -> list[int] | None: + """資料集載入器為每個觀測提供的相對時間步偏移量。 + + 對於單幀策略,回傳 `None`。對於需要使用多個過去或未來幀的時序策略, + 回傳偏移量的列表,例如 `[-20, -10, 0, 10]` 代表步長為 10 的 + 3 個過去幀與步長為 10 的 1 個未來幀。 + """ + return None + + @property + def action_delta_indices(self) -> list[int]: + """資料集載入器回傳的動作區塊的相對時間步偏移量。 + """ + return list(range(self.horizon)) + + @property + def reward_delta_indices(self) -> None: + return None +``` + +## 步驟 3:實作策略類 + +透過繼承 [`PreTrainedPolicy`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/policies/pretrained.py) 來建立您的策略實作: + +```python +# modeling_my_custom_policy.py +import torch +import torch.nn as nn +from typing import Any + +from lerobot.policies.pretrained import PreTrainedPolicy +from lerobot.utils.constants import ACTION +from .configuration_my_custom_policy import MyCustomPolicyConfig + +class MyCustomPolicy(PreTrainedPolicy): + config_class = MyCustomPolicyConfig # 必須與 @register_subclass 中的字串相符 + name = "my_custom_policy" + + def __init__(self, config: MyCustomPolicyConfig, dataset_stats: dict[str, Any] = None): + super().__init__(config, dataset_stats) + config.validate_features() # 基礎類別不會自動呼叫 + self.config = config + self.model = ... # 您的 nn.Module 放在這裡 + + def reset(self): + """重設回合狀態。""" + ... + + def get_optim_params(self) -> dict: + """回傳要傳遞給最佳化器的參數(例如分組的 lr/wd)。""" + return {"params": self.parameters()} + + def predict_action_chunk(self, batch: dict[str, torch.Tensor], **kwargs) -> torch.Tensor: + """回傳當前觀測的完整動作區塊 (B, chunk_size, action_dim)。""" + ... + + def select_action(self, batch: dict[str, torch.Tensor], **kwargs) -> torch.Tensor: + """回傳當前時間步的單一動作(在推論時呼叫)。""" + ... + + def forward(self, batch: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]: + """計算訓練損失。 + + `batch["action_is_pad"]` 是形狀為 (B, horizon) 的布林遮罩,標記 + 因回合在 `horizon` 步之前結束而填充的時間步,您可以將這些從損失中 + 排除。 + """ + actions = batch[ACTION] + action_is_pad = batch.get("action_is_pad") + ... + return {"loss": ...} +``` + +## 步驟 4:新增資料處理器 + +建立處理器函數。如需具體參考,請查看 [processor_act.py](https://github.com/huggingface/lerobot/blob/main/src/lerobot/policies/act/processor_act.py) 或 [processor_diffusion.py](https://github.com/huggingface/lerobot/blob/main/src/lerobot/policies/diffusion/processor_diffusion.py)。 + +```python +# processor_my_custom_policy.py +from typing import Any +import torch + +from lerobot.processor import PolicyAction, PolicyProcessorPipeline + + +def make_my_custom_policy_pre_post_processors( + config, + dataset_stats: dict[str, dict[str, torch.Tensor]] | None = None, +) -> tuple[ + PolicyProcessorPipeline[dict[str, Any], dict[str, Any]], + PolicyProcessorPipeline[PolicyAction, PolicyAction], +]: + preprocessor = ... # 為輸入建立您的 PolicyProcessorPipeline + postprocessor = ... # 為輸出建立您的 PolicyProcessorPipeline + return preprocessor, postprocessor +``` + +**重要 — 函數命名:** LeRobot 透過名稱來探索您的處理器。函式**必須**命名為 `make_{policy_name}_pre_post_processors`(與您傳給 `@PreTrainedConfig.register_subclass` 的字串相符)。 + +## 步驟 5:套件初始化 + +在套件的 `__init__.py` 中暴露您的類: + +```python +# __init__.py +"""為 LeRobot 自訂的策略套件。""" + +try: + import lerobot # noqa: F401 +except ImportError: + raise ImportError( + "lerobot is not installed. Please install lerobot to use this policy package." + ) + +from .configuration_my_custom_policy import MyCustomPolicyConfig +from .modeling_my_custom_policy import MyCustomPolicy +from .processor_my_custom_policy import make_my_custom_policy_pre_post_processors + +__all__ = [ + "MyCustomPolicyConfig", + "MyCustomPolicy", + "make_my_custom_policy_pre_post_processors", +] +``` + +## 步驟 6:安裝與使用 + +### 安裝您的策略套件 + +```bash +cd lerobot_policy_my_custom_policy +pip install -e . + +# 或者如果已發布到 PyPI,從 PyPI 安裝 +pip install lerobot_policy_my_custom_policy +``` + +### 使用您的策略 + +安裝完成後,您的策略會自動整合到 LeRobot 的訓練和評估工具中: + +```bash +lerobot-train \ + --policy.type my_custom_policy \ + --env.type pusht \ + --steps 200000 +``` + +## 範例與社群貢獻 + +查看以下策略實作範例: + +- [DiTFlow 策略](https://github.com/danielsanjosepro/lerobot_policy_ditflow) — 使用流匹配目標(flow-matching objective)的擴散 (Diffusion) Transformer 策略。在此範例中試用:[DiTFlow 範例](https://github.com/danielsanjosepro/test_lerobot_policy_ditflow) + +歡迎與社群分享您的策略實作!🤗 diff --git a/docs/source/zh/hil_data_collection.mdx b/docs/source/zh/hil_data_collection.mdx new file mode 100644 index 0000000000..f65e49ea8d --- /dev/null +++ b/docs/source/zh/hil_data_collection.mdx @@ -0,0 +1,270 @@ +# 人在迴圈中的資料收集 + +人在迴圈中(Human-In-the-Loop, HIL)的資料收集讓您能透過將已訓練的策略部署到真實機器人上,同時由人類操作員監控並在需要時介入,來改進該策略。介入資料(恢復動作與修正動作)會與自主運行片段一併記錄,產生更豐富的訓練資料集,教導策略如何處理失敗情況。 + +--- + +## 為什麼需要人在迴圈中的機制? + +標準的行為複製僅在成功的示範上訓練策略。在部署期間,微小的誤差可能會不斷累積,將機器人推入訓練期間從未見過的狀態(分佈偏移)。HIL 資料收集透過以下方式解決此問題: + +- 在真實機器人上執行已訓練的策略 +- 當機器人即將失敗時由人為介入 +- 將人為的恢復與修正動作記錄為訓練資料 +- 使用合併的資料集微調策略 + +這將產生一個不僅知道如何執行任務,還知道如何在出錯時恢復的策略。 + +--- + +## 運作方式 + +在 HIL 進行期間,人類操作員在每個回合中遵循以下循環: + +1. **觀察**策略自主運行 +2. 當即將發生失敗時**暫停**,機器人保持當前位置 +3. **接管控制**並遙控操作機器人回到良好狀態(恢復),然後修正行為 +4. **將控制權交還給策略**,策略恢復自主執行 +5. 在回合內根據需要重複步驟 2–4 任意次數 +6. 當任務完成時**結束回合**,儲存並進入下一個推演 + +自主與人為控制的片段都會被記錄。策略和人類可以在單一回合內多次交替控制,每次交接後回合會從當前狀態繼續(不需要因為發生介入而重置)。這在一條連續軌跡中捕捉了自主執行、恢復和修正。收集完成後,合併的資料集(原始示範 + HIL 資料)用於微調策略。 + +此過程可以迭代重複:部署、收集、微調、再重複。每一輪針對當前策略的失敗模式。 + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ 策略 v0(在示範上訓練) │ +│ ↓ │ +│ HIL 收集(針對當前失敗模式)→ 微調 → 策略 v1 │ +│ ↓ │ +│ HIL 收集(針對新的失敗模式)→ 微調 → 策略 v2 │ +│ ↓ │ +│ ...(重複直到效能令人滿意) │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 硬體需求 + +### 遙操作器需求 + +`examples/hil` 中的 HIL 腳本需要**具有主動馬達的遙操作器**,能夠: + +- 以程式方式啟用/停用扭力 +- 移動到目標位置(在暫停時鏡像機器人狀態) + +**當前 `examples/hil` 腳本中相容的遙操作器:** + +- `openarm_mini` - OpenArm Mini +- `so_leader` - SO100 / SO101 的領導臂 + +> [!IMPORTANT] +> 提供的 `examples/hil` 指令預設使用 `bi_openarm_follower` + `openarm_mini`。 +> `so_follower` + `so_leader` 的配置也已註冊,可透過 CLI flags 使用。 + +--- + +## 腳本 + +單一腳本可同時處理同步與 RTC 推論。透過 `--rtc.enabled=true` 切換 RTC: + +| 模式 | 旗標 | 模型 | +| --------------- | -------------------- | --------------------- | +| 標準(預設) | _(不需要旗標)_ | ACT、Diffusion Policy | +| 即時分塊(RTC) | `--rtc.enabled=true` | Pi0、Pi0.5、SmolVLA | + +--- + +## 逐步指南 + +### 步驟 1:預訓練基礎策略 + +首先,在您的示範資料集上訓練策略: + +```bash +python src/lerobot/scripts/lerobot_train.py \ + --dataset.repo_id=your-username/demo-dataset \ + --policy.type=pi0 \ + --output_dir=outputs/pretrain \ + --batch_size=32 \ + --steps=50000 +``` + +### 步驟 2:收集 HIL 資料 + +**標準推論(ACT、Diffusion Policy):** + +```bash +python examples/hil/hil_data_collection.py \ + --robot.type=bi_openarm_follower \ + --robot.left_arm_config.port=can1 \ + --robot.left_arm_config.side=left \ + --robot.right_arm_config.port=can0 \ + --robot.right_arm_config.side=right \ + --robot.cameras='{left_wrist: {type: opencv, index_or_path: "/dev/video0", width: 1280, height: 720, fps: 30}, right_wrist: {type: opencv, index_or_path: "/dev/video4", width: 1280, height: 720, fps: 30}, base: {type: opencv, index_or_path: "/dev/video2", width: 640, height: 480, fps: 30}}' \ + --teleop.type=openarm_mini \ + --teleop.port_left=/dev/ttyACM0 \ + --teleop.port_right=/dev/ttyACM1 \ + --policy.path=outputs/pretrain/checkpoints/last/pretrained_model \ + --dataset.repo_id=your-username/hil-dataset \ + --dataset.single_task="Fold the T-shirt properly" \ + --dataset.fps=30 \ + --dataset.episode_time_s=1000 \ + --dataset.num_episodes=50 \ + --interpolation_multiplier=2 +``` + +**搭配 RTC 用於大型模型(Pi0、Pi0.5、SmolVLA):** + +對於推論延遲較高的模型,啟用 RTC 以實現流暢執行: + +```bash +python examples/hil/hil_data_collection.py \ + --rtc.enabled=true \ + --rtc.execution_horizon=20 \ + --rtc.max_guidance_weight=5.0 \ + --rtc.prefix_attention_schedule=LINEAR \ + --robot.type=bi_openarm_follower \ + --robot.left_arm_config.port=can1 \ + --robot.left_arm_config.side=left \ + --robot.right_arm_config.port=can0 \ + --robot.right_arm_config.side=right \ + --robot.cameras='{left_wrist: {type: opencv, index_or_path: "/dev/video0", width: 1280, height: 720, fps: 30}, right_wrist: {type: opencv, index_or_path: "/dev/video4", width: 1280, height: 720, fps: 30}, base: {type: opencv, index_or_path: "/dev/video2", width: 640, height: 480, fps: 30}}' \ + --teleop.type=openarm_mini \ + --teleop.port_left=/dev/ttyACM0 \ + --teleop.port_right=/dev/ttyACM1 \ + --policy.path=outputs/pretrain/checkpoints/last/pretrained_model \ + --dataset.repo_id=your-username/hil-rtc-dataset \ + --dataset.single_task="Fold the T-shirt properly" \ + --dataset.fps=30 \ + --dataset.episode_time_s=1000 \ + --dataset.num_episodes=50 \ + --interpolation_multiplier=3 +``` + +**操控方式(概念說明):** + +互動模式如下: + +- **暫停輸入**:暫停自主策略執行 +- **接管輸入**:將控制權轉移給人類操作員並記錄介入資料 +- **交還策略輸入**:將控制權交還給策略並繼續同一回合 +- **回合控制輸入**:根據需要儲存/重新錄製/停止/重置 + +實際的按鍵/踏板對應可能因腳本和硬體整合而異。請以每個腳本印出的操控說明作為您設定上具體對應關係的依據。 + +HIL 協定: + +1. 觀察策略自主運行(遙操作器處於閒置/自由狀態) +2. 當您看到即將發生失敗時,觸發**暫停輸入** + - 策略停止 + - 遙操作器移動以匹配機器人位置(扭力啟用) + - 暫停期間不記錄影格 +3. 觸發**接管輸入**以接管控制 + - 遙操作器扭力停用,可自由移動 + - **恢復**:遙控操作機器人回到良好狀態 + - **修正**:修正行為 + - 所有動作都會被記錄 +4. 觸發**交還策略輸入** + - 策略從當前狀態恢復自主執行 + - 您可以隨時再次介入(重複步驟 2–4) +5. 當任務完成時結束並儲存回合(或達到回合時間限制) +6. **重置**:遙操作器移動到機器人位置,您可以將機器人移動到起始位置 +7. 開始下一個回合 + +**腳踏板設定(Linux):** + +如果使用 USB 腳踏板(PCsensor FootSwitch),請確保存取權限: + +```bash +sudo setfacl -m u:$USER:rw /dev/input/by-id/usb-PCsensor_FootSwitch-event-kbd +``` + +### 步驟 3:微調策略 + +在**合併的**資料集(`demo-dataset` + `hil-dataset` 合併在一起)上進行微調: + +```bash +python src/lerobot/scripts/lerobot_train.py \ + --dataset.repo_id=your-username/hil-dataset \ + --policy.type=pi0 \ + --policy.pretrained_path=outputs/pretrain/checkpoints/last/pretrained_model \ + --output_dir=outputs/hil_finetune \ + --steps=20000 +``` + +然後部署微調後的策略,從步驟 2 重新開始,針對其剩餘的失敗模式進行改進。 + +--- + +## 有效 HIL 收集的技巧 + +### 何時介入 + +當您觀察到以下情況時介入: + +機器人即將犯下不可逆的錯誤 + +- 機器人猶豫不決或表現出不確定的行為 +- 機器人偏離預期軌跡 + +恢復:遙操作回到良好狀態 + +在恢復階段,遙操作機器人回到以下狀態: + +- 機器人處於熟悉的、分佈內的配置 +- 當前子任務仍然可以完成 +- 恢復軌跡本身就是有資訊量的訓練資料 + +### 修正的品質 + +在修正階段: + +- 提供**自信、乾淨的**軌跡 +- 完整地完成當前子任務 +- 不要過度修正或添加不必要的動作 + +--- + +## 相關工作 + +此 HIL 資料收集方法建立在互動式模仿學習的理念之上: + +- **DAgger** (Ross et al., 2011) 引入了核心理念:不只在專家示範上訓練,而是在學習者所造訪的狀態上查詢專家的修正。這透過迭代收集 on-policy資料,打破了標準行為複製的累積誤差循環。 + +- **HG-DAgger** (Kelly et al., 2019) 使其在機器人領域變得實用:人類專家監控機器人,僅在需要時介入,而非標註每一個狀態。自主與人類控制之間的切換正是此處腳本所使用的暫停 → 接管 → 交還策略循環。 + +- **RaC** (Hu et al., 2025) 透過將介入明確分解為**恢復**(遙控操作回到良好狀態)和**修正**(從該處示範正確行為),將此循環擴展至長期任務。此分解方式即為 `examples/hil` 中 HIL 腳本所遵循的協定。 + +- **π0.6/RECAP** (Physical Intelligence, 2025) 將相同的迭代收集與微調循環大規模應用於 VLA 模型,展示即使是大型預訓練策略也能從針對自身失敗模式的人類修正中獲得顯著改善。π0.6 使用 RECAP 進行訓練。 + +```bibtex +@article{ross2011dagger, + title={A Reduction of Imitation Learning and Structured Prediction to No-Regret Online Learning}, + author={Ross, Stéphane and Gordon, Geoffrey and Bagnell, Drew}, + journal={Proceedings of the Fourteenth International Conference on Artificial Intelligence and Statistics}, + year={2011} +} + +@article{kelly2019hgdagger, + title={HG-DAgger: Interactive Imitation Learning with Human Experts}, + author={Kelly, Michael and Sidrane, Chelsea and Driggs-Campbell, Katherine and Kochenderfer, Mykel J}, + journal={arXiv preprint arXiv:1810.02890}, + year={2019} +} + +@article{hu2025rac, + title={RaC: Robot Learning for Long-Horizon Tasks by Scaling Recovery and Correction}, + author={Hu, Zheyuan and Wu, Robyn and Enock, Naveen and Li, Jasmine and Kadakia, Riya and Erickson, Zackory and Kumar, Aviral}, + journal={arXiv preprint arXiv:2509.07953}, + year={2025} +} + +@article{pi2025recap, + title={π0.6: a VLA That Learns From Experience}, + author={Physical Intelligence}, + year={2025} +} +``` diff --git a/docs/source/zh/hilserl.mdx b/docs/source/zh/hilserl.mdx new file mode 100644 index 0000000000..be0f635503 --- /dev/null +++ b/docs/source/zh/hilserl.mdx @@ -0,0 +1,918 @@ +# HIL-SERL 實體機器人訓練工作流程指南 + +在本教學中,您將使用 LeRobot 完整體驗人在迴圈中的樣本高效強化學習(Human-in-the-Loop Sample-Efficient Reinforcement Learning,HIL-SERL)工作流程。您將在短短幾小時內,掌握透過強化學習在實體機器人上訓練一個策略。 + +HIL-SERL 是一種樣本高效的強化學習演算法,結合了人類示範、線上學習與人類介入。該方法從少量的人類示範開始,利用這些示範訓練一個獎勵分類器,然後採用行動者-學習者架構,讓人類可以在策略執行過程中隨時介入,以引導探索並修正不安全的行為。在本教學中,您將使用遊戲手把來提供介入操作並控制機器人的學習過程。 + +它結合了三個關鍵要素: + +1. **離線示範與獎勵分類器:** 少量的人類遙操作回合加上基於視覺的成功偵測器,為策略提供一個塑造過的起始點。 + +2. **機器人上的演員/學習者迴圈與人類介入:** 分散式的 Soft Actor Critic(SAC)行動者探索實體機器人的同時更新策略;人類可以隨時介入以修正危險或無效的行為。 + +3. **安全與效率工具:** 關節/末端執行器(EE)界限、裁切感興趣區域(ROI)前處理以及 WandB 監控,確保資料有用以及硬體安全。 + +這些要素結合在一起,使 HIL-SERL 能達到近乎完美的任務成功率,且循環時間比純模仿學習的基線更快。 + +

+ HIL-SERL workflow +

+ +

+ HIL-SERL workflow, Luo et al. 2024 +

+ +本指南提供逐步說明,教您如何使用 LeRobot 的 HilSerl 實作在實體機器人上訓練機器人策略。 + +## 我需要什麼? + +- 一個遊戲手把(建議)或鍵盤來控制機器人 +- 一張 Nvidia GPU +- 一個配備從動臂和主動臂的實體機器人(如果使用鍵盤或遊戲手把則為選配) +- 機器人的 URDF 檔案,供運動學套件使用(請參考 `lerobot/model/kinematics.py`) + +## 我可以訓練什麼類型的任務? + +您可以使用 HIL-SERL 訓練各種操作任務。以下是一些建議: + +- 從簡單的任務開始,以了解系統的運作方式。 + - 將方塊推到目標區域 + - 用夾爪夾取並抬起方塊 +- 避免極長時間範圍的任務。專注於可以在 5-10 秒內完成的任務。 +- 一旦您對系統的運作方式有了良好的了解,就可以嘗試更複雜的任務和更長的時間範圍。 + - 夾取並放置方塊 + - 使用雙臂夾取物體的雙臂任務 + - 從一隻手臂轉移物體到另一隻手臂的交接任務 + - 盡情發揮! + +## 安裝帶有 HIL-SERL 的 LeRobot + +要安裝帶有 HIL-SERL 的 LeRobot,您需要安裝 `hilserl` 額外套件。 + +```bash +pip install -e ".[hilserl]" +``` + +## 實體機器人訓練工作流程 + +### 了解配置 + +訓練過程從 HILSerl 環境的正確配置開始。主要的配置類別是 `lerobot/rl/gym_manipulator.py` 中的 `GymManipulatorConfig`,其中包含巢狀的 `HILSerlRobotEnvConfig` 和 `DatasetConfig`。配置被組織成清晰的巢狀子配置: + + +```python +class GymManipulatorConfig: + env: HILSerlRobotEnvConfig # 環境配置(巢狀) + dataset: DatasetConfig # 資料集記錄/重播配置(巢狀) + mode: str | None = None # "record"、"replay" 或 None(用於訓練) + device: str = "cpu" # 運算裝置 + +class HILSerlRobotEnvConfig(EnvConfig): + robot: RobotConfig | None = None # 主要機器人代理(定義於 lerobot/robots) + teleop: TeleoperatorConfig | None = None # 遙操作代理,例如遊戲手把或主動臂 + processor: HILSerlProcessorConfig # 處理管線配置(巢狀) + name: str = "real_robot" # 環境名稱 + task: str | None = None # 任務識別碼 + fps: int = 10 # 控制頻率 + +# 巢狀處理器配置 +class HILSerlProcessorConfig: + control_mode: str = "gamepad" # 控制模式 + observation: ObservationConfig | None = None # 觀測處理設定 + image_preprocessing: ImagePreprocessingConfig | None = None # 影像裁切/縮放設定 + gripper: GripperConfig | None = None # 夾爪控制與懲罰設定 + reset: ResetConfig | None = None # 環境重置與計時設定 + inverse_kinematics: InverseKinematicsConfig | None = None # 逆運動學處理設定 + reward_classifier: RewardClassifierConfig | None = None # 獎勵分類器設定 + max_gripper_pos: float | None = 100.0 # 最大夾爪位置 + +# 子配置類 +class ObservationConfig: + add_joint_velocity_to_observation: bool = False # 將關節速度加入狀態 + add_current_to_observation: bool = False # 將馬達電流加入狀態 + display_cameras: bool = False # 執行期間顯示相機畫面 + +class ImagePreprocessingConfig: + crop_params_dict: dict[str, tuple[int, int, int, int]] | None = None # 影像裁切參數 + resize_size: tuple[int, int] | None = None # 目標影像大小 + +class GripperConfig: + use_gripper: bool = True # 啟用夾爪控制 + gripper_penalty: float = 0.0 # 不當使用夾爪的懲罰 + +class ResetConfig: + fixed_reset_joint_positions: Any | None = None # 重置時的關節位置 + reset_time_s: float = 5.0 # 重置期間的等待時間 + control_time_s: float = 20.0 # 最大回合持續時間 + terminate_on_success: bool = True # 偵測到成功時是否終止回合 + +class InverseKinematicsConfig: + urdf_path: str | None = None # 機器人 URDF 檔案路徑 + target_frame_name: str | None = None # 末端執行器座標系名稱 + end_effector_bounds: dict[str, list[float]] | None = None # 末端執行器工作空間界限 + end_effector_step_sizes: dict[str, float] | None = None # 各軸的末端執行器步進大小 + +class RewardClassifierConfig: + pretrained_path: str | None = None # 預訓練獎勵分類器路徑 + success_threshold: float = 0.5 # 成功偵測閾值 + success_reward: float = 1.0 # 成功回合的獎勵值 + +# 資料集配置 +class DatasetConfig: + repo_id: str # LeRobot 資料集儲存庫 ID + task: str # 任務識別碼 + root: str | None = None # 本地資料集根目錄 + num_episodes_to_record: int = 5 # 錄製的回合數 + replay_episode: int | None = None # 重播的回合索引 + push_to_hub: bool = False # 是否將資料集推送到 Hub +``` + + +### 處理器管線架構 + +HIL-SERL 使用模組化的處理器管線架構,透過一系列可組合的步驟來處理機器人觀測和動作。管線分為兩個主要組件: + +#### 環境處理器管線 + +環境處理器(`env_processor`)處理傳入的觀測和環境狀態: + +1. **VanillaObservationProcessorStep**:將原始機器人觀測轉換為標準化格式 +2. **JointVelocityProcessorStep**(選配):將關節速度資訊加入觀測 +3. **MotorCurrentProcessorStep**(選配):將馬達電流讀數加入觀測 +4. **ForwardKinematicsJointsToEE**(選配):從關節位置計算末端執行器姿態 +5. **ImageCropResizeProcessorStep**(選配):裁切和調整攝影機影像大小 +6. **TimeLimitProcessorStep**(選配):強制執行回合時間限制 +7. **GripperPenaltyProcessorStep**(選配):對不當使用夾爪施加懲罰 +8. **RewardClassifierProcessorStep**(選配):使用視覺模型自動偵測獎勵 +9. **AddBatchDimensionProcessorStep**:將資料轉換為批次格式以供神經網路處理 +10. **DeviceProcessorStep**:將資料移至指定的計算裝置(CPU/GPU) + +#### 動作處理器管線 + +動作處理器(`action_processor`)處理輸出的動作和人類介入: + +1. **AddTeleopActionAsComplimentaryDataStep**:擷取遙操作動作以供記錄 +2. **AddTeleopEventsAsInfoStep**:記錄介入事件和回合控制訊號 +3. **InterventionActionProcessorStep**:處理人類介入和回合終止 +4. **逆運動學管線**(啟用時): + - **MapDeltaActionToRobotActionStep**:將差量動作轉換為機器人動作格式 + - **EEReferenceAndDelta**:計算末端執行器參考和差量移動 + - **EEBoundsAndSafety**:強制執行工作空間安全邊界 + - **InverseKinematicsEEToJoints**:將末端執行器動作轉換為關節目標 + - **GripperVelocityToJoint**:處理夾爪控制命令 + +#### 配置範例 + +**基本的觀測處理**: + +```json +{ + "env": { + "processor": { + "observation": { + "add_joint_velocity_to_observation": true, + "add_current_to_observation": false, + "display_cameras": false + } + } + } +} +``` + +**影像處理**: + +```json +{ + "env": { + "processor": { + "image_preprocessing": { + "crop_params_dict": { + "observation.images.front": [180, 250, 120, 150], + "observation.images.side": [180, 207, 180, 200] + }, + "resize_size": [128, 128] + } + } + } +} +``` + +**逆運動學設定**: + +```json +{ + "env": { + "processor": { + "inverse_kinematics": { + "urdf_path": "path/to/robot.urdf", + "target_frame_name": "end_effector", + "end_effector_bounds": { + "min": [0.16, -0.08, 0.03], + "max": [0.24, 0.2, 0.1] + }, + "end_effector_step_sizes": { + "x": 0.02, + "y": 0.02, + "z": 0.02 + } + } + } + } +} +``` + +### 進階的觀測處理 + +HIL-SERL 框架支援額外的觀測處理功能,可以改善策略的學習: + +#### 關節速度處理 + +啟用關節速度估計,為策略提供運動資訊: + +```json +{ + "env": { + "processor": { + "observation": { + "add_joint_velocity_to_observation": true + } + } + } +} +``` + +此處理器: + +- 使用連續關節位置讀數之間的有限差分來估計關節速度 +- 將速度資訊加入觀測狀態向量 +- 對於需要運動感知的動態任務很有用 + +#### 馬達電流處理 + +監控馬達電流以偵測接觸力和負載條件: + +```json +{ + "env": { + "processor": { + "observation": { + "add_current_to_observation": true + } + } + } +} +``` + +此處理器: + +- 從機器人的控制系統讀取馬達電流值 +- 將電流量測加入觀測狀態向量 +- 有助於偵測接觸事件、物體重量和機械阻力 +- 對於接觸充分的操作任務很有用 + +#### 組合觀測處理 + +您可以同時啟用多個觀測處理功能: + +```json +{ + "env": { + "processor": { + "observation": { + "add_joint_velocity_to_observation": true, + "add_current_to_observation": true, + "display_cameras": false + } + } + } +} +``` + +**注意**:啟用額外的觀測功能會增加狀態空間的維度,這可能需要調整您的策略網路架構,並可能需要收集更多訓練資料。 + +### 尋找機器人工作空間邊界 + +在收集示範之前,您需要確定機器人的適當操作邊界。 + +這有助於透過兩種方式簡化在實體機器人上學習的問題:1)將機器人的操作空間限制在能解決任務的特定區域,避免不必要或不安全的探索;2)允許在末端執行器空間而非關節空間中進行訓練。根據經驗,對於強化學習中的操作任務,在關節空間中學習通常是更困難的問題——有些任務在關節空間中幾乎不可能學習,但當動作空間轉換為末端效應器座標時就變得可學習。 + +**使用 lerobot-find-joint-limits** + +此腳本幫助您找到機器人末端執行器的安全操作邊界。假設您有從臂和主臂,您可以使用此腳本找到從臂的邊界,這些邊界將在訓練期間應用。 +限定動作空間將減少代理的冗餘探索並保證安全。 + +```bash +lerobot-find-joint-limits \ + --robot.type=so100_follower \ + --robot.port=/dev/tty.usbmodem58760431541 \ + --robot.id=black \ + --teleop.type=so100_leader \ + --teleop.port=/dev/tty.usbmodem58760431551 \ + --teleop.id=blue +``` + +**工作流程** + +1. 執行腳本並在要解決任務的空間中移動機器人 +2. 腳本會記錄末端執行器位置的最小值和最大值以及關節角度,並將它們列印到控制台,例如: + ``` + Max ee position [0.2417 0.2012 0.1027] + Min ee position [0.1663 -0.0823 0.0336] + Max joint positions [-20.0, -20.0, -20.0, -20.0, -20.0, -20.0] + Min joint positions [50.0, 50.0, 50.0, 50.0, 50.0, 50.0] + ``` +3. 將這些值用於遙操作裝置(TeleoperatorConfig)配置中的 `end_effector_bounds` 欄位 + +**配置範例** + +```json +"end_effector_bounds": { + "max": [0.24, 0.20, 0.10], + "min": [0.16, -0.08, 0.03] +} +``` + +### 收集示範 + +定義好邊界後,您可以安全地收集訓練示範。使用 off-policy 演算法進行 RL 訓練允許我們使用離線收集的資料集來提高學習效率。 + +**設定錄製模式** + +建立一個用於錄製示範的配置檔案(或編輯現有的檔案,如 [env_config.json](https://huggingface.co/datasets/lerobot/config_examples/resolve/main/rl/env_config.json)): + +1. 在根層級將 `mode` 設為 `"record"` +2. 在 `dataset` 區段中為您的資料集指定唯一的 `repo_id`(例如 "username/task_name") +3. 在 `dataset` 區段中將 `num_episodes_to_record` 設為您想收集的示範數量 +4. 先將 `env.processor.image_preprocessing.crop_params_dict` 設為 `{}`(我們稍後會決定裁切參數) +5. 在 `env` 區段中配置 `env.robot`、`env.teleop` 和其他硬體設定 + +配置範例片段: + +```json +{ + "env": { + "type": "gym_manipulator", + "name": "real_robot", + "fps": 10, + "processor": { + "control_mode": "gamepad", + "observation": { + "display_cameras": false + }, + "image_preprocessing": { + "crop_params_dict": {}, + "resize_size": [128, 128] + }, + "gripper": { + "use_gripper": true, + "gripper_penalty": 0.0 + }, + "reset": { + "reset_time_s": 5.0, + "control_time_s": 20.0 + } + }, + "robot": { + // ... 機器人配置 ... + }, + "teleop": { + // ... 遙操作器配置 ... + } + }, + "dataset": { + "repo_id": "username/pick_lift_cube", + "root": null, + "task": "pick_and_lift", + "num_episodes_to_record": 15, + "replay_episode": 0, + "push_to_hub": true + }, + "mode": "record", + "device": "cpu" +} +``` + +### 使用遙操作裝置 + +除了機器人之外,您還需要一個遙操作裝置來控制它,以便收集任務的資料集並在線上訓練期間執行介入。 +我們支援使用遊戲手把、鍵盤或機器人的主臂。 + +HIL-Serl 在機器人的末端執行器空間中學習動作。因此,遙操作將控制末端執行器的 x、y、z 位移。 + +為此,我們需要定義一個在末端執行器空間中接受動作的機器人版本。請查看機器人類別 `SO100FollowerEndEffector` 及其配置 `SO100FollowerEndEffectorConfig` 以了解與末端執行器空間相關的預設參數。 Check the robot class `SO100FollowerEndEffector` and its configuration `SO100FollowerEndEffectorConfig` for the default parameters related to the end-effector space. + + +```python +class SO100FollowerEndEffectorConfig(SO100FollowerConfig): + """SO100FollowerEndEffector 機器人的配置。""" + + # 末端執行器位置的預設邊界(單位:公尺) + end_effector_bounds: dict[str, list[float]] = field( # 末端執行器在 x,y,z 方向的邊界 + default_factory=lambda: { + "min": [-1.0, -1.0, -1.0], # 最小 x, y, z + "max": [1.0, 1.0, 1.0], # 最大 x, y, z + } + ) + + max_gripper_pos: float = 50 # 夾爪開啟的最大位置 + + end_effector_step_sizes: dict[str, float] = field( # 末端執行器在 x,y,z 方向的最大步長 + default_factory=lambda: { + "x": 0.02, + "y": 0.02, + "z": 0.02, + } + ) +``` + + +`Teleoperator` 定義遙操作裝置。您可以在 `lerobot/teleoperators` 中查看可用的遙操作器列表。 + +**設定遊戲手把** + +遊戲手把提供了一種非常方便的方式來控制機器人和回合狀態。 + +要設定遊戲手把,您需要將 `control_mode` 設為 `"gamepad"` 並在配置檔案中定義 `teleop` 區段。 + +```json +{ + "env": { + "teleop": { + "type": "gamepad", + "use_gripper": true + }, + "processor": { + "control_mode": "gamepad", + "gripper": { + "use_gripper": true + } + } + } +} +``` + +

+ Figure shows the control mappings on a Logitech gamepad. +

+

+ 遊戲手把上的機器人控制和回合管理按鍵對應 +

+ +**設定 SO101 主臂** + +SO101 主臂具有減速齒輪,使其能夠在探索期間移動並追蹤從臂。因此,接管控制比無齒輪的 SO100 更加順暢。 + +要設定 SO101 主臂,您需要將 `control_mode` 設為 `"leader"` 並在配置檔案中定義 `teleop` 片段。 + +```json +{ + "env": { + "teleop": { + "type": "so101_leader", + "port": "/dev/tty.usbmodem585A0077921", + "use_degrees": true + }, + "processor": { + "control_mode": "leader", + "gripper": { + "use_gripper": true + } + } + } +} +``` + +為了標註回合的成功/失敗,**您需要**使用鍵盤按 `s` 表示成功,按 `esc` 表示失敗。 +在線上訓練期間,按 `space` 接管策略控制,再按 `space` 將控制權交回策略。 + +
+影片:SO101 主臂遙操作 + +
+ +
+ +

SO101 主臂遙操作範例,主臂追蹤從臂,按 `space` 進行介入

+
+ +**錄製示範** + +開始錄製流程,配置檔案範例可在[此處](https://huggingface.co/datasets/aractingi/lerobot-example-config-files/blob/main/env_config_so100.json)找到: + +```bash +python -m lerobot.rl.gym_manipulator --config_path src/lerobot/configs/env_config_so100.json +``` + +錄製期間: + +1. 機器人將重置到配置檔案 `env.processor.reset.fixed_reset_joint_positions` 中定義的初始位置 +2. 成功完成任務 +3. 當您按下「成功」按鈕時,回合以獎勵 1 結束 +4. 如果達到時間限制或按下失敗按鈕,回合以獎勵 0 結束 +5. 您可以按下「重新錄製」按鈕重新錄製一個回合 +6. 流程會自動繼續到下一個回合 +7. 錄製完所有回合後,資料集會推送到 Hugging Face Hub(選配)並儲存在本地 + +### 處理資料集 + +收集示範後,處理它們以確定最佳的攝影機裁切參數。 +強化學習對背景干擾很敏感,因此將影像裁切到相關的工作空間區域非常重要。 + +基於視覺的 RL 演算法直接從像素輸入學習,使其容易受到無關視覺資訊的影響。背景元素如變化的光線、陰影、移動的人或工作空間外的物體都可能干擾學習過程。好的 ROI 選擇應該: + +- 僅包含任務發生的必要工作空間 +- 捕捉機器人的末端效應氣和任務涉及的所有物體 +- 排除不必要的背景元素和干擾 + +注意:如果您已經知道裁切參數,可以跳過此步驟,直接在錄製期間的配置檔案中設定 `crop_params_dict`。 + +**確定裁切參數** + +使用 `crop_dataset_roi.py` 腳本互動式地選擇攝影機影像中的感興趣區域: + +```bash +python -m lerobot.rl.crop_dataset_roi --repo-id username/pick_lift_cube +``` + +1. 對於每個攝影機視角,腳本將顯示第一幀 +2. 在相關的工作空間區域周圍繪製矩形 +3. 按 'c' 確認選擇 +4. 對所有攝影機視角重複操作 +5. 腳本輸出裁切參數並建立新的裁切資料集 + +輸出範例: + +``` +Selected Rectangular Regions of Interest (top, left, height, width): +observation.images.side: [180, 207, 180, 200] +observation.images.front: [180, 250, 120, 150] +``` + +

+ +

+ +

+ 用於選擇感興趣區域的互動式裁切工具 +

+ +**更新配置** + +將這些裁切參數加入您的訓練配置: + +```json +{ + "env": { + "processor": { + "image_preprocessing": { + "crop_params_dict": { + "observation.images.side": [180, 207, 180, 200], + "observation.images.front": [180, 250, 120, 150] + }, + "resize_size": [128, 128] + } + } + } +} +``` + +**建議的影像解析度** + +大多數基於視覺的策略已在 **128×128**(預設)或 **64×64** 像素的方形輸入上驗證。因此,我們建議將 resize_size 參數設為 [128, 128]——如果您需要節省 GPU 記憶體和頻寬,則設為 [64, 64]。其他解析度是可行的,但尚未經過充分測試。 + +### 訓練獎勵分類器 + +獎勵分類器在 HIL-SERL 工作流程中扮演重要角色,透過自動化獎勵分配和自動偵測回合成功。與其手動定義獎勵函數或每個時間步都依賴人類回饋,獎勵分類器學習從視覺觀測中預測成功/失敗。這使得 RL 演算法能夠根據機器人攝影機輸入提供一致且自動化的獎勵訊號,從而高效學習。 + +本指南說明如何訓練 LeRobot 人機協作強化學習實作中的獎勵分類器。獎勵分類器學習在給定狀態下預測獎勵值,可用於 RL 設定中訓練策略。 + +**注意**:訓練獎勵分類器是選配的。您可以透過使用遊戲手把或鍵盤裝置手動標註成功來開始第一輪 RL 實驗。 + +`modeling_classifier.py` 中的獎勵分類器實作使用預訓練的視覺模型來處理影像。它可以輸出單一值用於二元獎勵以預測成功/失敗情況,或輸出多個值用於多類別設定。 + +**為獎勵分類器收集資料集** + +在訓練之前,您需要收集帶有標註的資料集。`gym_manipulator.py` 中的 `record_dataset` 函數可以收集觀測、動作和獎勵的資料集。 + +要收集資料集,您需要根據 HILSerlRobotEnvConfig 修改環境配置中的一些參數。 + +```bash +python -m lerobot.rl.gym_manipulator --config_path src/lerobot/configs/reward_classifier_train_config.json +``` + +**資料收集的關鍵參數** + +- **mode**:設為 `"record"` 以收集資料集(在根層級) +- **dataset.repo_id**:`"hf_username/dataset_name"`,資料集名稱和 Hub 上的儲存庫名稱 +- **dataset.num_episodes_to_record**:要錄製的回合數 +- **env.processor.reset.terminate_on_success**:是否在偵測到成功時自動終止回合(預設:`true`) +- **env.fps**:每秒錄製的幀數 +- **dataset.push_to_hub**:是否將資料集推送到 Hub + +`env.processor.reset.terminate_on_success` 參數允許您控制回合終止行為。設為 `false` 時,即使偵測到成功,回合也會繼續,允許您收集更多帶有 reward=1 標籤的正面範例。這對於訓練獎勵分類器至關重要,因為它在您的資料集中提供更多成功狀態的範例。設為 `true`(預設)時,回合會在偵測到成功時立即終止。 + +**重要**:對於獎勵分類器訓練,將 `terminate_on_success` 設為 `false` 以收集足夠的正面範例。對於一般的 HIL-SERL 訓練,保持為 `true` 以在任務成功完成時啟用自動回合終止。 + +資料收集的配置範例片段: + +```json +{ + "env": { + "type": "gym_manipulator", + "name": "real_robot", + "fps": 10, + "processor": { + "reset": { + "reset_time_s": 5.0, + "control_time_s": 20.0, + "terminate_on_success": false + }, + "gripper": { + "use_gripper": true + } + }, + "robot": { + // ... 機器人配置 ... + }, + "teleop": { + // ... 遙操作器配置 ... + } + }, + "dataset": { + "repo_id": "hf_username/dataset_name", + "dataset_root": "data/your_dataset", + "task": "reward_classifier_task", + "num_episodes_to_record": 20, + "replay_episode": null, + "push_to_hub": true + }, + "mode": "record", + "device": "cpu" +} +``` + +**獎勵分類器配置** + +獎勵分類器使用 `configuration_classifier.py` 進行配置。以下是關鍵參數: + +- **model_name**:基礎模型架構(例如,我們主要使用 `"helper2424/resnet10"`) +- **model_type**:`"cnn"` 或 `"transformer"` +- **num_cameras**:攝影機輸入數量 +- **num_classes**:輸出類別數(通常為 2,用於二元成功/失敗) +- **hidden_dim**:隱藏表示的大小 +- **dropout_rate**:正則化參數 +- **learning_rate**:最佳化器的學習率 + +訓練[獎勵分類器](https://huggingface.co/datasets/aractingi/lerobot-example-config-files/blob/main/reward_classifier_train_config.json)的配置範例: + +```json +{ + "policy": { + "type": "reward_classifier", + "model_name": "helper2424/resnet10", + "model_type": "cnn", + "num_cameras": 2, + "num_classes": 2, + "hidden_dim": 256, + "dropout_rate": 0.1, + "learning_rate": 1e-4, + "device": "cuda", + "use_amp": true, + "input_features": { + "observation.images.front": { + "type": "VISUAL", + "shape": [3, 128, 128] + }, + "observation.images.side": { + "type": "VISUAL", + "shape": [3, 128, 128] + } + } + } +} +``` + +**訓練分類器** + +要訓練分類器,使用 `train.py` 腳本搭配您的配置: + +```bash +lerobot-train --config_path path/to/reward_classifier_train_config.json +``` + +**部署和測試模型** + +要使用您訓練好的獎勵分類器,配置 `HILSerlRobotEnvConfig` 以使用您的模型: + + +```python +config = GymManipulatorConfig( + env=HILSerlRobotEnvConfig( + processor=HILSerlProcessorConfig( + reward_classifier=RewardClassifierConfig( + pretrained_path="path_to_your_pretrained_trained_model" + ) + ), + # 其他環境參數 + ), + dataset=DatasetConfig(...), + mode=None # 用於訓練 +) +``` + + +或在 json 配置檔案中設定參數。 + +```json +{ + "env": { + "processor": { + "reward_classifier": { + "pretrained_path": "path_to_your_pretrained_model", + "success_threshold": 0.7, + "success_reward": 1.0 + }, + "reset": { + "terminate_on_success": true + } + } + } +} +``` + +執行 gym_manipulator.py 來測試模型。 + +```bash +python -m lerobot.rl.gym_manipulator --config_path path/to/env_config.json +``` + +獎勵分類器將根據機器人攝影機的視覺輸入自動提供獎勵。 + +**訓練獎勵分類器的範例工作流程** + +1. **建立配置檔案**: + 建立獎勵分類器和環境必要的 json 配置檔案。請查看[此處](https://huggingface.co/datasets/lerobot/config_examples/resolve/main/reward_classifier/config.json)的範例。 + +2. **收集資料集**: + + ```bash + python -m lerobot.rl.gym_manipulator --config_path src/lerobot/configs/env_config.json + ``` + +3. **訓練分類器**: + + ```bash + lerobot-train --config_path src/lerobot/configs/reward_classifier_train_config.json + ``` + +4. **測試分類器**: + ```bash + python -m lerobot.rl.gym_manipulator --config_path src/lerobot/configs/env_config.json + ``` + +### 使用執行者-學習者架構進行訓練 + +LeRobot 系統使用分散式執行者-學習者架構進行訓練。此架構將機器人互動與學習過程解耦,使它們能夠並行執行而不互相阻塞。執行者伺服器處理機器人觀測和動作,將互動資料發送給學習者伺服器。學習者伺服器執行梯度下降並定期更新執行者的策略權重。您需要啟動兩個處理程序:一個學習者和一個執行者。 + +**配置設定** + +建立訓練配置檔案(範例可在[此處](https://huggingface.co/datasets/lerobot/config_examples/resolve/main/rl/train_config.json)取得)。訓練配置基於 `lerobot/configs/train.py` 中的主要 `TrainRLServerPipelineConfig` 類。 + +1. 配置策略設定(`type="sac"`、`device` 等) +2. 將 `dataset` 設為您裁切過的資料集 +3. 配置環境設定和裁切參數 +4. 檢查 [configuration_sac.py](https://github.com/huggingface/lerobot/blob/main/src/lerobot/policies/sac/configuration_sac.py#L79) 中與 SAC 相關的其他參數。 +5. 驗證 `policy` 配置中的 `input_features` 和 `output_features` 對於您的任務是正確的。 + +**啟動學習者** + +首先,啟動學習者伺服器處理程序: + +```bash +python -m lerobot.rl.learner --config_path src/lerobot/configs/train_config_hilserl_so100.json +``` + +學習者: + +- 初始化策略的網路 +- 準備經驗重播緩衝區 +- 開啟 `gRPC` 伺服器並與執行者通訊 +- 處理策略的轉移與更新 + +**啟動執行者** + +在另一個終端中,使用相同的配置啟動執行者處理程序: + +```bash +python -m lerobot.rl.actor --config_path src/lerobot/configs/train_config_hilserl_so100.json +``` + +執行者: + +- 透過 `gRPC` 連接到學習者 +- 初始化環境 +- 執行策略的展開以收集經驗 +- 將轉移發送給學習者 +- 接收更新後的策略參數 + +**訓練流程** + +訓練會自動進行: + +1. 執行者在環境中執行策略 +2. 收集轉移並發送給學習者 +3. 學習者根據這些轉移更新策略 +4. 更新後的策略參數發送回執行者 +5. 過程持續進行直到達到指定的步數限制 + +**人在迴圈中** + +- 高效學習的關鍵是透過人類介入提供修正回饋並完成任務,以協助策略學習和探索。 +- 要進行人類介入,您可以按遊戲手把上的右上方扳機按鈕(或鍵盤上的 `space` 鍵)。這將暫停策略動作,允許您接管控制。 +- 成功的實驗是在開始時人類需要頻繁介入,但隨著策略改善逐漸減少介入次數。您可以在 `wandb` 儀表板中監控介入率。 + +

+ Figure shows the control mappings on a Logitech gamepad. +

+ +

+ 顯示人為介入如何隨時間引導策略學習的範例 +

+ +- 該圖顯示了回合獎勵隨互動步數變化的曲線。圖中展示了人為介入對策略學習的影響。 +- 橘色曲線是沒有任何人為介入的實驗。而粉色和藍色曲線是有人類介入的實驗。 +- 我們可以觀察到,當有人為介入時,策略開始達到最大獎勵所需的步數減少了四分之一。 + +**監控與除錯** + +如果您在配置中將 `wandb.enable` 設為 `true`,您可以透過 [Weights & Biases](https://wandb.ai/site/) 儀表板即時監控訓練進度。 + +### 人為介入指南 + +學習過程對介入策略非常敏感。需要幾次嘗試才能理解如何有效地介入。一些提示和建議: + +- 在訓練開始時允許策略自行探索幾個回合。 +- 避免長時間介入。盡量在機器人行為偏離軌道時進行介入以糾正行為。 +- 一旦策略開始完成任務,即使不完美,您可以將介入限制在簡單的快速動作,例如簡單的抓取命令。 + +理想的行為是您的介入率應該在訓練過程中逐漸下降,如下圖所示。 + +

+ Intervention rate +

+ +

+ 抓取並提起方塊任務訓練過程中的介入率曲線 +

+ +### 需要調整的關鍵超參數 + +某些配置值對訓練穩定性和速度具有不成比例的影響: + +- **`temperature_init`**(`policy.temperature_init`)——SAC 中的初始熵溫度。較高的值鼓勵更多探索;較低的值使策略在早期更具確定性。一個好的起始點是 `1e-2`。我們觀察到設定過高會使人為介入無效並減慢學習速度。 +- **`policy_parameters_push_frequency`**(`policy.actor_learner_config.policy_parameters_push_frequency`)——從學習者向執行者推送兩次權重之間的間隔(以*秒*為單位)。預設值為 `4 s`。減少到 **1-2 s** 以提供更新鮮的權重(但會增加更多網路流量);僅在連線速度慢時才增加此值,因為這會降低樣本效率。 +- **`storage_device`**(`policy.storage_device`)——學習者保存策略參數的裝置。如果您有多餘的 GPU 記憶體,將其設為 `"cuda"`(而非預設的 `"cpu"`)。將權重保留在 GPU 上可以消除 CPU→GPU 傳輸的開銷,並能顯著增加每秒學習者更新的次數。 + +恭喜 🎉,您已完成本教程! + +> [!TIP] +> 如果您有任何問題或需要協助,請在 [Discord](https://discord.com/invite/s3KuuzsPFb) 上聯繫我們。 + +論文引用: + +``` +@article{luo2024precise, + title={Precise and Dexterous Robotic Manipulation via Human-in-the-Loop Reinforcement Learning}, + author={Luo, Jianlan and Xu, Charles and Wu, Jeffrey and Levine, Sergey}, + journal={arXiv preprint arXiv:2410.21845}, + year={2024} +} +``` diff --git a/docs/source/zh/hilserl_sim.mdx b/docs/source/zh/hilserl_sim.mdx new file mode 100644 index 0000000000..ada0e309d0 --- /dev/null +++ b/docs/source/zh/hilserl_sim.mdx @@ -0,0 +1,154 @@ +# 在模擬環境中訓練 RL + +本指南說明如何使用 gym_hil 模擬環境作為真實機器人的替代方案,搭配 LeRobot 框架進人在迴圈中(Human-In-the-Loop, HIL)的強化學習。 + +`gym_hil` 是一個提供 Gymnasium 相容模擬環境的套件,專為人在迴圈中的強化學習所設計。這些環境讓您可以: + +- 在模擬中訓練策略,以便在真實機器人上訓練之前測試 RL 堆疊 + +- 使用外部裝置(如遊戲手把或鍵盤)在模擬中收集示範資料 +- 在策略學習過程中執行人為介入 + +目前,主要環境是基於 MuJoCo 的 Franka Panda 機器人模擬,包含撿取方塊等任務。 + +## 安裝 + +先,在 LeRobot 環境中安裝 `gym_hil` 套件: + +```bash +pip install -e ".[hilserl]" +``` + +## 我需要什麼? + +- 一個遊戲手把或鍵盤來控制機器人 +- 一張 Nvidia GPU + +## 配置 + +若要搭配 LeRobot 使用 `gym_hil`,您需要建立一個配置檔案。範例請參考[此處](https://huggingface.co/datasets/lerobot/config_examples/resolve/main/rl/gym_hil/env_config.json)。主要配置片段包括: + +### 環境類型與任務 + +```json +{ + "env": { + "type": "gym_manipulator", + "name": "gym_hil", + "task": "PandaPickCubeGamepad-v0", + "fps": 10 + }, + "device": "cuda" +} +``` + +可用任務: + +- `PandaPickCubeBase-v0`:基礎環境 +- `PandaPickCubeGamepad-v0`:搭配遊戲手把控制 +- `PandaPickCubeKeyboard-v0`:搭配鍵盤控制 + +### 處理器配置 + +```json +{ + "env": { + "processor": { + "control_mode": "gamepad", + "gripper": { + "use_gripper": true, + "gripper_penalty": -0.02 + }, + "reset": { + "control_time_s": 15.0, + "fixed_reset_joint_positions": [ + 0.0, 0.195, 0.0, -2.43, 0.0, 2.62, 0.785 + ] + }, + "inverse_kinematics": { + "end_effector_step_sizes": { + "x": 0.025, + "y": 0.025, + "z": 0.025 + } + } + } + } +} +``` + +重要參數: + +- `gripper.gripper_penalty`:夾爪過度移動的懲罰值 +- `gripper.use_gripper`:是否啟用夾爪控制 +- `inverse_kinematics.end_effector_step_sizes`:末端執行器在 x、y、z 軸的步進大小 +- `control_mode`:設定為 `"gamepad"` 以使用遊戲手把控制器 + +## 搭配 LeRobot 的 HILRL 執行 + +### 基本用法 + +若要執行環境,將 mode 設為 null: + +```bash +python -m lerobot.rl.gym_manipulator --config_path path/to/gym_hil_env.json +``` + +### 錄製資料集 + +若要收集資料集,將 mode 設為 `record`,同時定義 repo_id 和要錄製的回合數: + +```json +{ + "env": { + "type": "gym_manipulator", + "name": "gym_hil", + "task": "PandaPickCubeGamepad-v0" + }, + "dataset": { + "repo_id": "username/sim_dataset", + "root": null, + "task": "pick_cube", + "num_episodes_to_record": 10, + "replay_episode": null, + "push_to_hub": true + }, + "mode": "record" +} +``` + +```bash +python -m lerobot.rl.gym_manipulator --config_path path/to/gym_hil_env.json +``` + +### 訓練策略 + +若要訓練策略,請參考[此處](https://huggingface.co/datasets/lerobot/config_examples/resolve/main/rl/gym_hil/train_config.json)提供的組態範例,然後跑執行者與學習者伺服器: + +```bash +python -m lerobot.rl.actor --config_path path/to/train_gym_hil_env.json +``` + +在另一個終端機中,執行學習者伺服器: + +```bash +python -m lerobot.rl.learner --config_path path/to/train_gym_hil_env.json +``` + +模擬環境提供了一個安全且可重複的方式,讓您在部署到真實機器人之前,開發和測試人在迴圈中的強化學習的各個元件。 + +恭喜 🎉,您已完成本教學! + +> [!TIP] +> 如果您有任何問題或需要協助,請透過 [Discord](https://discord.com/invite/s3KuuzsPFb) 與我們聯繫。 + +論文引用: + +``` +@article{luo2024precise, + title={Precise and Dexterous Robotic Manipulation via Human-in-the-Loop Reinforcement Learning}, + author={Luo, Jianlan and Xu, Charles and Wu, Jeffrey and Levine, Sergey}, + journal={arXiv preprint arXiv:2410.21845}, + year={2024} +} +``` diff --git a/docs/source/zh/il_robots.mdx b/docs/source/zh/il_robots.mdx new file mode 100644 index 0000000000..12b21296d4 --- /dev/null +++ b/docs/source/zh/il_robots.mdx @@ -0,0 +1,626 @@ +# 在真實世界機器人上進行模仿學習(Imitation Learning) + +本教學將說明如何訓練神經網路來自主控制真實的機器人。 + +**您將學到:** + +1. 如何錄製並視覺化您的資料集。 +2. 如何使用您的資料訓練策略,並準備進行評估。 +3. 如何評估您的策略並視覺化結果。 + +按照這些步驟,您將能夠複現各種任務,例如撿起一塊樂高積木並放入箱子中,並達到很高的成功率,如下方影片所示。 + +
+影片:撿起樂高積木任務 + +
+ +
+ +
+ +本教學不限定於特定機器人:我們會帶您了解可適用於任何支援平台的命令和 API 程式碼範例。 + +在資料收集過程中,您將使用「遙操作(teloperation)」裝置,例如領導臂或鍵盤來遠程操作機器人並記錄其運動軌跡。 + +一旦收集到足夠的軌跡,您將訓練一個神經網路來模仿這些軌跡(trajectories),並部署訓練好的模型,讓您的機器人能夠自主執行任務。 + +如果您在任何環節遇到問題,歡迎加入我們的 [Discord 社群](https://discord.com/invite/s3KuuzsPFb)尋求支援。 + +## 設定與校準 + +如果您尚未設定和校準您的機器人與遙操作裝置,請按照機器人專屬的教學進行操作。 + +## 遙操作(Teleoperate) + +在此範例中,我們將示範如何遙操作 SO101 機器人。每個命令都附有對應的 API 範例。 + +請注意,與機器人關聯的 `id` 用於儲存校準檔案。在遙操作、錄製和評估使用相同設定時,務必使用相同的 `id`。 + + + +```bash +lerobot-teleoperate \ + --robot.type=so101_follower \ + --robot.port=/dev/tty.usbmodem58760431541 \ + --robot.id=my_awesome_follower_arm \ + --teleop.type=so101_leader \ + --teleop.port=/dev/tty.usbmodem58760431551 \ + --teleop.id=my_awesome_leader_arm +``` + + + + +```python +from lerobot.teleoperators.so_leader import SO101LeaderConfig, SO101Leader +from lerobot.robots.so_follower import SO101FollowerConfig, SO101Follower + +robot_config = SO101FollowerConfig( + port="/dev/tty.usbmodem58760431541", + id="my_red_robot_arm", +) + +teleop_config = SO101LeaderConfig( + port="/dev/tty.usbmodem58760431551", + id="my_blue_leader_arm", +) + +robot = SO101Follower(robot_config) +teleop_device = SO101Leader(teleop_config) +robot.connect() +teleop_device.connect() + +while True: + action = teleop_device.get_action() + robot.send_action(action) +``` + + + + + +遙操作指令會自動: + +1. 識別任何缺少的校準,並啟動校準程序。 +2. 連接機器人和遙操作裝置,並開始遙操作。 + +## 攝影機 + +要將攝影機加入您的設定,請參照此[指南](./cameras#setup-cameras)。 + +## 搭配攝影機進行遙操作 + +使用 `rerun`,您可以在遙操作的同時視覺化攝影機畫面和關節位置。在此範例中,我們使用的是 Koch 手臂。 + + + +```bash +lerobot-teleoperate \ + --robot.type=koch_follower \ + --robot.port=/dev/tty.usbmodem58760431541 \ + --robot.id=my_awesome_follower_arm \ + --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 1920, height: 1080, fps: 30}}" \ + --teleop.type=koch_leader \ + --teleop.port=/dev/tty.usbmodem58760431551 \ + --teleop.id=my_awesome_leader_arm \ + --display_data=true +``` + + + + +```python +from lerobot.cameras.opencv.configuration_opencv import OpenCVCameraConfig +from lerobot.teleoperators.koch_leader import KochLeaderConfig, KochLeader +from lerobot.robots.koch_follower import KochFollowerConfig, KochFollower + +camera_config = { + "front": OpenCVCameraConfig(index_or_path=0, width=1920, height=1080, fps=30) +} + +robot_config = KochFollowerConfig( + port="/dev/tty.usbmodem585A0076841", + id="my_red_robot_arm", + cameras=camera_config +) + +teleop_config = KochLeaderConfig( + port="/dev/tty.usbmodem58760431551", + id="my_blue_leader_arm", +) + +robot = KochFollower(robot_config) +teleop_device = KochLeader(teleop_config) +robot.connect() +teleop_device.connect() + +while True: + observation = robot.get_observation() + action = teleop_device.get_action() + robot.send_action(action) +``` + + + + + +## 錄製資料集 + +熟悉遙操作後,您就可以錄製您的第一個資料集。 + +我們使用 Hugging Face Hub 功能來上傳您的資料集。如果您之前未使用過 Hub,請確保您可以使用具有寫入權限的 token 登入 CLI,此 token 可從 [Hugging Face 設定](https://huggingface.co/settings/tokens)頁面產生。 + +執行以下命令將您的 token 加入 CLI: + +```bash +hf auth login --token ${HUGGINGFACE_TOKEN} --add-to-git-credential +``` + +然後將您的 Hugging Face 儲存庫名稱存入變數: + +```bash +HF_USER=$(NO_COLOR=1 hf auth whoami | awk -F': *' 'NR==1 {print $2}') +echo $HF_USER +``` + +現在您可以錄製資料集了。要錄製 5 個回合(episodes)並將資料集上傳到 Hub,請根據您的機器人調整下方程式碼,然後執行命令或 API 範例。 + + + +```bash +lerobot-record \ + --robot.type=so101_follower \ + --robot.port=/dev/tty.usbmodem585A0076841 \ + --robot.id=my_awesome_follower_arm \ + --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 1920, height: 1080, fps: 30}}" \ + --teleop.type=so101_leader \ + --teleop.port=/dev/tty.usbmodem58760431551 \ + --teleop.id=my_awesome_leader_arm \ + --display_data=true \ + --dataset.repo_id=${HF_USER}/record-test \ + --dataset.num_episodes=5 \ + --dataset.single_task="Grab the black cube" \ + --dataset.streaming_encoding=true \ + # --dataset.vcodec=auto \ + --dataset.encoder_threads=2 +``` + + + + +```python +from lerobot.cameras.opencv.configuration_opencv import OpenCVCameraConfig +from lerobot.datasets.lerobot_dataset import LeRobotDataset +from lerobot.datasets.utils import hw_to_dataset_features +from lerobot.robots.so_follower import SO100Follower, SO100FollowerConfig +from lerobot.teleoperators.so_leader.config_so100_leader import SO100LeaderConfig +from lerobot.teleoperators.so_leader.so100_leader import SO100Leader +from lerobot.utils.control_utils import init_keyboard_listener +from lerobot.utils.utils import log_say +from lerobot.utils.visualization_utils import init_rerun +from lerobot.scripts.lerobot_record import record_loop +from lerobot.processor import make_default_processors + +NUM_EPISODES = 5 +FPS = 30 +EPISODE_TIME_SEC = 60 +RESET_TIME_SEC = 10 +TASK_DESCRIPTION = "My task description" + +# 建立機器人配置 +robot_config = SO100FollowerConfig( + id="my_awesome_follower_arm", + cameras={ + "front": OpenCVCameraConfig(index_or_path=0, width=640, height=480, fps=FPS) # 選用:fourcc="MJPG" 用於排除 OpenCV 非同步錯誤。 + }, + port="/dev/tty.usbmodem58760434471", +) + +teleop_config = SO100LeaderConfig( + id="my_awesome_leader_arm", + port="/dev/tty.usbmodem585A0077581", +) + +# 初始化機器人和遙操作器(teleoperator) +robot = SO100Follower(robot_config) +teleop = SO100Leader(teleop_config) + +# 設置資料集特徵 +action_features = hw_to_dataset_features(robot.action_features, "action") +obs_features = hw_to_dataset_features(robot.observation_features, "observation") +dataset_features = {**action_features, **obs_features} + +# 建立資料集 +dataset = LeRobotDataset.create( + repo_id="/", + fps=FPS, + features=dataset_features, + robot_type=robot.name, + use_videos=True, + image_writer_threads=4, +) + +# 初始化鍵盤監聽器和 rerun 視覺化 +_, events = init_keyboard_listener() +init_rerun(session_name="recording") + +# 連接機器人和遙操作器 +robot.connect() +teleop.connect() + +# 建立所需的處理器 +teleop_action_processor, robot_action_processor, robot_observation_processor = make_default_processors() + +episode_idx = 0 +while episode_idx < NUM_EPISODES and not events["stop_recording"]: + log_say(f"Recording episode {episode_idx + 1} of {NUM_EPISODES}") + + record_loop( + robot=robot, + events=events, + fps=FPS, + teleop_action_processor=teleop_action_processor, + robot_action_processor=robot_action_processor, + robot_observation_processor=robot_observation_processor, + teleop=teleop, + dataset=dataset, + control_time_s=EPISODE_TIME_SEC, + single_task=TASK_DESCRIPTION, + display_data=True, + ) + + # 如果不是停止錄製或重新錄製,則重置環境 + if not events["stop_recording"] and (episode_idx < NUM_EPISODES - 1 or events["rerecord_episode"]): + log_say("Reset the environment") + record_loop( + robot=robot, + events=events, + fps=FPS, + teleop_action_processor=teleop_action_processor, + robot_action_processor=robot_action_processor, + robot_observation_processor=robot_observation_processor, + teleop=teleop, + control_time_s=RESET_TIME_SEC, + single_task=TASK_DESCRIPTION, + display_data=True, + ) + + if events["rerecord_episode"]: + log_say("Re-recording episode") + events["rerecord_episode"] = False + events["exit_early"] = False + dataset.clear_episode_buffer() + continue + + dataset.save_episode() + episode_idx += 1 + +# 清除資源 +log_say("Stop recording") +robot.disconnect() +teleop.disconnect() +dataset.push_to_hub() +``` + + + + + +#### 資料集上傳 + +在本機端,您的資料集儲存在此資料夾中:`~/.cache/huggingface/lerobot/{repo-id}`。資料錄製結束後,您的資料集將被上傳到您的 Hugging Face 頁面(例如 `https://huggingface.co/datasets/${HF_USER}/so101_test`),您可以執行以下命令取得該連結: + +```bash +echo https://huggingface.co/datasets/${HF_USER}/so101_test +``` + +您的資料集會自動標記 `LeRobot` 標籤,方便社群輕鬆找到它,您也可以新增自訂標籤(例如此處加上 `tutorial`)。 + +您可以在 Hub 上搜尋 `LeRobot` [標籤](https://huggingface.co/datasets?other=LeRobot)來瀏覽其他 LeRobot 資料集。 + +您也可以手動將本機資料集推送到 Hub,執行: + +```bash +hf upload ${HF_USER}/record-test ~/.cache/huggingface/lerobot/{repo-id} --repo-type dataset +``` + +#### 錄製功能 + +`record` 功能提供了一套工具,用於在機器人操作期間擷取和管理資料: + +##### 1. 資料儲存 + +- 資料使用 `LeRobotDataset` 格式儲存,並在錄製期間存入磁碟。 +- 預設情況下,資料集會在錄製完成後推送到您的 Hugging Face 頁面。 + - 若要停用上傳功能,請使用 `--dataset.push_to_hub=False`。 + +##### 2. Checkpointing 與 Resuming + +- 錄製過程中會自動建立 checkpoints。 +- 如果發生問題,您可以使用 `--resume=true` 重新執行相同命令來續錄。續錄時,`--dataset.num_episodes` 必須設定為**額外要錄製的回合數**,而不是資料集中的目標總回合數! +- 若要從頭開始錄製,請**手動刪除**資料集目錄。 + +##### 3. 錄製參數 + +使用命令列參數設定資料錄製的流程: + +- `--dataset.episode_time_s=60` + 每次資料錄製回合的持續時間(預設:**60 秒**)。 +- `--dataset.reset_time_s=60` + 每個回合結束後重設環境的持續時間(預設:**60 秒**)。 +- `--dataset.num_episodes=50` + 要錄製的總回合數(預設:**50**)。 + +##### 4. 錄製期間的鍵盤控制 + +使用鍵盤快捷鍵控制資料錄製流程: + +- 按下**右方向鍵(`→`)**:提前結束目前的回合或重設時間,並進入下一個。 +- 按下**左方向鍵(`←`)**:取消目前的回合並重新錄製。 +- 按下 **Escape(`ESC`)**:立即停止錄製階段,編碼影片並上傳資料集。 + +#### 收集資料的技巧 + +熟悉資料錄製後,您可以建立更大的資料集進行訓練。一個好的入門任務是在不同位置抓取物體並放入箱中。我們建議至少錄製 50 個回合,每個位置 10 個回合。保持攝影機固定,並在整個錄製過程中維持一致的抓取行為。同時確保您操作的物體在攝影機畫面中可見。一個好的經驗法則是,您應該能夠僅透過觀看攝影機影像就能自行完成任務。 + +在接下來的章節中,您將訓練您的神經網路。在達到可靠的抓取效能後,您可以開始在資料收集中引入更多變化,例如增加抓取位置、不同的抓取技巧,以及改變攝影機位置。 + +避免太快引入過多變化,因為這可能會影響您的結果。 + +如果您想深入了解這個重要主題,可以參閱我們撰寫的關於什麼是好的資料集的[部落格文章](https://huggingface.co/blog/lerobot-datasets#what-makes-a-good-dataset)。 + +#### 疑難排解: + +- 在 Linux 上,如果左右方向鍵和 Escape 鍵在資料錄製期間沒有任何效果,請確認您已設定 `$DISPLAY` 環境變數。請參閱 [pynput](https://pynput.readthedocs.io/en/latest/limitations.html#linux) 限制。 + +## 視覺化資料集 + +若您已使用 `--control.push_to_hub=true` 將資料集上傳至 Hub,可透過複製貼上下方指令所提供的儲存庫 ID,於[線上工具中視覺化您的資料集](https://huggingface.co/spaces/lerobot/visualize_dataset): + +```bash +echo ${HF_USER}/so101_test +``` + +## 回合重播 + +一個實用的功能是 `replay` 函式,它允許您重播任何已錄製的回合或任何現有資料集中的回合。此功能可幫助您測試機器人動作的可重複性,並評估在相同型號機器人之間的可遷移性。 + +您可以使用以下命令或 API 範例在機器人上重播第一個回合: + + + +```bash +lerobot-replay \ + --robot.type=so101_follower \ + --robot.port=/dev/tty.usbmodem58760431541 \ + --robot.id=my_awesome_follower_arm \ + --dataset.repo_id=${HF_USER}/record-test \ + --dataset.episode=0 # 選擇您想要重播的回合 +``` + + + + +```python +import time + +from lerobot.datasets.lerobot_dataset import LeRobotDataset +from lerobot.robots.so_follower.config_so100_follower import SO100FollowerConfig +from lerobot.robots.so_follower.so100_follower import SO100Follower +from lerobot.utils.robot_utils import precise_sleep +from lerobot.utils.utils import log_say + +episode_idx = 0 + +robot_config = SO100FollowerConfig(port="/dev/tty.usbmodem58760434471", id="my_awesome_follower_arm") + +robot = SO100Follower(robot_config) +robot.connect() + +dataset = LeRobotDataset("/", episodes=[episode_idx]) +actions = dataset.select_columns("action") + +log_say(f"Replaying episode {episode_idx}") +for idx in range(dataset.num_frames): + t0 = time.perf_counter() + + action = { + name: float(actions[idx]["action"][i]) for i, name in enumerate(dataset.features["action"]["names"]) + } + robot.send_action(action) + + precise_sleep(max(1.0 / dataset.fps - (time.perf_counter() - t0), 0.0)) + +robot.disconnect() +``` + + + + + +您的機器人應該會複現與您錄製時類似的動作。例如,觀看[這段影片](https://x.com/RemiCadene/status/1793654950905680090),我們在 [Trossen Robotics](https://www.trossenrobotics.com) 的 Aloha 機器人上使用了 `replay`。 + +## 訓練策略 + +要訓練一個策略來控制您的機器人,請使用 [`lerobot-train`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/scripts/lerobot_train.py) 腳本。需要幾個必要參數。以下是一個範例命令: + +```bash +lerobot-train \ + --dataset.repo_id=${HF_USER}/so101_test \ + --policy.type=act \ + --output_dir=outputs/train/act_so101_test \ + --job_name=act_so101_test \ + --policy.device=cuda \ + --wandb.enable=true \ + --policy.repo_id=${HF_USER}/my_policy +``` + +讓我們說明這個指令: + +1. 我們透過 `--dataset.repo_id=${HF_USER}/so101_test` 提供了資料集作為參數。 +2. 我們透過 `policy.type=act` 提供了策略。這會從 [`configuration_act.py`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/policies/act/configuration_act.py) 載入設定。重要的是,此策略會自動適配您機器人的馬達狀態數、馬達動作數和攝影機(例如 `laptop` 和 `phone`),這些資訊已儲存在您的資料集中。 +3. 我們提供了 `policy.device=cuda`,因為我們在 Nvidia GPU 上訓練,但您可以使用 `policy.device=mps` 在 Apple 晶片上訓練。 +4. 我們提供了 `wandb.enable=true` 以使用 [Weights and Biases](https://docs.wandb.ai/quickstart) 來視覺化訓練圖表。這是選用的,但如果您要使用,請確保已執行 `wandb login` 完成登入。 + +訓練應需要數小時。您會在 `outputs/train/act_so101_test/checkpoints` 中找到檢查點。 + +要從 checkpoint 繼續訓練,以下是從 `act_so101_test` 策略的 `last` checkpoint 繼續的範例命令: + +```bash +lerobot-train \ + --config_path=outputs/train/act_so101_test/checkpoints/last/pretrained_model/train_config.json \ + --resume=true +``` + +如果您不想在訓練後將模型推送到 Hub,請使用 `--policy.push_to_hub=false`。 + +此外,您可以為模型提供額外的 `tags` 或指定 `license`,或透過新增以下參數將模型儲存庫設為 `private`:`--policy.private=true --policy.tags=\[ppo,rl\] --policy.license=mit` + +#### 使用 Google Colab 訓練 + +如果您的本機電腦沒有強大的 GPU,您可以透過 [ACT 訓練筆記本](./notebooks#training-act)利用 Google Colab 來訓練模型。 + +#### 上傳策略的 checkpoints + +訓練完成後,使用以下命令上傳最新的 checkpoint: + +```bash +hf upload ${HF_USER}/act_so101_test \ + outputs/train/act_so101_test/checkpoints/last/pretrained_model +``` + +您也可以上傳中間 checkpoints: + +```bash +CKPT=010000 +hf upload ${HF_USER}/act_so101_test${CKPT} \ + outputs/train/act_so101_test/checkpoints/${CKPT}/pretrained_model +``` + +## 執行推論並評估您的策略 + +您可以使用 [`lerobot-record`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/scripts/lerobot_record.py) 的 `record` 腳本,並輸入策略的 checkpoint,來執行推論並評估您的策略。例如,執行此命令或 API 範例來執行推論並錄製 10 個評估回合: + + + +```bash +lerobot-record \ + --robot.type=so100_follower \ + --robot.port=/dev/ttyACM1 \ + --robot.cameras="{ up: {type: opencv, index_or_path: /dev/video10, width: 640, height: 480, fps: 30}, side: {type: intelrealsense, serial_number_or_name: 233522074606, width: 640, height: 480, fps: 30}}" \ + --robot.id=my_awesome_follower_arm \ + --display_data=false \ + --dataset.repo_id=${HF_USER}/eval_so100 \ + --dataset.single_task="Put lego brick into the transparent box" \ + --dataset.streaming_encoding=true \ + --dataset.encoder_threads=2 \ + # --dataset.vcodec=auto \ + # <- 如果您想在情節之間進行遙操作,Teleop 為選用 \ + # --teleop.type=so100_leader \ + # --teleop.port=/dev/ttyACM0 \ + # --teleop.id=my_awesome_leader_arm \ + --policy.path=${HF_USER}/my_policy +``` + + + + +```python +from lerobot.cameras.opencv.configuration_opencv import OpenCVCameraConfig +from lerobot.datasets.lerobot_dataset import LeRobotDataset +from lerobot.datasets.utils import hw_to_dataset_features +from lerobot.policies.act.modeling_act import ACTPolicy +from lerobot.policies.factory import make_pre_post_processors +from lerobot.robots.so_follower.config_so100_follower import SO100FollowerConfig +from lerobot.robots.so_follower.so100_follower import SO100Follower +from lerobot.scripts.lerobot_record import record_loop +from lerobot.utils.control_utils import init_keyboard_listener +from lerobot.utils.utils import log_say +from lerobot.utils.visualization_utils import init_rerun + + +NUM_EPISODES = 5 +FPS = 30 +EPISODE_TIME_SEC = 60 +TASK_DESCRIPTION = "My task description" +HF_MODEL_ID = "/" +HF_DATASET_ID = "/" + +# 建立機器人配置 +camera_config = {"front": OpenCVCameraConfig(index_or_path=0, width=640, height=480, fps=FPS)} +robot_config = SO100FollowerConfig( + port="/dev/tty.usbmodem58760434471", id="my_awesome_follower_arm", cameras=camera_config +) + +# 初始化機器人 +robot = SO100Follower(robot_config) + +# 初始化策略 +policy = ACTPolicy.from_pretrained(HF_MODEL_ID) + +# 設置資料集特徵 +action_features = hw_to_dataset_features(robot.action_features, "action") +obs_features = hw_to_dataset_features(robot.observation_features, "observation") +dataset_features = {**action_features, **obs_features} + +# 建立資料集 +dataset = LeRobotDataset.create( + repo_id=HF_DATASET_ID, + fps=FPS, + features=dataset_features, + robot_type=robot.name, + use_videos=True, + image_writer_threads=4, +) + +# 初始化鍵盤監聽器和 rerun 視覺化 +_, events = init_keyboard_listener() +init_rerun(session_name="recording") + +# 連接機器人 +robot.connect() + +preprocessor, postprocessor = make_pre_post_processors( + policy_cfg=policy, + pretrained_path=HF_MODEL_ID, + dataset_stats=dataset.meta.stats, +) + +for episode_idx in range(NUM_EPISODES): + log_say(f"Running inference, recording eval episode {episode_idx + 1} of {NUM_EPISODES}") + + # 執行策略推論迴圈 + record_loop( + robot=robot, + events=events, + fps=FPS, + policy=policy, + preprocessor=preprocessor, + postprocessor=postprocessor, + dataset=dataset, + control_time_s=EPISODE_TIME_SEC, + single_task=TASK_DESCRIPTION, + display_data=True, + ) + + dataset.save_episode() + +# 清理資源 +robot.disconnect() +dataset.push_to_hub() +``` + + + + + +如您所見,這與之前用來錄製訓練資料集的命令幾乎相同。有兩處變更: + +1. 新增了 `--control.policy.path` 參數,用於指定您的策略檢查點路徑(例如 `outputs/train/eval_act_so101_test/checkpoints/last/pretrained_model`)。如果您已將模型檢查點上傳到 Hub,也可以使用模型儲存庫(例如 `${HF_USER}/act_so101_test`)。 +2. 資料集名稱以 `eval` 開頭,以表示您正在執行推論(例如 `${HF_USER}/eval_act_so101_test`)。 diff --git a/docs/source/zh/integrate_hardware.mdx b/docs/source/zh/integrate_hardware.mdx new file mode 100644 index 0000000000..3ec60da4d3 --- /dev/null +++ b/docs/source/zh/integrate_hardware.mdx @@ -0,0 +1,476 @@ +# 自備硬體 + +本教學將說明如何將你自己的機器人設計整合到 LeRobot 生態系統中,並使其能存取我們所有的工具(資料收集、控制管線、策略訓練與推論)。 + +為此,我們在 LeRobot 中提供了 [`Robot`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/robots/robot.py) 基底類別,它定義了實體機器人整合的標準介面。讓我們來看看如何實作它。 + +## 先決條件 + +- 您的機器人並具備暴露的通訊介面(例如序列埠、CAN、TCP) +- 能以程式化方式讀取感測器資料並傳送馬達指令的方式,例如製造商提供的 SDK 或 API,或是您自行實作的通訊協定。 +- 已在您的環境中安裝 LeRobot。請依照我們的[安裝指南](./installation)進行。 + +## 選擇你的馬達 + +如果你使用的是 Feetech 或 Dynamixel 馬達,LeRobot 提供了內建的匯流排介面: + +- [`FeetechMotorsBus`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/motors/feetech/feetech.py) – 用於控制 Feetech 的伺服馬達 +- [`DynamixelMotorsBus`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/motors/dynamixel/dynamixel.py) – 用於控制 Dynamixel 的伺服馬達 + +請參考 [`MotorsBus`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/motors/motors_bus.py) 抽象類來了解其 API。 +要看一個好的使用範例,你可以參考我們自己的 [SO101 從臂實作](https://github.com/huggingface/lerobot/blob/main/src/lerobot/robots/so_follower/so101_follower/so101_follower.py) + +如果相容的話請使用這些介面。否則,你需要找到或撰寫一個 Python 介面(本教學不涵蓋此內容): + +- 找到現有的 Python SDK(或使用 C/C++ 的綁定) +- 或實作一個基本的通訊包裝器(例如透過 pyserial、socket 或 CANopen) + +你並不孤單——許多社群貢獻使用了自訂的開發板或韌體! + +對於 Feetech 和 Dynamixel,我們目前支援以下伺服馬達:- Feetech:- STS 與 SMS 系列(協定 0):`sts3215`、`sts3250`、`sm8512bl` - SCS 系列(協定 1):`scs0009` - Dynamixel(僅協定 2.0):`xl330-m077`、`xl330-m288`、`xl430-w250`、`xm430-w350`、`xm540-w270`、`xc430-w150` + +如果你使用的 Feetech 或 Dynamixel 伺服馬達不在此列表中,你可以在 [Feetech 表格](https://github.com/huggingface/lerobot/blob/main/src/lerobot/motors/feetech/tables.py)或 [Dynamixel 表格](https://github.com/huggingface/lerobot/blob/main/src/lerobot/motors/dynamixel/tables.py)中新增。根據型號不同,這需要你添加型號特定的資訊。不過在大多數情況下,需要添加的內容不會太多。 + +在接下來的章節中,我們將使用 `FeetechMotorsBus` 作為範例中的馬達介面。如有需要,請替換並適配你的馬達。 + +## 步驟 1: 建立 `Robot` 類的子類別 + +你首先需要為你的機器人指定其配置類和一個字串識別碼(`name`)。如果你的機器人有特殊需求且你希望能輕鬆變更,那些應該放在這裡(例如連接埠/位址、鮑率)。 + +在這裡,我們將為我們的機器人新增連接埠名稱和一個預設攝影機: + + +```python +from dataclasses import dataclass, field + +from lerobot.cameras import CameraConfig +from lerobot.cameras.opencv import OpenCVCameraConfig +from lerobot.robots import RobotConfig + + +@RobotConfig.register_subclass("my_cool_robot") +@dataclass +class MyCoolRobotConfig(RobotConfig): + port: str + cameras: dict[str, CameraConfig] = field( + default_factory={ + "cam_1": OpenCVCameraConfig( + index_or_path=2, + fps=30, + width=480, + height=640, + ), + } + ) +``` + + +[攝影機教學](./cameras)以了解如何偵測並新增您的攝影機。 + +接下來,我們將建立繼承自 `Robot` 的實際機器人類。這個抽象類別定義了一個規範,你的機器人必須遵循它才能與 LeRobot 的其餘工具配合使用。 + +在這裡我們將建立一個帶有一個攝影機的簡單 5 自由度機器人。它可以是一個簡單的機械臂,但請注意 `Robot` 抽象類不對你的機器人形態做任何假設。設計新機器人時你可以盡情發揮想像力! + + +```python +from lerobot.cameras import make_cameras_from_configs +from lerobot.motors import Motor, MotorNormMode +from lerobot.motors.feetech import FeetechMotorsBus +from lerobot.robots import Robot + +class MyCoolRobot(Robot): + config_class = MyCoolRobotConfig + name = "my_cool_robot" + + def __init__(self, config: MyCoolRobotConfig): + super().__init__(config) + self.bus = FeetechMotorsBus( + port=self.config.port, + motors={ + "joint_1": Motor(1, "sts3250", MotorNormMode.RANGE_M100_100), + "joint_2": Motor(2, "sts3215", MotorNormMode.RANGE_M100_100), + "joint_3": Motor(3, "sts3215", MotorNormMode.RANGE_M100_100), + "joint_4": Motor(4, "sts3215", MotorNormMode.RANGE_M100_100), + "joint_5": Motor(5, "sts3215", MotorNormMode.RANGE_M100_100), + }, + calibration=self.calibration, + ) + self.cameras = make_cameras_from_configs(config.cameras) +``` + + +## 步驟 2:定義觀測與動作特徵 + +這兩個屬性定義了你的機器人與使用它的工具(如資料收集或學習管線)之間的*介面規格*。 + +> [!WARNING] +> 請注意,這些屬性必須在機器人尚未連線的情況下也能呼叫,因此避免依賴執行時的硬體狀態來定義它們。 + +### `observation_features` + +此屬性應返回一個字典,描述機器人感測器輸出的結構。鍵值對應 `get_observation()` 返回的內容,值則描述形狀(用於陣列/影像)或型別(用於簡單數值)。 + +我們的 5 自由度手臂搭配一個攝影機的範例: + + +```python +@property +def _motors_ft(self) -> dict[str, type]: + return { + "joint_1.pos": float, + "joint_2.pos": float, + "joint_3.pos": float, + "joint_4.pos": float, + "joint_5.pos": float, + } + +@property +def _cameras_ft(self) -> dict[str, tuple]: + return { + cam: (self.cameras[cam].height, self.cameras[cam].width, 3) for cam in self.cameras + } + +@property +def observation_features(self) -> dict: + return {**self._motors_ft, **self._cameras_ft} +``` + + +在這個案例中,觀測為一個儲存每個馬達的位置和一張攝影機影像的簡單字典。 + +### `action_features` + +此屬性描述你的機器人透過 send_action() 期望接收的指令。同樣,鍵值必須符合預期的輸入格式,值則定義每個指令的形狀型別。 + +這裡,我們簡單地使用與 `observation_features` 相同的關節本體感覺特徵(`self._motors_ft`):發送的動作就是每個馬達的目標位置。 + + +```python +def action_features(self) -> dict: + return self._motors_ft +``` + + +## 步驟 3:處理連線與斷線 + +這些方法應處理與你的硬體(例如序列埠、CAN 介面、USB 裝置、攝影機)的通訊開啟與關閉。 + +### `is_connected` + +此屬性應簡單地反映是否已與機器人硬體建立通訊。當此屬性為 `True` 時,應該能夠使用 `get_observation()` 和 `send_action()` 對硬體進行讀寫。 + + +```python +@property +def is_connected(self) -> bool: + return self.bus.is_connected and all(cam.is_connected for cam in self.cameras.values()) +``` + + +### `connect()` + +此方法應建立與硬體的通訊。此外,如果你的機器人需要校準且尚未校準,預設應啟動校準程序。如果你的機器人需要特定的配置設定,也應在此呼叫。 + + +```python +def connect(self, calibrate: bool = True) -> None: + self.bus.connect() + if not self.is_calibrated and calibrate: + self.calibrate() + + for cam in self.cameras.values(): + cam.connect() + + self.configure() +``` + + +### `disconnect()` + +此方法應優雅地終止與硬體的通訊:釋放任何相關資源(執行緒或程序)、關閉連接埠等。 + +在這裡,我們已經在 `MotorsBus` 和 `Camera` 類別中處理了這些,所以只需要呼叫它們自己的 `disconnect()` 方法: + + +```python +def disconnect(self) -> None: + self.bus.disconnect() + for cam in self.cameras.values(): + cam.disconnect() +``` + + +## 步驟 4:支援校準與配置設定 + +LeRobot 支援自動儲存和載入校準資料。這對於關節偏移量、零位位置或感測器對齊非常有用。 + +> 請注意,根據你的硬體不同,這可能不適用。如果是這種情況,你可以簡單地將這些方法留為空操作: + + +```python +@property +def is_calibrated(self) -> bool: + return True + +def calibrate(self) -> None: + pass +``` + + +### `is_calibrated` + +這應反映你的機器人是否已載入所需的校準資料。 + + +```python +@property +def is_calibrated(self) -> bool: + return self.bus.is_calibrated +``` + + +### `calibrate()` + +校準的目標有兩個: + +- 了解每個馬達的物理運動範圍,以便僅在此範圍內發送指令。 +- 將原始馬達位置正規化為有意義的連續值(例如百分比、角度),而非取決於特定馬達的任意離散值,這些值在其他地方無法複製。 + +它應實作校準的邏輯(如果適用)並更新 `self.calibration` 字典。如果你使用的是 Feetech 或 Dynamixel 馬達,我們的匯流排介面已包含協助此操作的方法。 + + +```python +def calibrate(self) -> None: + self.bus.disable_torque() + for motor in self.bus.motors: + self.bus.write("Operating_Mode", motor, OperatingMode.POSITION.value) + + input(f"Move {self} to the middle of its range of motion and press ENTER....") + homing_offsets = self.bus.set_half_turn_homings() + + print( + "Move all joints sequentially through their entire ranges " + "of motion.\nRecording positions. Press ENTER to stop..." + ) + range_mins, range_maxes = self.bus.record_ranges_of_motion() + + self.calibration = {} + for motor, m in self.bus.motors.items(): + self.calibration[motor] = MotorCalibration( + id=m.id, + drive_mode=0, + homing_offset=homing_offsets[motor], + range_min=range_mins[motor], + range_max=range_maxes[motor], + ) + + self.bus.write_calibration(self.calibration) + self._save_calibration() + print("Calibration saved to", self.calibration_fpath) +``` + + +### `configure()` + +使用此方法為你的硬體設定任何配置(伺服馬達控制模式、控制器增益等)。這通常應在連線時執行且具有冪等性。 + + +```python +def configure(self) -> None: + with self.bus.torque_disabled(): + self.bus.configure_motors() + for motor in self.bus.motors: + self.bus.write("Operating_Mode", motor, OperatingMode.POSITION.value) + self.bus.write("P_Coefficient", motor, 16) + self.bus.write("I_Coefficient", motor, 0) + self.bus.write("D_Coefficient", motor, 32) +``` + + +## 步驟 5:實作感測器讀取與動作發送 + +這些是最重要的執行時函數(runtime functions):核心 I/O 迴圈。 + +### `get_observation()` + +從機器人返回一個感測器數值的字典。這些通常包括馬達狀態、攝影機畫面、各種感測器等。在 LeRobot 框架中,這些觀測將被饋送給策略以預測要採取的動作。字典的鍵和結構必須與 `observation_features` 相符。 + + +```python +def get_observation(self) -> dict[str, Any]: + if not self.is_connected: + raise ConnectionError(f"{self} is not connected.") + + # Read arm position + obs_dict = self.bus.sync_read("Present_Position") + obs_dict = {f"{motor}.pos": val for motor, val in obs_dict.items()} + + # Capture images from cameras + for cam_key, cam in self.cameras.items(): + obs_dict[cam_key] = cam.async_read() + + return obs_dict +``` + + +### `send_action()` + +接收一個與 `action_features` 相符的字典,並將其發送到你的硬體。你可以加入安全限制(截斷、平滑),並返回實際發送的內容。 + +為了簡化,在我們的範例中不會對動作做任何修改。 + + +```python +def send_action(self, action: dict[str, Any]) -> dict[str, Any]: + goal_pos = {key.removesuffix(".pos"): val for key, val in action.items()} + + # Send goal position to the arm + self.bus.sync_write("Goal_Position", goal_pos) + + return action +``` + + +## 新增遙操作器 + +對於實作遙操作裝置,我們也提供了 [`Teleoperator`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/teleoperators/teleoperator.py) 基底類。此類別與 `Robot` 基底類非常相似,同樣不對外形因素做任何假設。 + +主要差異在於 I/O 函式:遙操作器允許你透過 `get_action` 產生動作,並可以透過 `send_feedback` 接收回饋動作。回饋可以是遙操作裝置上任何可控制的東西,幫助操控者理解所發送動作的後果。例如主臂上的運動/力回饋、遊戲手把控制器上的振動等。要實作遙操作器,你可以遵循本教學並針對這兩個方法進行調整。 + +## 使用你自己的 `LeRobot` 裝置 🔌 + +你可以透過建立一個獨立的、可安裝的 Python 套件,輕鬆地以你的自訂硬體擴展 `lerobot`——無論是攝影機、機器人還是遙操作裝置。只要你遵循一些簡單的慣例,`lerobot` 的命令列工具(如 `lerobot-teleop` 和 `lerobot-record`)將**自動發現並整合你的裝置**,而無需對 `lerobot` 原始碼做任何修改。 + +本指南概述了你的外掛必須遵循的慣例。 + +### 4 項核心慣例 + +為確保你的自訂裝置可被發現,你必須遵循以下四條規則。 + +#### 1\. 建立具有特定前綴的可安裝套件 + +Your project must be a standard, installable Python package. Crucially, the name of your package (as defined in `pyproject.toml` or `setup.py`) must begin with one of these prefixes: + +- `lerobot_robot_` 用於機器人。 +- `lerobot_camera_` 用於攝影機。 +- `lerobot_teleoperator_` 用於遙操作裝置。 + +這個前綴系統是 `lerobot` 在 Python 環境中自動找到你的外掛的方式。 + +#### 2\. 遵循 `SomethingConfig`/`Something` 的命名模式 + +你的裝置實作類必須以其設定類命名,只需移除 `Config` 後綴。 + +- **設定類:** `MyAwesomeTeleopConfig` +- **裝置類:** `MyAwesomeTeleop` + +#### 3\. 將你的檔案放在可預測的結構中 + +裝置類(`MyAwesomeTeleop`)必須位於相對於其配置類(`MyAwesomeTeleopConfig`)的可預測模組中。`lerobot` 將自動在以下位置搜尋: + +- 與設定類別**相同的模組**中。 +- 在一個**以裝置命名的子模組**中(例如 `my_awesome_teleop.py`)。 + +建議且最簡單的結構是將它們放在同一目錄中清楚命名的獨立檔案中。 + +#### 4\. 在 `__init__.py` 中暴露類 + +你的套件的 `__init__.py` 檔案應導入並暴露設定類別和裝置類,使它們容易被存取。 + +### 全部串起來:完整範例 + +讓我們建立一個名為 `my_awesome_teleop` 的新遙操作器。 + +#### 目錄結構 + +以下是專案資料夾的結構。套件名稱 `lerobot_teleoperator_my_awesome_teleop` 遵循**慣例 #1**。 + +``` +lerobot_teleoperator_my_awesome_teleop/ +├── pyproject.toml #(或 setup.py)列出 lerobot 作為依賴 +└── lerobot_teleoperator_my_awesome_teleop/ + ├── __init__.py + ├── config_my_awesome_teleop.py + └── my_awesome_teleop.py +``` + +#### 檔案內容 + +- **`config_my_awesome_teleop.py`**:定義配置類。注意 `Config` 後綴(**慣例 #2**)。 + + ```python + from dataclasses import dataclass + + from lerobot.teleoperators.config import TeleoperatorConfig + + @TeleoperatorConfig.register_subclass("my_awesome_teleop") + @dataclass + class MyAwesomeTeleopConfig(TeleoperatorConfig): + # 你的配置放在這裡 + port: str = "192.168.1.1" + ``` + +- **`my_awesome_teleop.py`**:實作裝置。類名稱 `MyAwesomeTeleop` 與其配置類的別名稱相符(**慣例 #2**)。此檔案結構遵循**慣例 #3**。 + + ```python + from lerobot.teleoperators.teleoperator import Teleoperator + + from .config_my_awesome_teleop import MyAwesomeTeleopConfig + + class MyAwesomeTeleop(Teleoperator): + config_class = MyAwesomeTeleopConfig + name = "my_awesome_teleop" + + def __init__(self, config: MyAwesomeTeleopConfig): + super().__init__(config) + self.config = config + + # 你的裝置邏輯(例如 connect)放在這裡 + ``` + +- **`__init__.py`**:暴露關鍵類別(**慣例 #4**)。 + + ```python + from .config_my_awesome_teleop import MyAwesomeTeleopConfig + from .my_awesome_teleop import MyAwesomeTeleop + ``` + +### 安裝與使用 + +1. **在你的 Python 環境中安裝你的新外掛程式。** 你可以使用 `pip` 的可編輯模式或從 PyPi 安裝你的本地外掛程式套件。 + + ```bash + # 本地安裝 + # 導航到你的外掛程式根目錄並安裝 + cd lerobot_teleoperator_my_awesome_teleop + pip install -e . + + # 從 PyPi 安裝 + pip install lerobot_teleoperator_my_awesome_teleop + ``` + +2. **直接從命令列使用它。** 現在,你可以透過引用其類型來使用你的自訂裝置。 + + ```bash + lerobot-teleoperate --teleop.type=my_awesome_teleop \ + # 其他參數 + ``` + +就是這樣!你的自訂裝置現在已完全整合。 + +### 尋找範例? + +Check out these two packages from the community: + +- https://github.com/SpesRobotics/lerobot-robot-xarm +- https://github.com/SpesRobotics/lerobot-teleoperator-teleop + +## 總結 + +一旦你的機器人類完成,你就可以利用 LeRobot 生態系統: + +- 使用可用的遙操作器控制你的機器人,或直接整合你的遙操作裝置 +- 記錄訓練資料並視覺化 +- 將其整合到強化學習或模仿學習管線中 + +不要猶豫,在我們的 [Discord](https://discord.gg/s3KuuzsPFb) 上向社群尋求幫助 🤗 diff --git a/docs/source/zh/multi_gpu_training.mdx b/docs/source/zh/multi_gpu_training.mdx new file mode 100644 index 0000000000..c84ba88003 --- /dev/null +++ b/docs/source/zh/multi_gpu_training.mdx @@ -0,0 +1,125 @@ +# 多 GPU 訓練 + +本指南說明如何使用 [Hugging Face Accelerate](https://huggingface.co/docs/accelerate) 在多個 GPU 上訓練策略。 + +## 安裝 + +首先,請確保已安裝 accelerate: + +```bash +pip install accelerate +``` + +## 使用多 GPU 進行訓練 + +您可以透過兩種方式啟動訓練: + +### 選項 1:不使用配置檔案(直接指定參數) + +您可以在命令中直接指定所有參數,無需執行 `accelerate config`: + +```bash +accelerate launch \ + --multi_gpu \ + --num_processes=2 \ + $(which lerobot-train) \ + --dataset.repo_id=${HF_USER}/my_dataset \ + --policy.type=act \ + --policy.repo_id=${HF_USER}/my_trained_policy \ + --output_dir=outputs/train/act_multi_gpu \ + --job_name=act_multi_gpu \ + --wandb.enable=true +``` + +**主要的 accelerate 參數:** + +- `--multi_gpu`:啟用多 GPU 訓練 +- `--num_processes=2`:要使用的 GPU 數量 +- `--mixed_precision=fp16`:使用 fp16 混合精度(若支援也可使用 `bf16`) + +### 選項 2:使用 accelerate config + +如果您偏好將設置儲存,可以選擇性地透過以下命令為您的硬體環境配置 accelerate: + +```bash +accelerate config +``` + +此互動式設定會詢問您關於訓練環境的問題(GPU 數量、混合精度設定等),並儲存設定供日後使用。對於在單台機器上進行簡單的多 GPU 設定,您可以使用以下建議設定: + +- 運算環境:This machine +- 機器數量:1 +- 處理程序數量:(您想使用的 GPU 數量) +- 要使用的 GPU ID:(留空以使用全部) +- 混合精度:fp16 或 bf16(建議使用以加速訓練) + +然後使用以下命令啟動訓練: + +```bash +accelerate launch $(which lerobot-train) \ + --dataset.repo_id=${HF_USER}/my_dataset \ + --policy.type=act \ + --policy.repo_id=${HF_USER}/my_trained_policy \ + --output_dir=outputs/train/act_multi_gpu \ + --job_name=act_multi_gpu \ + --wandb.enable=true +``` + +## 運作原理 + +當您使用 accelerate 啟動訓練時: + +1. **自動偵測**:LeRobot 會自動偵測是否在 accelerate 環境下執行 +2. **資料分配**:您的批次會自動分配到各個 GPU +3. **梯度同步**:在反向傳播過程中,梯度會在各 GPU 之間同步 +4. **單一處理程序記錄**:僅由主處理程序記錄到 wandb 並儲存檢查點 + +## 學習率與訓練步數縮放 + +**重要:** LeRobot **不會**根據 GPU 數量自動縮放學習率或訓練步數。這讓您能完全掌控訓練的超參數。 + +### 為什麼不自動縮放? + +許多分散式訓練框架會根據 GPU 數量自動縮放學習率(例如 `lr = base_lr × num_gpus`)。 +然而,LeRobot 會完全按照您指定的學習率執行。 + +### 何時及如何縮放 + +如果您希望在使用多 GPU 時縮放超參數,應手動進行: + +**學習率縮放:** + +```bash +# 範例:2 個 GPU 搭配線性學習率縮放 +# 基礎學習率:1e-4,使用 2 個 GPU -> 2e-4 +accelerate launch --num_processes=2 $(which lerobot-train) \ + --optimizer.lr=2e-4 \ + --dataset.repo_id=lerobot/pusht \ + --policy=act +``` + +**訓練步數縮放:** + +由於有效批次大小 `bs` 會隨多 GPU 增加(batch_size × num_gpus),您可能希望按比例減少訓練步數: + +```bash +# 範例:2 個 GPU,有效批次大小為 2 倍 +# 原始設定:batch_size=8, steps=100000 +# 使用 2 個 GPU:batch_size=8(總計 16),steps=50000 +accelerate launch --num_processes=2 $(which lerobot-train) \ + --batch_size=8 \ + --steps=50000 \ + --dataset.repo_id=lerobot/pusht \ + --policy=act +``` + +## 注意事項 + +- `lerobot-train` 中的 `--policy.use_amp` 旗標僅在**未**使用 accelerate 時有效。使用 accelerate 時,混合精度由 accelerate 的設定控制。 +- 訓練日誌、檢查點和 Hub 上傳僅由主處理程序執行,以避免衝突。非主處理程序的主控台記錄會被停用,以防止重複輸出。 +- 有效批次大小為 `batch_size × num_gpus`。如果您使用 4 個 GPU 且 `--batch_size=8`,有效批次大小為 32。 +- 學習率排程在多個處理程序之間能正確處理——LeRobot 設定 `step_scheduler_with_optimizer=False` 以防止 accelerate 根據處理程序數量調整排程器步數。 +- 儲存或推送模型時,LeRobot 會自動將模型從 accelerate 的分散式包裝器中解包,以確保相容性。 +- WandB 整合會自動僅在主處理程序上初始化,防止建立多個執行紀錄。 + +如需更進階的設定與疑難排解,請參閱 [Accelerate 文件](https://huggingface.co/docs/accelerate)。如果您想了解更多關於如何在大量 GPU 上進行訓練的資訊,請參考這份優秀的指南:[Ultrascale Playbook](https://huggingface.co/spaces/nanotron/ultrascale-playbook)。 diff --git a/docs/source/zh/peft_training.mdx b/docs/source/zh/peft_training.mdx new file mode 100644 index 0000000000..e95d96ae61 --- /dev/null +++ b/docs/source/zh/peft_training.mdx @@ -0,0 +1,62 @@ +# 使用 🤗 PEFT 進行參數高效微調 + +[🤗 PEFT](https://github.com/huggingface/peft)(Parameter-Efficient Fine-Tuning)是一個用於將如預訓練策略的大型預訓練模型(例如 SmolVLA、π₀ 等)高效地適配到新任務的函式庫, +無需訓練模型的所有參數, +同時能達到相當的效能表現。 + +安裝 `lerobot[peft]` 選用套件以啟用 PEFT 支援。 + +若要了解所有可用的適配方法,請參閱 [🤗 PEFT 文件](https://huggingface.co/docs/peft/index)。 + +## 訓練 SmolVLA + +在本節中,我們將展示如何使用 PEFT 在 libero 資料集上訓練預訓練的 SmolVLA 策略。 +為求簡潔,我們僅在 libero_spatial 子集上進行訓練。 +我們將使用 lerobot/smolvla_base 作為要進行參數高效微調的模型: + +``` +lerobot-train \ + --policy.path=lerobot/smolvla_base \ + --policy.repo_id=your_hub_name/my_libero_smolvla \ + --dataset.repo_id=HuggingFaceVLA/libero \ + --policy.output_features=null \ + --policy.input_features=null \ + --policy.optimizer_lr=1e-3 \ + --policy.scheduler_decay_lr=1e-4 \ + --env.type=libero \ + --env.task=libero_spatial \ + --steps=100000 \ + --batch_size=32 \ + --peft.method_type=LORA \ + --peft.r=64 +``` + +請注意 `--peft.method_type` 參數,它可讓你選擇使用哪種 PEFT 方法。 +這裡我們使用 [LoRA](https://huggingface.co/docs/peft/main/en/package_reference/lora)(Low-Rank Adapter,低秩適配器),這可能是目前最流行的微調方法。 +低秩適配意味著我們只微調一個秩相對較低的矩陣,而非完整的權重矩陣。 +這個秩可以透過 `--peft.r` 參數來指定。 +秩越高,就越接近完整微調。 + +還有更複雜且具有更多參數的方法。這些方法目前尚未支援, +如果你希望看到特定的 PEFT 方法被支援,歡迎提出 issue。 + +預設情況下,PEFT 會針對 SmolVLA 中 LM expert 的 `q_proj` 和 `v_proj` 層。 +它也會針對狀態和動作投影矩陣,因為這些最可能與任務相關。 +如果你需要針對不同的層,可以使用 `--peft.target_modules` 來指定要針對哪些層。 +你可以參閱對應 PEFT 方法的文件以了解支援哪些輸入(例如 [LoRA 的 target_modules 文件](https://huggingface.co/docs/peft/main/en/package_reference/lora#peft.LoraConfig.target_modules))。 +通常支援後綴名列表或正規表達式。例如,要針對 `lm_expert` 的 MLP 而非 `q` 和 `v` 投影, +可使用: + +``` +--peft.target_modules='(model\.vlm_with_expert\.lm_expert\..*\.(down|gate|up)_proj|.*\.(state_proj|action_in_proj|action_out_proj|action_time_mlp_in|action_time_mlp_out))' +``` + +如果你需要完整微調某一層而非僅進行適配, +可以透過 `--peft.full_training_modules` 參數提供層後綴名列表: + +``` +--peft.full_training_modules=["state_proj"] +``` + +學習率和排程目標學習率通常可以比完整微調所使用的學習率放大 10 倍 +(例如,一般為 1e-4,使用 LoRA 時則為 1e-3)。 diff --git a/docs/source/zh/rename_map.mdx b/docs/source/zh/rename_map.mdx new file mode 100644 index 0000000000..98e822faf9 --- /dev/null +++ b/docs/source/zh/rename_map.mdx @@ -0,0 +1,114 @@ +# 重新命名映射表與空白相機 + +當您使用機器人策略進行訓練、評估或錄製時,您的**資料集**或**環境**提供的觀測資料使用一組鍵名(例如 `observation.images.front`、`observation.images.eagle`),而您的**策略**則期望另一組鍵名(例如 `observation.images.image`、`observation.images.image2`)。**重新命名映射表**可以在不修改策略或資料來源的情況下橋接這個差異。 + +> **適用範圍:**重新命名對應表僅重新命名**觀測**鍵(影像與狀態)。動作鍵不受影響。 + +## 為什麼觀測鍵名不一定匹配 + +策略有一組固定的**輸入特徵名稱**,內建於其預訓練設定中。例如: + +- [pi0fast-libero](https://huggingface.co/lerobot/pi0fast-libero) 需要 `observation.images.base_0_rgb` 與 `observation.images.left_wrist_0_rgb`。 +- [xvla-base](https://huggingface.co/lerobot/xvla-base) 需要 `observation.images.image`、`observation.images.image2` 以及 `observation.images.image3`。 + +您的資料集可能使用完全不同的名稱(例如 `observation.images.front`、`observation.images.eagle`、`observation.images.glove`),而您的評估環境可能又使用另一組名稱。與其編輯策略設定或重新命名資料集中的欄位,您可以傳入一個**重新命名對應表**:一個 JSON 字典,將來源鍵映射到策略期望的鍵。重新命名在預處理管線中進行,因此策略始終看到它所期望的鍵名。 + +## 使用重新命名映射表 + +在命令列中以 JSON 字串傳入映射。慣例格式如下: + +``` +--rename_map='{"source_key": "policy_key", ...}' +``` + +其中 **source_key** 是資料集或環境提供的鍵名,而 **policy_key** 是策略期望的鍵名。 + +只有列出的鍵會被重新命名;其餘所有鍵不變地直接傳遞。條目的順序無關緊要。 + +支援的策略:**PI0**、**PI05**、**PI0Fast**、**SmolVLA** 和 **XVLA**。 + +### 訓練 + +假設您在一個資料集上微調 [lerobot/xvla-base](https://huggingface.co/lerobot/xvla-base),該資料集的影像在 `observation.images.front`、`observation.images.eagle` 和 `observation.images.glove` 下。XVLA 期望 `observation.images.image`、`observation.images.image2` 和 `observation.images.image3`: + +```bash +lerobot-train \ + --dataset.repo_id=YOUR_DATASET \ + --output_dir=./outputs/xvla_training \ + --job_name=xvla_training \ + --policy.path="lerobot/xvla-base" \ + --policy.repo_id="HF_USER/xvla-your-robot" \ + --policy.dtype=bfloat16 \ + --policy.action_mode=auto \ + --steps=20000 \ + --policy.device=cuda \ + --policy.freeze_vision_encoder=false \ + --policy.freeze_language_encoder=false \ + --policy.train_policy_transformer=true \ + --policy.train_soft_prompts=true \ + --rename_map='{"observation.images.front": "observation.images.image", "observation.images.eagle": "observation.images.image2", "observation.images.glove": "observation.images.image3"}' +``` + +### 評估 + +一個策略期望 `observation.images.base_0_rgb` 和 `observation.images.left_wrist_0_rgb`(例如 [pi0fast-libero](https://huggingface.co/lerobot/pi0fast-libero)),但 LIBERO 環境回傳的是 `observation.images.image` 和 `observation.images.image2`: + +```bash +lerobot-eval \ + --policy.path=lerobot/pi0fast-libero \ + --env.type=libero \ + ... \ + --rename_map='{"observation.images.image": "observation.images.base_0_rgb", "observation.images.image2": "observation.images.left_wrist_0_rgb"}' +``` + +### 錄製 + +`lerobot-record` 也支援重新命名映射表,嵌套在資料集的配置下: + +```bash +lerobot-record \ # 執行推論時 + --policy.path="/smolVLA_finetuned" \ + ... \ + --dataset.rename_map='{"observation.images.glove2": "observation.images.image"}' +``` + +替代方案:直接編輯策略配置 + +如果您總是使用相同的資料集或環境,您可以**編輯策略的 `config.json`**,使其觀測鍵名與您的資料來源匹配。這樣就不需要重新命名映射表。 + +取捨在於:修改策略設定會將其綁定到單一資料來源。重新命名對應表則讓一個策略可以跨多個資料集和環境使用。 + +## 空白相機:視角數少於策略期望的數量 + +有些策略針對固定數量的影像輸入而建構。如果您的資料集擁有較少的相機,您可以在策略設定中設定 **`empty_cameras`**,而不需要修改模型架構。 + +### 運作原理 + +設定 `empty_cameras=N` 會在策略設定中新增 N 個佔位影像特徵,命名為: + +``` +observation.images.empty_camera_0 +observation.images.empty_camera_1 +... +``` + +在執行時,這些鍵在批次中沒有對應的資料。策略會以遮罩的虛擬張量填充它們(對於基於 SigLIP 的視覺編碼器,以 `-1` 填充,注意力遮罩設為零),因此額外的影像插槽在訓練和推論期間實際上會被忽略。 + +### 範例 + +XVLA-base 有三個視覺輸入,預設 `empty_cameras=0`。您的資料集只有兩個相機: + +1. 設定 `--policy.empty_cameras=1`。 +2. 配置會新增第三個鍵:`observation.images.empty_camera_0`。 +3. 照常使用重新命名映射表對應您的兩個實際相機。 +4. 第三個插槽會被遮罩掉——您的資料集中不需要假影像。 + +## 快速參考 + +| 目標 | 做法 | +| ----------------------------- | -------------------------------------------------------------------- | +| 資料集鍵名 ≠ 策略鍵名 | `--rename_map='{"dataset_key": "policy_key", ...}'` | +| 環境鍵名 ≠ 策略鍵名(評估時) | `--rename_map='{"env_key": "policy_key", ...}'` | +| 錄製時使用不同鍵名(推論時) | `--dataset.rename_map='{"source_key": "policy_key", ...}'` | +| 相機數量少於策略期望 | `--policy.empty_cameras=N`(PI0、PI05、PI0Fast、SmolVLA、XVLA 支援) | +| 避免傳入重新命名對應表 | 編輯策略的 `config.json`,使其鍵名與您的資料來源匹配 |