LeRobot ACT——LeRobot对ALOHA ACT策略的封装:含源码解析与真机部署(效果比肩ACT原论文)

article/2025/8/2 23:54:10

前言

本文一开始是此文的第一部分,后随着我司各大具身团队对各个动作策略的实践、深入,觉得可以挖掘且分享的细节越来越多,比如LeRobot ACT,其效果也不错

ALOHA ACT的复现与应用:双臂下的智能分拣场景

故把其中的「LeRobot ACT的源码解析与真机部署」单独抽取出来,独立成此文

第一部分 封装的ALOHA ACT策略

如本博客中的此文《一文通透动作分块算法ACT:斯坦福ALOHA团队推出的动作序列预测算法(Action Chunking with Transformers)》所述

 下图左侧是CVAE编码器——包含一个transformer encoder,右侧是CVAE解码器——包含一个transformer encoder和一个transformer decoder)

  1. 上图左侧的CVAE 编码器(采用类似BERT的transformer编码器实现),其预测样式变量 z 的分布的均值和方差,该分布被参数化为对角高斯分布
    输入是来自当前关节位置,和来自示范数据集长度为k目标动作序列,前面再加上一个习得的类似于BERT中的“[CLS]”token,从而形成了一个k+2长度的输入

    通过编码器之后,使用“[CLS]”对应的特征用于预测“风格变量”z的均值和方差,这相当于CVAE 编码器的输出(当然,其同时也是CVAE解码器的输入之一)
  2. 上图右侧的CVAE解码器(即策略),通过z和当前观测(当前观测包括图像cam1~cam4、机器人关节位置joints)的条件来预测动作序列(即接下来的k个动作)
    且他们使用ResNet图像编码器、transformer encoder,和transformer decoder来实现CVAE解码器

ACT模型的核心思想是同时预测一系列未来动作(称为"动作块"),而不是传统方法中单步预测动作。这种设计使机器人能够表现出更连贯、更具前瞻性的行为模式,特别适合需要精确协调的复杂任务

1.1 policies/act/modeling_act.py

`ACTPolicy`类继承自`PreTrainedPolicy`,作为用户接口层,负责输入/输出归一化、动作选择和训练过程管理

它包含两种关键的动作选择机制:

  1. 一种是简单地维护预测动作的队列
  2. 另一种是使用`ACTTemporalEnsembler`进行时序集成,通过加权平均多次预测结果来提高稳定性
    时序集成器使用指数权重函数(`w_i = exp(-temporal_ensemble_coeff * i)`),可以调整对新旧预测的重视程度

底层神经网络`ACT`类采用多模态Transformer架构,包括:

  1. 可选的变分自编码器(VAE)编码器,用于在训练时捕获动作空间的潜在分布
  2. 基于ResNet的视觉骨干网络,用于提取图像特征
  3. Transformer编码器,处理来自不同输入模态(潜变量、机器人状态、环境状态、图像特征)的标记
  4. Transformer解码器,通过交叉注意力机制整合编码器信息并生成动作序列
  5. 动作回归头,将解码器输出转换为具体的控制信号
  6. 位置编码在整个架构中起着关键作用,包括一维和二维的正弦位置编码,使模型能够处理序列和空间信息

模型支持两种训练方式:使用变分目标(带KL散度正则化)或直接使用L1损失

1.1.1 ACTPolicy类

1.1.2 ACTTemporalEnsembler类

1.1.3 ACT类

如代码中的ASCII图所示

                                 TransformerUsed alone for inference(acts as VAE decoderduring training)┌───────────────────────┐│             Outputs   ││                ▲      ││     ┌─────►┌───────┐  │┌──────┐     │     │      │Transf.│  ││      │     │     ├─────►│decoder│  │┌────┴────┐ │     │     │      │       │  ││         │ │     │ ┌───┴───┬─►│       │  ││ VAE     │ │     │ │       │  └───────┘  ││ encoder │ │     │ │Transf.│             ││         │ │     │ │encoder│             │└───▲─────┘ │     │ │       │             ││       │     │ └▲──▲─▲─┘             ││       │     │  │  │ │               │inputs    └─────┼──┘  │ image emb.      ││    state emb.         │└───────────────────────┘

    整体结构包含三个主要组件:

    1. 用于捕获动作分布的VAE编码器(训练时使用)
    2. 处理多模态观察的Transformer编码器
    3. 以及生成动作序列的Transformer解码器
    1.3.1.1 __init__方法的实现

    初始化方法构建了一个由多个精心设计的组件组成的网络:

    1. 首先是可选的变分自编码器(VAE)部分,它采用BERT风格的设计,以CLS标记、机器人状态和动作序列作为输入,通过编码过程捕获动作分布的潜在表示
          def __init__(self, config: ACTConfig):# 初始化父类nn.Modulesuper().__init__()        # 存储配置参数  self.config = config      # 如果启用VAE模式if self.config.use_vae:  # 创建VAE编码器self.vae_encoder = ACTEncoder(config, is_vae_encoder=True)  # 创建分类标记嵌入层,只有1个标记self.vae_encoder_cls_embed = nn.Embedding(1, config.dim_model)  # 为机器人关节状态创建投影层,将其映射到隐藏维度# 如果提供了机器人状态特征if self.config.robot_state_feature:  # 从原始维度映射到模型维度self.vae_encoder_robot_state_input_proj = nn.Linear(self.config.robot_state_feature.shape[0], config.dim_model  )# 为动作(关节空间目标)创建投影层,将其映射到隐藏维度self.vae_encoder_action_input_proj = nn.Linear(# 动作特征的原始维度self.config.action_feature.shape[0],  # 映射到模型维度config.dim_model,  )
      VAE编码器使用固定的正弦位置编码和多层投影来处理不同类型的输入
                  # 从VAE编码器的输出创建到潜在分布参数空间的投影层(输出均值和方差)# *2是因为需要输出均值和方差self.vae_encoder_latent_output_proj = nn.Linear(config.dim_model, config.latent_dim * 2) # 为VAE编码器的输入创建固定的正弦位置嵌入,为批次维度添加一个维度# *2是因为需要输出均值和方差num_input_token_encoder = 1 + config.chunk_size Ç# 如果有机器人状态,则增加一个标记if self.config.robot_state_feature:  num_input_token_encoder += 1# 注册一个不需要梯度的缓冲区self.register_buffer(  # 缓冲区名称"vae_encoder_pos_enc", # 创建正弦位置编码并扩展批次维度create_sinusoidal_pos_embedding(num_input_token_encoder, config.dim_model).unsqueeze(0),  )
      当`use_vae`设为False时,这部分会被完全跳过,模型将使用全零向量作为潜变量
    2. 视觉处理采用配置化的预训练骨干网络(通常是ResNet),通过`IntermediateLayerGetter`提取深层特征
              # 用于图像特征提取的骨干网络# 如果使用图像特征if self.config.image_features:  # 从torchvision.models获取指定的骨干网络backbone_model = getattr(torchvision.models, config.vision_backbone)(  # 控制是否使用空洞卷积replace_stride_with_dilation=[False, False, config.replace_final_stride_with_dilation],  # 使用预训练权重weights=config.pretrained_backbone_weights,  # 使用冻结的批量归一化层(不更新统计信息)norm_layer=FrozenBatchNorm2d,  )# 注意:这里假设我们使用的是ResNet模型(因此layer4是最终特征图)# 注意:这个forward方法返回一个字典:{"feature_map": output}self.backbone = IntermediateLayerGetter(backbone_model, return_layers={"layer4": "feature_map"})  # 创建一个获取中间层输出的包装器
      这种设计使模型能够处理原始相机输入,而不需要手工设计的特征提取器
    3. 核心Transformer结构包含编码器和解码器
              # Transformer(在使用变分目标训练时充当VAE解码器)self.encoder = ACTEncoder(config)      # 创建Transformer编码器self.decoder = ACTDecoder(config)      # 创建Transformer解码器

      前者处理包括潜变量、机器人状态(即机器人的关节角度joints等状态信息)、环境状态和图像特征在内的多模态输入
              # Transformer编码器输入投影。标记将被结构化为# [latent, (robot_state), (env_state), (image_feature_map_pixels)]# 从骨干网络最后一层特征数到模型维度if self.config.robot_state_feature:  # 为机器人状态创建投影层self.encoder_robot_state_input_proj = nn.Linear(  # 从原始维度映射到模型维度self.config.robot_state_feature.shape[0], config.dim_model  )# 如果使用环境状态特征if self.config.env_state_feature:  # 为环境状态创建投影层self.encoder_env_state_input_proj = nn.Linear(  # 从原始维度映射到模型维度self.config.env_state_feature.shape[0], config.dim_model  )# 为潜在向量创建投影层self.encoder_latent_input_proj = nn.Linear(config.latent_dim, config.dim_model) # 如果使用图像特征if self.config.image_features:  # 为图像特征创建1x1卷积投影层self.encoder_img_feat_input_proj = nn.Conv2d(  # 从骨干网络最后一层特征数到模型维度backbone_model.fc.in_features, config.dim_model, kernel_size=1  )
      后者通过交叉注意力机制生成动作序列
              # Transformer解码器# 为transformer的解码器创建可学习的位置嵌入(类似于DETR的对象查询)# 为每个动作块位置创建嵌入self.decoder_pos_embed = nn.Embedding(config.chunk_size, config.dim_model)  # 在transformer解码器输出上的最终动作回归头# 从模型维度映射到动作维度self.action_head = nn.Linear(config.dim_model, self.config.action_feature.shape[0])  # 重置模型参数self._reset_parameters() 
      特别值得注意的是位置编码的处理:一维特征使用简单的嵌入层,而图像特征使用复杂的二维正弦位置编码(通过`ACTSinusoidalPositionEmbedding2d`实现),确保模型能够理解空间关系
              # Transformer编码器位置嵌入# 为潜在向量预留1个标记n_1d_tokens = 1  # 如果有机器人状态,则增加一个标记if self.config.robot_state_feature: n_1d_tokens += 1# 如果有环境状态,则增加一个标记if self.config.env_state_feature:  n_1d_tokens += 1# 为一维特征创建位置嵌入self.encoder_1d_feature_pos_embed = nn.Embedding(n_1d_tokens, config.dim_model)  # 如果使用图像特征if self.config.image_features:  # 创建二维正弦位置嵌入self.encoder_cam_feat_pos_embed = ACTSinusoidalPositionEmbedding2d(config.dim_model // 2)  

    该架构的模块化设计使其能够适应不同的任务需求:它可以处理多摄像头输入、不同的状态表示,并且可以通过配置参数调整如块大小、层数、头数等性能关键因素。最终,通过动作回归头,模型将解码器的输出映射为具体的控制信号,形成一个完整的感知-决策-控制流程,使机器人能够执行连贯、前瞻性的动作序列

    1.3.1.2 _reset_parameters的实现

    对于视觉处理,模型使用预训练的ResNet骨干网络(可配置)提取特征,并支持多摄像头输入

        def _reset_parameters(self):"""Xavier-uniform initialization of the transformer parameters as in the original code."""# 遍历编码器和解码器的所有参数for p in chain(self.encoder.parameters(), self.decoder.parameters()):  # 如果参数维度大于1(通常是权重矩阵if p.dim() > 1:  )# 使用Xavier均匀初始化nn.init.xavier_uniform_(p)  
    1.3.1.3 forward方法的实现

    前向传播流程清晰分明:可选的VAE编码阶段(仅用于训练)、输入准备阶段、Transformer编码-解码阶段和输出阶段

    1. Transformer部分的设计特别注重处理多模态输入和位置编码
      编码器处理包括潜在向量、机器人状态、环境状态和图像特征的标记序列,每种输入都有相应的投影层将其映射到共同的嵌入维度
      位置编码同样精心设计,包括一维序列的正弦位置编码和图像特征的二维正弦位置编码
    2. 解码器则使用可学习的位置嵌入(类似DETR的对象查询)和交叉注意力机制从编码器输出生成动作序列

    具体而言,方法首先处理批次大小确定,并根据配置和运行模式决定如何准备潜在向量

    1. 当启用VAE且处于训练模式时,它构建一个BERT风格的输入序列——如下图左下角所示,以CLS标记开始,后跟机器人状态(如果配置),最后是动作序列

    2. 这些输入经过嵌入层投影到统一维度空间,并添加正弦位置编码以保留序列顺序信息

      经过VAE编码器处理后,如上图右上角所示,CLS标记的输出被用来生成潜在空间分布参数(均值和对数方差),最后通过重参数化技巧(mu + exp(log_sigma/2) * 随机噪声)采样得到潜在向量z
                  # 将cls标记输出投影为潜在分布参数latent_pdf_params = self.vae_encoder_latent_output_proj(cls_token_out)  # 前半部分为均值参数mu = latent_pdf_params[:, : self.config.latent_dim]  # 后半部分为对数方差参数,这是2*log(sigma),这样做是为了匹配原始实现log_sigma_x2 = latent_pdf_params[:, self.config.latent_dim :]  # 使用重参数化技巧采样潜在变量,mu + exp(log_sigma/2)*噪声latent_sample = mu + log_sigma_x2.div(2).exp() * torch.randn_like(mu)
      这是VAE训练的关键步骤,确保梯度可以通过随机采样过程反向传播
      若不使用VAE,则简单地使用全零向量作为潜在表示

    接下来的多模态融合阶段展示了处理异构数据的精妙设计

    1. 方法首先准备Transformer编码器的输入「接收包含多模态输入(机器人状态、环境状态和/或摄像头图像)的批次数据」:
      从投影后的潜在向量开始
              # 准备transformer编码器的输入,首先添加投影后的潜在变量encoder_in_tokens = [self.encoder_latent_input_proj(latent_sample)]  # 准备一维特征的位置嵌入encoder_in_pos_embed = list(self.encoder_1d_feature_pos_embed.weight.unsqueeze(1))  
      根据配置添加机器人状态和环境状态标记
              # 机器人状态标记,如果配置包含机器人状态特征if self.config.robot_state_feature:  # 添加投影后的机器人状态
      encoder_in_tokens.append(self.encoder_robot_state_input_proj(batch["observation.state"]))  # 环境状态标记,如果配置包含环境状态特征if self.config.env_state_feature: # 添加投影后的环境状态encoder_in_tokens.append(  self.encoder_env_state_input_proj(batch["observation.environment_state"]))
      对于图像处理,它遍历每个摄像头视角,通过ResNet骨干网络提取特征
              # 相机观察特征和位置嵌入,如果配置包含图像特征if self.config.image_features: # 用于存储所有相机的特征all_cam_features = [] # 用于存储所有相机特征的位置嵌入all_cam_pos_embeds = []  # 遍历每个相机for cam_index in range(batch["observation.images"].shape[-4]):  # 通过骨干网络提取特征cam_features = self.backbone(batch["observation.images"][:, cam_index])["feature_map"]  # 生成2D位置嵌入并转换为与特征相同的数据类型,(B, C, h, w) , 将特征投影到模型维度cam_features = self.encoder_img_feat_input_proj(cam_features) # 添加到所有相机特征列表 all_cam_features.append(cam_features)  # 添加到所有相机位置嵌入列表all_cam_pos_embeds.append(cam_pos_embed)  
      添加二维位置编码,然后将所有特征拼接并重排为序列形式。这种设计允许模型无缝地整合来自不同来源的信息
    2. 最后的Transformer处理阶段将所有准备好的标记和位置编码输入编码器,产生上下文化的表示
      解码器以全零输入开始,通过交叉注意力机制关注编码器输出的相关部分,生成动作表示序列

      最终通过线性层将这些表示映射为具体的动作向量

    1.1.4 ACTEncoder类和ACTEncoderLayer类

    1.1.5 ACTDecoder类和ACTDecoderLayer类

    1.1.6 ACTSinusoidalPositionEmbedding2d类

    1.2 policies/act/configuration_act.py

    // 待更


    http://www.hkcw.cn/article/dsEPMbgwyr.shtml

    相关文章

    【Linux网络编程】网络层IP协议

    目录 IP协议的协议头格式 网段划分 特殊的IP地址 IP地址的数量限制 私有IP地址和公网IP地址 路由 IP协议的协议头格式 4位版本号 :指定IP协议的版本,对于IPv4,版本号就是4。 4位首部长度:表名IP协议报头的长度,单…

    微调大模型:什么时候该做,什么时候不该做?

    目录 一、什么是“微调”?你真的需要它吗? 二、什么时候不该微调? 🚫 不该微调的 5 个典型场景: 1. 通用问答、闲聊、常识类内容 2. 企业内部问答 / 文档助手 3. 想要通过微调“学会格式” 4. 没有大量高质量标…

    [AD] CrownJewel-1 Logon 4799+vss-ShadowCopy+NTDS.dit/SYSTEM+$MFT

    QA QA攻擊者可以濫用 vssadmin 實用程式來建立卷影快照,然後提取 NTDS.dit 等敏感檔案來繞過安全機制。確定卷影複製服務進入運作狀態的時間。2024-05-14 03:42:16建立卷影快照時,磁碟區複製服務會使用機器帳戶驗證權限並列舉使用者群組。找到卷影複製過…

    系统思考:整体观和心智模式

    如果你是小区管委会的主委,面对住户抱怨“电梯太慢,每次都要花很久等电梯”,是不是第一反应就是——换马达、更新软件,甚至换整台电梯?这其实是典型的“线性思维”陷阱——把问题看成孤立的零件故障。 从系统思考的角…

    常见相机的ISP算法

    常见的ISP算法 3A算法 去雾算法 图像增强算法 图像宽动态算法 图像的电子缩放算法,无极电子缩放 图像降噪算法 相机常见问题 1.相机启动速度问题,启动速度较慢 2.相机扛不住高低温问题 3.相机散热问题问题 4.相机高低温芯片保护掉电 5.相机的成像效果或者…

    黑马Java面试笔记之框架篇(Spring、SpringMvc、Springboot)

    一. 单例bean Spring框架中的单例bean是线程安全的吗? Spring框架中的bean是单例的,可以在注解Scope()进行设置 singleton:bean在每一个Spring IOC容器中只有一个实例。prototype:一个bean的定义可以有多个实例 总结 二. AOP AOP称…

    【Go】2、Go语言实战

    前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 前置知识 本篇将涉及到一些在命令行的输入输出操作,之前我们已经学习了fmt包用于输出内容,下面将介绍bufio包用于读入数据。 bufio包简介 bufio 是 Go 标准库…

    基于Python与本地Ollama的智能语音唤醒助手实现

    项目简介 本项目是一个基于 Python 的智能语音助手,集成了语音录制、语音识别、AI对话和语音合成功能。用户可以通过语音与本地部署的 Ollama 大模型进行自然对话。 技术架构 核心功能模块 语音录制 - 使用 sounddevice 录制用户语音语音识别 - 使用 faster-whi…

    Vue框架2(vue搭建方式2:利用脚手架,ElementUI)

    一.引入vue第二种搭建方式 在以前的前端项目中,一个项目需要多个html文件实现页面之前的切换,如果页面中需要依赖js或者css文件,那么我们就需要在多个html文件中都需要导入vue.js文件,太过繁琐. 现在前端开发都采用单页面结果,一个项目中只有一个html文件 其他不同的内容都写…

    维斯塔潘谈和拉塞尔碰撞 意外相撞引发讨论

    在F1西班牙大奖赛正赛中,维斯塔潘因与拉塞尔相撞被罚时10秒,最终排名第十。赛后采访中,记者问及那次碰撞。维斯塔潘表示两人开车时确实撞到了一起。当记者指出他本可以避免这种情况时,维斯塔潘承认了这一点。至于为什么会发生这样的情况,他表示自己也不清楚。责任编辑:zx…

    乌称摧毁俄大量轰炸机 俄媒称系谣言 谎言蛛网

    俄罗斯“与假新闻作战”网站发布文章称,通过分析乌克兰方面发布的视频可以确认,乌总统泽连斯基所谓“已摧毁34%俄罗斯远程机队”的说法并不属实。俄方认为,乌方的行动更像是编织了一张“谎言蛛网”。俄方分析指出,乌克兰实际上可能仅摧毁了两架图-95战略轰炸机及一架安-12运…

    IntelliJ IDEA 接入 Ollama 本地模型 Qwen-coder

    一:下载ollama 官网下载https://ollama.com/ 二:安装 一键自动安装,且安装的是C盘 如果C盘紧张,想装在其他盘符,在安装包目录下打开cmd命令行, 在你想安装的盘下创建一个文件夹,例如在D盘创建…

    C++学习-入门到精通【12】文件处理

    C学习-入门到精通【12】文件处理 目录 C学习-入门到精通【12】文件处理一、文件和流二、创建顺序文件三、从顺序文件读取数据文件定位指针对之前的程序进行修改:贷款查询程序 四、更新顺序文件五、随机存取文件1.创建随机存取文件2.修改程序:贷款处理程序…

    生成式AI模型的重要评估指标——FID

    1、引言 随着深度学习的发展迅速,生成式模型如生成对抗网络(GAN)、变分自编码器(VAE)等取得了显著的进展。看似逼真的图像数据,仍旧会有结构缺陷等情况发生,那么如何客观、准确的评估这些生成式…

    第十:如何在Pycharm中安装AI插件(Proxy AI)

    一.安装插件 1.通过官网安装:https://plugins.jetbrains.com/plugin/21056-proxy-ai2.通过设置安装:设置->插件->搜索:Proxy AI->点击安装3.安装后重启二.配置插件 1.配置路径:设置 -> 工具 -> CodeGPT或者Proxy…

    在Visual Studio开发平台使用通义灵码:AI代码助手的深度实践指南

    引言:当经典IDE遇见AI代码革命 Visual Studio(以下简称VS)作为微软推出的旗舰级集成开发环境,长期占据企业级开发工具的核心地位。然而,在智能化浪潮下,传统IDE的代码编写效率瓶颈日益显现。阿里云推出的通…

    为什么你必须降AI?——写给每一位学生与科研人

    📉 为什么要降 AI 检测率?一篇文章带你看清真相! 随着AI大模型的发展,越来越多的人开始使用人工智能辅助写作,无论是撰写论文、文案,还是职称申请材料,都大大提升了效率。然而,随之…

    万字长文带你深度探索 MCP:AI 连接的未来之光​,MCP如何让AI产生“心灵感应“

    文章目录 一、引言:开启 MCP 的神秘大门​二、MCP 的基本概念解析​2.1 MCP 的定义与内涵​2.2 与传统协议的区别与优势​ 三、MCP 的技术原理深度剖析​3.1 核心技术架构​3.2 数据格式与通信协议​ 四、MCP 的应用案例全景展示​4.1 WhatsApp MCP:AI 助…

    【人工智能】人工智能的10大算法详解(优缺点+实际案例)

    人工智能(AI)是现代科技的重要领域,其中的算法是实现智能的核心。本文将介绍10种常见的人工智能算法,包括它们的原理、训练方法、优缺点及适用场景。 1. 线性回归(Linear Regression) 模型原理 线性回归…

    程序员鱼皮最新项目-----AI超级智能体教程(一)

    文章目录 1.前言1.什么是AI大模型2.什么是多模态3.阿里云百炼平台介绍3.1文本调试展示3.2阿里云和dashscope的关系3.3平台智能体应用3.4工作流的创建3.5智能体编排应用 1.前言 最近鱼皮大佬出了一套关于这个AI 的教程,关注鱼皮大佬很久了,鱼皮大佬确实在…