Vì sao cần ManiGuard-Bench?
Nếu bạn đã fine-tune một policy kiểu Vision-Language-Action (VLA) trên LeRobot, openpi, GR00T hoặc SmolVLA, câu hỏi đầu tiên thường là: "Tỷ lệ hoàn thành task là bao nhiêu?". Với robot manipulation thật, câu hỏi đó chưa đủ. Một rollout có thể pick đúng object nhưng làm đổ cốc bên cạnh. Robot có thể đặt lọ vào đúng vùng đích nhưng nghiêng lọ, làm rơi nắp, hoặc chạm vào vật cấm. Trong dashboard task success truyền thống, những lỗi đó dễ bị che khuất vì episode vẫn được tính là thành công.
ManiGuard giải quyết đúng khoảng trống này. Paper "MANIGUARD: A Benchmark and Data Suite for Specification-Grounded Safety Evaluation and Improvement of Robotic Manipulation" của Yiyan Peng, Philip Wang, Simon Sinong Zhan và cộng sự được công bố trên arXiv ngày 18/08/2026. Project gốc nằm ở NU-IDEAS-Lab/ManiGuard, tài liệu tại nu-ideas-lab.github.io/ManiGuard, benchmark và checkpoints nằm trên Hugging Face.
Ý tưởng quan trọng nhất: task success và safety là hai trục độc lập. Một policy chỉ được coi là thật sự tốt khi nó vừa hoàn thành mục tiêu vừa không vi phạm safety specification trong quá trình thao tác. ManiGuard-Bench vì vậy không hỏi "robot có đặt vật vào đúng chỗ không?" một cách đơn lẻ. Nó hỏi thêm: "Trong lúc làm việc đó, robot có làm đổ, làm rơi, làm tràn, nâng sai thứ tự, hoặc chạm vật không nên chạm không?".
ManiGuard-Bench đặc biệt hữu ích nếu bạn đang đọc các bài trước của vnrobo như SmolVLA trên LeRobot, GR00T N1.6 fine-tune, hoặc SafeContract cho VLA. Các bài đó tập trung vào training và runtime guardrail; ManiGuard bổ sung một lớp evaluation có specification rõ ràng, tái lập được, và áp dụng được cho nhiều VLA stack.

Paper đang đề xuất gì?
ManiGuard gồm hai phần đi cùng nhau.
Phần thứ nhất là ManiGuard-Bench, một benchmark frozen cho contact-rich household manipulation. Benchmark có 200 base tasks chia thành 6 task family: clutter_pickup, cabinet_pickup, stack_retrieve, jar_transport, lid_transport, và dusty_transfer. Mỗi base task có một phiên bản in-distribution và bốn perturbation out-of-distribution theo một trục duy nhất: target appearance, language, location, và environment. Tổng cộng paper báo cáo 1.000 locked evaluation scenarios. "Locked" ở đây quan trọng: scene, goal, object, prompt và safety spec được cố định để các model được so sánh trên cùng điều kiện.
Phần thứ hai là safety-annotated data suite. Nhóm tác giả release 8.000 demonstrations, tức 40 demonstrations cho mỗi base task. Demonstrations đến từ pipeline motion planning tự động bằng cuRobo và từ human teleoperation. Điểm mạnh là data không chỉ có ảnh, state và action; mỗi step còn được annotate bởi cùng runtime monitor dùng trong evaluation. Vì vậy data có thể dùng cho supervised fine-tuning hướng safety, không chỉ để bắt chước motion.
Điểm khác biệt của ManiGuard so với benchmark manipulation thông thường là safety được viết thành LTLf specification. LTLf là Linear Temporal Logic over finite traces, tức logic thời gian trên rollout hữu hạn. Với beginner, bạn có thể hiểu nó là cách viết ràng buộc kiểu: "luôn giữ vật đứng thẳng", "không được nâng object trước khi nắp đã đóng", hoặc "một khi đã chạm vật bẩn thì không được chạm vùng sạch". Công thức này được compile thành deterministic finite automaton (DFA). Trong mỗi simulator step, monitor đọc các predicate vật lý từ OmniGibson/Isaac Sim như touching, inside, ontop, upright, dropped, covered, rồi chuyển trạng thái automaton. Nếu automaton đi vào trạng thái violation, rollout được đánh dấu unsafe.
Đây là một lựa chọn kỹ thuật rất thực dụng. ManiGuard không dùng LLM judge để "nhìn video rồi đoán có an toàn không". Nó cũng không train classifier riêng cho safety. Verdict được tính từ simulator state và công thức formal, nên bạn có thể debug episode bằng predicate trace thay vì tranh luận với một model khác.
Kiến trúc hệ thống
Ở mức engineering, ManiGuard tách policy khỏi simulator. Simulator chạy trong môi trường behavior với BEHAVIOR-1K, OmniGibson và Isaac Sim. Policy VLA chạy trong môi trường riêng của nó: openpi dùng JAX/openpi venv, GR00T dùng Isaac-GR00T/PyTorch stack, còn SmolVLA dùng LeRobot environment. Hai bên nói chuyện qua một contract đơn giản: eval client gửi observation, policy server trả action chunk.
Observation chuẩn gồm một overview camera, một wrist camera, robot state và language prompt. Action chuẩn của benchmark là 8-D absolute joint target cho Franka Panda: 7 arm joints cộng 1 gripper command. Eval-time controller là JointController; pipeline cố tình tránh end-effector IK để collection, training và evaluation không lệch nhau. Đây là chi tiết bạn không nên bỏ qua: nếu dataset dùng joint action nhưng eval YAML lại chạy EEF action hoặc sai camera, kết quả sẽ xấu mà không báo lỗi rõ ràng.
Sơ đồ runtime có thể tóm tắt như sau:
policy server ManiGuard eval client
openpi / GR00T / SmolVLA -> load frozen scene
receive obs -> build OmniGibson env
return action chunk <- step JointController
check task success
run LTL safety monitor
write results.jsonl + summary.json
Eval client ghi raw verdict cho từng scene: success hay không, safety violation hay không, engagement signal, và các trường monitor. Vì safety được contact-gated, một policy đứng yên không được xem là "safe behavior" thật sự. Nó có thể vacuously safe vì chưa chạm object, nhưng engagement metric sẽ chỉ ra policy không tham gia task. Đây là lý do paper báo cáo thêm engaged-and-safe behavior và engagement-conditioned violation rate (EVR).

Cài đặt môi trường ManiGuard
Bạn cần một máy Linux có NVIDIA GPU, driver/Vulkan phù hợp, đủ disk cho BEHAVIOR-1K assets và benchmark scenes. ManiGuard chạy simulation khá nặng; nếu policy cũng dùng GPU lớn, tốt nhất để simulator và policy server trên hai GPU khác nhau hoặc ít nhất pin CUDA_VISIBLE_DEVICES.
Bắt đầu bằng repo gốc và submodule:
git clone --recursive https://github.com/NU-IDEAS-Lab/ManiGuard.git
cd ManiGuard
Sau đó cài BEHAVIOR-1K từ submodule. Lệnh setup này tạo conda env behavior, cài OmniGibson, BDDL, JOYLO, dataset, eval và primitives:
cd behavior-1k
./setup.sh --new-env --omnigibson --bddl --joylo --dataset --eval --primitives
cd ..
Cài ManiGuard editable trong env behavior:
conda activate behavior
pip install -e .
pip install -e ".[serve]"
Bạn còn cần robot asset riêng: Franka Panda với extended fin-ray fingers. Nếu thiếu asset này, OmniGibson có thể vẫn load stock Franka mà không crash, nhưng policy đã train trên long-finger sẽ approach object mà grasp không đúng. Theo docs, asset phải nằm tại:
behavior-1k/datasets/omnigibson-robot-assets/models/franka/franka_panda_longfinger/
Tải bằng Hugging Face CLI:
hf download IDEAS-Lab-Northwestern/franka-panda-longfinger --repo-type dataset \
--local-dir behavior-1k/datasets/omnigibson-robot-assets/models/franka/franka_panda_longfinger
Benchmark scenes có thể để eval client tự snapshot-download từ IDEAS-Lab-Northwestern/ManiGuard-Bench, hoặc bạn tải trước:
hf download IDEAS-Lab-Northwestern/ManiGuard-Bench --repo-type dataset \
--local-dir outputs/lerobot_datasets/maniguard-bench
Nếu chạy headless server, chuẩn bị thêm:
export OMNIGIBSON_HEADLESS=1
export CUDA_VISIBLE_DEVICES=0
Nếu gặp Vulkan ERROR_INCOMPATIBLE_DRIVER, kiểm tra VK_ICD_FILENAMES. Nếu gặp PhysX CUDA error hoặc OOM, giảm camera resolution trong eval config hoặc tách GPU cho simulator và policy.
Chuẩn bị data để fine-tune openpi, GR00T, SmolVLA
ManiGuard cố tình dùng một schema chung để cùng một dataset nuôi nhiều model. Mỗi sample có:
state (8,) absolute joint config: joint_0..6 + gripper
actions (8,) next-step absolute joint target + gripper
image_* 256x256x3 overview cameras + wrist camera
Scripted datagen là nguồn chính, sinh các dataset tên dạng datagen-<fam>-v1-joint-5cam. Dataset gốc có nhiều camera: image_left_shoulder, image_left, image_opposite, image_right, và wrist_image. Để benchmark công bằng, các policy thường chỉ dùng 2 camera: một overview được chọn qua external_cam và wrist camera.

Với openpi, ManiGuard không sửa source openpi. Bạn clone ManiGuard và openpi cạnh nhau, rồi ManiGuard inject train configs ở runtime qua maniguard/openpi_sft. Dataset gốc là absolute joint, nhưng config openpi chuyển 7 arm joints thành delta action nội bộ rồi reconstruct về absolute joint target ở inference. Pi0.5 dùng action horizon 16; pi0 dùng horizon 50 và warm-start từ pi0_base. Lệnh tối thiểu:
export OPENPI_ROOT=/abs/path/to/openpi
export HF_TOKEN=hf_...
export WANDB_API_KEY=...
cd ManiGuard
tools/openpi_sft/run_sft.sh \
--config pi05-base_datagen_v1_dusty_joint_2cam_lora \
--norm-stats
Với GR00T N1.6, ManiGuard khai báo Franka sim như NEW_EMBODIMENT, vẫn joint-space, vẫn 8-D state/action, và dùng one overview + wrist. Training dùng PyTorch/HF Trainer, component-freeze thay vì LoRA. Tooling nằm trong tools/gr00t_sft/: prepare_dataset.py, bake_stats.py, run_sft.sh, run_all.sh, push_to_hf.py. Một run thực tế sẽ chuẩn bị dataset view, train khoảng 2 epochs, rồi push checkpoint lên Hugging Face theo pattern gr00t-n16-datagen-v1-<fam>-joint-2cam.
Với SmolVLA, vì LeRobot lerobot-train nhận feature theo prefix chuẩn, ManiGuard cần một bước prepare dataset để đổi key: image_<external_cam> thành observation.images.top, wrist_image thành observation.images.wrist, state thành observation.state, và actions thành action. SmolVLA dùng base lerobot/smolvla_base, SmolVLM2 backbone cộng flow-matching action expert; vision encoder frozen, action expert được train. Lệnh end-to-end:
export HF_TOKEN=...
export WANDB_API_KEY=...
bash tools/smolvla_sft/run_all.sh --family clutter
# hoặc:
bash tools/smolvla_sft/run_all.sh --all
Điểm cần nhớ: external_cam, controller preset, action dimension và state mode phải giống giữa training và eval. Nếu train trên image_left nhưng eval feed image_right, policy sẽ thấy input out-of-distribution.
Chạy inference và benchmark
Quy trình benchmark có 4 bước: tải scene, serve checkpoint, chạy family, đọc summary.
Trước hết start policy server trong env tương ứng:
# openpi / pi0.5 / pi0
python -m maniguard.serve.openpi_native \
--config <train-config> \
--checkpoint <ckpt-dir>
# GR00T N1.6
python -m maniguard.serve.gr00t_native \
--checkpoint <ckpt-dir>
# SmolVLA
python -m maniguard.serve.smolvla_native \
--checkpoint <ckpt-dir>
Các server mặc định expose websocket kiểu openpi-compatible ở 0.0.0.0:8000. Sau đó, trong env behavior, chạy một family:
bash scripts/eval_family.sh jar_transport
Script này chạy cả ID và bốn OOD levels. Kết quả nằm trong:
outputs/eval_logs/jar_transport_joint/
ID/results.jsonl
ID/summary.json
OOD/target/results.jsonl
OOD/language/results.jsonl
OOD/location/results.jsonl
OOD/env/results.jsonl
Để chạy tất cả 6 family, bạn cần đổi checkpoint theo family rồi chạy:
for fam in clutter_pickup cabinet_pickup stack_retrieve jar_transport lid_transport dusty_transfer; do
bash scripts/eval_family.sh "$fam"
done
Đọc kết quả bằng:
python tools/eval_summary.py outputs/eval_logs/*_joint --full
Các metric nên đọc cùng nhau:
| Metric | Ý nghĩa |
|---|---|
| Task success | Robot đạt goal condition hay không |
| Safe success | Success và không vi phạm LTL spec |
| Unsafe success | Success nhưng có safety violation |
| Engagement | Rollout có chạm/engage task object hay không |
| EVR | Violation rate trong các rollout đã engage |
| OOD gap | Độ giảm khi đổi target, language, location, environment |
Kết quả chính từ paper
Paper benchmark zero-shot và fine-tuned VLAs trên hơn 23.000 rollouts. Kết luận đầu tiên là task success không đủ: 6-21% successful rollouts vẫn vi phạm specification. Nói cách khác, nếu dashboard của bạn chỉ xem success, bạn có thể đang deploy một policy "hoàn thành việc" nhưng gây lỗi vật lý trong quá trình làm.
Kết luận thứ hai: fine-tuning trên data suite của ManiGuard giúp đáng kể, nhưng không giải quyết hoàn toàn. Safe task completion tăng từ gần 0 lên khoảng 7,5-29,8%. Engaged-and-safe behavior tăng từ 16-40% lên 51-72%. Tuy nhiên, trong các rollout đã engage, vẫn còn 21-42% bị violation. Hai trong sáu task family vẫn dưới 2% safe success cho mọi policy. Đây là tín hiệu rất rõ rằng "thêm demonstration cùng loại" chưa đủ; cần data có cấu trúc safety, monitor tốt hơn, hoặc policy objective khác.

Kết luận thứ ba là OOD perturbation rất đáng sợ với robot manipulation. Vì ManiGuard giữ nguyên safety specification khi đổi target appearance, language, location hoặc environment, nó đo đúng thứ ta cần: policy có giữ cùng rule an toàn trong điều kiện hơi khác không? Nếu EVR tăng mạnh chỉ vì object đổi vị trí, model có thể chưa học "nguyên tắc" mà chỉ học trajectory shortcut.
Checklist cho beginner
Nếu bạn mới bắt đầu, đừng chạy toàn bộ 1.000 scenarios ngay. Hãy làm theo thứ tự nhỏ:
- Cài
behaviorenv và verify OmniGibson load được một scene. - Tải long-finger Franka asset và kiểm tra đúng path.
- Tải ManiGuard-Bench hoặc để eval tự pull từ Hugging Face.
- Chọn một family dễ đọc như
jar_transport. - Serve một checkpoint released từ Hugging Face collection trước khi tự train.
- Chạy
LEVELS="base" REPEAT=1 bash scripts/eval_family.sh jar_transportđể smoke test. - Mở
results.jsonl, tìm rollout unsafe-success và xem monitor field. - Chỉ sau khi hiểu summary, hãy mở rộng sang OOD và nhiều seeds.
Với team đang xây sản phẩm, ManiGuard nên nằm sau unit test/controller safety và trước robot thật. Nó không thay thế emergency stop, joint limits, collision checking hay runtime action guard như SafeContract. Nhưng nó cho bạn một câu trả lời chuẩn hơn: model nào hoàn thành task mà vẫn giữ safety spec?
Khi nào nên dùng ManiGuard-Bench?
Dùng ManiGuard-Bench khi bạn cần so sánh openpi, GR00T và SmolVLA trên cùng task family, cùng camera convention, cùng action controller và cùng safety specification. Dùng nó khi bạn nghi ngờ fine-tune cải thiện success nhưng làm policy táo bạo hơn, hoặc khi bạn cần biết OOD shift nào làm policy unsafe.
Không nên xem ManiGuard là proof rằng robot đã an toàn tuyệt đối. Benchmark chạy trong OmniGibson/Isaac Sim và một phần real Franka, nhưng factory cell, gripper khác, camera khác, object mesh khác và human-in-the-loop sẽ tạo risk mới. Cách dùng đúng là xem ManiGuard như một safety regression suite: mỗi lần đổi checkpoint, dataset, prompt template hoặc camera mapping, chạy lại cùng frozen scenarios và so sánh safe success, unsafe success, engagement và EVR.



