写点什么

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

  • 2025-11-25
    浙江
  • 本文字数:7961 字

    阅读完需:约 26 分钟

在前 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 中,我们已经预置了一个最佳实践,就是这个过程的一个具体示例:

https://gallery.pai-ml.com/#/preview/deepLearning/cv/isaac_lab_wf4


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

1. 环境准备

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

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

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 模型

import subprocessimport osfrom urllib.parse import quotefrom 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_Datasetos.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_PATHpath = os.environ['ISAAC_GR00T_PATH']print(f"代码已下载到ISAAC_GR00T_PATH: {path}")
复制代码


import osfrom 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:

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


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

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


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

# 步骤a: 创建数据集文件夹mkdir -p /mnt/data/isaac_tmp/nb4/datasets
# 步骤b: 使用选定的teleoperation设备收集数据# 可用选项: spacemouse, keyboardcd /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 文件进行子任务标注:

# 创建数据集目录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 数据扩增过程:

# 创建数据集目录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


启动命令:

/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 模型的模仿学习。


数据合并:

# 创建数据集目录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_pathbase_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}。")
复制代码


视频重放:

# 创建数据集目录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 格式:

# 创建数据集目录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 模型训练所需的环境

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


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


启动命令:

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:

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

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


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

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 的模型服务:

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 模型,可以很好的模仿人类的“叠方块”动作,实现新技能的学习。

用户头像

还未添加个人签名 2020-10-15 加入

分享阿里云计算平台的大数据和AI方向的技术创新和趋势、实战案例、经验总结。

评论

发布
暂无评论
PAI Physical AI Notebook详解4:基于仿真的GR00T-N1.5模型微调_人工智能_阿里云大数据AI技术_InfoQ写作社区