# Guia do Fluxo de Trabalho de Treinamento em Robôs Reais do HIL-SERL

Neste tutorial, você percorrerá o fluxo de trabalho completo de Aprendizado por Reforço Eficiente em Amostra com Humano no Loop (HIL-SERL) usando LeRobot. Você dominará o treinamento de uma política com RL em um robô real em apenas algumas horas.

HIL-SERL é um algoritmo de aprendizado por reforço eficiente em amostras que combina demonstrações humanas com aprendizado online e intervenções humanas. A abordagem parte de um pequeno conjunto de demonstrações humanas, usa-as para treinar um classificador de recompensa e, em seguida, emprega uma arquitetura ator-aprendiz em que humanos podem intervir durante a execução da política para orientar a exploração e corrigir comportamentos inseguros. Neste tutorial, você usará um controle de videogame para fornecer intervenções e controlar o robô durante o processo de aprendizado.

Ele combina três ingredientes-chave:

1. **Demonstrações offline e classificador de recompensa:** alguns episódios de teleoperação humana, juntamente com um detector de sucesso baseado em visão, fornecem ao policy um ponto de partida estruturado.

2. **Laço ator/learner no robô com intervenções humanas:** um learner distribuído de Soft Actor Critic (SAC) atualiza a política enquanto um ator explora no robô físico; o humano pode intervir a qualquer momento para corrigir comportamentos perigosos ou improdutivos.

3. **Ferramentas de segurança e eficiência:** limites de junta/eficaz final (EE), pré-processamento da região de interesse (ROI) e monitoramento com Trackio mantêm os dados úteis e o hardware seguro.

Juntos, esses elementos permitem que o HIL-SERL alcance um sucesso de tarefa quase perfeito e tempos de ciclo mais rápidos do que as linhas de base baseadas apenas em imitação.

  <img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/hilserl-main-figure.png" alt="Fluxo de trabalho do HIL-SERL" title="Fluxo de trabalho do HIL-SERL" width="100%"
  >

  Fluxo de trabalho HIL-SERL, Luo et al. 2024

Este guia fornece instruções passo a passo para treinar uma política de robô usando a implementação HilSerl do LeRobot para treinar em um robô real.

## Do que eu preciso?

- Um gamepad (recomendado) ou teclado para controlar o robô
- Uma GPU da Nvidia
- Um robô real com um braço seguidor e um braço líder (opcional se você usar o teclado ou o controle)
- Um arquivo URDF do robô para o pacote de cinemática (consulte `lerobot/model/kinematics.py`)

## Que tipo de tarefas posso treinar?

É possível usar o HIL-SERL para treinar em uma variedade de tarefas de manipulação. Algumas recomendações:

- Comece com uma tarefa simples para entender como o sistema funciona.
  - Empurre o cubo para uma região de destino
  - Pegue e levante o cubo com a pinça
- Evite tarefas com horizonte extremamente longo. Foque em tarefas que podem ser concluídas em 5 a 10 segundos.
- Depois que você tiver uma boa noção de como o sistema funciona, pode tentar tarefas mais complexas e horizontes mais longos.
  - Pegar e posicionar cubo
  - Tarefas bimanuais para pegar objetos com dois braços
  - Tarefas de passagem para transferir objetos de um braço para o outro
  - Vá à loucura!

## Instale o LeRobot com HIL-SERL

Para instalar o LeRobot com HIL-SERL, você precisa instalar o extra `hilserl`.

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

## Fluxo de Trabalho de Treinamento de Robô Real

### Compreendendo a Configuração

O processo de treinamento começa com a configuração adequada para o ambiente HILSERl. A classe de configuração principal é `GymManipulatorConfig` em `lerobot/rl/gym_manipulator.py`, que contém `HILSerlRobotEnvConfig` (definida em `lerobot/envs/configs.py`) e `DatasetConfig` aninhados. A configuração é organizada em subconfigurações aninhadas e focadas:

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

### Arquitetura do Pipeline do Processor

O HIL-SERL usa uma arquitetura de pipeline de processadores modular que processa observações e ações do robô por meio de uma série de etapas componíveis. O pipeline é dividido em dois componentes principais:

#### Pipeline do Processador de Ambiente

O processador de ambiente (`env_processor`) trata as observações recebidas e o estado do ambiente:

1. **VanillaObservationProcessorStep**: Converte observações brutas do robô para um formato padronizado
2. **JointVelocityProcessorStep** (opcional): Adiciona informações de velocidade das juntas às observações
3. **MotorCurrentProcessorStep** (opcional): Adiciona leituras de corrente do motor às observações
4. **ForwardKinematicsJointsToEE** (opcional): Calcula a pose do efetuor final a partir das posições das juntas
5. **ImageCropResizeProcessorStep** (opcional): Recorta e redimensiona imagens da câmera
6. **TimeLimitProcessorStep** (opcional): Impõe limites de tempo por episódio
7. **GripperPenaltyProcessorStep** (opcional): aplica penalidades por uso inadequado do garra
8. **RewardClassifierProcessorStep** (opcional): detecção automática de recompensas usando modelos de visão
9. **AddBatchDimensionProcessorStep**: Converte os dados para o formato de lote para processamento por redes neurais
10. **DeviceProcessorStep**: Move os dados para o dispositivo de computação especificado (CPU/GPU)

#### Pipeline do Processador de Ações

O processador de ações (`action_processor`) trata as ações de saída e as intervenções humanas:

1. **AddTeleopActionAsComplimentaryDataStep**: Captura as ações do teleoperador para registro
2. **AddTeleopEventsAsInfoStep**: Registra eventos de intervenção e sinais de controle de episódio
3. **InterventionActionProcessorStep**: Trata intervenções humanas e término de episódios
4. **Pipeline de Cinemática Inversa** (quando habilitado):
   - **MapDeltaActionToRobotActionStep**: Converte ações delta para o formato de ação do robô
   - **EEReferenceAndDelta**: Calcula os movimentos de referência e delta do efetuador final
   - **EEBoundsAndSafety**: Impõe limites de segurança do espaço de trabalho
   - **InverseKinematicsEEToJoints**: Converte ações do efetuador final em alvos de juntas
   - **GripperVelocityToJoint**: Trata os comandos de controle do garra

#### Exemplos de Configuração

**Processamento básico de observações**:

```json
{
  "env": {
    "processor": {
      "observation": {
        "add_joint_velocity_to_observation": true,
        "add_current_to_observation": false,
        "display_cameras": false
      }
    }
  }
}
```

**Processamento de Imagens**:

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

**Configuração da Cinemática Inversa**:

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

### Processamento Avançado de Observações

O framework HIL-SERL suporta recursos adicionais de processamento de observações que podem melhorar o aprendizado da política:

#### Processamento de Velocidade Conjunta

Ative a estimativa conjunta de velocidade para fornecer informações de movimento à política:

```json
{
  "env": {
    "processor": {
      "observation": {
        "add_joint_velocity_to_observation": true
      }
    }
  }
}
```

Este processador:

- Estima as velocidades articulares usando diferenças finitas entre leituras consecutivas de posição das articulações
- Adiciona informações de velocidade ao vetor de estado da observação
- Útil para políticas que precisam de consciência de movimento para tarefas dinâmicas

#### Processamento da Corrente do Motor

Monitore as correntes do motor para detectar forças de contato e condições de carga:

```json
{
  "env": {
    "processor": {
      "observation": {
        "add_current_to_observation": true
      }
    }
  }
}
```

Este processador:

- Lê os valores de corrente do motor do sistema de controle do robô
- Adiciona as medições atuais ao vetor de estado da observação
- Ajuda a detectar eventos de contato, pesos de objetos e resistência mecânica
- Útil para tarefas de manipulação com muitos contatos

#### Processamento de Observações Combinadas

Você pode habilitar vários recursos de processamento de observações simultaneamente:

```json
{
  "env": {
    "processor": {
      "observation": {
        "add_joint_velocity_to_observation": true,
        "add_current_to_observation": true,
        "display_cameras": false
      }
    }
  }
}
```

**Nota**: Habilitar recursos de observação adicionais aumenta a dimensionalidade do espaço de estados, o que pode exigir ajustes na arquitetura da sua rede de política e, potencialmente, a coleta de mais dados de treinamento.

### Encontrando os limites do espaço de trabalho do robô

Antes de coletar demonstrações, você precisa determinar os limites operacionais adequados para o seu robô.

Isso ajuda a simplificar o problema de aprendizado no robô real de duas formas: 1) limitando o espaço operacional do robô a uma região específica que resolve a tarefa e evita exploração desnecessária ou insegura, e 2) permitindo o treinamento no espaço do efetuor final em vez do espaço das juntas. Empiricamente, o aprendizado no espaço das juntas para aprendizado por reforço em manipulação é frequentemente um problema mais difícil - algumas tarefas são quase impossíveis de aprender no espaço das juntas, mas se tornam aprendíveis quando o espaço de ações é transformado para coordenadas do efetuor final.

**Usando o lerobot-find-joint-limits**

Este script ajuda você a encontrar os limites operacionais seguros para o efetuador final do seu robô. Dado que você possui um braço seguidor e um braço líder, pode usar o script para encontrar os limites para o braço seguidor que serão aplicados durante o treinamento. Limitar o espaço de ações reduzirá a exploração redundante do agente e garante a segurança.

```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` é obrigatório: ele aponta para o arquivo URDF do seu robô, que o script usa para calcular a posição do efetuor final. Para o SO-100/SO-101, clone o repositório [SO-ARM100](https://github.com/TheRobotStudio/SO-ARM100) com `git clone https://github.com/TheRobotStudio/SO-ARM100.git`; o URDF estará então em `SO-ARM100/Simulation/SO101/so101_new_calib.urdf`.

**Fluxo de trabalho**

1. Execute o script e mova o robô pelo espaço que resolve a tarefa
2. O script registrará as posições mínimas e máximas do efetuador final e os ângulos das juntas e os exibirá no console, por exemplo:

   ```
   # 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. Use esses valores na configuração do seu ambiente sob `env.processor.inverse_kinematics.end_effector_bounds` (veja `InverseKinematicsConfig` em `lerobot/envs/configs.py`)

**Configuração de exemplo**

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

### Coletando Demonstrações

Com os limites definidos, você pode coletar com segurança demonstrações para o treinamento. Treinar RL com um algoritmo off-policy nos permite usar conjuntos de dados offline coletados para melhorar a eficiência do processo de aprendizado.

**Configurando o modo de gravação**

Os arquivos de configuração de exemplo para este guia estão no dataset [lerobot/config_examples](https://huggingface.co/datasets/lerobot/config_examples) no Hub. Baixe as configurações de ambiente e de treinamento para o seu diretório de trabalho:

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

Isso os salva em `rl/env_config.json` e `rl/train_config.json`, os caminhos usados nos comandos abaixo. Edite `rl/env_config.json` para gravar demonstrações:

1. Defina `mode` como `"record"` no nível raiz
2. Especifique um `repo_id` único para o seu conjunto de dados na seção `dataset` (por exemplo, "username/task_name")
3. Defina `num_episodes_to_record` na seção `dataset` para o número de demonstrações que você deseja coletar
4. Defina `env.processor.image_preprocessing.crop_params_dict` como `{}` inicialmente (determinaremos os recortes mais tarde)
5. Configure `env.robot`, `env.teleop` e outras configurações de hardware na seção `env`

Seção de configuração de exemplo:

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

### Usando um dispositivo de teleoperação

Junto com seu robô, você precisará de um dispositivo de teleoperação para controlá-lo, a fim de coletar conjuntos de dados da sua tarefa e realizar intervenções durante o treinamento online. Suportamos o uso de um controle de videogame, um teclado ou o braço líder do robô.

HIL-Serl aprende ações no espaço do efetuor final do robô. Portanto, a teleoperação controlará os deslocamentos x, y, z do efetuor final.

A transformação do efetuor final é aplicada pelo pipeline do processador (`InverseKinematicsRLStep`, `EEBoundsAndSafety`, `EEReferenceAndDelta`, `GripperVelocityToJoint`) configurado sob `env.processor.inverse_kinematics` (`InverseKinematicsConfig`) e `env.processor.gripper` / `env.processor.max_gripper_pos`. Os padrões relacionados ao espaço do efetuor final são:

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

O `Teleoperator` define o dispositivo de teleoperação. Você pode verificar a lista de teleoperadores disponíveis em `lerobot/teleoperators`.

**Configurando o Gamepad**

O gamepad oferece uma maneira muito conveniente de controlar o robô e o estado do episódio.

Para configurar o gamepad, você precisa definir o `control_mode` como `"gamepad"` e definir a seção `teleop` no arquivo de configuração.

```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="A figura mostra os mapeamentos de controle em um controle Logitech." title="Mapeamento de Controle do Gamepad" width="100%"
  >

  Mapeamento de botões do gamepad para controle do robô e gerenciamento de episódios

**Configurando o líder SO101**

O braço líder do SO101 possui engrenagens reduzidas que permitem que ele se mova e acompanhe o braço seguidor durante a exploração. Portanto, a transição de controle é muito mais suave do que no SO100, que não possui engrenagens.

Para configurar o líder SO101, você precisa definir o `control_mode` como `"leader"` e definir a seção `teleop` no arquivo de configuração.

```json
{
  "env": {
    "teleop": {
      "type": "so101_leader",
      "port": "/dev/tty.usbmodem585A0077921",
      "use_degrees": true
    },
    "processor": {
      "control_mode": "leader",
      "gripper": {
        "use_gripper": true
      }
    }
  }
}
```

Para anotar o sucesso/falha do episódio, **você precisará** usar um teclado para pressionar `s` para sucesso e `esc` para falha. Durante o treinamento online, pressione `space` para assumir o controle da política e `space` novamente para devolver o controle à política.

Vídeo: teleoperação do líder SO101

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

Exemplo de teleoperação do líder SO101, o líder acompanha o seguidor, pressione `space` para intervir

**Gravação de Demonstrações**

Inicie o processo de gravação com a configuração de ambiente que você editou acima:

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

Durante a gravação:

1. O robô será redefinido para a posição inicial definida no arquivo de configuração `env.processor.reset.fixed_reset_joint_positions`
2. Conclua a tarefa com sucesso
3. O episódio termina com uma recompensa de 1 quando você pressiona o botão "success"
4. Se o limite de tempo for atingido ou o botão de falha for pressionado, o episódio termina com uma recompensa de 0
5. Você pode gravar novamente um episódio pressionando o botão "rerecord"
6. O processo continua automaticamente para o próximo episódio
7. Após gravar todos os episódios, o conjunto de dados é enviado para o Hugging Face Hub (opcional) e salvo localmente

### Processando o Conjunto de Dados

Após coletar as demonstrações, processe-as para determinar os recortes de câmera ideais. O aprendizado por reforço é sensível a distrações do fundo, portanto, é importante recortar as imagens para a área de trabalho relevante.

Algoritmos de RL visual aprendem diretamente a partir de entradas de pixels, tornando-os vulneráveis a informações visuais irrelevantes. Elementos de fundo, como mudanças de iluminação, sombras, pessoas em movimento ou objetos fora da área de trabalho, podem confundir o processo de aprendizado. Uma boa seleção de ROI deve:

- Inclua apenas o workspace essencial onde a tarefa é executada
- Capture o efector final do robô e todos os objetos envolvidos na tarefa
- Exclua elementos de fundo e distrações desnecessários

Nota: Se você já conhece os parâmetros de recorte, pode pular esta etapa e simplesmente definir o `crop_params_dict` no arquivo de configuração durante a gravação.

**Determinando os Parâmetros de Corte**

Use o script `crop_dataset_roi.py` para selecionar interativamente regiões de interesse nas imagens da sua câmera:

```bash
python -m lerobot.rl.crop_dataset_roi --repo-id username/pick_lift_cube
```

1. Para cada visão da câmera, o script exibirá o primeiro quadro
2. Desenhe um retângulo ao redor da área relevante do espaço de trabalho
3. Pressione 'c' para confirmar a seleção
4. Repita para todas as visões da câmera
5. O script exibe os parâmetros de recorte e cria um novo conjunto de dados recortado

Exemplo de saída:

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

  Ferramenta interativa de recorte para selecionar regiões de interesse

**Atualizando a Configuração**

Adicione estes parâmetros de recorte à sua configuração de treinamento:

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

**Resolução de imagem recomendada**

A maioria das políticas baseadas em visão foi validada em entradas quadradas de **128×128** (padrão) ou **64×64** pixels. Portanto, recomendamos definir o parâmetro resize_size como [128, 128] – ou [64, 64] se você precisar economizar memória e largura de banda da GPU. Outras resoluções são possíveis, mas não foram amplamente testadas.

### Treinando um Classificador de Recompensa

O classificador de recompensa desempenha um papel importante no fluxo de trabalho do HIL-SERL ao automatizar a atribuição de recompensas e detectar automaticamente o sucesso dos episódios. Em vez de definir manualmente funções de recompensa ou depender de feedback humano para cada passo de tempo, o classificador de recompensa aprende a prever sucesso/falha a partir de observações visuais. Isso permite que o algoritmo de RL aprenda de forma eficiente, fornecendo sinais de recompensa consistentes e automatizados com base nas entradas da câmera do robô.

Este guia explica como treinar um classificador de recompensa para a implementação de aprendizado por reforço com intervenção humana (human-in-the-loop) do LeRobot. Os classificadores de recompensa aprendem a prever o valor da recompensa dado um estado, o que pode ser usado em uma configuração de RL para treinar uma política.

**Nota**: Treinar um classificador de recompensa é opcional. Você pode iniciar a primeira rodada de experimentos de RL anotando o sucesso manualmente com seu controle ou dispositivo de teclado.

A implementação do classificador de recompensas em `lerobot/rewards/classifier/modeling_classifier.py` usa um modelo de visão pré-treinado para processar as imagens. Ele pode gerar um único valor para recompensas binárias, a fim de prever casos de sucesso/falha, ou múltiplos valores para configurações de múltiplas classes.

**Coletando um Conjunto de Dados para o classificador de recompensa**

Antes do treinamento, você precisa coletar um conjunto de dados com exemplos rotulados. Definir `mode: "record"` na sua configuração e executar `gym_manipulator.py` habilita o processo de coleta de um conjunto de dados de observações, ações e recompensas.

Para coletar um conjunto de dados, você precisa modificar alguns parâmetros na configuração do ambiente com base em HILSerlRobotEnvConfig.

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

**Parâmetros-chave para a coleta de dados**

- **mode**: defina como `"record"` para coletar um conjunto de dados (no nível raiz)
- **dataset.repo_id**: `"hf_username/dataset_name"`, nome do dataset e do repositório no hub
- **dataset.num_episodes_to_record**: Número de episódios a serem gravados
- **env.processor.reset.terminate_on_success**: Se os episódios devem ser encerrados automaticamente quando o sucesso é detectado (padrão: `true`)
- **env.fps**: Número de quadros por segundo a serem gravados
- **dataset.push_to_hub**: Se deve enviar o dataset para o hub

O parâmetro `env.processor.reset.terminate_on_success` permite controlar o comportamento de término dos episódios. Quando definido como `false`, os episódios continuam mesmo após a detecção de sucesso, permitindo coletar mais exemplos positivos com o rótulo reward=1. Isso é crucial para o treinamento de classificadores de recompensa, pois fornece mais exemplos de estados de sucesso no seu conjunto de dados. Quando definido como `true` (padrão), os episódios terminam imediatamente ao detectar o sucesso.

**Importante**: Para o treinamento do classificador de recompensa, defina `terminate_on_success: false` para coletar exemplos positivos suficientes. Para o treinamento regular do HIL-SERL, mantenha como `true` para permitir o término automático do episódio quando a tarefa for concluída com sucesso.

Exemplo de seção de configuração para coleta de dados:

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

**Configuração do Classificador de Recompensa**

O classificador de recompensa é configurado usando `lerobot/rewards/classifier/configuration_classifier.py`. Aqui estão os principais parâmetros:

- **model_name**: Arquitetura do modelo base (por exemplo, usamos principalmente `"helper2424/resnet10"`)
- **model_type**: `"cnn"` ou `"transformer"`
- **num_cameras**: Número de entradas de câmera
- **num_classes**: Número de classes de saída (geralmente 2 para sucesso/falha binário)
- **hidden_dim**: Tamanho da representação oculta
- **dropout_rate**: Parâmetro de regularização
- **learning_rate**: Taxa de aprendizado para o otimizador

Exemplo de configuração para treinar o classificador de recompensa. Salve-o como `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"
}
```

**Treinando o Classificador**

Para treinar o classificador, use o script `train.py` com sua configuração:

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

**Implantação e Teste do Modelo**

Para usar seu classificador de recompensa treinado, configure o `HILSerlRobotEnvConfig` para usar seu modelo:

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

ou defina o argumento no arquivo de configuração 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
      }
    }
  }
}
```

Execute `gym_manipulator.py` para testar o modelo.

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

O classificador de recompensas fornecerá automaticamente recompensas com base na entrada visual das câmeras do robô.

**Exemplo de fluxo de trabalho para treinar o classificador de recompensa**

1. **Crie os arquivos de configuração**: Crie os arquivos de configuração json necessários para o classificador de recompensa e o ambiente: `reward_classifier_train_config.json` do exemplo acima e o `rl/env_config.json` baixado.

2. **Coletar um conjunto de dados**:

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

3. **Treinar o classificador**:

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

4. **Teste o classificador**:
   ```bash
   python -m lerobot.rl.gym_manipulator --config_path rl/env_config.json
   ```

### Treinamento com Actor-Learner

O sistema LeRobot usa uma arquitetura distribuída de ator-aprendiz para treinamento. Essa arquitetura desacopla as interações do robô do processo de aprendizado, permitindo que eles sejam executados simultaneamente sem bloquear um ao outro. O servidor de ator lida com as observações e ações do robô, enviando dados de interação para o servidor de aprendizado. O servidor de aprendizado executa a descida do gradiente e atualiza periodicamente os pesos da política do ator. Você precisará iniciar dois processos: um de aprendizado e um de ator.

**Configuração do Setup**

Edite o arquivo de configuração de treinamento que você baixou anteriormente, `rl/train_config.json` (exemplo disponível [aqui](https://huggingface.co/datasets/lerobot/config_examples/resolve/main/rl/train_config.json)). A configuração de treinamento é baseada na classe principal `TrainRLServerPipelineConfig` em `lerobot/rl/train_rl.py`.

1. Configure as configurações da política (`type="gaussian_actor"`, `device`, etc.)
2. Configure as configurações do algoritmo no bloco de nível superior `algorithm` (`type="sac"`, taxas de aprendizado, desconto, etc., definidas em `lerobot/rl/algorithms/sac/configuration_sac.py`).
3. Defina `dataset` como seu dataset recortado
4. Configure as configurações do ambiente com parâmetros de recorte
5. Verifique os outros parâmetros relacionados ao Ator Gaussiano em [configuration_gaussian_actor.py](https://github.com/huggingface/lerobot/blob/main/src/lerobot/policies/gaussian_actor/configuration_gaussian_actor.py#L79).
6. Verifique se a configuração `policy` está correta, com os `input_features` e `output_features` adequados para a sua tarefa.

**Iniciando o Learner**

Primeiro, inicie o processo do servidor de aprendizado:

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

O aprendiz:

- Inicializa a rede de política
- Prepara buffers de replay
- Abre um servidor `gRPC` para se comunicar com atores
- Processa transições e atualiza a política

**Iniciando o Actor**

Em um terminal separado, inicie o processo do ator com a mesma configuração:

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

O ator:

- Conecta-se ao learner via `gRPC`
- Inicializa o ambiente
- Execute rollouts da política para coletar experiência
- Envia transições para o aprendiz
- Recebe os parâmetros de política atualizados

**Fluxo de Treinamento**

O treinamento prossegue automaticamente:

1. O ator executa a política no ambiente
2. As transições são coletadas e enviadas ao aprendiz
3. O learner atualiza a política com base nessas transições
4. Os parâmetros de política atualizados são enviados de volta para o ator
5. O processo continua até que o limite de etapas especificado seja atingido

**Humano no Loop**

- A chave para aprender de forma eficiente é contar com intervenções humanas que forneçam feedback corretivo e completem a tarefa, auxiliando o aprendizado e a exploração da política.
- Para realizar intervenções humanas, você pode pressionar o gatilho superior direito no controle (ou a tecla `space` no teclado). Isso pausará as ações da política e permitirá que você assuma o controle.
- Um experimento bem-sucedido é aquele em que o humano precisa intervir no início, mas reduz a quantidade de intervenções à medida que a política melhora. Você pode monitorar a taxa de intervenção no dashboard do Trackio (`trackio show --project <project>`).

  <img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/hil_effect.png?raw=true" alt="A figura mostra os mapeamentos de controle em um controle de jogo Logitech." title="Mapeamento de Controle do Controle de Jogo" width="100%"
  >

  
    Exemplo mostrando como intervenções humanas ajudam a orientar o aprendizado de política ao longo do tempo
  

- A figura mostra o gráfico da recompensa episódica em função do passo de interação. A figura mostra o efeito das intervenções humanas no aprendizado da política.
- A curva laranja é um experimento sem nenhuma intervenção humana. Enquanto as curvas rosa e azul são experimentos com intervenções humanas.
- Podemos observar que o número de etapas em que a política começa a alcançar a recompensa máxima é reduzido em um quarto quando há intervenções humanas.

**Monitoramento e Depuração**

Se você tiver `trackio.enable` definido como `true` na sua configuração, pode monitorar o progresso do treinamento em tempo real por meio do painel [Trackio](https://huggingface.co/docs/trackio) (`trackio show --project <project>`).

### Guia de Intervenções Humanas

O processo de aprendizado é muito sensível à estratégia de intervenção. Serão necessários alguns testes para entender como intervir de forma eficaz. Algumas dicas e sugestões:

- Permita que a política explore por alguns episódios no início do treinamento.
- Evite intervenções por longos períodos. Tente intervir na situação para corrigir o comportamento do robô quando ele se desvia do caminho.
- Quando a política começa a realizar a tarefa, mesmo que não perfeitamente, você pode limitar suas intervenções a ações simples e rápidas, como comandos simples de preensão.

O comportamento ideal é que sua taxa de intervenção diminua gradualmente durante o treinamento, conforme mostrado na figura abaixo.

  <img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/intervention_rate_tutorial_rl.png?raw=true" alt="Taxa de intervenção" title="Taxa de intervenção durante o treinamento" width="100%"
  >

  
    Gráfico da taxa de intervenção durante uma execução de treinamento em uma tarefa de pegar e levantar um cubo
  

### Principais hiperparâmetros para ajustar

Alguns valores de configuração têm um impacto desproporcional na estabilidade e na velocidade do treinamento:

- **`temperature_init`** (`algorithm.temperature_init`) – temperatura inicial de entropia no SAC. Valores mais altos incentivam mais exploração; valores mais baixos tornam a política mais determinística no início. Um bom ponto de partida é `1e-2`. Observamos que configurá-la muito alta pode tornar as intervenções humanas ineficazes e desacelerar o aprendizado.
- **`policy_parameters_push_frequency`** (`policy.actor_learner_config.policy_parameters_push_frequency`) – intervalo em _segundos_ entre duas transferências de pesos do learner para o actor. O padrão é `4 s`. Diminua para **1-2 s** para fornecer pesos mais atualizados (ao custo de mais tráfego de rede); aumente apenas se sua conexão for lenta, pois isso reduzirá a eficiência da amostragem.
- **`storage_device`** (`policy.storage_device`) – dispositivo no qual o learner mantém os parâmetros da policy. Se você tiver memória GPU disponível, defina isso como `"cuda"` (em vez do padrão `"cpu"`). Manter os pesos na GPU elimina o overhead de transferência CPU→GPU e pode aumentar significativamente o número de atualizações do learner por segundo.

Parabéns 🎉, você concluiu este tutorial!

> [!TIP]
> Se você tiver alguma dúvida ou precisar de ajuda, entre em contato no [Discord](https://discord.com/invite/s3KuuzsPFb).

Citação do artigo:

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

