LeRobot入门教程 15:LeRobot 强化学习 (SAC)
1. 模仿学习和强化学习的区别
前面几册的内容(数据集、策略、微调)都属于模仿学习:照着人的演示学。它的天花板是演示数据的水平——人做不到的,模型也做不到。
强化学习(RL)换了个思路:不看演示,自己试,做对了给奖励。理论上能超过人类演示,代价是样本效率极低,真机上要几万次尝试。
| 模仿学习 | 强化学习 | |
|---|---|---|
| 数据 | 人的演示 | 自己采的轨迹 + 奖励 |
| 奖励信号 | 不需要 | 必须有(真机靠奖励模型) |
| 优点 | 快、稳、易复现 | 能超过演示水平 |
| 缺点 | 上限受演示限制 | 慢、不稳定、真机有风险 |
2. SAC 是什么
SAC(Soft Actor-Critic)是连续控制里最常用的 off-policy 算法之一,三个角色:
| 角色 | 类 | 作用 |
|---|---|---|
| Actor | GaussianActorPolicy | 输出动作的高斯分布,边学边探索 |
| Critic | 算法内部 | 估计「这个状态动作值多少」,SAC 用双 Q 网络缓解高估 |
| 经验池 | ReplayBuffer | 存历史 (s, a, r, s'),反复采样学习 |
「Soft」指的是在目标里加了熵项:鼓励策略保持一定随机性,别过早收敛到局部最优。
3. 一段最小接线演示
下面这段不是真训练,是「把管线接起来看能不能跑」的最小例子:随机数据的经验池 + 5 次更新。
import torch
from lerobot.configs.types import FeatureType, PolicyFeature
from lerobot.policies.gaussian_actor.configuration_gaussian_actor import GaussianActorConfig
from lerobot.policies.gaussian_actor.modeling_gaussian_actor import GaussianActorPolicy
from lerobot.rl import ReplayBuffer, RLTrainer, OnlineOfflineMixer, make_algorithm, make_algorithm_config
from lerobot.utils.constants import ACTION, OBS_STATE
cfg = GaussianActorConfig(device="cuda")
cfg.input_features = {OBS_STATE: PolicyFeature(type=FeatureType.STATE, shape=(8,))}
cfg.output_features = {ACTION: PolicyFeature(type=FeatureType.ACTION, shape=(7,))}
policy = GaussianActorPolicy(cfg).to("cuda")
sac = make_algorithm_config("sac")
sac.policy_config = cfg
algo = make_algorithm(cfg=sac, policy=policy)
rb = ReplayBuffer(capacity=2000, device="cuda", state_keys=[OBS_STATE], use_drq=False)
for _ in range(500):
rb.add(state={OBS_STATE: torch.randn(1, 8)}, action=torch.rand(1, 7) * 2 - 1, reward=0.0,
next_state={OBS_STATE: torch.randn(1, 8)}, done=False, truncated=False)
trainer = RLTrainer(algo, OnlineOfflineMixer(online_buffer=rb, online_ratio=1.0), batch_size=32)
for s in range(5):
st = trainer.training_step()
print(f"step {s}: critic_loss={st.losses['loss_critic']:.2f}")
step 0: critic_loss=35.86
step 1: critic_loss=29.99
step 2: critic_loss=20.88
step 3: critic_loss=15.41
step 4: critic_loss=9.47
4. 逐段解释
定义 actor 的输入输出:
cfg.input_features = {OBS_STATE: PolicyFeature(type=FeatureType.STATE, shape=(8,))}
cfg.output_features = {ACTION: PolicyFeature(type=FeatureType.ACTION, shape=(7,))}
这里的 8 和 7 就是 08 册《数据集》里 observation.state 和 action 的维度。LeRobot 用 PolicyFeature 显式声明特征类型和形状,好处是同一个 actor 类能适配不同机器人。
造算法:
sac = make_algorithm_config("sac"); sac.policy_config = cfg
algo = make_algorithm(cfg=sac, policy=policy)
make_algorithm_config 按名字取算法配置(还支持 tdmpc 等),把 actor 配置塞进去,再实例化——这样 critic、目标网络、优化器都由算法自己建。
经验池:
rb = ReplayBuffer(capacity=2000, device="cuda", state_keys=[OBS_STATE], use_drq=False)
capacity=2000:最多存 2000 条转移;device="cuda":经验池放在显存里,采样不经过 CPU,快很多;state_keys=[OBS_STATE]:告诉它状态字典里哪些键是状态(图像观测时这里会有多个键);use_drq=False:DRQ 是图像增强技巧,这里用低维状态就不需要。
接着往里塞 500 条随机数据:状态是 randn(1, 8),动作是 rand(1,7)*2-1(映射到 [-1,1]),奖励全 0。这些数据没有任何物理意义,只是为了把 buffer 填起来。
训练:
trainer = RLTrainer(algo, OnlineOfflineMixer(online_buffer=rb, online_ratio=1.0), batch_size=32)
for s in range(5):
st = trainer.training_step()
OnlineOfflineMixer 是「在线 + 离线数据混合采样」的封装,online_ratio=1.0 表示全部用在线数据。真机上常见做法是混一部分离线演示数据,缓解冷启动。
5. critic loss 从 35.86 降到 9.47 说明什么
step 0: critic_loss=35.86
step 1: critic_loss=29.99
step 2: critic_loss=20.88
step 3: critic_loss=15.41
step 4: critic_loss= 9.47
6. 真机 HIL-SERL
LeRobot 的真机 RL 走的是 HIL-SERL(Human-In-the-Loop SERL)路线:机器自己练,人偶尔接管纠正。它分两个进程:
python -m lerobot.rl.learner --config_path=train_config_hilserl_so100.json
python -m lerobot.rl.actor --config_path=train_config_hilserl_so100.json
| 进程 | 跑在哪 | 干什么 |
|---|---|---|
learner | 训练机(可以是有 GPU 的服务器) | 从经验池采样、更新 actor/critic |
actor | 连着机器人的那台 | 读相机、发动作、往经验池写数据 |
两者通过队列/网络通信,所以训练和控制在物理上可以分开,这对真机很重要:机器人那台机器只需要跑推理,不需要扛训练负载。
train_config_hilserl_so100.json 里要配的东西包括:机器人型号和串口、相机、奖励模型、学习率、buffer 大小、人工介入的开关方式。第一次跑之前务必先用仿真验证整套配置。
7. 真跑 RL 的前提
- 一个能用的奖励信号:仿真用真值,真机用 14 册的奖励模型,并且验证过它的排序和人类判断一致;
- 安全边界:动作限幅、工作空间限制、急停;
- 足够的时间:真机 RL 常以「小时」为单位计;
- 检查点策略:定期存,RL 训崩是常态;
- 先仿真后真机:同一个配置先在 LIBERO 里跑到能收敛,再上真机。