LIBERO consists of 4 task suites and 130 tasks for studying LLDM. Specifically, the tasks in 3 of the 4 task suites vary only in one type of knowledge, while the last task suite requires transfer of entangled knowledge. (Copied from docs)
In this dataset, we have made several key improvements:
- OpenVLA-based LIBERO Regeneration: Resolution enhancement, No-op action filtration, 180掳 RGB frame rotation, Failed trajectory filtering.
- State Data Preservation: Maintained native LIBERO state information (accessible via
states.ee_state,states.joint_stateand etc.). - Robust Conversion Pipeline: Using the shared
generic_converterpipeline with local and Ray DataTrove executors for high-speed dataset transformation and resumable conversion.
Dataset Structure of meta/info.json:
{
"codebase_version": "v3.0", // latest lerobot format
"robot_type": "franka", // specific robot type
"fps": 20, // control frequency
"features": {
"observation.images.image": {
"dtype": "video",
"shape": [
256,
256,
3
],
"names": [
"height",
"width",
"rgb"
],
"info": {
"video.height": 256,
"video.width": 256,
"video.codec": "av1",
"video.pix_fmt": "yuv420p",
"video.is_depth_map": false,
"video.fps": 20,
"video.channels": 3,
"has_audio": false
}
},
"observation.images.wrist_image": {
"dtype": "video",
"shape": [
256,
256,
3
],
"names": [
"height",
"width",
"rgb"
],
"info": {
"video.height": 256,
"video.width": 256,
"video.codec": "av1",
"video.pix_fmt": "yuv420p",
"video.is_depth_map": false,
"video.fps": 20,
"video.channels": 3,
"has_audio": false
}
},
// for more state keys, see LiberoAdapter.features in libero_h5.py
"observation.state": {
"dtype": "float32",
"shape": [
8
],
"names": {
"motors": [
"x",
"y",
"z",
"axis_angle1",
"axis_angle2",
"axis_angle3",
"gripper",
"gripper"
]
}
},
...
"action": {
"dtype": "float32",
"shape": [
7
],
"names": {
"motors": [
"x",
"y",
"z",
"axis_angle1",
"axis_angle2",
"axis_angle3",
"gripper"
]
}
},
...
}
}-
Install LeRobot:
Follow instructions in official repo. -
Install others:
We use DataTrove for conversion. Install the Ray extra if you want distributed execution across multiple cores or nodes.pip install h5py pip install -U datatrove pip install -U "datatrove[ray]" # optional, for --executor ray
Note
This script supports converting LIBERO-style HDF5 directories to LeRobot. If you want to convert from RLDS to LeRobot, check openx2lerobot.
git clone https://github.com/Tavish9/any4lerobot.git
cd any4lerobot/libero2lerobot- Install LIBERO dependency
- Replace
libero_90with your target libero dataset. - The converter feature schema expects
256x256x3RGB observations. If your source HDF5 files are the original128x128LIBERO files, regenerate them first with--resolution 256, or update the image feature shapes inlibero_h5.pyto match your data.
python regenerate_libero_dataset.py \
--resolution 256 \
--libero_task_suite libero_90 \
--libero_raw_data_dir /path/to/libero/datasets/libero_90 \
--libero_target_dir /path/to/libero/datasets/libero_90_no_noops--src-pathsaccepts one or more directories containing*.hdf5LIBERO task files. To merge many suites into one LeRobot dataset, specify all source directories, for example--src-paths /path/libero_10 /path/libero_90.--output-pathis the final aggregated LeRobot dataset root. Temporary per-task datasets are written next to it under<output-name>_tempand removed after aggregation.- If you have installed
datatrove[ray], use--executor rayfor faster conversion. Increase--workers,--tasks-per-job, and--cpus-per-taskif you have enough CPU and memory. - To resume a previous conversion, pass the existing DataTrove log directory with
--resume-dir /path/to/logs/.... - Use
--debugfor a small local smoke test. It converts only the first two tasks, forces local execution, and disables Hub upload. - Use
--repo-id <namespace/name>together with--push-to-hubto upload the aggregated dataset. Without--push-to-hub,--repo-idonly controls the local aggregate repo id.
python libero_h5.py \
--src-paths /path/to/libero/datasets/libero_90_no_noops \
--output-path /path/to/local/libero_90_lerobot \
--executor local \
--tasks-per-job 3 \
--workers 10bash convert.shDirect Access to Nodes (2 nodes in example)
On Node 1:
ray start --head --port=6379On Node 2:
ray start --address='node_1_ip:6379'On either Node, check the ray cluster status, and start the script
ray status
bash convert.shSlurm-managed System
#!/bin/bash
#SBATCH --job-name=ray-cluster
#SBATCH --ntasks=2
#SBATCH --nodes=2
#SBATCH --partition=partition
# Getting the node names
nodes=$(scontrol show hostnames "$SLURM_JOB_NODELIST")
nodes_array=($nodes)
head_node=${nodes_array[0]}
head_node_ip=$(srun --nodes=1 --ntasks=1 -w "$head_node" hostname --ip-address)
# if we detect a space character in the head node IP, we'll
# convert it to an ipv4 address. This step is optional.
if [[ "$head_node_ip" == *" "* ]]; then
IFS=' ' read -ra ADDR <<<"$head_node_ip"
if [[ ${#ADDR[0]} -gt 16 ]]; then
head_node_ip=${ADDR[1]}
else
head_node_ip=${ADDR[0]}
fi
echo "IPV6 address detected. We split the IPV4 address as $head_node_ip"
fi
port=6379
ip_head=$head_node_ip:$port
export ip_head
echo "IP Head: $ip_head"
echo "Starting HEAD at $head_node"
srun --nodes=1 --ntasks=1 -w "$head_node" \
ray start --head \
--node-ip-address="$head_node_ip" \
--port=$port \
--block &
sleep 10
# number of nodes other than the head node
worker_num=$((SLURM_JOB_NUM_NODES - 1))
for ((i = 1; i <= worker_num; i++)); do
node_i=${nodes_array[$i]}
echo "Starting WORKER $i at $node_i"
srun --nodes=1 --ntasks=1 -w "$node_i" \
ray start \
--address "$ip_head" \
--block &
sleep 5
done
sleep 10
bash convert.shOther Community Supported Cluster Managers
See the doc for more details.