# HIL-SERL 実ロボット学習ワークフローガイド

このチュートリアルでは、LeRobotを使用して、Human-in-the-Loop Sample-Efficient Reinforcement Learning (HIL-SERL) のワークフロー全体を体験します。わずか数時間で、実ロボット上で強化学習 (RL) によるポリシーの学習を習得できます。

HIL-SERLは、人間のデモとオンライン学習、および人間の介入を組み合わせるサンプル効率の高い強化学習アルゴリズムです。このアプローチは、少量の人間のデモから開始し、それらを使用して報酬分類器を訓練します。その後、人間の介入を可能にするアクター・ラーナーアーキテクチャを採用し、ポリシーの実行中に探索を誘導し、安全でない行動を修正します。このチュートリアルでは、ゲームパッドを使用して介入を提供し、学習プロセス中にロボットを制御します。

3つの重要な要素を組み合わせています:

1. **オフラインデモと報酬分類器:** 人間のテレオペレーションによる少数のエピソードと、視覚ベースの成功検出器により、ポリシーに整形された初期点が与えられます。

2. **人間による介入を伴うロボット上のアクター/ラーナーのループ:** 分散型の Soft Actor Critic (SAC) ラーナーがポリシーを更新する一方で、アクターが物理ロボット上で探索を行います。人間はいつでも介入して、危険な行動や生産性のない行動を修正できます。

3. **安全性と効率性のツール:** 関節/エンドエフェクタ（EE）の境界値、関心領域（ROI）のクロップ前処理、Trackioによる監視により、データの有用性とハードウェアの安全性を確保します。

これらの要素を組み合わせることで、HIL-SERLは模倣学習のみを用いたベースラインと比較して、ほぼ完全なタスク成功率とより短いサイクルタイムを実現します。

  <img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/hilserl-main-figure.png" alt="HIL-SERL ワークフロー" title="HIL-SERL ワークフロー" width="100%"
  >

  HIL-SERL ワークフロー、Luo et al. 2024

このガイドでは、LeRobotのHilSerl実装を使用して実ロボットで学習するためのロボットポリシーの学習手順を、ステップバイステップで説明します。

## 必要なものは何ですか？

- ロボットを操作するためのゲームパッド（推奨）またはキーボード
- Nvidia製GPU
- フォロワーアームとリーダーアームを備えた実際のロボット（キーボードまたはゲームパッドを使用する場合は任意）
- kinematicsパッケージ用のロボットのURDFファイル（`lerobot/model/kinematics.py`を確認してください）

## どのようなタスクを学習できますか？

HIL-SERLを使用して、さまざまな操作タスクの学習を行うことができます。いくつかの推奨事項:

- システムの仕組みを理解するために、シンプルなタスクから始めましょう。
  - キューブをゴール領域に押し込む
  - グリッパーで立方体を持ち上げる
- 非常に長いホライズンのタスクは避けてください。5〜10秒で完了できるタスクに焦点を当ててください。
- システムの仕組みが十分に理解できたら、より複雑なタスクや長いホライズンに挑戦できます。
  - 立方体のピック＆プレース
  - 両腕で物体を掴むバイマヌアルタスク
  - 片方の腕からもう片方の腕へ物体を移すHand-overタスク
  - 存分に楽しんでください！

## HIL-SERLでLeRobotをインストール

LeRobotをHIL-SERLと組み合わせてインストールするには、`hilserl`エクストラのインストールが必要です。

```bash
pip install -e ".[hilserl]"
```

## 実ロボット学習ワークフロー

### 設定の理解

学習プロセスは、HILSERl環境の適切な設定から始まります。メインの設定クラスは`lerobot/rl/gym_manipulator.py`にある`GymManipulatorConfig`で、`lerobot/envs/configs.py`で定義される`HILSerlRobotEnvConfig`と`DatasetConfig`というネストされた設定を含みます。設定は、焦点を絞ったネストされたサブ設定に整理されています。

```python
class GymManipulatorConfig:
    env: HILSerlRobotEnvConfig    # Environment configuration (nested)
    dataset: DatasetConfig    # Dataset recording/replay configuration (nested)
    mode: str | None = None    # "record", "replay", or None (for training)
    device: str = "cpu"    # Compute device

class HILSerlRobotEnvConfig(EnvConfig):
    robot: RobotConfig | None = None    # Main robot agent (defined in `lerobot/robots`)
    teleop: TeleoperatorConfig | None = None    # Teleoperator agent, e.g., gamepad or leader arm
    processor: HILSerlProcessorConfig    # Processing pipeline configuration (nested)
    name: str = "real_robot"    # Environment name
    task: str | None = None    # Task identifier
    fps: int = 30    # Control frequency

# Nested processor configuration
class HILSerlProcessorConfig:
    control_mode: str = "gamepad"    # Control mode
    observation: ObservationConfig | None = None    # Observation processing settings
    image_preprocessing: ImagePreprocessingConfig | None = None    # Image crop/resize settings
    gripper: GripperConfig | None = None    # Gripper control and penalty settings
    reset: ResetConfig | None = None    # Environment reset and timing settings
    inverse_kinematics: InverseKinematicsConfig | None = None    # IK processing settings
    reward_classifier: RewardClassifierConfig | None = None    # Reward classifier settings
    max_gripper_pos: float | None = 100.0    # Maximum gripper position

# Sub-configuration classes
class ObservationConfig:
    add_joint_velocity_to_observation: bool = False    # Add joint velocities to state
    add_current_to_observation: bool = False    # Add motor currents to state
    add_ee_pose_to_observation: bool = False    # Add end-effector pose to state
    display_cameras: bool = False    # Display camera feeds during execution

class ImagePreprocessingConfig:
    crop_params_dict: dict[str, tuple[int, int, int, int]] | None = None    # Image cropping parameters
    resize_size: tuple[int, int] | None = None    # Target image size

class GripperConfig:
    use_gripper: bool = True    # Enable gripper control
    gripper_penalty: float = 0.0    # Penalty for inappropriate gripper usage

class ResetConfig:
    fixed_reset_joint_positions: list[float] | None = None    # Joint positions for reset
    reset_time_s: float = 5.0    # Time to wait during reset
    control_time_s: float = 20.0    # Maximum episode duration
    terminate_on_success: bool = True    # Whether to terminate episodes on success detection

class InverseKinematicsConfig:
    urdf_path: str | None = None    # Path to robot URDF file
    target_frame_name: str | None = None    # End-effector frame name
    end_effector_bounds: dict[str, list[float]] | None = None    # EE workspace bounds
    end_effector_step_sizes: dict[str, float] | None = None    # EE step sizes per axis

class RewardClassifierConfig:
    pretrained_path: str | None = None    # Path to pretrained reward classifier
    success_threshold: float = 0.5    # Success detection threshold
    success_reward: float = 1.0    # Reward value for successful episodes

# Dataset configuration
class DatasetConfig:
    repo_id: str    # LeRobot dataset repository ID
    task: str    # Task identifier
    root: str | None = None    # Local dataset root directory
    num_episodes_to_record: int = 5    # Number of episodes for recording
    replay_episode: int | None = None    # Episode index for replay
    push_to_hub: bool = False    # Whether to push datasets to Hub
```

### プロセッサのパイプラインアーキテクチャ

HIL-SERLは、ロボットの観測とアクションを、組み合わせ可能な一連のステップを通じて処理するモジュール化されたプロセッサパイプラインアーキテクチャを使用しています。このパイプラインは、主に2つのコンポーネントに分けられます。

#### 環境プロセッサパイプライン

環境プロセッサ(`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 パイプライン

アクションプロセッサ(`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
      }
    }
  }
}
```

**注**: 追加の観測特徴を有効にすると、状態空間の次元数が増加し、ポリシーネットワークのアーキテクチャの調整や、さらなる学習データの収集が必要になる場合があります。

### ロボットのワークスペースの範囲の特定

デモの収集を開始する前に、ロボットに適した動作範囲を決定する必要があります。

これは、実ロボットでの学習という問題を2つの側面から簡素化します。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 \
  --urdf_path=SO-ARM100/Simulation/SO101/so101_new_calib.urdf \
  --target_frame_name=gripper
```

`--urdf_path` は必須です。ロボット本体の URDF ファイルへのパスを指定し、スクリプトはこのファイルを使用してエンドエフェクタの位置を計算します。SO-100/SO-101 の場合は、`git clone https://github.com/TheRobotStudio/SO-ARM100.git` を実行して [SO-ARM100 リポジトリ](https://github.com/TheRobotStudio/SO-ARM100) をクローンしてください。その後、URDF ファイルは `SO-ARM100/Simulation/SO101/so101_new_calib.urdf` に配置されます。

**ワークフロー**

1. スクリプトを実行し、タスクを解決する空間をロボットが移動するようにします
2. スクリプトは、末端の最小および最大位置と関節角度を記録し、コンソールに出力します。例:

   ```
   # End Effector Bounds (x, y, z):
   max_ee = [0.2417, 0.2012, 0.1027]
   min_ee = [0.1663, -0.0823, 0.0336]

   # Joint Position Limits (radians):
   max_pos = [...]
   min_pos = [...]
   ```

3. これらの値は、`lerobot/envs/configs.py` の `InverseKinematicsConfig`（参照）に記載されている `env.processor.inverse_kinematics.end_effector_bounds` 配下の環境設定で使用する。

**設定の例**

```json
{
  "env": {
    "processor": {
      "inverse_kinematics": {
        "end_effector_bounds": {
          "max": [0.24, 0.2, 0.1],
          "min": [0.16, -0.08, 0.03]
        }
      }
    }
  }
}
```

### デモの収集

境界が定義されたことで、学習用のデモを安全に収集できます。オフポリシーアルゴリズムによる強化学習では、学習プロセスの効率を向上させるために、オフラインで収集されたデータセットを利用できます。

**レコードモードの設定**

このガイドの例設定ファイルは、Hub上の[lerobot/config_examples](https://huggingface.co/datasets/lerobot/config_examples)データセットにあります。環境設定と学習設定を作業ディレクトリにダウンロードしてください:

```bash
hf download lerobot/config_examples rl/env_config.json rl/train_config.json --repo-type dataset --local-dir .
```

これにより、`rl/env_config.json` と `rl/train_config.json` に保存されます。これらは以下のコマンドで使用するパスです。デモの記録には、`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": {
      // ... robot configuration ...
    },
    "teleop": {
      // ... teleoperator configuration ...
    }
  },
  "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方向の移動を制御します。

エンドエフェクタの変換は、`env.processor.inverse_kinematics` (`InverseKinematicsConfig`) および `env.processor.gripper` / `env.processor.max_gripper_pos` 下で設定されるプロセッサパイプライン (`InverseKinematicsRLStep`、`EEBoundsAndSafety`、`EEReferenceAndDelta`、`GripperVelocityToJoint`) によって適用されます。エンドエフェクタ空間に関連するデフォルト値は以下の通りです。

```python
class InverseKinematicsConfig:
    """Configuration for inverse kinematics processing."""

    urdf_path: str | None = None
    target_frame_name: str | None = None
    # bounds for the end-effector in x,y,z direction
    end_effector_bounds: dict[str, list[float]] | None = None
    # maximum step size for the end-effector in x,y,z direction
    end_effector_step_sizes: dict[str, float] | None = None

class HILSerlProcessorConfig:
    ...
    # maximum gripper position that the gripper will be open at
    max_gripper_pos: float | None = 100.0
```

`Teleoperator`はテレオペレーションデバイスを定義します。利用可能なテレオペレーターのリストは`lerobot/teleoperators`で確認できます。

**ゲームパッドのセットアップ**

ゲームパッドは、ロボットとエピソードの状態を制御する非常に便利な方法を提供します。

ゲームパッドを設定するには、`control_mode`を`"gamepad"`に設定し、設定ファイルで`teleop`セクションを定義する必要があります。

```json
{
  "env": {
    "teleop": {
      "type": "gamepad",
      "use_gripper": true
    },
    "processor": {
      "control_mode": "gamepad",
      "gripper": {
        "use_gripper": true
      }
    }
  }
}
```

  <img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/gamepad_guide.jpg?raw=true" alt="図はLogitechゲームパッドのコントロールマッピングを示しています。" title="ゲームパッドのコントロールマッピング" width="100%"
  >

  ロボット制御とエピソード管理用のゲームパッドボタン割り当て

**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`を押して制御をポリシーに返します。

Video: SO101 リーダーによる遠隔操作

  
    <source
      src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so101_leader_tutorial.mp4"
      type="video/mp4"
    />
  

SO101 リーダーによる遠隔操作の例。リーダーがフォロワーを追従します。介入するには`space`を押してください

**デモの記録**

上記で編集した環境設定で、録画プロセスを開始します:

```bash
python -m lerobot.rl.gym_manipulator --config_path rl/env_config.json
```

録画中:

1. ロボットは、設定ファイルで定義された初期位置`env.processor.reset.fixed_reset_joint_positions`にリセットされます。
2. タスクを正常に完了します
3. エピソードは、"success" ボタンを押すと報酬 1 で終了します
4. 時間制限に達した場合、または失敗ボタンが押された場合、報酬0でエピソードが終了します
5. 「rerecord」ボタンを押すことで、エピソードを再録画できます。
6. このプロセスは自動的に次のエピソードに進みます
7. すべてのエピソードの記録が完了すると、データセットは Hugging Face Hub にプッシュされ（オプション）、ローカルに保存されます

### データセットの処理

デモデータを集めた後、最適なカメラクロップを決定するためにそれらを処理します。強化学習は背景の干渉に敏感であるため、画像を関連するワークスペース領域にクロップすることが重要です。

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

  <img
    src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/crop_dataset.gif"
    width="600"
  />

  インタラクティブなクロッピングツール

**設定の更新**

トレーニング設定にこれらのクロップパラメータを追加します:

```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実験の最初のラウンドを開始できます。

`lerobot/rewards/classifier/modeling_classifier.py` 内の報酬分類器の実装は、事前学習済みのビジョンモデルを使用して画像を処理します。成功/失敗を予測するための二値報酬には単一の値を、多クラス設定には複数の値を出力できます。

**報酬分類器用のデータセットの収集**

学習を開始する前に、ラベル付きの例を含むデータセットを収集する必要があります。設定ファイルで`mode: "record"`を設定し、`gym_manipulator.py`を実行すると、観測、アクション、報酬のデータセットを収集するプロセスが有効になります。

…

```bash
python -m lerobot.rl.gym_manipulator --config_path rl/env_config.json
```

**データ収集の主要なパラメータ**

- **mode**: データセットを収集するには（ルートレベルで）`"record"`に設定します
- **dataset.repo_id**: `"hf_username/dataset_name"`、ハブ上のデータセットおよびリポジトリの名前
- **dataset.num_episodes_to_record**: 記録するエピソード数
- **env.processor.reset.terminate_on_success**: 成功が検出されたときにエピソードを自動的に終了するかどうか（デフォルト: `true`）
- **env.fps**: 記録する毎秒のフレーム数
- **dataset.push_to_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": {
      // ... robot configuration ...
    },
    "teleop": {
      // ... teleoperator configuration ...
    }
  },
  "dataset": {
    "repo_id": "hf_username/dataset_name",
    "root": "data/your_dataset",
    "task": "reward_classifier_task",
    "num_episodes_to_record": 20,
    "replay_episode": null,
    "push_to_hub": true
  },
  "mode": "record",
  "device": "cpu"
}
```

**報酬分類器の設定**

報酬分類器は`lerobot/rewards/classifier/configuration_classifier.py`で設定されます。主なパラメータは以下の通りです。

- **model_name**: ベースモデルのアーキテクチャ（例: 主に`"helper2424/resnet10"`を使用）
- **model_type**: `"cnn"` または `"transformer"`
- **num_cameras**: カメラ入力の数
- **num_classes**: 出力クラスの数（二値の成功/失敗の場合は通常 2）
- **hidden_dim**: 隠れ表現のサイズ
- **dropout_rate**: 正則化パラメータ
- **learning_rate**: オプティマイザの学習率

報酬分類器の学習用の設定例です。`reward_classifier_train_config.json`として保存してください。

```json
{
  "dataset": {
    "repo_id": "hf_username/dataset_name",
    "root": null
  },
  "reward_model": {
    "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",
    "input_features": {
      "observation.images.front": {
        "type": "VISUAL",
        "shape": [3, 128, 128]
      },
      "observation.images.side": {
        "type": "VISUAL",
        "shape": [3, 128, 128]
      }
    },
    "push_to_hub": true,
    "repo_id": "hf_username/model_repo"
  },
  "batch_size": 16,
  "num_workers": 4,
  "steps": 5000,
  "log_freq": 10,
  "env_eval_freq": 1000,
  "save_freq": 1000,
  "save_checkpoint": true,
  "seed": 2,
  "resume": false,
  "optimizer": {
    "grad_clip_norm": 10.0
  },
  "trackio": {
    "enable": true,
    "project": "reward-classifier"
  },
  "job_name": "reward-classifier"
}
```

**分類器の学習**

分類器を学習するには、`train.py`スクリプトをあなたの設定と併せて使用します:

```bash
lerobot-train --config_path reward_classifier_train_config.json
```

**モデルのデプロイとテスト**

学習した報酬分類器を使用するには、`HILSerlRobotEnvConfig`を設定して、モデルを使用するようにしてください。

```python
config = GymManipulatorConfig(
    env=HILSerlRobotEnvConfig(
        processor=HILSerlProcessorConfig(
            reward_classifier=RewardClassifierConfig(
                pretrained_path="path_to_your_pretrained_trained_model"
            )
        ),
        # Other environment parameters
    ),
    dataset=DatasetConfig(...),
    mode=None  # For training
)
```

または、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 rl/env_config.json
```

報酬分類器は、ロボットのカメラからの視覚入力に基づいて自動的に報酬を提供します。

**報酬分類器の学習のためのワークフロー例**

1. **設定ファイルの作成**: リワード分類器と環境に必要な json 設定ファイルを作成します: 上記の例にある `reward_classifier_train_config.json` と、ダウンロードした `rl/env_config.json` です。

2. **データセットを収集する**:

   ```bash
   python -m lerobot.rl.gym_manipulator --config_path rl/env_config.json
   ```

3. **分類器を学習する**：

   ```bash
   lerobot-train --config_path reward_classifier_train_config.json
   ```

4. **分類器をテストする**：
   ```bash
   python -m lerobot.rl.gym_manipulator --config_path rl/env_config.json
   ```

### Actor-Learnerによる学習

LeRobot システムは、学習のために分散型アクター・ラーナーアーキテクチャを使用しています。このアーキテクチャは、ロボットのインタラクションと学習プロセスを分離し、互いをブロックせずに並行して実行できるようにします。アクターサーバーはロボットの観測とアクションを処理し、インタラクションデータをラーナーサーバーに送信します。ラーナーサーバーは勾配降下法を実行し、定期的にアクターのポリシー重みを更新します。2つのプロセス、すなわちラーナーとアクターを起動する必要があります。

**設定のセットアップ**

先ほどダウンロードした学習設定ファイル`rl/train_config.json`（[こちら](https://huggingface.co/datasets/lerobot/config_examples/resolve/main/rl/train_config.json)に例があります）を編集してください。学習設定は、`lerobot/rl/train_rl.py`内のメインクラスである`TrainRLServerPipelineConfig`に基づいています。

1. ポリシー設定（`type="gaussian_actor"`、`device` など）を設定します
2. トップレベルの`algorithm`ブロック（`type="sac"`、学習率、割引率など、`lerobot/rl/algorithms/sac/configuration_sac.py`で定義されています）でアルゴリズムの設定を行います。
3. `dataset`をトリミング済みのデータセットに設定します
4. cropパラメータで環境設定を構成します
5. [configuration_gaussian_actor.py](https://github.com/huggingface/lerobot/blob/main/src/lerobot/policies/gaussian_actor/configuration_gaussian_actor.py#L79) で、Gaussian Actor に関連するその他のパラメータを確認してください。
6. タスクに適切な`input_features`と`output_features`が設定されていることを確認し、`policy`の設定が正しいことを検証してください。

**Learnerの開始**

まず、ラーナーサーバーのプロセスを開始します:

```bash
python -m lerobot.rl.learner --config_path rl/train_config.json
```

学習者:

- ポリシーネットワークを初期化します
- リプレイバッファを準備します
- `gRPC`サーバーを開き、アクターと通信します
- 遷移を処理し、ポリシーを更新します

**Actorの起動**

別のターミナルで、同じ設定を使用してactorプロセスを開始します:

```bash
python -m lerobot.rl.actor --config_path rl/train_config.json
```

アクター:

- `gRPC` 経由でラーナーに接続します
- 環境を初期化します
- policyのロールアウトを実行して、経験データを収集します
- 学習者にトランジションを送信します
- 更新されたポリシーパラメータを受け取ります

**トレーニングフロー**

トレーニングは自動的に進行します:

1. actorは環境内でポリシーを実行します
2. Transitionsは収集され、learnerに送信されます
3. 学習者は、これらの遷移に基づいてポリシーを更新します
4. 更新されたポリシーパラメータはアクターに返送されます
5. 指定されたステップの上限に達するまで、このプロセスは続行されます。

**ヒューマン・イン・ザ・ループ**

- 効率的に学習するための鍵は、人間の介入によって修正フィードバックを提供し、タスクを完了させることで、ポリシーの学習と探索を支援することです。
- 人間による介入を行うには、ゲームパッドの右上のトリガーボタン（またはキーボードの`space`キー）を押します。これにより、ポリシーのアクションが一時停止され、操作を引き継ぐことができます。
- 成功した実験とは、人間が開始時に介入するものの、ポリシーが改善するにつれて介入の頻度を減らしていけるものです。介入率をTrackioのダッシュボードで監視できます（`trackio show --project <project>`）。

  <img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/hil_effect.png?raw=true" alt="図は、Logitechゲームパッド上のコントロールマッピングを示しています。" title="ゲームパッドのコントロールマッピング" width="100%"
  >

  
    人間の介入が時間とともにポリシー学習をどのように導くかを示す例
  

- 図は、インタラクションステップに対するエピソード報酬のプロットを示しています。図は、人間の介入がポリシー学習に与える影響を示しています。
- オレンジ色の曲線は、人間の介入なしの実験を示しています。一方、ピンク色と青色の曲線は、人間の介入ありの実験を示しています。
- 人間の介入がある場合、ポリシーが最大報酬を獲得し始めるステップ数が4分の1に減少していることが観察できます。

**モニタリングとデバッグ**

設定で`trackio.enable`が`true`に設定されている場合、[Trackio](https://huggingface.co/docs/trackio)ダッシュボード（`trackio show --project <project>`）を通じて、トレーニングの進捗をリアルタイムで監視できます。

### 人間介入のガイド

学習プロセスは介入戦略に対して非常に敏感です。効果的に介入する方法を理解するには、数回の実行が必要です。いくつかのヒントとコツ:

- 学習の開始時に、ポリシーが数エピソードにわたり探索できるようにします。
- 長時間介入を避けてください。ロボットが軌道から外れた際に、その状況で介入してロボットの動作を修正するようにしてください。
- ポリシーがタスクを達成し始めたら、完璧でなくても、介入を単純なクイックアクション、例えば単純なグリップコマンドなどに限定できます。

理想的な挙動は、下の図に示すように、トレーニング中に介入率が徐々に低下することです。

  <img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/intervention_rate_tutorial_rl.png?raw=true" alt="介入率" title="学習中の介入率" width="100%"
  >

  
    ピック&リフトキューブタスクにおけるトレーニング実行中の介入率のプロット
  

### 調整すべき主要なハイパーパラメータ

一部の構成値は、トレーニングの安定性や速度に不均衡なほど大きな影響を与えます:

- **`temperature_init`** (`algorithm.temperature_init`) – SACにおける初期エントロピー温度です。値を高くすると探索が促進され、低くすると初期段階でポリシーがより決定論的になります。適切な初期値は`1e-2`です。この値が高すぎると、人間の介入が効かなくなり、学習が遅くなることを確認しています。
- **`policy_parameters_push_frequency`** (`policy.actor_learner_config.policy_parameters_push_frequency`) – learner から actor への重みのプッシュ間隔（_秒_単位）。デフォルト値は `4 s` です。より新しい重みを提供するには **1-2 s** に減らしてください（ネットワークトラフィックが増えるという代償があります）。接続が遅い場合のみ増やしてください。サンプル効率が悪化するためです。
- **`storage_device`** (`policy.storage_device`) – learner がポリシーパラメータを保持するデバイス。GPU メモリに空きがある場合は、デフォルトの `"cpu"` の代わりに `"cuda"` に設定してください。重みを GPU 上に保持することで、CPU→GPU 間の転送オーバーヘッドを排除でき、1 秒あたりの learner 更新回数を大幅に増加させることができます。

おめでとうございます🎉、このチュートリアルを完了しました！

> [!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}
}
```

