manipulationvlareinforcement-learningpi05robot-learning

EXPO-FT: RL Online Cho VLA π0.5

Hướng dẫn EXPO-FT mã nguồn mở: fine-tune VLA π0.5 bằng RL online với chỉ 19.1 phút dữ liệu robot thật.

Nguyễn Anh Tuấn4 tháng 6, 202615 phút đọcCập nhật: 13 thg 6, 2026
EXPO-FT: RL Online Cho VLA π0.5

EXPO-FT giải quyết vấn đề gì?

EXPO-FT là hệ thống fine-tuning bằng online reinforcement learning cho Vision-Language-Action model, được Perry Dong, Kuo-Han Hung, Tian Gao, Dorsa Sadigh và Chelsea Finn công bố trong paper EXPO-FT: Sample-Efficient Reinforcement Learning Finetuning for Vision-Language-Action Models. Điểm gây chú ý là kết quả: trên 8 task manipulation thật, hệ thống đạt 30/30 success cho mọi task, với trung bình 19.1 phút online robot data. Code được mở tại repo pd-perry/expo-ft, project page có video rollout và visualization tại pd-perry.github.io/expo-ft.

Vấn đề thực tế phía sau con số này rất quen thuộc. VLA như π0.5 có prior rất mạnh: nhìn ảnh, đọc instruction, sinh action chunk cho robot. Nhưng "làm được vài lần" chưa đủ cho deployment. Một robot trong lab có thể thành công 60-80%, nhưng nhà máy, kho hàng hoặc hệ thống dịch vụ cần mức tin cậy gần 95-99% tùy task. Nếu chỉ thu thêm demonstration rồi supervised fine-tuning, model thường học tốt các tình huống giống demo, nhưng vẫn dễ lỗi khi object lệch vị trí, contact hơi khác, hoặc thao tác cần force/timing chính xác. Nếu train RL từ đầu, policy có thể học reward, nhưng mất nhiều data robot thật và không tận dụng được prior ngữ nghĩa của VLA.

EXPO-FT nằm ở giữa hai hướng đó:

Pretrained π0.5
    ↓
Task demos nhỏ bằng teleoperation
    ↓
SFT để policy đạt mức khởi động khoảng 40%+
    ↓
Online RL trên robot thật
    ↓
Edit policy + Q-guided sampling + human interventions
    ↓
Reliable policy: 30/30 evaluation trials

Ý tưởng cốt lõi không phải là "backprop RL trực tiếp qua toàn bộ VLA ở mọi bước". EXPO-FT giữ VLA làm base policy, thêm một edit policy nhỏ để sửa residual trên action chunk, học một Q-function để chọn action chunk tốt nhất, rồi tiếp tục distill/finetune base VLA bằng objective gốc. Nhờ vậy hệ thống vừa bám prior đã học từ π0.5, vừa dùng reward thật để cải thiện những lỗi nhỏ nhưng quan trọng.

Bối cảnh: vì sao RL trên VLA khó?

VLA hiện đại không giống policy Gaussian cổ điển trong SAC/PPO. π0/π0.5 dùng flow-matching/action-chunking style: model sinh một chuỗi hành động liên tiếp thay vì một action đơn. Điều này rất hợp lý cho robot, vì một command "insert flower into bottle" cần nhiều bước liên tục và mượt. Nhưng với RL, nó tạo ra ba khó khăn.

Thứ nhất, nhiều thuật toán RL cần log probability của action. Với diffusion hoặc flow policy, log-likelihood không luôn dễ tính hoặc rẻ để tính trong online loop. Thứ hai, action chunk có chiều lớn: nếu mỗi chunk chứa 8 bước, mỗi bước gồm Cartesian velocity và gripper command, action space hiệu dụng lớn hơn nhiều so với single-step control. Thứ ba, robot thật có latency và safety constraint. Mỗi lần rollout không chỉ là một sample trong simulator; đó là thời gian thật, có nguy cơ va chạm, có reset, có camera, có operator.

EXPO-FT dựa trên thuật toán EXPO trước đó, vốn được thiết kế cho policy biểu đạt mạnh như diffusion/flow. Trong paper, nhóm tác giả mở rộng EXPO cho temporally extended actions và thêm human-in-the-loop interventions. Bài này tập trung vào cách đọc hệ thống đó như một pipeline thực hành: bạn cần chuẩn bị gì, chạy bước nào, và nên hiểu kết quả ra sao.

Kiến trúc hệ thống

Repo EXPO-FT chia hệ thống thành hai phía:

GPU server / learner
  - train_pi_robo.py
  - train_pi_robo_async.py
  - eval_droid_policy.py
  - π0.5 wrapper qua modified OpenPI
  - replay buffer, critic, edit actor, checkpoint
          ↑ WebSocket
          ↓
Robot client / actor
  - client/run_client.py
  - DROID robot environment
  - camera side view + wrist view
  - SpaceMouse intervention
  - success detector

Thiết kế server-client rất thực dụng. Learner cần GPU mạnh để chạy π0.5, critic và update. Actor cần gần robot, camera, DROID SDK và input device cho teleoperation. Hai bên nói chuyện qua WebSocket. Nếu GPU server và robot laptop không cùng máy, repo hỗ trợ SSH reverse tunnel để server kết nối tới client qua localhost:8102.

Ở mức model, EXPO-FT có bốn thành phần chính:

Thành phần Vai trò Vì sao cần
Base VLA π0.5 Sinh action chunks từ ảnh, state và instruction Mang prior ngữ nghĩa và manipulation từ pretraining
Edit policy Dự đoán residual correction cho action chunk Sửa hành vi mà không phá prior của VLA
Q ensemble Ước lượng giá trị của action chunk Chọn candidate có khả năng thành công cao nhất
Replay buffer Lưu demo, rollout, intervention Cho off-policy RL sample-efficient

Trong appendix của paper, implementation cụ thể dùng RedQ-style ensemble 10 Q-networks, chọn ngẫu nhiên 2 Q để lấy minimum khi tạo target nhằm giảm overestimation. Mỗi decision, base model sample 8 action chunks; edit policy tạo thêm 8 edited chunks; tổng cộng 16 candidate được đưa qua Q-function và hệ thống execute candidate có Q cao nhất. Critic dùng ResNet-50 nhẹ hơn thay vì dùng lại visual encoder lớn của VLA, vì online loop cần latency thấp.

Sơ đồ luồng action:

Observation:
  side RGB 224x224
  wrist RGB 224x224
  robot proprioception
  language instruction

π0.5 base policy
  ├─ sample 8 base action chunks
  └─ mỗi chunk gồm nhiều action bước ngắn

Edit actor
  └─ thêm residual edit vào từng chunk

Candidate set
  ├─ 8 base chunks
  └─ 8 edited chunks

Q ensemble
  └─ chọn chunk có Q-value cao nhất

Robot
  └─ execute 4 hoặc 8 bước rồi replan

Điểm hay là edit không cần "phát minh lại" toàn bộ action. Nó chỉ cần học các correction nhỏ như thấp thêm vài cm, xoay gripper một chút, đánh pool mạnh hơn, hoặc chỉnh hướng stem trước khi insert. Với task precision, các correction nhỏ này quyết định thành công.

Dữ liệu đầu vào: không phải chỉ 19 phút từ con số 0

Cần đọc kỹ claim 19.1 phút. Đây là online robot data dùng trong RL phase, không có nghĩa bạn bật robot rỗng và không cần demo. Trong setup của paper, nếu pretrained VLA chưa đạt zero-shot đủ tốt, nhóm tác giả thu một tập demonstration nhỏ bằng teleoperation, SFT π0.5 trước, rồi mới online RL. Ví dụ appendix ghi các task có số demo pre-collect khác nhau: Candy Scoop 10 demos, Cube Pick 10 demos, Flower Insert 25 demos, Pool Shot 30 demos. Sau SFT, policy khởi động chưa hoàn hảo nhưng đủ để RL có tín hiệu.

Quy trình beginner nên hiểu như sau:

  1. Nếu π0.5 zero-shot làm task của bạn trên robot đạt mức chấp nhận được, bạn có thể dùng nó làm base cho RL.
  2. Nếu không, thu demo thành công bằng teleoperation.
  3. Convert data sang LeRobot format.
  4. Compute normalization stats cho robot/action space.
  5. SFT π0.5 bằng LoRA/task checkpoint.
  6. Chạy EXPO-FT online, cho phép operator can thiệp ở trạng thái dễ fail.
  7. Evaluate bằng 30 trial hoặc số trial đủ nghiêm túc cho use case.

Điểm quan trọng là reward trong paper chủ yếu là sparse binary reward: thành công thì 1, chưa thành công thì 0. Nhóm tác giả tránh reward shaping phức tạp bằng success detector rule-based cho từng task. Ví dụ Candy Scoop kiểm tra kẹo trong muỗng, độ cao, và số pixel màu trong vùng target; Pool Shot kiểm tra bóng đen vào lỗ, bi trắng không rơi lỗ, cue stick không chạm trực tiếp bóng đen. Success detector đạt trên 95% accuracy và evaluation cuối cùng do người quan sát xác nhận.

Cài đặt repo EXPO-FT

Repo có hai Python environment độc lập. Đây là chi tiết dễ sai nếu bạn mới bắt đầu.

# Cần Python 3.11+ và uv
curl -LsSf https://astral.sh/uv/install.sh | sh

# Clone repo chính và hai fork phụ theo README
git clone https://github.com/pd-perry/expo-ft.git
cd expo-ft
git clone -b expo_ft https://github.com/pd-perry/openpi.git expo_ft/agents/vla/openpi
git clone https://github.com/pd-perry/droid.git client/droid

Server environment nằm ở root:

# Server / learner
uv sync

Client environment nằm trong client/:

# Client / actor
cd client
uv sync
cd ..

# Nếu dùng ZED camera
bash client/install_pyzed.sh

Bạn cần cấu hình phần cứng trước khi chạy thật. Trong DROID fork, chỉnh client/droid/droid/misc/parameters.py cho nuc_ip. Trong task config như configs/task/real_base.py hoặc configs/task/pick.py, chỉnh side_camera_id, wrist_camera_id, reset joints, workspace bounds và language instruction. Trên NUC điều khiển robot, DROID cần đúng robot_type, robot_serial_number, robot_ip và Polymetis/hardware config.

Với beginner, hãy chạy theo task pick có sẵn trước. README nói rõ chỉ scripts/pick/ được wire đầy đủ như example. Với task mới, copy folder script này rồi thay path, task config, dataset id và checkpoint.

Tạo task mới

Một task EXPO-FT tối thiểu có ba phần:

client/envs/droid_env.py
  - reset()
  - step(action)
  - observation gồm image + proprio
  - detect() gọi success detector

configs/task/my_task.py
  - language instruction
  - camera ids
  - action bounds
  - reset pose
  - episode horizon

client/real_utils/detector.py
  - rule-based hoặc learned binary success detector

Ví dụ task "insert cable" có thể dùng detector rule-based từ pose connector, trạng thái đèn, hoặc pixel threshold vùng LED. Task "pick cube" có thể dùng gripper height và object visibility. Task "scoop candy" cần detector thị giác phức tạp hơn. Đừng cố viết reward dense ngay từ đầu nếu bạn chưa kiểm soát được detector binary; sparse reward dễ debug hơn vì nó buộc bạn xác định rõ điều kiện "done".

Checklist trước khi thu data:

Hạng mục Câu hỏi kiểm tra
Camera Side và wrist view có thấy vùng thao tác không?
Action scale Cartesian velocity có quá lớn hoặc quá nhỏ không?
Reset Robot có trở lại trạng thái an toàn sau mỗi episode không?
Detector Success detector có ít false positive không?
Intervention SpaceMouse có override policy mượt không?
Network Server có kết nối được client port không?

Thu demo và convert sang LeRobot

Trên NUC, chạy DROID server:

# On the NUC
python scripts/server/run_server.py

Trên robot client/laptop, thu demonstration:

# On the client / robot machine
bash scripts/${TASK_NAME}/collect_data.sh

Các tham số cần chỉnh trong script:

--save_root      # nơi lưu raw episodes
--num_episodes   # số demonstration cần thu
--task_config    # task config đúng với robot

Sau khi có raw data, convert sang LeRobot format trên server/GPU machine:

bash scripts/${TASK_NAME}/convert_data.sh

Bạn cần chỉnh MAX_EPISODES, TASK_CONFIG, DATA_DIRREPO_NAME. Nếu client và server là hai filesystem khác nhau, copy hoặc sync data sang server trước khi convert, compute norm stats, SFT và RL. Đây không phải chi tiết phụ: nhiều lỗi training thực tế đến từ path dataset không khớp giữa máy robot và máy GPU.

SFT π0.5 trước khi RL

Trước EXPO-FT, bạn cần supervised fine-tuning. Repo gọi script OpenPI trong fork đã chỉnh:

# Tính normalization stats lần đầu cho task
bash scripts/${TASK_NAME}/calculate_norm.sh

# Fine-tune π0.5 bằng LoRA/SFT
bash scripts/${TASK_NAME}/finetune_droid.sh

Trong example pick, finetune_droid.sh chạy khoảng 4001 train steps và save mỗi 2000 steps:

uv run expo_ft/agents/vla/openpi/scripts/train.py \
  expo_pi05_droid_lora_finetune_sft_cartesian_state \
  --exp-name="${DATA_ID}_lora_sft" \
  --resume \
  --data.repo_id="$REPO_ID" \
  --data.assets.assets_dir="$ASSETS_DIR" \
  --data.assets.asset_id="$ASSET_ID" \
  --num_train_steps=4001 \
  --save_interval=2000 \
  --fsdp_devices=1

Mục tiêu của SFT không nhất thiết là 100%. Paper mô tả nếu zero-shot chưa đủ tốt, nhóm tác giả dùng demo để đưa policy lên khoảng 40% success trở lên, sau đó để RL cải thiện. Đây là mindset quan trọng: SFT tạo policy đủ an toàn và có hướng; RL tối ưu reliability.

Chạy EXPO-FT online

Khởi động DROID server trên NUC:

python scripts/server/run_server.py

Khởi động rollout client:

bash scripts/${TASK_NAME}/run_policy.sh

Nếu server và client khác máy:

bash scripts/set_server.sh <server-hostname> 8102 <your-username>

Sau đó chạy learner trên GPU server:

# Synchronous
bash scripts/${TASK_NAME}/run_server.sh

# Asynchronous, cần ít nhất 2 GPU
bash scripts/${TASK_NAME}/run_server_async.sh

Example run_server.sh cho pick cho thấy các tham số quan trọng:

python train_pi_robo.py \
  --config_task=configs/task/pick.py \
  --dataset_path=./data/pick_cube_balance/success \
  --num_data=10 \
  --update_type=episode \
  --num_updates=3 \
  --offline_ratio=0 \
  --config=configs/model/expo_ft_pi_config.py \
  --config.N=8 \
  --config.n_edit_samples=8 \
  --config.edit_scale=0.2 \
  --config.pi05_weight_loader_path="./checkpoints/.../params" \
  --config.pi05_assets_dir="./assets/expo_pi05_droid_lora_finetune_sft_cartesian_state" \
  --config.pi05_asset_id="expo_ft/droid_pick_cube_10" \
  --client_host=localhost \
  --client_port=8102 \
  --checkpoint_model \
  --checkpoint_buffer

N=8 nghĩa là sample 8 base chunks. n_edit_samples=8 tạo 8 edited chunks. edit_scale=0.2 là mức residual edit khởi đầu tốt theo README, nhưng task precision có thể cần nhỏ hơn. update_type=episode an toàn hơn cho robot vì update sau episode; update per step có thể sample-efficient hơn nếu compute đủ và safety loop ổn.

Human-in-the-loop hoạt động theo kiểu operator quan sát robot. Khi thấy robot sắp fail, operator dùng SpaceMouse override action trong một hoặc nhiều timestep của action chunk. Các action đã sửa được ghi vào replay buffer. Trong paper, intervention rate cao ở đầu training và giảm dần về 0 khi policy học ổn. Đây là tín hiệu tốt: nếu sau nhiều episode intervention vẫn cao, có thể reward detector sai, action scale sai, SFT checkpoint yếu, hoặc initial randomization quá rộng.

Inference và evaluation

Sau training, chạy evaluation với cùng DROID server và client rollout server:

bash scripts/${TASK_NAME}/eval_policy.sh

Evaluation cần khớp cấu hình với training: task config, checkpoint, assets/norm stats, edit_scale, replan steps và camera setup. Trong paper, mỗi task được đánh giá 30 trials, initial state randomization bằng scripted motion hoặc human reset, và success cuối cùng do người quan sát xác nhận. Bạn nên giữ quy tắc này: đừng chỉ quay một video thành công. Hãy report số trial, randomization range, online data minutes và failure mode còn lại.

Một template log nên có:

Task: cable insertion
Base π0.5 zero-shot: 6/30
SFT after 20 demos: 14/30
EXPO-FT online data: 22 minutes
Final eval: 29/30
Intervention rate: 35% early → 0% final
Main failure: connector yaw > 20 degrees

Kết quả paper

EXPO-FT được test trên 8 real-world manipulation tasks: Egg Flip, String Light Routing Route I, Route II, Insert, Candy Scoop, Cube Pick, Flower Insert và Pool Shot. Các task này bao phủ contact-rich manipulation, precision insertion, deformable/flexible object, dynamic striking và scene randomization lớn.

Task Online data SFT HG-DAgger EXPO-FT
Egg Flip 18 min 16/30 18/30 30/30
String Light Route I 18 min 23/30 18/30 30/30
String Light Route II 35 min 21/30 25/30 30/30
String Light Insert 16 min 23/30 24/30 30/30
Candy Scoop 20 min 22/30 28/30 30/30
Cube Pick 14 min 22/30 26/30 30/30
Flower Insert 14 min 14/30 24/30 30/30
Pool Shot 18 min 23/30 14/30 30/30
Average 19.1 min 20.5/30 22.1/30 30/30

Trên subset 4 task, paper cũng so sánh với DSRL và HIL-SERL. EXPO-FT đạt 30/30 trung bình; DSRL khoảng 19/30; HIL-SERL trong budget chuẩn chỉ khoảng 5.5/30, dù bản thêm sample đạt tốt hơn ở một số task. Diễn giải hợp lý là: HIL-SERL mạnh khi train policy nhỏ từ đầu trong setup phù hợp, nhưng ở task có initial-state distribution rộng hoặc cần prior thị giác/ngữ nghĩa lớn, VLA initialization giúp nhiều. DSRL tận dụng pretrained policy nhưng bị giới hạn trong mode của prior, khó học behavior mới nếu offline data chưa phủ đủ.

Khi nào nên dùng EXPO-FT?

EXPO-FT phù hợp khi bạn có robot thật, camera, teleoperation, một task manipulation có success detector rõ, và bạn cần tăng reliability từ mức "khá ổn" lên gần deployment. Nó không phải lựa chọn đầu tiên nếu bạn chưa có robot stack ổn định, chưa calibrate camera, hoặc task còn mơ hồ đến mức không định nghĩa được success.

Nên dùng:

Tình huống Vì sao hợp
SFT đã làm được 40-80% nhưng hay fail edge case RL tối ưu trực tiếp reward thành công
Task cần precision/contact/dynamic action Q-guided edit học correction nhỏ
Demo đắt nhưng online robot time có thể kiểm soát Off-policy replay giúp sample-efficient
Có operator can thiệp an toàn Human intervention giảm exploration vô ích

Chưa nên dùng:

Tình huống Rủi ro
Reward detector nhiều false positive Policy sẽ học "hack" detector
Camera không ổn định Critic và VLA nhận observation nhiễu
Reset thủ công quá lâu 19 phút online data có thể thành nhiều giờ wall-clock
Action bounds chưa an toàn RL có thể thử correction nguy hiểm

Kết luận

EXPO-FT là một bước quan trọng vì nó biến VLA từ "generalist policy biết làm nhiều thứ" thành "policy có thể được post-train để đáng tin hơn trên robot thật". Công thức của nó khá rõ: SFT π0.5 bằng một ít demo, chạy online off-policy RL với edit residual, dùng Q ensemble để chọn action chunk, cho phép human intervention, và đánh giá bằng trial count nghiêm túc.

Điểm đáng học nhất không chỉ là con số 19.1 phút. Đó là cách hệ thống kết hợp ba nguồn tín hiệu: prior lớn của π0.5, reward thật từ task, và correction của con người đúng lúc policy sắp sai. Với robotics, đây là hướng thực dụng: không bỏ pretraining, không phụ thuộc hoàn toàn vào imitation, và không bắt robot học từ con số 0.

Nguồn tham khảo

Bài viết liên quan

NT

Nguyễn Anh Tuấn

Robotics & AI Engineer. Building VnRobo — sharing knowledge about robot learning, VLA models, and automation.

Khám phá VnRobo

Bài viết liên quan

Chạy FineVLA cho robot dual-arm
manipulation

Chạy FineVLA cho robot dual-arm

5/6/202613 phút đọc
NT
UMI là gì? Cách thu data VLA cho robot mà không cần teleop
manipulation

UMI là gì? Cách thu data VLA cho robot mà không cần teleop

25/5/20268 phút đọc
NT
AffordanceVLA: VLA hiểu affordance
manipulation

AffordanceVLA: VLA hiểu affordance

6/6/202612 phút đọc
NT