Mục tiêu của bài này
Trong bài 2, chúng ta đã nói về cách thu teleoperation sao cho action đủ mượt để policy học được. Trong bài 3, raw log được giữ bằng MCAP để còn replay và audit. Trong bài 4, dataset training được đưa vào data lake LeRobot/Robo-DM.
Bài 5 đi vào một lớp rất thực dụng: synthetic data và QA bằng Isaac Lab Mimic. Mục tiêu không phải tạo dữ liệu ảo cho đẹp, mà là biến một nhóm demo teleop nhỏ thành một dataset đủ lớn để train BC/VLA, đồng thời có checklist để biết khi nào dataset nên bị loại.
Workflow chính:
record_demos.py
-> annotate_demos.py
-> generate_dataset.py
-> robomimic/train.py
-> play.py + QA report
Ta sẽ dùng ví dụ humanoid nut pouring trong Isaac Lab:
Isaac-NutPour-GR1T2-Pink-IK-Abs-v0
Isaac-NutPour-GR1T2-Pink-IK-Abs-Mimic-v0
Theo tài liệu Isaac Lab Mimic, task này có dataset 1000 demonstration được tạo từ pipeline Mimic cho robot GR1T2: robot nhặt cốc đỏ, đổ vật thể vào bát vàng, bỏ cốc vào thùng xanh, rồi đặt bát lên cân trắng. Tài liệu cũng đưa ra con số kỳ vọng: với 1000 generated demonstrations, BC visuomotor cho nut pouring thường đạt khoảng 50-60% success trên 50 rollout; với locomanipulation pick-and-place, generation success thường nằm trong khoảng 65-82% trên 1000 demonstrations, tùy chất lượng demo, annotation và GPU.
Nếu bạn mới đọc series này từ giữa chừng, nên xem thêm tổng quan software stack humanoid robot và hướng dẫn LeRobot ecosystem để hiểu vì sao synthetic dataset vẫn cần raw log và dataset versioning.
Synthetic data ở đây nghĩa là gì?
Trong Isaac Lab Mimic, synthetic data không phải là video diffusion hay render ảnh ngẫu nhiên. Nó là data generation dựa trên demo thật. Bạn thu vài demonstration thành công, chia mỗi demonstration thành các subtask, rồi để Mimic ghép, biến đổi và replay các đoạn kỹ năng đó trong các biến thể scene khác nhau.
Ví dụ với nut pouring:
| Giai đoạn | Ý nghĩa thao tác | Lý do cần QA |
|---|---|---|
| Pick red beaker | Tay tiếp cận và nắm cốc đỏ | Demo giật hoặc grasp lệch sẽ làm nhiều trial thất bại |
| Pour into yellow bowl | Nghiêng cốc để hạt/đai ốc rơi vào bát | Cần đúng object pose và timing, không chỉ đúng end-effector pose |
| Drop beaker into blue bin | Đưa cốc vào thùng và nhả | Nếu annotation kết thúc quá sớm, replay có thể chưa kích hoạt success |
| Place bowl on scale | Đặt bát vàng lên cân trắng | Lỗi nhỏ ở đoạn cuối làm cả task fail dù ba đoạn trước ổn |
Mimic không cứu được demo xấu. Nó khuếch đại demo tốt, nhưng cũng khuếch đại lỗi. Vì vậy workflow đúng là: thu nhiều hơn số demo cần, replay lại, chỉ giữ demo mượt, annotate rõ ràng, generate có thống kê, rồi train sau cùng.
Bước 1: Record 5 demo gốc
Tài liệu Isaac Lab hiện tại dùng record_demos.py để thu 5 demo cho Isaac-NutPour-GR1T2-Pink-IK-Abs-v0. Với biến thể dùng hand tracking và Pink IK, lệnh tham khảo như sau:
./isaaclab.sh -p scripts/tools/record_demos.py \
--device cpu \
--task Isaac-NutPour-GR1T2-Pink-IK-Abs-v0 \
--teleop_device handtracking \
--dataset_file ./datasets/dataset_gr1_nut_pouring.hdf5 \
--num_demos 5 \
--enable_pinocchio
Với beginner, điểm cần hiểu là task record không có hậu tố Mimic. Đây là môi trường teleop gốc. File đầu ra là HDF5 chứa trajectory, action, observation và metadata cần thiết để annotation bước sau đọc lại được.
Trước khi annotate, chạy một vòng QA nhỏ. Đừng chờ tới sau khi generate 1000 trial mới phát hiện 5 demo gốc có một demo đứng im 10 giây.
python - <<'PY'
import h5py
from pathlib import Path
path = Path("./datasets/dataset_gr1_nut_pouring.hdf5")
with h5py.File(path, "r") as f:
demos = sorted(f["data"].keys())
print("num demos:", len(demos))
for key in demos:
grp = f["data"][key]
n = grp.attrs.get("num_samples", None)
model = grp.attrs.get("model_file", None)
print(key, "samples=", n, "has_model=", model is not None)
PY
Một demo nên bị loại hoặc thu lại nếu có các dấu hiệu sau:
| Dấu hiệu | Vì sao nguy hiểm | Cách xử lý |
|---|---|---|
| Thời lượng dài bất thường | BC học cả đoạn chờ, pause và correction | Thu lại với đường đi ngắn hơn |
| Wrist pose nhảy mạnh | Pink IK có thể không bám được, action bị spike | Giảm tốc tay operator, reset anchor XR |
| Robot chạm object quá muộn | Subtask pick bị kéo dài, khó stitch | Đưa robot/scene về vị trí bắt đầu gần hơn |
| Stop recording ngay khi success vừa bật | Replay có thể không tái kích hoạt success | Giữ thêm buffer cuối episode |
| Một tay làm việc ngoài kế hoạch | Multi-EEF annotation dễ trùng index hoặc sai subtask | Thu lại demo sạch hơn |
Checklist này khớp với các pitfall Isaac Lab nêu: demo quá dài, chuyển động không mượt, pause nhiều, quá nhiều subtask, thiếu action noise, crop quá sát cuối recording và replay không hoàn toàn deterministic.
Bước 2: Annotate demo cho Mimic
Annotation là bước biến trajectory liên tục thành các đoạn có nghĩa. Với nut pouring, dùng task có hậu tố Mimic và bật camera vì đây là visuomotor task:
./isaaclab.sh -p scripts/imitation_learning/isaaclab_mimic/annotate_demos.py \
--device cpu \
--enable_cameras \
--rendering_mode balanced \
--task Isaac-NutPour-GR1T2-Pink-IK-Abs-Mimic-v0 \
--input_file ./datasets/dataset_gr1_nut_pouring.hdf5 \
--output_file ./datasets/dataset_annotated_gr1_nut_pouring.hdf5 \
--enable_pinocchio
Hai lỗi hay gặp ở bước này:
- Quên
--enable_camerasvới visuomotor task. Khi đó dataset có thể dùng được cho state-based debug nhưng không đủ input để train policy nhìn ảnh. - Gán cùng action index cho nhiều annotation của cùng right end-effector. Isaac Lab cảnh báo riêng cho nut pouring rằng task này có nhiều annotation cho right EEF, nên các subtask của cùng EEF không được dùng trùng action index.
Sau annotation, kiểm tra HDF5 theo hướng "có đủ dữ liệu để generate không", không chỉ "file có tồn tại không":
python - <<'PY'
import h5py
path = "./datasets/dataset_annotated_gr1_nut_pouring.hdf5"
with h5py.File(path, "r") as f:
for demo in sorted(f["data"].keys()):
grp = f["data"][demo]
print("\n", demo)
def walk(name, obj):
if "subtask" in name.lower() or "datagen" in name.lower():
print(" ", name, type(obj).__name__)
grp.visititems(walk)
PY
Tên group cụ thể có thể thay đổi theo version Isaac Lab, nhưng nguyên tắc không đổi: mỗi demo được chọn phải có thông tin subtask đủ cho Mimic. Nếu một demo annotate fail, hãy loại demo đó hoặc annotate lại. Đừng trộn demo "có vẻ ổn" vào source set, vì generation success sẽ giảm và bạn khó biết lỗi từ đâu.
Bước 3: Hiểu DataGenConfig và SubTaskConfig
DataGenConfig là cấu hình tổng thể cho quá trình generation. Trong source Isaac Lab, các trường quan trọng gồm:
| Trường | Ý nghĩa thực tế |
|---|---|
generation_guarantee |
Khi bật, generator sẽ retry cho đến khi đạt số trial thành công mong muốn, trong giới hạn failure |
generation_keep_failed |
Giữ trial fail để debug; hữu ích khi success rate thấp nhưng không nên dùng làm training set chính |
max_num_failures |
Ngưỡng dừng khi fail quá nhiều |
seed |
Seed để tái lập generation |
source_dataset_path |
Dataset annotated đầu vào |
generation_path |
File HDF5 generated đầu ra |
generation_num_trials |
Số trial cần tạo, ví dụ 1000 |
generation_select_src_per_subtask |
Chọn source demo theo từng subtask, cần constraint tốt |
generation_interpolate_from_last_target_pose |
Interpolate từ target pose trước đó để giảm nhảy waypoint |
use_skillgen |
Dùng skill generation nâng cao |
use_navigation_controller |
Dùng controller navigation cho locomanipulation |
SubTaskConfig là nơi chất lượng generation thường thắng hoặc thua. Một cấu hình minh họa:
from isaaclab.envs.mimic_env_cfg import DataGenConfig, SubTaskConfig, MimicEnvCfg
cfg = MimicEnvCfg()
cfg.datagen_config = DataGenConfig(
name="nut_pour_gr1t2_qa",
generation_guarantee=True,
generation_keep_failed=False,
max_num_failures=80,
seed=42,
generation_num_trials=1000,
)
cfg.subtask_configs = {
"left_hand": [
SubTaskConfig(
object_ref="red_beaker",
subtask_term_signal="left_grasp_beaker",
selection_strategy="nearest_neighbor_object",
action_noise=0.02,
num_interpolation_steps=6,
),
],
"right_hand": [
SubTaskConfig(
object_ref="yellow_bowl",
subtask_term_signal="right_support_bowl",
selection_strategy="nearest_neighbor_object",
action_noise=0.015,
num_interpolation_steps=8,
),
],
}
Đoạn trên là skeleton để đọc config, không phải lời hứa rằng tên object_ref trong task nut pouring của bạn đúng y như vậy. Khi làm thật, hãy mở env config của task để lấy đúng object key. Nguyên tắc quan trọng là:
| Tham số | Nên chỉnh khi nào | Rủi ro nếu chỉnh sai |
|---|---|---|
object_ref |
Subtask phụ thuộc pose của một vật thể cụ thể | Nếu để None, các strategy nearest-neighbor theo object không dùng được |
selection_strategy='nearest_neighbor_object' |
Scene randomize object pose và bạn muốn lấy source segment gần nhất theo object | Nếu object_ref sai, source segment được chọn không liên quan |
action_noise |
Muốn policy robust hơn với nhiễu nhỏ | Quá lớn làm robot lệch grasp/pour |
num_interpolation_steps |
Waypoint bị gãy, robot nhảy giữa subtask | Quá lớn làm motion chậm, horizon dài hơn |
subtask_term_offset_range |
Annotation kết thúc quá sát success | Offset lớn có thể ăn sang subtask tiếp theo |
Tài liệu Isaac Lab ghi rõ nearest_neighbor_object và nearest_neighbor_robot_distance cần object_ref khác None, và thường cho success tốt hơn random khi object reference được đặt đúng. Với beginner, đây là lý do không nên chỉ copy config rồi đổi task name. Bạn cần hiểu subtask nào bám vào object nào.
Bước 4: Generate 1000 trials
Khi 5 demo gốc đã qua QA và annotation sạch, chạy generation:
./isaaclab.sh -p scripts/imitation_learning/isaaclab_mimic/generate_dataset.py \
--device cpu \
--headless \
--enable_pinocchio \
--enable_cameras \
--rendering_mode balanced \
--task Isaac-NutPour-GR1T2-Pink-IK-Abs-Mimic-v0 \
--generation_num_trials 1000 \
--num_envs 5 \
--input_file ./datasets/dataset_annotated_gr1_nut_pouring.hdf5 \
--output_file ./datasets/generated_dataset_gr1_nut_pouring.hdf5
Ở bước này, metric quan trọng không chỉ là "có file 12-15GB". Bạn cần log các thông tin sau vào manifest:
task: Isaac-NutPour-GR1T2-Pink-IK-Abs-Mimic-v0
source_dataset: dataset_annotated_gr1_nut_pouring.hdf5
generated_dataset: generated_dataset_gr1_nut_pouring.hdf5
source_demos: 5
target_trials: 1000
num_envs: 5
seed: 42
enable_cameras: true
enable_pinocchio: true
qa_owner: data_supervisor_01
qa_status: pending
Sau generation, tạo QA report tối thiểu:
python - <<'PY'
import h5py
import numpy as np
path = "./datasets/generated_dataset_gr1_nut_pouring.hdf5"
lengths = []
with h5py.File(path, "r") as f:
demos = sorted(f["data"].keys())
for key in demos:
n = int(f["data"][key].attrs.get("num_samples", 0))
lengths.append(n)
print("demos:", len(lengths))
print("min/mean/max length:", min(lengths), np.mean(lengths), max(lengths))
print("p95 length:", np.percentile(lengths, 95))
PY
Nếu p95 dài gấp đôi median, dataset có thể chứa nhiều trial vòng vèo hoặc pause. Nếu số demo thấp hơn 1000 trong khi generation_guarantee đang bật, hãy đọc log failure thay vì train ngay.
Bước 5: Train BC bằng robomimic
Tài liệu Isaac Lab dùng robomimic/train.py để train visuomotor BC cho nut pouring:
./isaaclab.sh -p scripts/imitation_learning/robomimic/train.py \
--task Isaac-NutPour-GR1T2-Pink-IK-Abs-v0 \
--algo bc \
--normalize_training_actions \
--dataset ./datasets/generated_dataset_gr1_nut_pouring.hdf5
--normalize_training_actions rất quan trọng vì Isaac Lab lưu normalization params dưới thư mục log model, rồi cần truyền lại khi play.py. Nếu quên bước này, policy có thể train được nhưng rollout sai scale action.
Robomimic xem HDF5 dataset là nguồn minibatch cho thuật toán imitation/offline RL. BC là baseline supervised learning: học ánh xạ từ observation sang action. Với nut pouring, observation có ảnh camera, hand pose, joint position, object pose hoặc các trường task config cung cấp; action là target base/hand/finger tương ứng môi trường Isaac Lab.
Sau train, evaluate bằng nhiều checkpoint, không chỉ checkpoint cuối:
./isaaclab.sh -p scripts/imitation_learning/robomimic/play.py \
--task Isaac-NutPour-GR1T2-Pink-IK-Abs-v0 \
--visualizer kit \
--device cpu \
--enable_cameras \
--num_rollouts 50 \
--horizon 350 \
--norm_factor_min <NORM_FACTOR_MIN> \
--norm_factor_max <NORM_FACTOR_MAX> \
--checkpoint /PATH/TO/desired_model_checkpoint.pth
Với nut pouring, Isaac Lab khuyến nghị train 600 epoch trên 1000 generated demos và kiểm tra các checkpoint giữa epoch 300-600. Với locomanipulation, tài liệu khuyến nghị 2000 epoch và chọn checkpoint trong khoảng 1000-2000.
Bảng đối chiếu success rate
Đây là baseline để data supervisor dùng khi đọc QA report:
| Workflow | Dataset | Expected metric | Ý nghĩa |
|---|---|---|---|
| GR1T2 nut pouring visuomotor | 1000 generated demos | BC success 50-60% trên 50 rollouts | Nếu thấp hơn nhiều, kiểm tra camera, annotation và action normalization |
| G1 locomanipulation pick-and-place | 1000 generated demos | Generation success 65-82% | Nếu thấp hơn, kiểm tra demo gốc, subtask split, object_ref, interpolation |
| G1 locomanipulation BC | 1000 generated demos, 2000 epochs | BC success 75-85% trên 50 rollouts | Dùng làm mức tham chiếu, không phải SLA tuyệt đối |
Đừng dùng các con số này như cam kết sản phẩm. Chúng là điểm neo để biết pipeline của bạn có nằm trong vùng hợp lý không. Nếu nut pouring chỉ đạt 20%, lỗi thường không nằm ở "model chưa đủ lớn" mà ở data: demo giật, annotation sai action index, camera thiếu, horizon quá dài, hoặc normalization không được truyền đúng khi rollout.
QA workflow đề xuất cho data center
Trong data center humanoid VLA, tôi sẽ đặt gate như sau:
| Gate | Người chịu trách nhiệm | Điều kiện pass |
|---|---|---|
| Raw demo QA | Operator + data supervisor | Demo thành công, mượt, không pause dài, có buffer cuối |
| Annotation QA | Data supervisor | Subtask đủ, right EEF không trùng action index, replay không lỗi nghiêm trọng |
| Generation QA | Simulation engineer | Đủ số trial, success rate trong vùng kỳ vọng, length distribution không lệch |
| Training QA | ML engineer | Train không NaN, validation/rollout tăng, nhiều checkpoint được so sánh |
| Release QA | Tech lead | Manifest, config, seed, source dataset và model checkpoint được version |
Một dataset generated chỉ nên promote sang data lake training khi có manifest kiểu này:
qa_status: approved
approved_by: simulation_lead
date: 2026-06-10
source_demo_count: 5
generated_demo_count: 1000
generation_success_rate: 0.78
train_algo: robomimic_bc
rollout_count: 50
best_checkpoint_epoch: 520
rollout_success_rate: 0.56
known_limitations:
- "Fails when red beaker starts near workspace edge"
- "Sensitive to camera exposure in reflective bowl scenes"
Lợi ích của cách làm này là bài eval và scale ở phần 6 không phải đoán dataset nào đã dùng để train model nào. Khi một policy fail ngoài đời thật, bạn có đường truy ngược từ checkpoint về generated HDF5, annotated demos, raw MCAP và operator note.
Troubleshooting nhanh
| Triệu chứng | Nguyên nhân thường gặp | Cách kiểm tra |
|---|---|---|
| Generate fail liên tục | Demo gốc không replay ổn hoặc subtask quá dài | Replay demo, giảm số subtask, thu lại demo sạch |
| Trial thành công thấp dù demo đẹp | object_ref sai hoặc dùng random khi scene randomize nhiều |
Mở env config, đổi sang nearest_neighbor_object cho subtask bám object |
| Robot nhảy giữa hai đoạn | num_interpolation_steps quá thấp |
Tăng từ 5 lên 8-10 cho subtask chuyển pose lớn |
| Grasp bị lệch sau khi thêm noise | action_noise quá cao |
Giảm noise ở subtask grasp/pour, chỉ tăng ở đoạn move tự do |
| BC train xong rollout rất tệ | Quên action normalization params hoặc checkpoint cuối không tốt | Dùng normalization_params.txt, evaluate nhiều checkpoint |
| Camera observation thiếu | Quên --enable_cameras khi annotate/generate |
Inspect HDF5 keys và chạy smoke test dataloader |
Nguồn tham khảo
- Isaac Lab Mimic Teleoperation and Imitation Learning
- Isaac Lab
mimic_env_cfg.py - robomimic Getting Started
- robomimic Implemented Algorithms