PAI Physical AI Notebook详解4:基于仿真的GR00T-N1.5模型微调

在前3期Physical AI详解系列中,我们详细解读了数据采集、扩增、增强的全过程,以及导航模型(X-Mobility)微调训练的全过程。

在本期,我们将针对更复杂的VLA模型(以GR00T-N1.5为例)进行微调,同样需要经过人工演示、数据扩增、模仿学习、在环验证这几个步骤。

但是,相比前例中的BC-RNN和X-Mobility模型,GR00T-N1.5是一个更复杂的模型,需要更大规模的数据合成、模仿学习,并需要独立的服务端-客户端架构进行在环验证。相对于本系列的前3个最佳实践,本例可重点学习以下能力:

  1. 使用RobotLearningLab公共数据集

  2. 使用DLC进行分布式大规模数据扩增

  3. 使用DLC,针对较复杂的VLA模型进行分布式模仿学习

  4. 组合使用两台DSW进行服务端-客户端架构的软件在环验证

在PAI的Notebook Gallery中,我们已经预置了一个最佳实践,就是这个过程的一个具体示例:

gallery.pai-ml.com/#/preview/d...

下面我们来详细解读这个示例。

1. 环境准备

由于需要交互式环境进行人工演示,我们需要启动DSW。

以北京Region为例,我们可以基于以下镜像启动DSW,其中已经包含了Isaac Lab 2.2及其依赖环境:

bash 复制代码
dsw-registry-vpc.cn-beijing.cr.aliyuncs.com/pai-training-algorithm/isaac-sim:isaaclab220-nb4-v7-20250916

建议在启动时选择以下规格的公共资源或预付费资源配额,以确保具备Isaac Lab运行所需的RT Core:

  • ecs.ebmgn8is.32xlarge

  • ecs.gn8is-8x.32xlarge

  • ecs.ebmgn8te.32xlarge

  • ecs.ebmgn9t.48xlarge

同时,由于需要使用NVIDIA RobotLearningLab公共数据集,务必在启动时挂载此数据集到/mnt/RobotLearningLab_Dataset/路径,从而避免重复下载:

在环境启动后,使用Notebook中的初始化脚本,配置环境变量并下载GR00T模型

python 复制代码
import subprocess
import os
from urllib.parse import quote
from pathlib import Path

# 1. 持久&外部存储的路径,默认挂载外部存储到/mnt/data下
os.environ['EXTERNAL_STORAGE_PATH'] = '/mnt/data/isaac_tmp/nb4'
path = os.environ['EXTERNAL_STORAGE_PATH']
os.system(f'mkdir -p "{path}"')
print(f"需要将外部存储挂载到/mnt/data")
print(f"EXTERNAL_STORAGE_PATH: {path}\n")

# 2. Isaac Lab项目路径
os.environ['ROBOT_LEARNING_LAB_PATH'] = "/workspace/RobotLearningLab"
path = os.environ['ROBOT_LEARNING_LAB_PATH']
print(f"ROBOT_LEARNING_LAB_PATH: {path}")
path = os.environ['ISAACLAB_PATH']
print(f"ISAACLAB_PATH: {path}\n")

# 3. 相关数据路径,直接挂载PAI公共数据集RobotLearningLab_Dataset到/mnt/RobotLearningLab_Dataset
os.environ['ROBOT_LEARNING_LAB_DATA_PATH'] = "/mnt/RobotLearningLab_Dataset"
path = os.environ['ROBOT_LEARNING_LAB_DATA_PATH']
print(f"需要将PAI公共数据集RobotLearningLab_Dataset挂载到/mnt/RobotLearningLab_Dataset")
print(f"ROBOT_LEARNING_LAB_DATA_PATH: {path}")
print(f"我们预先采集和处理好的,可以用来训练的数据集位于: {path}/usecase/galbot_stack_cube/lerobot_joint_space\n")

# 4. Isaac-GR00T代码路径
os.environ['ISAAC_GR00T_PATH'] = os.environ['EXTERNAL_STORAGE_PATH']+"/Isaac-GR00T"
path = os.environ['ISAAC_GR00T_PATH']
print(f"需要将代码下载到指定路径")
print(f"ISAAC_GR00T_PATH: {path}\n")

# 5. 相关模型路径
os.environ['ISAAC_GR00T_MODEL_PATH'] = os.environ['EXTERNAL_STORAGE_PATH'] + "/GR00T-N1.5-3B"
path = os.environ['ISAAC_GR00T_MODEL_PATH']

print(f"需要将模型下载到指定路径")
print(f"ISAAC_GR00T_MODEL_PATH: {path}")
os.environ['ISAAC_GR00T_MODEL_POST_PATH'] = os.environ['EXTERNAL_STORAGE_PATH'] + "/checkpoint-40000"
path = os.environ['ISAAC_GR00T_MODEL_POST_PATH']
print(f"ISAAC_GR00T_MODEL_POST_PATH: {path}\n")

!wget https://pai-vision-data-sh.oss-cn-shanghai.aliyuncs.com/aigc-data/isaac/nb4/gr00t.tar -O /tmp/gr00t.tar
!tar -xf /tmp/gr00t.tar -C /tmp/ && rm /tmp/gr00t.tar && mv /tmp/gr00t $ISAAC_GR00T_PATH
path = os.environ['ISAAC_GR00T_PATH']
print(f"代码已下载到ISAAC_GR00T_PATH: {path}")

import os
from pathlib import Path

local_dir = Path("/root/isaac_cache")  # 缓存目录
external_dir = os.environ['EXTERNAL_STORAGE_PATH'] #持久化存储目录
print(f"下载模型到: {local_dir}")
if os.path.exists(local_dir):
    !rm -rf {local_dir}
local_dir.mkdir(parents=True, exist_ok=True)

print("开始下载模型...")
package = "GR00T-N1.5-3B.tar"
download_from_oss('aigc-data/isaac/nb4/', package, str(local_dir))
print("下载完成")
print("开始解压模型...")
zip_file = os.path.join(local_dir, package)
print(zip_file)
!tar -xf {zip_file} -C {local_dir}
!rm {zip_file}
print("解压完成")

print(f"开始移动到资产目录: {external_dir}") # 持久化存储目录
path = os.environ['ISAAC_GR00T_MODEL_PATH']
if os.path.exists(path):
    !rm -rf {path}
!mv {local_dir}/* {external_dir} 

print(f"GR00T-N1.5-3B已下载到ISAAC_GR00T_MODEL_PATH: {path}")

2. 人工演示

在DSW WebTerminal中,运行以下命令启动VNC:

bash 复制代码
/opt/TurboVNC/bin/vncserver :0 -geometry 3840x2160

在本地Terminal中执行以下命令连接DSW:

java 复制代码
ssh -L 5900:127.0.0.1:5900 root@DSW公网IP地址 -p DSW公网端口

使用TigerVNC等VNC工具打开VNC窗口,并在VNC中执行以下命令启动人工演示界面:

bash 复制代码
# 步骤a: 创建数据集文件夹
mkdir -p /mnt/data/isaac_tmp/nb4/datasets

# 步骤b: 使用选定的teleoperation设备收集数据
# 可用选项: spacemouse, keyboard
cd /workspace/RobotLearningLab && ./isaaclab.sh -p usecase/scripts/record_demos.py --task Isaac-Stack-Cube-Galbot-Left-Arm-RmpFlow-Rel-v0 --teleop_device keyboard --dataset_file /mnt/data/isaac_tmp/nb4/datasets/dataset.hdf5 --num_demos 10

在人工演示界面中,可以通过以下按键控制机器人夹爪的运动:

  • 重置所有命令: R

  • 切换夹爪(开/关): K

  • 沿x轴移动机械臂: W/S

  • 沿y轴移动机械臂: A/D

  • 沿z轴移动机械臂: Q/E

  • 沿x轴旋转机械臂: Z/X

  • 沿y轴旋转机械臂: T/G

  • 沿z轴旋转机械臂: C/V

视频演示>>

通过控制夹爪,将桌面上的立方体按照蓝色(底部) -> 红色(中间) -> 绿色(顶部)的顺序叠放,大约需要10个成功的演示。以下是一个成功演示的示例:

视频演示>>

3. 数据扩增

首先对采集得到的dataset.hdf5文件进行子任务标注:

ini 复制代码
# 创建数据集目录
path = os.environ.get("ROBOT_LEARNING_LAB_PATH")

output_path_str = os.environ.get("EXTERNAL_STORAGE_PATH")+"/datasets"
output_path = Path(output_path_str)
output_path.mkdir(parents=True, exist_ok=True)

# 标注
annotate_command = f"""
cd {path} && \
./isaaclab.sh -p usecase/scripts/annotate_demos.py \
--task Isaac-Stack-Cube-Galbot-Left-Arm-RmpFlow-Abs-Mimic-v0 \
--device cuda \
--auto \
--input_file {output_path_str}/dataset.hdf5 \
--output_file {output_path_str}/dataset_annotate.hdf5 \
--headless
"""


print("标注命令:")
print(annotate_command)

# 执行
!{annotate_command}

在DSW执行以下代码启动headless数据扩增过程:

ini 复制代码
# 创建数据集目录
path = os.environ.get("ROBOT_LEARNING_LAB_PATH")

output_path_str = os.environ.get("EXTERNAL_STORAGE_PATH")+"/datasets"
output_path = Path(output_path_str)
output_path.mkdir(parents=True, exist_ok=True)

# 扩增
generate_command = f"""
cd {path} && \
./isaaclab.sh -p usecase/scripts/generate_dataset.py \
--task Isaac-Stack-Cube-Galbot-Left-Arm-RmpFlow-Abs-Mimic-v0 \
--device cuda \
--num_envs 10 \
--generation_num_trials 10000 \
--input_file {output_path_str}/dataset_annotate.hdf5 \
--output_file {output_path_str}/dataset_generate.hdf5 \
--headless
"""

print("扩增命令:")
print(generate_command)

# 执行
!{generate_command}

其中:

  • --num_envs 10 代表同一时刻并行扩增10份数据

  • --generation_num_trials 10000 代表目标生成10000份成功操作的数据

  • --input_file {output_path_str}/dataset_annotate.hdf5 代表输入的数据,即上述步骤中经过子任务标注的数据文件

  • --output_file {output_path_str}/dataset_generate.hdf5 代表输出的数据文件存放位置

  • --device cuda 代表使用GPU卡进行生成加速

  • --headless 代表以无GUI的方式进行后台数据合成

运行过程中会产生如下日志:

其中类似84/144 (58.3%)的数据分别代表成功生成的数据条数、总共尝试的数据合成次数,以及数据合成的成功率。

3.1 在DLC中执行分布式数据扩增

可以看到,在DSW使用单机资源进行数据扩增,任务执行较慢。但其实每份数据的合成过程相互独立,可以使用数据并行(DP)的方式进行分布式处理:

在DLC中创建任务,环境配置如下:

镜像地址:dsw-registry-vpc.cn-beijing.cr.aliyuncs.com/pai-training-algorithm/isaac-sim:isaaclab220-nb4-v7-20250916

自定义数据集:挂载DSW中相同的自定义数据集,以确保可以读取到annotated_dataset.hdf5

启动命令:

css 复制代码
/workspace/RobotLearningLab/isaaclab.sh -p /mnt/data/isaac_tmp/nb4/datasets/ray_isaac_new.py
  --command "cd /workspace/RobotLearningLab &&         
  ./isaaclab.sh -p 
      /mnt/data/isaac_tmp/nb4/datasets/generate_dataset_ray.py         --task Isaac-Stack-Cube-Galbot-Left-Arm-RmpFlow-Abs-Mimic-v0        --device cuda         
   --num_envs 10         
   --generation_num_trials 625         
   --input_file 
     /mnt/data/isaac_tmp/nb4/datasets/dataset_annotate.hdf5         
   --output_file 
     /mnt/data/isaac_tmp/nb4/datasets/dataset_generate.hdf5         
   --headless"         
   --gpu 1         
   --cpu 10         
   --memory 80         
   --num_per_worker 8

其中:

  • --num_per_worker 8 代表一个节点运行8个数据合成任务

  • --gpu 1 --cpu 10 --memory 80 代表每个任务使用1张GPU、10个CPU核心、80GB内存

  • --generation_num_trials 625 代表每个数据合成任务目标生成625份数据

资源配置如下:

其中使用了Ray类型任务,以实现任务分布式执行

设置Ray的Head节点数为1,CPU核数为8,内存数为32GB

设置Ray的Worker节点数为2,每个Worker的GPU卡数为8,CPU核数为90,内存数为700

综上所述,我们总共将启动16个数据合成任务,每个任务:

  • CPU核数:10

  • 内存:80GB

  • GPU:1张

  • 目标数据合成数量:625条

这样总共使用2台8卡的ecs.ebmgn8te.32xlarge资源即可运行。

任务启动后,可以通过DLC界面右上角的Dashboard打开Ray控制台,查看任务运行的详细信息:

可以看到,16个数据合成任务已经成功启动并运行:

4. 数据处理

在完成数据扩增之后,需要经过合并、重放并转换为Lerobot格式才能用户GR00T N1.5模型的模仿学习。

数据合并:

python 复制代码
# 创建数据集目录
path = os.environ.get("ROBOT_LEARNING_LAB_PATH")

output_path_str = os.environ.get("EXTERNAL_STORAGE_PATH")+"/datasets"
output_path = Path(output_path_str)
output_path.mkdir(parents=True, exist_ok=True)

# 合并DLC生成的Mimic分片文件
def merge_datasets(input_files, output_file="merged_dataset.hdf5"):
    """
    合并多个HDF5数据集
    """
    cmd = f"{path}/isaaclab.sh -p {path}/scripts/tools/merge_hdf5_datasets.py \
    --input_files {' '.join(input_files)} \
    --output_file {output_file}"
    
    print(f"合并数据集: {cmd}")
    result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
    print(result.stdout)
    
    return output_file

dataset_path = output_path
base_name = "dataset_generate"

success_files = list(dataset_path.glob(f"{base_name}_*.hdf5"))
success_files = [f for f in success_files if "_failed" not in f.name]
 
failed_files = list(dataset_path.glob(f"{base_name}_*_failed.hdf5"))

if success_files:
    print(f"找到 {len(success_files)} 个成功分片文件,开始合并...")
    
    success_input_files = [str(f) for f in success_files]
    success_output = dataset_path / f"{base_name}.hdf5"
    
    merged_dataset = merge_datasets(success_input_files, str(success_output))
    if os.path.exists(success_output):
        print(f"成功文件合并完成: {merged_dataset}")
        for f in success_files:
            f.unlink() 
        
        mimic_dataset_path = success_output
    else:
        print(f"合并失败或未找到输出文件 {success_output}。")
    
if failed_files:
    print(f"找到 {len(failed_files)} 个失败分片文件,开始合并...")
    
    failed_input_files = [str(f) for f in failed_files]
    failed_output = dataset_path / f"{base_name}_failed.hdf5"

    failed_merged_dataset = merge_datasets(failed_input_files, str(failed_output))
    if os.path.exists(failed_output):
        print(f"失败文件合并完成: {failed_merged_dataset}")
        for f in failed_files:
            f.unlink() 

    else:
        print(f"合并失败或未找到输出文件 {failed_output}。")

视频重放:

ini 复制代码
# 创建数据集目录
path = os.environ.get("ROBOT_LEARNING_LAB_PATH")

output_path_str = os.environ.get("EXTERNAL_STORAGE_PATH")+"/datasets"
output_path = Path(output_path_str)
output_path.mkdir(parents=True, exist_ok=True)

# 重放演示命令
command = f"""
cd {path} && \
./isaaclab.sh -p usecase/scripts/replay_demos_with_camera.py \
--task Isaac-Stack-Cube-Galbot-Left-Arm-Image-Based-v0 \
--dataset_file {output_path_str}/dataset_generate.hdf5 \
--num_envs 10 \
--video \
--video_path {output_path_str} \
--camera_view_list ego left_wrist right_wrist \
--headless
"""

print("需要先重播轨迹以生成相应的视频数据,用于视觉模态的输入。")
print("生成后的数据会保存在Isaac-Stack-Cube-Galbot-Left-Arm-Image-Based-v0/videos中。")
print(command)

# 执行
!{command}

转换为Lerobot格式:

ini 复制代码
# 创建数据集目录
path = os.environ.get("ROBOT_LEARNING_LAB_PATH")

output_path_str = os.environ.get("EXTERNAL_STORAGE_PATH")+"/datasets"
output_path = Path(output_path_str)
output_path.mkdir(parents=True, exist_ok=True)

# 数据格式转换命令
command = f"""
cd {path} && \
./isaaclab.sh -p benchmarks/gr00t/convert_hdf5_to_lerobot_joint_space.py \
--data_root {output_path} \
--hdf5_filename dataset_generate.hdf5 \
--hdf5_file_path {output_path}/dataset_generate.hdf5 \
--lerobot_data_dir {output_path}/lerobot_joint_space
"""

print("需要再将所有模态的数据转成GR00T支持的 LeRobot 格式。")
print(command)

# 执行
!{command}

以下为一段头部与腕部合成视频的示例:

头部:视频演示>>

腕部:视频演示>>

5. 模仿学习

我们可以直接在DLC中启动分布式模仿学习任务:

环境配置:

镜像地址:使用以下预置的镜像,包含了GR00T N1.5模型训练所需的环境

bash 复制代码
dsw-registry-vpc.cn-beijing.cr.aliyuncs.com/pai-training-algorithm/isaac-sim:gr00t-nb4-v1-20250916

数据集挂载:确保挂载了DSW中使用的自定义数据集,以及RobotLearningLab公共数据集

启动命令:

bash 复制代码
cd /mnt/data/isaac_tmp/nb4/Isaac-GR00T &&             
    export WANDB_MODE=offline &&             
    NCCL_P2P_DISABLE=1 NCCL_IB_DISABLE=1 PYTHONPATH='./' 
    python scripts/gr00t_finetune.py             
    --base_model_path /mnt/data/isaac_tmp/nb4/GR00T-N1.5-3B             --dataset-path 
        /mnt/data/isaac_tmp/nb4/datasets/lerobot_joint_space            --num-gpus 2             
    --batch-size 2             
    --output-dir /mnt/data/isaac_tmp/nb4/datasets/joint_space_2_2       --max-steps 40000             
    --data-config galbot_joint_space             
    --video-backend decord             
    --no-tune-visual &&             
    sleep 30

其中:

  • --base_model_path /mnt/data/isaac_tmp/nb4/GR00T-N1.5-3B 代表使用GR00T-N1.5-3B模型作为基模进行模仿学习

  • --dataset-path /mnt/data/isaac_tmp/nb4/datasets/lerobot_joint_space 代表使用上述过程中扩增的数据作为训练集

  • --num-gpus 2 代表使用2张GPU作为训练资源,这里可以根据自己的资源配额余量自行调节

  • export WANDB_MODE=offline && NCCL_P2P_DISABLE=1 NCCL_IB_DISABLE=1 这里关闭了在线WandB和卡间互联,这里也可以根据实际环境和需求调整

观察任务日志,等待训练完成:

6. 闭环评估

待模仿学习过程完成后,我们可以组合使用2个DSW实例组合进行模型的闭环评估。

评估过程使用一个新的DSW作为服务端运行微调后的GR00T-N1.5模型,前面运行Isaac Lab的DSW作为客户端运行机器人本体,连接服务端指挥其动作。

6.1 启动服务端DSW

启动一个新的DSW实例,其中:

  • 使用GR00T模型服务镜像

    dsw-registry-vpc.${regionId}.cr.aliyuncs.com/pai-training-algorithm/isaac-sim:gr00t-nb4-v1-20250916

作为启动镜像

  • 确保挂载RobotLearningLab_Dataset和保存微调后模型的自定义数据集
  • 确保服务端DSW与客户端DSW位于同一个VPC内

启动后,在服务端DSW中执行以下代码获取服务端IP:

bash 复制代码
PRI_IP=$(ifconfig eth1 | grep 'inet ' | awk '{print $2}') && echo "我的私网IP是: $PRI_IP"

此处以获取的服务端IP为10.0.0.207为例。

在服务端DSW中启动GR00T-N1.5模型服务:

bash 复制代码
cd /mnt/data/isaac_tmp/nb4/Isaac-GR00T && 
python gr00t_inference_server.py --port 5555   --model_path /mnt/data/isaac_tmp/nb4/checkpoint-40000   --data_config galbot_joint_space

成功启动后可以观察到如下日志:

6.2 启动客户端DSW

可以复用数据扩增的DSW作为客户端DSW。

在客户端DSW的VNC桌面中,启动Isaac Lab环境,同时连接到服务端DSW的模型服务:

css 复制代码
cd /workspace/RobotLearningLab && ./isaaclab.sh -p benchmarks/gr00t/gr00t_inference_client.py --server_port 5555 --server_host 10.0.0.207 --num_total_experiments 100 --num_success_steps 8 --policy_type joint_space --task Isaac-Stack-Cube-Galbot-Left-Arm-Joint-Position-Image-Based-v0

请注意将其中的10.0.0.207替换为服务端DSW的实际IP地址。

在启动的Isaac Lab窗口中,可以看到机器人本体在模型的指挥下,开始执行叠方块的动作。

视频演示>>

两台DSW组合运行的整体效果如下:

视频演示>>

7. 总结

本最佳实践综合使用PAI-DSW、DLC等模块,针对GR00T-N1.5-3B模型,进行了人工演示、数据扩增、模仿学习以及在环验证。相对于本系列的前3个最佳实践,本例可重点学习以下能力:

  1. 使用RobotLearningLab公共数据集

  2. 使用DLC进行分布式大规模数据扩增

  3. 使用DLC,针对较复杂的VLA模型进行分布式模仿学习

  4. 组合使用两台DSW进行服务端-客户端架构的软件在环验证

经过实际操作可以验证,经过模仿学习的GR00T-N1.5-3B模型,可以很好的模仿人类的"叠方块"动作,实现新技能的学习。

相关推荐
老友@2 小时前
深入 Spring AI:架构与应用
人工智能·spring·ai·架构
caiyueloveclamp3 小时前
ChatPPT:AI PPT生成领域的“六边形战士“
人工智能·powerpoint·ai生成ppt·aippt·免费aippt
paperxie_xiexuo3 小时前
学术与职场演示文稿的结构化生成机制探析:基于 PaperXie AI PPT 功能的流程解构与适用性研究
大数据·数据库·人工智能·powerpoint
算家计算3 小时前
Meta第三代“分割一切”模型——SAM 3本地部署教程:首支持文本提示分割,400万概念、30毫秒响应,检测分割追踪一网打尽
人工智能·meta
CNRio3 小时前
生成式AI技术栈全解析:从模型架构到落地工程化
人工智能·架构
算家计算3 小时前
编程AI新王Claude Opus 4.5正式发布!编程基准突破80.9%,成本降三分之二
人工智能·ai编程·claude
青瓷程序设计3 小时前
鱼类识别系统【最新版】Python+TensorFlow+Vue3+Django+人工智能+深度学习+卷积神经网络算法
人工智能·python·深度学习
央链知播3 小时前
第二届中国数据产业发展大会暨2025元宇宙AI数据要素“金杏奖”颁奖盛典在广州隆重举行
人工智能·业界资讯·数据产业
GEO_NEWS3 小时前
解析华为Flex:ai的开源棋局
人工智能·华为·开源