AiPaper
论文状态:已完成

Robot Learning: A Tutorial

发表:2025/10/14
原文链接PDF 下载
价格:0.10
价格:0.10
已有 2 人读过
本分析由 AI 生成,可能不完全准确,请以原文为准。

TL;DR 精炼摘要

本教程系统介绍机器人学习的核心方法,涵盖强化学习、行为克隆及通用语言条件机器人策略,突破传统基于模型方法的局限。通过数据驱动视角和lerobot示例,支持多任务、多机器人本体的泛化能力提升,推动机器人自主性和适应性发展。

摘要

Robot learning is at an inflection point, driven by rapid advancements in machine learning and the growing availability of large-scale robotics data. This shift from classical, model-based methods to data-driven, learning-based paradigms is unlocking unprecedented capabilities in autonomous systems. This tutorial navigates the landscape of modern robot learning, charting a course from the foundational principles of Reinforcement Learning and Behavioral Cloning to generalist, language-conditioned models capable of operating across diverse tasks and even robot embodiments. This work is intended as a guide for researchers and practitioners, and our goal is to equip the reader with the conceptual understanding and practical tools necessary to contribute to developments in robot learning, with ready-to-use examples implemented in lerobot\texttt{lerobot}.

思维导图

论文精读

中文精读

1. 论文基本信息

1.1. 标题

机器人学习:一个教程 (Robot Learning: A Tutorial)

1.2. 作者

论文中未明确列出具体作者,但根据 lerobotHugging Face 的提及,以及教程的性质,推测作者团队可能来自 Hugging Face 或其合作机构。

1.3. 发表期刊/会议

本工作以教程 (Tutorial) 形式发布,标题中并未提及具体的期刊或会议。鉴于原文链接指向 arXiv,它目前是一个预印本 (pre-print)。

1.4. 发表年份

2025年10月14日(UTC时间)

1.5. 摘要

本教程探讨了现代机器人学习的领域,其核心是机器学习的快速发展和大规模机器人数据的日益普及,这促使机器人领域从传统的、基于模型的范式转向数据驱动的、基于学习的范式,从而极大地提升了自主系统的能力。教程内容涵盖了从强化学习 (Reinforcement Learning, RL) 和行为克隆 (Behavioral Cloning, BC) 的基础原理,到能够在不同任务甚至不同机器人本体上运行的通用型、语言条件型模型。其目标是为研究人员和实践者提供概念理解和实用工具,以促进他们在机器人学习领域的发展,并提供在 lerobot 框架中实现的即用型示例。

1.6. 原文链接

  • 官方链接: https://arxiv.org/abs/2510.12403v1
  • PDF 链接: https://arxiv.org/pdf/2510.12403v1.pdf
  • 发布状态: 预印本

2. 整体概括

2.1. 研究背景与动机

论文试图解决的核心问题: 传统的、基于模型的机器人控制方法在应对复杂、动态和不确定的现实世界环境时面临泛化能力差、对人类专业知识依赖高以及难以有效利用大规模多模态数据等挑战。这限制了自主系统在多样化任务和环境中的应用。

为什么这个问题在当前领域是重要的?现有研究存在哪些具体的挑战或空白? 随着机器学习技术(特别是深度学习)的飞速发展,以及大规模机器人数据集的日益增长,机器人领域正经历一场范式转变。现有基于模型的机器人学虽然在特定、结构化环境下表现优异,但在以下方面存在挑战或空白:

  1. 泛化能力弱: 难以将习得的技能泛化到新的任务和不同的机器人本体 (embodiment) 上。
  2. 对人类专业知识依赖高: 精确的动力学建模和控制器设计需要大量人类专家知识和工程投入。
  3. 多模态数据处理不足: 难以直接处理原始、异构且嘈杂的多模态传感器数据流。
  4. 未充分利用开放数据增长: 无法有效利用日益增长的开放机器人数据集。
  5. 单任务/单模型限制: 通常为特定任务和机器人定制,难以实现通用性。

这篇论文的切入点或创新思路是什么? 本教程的切入点是提供一个全面、系统且实践性强的指南,帮助读者理解并掌握现代机器人学习的核心概念和工具。它通过结合理论基础(强化学习、行为克隆)和 lerobot 框架中的具体代码示例,展示了如何从数据驱动的视角解决机器人控制问题,从而克服传统方法的局限性,并为开发通用型、语言条件型机器人策略提供路径。

2.2. 核心贡献/主要发现

论文最主要的贡献是什么? 该教程的主要贡献在于:

  1. 系统性概述: 首次全面而严谨地概述了现代机器人学习的图景,从基础的强化学习和行为克隆,到最新的通用型、语言条件型机器人模型。
  2. 理论与实践结合: 将机器人学习的理论概念与 lerobot 开源库中的实际实现相结合,提供了可直接使用的代码示例,极大地降低了学习和实践的门槛。
  3. 强调数据驱动范式: 明确指出了数据驱动、学习型方法如何克服传统基于模型的机器人学的局限性,特别是在泛化能力、对多模态数据的处理以及对大规模数据利用方面的优势。
  4. 推广 lerobot 框架: lerobot 是一个旨在整合整个机器人技术栈的开源库,本教程通过详细介绍其数据集格式和实际应用(如 HIL-SERL),推动了该框架的普及和使用。

论文得出了哪些关键的结论或发现?这些发现解决了什么具体问题?

  1. 数据驱动范式的潜力: 机器人学习通过大规模数据和计算,实现了传统模型驱动方法难以达到的泛化能力和鲁棒性,解决了机器人系统在复杂动态环境中适应性差的问题。
  2. lerobot 的实用性: lerobot 框架为机器人学习提供了一个统一的、易于使用的平台,解决了数据处理、模型实现和真实世界部署中的诸多工程挑战。
  3. RL 和 BC 的互补性: 强化学习擅长通过试错探索最优策略,但面临样本效率和奖励设计难题;行为克隆擅长从专家演示中高效学习,但受限于演示数据的质量和覆盖范围。现代方法常常结合两者的优势。
  4. HIL-SERL (人机协作样本高效强化学习) 的有效性: 论文展示了 HIL-SERL 这种结合人类干预和离线数据的在线强化学习方法,能在短时间内(1-2小时)实现高成功率,解决了真实世界机器人强化学习中样本效率低和奖励设计困难的问题。

3. 预备知识与相关工作

3.1. 基础概念

为了帮助初学者理解本教程,以下将对其中涉及的核心概念进行详细解释:

  • 机器人学习 (Robot Learning): 这是一个交叉学科领域,旨在使机器人通过与环境的互动或从数据中学习来获取技能和行为。它结合了机器人学、机器学习、人工智能和控制理论等知识。

  • 强化学习 (Reinforcement Learning, RL): 机器学习的一个分支,智能体 (agent) 通过与环境的不断互动,学习如何采取行动以最大化长期累积奖励。智能体在不同状态 (state) 下选择动作 (action),环境根据动作反馈奖励 (reward) 并转移到新状态。

  • 行为克隆 (Behavioral Cloning, BC): 一种模仿学习 (imitation learning) 的形式,智能体通过学习专家演示数据 (expert demonstration data) 中的状态-动作对,直接模仿专家的行为。本质上是监督学习,将状态作为输入,专家的动作作为输出进行训练。

  • 模型驱动 (Model-based) 方法: 在机器人学中,这类方法依赖于精确的机器人和环境的数学模型(如动力学方程、几何模型)来规划和控制。优点是可解释性强、理论严谨,缺点是模型建立困难、对模型误差敏感、泛化能力差。

  • 数据驱动 (Data-driven) 方法: 这类方法通过从大量数据中学习模式来控制机器人,不依赖于显式的数学模型。优点是泛化能力强、可以处理复杂和不确定的环境,缺点是需要大量数据、计算资源,且模型往往是“黑箱”。

  • 多模态数据 (Multimodal Data): 指来自不同传感器类型的数据,例如视觉(RGB图像)、深度信息、触觉(力/扭矩)、本体感受(关节角度、速度)等。在机器人学习中,整合多模态信息有助于智能体更全面地感知环境。

  • 机器人本体 (Robot Embodiment): 机器人的物理形态、结构、传感器和执行器配置。不同的本体意味着不同的运动能力和感知方式。

  • 泛化 (Generalization): 机器学习模型在训练数据之外的、未见过的新任务、新环境或新机器人本体上表现良好、执行有效的能力。

  • Markov 决策过程 (Markov Decision Process, MDP): 强化学习中用于形式化描述顺序决策问题的数学框架。它包括状态空间 (state space)、动作空间 (action space)、状态转移函数 (transition function)、奖励函数 (reward function) 和折扣因子 (discount factor)。

  • 正运动学 (Forward Kinematics, FK): 根据机器人各关节的已知角度(或位置),计算机器人末端执行器 (end-effector) 在笛卡尔空间中的位置和姿态。

  • 逆运动学 (Inverse Kinematics, IK): 根据机器人末端执行器在笛卡尔空间中的期望位置和姿态,反向计算出机器人各关节所需的角度(或位置)。通常比正运动学更复杂,可能存在多个解或无解。

  • 微分逆运动学 (Differential Inverse Kinematics, Dif-IK): 关注末端执行器速度与关节速度之间的关系。通过雅可比矩阵 (Jacobian matrix),可以将末端执行器的线速度和角速度与关节的角速度(或线速度)关联起来。常用于实时轨迹跟踪控制。

  • 轨迹跟踪 (Trajectory Tracking): 机器人控制器试图使其末端执行器或某个特定点沿着预定义的路径(轨迹)精确移动的任务。

  • 反馈控制 (Feedback Control): 一种控制策略,系统通过测量输出(如传感器数据)与期望输出之间的误差,并利用这个误差来调整控制输入,以使系统输出尽可能接近期望值。

3.2. 前人工作

本教程引用了机器人学和强化学习领域的经典及最新研究,为读者提供了理解机器人学习发展脉络的背景。

  • 经典机器人学基础:

    • Siciliano and Khatib (2016): 《Springer Handbook of Robotics》,机器人学领域的权威参考书,涵盖了从运动学、动力学到控制等经典机器人学的方方面面。教程中提到其在正运动学 (FK)、逆运动学 (IK)、微分逆运动学 (dif-IK) 和控制方面的详细内容。
    • Lynch and Park (2017): 《Modern Robotics: Mechanics, Planning, and Control》,另一本机器人学经典教材,提供了机械臂运动学、动力学和运动规划的全面介绍。
    • Tedrake (a,b): 教程中多次引用,可能指代其在控制和优化方面的贡献,例如模型预测控制 (Model Predictive Control, MPC) 或基于优化的运动规划。
  • 强化学习基础:

    • Sutton and Barto (2018): 《Reinforcement Learning: An Introduction》,强化学习领域的圣经级教材,是理解 RL 核心概念(如 MDP、价值函数、策略梯度)的基石。
  • 机器人强化学习与行为克隆算法 (lerobot中实现的SOTA算法): 本教程特别提到了 lerobot 框架中实现的多种先进算法,这些是现代机器人学习的代表。

    • Action Chunking with Transformers (ACT) (Zhao et al., 2023): 一种利用 Transformer 模型进行动作块预测的方法,旨在处理高维动作空间和长序列依赖。
    • Diffusion Policy (Chi et al., 2024): 将扩散模型 (Diffusion Models) 应用于机器人策略学习,通过去噪过程生成平滑且多样化的动作序列。
    • Vector-Quantized Behavior Transformer (VQ-BeT) (Lee et al., 2024): 结合向量量化和 Transformer,学习离散化的行为模式。
    • π0\pi_0 (Black et al., 2024): 一个可能指代通用型机器人基础模型的工作,强调多任务和多模态能力。
    • SmolVLA (Shukor et al., 2025): 另一个通用型视觉-语言-动作 (Vision-Language-Action, VLA) 模型,旨在实现跨任务和跨机器人本体的泛化。
    • Human-in-the-loop Sample-efficient RL (HILSERL) (Luo et al., 2024): 一种结合人类干预来提高真实世界强化学习样本效率的方法。
    • TD-MPC (Hansen et al., 2022): 结合时序差分 (Temporal Difference) 学习和模型预测控制,以提高样本效率和控制性能。
  • 特定强化学习算法:

    • Mnih et al. (2013, 2015): 提出 Deep Q-Network (DQN),将深度学习与 Q-learning 结合,首次在 Atari 游戏中达到人类水平,标志着深度强化学习的开端。
    • Silver et al. (2014): 提出 Deterministic Policy Gradient (DPG),为连续动作空间强化学习奠定了基础。
    • Lillicrap et al. (2015): 提出 Deep Deterministic Policy Gradient (DDPG),是 DPG 的深度学习版本,结合了 DQN 的思想(如经验回放、目标网络)。
    • Haarnoja et al. (2018): 提出 Soft Actor-Critic (SAC),一种基于最大熵 (MaxEnt) 框架的强化学习算法,旨在鼓励探索和学习多样化行为,同时保持样本效率和性能。

3.3. 技术演进

机器人领域的技术演进经历了从早期的基于精确数学模型的控制(如运动学、动力学、路径规划)到机器学习技术融入感知和决策,再到如今大规模数据驱动的机器人学习范式。

  1. 经典机器人学 (50年代至今): 早期聚焦于机械设计、运动学、动力学和基于模型的控制。机器人通过精确建模和规划来执行任务,如工业机械臂。核心挑战是模型精确性、实时计算和对环境变化的鲁棒性。

  2. 机器学习的介入 (90年代至今): 随着机器学习的兴起,其在机器人感知(如视觉识别、SLAM)和部分决策(如分类、回归)中发挥作用。但控制层面仍多采用传统方法。

  3. 深度学习与强化学习的融合 (2010年代至今): 深度学习在处理高维感知数据(图像、视频)方面取得突破,与强化学习结合形成了深度强化学习,使得机器人可以直接从原始传感器输入学习复杂的感知-动作映射,尤其是在虚拟环境中。

  4. 数据驱动范式的崛起 (近年): 随着大规模开放机器人数据集的出现和计算能力的提升,机器人学习越来越倾向于从海量数据中学习通用技能。这包括行为克隆、模仿学习以及通用型、语言条件型机器人基础模型。这些方法旨在解决传统方法的泛化能力、对人类专业知识依赖和多模态处理能力不足的问题。

    本教程的工作正是处于这一技术演进的最新阶段,它旨在引导读者从传统概念过渡到现代数据驱动的机器人学习,特别是强调了像 lerobot 这样的开源框架在整合这些技术栈中的作用。

3.4. 差异化分析

本教程与传统机器人学著作或纯理论型论文相比,其核心区别和创新点在于:

  • 教程性与实践性: 它并非一篇提出新算法的原创研究,而是一个指南 (tutorial)。其目标是系统地梳理和介绍现代机器人学习的最新进展,并特别强调实践应用。通过与 lerobot 开源库深度结合,提供了大量的代码示例,这是许多纯学术论文所不具备的。
  • 整合性和全面性: 教程覆盖了从经典机器人学的局限性,到强化学习和行为克隆的基础理论,再到最新的通用型、语言条件型机器人模型的全景图。它将这些不同层次的知识整合在一个框架下,为读者提供了一个清晰的学习路径。
  • 面向未来趋势: 教程明确指出了机器人学习领域从模型驱动向数据驱动的范式转变,并重点介绍了如何利用大规模数据、多模态输入以及语言指令来构建更通用、更灵活的机器人系统,这体现了对前沿趋势的敏锐洞察。
  • 降低门槛: 通过 lerobot 提供的统一数据集格式、算法实现和易于上手的代码,该教程旨在显著降低研究人员和实践者进入机器人学习领域的门槛,促进该领域的快速发展和复现性。
  • 强调真实世界应用: 教程中强调了真实世界强化学习面临的挑战(如样本效率、奖励设计)以及解决方案(如域随机化、HIL-SERL),这使得其内容更具实用价值。

4. 方法论

本教程旨在通过对机器人学习理论和实践的结合,引导读者理解现代机器人学习的图景。方法论部分将深入剖析教程中介绍的各种概念、公式和 lerobot 框架下的代码实现。

4.1. lerobot 数据集与数据处理

lerobot 数据集 (LeRobotDataset) 是 lerobot 框架的核心,旨在高效地处理机器人学习中常见的各种复杂数据模态,并与 PyTorchHugging Face 生态系统无缝集成。

4.1.1. 数据集类设计

LeRobotDataset 的设计理念是将底层的数据存储与用户友好的应用程序接口 (API) 分离,以实现高效存储同时提供直观、即用型的数据格式。

数据集主要由三部分组成:

  1. 元数据 (Metadata): 描述数据集的总体信息,如帧率、版本、数据路径模板等。

  2. 映射文件 (Mapped Files): 通常卸载到 Hugging Facedatasets 库,提供快速且内存消耗有限的数据访问。

  3. 数据 (Data): 实际的传感器数据和机器人状态。

    数据集的物理组织结构如下所示:

  • /metadata.json: 包含数据集的元信息,例如帧率 (fps)、lerobot 版本以及数据和视频文件的路径模板。
  • /meta_stats.json: 存储数据集的统计信息,如数据归一化参数,对大多数策略模型和外部访问非常重要。
  • /meta_tasks.json: 包含有关数据集中任务的元数据,对于任务条件型策略训练很有用。
  • /meta_episodes/: 包含每个独立回合的元数据,如长度、初始任务和策略。为了可扩展性,通常存储在多个文件中而非一个大型 JSON 文件中。
  • /data/: 包含核心的逐帧表格数据,使用 parquet 文件存储,支持快速内存映射访问。为了优化性能和处理大型数据集,多个回合的数据通常会拼接成一个或多个 parquet 文件。
  • /videos/: 包含所有视觉观测流的 MP4 视频文件。与 /data/ 目录类似,多个回合的视频片段也会拼接成单个文件,以减少文件系统中的文件数量,提高现代文件系统的效率。

4.1.2. 代码示例:批处理(流式)数据集

在实际应用中,大多数强化学习 (RL) 和行为克隆 (BC) 算法通常在帧堆栈上操作。例如,RL 算法可能使用历史帧 OtHo:tO_{t-H_o:t} 来缓解部分可观测性问题,而 BC 算法通常训练用于回归多动作块 (at+t+Ha)( \boldsymbol { a } _ { t + t + H _ { a } } ) 而非单个控制命令。LeRobotDataset 提供了定义帧周围时间窗(之前和之后)的功能,以支持这种帧堆叠。不可用的帧会被填充 padding masks。它还与 torch.utils.data.DataLoader 等更高级别的包装器兼容,以方便批处理。

此外,LeRobotDataset 原生支持数据集的流式模式。用户可以从 Hugging Face Hub 流式传输大型数据集,只需通过一行代码更改即可实现,无需下载整个数据集。流式数据集在处理大量数据时,可以避免高内存和存储消耗。

以下是原文 Code 1: Batching a (Streaming) Dataset 的代码:

import torch   
from lerobot.datasets.lerobot_dataset import LeRobotDataset   
from lerobot.datasets.streaming_dataset import StreamingLeRobotDataset   

delta_timestamps = {
    # 0.2, and O.1 seconds *before* each frame   
    "observation.images.wrist_camera": [-0.2, -0.1, 0.0]   
}   

# Optionally use StreamingLeRobotDataset to avoid downloading the dataset   
dataset = LeRobotDataset(   
    "lerobot/svla_so101_pickplace",   
    delta_timestamps = delta_timestamps   
)   

# Streams frames from the Hugging Face Hub without loading into memory   
streaming_dataset = StreamingLeRobotDataset(   
    "lerobot/svla_so101_pickplace",   
    delta_timestamps = delta_timestamps   
)   

# Get the 100th frame in the dataset by   
sample = dataset[100]   
print(sample)   
# {   
# 'observation.state': tensor([...]),   
# 'action': tensor([...]),   
# 'observation.images.wrist_camera': tensor([3, C, H, W]), for delta timesteps   
#   
# }   

batch_size = 16   
# wrap the dataset in a DataLoader to use process it batches for training purposes   
data_loader = torch.utils.data.DataLoader(   
    dataset,   
    batch_size = batch_size   
)   

# Iterate over the DataLoader in a training loop   
num_epochs = 1   
device = "cuda" if torch.cuda.is_available() else "cpu"   

for epoch in range(num_epochs):   
    for batch in data_loader:   
        # Move data to the appropriate device (e.g., GPU)   
        observations = batch["observation.state"].to(device)   
        actions = batch["action"].to(device)   
        images = batch["observation.images.wrist_camera"].to(device)   

        # Next, you can do amazing_model.forward(batch)   

代码解释:

  1. delta_timestamps: 这是一个字典,定义了对于特定观测(例如 wrist_camera 的图像),需要获取当前帧以及当前帧之前 0.2 秒和 0.1 秒的帧。这实现了帧堆叠,为策略提供时序信息。
  2. LeRobotDatasetStreamingLeRobotDataset:
    • LeRobotDataset 会下载整个数据集到本地。
    • StreamingLeRobotDataset 允许直接从 Hugging Face Hub 流式传输数据,避免了本地存储的限制,特别适用于大型数据集。
  3. dataset[100]: 演示如何访问数据集中的单个样本(第100帧),并打印其结构,包括状态、动作和堆叠后的图像。图像的形状 [3, C, H, W] 表示 3 个时间步的图像(对应 delta_timestamps 定义的 [0.2,0.1,0.0][-0.2, -0.1, 0.0]),每个图像有 CC 个通道,HH 高度,WW 宽度。
  4. torch.utils.data.DataLoader:LeRobotDataset 封装成一个数据加载器,使其能够按 batch_size 进行批处理,并在训练循环中迭代。
  5. 训练循环: 演示了一个基本的训练循环,其中 DataLoader 迭代生成批次数据,并将数据移动到指定设备(如 GPU)上,为模型前向传播做准备。

4.1.3. 代码示例:数据采集

lerobot 框架不仅支持数据使用,也支持数据采集。通过命令行界面 (lerobot-record --help) 或 Python 脚本可以记录数据。该代码示例展示了如何使用 lerobot 库来记录机器人数据。

以下是原文 Code 2: Record a Dataset 的代码:

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.so10o_follower import S0100Follower, S0100FollowerConfig 
from lerobot.teleoperators.so100_leader.config_so100_leader import S0100LeaderConfig 
from lerobot.teleoperators.so100_leader.so100_leader import S0100Leader 
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 

NUM_EPISODES = 5 
FPS = 30 
EPISODE_TIME_SEC = 60 
RESET_TIME_SEC = 10

TASK_DESCRIPTION = "..." # provide a task description   

HF_USER = "..." # provide your Hugging Face username   

follower_port = "..." # find your ports running: lerobot-find-port   
leader_port = "..."   
follower_id = "..." # to load the calibration file   
leader_id = "..."   

# Create the robot and teleoperator configurations   
camera_config = {
    "front": OpenCVCameraConfig(   
        index_or_path = 0, width = 640, height = 480, fps = FPS   
    )   
}   
robot_config = S0100FollowerConfig(   
    port = follower_port,   
    id = follower_id,   
    cameras = camera_config   
)   
teleop_config = S0100LeaderConfig(   
    port = leader_port,   
    id = leader_id   
)   

# Initialize the robot and teleoperator   
robot = S0100Follower(robot_config)   
teleop = S0100Leader(teleop_config)   

# Configure the dataset features   
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}   

# Create the dataset where to store the data   
dataset = LeRobotDataset.create(   
    repo_id = f"{HF_USER}/robot-learning-tutorial-data",   
    fps = FPS,   
    features = dataset_features,   
    robot_type = robot.name,   
    use_videos = True,   
    image_writer_threads = 4,   
)   

# Initialize the keyboard listener and rerun visualization   
events = init_keyboard_listener()   
init_rerun(session_name = "recording")   

# Connect the robot and teleoperator   
robot.connect()   
teleop.connect()   

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 = teleop,   
        dataset = dataset,   
        control_time_s = EPISODE_TIME_SEC,   
        single_task = TASK_DESCRIPTION,   
        display_data = True,   
    )   

    # Reset the environment if not stopping or re-recording   
    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 = 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   

# Clean up   
log_say("Stop recording")   
robot.disconnect()   
teleop.disconnect()   
dataset.push_to_hub()

代码解释:

  1. 参数配置: 定义了录制的回合数 NUM_EPISODES、帧率 FPS、每个回合的时间 EPISODE_TIME_SEC、重置时间 RESET_TIME_SECTASK_DESCRIPTIONHF_USER 需要用户自行填写。机器人和遥操作器 (teleoperator) 的端口和ID也需配置。
  2. 机器人与遥操作器配置:
    • OpenCVCameraConfig: 配置摄像头,指定索引、分辨率和帧率。
    • S0100FollowerConfig: 配置机器人(遵循者),包括端口、ID和摄像头配置。
    • S0100LeaderConfig: 配置遥操作器(领导者),包括端口和ID。
    • S0100FollowerS0100Leader: 实例化机器人和遥操作器对象。
  3. 数据集特征配置:
    • hw_to_dataset_features: 将机器人硬件的动作特征 (robot.action_features) 和观测特征 (robot.observation_features) 转换为数据集所需的特征格式。
    • dataset_features: 合并动作和观测特征。
  4. 创建数据集:
    • LeRobotDataset.create: 创建一个新的 LeRobotDataset 实例,指定 repo_id(将上传到 Hugging Face Hub)、帧率、特征、机器人类型、是否使用视频和图像写入线程数。
  5. 初始化辅助工具:
    • init_keyboard_listener(): 初始化键盘事件监听器,用于捕获用户输入(如停止录制、重新录制)。
    • init_rerun(): 初始化 rerun 可视化工具(如果使用),用于实时显示录制数据。
  6. 连接与录制循环:
    • robot.connect()teleop.connect(): 连接机器人和遥操作器。
    • while 循环: 持续录制直到达到指定回合数或用户停止。
    • record_loop(): 这是核心的录制函数,负责在指定时间内收集机器人状态、动作和传感器数据,并将其存储到 dataset 中。
    • 环境重置与重新录制: 循环内包含环境重置逻辑,以及用户通过键盘事件触发重新录制当前回合的功能 (rerecord_episode)。
    • dataset.save_episode(): 每个回合结束后,将当前回合的数据保存到数据集中。
  7. 清理与推送:
    • robot.disconnect()teleop.disconnect(): 断开机器人和遥操作器连接。

    • dataset.push_to_hub(): 将收集到的完整数据集推送到 Hugging Face Hub

      这部分代码展示了 lerobot 如何实现从硬件设备收集原始机器人数据,并将其结构化为 LeRobotDataset 格式的完整流程。

4.2. 经典机器人学 (Classical Robotics)

本教程通过回顾经典机器人学,旨在突出其局限性,从而引出机器人学习的必要性。

4.2.1. 显式模型与隐式模型

在机器人学中,生成运动的方法大致分为两类:

  • 显式模型 (Explicit Models): 这类方法,如基于动力学的方法,利用机器人本体及其与环境交互的预测力学模型。例如,使用预定义的物理方程来计算关节扭矩以实现期望运动。

  • 隐式模型 (Implicit Models): 这类方法,如现代机器学习方法,通过从多模态传感器数据中学习统计模式来生成运动。它不直接依赖于物理模型,而是从数据中提取行为规律。

    下图 (images/2.jpg) 展示了生成运动的显式建模和隐式建模两大类方法。

    该图像是由两部分组成的示意图,左侧(A)展示机器人抓取物体的起止状态及环境视角,右侧(B)展示了机器人头部的三个不同旋转姿态,形象说明机器人的视觉或姿态调整过程。 该图像是由两部分组成的示意图,左侧(A)展示机器人抓取物体的起止状态及环境视角,右侧(B)展示了机器人头部的三个不同旋转姿态,形象说明机器人的视觉或姿态调整过程。

  • 图像解释:

    • 左侧的“显式建模”部分包括正运动学 (Forward Kinematics)、逆运动学 (Inverse Kinematics) 和基于控制的规划 (Control-based Planning),这些都依赖于明确的数学模型。
    • 右侧的“隐式建模”部分包括深度强化学习 (Deep Reinforcement Learning, DRL)、专家演示学习 (Learning from Expert Demonstration, LED) 和行为克隆 (Behavioral Cloning, BC) 等,这些方法通过数据而非显式模型来学习运动。
    • 图中间的双向箭头表示显式和隐式模型之间存在融合和互补的可能性。

4.2.2. 不同类型的运动

机器人运动可以根据其与环境的交互方式分为三类:

  1. 操作 (Manipulation): 机器人通过末端执行器 (end-effector) 改变环境中的物体,例如抓取、放置、组装。

  2. 运动 (Locomotion): 机器人改变自身在环境中的位置,例如行走、奔跑、驾驶。

  3. 全身控制 (Whole-body Control): 结合了操作和运动,机器人需要同时协调其身体和末端执行器来与环境进行复杂交互,通常涉及更多的控制变量。

    下图 (images/3.jpg) 形象地展示了这三类任务的机器人形态:

    Figure 10| Overview of the robot learning methods implemented in lerobot. All algorithms are implemented in Pytorch. References: Zhao et al. (2023); Chi et al. (2024); Lee et al. (2024); Black et al.… 该图像是论文Robot Learning中图10的示意图,展示了lerobot中实现的机器人学习方法框架,分为行为克隆(BC)和强化学习(RL),细分多任务策略和算法。

  • 图像解释:
    • 左侧 (1) 展示了一个机械臂正在进行操作任务。
    • 中间 (2) 展示了一个四足机器人正在进行运动任务。
    • 右侧 (3) 展示了一个人形机器人,其全身的协调运动可以同时涉及操作和运动,体现了全身控制的复杂性。

4.2.3. 示例:平面操作 (Planar Manipulation)

教程以简化版的SO-100机械臂为例,详细阐述了经典运动学和控制的概念。

下图 (images/4.jpg) 展示了SO-100机械臂在成本与可达性上的定位,表明其是一种低成本、高可达性的平台:

Figure 12 | Agent-Environment interaction diagram (image credits to Sutton and Barto (2018)). 该图像是图12,展示了代理(agent)与环境(environment)之间的交互示意图,说明了状态 sts_t、动作 ata_t 和奖励 rtr_t 的传递过程。

下图 (images/5.jpg) 展示了一个通用机械臂的关节和连杆结构:

Figure 13 | Popular RL algorithms. See Achiam (2018) for a complete list of citations. 该图像是图表,展示了图13中常见的强化学习(RL)算法分类,包括基于模型(Model-based)和无模型(Model-free)的方法,细分为策略优化和Q学习两类,列举了相关算法名称。

  • 图像解释: 左侧是一个实际的机械臂,展示了其肩部、肘部和腕部关节。右侧是该机械臂的简化模型,清晰地标识了关节 (joints)、连杆 (links) 以及它们之间的参考坐标系,这对于理解运动学至关重要。

    考虑一个简化的SO-100机器人,其运动仅限于肩部平面运动(肩部俯仰和肘部弯曲),这将其自由度从原始的5+1(5个关节+1个夹爪)减少到2+1(肩部俯仰、肘部弯曲+夹爪)。当不考虑夹爪的运动时,机器人可简化为一个平面机械臂。 假设连杆长度为 ll,两个关节角分别为 θ1\theta_1θ2\theta_2

  1. 正运动学 (Forward Kinematics, FK): 根据关节角度 q=[θ1,θ2]q = [\theta_1, \theta_2],计算末端执行器位置 pR2p \in \mathbb{R}^2p(q)=(px(θ1,θ2)py(θ1,θ2))=(lcos(θ1)+lcos(θ1+θ2)lsin(θ1)+lsin(θ1+θ2))Sl1+l2n=2={p(q)R2:p(q)22(2l)2, q1} p(q) = \begin{pmatrix} p_x(\theta_1, \theta_2) \\ p_y(\theta_1, \theta_2) \end{pmatrix} = \begin{pmatrix} l \cos(\theta_1) + l \cos(\theta_1 + \theta_2) \\ l \sin(\theta_1) + l \sin(\theta_1 + \theta_2) \end{pmatrix} \in S_{l_1 + l_2}^{n=2} = \{ p(q) \in \mathbb{R}^2 : \|p(q)\|_2^2 \leq (2l)^2, \ \forall q_1 \} 符号解释:

    • p(q): 末端执行器在二维空间中的位置向量,它是机器人配置 qq 的函数。
    • q=[θ1,θ2]q = [\theta_1, \theta_2]: 机器人的配置,由两个关节角度组成。
    • θ1\theta_1: 第一个关节(肩部)的角度。
    • θ2\theta_2: 第二个关节(肘部)的角度。
    • ll: 机械臂每个连杆的长度。这里假设两个连杆长度相同。
    • px(θ1,θ2)p_x(\theta_1, \theta_2): 末端执行器位置的 xx 坐标。
    • py(θ1,θ2)p_y(\theta_1, \theta_2): 末端执行器位置的 yy 坐标。
    • Sl1+l2n=2S_{l_1 + l_2}^{n=2}: 机械臂末端执行器可以到达的工作空间。当 l1=l2=ll_1=l_2=l 时,这个工作空间是一个以原点为中心、半径为 2l 的圆盘。
    • p(q)22(2l)2\|p(q)\|_2^2 \leq (2l)^2: 表示末端执行器位置向量的欧几里得范数平方小于等于 (2l)2(2l)^2,即末端执行器位于半径为 2l 的圆内。
  2. 逆运动学 (Inverse Kinematics, IK): 给定期望的末端执行器目标位置 pp^*,求解对应的关节配置 qq。通常没有解析解,需要通过优化方法求解: minqQp(q)p22 \operatorname*{min}_{\boldsymbol{q} \in \mathcal{Q}} \|\boldsymbol{p}(\boldsymbol{q}) - \boldsymbol{p}^*\|_2^2 符号解释:

    • q\boldsymbol{q}: 机器人的关节配置向量,例如 [θ1,θ2][\theta_1, \theta_2]
    • Q\mathcal{Q}: 合法的关节配置空间,考虑到关节限位和障碍物等约束。
    • p(q)\boldsymbol{p}(\boldsymbol{q}): 给定关节配置 q\boldsymbol{q} 时末端执行器在空间中的位姿(在此简化案例中是位置)。
    • p\boldsymbol{p}^*: 目标末端执行器位姿(位置)。
    • 22\|\cdot\|_2^2: L2 范数的平方,表示欧几里得距离的平方。这个表达式衡量了当前末端执行器位置 p(q)\boldsymbol{p}(\boldsymbol{q}) 与目标位置 p\boldsymbol{p}^* 之间的误差平方。优化目标是最小化这个误差。
  3. 微分逆运动学 (Differential Inverse Kinematics, Dif-IK): 用于在控制周期内跟踪期望的末端执行器速度 p˙\dot{p}^*。通过雅可比矩阵 J(q)=fFK(q)qJ(q) = \frac{\partial f_{FK}(q)}{\partial q} 关联关节速度 q˙\dot{q} 和末端执行器速度 p˙\dot{p} (p˙=J(q)q˙ \dot{p} = J(q)\dot{q} )。求解关节速度 q˙(t)\dot{q}(t) 以最小化与期望末端执行器速度的差异: q˙(t)=argminνJ(q(t))νp˙(t)22 \dot{q}(t) = \operatorname*{argmin}_{\nu} \|J(q(t))\nu - \dot{p}^*(t)\|_2^2 符号解释:

    • q˙(t)\dot{q}(t): 在时间 tt 机器人的关节速度向量,是我们需要求解的变量。

    • ν\nu: 代表待优化的关节速度向量。

    • J(q(t)): 在当前关节配置 q(t) 下的雅可比矩阵。雅可比矩阵将关节速度映射到末端执行器速度。

    • p˙(t)\dot{p}^*(t): 在时间 tt 期望的末端执行器速度。

    • 22\|\cdot\|_2^2: L2 范数的平方。这个表达式衡量了通过关节速度 ν\nu 产生的末端执行器速度 J(q(t))νJ(q(t))\nu 与期望的末端执行器速度 p˙(t)\dot{p}^*(t) 之间的误差平方。优化目标是找到最小化这个误差的关节速度 ν\nu

      该优化问题通常有闭式解:q˙=J(q)+p˙\dot{q} = J(q)^+\dot{p}^*,其中 J(q)+J(q)^+ 是雅可比矩阵的 Moore-Penrose 伪逆。然后通过 qt+1=qt+Δtq˙tq_{t+1} = q_t + \Delta t \dot{q}_t 可以重构离散时间步的关节配置。

下图 (images/6.jpg) 展示了平面机械臂在不同约束下的运动空间:

该图像是机器人实体与仿真模型的对比示意图,左侧为机器人仿真模型,右侧为对应的实体机器人。图像展示了从虚拟仿真到真实硬件的移植关系,呼应论文中机器人学习的应用场景。 该图像是机器人实体与仿真模型的对比示意图,左侧为机器人仿真模型,右侧为对应的实体机器人。图像展示了从虚拟仿真到真实硬件的移植关系,呼应论文中机器人学习的应用场景。

  • 图像解释:
    • (a) 自由运动的平面机械臂,关节角度 θ1,θ2\theta_1, \theta_2 可以在 [π,+π][-\pi, +\pi] 范围内自由变化。
    • (b) 机械臂受到一个平面(如桌面)的约束,关节角度 θ1\theta_1 只能在 [0,π][0, \pi] 范围内变化。
    • (c) 机械臂除了受到平面约束外,还受到一个圆形障碍物的约束,进一步限制了关节角度的变化范围,此时可行配置空间 Q\mathcal{Q} 变得更加复杂。

4.2.4. 添加反馈回路

为了缓解模型误差、传感噪声和外部扰动(例如环境中移动的障碍物)的影响,经典机器人学引入了反馈控制。例如,将测量到的末端执行器位姿与期望位姿之间的误差 Δp=pp(q)\Delta p = p^* - p(q) 引入控制器,修正关节速度控制律为 q˙=J(q)+(p˙+kpΔp)\dot{q} = J(q)^+ (\dot{p}^* + k_p \Delta p),其中 kpk_p 是比例增益。

下图 (images/7.jpg) 展示了平面机械臂在移动障碍物存在下的情况:

该图像是三幅机器人插图,展示了三台相同型号机器人在不同地面环境(蓝色格栅地、沙地和堆满石块的地面)中的排列和站立状态,体现机器人对多样化地形的适应能力。 该图像是三幅机器人插图,展示了三台相同型号机器人在不同地面环境(蓝色格栅地、沙地和堆满石块的地面)中的排列和站立状态,体现机器人对多样化地形的适应能力。

  • 图像解释: 一个平面机械臂正在一个有移动障碍物(矩形物体以速度 x˙B\dot{x}_B 移动)的环境中操作。为了避免碰撞,需要实时感知障碍物位置并调整机械臂运动。这说明了在动态、不确定环境中,纯模型驱动方法需要复杂的模型更新或额外的反馈机制。

4.3. 动力学控制机器人学的局限性 (Limitations of Dynamics-based Robotics)

尽管经典机器人学研究已逾六十年,自主机器人仍远未能达到人类水平的性能,特别是在跨任务、跨机器人本体的泛化能力方面。本教程明确指出了基于动力学的机器人学面临的几个核心局限性:

  1. 泛化能力差 (Lack of Generalization): 传统方法通常针对特定应用问题定制,难以泛化到不同的机器人本体(例如不同型号的机械臂、各种移动平台)和多样化的任务。这导致了解决方案的碎片化。

  2. 集成挑战 (Integration Challenges): 传统的感知、规划、控制模块通常是独立的,各个模块之间的误差会累积和放大,导致系统脆弱。任何模块的更改或故障都会带来巨大的工程开销。

    该图像是一个图表,展示了HIL-SERL算法框架,包括Soft-Actor Critic的核心公式\(r_t + \\gamma \\left\[Q_{i-1}(s_{t+1}, a_{t+1}) - \\alpha \\log \\pi_\\phi(a_{t+1}|s_{t+1})\\right\]\),结合专家演示和人类干预的数据采样方式,以及并行训练和双Q学习等技术。同时右侧配有机器人自主操作与人工控制的现场照… 该图像是一个图表,展示了HIL-SERL算法框架,包括Soft-Actor Critic的核心公式rt+γ[Qi1(st+1,at+1)αlogπϕ(at+1st+1)]r_t + \gamma \left[Q_{i-1}(s_{t+1}, a_{t+1}) - \alpha \log \pi_\phi(a_{t+1}|s_{t+1})\right],结合专家演示和人类干预的数据采样方式,以及并行训练和双Q学习等技术。同时右侧配有机器人自主操作与人工控制的现场照片。

    • 图像解释: (左) 传统的机器人控制流水线通常由独立的模块(如感知、状态估计、规划、控制)组成,这些模块串联工作,每个模块的误差都可能累积,导致系统整体脆弱。
  3. 多模态挑战 (Multimodality Challenges): 难以直接处理原始、异构且嘈杂的多模态数据流(如 RGB 图像、深度图、触觉信息)。将高维感知输入纳入决策过程并非易事,限制了其在大规模多任务环境中的可扩展性。

    该图像是一个示意图,展示了HIL-SERL方法的整体架构,包括环境、策略执行、奖励分类器、经验缓冲区及参数更新的流程。 该图像是一个示意图,展示了HIL-SERL方法的整体架构,包括环境、策略执行、奖励分类器、经验缓冲区及参数更新的流程。

    • 图像解释: 原始多模态数据(陀螺仪原始数据、原始深度图、原始图像)需要复杂的预处理才能用于传统方法,这增加了设计的复杂性和脆性。
  4. 模型不足 (Undermodeling Issues): 对于复杂系统,精确建模本身就是挑战。刚体近似在处理可变形物体时不足,而对复杂非线性动力学(如摩擦、抓取引起的耦合)的轻微模型失配都可能导致实际行为与预测行为的显著偏差。

    该图像是一个流程图,展示了生成运动的显式建模和隐式建模两大类方法,显式建模包括正运动学、逆运动学和基于控制的规划,隐式建模包括深度强化学习和专家演示学习等。 该图像是一个流程图,展示了生成运动的显式建模和隐式建模两大类方法,显式建模包括正运动学、逆运动学和基于控制的规划,隐式建模包括深度强化学习和专家演示学习等。

    • 图像解释: 该图通过一个包含摩擦模型的公式 (I+mr2+mlrcos(ϕgrp+ϕtl))ϕ¨tl+...(I + mr^{2} + mlr \cos(\phi_{grp} + \phi_{tl}))\ddot{\phi}_{tl} + ... 和数据分布图,说明了精确建模复杂物理现象的难度。
  5. 忽略开放数据增长 (Ignoring Open-Data Growth): 传统的基于动力学的方法未能有效利用日益增长的大规模开放机器人数据集。与计算机视觉和自然语言处理领域通过大规模数据实现突破不同,传统机器人学未能充分受益于这一趋势。

    该图像是一个流程图,展示了生成运动的显式建模和隐式建模两大类方法,显式建模包括正运动学、逆运动学和基于控制的规划,隐式建模包括深度强化学习和专家演示学习等。 该图像是一个流程图,展示了生成运动的显式建模和隐式建模两大类方法,显式建模包括正运动学、逆运动学和基于控制的规划,隐式建模包括深度强化学习和专家演示学习等。

    • 图像解释: 该图中间的柱状图显示了自2020年以来开放机器人数据集数量的显著增长,右侧的柱状图也展示了不同学术数据集包含轨迹数量的庞大规模。这表明数据已成为关键资源,而传统方法未能有效利用。

      这些局限性共同促使研究人员探索基于学习的方法,以期实现更通用、更鲁棒、更具适应性的自主机器人系统。

4.4. 机器人(强化)学习 (Robot (Reinforcement) Learning)

“近似求解,而不是近似问题。” — Richard Sutton

4.4.1. 强化学习简介 (A (Concise) Introduction to RL)

强化学习 (RL) 是机器学习的一个子领域,旨在开发能够通过试错 (trial and error) 来学习自主行为的智能体 (agent)。在机器人学中,RL 智能体通过与环境互动,最大化其获得的累积奖励 (cumulative reward),从而学习有效的控制策略 (policy)。

Markov 决策过程 (Markov Decision Process, MDP): 智能体与其环境之间的交互通常通过一个 Markov 决策过程 (MDP) 来建模。一个长度为 TT 的 MDP 可以定义为一个元组 M=S,A,D,r,γ,ρ,T\mathcal { M } = \langle { \mathcal { S } } , \mathcal { A } , \mathcal { D } , r , \gamma , \rho , T \rangle,其中:

  • S\boldsymbol { \mathcal { S } }状态空间 (State Space)stSs_t \in \mathcal{S} 表示在时间 tt 的(可能非直接可观测的)环境状态。在机器人学中,状态通常包括机器人配置和速度 (qt,q˙t)(q_t, \dot{q}_t),也可以包含传感器读数,如摄像头图像或音频流。
  • A\boldsymbol { \mathcal { A } }动作空间 (Action Space)atAa_t \in \mathcal{A} 可能代表在时间 tt 的关节扭矩、关节速度,甚至是末端执行器命令。通常,动作对应于干预机器人配置的命令。
  • D\boldsymbol { \mathcal { D } }环境动力学 (Environment Dynamics)。表示(可能非确定性的)环境状态转移概率,D:S×A×S[0,1]\mathcal{D}: \mathcal{S} \times \mathcal{A} \times \mathcal{S} \mapsto [0, 1],具体地,D(st,at,st+1)=P(st+1st,at)\mathcal{D}(s_t, a_t, s_{t+1}) = \mathbb{P}(s_{t+1} | s_t, a_t)
  • rr: 奖励函数 (Reward Function)r:S×A×SRr: \mathcal{S} \times \mathcal{A} \times \mathcal{S} \to \mathbb{R},评估状态转移 (st,at,st+1)(s_t, a_t, s_{t+1}) 的好坏,以衡量其对实现某个目标的贡献。
  • γ\gamma: 折扣因子 (Discount Factor)γ[0,1)\gamma \in [0, 1),调节智能体对即时奖励与未来奖励的偏好(越接近1越看重未来奖励)。
  • ρ\rho: 初始状态分布 (Initial State Distribution)ρ\rho 是 MDP 初始状态 s0s_0 的分布,s0ρs_0 \sim \rho
  • TT: 轨迹长度/时间步 (Trajectory Length/Timesteps)

轨迹 (Trajectory): 一个长度为 TT 的轨迹 τ\tau 是一个(随机)序列: τ=(s0,a0,r0,s1,a1,r1,,sT1,aT1,rT1,sT) \tau = (s_0, a_0, r_0, s_1, a_1, r_1, \ldots, s_{T-1}, a_{T-1}, r_{T-1}, s_T) 其中 rt=r(st,at,st+1)r_t = r(s_t, a_t, s_{t+1})。 假设环境动力学和策略(在给定状态下的动作条件分布)都是 Markovian 的,则观察到特定轨迹 τ\tau 的概率可以分解为: P(τ)=P(s0)t=0T1P(st+1st,at) P(atst) \mathbb{P}(\tau) = \mathbb{P}(s_0) \prod_{t=0}^{T-1} \mathbb{P}(s_{t+1}|s_t, a_t) \ \mathbb{P}(a_t|s_t) 符号解释:

  • P(τ)\mathbb{P}(\tau): 观察到特定轨迹 τ\tau 的概率。
  • P(s0)\mathbb{P}(s_0): 初始状态 s0s_0 的概率,即 ρ(s0)\rho(s_0)
  • t=0T1\prod_{t=0}^{T-1}: 连乘符号,表示从 t=0t=0T-1 的乘积。
  • P(st+1st,at)\mathbb{P}(s_{t+1}|s_t, a_t): 在状态 sts_t 执行动作 ata_t 后转移到状态 st+1s_{t+1} 的概率,即环境动力学 D(st,at,st+1)\mathcal{D}(s_t, a_t, s_{t+1})
  • P(atst)\mathbb{P}(a_t|s_t): 在状态 sts_t 下执行动作 ata_t 的概率,这通常由策略 π(atst)\pi(a_t|s_t) 给出。

策略 (Policy) 和回报 (Return): 策略 P(atst)\mathbb{P}(a_t|s_t) 通常表示为 π(atst)\pi(\boldsymbol{a}_t|\boldsymbol{s}_t),并常由参数 θ\boldsymbol{\theta} 参数化,记为 πθ(atst)\pi_{\boldsymbol{\theta}}(\boldsymbol{a}_t|\boldsymbol{s}_t)。训练的目标是通过优化策略参数来最大化与给定轨迹 τ\tau 相关联的(折扣)回报 G(τ)G(\tau),即: G(τ)=t=0T1γtrt G(\tau) = \sum_{t=0}^{T-1} \gamma^t r_t 优化目标 (Objective Function): 智能体试图学习控制策略 πθ\pi_{\boldsymbol{\theta}},以最大化期望回报 EτπθG(τ)\mathbb{E}_{\tau \sim \pi_{\theta}} G(\tau)。对于给定的动力学 D\mathcal{D},目标函数 J:ΠRJ: \Pi \mapsto \mathbb{R} 为: J(πθ)=EτPθ;D[G(τ)],Pθ;D(τ)=ρt=0T1D(st,at,st+1) πθ(atst). \begin{aligned} \boldsymbol{J}(\pi_{\boldsymbol{\theta}}) &= \mathbb{E}_{\tau \sim \mathbb{P}_{\boldsymbol{\theta}; \mathcal{D}}} [G(\tau)], \\ \mathbb{P}_{\boldsymbol{\theta}; \mathcal{D}}(\tau) &= \rho \prod_{t=0}^{T-1} \mathcal{D}(s_t, a_t, s_{t+1}) ~ \pi_{\boldsymbol{\theta}}(a_t|s_t). \end{aligned} 符号解释:

  • J(πθ)\boldsymbol{J}(\pi_{\boldsymbol{\theta}}): 策略 πθ\pi_{\boldsymbol{\theta}} 的性能指标,通常是期望的总回报。智能体的目标就是最大化这个值。
  • πθ\pi_{\boldsymbol{\theta}}: 由参数 θ\boldsymbol{\theta} 参数化的策略。
  • EτPθ;D[]\mathbb{E}_{\tau \sim \mathbb{P}_{\boldsymbol{\theta}; \mathcal{D}}}[\cdot]: 在由策略 πθ\pi_{\boldsymbol{\theta}} 和环境动力学 D\mathcal{D} 诱导的轨迹分布 Pθ;D\mathbb{P}_{\boldsymbol{\theta}; \mathcal{D}} 下,对轨迹 τ\tau 的期望。
  • G(τ)G(\tau): 轨迹 τ\tau 的总回报,即累积的折扣奖励。
  • Pθ;D(τ)\mathbb{P}_{\boldsymbol{\theta}; \mathcal{D}}(\tau): 策略 πθ\pi_{\boldsymbol{\theta}} 和环境动力学 D\mathcal{D} 诱导的轨迹 τ\tau 的概率。这个概率是由初始状态分布 ρ\rho、环境动力学 D\mathcal{D} 和策略 πθ\pi_{\boldsymbol{\theta}} 共同决定的。
  • ρ\rho: 初始状态分布,即 P(s0)\mathbb{P}(s_0)
  • D(st,at,st+1)\mathcal{D}(s_t, a_t, s_{t+1}): 环境动力学,即 P(st+1st,at)\mathbb{P}(s_{t+1}|s_t, a_t)
  • πθ(atst)\pi_{\boldsymbol{\theta}}(a_t|s_t): 策略在状态 sts_t 下选择动作 ata_t 的概率。

价值函数 (Value Functions): 为了指导策略学习,RL 定义了价值函数来评估状态或状态-动作对的长期回报。

  • 状态价值函数 (State-Value Function): Vπ(s)=Eτπ[G(τ)s0=s]V_{\pi}(s) = \mathbb{E}_{\tau \sim \pi} [G(\tau) | s_0=s],表示从状态 ss 开始,遵循策略 π\pi 所能获得的期望累积折扣奖励。

  • 状态-动作价值函数 (State-Action Value Function): Qπ(s,a)=Eτπ[G(τ)s0=s,a0=a]Q_{\pi}(s, a) = \mathbb{E}_{\tau \sim \pi} [G(\tau) | s_0=s, a_0=a],表示从状态 ss 开始,执行动作 aa 后,再遵循策略 π\pi 所能获得的期望累积折扣奖励。

    价值函数之间通过贝尔曼方程 (Bellman Equation) 相互关联: Qπ(st,at)=Est+1P(st,at)[rt+γVπ(st+1)]Vπ(st)=Eatπ(st)[Qπ(st,at)], \begin{aligned} Q_{\pi}(s_t, a_t) &= \mathbb{E}_{s_{t+1} \sim \mathbb{P}(\bullet \mid s_t, a_t)} [r_t + \gamma V_{\pi}(s_{t+1})] \\ V_{\pi}(s_t) &= \mathbb{E}_{a_t \sim \pi(\bullet \mid s_t)} [Q_{\pi}(s_t, a_t)], \end{aligned} 符号解释:

  • Qπ(st,at)Q_{\pi}(s_t, a_t): 在策略 π\pi 下,从状态 sts_t 执行动作 ata_t 后,所能获得的期望累积折扣奖励。

  • Est+1P(st,at)[]\mathbb{E}_{s_{t+1} \sim \mathbb{P}(\bullet \mid s_t, a_t)}[\cdot]: 在给定状态 sts_t 和动作 ata_t 的情况下,对下一个状态 st+1s_{t+1} 上的期望。这表示考虑所有可能的下一个状态及其发生的概率。

  • rtr_t: 在时间步 tt 执行动作 ata_t 从状态 sts_t 转移到 st+1s_{t+1} 时获得的即时奖励。

  • γ\gamma: 折扣因子。

  • Vπ(st+1)V_{\pi}(s_{t+1}): 在策略 π\pi 下,从下一个状态 st+1s_{t+1} 开始的期望累积折扣奖励。

  • Vπ(st)V_{\pi}(s_t): 在策略 π\pi 下,从状态 sts_t 开始的期望累积折扣奖励。

  • Eatπ(st)[]\mathbb{E}_{a_t \sim \pi(\bullet \mid s_t)}[\cdot]: 在给定状态 sts_t 的情况下,对根据策略 π\pi 选择的动作 ata_t 上的期望。这表示考虑策略 π\pi 在状态 sts_t 可能选择的所有动作及其概率。

热门 RL 算法: 下图 (images/7.jpg) 展示了常见的强化学习算法分类。

Figure 13 | Popular RL algorithms. See Achiam (2018) for a complete list of citations. 该图像是图表,展示了图13中常见的强化学习(RL)算法分类,包括基于模型(Model-based)和无模型(Model-free)的方法,细分为策略优化和Q学习两类,列举了相关算法名称。

  • 图像解释: 该图将流行的 RL 算法分为基于模型的 (Model-based) 和无模型的 (Model-free) 两大类,每类又细分为策略优化 (Policy Optimization) 和 Q 学习 (Q-Learning) 等子类,并列举了具体的算法名称,如 DQN, DDPG, SAC, PPO, TRPO 等。

    RL 算法的核心是寻找最优策略 π\pi^*,它能最大化期望回报。最优 QQ 函数 QQ^* 满足贝尔曼最优方程: Q(st,at)=Est+1P(st,at)[rt+γmaxat+1AQ(st+1,at+1)st,at] Q^*(s_t, a_t) = \mathbb{E}_{s_{t+1} \sim \mathbb{P}(\bullet | s_t, a_t)} \biggl[ r_t + \gamma \operatorname*{max}_{a_{t+1} \in A} Q^*(s_{t+1}, a_{t+1}) \big| s_t, a_t \biggr] 符号解释:

  • Q(st,at)Q^*(s_t, a_t): 最优策略下的状态-动作价值函数,表示在状态 sts_t 采取动作 ata_t 后,如果之后都遵循最优策略,所能获得的期望累积折扣奖励。

  • Est+1P(st,at)[]\mathbb{E}_{s_{t+1} \sim \mathbb{P}(\bullet | s_t, a_t)}[\cdot]: 在给定状态 sts_t 和动作 ata_t 时,对下一个状态 st+1s_{t+1} 上的期望。这考虑了环境动力学的不确定性。

  • rtr_t: 在时间步 tt 获得的即时奖励。

  • γ\gamma: 折扣因子。

  • maxat+1AQ(st+1,at+1)\operatorname*{max}_{a_{t+1} \in A} Q^*(s_{t+1}, a_{t+1}): 在下一个状态 st+1s_{t+1} 时,选择能够使得最优 QQ^* 值最大的动作 at+1a_{t+1}。这体现了贪婪选择未来最优动作的原则。

  • st,ats_t, a_t: 条件,表示是在状态 sts_t 采取动作 ata_t 后进行计算。

Q-学习 (Q-learning): Q-学习通过迭代更新 QQ 值的估计来逼近 QQ^*Qi+1(st,at)Est+1P(st,at)[rt+γmaxat+1AQi(st+1,at+1)st,at],i=0,1,2,,K Q_{i+1}(s_t, a_t) \gets \mathbb{E}_{s_{t+1} \sim \mathbb{P}(\bullet | s_t, a_t)} \biggl[ r_t + \gamma \operatorname*{max}_{a_{t+1} \in A} Q_i(s_{t+1}, a_{t+1}) \big| s_t, a_t \biggr], \quad i = 0, 1, 2, \dots, K 符号解释:

  • Qi+1(st,at)Q_{i+1}(s_t, a_t): 在第 i+1i+1 次迭代中更新后的状态-动作价值估计。
  • Qi(st+1,at+1)Q_i(s_{t+1}, a_{t+1}): 在第 ii 次迭代中,下一个状态 st+1s_{t+1} 和动作 at+1a_{t+1} 的状态-动作价值估计。
  • 其余符号与最优 QQ 函数的贝尔曼方程相同。

深度 Q 网络 (Deep Q-Network, DQN): DQN (Mnih et al., 2013) 使用深度卷积神经网络作为 Q 函数的近似器,并通过最小化时序差分误差 (TD-error) 来更新网络参数 θ\theta: L(θi)=E(st,at)χ()[(yiQθi(st,at)δi)2],yi=Est+1P(st,at)[rt+γmaxatAQθi1(st+1,at+1)], \begin{aligned} \mathcal{L}(\theta_i) &= \mathbb{E}_{(s_t, a_t) \sim \chi(\bullet)} \big[ (\underbrace{y_i - Q_{\theta_i}(s_t, a_t)}_{\delta_i})^2 \big], \\ y_i &= \mathbb{E}_{s_{t+1} \sim \mathbb{P}(\bullet | s_t, a_t)} \big[ r_t + \gamma \operatorname*{max}_{a_t \in A} Q_{\theta_{i-1}}(s_{t+1}, a_{t+1}) \big], \end{aligned} 符号解释:

  • L(θi)\mathcal{L}(\theta_i): 在第 ii 次迭代中,用于更新神经网络参数 θi\theta_i 的损失函数。
  • E(st,at)χ()[]\mathbb{E}_{(s_t, a_t) \sim \chi(\bullet)}[\cdot]: 在行为分布 χ\chi 下,对状态-动作对 (st,at)(s_t, a_t) 的期望。这里的 χ\chi 通常指经验回放缓冲区中的采样分布。
  • yiy_i: 目标 QQ 值,或称为 TD 目标 (TD Target)。
  • Qθi(st,at)Q_{\theta_i}(s_t, a_t): 当前策略(由参数 θi\theta_i 参数化)在状态 sts_t 采取动作 ata_tQQ 值。
  • δi\delta_i: TD 误差 (Temporal-Difference error),即目标 QQyiy_i 与当前预测 QQQθi(st,at)Q_{\theta_i}(s_t, a_t) 之间的差。
  • Est+1P(st,at)[]\mathbb{E}_{s_{t+1} \sim \mathbb{P}(\bullet | s_t, a_t)}[\cdot]: 在给定状态 sts_t 和动作 ata_t 时,对下一个状态 st+1s_{t+1} 的期望。
  • rtr_t: 即时奖励。
  • γ\gamma: 折扣因子。
  • maxatAQθi1(st+1,at+1)\operatorname*{max}_{a_t \in A} Q_{\theta_{i-1}}(s_{t+1}, a_{t+1}): 使用旧参数 θi1\theta_{i-1}(来自目标网络)计算的下一个状态 st+1s_{t+1} 和最优动作 at+1a_{t+1}QQ 值。目标网络的使用是为了稳定训练。

深度确定性策略梯度 (Deep Deterministic Policy Gradient, DDPG): DDPG (Lillicrap et al., 2015) 扩展了 DPG (Silver et al., 2014) 到深度学习,并应用于连续动作空间。它使用一个确定性策略 μϕ(st)=at\mu_{\phi}(s_t) = a_t(由参数 ϕ\phi 参数化),并通过策略梯度更新 ϕ\phi。策略梯度的方向为: dϕ=EstP()[ϕQ(st,at)at=μϕ(st)]=EstP()[atQ(st,at)at=μϕ(st)ϕμ(st)] d_{\phi} = \mathbb{E}_{s_t \sim \mathbb{P}(\bullet)} \left[ \nabla_{\phi} Q(s_t, a_t) \big|_{a_t = \mu_{\phi}(s_t)} \right] = \mathbb{E}_{s_t \sim \mathbb{P}(\bullet)} \left[ \nabla_{a_t} Q(s_t, a_t) \big|_{a_t = \mu_{\phi}(s_t)} \cdot \nabla_{\phi} \mu(s_t) \right] 符号解释:

  • dϕd_{\phi}: 策略参数 ϕ\phi 的梯度更新方向。
  • EstP()[]\mathbb{E}_{s_t \sim \mathbb{P}(\bullet)}[\cdot]: 对状态分布 P()\mathbb{P}(\bullet) 下的状态 sts_t 的期望。
  • ϕQ(st,at)at=μϕ(st)\nabla_{\phi} Q(s_t, a_t) \big|_{a_t = \mu_{\phi}(s_t)}: QQ 函数对策略参数 ϕ\phi 的梯度,其中动作 ata_t 由确定性策略 μϕ(st)\mu_{\phi}(s_t) 给出。
  • atQ(st,at)at=μϕ(st)\nabla_{a_t} Q(s_t, a_t) \big|_{a_t = \mu_{\phi}(s_t)}: QQ 函数对动作 ata_t 的梯度,在 at=μϕ(st)a_t = \mu_{\phi}(s_t) 处评估。这表示 QQ 值对动作的敏感度。
  • ϕμ(st)\nabla_{\phi} \mu(s_t): 策略 μ\mu 对其参数 ϕ\phi 的梯度。 DDPG 采用修改后的 TD 目标: yi=Est+1P(st,at)[rt+γQθi1(st+1,μϕ(st+1))] y_i = \mathbb{E}_{s_{t+1} \sim \mathbb{P}(\bullet | s_t, a_t)} \left[ r_t + \gamma Q_{\theta_{i-1}} (s_{t+1}, \mu_{\phi} (s_{t+1})) \right] 符号解释:
  • yiy_i: DDPG 中用于更新 QQ 网络的 TD 目标。
  • Est+1P(st,at)[]\mathbb{E}_{s_{t+1} \sim \mathbb{P}(\bullet | s_t, a_t)}[\cdot]: 在给定状态 sts_t 和动作 ata_t 时,对下一个状态 st+1s_{t+1} 的期望。
  • rtr_t: 即时奖励。
  • γ\gamma: 折扣因子。
  • Qθi1(st+1,μϕ(st+1))Q_{\theta_{i-1}}(s_{t+1}, \mu_{\phi}(s_{t+1})): 使用目标 QQ 网络参数 θi1\theta_{i-1} 和目标策略网络 μϕ\mu_{\phi}(可能使用软更新的参数 ϕ\phi)计算的下一个状态 st+1s_{t+1}QQ 值。

软动作-评论家 (Soft Actor-Critic, SAC): SAC (Haarnoja et al., 2018) 是 DDPG 的一种变体,它在最大熵 (MaxEnt) RL 框架下运行。SAC 的目标是最大化折扣累积奖励的同时,尽可能提高策略的随机性(熵)。其目标函数为: J(π)=t=0TE(st,at)χ[rt+αH(π(st))] J(\pi) = \sum_{t=0}^{T} \mathbb{E}_{(s_t, a_t) \sim \chi} [r_t + \alpha \mathcal{H}(\pi(\bullet | s_t))] 符号解释:

  • J(π)J(\pi): 策略 π\pi 的目标函数。SAC 的目标是最大化这个值。

  • t=0T\sum_{t=0}^{T}: 对时间步 tt0TT 的求和。

  • E(st,at)χ[]\mathbb{E}_{(s_t, a_t) \sim \chi}[\cdot]: 在行为分布 χ\chi 下,对状态-动作对 (st,at)(s_t, a_t) 的期望。

  • rtr_t: 即时奖励。

  • α\alpha: 温度参数 (temperature parameter),一个超参数,控制熵正则化的强度。α\alpha 越大,策略越倾向于探索。

  • H(π(st))\mathcal{H}(\pi(\bullet | s_t)): 策略 π\pi 在状态 sts_t 下的动作分布的熵 (entropy)。熵越高表示动作分布越随机,策略越具有探索性。

    SAC 的软 TD 目标为: yi=Est+1P(st,at)[rt+γ(Qθi1(st+1,at+1)αlogπϕ(at+1st+1))],at+1πϕ(st) y_i = \mathbb{E}_{s_{t+1} \sim \mathbb{P}(\bullet | s_t, a_t)} \left[ r_t + \gamma \big( Q_{\theta_{i-1}} (s_{t+1}, a_{t+1}) - \alpha \log \pi_{\phi} (a_{t+1} | s_{t+1}) \big) \right], \quad a_{t+1} \sim \pi_{\phi} (\bullet | s_t) 符号解释:

  • yiy_i: SAC 中用于更新 QQ 网络的软 TD 目标。

  • Est+1P(st,at)[]\mathbb{E}_{s_{t+1} \sim \mathbb{P}(\bullet | s_t, a_t)}[\cdot]: 在给定状态 sts_t 和动作 ata_t 时,对下一个状态 st+1s_{t+1} 的期望。

  • rtr_t: 即时奖励。

  • γ\gamma: 折扣因子。

  • Qθi1(st+1,at+1)Q_{\theta_{i-1}}(s_{t+1}, a_{t+1}): 使用目标 QQ 网络参数 θi1\theta_{i-1} 计算的下一个状态 st+1s_{t+1} 和动作 at+1a_{t+1}QQ 值。

  • α\alpha: 温度参数。

  • logπϕ(at+1st+1)\log \pi_{\phi}(a_{t+1} | s_{t+1}): 在下一个状态 st+1s_{t+1} 时,根据当前策略 πϕ\pi_{\phi} 选择动作 at+1a_{t+1} 的对数概率。这个项通过熵正则化鼓励策略探索。

  • at+1πϕ(st)a_{t+1} \sim \pi_{\phi}(\bullet | s_t): 下一个动作 at+1a_{t+1} 是从当前策略 πϕ\pi_{\phi} 在状态 sts_t 下的动作分布中采样得到。

    SAC 策略的更新通常通过最小化 KL 散度来实现: πk+1argminπΠDKL(π(st)exp(Qπk(st,))Zπk(st)) \pi_{k+1} \gets \operatorname*{argmin}_{\pi' \in \Pi} \mathrm{D}_{\mathrm{KL}} \bigg( \pi'(\bullet | s_t) \bigg| \bigg| \frac{\exp(Q_{\pi_k}(s_t, \bullet))}{\mathrm{Z}_{\pi_k}(s_t)} \bigg) 符号解释:

  • πk+1\pi_{k+1}: 在第 k+1k+1 次迭代中更新后的策略。

  • argminπΠ[]\operatorname*{argmin}_{\pi' \in \Pi}[\cdot]: 寻找在策略空间 Π\Pi 中使目标函数(这里是 KL 散度)最小的策略 π\pi'

  • DKL()\mathrm{D}_{\mathrm{KL}}(\cdot || \cdot): KL 散度 (Kullback-Leibler divergence),衡量两个概率分布之间的差异。

  • π(st)\pi'(\bullet | s_t): 在状态 sts_t 下的候选策略 π\pi' 的动作分布。

  • exp(Qπk(st,))/Zπk(st)\exp(Q_{\pi_k}(s_t, \bullet)) / \mathrm{Z}_{\pi_k}(s_t): 一个 Boltzmann 分布,其概率与 Qπk(st,)Q_{\pi_k}(s_t, \bullet) 成正比,其中 Zπk(st)\mathrm{Z}_{\pi_k}(s_t) 是归一化常数,用于确保这是一个有效的概率分布。策略更新的目标是使当前策略的动作分布尽可能接近这个由 QQ 值导出的 Boltzmann 分布。

4.4.2. 真实世界机器人强化学习 (Real-world RL for Robotics)

在真实世界中训练机器人强化学习智能体面临巨大挑战,主要包括样本效率低下、安全性问题和奖励函数设计困难。

仿真到真实 (Sim-to-Real) 和域随机化 (Domain Randomization, DR): 为了克服真实世界训练的困难,一个常见方法是在仿真器中训练策略,然后将其转移到真实机器人上。然而,仿真器与真实世界之间存在域鸿沟 (domain gap)域随机化 (Domain Randomization, DR) 是一种弥合这一鸿沟的技术,通过在仿真器中随机化环境参数(如摩擦、纹理、光照等),使策略对这些变化具有鲁棒性,从而在真实世界中表现更好。 DR 的核心思想是训练一个在不同动力学 Dξ\mathcal{D}_\xi 下表现良好的策略,其中 DDξ\mathcal{D} \equiv \mathcal{D}_\xi with a dynamics (random) vector ξ\xi drawn an arbitrary distribution, ξΞ\xi \sim \Xi。例如,可以随机化机械臂的摩擦系数或物体的质量。

下图 (images/9.jpg) 展示了DR如何提高策略在多样化环境中的鲁棒性:

该图像是三幅机器人插图,展示了三台相同型号机器人在不同地面环境(蓝色格栅地、沙地和堆满石块的地面)中的排列和站立状态,体现机器人对多样化地形的适应能力。 该图像是三幅机器人插图,展示了三台相同型号机器人在不同地面环境(蓝色格栅地、沙地和堆满石块的地面)中的排列和站立状态,体现机器人对多样化地形的适应能力。

  • 图像解释: 该图展示了同一个机器人本体在训练时被放置在多种不同地形(蓝色格栅、沙地、石块地)中,通过在这些多样化环境中进行训练(即域随机化),机器人策略能够提高对不同环境动力学的鲁棒性,从而更好地适应真实世界中未知的复杂地形。

奖励设计 (Reward Design): 奖励函数的设计是真实世界 RL 的另一个主要挑战。稀疏奖励 (sparse rewards) 会导致探索效率低下,而手动设计密集奖励 (dense rewards) 则耗时、易错且需要专家知识。奖励分类器 (reward classifiers) 可以通过从成功和失败的演示中学习来自动设计奖励函数。

人机协作样本高效强化学习 (Human-in-the-Loop, Sample Effcient Robot Reinforcement Learning, HIL-SERL): HIL-SERL (Luo et al., 2024) 是一种结合了人类干预的在线强化学习算法,旨在提高真实世界机器人学习的样本效率和安全性。它利用了离线数据 (offline data)人类干预 (human intervention) 来加速学习。 HIL-SERL 的核心思想包括:

  1. 经验回放缓冲区 (Replay Buffer): 算法利用经验回放缓冲区存储过去的交互数据。

  2. 人机协作 (Human-in-the-Loop): 当机器人遇到困难或表现不佳时,人类操作员可以进行干预,提供专家演示。这些人类干预数据被特殊对待,以更快地影响学习过程。

  3. 在线学习 (Online Learning): 策略在真实世界中持续学习,通过收集新数据并结合离线数据进行优化。

  4. 奖励分类器 (Reward Classifier): 可能用于从人类提供的成功/失败信号中学习奖励函数,减轻手动设计奖励的负担。

    HIL-SERL 框架的核心在于其双缓冲区机制,一个用于在线收集的自主数据,另一个用于人类干预的离线数据,并将这些数据以智能的方式结合起来进行策略更新。

下图 (images/10.jpg) 总结了 HIL-SERL 的核心思想。

该图像是一个图表,展示了HIL-SERL算法框架,包括Soft-Actor Critic的核心公式\(r_t + \\gamma \\left\[Q_{i-1}(s_{t+1}, a_{t+1}) - \\alpha \\log \\pi_\\phi(a_{t+1}|s_{t+1})\\right\]\),结合专家演示和人类干预的数据采样方式,以及并行训练和双Q学习等技术。同时右侧配有机器人自主操作与人工控制的现场照… 该图像是一个图表,展示了HIL-SERL算法框架,包括Soft-Actor Critic的核心公式rt+γ[Qi1(st+1,at+1)αlogπϕ(at+1st+1)]r_t + \gamma \left[Q_{i-1}(s_{t+1}, a_{t+1}) - \alpha \log \pi_\phi(a_{t+1}|s_{t+1})\right],结合专家演示和人类干预的数据采样方式,以及并行训练和双Q学习等技术。同时右侧配有机器人自主操作与人工控制的现场照片。

  • 图像解释: 该图展示了 HIL-SERL 算法的核心框架,包括:
    • Soft-Actor Critic (SAC) 核心: 指出了 SAC 作为基础强化学习算法。
    • 经验回放缓冲区 (Replay Buffer): 用于存储交互数据。
    • 专家演示 (Expert Demonstrations): 离线数据,用于加速学习。
    • 人类干预 (Human Intervention): 在线干预,提高样本效率和安全性。
    • 双 Q 学习 (Double Q-learning): 提高 Q 值估计的稳定性。
    • 并行训练 (Parallel Training): Actor-Learner 架构,Actor 收集数据,Learner 训练。
    • 奖励分类器 (Reward Classifier): 从专家数据中学习奖励信号。
    • 图像右侧: 配有机器人自主操作和人工控制的现场照片,直观展示了人机协作的场景。

4.4.3. 代码示例:真实世界强化学习 (HIL-SERL)

本教程通过一系列代码示例详细展示了 lerobot 框架下 HIL-SERL 的实现。HIL-SERL 的架构基于 Actor-Learner 分离的模式,其中 Actor (执行者) 负责与环境互动并收集数据,而 Learner (学习者) 负责优化策略参数。

下图 (images/11.jpg) 展示了 HIL-SERL 的整体架构:

该图像是一个示意图,展示了HIL-SERL方法的整体架构,包括环境、策略执行、奖励分类器、经验缓冲区及参数更新的流程。 该图像是一个示意图,展示了HIL-SERL方法的整体架构,包括环境、策略执行、奖励分类器、经验缓冲区及参数更新的流程。

  • 图像解释: 这是一个 Actor-Learner 架构:
    • Actor: 运行冻结的策略网络与环境互动,生成状态-动作-奖励-下一状态 (st,at,rt,st+1)(s_t, a_t, r_t, s_{t+1}) 转移数据。这些数据被发送到 transitions_queue
    • Learner:transitions_queue 接收数据,并从经验回放缓冲区采样数据来优化策略参数 θ\theta。优化后的参数通过 parameters_queue 发送回 Actor,实现策略的更新。
    • 奖励分类器 (Reward Classifier): 独立训练,用于预测奖励 rtr_t
    • Online Buffer 和 Offline Buffer: Learner 使用两个缓冲区,online_buffer 存储所有在线收集的经验,offline_buffer 则专门存储人类干预的经验。

4.4.3.1. 代码 3: 训练奖励分类器 (Training a Reward Classifier)

奖励分类器在 HIL-SERL 中扮演关键角色,它根据观测(如图像)预测奖励,从而将稀疏的成功/失败信号转化为稠密的奖励信号。

import torch   
from lerobot.datasets.lerobot_dataset import LeRobotDataset   
from lerobot.policies.factory import make_policy, make_pre_post_processors   
from lerobot.policies.sac.reward_model.configuration_classifier import RewardClassifierConfig   
   
# Device to use for training   
device = "mps" # or "cuda", or "cpu"   
   
# Load the dataset used for training   
repo_id = "lerobot/example_hil_serl_dataset"   
dataset = LeRobotDataset(repo_id)   
   
# Configure the policy to extract features from the image frames   
camera_keys = dataset.meta.camera_keys   
   
config = RewardClassifierConfig(   
    num_cameras = len(camera_keys),   
    device = device,   
    # backbone model to extract features from the image frames   
    model_name = "microsoft/resnet-18",   
)   
   
# Make policy, preprocessor, and optimizer   
policy = make_policy(config, ds_meta = dataset.meta)   
optimizer = config.get_optimizer_preset().build(policy.parameters())   
preprocessor, _ = make_pre_post_processors(policy_cfg = config, dataset_stats = dataset.meta.stats)   
   
   
# your HF username and model repo id for the reward classifier   
classifier_id = "lerobot/reward_classifier_hil_serl_example"   
   
# Instantiate a dataloader   
dataloader = torch.utils.data.DataLoader(dataset, batch_size = 16, shuffle = True)   
   
# Training loop   
num_epochs = 5   
for epoch in range(num_epochs):   
    total_loss = 0   
    total_accuracy = 0   
    for batch in dataloader:   
        # Preprocess the batch and move it to the correct device.   
        batch = preprocessor(batch)   
           
        # Forward pass   
        loss, output_dict = policy.forward(batch)   
           
        # Backward pass and optimization   
        optimizer.zero_grad()   
        loss.backward()   
        optimizer.step()   
           
        total_loss += loss.item()   
        total_accuracy += output_dict["accuracy"]   
        
    avg_loss = total_loss / len(dataloader)   
    avg_accuracy = total_accuracy / len(dataloader)   
    print(   
        f"Epoch {epoch + 1}/{num_epochs}, Loss: {avg_loss:.4f}, Accuracy: {avg_accuracy:.2f}%"   
    )   
   
print("Training finished!")   
   
# You can now save the trained policy.   
policy.push_to_hub(classifier_id)

代码解释:

  1. 加载数据集与配置: 使用 LeRobotDataset 加载一个包含演示数据的数据集 (lerobot/example_hil_serl_dataset)。RewardClassifierConfig 用于配置奖励分类器模型,指定摄像头数量、设备和主干网络 (resnet-18)。
  2. 模型、优化器与预处理器: make_policy 创建奖励分类器模型 (policy),get_optimizer_preset().build 创建优化器,make_pre_post_processors 创建数据预处理器。
  3. 训练循环:
    • 通过 DataLoader 迭代数据集。
    • preprocessor(batch) 对批次数据进行预处理(如图像归一化、特征提取)。
    • policy.forward(batch) 执行模型前向传播,计算损失 (loss) 和输出字典 (output_dict,包含准确率)。
    • optimizer.zero_grad(), loss.backward(), optimizer.step() 执行反向传播和参数更新。
    • 每个 epoch 结束后,打印平均损失和准确率。
  4. 保存模型: 训练完成后,policy.push_to_hub(classifier_id) 将训练好的奖励分类器模型保存并推送到 Hugging Face Hub

4.4.3.2. 代码 4: 定义 Actor (Defining the Actor)

Actor 进程负责与真实环境互动,执行策略,收集经验数据,并将数据发送给 Learner。它的策略参数会定期从 Learner 接收更新。

import multiprocessing as mp   
from queue import Empty   
   
import torch   
from pathlib import Path   
   
from lerobot.envs.configs import HILSerlRobotEnvConfig   
from lerobot.policies.sac.modeling_sac import SACPolicy   
from lerobot.policies.sac.reward_model.modeling_classifier import Classifier   
from lerobot.rl.gym_manipulator import make_robot_env   
from lerobot.teleoperators.utils import TeleopEvents   
   
MAX_EPISODES = 5   
MAX_STEPS_PER_EPISODE = 20   
   
def make_policy_obs(obs, device: torch.device = "cpu"):   
    return {   
        "observation.state": torch.from_numpy(obs["agent_pos"]).float().unsqueeze(0).to(device),   
        **{   
            f"observation.image.{k}":   
            torch.from_numpy(obs["pixels"][k]).float().unsqueeze(0).to(device)   
            for k in obs["pixels"]   
        },   
    }   
   
def run_actor(   
    transitions_queue: mp.Queue,   
    parameters_queue: mp.Queue,   
    shutdown_event: mp.Event,   
    policy_actor: SACPolicy,   
    reward_classifier: Classifier,   
    env_cfg: HILSerlRobotEnvConfig,   
    device: torch.device = "mps",   
    output_directory: Path | None = None   
):   
    """The actor process - interacts with environment and collects data   
    The policy is frozen and only the parameters are updated, popping the most recent ones   
    from a queue.""   
    policy_actor.eval()   
    policy_actor.to(device)   
   
    reward_classifier.eval()   
    reward_classifier.to(device)   
   
    # Create robot environment inside the actor process   
    env, teleop_device = make_robot_env(env_cfg)   
   
    try:   
        for episode in range(MAX_EPISODES):   
            if shutdown_event.is_set():   
                break   
            
            obs, _info = env.reset()   
            episode_reward = 0.0   
            step = 0   
            episode_transitions = []   
            
            print(f"[ACTOR] Starting episode {episode + 1}")   
            
            while step < MAX_STEPS_PER_EPISODE and not shutdown_event.is_set():   
                try:   
                    new_params = parameters_queue.get_nowait()   
                    policy_actor.load_state_dict(new_params)   
                    print("[AcToR] Updated policy parameters from learner")   
                except Empty: # No new updated parameters available from learner, waiting   
                    pass   
                
                # Get action from policy   
                policy_obs = make_policy_obs(obs, device = device)   
                # predicts a single action, not a chunk of actions!   
                action_tensor = policy_actor.select_action(policy_obs)   
                action = action_tensor.squeeze(0).cpu().numpy()   
                
                # Step environment   
                next_obs, _env_reward, terminated, truncated, _info = env.step(action)   
                done = terminated or truncated   
                
                # Predict reward   
                policy_next_obs = make_policy_obs(next_obs, device = device)   
                reward = reward_classifier.predict_reward(policy_next_obs)   
                
                if reward >= 1.0: # success detected! halt episode   
                    if not done:   
                        terminated = True   
                        done = True   
                
                # In HIL-SERL, human interventions come from the teleop device   
                is_intervention = False   
                if hasattr(teleop_device, "get_teleop_events"):   
                    # Real intervention detection from teleop device   
                    teleop_events = teleop_device.get_teleop_events()   
                    is_intervention = teleop_events.get(TeleopEvents.IS_INTERVENTION, False)   
                
                # Store transition with intervention metadata   
                transition = {   
                    "state": policy_obs,   
                    "action": action,   
                    "reward": float(reward) if hasattr(reward, "item") else reward,   
                    "next_state": policy_next_obs,   
                    "done": done,   
                    "truncated": truncated,   
                    "complementary_info": {   
                        "is_intervention": is_intervention,   
                    },   
                }   
                
                episode_transitions.append(transition)   
                
                episode_reward += reward   
                step += 1   
                
                obs = next_obs   
                
                if done:   
                    break   
                
            # Send episode transitions to learner   
            transitions_queue.put_nowait(episode_transitions)   
            
    except KeyboardInterrupt:   
        print("[ACToR] Interrupted by user")   
    finally:   
        # Clean up   
        if hasattr(env.robot, "disconnect") and env.robot.is_connected:   
            env.robot.disconnect()   
        if teleop_device and hasattr(teleop_device, "disconnect"):   
            teleop_device.disconnect()   
        if output_directory is not None:   
            policy_actor.save_pretrained(output_directory)   
            print(f"[AcToR] Latest actor policy saved at: {output_directory}")   
        
    print("[ACTOR] Actor process finished")

代码解释:

  1. run_actor 函数: 这是 Actor 进程的主函数。它接收用于进程间通信的队列 (transitions_queue, parameters_queue)、关机事件 (shutdown_event)、Actor 策略 (policy_actor)、奖励分类器 (reward_classifier) 和环境配置 (env_cfg)。
  2. 初始化: Actor 策略和奖励分类器被设置为评估模式 (eval()) 并移动到指定设备。make_robot_env 根据配置创建机器人环境。
  3. 回合循环: 进程在一个外部循环中运行多个回合 (MAX_EPISODES)。
  4. 策略参数更新: 在每个时间步内,Actor 尝试从 parameters_queue 获取最新的策略参数。如果 Learner 更新了参数,Actor 会加载这些新参数,从而使其策略保持最新。
  5. 动作选择: policy_actor.select_action(policy_obs) 根据当前观测选择一个动作。make_policy_obs 函数将原始环境观测转换为策略所需的格式。
  6. 环境交互: env.step(action) 在环境中执行所选动作,并返回下一个观测、环境奖励、终止/截断标志等。
  7. 奖励预测: reward_classifier.predict_reward(policy_next_obs) 使用预训练的奖励分类器预测当前步骤的奖励。如果奖励达到成功阈值 (>=1.0>= 1.0),则当前回合可能被标记为成功终止。
  8. 人类干预检测: 检查遥操作设备 (teleop_device) 是否检测到人类干预 (is_intervention)。这个信息会作为元数据存储在经验转换中。
  9. 经验存储与发送: 每个时间步的经验 (state, action, reward, next_state, done, truncated, is_intervention) 被封装成一个 transition 字典并添加到 episode_transitions 列表中。回合结束后,整个回合的 episode_transitions 列表被发送到 transitions_queue 给 Learner。
  10. 清理: 进程结束时,断开机器人和遥操作器连接,并可选地保存 Actor 的最终策略。

4.4.3.3. 代码 5: 定义 Learner (Defining the Learner)

Learner 进程负责从 Actor 接收经验数据,并使用这些数据以及离线数据来优化策略网络。优化后的策略参数会定期发送回 Actor。

import multiprocessing as mp   
from queue import Empty, Full   
   
import torch   
import torch.optim as optim   
   
from lerobot.policies.sac.modeling_sac import SACPolicy   
from lerobot.rl.buffer import ReplayBuffer   
   
LOG_EVERY = 10   
SEND_EVERY = 10   
   
def run_learner(   
    transitions_queue: mp.Queue,   
    parameters_queue: mp.Queue,   
    shutdown_event: mp.Event,   
    policy_learner: SACPolicy,   
    online_buffer: ReplayBuffer,   
    offline_buffer: ReplayBuffer,   
    lr: float = 3e-4,   
    batch_size: int = 32,   
    device: torch.device = "mps",   
):   
    """The learner process - trains SAC policy on transitions streamed from the actor,   
    updating parameters for the actor to adopt."""   
    policy_learner.train()   
    policy_learner.to(device)   
   
    # Create Adam optimizer from scratch - simple and clean   
    optimizer = optim.Adam(policy_learner.parameters(), lr = lr)   
   
    print(f"[LEARNER] Online buffer capacity: {online_buffer.capacity}")   
    print(f"[LEARNER] Offline buffer capacity: {offline_buffer.capacity}")   
   
    training_step = 0   
   
    while not shutdown_event.is_set():   
        # retrieve incoming transitions from the actor process   
        try:   
            transitions = transitions_queue.get(timeout = 0.1)   
            for transition in transitions:   
                # HIL-SERL: Add ALL transitions to online buffer   
                online_buffer.add(**transition)   
   
                # HIL-SERL: Add ONLY human intervention transitions to offline buffer   
                is_intervention = \
                    transition.get("complementary_info", {}).get("is_intervention", False)   
                if is_intervention:   
                    offline_buffer.add(**transition)   
                    print(   
                        f"[LEARNER] Human intervention detected!"   
                        f"Added to offline buffer (now {len(offline_buffer)} transitions)"   
                    )   
        except Empty: # No transitions available, continue   
            pass   
        
        # Train if we have enough data   
        if len(online_buffer) >= policy_learner.config.online_step_before_learning: # Sample from online buffer (autonomous + human data)   
            online_batch = online_buffer.sample(batch_size // 2)   
            # Sample from offline buffer (human demonstrations only)   
            offline_batch = offline_buffer.sample(batch_size // 2)   
            # Combine batches - this is the key HIL-SERL mechanism!   
            batch = {}   
            for key in online_batch.keys():   
                if key in offline_batch:   
                    batch[key] = torch.cat([online_batch[key], offline_batch[key]], dim = 0)   
                else:   
                    batch[key] = online_batch[key]   
            
            loss, _ = policy_learner.forward(batch)   
            optimizer.zero_grad()   
            loss.backward()   
            optimizer.step()   
            training_step += 1   
            
            if training_step % LOG_EVERY == 0:   
                print(   
                    f"[LEARNER] Training step {training_step}, Loss: {loss.item():.4f}, "   
                    f"Buffers: Online = {len(online_buffer)}, Offline = {len(offline_buffer)}"   
                )   
            
            # Send updated parameters to actor every 10 training steps   
            if training_step % SEND_EVERY == 0:   
                try:   
                    state_dict = {k: v.cpu() for k, v in policy_learner.state_dict().items()}   
                    parameters_queue.put_nowait(state_dict)   
                    print("[LEARNER] Sent updated parameters to actor")   
                except Full: # Missing write due to queue not being consumed (should happen rarely)   
                    pass

代码解释:

  1. run_learner 函数: 这是 Learner 进程的主函数。它接收与 run_actor 类似的队列和事件,以及 Learner 策略 (policy_learner) 和两个经验回放缓冲区 (online_buffer, offline_buffer)。
  2. 初始化: Learner 策略被设置为训练模式 (train()) 并移动到指定设备。创建一个 Adam 优化器。
  3. 主循环: 进程在一个 while 循环中运行,直到 shutdown_event 被设置。
  4. 接收经验: Learner 尝试从 transitions_queue 获取 Actor 发送的经验回合数据。
  5. 缓冲区填充 (HIL-SERL 机制):
    • 所有接收到的 transition 都会添加到 online_buffer 中(包含自主探索和人类干预数据)。
    • 如果 transitioncomplementary_infois_intervention 标志为 True,则该 transition 也会被添加到 offline_buffer 中。这是 HIL-SERL 区分和利用人类干预数据的关键。
  6. 策略训练:
    • online_buffer 中的数据量达到一定阈值时 (online_step_before_learning),Learner 开始训练。
    • 批次组合:online_bufferoffline_buffer 各采样一半的 batch_size 样本。然后将这两个批次合并成一个完整的训练批次。这种组合确保了训练同时利用了自主探索和人类专家的经验。
    • policy_learner.forward(batch) 计算策略的损失。
    • optimizer.zero_grad(), loss.backward(), optimizer.step() 执行反向传播和参数更新。
  7. 参数发送: 每隔 SEND_EVERY 个训练步,Learner 会将当前策略的参数 (state_dict) 发送到 parameters_queue,供 Actor 更新其策略。

4.4.3.4. 代码 6: 使用 HIL-SERL (Using HIL-SERL)

这是主脚本,负责协调 Actor 和 Learner 进程的启动和通信。

import multiprocessing as mp   
import signal   
from typing import Callable   
from pathlib import Path   
   
from lerobot.datasets.lerobot_dataset import LeRobotDataset   
from lerobot.datasets.utils import hw_to_dataset_features   
from lerobot.envs.configs import HILSerlProcessorConfig, HILSerlRobotEnvConfig   
from lerobot.policies.sac.configuration_sac import SACConfig   
from lerobot.policies.sac.modeling_sac import SACPolicy   
from lerobot.policies.sac.reward_model.modeling_classifier import Classifier   
from lerobot.rl.buffer import ReplayBuffer   
from lerobot.rl.gym_manipulator import make_robot_env   
from lerobot.robots.so100_follower import S0100FollowerConfig   
from lerobot.teleoperators.so10o_leader import S0100LeaderConfig   
   
   
run_learner: Callable = ... # use/modify the functions defined earlier   
run_actor: Callable = ...   
   
"""Main function - coordinates actor and learner processes."""   
   
device = "mps" # or "cuda" or "cpu"   
output_directory = Path("outputs/robot_learning_tutorial/hil_serl")   
output_directory.mkdir(parents = True, exist_ok = True)   
   
# find ports using lerobot-find-port   
follower_port = "..."   
leader_port = "..."   
   
# the robot ids are used the load the right calibration files   
follower_id = "..."   
leader_id = "..."   
   
# A pretrained model (to be used in-distribution!)   
reward_classifier_id = "lerobot/reward_classifier_hil_serl_example"   
reward_classifier = Classifier.from_pretrained(reward_classifier_id)   
   
reward_classifier.to(device)   
reward_classifier.eval()   
   
MAX_EPISODES = 5   
MAX_STEPS_PER_EPISODE = 20   
   
# Robot and environment configuration   
robot_cfg = S0100FollowerConfig(port = follower_port, id = follower_id)   
teleop_cfg = S0100LeaderConfig(port = leader_port, id = leader_id)   
processor_cfg = HILSerlProcessorConfig(control_mode = "leader")   
   
env_cfg = HILSerlRobotEnvConfig(robot = robot_cfg, teleop = teleop_cfg, processor = processor_cfg)   
   
# Create robot environment   
env, teleop_device = make_robot_env(env_cfg)   
   
obs_features = hw_to_dataset_features(env.robot.observation_features, "observation")   
action_features = hw_to_dataset_features(env.robot.action_features, "action")   
   
# Create SAC policy for action selection   
policy_cfg = SACConfig(   
    device = device,   
    input_features = obs_features,   
    output_features = action_features,   
)   
   
policy_actor = SACPolicy(policy_cfg)   
policy_learner = SACPolicy(policy_cfg)   
   
demonstrations_repo_id = "lerobot/example_hil_serl_dataset"   
offline_dataset = LeRobotDataset(repo_id = demonstrations_repo_id)   
   
# Online buffer: initialized from scratch   
online_replay_buffer = ReplayBuffer(device = device, state_keys = list(obs_features.keys()))   
# Offline buffer: Created from dataset (pre-populated it with demonstrations)   
offline_replay_buffer = ReplayBuffer.from_lerobot_dataset(   
    lerobot_dataset = offline_dataset, device = device, state_keys = list(obs_features.keys())   
)   
   
# Create communication channels between learner and actor processes   
transitions_queue = mp.Queue(maxsize = 10)   
parameters_queue = mp.Queue(maxsize = 2)   
shutdown_event = mp.Event()   
   
   
# Signal handler for graceful shutdown   
def signal_handler(sig):   
    print(f"\nSignal {sig} received, shutting down...")   
    shutdown_event.set()   
   
   
signal.signal(signal.SIGINT, signal_handler)   
signal.signal(signal.SIGTERM, signal_handler)   
   
# Create processes   
learner_process = mp.Process(   
    target = run_learner,   
    args=(   
        transitions_queue,   
        parameters_queue,   
        shutdown_event,   
        policy_learner,   
        online_replay_buffer,   
        offline_replay_buffer,   
    ),   
    kwargs = {"device": device}, # can run on accelerated hardware for training   
)   
   
actor_process = mp.Process(   
    target = run_actor,   
    args = (   
        transitions_queue,   
        parameters_queue,   
        shutdown_event,   
        policy_actor,   
        reward_classifier,   
        env_cfg,   
        output_directory,   
    ),   
    kwargs = {"device": "cpu"}, # actor is frozen, can run on CPU or accelerate fc   
)   
   
learner_process.start()   
actor_process.start()   
   
try:   
    # Wait for actor to finish (it controls the episode loop)   
    actor_process.join()   
    shutdown_event.set()   
    learner_process.join(timeout = 10)   
   
except KeyboardInterrupt:   
    print("Main process interrupted")   
    shutdown_event.set()   
    actor_process.join(timeout = 5)   
    learner_process.join(timeout = 10)   
   
if learner_process.is_alive(): learner_process.terminate()   
if actor_process.is_alive(): actor_process.terminate()

代码解释:

  1. 初始化配置与模型:
    • 设置输出目录,并配置机器人 (S0100FollowerConfig)、遥操作器 (S0100LeaderConfig) 和环境处理器 (HILSerlProcessorConfig)。
    • 加载预训练的奖励分类器 (Classifier.from_pretrained)。
    • 创建 Actor 和 Learner 的 SAC 策略实例 (SACPolicy),它们最初具有相同的配置。
  2. 创建经验回放缓冲区:
    • online_replay_buffer: 一个空的经验回放缓冲区,用于存储在线收集的数据。
    • offline_replay_buffer: 从一个预先存在的离线数据集 (lerobot/example_hil_serl_dataset) 中初始化,用于存储专家演示或人类干预数据。
  3. 进程间通信机制:
    • mp.Queue: 创建两个多进程队列 (transitions_queue, parameters_queue),分别用于 Actor 向 Learner 发送经验数据,以及 Learner 向 Actor 发送更新后的策略参数。
    • mp.Event: 创建一个 shutdown_event,用于在需要时向所有进程发送停止信号。
  4. 信号处理: 注册 signal_handler 函数来捕获中断信号 (SIGINT, SIGTERM),以便优雅地关闭进程。
  5. 创建和启动进程:
    • mp.Process: 创建 learner_processactor_process,分别将 run_learnerrun_actor 函数作为其目标。
    • learner_process.start()actor_process.start(): 启动这两个独立的进程。Learner 通常运行在加速硬件(如 GPU)上进行训练,而 Actor 可以在 CPU 或其他硬件上运行。
  6. 进程协调与关闭:
    • 主进程等待 actor_process 完成,因为它控制着回合循环。

    • 一旦 Actor 完成或检测到中断,shutdown_event 被设置,通知所有进程关闭。

    • join() 方法用于等待进程终止,并设置了超时,以防进程卡住。

    • terminate() 用于强制终止仍活动的进程。

      这部分代码完整地展示了 HIL-SERL 算法在 lerobot 框架下,如何通过多进程架构实现 Actor-Learner 分离,结合在线探索和离线专家数据进行高效训练的实践。

4.4.4. 机器人强化学习在真实世界中的局限性:仿真器与奖励设计

尽管真实世界机器人强化学习取得了显著进展,但它仍然面临一些限制:

  • 仿真器的高成本和维护难度: 在某些情况下(如 Tokamak 控制、高空平流层导航),收集真实世界经验非常昂贵或危险,使得仿真成为必需。然而,构建和维护高保真度仿真器非常困难,特别是对于涉及接触、可变形物体或软材料的操作任务。

  • 奖励设计的挑战: 奖励函数的设计是真实世界 RL 管道中脆性 (brittleness) 的根本来源。虽然密集的奖励 (dense rewards) 对于指导长视野任务的探索至关重要,但其设计过程容易出错,且高度依赖人类专业知识和试错。稀疏奖励 (sparse rewards) 虽然可以避免这些问题,但通常会导致学习速度慢得多。

    这些局限性促使研究者转向行为克隆 (Behavioral Cloning, BC) 等模仿学习方法,这些方法可以通过大量演示数据来避免对高保真仿真器和复杂奖励函数的需求。

5. 实验设置

本教程性质的论文主要通过 lerobot 框架中的代码示例来展示其方法论。因此,这里将重点介绍这些示例所使用的数据集、评估指标和相关的配置。

5.1. 数据集

教程中主要提及并使用了两类数据集,它们都以 LeRobotDataset 格式组织,支持多模态数据和灵活的访问方式。

  • lerobot/svla_so101_pickplace:

    • 来源: Hugging Face Hub 上的一个 lerobot 数据集。
    • 规模与特点: 用于批处理和流式数据集的示例,包含机器人操作任务(如抓取和放置)的数据。其特点是数据结构丰富,包含状态、动作以及堆叠的图像帧,用于演示 LeRobotDataset 的基本功能和时间戳处理能力。
    • 用途: 主要用于展示 LeRobotDataset 如何加载、访问数据以及与 PyTorch DataLoader 集成进行批处理。
    • 样本示例 (来自 Code 1 的 sample 输出):
      # {   
      # 'observation.state': tensor([...]),
      # 'action': tensor([...]),
      # 'observation.images.wrist_camera': tensor([3, C, H, W]), for delta timesteps
      # }
      
      这个示例展示了单个数据点(帧)的结构,包括机器人状态张量、动作张量,以及一个手腕摄像头图像张量。图像张量的形状 [3, C, H, W] 表明它包含了三个时间步(当前帧以及之前两个时间步)的图像。
  • lerobot/example_hil_serl_dataset:

    • 来源: Hugging Face Hub 上的一个 lerobot 数据集。
    • 规模与特点: 这是一个用于 HIL-SERL 示例的演示数据集,主要用于训练奖励分类器和作为 offline_replay_buffer 的来源,提供了专家演示数据。它包含用于分类器训练的成功/失败状态标签。
    • 用途: 用于演示如何训练一个奖励分类器以生成稠密奖励信号,以及如何在 HIL-SERL 框架中作为离线经验回放缓冲区的数据源。
    • 样本示例: 虽然教程代码中未直接打印此数据集的样本,但根据其用途,它应包含机器人状态、观测(如图像)以及隐式或显式的奖励信号(例如,任务成功/失败的标签),这些标签用于奖励分类器学习。

选择这些数据集进行实验的原因:

  • 验证 lerobot 功能: 这些数据集是为演示 lerobot 库的功能而设计的,包括其统一的数据格式、数据加载、流式传输以及与机器学习模型集成的能力。
  • 代表性任务: 它们代表了机器人学习中的典型任务,如抓取放置 (pickplace) 和需要精细控制的操作,这些任务对于验证算法的有效性具有代表性。
  • Hugging Face 生态集成: 利用 Hugging Face Hub 托管数据集,体现了 lerobot 在开放性和社区共享方面的设计理念。

5.2. 评估指标

在 HIL-SERL 奖励分类器的训练示例 (Code 3) 中,使用了 lossaccuracy 作为评估指标。

  1. 准确率 (Accuracy):

    • 概念定义: 准确率是分类任务中最直观的评估指标之一,它衡量模型正确预测的样本比例。在奖励分类器中,它表示模型正确预测(例如,成功状态或失败状态)的样本数占总样本数的比例。
    • 数学公式: Accuracy=Number of Correct PredictionsTotal Number of Predictions \text{Accuracy} = \frac{\text{Number of Correct Predictions}}{\text{Total Number of Predictions}}
    • 符号解释:
      • Number of Correct Predictions\text{Number of Correct Predictions}: 模型正确分类(即预测与真实标签一致)的样本数量。
      • Total Number of Predictions\text{Total Number of Predictions}: 参与评估的所有样本的总数量。
  2. 损失 (Loss):

    • 概念定义: 损失函数 (Loss Function) 衡量模型预测值与真实值之间的差异。在训练过程中,优化算法的目标是最小化这个损失。在奖励分类器这样的二分类任务中,通常使用的是交叉熵损失 (Cross-Entropy Loss)。损失越小,表示模型预测越接近真实标签。
    • 数学公式 (二分类交叉熵损失为例): L=1Ni=1N[yilog(y^i)+(1yi)log(1y^i)] L = -\frac{1}{N} \sum_{i=1}^{N} [y_i \log(\hat{y}_i) + (1 - y_i) \log(1 - \hat{y}_i)]
    • 符号解释:
      • LL: 计算出的总损失值。
      • NN: 批次 (batch) 中的样本总数。
      • i=1N\sum_{i=1}^{N}: 对批次中所有 NN 个样本进行求和。
      • yiy_i: 第 ii 个样本的真实标签(对于二分类,通常为 0 或 1)。
      • y^i\hat{y}_i: 第 ii 个样本的模型预测概率(介于 0 和 1 之间,表示模型预测为正类的概率)。
      • log()\log(\cdot): 自然对数。

5.3. 对比基线

本教程的目的是提供一个全面的学习指南和实践框架,而非进行一项新的算法研究。因此,在教程的“实验设置”部分(即代码示例部分),并未设置明确的“对比基线”来比较 lerobot 中实现的不同算法或其性能。相反,教程展示了 lerobot 框架下各种先进算法(如 SAC)的实现和使用方式。

虽然在“机器人强化学习”章节中提及了多种 lerobot 中实现的 SOTA 算法 (如 ACT, Diffusion Policy, VQ-BeT, π0\pi_0, SmolVLA, HILSERL, TD-MPC),但这些提及是为了展示 lerobot 生态系统的广度,而非作为直接的实验对比对象。

6. 实验结果与分析

本教程的“实验结果与分析”主要体现在通过 lerobot 框架提供的代码示例,展示了机器人学习方法在实际操作中的配置、运行流程和预期输出。由于其教程性质,没有像研究论文那样提供大量的性能对比表格或图表,而是侧重于功能的实现和流程的演示。

6.1. 核心结果分析

6.1.1. Code 1: 批处理(流式)数据集

  • 预期输出与意义:
    • print(sample) 的输出展示了 LeRobotDataset 加载单个数据帧后的结构,包括 observation.state (机器人状态)、action (机器人动作) 和 observation.images.wrist_camera (手腕摄像头图像)。特别地,图像张量形状为 [3, C, H, W],这直观地表明了 delta_timestamps 配置成功实现了多帧堆叠,为时间序列建模提供了输入。
    • data_loader 的使用演示了如何将数据集封装成可迭代的批次数据流。在训练循环中,batch 变量能够正确地将数据移动到指定设备(如 cuda),这确认了 lerobot 数据集与 PyTorch 训练流程的无缝衔接。
  • 分析: 这个示例成功地展示了 LeRobotDataset 在数据准备阶段的实用性,特别是其处理多模态和时序数据的能力,以及与现有深度学习框架的兼容性。StreamingLeRobotDataset 的存在也凸显了 lerobot 在处理大规模数据集时的效率考量。

6.1.2. Code 2: 数据采集

  • 预期输出与意义:
    • 代码会打印录制过程中的日志信息,例如 "[LOG] Recording episode X of Y",显示当前正在录制的回合进度。
    • 录制结束后,会将收集到的数据推送到 Hugging Face Hub,并打印成功信息。
    • 在本地,会创建相应的 LeRobotDataset 目录结构 (data/data/, videos/videos/, meta_episodes/ 等),其中包含 parquet 文件和 MP4 视频文件。
  • 分析: 这个示例详细演示了如何使用 lerobot 框架从真实机器人(如 SO-100)和遥操作器(如 S0100Leader)收集多模态机器人数据。其意义在于:
    • 降低数据采集门槛: 提供了一个标准化的、易于使用的接口来管理复杂的机器人数据流。
    • 促进数据集共享: 数据可以直接推送到 Hugging Face Hub,便于社区共享和复现。
    • 结构化数据: 确保了采集到的数据以 LeRobotDataset 格式存储,为后续的机器人学习算法训练提供了统一的输入。

6.1.3. Code 3: 训练奖励分类器

  • 预期输出与意义:
    • 训练过程中会周期性地打印每个 epoch 的平均损失 (avg_loss) 和平均准确率 (avg_accuracy),例如 Epoch 1/5, Loss: 0.1234, Accuracy: 95.67%
    • 训练结束后,会打印 Training finished!,并将训练好的模型推送到 Hugging Face Hub
  • 分析: 该示例展示了如何在 lerobot 框架下训练一个奖励分类器。其核心意义在于解决了真实世界机器人强化学习中奖励函数设计困难的问题:
    • 自动化奖励设计: 通过监督学习的方式,从专家演示(通常是成功/失败标签)中学习一个分类器,将其输出转化为稠密奖励信号。
    • 可解释性与鲁棒性: 训练日志中的损失和准确率提供了模型性能的量化依据,确保了奖励分类器的有效性。
    • 模块化组件: 奖励分类器作为一个独立组件,可以预训练并用于后续的强化学习循环,提升了整个 HIL-SERL 系统的模块化和效率。

6.1.4. Code 4, 5, 6: 使用 HIL-SERL

  • 预期输出与意义:
    • Actor 进程输出: 会打印每个回合的开始信息 ("[ACTOR] Starting episode X")。当 Learner 更新策略参数时,Actor 会打印 "[ACTOR] Updated policy parameters from learner"。它还会输出机器人与环境互动的实时信息。
    • Learner 进程输出: 会打印在线和离线缓冲区的容量信息 ("[LEARNER] Online buffer capacity: X")。当检测到人类干预时,会打印 "[LEARNER] Human intervention detected! Added to offline buffer..."。训练过程中,会周期性打印训练步数、损失和缓冲区状态 ("[LEARNER]TrainingstepX,Loss:Y,Buffers:Online=A,Offline=B""[LEARNER] Training step X, Loss: Y, Buffers: Online = A, Offline = B")。当参数发送给 Actor 时,会打印 "[LEARNER] Sent updated parameters to actor"
    • 主进程输出: 协调两个进程的启动和关闭,并在接收到中断信号时优雅地关闭系统。
  • 分析: 这一系列代码完整地演示了 HIL-SERL 的核心工作机制:
    • Actor-Learner 分离架构: 成功实现了训练与探索的解耦,允许 Learner 在 GPU 上高效训练,而 Actor 在机器人上并行收集数据,提高了整体的样本效率。
    • 多进程通信: 通过 Queue 机制实现了 Actor 和 Learner 之间的数据和参数的异步传递,保证了系统的响应性和效率。
    • 混合经验回放: HIL-SERL 的关键在于 online_bufferoffline_buffer 的巧妙结合。offline_buffer 预填充专家演示和人类干预数据,确保了训练的稳定性和初始性能。online_buffer 则负责持续收集新的探索数据。训练时从两者中采样,最大化了数据的利用效率。
    • 实时策略更新: Learner 定期将最新策略参数推送到 Actor,使得 Actor 能够基于最新学习到的策略进行探索,形成闭环。
    • 样本效率提升: 通过人类干预和离线数据的利用,HIL-SERL 有望在真实世界机器人任务中实现更高的样本效率,减少昂贵的真实世界交互次数。

6.2. 数据呈现 (表格)

本教程的原文内容中,在方法论和代码示例章节没有直接提供表格形式的实验结果。它更多地是展示代码、概念和理论公式。

6.3. 消融实验/参数分析

作为一篇教程,本文档没有包含特定算法的消融实验或详细的参数分析。其重点在于展示 lerobot 框架的用法和 HIL-SERL 算法的实现流程,而非对算法本身进行性能验证或组件分析。教程中提及的超参数(如 batch_size, lr, MAX_EPISODES, FPS 等)是作为代码示例的配置参数出现,而非作为实验变量进行系统性研究。

7. 总结与思考

7.1. 结论总结

本教程深入探讨了机器人学习领域的现状,强调了其从经典模型驱动方法向数据驱动、学习型范式的转变。这一转变得益于机器学习的快速发展和大规模机器人数据的可用性,为自主系统带来了前所未有的能力。教程从强化学习和行为克隆的基础原理出发,逐步介绍了能够跨任务和跨机器人本体运行的通用型、语言条件型模型。通过 lerobot 开源框架中的实践示例,教程不仅提供了概念上的理解,更提供了实用的工具,旨在帮助研究人员和实践者投身于机器人学习的发展。核心结论是,数据驱动的机器人学习能够克服传统方法的泛化能力差、对人类专业知识依赖高和难以处理多模态数据等局限性,特别是在 lerobot 这样的集成框架下,真实世界机器人学习的门槛被显著降低。

7.2. 局限性与未来工作

论文(或其所介绍的方法)指出的自身局限性:

  1. 经典方法的局限性:
    • 泛化能力差: 难以跨任务、跨机器人本体泛化。
    • 对人类专业知识高度依赖: 模型设计和控制器调优需要大量人工投入。
    • 难以处理原始多模态数据: 传统方法难以直接处理异构、嘈杂的传感器数据流。
    • 未充分利用数据增长: 传统范式未能有效利用日益增长的开放机器人数据集。
  2. 强化学习在真实世界中的局限性:
    • 仿真器的高成本和维护难度: 构建高保真仿真器,特别是对于复杂接触和软体交互,耗时且昂贵。
    • 奖励函数设计困难: 设计有效的奖励函数是 RL 管道中的一个主要脆性来源,稀疏奖励导致探索效率低下,而密集奖励设计又需要大量专家知识和试错。

论文提出的未来可能的研究方向:

  1. 通用型机器人策略 (Generalist Robot Policies): 开发能够通过学习大规模多任务、多机器人数据来泛化到新任务和新环境的模型(即机器人基础模型)。
  2. 语言条件型模型 (Language-Conditioned Models): 将自然语言指令融入机器人学习,使机器人能够理解和执行更抽象、更灵活的任务。
  3. 样本高效的真实世界 RL: 进一步提升真实世界强化学习的样本效率,例如通过结合人类干预 (Human-in-the-Loop)、离线学习、奖励塑形等技术。
  4. 优化推理与部署: 提高学习型策略在真实机器人上的推理速度和效率,确保其在运行时具有适应性和鲁棒性。

7.3. 个人启发与批判

这篇论文对我的启发:

  • 范式转变的必然性: 论文清晰地展示了机器人领域从基于模型到数据驱动的范式转变,这不仅仅是技术迭代,更是解决复杂现实世界问题、实现机器人通用智能的必然路径。
  • 数据作为核心资产:lerobot 这样的框架强调了标准化、大规模机器人数据集的重要性,并提供了数据采集、管理和使用的工具,这表明数据在机器人学习中的核心地位。
  • 实践是理解的关键: 教程提供了大量的代码示例,这让我深刻体会到,理论概念只有通过实践才能真正内化。lerobot 作为一个开源库,大大降低了机器人学习的实践门槛。
  • 人机协作的潜力: HIL-SERL 算法展示了在真实世界 RL 中,人类的干预和专家演示如何有效地加速学习过程,提高样本效率和安全性。这提示在设计自主系统时,应充分考虑人机协作的潜力,而非一味追求完全自主。
  • 模块化与可组合性: lerobot 框架将数据集、策略、环境等组件模块化,并支持组合使用,这有助于快速迭代和实验,也更容易集成新的研究成果。

我对其潜在的问题、未经验证的假设或可以改进的地方:

  • 理论深度与算法细节: 作为一篇教程,它在介绍 RL 和 BC 基础时力求简洁,但在一些复杂算法(如扩散模型、通用型 VLA)的理论细节上未深入展开。对于完全的初学者而言,可能还需要查阅更多资料才能完全理解这些先进算法的内部机制。
  • 安全性与鲁棒性的验证: 真实世界机器人部署最核心的挑战之一是安全性与鲁棒性。虽然 HIL-SERL 提到了人类干预有助于安全性,但教程中未详细讨论在复杂、未知或高风险环境中学习型策略的故障模式、安全保障和认证问题。
  • 计算资源需求: 尽管 lerobot 提供了流式数据集等优化,但大规模数据驱动的机器人学习依然对计算资源(特别是 GPU)有较高要求。教程可以进一步探讨如何在有限资源下进行有效学习的策略,例如更高效的离线强化学习、模型压缩等。
  • lerobot 生态系统的成熟度: 作为一个相对较新的开源框架,lerobot 的生态系统成熟度、社区支持和文档完善程度可能会影响其长期可用性和普及。教程可以更详细地介绍如何贡献和寻求社区支持。
  • 超越操作和运动的泛化: 教程主要关注操作和运动任务。虽然提到了通用型机器人模型,但这些模型在更广泛、更开放的世界中(例如,需要长期规划、符号推理、常识理解的复杂任务)的实际能力和泛化界限仍是一个开放问题。

相似论文推荐

基于向量语义检索推荐的相关论文。

暂时没有找到相似论文。