Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +53 -0
- Piper_ros_private-ros-noetic/src/piper_description/meshes/base_link.STL +3 -0
- Piper_ros_private-ros-noetic/src/piper_description/meshes/link1.STL +3 -0
- Piper_ros_private-ros-noetic/src/piper_description/meshes/link2.STL +3 -0
- Piper_ros_private-ros-noetic/src/piper_description/meshes/link3.STL +3 -0
- Piper_ros_private-ros-noetic/src/piper_description/meshes/link4.STL +3 -0
- Piper_ros_private-ros-noetic/src/piper_description/meshes/link5.STL +3 -0
- Piper_ros_private-ros-noetic/src/piper_description/meshes/link6.STL +3 -0
- Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/base_link.STL +3 -0
- Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link1.STL +3 -0
- Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link2.STL +3 -0
- Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link3.STL +3 -0
- Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link4.STL +3 -0
- Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link5.STL +3 -0
- Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link6.STL +3 -0
- aloha-devel/act/train.sh +20 -0
- aloha-devel/robomimic/algo/__pycache__/algo.cpython-38.pyc +0 -0
- aloha-devel/robomimic/algo/__pycache__/bcq.cpython-38.pyc +0 -0
- aloha-devel/robomimic/algo/__pycache__/cql.cpython-38.pyc +0 -0
- aloha-devel/robomimic/algo/__pycache__/diffusion_policy.cpython-38.pyc +0 -0
- aloha-devel/robomimic/algo/__pycache__/hbc.cpython-38.pyc +0 -0
- aloha-devel/robomimic/algo/__pycache__/td3_bc.cpython-38.pyc +0 -0
- aloha-devel/robomimic/scripts/config_gen/bc_xfmr_gen.py +169 -0
- aloha-devel/robomimic/scripts/config_gen/diffusion_gen.py +263 -0
- aloha-devel/robomimic/scripts/conversion/convert_roboturk_pilot.py +192 -0
- aloha-devel/robomimic/scripts/conversion/convert_to_robosuite_v141.py +156 -0
- aloha-devel/robomimic/scripts/conversion/extract_action_dict.py +81 -0
- aloha-devel/robomimic/scripts/conversion/robosuite_add_absolute_actions.py +306 -0
- aloha-devel/robomimic/scripts/dataset_states_to_obs.py +375 -0
- aloha-devel/robomimic/scripts/download_momart_datasets.py +161 -0
- aloha-devel/robomimic/scripts/filter_dataset_size.py +81 -0
- aloha-devel/robomimic/scripts/plot_model_predictions.py +213 -0
- aloha-devel/robomimic/scripts/setup_macros.py +32 -0
- aloha-devel/robomimic/scripts/split_train_val.py +105 -0
- aloha-devel/robomimic/scripts/train.py +512 -0
- camera_ws/build/realsense-ros/realsense2_camera/CMakeFiles/realsense2_camera.dir/src/base_realsense_node.cpp.o +3 -0
- camera_ws/build/realsense-ros/realsense2_camera/CMakeFiles/realsense2_camera.dir/src/realsense_node_factory.cpp.o +3 -0
- camera_ws/build/realsense-ros/realsense2_camera/CMakeFiles/realsense2_camera.dir/src/t265_realsense_node.cpp.o +3 -0
- camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/d2c_viewer.cpp.o +3 -0
- camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/ob_camera_info.cpp.o +3 -0
- camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/ob_camera_node.cpp.o +3 -0
- camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/ob_camera_node_factory.cpp.o +3 -0
- camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/point_cloud_proc/point_cloud_xyz.cpp.o +3 -0
- camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/point_cloud_proc/point_cloud_xyzrgb.cpp.o +3 -0
- camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/ros_service.cpp.o +3 -0
- camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/utils.cpp.o +3 -0
- camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/uvc_camera_driver.cpp.o +3 -0
- camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera_node.dir/src/main.cpp.o +3 -0
- camera_ws/devel/lib/astra_camera/astra_camera_node +3 -0
- camera_ws/devel/lib/libastra_camera.so +3 -0
.gitattributes
CHANGED
|
@@ -34,3 +34,56 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
Piper_ros_private-ros-noetic/asserts/pictures/piper_rviz.jpg filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
Piper_ros_private-ros-noetic/asserts/pictures/piper_rviz.jpg filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/utils.cpp.o filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera_node.dir/src/main.cpp.o filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/base_link.STL filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
camera_ws/src/ros_astra_camera/include/openni2_redist/x64/PS1080Console filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
camera_ws/src/ros_astra_camera/include/openni2_redist/arm/OpenNI2/Drivers/libOniFile.so filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
camera_ws/devel/lib/astra_camera/astra_camera_node filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
camera_ws/src/ros_astra_camera/include/openni2_redist/x64/NiViewer filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
camera_ws/src/ros_astra_camera/include/openni2_redist/x64/OpenNI2/Drivers/libOniFile.so filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
camera_ws/src/ros_astra_camera/include/openni2_redist/arm/PS1080Console filter=lfs diff=lfs merge=lfs -text
|
| 46 |
+
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/uvc_camera_driver.cpp.o filter=lfs diff=lfs merge=lfs -text
|
| 47 |
+
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/d2c_viewer.cpp.o filter=lfs diff=lfs merge=lfs -text
|
| 48 |
+
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/ros_service.cpp.o filter=lfs diff=lfs merge=lfs -text
|
| 49 |
+
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/ob_camera_info.cpp.o filter=lfs diff=lfs merge=lfs -text
|
| 50 |
+
Piper_ros_private-ros-noetic/src/piper_description/meshes/base_link.STL filter=lfs diff=lfs merge=lfs -text
|
| 51 |
+
camera_ws/src/ros_astra_camera/cfg/1.png filter=lfs diff=lfs merge=lfs -text
|
| 52 |
+
camera_ws/build/realsense-ros/realsense2_camera/CMakeFiles/realsense2_camera.dir/src/base_realsense_node.cpp.o filter=lfs diff=lfs merge=lfs -text
|
| 53 |
+
camera_ws/src/ros_astra_camera/include/openni2_redist/arm64/PS1080Console filter=lfs diff=lfs merge=lfs -text
|
| 54 |
+
camera_ws/src/ros_astra_camera/include/openni2_redist/x64/OpenNI2/Drivers/liborbbec.so filter=lfs diff=lfs merge=lfs -text
|
| 55 |
+
collect_data/docs/episode_0_qpos.png filter=lfs diff=lfs merge=lfs -text
|
| 56 |
+
camera_ws/build/realsense-ros/realsense2_camera/CMakeFiles/realsense2_camera.dir/src/realsense_node_factory.cpp.o filter=lfs diff=lfs merge=lfs -text
|
| 57 |
+
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/point_cloud_proc/point_cloud_xyz.cpp.o filter=lfs diff=lfs merge=lfs -text
|
| 58 |
+
Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link4.STL filter=lfs diff=lfs merge=lfs -text
|
| 59 |
+
Piper_ros_private-ros-noetic/src/piper_description/meshes/link4.STL filter=lfs diff=lfs merge=lfs -text
|
| 60 |
+
camera_ws/src/realsense-ros/realsense2_description/meshes/plug.stl filter=lfs diff=lfs merge=lfs -text
|
| 61 |
+
Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link2.STL filter=lfs diff=lfs merge=lfs -text
|
| 62 |
+
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/ob_camera_node_factory.cpp.o filter=lfs diff=lfs merge=lfs -text
|
| 63 |
+
camera_ws/src/realsense-ros/realsense2_description/meshes/d455.stl filter=lfs diff=lfs merge=lfs -text
|
| 64 |
+
camera_ws/build/realsense-ros/realsense2_camera/CMakeFiles/realsense2_camera.dir/src/t265_realsense_node.cpp.o filter=lfs diff=lfs merge=lfs -text
|
| 65 |
+
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/ob_camera_node.cpp.o filter=lfs diff=lfs merge=lfs -text
|
| 66 |
+
camera_ws/src/ros_astra_camera/include/openni2_redist/x64/libOpenNI2.so filter=lfs diff=lfs merge=lfs -text
|
| 67 |
+
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/point_cloud_proc/point_cloud_xyzrgb.cpp.o filter=lfs diff=lfs merge=lfs -text
|
| 68 |
+
Piper_ros_private-ros-noetic/src/piper_description/meshes/link1.STL filter=lfs diff=lfs merge=lfs -text
|
| 69 |
+
Piper_ros_private-ros-noetic/src/piper_description/meshes/link5.STL filter=lfs diff=lfs merge=lfs -text
|
| 70 |
+
camera_ws/devel/lib/libastra_camera.so filter=lfs diff=lfs merge=lfs -text
|
| 71 |
+
camera_ws/src/ros_astra_camera/include/openni2_redist/arm/libOpenNI2.so filter=lfs diff=lfs merge=lfs -text
|
| 72 |
+
camera_ws/src/ros_astra_camera/include/openni2_redist/arm64/NiViewer filter=lfs diff=lfs merge=lfs -text
|
| 73 |
+
camera_ws/src/ros_astra_camera/include/openni2_redist/arm64/libOpenNI2.so filter=lfs diff=lfs merge=lfs -text
|
| 74 |
+
Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link1.STL filter=lfs diff=lfs merge=lfs -text
|
| 75 |
+
Piper_ros_private-ros-noetic/src/piper_description/meshes/link2.STL filter=lfs diff=lfs merge=lfs -text
|
| 76 |
+
collect_data/docs/1.png filter=lfs diff=lfs merge=lfs -text
|
| 77 |
+
Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link5.STL filter=lfs diff=lfs merge=lfs -text
|
| 78 |
+
camera_ws/src/ros_astra_camera/include/openni2_redist/arm/OpenNI2/Drivers/liborbbec.so filter=lfs diff=lfs merge=lfs -text
|
| 79 |
+
camera_ws/src/ros_astra_camera/include/openni2_redist/arm64/OpenNI2/Drivers/liborbbec.so filter=lfs diff=lfs merge=lfs -text
|
| 80 |
+
camera_ws/devel/lib/librealsense2_camera.so filter=lfs diff=lfs merge=lfs -text
|
| 81 |
+
Piper_ros_private-ros-noetic/src/piper_description/meshes/link3.STL filter=lfs diff=lfs merge=lfs -text
|
| 82 |
+
Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link3.STL filter=lfs diff=lfs merge=lfs -text
|
| 83 |
+
Piper_ros_private-ros-noetic/src/piper_description/meshes/link6.STL filter=lfs diff=lfs merge=lfs -text
|
| 84 |
+
camera_ws/src/ros_astra_camera/include/openni2_redist/arm64/OpenNI2/Drivers/libOniFile.so filter=lfs diff=lfs merge=lfs -text
|
| 85 |
+
camera_ws/src/realsense-ros/realsense2_description/meshes/d435.dae filter=lfs diff=lfs merge=lfs -text
|
| 86 |
+
Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link6.STL filter=lfs diff=lfs merge=lfs -text
|
| 87 |
+
camera_ws/src/realsense-ros/realsense2_description/meshes/d415.stl filter=lfs diff=lfs merge=lfs -text
|
| 88 |
+
camera_ws/src/realsense-ros/realsense2_description/meshes/l515.dae filter=lfs diff=lfs merge=lfs -text
|
| 89 |
+
collect_data/docs/1.gif filter=lfs diff=lfs merge=lfs -text
|
Piper_ros_private-ros-noetic/src/piper_description/meshes/base_link.STL
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:931bbb6f5c5290b3b62a85158b8df5385cf062586382072806819dc393c62bc2
|
| 3 |
+
size 509684
|
Piper_ros_private-ros-noetic/src/piper_description/meshes/link1.STL
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2c33c970be7eb178e8cca7c18e0f2f29a678bc1057e3387c5931104de11c3785
|
| 3 |
+
size 938084
|
Piper_ros_private-ros-noetic/src/piper_description/meshes/link2.STL
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f9d1ee8f4861c7f04ee0ae100363c92cd10b6e9961fa81527345d6b88c397da7
|
| 3 |
+
size 2658484
|
Piper_ros_private-ros-noetic/src/piper_description/meshes/link3.STL
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6b8befd0d8020ae1ebeb4bc6af3524c1d7fce12cff5524fe94f886fe7c110b8f
|
| 3 |
+
size 2511784
|
Piper_ros_private-ros-noetic/src/piper_description/meshes/link4.STL
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:322f3f19233d4c312d3074dfecda3b13a285f08fd83ef5adac77020d8db541f3
|
| 3 |
+
size 730484
|
Piper_ros_private-ros-noetic/src/piper_description/meshes/link5.STL
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:82700536a6c9a5cbd08d974f6785a0ecb38e66752a893df5ad68b87c13762890
|
| 3 |
+
size 1147884
|
Piper_ros_private-ros-noetic/src/piper_description/meshes/link6.STL
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e0b2050ba81a45c79c045b9f13e3d1dd11f84bca1beb12eebc3102651c8476cf
|
| 3 |
+
size 671184
|
Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/base_link.STL
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:931bbb6f5c5290b3b62a85158b8df5385cf062586382072806819dc393c62bc2
|
| 3 |
+
size 509684
|
Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link1.STL
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2c33c970be7eb178e8cca7c18e0f2f29a678bc1057e3387c5931104de11c3785
|
| 3 |
+
size 938084
|
Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link2.STL
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f9d1ee8f4861c7f04ee0ae100363c92cd10b6e9961fa81527345d6b88c397da7
|
| 3 |
+
size 2658484
|
Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link3.STL
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6b8befd0d8020ae1ebeb4bc6af3524c1d7fce12cff5524fe94f886fe7c110b8f
|
| 3 |
+
size 2511784
|
Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link4.STL
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:322f3f19233d4c312d3074dfecda3b13a285f08fd83ef5adac77020d8db541f3
|
| 3 |
+
size 730484
|
Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link5.STL
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:82700536a6c9a5cbd08d974f6785a0ecb38e66752a893df5ad68b87c13762890
|
| 3 |
+
size 1147884
|
Piper_ros_private-ros-noetic/src/piper_mujoco/mujoco_description/meshes_mujoco/link6.STL
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e0b2050ba81a45c79c045b9f13e3d1dd11f84bca1beb12eebc3102651c8476cf
|
| 3 |
+
size 671184
|
aloha-devel/act/train.sh
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
num_epochs=600
|
| 2 |
+
batch_size=48
|
| 3 |
+
num_episodes=80
|
| 4 |
+
ROOT=/inspire/hdd/ws-f4d69b29-e0a5-44e6-bd92-acf4de9990f0/public-project/chengdongzhou-240108390137/vla_projects/cobot_magic
|
| 5 |
+
train_dir=$ROOT/tranin_dir
|
| 6 |
+
pretrain_ckpt=$ROOT/policy_best.ckpt
|
| 7 |
+
ws_path=$(pwd)
|
| 8 |
+
dataset_dir=/inspire/ssd/ws-f4d69b29-e0a5-44e6-bd92-acf4de9990f0/public-project/public/aloha_group/blue_new
|
| 9 |
+
# echo "$pretrain_ckpt"
|
| 10 |
+
# echo "$train_dir"
|
| 11 |
+
# echo $(pwd)
|
| 12 |
+
|
| 13 |
+
cd $ws_path
|
| 14 |
+
|
| 15 |
+
python act/train.py --dataset $dataset_dir --ckpt_dir $train_dir/pretrain --batch_size $batch_size --num_epochs $num_epochs --num_episodes $num_episodes --pretrain_ckpt $pretrain_ckpt
|
| 16 |
+
python act/train.py --dataset /media/lin/T7/data0314/ --ckpt_dir $train_dir/no_pretrain --batch_size $batch_size --num_epochs $num_epochs --num_episodes $num_episodes
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
python act/train.py --dataset $dataset_dir --ckpt_dir $train_dir/no_pretrain --batch_size $batch_size --num_epochs $num_epochs --num_episodes $num_episodes
|
aloha-devel/robomimic/algo/__pycache__/algo.cpython-38.pyc
ADDED
|
Binary file (23 kB). View file
|
|
|
aloha-devel/robomimic/algo/__pycache__/bcq.cpython-38.pyc
ADDED
|
Binary file (31.9 kB). View file
|
|
|
aloha-devel/robomimic/algo/__pycache__/cql.cpython-38.pyc
ADDED
|
Binary file (21.5 kB). View file
|
|
|
aloha-devel/robomimic/algo/__pycache__/diffusion_policy.cpython-38.pyc
ADDED
|
Binary file (18.2 kB). View file
|
|
|
aloha-devel/robomimic/algo/__pycache__/hbc.cpython-38.pyc
ADDED
|
Binary file (10.5 kB). View file
|
|
|
aloha-devel/robomimic/algo/__pycache__/td3_bc.cpython-38.pyc
ADDED
|
Binary file (17 kB). View file
|
|
|
aloha-devel/robomimic/scripts/config_gen/bc_xfmr_gen.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from robomimic.scripts.config_gen.helper import *
|
| 2 |
+
|
| 3 |
+
def make_generator_helper(args):
|
| 4 |
+
algo_name_short = "bc_xfmr"
|
| 5 |
+
|
| 6 |
+
generator = get_generator(
|
| 7 |
+
algo_name="bc",
|
| 8 |
+
config_file=os.path.join(base_path, 'robomimic/exps/templates/bc_transformer.json'),
|
| 9 |
+
args=args,
|
| 10 |
+
algo_name_short=algo_name_short,
|
| 11 |
+
pt=True,
|
| 12 |
+
)
|
| 13 |
+
if args.ckpt_mode is None:
|
| 14 |
+
args.ckpt_mode = "off"
|
| 15 |
+
|
| 16 |
+
if args.env == "r2d2":
|
| 17 |
+
generator.add_param(
|
| 18 |
+
key="train.data",
|
| 19 |
+
name="ds",
|
| 20 |
+
group=2,
|
| 21 |
+
values=[
|
| 22 |
+
[{"path": p} for p in scan_datasets("~/Downloads/example_pen_in_cup", postfix="trajectory_im128.h5")],
|
| 23 |
+
],
|
| 24 |
+
value_names=[
|
| 25 |
+
"pen-in-cup",
|
| 26 |
+
],
|
| 27 |
+
)
|
| 28 |
+
generator.add_param(
|
| 29 |
+
key="observation.modalities.obs.rgb",
|
| 30 |
+
name="cams",
|
| 31 |
+
group=130,
|
| 32 |
+
values=[
|
| 33 |
+
# ["camera/image/hand_camera_left_image"],
|
| 34 |
+
["camera/image/hand_camera_left_image", "camera/image/varied_camera_1_left_image", "camera/image/varied_camera_2_left_image"],
|
| 35 |
+
],
|
| 36 |
+
value_names=[
|
| 37 |
+
# "wrist",
|
| 38 |
+
"3cams",
|
| 39 |
+
]
|
| 40 |
+
)
|
| 41 |
+
elif args.env == "kitchen":
|
| 42 |
+
generator.add_param(
|
| 43 |
+
key="train.data",
|
| 44 |
+
name="ds",
|
| 45 |
+
group=2,
|
| 46 |
+
values=[
|
| 47 |
+
[
|
| 48 |
+
{
|
| 49 |
+
"path": "/home/aaronl/tmp/v2_demos/KitchenPnPCounterToCab_im84.hdf5",
|
| 50 |
+
"filter_key": "100_demos",
|
| 51 |
+
"lang": "pick and place the object from the counter to the cabinet",
|
| 52 |
+
},
|
| 53 |
+
{
|
| 54 |
+
"path": "/home/aaronl/tmp/v2_demos/KitchenPnPCabToCounter_im84.hdf5",
|
| 55 |
+
"filter_key": "100_demos",
|
| 56 |
+
"lang": "pick and place the object from the cabinet to the counter",
|
| 57 |
+
},
|
| 58 |
+
],
|
| 59 |
+
],
|
| 60 |
+
value_names=[
|
| 61 |
+
"pnp-multi-task"
|
| 62 |
+
],
|
| 63 |
+
)
|
| 64 |
+
generator.add_param(
|
| 65 |
+
key="algo.language_conditioned",
|
| 66 |
+
name="langcond",
|
| 67 |
+
group=145892,
|
| 68 |
+
values=[
|
| 69 |
+
True,
|
| 70 |
+
False,
|
| 71 |
+
],
|
| 72 |
+
)
|
| 73 |
+
elif args.env == "square":
|
| 74 |
+
generator.add_param(
|
| 75 |
+
key="train.data",
|
| 76 |
+
name="ds",
|
| 77 |
+
group=2,
|
| 78 |
+
values=[
|
| 79 |
+
[
|
| 80 |
+
{"path": "~/datasets/square/ph/square_ph_abs_tmp.hdf5"}, # replace with your own path
|
| 81 |
+
],
|
| 82 |
+
],
|
| 83 |
+
value_names=[
|
| 84 |
+
"square",
|
| 85 |
+
],
|
| 86 |
+
)
|
| 87 |
+
else:
|
| 88 |
+
raise ValueError
|
| 89 |
+
|
| 90 |
+
# change default settings: predict 10 steps into future
|
| 91 |
+
generator.add_param(
|
| 92 |
+
key="algo.transformer.pred_future_acs",
|
| 93 |
+
name="predfuture",
|
| 94 |
+
group=1,
|
| 95 |
+
values=[
|
| 96 |
+
True,
|
| 97 |
+
# False,
|
| 98 |
+
],
|
| 99 |
+
hidename=True,
|
| 100 |
+
)
|
| 101 |
+
generator.add_param(
|
| 102 |
+
key="algo.transformer.supervise_all_steps",
|
| 103 |
+
name="supallsteps",
|
| 104 |
+
group=1,
|
| 105 |
+
values=[
|
| 106 |
+
True,
|
| 107 |
+
# False,
|
| 108 |
+
],
|
| 109 |
+
hidename=True,
|
| 110 |
+
)
|
| 111 |
+
generator.add_param(
|
| 112 |
+
key="algo.transformer.causal",
|
| 113 |
+
name="causal",
|
| 114 |
+
group=1,
|
| 115 |
+
values=[
|
| 116 |
+
False,
|
| 117 |
+
# True,
|
| 118 |
+
],
|
| 119 |
+
hidename=True,
|
| 120 |
+
)
|
| 121 |
+
generator.add_param(
|
| 122 |
+
key="train.seq_length",
|
| 123 |
+
name="",
|
| 124 |
+
group=-1,
|
| 125 |
+
values=[10],
|
| 126 |
+
hidename=True,
|
| 127 |
+
)
|
| 128 |
+
|
| 129 |
+
generator.add_param(
|
| 130 |
+
key="algo.gmm.min_std",
|
| 131 |
+
name="mindstd",
|
| 132 |
+
group=271314,
|
| 133 |
+
values=[
|
| 134 |
+
0.03,
|
| 135 |
+
#0.0001,
|
| 136 |
+
],
|
| 137 |
+
hidename=True,
|
| 138 |
+
)
|
| 139 |
+
generator.add_param(
|
| 140 |
+
key="train.max_grad_norm",
|
| 141 |
+
name="maxgradnorm",
|
| 142 |
+
group=18371,
|
| 143 |
+
values=[
|
| 144 |
+
# None,
|
| 145 |
+
100.0,
|
| 146 |
+
],
|
| 147 |
+
hidename=True,
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
generator.add_param(
|
| 151 |
+
key="train.output_dir",
|
| 152 |
+
name="",
|
| 153 |
+
group=-1,
|
| 154 |
+
values=[
|
| 155 |
+
"~/expdata/{env}/{mod}/{algo_name_short}".format(
|
| 156 |
+
env=args.env,
|
| 157 |
+
mod=args.mod,
|
| 158 |
+
algo_name_short=algo_name_short,
|
| 159 |
+
)
|
| 160 |
+
],
|
| 161 |
+
)
|
| 162 |
+
|
| 163 |
+
return generator
|
| 164 |
+
|
| 165 |
+
if __name__ == "__main__":
|
| 166 |
+
parser = get_argparser()
|
| 167 |
+
|
| 168 |
+
args = parser.parse_args()
|
| 169 |
+
make_generator(args, make_generator_helper)
|
aloha-devel/robomimic/scripts/config_gen/diffusion_gen.py
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from robomimic.scripts.config_gen.helper import *
|
| 2 |
+
|
| 3 |
+
def make_generator_helper(args):
|
| 4 |
+
algo_name_short = "diffusion_policy"
|
| 5 |
+
|
| 6 |
+
generator = get_generator(
|
| 7 |
+
algo_name="diffusion_policy",
|
| 8 |
+
config_file=os.path.join(base_path, 'robomimic/exps/templates/diffusion_policy.json'),
|
| 9 |
+
args=args,
|
| 10 |
+
algo_name_short=algo_name_short,
|
| 11 |
+
pt=True,
|
| 12 |
+
)
|
| 13 |
+
if args.ckpt_mode is None:
|
| 14 |
+
args.ckpt_mode = "off"
|
| 15 |
+
|
| 16 |
+
generator.add_param(
|
| 17 |
+
key="train.num_data_workers",
|
| 18 |
+
name="",
|
| 19 |
+
group=-1,
|
| 20 |
+
values=[8],
|
| 21 |
+
)
|
| 22 |
+
|
| 23 |
+
generator.add_param(
|
| 24 |
+
key="train.num_epochs",
|
| 25 |
+
name="",
|
| 26 |
+
group=-1,
|
| 27 |
+
values=[1000],
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
# use ddim by default
|
| 31 |
+
generator.add_param(
|
| 32 |
+
key="algo.ddim.enabled",
|
| 33 |
+
name="ddim",
|
| 34 |
+
group=1001,
|
| 35 |
+
values=[
|
| 36 |
+
True,
|
| 37 |
+
# False,
|
| 38 |
+
],
|
| 39 |
+
hidename=True,
|
| 40 |
+
)
|
| 41 |
+
generator.add_param(
|
| 42 |
+
key="algo.ddpm.enabled",
|
| 43 |
+
name="ddpm",
|
| 44 |
+
group=1001,
|
| 45 |
+
values=[
|
| 46 |
+
False,
|
| 47 |
+
# True,
|
| 48 |
+
],
|
| 49 |
+
hidename=True,
|
| 50 |
+
)
|
| 51 |
+
|
| 52 |
+
if args.env == "r2d2":
|
| 53 |
+
generator.add_param(
|
| 54 |
+
key="train.data",
|
| 55 |
+
name="ds",
|
| 56 |
+
group=2,
|
| 57 |
+
values=[
|
| 58 |
+
[{"path": p, "lang": "put the pen in the cup"} for p in scan_datasets("~/Downloads/example_pen_in_cup", postfix="trajectory_im128.h5")],
|
| 59 |
+
],
|
| 60 |
+
value_names=[
|
| 61 |
+
"pen-in-cup",
|
| 62 |
+
],
|
| 63 |
+
)
|
| 64 |
+
generator.add_param(
|
| 65 |
+
key="train.action_keys",
|
| 66 |
+
name="ac_keys",
|
| 67 |
+
group=-1,
|
| 68 |
+
values=[
|
| 69 |
+
[
|
| 70 |
+
"action/abs_pos",
|
| 71 |
+
"action/abs_rot_6d",
|
| 72 |
+
"action/gripper_position",
|
| 73 |
+
],
|
| 74 |
+
],
|
| 75 |
+
value_names=[
|
| 76 |
+
"abs",
|
| 77 |
+
],
|
| 78 |
+
hidename=True,
|
| 79 |
+
)
|
| 80 |
+
generator.add_param(
|
| 81 |
+
key="observation.modalities.obs.rgb",
|
| 82 |
+
name="cams",
|
| 83 |
+
group=130,
|
| 84 |
+
values=[
|
| 85 |
+
# ["camera/image/hand_camera_left_image"],
|
| 86 |
+
# ["camera/image/hand_camera_left_image", "camera/image/hand_camera_right_image"],
|
| 87 |
+
["camera/image/hand_camera_left_image", "camera/image/varied_camera_1_left_image", "camera/image/varied_camera_2_left_image"],
|
| 88 |
+
# [
|
| 89 |
+
# "camera/image/hand_camera_left_image", "camera/image/hand_camera_right_image",
|
| 90 |
+
# "camera/image/varied_camera_1_left_image", "camera/image/varied_camera_1_right_image",
|
| 91 |
+
# "camera/image/varied_camera_2_left_image", "camera/image/varied_camera_2_right_image",
|
| 92 |
+
# ],
|
| 93 |
+
],
|
| 94 |
+
value_names=[
|
| 95 |
+
# "wrist",
|
| 96 |
+
# "wrist-stereo",
|
| 97 |
+
"3cams",
|
| 98 |
+
# "3cams-stereo",
|
| 99 |
+
]
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
generator.add_param(
|
| 103 |
+
key="observation.modalities.obs.low_dim",
|
| 104 |
+
name="ldkeys",
|
| 105 |
+
group=2498,
|
| 106 |
+
values=[
|
| 107 |
+
["robot_state/cartesian_position", "robot_state/gripper_position"],
|
| 108 |
+
# [
|
| 109 |
+
# "robot_state/cartesian_position", "robot_state/gripper_position",
|
| 110 |
+
# "camera/extrinsics/hand_camera_left", "camera/extrinsics/hand_camera_left_gripper_offset",
|
| 111 |
+
# "camera/extrinsics/hand_camera_right", "camera/extrinsics/hand_camera_right_gripper_offset",
|
| 112 |
+
# "camera/extrinsics/varied_camera_1_left", "camera/extrinsics/varied_camera_1_right",
|
| 113 |
+
# "camera/extrinsics/varied_camera_2_left", "camera/extrinsics/varied_camera_2_right",
|
| 114 |
+
# ]
|
| 115 |
+
],
|
| 116 |
+
value_names=[
|
| 117 |
+
"proprio",
|
| 118 |
+
# "proprio-extrinsics",
|
| 119 |
+
]
|
| 120 |
+
)
|
| 121 |
+
|
| 122 |
+
generator.add_param(
|
| 123 |
+
key="observation.encoder.rgb.core_kwargs.backbone_class",
|
| 124 |
+
name="backbone",
|
| 125 |
+
group=1234,
|
| 126 |
+
values=[
|
| 127 |
+
"ResNet18Conv",
|
| 128 |
+
# "ResNet50Conv",
|
| 129 |
+
],
|
| 130 |
+
)
|
| 131 |
+
generator.add_param(
|
| 132 |
+
key="observation.encoder.rgb.core_kwargs.feature_dimension",
|
| 133 |
+
name="visdim",
|
| 134 |
+
group=1234,
|
| 135 |
+
values=[
|
| 136 |
+
64,
|
| 137 |
+
# 512,
|
| 138 |
+
],
|
| 139 |
+
)
|
| 140 |
+
|
| 141 |
+
generator.add_param(
|
| 142 |
+
key="algo.language_conditioned",
|
| 143 |
+
name="langcond",
|
| 144 |
+
group=145892,
|
| 145 |
+
values=[
|
| 146 |
+
True,
|
| 147 |
+
False,
|
| 148 |
+
],
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
elif args.env == "kitchen":
|
| 152 |
+
generator.add_param(
|
| 153 |
+
key="train.data",
|
| 154 |
+
name="ds",
|
| 155 |
+
group=2,
|
| 156 |
+
values=[
|
| 157 |
+
# [{"path": "~/datasets/kitchen/prior/human_demos/pnp_table_to_cab/bowls/20230816_im84.hdf5", "filter_key": "100_demos"}],
|
| 158 |
+
[{"path": "~/datasets/kitchen/prior/human_demos/pnp_table_to_cab/all/20230806_im84.hdf5", "filter_key": "100_demos"}],
|
| 159 |
+
# [{"path": "~/datasets/kitchen/prior/mimicgen/pnp_table_to_cab/viraj_mg_2023-08-10-20-31-14/demo_im84.hdf5", "filter_key": "100_demos"}],
|
| 160 |
+
# [{"path": "~/datasets/kitchen/prior/mimicgen/pnp_table_to_cab/viraj_mg_2023-08-10-20-31-14/demo_im84.hdf5", "filter_key": "1000_demos"}],
|
| 161 |
+
],
|
| 162 |
+
value_names=[
|
| 163 |
+
# "bowls-human-100",
|
| 164 |
+
"human-100",
|
| 165 |
+
# "mg-100",
|
| 166 |
+
# "mg-1000",
|
| 167 |
+
],
|
| 168 |
+
)
|
| 169 |
+
|
| 170 |
+
# update env config to use absolute action control
|
| 171 |
+
generator.add_param(
|
| 172 |
+
key="experiment.env_meta_update_dict",
|
| 173 |
+
name="",
|
| 174 |
+
group=-1,
|
| 175 |
+
values=[
|
| 176 |
+
{"env_kwargs": {"controller_configs": {"control_delta": False}}}
|
| 177 |
+
],
|
| 178 |
+
)
|
| 179 |
+
|
| 180 |
+
generator.add_param(
|
| 181 |
+
key="train.action_keys",
|
| 182 |
+
name="ac_keys",
|
| 183 |
+
group=-1,
|
| 184 |
+
values=[
|
| 185 |
+
[
|
| 186 |
+
"action_dict/abs_pos",
|
| 187 |
+
"action_dict/abs_rot_6d",
|
| 188 |
+
"action_dict/gripper",
|
| 189 |
+
"action_dict/base_mode",
|
| 190 |
+
# "actions",
|
| 191 |
+
],
|
| 192 |
+
],
|
| 193 |
+
value_names=[
|
| 194 |
+
"abs",
|
| 195 |
+
],
|
| 196 |
+
hidename=True,
|
| 197 |
+
)
|
| 198 |
+
elif args.env == "square":
|
| 199 |
+
generator.add_param(
|
| 200 |
+
key="train.data",
|
| 201 |
+
name="ds",
|
| 202 |
+
group=2,
|
| 203 |
+
values=[
|
| 204 |
+
[
|
| 205 |
+
{"path": "~/datasets/square/ph/square_ph_abs_tmp.hdf5"}, # replace with your own path
|
| 206 |
+
],
|
| 207 |
+
],
|
| 208 |
+
value_names=[
|
| 209 |
+
"square",
|
| 210 |
+
],
|
| 211 |
+
)
|
| 212 |
+
|
| 213 |
+
# update env config to use absolute action control
|
| 214 |
+
generator.add_param(
|
| 215 |
+
key="experiment.env_meta_update_dict",
|
| 216 |
+
name="",
|
| 217 |
+
group=-1,
|
| 218 |
+
values=[
|
| 219 |
+
{"env_kwargs": {"controller_configs": {"control_delta": False}}}
|
| 220 |
+
],
|
| 221 |
+
)
|
| 222 |
+
|
| 223 |
+
generator.add_param(
|
| 224 |
+
key="train.action_keys",
|
| 225 |
+
name="ac_keys",
|
| 226 |
+
group=-1,
|
| 227 |
+
values=[
|
| 228 |
+
[
|
| 229 |
+
"action_dict/abs_pos",
|
| 230 |
+
"action_dict/abs_rot_6d",
|
| 231 |
+
"action_dict/gripper",
|
| 232 |
+
# "actions",
|
| 233 |
+
],
|
| 234 |
+
],
|
| 235 |
+
value_names=[
|
| 236 |
+
"abs",
|
| 237 |
+
],
|
| 238 |
+
)
|
| 239 |
+
|
| 240 |
+
|
| 241 |
+
else:
|
| 242 |
+
raise ValueError
|
| 243 |
+
|
| 244 |
+
generator.add_param(
|
| 245 |
+
key="train.output_dir",
|
| 246 |
+
name="",
|
| 247 |
+
group=-1,
|
| 248 |
+
values=[
|
| 249 |
+
"~/expdata/{env}/{mod}/{algo_name_short}".format(
|
| 250 |
+
env=args.env,
|
| 251 |
+
mod=args.mod,
|
| 252 |
+
algo_name_short=algo_name_short,
|
| 253 |
+
)
|
| 254 |
+
],
|
| 255 |
+
)
|
| 256 |
+
|
| 257 |
+
return generator
|
| 258 |
+
|
| 259 |
+
if __name__ == "__main__":
|
| 260 |
+
parser = get_argparser()
|
| 261 |
+
|
| 262 |
+
args = parser.parse_args()
|
| 263 |
+
make_generator(args, make_generator_helper)
|
aloha-devel/robomimic/scripts/conversion/convert_roboturk_pilot.py
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Helper script to convert the RoboTurk Pilot datasets (https://roboturk.stanford.edu/dataset_sim.html)
|
| 3 |
+
into a format compatible with this repository. It will also create some useful filter keys
|
| 4 |
+
in the file (e.g. training, validation, and fastest n trajectories). Prior work
|
| 5 |
+
(https://arxiv.org/abs/1911.05321) has found this useful (for example, training on the
|
| 6 |
+
fastest 225 demonstrations for bins-Can).
|
| 7 |
+
|
| 8 |
+
Direct download link for dataset: http://cvgl.stanford.edu/projects/roboturk/RoboTurkPilot.zip
|
| 9 |
+
|
| 10 |
+
Args:
|
| 11 |
+
folder (str): path to a folder containing a demo.hdf5 and a models directory containing
|
| 12 |
+
mujoco xml files. For example, RoboTurkPilot/bins-Can.
|
| 13 |
+
|
| 14 |
+
n (int): creates a filter key corresponding to the n fastest trajectories. Defaults to 225.
|
| 15 |
+
|
| 16 |
+
Example usage:
|
| 17 |
+
|
| 18 |
+
python convert_roboturk_pilot.py --folder /path/to/RoboTurkPilot/bins-Can --n 225
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
import os
|
| 22 |
+
import h5py
|
| 23 |
+
import json
|
| 24 |
+
import argparse
|
| 25 |
+
import numpy as np
|
| 26 |
+
from tqdm import tqdm
|
| 27 |
+
|
| 28 |
+
import robomimic
|
| 29 |
+
import robomimic.envs.env_base as EB
|
| 30 |
+
from robomimic.utils.file_utils import create_hdf5_filter_key
|
| 31 |
+
from robomimic.scripts.split_train_val import split_train_val_from_hdf5
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def convert_rt_pilot_hdf5(ref_folder):
|
| 35 |
+
"""
|
| 36 |
+
Uses the reference demo hdf5 to write a new converted hdf5 compatible with
|
| 37 |
+
the repository.
|
| 38 |
+
|
| 39 |
+
Args:
|
| 40 |
+
ref_folder (str): path to a folder containing a demo.hdf5 and a models directory containing
|
| 41 |
+
mujoco xml files.
|
| 42 |
+
"""
|
| 43 |
+
hdf5_path = os.path.join(ref_folder, "demo.hdf5")
|
| 44 |
+
new_path = os.path.join(ref_folder, "demo_new.hdf5")
|
| 45 |
+
|
| 46 |
+
f = h5py.File(hdf5_path, "r")
|
| 47 |
+
f_new = h5py.File(new_path, "w")
|
| 48 |
+
f_new_grp = f_new.create_group("data")
|
| 49 |
+
|
| 50 |
+
# sorted list of demonstrations by demo number
|
| 51 |
+
demos = list(f["data"].keys())
|
| 52 |
+
inds = np.argsort([int(elem[5:]) for elem in demos])
|
| 53 |
+
demos = [demos[i] for i in inds]
|
| 54 |
+
|
| 55 |
+
# write each demo
|
| 56 |
+
num_samples_arr = []
|
| 57 |
+
for demo_id in tqdm(range(len(demos))):
|
| 58 |
+
ep = demos[demo_id]
|
| 59 |
+
|
| 60 |
+
# create group for this demonstration
|
| 61 |
+
ep_data_grp = f_new_grp.create_group(ep)
|
| 62 |
+
|
| 63 |
+
# copy states over
|
| 64 |
+
states = f["data/{}/states".format(ep)][()]
|
| 65 |
+
ep_data_grp.create_dataset("states", data=np.array(states))
|
| 66 |
+
|
| 67 |
+
# concat jvels and gripper actions to form full actions
|
| 68 |
+
jvels = f["data/{}/joint_velocities".format(ep)][()]
|
| 69 |
+
gripper_acts = f["data/{}/gripper_actuations".format(ep)][()]
|
| 70 |
+
actions = np.concatenate([jvels, gripper_acts], axis=1)
|
| 71 |
+
|
| 72 |
+
# IMPORTANT: clip actions to -1, 1, since this is expected by the codebase
|
| 73 |
+
actions = np.clip(actions, -1., 1.)
|
| 74 |
+
ep_data_grp.create_dataset("actions", data=actions)
|
| 75 |
+
|
| 76 |
+
# store model xml directly in the new hdf5 file
|
| 77 |
+
model_path = os.path.join(ref_folder, "models", f["data/{}".format(ep)].attrs["model_file"])
|
| 78 |
+
f_model = open(model_path, "r")
|
| 79 |
+
model_xml = f_model.read()
|
| 80 |
+
f_model.close()
|
| 81 |
+
ep_data_grp.attrs["model_file"] = model_xml
|
| 82 |
+
|
| 83 |
+
# store num samples for this ep
|
| 84 |
+
num_samples = actions.shape[0]
|
| 85 |
+
ep_data_grp.attrs["num_samples"] = num_samples # number of transitions in this episode
|
| 86 |
+
num_samples_arr.append(num_samples)
|
| 87 |
+
|
| 88 |
+
# write dataset attributes (metadata)
|
| 89 |
+
f_new_grp.attrs["total"] = np.sum(num_samples_arr)
|
| 90 |
+
|
| 91 |
+
# construct and save env metadata
|
| 92 |
+
env_meta = dict()
|
| 93 |
+
env_meta["type"] = EB.EnvType.ROBOSUITE_TYPE
|
| 94 |
+
env_meta["env_name"] = (f["data"].attrs["env"] + "Teleop")
|
| 95 |
+
# hardcode robosuite v0.3 args
|
| 96 |
+
robosuite_args = {
|
| 97 |
+
"has_renderer": False,
|
| 98 |
+
"has_offscreen_renderer": False,
|
| 99 |
+
"ignore_done": True,
|
| 100 |
+
"use_object_obs": True,
|
| 101 |
+
"use_camera_obs": False,
|
| 102 |
+
"camera_depth": False,
|
| 103 |
+
"camera_height": 84,
|
| 104 |
+
"camera_width": 84,
|
| 105 |
+
"camera_name": "agentview",
|
| 106 |
+
"gripper_visualization": False,
|
| 107 |
+
"reward_shaping": False,
|
| 108 |
+
"control_freq": 100,
|
| 109 |
+
}
|
| 110 |
+
env_meta["env_kwargs"] = robosuite_args
|
| 111 |
+
f_new_grp.attrs["env_args"] = json.dumps(env_meta, indent=4) # environment info
|
| 112 |
+
|
| 113 |
+
print("\n====== Added env meta ======")
|
| 114 |
+
print(f_new_grp.attrs["env_args"])
|
| 115 |
+
|
| 116 |
+
f.close()
|
| 117 |
+
f_new.close()
|
| 118 |
+
|
| 119 |
+
# back up the old dataset, and replace with new dataset
|
| 120 |
+
os.rename(hdf5_path, os.path.join(ref_folder, "demo_bak.hdf5"))
|
| 121 |
+
os.rename(new_path, hdf5_path)
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
def split_fastest_from_hdf5(hdf5_path, n):
|
| 125 |
+
"""
|
| 126 |
+
Creates filter key for fastest N trajectories, named
|
| 127 |
+
"fastest_{}".format(n).
|
| 128 |
+
|
| 129 |
+
Args:
|
| 130 |
+
hdf5_path (str): path to the hdf5 file
|
| 131 |
+
|
| 132 |
+
n (int): fastest n demos to create filter key for
|
| 133 |
+
"""
|
| 134 |
+
|
| 135 |
+
# retrieve fastest n demos
|
| 136 |
+
f = h5py.File(hdf5_path, "r")
|
| 137 |
+
demos = sorted(list(f["data"].keys()))
|
| 138 |
+
traj_lengths = []
|
| 139 |
+
for ep in demos:
|
| 140 |
+
traj_lengths.append(f["data/{}/actions".format(ep)].shape[0])
|
| 141 |
+
inds = np.argsort(traj_lengths)[:n]
|
| 142 |
+
filtered_demos = [demos[i] for i in inds]
|
| 143 |
+
f.close()
|
| 144 |
+
|
| 145 |
+
# create filter key
|
| 146 |
+
name = "fastest_{}".format(n)
|
| 147 |
+
lengths = create_hdf5_filter_key(hdf5_path=hdf5_path, demo_keys=filtered_demos, key_name=name)
|
| 148 |
+
|
| 149 |
+
print("Total number of samples in fastest {} demos: {}".format(n, np.sum(lengths)))
|
| 150 |
+
print("Average number of samples in fastest {} demos: {}".format(n, np.mean(lengths)))
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
if __name__ == "__main__":
|
| 154 |
+
parser = argparse.ArgumentParser()
|
| 155 |
+
parser.add_argument(
|
| 156 |
+
"--folder",
|
| 157 |
+
type=str,
|
| 158 |
+
help="path to a folder containing a demo.hdf5 and a models directory containing \
|
| 159 |
+
mujoco xml files. For example, RoboTurkPilot/bins-Can.",
|
| 160 |
+
)
|
| 161 |
+
parser.add_argument(
|
| 162 |
+
"--n",
|
| 163 |
+
type=int,
|
| 164 |
+
default=225,
|
| 165 |
+
help="creates a filter key corresponding to the n fastest trajectories. Defaults to 225.",
|
| 166 |
+
)
|
| 167 |
+
args = parser.parse_args()
|
| 168 |
+
|
| 169 |
+
# convert hdf5
|
| 170 |
+
convert_rt_pilot_hdf5(ref_folder=args.folder)
|
| 171 |
+
|
| 172 |
+
# create 90-10 train-validation split in the dataset
|
| 173 |
+
print("\nCreating 90-10 train-validation split...\n")
|
| 174 |
+
hdf5_path = os.path.join(args.folder, "demo.hdf5")
|
| 175 |
+
split_train_val_from_hdf5(hdf5_path=hdf5_path, val_ratio=0.1)
|
| 176 |
+
|
| 177 |
+
print("\nCreating filter key for fastest {} trajectories...".format(args.n))
|
| 178 |
+
split_fastest_from_hdf5(hdf5_path=hdf5_path, n=args.n)
|
| 179 |
+
|
| 180 |
+
print("\nCreating 90-10 train-validation split for fastest {} trajectories...".format(args.n))
|
| 181 |
+
split_train_val_from_hdf5(hdf5_path=hdf5_path, val_ratio=0.1, filter_key="fastest_{}".format(args.n))
|
| 182 |
+
|
| 183 |
+
print(
|
| 184 |
+
"\nWARNING: new dataset has replaced old one in demo.hdf5 file. "
|
| 185 |
+
"The old dataset file has been moved to demo_bak.hdf5"
|
| 186 |
+
)
|
| 187 |
+
|
| 188 |
+
print(
|
| 189 |
+
"\nNOTE: the new dataset also contains a fastest_{} filter key, for an easy way "
|
| 190 |
+
"to train on the fastest trajectories. Just set config.train.hdf5_filter to train on this "
|
| 191 |
+
"subset. A common choice is 225 when training on the bins-Can dataset.\n".format(args.n)
|
| 192 |
+
)
|
aloha-devel/robomimic/scripts/conversion/convert_to_robosuite_v141.py
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import h5py
|
| 2 |
+
import json
|
| 3 |
+
import argparse
|
| 4 |
+
import os
|
| 5 |
+
from shutil import copyfile
|
| 6 |
+
import robosuite
|
| 7 |
+
import xml.etree.ElementTree as ET
|
| 8 |
+
|
| 9 |
+
import robomimic.utils.obs_utils as ObsUtils
|
| 10 |
+
import robomimic.utils.env_utils as EnvUtils
|
| 11 |
+
import robomimic.utils.file_utils as FileUtils
|
| 12 |
+
|
| 13 |
+
from robosuite.utils.mjcf_utils import find_elements
|
| 14 |
+
|
| 15 |
+
def replace_elem(parent, old_elem, new_elem):
|
| 16 |
+
"""
|
| 17 |
+
code adapted from https://stackoverflow.com/a/20931505
|
| 18 |
+
"""
|
| 19 |
+
parent_index = list(parent).index(old_elem)
|
| 20 |
+
parent.remove(old_elem)
|
| 21 |
+
parent.insert(parent_index, new_elem)
|
| 22 |
+
|
| 23 |
+
def convert_xml(old_xml_str, env_name, env):
|
| 24 |
+
"""
|
| 25 |
+
Postprocess xml string generated by robosuite to be compatible with robosuite v1.3
|
| 26 |
+
This script should not the xml string if it was already generated using robosuite v1.3
|
| 27 |
+
Args:
|
| 28 |
+
xml_str (str): xml string to process (from robosuite v1.2)
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
if env_name in ["PickPlaceCan", "NutAssemblySquare", "ToolHang"]:
|
| 32 |
+
xml_str = env.env.sim.model.get_xml()
|
| 33 |
+
elif env_name == "Lift":
|
| 34 |
+
xml_str = env.env.sim.model.get_xml()
|
| 35 |
+
# replace the cube_g0 and cube_g0_vis with elements in old_xml_str
|
| 36 |
+
old_et = ET.ElementTree(ET.fromstring(old_xml_str)).getroot()
|
| 37 |
+
new_et = ET.ElementTree(ET.fromstring(xml_str)).getroot()
|
| 38 |
+
|
| 39 |
+
cube_new = find_elements(
|
| 40 |
+
root=new_et,
|
| 41 |
+
tags="body",
|
| 42 |
+
attribs={"name": "cube_main"},
|
| 43 |
+
return_first=True
|
| 44 |
+
)
|
| 45 |
+
|
| 46 |
+
cube_old = find_elements(
|
| 47 |
+
root=old_et,
|
| 48 |
+
tags="body",
|
| 49 |
+
attribs={"name": "cube_main"},
|
| 50 |
+
return_first=True
|
| 51 |
+
)
|
| 52 |
+
|
| 53 |
+
worldbody_new = find_elements(
|
| 54 |
+
root=new_et,
|
| 55 |
+
tags="worldbody",
|
| 56 |
+
return_first=True
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
+
replace_elem(worldbody_new, cube_new, cube_old)
|
| 60 |
+
|
| 61 |
+
xml_str = ET.tostring(new_et, encoding="utf8").decode("utf8")
|
| 62 |
+
elif env_name == "TwoArmTransport":
|
| 63 |
+
xml_str = env.env.sim.model.get_xml()
|
| 64 |
+
# replace the cube_g0 and cube_g0_vis with elements in old_xml_str
|
| 65 |
+
old_et = ET.ElementTree(ET.fromstring(old_xml_str)).getroot()
|
| 66 |
+
new_et = ET.ElementTree(ET.fromstring(xml_str)).getroot()
|
| 67 |
+
|
| 68 |
+
worldbody_new = find_elements(
|
| 69 |
+
root=new_et,
|
| 70 |
+
tags="worldbody",
|
| 71 |
+
return_first=True
|
| 72 |
+
)
|
| 73 |
+
for bname in [
|
| 74 |
+
"payload_root",
|
| 75 |
+
|
| 76 |
+
### ignore all these other following assets (makes playback worse for some reason...)
|
| 77 |
+
# "trash_main",
|
| 78 |
+
# "transport_start_bin_root", "transport_target_bin_root",
|
| 79 |
+
# "transport_trash_bin_root", "transport_start_bin_lid_root"
|
| 80 |
+
]:
|
| 81 |
+
body_new = find_elements(
|
| 82 |
+
root=new_et,
|
| 83 |
+
tags="body",
|
| 84 |
+
attribs={"name": bname},
|
| 85 |
+
return_first=True
|
| 86 |
+
)
|
| 87 |
+
|
| 88 |
+
body_old = find_elements(
|
| 89 |
+
root=old_et,
|
| 90 |
+
tags="body",
|
| 91 |
+
attribs={"name": bname},
|
| 92 |
+
return_first=True
|
| 93 |
+
)
|
| 94 |
+
|
| 95 |
+
replace_elem(worldbody_new, body_new, body_old)
|
| 96 |
+
|
| 97 |
+
xml_str = ET.tostring(new_et, encoding="utf8").decode("utf8")
|
| 98 |
+
|
| 99 |
+
return xml_str
|
| 100 |
+
|
| 101 |
+
if __name__ == "__main__":
|
| 102 |
+
parser = argparse.ArgumentParser()
|
| 103 |
+
parser.add_argument(
|
| 104 |
+
"--dataset",
|
| 105 |
+
type=str,
|
| 106 |
+
help="path to input hdf5 dataset",
|
| 107 |
+
)
|
| 108 |
+
parser.add_argument(
|
| 109 |
+
"--output_dataset",
|
| 110 |
+
type=str,
|
| 111 |
+
help="path to output hdf5 dataset",
|
| 112 |
+
)
|
| 113 |
+
args = parser.parse_args()
|
| 114 |
+
|
| 115 |
+
args.dataset = os.path.expanduser(args.dataset)
|
| 116 |
+
args.output_dataset = os.path.expanduser(args.output_dataset)
|
| 117 |
+
|
| 118 |
+
assert args.output_dataset != args.dataset
|
| 119 |
+
assert robosuite.__version__ == '1.4.1'
|
| 120 |
+
|
| 121 |
+
copyfile(args.dataset, args.output_dataset)
|
| 122 |
+
|
| 123 |
+
f = h5py.File(args.output_dataset, "r+")
|
| 124 |
+
|
| 125 |
+
env_args = json.loads(f["data"].attrs["env_args"])
|
| 126 |
+
env_name = env_args["env_name"]
|
| 127 |
+
|
| 128 |
+
env_meta = FileUtils.get_env_metadata_from_dataset(dataset_path=args.dataset)
|
| 129 |
+
env_type = EnvUtils.get_env_type(env_meta=env_meta)
|
| 130 |
+
|
| 131 |
+
# need to make sure ObsUtils knows which observations are images, but it doesn't matter
|
| 132 |
+
# for playback since observations are unused. Pass a dummy spec here.
|
| 133 |
+
dummy_spec = dict(
|
| 134 |
+
obs=dict(
|
| 135 |
+
low_dim=["robot0_eef_pos"],
|
| 136 |
+
rgb=[],
|
| 137 |
+
),
|
| 138 |
+
)
|
| 139 |
+
ObsUtils.initialize_obs_utils_with_obs_specs(obs_modality_specs=dummy_spec)
|
| 140 |
+
|
| 141 |
+
env_meta = FileUtils.get_env_metadata_from_dataset(dataset_path=args.dataset)
|
| 142 |
+
env = EnvUtils.create_env_from_metadata(env_meta=env_meta, render=False, render_offscreen=True)
|
| 143 |
+
env.reset()
|
| 144 |
+
|
| 145 |
+
for demo_key in list(f["data"].keys()):
|
| 146 |
+
ep_data_grp = f["data/{}".format(demo_key)]
|
| 147 |
+
model_file = ep_data_grp.attrs["model_file"]
|
| 148 |
+
|
| 149 |
+
coverted_model_file = convert_xml(model_file, env_name, env)
|
| 150 |
+
ep_data_grp.attrs["model_file"] = coverted_model_file
|
| 151 |
+
|
| 152 |
+
env_args = json.loads(f["data"].attrs["env_args"])
|
| 153 |
+
env_args["env_version"] = robosuite.__version__
|
| 154 |
+
f["data"].attrs["env_args"] = json.dumps(env_args, indent=4)
|
| 155 |
+
|
| 156 |
+
f.close()
|
aloha-devel/robomimic/scripts/conversion/extract_action_dict.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import pathlib
|
| 3 |
+
import sys
|
| 4 |
+
import tqdm
|
| 5 |
+
import h5py
|
| 6 |
+
import numpy as np
|
| 7 |
+
import torch
|
| 8 |
+
import os
|
| 9 |
+
|
| 10 |
+
import robomimic.utils.torch_utils as TorchUtils
|
| 11 |
+
|
| 12 |
+
def extract_action_dict(dataset):
|
| 13 |
+
# find files
|
| 14 |
+
f = h5py.File(os.path.expanduser(dataset), mode="r+")
|
| 15 |
+
|
| 16 |
+
SPECS = [
|
| 17 |
+
dict(
|
| 18 |
+
key="actions",
|
| 19 |
+
is_absolute=False,
|
| 20 |
+
),
|
| 21 |
+
dict(
|
| 22 |
+
key="actions_abs",
|
| 23 |
+
is_absolute=True,
|
| 24 |
+
)
|
| 25 |
+
]
|
| 26 |
+
|
| 27 |
+
# execute
|
| 28 |
+
for spec in SPECS:
|
| 29 |
+
input_action_key = spec["key"]
|
| 30 |
+
is_absolute = spec["is_absolute"]
|
| 31 |
+
|
| 32 |
+
if is_absolute:
|
| 33 |
+
prefix = "abs_"
|
| 34 |
+
else:
|
| 35 |
+
prefix = "rel_"
|
| 36 |
+
|
| 37 |
+
for demo in f["data"].values():
|
| 38 |
+
in_action = demo[str(input_action_key)][:]
|
| 39 |
+
in_pos = in_action[:,:3].astype(np.float32)
|
| 40 |
+
in_rot = in_action[:,3:6].astype(np.float32)
|
| 41 |
+
in_grip = in_action[:,6:7].astype(np.float32)
|
| 42 |
+
|
| 43 |
+
rot_6d = TorchUtils.axis_angle_to_rot_6d(
|
| 44 |
+
axis_angle=torch.from_numpy(in_rot)
|
| 45 |
+
)
|
| 46 |
+
rot_6d = rot_6d.numpy().astype(np.float32) # convert to numpy
|
| 47 |
+
|
| 48 |
+
this_action_dict = {
|
| 49 |
+
prefix + "pos": in_pos,
|
| 50 |
+
prefix + "rot_axis_angle": in_rot,
|
| 51 |
+
prefix + "rot_6d": rot_6d,
|
| 52 |
+
"gripper": in_grip
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
# special case: 8 dim actions mean there is a mobile base mode in the action space
|
| 56 |
+
if in_action.shape[1] == 8:
|
| 57 |
+
this_action_dict["base_mode"] = in_action[:,7:8].astype(np.float32)
|
| 58 |
+
|
| 59 |
+
action_dict_group = demo.require_group("action_dict")
|
| 60 |
+
for key, data in this_action_dict.items():
|
| 61 |
+
if key in action_dict_group:
|
| 62 |
+
del action_dict_group[key]
|
| 63 |
+
action_dict_group.create_dataset(key, data=data)
|
| 64 |
+
|
| 65 |
+
f.close()
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def main():
|
| 69 |
+
parser = argparse.ArgumentParser()
|
| 70 |
+
|
| 71 |
+
parser.add_argument(
|
| 72 |
+
"--dataset",
|
| 73 |
+
type=str,
|
| 74 |
+
required=True
|
| 75 |
+
)
|
| 76 |
+
|
| 77 |
+
args = parser.parse_args()
|
| 78 |
+
extract_action_dict(args.dataset)
|
| 79 |
+
|
| 80 |
+
if __name__ == "__main__":
|
| 81 |
+
main()
|
aloha-devel/robomimic/scripts/conversion/robosuite_add_absolute_actions.py
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import multiprocessing
|
| 2 |
+
import os
|
| 3 |
+
import pathlib
|
| 4 |
+
import h5py
|
| 5 |
+
from tqdm import tqdm
|
| 6 |
+
import collections
|
| 7 |
+
import pickle
|
| 8 |
+
import argparse
|
| 9 |
+
import numpy as np
|
| 10 |
+
import copy
|
| 11 |
+
|
| 12 |
+
import h5py
|
| 13 |
+
import robomimic.utils.obs_utils as ObsUtils
|
| 14 |
+
import robomimic.utils.file_utils as FileUtils
|
| 15 |
+
import robomimic.utils.env_utils as EnvUtils
|
| 16 |
+
from scipy.spatial.transform import Rotation
|
| 17 |
+
|
| 18 |
+
from robomimic.config import config_factory
|
| 19 |
+
|
| 20 |
+
"""
|
| 21 |
+
copied/adapted from https://github.com/columbia-ai-robotics/diffusion_policy/blob/main/diffusion_policy/common/robomimic_util.py
|
| 22 |
+
"""
|
| 23 |
+
class RobomimicAbsoluteActionConverter:
|
| 24 |
+
def __init__(self, dataset_path, algo_name='bc'):
|
| 25 |
+
# default BC config
|
| 26 |
+
config = config_factory(algo_name=algo_name)
|
| 27 |
+
|
| 28 |
+
# read config to set up metadata for observation modalities (e.g. detecting rgb observations)
|
| 29 |
+
# must ran before create dataset
|
| 30 |
+
ObsUtils.initialize_obs_utils_with_config(config)
|
| 31 |
+
|
| 32 |
+
env_meta = FileUtils.get_env_metadata_from_dataset(dataset_path)
|
| 33 |
+
abs_env_meta = copy.deepcopy(env_meta)
|
| 34 |
+
abs_env_meta['env_kwargs']['controller_configs']['control_delta'] = False
|
| 35 |
+
|
| 36 |
+
env = EnvUtils.create_env_from_metadata(
|
| 37 |
+
env_meta=env_meta,
|
| 38 |
+
render=False,
|
| 39 |
+
render_offscreen=False,
|
| 40 |
+
use_image_obs=False,
|
| 41 |
+
)
|
| 42 |
+
assert len(env.env.robots) in (1, 2)
|
| 43 |
+
|
| 44 |
+
abs_env = EnvUtils.create_env_from_metadata(
|
| 45 |
+
env_meta=abs_env_meta,
|
| 46 |
+
render=False,
|
| 47 |
+
render_offscreen=False,
|
| 48 |
+
use_image_obs=False,
|
| 49 |
+
)
|
| 50 |
+
assert not abs_env.env.robots[0].controller.use_delta
|
| 51 |
+
|
| 52 |
+
self.env = env
|
| 53 |
+
self.abs_env = abs_env
|
| 54 |
+
self.file = h5py.File(dataset_path, 'r')
|
| 55 |
+
|
| 56 |
+
def get_demo_keys(self):
|
| 57 |
+
return list(self.file['data'].keys())
|
| 58 |
+
|
| 59 |
+
def convert_actions(self,
|
| 60 |
+
states: np.ndarray,
|
| 61 |
+
actions: np.ndarray,
|
| 62 |
+
initial_state: dict) -> np.ndarray:
|
| 63 |
+
"""
|
| 64 |
+
Given state and delta action sequence
|
| 65 |
+
generate equivalent goal position and orientation for each step
|
| 66 |
+
keep the original gripper action intact.
|
| 67 |
+
"""
|
| 68 |
+
env = self.env
|
| 69 |
+
d_a = len(env.env.robots[0].action_limits[0])
|
| 70 |
+
|
| 71 |
+
# in case of multi robot
|
| 72 |
+
# reshape (N,14) to (N,2,7)
|
| 73 |
+
# or (N,7) to (N,1,7)
|
| 74 |
+
stacked_actions = actions.reshape(*actions.shape[:-1], -1, d_a)
|
| 75 |
+
|
| 76 |
+
# generate abs actions
|
| 77 |
+
action_goal_pos = np.zeros(
|
| 78 |
+
stacked_actions.shape[:-1]+(3,),
|
| 79 |
+
dtype=stacked_actions.dtype)
|
| 80 |
+
action_goal_ori = np.zeros(
|
| 81 |
+
stacked_actions.shape[:-1]+(3,),
|
| 82 |
+
dtype=stacked_actions.dtype)
|
| 83 |
+
action_remainder = stacked_actions[...,6:]
|
| 84 |
+
for i in range(len(states)):
|
| 85 |
+
if i == 0:
|
| 86 |
+
_ = env.reset_to(initial_state)
|
| 87 |
+
else:
|
| 88 |
+
_ = env.reset_to({'states': states[i]})
|
| 89 |
+
|
| 90 |
+
# taken from robot_env.py L#454
|
| 91 |
+
for idx, robot in enumerate(env.env.robots):
|
| 92 |
+
# run controller goal generator
|
| 93 |
+
robot.control(stacked_actions[i,idx], policy_step=True)
|
| 94 |
+
|
| 95 |
+
# read pos and ori from robots
|
| 96 |
+
controller = robot.controller
|
| 97 |
+
action_goal_pos[i,idx] = controller.goal_pos
|
| 98 |
+
action_goal_ori[i,idx] = Rotation.from_matrix(
|
| 99 |
+
controller.goal_ori).as_rotvec()
|
| 100 |
+
|
| 101 |
+
stacked_abs_actions = np.concatenate([
|
| 102 |
+
action_goal_pos,
|
| 103 |
+
action_goal_ori,
|
| 104 |
+
action_remainder
|
| 105 |
+
], axis=-1)
|
| 106 |
+
abs_actions = stacked_abs_actions.reshape(actions.shape)
|
| 107 |
+
return abs_actions
|
| 108 |
+
|
| 109 |
+
def convert_demo(self, demo_key):
|
| 110 |
+
file = self.file
|
| 111 |
+
demo = file["data/{}".format(demo_key)]
|
| 112 |
+
# input
|
| 113 |
+
states = demo['states'][:]
|
| 114 |
+
actions = demo['actions'][:]
|
| 115 |
+
initial_state = dict(states=states[0])
|
| 116 |
+
initial_state["model"] = demo.attrs["model_file"]
|
| 117 |
+
initial_state["ep_meta"] = demo.attrs.get("ep_meta", None)
|
| 118 |
+
|
| 119 |
+
# generate abs actions
|
| 120 |
+
abs_actions = self.convert_actions(states, actions, initial_state=initial_state)
|
| 121 |
+
return abs_actions
|
| 122 |
+
|
| 123 |
+
def convert_and_eval_demo(self, demo_key):
|
| 124 |
+
raise NotImplementedError
|
| 125 |
+
env = self.env
|
| 126 |
+
abs_env = self.abs_env
|
| 127 |
+
file = self.file
|
| 128 |
+
# first step have high error for some reason, not representative
|
| 129 |
+
eval_skip_steps = 1
|
| 130 |
+
|
| 131 |
+
demo = file["data/{}".format(demo_key)]
|
| 132 |
+
# input
|
| 133 |
+
states = demo['states'][:]
|
| 134 |
+
actions = demo['actions'][:]
|
| 135 |
+
|
| 136 |
+
# generate abs actions
|
| 137 |
+
abs_actions = self.convert_actions(states, actions)
|
| 138 |
+
|
| 139 |
+
# verify
|
| 140 |
+
robot0_eef_pos = demo['obs']['robot0_eef_pos'][:]
|
| 141 |
+
robot0_eef_quat = demo['obs']['robot0_eef_quat'][:]
|
| 142 |
+
|
| 143 |
+
delta_error_info = self.evaluate_rollout_error(
|
| 144 |
+
env, states, actions, robot0_eef_pos, robot0_eef_quat,
|
| 145 |
+
metric_skip_steps=eval_skip_steps)
|
| 146 |
+
abs_error_info = self.evaluate_rollout_error(
|
| 147 |
+
abs_env, states, abs_actions, robot0_eef_pos, robot0_eef_quat,
|
| 148 |
+
metric_skip_steps=eval_skip_steps)
|
| 149 |
+
|
| 150 |
+
info = {
|
| 151 |
+
'delta_max_error': delta_error_info,
|
| 152 |
+
'abs_max_error': abs_error_info
|
| 153 |
+
}
|
| 154 |
+
return abs_actions, info
|
| 155 |
+
|
| 156 |
+
@staticmethod
|
| 157 |
+
def evaluate_rollout_error(env,
|
| 158 |
+
states, actions,
|
| 159 |
+
robot0_eef_pos,
|
| 160 |
+
robot0_eef_quat,
|
| 161 |
+
metric_skip_steps=1):
|
| 162 |
+
# first step have high error for some reason, not representative
|
| 163 |
+
|
| 164 |
+
# evaluate abs actions
|
| 165 |
+
rollout_next_states = list()
|
| 166 |
+
rollout_next_eef_pos = list()
|
| 167 |
+
rollout_next_eef_quat = list()
|
| 168 |
+
obs = env.reset_to({'states': states[0]})
|
| 169 |
+
for i in range(len(states)):
|
| 170 |
+
obs = env.reset_to({'states': states[i]})
|
| 171 |
+
obs, reward, done, info = env.step(actions[i])
|
| 172 |
+
obs = env.get_observation()
|
| 173 |
+
rollout_next_states.append(env.get_state()['states'])
|
| 174 |
+
rollout_next_eef_pos.append(obs['robot0_eef_pos'])
|
| 175 |
+
rollout_next_eef_quat.append(obs['robot0_eef_quat'])
|
| 176 |
+
rollout_next_states = np.array(rollout_next_states)
|
| 177 |
+
rollout_next_eef_pos = np.array(rollout_next_eef_pos)
|
| 178 |
+
rollout_next_eef_quat = np.array(rollout_next_eef_quat)
|
| 179 |
+
|
| 180 |
+
next_state_diff = states[1:] - rollout_next_states[:-1]
|
| 181 |
+
max_next_state_diff = np.max(np.abs(next_state_diff[metric_skip_steps:]))
|
| 182 |
+
|
| 183 |
+
next_eef_pos_diff = robot0_eef_pos[1:] - rollout_next_eef_pos[:-1]
|
| 184 |
+
next_eef_pos_dist = np.linalg.norm(next_eef_pos_diff, axis=-1)
|
| 185 |
+
max_next_eef_pos_dist = next_eef_pos_dist[metric_skip_steps:].max()
|
| 186 |
+
|
| 187 |
+
next_eef_rot_diff = Rotation.from_quat(robot0_eef_quat[1:]) \
|
| 188 |
+
* Rotation.from_quat(rollout_next_eef_quat[:-1]).inv()
|
| 189 |
+
next_eef_rot_dist = next_eef_rot_diff.magnitude()
|
| 190 |
+
max_next_eef_rot_dist = next_eef_rot_dist[metric_skip_steps:].max()
|
| 191 |
+
|
| 192 |
+
info = {
|
| 193 |
+
'state': max_next_state_diff,
|
| 194 |
+
'pos': max_next_eef_pos_dist,
|
| 195 |
+
'rot': max_next_eef_rot_dist
|
| 196 |
+
}
|
| 197 |
+
return info
|
| 198 |
+
|
| 199 |
+
"""
|
| 200 |
+
copied/adapted from https://github.com/columbia-ai-robotics/diffusion_policy/blob/main/diffusion_policy/scripts/robomimic_dataset_conversion.py
|
| 201 |
+
"""
|
| 202 |
+
def worker(x):
|
| 203 |
+
path, demo_key, do_eval = x
|
| 204 |
+
converter = RobomimicAbsoluteActionConverter(path)
|
| 205 |
+
if do_eval:
|
| 206 |
+
abs_actions, info = converter.convert_and_eval_demo(demo_key)
|
| 207 |
+
else:
|
| 208 |
+
abs_actions = converter.convert_demo(demo_key)
|
| 209 |
+
info = dict()
|
| 210 |
+
return abs_actions, info
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
def add_absolute_actions_to_dataset(dataset, eval_dir, num_workers):
|
| 214 |
+
# process inputs
|
| 215 |
+
dataset = pathlib.Path(dataset).expanduser()
|
| 216 |
+
assert dataset.is_file()
|
| 217 |
+
|
| 218 |
+
do_eval = False
|
| 219 |
+
if eval_dir is not None:
|
| 220 |
+
eval_dir = pathlib.Path(eval_dir).expanduser()
|
| 221 |
+
assert eval_dir.parent.exists()
|
| 222 |
+
do_eval = True
|
| 223 |
+
|
| 224 |
+
converter = RobomimicAbsoluteActionConverter(dataset)
|
| 225 |
+
demo_keys = converter.get_demo_keys()
|
| 226 |
+
del converter
|
| 227 |
+
|
| 228 |
+
# run
|
| 229 |
+
with multiprocessing.Pool(num_workers) as pool:
|
| 230 |
+
results = pool.map(worker, [(dataset, demo_key, do_eval) for demo_key in demo_keys])
|
| 231 |
+
|
| 232 |
+
# modify action
|
| 233 |
+
with h5py.File(dataset, 'r+') as out_file:
|
| 234 |
+
for i in tqdm(range(len(results)), desc="Writing to output"):
|
| 235 |
+
abs_actions, info = results[i]
|
| 236 |
+
demo = out_file["data/{}".format(demo_keys[i])]
|
| 237 |
+
if "actions_abs" not in demo:
|
| 238 |
+
demo.create_dataset("actions_abs", data=np.array(abs_actions))
|
| 239 |
+
else:
|
| 240 |
+
demo['actions_abs'][:] = abs_actions
|
| 241 |
+
|
| 242 |
+
# save eval
|
| 243 |
+
if do_eval:
|
| 244 |
+
eval_dir.mkdir(parents=False, exist_ok=True)
|
| 245 |
+
|
| 246 |
+
print("Writing error_stats.pkl")
|
| 247 |
+
infos = [info for _, info in results]
|
| 248 |
+
pickle.dump(infos, eval_dir.joinpath('error_stats.pkl').open('wb'))
|
| 249 |
+
|
| 250 |
+
print("Generating visualization")
|
| 251 |
+
metrics = ['pos', 'rot']
|
| 252 |
+
metrics_dicts = dict()
|
| 253 |
+
for m in metrics:
|
| 254 |
+
metrics_dicts[m] = collections.defaultdict(list)
|
| 255 |
+
|
| 256 |
+
for i in range(len(infos)):
|
| 257 |
+
info = infos[i]
|
| 258 |
+
for k, v in info.items():
|
| 259 |
+
for m in metrics:
|
| 260 |
+
metrics_dicts[m][k].append(v[m])
|
| 261 |
+
|
| 262 |
+
from matplotlib import pyplot as plt
|
| 263 |
+
plt.switch_backend('PDF')
|
| 264 |
+
|
| 265 |
+
fig, ax = plt.subplots(1, len(metrics))
|
| 266 |
+
for i in range(len(metrics)):
|
| 267 |
+
axis = ax[i]
|
| 268 |
+
data = metrics_dicts[metrics[i]]
|
| 269 |
+
for key, value in data.items():
|
| 270 |
+
axis.plot(value, label=key)
|
| 271 |
+
axis.legend()
|
| 272 |
+
axis.set_title(metrics[i])
|
| 273 |
+
fig.set_size_inches(10,4)
|
| 274 |
+
fig.savefig(str(eval_dir.joinpath('error_stats.pdf')))
|
| 275 |
+
fig.savefig(str(eval_dir.joinpath('error_stats.png')))
|
| 276 |
+
|
| 277 |
+
|
| 278 |
+
if __name__ == "__main__":
|
| 279 |
+
parser = argparse.ArgumentParser()
|
| 280 |
+
|
| 281 |
+
parser.add_argument(
|
| 282 |
+
"--dataset",
|
| 283 |
+
type=str,
|
| 284 |
+
required=True
|
| 285 |
+
)
|
| 286 |
+
|
| 287 |
+
parser.add_argument(
|
| 288 |
+
"--eval_dir",
|
| 289 |
+
type=str,
|
| 290 |
+
help="directory to output evaluation metrics",
|
| 291 |
+
)
|
| 292 |
+
|
| 293 |
+
parser.add_argument(
|
| 294 |
+
"--num_workers",
|
| 295 |
+
type=int,
|
| 296 |
+
default=10,
|
| 297 |
+
)
|
| 298 |
+
|
| 299 |
+
args = parser.parse_args()
|
| 300 |
+
|
| 301 |
+
|
| 302 |
+
add_absolute_actions_to_dataset(
|
| 303 |
+
dataset=args.dataset,
|
| 304 |
+
eval_dir=args.eval_dir,
|
| 305 |
+
num_workers=args.num_workers,
|
| 306 |
+
)
|
aloha-devel/robomimic/scripts/dataset_states_to_obs.py
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Script to extract observations from low-dimensional simulation states in a robosuite dataset.
|
| 3 |
+
|
| 4 |
+
Args:
|
| 5 |
+
dataset (str): path to input hdf5 dataset
|
| 6 |
+
|
| 7 |
+
output_name (str): name of output hdf5 dataset
|
| 8 |
+
|
| 9 |
+
n (int): if provided, stop after n trajectories are processed
|
| 10 |
+
|
| 11 |
+
shaped (bool): if flag is set, use dense rewards
|
| 12 |
+
|
| 13 |
+
camera_names (str or [str]): camera name(s) to use for image observations.
|
| 14 |
+
Leave out to not use image observations.
|
| 15 |
+
|
| 16 |
+
camera_height (int): height of image observation.
|
| 17 |
+
|
| 18 |
+
camera_width (int): width of image observation
|
| 19 |
+
|
| 20 |
+
done_mode (int): how to write done signal. If 0, done is 1 whenever s' is a success state.
|
| 21 |
+
If 1, done is 1 at the end of each trajectory. If 2, both.
|
| 22 |
+
|
| 23 |
+
copy_rewards (bool): if provided, copy rewards from source file instead of inferring them
|
| 24 |
+
|
| 25 |
+
copy_dones (bool): if provided, copy dones from source file instead of inferring them
|
| 26 |
+
|
| 27 |
+
Example usage:
|
| 28 |
+
|
| 29 |
+
# extract low-dimensional observations
|
| 30 |
+
python dataset_states_to_obs.py --dataset /path/to/demo.hdf5 --output_name low_dim.hdf5 --done_mode 2
|
| 31 |
+
|
| 32 |
+
# extract 84x84 image observations
|
| 33 |
+
python dataset_states_to_obs.py --dataset /path/to/demo.hdf5 --output_name image.hdf5 \
|
| 34 |
+
--done_mode 2 --camera_names agentview robot0_eye_in_hand --camera_height 84 --camera_width 84
|
| 35 |
+
|
| 36 |
+
# (space saving option) extract 84x84 image observations with compression and without
|
| 37 |
+
# extracting next obs (not needed for pure imitation learning algos)
|
| 38 |
+
python dataset_states_to_obs.py --dataset /path/to/demo.hdf5 --output_name image.hdf5 \
|
| 39 |
+
--done_mode 2 --camera_names agentview robot0_eye_in_hand --camera_height 84 --camera_width 84 \
|
| 40 |
+
--compress --exclude-next-obs
|
| 41 |
+
|
| 42 |
+
# use dense rewards, and only annotate the end of trajectories with done signal
|
| 43 |
+
python dataset_states_to_obs.py --dataset /path/to/demo.hdf5 --output_name image_dense_done_1.hdf5 \
|
| 44 |
+
--done_mode 1 --dense --camera_names agentview robot0_eye_in_hand --camera_height 84 --camera_width 84
|
| 45 |
+
"""
|
| 46 |
+
import os
|
| 47 |
+
import json
|
| 48 |
+
import h5py
|
| 49 |
+
import argparse
|
| 50 |
+
import numpy as np
|
| 51 |
+
from copy import deepcopy
|
| 52 |
+
|
| 53 |
+
import robomimic.utils.tensor_utils as TensorUtils
|
| 54 |
+
import robomimic.utils.file_utils as FileUtils
|
| 55 |
+
import robomimic.utils.env_utils as EnvUtils
|
| 56 |
+
from robomimic.envs.env_base import EnvBase
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def extract_trajectory(
|
| 60 |
+
env,
|
| 61 |
+
initial_state,
|
| 62 |
+
states,
|
| 63 |
+
actions,
|
| 64 |
+
actions_abs,
|
| 65 |
+
done_mode,
|
| 66 |
+
):
|
| 67 |
+
"""
|
| 68 |
+
Helper function to extract observations, rewards, and dones along a trajectory using
|
| 69 |
+
the simulator environment.
|
| 70 |
+
|
| 71 |
+
Args:
|
| 72 |
+
env (instance of EnvBase): environment
|
| 73 |
+
initial_state (dict): initial simulation state to load
|
| 74 |
+
states (np.array): array of simulation states to load to extract information
|
| 75 |
+
actions (np.array): array of actions
|
| 76 |
+
done_mode (int): how to write done signal. If 0, done is 1 whenever s' is a
|
| 77 |
+
success state. If 1, done is 1 at the end of each trajectory.
|
| 78 |
+
If 2, do both.
|
| 79 |
+
"""
|
| 80 |
+
assert isinstance(env, EnvBase)
|
| 81 |
+
assert states.shape[0] == actions.shape[0]
|
| 82 |
+
|
| 83 |
+
# load the initial state
|
| 84 |
+
## this reset call doesn't seem necessary.
|
| 85 |
+
## seems ok to remove but haven't fully tested it.
|
| 86 |
+
## removing for now
|
| 87 |
+
# env.reset()
|
| 88 |
+
obs = env.reset_to(initial_state)
|
| 89 |
+
|
| 90 |
+
traj = dict(
|
| 91 |
+
obs=[],
|
| 92 |
+
next_obs=[],
|
| 93 |
+
rewards=[],
|
| 94 |
+
dones=[],
|
| 95 |
+
actions=np.array(actions),
|
| 96 |
+
states=np.array(states),
|
| 97 |
+
initial_state_dict=initial_state,
|
| 98 |
+
)
|
| 99 |
+
if actions_abs is not None:
|
| 100 |
+
traj["actions_abs"] = np.array(actions_abs)
|
| 101 |
+
|
| 102 |
+
traj_len = states.shape[0]
|
| 103 |
+
# iteration variable @t is over "next obs" indices
|
| 104 |
+
for t in range(1, traj_len + 1):
|
| 105 |
+
|
| 106 |
+
# get next observation
|
| 107 |
+
if t == traj_len:
|
| 108 |
+
# play final action to get next observation for last timestep
|
| 109 |
+
next_obs, _, _, _ = env.step(actions[t - 1])
|
| 110 |
+
else:
|
| 111 |
+
# reset to simulator state to get observation
|
| 112 |
+
next_obs = env.reset_to({"states" : states[t]})
|
| 113 |
+
|
| 114 |
+
# infer reward signal
|
| 115 |
+
# note: our tasks use reward r(s'), reward AFTER transition, so this is
|
| 116 |
+
# the reward for the current timestep
|
| 117 |
+
r = env.get_reward()
|
| 118 |
+
|
| 119 |
+
# infer done signal
|
| 120 |
+
done = False
|
| 121 |
+
if (done_mode == 1) or (done_mode == 2):
|
| 122 |
+
# done = 1 at end of trajectory
|
| 123 |
+
done = done or (t == traj_len)
|
| 124 |
+
if (done_mode == 0) or (done_mode == 2):
|
| 125 |
+
# done = 1 when s' is task success state
|
| 126 |
+
done = done or env.is_success()["task"]
|
| 127 |
+
done = int(done)
|
| 128 |
+
|
| 129 |
+
# collect transition
|
| 130 |
+
traj["obs"].append(obs)
|
| 131 |
+
traj["next_obs"].append(next_obs)
|
| 132 |
+
traj["rewards"].append(r)
|
| 133 |
+
traj["dones"].append(done)
|
| 134 |
+
|
| 135 |
+
# update for next iter
|
| 136 |
+
obs = deepcopy(next_obs)
|
| 137 |
+
|
| 138 |
+
# convert list of dict to dict of list for obs dictionaries (for convenient writes to hdf5 dataset)
|
| 139 |
+
traj["obs"] = TensorUtils.list_of_flat_dict_to_dict_of_list(traj["obs"])
|
| 140 |
+
traj["next_obs"] = TensorUtils.list_of_flat_dict_to_dict_of_list(traj["next_obs"])
|
| 141 |
+
|
| 142 |
+
# list to numpy array
|
| 143 |
+
for k in traj:
|
| 144 |
+
if k == "initial_state_dict":
|
| 145 |
+
continue
|
| 146 |
+
if isinstance(traj[k], dict):
|
| 147 |
+
for kp in traj[k]:
|
| 148 |
+
traj[k][kp] = np.array(traj[k][kp])
|
| 149 |
+
else:
|
| 150 |
+
traj[k] = np.array(traj[k])
|
| 151 |
+
|
| 152 |
+
return traj
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def dataset_states_to_obs(args):
|
| 156 |
+
# create environment to use for data processing
|
| 157 |
+
env_meta = FileUtils.get_env_metadata_from_dataset(dataset_path=args.dataset)
|
| 158 |
+
env = EnvUtils.create_env_for_data_processing(
|
| 159 |
+
env_meta=env_meta,
|
| 160 |
+
camera_names=args.camera_names,
|
| 161 |
+
camera_height=args.camera_height,
|
| 162 |
+
camera_width=args.camera_width,
|
| 163 |
+
reward_shaping=args.shaped,
|
| 164 |
+
)
|
| 165 |
+
|
| 166 |
+
print("==== Using environment with the following metadata ====")
|
| 167 |
+
print(json.dumps(env.serialize(), indent=4))
|
| 168 |
+
print("")
|
| 169 |
+
|
| 170 |
+
# some operations for playback are robosuite-specific, so determine if this environment is a robosuite env
|
| 171 |
+
is_robosuite_env = EnvUtils.is_robosuite_env(env_meta)
|
| 172 |
+
|
| 173 |
+
# list of all demonstration episodes (sorted in increasing number order)
|
| 174 |
+
f = h5py.File(args.dataset, "r")
|
| 175 |
+
demos = list(f["data"].keys())
|
| 176 |
+
inds = np.argsort([int(elem[5:]) for elem in demos])
|
| 177 |
+
demos = [demos[i] for i in inds]
|
| 178 |
+
|
| 179 |
+
# maybe reduce the number of demonstrations to playback
|
| 180 |
+
if args.n is not None:
|
| 181 |
+
demos = demos[:args.n]
|
| 182 |
+
|
| 183 |
+
# output file in same directory as input file
|
| 184 |
+
output_name = args.output_name
|
| 185 |
+
if output_name is None:
|
| 186 |
+
if len(args.camera_names) == 0:
|
| 187 |
+
output_name = os.path.basename(args.dataset)[:-5] + "_ld.hdf5"
|
| 188 |
+
else:
|
| 189 |
+
output_name = os.path.basename(args.dataset)[:-5] + "_im{}.hdf5".format(args.camera_width)
|
| 190 |
+
|
| 191 |
+
output_path = os.path.join(os.path.dirname(args.dataset), output_name)
|
| 192 |
+
f_out = h5py.File(output_path, "w")
|
| 193 |
+
data_grp = f_out.create_group("data")
|
| 194 |
+
print("input file: {}".format(args.dataset))
|
| 195 |
+
print("output file: {}".format(output_path))
|
| 196 |
+
|
| 197 |
+
total_samples = 0
|
| 198 |
+
for ind in range(len(demos)):
|
| 199 |
+
ep = demos[ind]
|
| 200 |
+
|
| 201 |
+
# prepare initial state to reload from
|
| 202 |
+
states = f["data/{}/states".format(ep)][()]
|
| 203 |
+
initial_state = dict(states=states[0])
|
| 204 |
+
if is_robosuite_env:
|
| 205 |
+
initial_state["model"] = f["data/{}".format(ep)].attrs["model_file"]
|
| 206 |
+
initial_state["ep_meta"] = f["data/{}".format(ep)].attrs.get("ep_meta", None)
|
| 207 |
+
|
| 208 |
+
# extract obs, rewards, dones
|
| 209 |
+
actions = f["data/{}/actions".format(ep)][()]
|
| 210 |
+
if "data/{}/actions_abs".format(ep) in f:
|
| 211 |
+
actions_abs = f["data/{}/actions_abs".format(ep)][()]
|
| 212 |
+
else:
|
| 213 |
+
actions_abs = None
|
| 214 |
+
traj = extract_trajectory(
|
| 215 |
+
env=env,
|
| 216 |
+
initial_state=initial_state,
|
| 217 |
+
states=states,
|
| 218 |
+
actions=actions,
|
| 219 |
+
actions_abs=actions_abs,
|
| 220 |
+
done_mode=args.done_mode,
|
| 221 |
+
)
|
| 222 |
+
|
| 223 |
+
# maybe copy reward or done signal from source file
|
| 224 |
+
if args.copy_rewards:
|
| 225 |
+
traj["rewards"] = f["data/{}/rewards".format(ep)][()]
|
| 226 |
+
if args.copy_dones:
|
| 227 |
+
traj["dones"] = f["data/{}/dones".format(ep)][()]
|
| 228 |
+
|
| 229 |
+
# store transitions
|
| 230 |
+
|
| 231 |
+
# IMPORTANT: keep name of group the same as source file, to make sure that filter keys are
|
| 232 |
+
# consistent as well
|
| 233 |
+
ep_data_grp = data_grp.create_group(ep)
|
| 234 |
+
ep_data_grp.create_dataset("actions", data=np.array(traj["actions"]))
|
| 235 |
+
ep_data_grp.create_dataset("states", data=np.array(traj["states"]))
|
| 236 |
+
ep_data_grp.create_dataset("rewards", data=np.array(traj["rewards"]))
|
| 237 |
+
ep_data_grp.create_dataset("dones", data=np.array(traj["dones"]))
|
| 238 |
+
if "actions_abs" in traj:
|
| 239 |
+
ep_data_grp.create_dataset("actions_abs", data=np.array(traj["actions_abs"]))
|
| 240 |
+
for k in traj["obs"]:
|
| 241 |
+
if args.compress:
|
| 242 |
+
ep_data_grp.create_dataset("obs/{}".format(k), data=np.array(traj["obs"][k]), compression="gzip")
|
| 243 |
+
else:
|
| 244 |
+
ep_data_grp.create_dataset("obs/{}".format(k), data=np.array(traj["obs"][k]))
|
| 245 |
+
if not args.exclude_next_obs:
|
| 246 |
+
if args.compress:
|
| 247 |
+
ep_data_grp.create_dataset("next_obs/{}".format(k), data=np.array(traj["next_obs"][k]), compression="gzip")
|
| 248 |
+
else:
|
| 249 |
+
ep_data_grp.create_dataset("next_obs/{}".format(k), data=np.array(traj["next_obs"][k]))
|
| 250 |
+
|
| 251 |
+
# copy action dict (if applicable)
|
| 252 |
+
if "data/{}/action_dict".format(ep) in f:
|
| 253 |
+
action_dict = f["data/{}/action_dict".format(ep)]
|
| 254 |
+
for k in action_dict:
|
| 255 |
+
ep_data_grp.create_dataset("action_dict/{}".format(k), data=np.array(action_dict[k][()]))
|
| 256 |
+
|
| 257 |
+
# episode metadata
|
| 258 |
+
if is_robosuite_env:
|
| 259 |
+
ep_data_grp.attrs["model_file"] = traj["initial_state_dict"]["model"] # model xml for this episode
|
| 260 |
+
if "ep_meta" in f["data/{}".format(ep)].attrs:
|
| 261 |
+
ep_data_grp.attrs["ep_meta"] = f["data/{}".format(ep)].attrs["ep_meta"]
|
| 262 |
+
ep_data_grp.attrs["num_samples"] = traj["actions"].shape[0] # number of transitions in this episode
|
| 263 |
+
total_samples += traj["actions"].shape[0]
|
| 264 |
+
print("ep {}: wrote {} transitions to group {}".format(ind, ep_data_grp.attrs["num_samples"], ep))
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
# copy over all filter keys that exist in the original hdf5
|
| 268 |
+
if "mask" in f:
|
| 269 |
+
f.copy("mask", f_out)
|
| 270 |
+
|
| 271 |
+
# global metadata
|
| 272 |
+
data_grp.attrs["total"] = total_samples
|
| 273 |
+
data_grp.attrs["env_args"] = json.dumps(env.serialize(), indent=4) # environment info
|
| 274 |
+
print("Wrote {} trajectories to {}".format(len(demos), output_path))
|
| 275 |
+
|
| 276 |
+
f.close()
|
| 277 |
+
f_out.close()
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
if __name__ == "__main__":
|
| 281 |
+
parser = argparse.ArgumentParser()
|
| 282 |
+
parser.add_argument(
|
| 283 |
+
"--dataset",
|
| 284 |
+
type=str,
|
| 285 |
+
required=True,
|
| 286 |
+
help="path to input hdf5 dataset",
|
| 287 |
+
)
|
| 288 |
+
# name of hdf5 to write - it will be in the same directory as @dataset
|
| 289 |
+
parser.add_argument(
|
| 290 |
+
"--output_name",
|
| 291 |
+
type=str,
|
| 292 |
+
help="name of output hdf5 dataset",
|
| 293 |
+
)
|
| 294 |
+
|
| 295 |
+
# specify number of demos to process - useful for debugging conversion with a handful
|
| 296 |
+
# of trajectories
|
| 297 |
+
parser.add_argument(
|
| 298 |
+
"--n",
|
| 299 |
+
type=int,
|
| 300 |
+
default=None,
|
| 301 |
+
help="(optional) stop after n trajectories are processed",
|
| 302 |
+
)
|
| 303 |
+
|
| 304 |
+
# flag for reward shaping
|
| 305 |
+
parser.add_argument(
|
| 306 |
+
"--shaped",
|
| 307 |
+
action='store_true',
|
| 308 |
+
help="(optional) use shaped rewards",
|
| 309 |
+
)
|
| 310 |
+
|
| 311 |
+
# camera names to use for observations
|
| 312 |
+
parser.add_argument(
|
| 313 |
+
"--camera_names",
|
| 314 |
+
type=str,
|
| 315 |
+
nargs='+',
|
| 316 |
+
default=[],
|
| 317 |
+
help="(optional) camera name(s) to use for image observations. Leave out to not use image observations.",
|
| 318 |
+
)
|
| 319 |
+
|
| 320 |
+
parser.add_argument(
|
| 321 |
+
"--camera_height",
|
| 322 |
+
type=int,
|
| 323 |
+
default=84,
|
| 324 |
+
help="(optional) height of image observations",
|
| 325 |
+
)
|
| 326 |
+
|
| 327 |
+
parser.add_argument(
|
| 328 |
+
"--camera_width",
|
| 329 |
+
type=int,
|
| 330 |
+
default=84,
|
| 331 |
+
help="(optional) width of image observations",
|
| 332 |
+
)
|
| 333 |
+
|
| 334 |
+
# specifies how the "done" signal is written. If "0", then the "done" signal is 1 wherever
|
| 335 |
+
# the transition (s, a, s') has s' in a task completion state. If "1", the "done" signal
|
| 336 |
+
# is one at the end of every trajectory. If "2", the "done" signal is 1 at task completion
|
| 337 |
+
# states for successful trajectories and 1 at the end of all trajectories.
|
| 338 |
+
parser.add_argument(
|
| 339 |
+
"--done_mode",
|
| 340 |
+
type=int,
|
| 341 |
+
default=0,
|
| 342 |
+
help="how to write done signal. If 0, done is 1 whenever s' is a success state.\
|
| 343 |
+
If 1, done is 1 at the end of each trajectory. If 2, both.",
|
| 344 |
+
)
|
| 345 |
+
|
| 346 |
+
# flag for copying rewards from source file instead of re-writing them
|
| 347 |
+
parser.add_argument(
|
| 348 |
+
"--copy_rewards",
|
| 349 |
+
action='store_true',
|
| 350 |
+
help="(optional) copy rewards from source file instead of inferring them",
|
| 351 |
+
)
|
| 352 |
+
|
| 353 |
+
# flag for copying dones from source file instead of re-writing them
|
| 354 |
+
parser.add_argument(
|
| 355 |
+
"--copy_dones",
|
| 356 |
+
action='store_true',
|
| 357 |
+
help="(optional) copy dones from source file instead of inferring them",
|
| 358 |
+
)
|
| 359 |
+
|
| 360 |
+
# flag to exclude next obs in dataset
|
| 361 |
+
parser.add_argument(
|
| 362 |
+
"--exclude-next-obs",
|
| 363 |
+
action='store_true',
|
| 364 |
+
help="(optional) exclude next obs in dataset",
|
| 365 |
+
)
|
| 366 |
+
|
| 367 |
+
# flag to compress observations with gzip option in hdf5
|
| 368 |
+
parser.add_argument(
|
| 369 |
+
"--compress",
|
| 370 |
+
action='store_true',
|
| 371 |
+
help="(optional) compress observations with gzip option in hdf5",
|
| 372 |
+
)
|
| 373 |
+
|
| 374 |
+
args = parser.parse_args()
|
| 375 |
+
dataset_states_to_obs(args)
|
aloha-devel/robomimic/scripts/download_momart_datasets.py
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Script to download datasets used in MoMaRT paper (https://arxiv.org/abs/2112.05251). By default, all
|
| 3 |
+
datasets will be stored at robomimic/datasets, unless the @download_dir
|
| 4 |
+
argument is supplied. We recommend using the default, as most examples that
|
| 5 |
+
use these datasets assume that they can be found there.
|
| 6 |
+
|
| 7 |
+
The @tasks and @dataset_types arguments can all be supplied
|
| 8 |
+
to choose which datasets to download.
|
| 9 |
+
|
| 10 |
+
Args:
|
| 11 |
+
download_dir (str): Base download directory. Created if it doesn't exist.
|
| 12 |
+
Defaults to datasets folder in repository - only pass in if you would
|
| 13 |
+
like to override the location.
|
| 14 |
+
|
| 15 |
+
tasks (list): Tasks to download datasets for. Defaults to table_setup_from_dishwasher task. Pass 'all' to
|
| 16 |
+
download all tasks - 5 total:
|
| 17 |
+
- table_setup_from_dishwasher
|
| 18 |
+
- table_setup_from_dresser
|
| 19 |
+
- table_cleanup_to_dishwasher
|
| 20 |
+
- table_cleanup_to_sink
|
| 21 |
+
- unload_dishwasher
|
| 22 |
+
|
| 23 |
+
dataset_types (list): Dataset types to download datasets for (expert, suboptimal, generalize, sample).
|
| 24 |
+
Defaults to expert. Pass 'all' to download datasets for all available dataset
|
| 25 |
+
types per task, or directly specify the list of dataset types.
|
| 26 |
+
NOTE: Because these datasets are huge, we will always print out a warning
|
| 27 |
+
that a user must respond yes to to acknowledge the data size (can be up to >100G for all tasks of a single type)
|
| 28 |
+
|
| 29 |
+
Example usage:
|
| 30 |
+
|
| 31 |
+
# default behavior - just download expert table_setup_from_dishwasher dataset
|
| 32 |
+
python download_momart_datasets.py
|
| 33 |
+
|
| 34 |
+
# download expert datasets for all tasks
|
| 35 |
+
# (do a dry run first to see which datasets would be downloaded)
|
| 36 |
+
python download_momart_datasets.py --tasks all --dataset_types expert --dry_run
|
| 37 |
+
python download_momart_datasets.py --tasks all --dataset_types expert low_dim
|
| 38 |
+
|
| 39 |
+
# download all expert and suboptimal datasets for the table_setup_from_dishwasher and table_cleanup_to_dishwasher tasks
|
| 40 |
+
python download_datasets.py --tasks table_setup_from_dishwasher table_cleanup_to_dishwasher --dataset_types expert suboptimal
|
| 41 |
+
|
| 42 |
+
# download the sample datasets
|
| 43 |
+
python download_datasets.py --tasks all --dataset_types sample
|
| 44 |
+
|
| 45 |
+
# download all datasets
|
| 46 |
+
python download_datasets.py --tasks all --dataset_types all
|
| 47 |
+
"""
|
| 48 |
+
import os
|
| 49 |
+
import argparse
|
| 50 |
+
|
| 51 |
+
import robomimic
|
| 52 |
+
import robomimic.utils.file_utils as FileUtils
|
| 53 |
+
from robomimic import MOMART_DATASET_REGISTRY
|
| 54 |
+
|
| 55 |
+
ALL_TASKS = [
|
| 56 |
+
"table_setup_from_dishwasher",
|
| 57 |
+
"table_setup_from_dresser",
|
| 58 |
+
"table_cleanup_to_dishwasher",
|
| 59 |
+
"table_cleanup_to_sink",
|
| 60 |
+
"unload_dishwasher",
|
| 61 |
+
]
|
| 62 |
+
ALL_DATASET_TYPES = [
|
| 63 |
+
"expert",
|
| 64 |
+
"suboptimal",
|
| 65 |
+
"generalize",
|
| 66 |
+
"sample",
|
| 67 |
+
]
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
if __name__ == "__main__":
|
| 71 |
+
parser = argparse.ArgumentParser()
|
| 72 |
+
|
| 73 |
+
# directory to download datasets to
|
| 74 |
+
parser.add_argument(
|
| 75 |
+
"--download_dir",
|
| 76 |
+
type=str,
|
| 77 |
+
default=None,
|
| 78 |
+
help="Base download directory. Created if it doesn't exist. Defaults to datasets folder in repository.",
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
# tasks to download datasets for
|
| 82 |
+
parser.add_argument(
|
| 83 |
+
"--tasks",
|
| 84 |
+
type=str,
|
| 85 |
+
nargs='+',
|
| 86 |
+
default=["table_setup_from_dishwasher"],
|
| 87 |
+
help="Tasks to download datasets for. Defaults to table_setup_from_dishwasher task. Pass 'all' to download all"
|
| 88 |
+
f"5 tasks, or directly specify the list of tasks. Options are any of: {ALL_TASKS}",
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
# dataset types to download datasets for
|
| 92 |
+
parser.add_argument(
|
| 93 |
+
"--dataset_types",
|
| 94 |
+
type=str,
|
| 95 |
+
nargs='+',
|
| 96 |
+
default=["expert"],
|
| 97 |
+
help="Dataset types to download datasets for (e.g. expert, suboptimal). Defaults to expert. Pass 'all' to "
|
| 98 |
+
"download datasets for all available dataset types per task, or directly specify the list of dataset "
|
| 99 |
+
f"types. Options are any of: {ALL_DATASET_TYPES}",
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
# dry run - don't actually download datasets, but print which datasets would be downloaded
|
| 103 |
+
parser.add_argument(
|
| 104 |
+
"--dry_run",
|
| 105 |
+
action='store_true',
|
| 106 |
+
help="set this flag to do a dry run to only print which datasets would be downloaded"
|
| 107 |
+
)
|
| 108 |
+
|
| 109 |
+
args = parser.parse_args()
|
| 110 |
+
|
| 111 |
+
# set default base directory for downloads
|
| 112 |
+
default_base_dir = args.download_dir
|
| 113 |
+
if default_base_dir is None:
|
| 114 |
+
default_base_dir = os.path.join(robomimic.__path__[0], "../datasets")
|
| 115 |
+
|
| 116 |
+
# load args
|
| 117 |
+
download_tasks = args.tasks
|
| 118 |
+
if "all" in download_tasks:
|
| 119 |
+
assert len(download_tasks) == 1, "all should be only tasks argument but got: {}".format(args.tasks)
|
| 120 |
+
download_tasks = ALL_TASKS
|
| 121 |
+
|
| 122 |
+
download_dataset_types = args.dataset_types
|
| 123 |
+
if "all" in download_dataset_types:
|
| 124 |
+
assert len(download_dataset_types) == 1, "all should be only dataset_types argument but got: {}".format(args.dataset_types)
|
| 125 |
+
download_dataset_types = ALL_DATASET_TYPES
|
| 126 |
+
|
| 127 |
+
# Run sanity check first to warn user if they're about to download a huge amount of data
|
| 128 |
+
total_size = 0
|
| 129 |
+
for task in MOMART_DATASET_REGISTRY:
|
| 130 |
+
if task in download_tasks:
|
| 131 |
+
for dataset_type in MOMART_DATASET_REGISTRY[task]:
|
| 132 |
+
if dataset_type in download_dataset_types:
|
| 133 |
+
total_size += MOMART_DATASET_REGISTRY[task][dataset_type]["size"]
|
| 134 |
+
|
| 135 |
+
# Verify user acknowledgement if we're not doing a dry run
|
| 136 |
+
if not args.dry_run:
|
| 137 |
+
user_response = input(f"Warning: requested datasets will take a total of {total_size}GB. Proceed? y/n\n")
|
| 138 |
+
assert user_response.lower() in {"yes", "y"}, f"Did not receive confirmation. Aborting download."
|
| 139 |
+
|
| 140 |
+
# download requested datasets
|
| 141 |
+
for task in MOMART_DATASET_REGISTRY:
|
| 142 |
+
if task in download_tasks:
|
| 143 |
+
for dataset_type in MOMART_DATASET_REGISTRY[task]:
|
| 144 |
+
if dataset_type in download_dataset_types:
|
| 145 |
+
dataset_info = MOMART_DATASET_REGISTRY[task][dataset_type]
|
| 146 |
+
download_dir = os.path.abspath(os.path.join(default_base_dir, task, dataset_type))
|
| 147 |
+
print(f"\nDownloading dataset:\n"
|
| 148 |
+
f" task: {task}\n"
|
| 149 |
+
f" dataset type: {dataset_type}\n"
|
| 150 |
+
f" dataset size: {dataset_info['size']}GB\n"
|
| 151 |
+
f" download path: {download_dir}")
|
| 152 |
+
if args.dry_run:
|
| 153 |
+
print("\ndry run: skip download")
|
| 154 |
+
else:
|
| 155 |
+
# Make sure path exists and create if it doesn't
|
| 156 |
+
os.makedirs(download_dir, exist_ok=True)
|
| 157 |
+
FileUtils.download_url(
|
| 158 |
+
url=dataset_info["url"],
|
| 159 |
+
download_dir=download_dir,
|
| 160 |
+
)
|
| 161 |
+
print("")
|
aloha-devel/robomimic/scripts/filter_dataset_size.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import h5py
|
| 3 |
+
import numpy as np
|
| 4 |
+
|
| 5 |
+
from robomimic.utils.file_utils import create_hdf5_filter_key
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def filter_dataset_size(hdf5_path, num_demos, input_filter_key=None, output_filter_key=None):
|
| 9 |
+
# retrieve number of demos
|
| 10 |
+
f = h5py.File(hdf5_path, "r")
|
| 11 |
+
if input_filter_key is not None:
|
| 12 |
+
print("using filter key: {}".format(input_filter_key))
|
| 13 |
+
demos = sorted([elem.decode("utf-8") for elem in np.array(f["mask/{}".format(input_filter_key)])])
|
| 14 |
+
else:
|
| 15 |
+
demos = sorted(list(f["data"].keys()))
|
| 16 |
+
f.close()
|
| 17 |
+
|
| 18 |
+
# get random split
|
| 19 |
+
total_num_demos = len(demos)
|
| 20 |
+
mask = np.zeros(total_num_demos)
|
| 21 |
+
mask[:num_demos] = 1.
|
| 22 |
+
np.random.shuffle(mask)
|
| 23 |
+
mask = mask.astype(int)
|
| 24 |
+
subset_inds = mask.nonzero()[0]
|
| 25 |
+
subset_keys = [demos[i] for i in subset_inds]
|
| 26 |
+
|
| 27 |
+
# pass mask to generate split
|
| 28 |
+
if output_filter_key is not None:
|
| 29 |
+
name = output_filter_key
|
| 30 |
+
else:
|
| 31 |
+
name = "{}_demos".format(num_demos)
|
| 32 |
+
|
| 33 |
+
if input_filter_key is not None:
|
| 34 |
+
name = "{}_{}".format(input_filter_key, name)
|
| 35 |
+
|
| 36 |
+
subset_lengths = create_hdf5_filter_key(hdf5_path=hdf5_path, demo_keys=subset_keys, key_name=name)
|
| 37 |
+
|
| 38 |
+
print("Total number of subset samples: {}".format(np.sum(subset_lengths)))
|
| 39 |
+
print("Average number of subset samples {}".format(np.mean(subset_lengths)))
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
if __name__ == "__main__":
|
| 43 |
+
parser = argparse.ArgumentParser()
|
| 44 |
+
parser.add_argument(
|
| 45 |
+
"--dataset",
|
| 46 |
+
type=str,
|
| 47 |
+
required=True,
|
| 48 |
+
help="path to hdf5 dataset",
|
| 49 |
+
)
|
| 50 |
+
parser.add_argument(
|
| 51 |
+
"--input_filter_key",
|
| 52 |
+
type=str,
|
| 53 |
+
default=None,
|
| 54 |
+
help="if provided, split the subset of trajectories in the file that correspond to\
|
| 55 |
+
this filter key into a training and validation set of trajectories, instead of\
|
| 56 |
+
splitting the full set of trajectories",
|
| 57 |
+
)
|
| 58 |
+
parser.add_argument(
|
| 59 |
+
"--num_demos",
|
| 60 |
+
type=int,
|
| 61 |
+
nargs='+',
|
| 62 |
+
required=True,
|
| 63 |
+
)
|
| 64 |
+
parser.add_argument(
|
| 65 |
+
"--output_filter_key",
|
| 66 |
+
type=str,
|
| 67 |
+
required=False,
|
| 68 |
+
help="(optional) use custom name for output filter key name"
|
| 69 |
+
)
|
| 70 |
+
args = parser.parse_args()
|
| 71 |
+
|
| 72 |
+
# seed to make sure results are consistent
|
| 73 |
+
np.random.seed(0)
|
| 74 |
+
|
| 75 |
+
for n in args.num_demos:
|
| 76 |
+
filter_dataset_size(
|
| 77 |
+
args.dataset,
|
| 78 |
+
input_filter_key=args.input_filter_key,
|
| 79 |
+
num_demos=n,
|
| 80 |
+
output_filter_key=args.output_filter_key,
|
| 81 |
+
)
|
aloha-devel/robomimic/scripts/plot_model_predictions.py
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import os
|
| 3 |
+
import numpy as np
|
| 4 |
+
import matplotlib.pyplot as plt
|
| 5 |
+
import matplotlib.gridspec as gridspec
|
| 6 |
+
from copy import deepcopy
|
| 7 |
+
import random
|
| 8 |
+
from sklearn.metrics import mean_squared_error
|
| 9 |
+
import re
|
| 10 |
+
import robomimic.utils.file_utils as FileUtils
|
| 11 |
+
import robomimic.utils.torch_utils as TorchUtils
|
| 12 |
+
import robomimic.utils.tensor_utils as TensorUtils
|
| 13 |
+
import robomimic.utils.train_utils as TrainUtils
|
| 14 |
+
from robomimic.config import config_factory
|
| 15 |
+
import robomimic.utils.obs_utils as ObsUtils
|
| 16 |
+
import torch
|
| 17 |
+
from torch.utils.data import DataLoader
|
| 18 |
+
|
| 19 |
+
"""
|
| 20 |
+
TODO: track rotation magnitude seperately (https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.transform.Rotation.magnitude.html)
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
# the configs of the models to be plotted
|
| 24 |
+
model_config_mapping = {
|
| 25 |
+
# "bottle_less_obs": {
|
| 26 |
+
# "model":"/home/zehan/expdata/r2d2/im/bc_xfmr/google_bc_baseline/bottle_less_obs/20230815225106/models/model_epoch_60.pth",
|
| 27 |
+
# 'folder':"/home/zehan/expdata/r2d2/im/bc_xfmr/google_bc_baseline/bottle_less_obs/20230815225106/test_inference_figures/",
|
| 28 |
+
# # "action_names": ['x', 'y', 'z', 'roll', 'pitch', 'yaw', "gripper_action" , 'terminate'],
|
| 29 |
+
# "action_names": None,
|
| 30 |
+
# "trajectory_name_regex": r'(\d+_trajectory_im\d+)'
|
| 31 |
+
# },
|
| 32 |
+
"r2d2_wire": {
|
| 33 |
+
# "model": "/home/soroushn/expdata/r2d2/im/diffusion_policy/debug/ds_pen-in-cup_cams_3cams/20230830160945/models/model_epoch_2.pth",
|
| 34 |
+
"model": "/home/soroushn/expdata/r2d2/im/bc_xfmr/debug/ds_pen-in-cup_cams_3cams_predfuture_True_ac_keys_rel/20230830161631/models/model_epoch_2.pth",
|
| 35 |
+
"folder": "/home/soroushn/tmp/model_predictions",
|
| 36 |
+
# "action_names": ['x', 'y', 'z', 'r', 'p', 'y', "gripper_pos"], # use custom names
|
| 37 |
+
"action_names": None, # use default names, see line 71
|
| 38 |
+
"trajectory_name_regex": r'(\w+_\w+_\d{2}_\d{2}:\d{2}:\d{2}_\d{4})' # the name of the figure files need to be custom defined (the part of the names of the trajectories that uniquely identifies them)
|
| 39 |
+
}
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
NUM_SAMPLES = 2
|
| 43 |
+
|
| 44 |
+
# loop through each model
|
| 45 |
+
for model_name in model_config_mapping:
|
| 46 |
+
ckpt_path = model_config_mapping[model_name]['model']
|
| 47 |
+
saving_folder = model_config_mapping[model_name]['folder']
|
| 48 |
+
# can custom-define or using default action_names
|
| 49 |
+
action_names = model_config_mapping[model_name]['action_names']
|
| 50 |
+
trajectory_name_regex = model_config_mapping[model_name]['trajectory_name_regex']
|
| 51 |
+
accuracy_thresholds = np.logspace(-3,-5, num=3).tolist()
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
device = TorchUtils.get_torch_device(try_to_use_cuda=True)
|
| 56 |
+
|
| 57 |
+
ckpt_dict = FileUtils.maybe_dict_from_checkpoint(ckpt_path=ckpt_path)
|
| 58 |
+
config = json.loads(ckpt_dict["config"])
|
| 59 |
+
config["train"]["shuffled_obs_key_groups"] = None
|
| 60 |
+
ckpt_dict["config"] = json.dumps(config)
|
| 61 |
+
policy, _ = FileUtils.policy_from_checkpoint(ckpt_dict=ckpt_dict, device=device, verbose=True)
|
| 62 |
+
shape_meta = ckpt_dict['shape_metadata']
|
| 63 |
+
ext_cfg = json.loads(ckpt_dict["config"])
|
| 64 |
+
config = config_factory(ext_cfg["algo_name"])
|
| 65 |
+
with config.values_unlocked():
|
| 66 |
+
config.update(ext_cfg)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
frame_stack = config.train.frame_stack
|
| 70 |
+
device = TorchUtils.get_torch_device(try_to_use_cuda=config.train.cuda)
|
| 71 |
+
|
| 72 |
+
trainset, validset = TrainUtils.load_data_for_training(config, obs_keys=shape_meta["all_obs_keys"])
|
| 73 |
+
# trainset.datasets is a list
|
| 74 |
+
# the trajectories to plot is randomly sampled from the training and validation sets
|
| 75 |
+
training_sampled_data = random.sample(trainset.datasets, NUM_SAMPLES)
|
| 76 |
+
# validation_sampled_data = random.sample(validset.datasets, NUM_SAMPLES)
|
| 77 |
+
|
| 78 |
+
inference_datasets_mapping = {"training": training_sampled_data} #, "validation": validation_sampled_data}
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
if action_names == None:
|
| 82 |
+
# TODO
|
| 83 |
+
action_keys = config.train.action_keys # Need to adjust. For Robomimic datasets, there is no `action_keys`, it is config.train.dataset_keys
|
| 84 |
+
modified_action_keys = [element.replace('action/', '') for element in action_keys]
|
| 85 |
+
action_names = []
|
| 86 |
+
for i, action_key in enumerate(action_keys):
|
| 87 |
+
if isinstance(training_sampled_data[0].__getitem__(0)[action_key][frame_stack-1], np.ndarray):
|
| 88 |
+
action_names.extend([f'{modified_action_keys[i]}_{j+1}' for j in range(len(training_sampled_data[0].__getitem__(0)[action_key][frame_stack-1]))])
|
| 89 |
+
else:
|
| 90 |
+
action_names.append(modified_action_keys[i])
|
| 91 |
+
|
| 92 |
+
# loop through training and validation sets
|
| 93 |
+
for inference_key in inference_datasets_mapping:
|
| 94 |
+
mse_training_per_traj = []
|
| 95 |
+
data_name = []
|
| 96 |
+
actual_actions_all_traj = [] # (NxT, D)
|
| 97 |
+
predicted_actions_all_traj = [] # (NxT, D)
|
| 98 |
+
|
| 99 |
+
# loop through each trajectory
|
| 100 |
+
for d in inference_datasets_mapping[inference_key]:
|
| 101 |
+
hdf5_path = d.hdf5_path
|
| 102 |
+
mse_for_one_traj = []
|
| 103 |
+
traj_length = len(d)
|
| 104 |
+
action_dim = len(action_names)
|
| 105 |
+
actual_actions = [[] for _ in range(action_dim)] # (T, D)
|
| 106 |
+
predicted_actions = [[] for _ in range(action_dim)] # (T, D)
|
| 107 |
+
|
| 108 |
+
image_keys = [item for item in d.__getitem__(0)['obs'].keys() if "image" in item]
|
| 109 |
+
images = {key: [] for key in image_keys}
|
| 110 |
+
|
| 111 |
+
dataloader = DataLoader(
|
| 112 |
+
dataset=d,
|
| 113 |
+
sampler=None,
|
| 114 |
+
batch_size=1,
|
| 115 |
+
shuffle=False,
|
| 116 |
+
num_workers=1,
|
| 117 |
+
drop_last=True,
|
| 118 |
+
)
|
| 119 |
+
|
| 120 |
+
model = policy.policy
|
| 121 |
+
|
| 122 |
+
model.reset()
|
| 123 |
+
|
| 124 |
+
# loop through each timestep
|
| 125 |
+
for batch in iter(dataloader):
|
| 126 |
+
batch = model.process_batch_for_training(batch)
|
| 127 |
+
|
| 128 |
+
for image_key in image_keys:
|
| 129 |
+
im = batch["obs"][image_key][0][-1]
|
| 130 |
+
im = TensorUtils.to_numpy(im).astype(np.uint32)
|
| 131 |
+
images[image_key].append(im)
|
| 132 |
+
|
| 133 |
+
batch = model.postprocess_batch_for_training(batch, obs_normalization_stats=None) # ignore obs_normalization for now
|
| 134 |
+
# model_output = model.nets["policy"](batch["obs"])
|
| 135 |
+
|
| 136 |
+
model_output = model.get_action(batch["obs"])
|
| 137 |
+
|
| 138 |
+
actual_action = TensorUtils.to_numpy(
|
| 139 |
+
batch["actions"][0][0]
|
| 140 |
+
)
|
| 141 |
+
predicted_action = TensorUtils.to_numpy(
|
| 142 |
+
model_output[0]
|
| 143 |
+
)
|
| 144 |
+
|
| 145 |
+
actual_actions_all_traj.append(actual_action)
|
| 146 |
+
predicted_actions_all_traj.append(predicted_action)
|
| 147 |
+
|
| 148 |
+
for dim in range(action_dim):
|
| 149 |
+
actual_actions[dim].append(actual_action[dim])
|
| 150 |
+
predicted_actions[dim].append(predicted_action[dim])
|
| 151 |
+
|
| 152 |
+
# Plot
|
| 153 |
+
fig, axs = plt.subplots(len(images) + action_dim, 1, figsize=(30, (len(images) + action_dim) * 3))
|
| 154 |
+
for i, image_key in enumerate(image_keys):
|
| 155 |
+
interval = int(traj_length/15) # plot `5` images
|
| 156 |
+
images[image_key] = images[image_key][::interval]
|
| 157 |
+
combined_images = np.concatenate(images[image_key], axis=1)
|
| 158 |
+
axs[i].imshow(combined_images)
|
| 159 |
+
if i == 0:
|
| 160 |
+
axs[i].set_title(hdf5_path + '\n' + image_key, fontsize=30)
|
| 161 |
+
else:
|
| 162 |
+
axs[i].set_title(image_key, fontsize=30)
|
| 163 |
+
axs[i].axis("off")
|
| 164 |
+
for dim in range(action_dim):
|
| 165 |
+
mse = mean_squared_error(actual_actions[dim], predicted_actions[dim])
|
| 166 |
+
mse_for_one_traj.append(mse)
|
| 167 |
+
axs[len(images)+dim].plot(range(traj_length), actual_actions[dim], label='Actual Action', color='blue')
|
| 168 |
+
axs[len(images)+dim].plot(range(traj_length), predicted_actions[dim], label='Predicted Action', color='red')
|
| 169 |
+
# axs[len(images)+dim].set_xlabel('Timestep')
|
| 170 |
+
# axs[len(images)+dim].set_ylabel('Action Dimension {}'.format(dim + 1))
|
| 171 |
+
axs[len(images)+dim].set_title(action_names[dim], fontsize=30)
|
| 172 |
+
axs[len(images)+dim].xaxis.set_tick_params(labelsize=24)
|
| 173 |
+
axs[len(images)+dim].yaxis.set_tick_params(labelsize=24)
|
| 174 |
+
axs[len(images)+dim].legend(fontsize=20)
|
| 175 |
+
plt.subplots_adjust(left=0.05, right=0.95, top=0.95, bottom=0.05, wspace=0.3, hspace=0.6)
|
| 176 |
+
|
| 177 |
+
# Save inference figures
|
| 178 |
+
save_path = saving_folder + inference_key+"/" #remember to add / at the end
|
| 179 |
+
# data_content = re.search(trajectory_name_regex, hdf5_path).group(1)
|
| 180 |
+
data_content = "test"
|
| 181 |
+
filename = "comparison_figure_"+data_content +".png"
|
| 182 |
+
if not os.path.exists(save_path):
|
| 183 |
+
os.makedirs(save_path)
|
| 184 |
+
print(save_path + filename)
|
| 185 |
+
# Save the figure with the specified path and filename
|
| 186 |
+
plt.savefig(save_path + filename)
|
| 187 |
+
mse_training_per_traj.append(mse_for_one_traj)
|
| 188 |
+
data_name.append(hdf5_path)
|
| 189 |
+
|
| 190 |
+
# log MSE information
|
| 191 |
+
accuracy_thresholds = np.logspace(-3,-5, num=3).tolist()
|
| 192 |
+
mse = torch.nn.functional.mse_loss(torch.tensor(predicted_actions_all_traj), torch.tensor(actual_actions_all_traj), reduction='none') # (NxT, D)
|
| 193 |
+
step_log = {}
|
| 194 |
+
step_log[f'{inference_key}_action_mse_error'] = mse.mean().item() # average MSE across all timesteps averaged across all action dimensions (D,)
|
| 195 |
+
|
| 196 |
+
# compute percentage of timesteps that have MSE less than the accuracy thresholds
|
| 197 |
+
for accuracy_threshold in accuracy_thresholds:
|
| 198 |
+
step_log[f'{inference_key}_action_accuracy@{accuracy_threshold}'] = (torch.less(mse,accuracy_threshold).float().mean().item())
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
average_mse_per_dimension = np.mean(mse_training_per_traj, axis=0) # (D,)
|
| 202 |
+
txt_path = saving_folder+inference_key+"/" +"output.txt"
|
| 203 |
+
list_str = '\n'.join(['{} {}'.format(desc, ' '.join(map(str, sublist))) for desc, sublist in zip(data_name, mse_training_per_traj)])
|
| 204 |
+
|
| 205 |
+
# save MSE information
|
| 206 |
+
with open(txt_path, "w+") as txt_file:
|
| 207 |
+
txt_file.write(f"MSE per trajectory:\n{list_str}\n")
|
| 208 |
+
txt_file.write("\n")
|
| 209 |
+
txt_file.write(f"Average MSE across trajectories per dimension: {average_mse_per_dimension}\n")
|
| 210 |
+
txt_file.write("\n")
|
| 211 |
+
txt_file.write(f"MSE log: {step_log}\n")
|
| 212 |
+
|
| 213 |
+
|
aloha-devel/robomimic/scripts/setup_macros.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This script sets up a private macros file.
|
| 3 |
+
|
| 4 |
+
The private macros file (macros_private.py) is not tracked by git,
|
| 5 |
+
allowing user-specific settings that are not tracked by git.
|
| 6 |
+
|
| 7 |
+
This script checks if macros_private.py exists.
|
| 8 |
+
If applicable, it creates the private macros at robomimic/macros_private.py
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import os
|
| 12 |
+
import robomimic
|
| 13 |
+
import shutil
|
| 14 |
+
|
| 15 |
+
if __name__ == "__main__":
|
| 16 |
+
base_path = robomimic.__path__[0]
|
| 17 |
+
macros_path = os.path.join(base_path, "macros.py")
|
| 18 |
+
macros_private_path = os.path.join(base_path, "macros_private.py")
|
| 19 |
+
|
| 20 |
+
if not os.path.exists(macros_path):
|
| 21 |
+
print("{} does not exist! Aborting...".format(macros_path))
|
| 22 |
+
|
| 23 |
+
if os.path.exists(macros_private_path):
|
| 24 |
+
ans = input("{} already exists! \noverwrite? (y/n)\n".format(macros_private_path))
|
| 25 |
+
|
| 26 |
+
if ans == "y":
|
| 27 |
+
print("REMOVING")
|
| 28 |
+
else:
|
| 29 |
+
exit()
|
| 30 |
+
|
| 31 |
+
shutil.copyfile(macros_path, macros_private_path)
|
| 32 |
+
print("copied {}\nto {}".format(macros_path, macros_private_path))
|
aloha-devel/robomimic/scripts/split_train_val.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Script for splitting a dataset hdf5 file into training and validation trajectories.
|
| 3 |
+
|
| 4 |
+
Args:
|
| 5 |
+
dataset (str): path to hdf5 dataset
|
| 6 |
+
|
| 7 |
+
filter_key (str): if provided, split the subset of trajectories
|
| 8 |
+
in the file that correspond to this filter key into a training
|
| 9 |
+
and validation set of trajectories, instead of splitting the
|
| 10 |
+
full set of trajectories
|
| 11 |
+
|
| 12 |
+
ratio (float): validation ratio, in (0, 1). Defaults to 0.1, which is 10%.
|
| 13 |
+
|
| 14 |
+
Example usage:
|
| 15 |
+
python split_train_val.py --dataset /path/to/demo.hdf5 --ratio 0.1
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
import argparse
|
| 19 |
+
import h5py
|
| 20 |
+
import numpy as np
|
| 21 |
+
|
| 22 |
+
from robomimic.utils.file_utils import create_hdf5_filter_key
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def split_train_val_from_hdf5(hdf5_path, val_ratio=0.1, filter_key=None):
|
| 26 |
+
"""
|
| 27 |
+
Splits data into training set and validation set from HDF5 file.
|
| 28 |
+
|
| 29 |
+
Args:
|
| 30 |
+
hdf5_path (str): path to the hdf5 file
|
| 31 |
+
to load the transitions from
|
| 32 |
+
|
| 33 |
+
val_ratio (float): ratio of validation demonstrations to all demonstrations
|
| 34 |
+
|
| 35 |
+
filter_key (str): if provided, split the subset of demonstration keys stored
|
| 36 |
+
under mask/@filter_key instead of the full set of demonstrations
|
| 37 |
+
"""
|
| 38 |
+
|
| 39 |
+
# retrieve number of demos
|
| 40 |
+
f = h5py.File(hdf5_path, "r")
|
| 41 |
+
if filter_key is not None:
|
| 42 |
+
print("using filter key: {}".format(filter_key))
|
| 43 |
+
demos = sorted([elem.decode("utf-8") for elem in np.array(f["mask/{}".format(filter_key)])])
|
| 44 |
+
else:
|
| 45 |
+
demos = sorted(list(f["data"].keys()))
|
| 46 |
+
num_demos = len(demos)
|
| 47 |
+
f.close()
|
| 48 |
+
|
| 49 |
+
# get random split
|
| 50 |
+
num_demos = len(demos)
|
| 51 |
+
num_val = int(val_ratio * num_demos)
|
| 52 |
+
mask = np.zeros(num_demos)
|
| 53 |
+
mask[:num_val] = 1.
|
| 54 |
+
np.random.shuffle(mask)
|
| 55 |
+
mask = mask.astype(int)
|
| 56 |
+
train_inds = (1 - mask).nonzero()[0]
|
| 57 |
+
valid_inds = mask.nonzero()[0]
|
| 58 |
+
train_keys = [demos[i] for i in train_inds]
|
| 59 |
+
valid_keys = [demos[i] for i in valid_inds]
|
| 60 |
+
print("{} validation demonstrations out of {} total demonstrations.".format(num_val, num_demos))
|
| 61 |
+
|
| 62 |
+
# pass mask to generate split
|
| 63 |
+
name_1 = "train"
|
| 64 |
+
name_2 = "valid"
|
| 65 |
+
if filter_key is not None:
|
| 66 |
+
name_1 = "{}_{}".format(filter_key, name_1)
|
| 67 |
+
name_2 = "{}_{}".format(filter_key, name_2)
|
| 68 |
+
|
| 69 |
+
train_lengths = create_hdf5_filter_key(hdf5_path=hdf5_path, demo_keys=train_keys, key_name=name_1)
|
| 70 |
+
valid_lengths = create_hdf5_filter_key(hdf5_path=hdf5_path, demo_keys=valid_keys, key_name=name_2)
|
| 71 |
+
|
| 72 |
+
print("Total number of train samples: {}".format(np.sum(train_lengths)))
|
| 73 |
+
print("Average number of train samples {}".format(np.mean(train_lengths)))
|
| 74 |
+
|
| 75 |
+
print("Total number of valid samples: {}".format(np.sum(valid_lengths)))
|
| 76 |
+
print("Average number of valid samples {}".format(np.mean(valid_lengths)))
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
if __name__ == "__main__":
|
| 80 |
+
parser = argparse.ArgumentParser()
|
| 81 |
+
parser.add_argument(
|
| 82 |
+
"--dataset",
|
| 83 |
+
type=str,
|
| 84 |
+
help="path to hdf5 dataset",
|
| 85 |
+
)
|
| 86 |
+
parser.add_argument(
|
| 87 |
+
"--filter_key",
|
| 88 |
+
type=str,
|
| 89 |
+
default=None,
|
| 90 |
+
help="if provided, split the subset of trajectories in the file that correspond to\
|
| 91 |
+
this filter key into a training and validation set of trajectories, instead of\
|
| 92 |
+
splitting the full set of trajectories",
|
| 93 |
+
)
|
| 94 |
+
parser.add_argument(
|
| 95 |
+
"--ratio",
|
| 96 |
+
type=float,
|
| 97 |
+
default=0.1,
|
| 98 |
+
help="validation ratio, in (0, 1)"
|
| 99 |
+
)
|
| 100 |
+
args = parser.parse_args()
|
| 101 |
+
|
| 102 |
+
# seed to make sure results are consistent
|
| 103 |
+
np.random.seed(0)
|
| 104 |
+
|
| 105 |
+
split_train_val_from_hdf5(args.dataset, val_ratio=args.ratio, filter_key=args.filter_key)
|
aloha-devel/robomimic/scripts/train.py
ADDED
|
@@ -0,0 +1,512 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
The main entry point for training policies.
|
| 3 |
+
|
| 4 |
+
Args:
|
| 5 |
+
config (str): path to a config json that will be used to override the default settings.
|
| 6 |
+
If omitted, default settings are used. This is the preferred way to run experiments.
|
| 7 |
+
|
| 8 |
+
algo (str): name of the algorithm to run. Only needs to be provided if @config is not
|
| 9 |
+
provided.
|
| 10 |
+
|
| 11 |
+
name (str): if provided, override the experiment name defined in the config
|
| 12 |
+
|
| 13 |
+
dataset (str): if provided, override the dataset path defined in the config
|
| 14 |
+
|
| 15 |
+
debug (bool): set this flag to run a quick training run for debugging purposes
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
import argparse
|
| 19 |
+
import json
|
| 20 |
+
import numpy as np
|
| 21 |
+
import time
|
| 22 |
+
import os
|
| 23 |
+
import shutil
|
| 24 |
+
import psutil
|
| 25 |
+
import sys
|
| 26 |
+
import socket
|
| 27 |
+
import traceback
|
| 28 |
+
|
| 29 |
+
from collections import OrderedDict
|
| 30 |
+
|
| 31 |
+
import torch
|
| 32 |
+
from torch.utils.data import DataLoader
|
| 33 |
+
|
| 34 |
+
import robomimic
|
| 35 |
+
import robomimic.utils.train_utils as TrainUtils
|
| 36 |
+
import robomimic.utils.torch_utils as TorchUtils
|
| 37 |
+
import robomimic.utils.obs_utils as ObsUtils
|
| 38 |
+
import robomimic.utils.env_utils as EnvUtils
|
| 39 |
+
import robomimic.utils.file_utils as FileUtils
|
| 40 |
+
from robomimic.config import config_factory
|
| 41 |
+
from robomimic.algo import algo_factory, RolloutPolicy
|
| 42 |
+
from robomimic.utils.log_utils import PrintLogger, DataLogger, flush_warnings
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def train(config, device):
|
| 46 |
+
"""
|
| 47 |
+
Train a model using the algorithm.
|
| 48 |
+
"""
|
| 49 |
+
|
| 50 |
+
# first set seeds
|
| 51 |
+
np.random.seed(config.train.seed)
|
| 52 |
+
torch.manual_seed(config.train.seed)
|
| 53 |
+
|
| 54 |
+
# set num workers
|
| 55 |
+
torch.set_num_threads(1)
|
| 56 |
+
|
| 57 |
+
print("\n============= New Training Run with Config =============")
|
| 58 |
+
print(config)
|
| 59 |
+
print("")
|
| 60 |
+
log_dir, ckpt_dir, video_dir, vis_dir = TrainUtils.get_exp_dir(config)
|
| 61 |
+
|
| 62 |
+
if config.experiment.logging.terminal_output_to_txt:
|
| 63 |
+
# log stdout and stderr to a text file
|
| 64 |
+
logger = PrintLogger(os.path.join(log_dir, 'log.txt'))
|
| 65 |
+
sys.stdout = logger
|
| 66 |
+
sys.stderr = logger
|
| 67 |
+
|
| 68 |
+
# read config to set up metadata for observation modalities (e.g. detecting rgb observations)
|
| 69 |
+
ObsUtils.initialize_obs_utils_with_config(config)
|
| 70 |
+
|
| 71 |
+
# extract the metadata and shape metadata across all datasets
|
| 72 |
+
env_meta_list = []
|
| 73 |
+
shape_meta_list = []
|
| 74 |
+
for dataset_cfg in config.train.data:
|
| 75 |
+
dataset_path = os.path.expanduser(dataset_cfg["path"])
|
| 76 |
+
ds_format = config.train.data_format
|
| 77 |
+
if not os.path.exists(dataset_path):
|
| 78 |
+
raise Exception("Dataset at provided path {} not found!".format(dataset_path))
|
| 79 |
+
|
| 80 |
+
# load basic metadata from training file
|
| 81 |
+
print("\n============= Loaded Environment Metadata =============")
|
| 82 |
+
env_meta = FileUtils.get_env_metadata_from_dataset(dataset_path=dataset_path, ds_format=ds_format)
|
| 83 |
+
|
| 84 |
+
# populate language instruction for env in env_meta
|
| 85 |
+
env_meta["lang"] = dataset_cfg.get("lang", "dummy")
|
| 86 |
+
|
| 87 |
+
# update env meta if applicable
|
| 88 |
+
from robomimic.utils.script_utils import deep_update
|
| 89 |
+
deep_update(env_meta, config.experiment.env_meta_update_dict)
|
| 90 |
+
env_meta_list.append(env_meta)
|
| 91 |
+
|
| 92 |
+
shape_meta = FileUtils.get_shape_metadata_from_dataset(
|
| 93 |
+
dataset_path=dataset_path,
|
| 94 |
+
action_keys=config.train.action_keys,
|
| 95 |
+
all_obs_keys=config.all_obs_keys,
|
| 96 |
+
ds_format=ds_format,
|
| 97 |
+
verbose=True
|
| 98 |
+
)
|
| 99 |
+
shape_meta_list.append(shape_meta)
|
| 100 |
+
|
| 101 |
+
if config.experiment.env is not None:
|
| 102 |
+
env_meta["env_name"] = config.experiment.env
|
| 103 |
+
print("=" * 30 + "\n" + "Replacing Env to {}\n".format(env_meta["env_name"]) + "=" * 30)
|
| 104 |
+
|
| 105 |
+
# create environment
|
| 106 |
+
envs = OrderedDict()
|
| 107 |
+
if config.experiment.rollout.enabled:
|
| 108 |
+
# create environments for validation runs
|
| 109 |
+
# env_names = [env_meta["env_name"]]
|
| 110 |
+
|
| 111 |
+
# # disable this feature for now
|
| 112 |
+
# if config.experiment.additional_envs is not None:
|
| 113 |
+
# raise NotImplementedError
|
| 114 |
+
# for name in config.experiment.additional_envs:
|
| 115 |
+
# env_names.append(name)
|
| 116 |
+
|
| 117 |
+
for (dataset_i, dataset_cfg) in enumerate(config.train.data):
|
| 118 |
+
do_eval = dataset_cfg.get("eval", True)
|
| 119 |
+
if do_eval is not True:
|
| 120 |
+
continue
|
| 121 |
+
env_meta = env_meta_list[dataset_i]
|
| 122 |
+
shape_meta = shape_meta_list[dataset_i]
|
| 123 |
+
env_name = env_meta["env_name"]
|
| 124 |
+
|
| 125 |
+
def create_env(env_i=0):
|
| 126 |
+
env_kwargs = dict(
|
| 127 |
+
env_meta=env_meta,
|
| 128 |
+
env_name=env_name,
|
| 129 |
+
render=False,
|
| 130 |
+
render_offscreen=config.experiment.render_video,
|
| 131 |
+
use_image_obs=shape_meta["use_images"],
|
| 132 |
+
# seed=config.train.seed * 1000 + env_i # TODO: add seeding across environments
|
| 133 |
+
)
|
| 134 |
+
env = EnvUtils.create_env_from_metadata(**env_kwargs)
|
| 135 |
+
# handle environment wrappers
|
| 136 |
+
env = EnvUtils.wrap_env_from_config(env, config=config) # apply environment warpper, if applicable
|
| 137 |
+
|
| 138 |
+
return env
|
| 139 |
+
|
| 140 |
+
if config.experiment.rollout.batched:
|
| 141 |
+
from tianshou.env import SubprocVectorEnv
|
| 142 |
+
env_fns = [lambda env_i=i: create_env(env_i) for i in range(config.experiment.rollout.num_batch_envs)]
|
| 143 |
+
env = SubprocVectorEnv(env_fns)
|
| 144 |
+
env_name = env.get_env_attr(key="name", id=0)[0]
|
| 145 |
+
else:
|
| 146 |
+
env = create_env()
|
| 147 |
+
env_name = env.name
|
| 148 |
+
|
| 149 |
+
envs[env_name] = env
|
| 150 |
+
print(env)
|
| 151 |
+
|
| 152 |
+
print("")
|
| 153 |
+
|
| 154 |
+
# setup for a new training run
|
| 155 |
+
data_logger = DataLogger(
|
| 156 |
+
log_dir,
|
| 157 |
+
config,
|
| 158 |
+
log_tb=config.experiment.logging.log_tb,
|
| 159 |
+
log_wandb=config.experiment.logging.log_wandb,
|
| 160 |
+
)
|
| 161 |
+
model = algo_factory(
|
| 162 |
+
algo_name=config.algo_name,
|
| 163 |
+
config=config,
|
| 164 |
+
obs_key_shapes=shape_meta_list[0]["all_shapes"],
|
| 165 |
+
ac_dim=shape_meta_list[0]["ac_dim"],
|
| 166 |
+
device=device,
|
| 167 |
+
)
|
| 168 |
+
|
| 169 |
+
# save the config as a json file
|
| 170 |
+
with open(os.path.join(log_dir, '..', 'config.json'), 'w') as outfile:
|
| 171 |
+
json.dump(config, outfile, indent=4)
|
| 172 |
+
|
| 173 |
+
# if checkpoint is specified, load in model weights
|
| 174 |
+
ckpt_path = config.experiment.ckpt_path
|
| 175 |
+
if ckpt_path is not None:
|
| 176 |
+
print("LOADING MODEL WEIGHTS FROM " + ckpt_path)
|
| 177 |
+
from robomimic.utils.file_utils import maybe_dict_from_checkpoint
|
| 178 |
+
ckpt_dict = maybe_dict_from_checkpoint(ckpt_path=ckpt_path)
|
| 179 |
+
model.deserialize(ckpt_dict["model"])
|
| 180 |
+
|
| 181 |
+
print("\n============= Model Summary =============")
|
| 182 |
+
print(model) # print model summary
|
| 183 |
+
print("")
|
| 184 |
+
|
| 185 |
+
# load training data
|
| 186 |
+
trainset, validset = TrainUtils.load_data_for_training(
|
| 187 |
+
config, obs_keys=shape_meta["all_obs_keys"])
|
| 188 |
+
train_sampler = trainset.get_dataset_sampler()
|
| 189 |
+
print("\n============= Training Dataset =============")
|
| 190 |
+
print(trainset)
|
| 191 |
+
print("")
|
| 192 |
+
if validset is not None:
|
| 193 |
+
print("\n============= Validation Dataset =============")
|
| 194 |
+
print(validset)
|
| 195 |
+
print("")
|
| 196 |
+
|
| 197 |
+
# maybe retreve statistics for normalizing observations
|
| 198 |
+
obs_normalization_stats = None
|
| 199 |
+
if config.train.hdf5_normalize_obs:
|
| 200 |
+
obs_normalization_stats = trainset.get_obs_normalization_stats()
|
| 201 |
+
|
| 202 |
+
# maybe retreve statistics for normalizing actions
|
| 203 |
+
action_normalization_stats = trainset.get_action_normalization_stats()
|
| 204 |
+
|
| 205 |
+
# initialize data loaders
|
| 206 |
+
train_loader = DataLoader(
|
| 207 |
+
dataset=trainset,
|
| 208 |
+
sampler=train_sampler,
|
| 209 |
+
batch_size=config.train.batch_size,
|
| 210 |
+
shuffle=(train_sampler is None),
|
| 211 |
+
num_workers=config.train.num_data_workers,
|
| 212 |
+
drop_last=True
|
| 213 |
+
)
|
| 214 |
+
|
| 215 |
+
if config.experiment.validate:
|
| 216 |
+
# cap num workers for validation dataset at 1
|
| 217 |
+
num_workers = min(config.train.num_data_workers, 1)
|
| 218 |
+
valid_sampler = validset.get_dataset_sampler()
|
| 219 |
+
valid_loader = DataLoader(
|
| 220 |
+
dataset=validset,
|
| 221 |
+
sampler=valid_sampler,
|
| 222 |
+
batch_size=config.train.batch_size,
|
| 223 |
+
shuffle=(valid_sampler is None),
|
| 224 |
+
num_workers=num_workers,
|
| 225 |
+
drop_last=True
|
| 226 |
+
)
|
| 227 |
+
else:
|
| 228 |
+
valid_loader = None
|
| 229 |
+
|
| 230 |
+
# print all warnings before training begins
|
| 231 |
+
print("*" * 50)
|
| 232 |
+
print("Warnings generated by robomimic have been duplicated here (from above) for convenience. Please check them carefully.")
|
| 233 |
+
flush_warnings()
|
| 234 |
+
print("*" * 50)
|
| 235 |
+
print("")
|
| 236 |
+
|
| 237 |
+
# main training loop
|
| 238 |
+
best_valid_loss = None
|
| 239 |
+
best_return = {k: -np.inf for k in envs} if config.experiment.rollout.enabled else None
|
| 240 |
+
best_success_rate = {k: -1. for k in envs} if config.experiment.rollout.enabled else None
|
| 241 |
+
last_ckpt_time = time.time()
|
| 242 |
+
|
| 243 |
+
# number of learning steps per epoch (defaults to a full dataset pass)
|
| 244 |
+
train_num_steps = config.experiment.epoch_every_n_steps
|
| 245 |
+
valid_num_steps = config.experiment.validation_epoch_every_n_steps
|
| 246 |
+
|
| 247 |
+
for epoch in range(1, config.train.num_epochs + 1): # epoch numbers start at 1
|
| 248 |
+
step_log = TrainUtils.run_epoch(
|
| 249 |
+
model=model,
|
| 250 |
+
data_loader=train_loader,
|
| 251 |
+
epoch=epoch,
|
| 252 |
+
num_steps=train_num_steps,
|
| 253 |
+
obs_normalization_stats=obs_normalization_stats,
|
| 254 |
+
)
|
| 255 |
+
model.on_epoch_end(epoch)
|
| 256 |
+
|
| 257 |
+
# setup checkpoint path
|
| 258 |
+
epoch_ckpt_name = "model_epoch_{}".format(epoch)
|
| 259 |
+
|
| 260 |
+
# check for recurring checkpoint saving conditions
|
| 261 |
+
should_save_ckpt = False
|
| 262 |
+
if config.experiment.save.enabled:
|
| 263 |
+
time_check = (config.experiment.save.every_n_seconds is not None) and \
|
| 264 |
+
(time.time() - last_ckpt_time > config.experiment.save.every_n_seconds)
|
| 265 |
+
epoch_check = (config.experiment.save.every_n_epochs is not None) and \
|
| 266 |
+
(epoch > 0) and (epoch % config.experiment.save.every_n_epochs == 0)
|
| 267 |
+
epoch_list_check = (epoch in config.experiment.save.epochs)
|
| 268 |
+
should_save_ckpt = (time_check or epoch_check or epoch_list_check)
|
| 269 |
+
ckpt_reason = None
|
| 270 |
+
if should_save_ckpt:
|
| 271 |
+
last_ckpt_time = time.time()
|
| 272 |
+
ckpt_reason = "time"
|
| 273 |
+
|
| 274 |
+
print("Train Epoch {}".format(epoch))
|
| 275 |
+
print(json.dumps(step_log, sort_keys=True, indent=4))
|
| 276 |
+
for k, v in step_log.items():
|
| 277 |
+
if k.startswith("Time_"):
|
| 278 |
+
data_logger.record("Timing_Stats/Train_{}".format(k[5:]), v, epoch)
|
| 279 |
+
else:
|
| 280 |
+
data_logger.record("Train/{}".format(k), v, epoch)
|
| 281 |
+
|
| 282 |
+
# Evaluate the model on validation set
|
| 283 |
+
if config.experiment.validate:
|
| 284 |
+
with torch.no_grad():
|
| 285 |
+
step_log = TrainUtils.run_epoch(model=model, data_loader=valid_loader, epoch=epoch, validate=True, num_steps=valid_num_steps)
|
| 286 |
+
for k, v in step_log.items():
|
| 287 |
+
if k.startswith("Time_"):
|
| 288 |
+
data_logger.record("Timing_Stats/Valid_{}".format(k[5:]), v, epoch)
|
| 289 |
+
else:
|
| 290 |
+
data_logger.record("Valid/{}".format(k), v, epoch)
|
| 291 |
+
|
| 292 |
+
print("Validation Epoch {}".format(epoch))
|
| 293 |
+
print(json.dumps(step_log, sort_keys=True, indent=4))
|
| 294 |
+
|
| 295 |
+
# save checkpoint if achieve new best validation loss
|
| 296 |
+
valid_check = "Loss" in step_log
|
| 297 |
+
if valid_check and (best_valid_loss is None or (step_log["Loss"] <= best_valid_loss)):
|
| 298 |
+
best_valid_loss = step_log["Loss"]
|
| 299 |
+
if config.experiment.save.enabled and config.experiment.save.on_best_validation:
|
| 300 |
+
epoch_ckpt_name += "_best_validation_{}".format(best_valid_loss)
|
| 301 |
+
should_save_ckpt = True
|
| 302 |
+
ckpt_reason = "valid" if ckpt_reason is None else ckpt_reason
|
| 303 |
+
|
| 304 |
+
# Evaluate the model by by running rollouts
|
| 305 |
+
|
| 306 |
+
# do rollouts at fixed rate or if it's time to save a new ckpt
|
| 307 |
+
video_paths = None
|
| 308 |
+
rollout_check = (epoch % config.experiment.rollout.rate == 0) or (should_save_ckpt and ckpt_reason == "time")
|
| 309 |
+
if config.experiment.rollout.enabled and (epoch > config.experiment.rollout.warmstart) and rollout_check:
|
| 310 |
+
# wrap model as a RolloutPolicy to prepare for rollouts
|
| 311 |
+
rollout_model = RolloutPolicy(
|
| 312 |
+
model,
|
| 313 |
+
obs_normalization_stats=obs_normalization_stats,
|
| 314 |
+
action_normalization_stats=action_normalization_stats,
|
| 315 |
+
)
|
| 316 |
+
|
| 317 |
+
num_episodes = config.experiment.rollout.n
|
| 318 |
+
all_rollout_logs, video_paths = TrainUtils.rollout_with_stats(
|
| 319 |
+
policy=rollout_model,
|
| 320 |
+
envs=envs,
|
| 321 |
+
horizon=config.experiment.rollout.horizon,
|
| 322 |
+
use_goals=config.use_goals,
|
| 323 |
+
num_episodes=num_episodes,
|
| 324 |
+
render=False,
|
| 325 |
+
video_dir=video_dir if config.experiment.render_video else None,
|
| 326 |
+
epoch=epoch,
|
| 327 |
+
video_skip=config.experiment.get("video_skip", 5),
|
| 328 |
+
terminate_on_success=config.experiment.rollout.terminate_on_success,
|
| 329 |
+
)
|
| 330 |
+
|
| 331 |
+
# summarize results from rollouts to tensorboard and terminal
|
| 332 |
+
for env_name in all_rollout_logs:
|
| 333 |
+
rollout_logs = all_rollout_logs[env_name]
|
| 334 |
+
for k, v in rollout_logs.items():
|
| 335 |
+
if k.startswith("Time_"):
|
| 336 |
+
data_logger.record("Timing_Stats/Rollout_{}_{}".format(env_name, k[5:]), v, epoch)
|
| 337 |
+
else:
|
| 338 |
+
data_logger.record("Rollout/{}/{}".format(k, env_name), v, epoch, log_stats=True)
|
| 339 |
+
|
| 340 |
+
print("\nEpoch {} Rollouts took {}s (avg) with results:".format(epoch, rollout_logs["time"]))
|
| 341 |
+
print('Env: {}'.format(env_name))
|
| 342 |
+
print(json.dumps(rollout_logs, sort_keys=True, indent=4))
|
| 343 |
+
|
| 344 |
+
# checkpoint and video saving logic
|
| 345 |
+
updated_stats = TrainUtils.should_save_from_rollout_logs(
|
| 346 |
+
all_rollout_logs=all_rollout_logs,
|
| 347 |
+
best_return=best_return,
|
| 348 |
+
best_success_rate=best_success_rate,
|
| 349 |
+
epoch_ckpt_name=epoch_ckpt_name,
|
| 350 |
+
save_on_best_rollout_return=config.experiment.save.on_best_rollout_return,
|
| 351 |
+
save_on_best_rollout_success_rate=config.experiment.save.on_best_rollout_success_rate,
|
| 352 |
+
)
|
| 353 |
+
best_return = updated_stats["best_return"]
|
| 354 |
+
best_success_rate = updated_stats["best_success_rate"]
|
| 355 |
+
epoch_ckpt_name = updated_stats["epoch_ckpt_name"]
|
| 356 |
+
should_save_ckpt = (config.experiment.save.enabled and updated_stats["should_save_ckpt"]) or should_save_ckpt
|
| 357 |
+
if updated_stats["ckpt_reason"] is not None:
|
| 358 |
+
ckpt_reason = updated_stats["ckpt_reason"]
|
| 359 |
+
|
| 360 |
+
# check if we need to save model MSE
|
| 361 |
+
should_save_mse = False
|
| 362 |
+
if config.experiment.mse.enabled:
|
| 363 |
+
if config.experiment.mse.every_n_epochs is not None and epoch % config.experiment.mse.every_n_epochs == 0:
|
| 364 |
+
should_save_mse = True
|
| 365 |
+
if config.experiment.mse.on_save_ckpt and should_save_ckpt:
|
| 366 |
+
should_save_mse = True
|
| 367 |
+
if should_save_mse:
|
| 368 |
+
print("Computing MSE ...")
|
| 369 |
+
if config.experiment.mse.visualize:
|
| 370 |
+
save_vis_dir = os.path.join(vis_dir, epoch_ckpt_name)
|
| 371 |
+
else:
|
| 372 |
+
save_vis_dir = None
|
| 373 |
+
mse_log, vis_log = model.compute_mse_visualize(
|
| 374 |
+
trainset,
|
| 375 |
+
validset,
|
| 376 |
+
num_samples=config.experiment.mse.num_samples,
|
| 377 |
+
savedir=save_vis_dir,
|
| 378 |
+
)
|
| 379 |
+
for k, v in mse_log.items():
|
| 380 |
+
data_logger.record("{}".format(k), v, epoch)
|
| 381 |
+
|
| 382 |
+
for k, v in vis_log.items():
|
| 383 |
+
data_logger.record("{}".format(k), v, epoch, data_type='image')
|
| 384 |
+
|
| 385 |
+
|
| 386 |
+
print("MSE Log Epoch {}".format(epoch))
|
| 387 |
+
print(json.dumps(mse_log, sort_keys=True, indent=4))
|
| 388 |
+
|
| 389 |
+
# # Only keep saved videos if the ckpt should be saved (but not because of validation score)
|
| 390 |
+
# should_save_video = (should_save_ckpt and (ckpt_reason != "valid")) or config.experiment.keep_all_videos
|
| 391 |
+
# if video_paths is not None and not should_save_video:
|
| 392 |
+
# for env_name in video_paths:
|
| 393 |
+
# os.remove(video_paths[env_name])
|
| 394 |
+
|
| 395 |
+
# Save model checkpoints based on conditions (success rate, validation loss, etc)
|
| 396 |
+
if should_save_ckpt:
|
| 397 |
+
TrainUtils.save_model(
|
| 398 |
+
model=model,
|
| 399 |
+
config=config,
|
| 400 |
+
env_meta=env_meta,
|
| 401 |
+
shape_meta=shape_meta,
|
| 402 |
+
ckpt_path=os.path.join(ckpt_dir, epoch_ckpt_name + ".pth"),
|
| 403 |
+
obs_normalization_stats=obs_normalization_stats,
|
| 404 |
+
action_normalization_stats=action_normalization_stats,
|
| 405 |
+
)
|
| 406 |
+
|
| 407 |
+
# Finally, log memory usage in MB
|
| 408 |
+
process = psutil.Process(os.getpid())
|
| 409 |
+
mem_usage = int(process.memory_info().rss / 1000000)
|
| 410 |
+
data_logger.record("System/RAM Usage (MB)", mem_usage, epoch)
|
| 411 |
+
print("\nEpoch {} Memory Usage: {} MB\n".format(epoch, mem_usage))
|
| 412 |
+
|
| 413 |
+
# terminate logging
|
| 414 |
+
data_logger.close()
|
| 415 |
+
|
| 416 |
+
|
| 417 |
+
def main(args):
|
| 418 |
+
|
| 419 |
+
if args.config is not None:
|
| 420 |
+
ext_cfg = json.load(open(args.config, 'r'))
|
| 421 |
+
config = config_factory(ext_cfg["algo_name"])
|
| 422 |
+
# update config with external json - this will throw errors if
|
| 423 |
+
# the external config has keys not present in the base algo config
|
| 424 |
+
with config.values_unlocked():
|
| 425 |
+
config.update(ext_cfg)
|
| 426 |
+
else:
|
| 427 |
+
config = config_factory(args.algo)
|
| 428 |
+
|
| 429 |
+
if args.dataset is not None:
|
| 430 |
+
config.train.data = args.dataset
|
| 431 |
+
|
| 432 |
+
if args.name is not None:
|
| 433 |
+
config.experiment.name = args.name
|
| 434 |
+
|
| 435 |
+
# get torch device
|
| 436 |
+
device = TorchUtils.get_torch_device(try_to_use_cuda=config.train.cuda)
|
| 437 |
+
|
| 438 |
+
# maybe modify config for debugging purposes
|
| 439 |
+
if args.debug:
|
| 440 |
+
# shrink length of training to test whether this run is likely to crash
|
| 441 |
+
config.unlock()
|
| 442 |
+
config.lock_keys()
|
| 443 |
+
|
| 444 |
+
# train and validate (if enabled) for 3 gradient steps, for 2 epochs
|
| 445 |
+
config.experiment.epoch_every_n_steps = 3
|
| 446 |
+
config.experiment.validation_epoch_every_n_steps = 3
|
| 447 |
+
config.train.num_epochs = 2
|
| 448 |
+
|
| 449 |
+
# if rollouts are enabled, try 2 rollouts at end of each epoch, with 10 environment steps
|
| 450 |
+
config.experiment.rollout.rate = 1
|
| 451 |
+
config.experiment.rollout.n = 2
|
| 452 |
+
config.experiment.rollout.horizon = 10
|
| 453 |
+
|
| 454 |
+
# send output to a temporary directory
|
| 455 |
+
config.train.output_dir = "/tmp/tmp_trained_models"
|
| 456 |
+
|
| 457 |
+
# lock config to prevent further modifications and ensure missing keys raise errors
|
| 458 |
+
config.lock()
|
| 459 |
+
|
| 460 |
+
# catch error during training and print it
|
| 461 |
+
res_str = "finished run successfully!"
|
| 462 |
+
try:
|
| 463 |
+
train(config, device=device)
|
| 464 |
+
except Exception as e:
|
| 465 |
+
res_str = "run failed with error:\n{}\n\n{}".format(e, traceback.format_exc())
|
| 466 |
+
print(res_str)
|
| 467 |
+
|
| 468 |
+
|
| 469 |
+
if __name__ == "__main__":
|
| 470 |
+
parser = argparse.ArgumentParser()
|
| 471 |
+
|
| 472 |
+
# External config file that overwrites default config
|
| 473 |
+
parser.add_argument(
|
| 474 |
+
"--config",
|
| 475 |
+
type=str,
|
| 476 |
+
default=None,
|
| 477 |
+
help="(optional) path to a config json that will be used to override the default settings. \
|
| 478 |
+
If omitted, default settings are used. This is the preferred way to run experiments.",
|
| 479 |
+
)
|
| 480 |
+
|
| 481 |
+
# Algorithm Name
|
| 482 |
+
parser.add_argument(
|
| 483 |
+
"--algo",
|
| 484 |
+
type=str,
|
| 485 |
+
help="(optional) name of algorithm to run. Only needs to be provided if --config is not provided",
|
| 486 |
+
)
|
| 487 |
+
|
| 488 |
+
# Experiment Name (for tensorboard, saving models, etc.)
|
| 489 |
+
parser.add_argument(
|
| 490 |
+
"--name",
|
| 491 |
+
type=str,
|
| 492 |
+
default=None,
|
| 493 |
+
help="(optional) if provided, override the experiment name defined in the config",
|
| 494 |
+
)
|
| 495 |
+
|
| 496 |
+
# Dataset path, to override the one in the config
|
| 497 |
+
parser.add_argument(
|
| 498 |
+
"--dataset",
|
| 499 |
+
type=str,
|
| 500 |
+
default=None,
|
| 501 |
+
help="(optional) if provided, override the dataset path defined in the config",
|
| 502 |
+
)
|
| 503 |
+
|
| 504 |
+
# debug mode
|
| 505 |
+
parser.add_argument(
|
| 506 |
+
"--debug",
|
| 507 |
+
action='store_true',
|
| 508 |
+
help="set this flag to run a quick training run for debugging purposes"
|
| 509 |
+
)
|
| 510 |
+
|
| 511 |
+
args = parser.parse_args()
|
| 512 |
+
main(args)
|
camera_ws/build/realsense-ros/realsense2_camera/CMakeFiles/realsense2_camera.dir/src/base_realsense_node.cpp.o
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5541553727cbf098869ea2e94b1d1296cb4a23f3258499d0318e27bae3858a8f
|
| 3 |
+
size 1491304
|
camera_ws/build/realsense-ros/realsense2_camera/CMakeFiles/realsense2_camera.dir/src/realsense_node_factory.cpp.o
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:aa2a7c905e752af30b16e13412c4114c0b73c4848379d92bf532a79e3dc7f299
|
| 3 |
+
size 803520
|
camera_ws/build/realsense-ros/realsense2_camera/CMakeFiles/realsense2_camera.dir/src/t265_realsense_node.cpp.o
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:189eb3a5400ed16e4bcab1e831922471e8fc927cdc0235594120a8c3e2be9a35
|
| 3 |
+
size 461856
|
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/d2c_viewer.cpp.o
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b2aa26446f153e3aad326a6f330b067fbb42b34e88de3dc8609aad0de1610f1f
|
| 3 |
+
size 680928
|
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/ob_camera_info.cpp.o
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c188bd95821da73d09da0921b14b9e18a510f296500023b092ac22f42cf865e2
|
| 3 |
+
size 237456
|
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/ob_camera_node.cpp.o
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:583cd3770af8e1212e18b2e660a460b508c6537760c8a439a7630a6652c7ba7c
|
| 3 |
+
size 1317640
|
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/ob_camera_node_factory.cpp.o
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b7d398107f96df3449e2551b80e7f07b646935f64a5540be3ad73d1bf80cc928
|
| 3 |
+
size 266032
|
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/point_cloud_proc/point_cloud_xyz.cpp.o
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:69cbd4b7187bd4e4363f70c0d6d412a2d08e2cb75752b7bdbf9d6a655a01e4d2
|
| 3 |
+
size 258720
|
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/point_cloud_proc/point_cloud_xyzrgb.cpp.o
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:aca6aa937515cc81b5f6a8ea1770c64a00a313df60efbddce8fa68e0b31a2ab5
|
| 3 |
+
size 938608
|
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/ros_service.cpp.o
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ead048ee4c26f280065dac38206a5a910a6e2f8c409bd04b024d45f18386ce73
|
| 3 |
+
size 975208
|
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/utils.cpp.o
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:79af685dc753110ab6acf4c2f91b1de9d6d22b07ac08d75f76d0e12b8fc2cdef
|
| 3 |
+
size 120352
|
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera.dir/src/uvc_camera_driver.cpp.o
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e1be3bf2cd7b7243b156945d353a7f4b87b9c804654d0552c6c9183558d3dc73
|
| 3 |
+
size 586224
|
camera_ws/build/ros_astra_camera/CMakeFiles/astra_camera_node.dir/src/main.cpp.o
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:cab5e1b87593816f7c47df5a3ade6f8e61bd8591e770939ae65f3fbe84845685
|
| 3 |
+
size 163160
|
camera_ws/devel/lib/astra_camera/astra_camera_node
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9853d91bcfa0dd299e1e680ce58b6227154200d486514a8081e2b45c0d7dd1f4
|
| 3 |
+
size 115152
|
camera_ws/devel/lib/libastra_camera.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ba880c2c2a063ee0746bcb0f604b0cb7cc69e2cb0ca631fe01687ce38d19b119
|
| 3 |
+
size 2427240
|