Publish completed ant QwenOFT H1 mean-profile 5000-update run
Browse files- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/README.md +8 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/checkpoints/model.pt +3 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/collection_quality_report.json +14 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/config.full.yaml +438 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/config.yaml +45 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/dataset_statistics.json +254 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/dataset_statistics_eval.json +254 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/files.sha256.json +110 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/latency_prompt_map.json +7 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/launch_audit.json +41 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/manifest.json +232 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/profile.source.json +66 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/provenance.json +147 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/startup_verified.json +67 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/summary.jsonl +10 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/task_contract.json +94 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/QWen3.py +444 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/QwenOFT.py +1244 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/datasets.py +0 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/doom-mean-reset.patch +192 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/gym-language-contract.patch +17 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/loader-spawn-cache.patch +18 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/loader-spawn-test.patch +31 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/mean-profile-preparation.patch +147 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/train_starvla.py +0 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/trainer_tools.py +736 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/worker_context.py +77 -0
- latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training_results.json +46 -0
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/README.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ant QwenOFT H1 mean-profile VLA
|
| 2 |
+
|
| 3 |
+
Training complete:5000 optimizer updates, seed42, globalbatch128, microbatch64 perGPU, accumulation1, gradientcheckpointingTrue, BF16/ZeRO2. Hardware:2 RTX PRO6000 Blackwell GPUs. Fixed mean90.56460638563993ms uses originalRTX3090 profile; all actual science/runtime settings and user-authorized throughput changes are recorded in config.full.yaml/launch_audit.json. Horizon1, native state/action dimensions27/8.
|
| 4 |
+
|
| 5 |
+
Puretensor weights checkCPUweights_only/allfinite passed. Portable inferenceconfig, normalization/statistics, taskcontract, sourcecode/profile/data provenance included. Full optimizer recovery remains local. Finalofflinevalidation loss0.018865827471017838; this is not closed-loop task-performance acceptance. Latency-bench evaluation pending until all four models finish.
|
| 6 |
+
|
| 7 |
+
Dataset:https://huggingface.co/datasets/latency-sensitive-bench/Standard-Pipeline/tree/6246ccc57caf32da0e02547c3e3e1080894d4035/ant/profile_latency/OpenVLA/mean_rtx3090_s2222_100ep_v1
|
| 8 |
+
Training:https://wandb.ai/dongqianyu99-zhejiang-university/latency-sensitive-bench/runs/mean3090-ant-vla-blackwell-20260930
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/checkpoints/model.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:afb954569065450b9b80a86ca96e3898e3fe8d2f8c38a06f63bf3b11c41163b3
|
| 3 |
+
size 9785070315
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/collection_quality_report.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"task": "ant",
|
| 3 |
+
"teacher_checkpoint": "/home/ubuntu/lzj/mean-profiling/ant/teacher-publication/checkpoint.pth",
|
| 4 |
+
"teacher_sha256": "a7899b32beb9b2cfec1bcff85b285dddc243a73f1c322fafefae599df0f67b3b",
|
| 5 |
+
"episodes": 100,
|
| 6 |
+
"train_episodes": 90,
|
| 7 |
+
"val_episodes": 10,
|
| 8 |
+
"train_rows": 90000,
|
| 9 |
+
"val_rows": 10000,
|
| 10 |
+
"fixed_latency_ms": 90.56460638563993,
|
| 11 |
+
"action_horizon": 1,
|
| 12 |
+
"unique_seeds": 100,
|
| 13 |
+
"state_dim": 27
|
| 14 |
+
}
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/config.full.yaml
ADDED
|
@@ -0,0 +1,438 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
framework:
|
| 2 |
+
name: QwenOFT
|
| 3 |
+
qwenvl:
|
| 4 |
+
base_vlm: /home/ubuntu/lzj/models/Qwen3-VL-4B-Instruct
|
| 5 |
+
attn_implementation: flash_attention_2
|
| 6 |
+
enable_gradient_checkpointing: true
|
| 7 |
+
action_model:
|
| 8 |
+
action_model_type: MLP
|
| 9 |
+
action_dim: 8
|
| 10 |
+
state_dim: 27
|
| 11 |
+
action_hidden_dim: 2560
|
| 12 |
+
future_action_window_size: 0
|
| 13 |
+
past_action_window_size: 0
|
| 14 |
+
loss_type: l1
|
| 15 |
+
state_encoding: discretized_text
|
| 16 |
+
task_objective: null
|
| 17 |
+
action_horizon: 1
|
| 18 |
+
action_env_dim: 8
|
| 19 |
+
kv_memory:
|
| 20 |
+
enabled: false
|
| 21 |
+
window: 4
|
| 22 |
+
rollout_len: 8
|
| 23 |
+
packed_train: false
|
| 24 |
+
rebased_sink: true
|
| 25 |
+
datasets:
|
| 26 |
+
vla_data:
|
| 27 |
+
dataset_py: lerobot_datasets
|
| 28 |
+
include_state: true
|
| 29 |
+
data_root_dir: /home/ubuntu/lzj/mean-profiling/ant/data
|
| 30 |
+
data_mix: lerobot
|
| 31 |
+
eval_data_mix: lerobot__val
|
| 32 |
+
custom_mixtures_path: /home/ubuntu/lzj/mean-profiling/ant/data/_generated_mixtures/lerobot.json
|
| 33 |
+
action_type: discrete
|
| 34 |
+
sequential_step_sampling: false
|
| 35 |
+
eval_sequential_step_sampling: null
|
| 36 |
+
num_workers: 2
|
| 37 |
+
eval_num_workers: 2
|
| 38 |
+
prefetch_factor: 4
|
| 39 |
+
persistent_workers: true
|
| 40 |
+
pin_memory: true
|
| 41 |
+
shuffle: true
|
| 42 |
+
action_balance:
|
| 43 |
+
enabled: false
|
| 44 |
+
strategy: balanced_epoch
|
| 45 |
+
action_key: action_id
|
| 46 |
+
target_flap_fraction: 0.3
|
| 47 |
+
noop_id: 0
|
| 48 |
+
flap_id: 1
|
| 49 |
+
latency_curriculum:
|
| 50 |
+
enabled: false
|
| 51 |
+
strategy: exclusive
|
| 52 |
+
latencies: null
|
| 53 |
+
phase_steps: null
|
| 54 |
+
phase_distributions: null
|
| 55 |
+
new_latency_passes: 1.0
|
| 56 |
+
replay_passes: 0.25
|
| 57 |
+
target_total_passes: 2.0
|
| 58 |
+
final_equalization: true
|
| 59 |
+
step_budget_mode: auto
|
| 60 |
+
eval_at_phase_end: false
|
| 61 |
+
save_at_phase_end: false
|
| 62 |
+
computed_plan: null
|
| 63 |
+
per_device_batch_size: 64
|
| 64 |
+
load_all_data_for_training: true
|
| 65 |
+
num_obs_frames: 1
|
| 66 |
+
image_mode: single
|
| 67 |
+
prompt_mode: raw
|
| 68 |
+
stitch_grid:
|
| 69 |
+
- 2
|
| 70 |
+
- 2
|
| 71 |
+
obs_image_size: null
|
| 72 |
+
video_backend: torchvision_av
|
| 73 |
+
gymnasium_task_contract:
|
| 74 |
+
action_space:
|
| 75 |
+
dtype: float32
|
| 76 |
+
high:
|
| 77 |
+
- 1.0
|
| 78 |
+
- 1.0
|
| 79 |
+
- 1.0
|
| 80 |
+
- 1.0
|
| 81 |
+
- 1.0
|
| 82 |
+
- 1.0
|
| 83 |
+
- 1.0
|
| 84 |
+
- 1.0
|
| 85 |
+
labels:
|
| 86 |
+
- back_right_hip_torque
|
| 87 |
+
- back_right_ankle_torque
|
| 88 |
+
- front_left_hip_torque
|
| 89 |
+
- front_left_ankle_torque
|
| 90 |
+
- front_right_hip_torque
|
| 91 |
+
- front_right_ankle_torque
|
| 92 |
+
- back_left_hip_torque
|
| 93 |
+
- back_left_ankle_torque
|
| 94 |
+
low:
|
| 95 |
+
- -1.0
|
| 96 |
+
- -1.0
|
| 97 |
+
- -1.0
|
| 98 |
+
- -1.0
|
| 99 |
+
- -1.0
|
| 100 |
+
- -1.0
|
| 101 |
+
- -1.0
|
| 102 |
+
- -1.0
|
| 103 |
+
type: box
|
| 104 |
+
base_prompt: Make the Ant move forward as fast as possible without falling.
|
| 105 |
+
Predict eight continuous torques in [-1, 1] ordered as back right hip, back
|
| 106 |
+
right ankle, front left hip, front left ankle, front right hip, front right
|
| 107 |
+
ankle, back left hip, and back left ankle.
|
| 108 |
+
env_fps: 10.0
|
| 109 |
+
env_id: LatencyBench/AntContinuous-v0
|
| 110 |
+
frame_stack: 1
|
| 111 |
+
make_kwargs:
|
| 112 |
+
base_env_id: Ant-v4
|
| 113 |
+
base_make_kwargs:
|
| 114 |
+
exclude_current_positions_from_observation: true
|
| 115 |
+
use_contact_forces: false
|
| 116 |
+
render_mode: rgb_array
|
| 117 |
+
noop_action:
|
| 118 |
+
- 0.0
|
| 119 |
+
- 0.0
|
| 120 |
+
- 0.0
|
| 121 |
+
- 0.0
|
| 122 |
+
- 0.0
|
| 123 |
+
- 0.0
|
| 124 |
+
- 0.0
|
| 125 |
+
- 0.0
|
| 126 |
+
obs_fps: 10.0
|
| 127 |
+
registration_imports:
|
| 128 |
+
- latency_bench.envs.gymnasium_ant
|
| 129 |
+
state_space:
|
| 130 |
+
labels:
|
| 131 |
+
- torso_z
|
| 132 |
+
- torso_quaternion_w
|
| 133 |
+
- torso_quaternion_x
|
| 134 |
+
- torso_quaternion_y
|
| 135 |
+
- torso_quaternion_z
|
| 136 |
+
- front_left_hip_angle
|
| 137 |
+
- front_left_ankle_angle
|
| 138 |
+
- front_right_hip_angle
|
| 139 |
+
- front_right_ankle_angle
|
| 140 |
+
- back_left_hip_angle
|
| 141 |
+
- back_left_ankle_angle
|
| 142 |
+
- back_right_hip_angle
|
| 143 |
+
- back_right_ankle_angle
|
| 144 |
+
- torso_x_velocity
|
| 145 |
+
- torso_y_velocity
|
| 146 |
+
- torso_z_velocity
|
| 147 |
+
- torso_angular_velocity_x
|
| 148 |
+
- torso_angular_velocity_y
|
| 149 |
+
- torso_angular_velocity_z
|
| 150 |
+
- front_left_hip_angular_velocity
|
| 151 |
+
- front_left_ankle_angular_velocity
|
| 152 |
+
- front_right_hip_angular_velocity
|
| 153 |
+
- front_right_ankle_angular_velocity
|
| 154 |
+
- back_left_hip_angular_velocity
|
| 155 |
+
- back_left_ankle_angular_velocity
|
| 156 |
+
- back_right_hip_angular_velocity
|
| 157 |
+
- back_right_ankle_angular_velocity
|
| 158 |
+
task_name: ant_rgb_state
|
| 159 |
+
active_action_dim: 8
|
| 160 |
+
dataset:
|
| 161 |
+
source_hf: ''
|
| 162 |
+
config_name: null
|
| 163 |
+
source_subdir: null
|
| 164 |
+
converted_name: ant_rgb_state_profile_20260911T112232Z
|
| 165 |
+
single_source_hf: ''
|
| 166 |
+
mixed_source_hf: ''
|
| 167 |
+
single_converted_name: ant_rgb_state_profile_20260911T112232Z
|
| 168 |
+
mixed_converted_name: ant_rgb_state_profile_20260911T112232Z
|
| 169 |
+
single_latency_filter: null
|
| 170 |
+
mixed_latency_filter: null
|
| 171 |
+
force_download: false
|
| 172 |
+
setup_force: false
|
| 173 |
+
skip_verification: false
|
| 174 |
+
target_latency_unit: observation_steps
|
| 175 |
+
verify_rows: 200
|
| 176 |
+
max_episodes: null
|
| 177 |
+
episodes_per_latency: null
|
| 178 |
+
latency_filter: null
|
| 179 |
+
debug_subset:
|
| 180 |
+
enabled: false
|
| 181 |
+
max_episodes: 5
|
| 182 |
+
suffix: debug
|
| 183 |
+
base_model:
|
| 184 |
+
repo_id: StarVLA/Qwen3-VL-4B-Instruct-Action
|
| 185 |
+
initialization:
|
| 186 |
+
checkpoint_local_dir: null
|
| 187 |
+
checkpoint_hf_repo_id: null
|
| 188 |
+
checkpoint_filename: null
|
| 189 |
+
trainer:
|
| 190 |
+
max_train_steps: 5000
|
| 191 |
+
num_warmup_steps: 100
|
| 192 |
+
save_interval: 500
|
| 193 |
+
eval_interval: 500
|
| 194 |
+
eval_num_batches: 200
|
| 195 |
+
per_latency_eval_num_batches: null
|
| 196 |
+
eval_action_classification: false
|
| 197 |
+
eval_action_classification_interval: null
|
| 198 |
+
cc_f1_tolerance: 1
|
| 199 |
+
learning_rate:
|
| 200 |
+
base: 2.0e-05
|
| 201 |
+
qwen_vl_interface: 1.0e-05
|
| 202 |
+
action_model: 0.0001
|
| 203 |
+
lr_scheduler_type: cosine_with_min_lr
|
| 204 |
+
scheduler_specific_kwargs:
|
| 205 |
+
min_lr: 1.0e-06
|
| 206 |
+
freeze_modules: ''
|
| 207 |
+
freeze_vit: false
|
| 208 |
+
freeze_tied_embedding: false
|
| 209 |
+
freeze_llm_layers: []
|
| 210 |
+
loss_scale:
|
| 211 |
+
vla: 1.0
|
| 212 |
+
vlm: 0.1
|
| 213 |
+
max_grad_norm: 1.0
|
| 214 |
+
weight_decay: 0.0
|
| 215 |
+
logging_frequency: 1
|
| 216 |
+
profile_timing:
|
| 217 |
+
enabled: false
|
| 218 |
+
log_interval: 10
|
| 219 |
+
gradient_clipping: 1.0
|
| 220 |
+
gradient_accumulation_steps: 1
|
| 221 |
+
distributed_backend: deepspeed
|
| 222 |
+
is_resume: false
|
| 223 |
+
pretrained_checkpoint: null
|
| 224 |
+
resume_step: 0
|
| 225 |
+
reload_modules: null
|
| 226 |
+
optimizer:
|
| 227 |
+
name: AdamW
|
| 228 |
+
betas:
|
| 229 |
+
- 0.9
|
| 230 |
+
- 0.95
|
| 231 |
+
eps: 1.0e-08
|
| 232 |
+
weight_decay: 1.0e-08
|
| 233 |
+
fused: true
|
| 234 |
+
save_format: pt
|
| 235 |
+
workspace_dir: WORKSPACE_DIR
|
| 236 |
+
run_root_dir: /home/ubuntu/lzj/mean-profiling/ant/vla
|
| 237 |
+
seed: 42
|
| 238 |
+
wandb_entity: dongqianyu99-zhejiang-university
|
| 239 |
+
wandb_project: latency-sensitive-bench
|
| 240 |
+
auth:
|
| 241 |
+
env_file: null
|
| 242 |
+
hf_token_env: HF_TOKEN
|
| 243 |
+
wandb_api_key_env: WANDB_API_KEY
|
| 244 |
+
paths:
|
| 245 |
+
run_root_dir: /mnt/results/latency-sensitive-bench/profile-latency-new/ant/20260911T112232Z-ant/vla
|
| 246 |
+
dataset_local_dir: /mnt/results/latency-sensitive-bench/profile-latency-new/ant/20260911T112232Z-ant/converted
|
| 247 |
+
dataset_cache_dir: null
|
| 248 |
+
base_model_dir: /home/ubuntu/lzj/models/Qwen3-VL-4B-Instruct
|
| 249 |
+
accelerate_config: starVLA/config/deepseeds/deepspeed_zero2_cpu_offload.yaml
|
| 250 |
+
launch:
|
| 251 |
+
use_accelerate: true
|
| 252 |
+
gpus: null
|
| 253 |
+
num_processes: 1
|
| 254 |
+
dry_run: false
|
| 255 |
+
conda:
|
| 256 |
+
enabled: true
|
| 257 |
+
env_name: null
|
| 258 |
+
rl_games:
|
| 259 |
+
model_alias: openvla
|
| 260 |
+
env_eval:
|
| 261 |
+
image_size: 224
|
| 262 |
+
frameskip: 1
|
| 263 |
+
image_transform: raw_rgb
|
| 264 |
+
prompt_mode: raw
|
| 265 |
+
ghost_trail:
|
| 266 |
+
history_frames: 5
|
| 267 |
+
gamma: 1.3
|
| 268 |
+
min_alpha: 35
|
| 269 |
+
scroll_px_per_step: 4.0
|
| 270 |
+
ground_fraction: 0.22
|
| 271 |
+
seed: 42
|
| 272 |
+
fixed_episode_seeds: true
|
| 273 |
+
latency_seed_stride: 0
|
| 274 |
+
task_seed_stride: 0
|
| 275 |
+
task_description: ''
|
| 276 |
+
eval_parallel_envs: 5
|
| 277 |
+
action_chunk_execution:
|
| 278 |
+
enabled: false
|
| 279 |
+
chunk_size: null
|
| 280 |
+
enabled: false
|
| 281 |
+
gymnasium:
|
| 282 |
+
make_kwargs: {}
|
| 283 |
+
mid_train:
|
| 284 |
+
enabled: false
|
| 285 |
+
interval_steps: 100
|
| 286 |
+
latencies:
|
| 287 |
+
- 0
|
| 288 |
+
num_episodes: 5
|
| 289 |
+
max_steps_per_episode: 3600
|
| 290 |
+
post_train:
|
| 291 |
+
enabled: false
|
| 292 |
+
latencies:
|
| 293 |
+
- 0
|
| 294 |
+
- 1
|
| 295 |
+
- 2
|
| 296 |
+
- 3
|
| 297 |
+
- 4
|
| 298 |
+
num_episodes: 5
|
| 299 |
+
max_steps_per_episode: 3600
|
| 300 |
+
eval_backend: latency_bench
|
| 301 |
+
distributed_mode: none
|
| 302 |
+
vectorized:
|
| 303 |
+
enabled: false
|
| 304 |
+
batch_size: 1
|
| 305 |
+
latency:
|
| 306 |
+
prompt_map_path: null
|
| 307 |
+
mode: single
|
| 308 |
+
values:
|
| 309 |
+
- 1
|
| 310 |
+
- 2
|
| 311 |
+
task: gymnasium
|
| 312 |
+
gymnasium:
|
| 313 |
+
task_contract:
|
| 314 |
+
action_space:
|
| 315 |
+
dtype: float32
|
| 316 |
+
high:
|
| 317 |
+
- 1.0
|
| 318 |
+
- 1.0
|
| 319 |
+
- 1.0
|
| 320 |
+
- 1.0
|
| 321 |
+
- 1.0
|
| 322 |
+
- 1.0
|
| 323 |
+
- 1.0
|
| 324 |
+
- 1.0
|
| 325 |
+
labels:
|
| 326 |
+
- back_right_hip_torque
|
| 327 |
+
- back_right_ankle_torque
|
| 328 |
+
- front_left_hip_torque
|
| 329 |
+
- front_left_ankle_torque
|
| 330 |
+
- front_right_hip_torque
|
| 331 |
+
- front_right_ankle_torque
|
| 332 |
+
- back_left_hip_torque
|
| 333 |
+
- back_left_ankle_torque
|
| 334 |
+
low:
|
| 335 |
+
- -1.0
|
| 336 |
+
- -1.0
|
| 337 |
+
- -1.0
|
| 338 |
+
- -1.0
|
| 339 |
+
- -1.0
|
| 340 |
+
- -1.0
|
| 341 |
+
- -1.0
|
| 342 |
+
- -1.0
|
| 343 |
+
type: box
|
| 344 |
+
base_prompt: Make the Ant move forward as fast as possible without falling.
|
| 345 |
+
Predict eight continuous torques in [-1, 1] ordered as back right hip, back
|
| 346 |
+
right ankle, front left hip, front left ankle, front right hip, front right
|
| 347 |
+
ankle, back left hip, and back left ankle.
|
| 348 |
+
env_fps: 10.0
|
| 349 |
+
env_id: LatencyBench/AntContinuous-v0
|
| 350 |
+
frame_stack: 1
|
| 351 |
+
make_kwargs:
|
| 352 |
+
base_env_id: Ant-v4
|
| 353 |
+
base_make_kwargs:
|
| 354 |
+
exclude_current_positions_from_observation: true
|
| 355 |
+
use_contact_forces: false
|
| 356 |
+
render_mode: rgb_array
|
| 357 |
+
noop_action:
|
| 358 |
+
- 0.0
|
| 359 |
+
- 0.0
|
| 360 |
+
- 0.0
|
| 361 |
+
- 0.0
|
| 362 |
+
- 0.0
|
| 363 |
+
- 0.0
|
| 364 |
+
- 0.0
|
| 365 |
+
- 0.0
|
| 366 |
+
obs_fps: 10.0
|
| 367 |
+
registration_imports:
|
| 368 |
+
- latency_bench.envs.gymnasium_ant
|
| 369 |
+
state_space:
|
| 370 |
+
labels:
|
| 371 |
+
- torso_z
|
| 372 |
+
- torso_quaternion_w
|
| 373 |
+
- torso_quaternion_x
|
| 374 |
+
- torso_quaternion_y
|
| 375 |
+
- torso_quaternion_z
|
| 376 |
+
- front_left_hip_angle
|
| 377 |
+
- front_left_ankle_angle
|
| 378 |
+
- front_right_hip_angle
|
| 379 |
+
- front_right_ankle_angle
|
| 380 |
+
- back_left_hip_angle
|
| 381 |
+
- back_left_ankle_angle
|
| 382 |
+
- back_right_hip_angle
|
| 383 |
+
- back_right_ankle_angle
|
| 384 |
+
- torso_x_velocity
|
| 385 |
+
- torso_y_velocity
|
| 386 |
+
- torso_z_velocity
|
| 387 |
+
- torso_angular_velocity_x
|
| 388 |
+
- torso_angular_velocity_y
|
| 389 |
+
- torso_angular_velocity_z
|
| 390 |
+
- front_left_hip_angular_velocity
|
| 391 |
+
- front_left_ankle_angular_velocity
|
| 392 |
+
- front_right_hip_angular_velocity
|
| 393 |
+
- front_right_ankle_angular_velocity
|
| 394 |
+
- back_left_hip_angular_velocity
|
| 395 |
+
- back_left_ankle_angular_velocity
|
| 396 |
+
- back_right_hip_angular_velocity
|
| 397 |
+
- back_right_ankle_angular_velocity
|
| 398 |
+
task_name: ant_rgb_state
|
| 399 |
+
task_name: ant_rgb_state
|
| 400 |
+
initialization_mode: scratch
|
| 401 |
+
action_carrier: native
|
| 402 |
+
model: openvla
|
| 403 |
+
env: gymnasium
|
| 404 |
+
init: scratch
|
| 405 |
+
mode: single
|
| 406 |
+
checkpoint:
|
| 407 |
+
load: none
|
| 408 |
+
hf_repo_id: null
|
| 409 |
+
save_best_model: false
|
| 410 |
+
save_final_model: true
|
| 411 |
+
save_pt_file: true
|
| 412 |
+
save_training_state: true
|
| 413 |
+
save_safetensors_file: false
|
| 414 |
+
local:
|
| 415 |
+
keep_last_n: 2
|
| 416 |
+
sync:
|
| 417 |
+
enabled: false
|
| 418 |
+
repo_id: null
|
| 419 |
+
keep_last_n: 0
|
| 420 |
+
sync_every_n_checkpoints: 1
|
| 421 |
+
resume_policy: local_latest
|
| 422 |
+
run_id: ant-qwenoft-mean-3090-s42
|
| 423 |
+
output_dir: /home/ubuntu/lzj/mean-profiling/ant/vla/ant-qwenoft-mean-3090-s42
|
| 424 |
+
config_yaml: /home/ubuntu/lzj/mean-profiling/ant/vla.yaml
|
| 425 |
+
is_debug: false
|
| 426 |
+
version_id: '0.21'
|
| 427 |
+
wandb_name: ant-qwenoft-mean-3090-s42
|
| 428 |
+
wandb_group: mean-profiling-3090-blackwell
|
| 429 |
+
training_latency_condition: mean-profile
|
| 430 |
+
wandb_tags:
|
| 431 |
+
- ant
|
| 432 |
+
- qwenoft
|
| 433 |
+
- mean-profile
|
| 434 |
+
- h1
|
| 435 |
+
- blackwell
|
| 436 |
+
- throughput-priority
|
| 437 |
+
- micro64-global128
|
| 438 |
+
- gradient-checkpointing
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/config.yaml
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
framework:
|
| 2 |
+
name: QwenOFT
|
| 3 |
+
qwenvl:
|
| 4 |
+
base_vlm: Qwen/Qwen3-VL-4B-Instruct
|
| 5 |
+
attn_implementation: flash_attention_2
|
| 6 |
+
enable_gradient_checkpointing: true
|
| 7 |
+
action_model:
|
| 8 |
+
action_model_type: MLP
|
| 9 |
+
action_dim: 8
|
| 10 |
+
state_dim: 27
|
| 11 |
+
action_hidden_dim: 2560
|
| 12 |
+
future_action_window_size: 0
|
| 13 |
+
past_action_window_size: 0
|
| 14 |
+
loss_type: l1
|
| 15 |
+
state_encoding: discretized_text
|
| 16 |
+
task_objective: null
|
| 17 |
+
action_horizon: 1
|
| 18 |
+
action_env_dim: 8
|
| 19 |
+
kv_memory:
|
| 20 |
+
enabled: false
|
| 21 |
+
window: 4
|
| 22 |
+
rollout_len: 8
|
| 23 |
+
packed_train: false
|
| 24 |
+
rebased_sink: true
|
| 25 |
+
version_id: '0.21'
|
| 26 |
+
datasets:
|
| 27 |
+
vla_data:
|
| 28 |
+
include_state: true
|
| 29 |
+
obs_image_size: null
|
| 30 |
+
image_mode: single
|
| 31 |
+
stitch_grid:
|
| 32 |
+
- 2
|
| 33 |
+
- 2
|
| 34 |
+
num_obs_frames: 1
|
| 35 |
+
trainer:
|
| 36 |
+
pretrained_checkpoint: null
|
| 37 |
+
backbone:
|
| 38 |
+
repo_id: Qwen/Qwen3-VL-4B-Instruct
|
| 39 |
+
revision: ebb281ec70b05090aa6165b016eac8ec08e71b17
|
| 40 |
+
allow_patterns:
|
| 41 |
+
- '*.json'
|
| 42 |
+
- '*.safetensors'
|
| 43 |
+
- '*.txt'
|
| 44 |
+
- '*.jinja'
|
| 45 |
+
- '*.model'
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/dataset_statistics.json
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"new_embodiment": {
|
| 3 |
+
"action": {
|
| 4 |
+
"mean": [
|
| 5 |
+
-0.19492579996585846,
|
| 6 |
+
0.04469946771860123,
|
| 7 |
+
0.10307926684617996,
|
| 8 |
+
0.06500687450170517,
|
| 9 |
+
-0.07598323374986649,
|
| 10 |
+
0.10469535738229752,
|
| 11 |
+
-0.027709610760211945,
|
| 12 |
+
0.1776909977197647
|
| 13 |
+
],
|
| 14 |
+
"std": [
|
| 15 |
+
0.2916632294654846,
|
| 16 |
+
0.18000850081443787,
|
| 17 |
+
0.3355802595615387,
|
| 18 |
+
0.2449917495250702,
|
| 19 |
+
0.3372354805469513,
|
| 20 |
+
0.055361147969961166,
|
| 21 |
+
0.29043376445770264,
|
| 22 |
+
0.06610933691263199
|
| 23 |
+
],
|
| 24 |
+
"max": [
|
| 25 |
+
0.6329135894775391,
|
| 26 |
+
0.6100203394889832,
|
| 27 |
+
1.0,
|
| 28 |
+
0.7914915680885315,
|
| 29 |
+
0.7937509417533875,
|
| 30 |
+
0.4119175970554352,
|
| 31 |
+
0.8763647675514221,
|
| 32 |
+
0.4558652639389038
|
| 33 |
+
],
|
| 34 |
+
"min": [
|
| 35 |
+
-1.0,
|
| 36 |
+
-0.5158019661903381,
|
| 37 |
+
-0.7942351698875427,
|
| 38 |
+
-0.6549583673477173,
|
| 39 |
+
-0.7899840474128723,
|
| 40 |
+
-0.1914844959974289,
|
| 41 |
+
-0.8830769658088684,
|
| 42 |
+
-0.25145918130874634
|
| 43 |
+
],
|
| 44 |
+
"q01": [
|
| 45 |
+
-0.7246493166685104,
|
| 46 |
+
-0.36842879801988604,
|
| 47 |
+
-0.4745602348446846,
|
| 48 |
+
-0.32548967510461807,
|
| 49 |
+
-0.6590064060688019,
|
| 50 |
+
-0.00425734419375658,
|
| 51 |
+
-0.667693349123001,
|
| 52 |
+
0.03753467075526715
|
| 53 |
+
],
|
| 54 |
+
"q99": [
|
| 55 |
+
0.38912478089332564,
|
| 56 |
+
0.4704011854529379,
|
| 57 |
+
0.9895162123441696,
|
| 58 |
+
0.6802999329566952,
|
| 59 |
+
0.6482488948106765,
|
| 60 |
+
0.26210771769285157,
|
| 61 |
+
0.4697745823860167,
|
| 62 |
+
0.32386209577322006
|
| 63 |
+
],
|
| 64 |
+
"mask": [
|
| 65 |
+
true,
|
| 66 |
+
true,
|
| 67 |
+
true,
|
| 68 |
+
true,
|
| 69 |
+
true,
|
| 70 |
+
true,
|
| 71 |
+
true,
|
| 72 |
+
true
|
| 73 |
+
]
|
| 74 |
+
},
|
| 75 |
+
"state": {
|
| 76 |
+
"mean": [
|
| 77 |
+
-0.03927938640117645,
|
| 78 |
+
0.873625636100769,
|
| 79 |
+
-0.2643051743507385,
|
| 80 |
+
-0.5193795561790466,
|
| 81 |
+
-0.03129394352436066,
|
| 82 |
+
0.37781062722206116,
|
| 83 |
+
0.3676287829875946,
|
| 84 |
+
-0.12228213250637054,
|
| 85 |
+
0.10376925021409988,
|
| 86 |
+
0.0348481647670269,
|
| 87 |
+
0.10585025697946548,
|
| 88 |
+
-0.3591102361679077,
|
| 89 |
+
0.4178043007850647,
|
| 90 |
+
0.3299199938774109,
|
| 91 |
+
-0.09238386154174805,
|
| 92 |
+
-0.07736567407846451,
|
| 93 |
+
0.08624251186847687,
|
| 94 |
+
-0.0959310308098793,
|
| 95 |
+
0.05461423099040985,
|
| 96 |
+
-0.14337068796157837,
|
| 97 |
+
-0.10180454701185226,
|
| 98 |
+
0.04959503188729286,
|
| 99 |
+
0.18128058314323425,
|
| 100 |
+
-0.015483468770980835,
|
| 101 |
+
0.28967317938804626,
|
| 102 |
+
0.2775602340698242,
|
| 103 |
+
-0.33862781524658203
|
| 104 |
+
],
|
| 105 |
+
"std": [
|
| 106 |
+
0.24292634427547455,
|
| 107 |
+
0.06530473381280856,
|
| 108 |
+
0.13237309455871582,
|
| 109 |
+
0.13348814845085144,
|
| 110 |
+
0.15209674835205078,
|
| 111 |
+
0.4691879153251648,
|
| 112 |
+
0.39366209506988525,
|
| 113 |
+
0.6651913523674011,
|
| 114 |
+
0.08553778380155563,
|
| 115 |
+
0.6054338812828064,
|
| 116 |
+
0.08797592669725418,
|
| 117 |
+
0.48128432035446167,
|
| 118 |
+
0.33567723631858826,
|
| 119 |
+
0.2170608788728714,
|
| 120 |
+
0.24111506342887878,
|
| 121 |
+
0.35090306401252747,
|
| 122 |
+
0.2857387363910675,
|
| 123 |
+
0.20407065749168396,
|
| 124 |
+
0.22814442217350006,
|
| 125 |
+
0.3093811273574829,
|
| 126 |
+
0.3431510031223297,
|
| 127 |
+
0.41457003355026245,
|
| 128 |
+
0.05459607020020485,
|
| 129 |
+
0.33612897992134094,
|
| 130 |
+
0.05801063030958176,
|
| 131 |
+
0.34881407022476196,
|
| 132 |
+
0.31408628821372986
|
| 133 |
+
],
|
| 134 |
+
"max": [
|
| 135 |
+
1.0,
|
| 136 |
+
1.0,
|
| 137 |
+
1.0,
|
| 138 |
+
1.0,
|
| 139 |
+
1.0,
|
| 140 |
+
1.0,
|
| 141 |
+
1.0,
|
| 142 |
+
1.0,
|
| 143 |
+
1.0,
|
| 144 |
+
1.0,
|
| 145 |
+
1.0,
|
| 146 |
+
1.0,
|
| 147 |
+
1.0,
|
| 148 |
+
1.0,
|
| 149 |
+
1.0,
|
| 150 |
+
1.0,
|
| 151 |
+
1.0,
|
| 152 |
+
1.0,
|
| 153 |
+
1.0,
|
| 154 |
+
1.0,
|
| 155 |
+
1.0,
|
| 156 |
+
1.0,
|
| 157 |
+
1.0,
|
| 158 |
+
1.0,
|
| 159 |
+
1.0,
|
| 160 |
+
1.0,
|
| 161 |
+
1.0
|
| 162 |
+
],
|
| 163 |
+
"min": [
|
| 164 |
+
-1.0,
|
| 165 |
+
-1.0,
|
| 166 |
+
-1.0,
|
| 167 |
+
-1.0,
|
| 168 |
+
-1.0,
|
| 169 |
+
-1.0,
|
| 170 |
+
-1.0,
|
| 171 |
+
-1.0,
|
| 172 |
+
-1.0,
|
| 173 |
+
-1.0,
|
| 174 |
+
-1.0,
|
| 175 |
+
-1.0,
|
| 176 |
+
-1.0,
|
| 177 |
+
-1.0,
|
| 178 |
+
-1.0,
|
| 179 |
+
-1.0,
|
| 180 |
+
-1.0,
|
| 181 |
+
-1.0,
|
| 182 |
+
-1.0,
|
| 183 |
+
-1.0,
|
| 184 |
+
-1.0,
|
| 185 |
+
-1.0,
|
| 186 |
+
-1.0,
|
| 187 |
+
-1.0,
|
| 188 |
+
-1.0,
|
| 189 |
+
-1.0,
|
| 190 |
+
-1.0
|
| 191 |
+
],
|
| 192 |
+
"q01": [
|
| 193 |
+
-0.518711000084877,
|
| 194 |
+
0.7832470858097076,
|
| 195 |
+
-0.48747050642967227,
|
| 196 |
+
-0.8287142354249954,
|
| 197 |
+
-0.3970690089464188,
|
| 198 |
+
-0.7996528524160386,
|
| 199 |
+
-0.18211212992668152,
|
| 200 |
+
-0.9498927110433578,
|
| 201 |
+
0.05799898505210877,
|
| 202 |
+
-0.9213203591108322,
|
| 203 |
+
0.06377534270286564,
|
| 204 |
+
-0.9172824740409851,
|
| 205 |
+
-0.14945583879947663,
|
| 206 |
+
-0.47512653708457947,
|
| 207 |
+
-0.5667413014173508,
|
| 208 |
+
-0.720048052072525,
|
| 209 |
+
-0.6468206322193146,
|
| 210 |
+
-0.4755307936668396,
|
| 211 |
+
-0.4702010858058929,
|
| 212 |
+
-0.6532424187660217,
|
| 213 |
+
-0.637979581952095,
|
| 214 |
+
-0.8247658777236938,
|
| 215 |
+
0.17336984157562255,
|
| 216 |
+
-0.7672037160396576,
|
| 217 |
+
0.28981017947196963,
|
| 218 |
+
-0.6314861965179444,
|
| 219 |
+
-0.8276125568151474
|
| 220 |
+
],
|
| 221 |
+
"q99": [
|
| 222 |
+
0.5284208941459655,
|
| 223 |
+
0.8995754766464233,
|
| 224 |
+
0.07895282626152018,
|
| 225 |
+
-0.29791240513324774,
|
| 226 |
+
0.3613759696483611,
|
| 227 |
+
0.9232616770267487,
|
| 228 |
+
0.9520751488208771,
|
| 229 |
+
0.944451036453247,
|
| 230 |
+
0.11151877999305723,
|
| 231 |
+
0.8851249778270721,
|
| 232 |
+
0.11331057786941529,
|
| 233 |
+
0.7722350835800162,
|
| 234 |
+
0.9076120913028717,
|
| 235 |
+
0.7570547771453847,
|
| 236 |
+
0.543445667028426,
|
| 237 |
+
0.718429600000381,
|
| 238 |
+
0.6114705646038047,
|
| 239 |
+
0.3634060764312739,
|
| 240 |
+
0.6103977251052853,
|
| 241 |
+
0.6279066145420074,
|
| 242 |
+
0.8004330182075499,
|
| 243 |
+
0.8364576077461242,
|
| 244 |
+
0.1844600486755371,
|
| 245 |
+
0.5733257675170897,
|
| 246 |
+
0.2910482907295227,
|
| 247 |
+
0.8056755244731904,
|
| 248 |
+
0.2977444970607755
|
| 249 |
+
]
|
| 250 |
+
},
|
| 251 |
+
"num_transitions": 90000,
|
| 252 |
+
"num_trajectories": 90
|
| 253 |
+
}
|
| 254 |
+
}
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/dataset_statistics_eval.json
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"new_embodiment": {
|
| 3 |
+
"action": {
|
| 4 |
+
"mean": [
|
| 5 |
+
-0.194865420460701,
|
| 6 |
+
0.045133840292692184,
|
| 7 |
+
0.10328157991170883,
|
| 8 |
+
0.06766745448112488,
|
| 9 |
+
-0.07633885741233826,
|
| 10 |
+
0.10476952791213989,
|
| 11 |
+
-0.02807306870818138,
|
| 12 |
+
0.17962458729743958
|
| 13 |
+
],
|
| 14 |
+
"std": [
|
| 15 |
+
0.2925890386104584,
|
| 16 |
+
0.179392471909523,
|
| 17 |
+
0.33783403038978577,
|
| 18 |
+
0.24546940624713898,
|
| 19 |
+
0.33822667598724365,
|
| 20 |
+
0.052730318158864975,
|
| 21 |
+
0.28934720158576965,
|
| 22 |
+
0.06433656811714172
|
| 23 |
+
],
|
| 24 |
+
"max": [
|
| 25 |
+
0.5322136878967285,
|
| 26 |
+
0.555697500705719,
|
| 27 |
+
1.0,
|
| 28 |
+
0.7869182229042053,
|
| 29 |
+
0.8116569519042969,
|
| 30 |
+
0.3534770607948303,
|
| 31 |
+
0.7703150510787964,
|
| 32 |
+
0.440703809261322
|
| 33 |
+
],
|
| 34 |
+
"min": [
|
| 35 |
+
-1.0,
|
| 36 |
+
-0.47031596302986145,
|
| 37 |
+
-0.730529248714447,
|
| 38 |
+
-0.6560564637184143,
|
| 39 |
+
-0.8157420754432678,
|
| 40 |
+
-0.052262552082538605,
|
| 41 |
+
-0.8346825242042542,
|
| 42 |
+
-0.025107912719249725
|
| 43 |
+
],
|
| 44 |
+
"q01": [
|
| 45 |
+
-0.7260830360651016,
|
| 46 |
+
-0.36782372266054153,
|
| 47 |
+
-0.47317668825387954,
|
| 48 |
+
-0.31557414084672925,
|
| 49 |
+
-0.66000783264637,
|
| 50 |
+
0.0017754910979419962,
|
| 51 |
+
-0.6687433636188507,
|
| 52 |
+
0.044861558452248575
|
| 53 |
+
],
|
| 54 |
+
"q99": [
|
| 55 |
+
0.38754730314016345,
|
| 56 |
+
0.46464609265327456,
|
| 57 |
+
1.0,
|
| 58 |
+
0.6821840578317643,
|
| 59 |
+
0.6534658980369571,
|
| 60 |
+
0.2567682746052742,
|
| 61 |
+
0.466521698832512,
|
| 62 |
+
0.3254868069291115
|
| 63 |
+
],
|
| 64 |
+
"mask": [
|
| 65 |
+
true,
|
| 66 |
+
true,
|
| 67 |
+
true,
|
| 68 |
+
true,
|
| 69 |
+
true,
|
| 70 |
+
true,
|
| 71 |
+
true,
|
| 72 |
+
true
|
| 73 |
+
]
|
| 74 |
+
},
|
| 75 |
+
"state": {
|
| 76 |
+
"mean": [
|
| 77 |
+
-0.03446132689714432,
|
| 78 |
+
0.8770178556442261,
|
| 79 |
+
-0.26813629269599915,
|
| 80 |
+
-0.5243244767189026,
|
| 81 |
+
-0.036261554807424545,
|
| 82 |
+
0.38102391362190247,
|
| 83 |
+
0.368524432182312,
|
| 84 |
+
-0.12297961115837097,
|
| 85 |
+
0.10743273794651031,
|
| 86 |
+
0.03137503191828728,
|
| 87 |
+
0.10943524539470673,
|
| 88 |
+
-0.3544634282588959,
|
| 89 |
+
0.4190467298030853,
|
| 90 |
+
0.3441190719604492,
|
| 91 |
+
-0.09693243354558945,
|
| 92 |
+
-0.07695353031158447,
|
| 93 |
+
0.08566370606422424,
|
| 94 |
+
-0.09651442617177963,
|
| 95 |
+
0.054840974509716034,
|
| 96 |
+
-0.14340537786483765,
|
| 97 |
+
-0.1022859439253807,
|
| 98 |
+
0.04956989362835884,
|
| 99 |
+
0.18135188519954681,
|
| 100 |
+
-0.015385560691356659,
|
| 101 |
+
0.2896140515804291,
|
| 102 |
+
0.2777324914932251,
|
| 103 |
+
-0.3387359380722046
|
| 104 |
+
],
|
| 105 |
+
"std": [
|
| 106 |
+
0.23964886367321014,
|
| 107 |
+
0.023951832205056853,
|
| 108 |
+
0.11455036699771881,
|
| 109 |
+
0.1093541756272316,
|
| 110 |
+
0.14902757108211517,
|
| 111 |
+
0.46400782465934753,
|
| 112 |
+
0.39322152733802795,
|
| 113 |
+
0.666404664516449,
|
| 114 |
+
0.06292039155960083,
|
| 115 |
+
0.6054039001464844,
|
| 116 |
+
0.06391128897666931,
|
| 117 |
+
0.48054811358451843,
|
| 118 |
+
0.33541467785835266,
|
| 119 |
+
0.20528468489646912,
|
| 120 |
+
0.23731346428394318,
|
| 121 |
+
0.3526037931442261,
|
| 122 |
+
0.28841397166252136,
|
| 123 |
+
0.2061758041381836,
|
| 124 |
+
0.22504228353500366,
|
| 125 |
+
0.3090031147003174,
|
| 126 |
+
0.3419175148010254,
|
| 127 |
+
0.4147181808948517,
|
| 128 |
+
0.054758649319410324,
|
| 129 |
+
0.3359338939189911,
|
| 130 |
+
0.05688738450407982,
|
| 131 |
+
0.35167375206947327,
|
| 132 |
+
0.3148670196533203
|
| 133 |
+
],
|
| 134 |
+
"max": [
|
| 135 |
+
0.8509142398834229,
|
| 136 |
+
0.946937084197998,
|
| 137 |
+
0.28078794479370117,
|
| 138 |
+
0.13082659244537354,
|
| 139 |
+
0.7544276714324951,
|
| 140 |
+
0.9886277914047241,
|
| 141 |
+
0.9866607189178467,
|
| 142 |
+
0.9863904714584351,
|
| 143 |
+
0.9886200428009033,
|
| 144 |
+
0.9180272817611694,
|
| 145 |
+
0.958978533744812,
|
| 146 |
+
0.976783037185669,
|
| 147 |
+
0.994597315788269,
|
| 148 |
+
0.9207459688186646,
|
| 149 |
+
0.9506415128707886,
|
| 150 |
+
0.9698106050491333,
|
| 151 |
+
0.8268996477127075,
|
| 152 |
+
0.5188288688659668,
|
| 153 |
+
0.899605393409729,
|
| 154 |
+
0.8091031312942505,
|
| 155 |
+
0.9923845529556274,
|
| 156 |
+
0.9708276987075806,
|
| 157 |
+
0.9690662622451782,
|
| 158 |
+
0.8003939390182495,
|
| 159 |
+
1.0,
|
| 160 |
+
0.9442052841186523,
|
| 161 |
+
0.9767690896987915
|
| 162 |
+
],
|
| 163 |
+
"min": [
|
| 164 |
+
-0.6200818419456482,
|
| 165 |
+
0.5183085203170776,
|
| 166 |
+
-0.7695543766021729,
|
| 167 |
+
-0.9485529661178589,
|
| 168 |
+
-0.8429219722747803,
|
| 169 |
+
-0.9506317377090454,
|
| 170 |
+
-0.9622589349746704,
|
| 171 |
+
-1.0,
|
| 172 |
+
-0.9714068174362183,
|
| 173 |
+
-1.0,
|
| 174 |
+
-0.9771743416786194,
|
| 175 |
+
-0.9749248623847961,
|
| 176 |
+
-1.0,
|
| 177 |
+
-0.7751631736755371,
|
| 178 |
+
-0.8879467844963074,
|
| 179 |
+
-1.0,
|
| 180 |
+
-1.0,
|
| 181 |
+
-0.7477306723594666,
|
| 182 |
+
-0.7433239221572876,
|
| 183 |
+
-0.8804571628570557,
|
| 184 |
+
-0.9065881967544556,
|
| 185 |
+
-0.9710677862167358,
|
| 186 |
+
-0.9849591851234436,
|
| 187 |
+
-0.9246947765350342,
|
| 188 |
+
-0.9404064416885376,
|
| 189 |
+
-0.956570029258728,
|
| 190 |
+
-1.0
|
| 191 |
+
],
|
| 192 |
+
"q01": [
|
| 193 |
+
-0.5038023978471756,
|
| 194 |
+
0.7942106568813324,
|
| 195 |
+
-0.478440306186676,
|
| 196 |
+
-0.8267061966657638,
|
| 197 |
+
-0.39669507682323457,
|
| 198 |
+
-0.7862418442964554,
|
| 199 |
+
-0.1804919111728668,
|
| 200 |
+
-0.9492776465415954,
|
| 201 |
+
0.10735819339752198,
|
| 202 |
+
-0.919443871974945,
|
| 203 |
+
0.11226175785064697,
|
| 204 |
+
-0.9184101295471191,
|
| 205 |
+
-0.1500501948595047,
|
| 206 |
+
-0.34228765964508057,
|
| 207 |
+
-0.5650507682561874,
|
| 208 |
+
-0.7155984926223755,
|
| 209 |
+
-0.6520336997509003,
|
| 210 |
+
-0.4805710732936859,
|
| 211 |
+
-0.46580726146698,
|
| 212 |
+
-0.6449919211864471,
|
| 213 |
+
-0.6242685246467591,
|
| 214 |
+
-0.819073212146759,
|
| 215 |
+
0.17577075600624084,
|
| 216 |
+
-0.7636688566207885,
|
| 217 |
+
0.28973553419113157,
|
| 218 |
+
-0.6239250099658966,
|
| 219 |
+
-0.8301586848497391
|
| 220 |
+
],
|
| 221 |
+
"q99": [
|
| 222 |
+
0.531941732168198,
|
| 223 |
+
0.8995999598503113,
|
| 224 |
+
0.04719418048858646,
|
| 225 |
+
-0.3141447216272354,
|
| 226 |
+
0.33111580729484597,
|
| 227 |
+
0.9231463372707368,
|
| 228 |
+
0.9524696123600006,
|
| 229 |
+
0.9444611060619355,
|
| 230 |
+
0.11135421514511108,
|
| 231 |
+
0.8837961864471436,
|
| 232 |
+
0.11332787156105041,
|
| 233 |
+
0.7487831759452822,
|
| 234 |
+
0.9076400446891785,
|
| 235 |
+
0.7634504711627961,
|
| 236 |
+
0.5362399804592136,
|
| 237 |
+
0.7234879946708682,
|
| 238 |
+
0.6047599220275879,
|
| 239 |
+
0.36570024728775025,
|
| 240 |
+
0.6087638485431678,
|
| 241 |
+
0.6343572854995728,
|
| 242 |
+
0.8117764890193939,
|
| 243 |
+
0.836361961364746,
|
| 244 |
+
0.18426278471946717,
|
| 245 |
+
0.5724071526527406,
|
| 246 |
+
0.2910631883144379,
|
| 247 |
+
0.7999724817276002,
|
| 248 |
+
0.29399525642395047
|
| 249 |
+
]
|
| 250 |
+
},
|
| 251 |
+
"num_transitions": 10000,
|
| 252 |
+
"num_trajectories": 10
|
| 253 |
+
}
|
| 254 |
+
}
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/files.sha256.json
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"README.md": {
|
| 3 |
+
"bytes": 1131,
|
| 4 |
+
"sha256": "b8d91b05b9719d73549c3e71fb89b846804e31e9870616d346875796a961a975"
|
| 5 |
+
},
|
| 6 |
+
"checkpoints/model.pt": {
|
| 7 |
+
"bytes": 9785070315,
|
| 8 |
+
"sha256": "afb954569065450b9b80a86ca96e3898e3fe8d2f8c38a06f63bf3b11c41163b3"
|
| 9 |
+
},
|
| 10 |
+
"collection_quality_report.json": {
|
| 11 |
+
"bytes": 421,
|
| 12 |
+
"sha256": "3a21eb8ce207f265fee8197c317c6f93013e10dd96dc32f5a702b1b658773de5"
|
| 13 |
+
},
|
| 14 |
+
"config.full.yaml": {
|
| 15 |
+
"bytes": 11309,
|
| 16 |
+
"sha256": "936acd2c14d8aa4c4ab817eab4acf046827b879f12b6454e4a1ae7e1ef69136c"
|
| 17 |
+
},
|
| 18 |
+
"config.yaml": {
|
| 19 |
+
"bytes": 965,
|
| 20 |
+
"sha256": "dfda64a8e3d18e6ceb8c0fdc686915cd897f0df78ea24b100b58a468335ee7c6"
|
| 21 |
+
},
|
| 22 |
+
"dataset_statistics.json": {
|
| 23 |
+
"bytes": 5727,
|
| 24 |
+
"sha256": "8808223c11ba20721109750a91a23cc2c81b5b92d8e48320edfe5f22722b3389"
|
| 25 |
+
},
|
| 26 |
+
"dataset_statistics_eval.json": {
|
| 27 |
+
"bytes": 6413,
|
| 28 |
+
"sha256": "85ee7976398bfc0cf7f75e6f3c9528f9fa872a77dcab0bb849dc3920683e973a"
|
| 29 |
+
},
|
| 30 |
+
"latency_prompt_map.json": {
|
| 31 |
+
"bytes": 497,
|
| 32 |
+
"sha256": "8be52633a13e9032392595f2e6d637a98f539dacb6757e1dec59e65ffc2074e3"
|
| 33 |
+
},
|
| 34 |
+
"launch_audit.json": {
|
| 35 |
+
"bytes": 1786,
|
| 36 |
+
"sha256": "262ce08821f1c2261b8567eed44c53818fba6d75cfe967c35e61fc2ddee42070"
|
| 37 |
+
},
|
| 38 |
+
"manifest.json": {
|
| 39 |
+
"bytes": 6710,
|
| 40 |
+
"sha256": "ec82945da958d7e29d172928b136177d2b0e23612b62889f64b475446cd655c4"
|
| 41 |
+
},
|
| 42 |
+
"profile.source.json": {
|
| 43 |
+
"bytes": 2148,
|
| 44 |
+
"sha256": "0e49f72ec05ac600a54e07bbca5af3143708444d606167f33fa21788a9fefe50"
|
| 45 |
+
},
|
| 46 |
+
"provenance.json": {
|
| 47 |
+
"bytes": 6152,
|
| 48 |
+
"sha256": "ddb044cd3a9ea15f9c07c2370df31f15c4ffda0236fee45b0935a99aba79720d"
|
| 49 |
+
},
|
| 50 |
+
"startup_verified.json": {
|
| 51 |
+
"bytes": 1553,
|
| 52 |
+
"sha256": "f7ade30c273f14972b8deacf42b9f0ff2bad29bb0cefffc1b131977a9933d3b5"
|
| 53 |
+
},
|
| 54 |
+
"summary.jsonl": {
|
| 55 |
+
"bytes": 159,
|
| 56 |
+
"sha256": "2905acb79c5fffb33fd4689d87af3bd05d74f4184b9d36ff3eae0c64deecd930"
|
| 57 |
+
},
|
| 58 |
+
"task_contract.json": {
|
| 59 |
+
"bytes": 2298,
|
| 60 |
+
"sha256": "a874a91173a6579750761e4aa65d8daecc167dc9a2d0c58041813f83d589c959"
|
| 61 |
+
},
|
| 62 |
+
"training-code/QWen3.py": {
|
| 63 |
+
"bytes": 17586,
|
| 64 |
+
"sha256": "5fe76fc98eaa84e215c3c25c11326815499d2a4b0683c6ab95382b881f535370"
|
| 65 |
+
},
|
| 66 |
+
"training-code/QwenOFT.py": {
|
| 67 |
+
"bytes": 62854,
|
| 68 |
+
"sha256": "acad1b0dcde6e9fed6e2912b6534db0f8e33a74ec7f6630bbf1b0161fc298b0d"
|
| 69 |
+
},
|
| 70 |
+
"training-code/datasets.py": {
|
| 71 |
+
"bytes": 154347,
|
| 72 |
+
"sha256": "33e22556471128a2bad18a1ef8b84c399847b4d98b2979d785d139de0cdf36df"
|
| 73 |
+
},
|
| 74 |
+
"training-code/doom-mean-reset.patch": {
|
| 75 |
+
"bytes": 9569,
|
| 76 |
+
"sha256": "4113989e16c547bd1f02f5f10f285c4d511be3a3c18d10a0aa3316bd8ff3175d"
|
| 77 |
+
},
|
| 78 |
+
"training-code/gym-language-contract.patch": {
|
| 79 |
+
"bytes": 688,
|
| 80 |
+
"sha256": "9f5dee2c5b52d5507aff27373a8cf6def4959361d2c5264d5079b416f28a4c49"
|
| 81 |
+
},
|
| 82 |
+
"training-code/loader-spawn-cache.patch": {
|
| 83 |
+
"bytes": 711,
|
| 84 |
+
"sha256": "24532ce84e5aa9aef381493fe699b4bb4987afd954422191ae852b0f5eb5b2cd"
|
| 85 |
+
},
|
| 86 |
+
"training-code/loader-spawn-test.patch": {
|
| 87 |
+
"bytes": 1500,
|
| 88 |
+
"sha256": "a36db15b13d68defeecb75ddc9efa1ac202d9aa0a40f66ba5baaee2dcaef21f1"
|
| 89 |
+
},
|
| 90 |
+
"training-code/mean-profile-preparation.patch": {
|
| 91 |
+
"bytes": 7053,
|
| 92 |
+
"sha256": "de5fe558376c98515a1cfb186ffdc09b618acc207eb8a5f667b0cbb303767c09"
|
| 93 |
+
},
|
| 94 |
+
"training-code/train_starvla.py": {
|
| 95 |
+
"bytes": 125159,
|
| 96 |
+
"sha256": "f872648f941cec272af724772e9d6fc3721e9ed6eaf0c8683ab285eb9396212e"
|
| 97 |
+
},
|
| 98 |
+
"training-code/trainer_tools.py": {
|
| 99 |
+
"bytes": 29144,
|
| 100 |
+
"sha256": "9a48bdfb99b405b03fececfc1e051d3ebb179eb423c15141f02b9be62e2e1791"
|
| 101 |
+
},
|
| 102 |
+
"training-code/worker_context.py": {
|
| 103 |
+
"bytes": 2279,
|
| 104 |
+
"sha256": "8493631104269f0630655ee2faae592a84ebfb3119aca142c8ac2701f5214464"
|
| 105 |
+
},
|
| 106 |
+
"training_results.json": {
|
| 107 |
+
"bytes": 1762,
|
| 108 |
+
"sha256": "8c3b350880c1fd9996fa4a77a9c81c8e9a4c3d0fd0c96ef5272dc88669bbba63"
|
| 109 |
+
}
|
| 110 |
+
}
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/latency_prompt_map.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"1": {
|
| 3 |
+
"prompt": "Make the Ant move forward as fast as possible without falling. Predict eight continuous torques in [-1, 1] ordered as back right hip, back right ankle, front left hip, front left ankle, front right hip, front right ankle, back left hip, and back left ankle. Current action latency is 1 raw frames (100.00 ms). The environment runs at 10 FPS and observations are emitted at 10 FPS. Choose the best next action.",
|
| 4 |
+
"latency_raw_frames": 1,
|
| 5 |
+
"latency_ms": 100.0
|
| 6 |
+
}
|
| 7 |
+
}
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/launch_audit.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"reference": "/home/ubuntu/lzj/mean-profiling/reference/checkpoint-configs/latency-aware/ant/vla/starvla-qwenoft-h1/ant_rgb_state_profile_20260911T112232Z_openvla_native_sft_5k/config.full.yaml",
|
| 3 |
+
"reference_sha256": "1abb758e750efa660e3a4e949a974eedf19e6d8e49cc5ef98ec29c6da453c56e",
|
| 4 |
+
"scientific_trainer_fields_equal": [
|
| 5 |
+
"max_train_steps",
|
| 6 |
+
"num_warmup_steps",
|
| 7 |
+
"learning_rate",
|
| 8 |
+
"lr_scheduler_type",
|
| 9 |
+
"scheduler_specific_kwargs",
|
| 10 |
+
"optimizer",
|
| 11 |
+
"eval_interval",
|
| 12 |
+
"eval_num_batches",
|
| 13 |
+
"save_interval",
|
| 14 |
+
"loss_scale"
|
| 15 |
+
],
|
| 16 |
+
"seed": 42,
|
| 17 |
+
"horizon": 1,
|
| 18 |
+
"state_dim": 27,
|
| 19 |
+
"action_dim": 8,
|
| 20 |
+
"global_batch": 128,
|
| 21 |
+
"micro_per_gpu": 64,
|
| 22 |
+
"accumulation": 1,
|
| 23 |
+
"gradient_checkpointing": true,
|
| 24 |
+
"formal_optimizer_updates": 5000,
|
| 25 |
+
"preflight_updates_discarded": 20,
|
| 26 |
+
"post_train_rollout_eval": false,
|
| 27 |
+
"data_revision": "6246ccc57caf32da0e02547c3e3e1080894d4035",
|
| 28 |
+
"runtime_save_training_state": true,
|
| 29 |
+
"runtime_keep_last_recovery_states": 2,
|
| 30 |
+
"profile_timing_same_as_reference": false,
|
| 31 |
+
"reference_global_batch": 16,
|
| 32 |
+
"profile_timing_enabled": false,
|
| 33 |
+
"user_authorized_scientific_difference": "Prioritize two GPU utilization; user explicitly requests Flappy micro64*2/accum1/global128, referenceglobal16 no longerbinding",
|
| 34 |
+
"failed_initial_preflight": "Missing requiredwandb_tags, noformaloptimizerupdates",
|
| 35 |
+
"metadata_repair": "Explicitwandb_tags added",
|
| 36 |
+
"optimizer_budget": 5000,
|
| 37 |
+
"previous_runtime_failure": "32/accum2 CUDA OOM atsecond optimizer update after1testupdate",
|
| 38 |
+
"runtime_adjustment": "Enableexistingnon-reentrantgradientcheckpointing;64*2*accum1/global128, othermath/scientificbudgets maintained",
|
| 39 |
+
"startup_verified": true,
|
| 40 |
+
"formal_startup_evidence": "/home/ubuntu/lzj/mean-profiling/ant/vla.startup-verified.json"
|
| 41 |
+
}
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/manifest.json
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"dataset_name": "lerobot",
|
| 3 |
+
"env_name": "ant_rgb_state",
|
| 4 |
+
"episodes": 90,
|
| 5 |
+
"frames": 90000,
|
| 6 |
+
"task_prompts": [
|
| 7 |
+
"Make the Ant move forward as fast as possible without falling. Predict eight continuous torques in [-1, 1] ordered as back right hip, back right ankle, front left hip, front left ankle, front right hip, front right ankle, back left hip, and back left ankle. Current action latency is 1 raw frames (100.00 ms). The environment runs at 10 FPS and observations are emitted at 10 FPS. Choose the best next action."
|
| 8 |
+
],
|
| 9 |
+
"format": "lerobot_v2_image_parquet",
|
| 10 |
+
"source": "/home/ubuntu/lzj/mean-profiling/ant/data/raw",
|
| 11 |
+
"integration_name": "gymnasium",
|
| 12 |
+
"task_name": "ant_rgb_state",
|
| 13 |
+
"action_layout": "gymnasium_continuous_v1",
|
| 14 |
+
"action_labels": [
|
| 15 |
+
"back_right_hip_torque",
|
| 16 |
+
"back_right_ankle_torque",
|
| 17 |
+
"front_left_hip_torque",
|
| 18 |
+
"front_left_ankle_torque",
|
| 19 |
+
"front_right_hip_torque",
|
| 20 |
+
"front_right_ankle_torque",
|
| 21 |
+
"back_left_hip_torque",
|
| 22 |
+
"back_left_ankle_torque"
|
| 23 |
+
],
|
| 24 |
+
"carrier_action_labels": [
|
| 25 |
+
"back_right_hip_torque",
|
| 26 |
+
"back_right_ankle_torque",
|
| 27 |
+
"front_left_hip_torque",
|
| 28 |
+
"front_left_ankle_torque",
|
| 29 |
+
"front_right_hip_torque",
|
| 30 |
+
"front_right_ankle_torque",
|
| 31 |
+
"back_left_hip_torque",
|
| 32 |
+
"back_left_ankle_torque"
|
| 33 |
+
],
|
| 34 |
+
"action_dim": 8,
|
| 35 |
+
"active_action_dim": 8,
|
| 36 |
+
"action_carrier": "native",
|
| 37 |
+
"rows_unit": "decision_step",
|
| 38 |
+
"obs_fps": 10.0,
|
| 39 |
+
"obs_stride_raw_frames": 1,
|
| 40 |
+
"uses_state": true,
|
| 41 |
+
"state_dim": 27,
|
| 42 |
+
"state_labels": [
|
| 43 |
+
"torso_z",
|
| 44 |
+
"torso_quaternion_w",
|
| 45 |
+
"torso_quaternion_x",
|
| 46 |
+
"torso_quaternion_y",
|
| 47 |
+
"torso_quaternion_z",
|
| 48 |
+
"front_left_hip_angle",
|
| 49 |
+
"front_left_ankle_angle",
|
| 50 |
+
"front_right_hip_angle",
|
| 51 |
+
"front_right_ankle_angle",
|
| 52 |
+
"back_left_hip_angle",
|
| 53 |
+
"back_left_ankle_angle",
|
| 54 |
+
"back_right_hip_angle",
|
| 55 |
+
"back_right_ankle_angle",
|
| 56 |
+
"torso_x_velocity",
|
| 57 |
+
"torso_y_velocity",
|
| 58 |
+
"torso_z_velocity",
|
| 59 |
+
"torso_angular_velocity_x",
|
| 60 |
+
"torso_angular_velocity_y",
|
| 61 |
+
"torso_angular_velocity_z",
|
| 62 |
+
"front_left_hip_angular_velocity",
|
| 63 |
+
"front_left_ankle_angular_velocity",
|
| 64 |
+
"front_right_hip_angular_velocity",
|
| 65 |
+
"front_right_ankle_angular_velocity",
|
| 66 |
+
"back_left_hip_angular_velocity",
|
| 67 |
+
"back_left_ankle_angular_velocity",
|
| 68 |
+
"back_right_hip_angular_velocity",
|
| 69 |
+
"back_right_ankle_angular_velocity"
|
| 70 |
+
],
|
| 71 |
+
"state_normalization": {
|
| 72 |
+
"type": "min_max",
|
| 73 |
+
"min": [
|
| 74 |
+
0.24513374269008636,
|
| 75 |
+
-0.8805694580078125,
|
| 76 |
+
-0.33691075444221497,
|
| 77 |
+
-0.4456058740615845,
|
| 78 |
+
-0.9112266302108765,
|
| 79 |
+
-0.6140146255493164,
|
| 80 |
+
-0.09917011857032776,
|
| 81 |
+
-0.6453427076339722,
|
| 82 |
+
-1.3009648323059082,
|
| 83 |
+
-0.6563361883163452,
|
| 84 |
+
-1.2990498542785645,
|
| 85 |
+
-0.6459031105041504,
|
| 86 |
+
-0.09470116347074509,
|
| 87 |
+
-1.9981460571289062,
|
| 88 |
+
-2.8870370388031006,
|
| 89 |
+
-2.5440866947174072,
|
| 90 |
+
-5.5593695640563965,
|
| 91 |
+
-6.843714237213135,
|
| 92 |
+
-5.608675003051758,
|
| 93 |
+
-10.695633888244629,
|
| 94 |
+
-9.341012001037598,
|
| 95 |
+
-13.44798469543457,
|
| 96 |
+
-11.152595520019531,
|
| 97 |
+
-14.51861572265625,
|
| 98 |
+
-11.078145980834961,
|
| 99 |
+
-12.814929008483887,
|
| 100 |
+
-5.827189922332764
|
| 101 |
+
],
|
| 102 |
+
"max": [
|
| 103 |
+
0.9843788743019104,
|
| 104 |
+
1.098469853401184,
|
| 105 |
+
0.557304859161377,
|
| 106 |
+
0.9673683047294617,
|
| 107 |
+
0.7864838242530823,
|
| 108 |
+
0.6336118578910828,
|
| 109 |
+
1.329100489616394,
|
| 110 |
+
0.624431848526001,
|
| 111 |
+
0.09998779743909836,
|
| 112 |
+
0.6632993221282959,
|
| 113 |
+
0.09576962888240814,
|
| 114 |
+
0.5784072875976562,
|
| 115 |
+
1.320813536643982,
|
| 116 |
+
5.847742557525635,
|
| 117 |
+
3.869502544403076,
|
| 118 |
+
2.964057445526123,
|
| 119 |
+
4.749230861663818,
|
| 120 |
+
8.3289155960083,
|
| 121 |
+
4.963846206665039,
|
| 122 |
+
14.281911849975586,
|
| 123 |
+
11.46115779876709,
|
| 124 |
+
12.22265911102295,
|
| 125 |
+
7.717322826385498,
|
| 126 |
+
15.017043113708496,
|
| 127 |
+
6.09257173538208,
|
| 128 |
+
7.276201248168945,
|
| 129 |
+
11.832711219787598
|
| 130 |
+
]
|
| 131 |
+
},
|
| 132 |
+
"robot_type": "rl_games_gymnasium",
|
| 133 |
+
"latency_prompt_map_path": "/home/ubuntu/lzj/mean-profiling/ant/data/lerobot/latency_prompt_map.json",
|
| 134 |
+
"custom_mixtures_path": "/home/ubuntu/lzj/mean-profiling/ant/data/_generated_mixtures/lerobot.json",
|
| 135 |
+
"gymnasium_task": {
|
| 136 |
+
"action_space": {
|
| 137 |
+
"dtype": "float32",
|
| 138 |
+
"high": [
|
| 139 |
+
1.0,
|
| 140 |
+
1.0,
|
| 141 |
+
1.0,
|
| 142 |
+
1.0,
|
| 143 |
+
1.0,
|
| 144 |
+
1.0,
|
| 145 |
+
1.0,
|
| 146 |
+
1.0
|
| 147 |
+
],
|
| 148 |
+
"labels": [
|
| 149 |
+
"back_right_hip_torque",
|
| 150 |
+
"back_right_ankle_torque",
|
| 151 |
+
"front_left_hip_torque",
|
| 152 |
+
"front_left_ankle_torque",
|
| 153 |
+
"front_right_hip_torque",
|
| 154 |
+
"front_right_ankle_torque",
|
| 155 |
+
"back_left_hip_torque",
|
| 156 |
+
"back_left_ankle_torque"
|
| 157 |
+
],
|
| 158 |
+
"low": [
|
| 159 |
+
-1.0,
|
| 160 |
+
-1.0,
|
| 161 |
+
-1.0,
|
| 162 |
+
-1.0,
|
| 163 |
+
-1.0,
|
| 164 |
+
-1.0,
|
| 165 |
+
-1.0,
|
| 166 |
+
-1.0
|
| 167 |
+
],
|
| 168 |
+
"type": "box"
|
| 169 |
+
},
|
| 170 |
+
"base_prompt": "Make the Ant move forward as fast as possible without falling. Predict eight continuous torques in [-1, 1] ordered as back right hip, back right ankle, front left hip, front left ankle, front right hip, front right ankle, back left hip, and back left ankle.",
|
| 171 |
+
"env_fps": 10.0,
|
| 172 |
+
"env_id": "LatencyBench/AntContinuous-v0",
|
| 173 |
+
"frame_stack": 1,
|
| 174 |
+
"make_kwargs": {
|
| 175 |
+
"base_env_id": "Ant-v4",
|
| 176 |
+
"base_make_kwargs": {
|
| 177 |
+
"exclude_current_positions_from_observation": true,
|
| 178 |
+
"use_contact_forces": false
|
| 179 |
+
},
|
| 180 |
+
"render_mode": "rgb_array"
|
| 181 |
+
},
|
| 182 |
+
"noop_action": [
|
| 183 |
+
0.0,
|
| 184 |
+
0.0,
|
| 185 |
+
0.0,
|
| 186 |
+
0.0,
|
| 187 |
+
0.0,
|
| 188 |
+
0.0,
|
| 189 |
+
0.0,
|
| 190 |
+
0.0
|
| 191 |
+
],
|
| 192 |
+
"obs_fps": 10.0,
|
| 193 |
+
"registration_imports": [
|
| 194 |
+
"latency_bench.envs.gymnasium_ant"
|
| 195 |
+
],
|
| 196 |
+
"state_space": {
|
| 197 |
+
"labels": [
|
| 198 |
+
"torso_z",
|
| 199 |
+
"torso_quaternion_w",
|
| 200 |
+
"torso_quaternion_x",
|
| 201 |
+
"torso_quaternion_y",
|
| 202 |
+
"torso_quaternion_z",
|
| 203 |
+
"front_left_hip_angle",
|
| 204 |
+
"front_left_ankle_angle",
|
| 205 |
+
"front_right_hip_angle",
|
| 206 |
+
"front_right_ankle_angle",
|
| 207 |
+
"back_left_hip_angle",
|
| 208 |
+
"back_left_ankle_angle",
|
| 209 |
+
"back_right_hip_angle",
|
| 210 |
+
"back_right_ankle_angle",
|
| 211 |
+
"torso_x_velocity",
|
| 212 |
+
"torso_y_velocity",
|
| 213 |
+
"torso_z_velocity",
|
| 214 |
+
"torso_angular_velocity_x",
|
| 215 |
+
"torso_angular_velocity_y",
|
| 216 |
+
"torso_angular_velocity_z",
|
| 217 |
+
"front_left_hip_angular_velocity",
|
| 218 |
+
"front_left_ankle_angular_velocity",
|
| 219 |
+
"front_right_hip_angular_velocity",
|
| 220 |
+
"front_right_ankle_angular_velocity",
|
| 221 |
+
"back_left_hip_angular_velocity",
|
| 222 |
+
"back_left_ankle_angular_velocity",
|
| 223 |
+
"back_right_hip_angular_velocity",
|
| 224 |
+
"back_right_ankle_angular_velocity"
|
| 225 |
+
]
|
| 226 |
+
},
|
| 227 |
+
"task_name": "ant_rgb_state"
|
| 228 |
+
},
|
| 229 |
+
"validation_dataset_name": "lerobot__val",
|
| 230 |
+
"validation_episodes": 10,
|
| 231 |
+
"validation_frames": 10000
|
| 232 |
+
}
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/profile.source.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"burst_model_path": "latency_burst_model.json",
|
| 3 |
+
"distribution_path": "latency_distribution.json",
|
| 4 |
+
"env_fps": 10,
|
| 5 |
+
"frame_ms": 100.0,
|
| 6 |
+
"gpu_class": "1x-rtx3090",
|
| 7 |
+
"instance_id": "instance_859cf1e47bca6046",
|
| 8 |
+
"latency_kind": "observation_to_action_latency",
|
| 9 |
+
"latency_method": "temporal",
|
| 10 |
+
"model_id": "qwenoft",
|
| 11 |
+
"n_admitted_observations": 7976,
|
| 12 |
+
"n_capacity_drops": 294,
|
| 13 |
+
"n_observation_attempts": 8270,
|
| 14 |
+
"per_slot_summary": {
|
| 15 |
+
"0": {
|
| 16 |
+
"admitted_count": 7976,
|
| 17 |
+
"mean_observation_to_action_latency_ms": 90.56460638563993,
|
| 18 |
+
"mean_worker_service_time_ms": 90.22241150451042,
|
| 19 |
+
"p95_observation_to_action_latency_ms": 92.13036412000656,
|
| 20 |
+
"p95_worker_service_time_ms": 91.75596672296524,
|
| 21 |
+
"p99_worker_service_time_ms": 110.92562991380692
|
| 22 |
+
}
|
| 23 |
+
},
|
| 24 |
+
"provenance": {
|
| 25 |
+
"base_config": "/workspace/tasks/20260911T023128Z-p-only4/ant/profile.yaml",
|
| 26 |
+
"checkpoint_kind": "best",
|
| 27 |
+
"model_artifact": {
|
| 28 |
+
"checkpoint": "checkpoints/steps_5000_pytorch_model.pt",
|
| 29 |
+
"model_config": "config.full.yaml",
|
| 30 |
+
"path_in_repo": "OpenVLA/zero-latency/ant_rgb_state_l0_return_gt3000_100ep_openvla_native_sft_5k",
|
| 31 |
+
"repo_id": "latency-sensitive-bench/extra-envs-checkpoints",
|
| 32 |
+
"source": "local"
|
| 33 |
+
},
|
| 34 |
+
"session_ids": [
|
| 35 |
+
0,
|
| 36 |
+
1,
|
| 37 |
+
2,
|
| 38 |
+
3,
|
| 39 |
+
4
|
| 40 |
+
]
|
| 41 |
+
},
|
| 42 |
+
"sample_model_type": "hidden_regime",
|
| 43 |
+
"source_run_id": "20260911T033037730561Z",
|
| 44 |
+
"summary": {
|
| 45 |
+
"frame_ms": 100.0,
|
| 46 |
+
"max_ms": 130.29119229316711,
|
| 47 |
+
"mean_effective_frames": 0.9056460638563993,
|
| 48 |
+
"mean_ms": 90.56460638563993,
|
| 49 |
+
"min_ms": 87.98952293395996,
|
| 50 |
+
"n_samples": 7976,
|
| 51 |
+
"p50_frames": 0.8970676946640015,
|
| 52 |
+
"p50_ms": 89.70676946640015,
|
| 53 |
+
"p90_frames": 0.9074710392951966,
|
| 54 |
+
"p90_ms": 90.74710392951965,
|
| 55 |
+
"p95_frames": 0.9213036412000656,
|
| 56 |
+
"p95_ms": 92.13036412000656,
|
| 57 |
+
"p99_frames": 1.1217999053001404,
|
| 58 |
+
"p99_ms": 112.17999053001404,
|
| 59 |
+
"prob_latency_gt_1_frame": 0.03686058174523571,
|
| 60 |
+
"prob_latency_gt_2_frames": 0.0,
|
| 61 |
+
"prob_latency_gt_3_frames": 0.0,
|
| 62 |
+
"std_ms": 4.164609685850939
|
| 63 |
+
},
|
| 64 |
+
"visualization_path": "latency_profile.png",
|
| 65 |
+
"workload_id": "ant"
|
| 66 |
+
}
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/provenance.json
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"task": "ant",
|
| 3 |
+
"model": "QwenOFT",
|
| 4 |
+
"run_id": "ant-qwenoft-mean-3090-s42",
|
| 5 |
+
"training_status": "complete",
|
| 6 |
+
"training_hardware": {
|
| 7 |
+
"gpu": "RTX PRO6000 Blackwell Server Edition",
|
| 8 |
+
"count": 2,
|
| 9 |
+
"physical_indices": [
|
| 10 |
+
0,
|
| 11 |
+
1
|
| 12 |
+
]
|
| 13 |
+
},
|
| 14 |
+
"profile": {
|
| 15 |
+
"mean_ms": 90.56460638563993,
|
| 16 |
+
"profile": "/home/ubuntu/lzj/mean-profiling/reference/checkpoint-configs/latency-aware/ant/small-policy/sample-factory-qwenoft-rtx3090-v1/profile/profile.json",
|
| 17 |
+
"sha256": "0e49f72ec05ac600a54e07bbca5af3143708444d606167f33fa21788a9fefe50"
|
| 18 |
+
},
|
| 19 |
+
"profile_hardware": "RTX3090",
|
| 20 |
+
"condition": "fixed_mean_profile",
|
| 21 |
+
"horizon": 1,
|
| 22 |
+
"seed": 42,
|
| 23 |
+
"state_dim": 27,
|
| 24 |
+
"action_dim": 8,
|
| 25 |
+
"micro_per_gpu": 64,
|
| 26 |
+
"gradient_accumulation": 1,
|
| 27 |
+
"global_batch": 128,
|
| 28 |
+
"gradient_checkpointing": true,
|
| 29 |
+
"precision": "BF16",
|
| 30 |
+
"backend": "ZeRO2",
|
| 31 |
+
"teacher": {
|
| 32 |
+
"repo_id": "latency-sensitive-bench/benchmark-models",
|
| 33 |
+
"revision": "1c2f38f16553622eef2c62ddde86036be989ea31",
|
| 34 |
+
"path": "latency-aware/ant/small-policy/sample-factory-qwenoft-rtx3090-mean-v1",
|
| 35 |
+
"local_checkpoint": "/home/ubuntu/lzj/mean-profiling/ant/teacher-publication/checkpoint.pth",
|
| 36 |
+
"status": "complete_verified",
|
| 37 |
+
"completed_env_steps": 10006528,
|
| 38 |
+
"selected_env_steps": 9969664,
|
| 39 |
+
"selected_source_checkpoint": "/home/ubuntu/lzj/mean-profiling/ant/teacher/ant_mean_3090_s2222/checkpoint_p0/best_000019472_9969664_reward_3371.900.pth",
|
| 40 |
+
"tensor_count": 15,
|
| 41 |
+
"weights_only_export": true,
|
| 42 |
+
"tensor_equality_verified": true,
|
| 43 |
+
"hash_readback_verified": true,
|
| 44 |
+
"url": "https://huggingface.co/latency-sensitive-bench/benchmark-models/tree/1c2f38f16553622eef2c62ddde86036be989ea31/latency-aware/ant/small-policy/sample-factory-qwenoft-rtx3090-mean-v1",
|
| 45 |
+
"completed_utc": "2026-09-30T13:54:03.497277+00:00"
|
| 46 |
+
},
|
| 47 |
+
"dataset": {
|
| 48 |
+
"repo_id": "latency-sensitive-bench/Standard-Pipeline",
|
| 49 |
+
"repo_type": "dataset",
|
| 50 |
+
"path": "ant/profile_latency/OpenVLA/mean_rtx3090_s2222_100ep_v1",
|
| 51 |
+
"revision": "6246ccc57caf32da0e02547c3e3e1080894d4035",
|
| 52 |
+
"data_uploaded_revision": "4faa069b31f461177e1adbb0c039da5db0adacb8",
|
| 53 |
+
"url": "https://huggingface.co/datasets/latency-sensitive-bench/Standard-Pipeline/tree/6246ccc57caf32da0e02547c3e3e1080894d4035/ant/profile_latency/OpenVLA/mean_rtx3090_s2222_100ep_v1",
|
| 54 |
+
"status": "complete_verified",
|
| 55 |
+
"episodes": 100,
|
| 56 |
+
"rows": 100000,
|
| 57 |
+
"strict_return_gt2500": true,
|
| 58 |
+
"payload_files_verified": 26,
|
| 59 |
+
"checksum_manifest_verified": true,
|
| 60 |
+
"dataset_config": "ant_profile_latency_mean_qwenoft",
|
| 61 |
+
"completed_utc": "2026-09-30T14:50:21.716749+00:00"
|
| 62 |
+
},
|
| 63 |
+
"collection": {
|
| 64 |
+
"task": "ant",
|
| 65 |
+
"teacher_checkpoint": "/home/ubuntu/lzj/mean-profiling/ant/teacher-publication/checkpoint.pth",
|
| 66 |
+
"teacher_sha256": "a7899b32beb9b2cfec1bcff85b285dddc243a73f1c322fafefae599df0f67b3b",
|
| 67 |
+
"episodes": 100,
|
| 68 |
+
"train_episodes": 90,
|
| 69 |
+
"val_episodes": 10,
|
| 70 |
+
"train_rows": 90000,
|
| 71 |
+
"val_rows": 10000,
|
| 72 |
+
"fixed_latency_ms": 90.56460638563993,
|
| 73 |
+
"action_horizon": 1,
|
| 74 |
+
"unique_seeds": 100,
|
| 75 |
+
"state_dim": 27
|
| 76 |
+
},
|
| 77 |
+
"runtime": {
|
| 78 |
+
"repo": "c3c6a39365a151e9b7a5e215452fd64e957c2b29",
|
| 79 |
+
"starvla": "ccca13c5177fe3d3c884b6e2de4965d916016649",
|
| 80 |
+
"runtime_fixes": [
|
| 81 |
+
"mean-profile-preparation.patch",
|
| 82 |
+
"gym-language-contract.patch",
|
| 83 |
+
"loader-spawn-cache.patch",
|
| 84 |
+
"loader-spawn-test.patch",
|
| 85 |
+
"doom-mean-reset.patch"
|
| 86 |
+
],
|
| 87 |
+
"pytorch3d": {
|
| 88 |
+
"revision": "33824be3cbc87a7dd1db0f6a9a9de9ac81b2d0ba",
|
| 89 |
+
"build": "transforms-only, no native render extension; QwenOFT uses transforms only"
|
| 90 |
+
},
|
| 91 |
+
"decord": {
|
| 92 |
+
"version": "0.6.0",
|
| 93 |
+
"build": "official source CPU decoder CP310",
|
| 94 |
+
"wheel_sha256": "e193b356b1e984b4eff08d23b62e482c2c9e5037a6efdc0b1af47079ae2e4c47"
|
| 95 |
+
}
|
| 96 |
+
},
|
| 97 |
+
"source_reference_revision": "180da0effdaaaeacef218cf5fbaa4db41af67495",
|
| 98 |
+
"performance_configuration_policy": "User authorized throughput priority; reference scientific parameters and actual runtime differences are documented by full config/launch audit",
|
| 99 |
+
"training_results": {
|
| 100 |
+
"training_complete": true,
|
| 101 |
+
"optimizer_updates": 5000,
|
| 102 |
+
"selection": "final_5000",
|
| 103 |
+
"train_loss": 0.011952828615903854,
|
| 104 |
+
"validation_action_loss": 0.018865827471017838,
|
| 105 |
+
"validation_samples": 10112,
|
| 106 |
+
"final_learning_rates": {
|
| 107 |
+
"learning_rate/action_model": 4.9999999999999996e-06,
|
| 108 |
+
"learning_rate/qwen_vl_interface": 5e-07
|
| 109 |
+
},
|
| 110 |
+
"closed_loop_evaluation": "pending until all four VLA trainings complete",
|
| 111 |
+
"tensor_keys": 730,
|
| 112 |
+
"serialized_tensor_elements_including_tied_aliases": 4892400136,
|
| 113 |
+
"weights_only_load": "passed",
|
| 114 |
+
"all_tensors_finite": true,
|
| 115 |
+
"completion_proof": {
|
| 116 |
+
"task": "ant",
|
| 117 |
+
"optimizer_updates": 5000,
|
| 118 |
+
"deepspeed_global_steps": 5000,
|
| 119 |
+
"deepspeed_global_samples": 640000,
|
| 120 |
+
"skipped_steps": 0,
|
| 121 |
+
"scheduler_last_epoch": 5000,
|
| 122 |
+
"scheduler_step_count": 5001,
|
| 123 |
+
"final_learning_rates": [
|
| 124 |
+
5e-07,
|
| 125 |
+
4.9999999999999996e-06
|
| 126 |
+
],
|
| 127 |
+
"summary_final_steps": 5000,
|
| 128 |
+
"final_inference_weight_bytes": 9785070315,
|
| 129 |
+
"wandb_global_step": 5000,
|
| 130 |
+
"wrapper_exit": 2,
|
| 131 |
+
"trainer_exit_separately_captured": false,
|
| 132 |
+
"training_complete_verified": true,
|
| 133 |
+
"failure_scope": "launcher_tail_parse_after_trainer_cleanup",
|
| 134 |
+
"cause": "Sharedrun_vla.shwasmodifiedforGPUmask/portwhileAntbashwasblockedinsidePython; remainingfileoffsetlaterparsedmodifiedtailandEOF",
|
| 135 |
+
"trainer_cleanup_log": "bothranksDestroyDistributedProcessGroup at2026-10-01 00:03:21UTC; no model exception",
|
| 136 |
+
"evidence_files": [
|
| 137 |
+
"checkpoints/steps_5000_state/pytorch_model/mp_rank_00_model_states.pt",
|
| 138 |
+
"checkpoints/steps_5000_state/custom_checkpoint_0.pkl",
|
| 139 |
+
"summary.jsonl",
|
| 140 |
+
"config.full.yaml"
|
| 141 |
+
],
|
| 142 |
+
"note": "No syntheticvla.exit0; wrapperexit2preserved; upload uses explicitcompletionproof"
|
| 143 |
+
}
|
| 144 |
+
},
|
| 145 |
+
"optimizer_recovery_states": "retained on host; inference weights only in this bundle",
|
| 146 |
+
"wandb_url": "https://wandb.ai/dongqianyu99-zhejiang-university/latency-sensitive-bench/runs/mean3090-ant-vla-blackwell-20260930"
|
| 147 |
+
}
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/startup_verified.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"snapshot_utc": "2026-09-30T17:38:42Z",
|
| 3 |
+
"unit": "mean-profile-ant-vla-20261001-b64gc.service",
|
| 4 |
+
"wrapper_pid": 675875,
|
| 5 |
+
"rank_pids": [
|
| 6 |
+
676262,
|
| 7 |
+
676263
|
| 8 |
+
],
|
| 9 |
+
"physical_gpus": [
|
| 10 |
+
0,
|
| 11 |
+
1
|
| 12 |
+
],
|
| 13 |
+
"formal_training_started": true,
|
| 14 |
+
"formal_optimizer_updates_completed": 36,
|
| 15 |
+
"formal_optimizer_budget": 5000,
|
| 16 |
+
"preflight_optimizer_updates_discarded": 20,
|
| 17 |
+
"consecutive_logged_steps": [
|
| 18 |
+
33,
|
| 19 |
+
34,
|
| 20 |
+
35,
|
| 21 |
+
36
|
| 22 |
+
],
|
| 23 |
+
"loss_at_steps": {
|
| 24 |
+
"33": 0.3258245885372162,
|
| 25 |
+
"34": 0.3107373118400574,
|
| 26 |
+
"35": 0.49765458703041077,
|
| 27 |
+
"36": 0.4269329905509949
|
| 28 |
+
},
|
| 29 |
+
"finite_loss_verified": true,
|
| 30 |
+
"gpu_utilization_percent": [
|
| 31 |
+
100,
|
| 32 |
+
100
|
| 33 |
+
],
|
| 34 |
+
"gpu_used_mib": [
|
| 35 |
+
63815,
|
| 36 |
+
65995
|
| 37 |
+
],
|
| 38 |
+
"micro_batch_per_gpu": 64,
|
| 39 |
+
"gradient_accumulation": 1,
|
| 40 |
+
"global_batch": 128,
|
| 41 |
+
"gradient_checkpointing": true,
|
| 42 |
+
"seconds_per_optimizer_update_recent": 3.7,
|
| 43 |
+
"data_wait_seconds_recent": 0.0006755599970347248,
|
| 44 |
+
"host_memory_peak_bytes": 38237016064,
|
| 45 |
+
"host_memory_current_bytes": 17592913920,
|
| 46 |
+
"cgroup_memory_events": {
|
| 47 |
+
"low": 0,
|
| 48 |
+
"high": 0,
|
| 49 |
+
"max": 0,
|
| 50 |
+
"oom": 0,
|
| 51 |
+
"oom_kill": 0,
|
| 52 |
+
"oom_group_kill": 0
|
| 53 |
+
},
|
| 54 |
+
"remaining_compute_hours": 5.1018888888888885,
|
| 55 |
+
"estimated_remaining_hours_including_offline_validation_and_saves": [
|
| 56 |
+
5.5,
|
| 57 |
+
6.0
|
| 58 |
+
],
|
| 59 |
+
"estimated_completion_utc_range": [
|
| 60 |
+
"2026-09-30T23:10:00Z",
|
| 61 |
+
"2026-09-30T23:40:00Z"
|
| 62 |
+
],
|
| 63 |
+
"next_completion_check_utc": "2026-10-01T00:00:00Z",
|
| 64 |
+
"training_complete": false,
|
| 65 |
+
"closed_loop_evaluation_complete": false,
|
| 66 |
+
"publication_complete": false
|
| 67 |
+
}
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/summary.jsonl
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"steps": 500}
|
| 2 |
+
{"steps": 1000}
|
| 3 |
+
{"steps": 1500}
|
| 4 |
+
{"steps": 2000}
|
| 5 |
+
{"steps": 2500}
|
| 6 |
+
{"steps": 3000}
|
| 7 |
+
{"steps": 3500}
|
| 8 |
+
{"steps": 4000}
|
| 9 |
+
{"steps": 4500}
|
| 10 |
+
{"steps": 5000}
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/task_contract.json
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"action_space": {
|
| 3 |
+
"dtype": "float32",
|
| 4 |
+
"high": [
|
| 5 |
+
1.0,
|
| 6 |
+
1.0,
|
| 7 |
+
1.0,
|
| 8 |
+
1.0,
|
| 9 |
+
1.0,
|
| 10 |
+
1.0,
|
| 11 |
+
1.0,
|
| 12 |
+
1.0
|
| 13 |
+
],
|
| 14 |
+
"labels": [
|
| 15 |
+
"back_right_hip_torque",
|
| 16 |
+
"back_right_ankle_torque",
|
| 17 |
+
"front_left_hip_torque",
|
| 18 |
+
"front_left_ankle_torque",
|
| 19 |
+
"front_right_hip_torque",
|
| 20 |
+
"front_right_ankle_torque",
|
| 21 |
+
"back_left_hip_torque",
|
| 22 |
+
"back_left_ankle_torque"
|
| 23 |
+
],
|
| 24 |
+
"low": [
|
| 25 |
+
-1.0,
|
| 26 |
+
-1.0,
|
| 27 |
+
-1.0,
|
| 28 |
+
-1.0,
|
| 29 |
+
-1.0,
|
| 30 |
+
-1.0,
|
| 31 |
+
-1.0,
|
| 32 |
+
-1.0
|
| 33 |
+
],
|
| 34 |
+
"type": "box"
|
| 35 |
+
},
|
| 36 |
+
"base_prompt": "Make the Ant move forward as fast as possible without falling. Predict eight continuous torques in [-1, 1] ordered as back right hip, back right ankle, front left hip, front left ankle, front right hip, front right ankle, back left hip, and back left ankle.",
|
| 37 |
+
"env_fps": 10.0,
|
| 38 |
+
"env_id": "LatencyBench/AntContinuous-v0",
|
| 39 |
+
"frame_stack": 1,
|
| 40 |
+
"make_kwargs": {
|
| 41 |
+
"base_env_id": "Ant-v4",
|
| 42 |
+
"base_make_kwargs": {
|
| 43 |
+
"exclude_current_positions_from_observation": true,
|
| 44 |
+
"use_contact_forces": false
|
| 45 |
+
},
|
| 46 |
+
"render_mode": "rgb_array"
|
| 47 |
+
},
|
| 48 |
+
"noop_action": [
|
| 49 |
+
0.0,
|
| 50 |
+
0.0,
|
| 51 |
+
0.0,
|
| 52 |
+
0.0,
|
| 53 |
+
0.0,
|
| 54 |
+
0.0,
|
| 55 |
+
0.0,
|
| 56 |
+
0.0
|
| 57 |
+
],
|
| 58 |
+
"obs_fps": 10.0,
|
| 59 |
+
"registration_imports": [
|
| 60 |
+
"latency_bench.envs.gymnasium_ant"
|
| 61 |
+
],
|
| 62 |
+
"state_space": {
|
| 63 |
+
"labels": [
|
| 64 |
+
"torso_z",
|
| 65 |
+
"torso_quaternion_w",
|
| 66 |
+
"torso_quaternion_x",
|
| 67 |
+
"torso_quaternion_y",
|
| 68 |
+
"torso_quaternion_z",
|
| 69 |
+
"front_left_hip_angle",
|
| 70 |
+
"front_left_ankle_angle",
|
| 71 |
+
"front_right_hip_angle",
|
| 72 |
+
"front_right_ankle_angle",
|
| 73 |
+
"back_left_hip_angle",
|
| 74 |
+
"back_left_ankle_angle",
|
| 75 |
+
"back_right_hip_angle",
|
| 76 |
+
"back_right_ankle_angle",
|
| 77 |
+
"torso_x_velocity",
|
| 78 |
+
"torso_y_velocity",
|
| 79 |
+
"torso_z_velocity",
|
| 80 |
+
"torso_angular_velocity_x",
|
| 81 |
+
"torso_angular_velocity_y",
|
| 82 |
+
"torso_angular_velocity_z",
|
| 83 |
+
"front_left_hip_angular_velocity",
|
| 84 |
+
"front_left_ankle_angular_velocity",
|
| 85 |
+
"front_right_hip_angular_velocity",
|
| 86 |
+
"front_right_ankle_angular_velocity",
|
| 87 |
+
"back_left_hip_angular_velocity",
|
| 88 |
+
"back_left_ankle_angular_velocity",
|
| 89 |
+
"back_right_hip_angular_velocity",
|
| 90 |
+
"back_right_ankle_angular_velocity"
|
| 91 |
+
]
|
| 92 |
+
},
|
| 93 |
+
"task_name": "ant_rgb_state"
|
| 94 |
+
}
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/QWen3.py
ADDED
|
@@ -0,0 +1,444 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025 starVLA community. All rights reserved.
|
| 2 |
+
# Licensed under the MIT License, Version 1.0 (the "License");
|
| 3 |
+
# Implemented by [Jinhui YE / HKUST University] in [2025].
|
| 4 |
+
|
| 5 |
+
import time
|
| 6 |
+
from collections import OrderedDict
|
| 7 |
+
from functools import wraps
|
| 8 |
+
from inspect import signature
|
| 9 |
+
from typing import Optional
|
| 10 |
+
|
| 11 |
+
import torch
|
| 12 |
+
from starVLA.model.profiling import stage_timer as _stage
|
| 13 |
+
from starVLA.training.trainer_utils import initialize_overwatch
|
| 14 |
+
from transformers import AutoProcessor, Qwen3VLForConditionalGeneration
|
| 15 |
+
from transformers.modeling_outputs import CausalLMOutputWithPast
|
| 16 |
+
|
| 17 |
+
logger = initialize_overwatch(__name__)
|
| 18 |
+
|
| 19 |
+
IGNORE_INDEX = -100
|
| 20 |
+
IMAGE_TOKEN_INDEX = 151655
|
| 21 |
+
VIDEO_TOKEN_INDEX = 151656
|
| 22 |
+
DEFAULT_IMAGE_TOKEN = "<image>"
|
| 23 |
+
DEFAULT_VIDEO_TOKEN = "<video>"
|
| 24 |
+
|
| 25 |
+
_ACTION_TOKEN_MIN = 151669 # how can we know this range? check how you add fast tokens into VLM
|
| 26 |
+
_ACTION_TOKEN_MAX = (
|
| 27 |
+
153716 # here only for fast_tokenizer, see starVLA/model/modules/vlm/tools/add_qwen_special_tokens/README.md
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
import torch.nn as nn
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def _patch_qwen3vl_flash_attention_position_ids() -> None:
|
| 35 |
+
from transformers.models.qwen3_vl import modeling_qwen3_vl as qwen3_vl
|
| 36 |
+
|
| 37 |
+
text_attention_cls = qwen3_vl.Qwen3VLTextAttention
|
| 38 |
+
if hasattr(text_attention_cls, "_starvla_flash_attention_position_ids_patched"):
|
| 39 |
+
return
|
| 40 |
+
|
| 41 |
+
original_forward = text_attention_cls.forward
|
| 42 |
+
|
| 43 |
+
def forward_without_flash_attention_position_ids(self, *args, **kwargs):
|
| 44 |
+
# Qwen3-VL already applies M-RoPE through position_embeddings before
|
| 45 |
+
# attention. Passing the repeated temporal M-RoPE ids into HF's FA2
|
| 46 |
+
# wrapper makes Transformers 4.57 mis-detect packed sequences and build
|
| 47 |
+
# empty cu_seqlens on KV-memory cache steps.
|
| 48 |
+
if self.config._attn_implementation == "flash_attention_2" and "position_ids" in kwargs:
|
| 49 |
+
del kwargs["position_ids"]
|
| 50 |
+
return original_forward(self, *args, **kwargs)
|
| 51 |
+
|
| 52 |
+
text_attention_cls.forward = forward_without_flash_attention_position_ids
|
| 53 |
+
text_attention_cls._starvla_flash_attention_position_ids_patched = True
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
# The fixed Triton stage counts keep the PyTorch 2.11 CUDA 12.8 kernel
|
| 57 |
+
# within the shared-memory budget on sm_120.
|
| 58 |
+
_FLEX_KERNEL_OPTIONS = {
|
| 59 |
+
"BACKEND": "TRITON",
|
| 60 |
+
"fwd_num_stages": 2,
|
| 61 |
+
"bwd_num_stages": 1,
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def _patch_qwen3vl_flex_attention_support() -> None:
|
| 66 |
+
"""Allow loading Qwen3-VL with ``attn_implementation='flex_attention'``.
|
| 67 |
+
|
| 68 |
+
Qwen3-VL's attention already dispatches through the generic
|
| 69 |
+
``ALL_ATTENTION_FUNCTIONS`` interface (which includes the ``flex_attention``
|
| 70 |
+
integration), but the model classes conservatively declare
|
| 71 |
+
``_supports_flex_attn = False``, so Transformers 4.57 refuses to load with
|
| 72 |
+
flex at __init__. Flipping the flag lets the official dispatch path run; the
|
| 73 |
+
packed KV-memory training (`QwenOFT._forward_memory_packed`) passes a
|
| 74 |
+
BlockMask that FlexAttention consumes natively.
|
| 75 |
+
|
| 76 |
+
Also wraps the registered ``flex_attention`` interface to inject the fixed
|
| 77 |
+
Triton kernel options. Wrapping the dispatch entry — rather than threading
|
| 78 |
+
``kernel_options`` through the top-level forward kwargs — guarantees both the
|
| 79 |
+
forward and the gradient-checkpointing backward recompile pick it up.
|
| 80 |
+
"""
|
| 81 |
+
from transformers.models.qwen3_vl import modeling_qwen3_vl as qwen3_vl
|
| 82 |
+
|
| 83 |
+
for cls_name in (
|
| 84 |
+
"Qwen3VLForConditionalGeneration",
|
| 85 |
+
"Qwen3VLModel",
|
| 86 |
+
"Qwen3VLTextModel",
|
| 87 |
+
"Qwen3VLPreTrainedModel",
|
| 88 |
+
):
|
| 89 |
+
cls = getattr(qwen3_vl, cls_name, None)
|
| 90 |
+
if cls is not None:
|
| 91 |
+
cls._supports_flex_attn = True
|
| 92 |
+
|
| 93 |
+
from transformers.modeling_utils import ALL_ATTENTION_FUNCTIONS
|
| 94 |
+
|
| 95 |
+
base_flex = ALL_ATTENTION_FUNCTIONS["flex_attention"]
|
| 96 |
+
if getattr(base_flex, "_starvla_kernel_options_patched", False):
|
| 97 |
+
return
|
| 98 |
+
|
| 99 |
+
def flex_attention_with_kernel_options(*args, **kwargs):
|
| 100 |
+
kwargs["kernel_options"] = _FLEX_KERNEL_OPTIONS
|
| 101 |
+
return base_flex(*args, **kwargs)
|
| 102 |
+
|
| 103 |
+
flex_attention_with_kernel_options._starvla_kernel_options_patched = True
|
| 104 |
+
ALL_ATTENTION_FUNCTIONS["flex_attention"] = flex_attention_with_kernel_options
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def _position_tensor_key(tensor):
|
| 108 |
+
if tensor is None:
|
| 109 |
+
return None
|
| 110 |
+
return (tensor.device, tensor.dtype, tuple(tensor.shape),
|
| 111 |
+
tuple(tensor.detach().cpu().reshape(-1).tolist()))
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def _cache_position_method(module, name, weight):
|
| 115 |
+
"""Cache layout-only outputs on one native model instance, never image features."""
|
| 116 |
+
original = getattr(module, name)
|
| 117 |
+
parameters = signature(original)
|
| 118 |
+
cache = OrderedDict()
|
| 119 |
+
|
| 120 |
+
@wraps(original)
|
| 121 |
+
def cached(*args, **kwargs):
|
| 122 |
+
if module.training or torch.is_grad_enabled():
|
| 123 |
+
cache.clear()
|
| 124 |
+
return original(*args, **kwargs)
|
| 125 |
+
arguments = parameters.bind(*args, **kwargs)
|
| 126 |
+
arguments.apply_defaults()
|
| 127 |
+
parameter = weight()
|
| 128 |
+
key = (
|
| 129 |
+
parameter.device, parameter.dtype, parameter._version,
|
| 130 |
+
tuple(_position_tensor_key(value) for value in arguments.arguments.values()),
|
| 131 |
+
)
|
| 132 |
+
if key not in cache:
|
| 133 |
+
cache[key] = original(*args, **kwargs)
|
| 134 |
+
if len(cache) > 8:
|
| 135 |
+
cache.popitem(last=False)
|
| 136 |
+
cache.move_to_end(key)
|
| 137 |
+
return cache[key]
|
| 138 |
+
|
| 139 |
+
setattr(module, name, cached)
|
| 140 |
+
return cache
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
class _QWen3_VL_Interface(nn.Module):
|
| 144 |
+
"""
|
| 145 |
+
This exists because of the diversity of VLMs, so we encapsulate the changes here.
|
| 146 |
+
Lightweight wrapper around Qwen3-VL (Qwen3VLForConditionalGeneration).
|
| 147 |
+
|
| 148 |
+
Purpose:
|
| 149 |
+
- Unify interface with other VLM backends (CausalLM-like usage).
|
| 150 |
+
- Centralize preprocessing (tokenization + multimodal packing).
|
| 151 |
+
- Provide consistent forward / generate signatures.
|
| 152 |
+
|
| 153 |
+
"""
|
| 154 |
+
|
| 155 |
+
def __init__(self, config: Optional[dict] = None, **kwargs):
|
| 156 |
+
"""
|
| 157 |
+
Initialize the Qwen3-VL wrapper.
|
| 158 |
+
Following https://huggingface.co/Qwen/Qwen3-VL-4B-Instruct
|
| 159 |
+
|
| 160 |
+
"""
|
| 161 |
+
super().__init__()
|
| 162 |
+
|
| 163 |
+
qwenvl_config = config.framework.get("qwenvl", {})
|
| 164 |
+
model_id = qwenvl_config.get("base_vlm", "Qwen/Qwen3-VL-4B-Instruct")
|
| 165 |
+
attn_implementation = qwenvl_config.get("attn_implementation", "sdpa")
|
| 166 |
+
enable_grad_ckpt = qwenvl_config.get("enable_gradient_checkpointing", False)
|
| 167 |
+
print(
|
| 168 |
+
f"[QWen3] loading {model_id} with gradient_checkpointing={enable_grad_ckpt}",
|
| 169 |
+
flush=True,
|
| 170 |
+
)
|
| 171 |
+
|
| 172 |
+
if attn_implementation == "flash_attention_2":
|
| 173 |
+
import flash_attn_2_cuda # noqa: F401
|
| 174 |
+
|
| 175 |
+
_patch_qwen3vl_flash_attention_position_ids()
|
| 176 |
+
|
| 177 |
+
if attn_implementation == "flex_attention":
|
| 178 |
+
_patch_qwen3vl_flex_attention_support()
|
| 179 |
+
|
| 180 |
+
model = Qwen3VLForConditionalGeneration.from_pretrained(
|
| 181 |
+
model_id,
|
| 182 |
+
attn_implementation=attn_implementation,
|
| 183 |
+
dtype=torch.bfloat16,
|
| 184 |
+
ignore_mismatched_sizes=True, # resize image no longer needed? @TODO check bug
|
| 185 |
+
)
|
| 186 |
+
processor = AutoProcessor.from_pretrained(model_id)
|
| 187 |
+
processor.tokenizer.padding_side = "left"
|
| 188 |
+
|
| 189 |
+
if enable_grad_ckpt:
|
| 190 |
+
model.config.text_config.use_cache = False
|
| 191 |
+
model.gradient_checkpointing_enable(
|
| 192 |
+
gradient_checkpointing_kwargs={"use_reentrant": False}
|
| 193 |
+
)
|
| 194 |
+
model.enable_input_require_grads()
|
| 195 |
+
print(
|
| 196 |
+
"[QWen3] gradient_checkpointing ENABLED "
|
| 197 |
+
f"(use_reentrant=False, active={model.is_gradient_checkpointing}, "
|
| 198 |
+
f"text_use_cache={model.config.text_config.use_cache})",
|
| 199 |
+
flush=True,
|
| 200 |
+
)
|
| 201 |
+
|
| 202 |
+
self.model = model
|
| 203 |
+
self.processor = processor
|
| 204 |
+
self.config = config
|
| 205 |
+
# align qwen3 with qwen2.5
|
| 206 |
+
self.model.config.hidden_size = self.model.config.text_config.hidden_size
|
| 207 |
+
self._last_build_timing = {}
|
| 208 |
+
visual = model.model.visual
|
| 209 |
+
self._position_caches = [
|
| 210 |
+
_cache_position_method(model.model, "get_rope_index", lambda: visual.rotary_pos_emb.inv_freq),
|
| 211 |
+
_cache_position_method(visual, "rot_pos_emb", lambda: visual.rotary_pos_emb.inv_freq),
|
| 212 |
+
_cache_position_method(visual, "fast_pos_embed_interpolate", lambda: visual.pos_embed.weight),
|
| 213 |
+
]
|
| 214 |
+
|
| 215 |
+
# only for fast base model
|
| 216 |
+
if "-Action" in model_id:
|
| 217 |
+
self._ACTION_TOKEN_MIN = _ACTION_TOKEN_MIN
|
| 218 |
+
self._ACTION_TOKEN_MAX = _ACTION_TOKEN_MAX
|
| 219 |
+
|
| 220 |
+
def _clear_position_caches(self):
|
| 221 |
+
for cache in self._position_caches:
|
| 222 |
+
cache.clear()
|
| 223 |
+
|
| 224 |
+
def train(self, mode=True):
|
| 225 |
+
self._clear_position_caches()
|
| 226 |
+
return super().train(mode)
|
| 227 |
+
|
| 228 |
+
def _apply(self, fn, recurse=True):
|
| 229 |
+
self._clear_position_caches()
|
| 230 |
+
return super()._apply(fn, recurse=recurse)
|
| 231 |
+
|
| 232 |
+
def _load_from_state_dict(self, *args, **kwargs):
|
| 233 |
+
self._clear_position_caches()
|
| 234 |
+
return super()._load_from_state_dict(*args, **kwargs)
|
| 235 |
+
|
| 236 |
+
def _profile_timing_enabled(self) -> bool:
|
| 237 |
+
return self.config.trainer.profile_timing.enabled
|
| 238 |
+
|
| 239 |
+
def _profile_sync(self) -> None:
|
| 240 |
+
if self._profile_timing_enabled() and torch.cuda.is_available():
|
| 241 |
+
torch.cuda.synchronize()
|
| 242 |
+
|
| 243 |
+
def forward(
|
| 244 |
+
self,
|
| 245 |
+
**kwargs,
|
| 246 |
+
) -> CausalLMOutputWithPast:
|
| 247 |
+
"""
|
| 248 |
+
Forward pass delegating to underlying Qwen2.5-VL backbone.
|
| 249 |
+
"""
|
| 250 |
+
|
| 251 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 252 |
+
outputs = self.model(
|
| 253 |
+
**kwargs,
|
| 254 |
+
)
|
| 255 |
+
|
| 256 |
+
return outputs
|
| 257 |
+
|
| 258 |
+
def forward_last_hidden(self, **kwargs) -> torch.Tensor:
|
| 259 |
+
"""
|
| 260 |
+
Run the Qwen3-VL backbone and return only the final hidden state.
|
| 261 |
+
|
| 262 |
+
OFT-style action heads only consume the last hidden layer. Calling the
|
| 263 |
+
full conditional-generation wrapper with ``output_hidden_states=True``
|
| 264 |
+
returns every layer's activations, which can largely erase the memory
|
| 265 |
+
benefit of gradient checkpointing.
|
| 266 |
+
"""
|
| 267 |
+
|
| 268 |
+
kwargs = dict(kwargs)
|
| 269 |
+
kwargs.pop("output_hidden_states", None)
|
| 270 |
+
kwargs.pop("output_attentions", None)
|
| 271 |
+
kwargs.setdefault("return_dict", True)
|
| 272 |
+
kwargs.setdefault("use_cache", False)
|
| 273 |
+
|
| 274 |
+
def _wrapper_forward_last_hidden() -> torch.Tensor:
|
| 275 |
+
lm_head = getattr(self.model, "lm_head", None)
|
| 276 |
+
captured = {}
|
| 277 |
+
handle = None
|
| 278 |
+
if lm_head is not None:
|
| 279 |
+
def _capture_lm_head_input(_module, inputs):
|
| 280 |
+
captured["last_hidden"] = inputs[0]
|
| 281 |
+
|
| 282 |
+
handle = lm_head.register_forward_pre_hook(_capture_lm_head_input)
|
| 283 |
+
|
| 284 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 285 |
+
try:
|
| 286 |
+
outputs = self.model(
|
| 287 |
+
**kwargs,
|
| 288 |
+
output_attentions=False,
|
| 289 |
+
output_hidden_states=False,
|
| 290 |
+
return_dict=True,
|
| 291 |
+
)
|
| 292 |
+
finally:
|
| 293 |
+
if handle is not None:
|
| 294 |
+
handle.remove()
|
| 295 |
+
|
| 296 |
+
if "last_hidden" in captured:
|
| 297 |
+
return captured["last_hidden"]
|
| 298 |
+
|
| 299 |
+
# Last-resort compatibility path for unusual model wrappers that do
|
| 300 |
+
# not expose lm_head. This preserves correctness, but returns every
|
| 301 |
+
# layer and therefore saves less memory.
|
| 302 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 303 |
+
outputs = self.model(
|
| 304 |
+
**kwargs,
|
| 305 |
+
output_attentions=False,
|
| 306 |
+
output_hidden_states=True,
|
| 307 |
+
return_dict=True,
|
| 308 |
+
)
|
| 309 |
+
return outputs.hidden_states[-1]
|
| 310 |
+
|
| 311 |
+
backbone = getattr(self.model, "model", None)
|
| 312 |
+
if backbone is None:
|
| 313 |
+
return _wrapper_forward_last_hidden()
|
| 314 |
+
|
| 315 |
+
try:
|
| 316 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 317 |
+
outputs = backbone(**kwargs)
|
| 318 |
+
except TypeError:
|
| 319 |
+
# Some Transformers Qwen-VL wrappers inject visual embeddings before
|
| 320 |
+
# calling the text backbone, so the backbone itself may not accept
|
| 321 |
+
# pixel_values/image_grid_thw. Keep those versions working.
|
| 322 |
+
return _wrapper_forward_last_hidden()
|
| 323 |
+
|
| 324 |
+
if hasattr(outputs, "last_hidden_state"):
|
| 325 |
+
return outputs.last_hidden_state
|
| 326 |
+
return outputs[0]
|
| 327 |
+
|
| 328 |
+
def generate(
|
| 329 |
+
self,
|
| 330 |
+
**kwargs,
|
| 331 |
+
):
|
| 332 |
+
"""
|
| 333 |
+
High-level generation interface (auto-regressive decoding), optionally vision-conditioned.
|
| 334 |
+
|
| 335 |
+
Args:
|
| 336 |
+
**kwargs: fully follow raw model.generate() signature.
|
| 337 |
+
Returns:
|
| 338 |
+
GenerateOutput | Model-dependent generation return.
|
| 339 |
+
"""
|
| 340 |
+
with torch.autocast("cuda", dtype=torch.float16):
|
| 341 |
+
generation_output = self.model.generate(
|
| 342 |
+
**kwargs,
|
| 343 |
+
)
|
| 344 |
+
return generation_output
|
| 345 |
+
|
| 346 |
+
def build_qwenvl_inputs(self, images, instructions, solutions=None, profiler=None, **kwargs):
|
| 347 |
+
"""
|
| 348 |
+
Build model inputs from raw data (images + instructions + optional solutions).
|
| 349 |
+
Follow Oficial Qwen3-VL Instruct format: https://huggingface.co/Qwen/Qwen3-VL-4B-Instruct
|
| 350 |
+
"""
|
| 351 |
+
|
| 352 |
+
# Create messages: one message per sample
|
| 353 |
+
with _stage(profiler, "starvla_qwen_message_build_ms"):
|
| 354 |
+
messages = []
|
| 355 |
+
assert len(images) == len(instructions), "Images and instructions must have the same length"
|
| 356 |
+
for imgs, instruction in zip(images, instructions):
|
| 357 |
+
content = [{"type": "image", "image": img} for img in imgs]
|
| 358 |
+
|
| 359 |
+
if "CoT_prompt" in self.config.datasets.vla_data: # If using a grounding prompt to task
|
| 360 |
+
CoT_prompt = self.config.datasets.vla_data.get("CoT_prompt", "")
|
| 361 |
+
prompt = CoT_prompt.replace("{instruction}", instruction)
|
| 362 |
+
else:
|
| 363 |
+
prompt = instruction
|
| 364 |
+
|
| 365 |
+
content.append({"type": "text", "text": prompt})
|
| 366 |
+
msg = [{"role": "user", "content": content}]
|
| 367 |
+
|
| 368 |
+
if solutions is not None:
|
| 369 |
+
solution = solutions[len(messages)]
|
| 370 |
+
msg.append({"role": "assistant", "content": [{"type": "text", "text": solution}]})
|
| 371 |
+
messages.append(msg)
|
| 372 |
+
|
| 373 |
+
profile_timing = self._profile_timing_enabled()
|
| 374 |
+
build_timing = {}
|
| 375 |
+
|
| 376 |
+
t_processor = time.perf_counter() if profile_timing else None
|
| 377 |
+
with _stage(profiler, "starvla_qwen_processor_ms"):
|
| 378 |
+
batch_inputs = self.processor.apply_chat_template(
|
| 379 |
+
messages, tokenize=True, padding=True, add_generation_prompt=True, return_dict=True, return_tensors="pt"
|
| 380 |
+
)
|
| 381 |
+
if profile_timing:
|
| 382 |
+
build_timing["timing/qwen_processor"] = time.perf_counter() - t_processor
|
| 383 |
+
|
| 384 |
+
# if solutions, mask out the solution tokens in labels
|
| 385 |
+
if solutions is not None: # here only for fast_tokenizer now.
|
| 386 |
+
action_token_min = _ACTION_TOKEN_MIN # how can we know this range? --> we has other way for this, but is slower see qwenhelix branch
|
| 387 |
+
action_token_max = _ACTION_TOKEN_MAX # here only for fast_tokenizer, see starVLA/model/modules/vlm/tools/add_qwen_special_tokens/README.md
|
| 388 |
+
labels = batch_inputs["input_ids"].clone()
|
| 389 |
+
# For each sequence in the batch, find the first occurrence of an action token.
|
| 390 |
+
for i in range(labels.size(0)):
|
| 391 |
+
seq = labels[i]
|
| 392 |
+
# Create a mask for tokens within the action token range.
|
| 393 |
+
mask_seq = (seq >= action_token_min) & (seq <= action_token_max)
|
| 394 |
+
nonzero_indices = torch.nonzero(mask_seq, as_tuple=False)
|
| 395 |
+
if nonzero_indices.numel() > 0:
|
| 396 |
+
first_action_index = nonzero_indices[0].item()
|
| 397 |
+
# Mask out all tokens before the first action token.
|
| 398 |
+
seq[:first_action_index] = IGNORE_INDEX
|
| 399 |
+
else:
|
| 400 |
+
# If no action token is found, mask the entire sequence.
|
| 401 |
+
seq[:] = IGNORE_INDEX
|
| 402 |
+
RuntimeWarning(
|
| 403 |
+
"action token are on in yout tokenizer, plz see starVLA/model/modules/vlm/tools/add_qwen_special_tokens/README.md."
|
| 404 |
+
)
|
| 405 |
+
|
| 406 |
+
labels[labels == self.processor.tokenizer.pad_token_id] = -100 ## mask out pad tokens as well
|
| 407 |
+
batch_inputs["labels"] = labels
|
| 408 |
+
|
| 409 |
+
t_h2d = time.perf_counter() if profile_timing else None
|
| 410 |
+
with _stage(profiler, "starvla_qwen_h2d_ms"):
|
| 411 |
+
batch_inputs = batch_inputs.to(self.model.device)
|
| 412 |
+
if profile_timing:
|
| 413 |
+
self._profile_sync()
|
| 414 |
+
build_timing["timing/qwen_h2d"] = time.perf_counter() - t_h2d
|
| 415 |
+
self._last_build_timing = build_timing
|
| 416 |
+
return batch_inputs
|
| 417 |
+
|
| 418 |
+
|
| 419 |
+
if __name__ == "__main__":
|
| 420 |
+
import argparse
|
| 421 |
+
import os
|
| 422 |
+
|
| 423 |
+
from omegaconf import OmegaConf
|
| 424 |
+
|
| 425 |
+
parser = argparse.ArgumentParser()
|
| 426 |
+
parser.add_argument(
|
| 427 |
+
"--config_yaml",
|
| 428 |
+
type=str,
|
| 429 |
+
default="examples/SimplerEnv/train_files/starvla_cotrain_oxe.yaml",
|
| 430 |
+
help="Path to YAML config",
|
| 431 |
+
)
|
| 432 |
+
args, clipargs = parser.parse_known_args()
|
| 433 |
+
|
| 434 |
+
if os.getenv("DEBUGPY_ENABLE", "0") == "1":
|
| 435 |
+
import debugpy
|
| 436 |
+
debugpy.listen(("0.0.0.0", 10092))
|
| 437 |
+
print("Rank 0 waiting for debugger attach on port 10092...")
|
| 438 |
+
debugpy.wait_for_client()
|
| 439 |
+
|
| 440 |
+
cfg = OmegaConf.load(args.config_yaml)
|
| 441 |
+
|
| 442 |
+
cfg.framework.qwenvl.base_vlm = "./playground/Pretrained_models/Qwen3-VL-4B-Instruct"
|
| 443 |
+
qwen_vl = _QWen3_VL_Interface(cfg)
|
| 444 |
+
pass
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/QwenOFT.py
ADDED
|
@@ -0,0 +1,1244 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025 starVLA community. All rights reserved.
|
| 2 |
+
# Licensed under the MIT License, Version 1.0 (the "License");
|
| 3 |
+
# Implemented by [Jinhui YE / HKUST University] in [2025].
|
| 4 |
+
|
| 5 |
+
"""
|
| 6 |
+
Qwen-OFT Framework
|
| 7 |
+
|
| 8 |
+
A lightweight implementation that uses an action special token to parallelly predict continuous actions
|
| 9 |
+
conditioned on multi-view images plus a language instruction (shares parameters with the VLM).
|
| 10 |
+
Inspired by OpenVLA-OFT
|
| 11 |
+
Key Points:
|
| 12 |
+
- Qwen2.5 vision-language backbone
|
| 13 |
+
- Injects an action special token into the VLM
|
| 14 |
+
- Continuous action prediction via L1 regression over the action special token hidden states
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
Note: How to add special tokens to Qwen2.5:
|
| 18 |
+
download our model checkpoint with special tokens added: https://huggingface.co/StarVLA/Qwen2.5-VL-3B-Instruct-Action
|
| 19 |
+
or /starVLA/model/modules/vlm/tools/add_qwen_special_tokens/README.md (adpat a little code)
|
| 20 |
+
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
from dataclasses import dataclass, field
|
| 24 |
+
import time
|
| 25 |
+
from typing import Any, List, Optional, Tuple
|
| 26 |
+
|
| 27 |
+
import numpy as np
|
| 28 |
+
import torch
|
| 29 |
+
import torch.nn as nn
|
| 30 |
+
import torch.nn.functional as F
|
| 31 |
+
from PIL import Image
|
| 32 |
+
|
| 33 |
+
from deployment.model_server.tools.image_tools import to_pil_preserve
|
| 34 |
+
from starVLA.model.tools import FRAMEWORK_REGISTRY
|
| 35 |
+
from starVLA.training.trainer_utils import initialize_overwatch
|
| 36 |
+
|
| 37 |
+
logger = initialize_overwatch(__name__)
|
| 38 |
+
|
| 39 |
+
# HuggingFace Default / LLaMa-2 IGNORE_INDEX (for labels)
|
| 40 |
+
IGNORE_INDEX = -100
|
| 41 |
+
|
| 42 |
+
from starVLA.model.framework.base_framework import baseframework
|
| 43 |
+
from starVLA.model.framework.share_tools import add_discretized_state_to_instruction, merge_framework_config
|
| 44 |
+
from starVLA.model.modules.action_model.MLP_ActionHeader import get_action_model
|
| 45 |
+
from starVLA.model.modules.vlm import get_vlm_model
|
| 46 |
+
from starVLA.training.trainer_utils.trainer_tools import resize_images
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
# ──────────────────────────────────────────────────────────────────────
|
| 50 |
+
# Default Config for QwenOFT
|
| 51 |
+
# - Documents every framework-level parameter with type + description
|
| 52 |
+
# - YAML values override these defaults; extra YAML keys are preserved
|
| 53 |
+
# ──────────────────────────────────────────────────────────────────────
|
| 54 |
+
@dataclass
|
| 55 |
+
class QwenOFTDefaultConfig:
|
| 56 |
+
"""QwenOFT framework default parameters.
|
| 57 |
+
|
| 58 |
+
All fields can be overridden by the corresponding key in the YAML
|
| 59 |
+
``framework:`` section. Extra YAML keys not listed here are kept
|
| 60 |
+
as-is (Config-as-API flexibility).
|
| 61 |
+
"""
|
| 62 |
+
|
| 63 |
+
# --- Registry identifier (must match @FRAMEWORK_REGISTRY.register) ---
|
| 64 |
+
name: str = "QwenOFT"
|
| 65 |
+
|
| 66 |
+
# === VLM backbone (Qwen2.5-VL / Qwen3-VL) ===
|
| 67 |
+
qwenvl: dict = field(
|
| 68 |
+
default_factory=lambda: {
|
| 69 |
+
# Path to base VLM checkpoint (local or HF hub id)
|
| 70 |
+
"base_vlm": "./playground/Pretrained_models/Qwen3-VL-4B-Instruct-Action",
|
| 71 |
+
# Attention implementation: "flash_attention_2" | "eager" | "sdpa"
|
| 72 |
+
"attn_implementation": "flash_attention_2",
|
| 73 |
+
}
|
| 74 |
+
)
|
| 75 |
+
|
| 76 |
+
# === Action head (MLP regression over action special tokens) ===
|
| 77 |
+
action_model: dict = field(
|
| 78 |
+
default_factory=lambda: {
|
| 79 |
+
# Action head architecture type
|
| 80 |
+
"action_model_type": "MLP",
|
| 81 |
+
# Dimensionality of each action vector (e.g., 7 for 6-DoF + gripper)
|
| 82 |
+
"action_dim": 7,
|
| 83 |
+
# Proprioceptive state dimension for continuous_projector mode
|
| 84 |
+
"state_dim": 7,
|
| 85 |
+
# Hidden dim for the action MLP (auto-set from VLM hidden_size at runtime)
|
| 86 |
+
"action_hidden_dim": 2560,
|
| 87 |
+
# How many future steps to predict
|
| 88 |
+
"future_action_window_size": 8,
|
| 89 |
+
# How many past steps included in action chunk (usually 0)
|
| 90 |
+
"past_action_window_size": 0,
|
| 91 |
+
# Loss over predicted actions. Supported: "l1", "discrete_ce",
|
| 92 |
+
# "multibinary_bce", "asterix_factorized_ce".
|
| 93 |
+
# "multibinary_ce" is accepted as a CLI alias for "multibinary_bce".
|
| 94 |
+
"loss_type": "l1",
|
| 95 |
+
# State conditioning: preserve the existing text-bin path by default.
|
| 96 |
+
"state_encoding": "discretized_text",
|
| 97 |
+
}
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
@FRAMEWORK_REGISTRY.register("QwenOFT")
|
| 102 |
+
class Qwenvl_OFT(baseframework):
|
| 103 |
+
"""
|
| 104 |
+
Multimodal vision-language-action model (OFT variant).
|
| 105 |
+
|
| 106 |
+
Components:
|
| 107 |
+
- Qwen2.5-VL / Qwen3-VL backbone for fused language/vision token embeddings
|
| 108 |
+
- Action special token injected into the VLM sequence
|
| 109 |
+
- MLP regression head over action token hidden states (L1 loss)
|
| 110 |
+
|
| 111 |
+
Focus: Predict future continuous actions conditioned on images + instruction.
|
| 112 |
+
"""
|
| 113 |
+
|
| 114 |
+
def __init__(
|
| 115 |
+
self,
|
| 116 |
+
config: Optional[dict] = None,
|
| 117 |
+
**kwargs,
|
| 118 |
+
) -> None:
|
| 119 |
+
"""
|
| 120 |
+
Construct all submodules and cache key configuration values.
|
| 121 |
+
|
| 122 |
+
Args:
|
| 123 |
+
config: Hierarchical configuration (OmegaConf/dict) containing framework + trainer sections.
|
| 124 |
+
**kwargs: Reserved for future overrides (unused).
|
| 125 |
+
"""
|
| 126 |
+
super().__init__()
|
| 127 |
+
# Merge framework defaults with YAML config (YAML wins on conflicts)
|
| 128 |
+
self.config = merge_framework_config(QwenOFTDefaultConfig, config)
|
| 129 |
+
self.qwen_vl_interface = get_vlm_model(config=self.config)
|
| 130 |
+
# align action_hidden_dim to VLM hidden_size at runtime
|
| 131 |
+
self.config.framework.action_model.action_hidden_dim = self.qwen_vl_interface.model.config.hidden_size
|
| 132 |
+
self.action_model = get_action_model(config=self.config)
|
| 133 |
+
|
| 134 |
+
# `action_horizon` is the single source of truth for chunk length.
|
| 135 |
+
# Legacy aliases (`future_action_window_size`, `past_action_window_size`)
|
| 136 |
+
# are normalised upstream by `share_tools.apply_config_compat`, so we
|
| 137 |
+
# only ever read `action_horizon` here.
|
| 138 |
+
self.action_horizon = int(self.config.framework.action_model.action_horizon)
|
| 139 |
+
self.chunk_len = self.action_horizon
|
| 140 |
+
self.action_dim = int(self.config.framework.action_model.action_dim)
|
| 141 |
+
self.action_env_dim = int(getattr(self.config.framework.action_model, "action_env_dim", self.action_dim))
|
| 142 |
+
self.action_loss_type = str(getattr(self.config.framework.action_model, "loss_type", "l1")).lower()
|
| 143 |
+
self.state_encoding = str(self.config.framework.action_model.state_encoding)
|
| 144 |
+
if self.state_encoding not in {"discretized_text", "continuous_projector"}:
|
| 145 |
+
raise ValueError(f"Unsupported state_encoding: {self.state_encoding}")
|
| 146 |
+
if self.state_encoding == "continuous_projector":
|
| 147 |
+
self.action_model.state_projector = nn.Linear(
|
| 148 |
+
int(self.config.framework.action_model.state_dim),
|
| 149 |
+
int(self.config.framework.action_model.action_hidden_dim),
|
| 150 |
+
)
|
| 151 |
+
cross_task_cfg = getattr(getattr(self.config, "rl_games", None), "cross_task", None)
|
| 152 |
+
self.loss_by_task = self._to_plain_dict(getattr(cross_task_cfg, "loss_by_task", None))
|
| 153 |
+
self.loss_weight_by_task = self._to_plain_dict(getattr(cross_task_cfg, "loss_weight_by_task", None))
|
| 154 |
+
# self.hidden_dim = config.framework.action_model.action_hidden_dim
|
| 155 |
+
|
| 156 |
+
self.action_token = "🔍" # TODO also can add spacail token to Qwen, but too complex
|
| 157 |
+
self.action_token_id = self.qwen_vl_interface.processor.tokenizer("🔍", add_special_tokens=False)["input_ids"][0]
|
| 158 |
+
|
| 159 |
+
# --- Fixed-size KV memory; default OFF so existing paths are untouched. ---
|
| 160 |
+
kv_cfg = getattr(self.config.framework, "kv_memory", None)
|
| 161 |
+
self.kv_memory_enabled = bool(getattr(kv_cfg, "enabled", False)) if kv_cfg is not None else False
|
| 162 |
+
self.kv_window = int(getattr(kv_cfg, "window", 4)) if kv_cfg is not None else 4
|
| 163 |
+
self.kv_rollout_len = int(getattr(kv_cfg, "rollout_len", max(self.kv_window + 1, 2))) if kv_cfg is not None else self.kv_window + 1
|
| 164 |
+
# Packed single-forward training path (StreamingLLM-style sliding-window+sink
|
| 165 |
+
# mask via FlexAttention) — replaces the per-frame Python loop. Eval/live still
|
| 166 |
+
# uses the streaming KV memory (`_predict_action_memory`). OFF by default so the
|
| 167 |
+
# legacy loop stays the reference; enable per experiment via
|
| 168 |
+
# `framework.kv_memory.packed_train: true`.
|
| 169 |
+
self.kv_train_packed = bool(getattr(kv_cfg, "packed_train", False)) if kv_cfg is not None else False
|
| 170 |
+
# Per-step re-based sink for the packed path: replicate the (short) text
|
| 171 |
+
# prefix once per step and re-base its M-RoPE positions so the sink→frame
|
| 172 |
+
# distance matches the eval rolling-KV layout exactly (StreamingLLM
|
| 173 |
+
# "positions within the cache"), instead of one global sink whose distance
|
| 174 |
+
# grows with the step index. ON by default — the growing-distance sink was
|
| 175 |
+
# the train/eval forward mismatch behind the packed run's eval collapse.
|
| 176 |
+
# Set false to fall back to the single global sink for A/B.
|
| 177 |
+
self.kv_rebased_sink = bool(getattr(kv_cfg, "rebased_sink", True)) if kv_cfg is not None else True
|
| 178 |
+
if self.state_encoding == "continuous_projector" and self.kv_memory_enabled:
|
| 179 |
+
raise ValueError("continuous_projector requires framework.kv_memory.enabled=false")
|
| 180 |
+
# Per-stream (eval slot) memories; rebuilt per sample during training.
|
| 181 |
+
self._kv_memories: dict = {}
|
| 182 |
+
|
| 183 |
+
# L1 loss
|
| 184 |
+
self.l1_loss = nn.L1Loss()
|
| 185 |
+
|
| 186 |
+
def _profile_timing_enabled(self) -> bool:
|
| 187 |
+
return self.config.trainer.profile_timing.enabled
|
| 188 |
+
|
| 189 |
+
def _profile_sync(self) -> None:
|
| 190 |
+
if self._profile_timing_enabled() and torch.cuda.is_available():
|
| 191 |
+
torch.cuda.synchronize()
|
| 192 |
+
|
| 193 |
+
def _profile_start(self) -> float:
|
| 194 |
+
self._profile_sync()
|
| 195 |
+
return time.perf_counter()
|
| 196 |
+
|
| 197 |
+
def _profile_elapsed(self, start: float) -> float:
|
| 198 |
+
self._profile_sync()
|
| 199 |
+
return time.perf_counter() - start
|
| 200 |
+
|
| 201 |
+
@staticmethod
|
| 202 |
+
def _to_plain_dict(value: Any) -> dict[str, Any]:
|
| 203 |
+
if value is None or value == "":
|
| 204 |
+
return {}
|
| 205 |
+
if isinstance(value, dict):
|
| 206 |
+
return {str(key): item for key, item in value.items()}
|
| 207 |
+
if hasattr(value, "items"):
|
| 208 |
+
return {str(key): item for key, item in value.items()}
|
| 209 |
+
return {}
|
| 210 |
+
|
| 211 |
+
def _prepare_action_array(self, action: Any) -> np.ndarray:
|
| 212 |
+
values = np.asarray(action)
|
| 213 |
+
if values.ndim == 1:
|
| 214 |
+
values = values[None, :]
|
| 215 |
+
if values.shape[-1] == self.action_dim:
|
| 216 |
+
return values
|
| 217 |
+
if values.shape[-1] > self.action_dim:
|
| 218 |
+
return values[..., : self.action_dim]
|
| 219 |
+
pad_width = [(0, 0)] * values.ndim
|
| 220 |
+
pad_width[-1] = (0, self.action_dim - values.shape[-1])
|
| 221 |
+
return np.pad(values, pad_width, mode="constant")
|
| 222 |
+
|
| 223 |
+
def _compute_action_loss_for_type(
|
| 224 |
+
self,
|
| 225 |
+
pred_actions: torch.Tensor,
|
| 226 |
+
actions_target: torch.Tensor,
|
| 227 |
+
*,
|
| 228 |
+
loss_type: str,
|
| 229 |
+
action_env_dims: Optional[List[int]] = None,
|
| 230 |
+
) -> torch.Tensor:
|
| 231 |
+
loss_type = str(loss_type).lower()
|
| 232 |
+
effective_dim = min(self.action_env_dim, pred_actions.shape[-1], actions_target.shape[-1])
|
| 233 |
+
if effective_dim <= 0:
|
| 234 |
+
raise ValueError(
|
| 235 |
+
f"Invalid action_env_dim={self.action_env_dim} for predicted shape={pred_actions.shape} "
|
| 236 |
+
f"and target shape={actions_target.shape}"
|
| 237 |
+
)
|
| 238 |
+
|
| 239 |
+
if loss_type in {"discrete_ce", "ce", "cross_entropy"}:
|
| 240 |
+
if action_env_dims is not None:
|
| 241 |
+
dims = torch.as_tensor(action_env_dims, device=pred_actions.device, dtype=torch.long)
|
| 242 |
+
if dims.numel() != pred_actions.shape[0]:
|
| 243 |
+
raise ValueError(f"Expected {pred_actions.shape[0]} action_env_dims, got {dims.numel()}")
|
| 244 |
+
losses = []
|
| 245 |
+
weights = []
|
| 246 |
+
for dim_value in torch.unique(dims).tolist():
|
| 247 |
+
dim = int(min(dim_value, pred_actions.shape[-1], actions_target.shape[-1]))
|
| 248 |
+
if dim < 2:
|
| 249 |
+
raise ValueError(f"discrete_ce requires at least 2 classes, got action_env_dim={dim}")
|
| 250 |
+
mask = dims == int(dim_value)
|
| 251 |
+
logits = pred_actions[mask, ..., :dim]
|
| 252 |
+
target_class = actions_target[mask, ..., :dim].argmax(dim=-1).long()
|
| 253 |
+
losses.append(F.cross_entropy(logits.reshape(-1, dim), target_class.reshape(-1), reduction="sum"))
|
| 254 |
+
weights.append(target_class.numel())
|
| 255 |
+
total_weight = max(1, int(sum(weights)))
|
| 256 |
+
return sum(losses) / total_weight
|
| 257 |
+
|
| 258 |
+
if effective_dim < 2:
|
| 259 |
+
raise ValueError(
|
| 260 |
+
f"action_model.loss_type={loss_type!r} requires at least 2 action classes, "
|
| 261 |
+
f"got effective_dim={effective_dim}"
|
| 262 |
+
)
|
| 263 |
+
logits = pred_actions[..., :effective_dim]
|
| 264 |
+
target_class = actions_target[..., :effective_dim].argmax(dim=-1).long()
|
| 265 |
+
return F.cross_entropy(
|
| 266 |
+
logits.reshape(-1, effective_dim),
|
| 267 |
+
target_class.reshape(-1),
|
| 268 |
+
)
|
| 269 |
+
|
| 270 |
+
if loss_type in {"asterix_factorized_ce", "factorized_6_ce", "factorized_ce"}:
|
| 271 |
+
if effective_dim < 6:
|
| 272 |
+
raise ValueError(
|
| 273 |
+
f"action_model.loss_type={loss_type!r} requires at least 6 action logits, "
|
| 274 |
+
f"got effective_dim={effective_dim}"
|
| 275 |
+
)
|
| 276 |
+
vertical_logits = pred_actions[..., 0:3]
|
| 277 |
+
vertical_target = actions_target[..., 0:3].argmax(dim=-1).long()
|
| 278 |
+
horizontal_logits = pred_actions[..., 3:6]
|
| 279 |
+
horizontal_target = actions_target[..., 3:6].argmax(dim=-1).long()
|
| 280 |
+
vertical_loss = F.cross_entropy(
|
| 281 |
+
vertical_logits.reshape(-1, 3),
|
| 282 |
+
vertical_target.reshape(-1),
|
| 283 |
+
)
|
| 284 |
+
horizontal_loss = F.cross_entropy(
|
| 285 |
+
horizontal_logits.reshape(-1, 3),
|
| 286 |
+
horizontal_target.reshape(-1),
|
| 287 |
+
)
|
| 288 |
+
return 0.5 * (vertical_loss + horizontal_loss)
|
| 289 |
+
|
| 290 |
+
if loss_type in {"multibinary_bce", "multibinary_ce", "bce", "binary_cross_entropy"}:
|
| 291 |
+
logits = pred_actions[..., :effective_dim]
|
| 292 |
+
targets = (actions_target[..., :effective_dim] > 0).to(dtype=logits.dtype)
|
| 293 |
+
return F.binary_cross_entropy_with_logits(logits, targets)
|
| 294 |
+
|
| 295 |
+
if loss_type in {"mse", "l2"}:
|
| 296 |
+
return F.mse_loss(
|
| 297 |
+
pred_actions[..., :effective_dim],
|
| 298 |
+
actions_target[..., :effective_dim],
|
| 299 |
+
)
|
| 300 |
+
|
| 301 |
+
if loss_type not in {"l1", "mae"}:
|
| 302 |
+
raise ValueError(
|
| 303 |
+
f"Unsupported action_model.loss_type={loss_type!r}; "
|
| 304 |
+
"expected one of: l1, discrete_ce, multibinary_bce, asterix_factorized_ce"
|
| 305 |
+
)
|
| 306 |
+
|
| 307 |
+
return self.l1_loss(
|
| 308 |
+
pred_actions[..., :effective_dim],
|
| 309 |
+
actions_target[..., :effective_dim],
|
| 310 |
+
)
|
| 311 |
+
|
| 312 |
+
def _compute_action_loss(
|
| 313 |
+
self,
|
| 314 |
+
pred_actions: torch.Tensor,
|
| 315 |
+
actions_target: torch.Tensor,
|
| 316 |
+
action_env_dims: Optional[List[int]] = None,
|
| 317 |
+
rl_games_tasks: Optional[List[str]] = None,
|
| 318 |
+
action_loss_mask: Optional[torch.Tensor] = None,
|
| 319 |
+
) -> torch.Tensor:
|
| 320 |
+
if action_loss_mask is not None:
|
| 321 |
+
error = (pred_actions[..., :self.action_env_dim] - actions_target[..., :self.action_env_dim]).abs().mean(dim=-1)
|
| 322 |
+
error = error.masked_fill(~action_loss_mask, 0)
|
| 323 |
+
return (error.sum(dim=-1) / action_loss_mask.sum(dim=-1)).mean()
|
| 324 |
+
if self.loss_by_task and rl_games_tasks is not None:
|
| 325 |
+
if len(rl_games_tasks) != pred_actions.shape[0]:
|
| 326 |
+
raise ValueError(f"Expected {pred_actions.shape[0]} task labels, got {len(rl_games_tasks)}")
|
| 327 |
+
losses = []
|
| 328 |
+
weights = []
|
| 329 |
+
for task_name in sorted(set(str(task) for task in rl_games_tasks)):
|
| 330 |
+
mask_values = [str(task) == task_name for task in rl_games_tasks]
|
| 331 |
+
mask = torch.as_tensor(mask_values, device=pred_actions.device, dtype=torch.bool)
|
| 332 |
+
if not bool(mask.any()):
|
| 333 |
+
continue
|
| 334 |
+
task_loss_type = str(self.loss_by_task.get(task_name, self.action_loss_type)).lower()
|
| 335 |
+
task_dims = (
|
| 336 |
+
[int(dim) for dim, keep in zip(action_env_dims, mask_values) if keep]
|
| 337 |
+
if action_env_dims is not None
|
| 338 |
+
else None
|
| 339 |
+
)
|
| 340 |
+
task_loss = self._compute_action_loss_for_type(
|
| 341 |
+
pred_actions[mask],
|
| 342 |
+
actions_target[mask],
|
| 343 |
+
loss_type=task_loss_type,
|
| 344 |
+
action_env_dims=task_dims,
|
| 345 |
+
)
|
| 346 |
+
task_weight = float(self.loss_weight_by_task.get(task_name, 1.0))
|
| 347 |
+
sample_count = int(mask.sum().item())
|
| 348 |
+
losses.append(task_loss * task_weight * sample_count)
|
| 349 |
+
weights.append(task_weight * sample_count)
|
| 350 |
+
if losses:
|
| 351 |
+
return sum(losses) / max(1.0, float(sum(weights)))
|
| 352 |
+
|
| 353 |
+
return self._compute_action_loss_for_type(
|
| 354 |
+
pred_actions,
|
| 355 |
+
actions_target,
|
| 356 |
+
loss_type=self.action_loss_type,
|
| 357 |
+
action_env_dims=action_env_dims,
|
| 358 |
+
)
|
| 359 |
+
|
| 360 |
+
def _forward_qwen_last_hidden(self, qwen_inputs: dict) -> torch.Tensor:
|
| 361 |
+
"""
|
| 362 |
+
Return only the final VLM hidden state when the interface supports it.
|
| 363 |
+
|
| 364 |
+
Requesting ``output_hidden_states=True`` from Hugging Face materializes
|
| 365 |
+
every layer's activations. For OFT we only need the last layer, so the
|
| 366 |
+
Qwen3 interface exposes a leaner path that preserves the practical memory
|
| 367 |
+
savings from gradient checkpointing.
|
| 368 |
+
"""
|
| 369 |
+
|
| 370 |
+
if hasattr(self.qwen_vl_interface, "forward_last_hidden"):
|
| 371 |
+
return self.qwen_vl_interface.forward_last_hidden(**qwen_inputs)
|
| 372 |
+
|
| 373 |
+
qwenvl_outputs = self.qwen_vl_interface(
|
| 374 |
+
**qwen_inputs,
|
| 375 |
+
output_attentions=False,
|
| 376 |
+
output_hidden_states=True,
|
| 377 |
+
return_dict=True,
|
| 378 |
+
use_cache=False,
|
| 379 |
+
)
|
| 380 |
+
return qwenvl_outputs.hidden_states[-1]
|
| 381 |
+
|
| 382 |
+
def _state_conditioned_instructions(self, instructions, state):
|
| 383 |
+
if state is not None and self.state_encoding == "discretized_text":
|
| 384 |
+
return self.add_discretized_state_to_instruction(instructions, state)
|
| 385 |
+
return instructions
|
| 386 |
+
|
| 387 |
+
def _condition_action_queries(self, action_queries, state):
|
| 388 |
+
if self.state_encoding == "discretized_text":
|
| 389 |
+
return action_queries
|
| 390 |
+
state_tensor = torch.as_tensor(
|
| 391 |
+
np.stack(state), device=action_queries.device, dtype=action_queries.dtype
|
| 392 |
+
).squeeze(1)
|
| 393 |
+
return action_queries + self.action_model.state_projector(state_tensor).unsqueeze(1)
|
| 394 |
+
|
| 395 |
+
def forward(
|
| 396 |
+
self,
|
| 397 |
+
examples: List[dict] = None,
|
| 398 |
+
**kwargs,
|
| 399 |
+
) -> Tuple:
|
| 400 |
+
"""
|
| 401 |
+
Training forward: directly regress future actions (no diffusion).
|
| 402 |
+
|
| 403 |
+
Flow:
|
| 404 |
+
1. Build QwenVL inputs (images + instruction tokens)
|
| 405 |
+
2. Extract hidden states from configured layer range
|
| 406 |
+
7. Predict action and compute L1 loss
|
| 407 |
+
|
| 408 |
+
Args:
|
| 409 |
+
examples: List[dict], each dict requires:
|
| 410 |
+
- image: List[PIL.Image] (multi-view)
|
| 411 |
+
- lang: str instruction
|
| 412 |
+
- action: np.ndarray or list shaped [T, action_dim]
|
| 413 |
+
**kwargs: Reserved.
|
| 414 |
+
|
| 415 |
+
Returns:
|
| 416 |
+
dict:
|
| 417 |
+
action_loss (torch.Tensor): Scalar diffusion noise prediction loss.
|
| 418 |
+
"""
|
| 419 |
+
if self.kv_memory_enabled:
|
| 420 |
+
if self.kv_train_packed:
|
| 421 |
+
return self._forward_memory_packed(examples)
|
| 422 |
+
return self._forward_memory(examples)
|
| 423 |
+
|
| 424 |
+
batch_images = [example["image"] for example in examples] # [B,[PLT]]
|
| 425 |
+
instructions = [example["lang"] for example in examples] # [B, str]
|
| 426 |
+
actions = [self._prepare_action_array(example["action"]) for example in examples] # label [B, len, action_dim]
|
| 427 |
+
action_env_dims = [int(example.get("action_env_dim", self.action_env_dim)) for example in examples]
|
| 428 |
+
rl_games_tasks = [str(example.get("rl_games_task", "")) for example in examples]
|
| 429 |
+
if not any(rl_games_tasks):
|
| 430 |
+
rl_games_tasks = None
|
| 431 |
+
state = (
|
| 432 |
+
[example["state"] for example in examples] if "state" in examples[0] else None
|
| 433 |
+
) # List[ndarray (1, state_dim)] or None
|
| 434 |
+
|
| 435 |
+
instructions = self._state_conditioned_instructions(instructions, state)
|
| 436 |
+
|
| 437 |
+
# step 0: add special action token to instruction
|
| 438 |
+
action_tokens = (
|
| 439 |
+
self.action_token * self.chunk_len
|
| 440 |
+
) # can't add " " between two tokens, otherwise will be tokenized to multiple tokens
|
| 441 |
+
prompt_suffix = f" Please predict the next {self.chunk_len} robot actions: <action>{action_tokens}<action>."
|
| 442 |
+
instructions = [instruction + prompt_suffix for instruction in instructions]
|
| 443 |
+
|
| 444 |
+
profile_timing = self._profile_timing_enabled()
|
| 445 |
+
timing_metrics = {}
|
| 446 |
+
batch_stats = {}
|
| 447 |
+
|
| 448 |
+
# Step 1: QWenVL input format
|
| 449 |
+
t_inputs = self._profile_start() if profile_timing else None
|
| 450 |
+
qwen_inputs = self.qwen_vl_interface.build_qwenvl_inputs(images=batch_images, instructions=instructions)
|
| 451 |
+
if profile_timing:
|
| 452 |
+
timing_metrics["timing/qwen_input_build_total"] = self._profile_elapsed(t_inputs)
|
| 453 |
+
timing_metrics.update(self.qwen_vl_interface._last_build_timing)
|
| 454 |
+
input_ids = qwen_inputs["input_ids"]
|
| 455 |
+
attention_mask = qwen_inputs["attention_mask"]
|
| 456 |
+
effective_tokens = attention_mask.sum()
|
| 457 |
+
effective_token_count = effective_tokens.detach().float().item()
|
| 458 |
+
batch_stats["batch/size"] = float(len(examples))
|
| 459 |
+
batch_stats["batch/input_len_max"] = float(input_ids.shape[1])
|
| 460 |
+
batch_stats["batch/input_len_mean"] = float(effective_token_count / input_ids.shape[0])
|
| 461 |
+
batch_stats["batch/padding_ratio"] = float(1.0 - effective_token_count / float(attention_mask.numel()))
|
| 462 |
+
batch_stats["batch/effective_tokens"] = float(effective_token_count)
|
| 463 |
+
batch_stats["batch/image_count"] = float(sum(len(images) for images in batch_images))
|
| 464 |
+
if "pixel_values" in qwen_inputs:
|
| 465 |
+
batch_stats["batch/pixel_values_rows"] = float(qwen_inputs["pixel_values"].shape[0])
|
| 466 |
+
|
| 467 |
+
t_vlm = self._profile_start() if profile_timing else None
|
| 468 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 469 |
+
last_hidden = self._forward_qwen_last_hidden(qwen_inputs) # [B, L, H]
|
| 470 |
+
if profile_timing:
|
| 471 |
+
timing_metrics["timing/vlm_forward"] = self._profile_elapsed(t_vlm)
|
| 472 |
+
|
| 473 |
+
# Step 4: Action Expert Forward and Loss
|
| 474 |
+
t_action = self._profile_start() if profile_timing else None
|
| 475 |
+
with torch.autocast("cuda", dtype=torch.float32):
|
| 476 |
+
# Extract action token embeddings as action prediction queries
|
| 477 |
+
input_ids = qwen_inputs["input_ids"]
|
| 478 |
+
action_queries = self._gather_action_token_embeddings(
|
| 479 |
+
last_hidden, input_ids, action_token_id=self.action_token_id
|
| 480 |
+
) # [B, chunk_len, H]
|
| 481 |
+
action_queries = self._condition_action_queries(action_queries, state)
|
| 482 |
+
pred_actions = self.action_model.predict_action(action_queries) # (B, chunk_len, action_dim)
|
| 483 |
+
|
| 484 |
+
# Label alignment: take the last chunk_len segment
|
| 485 |
+
actions = torch.tensor(
|
| 486 |
+
np.array(actions), device=pred_actions.device, dtype=pred_actions.dtype
|
| 487 |
+
) # [B, T_full, action_dim]
|
| 488 |
+
actions_target = actions[:, -self.action_horizon :, :] # (B, action_horizon, action_dim)
|
| 489 |
+
|
| 490 |
+
action_loss_mask = None
|
| 491 |
+
if "action_loss_mask" in examples[0]:
|
| 492 |
+
action_loss_mask = torch.as_tensor(
|
| 493 |
+
np.asarray([example["action_loss_mask"] for example in examples]),
|
| 494 |
+
device=pred_actions.device,
|
| 495 |
+
dtype=torch.bool,
|
| 496 |
+
)
|
| 497 |
+
|
| 498 |
+
action_loss = self._compute_action_loss(
|
| 499 |
+
pred_actions,
|
| 500 |
+
actions_target,
|
| 501 |
+
action_env_dims=action_env_dims,
|
| 502 |
+
rl_games_tasks=rl_games_tasks,
|
| 503 |
+
action_loss_mask=action_loss_mask,
|
| 504 |
+
)
|
| 505 |
+
if profile_timing:
|
| 506 |
+
timing_metrics["timing/action_head_loss"] = self._profile_elapsed(t_action)
|
| 507 |
+
|
| 508 |
+
return {"action_loss": action_loss, "loss_weight": float(len(examples)), "timing": timing_metrics, "batch_stats": batch_stats}
|
| 509 |
+
|
| 510 |
+
@torch.inference_mode()
|
| 511 |
+
def predict_action(
|
| 512 |
+
self,
|
| 513 |
+
examples: List[dict] = None,
|
| 514 |
+
**kwargs: str,
|
| 515 |
+
) -> np.ndarray:
|
| 516 |
+
"""
|
| 517 |
+
|
| 518 |
+
Steps:
|
| 519 |
+
1. Resize images to training resolution (if specified)
|
| 520 |
+
2. Encode with QwenVL (hidden states retained)
|
| 521 |
+
6. Return normalized action trajectory
|
| 522 |
+
|
| 523 |
+
Returns:
|
| 524 |
+
dict:
|
| 525 |
+
normalized_actions (np.ndarray): Shape [B, T, action_dim], diffusion-sampled normalized actions.
|
| 526 |
+
"""
|
| 527 |
+
if type(examples) is not list:
|
| 528 |
+
examples = [examples]
|
| 529 |
+
if self.kv_memory_enabled:
|
| 530 |
+
return self._predict_action_memory(examples)
|
| 531 |
+
batch_images = [to_pil_preserve(example["image"]) for example in examples] # [B,[PLT]]
|
| 532 |
+
instructions = [example["lang"] for example in examples] # [B, str]
|
| 533 |
+
state = (
|
| 534 |
+
[example["state"] for example in examples] if "state" in examples[0] else None
|
| 535 |
+
) # List[ndarray (1, state_dim)] or None
|
| 536 |
+
|
| 537 |
+
instructions = self._state_conditioned_instructions(instructions, state)
|
| 538 |
+
|
| 539 |
+
train_obs_image_size = getattr(self.config.datasets.vla_data, "obs_image_size", None)
|
| 540 |
+
if train_obs_image_size:
|
| 541 |
+
batch_images = resize_images(batch_images, target_size=train_obs_image_size)
|
| 542 |
+
|
| 543 |
+
# step 0: add special action token to instruction
|
| 544 |
+
action_tokens = (
|
| 545 |
+
self.action_token * self.chunk_len
|
| 546 |
+
) # can't add " " between two tokens, otherwise will be tokenized to multiple tokens
|
| 547 |
+
prompt_suffix = f" Please predict the next {self.chunk_len} robot actions: <action>{action_tokens}<action>."
|
| 548 |
+
instructions = [instruction + prompt_suffix for instruction in instructions]
|
| 549 |
+
|
| 550 |
+
# Step 1: QWenVL input format
|
| 551 |
+
qwen_inputs = self.qwen_vl_interface.build_qwenvl_inputs(images=batch_images, instructions=instructions)
|
| 552 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 553 |
+
last_hidden = self._forward_qwen_last_hidden(qwen_inputs) # [B, L, H]
|
| 554 |
+
|
| 555 |
+
# Step 4: Action Expert Forward and Loss
|
| 556 |
+
with torch.autocast("cuda", dtype=torch.float32):
|
| 557 |
+
# Extract action token embeddings as action prediction queries
|
| 558 |
+
input_ids = qwen_inputs["input_ids"]
|
| 559 |
+
action_queries = self._gather_action_token_embeddings(
|
| 560 |
+
last_hidden, input_ids, action_token_id=self.action_token_id
|
| 561 |
+
) # [B, chunk_len, H]
|
| 562 |
+
action_queries = self._condition_action_queries(action_queries, state)
|
| 563 |
+
pred_actions = self.action_model.predict_action(action_queries) # (B, chunk_len, action_dim)
|
| 564 |
+
|
| 565 |
+
normalized_actions = pred_actions.detach().cpu().numpy()
|
| 566 |
+
return {"normalized_actions": normalized_actions}
|
| 567 |
+
|
| 568 |
+
# ──────────────────────────────────────────────────────────────────
|
| 569 |
+
# Fixed-size KV memory. Default OFF. The cache/rotation core is
|
| 570 |
+
# unit-proven (tests/test_kv_memory_equivalence.py); the processor-driven
|
| 571 |
+
# segment construction below still needs end-to-end validation against the
|
| 572 |
+
# real Qwen3-VL-4B checkpoint on GPU.
|
| 573 |
+
# ──────────────────────────────────────────────────────────────────
|
| 574 |
+
def reset_memory(self, slot_id=None) -> None:
|
| 575 |
+
"""Clear the KV memory for one eval slot (episode boundary), or all."""
|
| 576 |
+
if slot_id is None:
|
| 577 |
+
self._kv_memories.clear()
|
| 578 |
+
else:
|
| 579 |
+
self._kv_memories.pop(slot_id, None)
|
| 580 |
+
|
| 581 |
+
def _kv_components(self):
|
| 582 |
+
hf = self.qwen_vl_interface.model # Qwen3VLForConditionalGeneration
|
| 583 |
+
backbone = hf.model # Qwen3VLModel
|
| 584 |
+
text_model = backbone.language_model # Qwen3VLTextModel
|
| 585 |
+
return backbone, text_model.rotary_emb, len(text_model.layers), text_model.config
|
| 586 |
+
|
| 587 |
+
def _new_kv_memory(self):
|
| 588 |
+
from starVLA.model.modules.vlm.kv_memory import FrameKVMemory
|
| 589 |
+
|
| 590 |
+
_, rotary_emb, num_layers, text_config = self._kv_components()
|
| 591 |
+
return FrameKVMemory(rotary_emb, self.kv_window, num_layers, text_config)
|
| 592 |
+
|
| 593 |
+
def _build_text_first_inputs(self, frames, instruction):
|
| 594 |
+
"""Tokenize a text-first window: [instruction][frame imgs...][action suffix].
|
| 595 |
+
|
| 596 |
+
Returns the processor batch (input_ids, pixel_values, image_grid_thw, ...).
|
| 597 |
+
Static text comes first so its KV stays positionally stable across steps.
|
| 598 |
+
"""
|
| 599 |
+
action_tokens = self.action_token * self.chunk_len
|
| 600 |
+
action_suffix = f" Please predict the next {self.chunk_len} robot actions: <action>{action_tokens}<action>."
|
| 601 |
+
content = [{"type": "text", "text": instruction}]
|
| 602 |
+
content += [{"type": "image", "image": img} for img in frames]
|
| 603 |
+
content += [{"type": "text", "text": action_suffix}]
|
| 604 |
+
messages = [[{"role": "user", "content": content}]]
|
| 605 |
+
batch = self.qwen_vl_interface.processor.apply_chat_template(
|
| 606 |
+
messages, tokenize=True, padding=True, add_generation_prompt=True, return_dict=True, return_tensors="pt"
|
| 607 |
+
)
|
| 608 |
+
return batch.to(self.qwen_vl_interface.model.device)
|
| 609 |
+
|
| 610 |
+
def _kv_segments(self, input_ids_1d):
|
| 611 |
+
"""Partition a text-first window's ids into (prefix_len, [frame_lens], action_len).
|
| 612 |
+
|
| 613 |
+
A frame block spans its vision_start .. vision_end (inclusive); the prefix is
|
| 614 |
+
everything before the first vision_start; the action suffix is everything
|
| 615 |
+
after the last vision_end. Using the real special-token ids keeps eviction
|
| 616 |
+
leak-free (each evicted frame removes exactly its own markers).
|
| 617 |
+
"""
|
| 618 |
+
cfg = self.qwen_vl_interface.model.config
|
| 619 |
+
vstart = int(getattr(cfg, "vision_start_token_id", 151652))
|
| 620 |
+
vend = int(getattr(cfg, "vision_end_token_id", 151653))
|
| 621 |
+
ids = input_ids_1d.tolist()
|
| 622 |
+
starts = [i for i, t in enumerate(ids) if t == vstart]
|
| 623 |
+
ends = [i for i, t in enumerate(ids) if t == vend]
|
| 624 |
+
if not starts or not ends:
|
| 625 |
+
raise RuntimeError("KV memory: window inputs have no vision_start/end tokens")
|
| 626 |
+
action_start = ends[-1] + 1
|
| 627 |
+
bounds = starts + [action_start]
|
| 628 |
+
frame_lens = [bounds[i + 1] - bounds[i] for i in range(len(starts))]
|
| 629 |
+
return starts[0], frame_lens, len(ids) - action_start
|
| 630 |
+
|
| 631 |
+
def _kv_forward_step_batched(self, memories, frames, instruction):
|
| 632 |
+
"""Run ONE streaming KV-memory step for a group of same-layout streams and
|
| 633 |
+
return ``(last_hidden_new [B, new_len, H], new_input_ids [B, new_len])``.
|
| 634 |
+
|
| 635 |
+
``memories`` and ``frames`` are aligned lists (one entry per stream / eval
|
| 636 |
+
slot); all entries share ``instruction`` and history layout (grouped by the
|
| 637 |
+
caller). Two efficiencies vs a naive per-frame, per-step encode:
|
| 638 |
+
|
| 639 |
+
- Single-frame preprocessing: the image processor runs once per stream on its
|
| 640 |
+
OWN current frame. The window's multi-frame token layout (needed only for
|
| 641 |
+
M-RoPE positions via ``get_rope_index``) is reconstructed by replicating the
|
| 642 |
+
frame's token block, so duplicate frames are never re-preprocessed.
|
| 643 |
+
- Cross-stream batching: the streams' canonical KV blocks are stacked along the
|
| 644 |
+
batch dim, so the whole group is one forward; results are sliced back to each
|
| 645 |
+
stream's memory afterwards.
|
| 646 |
+
|
| 647 |
+
Past frames come from each stream's memory; only the current frame's pixels are
|
| 648 |
+
encoded fresh. ``B == 1`` (training rollout) reuses the same path with no
|
| 649 |
+
stacking, so gradients flow through the in-place memory updates.
|
| 650 |
+
"""
|
| 651 |
+
from starVLA.model.modules.vlm.kv_memory import FrameKVMemory, memory_step
|
| 652 |
+
|
| 653 |
+
backbone = self.qwen_vl_interface.model.model # Qwen3VLModel
|
| 654 |
+
B = len(memories)
|
| 655 |
+
n_past = memories[0].num_past_frames()
|
| 656 |
+
n_visible = n_past + 1
|
| 657 |
+
|
| 658 |
+
# One processor call per stream's current frame (no duplicate-frame work).
|
| 659 |
+
per_stream = [self._build_text_first_inputs([frame], instruction) for frame in frames]
|
| 660 |
+
ids1 = per_stream[0]["input_ids"][0]
|
| 661 |
+
cur_grid = per_stream[0]["image_grid_thw"][:1]
|
| 662 |
+
prefix_len, frame_lens, action_len = self._kv_segments(ids1)
|
| 663 |
+
frame_len = frame_lens[0]
|
| 664 |
+
|
| 665 |
+
# Reconstruct the n_visible-frame window ids by replicating the frame block,
|
| 666 |
+
# then let get_rope_index assign the (content-independent) M-RoPE positions.
|
| 667 |
+
prefix, action = ids1[:prefix_len], ids1[prefix_len + frame_len :]
|
| 668 |
+
block = ids1[prefix_len : prefix_len + frame_len]
|
| 669 |
+
window_ids = torch.cat([prefix] + [block] * n_visible + [action]).unsqueeze(0)
|
| 670 |
+
full_pos1, _ = backbone.get_rope_index(window_ids, image_grid_thw=cur_grid.repeat(n_visible, 1))
|
| 671 |
+
full_pos = full_pos1.expand(3, B, full_pos1.shape[-1]).contiguous()
|
| 672 |
+
|
| 673 |
+
batched = FrameKVMemory.stack(memories) if B > 1 else memories[0]
|
| 674 |
+
past_len = batched.past_length()
|
| 675 |
+
is_prefill = not batched.has_text()
|
| 676 |
+
expected_past = 0 if is_prefill else prefix_len + n_past * frame_len
|
| 677 |
+
if past_len != expected_past:
|
| 678 |
+
raise RuntimeError(
|
| 679 |
+
f"KV memory slice misaligned: memory past_length={past_len} but window "
|
| 680 |
+
f"expects {expected_past}. Token boundaries drifted across steps."
|
| 681 |
+
)
|
| 682 |
+
if is_prefill:
|
| 683 |
+
new_start, frame_start_in_new, prefill_text_len = 0, prefix_len, prefix_len
|
| 684 |
+
else:
|
| 685 |
+
new_start, frame_start_in_new, prefill_text_len = past_len, 0, 0
|
| 686 |
+
|
| 687 |
+
new_ids = window_ids[:, new_start:].expand(B, -1).contiguous()
|
| 688 |
+
pixels = torch.cat([b["pixel_values"] for b in per_stream], dim=0)
|
| 689 |
+
grid = cur_grid.repeat(B, 1)
|
| 690 |
+
|
| 691 |
+
last_hidden = memory_step(
|
| 692 |
+
backbone,
|
| 693 |
+
batched,
|
| 694 |
+
new_input_ids=new_ids,
|
| 695 |
+
pixel_values=pixels,
|
| 696 |
+
image_grid_thw=grid,
|
| 697 |
+
full_position_ids=full_pos,
|
| 698 |
+
frame_start_in_new=frame_start_in_new,
|
| 699 |
+
frame_len=frame_len,
|
| 700 |
+
prefill_text_len=prefill_text_len,
|
| 701 |
+
)
|
| 702 |
+
|
| 703 |
+
if B > 1:
|
| 704 |
+
for i, memory in enumerate(memories):
|
| 705 |
+
sliced = batched.slice(i)
|
| 706 |
+
memory.text, memory.frames = sliced.text, sliced.frames
|
| 707 |
+
return last_hidden, new_ids
|
| 708 |
+
|
| 709 |
+
# ------------------------------------------------------------------ #
|
| 710 |
+
# Packed single-forward training path (StreamingLLM-style mask).
|
| 711 |
+
#
|
| 712 |
+
# Instead of the per-frame Python loop (`_forward_memory`), pack the whole
|
| 713 |
+
# rollout into ONE sequence
|
| 714 |
+
# [text/sink] [frame_1][action_1] ... [frame_R][action_R]
|
| 715 |
+
# and run a SINGLE Qwen3-VL forward under a FlexAttention BlockMask that
|
| 716 |
+
# reproduces the streaming visibility:
|
| 717 |
+
# * the text prefix is an always-visible attention sink (StreamingLLM);
|
| 718 |
+
# * each frame attends only the last `kv_window` frames (sliding window);
|
| 719 |
+
# * each action read-out block is isolated (seen only by its own step), so
|
| 720 |
+
# the frame KV stream is bit-identical to the streaming loop / eval.
|
| 721 |
+
# Custom M-RoPE `position_ids` keep frame->frame and action->frame relative
|
| 722 |
+
# distances exactly matching eval; only the text-sink->frame absolute distance
|
| 723 |
+
# grows with step (accepted approximation — the sink is distance-robust).
|
| 724 |
+
# Eval/live (`_predict_action_memory`) is untouched and keeps the rolling KV.
|
| 725 |
+
# ------------------------------------------------------------------ #
|
| 726 |
+
def _packed_window_layout(self, frames, instruction):
|
| 727 |
+
"""Build the packed [text][f1][a1]...[fR][aR] window for ONE stream.
|
| 728 |
+
|
| 729 |
+
Token structure is content-independent (image placeholders are identical
|
| 730 |
+
per frame), so the prefix / frame / action blocks are reconstructed by
|
| 731 |
+
token-replication (matching `_kv_forward_step_batched`'s `window_ids`),
|
| 732 |
+
which guarantees each action block equals the per-step layout exactly.
|
| 733 |
+
|
| 734 |
+
Returns dict with: input_ids [1,L], pixel_values, image_grid_thw [R,3],
|
| 735 |
+
position_ids [3,1,L] (custom M-RoPE), kind [L] (0=text,1=frame,2=action),
|
| 736 |
+
step [L] (frame/step index for frame&action tokens, -1 for text),
|
| 737 |
+
action_idx [R, chunk_len] (packed indices of each step's action tokens).
|
| 738 |
+
"""
|
| 739 |
+
R = len(frames)
|
| 740 |
+
backbone = self.qwen_vl_interface.model.model # Qwen3VLModel
|
| 741 |
+
device = self.qwen_vl_interface.model.device
|
| 742 |
+
|
| 743 |
+
# One processor call per frame: identical token block, distinct pixels.
|
| 744 |
+
per_frame = [self._build_text_first_inputs([f], instruction) for f in frames]
|
| 745 |
+
ids1 = per_frame[0]["input_ids"][0]
|
| 746 |
+
grid1 = per_frame[0]["image_grid_thw"][:1] # [1,3]
|
| 747 |
+
prefix_len, frame_lens, action_len = self._kv_segments(ids1)
|
| 748 |
+
frame_len = frame_lens[0]
|
| 749 |
+
for pf in per_frame:
|
| 750 |
+
pl, fl, al = self._kv_segments(pf["input_ids"][0])
|
| 751 |
+
if (pl, fl[0], al) != (prefix_len, frame_len, action_len):
|
| 752 |
+
raise RuntimeError(
|
| 753 |
+
"Packed KV memory: frames have inconsistent token layout "
|
| 754 |
+
f"({(pl, fl[0], al)} vs {(prefix_len, frame_len, action_len)}); "
|
| 755 |
+
"all frames in a rollout must share resolution/grid."
|
| 756 |
+
)
|
| 757 |
+
|
| 758 |
+
prefix = ids1[:prefix_len]
|
| 759 |
+
frame_block = ids1[prefix_len : prefix_len + frame_len]
|
| 760 |
+
action_block = ids1[prefix_len + frame_len :] # incl. assistant header
|
| 761 |
+
block_len = frame_len + action_len
|
| 762 |
+
|
| 763 |
+
pixel_values = torch.cat([pf["pixel_values"] for pf in per_frame], dim=0)
|
| 764 |
+
grid = grid1.repeat(R, 1) # [R, 3]
|
| 765 |
+
|
| 766 |
+
# Frames-only M-RoPE positions: frames laid out consecutively (no action
|
| 767 |
+
# in between), so frame→frame / action→frame relative distances match eval
|
| 768 |
+
# ("positions within the cache"). These are the canonical frame positions
|
| 769 |
+
# reused regardless of where the frame sits in the packed token sequence.
|
| 770 |
+
frames_only_ids = torch.cat([prefix] + [frame_block] * R).unsqueeze(0)
|
| 771 |
+
full_pos_f, _ = backbone.get_rope_index(frames_only_ids, image_grid_thw=grid) # [3,1,Lf]
|
| 772 |
+
text_pos = full_pos_f[:, :, :prefix_len]
|
| 773 |
+
|
| 774 |
+
action_offsets = (action_block == self.action_token_id).nonzero(as_tuple=False).flatten()
|
| 775 |
+
if action_offsets.numel() < self.chunk_len:
|
| 776 |
+
raise RuntimeError(
|
| 777 |
+
f"Packed KV memory: action block has {action_offsets.numel()} action "
|
| 778 |
+
f"tokens (< chunk_len={self.chunk_len})."
|
| 779 |
+
)
|
| 780 |
+
action_offsets = action_offsets[-self.chunk_len :] # last chunk_len, matches gather
|
| 781 |
+
|
| 782 |
+
def _frame_pos(k):
|
| 783 |
+
s = prefix_len + k * frame_len
|
| 784 |
+
return full_pos_f[:, :, s : s + frame_len]
|
| 785 |
+
|
| 786 |
+
def _action_pos(frame_pos_k):
|
| 787 |
+
fk_max = int(frame_pos_k.max().item())
|
| 788 |
+
ap = torch.arange(1, action_len + 1, device=device) + fk_max
|
| 789 |
+
return ap.view(1, 1, -1).expand(3, 1, -1)
|
| 790 |
+
|
| 791 |
+
W = self.kv_window
|
| 792 |
+
parts, pos_parts, kind_parts, step_parts, action_idx_rows = [], [], [], [], []
|
| 793 |
+
|
| 794 |
+
if self.kv_rebased_sink:
|
| 795 |
+
# Per-step re-based sink, with the redundant pre-eviction sinks deduped.
|
| 796 |
+
# Steps k < W all have j0=0 → o_k=0 → an identical sink at [0,P), so they
|
| 797 |
+
# share ONE front sink (step=-2, visible to queries with step < W). This
|
| 798 |
+
# is exactly eval before any eviction (sink pinned at the front, frames
|
| 799 |
+
# growing from P). Steps k >= W each carry their own re-based sink
|
| 800 |
+
# ([sink_k][frame_k][action_k]) at o_k so the sink→frame distance equals
|
| 801 |
+
# eval's rolling-KV layout (bit-exact). Net: 1 + max(0,R-W) sinks instead
|
| 802 |
+
# of R, saving (W-1) prefix copies while staying numerically identical.
|
| 803 |
+
base0 = int(full_pos_f[0, 0, prefix_len].item()) # frame 0's temporal start
|
| 804 |
+
|
| 805 |
+
# Shared front sink for the pre-eviction steps (step=-2).
|
| 806 |
+
parts.append(prefix)
|
| 807 |
+
pos_parts.append(text_pos)
|
| 808 |
+
kind_parts.append(torch.zeros(prefix_len, dtype=torch.long, device=device))
|
| 809 |
+
step_parts.append(torch.full((prefix_len,), -2, dtype=torch.long, device=device))
|
| 810 |
+
cursor = prefix_len
|
| 811 |
+
|
| 812 |
+
for k in range(R):
|
| 813 |
+
if k >= W:
|
| 814 |
+
# Re-based sink_k sits right before step k's oldest visible frame.
|
| 815 |
+
j0 = k - W + 1
|
| 816 |
+
o_k = int(full_pos_f[0, 0, prefix_len + j0 * frame_len].item()) - base0
|
| 817 |
+
parts.append(prefix)
|
| 818 |
+
pos_parts.append(text_pos + o_k) # shift all 3 M-RoPE dims by o_k
|
| 819 |
+
kind_parts.append(torch.zeros(prefix_len, dtype=torch.long, device=device))
|
| 820 |
+
step_parts.append(torch.full((prefix_len,), k, dtype=torch.long, device=device))
|
| 821 |
+
cursor += prefix_len
|
| 822 |
+
frame_pos_k = _frame_pos(k)
|
| 823 |
+
parts += [frame_block, action_block]
|
| 824 |
+
pos_parts += [frame_pos_k, _action_pos(frame_pos_k)]
|
| 825 |
+
kind_parts.append(
|
| 826 |
+
torch.cat([
|
| 827 |
+
torch.ones(frame_len, dtype=torch.long, device=device),
|
| 828 |
+
torch.full((action_len,), 2, dtype=torch.long, device=device),
|
| 829 |
+
])
|
| 830 |
+
)
|
| 831 |
+
step_parts.append(torch.full((block_len,), k, dtype=torch.long, device=device))
|
| 832 |
+
action_idx_rows.append(cursor + frame_len + action_offsets)
|
| 833 |
+
cursor += block_len
|
| 834 |
+
else:
|
| 835 |
+
# Legacy single global sink: [sink][f0 a0]...[f_{R-1} a_{R-1}]. Sink at
|
| 836 |
+
# the front (step=-1, always visible); sink→frame distance grows with k.
|
| 837 |
+
parts.append(prefix)
|
| 838 |
+
pos_parts.append(text_pos)
|
| 839 |
+
kind_parts.append(torch.zeros(prefix_len, dtype=torch.long, device=device))
|
| 840 |
+
step_parts.append(torch.full((prefix_len,), -1, dtype=torch.long, device=device))
|
| 841 |
+
cursor = prefix_len
|
| 842 |
+
for k in range(R):
|
| 843 |
+
frame_pos_k = _frame_pos(k)
|
| 844 |
+
parts += [frame_block, action_block]
|
| 845 |
+
pos_parts += [frame_pos_k, _action_pos(frame_pos_k)]
|
| 846 |
+
kind_parts.append(
|
| 847 |
+
torch.cat([
|
| 848 |
+
torch.ones(frame_len, dtype=torch.long, device=device),
|
| 849 |
+
torch.full((action_len,), 2, dtype=torch.long, device=device),
|
| 850 |
+
])
|
| 851 |
+
)
|
| 852 |
+
step_parts.append(torch.full((block_len,), k, dtype=torch.long, device=device))
|
| 853 |
+
action_idx_rows.append(cursor + frame_len + action_offsets)
|
| 854 |
+
cursor += block_len
|
| 855 |
+
|
| 856 |
+
input_ids = torch.cat(parts).unsqueeze(0) # [1, L]
|
| 857 |
+
position_ids = torch.cat(pos_parts, dim=2) # [3,1,L]
|
| 858 |
+
kind = torch.cat(kind_parts)
|
| 859 |
+
step = torch.cat(step_parts)
|
| 860 |
+
action_idx = torch.stack(action_idx_rows, dim=0) # [R, chunk_len]
|
| 861 |
+
|
| 862 |
+
return {
|
| 863 |
+
"input_ids": input_ids,
|
| 864 |
+
"pixel_values": pixel_values,
|
| 865 |
+
"image_grid_thw": grid,
|
| 866 |
+
"position_ids": position_ids,
|
| 867 |
+
"kind": kind,
|
| 868 |
+
"step": step,
|
| 869 |
+
"action_idx": action_idx,
|
| 870 |
+
}
|
| 871 |
+
|
| 872 |
+
def _packed_block_mask(self, kind, step, L, batch):
|
| 873 |
+
"""Build a FlexAttention BlockMask for the packed sliding-window+sink layout."""
|
| 874 |
+
from torch.nn.attention.flex_attention import create_block_mask
|
| 875 |
+
from starVLA.model.modules.vlm.kv_memory import make_packed_sliding_mask_mod
|
| 876 |
+
|
| 877 |
+
mask_mod = make_packed_sliding_mask_mod(kind, step, self.kv_window)
|
| 878 |
+
# B=H=None → the mask is shared across batch and heads (it depends only on
|
| 879 |
+
# token kind/step, not content), so one BlockMask covers the whole batch.
|
| 880 |
+
return create_block_mask(mask_mod, B=None, H=None, Q_LEN=L, KV_LEN=L, device=str(kind.device))
|
| 881 |
+
|
| 882 |
+
def _assert_flex_attention(self):
|
| 883 |
+
"""Packed training needs the decoder dispatched through FlexAttention.
|
| 884 |
+
|
| 885 |
+
We pass a FlexAttention BlockMask straight to the model, so the decoder
|
| 886 |
+
(forward AND gradient-checkpointing recompute during backward) must use
|
| 887 |
+
the flex backend the whole time — a transient toggle around the forward
|
| 888 |
+
would leave the recompute on sdpa and choke on the BlockMask. The eval
|
| 889 |
+
streaming path also runs fine under flex, so the whole model is simply
|
| 890 |
+
loaded with `attn_implementation: flex_attention`.
|
| 891 |
+
"""
|
| 892 |
+
_, _, _, text_config = self._kv_components()
|
| 893 |
+
impl = getattr(text_config, "_attn_implementation", None)
|
| 894 |
+
if impl != "flex_attention":
|
| 895 |
+
raise RuntimeError(
|
| 896 |
+
"Packed KV-memory training requires the VLM loaded with "
|
| 897 |
+
f"attn_implementation='flex_attention' (got {impl!r}). Set "
|
| 898 |
+
"framework.qwenvl.attn_implementation: flex_attention."
|
| 899 |
+
)
|
| 900 |
+
|
| 901 |
+
def _forward_memory_packed(self, examples: List[dict]) -> dict:
|
| 902 |
+
"""Training forward via a single packed sliding-window+sink masked pass.
|
| 903 |
+
|
| 904 |
+
Per-frame supervision identical to `_forward_memory` (every real frame is
|
| 905 |
+
supervised at the window it naturally has), but the expensive VLM forward
|
| 906 |
+
runs ONCE per rollout instead of R times. Full BPTT across the rollout
|
| 907 |
+
(no per-step detach) — pair with gradient checkpointing for memory.
|
| 908 |
+
"""
|
| 909 |
+
self._assert_flex_attention()
|
| 910 |
+
profile = self._profile_timing_enabled()
|
| 911 |
+
timing = {"timing/mem_nograd_fwd": 0.0, "timing/mem_grad_fwd": 0.0, "timing/mem_action_head": 0.0}
|
| 912 |
+
|
| 913 |
+
instructions = [
|
| 914 |
+
self._instruction_with_state(ex["lang"], ex.get("state") if "state" in ex else None)
|
| 915 |
+
for ex in examples
|
| 916 |
+
]
|
| 917 |
+
groups: dict = {}
|
| 918 |
+
for idx, instruction in enumerate(instructions):
|
| 919 |
+
valid = np.asarray(examples[idx]["valid"], dtype=bool)
|
| 920 |
+
groups.setdefault((instruction, tuple(valid.tolist())), []).append(idx)
|
| 921 |
+
|
| 922 |
+
total_weighted_loss = None
|
| 923 |
+
total_weight = 0.0
|
| 924 |
+
for (instruction, valid_key), indices in groups.items():
|
| 925 |
+
valid = np.asarray(valid_key, dtype=bool)
|
| 926 |
+
real_positions = [k for k in range(len(valid)) if valid[k]]
|
| 927 |
+
R = len(real_positions)
|
| 928 |
+
if R == 0:
|
| 929 |
+
continue
|
| 930 |
+
action_env_dims = [int(examples[i].get("action_env_dim", self.action_env_dim)) for i in indices]
|
| 931 |
+
rl_games_tasks = [str(examples[i].get("rl_games_task", "")) for i in indices]
|
| 932 |
+
if not any(rl_games_tasks):
|
| 933 |
+
rl_games_tasks = None
|
| 934 |
+
|
| 935 |
+
# Build per-sample packed layouts (identical token structure, distinct pixels).
|
| 936 |
+
layouts = [
|
| 937 |
+
self._packed_window_layout([examples[i]["image"][k] for k in real_positions], instruction)
|
| 938 |
+
for i in indices
|
| 939 |
+
]
|
| 940 |
+
base = layouts[0]
|
| 941 |
+
L = base["input_ids"].shape[1]
|
| 942 |
+
B = len(indices)
|
| 943 |
+
input_ids = base["input_ids"].expand(B, -1).contiguous()
|
| 944 |
+
position_ids = base["position_ids"].expand(3, B, -1).contiguous()
|
| 945 |
+
pixel_values = torch.cat([lay["pixel_values"] for lay in layouts], dim=0)
|
| 946 |
+
grid = torch.cat([lay["image_grid_thw"] for lay in layouts], dim=0) # [B*R, 3]
|
| 947 |
+
action_idx = base["action_idx"] # [R, chunk_len]
|
| 948 |
+
block_mask = self._packed_block_mask(base["kind"], base["step"], L, B)
|
| 949 |
+
|
| 950 |
+
t_fwd = self._profile_start() if profile else None
|
| 951 |
+
last_hidden = self._forward_qwen_last_hidden(
|
| 952 |
+
{
|
| 953 |
+
"input_ids": input_ids,
|
| 954 |
+
"position_ids": position_ids,
|
| 955 |
+
"attention_mask": block_mask,
|
| 956 |
+
"pixel_values": pixel_values,
|
| 957 |
+
"image_grid_thw": grid,
|
| 958 |
+
"use_cache": False,
|
| 959 |
+
}
|
| 960 |
+
) # [B, L, H]
|
| 961 |
+
if profile:
|
| 962 |
+
timing["timing/mem_grad_fwd"] += self._profile_elapsed(t_fwd)
|
| 963 |
+
|
| 964 |
+
t_head = self._profile_start() if profile else None
|
| 965 |
+
with torch.autocast("cuda", dtype=torch.float32):
|
| 966 |
+
for j, k in enumerate(real_positions):
|
| 967 |
+
action_queries = last_hidden[:, action_idx[j], :] # [B, chunk_len, H]
|
| 968 |
+
group_preds = self.action_model.predict_action(action_queries) # [B, chunk, dim]
|
| 969 |
+
targets = [self._prepare_action_array(examples[i]["actions_per_frame"][k]) for i in indices]
|
| 970 |
+
targets = torch.tensor(np.array(targets), device=group_preds.device, dtype=group_preds.dtype)
|
| 971 |
+
targets = targets[:, -self.action_horizon :, :]
|
| 972 |
+
step_loss = self._compute_action_loss(
|
| 973 |
+
group_preds, targets, action_env_dims=action_env_dims, rl_games_tasks=rl_games_tasks
|
| 974 |
+
)
|
| 975 |
+
weight = float(sum(float(np.asarray(examples[i]["density_weight"])[k]) for i in indices))
|
| 976 |
+
contribution = step_loss * weight
|
| 977 |
+
total_weighted_loss = contribution if total_weighted_loss is None else total_weighted_loss + contribution
|
| 978 |
+
total_weight += weight
|
| 979 |
+
if profile:
|
| 980 |
+
timing["timing/mem_action_head"] += self._profile_elapsed(t_head)
|
| 981 |
+
|
| 982 |
+
action_loss = total_weighted_loss / max(total_weight, 1e-6)
|
| 983 |
+
return {"action_loss": action_loss, "loss_weight": total_weight, "timing": timing, "batch_stats": {}}
|
| 984 |
+
|
| 985 |
+
def _instruction_with_state(self, instruction, state):
|
| 986 |
+
if state is None:
|
| 987 |
+
return instruction
|
| 988 |
+
return self.add_discretized_state_to_instruction([instruction], [state])[0]
|
| 989 |
+
|
| 990 |
+
def _forward_memory(self, examples: List[dict]) -> dict:
|
| 991 |
+
"""Training forward with the streaming KV memory: per-frame supervision.
|
| 992 |
+
|
| 993 |
+
Each sample is an R-frame rollout `[t-R+1 .. t]`; the dataloader marks clamp
|
| 994 |
+
padding via ``valid`` and supplies one action chunk per frame in
|
| 995 |
+
``actions_per_frame`` ([R, H, dim]). We skip padding frames (never feed memory,
|
| 996 |
+
never supervise) and supervise EVERY real frame at the window it naturally has
|
| 997 |
+
(1 -> window, then evict), which matches eval (`_predict_action_memory`) frame
|
| 998 |
+
for frame, including the unfilled window at an episode's start. History KV is
|
| 999 |
+
detached between steps (truncated BPTT depth 1), so each step's loss flows only
|
| 1000 |
+
through that step's forward; the per-step weighted losses are summed and the
|
| 1001 |
+
trainer backpropagates once.
|
| 1002 |
+
|
| 1003 |
+
Same-instruction, same-`valid` rollouts share a token layout and window
|
| 1004 |
+
evolution, so they run each step in one batched forward via
|
| 1005 |
+
`_kv_forward_step_batched` (degrades to per-sample otherwise), mirroring
|
| 1006 |
+
`_predict_action_memory`.
|
| 1007 |
+
"""
|
| 1008 |
+
profile = self._profile_timing_enabled()
|
| 1009 |
+
timing = {"timing/mem_nograd_fwd": 0.0, "timing/mem_grad_fwd": 0.0, "timing/mem_action_head": 0.0}
|
| 1010 |
+
|
| 1011 |
+
instructions = [
|
| 1012 |
+
self._instruction_with_state(ex["lang"], ex.get("state") if "state" in ex else None)
|
| 1013 |
+
for ex in examples
|
| 1014 |
+
]
|
| 1015 |
+
|
| 1016 |
+
# Group rollouts that share the prompt AND the same real/padding pattern: those
|
| 1017 |
+
# march through identical window states each step, so they batch cleanly.
|
| 1018 |
+
groups: dict = {}
|
| 1019 |
+
for idx, instruction in enumerate(instructions):
|
| 1020 |
+
valid = np.asarray(examples[idx]["valid"], dtype=bool)
|
| 1021 |
+
groups.setdefault((instruction, tuple(valid.tolist())), []).append(idx)
|
| 1022 |
+
|
| 1023 |
+
total_weighted_loss = None
|
| 1024 |
+
total_weight = 0.0
|
| 1025 |
+
for (instruction, valid_key), indices in groups.items():
|
| 1026 |
+
valid = np.asarray(valid_key, dtype=bool)
|
| 1027 |
+
real_positions = [k for k in range(len(valid)) if valid[k]]
|
| 1028 |
+
memories = [self._new_kv_memory() for _ in indices]
|
| 1029 |
+
rollout = [examples[i]["image"] for i in indices]
|
| 1030 |
+
action_env_dims = [int(examples[i].get("action_env_dim", self.action_env_dim)) for i in indices]
|
| 1031 |
+
rl_games_tasks = [str(examples[i].get("rl_games_task", "")) for i in indices]
|
| 1032 |
+
if not any(rl_games_tasks):
|
| 1033 |
+
rl_games_tasks = None
|
| 1034 |
+
|
| 1035 |
+
for step_pos, k in enumerate(real_positions):
|
| 1036 |
+
if step_pos > 0:
|
| 1037 |
+
for memory in memories:
|
| 1038 |
+
memory.detach_() # truncated BPTT: history is a fixed memory
|
| 1039 |
+
step_frames = [frames[k] for frames in rollout]
|
| 1040 |
+
|
| 1041 |
+
t_fwd = self._profile_start() if profile else None
|
| 1042 |
+
last_hidden, new_ids = self._kv_forward_step_batched(memories, step_frames, instruction)
|
| 1043 |
+
if profile:
|
| 1044 |
+
timing["timing/mem_grad_fwd"] += self._profile_elapsed(t_fwd)
|
| 1045 |
+
|
| 1046 |
+
t_head = self._profile_start() if profile else None
|
| 1047 |
+
with torch.autocast("cuda", dtype=torch.float32):
|
| 1048 |
+
action_queries = self._gather_action_token_embeddings(
|
| 1049 |
+
last_hidden, new_ids, action_token_id=self.action_token_id
|
| 1050 |
+
)
|
| 1051 |
+
group_preds = self.action_model.predict_action(action_queries) # [Bg, chunk, dim]
|
| 1052 |
+
targets = [
|
| 1053 |
+
self._prepare_action_array(examples[i]["actions_per_frame"][k]) for i in indices
|
| 1054 |
+
]
|
| 1055 |
+
targets = torch.tensor(
|
| 1056 |
+
np.array(targets), device=group_preds.device, dtype=group_preds.dtype
|
| 1057 |
+
) # [Bg, H, dim]
|
| 1058 |
+
targets = targets[:, -self.action_horizon :, :]
|
| 1059 |
+
step_loss = self._compute_action_loss(
|
| 1060 |
+
group_preds,
|
| 1061 |
+
targets,
|
| 1062 |
+
action_env_dims=action_env_dims,
|
| 1063 |
+
rl_games_tasks=rl_games_tasks,
|
| 1064 |
+
)
|
| 1065 |
+
if profile:
|
| 1066 |
+
timing["timing/mem_action_head"] += self._profile_elapsed(t_head)
|
| 1067 |
+
|
| 1068 |
+
# Per-supervised-step density weight: sum of the group's per-frame
|
| 1069 |
+
# weights at frame k. Uniform weights reduce this to a sample-count
|
| 1070 |
+
# weighting, i.e. the exact mean over all supervised (sample, step).
|
| 1071 |
+
weight = float(
|
| 1072 |
+
sum(float(np.asarray(examples[i]["density_weight"])[k]) for i in indices)
|
| 1073 |
+
)
|
| 1074 |
+
contribution = step_loss * weight
|
| 1075 |
+
total_weighted_loss = contribution if total_weighted_loss is None else total_weighted_loss + contribution
|
| 1076 |
+
total_weight += weight
|
| 1077 |
+
|
| 1078 |
+
action_loss = total_weighted_loss / max(total_weight, 1e-6)
|
| 1079 |
+
return {"action_loss": action_loss, "loss_weight": total_weight, "timing": timing, "batch_stats": {}}
|
| 1080 |
+
|
| 1081 |
+
@torch.inference_mode()
|
| 1082 |
+
def _predict_action_memory(self, examples: List[dict]) -> dict:
|
| 1083 |
+
"""Eval-time streaming prediction with per-slot KV memory (req3, milestone 4).
|
| 1084 |
+
|
| 1085 |
+
The newest frame (``example['image'][-1]``) is encoded fresh; past frames are
|
| 1086 |
+
served from the slot's memory. ``reset_memory(slot_id)`` (called from the
|
| 1087 |
+
policy at episode boundaries) clears a slot. Streams that currently share the
|
| 1088 |
+
same instruction and history layout are processed in one batched forward; the
|
| 1089 |
+
rest fall back to their own group (no left padding needed).
|
| 1090 |
+
"""
|
| 1091 |
+
train_obs_image_size = getattr(self.config.datasets.vla_data, "obs_image_size", None)
|
| 1092 |
+
|
| 1093 |
+
# Resolve each example to its (slot memory, current frame, instruction).
|
| 1094 |
+
entries = []
|
| 1095 |
+
for idx, example in enumerate(examples):
|
| 1096 |
+
slot_id = example.get("slot_id", idx)
|
| 1097 |
+
frames = [to_pil_preserve(f) for f in example["image"]]
|
| 1098 |
+
if train_obs_image_size:
|
| 1099 |
+
frames = resize_images(frames, target_size=train_obs_image_size)
|
| 1100 |
+
state = example.get("state") if "state" in example else None
|
| 1101 |
+
instruction = self._instruction_with_state(example["lang"], state)
|
| 1102 |
+
memory = self._kv_memories.get(slot_id)
|
| 1103 |
+
if memory is None:
|
| 1104 |
+
memory = self._new_kv_memory()
|
| 1105 |
+
self._kv_memories[slot_id] = memory
|
| 1106 |
+
entries.append({"idx": idx, "frame": frames[-1], "instruction": instruction, "memory": memory})
|
| 1107 |
+
|
| 1108 |
+
# Group same-layout streams (same prompt + same cached layout) into one forward.
|
| 1109 |
+
groups: dict = {}
|
| 1110 |
+
for entry in entries:
|
| 1111 |
+
key = (entry["instruction"], entry["memory"].layout_key())
|
| 1112 |
+
groups.setdefault(key, []).append(entry)
|
| 1113 |
+
|
| 1114 |
+
preds: List[Optional[torch.Tensor]] = [None] * len(examples)
|
| 1115 |
+
for group in groups.values():
|
| 1116 |
+
instruction = group[0]["instruction"]
|
| 1117 |
+
memories = [entry["memory"] for entry in group]
|
| 1118 |
+
frames = [entry["frame"] for entry in group]
|
| 1119 |
+
last_hidden, new_ids = self._kv_forward_step_batched(memories, frames, instruction)
|
| 1120 |
+
with torch.autocast("cuda", dtype=torch.float32):
|
| 1121 |
+
action_queries = self._gather_action_token_embeddings(
|
| 1122 |
+
last_hidden, new_ids, action_token_id=self.action_token_id
|
| 1123 |
+
)
|
| 1124 |
+
pred_actions = self.action_model.predict_action(action_queries)
|
| 1125 |
+
for i, entry in enumerate(group):
|
| 1126 |
+
preds[entry["idx"]] = pred_actions[i : i + 1]
|
| 1127 |
+
|
| 1128 |
+
normalized = torch.cat(preds, dim=0).detach().cpu().numpy()
|
| 1129 |
+
return {"normalized_actions": normalized}
|
| 1130 |
+
|
| 1131 |
+
def _gather_action_token_embeddings(
|
| 1132 |
+
self,
|
| 1133 |
+
last_hidden: torch.Tensor, # [B, L, H]
|
| 1134 |
+
input_ids: torch.Tensor, # [B, L]
|
| 1135 |
+
action_token_id=None, # Can be int or List[int]
|
| 1136 |
+
) -> torch.Tensor:
|
| 1137 |
+
"""
|
| 1138 |
+
Vectorized batch extraction of action token embeddings:
|
| 1139 |
+
- No per-sample for loop
|
| 1140 |
+
- Select the last chunk_len action placeholder tokens from each sample
|
| 1141 |
+
Args:
|
| 1142 |
+
last_hidden: [B, L, H]
|
| 1143 |
+
input_ids: [B, L]
|
| 1144 |
+
action_token_id: int or List[int]
|
| 1145 |
+
Returns:
|
| 1146 |
+
action_queries: [B, chunk_len, H]
|
| 1147 |
+
"""
|
| 1148 |
+
if action_token_id is None:
|
| 1149 |
+
raise ValueError("action_token_id must not be None")
|
| 1150 |
+
|
| 1151 |
+
device = input_ids.device
|
| 1152 |
+
B, L, H = last_hidden.shape
|
| 1153 |
+
|
| 1154 |
+
# Support multiple ids (e.g., multiple variants)
|
| 1155 |
+
if isinstance(action_token_id, (list, tuple, set)):
|
| 1156 |
+
id_list = torch.tensor(list(action_token_id), device=device, dtype=input_ids.dtype)
|
| 1157 |
+
# torch.isin requires PyTorch >=1.10
|
| 1158 |
+
mask = torch.isin(input_ids, id_list)
|
| 1159 |
+
else:
|
| 1160 |
+
mask = input_ids == action_token_id # [B, L]
|
| 1161 |
+
|
| 1162 |
+
counts = mask.sum(dim=1) # [B]
|
| 1163 |
+
if (counts < self.chunk_len).any():
|
| 1164 |
+
insufficient = (counts < self.chunk_len).nonzero(as_tuple=False).flatten().tolist()
|
| 1165 |
+
raise RuntimeError(
|
| 1166 |
+
f"The following samples have insufficient action tokens (< {self.chunk_len}): {insufficient} |"
|
| 1167 |
+
f" counts={counts.tolist()}"
|
| 1168 |
+
)
|
| 1169 |
+
|
| 1170 |
+
# Position indices
|
| 1171 |
+
idx = torch.arange(L, device=device).unsqueeze(0).expand(B, L) # [B, L]
|
| 1172 |
+
masked_pos = torch.where(mask, idx, torch.full_like(idx, -1)) # Set non-action positions to -1
|
| 1173 |
+
|
| 1174 |
+
# Take the last chunk_len positions (higher indices = later in sequence)
|
| 1175 |
+
# Note: count sufficiency already verified, so -1 won't be incorrectly selected
|
| 1176 |
+
topk_pos = masked_pos.topk(k=self.chunk_len, dim=-1).values # [B, chunk_len] unsorted
|
| 1177 |
+
# Sort in temporal order
|
| 1178 |
+
selected_pos = topk_pos.sort(dim=-1).values # [B, chunk_len]
|
| 1179 |
+
|
| 1180 |
+
# Gather
|
| 1181 |
+
expanded_index = selected_pos.unsqueeze(-1).expand(-1, -1, H) # [B, chunk_len, H]
|
| 1182 |
+
action_queries = last_hidden.gather(dim=1, index=expanded_index) # [B, chunk_len, H]
|
| 1183 |
+
return action_queries
|
| 1184 |
+
|
| 1185 |
+
# Discretised state → instruction prefix (π₀.5 style); shared with QwenPI_v3.
|
| 1186 |
+
add_discretized_state_to_instruction = staticmethod(add_discretized_state_to_instruction)
|
| 1187 |
+
|
| 1188 |
+
|
| 1189 |
+
if __name__ == "__main__":
|
| 1190 |
+
import argparse
|
| 1191 |
+
import os
|
| 1192 |
+
|
| 1193 |
+
from omegaconf import OmegaConf
|
| 1194 |
+
|
| 1195 |
+
parser = argparse.ArgumentParser()
|
| 1196 |
+
parser.add_argument(
|
| 1197 |
+
"--config_yaml",
|
| 1198 |
+
type=str,
|
| 1199 |
+
default="examples/LIBERO/train_files/starvla_cotrain_libero.yaml",
|
| 1200 |
+
help="Path to YAML config",
|
| 1201 |
+
)
|
| 1202 |
+
args, clipargs = parser.parse_known_args()
|
| 1203 |
+
|
| 1204 |
+
if os.getenv("DEBUGPY_ENABLE", "0") == "1":
|
| 1205 |
+
import debugpy
|
| 1206 |
+
|
| 1207 |
+
debugpy.listen(("0.0.0.0", 10092))
|
| 1208 |
+
print("Rank 0 waiting for debugger attach on port 10092...")
|
| 1209 |
+
debugpy.wait_for_client()
|
| 1210 |
+
|
| 1211 |
+
cfg = OmegaConf.load(args.config_yaml)
|
| 1212 |
+
|
| 1213 |
+
model = Qwenvl_OFT(cfg)
|
| 1214 |
+
print(model)
|
| 1215 |
+
|
| 1216 |
+
image = Image.fromarray(np.random.randint(0, 255, (224, 224, 3), dtype=np.uint8))
|
| 1217 |
+
sample = {
|
| 1218 |
+
"action": np.random.uniform(-1, 1, size=(16, 7)).astype(np.float16),
|
| 1219 |
+
"image": [image],
|
| 1220 |
+
"lang": "This is a fake instruction for testing.",
|
| 1221 |
+
"state": np.random.uniform(-1, 1, size=(1, 7)).astype(np.float16), # chunk, state_dim
|
| 1222 |
+
}
|
| 1223 |
+
sample2 = sample.copy()
|
| 1224 |
+
sample2["lang"] = "Another fake instruction for testing."
|
| 1225 |
+
|
| 1226 |
+
batch = [sample, sample2]
|
| 1227 |
+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
| 1228 |
+
model = model.to(device)
|
| 1229 |
+
forward_output = model(batch)
|
| 1230 |
+
action_loss = forward_output["action_loss"]
|
| 1231 |
+
print(f"[train] Action Loss (with state): {action_loss.item()}")
|
| 1232 |
+
|
| 1233 |
+
predict_output = model.predict_action(examples=[batch[0]])
|
| 1234 |
+
normalized_actions = predict_output["normalized_actions"]
|
| 1235 |
+
print(f"[infer] Predicted Action shape: {normalized_actions.shape}")
|
| 1236 |
+
|
| 1237 |
+
# Backward-compat: examples without `state` should still work.
|
| 1238 |
+
sample_no_state = {k: v for k, v in sample.items() if k != "state"}
|
| 1239 |
+
forward_no_state = model([sample_no_state, sample_no_state])
|
| 1240 |
+
print(f"[train] Action Loss (no state): {forward_no_state['action_loss'].item()}")
|
| 1241 |
+
predict_no_state = model.predict_action(examples=[sample_no_state])
|
| 1242 |
+
print(f"[infer] Predicted Action shape (no state): {predict_no_state['normalized_actions'].shape}")
|
| 1243 |
+
|
| 1244 |
+
print("Finished")
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/datasets.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/doom-mean-reset.patch
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
diff --git a/latency_bench/data/sf_teacher_rollout.py b/latency_bench/data/sf_teacher_rollout.py
|
| 2 |
+
index ef45d95b..e32b942e 100644
|
| 3 |
+
--- a/latency_bench/data/sf_teacher_rollout.py
|
| 4 |
+
+++ b/latency_bench/data/sf_teacher_rollout.py
|
| 5 |
+
@@ -964,6 +964,11 @@ def _replay_accepted_specs(
|
| 6 |
+
row_buffer_size=int(row_buffer_size),
|
| 7 |
+
export_image_size=export_image_size,
|
| 8 |
+
)
|
| 9 |
+
+ stream_current_images = (
|
| 10 |
+
+ image_transform_config.normalized_transform() == "raw_rgb"
|
| 11 |
+
+ and int(context_window) <= 1
|
| 12 |
+
+ and filter_preset == "none"
|
| 13 |
+
+ )
|
| 14 |
+
image_resolution: list[int] | None = None
|
| 15 |
+
|
| 16 |
+
def assign_specs_to_slots(slots: list[int]) -> dict[int, int]:
|
| 17 |
+
@@ -1051,7 +1056,10 @@ def _replay_accepted_specs(
|
| 18 |
+
next_raw_frame=next_decision_step * obs_stride_raw_frames,
|
| 19 |
+
max_steps_per_episode=int(max_steps_per_episode),
|
| 20 |
+
)
|
| 21 |
+
- active_episode_frames[slot].append(np.array(image_frame, copy=True))
|
| 22 |
+
+ if stream_current_images:
|
| 23 |
+
+ image_writer.write(image_frame, image_path)
|
| 24 |
+
+ else:
|
| 25 |
+
+ active_episode_frames[slot].append(np.array(image_frame, copy=True))
|
| 26 |
+
row = teacher_dataset_row(
|
| 27 |
+
env_name=env_name,
|
| 28 |
+
spec=spec,
|
| 29 |
+
@@ -1104,7 +1112,9 @@ def _replay_accepted_specs(
|
| 30 |
+
)
|
| 31 |
+
else:
|
| 32 |
+
shard_rows = [dict(row) for row in final_rows]
|
| 33 |
+
- if _is_demon_ghost_trail:
|
| 34 |
+
+ if stream_current_images:
|
| 35 |
+
+ image_writer.flush()
|
| 36 |
+
+ elif _is_demon_ghost_trail:
|
| 37 |
+
# Frames are pre-built ghost trail images; map directly.
|
| 38 |
+
ep_steps = [int(row["decision_step"]) for row in final_rows]
|
| 39 |
+
frames_by_decision_step = {
|
| 40 |
+
@@ -1118,12 +1128,13 @@ def _replay_accepted_specs(
|
| 41 |
+
frames=active_episode_frames[slot],
|
| 42 |
+
config=image_transform_config,
|
| 43 |
+
)
|
| 44 |
+
- shard_rows = _write_filtered_episode_images(
|
| 45 |
+
- image_writer,
|
| 46 |
+
- shard_rows,
|
| 47 |
+
- frames_by_decision_step,
|
| 48 |
+
- context_window=int(context_window),
|
| 49 |
+
- )
|
| 50 |
+
+ if not stream_current_images:
|
| 51 |
+
+ shard_rows = _write_filtered_episode_images(
|
| 52 |
+
+ image_writer,
|
| 53 |
+
+ shard_rows,
|
| 54 |
+
+ frames_by_decision_step,
|
| 55 |
+
+ context_window=int(context_window),
|
| 56 |
+
+ )
|
| 57 |
+
write_episode_row_shard(output_dir, shard_rows)
|
| 58 |
+
progress.update(1)
|
| 59 |
+
replayed += 1
|
| 60 |
+
@@ -1272,9 +1283,8 @@ def _build_rollout_driver_runtime(
|
| 61 |
+
driver = BatchedTeacherRolloutDriver(runtime["envs"][0], int(num_envs))
|
| 62 |
+
else:
|
| 63 |
+
recreate_env = None
|
| 64 |
+
- if integration_name == "deadly_corridor" and (
|
| 65 |
+
- "export_zero_action_history" in config or getattr(cfg, "rollout_profile_seed_by_reset", False)
|
| 66 |
+
- ):
|
| 67 |
+
+ # ViZDoom applies reset seeds only while creating its native game.
|
| 68 |
+
+ if integration_name == "deadly_corridor":
|
| 69 |
+
from sample_factory.algo.utils.make_env import make_env_func_batched
|
| 70 |
+
from sample_factory.utils.attr_dict import AttrDict
|
| 71 |
+
|
| 72 |
+
diff --git a/tests/data/test_sf_teacher_dataset_export.py b/tests/data/test_sf_teacher_dataset_export.py
|
| 73 |
+
index e6b25233..61a58118 100644
|
| 74 |
+
--- a/tests/data/test_sf_teacher_dataset_export.py
|
| 75 |
+
+++ b/tests/data/test_sf_teacher_dataset_export.py
|
| 76 |
+
@@ -498,8 +498,11 @@ def test_serial_rollout_driver_continues_life_loss_with_seedless_reset(monkeypat
|
| 77 |
+
assert info == {"reset_seed": None}
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
-def test_serial_teacher_replay_starts_each_seed_in_a_fresh_environment(monkeypatch):
|
| 81 |
+
- sf_teacher_drivers = _load_sf_teacher_drivers_for_direct_test(monkeypatch)
|
| 82 |
+
+@pytest.mark.parametrize("latency_type", ["fixed", "profile_sample"])
|
| 83 |
+
+def test_serial_teacher_replay_starts_each_seed_in_a_fresh_environment(monkeypatch, tmp_path, latency_type):
|
| 84 |
+
+ from contextlib import nullcontext
|
| 85 |
+
+ from latency_bench.data import sf_teacher_rollout
|
| 86 |
+
+ from sample_factory.algo.utils import make_env
|
| 87 |
+
|
| 88 |
+
class StatefulEnv:
|
| 89 |
+
action_space = object()
|
| 90 |
+
@@ -514,13 +517,17 @@ def test_serial_teacher_replay_starts_each_seed_in_a_fresh_environment(monkeypat
|
| 91 |
+
def close(self):
|
| 92 |
+
return None
|
| 93 |
+
|
| 94 |
+
- driver = sf_teacher_drivers.SerialTeacherRolloutDriver(
|
| 95 |
+
- [StatefulEnv()], recreate_env=lambda _slot: StatefulEnv()
|
| 96 |
+
+ cfg = SimpleNamespace(frame_stack=4, action_history_decisions=8, latency_type=latency_type)
|
| 97 |
+
+ monkeypatch.setattr(sf_teacher_rollout, "sample_factory_init_log", lambda _: nullcontext())
|
| 98 |
+
+ monkeypatch.setattr(sf_teacher_rollout, "build_sample_factory_rollout_cfg", lambda _: (object(), cfg))
|
| 99 |
+
+ monkeypatch.setattr(sf_teacher_rollout, "build_env_and_policy", lambda *args: {"envs": [StatefulEnv()]})
|
| 100 |
+
+ monkeypatch.setattr(make_env, "make_env_func_batched", lambda *args, **kwargs: StatefulEnv())
|
| 101 |
+
+ _, _, driver, _ = sf_teacher_rollout._build_rollout_driver_runtime(
|
| 102 |
+
+ {"env_name": "deadly_corridor", "integration_name": "deadly_corridor"},
|
| 103 |
+
+ output_dir=tmp_path, num_envs=1, export_env_raw_rgb_frames=False,
|
| 104 |
+
)
|
| 105 |
+
-
|
| 106 |
+
driver.reset_slots({0: 42})
|
| 107 |
+
observation, _ = driver.reset_slots({0: 43})[0]
|
| 108 |
+
-
|
| 109 |
+
assert observation["obs"].tolist() == [43, 1]
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
@@ -670,19 +677,22 @@ def test_collect_teacher_dataset_probe_retries_until_episode_is_accepted(monkeyp
|
| 113 |
+
def action_distribution(self):
|
| 114 |
+
return object()
|
| 115 |
+
|
| 116 |
+
+ reset_seeds = []
|
| 117 |
+
+
|
| 118 |
+
class FakeEnv:
|
| 119 |
+
def __init__(self):
|
| 120 |
+
self.action_space = object()
|
| 121 |
+
- self.reset_seeds: list[int] = []
|
| 122 |
+
+ self.reset_seeds = reset_seeds
|
| 123 |
+
|
| 124 |
+
def reset(self, seed=None):
|
| 125 |
+
self.reset_seeds.append(seed)
|
| 126 |
+
+ self.current_seed = seed
|
| 127 |
+
return np.zeros((3, 2, 2), dtype=np.uint8), [
|
| 128 |
+
{"env_raw_rgb_frame_stack": _env_raw_rgb_frame_stack(5)}
|
| 129 |
+
]
|
| 130 |
+
|
| 131 |
+
def step(self, action):
|
| 132 |
+
- reward = 3000.0 if len(self.reset_seeds) == 1 else 3000.001
|
| 133 |
+
+ reward = 3000.0 if self.current_seed == 11 else 3000.001
|
| 134 |
+
return (
|
| 135 |
+
np.zeros((3, 2, 2), dtype=np.uint8),
|
| 136 |
+
np.float32(reward),
|
| 137 |
+
@@ -702,6 +712,8 @@ def test_collect_teacher_dataset_probe_retries_until_episode_is_accepted(monkeyp
|
| 138 |
+
|
| 139 |
+
fake_env = FakeEnv()
|
| 140 |
+
fake_actor = FakeActorCritic()
|
| 141 |
+
+ from sample_factory.algo.utils import make_env
|
| 142 |
+
+ monkeypatch.setattr(make_env, "make_env_func_batched", lambda *args, **kwargs: FakeEnv())
|
| 143 |
+
fake_cfg = SimpleNamespace(frame_stack=1, env_fps=35.0, obs_fps=17.5, seed=11)
|
| 144 |
+
|
| 145 |
+
monkeypatch.setattr(exporter, "build_sample_factory_rollout_cfg", lambda config: (object(), fake_cfg))
|
| 146 |
+
@@ -1273,7 +1285,8 @@ def test_collect_teacher_dataset_saves_demon_attack_latest_raw_rgb_image(monkeyp
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
@pytest.mark.parametrize("export_history", [False, True])
|
| 150 |
+
-def test_collect_teacher_dataset_saves_flappy_latest_raw_rgb_image(monkeypatch, tmp_path, export_history):
|
| 151 |
+
+@pytest.mark.parametrize("filter_preset", ["clean_v1", "none"])
|
| 152 |
+
+def test_collect_teacher_dataset_saves_flappy_latest_raw_rgb_image(monkeypatch, tmp_path, export_history, filter_preset):
|
| 153 |
+
import torch
|
| 154 |
+
from gymnasium.spaces import Discrete
|
| 155 |
+
from PIL import Image
|
| 156 |
+
@@ -1307,6 +1320,9 @@ def test_collect_teacher_dataset_saves_flappy_latest_raw_rgb_image(monkeypatch,
|
| 157 |
+
class FakeEnv:
|
| 158 |
+
action_space = Discrete(2)
|
| 159 |
+
|
| 160 |
+
+ def __init__(self, exporting):
|
| 161 |
+
+ self.exporting = exporting
|
| 162 |
+
+
|
| 163 |
+
def reset(self, seed=None):
|
| 164 |
+
self.steps = 0
|
| 165 |
+
obs = {"obs": np.zeros((1, 12, 2, 2), dtype=np.uint8)}
|
| 166 |
+
@@ -1323,6 +1339,9 @@ def test_collect_teacher_dataset_saves_flappy_latest_raw_rgb_image(monkeypatch,
|
| 167 |
+
|
| 168 |
+
def step(self, action):
|
| 169 |
+
self.steps += 1
|
| 170 |
+
+ if self.exporting and self.steps == 2 and filter_preset == "none":
|
| 171 |
+
+ image_path = output_dir / "images/train/episode_000000/decision_step_000000.png"
|
| 172 |
+
+ assert image_path.is_file(), "First frame must be on disk before the episode ends"
|
| 173 |
+
obs = {"obs": np.ones((1, 12, 2, 2), dtype=np.uint8)}
|
| 174 |
+
next_stack = np.stack([np.full((6, 5, 3), 50 + idx, dtype=np.uint8) for idx in range(4)], axis=0)
|
| 175 |
+
return (
|
| 176 |
+
@@ -1354,7 +1373,7 @@ def test_collect_teacher_dataset_saves_flappy_latest_raw_rgb_image(monkeypatch,
|
| 177 |
+
exporter,
|
| 178 |
+
"build_env_and_policy",
|
| 179 |
+
lambda module, cfg, config, num_envs: {
|
| 180 |
+
- "envs": [FakeEnv()],
|
| 181 |
+
+ "envs": [FakeEnv(cfg.export_env_raw_rgb_frames)],
|
| 182 |
+
"env_info": object(),
|
| 183 |
+
"actor_critic": FakeActorCritic(),
|
| 184 |
+
"device": torch.device("cpu"),
|
| 185 |
+
@@ -1382,6 +1401,7 @@ def test_collect_teacher_dataset_saves_flappy_latest_raw_rgb_image(monkeypatch,
|
| 186 |
+
export_image_size=None,
|
| 187 |
+
image_writer_workers=0,
|
| 188 |
+
row_buffer_size=1,
|
| 189 |
+
+ filter_preset=filter_preset,
|
| 190 |
+
)
|
| 191 |
+
train_rows = _read_shard_rows(output_dir, "train")
|
| 192 |
+
val_rows = _read_shard_rows(output_dir, "val")
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/gym-language-contract.patch
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
diff --git a/examples/rl_games/train_files/data_registry/data_config.py b/examples/rl_games/train_files/data_registry/data_config.py
|
| 2 |
+
index 2ef8b39..6d76aeb 100644
|
| 3 |
+
--- a/examples/rl_games/train_files/data_registry/data_config.py
|
| 4 |
+
+++ b/examples/rl_games/train_files/data_registry/data_config.py
|
| 5 |
+
@@ -53,10 +53,10 @@ class AtlantisDataConfig(FlappyDataConfig):
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class GymnasiumDataConfig(FlappyDataConfig):
|
| 9 |
+
- pass
|
| 10 |
+
+ language_keys = ["annotation.human.task_description"]
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
-class GymnasiumNativeDataConfig(FlappyDataConfig):
|
| 14 |
+
+class GymnasiumNativeDataConfig(GymnasiumDataConfig):
|
| 15 |
+
"""Configure native Gymnasium state and action vectors."""
|
| 16 |
+
|
| 17 |
+
state_keys = ["state.native"]
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/loader-spawn-cache.patch
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
diff --git a/starVLA/dataloader/gr00t_lerobot/datasets.py b/starVLA/dataloader/gr00t_lerobot/datasets.py
|
| 2 |
+
index 17ce5f1..2346230 100644
|
| 3 |
+
--- a/starVLA/dataloader/gr00t_lerobot/datasets.py
|
| 4 |
+
+++ b/starVLA/dataloader/gr00t_lerobot/datasets.py
|
| 5 |
+
@@ -667,6 +667,13 @@ class LeRobotSingleDataset(Dataset):
|
| 6 |
+
# Check if the dataset is valid
|
| 7 |
+
self._check_integrity()
|
| 8 |
+
|
| 9 |
+
+ def __getstate__(self):
|
| 10 |
+
+ state = self.__dict__.copy()
|
| 11 |
+
+ state["_parquet_cache"] = {}
|
| 12 |
+
+ state["curr_traj_data"] = None
|
| 13 |
+
+ state["curr_traj_id"] = None
|
| 14 |
+
+ return state
|
| 15 |
+
+
|
| 16 |
+
@property
|
| 17 |
+
def dataset_path(self) -> Path:
|
| 18 |
+
"""The path to the dataset that contains the METADATA_FILENAME file."""
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/loader-spawn-test.patch
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
diff --git a/tests/data/test_starvla_tasks.py b/tests/data/test_starvla_tasks.py
|
| 2 |
+
index 1403fa13..62468aa6 100644
|
| 3 |
+
--- a/tests/data/test_starvla_tasks.py
|
| 4 |
+
+++ b/tests/data/test_starvla_tasks.py
|
| 5 |
+
@@ -395,3 +395,26 @@ def test_balance_masked_l1_uses_equal_sample_weights_and_no_padding_gradient(mon
|
| 6 |
+
all_valid = torch.ones((2, 8), dtype=torch.bool)
|
| 7 |
+
torch.testing.assert_close(model._compute_action_loss(pred, target, action_loss_mask=all_valid),
|
| 8 |
+
(pred - target).abs().mean())
|
| 9 |
+
+
|
| 10 |
+
+
|
| 11 |
+
+def test_lerobot_spawn_reload_preserves_data_without_copying_parent_cache(tmp_path, monkeypatch):
|
| 12 |
+
+ import pickle
|
| 13 |
+
+ pytest.importorskip("accelerate")
|
| 14 |
+
+ monkeypatch.syspath_prepend(str(Path(__file__).resolve().parents[2] / "third_party/starVLA"))
|
| 15 |
+
+ from starVLA.dataloader.gr00t_lerobot.datasets import LeRobotSingleDataset
|
| 16 |
+
+
|
| 17 |
+
+ path = tmp_path / "episode.parquet"
|
| 18 |
+
+ table = pd.DataFrame({"image": [b"rgb" * (1024 * 1024)], "action": [1]})
|
| 19 |
+
+ table.to_parquet(path)
|
| 20 |
+
+ parent = object.__new__(LeRobotSingleDataset)
|
| 21 |
+
+ parent._parquet_cache = {path: table}
|
| 22 |
+
+ parent.curr_traj_data = table
|
| 23 |
+
+ parent.curr_traj_id = 0
|
| 24 |
+
+ parent._all_steps = [(0, 0)]
|
| 25 |
+
+
|
| 26 |
+
+ payload = pickle.dumps(parent)
|
| 27 |
+
+ assert len(payload) < 64 * 1024
|
| 28 |
+
+ worker = pickle.loads(payload)
|
| 29 |
+
+ assert worker._all_steps == parent._all_steps
|
| 30 |
+
+ pd.testing.assert_frame_equal(worker._read_trajectory_parquet(path), table)
|
| 31 |
+
+ pd.testing.assert_frame_equal(parent.curr_traj_data, table)
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/mean-profile-preparation.patch
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
diff --git a/latency_bench/data/sf_teacher_rollout.py b/latency_bench/data/sf_teacher_rollout.py
|
| 2 |
+
index ef45d95b..af0a9fa9 100644
|
| 3 |
+
--- a/latency_bench/data/sf_teacher_rollout.py
|
| 4 |
+
+++ b/latency_bench/data/sf_teacher_rollout.py
|
| 5 |
+
@@ -964,6 +964,11 @@ def _replay_accepted_specs(
|
| 6 |
+
row_buffer_size=int(row_buffer_size),
|
| 7 |
+
export_image_size=export_image_size,
|
| 8 |
+
)
|
| 9 |
+
+ stream_current_images = (
|
| 10 |
+
+ image_transform_config.normalized_transform() == "raw_rgb"
|
| 11 |
+
+ and int(context_window) <= 1
|
| 12 |
+
+ and filter_preset == "none"
|
| 13 |
+
+ )
|
| 14 |
+
image_resolution: list[int] | None = None
|
| 15 |
+
|
| 16 |
+
def assign_specs_to_slots(slots: list[int]) -> dict[int, int]:
|
| 17 |
+
@@ -1051,7 +1056,10 @@ def _replay_accepted_specs(
|
| 18 |
+
next_raw_frame=next_decision_step * obs_stride_raw_frames,
|
| 19 |
+
max_steps_per_episode=int(max_steps_per_episode),
|
| 20 |
+
)
|
| 21 |
+
- active_episode_frames[slot].append(np.array(image_frame, copy=True))
|
| 22 |
+
+ if stream_current_images:
|
| 23 |
+
+ image_writer.write(image_frame, image_path)
|
| 24 |
+
+ else:
|
| 25 |
+
+ active_episode_frames[slot].append(np.array(image_frame, copy=True))
|
| 26 |
+
row = teacher_dataset_row(
|
| 27 |
+
env_name=env_name,
|
| 28 |
+
spec=spec,
|
| 29 |
+
@@ -1104,7 +1112,9 @@ def _replay_accepted_specs(
|
| 30 |
+
)
|
| 31 |
+
else:
|
| 32 |
+
shard_rows = [dict(row) for row in final_rows]
|
| 33 |
+
- if _is_demon_ghost_trail:
|
| 34 |
+
+ if stream_current_images:
|
| 35 |
+
+ image_writer.flush()
|
| 36 |
+
+ elif _is_demon_ghost_trail:
|
| 37 |
+
# Frames are pre-built ghost trail images; map directly.
|
| 38 |
+
ep_steps = [int(row["decision_step"]) for row in final_rows]
|
| 39 |
+
frames_by_decision_step = {
|
| 40 |
+
@@ -1118,12 +1128,13 @@ def _replay_accepted_specs(
|
| 41 |
+
frames=active_episode_frames[slot],
|
| 42 |
+
config=image_transform_config,
|
| 43 |
+
)
|
| 44 |
+
- shard_rows = _write_filtered_episode_images(
|
| 45 |
+
- image_writer,
|
| 46 |
+
- shard_rows,
|
| 47 |
+
- frames_by_decision_step,
|
| 48 |
+
- context_window=int(context_window),
|
| 49 |
+
- )
|
| 50 |
+
+ if not stream_current_images:
|
| 51 |
+
+ shard_rows = _write_filtered_episode_images(
|
| 52 |
+
+ image_writer,
|
| 53 |
+
+ shard_rows,
|
| 54 |
+
+ frames_by_decision_step,
|
| 55 |
+
+ context_window=int(context_window),
|
| 56 |
+
+ )
|
| 57 |
+
write_episode_row_shard(output_dir, shard_rows)
|
| 58 |
+
progress.update(1)
|
| 59 |
+
replayed += 1
|
| 60 |
+
diff --git a/tests/data/test_sf_teacher_dataset_export.py b/tests/data/test_sf_teacher_dataset_export.py
|
| 61 |
+
index e6b25233..7d5537ac 100644
|
| 62 |
+
--- a/tests/data/test_sf_teacher_dataset_export.py
|
| 63 |
+
+++ b/tests/data/test_sf_teacher_dataset_export.py
|
| 64 |
+
@@ -1273,7 +1273,8 @@ def test_collect_teacher_dataset_saves_demon_attack_latest_raw_rgb_image(monkeyp
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
@pytest.mark.parametrize("export_history", [False, True])
|
| 68 |
+
-def test_collect_teacher_dataset_saves_flappy_latest_raw_rgb_image(monkeypatch, tmp_path, export_history):
|
| 69 |
+
+@pytest.mark.parametrize("filter_preset", ["clean_v1", "none"])
|
| 70 |
+
+def test_collect_teacher_dataset_saves_flappy_latest_raw_rgb_image(monkeypatch, tmp_path, export_history, filter_preset):
|
| 71 |
+
import torch
|
| 72 |
+
from gymnasium.spaces import Discrete
|
| 73 |
+
from PIL import Image
|
| 74 |
+
@@ -1307,6 +1308,9 @@ def test_collect_teacher_dataset_saves_flappy_latest_raw_rgb_image(monkeypatch,
|
| 75 |
+
class FakeEnv:
|
| 76 |
+
action_space = Discrete(2)
|
| 77 |
+
|
| 78 |
+
+ def __init__(self, exporting):
|
| 79 |
+
+ self.exporting = exporting
|
| 80 |
+
+
|
| 81 |
+
def reset(self, seed=None):
|
| 82 |
+
self.steps = 0
|
| 83 |
+
obs = {"obs": np.zeros((1, 12, 2, 2), dtype=np.uint8)}
|
| 84 |
+
@@ -1323,6 +1327,9 @@ def test_collect_teacher_dataset_saves_flappy_latest_raw_rgb_image(monkeypatch,
|
| 85 |
+
|
| 86 |
+
def step(self, action):
|
| 87 |
+
self.steps += 1
|
| 88 |
+
+ if self.exporting and self.steps == 2 and filter_preset == "none":
|
| 89 |
+
+ image_path = output_dir / "images/train/episode_000000/decision_step_000000.png"
|
| 90 |
+
+ assert image_path.is_file(), "First frame must be on disk before the episode ends"
|
| 91 |
+
obs = {"obs": np.ones((1, 12, 2, 2), dtype=np.uint8)}
|
| 92 |
+
next_stack = np.stack([np.full((6, 5, 3), 50 + idx, dtype=np.uint8) for idx in range(4)], axis=0)
|
| 93 |
+
return (
|
| 94 |
+
@@ -1354,7 +1361,7 @@ def test_collect_teacher_dataset_saves_flappy_latest_raw_rgb_image(monkeypatch,
|
| 95 |
+
exporter,
|
| 96 |
+
"build_env_and_policy",
|
| 97 |
+
lambda module, cfg, config, num_envs: {
|
| 98 |
+
- "envs": [FakeEnv()],
|
| 99 |
+
+ "envs": [FakeEnv(cfg.export_env_raw_rgb_frames)],
|
| 100 |
+
"env_info": object(),
|
| 101 |
+
"actor_critic": FakeActorCritic(),
|
| 102 |
+
"device": torch.device("cpu"),
|
| 103 |
+
@@ -1382,6 +1389,7 @@ def test_collect_teacher_dataset_saves_flappy_latest_raw_rgb_image(monkeypatch,
|
| 104 |
+
export_image_size=None,
|
| 105 |
+
image_writer_workers=0,
|
| 106 |
+
row_buffer_size=1,
|
| 107 |
+
+ filter_preset=filter_preset,
|
| 108 |
+
)
|
| 109 |
+
train_rows = _read_shard_rows(output_dir, "train")
|
| 110 |
+
val_rows = _read_shard_rows(output_dir, "val")
|
| 111 |
+
diff --git a/third_party/MIKASA-Robo b/third_party/MIKASA-Robo
|
| 112 |
+
--- a/third_party/MIKASA-Robo
|
| 113 |
+
+++ b/third_party/MIKASA-Robo
|
| 114 |
+
@@ -1 +1 @@
|
| 115 |
+
-Subproject commit 017490bbb787c6efa8c025f9558e1a691965c0e0
|
| 116 |
+
+Subproject commit 017490bbb787c6efa8c025f9558e1a691965c0e0-dirty
|
| 117 |
+
diff --git a/third_party/starVLA b/third_party/starVLA
|
| 118 |
+
--- a/third_party/starVLA
|
| 119 |
+
+++ b/third_party/starVLA
|
| 120 |
+
@@ -1 +1 @@
|
| 121 |
+
-Subproject commit ccca13c5177fe3d3c884b6e2de4965d916016649
|
| 122 |
+
+Subproject commit ccca13c5177fe3d3c884b6e2de4965d916016649-dirty
|
| 123 |
+
diff --git a/training/gymnasium_sf/integration.py b/training/gymnasium_sf/integration.py
|
| 124 |
+
index 61c65ae9..874f655f 100644
|
| 125 |
+
--- a/training/gymnasium_sf/integration.py
|
| 126 |
+
+++ b/training/gymnasium_sf/integration.py
|
| 127 |
+
@@ -64,7 +64,6 @@ from training.common.sf_raw_reward_stats_compat import (
|
| 128 |
+
)
|
| 129 |
+
from training.common.utils import env_instance_seed, seed_everything, str2bool
|
| 130 |
+
from training.common.wandb_compat import patch_sample_factory_wandb
|
| 131 |
+
-from sample_factory.algo.mc_ppo.env import EpisodeEnv
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
SF_ENV_NAME = "latency_gymnasium"
|
| 135 |
+
@@ -385,7 +384,11 @@ def make_gymnasium_sf_env(
|
| 136 |
+
env_id=int(env_config.env_id),
|
| 137 |
+
issued_action_labels=action_labels,
|
| 138 |
+
)
|
| 139 |
+
- return EpisodeEnv(env, cfg.ppo) if cfg.algo == "PPO" else env
|
| 140 |
+
+ if cfg.algo == "PPO":
|
| 141 |
+
+ from sample_factory.algo.mc_ppo.env import EpisodeEnv
|
| 142 |
+
+
|
| 143 |
+
+ return EpisodeEnv(env, cfg.ppo)
|
| 144 |
+
+ return env
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
def register_gymnasium_envs() -> None:
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/train_starvla.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/trainer_tools.py
ADDED
|
@@ -0,0 +1,736 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
metrics.py
|
| 3 |
+
|
| 4 |
+
Utility classes defining a Metrics container and multiple Trackers to enable model/stage-specific logging to various
|
| 5 |
+
endpoints (e.g., JSONL local logs, Weights & Biases).
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
from typing import Tuple
|
| 9 |
+
import re
|
| 10 |
+
import json
|
| 11 |
+
import numpy as np
|
| 12 |
+
import torch
|
| 13 |
+
import torch.distributed as dist
|
| 14 |
+
from transformers import get_scheduler
|
| 15 |
+
|
| 16 |
+
from accelerate import Accelerator, DeepSpeedPlugin
|
| 17 |
+
from accelerate.logging import get_logger
|
| 18 |
+
from starVLA.training.trainer_utils.config_tracker import reload_module_paths
|
| 19 |
+
|
| 20 |
+
logger = get_logger(__name__)
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def build_accelerator(cfg, *, use_deepspeed: bool) -> Accelerator:
|
| 24 |
+
accelerator_kwargs = {
|
| 25 |
+
"gradient_accumulation_steps": cfg.trainer.gradient_accumulation_steps,
|
| 26 |
+
}
|
| 27 |
+
if use_deepspeed:
|
| 28 |
+
accelerator_kwargs["deepspeed_plugin"] = DeepSpeedPlugin()
|
| 29 |
+
|
| 30 |
+
accelerator = Accelerator(**accelerator_kwargs)
|
| 31 |
+
accelerator.print(accelerator.state)
|
| 32 |
+
return accelerator
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
_VOCAB_SIZED_WEIGHT_SUFFIXES = (
|
| 36 |
+
"embed_tokens.weight",
|
| 37 |
+
"lm_head.weight",
|
| 38 |
+
)
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def _adapt_vocab_sized_weights(module, state_dict):
|
| 42 |
+
"""Copy overlapping vocab rows when tokenizer-sized Qwen weights changed."""
|
| 43 |
+
target_state_dict = module.state_dict()
|
| 44 |
+
adapted = dict(state_dict)
|
| 45 |
+
adapted_keys = []
|
| 46 |
+
for key, source_tensor in state_dict.items():
|
| 47 |
+
target_tensor = target_state_dict.get(key)
|
| 48 |
+
if target_tensor is None or not hasattr(source_tensor, "shape") or not hasattr(target_tensor, "shape"):
|
| 49 |
+
continue
|
| 50 |
+
if tuple(source_tensor.shape) == tuple(target_tensor.shape):
|
| 51 |
+
continue
|
| 52 |
+
if not key.endswith(_VOCAB_SIZED_WEIGHT_SUFFIXES):
|
| 53 |
+
continue
|
| 54 |
+
if source_tensor.ndim != 2 or target_tensor.ndim != 2:
|
| 55 |
+
continue
|
| 56 |
+
if source_tensor.shape[1] != target_tensor.shape[1]:
|
| 57 |
+
continue
|
| 58 |
+
|
| 59 |
+
patched_tensor = target_tensor.detach().clone()
|
| 60 |
+
rows = min(source_tensor.shape[0], target_tensor.shape[0])
|
| 61 |
+
patched_tensor[:rows].copy_(source_tensor[:rows].to(dtype=patched_tensor.dtype, device=patched_tensor.device))
|
| 62 |
+
adapted[key] = patched_tensor
|
| 63 |
+
adapted_keys.append((key, tuple(source_tensor.shape), tuple(target_tensor.shape), rows))
|
| 64 |
+
return adapted, adapted_keys
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
# === Define Tracker Interface ===
|
| 68 |
+
#
|
| 69 |
+
|
| 70 |
+
# utils/cli_parser.py
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def normalize_dotlist_args(args):
|
| 74 |
+
"""
|
| 75 |
+
Convert ['--x.y', 'val'] and ['--flag'] → ['x.y=val', 'flag=true']
|
| 76 |
+
"""
|
| 77 |
+
normalized = []
|
| 78 |
+
skip = False
|
| 79 |
+
for i in range(len(args)):
|
| 80 |
+
if skip:
|
| 81 |
+
skip = False
|
| 82 |
+
continue
|
| 83 |
+
|
| 84 |
+
arg = args[i]
|
| 85 |
+
if arg.startswith("--"):
|
| 86 |
+
key = arg.lstrip("-")
|
| 87 |
+
if "=" in key:
|
| 88 |
+
normalized.append(key)
|
| 89 |
+
elif i + 1 < len(args) and not args[i + 1].startswith("--"):
|
| 90 |
+
normalized.append(f"{key}={args[i + 1]}")
|
| 91 |
+
skip = True
|
| 92 |
+
else:
|
| 93 |
+
normalized.append(f"{key}=true")
|
| 94 |
+
else:
|
| 95 |
+
pass # skip orphaned values
|
| 96 |
+
return normalized
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
def setup_optimizer_and_scheduler(model, cfg) -> Tuple[torch.optim.Optimizer, torch.optim.lr_scheduler._LRScheduler]:
|
| 100 |
+
"""Build AdamW optimizer + LR scheduler from cfg.trainer.
|
| 101 |
+
|
| 102 |
+
Supports:
|
| 103 |
+
- Per-module learning rates via cfg.trainer.learning_rate
|
| 104 |
+
- cosine_with_min_lr (or any transformers scheduler) via cfg.trainer.lr_scheduler_type
|
| 105 |
+
"""
|
| 106 |
+
param_groups = build_param_lr_groups(model=model, cfg=cfg)
|
| 107 |
+
fused_available = torch.cuda.is_available()
|
| 108 |
+
optimizer = torch.optim.AdamW(
|
| 109 |
+
param_groups,
|
| 110 |
+
lr=cfg.trainer.learning_rate.base,
|
| 111 |
+
betas=tuple(cfg.trainer.optimizer.betas),
|
| 112 |
+
weight_decay=cfg.trainer.optimizer.weight_decay,
|
| 113 |
+
eps=cfg.trainer.optimizer.eps,
|
| 114 |
+
fused=fused_available,
|
| 115 |
+
)
|
| 116 |
+
|
| 117 |
+
if dist.is_initialized() and dist.get_rank() == 0:
|
| 118 |
+
for group in optimizer.param_groups:
|
| 119 |
+
logger.info(f"LR Group {group['name']}: lr={group['lr']}, num_params={len(group['params'])}")
|
| 120 |
+
|
| 121 |
+
# Strip keys unknown to transformers' get_scheduler before passing kwargs.
|
| 122 |
+
sched_kwargs = cfg.trainer.scheduler_specific_kwargs
|
| 123 |
+
lr_scheduler = get_scheduler(
|
| 124 |
+
name=cfg.trainer.lr_scheduler_type,
|
| 125 |
+
optimizer=optimizer,
|
| 126 |
+
num_warmup_steps=cfg.trainer.num_warmup_steps,
|
| 127 |
+
num_training_steps=cfg.trainer.max_train_steps,
|
| 128 |
+
scheduler_specific_kwargs=sched_kwargs,
|
| 129 |
+
)
|
| 130 |
+
|
| 131 |
+
return optimizer, lr_scheduler
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def _qwen_vl_interface(model):
|
| 135 |
+
return model.qwen_vl_interface
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def _llm_language_model(model):
|
| 139 |
+
return _qwen_vl_interface(model).model.model.language_model
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
def _vit_module(model):
|
| 143 |
+
# Qwen-VL keeps the visual tower and its vision-to-language connector/merger
|
| 144 |
+
# under this module.
|
| 145 |
+
return _qwen_vl_interface(model).model.model.visual
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
def _llm_decoder_layers(model):
|
| 149 |
+
return _llm_language_model(model).layers
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def _tied_embedding_modules(model):
|
| 153 |
+
language_model = _llm_language_model(model)
|
| 154 |
+
hf_model = _qwen_vl_interface(model).model
|
| 155 |
+
return language_model.embed_tokens, hf_model.lm_head
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
def resolve_freeze_llm_layer_indices(model, cfg):
|
| 159 |
+
"""Translate ``trainer.freeze_llm_layers=[start,end]`` to an inclusive layer list."""
|
| 160 |
+
freeze_llm_layers = cfg.trainer.freeze_llm_layers
|
| 161 |
+
if not freeze_llm_layers:
|
| 162 |
+
return [], len(_llm_decoder_layers(model))
|
| 163 |
+
start, end = [int(value) for value in freeze_llm_layers]
|
| 164 |
+
return list(range(start, end + 1)), len(_llm_decoder_layers(model))
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def _module_param_ids(module):
|
| 168 |
+
return {id(param) for param in module.parameters()}
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
def _has_vit_or_llm_freeze_request(cfg) -> bool:
|
| 172 |
+
return bool(cfg.trainer.freeze_vit or cfg.trainer.freeze_tied_embedding or cfg.trainer.freeze_llm_layers)
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
def vit_llm_frozen_param_ids(model, cfg):
|
| 176 |
+
"""Parameter ids excluded from optimizer by trainer freeze controls."""
|
| 177 |
+
if not _has_vit_or_llm_freeze_request(cfg):
|
| 178 |
+
return set()
|
| 179 |
+
|
| 180 |
+
frozen_params = set()
|
| 181 |
+
freeze_vit = cfg.trainer.freeze_vit
|
| 182 |
+
if freeze_vit:
|
| 183 |
+
frozen_params.update(_module_param_ids(_vit_module(model)))
|
| 184 |
+
|
| 185 |
+
if cfg.trainer.freeze_tied_embedding:
|
| 186 |
+
for module in _tied_embedding_modules(model):
|
| 187 |
+
frozen_params.update(_module_param_ids(module))
|
| 188 |
+
|
| 189 |
+
frozen_layer_indices, _ = resolve_freeze_llm_layer_indices(model, cfg)
|
| 190 |
+
layers = list(_llm_decoder_layers(model))
|
| 191 |
+
for layer_index in frozen_layer_indices:
|
| 192 |
+
frozen_params.update(_module_param_ids(layers[layer_index]))
|
| 193 |
+
|
| 194 |
+
return frozen_params
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
def build_param_lr_groups(model, cfg):
|
| 198 |
+
"""
|
| 199 |
+
build multiple param groups based on cfg.trainer.learning_rate.
|
| 200 |
+
support specifying different learning rates for different modules, the rest use base.
|
| 201 |
+
|
| 202 |
+
Args:
|
| 203 |
+
vla: nn.Module model object
|
| 204 |
+
cfg: config object, requires cfg.trainer.learning_rate dictionary
|
| 205 |
+
|
| 206 |
+
Returns:
|
| 207 |
+
List[Dict]: param_groups that can be used to build optimizer with torch.optim
|
| 208 |
+
"""
|
| 209 |
+
|
| 210 |
+
lr_cfg = cfg.trainer.learning_rate
|
| 211 |
+
base_lr = lr_cfg.get("base", 1e-4) # default base learning rate
|
| 212 |
+
|
| 213 |
+
freeze_modules = cfg.trainer.get("freeze_modules", "")
|
| 214 |
+
if not isinstance(freeze_modules, str):
|
| 215 |
+
freeze_modules = ""
|
| 216 |
+
freeze_patterns = [p.strip() for p in freeze_modules.split(",") if p.strip()]
|
| 217 |
+
|
| 218 |
+
used_params = set()
|
| 219 |
+
frozen_params = set()
|
| 220 |
+
param_groups = []
|
| 221 |
+
|
| 222 |
+
for freeze_path in freeze_patterns:
|
| 223 |
+
module = model
|
| 224 |
+
try:
|
| 225 |
+
for attr in freeze_path.split("."):
|
| 226 |
+
module = getattr(module, attr)
|
| 227 |
+
frozen_params.update(id(p) for p in module.parameters())
|
| 228 |
+
except AttributeError:
|
| 229 |
+
print(f"⚠️ freeze module path does not exist: {freeze_path}")
|
| 230 |
+
continue
|
| 231 |
+
|
| 232 |
+
# Exclude trainer freeze controls so frozen parameters never enter an
|
| 233 |
+
# optimizer param group.
|
| 234 |
+
frozen_params.update(vit_llm_frozen_param_ids(model, cfg))
|
| 235 |
+
|
| 236 |
+
for module_name, lr in lr_cfg.items():
|
| 237 |
+
if module_name == "base":
|
| 238 |
+
continue
|
| 239 |
+
# try to find the module under vla by module_name (support nested paths)
|
| 240 |
+
module = model
|
| 241 |
+
try:
|
| 242 |
+
for attr in module_name.split("."):
|
| 243 |
+
module = getattr(module, attr)
|
| 244 |
+
# filter out frozen parameters
|
| 245 |
+
params = [p for p in module.parameters() if id(p) not in frozen_params]
|
| 246 |
+
if params: # only add param group if there are trainable parameters
|
| 247 |
+
param_groups.append({"params": params, "lr": lr, "name": module_name})
|
| 248 |
+
used_params.update(id(p) for p in params)
|
| 249 |
+
except AttributeError:
|
| 250 |
+
ReferenceError(f"⚠️ module path `{module_name}` not found in vla")
|
| 251 |
+
|
| 252 |
+
# assign base learning rate to the remaining unused parameters (exclude frozen ones)
|
| 253 |
+
other_params = [p for p in model.parameters() if id(p) not in used_params and id(p) not in frozen_params]
|
| 254 |
+
if other_params:
|
| 255 |
+
param_groups.append({"params": other_params, "lr": base_lr, "name": "base"})
|
| 256 |
+
|
| 257 |
+
return param_groups
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
import torch.distributed as dist
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
def only_main_process(func):
|
| 264 |
+
"""
|
| 265 |
+
decorator: only run in main process (rank=0)
|
| 266 |
+
"""
|
| 267 |
+
|
| 268 |
+
def wrapper(*args, **kwargs):
|
| 269 |
+
if dist.is_initialized() and dist.get_rank() != 0:
|
| 270 |
+
return None # non-main process does not execute
|
| 271 |
+
return func(*args, **kwargs)
|
| 272 |
+
|
| 273 |
+
return wrapper
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
from torchvision.ops import box_iou
|
| 277 |
+
from PIL import Image
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
def resize_images(images, target_size=(224, 224)):
|
| 281 |
+
"""
|
| 282 |
+
recursively resize all images in the nested list.
|
| 283 |
+
|
| 284 |
+
:param images: nested list of images or single image.
|
| 285 |
+
:param target_size: target size (width, height) after resizing.
|
| 286 |
+
:return: resized images list, keeping the original nested structure.
|
| 287 |
+
"""
|
| 288 |
+
if isinstance(images, Image.Image): # if it is a single PIL image
|
| 289 |
+
return images.resize(target_size)
|
| 290 |
+
elif isinstance(images, list): # if it is a list, recursively process each element
|
| 291 |
+
return [resize_images(img, target_size) for img in images]
|
| 292 |
+
else:
|
| 293 |
+
raise ValueError("Unsupported image type or structure.")
|
| 294 |
+
|
| 295 |
+
|
| 296 |
+
def stitch_frames(frames, grid=(2, 2), size=(224, 224)):
|
| 297 |
+
"""Tile temporal frames into one image, keeping the token count of a single image.
|
| 298 |
+
|
| 299 |
+
Used by the ``stitch`` multi-image mode: instead of feeding N frames as N
|
| 300 |
+
tokenized images, they are laid out on a fixed grid and the whole canvas is
|
| 301 |
+
returned at ``size``. Both training (``_pack_sample``) and eval
|
| 302 |
+
(``policy/starvla.py``) call this so the layouts match.
|
| 303 |
+
|
| 304 |
+
Args:
|
| 305 |
+
frames: list of ``PIL.Image`` or ``np.ndarray`` (H, W, C), oldest first.
|
| 306 |
+
grid: (rows, cols). Cells beyond ``len(frames)`` repeat the last frame so
|
| 307 |
+
the layout is fixed regardless of how many frames are available.
|
| 308 |
+
size: (width, height) of the returned canvas.
|
| 309 |
+
"""
|
| 310 |
+
rows, cols = grid
|
| 311 |
+
canvas_w, canvas_h = size
|
| 312 |
+
cell_w, cell_h = canvas_w // cols, canvas_h // rows
|
| 313 |
+
pil = [f if isinstance(f, Image.Image) else Image.fromarray(f) for f in frames]
|
| 314 |
+
capacity = rows * cols
|
| 315 |
+
pil = (pil + [pil[-1]] * (capacity - len(pil))) if len(pil) < capacity else pil[:capacity]
|
| 316 |
+
canvas = Image.new("RGB", (canvas_w, canvas_h))
|
| 317 |
+
for idx, frame in enumerate(pil):
|
| 318 |
+
r, c = divmod(idx, cols)
|
| 319 |
+
canvas.paste(frame.convert("RGB").resize((cell_w, cell_h)), (c * cell_w, r * cell_h))
|
| 320 |
+
return canvas
|
| 321 |
+
|
| 322 |
+
|
| 323 |
+
import torch.distributed as dist
|
| 324 |
+
|
| 325 |
+
|
| 326 |
+
class TrainerUtils:
|
| 327 |
+
@staticmethod
|
| 328 |
+
def freeze_backbones(model, freeze_modules=""):
|
| 329 |
+
"""
|
| 330 |
+
directly freeze the specified submodules based on the relative module path list (patterns), no longer recursively find all submodule names:
|
| 331 |
+
- patterns: read from config.trainer.freeze_modules, separated by commas to get the "relative path" list
|
| 332 |
+
for example "qwen_vl_interface, action_model.net",
|
| 333 |
+
it means to freeze model.qwen_vl_interface and model.action_model.net.
|
| 334 |
+
|
| 335 |
+
Args:
|
| 336 |
+
model: nn.Module model object
|
| 337 |
+
freeze_modules: relative module path list (patterns)
|
| 338 |
+
|
| 339 |
+
Returns:
|
| 340 |
+
model: nn.Module model object
|
| 341 |
+
return:
|
| 342 |
+
- model:
|
| 343 |
+
"""
|
| 344 |
+
frozen = []
|
| 345 |
+
print("#"*30)
|
| 346 |
+
print(freeze_modules)
|
| 347 |
+
if freeze_modules and type(freeze_modules) == str:
|
| 348 |
+
# split and remove whitespace
|
| 349 |
+
patterns = [p.strip() for p in freeze_modules.split(",") if p.strip()] if freeze_modules else []
|
| 350 |
+
|
| 351 |
+
for path in patterns:
|
| 352 |
+
# split the "relative path" by dots, for example "action_model.net" → ["action_model", "net"]
|
| 353 |
+
attrs = path.split(".")
|
| 354 |
+
module = model
|
| 355 |
+
try:
|
| 356 |
+
for attr in attrs:
|
| 357 |
+
module = getattr(module, attr)
|
| 358 |
+
# if the module is successfully get, freeze it and its all submodule parameters
|
| 359 |
+
for param in module.parameters():
|
| 360 |
+
param.requires_grad = False
|
| 361 |
+
frozen.append(path)
|
| 362 |
+
except AttributeError:
|
| 363 |
+
# if the attribute does not exist, skip and print warning
|
| 364 |
+
print(f"⚠️ module path does not exist, cannot freeze: {path}")
|
| 365 |
+
continue
|
| 366 |
+
|
| 367 |
+
# accelerator.wait_for_everyone() # synchronize when distributed training
|
| 368 |
+
if not dist.is_initialized() or dist.get_rank() == 0:
|
| 369 |
+
print(f"🔒 Frozen modules with re pattern: {frozen}")
|
| 370 |
+
return model
|
| 371 |
+
|
| 372 |
+
@staticmethod
|
| 373 |
+
def freeze_vit_and_llm_layers(model, cfg):
|
| 374 |
+
"""Apply trainer.freeze_vit/freeze_tied_embedding/freeze_llm_layers.
|
| 375 |
+
|
| 376 |
+
trainer.freeze_vit freezes Qwen-VL's visual module, including the
|
| 377 |
+
vision-to-language connector/merger it contains.
|
| 378 |
+
"""
|
| 379 |
+
if not _has_vit_or_llm_freeze_request(cfg):
|
| 380 |
+
return model
|
| 381 |
+
|
| 382 |
+
freeze_vit = cfg.trainer.freeze_vit
|
| 383 |
+
if freeze_vit:
|
| 384 |
+
for param in _vit_module(model).parameters():
|
| 385 |
+
param.requires_grad = False
|
| 386 |
+
|
| 387 |
+
freeze_tied_embedding = cfg.trainer.freeze_tied_embedding
|
| 388 |
+
if freeze_tied_embedding:
|
| 389 |
+
for module in _tied_embedding_modules(model):
|
| 390 |
+
for param in module.parameters():
|
| 391 |
+
param.requires_grad = False
|
| 392 |
+
|
| 393 |
+
frozen_layer_indices, total = resolve_freeze_llm_layer_indices(model, cfg)
|
| 394 |
+
layers = list(_llm_decoder_layers(model))
|
| 395 |
+
for layer_index in frozen_layer_indices:
|
| 396 |
+
for param in layers[layer_index].parameters():
|
| 397 |
+
param.requires_grad = False
|
| 398 |
+
|
| 399 |
+
if not dist.is_initialized() or dist.get_rank() == 0:
|
| 400 |
+
print(
|
| 401 |
+
"🔒 freeze_vit="
|
| 402 |
+
f"{freeze_vit}, freeze_tied_embedding={freeze_tied_embedding}, "
|
| 403 |
+
f"freeze_llm_layers={list(frozen_layer_indices)}"
|
| 404 |
+
f" / total={total}"
|
| 405 |
+
)
|
| 406 |
+
return model
|
| 407 |
+
|
| 408 |
+
@staticmethod
|
| 409 |
+
def print_trainable_parameters(model):
|
| 410 |
+
"""
|
| 411 |
+
print the total number of parameters and trainable parameters of the model
|
| 412 |
+
:param model: PyTorch model instance
|
| 413 |
+
"""
|
| 414 |
+
if dist.is_initialized() and dist.get_rank() != 0:
|
| 415 |
+
return
|
| 416 |
+
print("📊 model parameter statistics:")
|
| 417 |
+
num_params = sum(p.numel() for p in model.parameters())
|
| 418 |
+
num_trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
|
| 419 |
+
print(
|
| 420 |
+
f"# Parameters (in millions): {num_params / 10**6:.3f} Total, {num_trainable_params / 10**6:.3f} Trainable"
|
| 421 |
+
)
|
| 422 |
+
return num_params, num_trainable_params
|
| 423 |
+
|
| 424 |
+
@staticmethod
|
| 425 |
+
def load_pretrained_backbones(model, checkpoint_path=None, reload_modules=None):
|
| 426 |
+
"""
|
| 427 |
+
load checkpoint:
|
| 428 |
+
- if reload_modules is set, load by path part
|
| 429 |
+
- otherwise → load the entire model parameters (overwrite model)
|
| 430 |
+
|
| 431 |
+
return:
|
| 432 |
+
replace, loaded_modules: list of module paths that successfully loaded parameters; if global load, then ["<full_model>"]
|
| 433 |
+
"""
|
| 434 |
+
if not checkpoint_path:
|
| 435 |
+
return []
|
| 436 |
+
if not dist.is_initialized() or dist.get_rank() == 0:
|
| 437 |
+
print(f"📦 loading checkpoint: {checkpoint_path}")
|
| 438 |
+
try:
|
| 439 |
+
if _is_safetensors_path(checkpoint_path):
|
| 440 |
+
from safetensors.torch import load_file
|
| 441 |
+
|
| 442 |
+
checkpoint = load_file(checkpoint_path)
|
| 443 |
+
else:
|
| 444 |
+
checkpoint = torch.load(checkpoint_path, map_location="cpu")
|
| 445 |
+
except Exception as e:
|
| 446 |
+
raise RuntimeError(f"❌ loading checkpoint failed: {e}")
|
| 447 |
+
|
| 448 |
+
loaded_modules = []
|
| 449 |
+
|
| 450 |
+
module_paths = reload_module_paths(reload_modules)
|
| 451 |
+
if module_paths: # partial load
|
| 452 |
+
for path in module_paths:
|
| 453 |
+
reload_path = path.split(".")
|
| 454 |
+
module = model
|
| 455 |
+
try:
|
| 456 |
+
for module_name in reload_path: # find the module to modify level by level
|
| 457 |
+
module = getattr(module, module_name)
|
| 458 |
+
prefix = path + "."
|
| 459 |
+
sub_state_dict = {k[len(prefix) :]: v for k, v in checkpoint.items() if k.startswith(prefix)}
|
| 460 |
+
if sub_state_dict:
|
| 461 |
+
sub_state_dict, adapted_keys = _adapt_vocab_sized_weights(module, sub_state_dict)
|
| 462 |
+
for key, source_shape, target_shape, rows in adapted_keys:
|
| 463 |
+
if not dist.is_initialized() or dist.get_rank() == 0:
|
| 464 |
+
print(
|
| 465 |
+
f"⚠️ adapted vocab-sized weight '{path}.{key}' from checkpoint shape "
|
| 466 |
+
f"{source_shape} to current shape {target_shape}; copied {rows} rows"
|
| 467 |
+
)
|
| 468 |
+
module.load_state_dict(sub_state_dict, strict=True)
|
| 469 |
+
if not dist.is_initialized() or dist.get_rank() == 0:
|
| 470 |
+
print(f"✅ parameters loaded to module '{path}'")
|
| 471 |
+
loaded_modules.append(path)
|
| 472 |
+
else:
|
| 473 |
+
print(f"⚠️ parameters not found in checkpoint '{path}'")
|
| 474 |
+
except AttributeError:
|
| 475 |
+
print(f"❌ cannot find module path: {path}")
|
| 476 |
+
else: # full load
|
| 477 |
+
try:
|
| 478 |
+
checkpoint, adapted_keys = _adapt_vocab_sized_weights(model, checkpoint)
|
| 479 |
+
for key, source_shape, target_shape, rows in adapted_keys:
|
| 480 |
+
if not dist.is_initialized() or dist.get_rank() == 0:
|
| 481 |
+
print(
|
| 482 |
+
f"⚠️ adapted vocab-sized weight '{key}' from checkpoint shape "
|
| 483 |
+
f"{source_shape} to current shape {target_shape}; copied {rows} rows"
|
| 484 |
+
)
|
| 485 |
+
model.load_state_dict(checkpoint, strict=False)
|
| 486 |
+
if not dist.is_initialized() or dist.get_rank() == 0:
|
| 487 |
+
print("✅ loaded <full_model> model parameters")
|
| 488 |
+
loaded_modules = ["<full_model>"]
|
| 489 |
+
except Exception as e:
|
| 490 |
+
raise RuntimeError(f"❌ loading full model failed: {e}")
|
| 491 |
+
return model
|
| 492 |
+
|
| 493 |
+
@staticmethod
|
| 494 |
+
def print_freeze_status(model):
|
| 495 |
+
"""
|
| 496 |
+
print the freezing status of each parameter in the model
|
| 497 |
+
:param model: PyTorch model instance
|
| 498 |
+
"""
|
| 499 |
+
for name, param in model.named_parameters():
|
| 500 |
+
status = "Frozen" if not param.requires_grad else "Trainable"
|
| 501 |
+
print(f"{name:60s} | {status}")
|
| 502 |
+
|
| 503 |
+
@staticmethod
|
| 504 |
+
def setup_distributed_training(accelerator, *components):
|
| 505 |
+
"""
|
| 506 |
+
use Accelerator to prepare distributed training components
|
| 507 |
+
:param accelerator: Accelerate instance
|
| 508 |
+
:param components: any number of components (such as model, optimizer, dataloader, etc.)
|
| 509 |
+
:return: prepared distributed components (in the same order as input)
|
| 510 |
+
"""
|
| 511 |
+
|
| 512 |
+
# use accelerator.prepare method to wrap components
|
| 513 |
+
prepared_components = accelerator.prepare(*components)
|
| 514 |
+
return prepared_components
|
| 515 |
+
|
| 516 |
+
@staticmethod
|
| 517 |
+
def euclidean_distance(predicted: np.ndarray, ground_truth: np.ndarray) -> float:
|
| 518 |
+
return np.linalg.norm(predicted - ground_truth)
|
| 519 |
+
|
| 520 |
+
@staticmethod
|
| 521 |
+
def _reset_dataloader(dataloader, epoch_counter):
|
| 522 |
+
"""safe reset dataloader iterator"""
|
| 523 |
+
# 1. update epoch counter
|
| 524 |
+
epoch_counter += 1
|
| 525 |
+
|
| 526 |
+
dataset = getattr(dataloader, "dataset", None)
|
| 527 |
+
if dataset is not None and callable(getattr(dataset, "set_epoch", None)):
|
| 528 |
+
dataset.set_epoch(epoch_counter)
|
| 529 |
+
|
| 530 |
+
# 2. set new epoch (distributed core)
|
| 531 |
+
if hasattr(dataloader, "sampler") and callable(getattr(dataloader.sampler, "set_epoch", None)):
|
| 532 |
+
dataloader.sampler.set_epoch(epoch_counter)
|
| 533 |
+
|
| 534 |
+
# 3. create new iterator
|
| 535 |
+
return iter(dataloader), epoch_counter
|
| 536 |
+
|
| 537 |
+
@staticmethod
|
| 538 |
+
def compute_grad_angle_with_stats(grads_a: list[torch.Tensor], grads_v: list[torch.Tensor]) -> Tuple[float, float]:
|
| 539 |
+
"""
|
| 540 |
+
compute the cosine angle between two groups of gradient vectors (degrees), and calculate the average angle and variance.
|
| 541 |
+
grads_a, grads_v: gradient Tensor list corresponding to the same parameter list interface_params
|
| 542 |
+
return:
|
| 543 |
+
mean_angle_deg: average angle (degrees)
|
| 544 |
+
angle_variance: angle variance
|
| 545 |
+
"""
|
| 546 |
+
angle_degs = []
|
| 547 |
+
|
| 548 |
+
# compute the cosine angle between each gradient block grads_a[0].shape = 1280, 3, 14, 14
|
| 549 |
+
# grads_1 = grads_a[0][0] # [3, 14, 14]
|
| 550 |
+
# grads_2 = grads_v[0][0]
|
| 551 |
+
# grads_a = grads_1.view(-1, 3) # reshape to [196, 3]
|
| 552 |
+
# grads_v = grads_2.view(-1, 3)
|
| 553 |
+
|
| 554 |
+
# lang linear
|
| 555 |
+
# reshape to 14*14, 3
|
| 556 |
+
# layer
|
| 557 |
+
grads_action = grads_a[0] # [2048, 11008]
|
| 558 |
+
grads_action = grads_action[
|
| 559 |
+
:32, :7
|
| 560 |
+
] # only take the first 7 elements, avoid cosim failure in high-dimensional space
|
| 561 |
+
grads_vl = grads_v[0] # [2048, 11008]
|
| 562 |
+
grads_vl = grads_vl[
|
| 563 |
+
:32, :7
|
| 564 |
+
] # only take the first 32 elements, 7 dimensions, avoid cosim failure in high-dimensional space
|
| 565 |
+
for g_a, g_v in zip(grads_action, grads_vl):
|
| 566 |
+
dot = torch.sum(g_a * g_v)
|
| 567 |
+
norm_a_sq = torch.sum(g_a * g_a)
|
| 568 |
+
norm_v_sq = torch.sum(g_v * g_v)
|
| 569 |
+
|
| 570 |
+
# avoid division by zero
|
| 571 |
+
norm_a = torch.sqrt(norm_a_sq + 1e-16)
|
| 572 |
+
norm_v = torch.sqrt(norm_v_sq + 1e-16)
|
| 573 |
+
|
| 574 |
+
cos_sim = (dot / (norm_a * norm_v)).clamp(-1.0, 1.0)
|
| 575 |
+
angle_rad = torch.acos(cos_sim)
|
| 576 |
+
angle_deg = angle_rad * (180.0 / torch.pi)
|
| 577 |
+
|
| 578 |
+
angle_degs.append(angle_deg.item())
|
| 579 |
+
|
| 580 |
+
# compute the average angle and variance
|
| 581 |
+
angle_degs_tensor = torch.tensor(angle_degs)
|
| 582 |
+
mean_angle_deg = torch.mean(angle_degs_tensor).item()
|
| 583 |
+
angle_variance = torch.sqrt(torch.var(angle_degs_tensor)).item()
|
| 584 |
+
# accelerator.wait_for_everyone()
|
| 585 |
+
return mean_angle_deg, angle_variance
|
| 586 |
+
|
| 587 |
+
@staticmethod
|
| 588 |
+
def pcgrad_project(grads_a: list[torch.Tensor], grads_v: list[torch.Tensor]) -> list[torch.Tensor]:
|
| 589 |
+
"""
|
| 590 |
+
apply PCGrad projection to the second group of gradients grads_v, suppress negative transfer between grads_a and grads_v
|
| 591 |
+
if the dot product of two groups of gradients < 0, then:
|
| 592 |
+
grads_v <- grads_v - (dot / ||grads_a||^2) * grads_a
|
| 593 |
+
return the new grads_v list
|
| 594 |
+
"""
|
| 595 |
+
# first compute dot and ||grads_a||^2
|
| 596 |
+
dot, norm_a_sq = 0.0, 0.0
|
| 597 |
+
for g_a, g_v in zip(grads_a, grads_v):
|
| 598 |
+
dot += torch.sum(g_a * g_v)
|
| 599 |
+
norm_a_sq += torch.sum(g_a * g_a)
|
| 600 |
+
|
| 601 |
+
if dot < 0:
|
| 602 |
+
coeff = dot / (norm_a_sq + 1e-6)
|
| 603 |
+
# projection
|
| 604 |
+
grads_v = [g_v - coeff * g_a for g_a, g_v in zip(grads_a, grads_v)]
|
| 605 |
+
|
| 606 |
+
return grads_v
|
| 607 |
+
|
| 608 |
+
@staticmethod
|
| 609 |
+
def eval_qwenpi(qwenpi, dataloader, num_batches=20):
|
| 610 |
+
"""
|
| 611 |
+
evaluate QwenQFormerDiT model, compute IoU and action distance.
|
| 612 |
+
|
| 613 |
+
Args:
|
| 614 |
+
qwenpi: QwenQFormerDiT model instance.
|
| 615 |
+
dataloader: data loader.
|
| 616 |
+
num_batches: number of batches to evaluate.
|
| 617 |
+
|
| 618 |
+
Returns:
|
| 619 |
+
dict: contains IoU and action distance evaluation results.
|
| 620 |
+
"""
|
| 621 |
+
iou_scores = []
|
| 622 |
+
action_distances = []
|
| 623 |
+
count = 0
|
| 624 |
+
|
| 625 |
+
dataset_iter = iter(dataloader)
|
| 626 |
+
while count < num_batches:
|
| 627 |
+
try:
|
| 628 |
+
batch_samples = next(dataset_iter)
|
| 629 |
+
count += 1
|
| 630 |
+
except StopIteration:
|
| 631 |
+
break
|
| 632 |
+
|
| 633 |
+
# extract data
|
| 634 |
+
images = [example["image"] for example in batch_samples]
|
| 635 |
+
instructions = [example["lang"] for example in batch_samples]
|
| 636 |
+
actions = [example["action"] for example in batch_samples]
|
| 637 |
+
solutions = [example["solution"] for example in batch_samples]
|
| 638 |
+
|
| 639 |
+
# model prediction
|
| 640 |
+
predicted_solutions, normalized_actions = qwenpi.predict_action_withCoT(
|
| 641 |
+
images=images, instructions=instructions, use_ddim=False, num_ddim_steps=20
|
| 642 |
+
)
|
| 643 |
+
|
| 644 |
+
# extract and convert predicted results
|
| 645 |
+
parsed_solutions = []
|
| 646 |
+
for solution in predicted_solutions:
|
| 647 |
+
parsed_solution = TrainerUtils.extract_json_from_string(solution)
|
| 648 |
+
parsed_solutions.append(parsed_solution)
|
| 649 |
+
|
| 650 |
+
# compute IoU
|
| 651 |
+
for pred_dict, gt_dict in zip(parsed_solutions, solutions):
|
| 652 |
+
pred_pick_bbox = torch.tensor(pred_dict["pick"]["bbox_2d"], dtype=torch.float32).unsqueeze(0)
|
| 653 |
+
gt_pick_bbox = torch.tensor(gt_dict["pick"]["bbox_2d"], dtype=torch.float32).unsqueeze(0)
|
| 654 |
+
pred_place_bbox = torch.tensor(pred_dict["place"]["bbox_2d"], dtype=torch.float32).unsqueeze(0)
|
| 655 |
+
gt_place_bbox = torch.tensor(gt_dict["place"]["bbox_2d"], dtype=torch.float32).unsqueeze(0)
|
| 656 |
+
|
| 657 |
+
pick_iou = box_iou(pred_pick_bbox, gt_pick_bbox).item()
|
| 658 |
+
place_iou = box_iou(pred_place_bbox, gt_place_bbox).item()
|
| 659 |
+
|
| 660 |
+
iou_scores.append({"pick_iou": pick_iou, "place_iou": place_iou})
|
| 661 |
+
|
| 662 |
+
# compute action distance
|
| 663 |
+
actions = np.array(actions) # convert to numpy array
|
| 664 |
+
num_pots = np.prod(actions.shape) # B*len*dim
|
| 665 |
+
action_distance = TrainerUtils.euclidean_distance(normalized_actions, actions)
|
| 666 |
+
average_action_distance = action_distance / num_pots
|
| 667 |
+
action_distances.append(average_action_distance)
|
| 668 |
+
|
| 669 |
+
# summarize results
|
| 670 |
+
avg_action_distance = np.mean(action_distances)
|
| 671 |
+
return {"iou_scores": iou_scores, "average_action_distance": avg_action_distance}
|
| 672 |
+
|
| 673 |
+
@staticmethod
|
| 674 |
+
def extract_json_from_string(input_string):
|
| 675 |
+
"""
|
| 676 |
+
extract valid JSON part from string and convert to dictionary.
|
| 677 |
+
|
| 678 |
+
Args:
|
| 679 |
+
input_string (str): string containing extra characters.
|
| 680 |
+
|
| 681 |
+
Returns:
|
| 682 |
+
dict: dictionary extracted and parsed.
|
| 683 |
+
"""
|
| 684 |
+
json_match = re.search(r"{.*}", input_string, re.DOTALL)
|
| 685 |
+
if json_match:
|
| 686 |
+
json_str = json_match.group(0)
|
| 687 |
+
try:
|
| 688 |
+
return json.loads(json_str)
|
| 689 |
+
except json.JSONDecodeError as e:
|
| 690 |
+
print(f"JSON decode failed: {e}")
|
| 691 |
+
return None
|
| 692 |
+
else:
|
| 693 |
+
print("No valid JSON part found")
|
| 694 |
+
return None
|
| 695 |
+
|
| 696 |
+
def _get_latest_checkpoint(self, checkpoint_dir):
|
| 697 |
+
"""Find the latest checkpoint in the directory based on step number."""
|
| 698 |
+
if not os.path.exists(checkpoint_dir):
|
| 699 |
+
self.accelerator.print(f"No checkpoint directory found at {checkpoint_dir}")
|
| 700 |
+
return None, 0
|
| 701 |
+
|
| 702 |
+
checkpoints = []
|
| 703 |
+
for name in os.listdir(checkpoint_dir):
|
| 704 |
+
path = os.path.join(checkpoint_dir, name)
|
| 705 |
+
state_match = re.match(r"steps_(\d+)_state$", name)
|
| 706 |
+
if state_match and os.path.isdir(path):
|
| 707 |
+
checkpoints.append((name, int(state_match.group(1)), 1))
|
| 708 |
+
continue
|
| 709 |
+
file_match = re.match(r"steps_(\d+)_(?:pytorch_model\.pt|model\.safetensors)$", name)
|
| 710 |
+
if file_match and os.path.isfile(path):
|
| 711 |
+
checkpoints.append((name, int(file_match.group(1)), 0))
|
| 712 |
+
|
| 713 |
+
if not checkpoints:
|
| 714 |
+
self.accelerator.print(f"No checkpoints found in {checkpoint_dir}")
|
| 715 |
+
return None, 0
|
| 716 |
+
|
| 717 |
+
# Sort by step number, preferring full training-state directories over
|
| 718 |
+
# model-only files when both exist for the same step.
|
| 719 |
+
checkpoints.sort(key=lambda x: (x[1], x[2]))
|
| 720 |
+
latest_checkpoint, completed_steps, _ = checkpoints[-1]
|
| 721 |
+
|
| 722 |
+
latest_checkpoint_path = os.path.join(checkpoint_dir, latest_checkpoint)
|
| 723 |
+
self.accelerator.print(f"Latest checkpoint found: {latest_checkpoint_path}")
|
| 724 |
+
return latest_checkpoint_path, completed_steps
|
| 725 |
+
|
| 726 |
+
import os
|
| 727 |
+
|
| 728 |
+
|
| 729 |
+
def is_main_process():
|
| 730 |
+
rank = int(os.environ.get("RANK", 0)) # if RANK is not set, default to 0
|
| 731 |
+
return rank == 0
|
| 732 |
+
|
| 733 |
+
|
| 734 |
+
def _is_safetensors_path(path):
|
| 735 |
+
"""Check if a path refers to a safetensors file."""
|
| 736 |
+
return str(path).endswith(".safetensors")
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training-code/worker_context.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import multiprocessing.context
|
| 2 |
+
import os
|
| 3 |
+
from typing import Any
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
_DISTRIBUTED_ENV_KEYS = (
|
| 7 |
+
"LOCAL_RANK",
|
| 8 |
+
"RANK",
|
| 9 |
+
"WORLD_SIZE",
|
| 10 |
+
"MASTER_ADDR",
|
| 11 |
+
"MASTER_PORT",
|
| 12 |
+
"GROUP_RANK",
|
| 13 |
+
"LOCAL_WORLD_SIZE",
|
| 14 |
+
"ROLE_RANK",
|
| 15 |
+
"ROLE_WORLD_SIZE",
|
| 16 |
+
"TORCHELASTIC_RUN_ID",
|
| 17 |
+
"TORCHELASTIC_RESTART_COUNT",
|
| 18 |
+
"TORCHELASTIC_MAX_RESTARTS",
|
| 19 |
+
)
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class _CpuOnlyWorkerSpawnProcess(multiprocessing.context.SpawnProcess):
|
| 23 |
+
def start(self):
|
| 24 |
+
had_cuda_visible_devices = "CUDA_VISIBLE_DEVICES" in os.environ
|
| 25 |
+
if had_cuda_visible_devices:
|
| 26 |
+
cuda_visible_devices = os.environ["CUDA_VISIBLE_DEVICES"]
|
| 27 |
+
distributed_env = {key: os.environ[key] for key in _DISTRIBUTED_ENV_KEYS if key in os.environ}
|
| 28 |
+
|
| 29 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = ""
|
| 30 |
+
for key in distributed_env:
|
| 31 |
+
del os.environ[key]
|
| 32 |
+
try:
|
| 33 |
+
return super().start()
|
| 34 |
+
finally:
|
| 35 |
+
if had_cuda_visible_devices:
|
| 36 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = cuda_visible_devices
|
| 37 |
+
else:
|
| 38 |
+
del os.environ["CUDA_VISIBLE_DEVICES"]
|
| 39 |
+
for key, value in distributed_env.items():
|
| 40 |
+
os.environ[key] = value
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
class CpuOnlyWorkerSpawnContext(multiprocessing.context.SpawnContext):
|
| 44 |
+
Process = _CpuOnlyWorkerSpawnProcess
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
CPU_ONLY_WORKER_CONTEXT = CpuOnlyWorkerSpawnContext()
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def _as_bool(value: Any, default: bool = False) -> bool:
|
| 51 |
+
if value is None:
|
| 52 |
+
return default
|
| 53 |
+
if isinstance(value, bool):
|
| 54 |
+
return value
|
| 55 |
+
if isinstance(value, str):
|
| 56 |
+
return value.strip().lower() not in {"false", "0", "no", "off"}
|
| 57 |
+
return bool(value)
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def build_cpu_only_dataloader_kwargs(
|
| 61 |
+
num_workers: int,
|
| 62 |
+
*,
|
| 63 |
+
pin_memory: Any = False,
|
| 64 |
+
persistent_workers: Any = False,
|
| 65 |
+
prefetch_factor: Any = None,
|
| 66 |
+
) -> dict[str, Any]:
|
| 67 |
+
dataloader_kwargs: dict[str, Any] = {
|
| 68 |
+
"pin_memory": _as_bool(pin_memory),
|
| 69 |
+
}
|
| 70 |
+
if int(num_workers) <= 0:
|
| 71 |
+
return dataloader_kwargs
|
| 72 |
+
|
| 73 |
+
dataloader_kwargs["multiprocessing_context"] = CPU_ONLY_WORKER_CONTEXT
|
| 74 |
+
dataloader_kwargs["persistent_workers"] = _as_bool(persistent_workers)
|
| 75 |
+
if prefetch_factor is not None:
|
| 76 |
+
dataloader_kwargs["prefetch_factor"] = int(prefetch_factor)
|
| 77 |
+
return dataloader_kwargs
|
latency-aware/ant/vla/starvla-qwenoft-h1/ant-qwenoft-mean-3090-s42/training_results.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"training_complete": true,
|
| 3 |
+
"optimizer_updates": 5000,
|
| 4 |
+
"selection": "final_5000",
|
| 5 |
+
"train_loss": 0.011952828615903854,
|
| 6 |
+
"validation_action_loss": 0.018865827471017838,
|
| 7 |
+
"validation_samples": 10112,
|
| 8 |
+
"final_learning_rates": {
|
| 9 |
+
"learning_rate/action_model": 4.9999999999999996e-06,
|
| 10 |
+
"learning_rate/qwen_vl_interface": 5e-07
|
| 11 |
+
},
|
| 12 |
+
"closed_loop_evaluation": "pending until all four VLA trainings complete",
|
| 13 |
+
"tensor_keys": 730,
|
| 14 |
+
"serialized_tensor_elements_including_tied_aliases": 4892400136,
|
| 15 |
+
"weights_only_load": "passed",
|
| 16 |
+
"all_tensors_finite": true,
|
| 17 |
+
"completion_proof": {
|
| 18 |
+
"task": "ant",
|
| 19 |
+
"optimizer_updates": 5000,
|
| 20 |
+
"deepspeed_global_steps": 5000,
|
| 21 |
+
"deepspeed_global_samples": 640000,
|
| 22 |
+
"skipped_steps": 0,
|
| 23 |
+
"scheduler_last_epoch": 5000,
|
| 24 |
+
"scheduler_step_count": 5001,
|
| 25 |
+
"final_learning_rates": [
|
| 26 |
+
5e-07,
|
| 27 |
+
4.9999999999999996e-06
|
| 28 |
+
],
|
| 29 |
+
"summary_final_steps": 5000,
|
| 30 |
+
"final_inference_weight_bytes": 9785070315,
|
| 31 |
+
"wandb_global_step": 5000,
|
| 32 |
+
"wrapper_exit": 2,
|
| 33 |
+
"trainer_exit_separately_captured": false,
|
| 34 |
+
"training_complete_verified": true,
|
| 35 |
+
"failure_scope": "launcher_tail_parse_after_trainer_cleanup",
|
| 36 |
+
"cause": "Sharedrun_vla.shwasmodifiedforGPUmask/portwhileAntbashwasblockedinsidePython; remainingfileoffsetlaterparsedmodifiedtailandEOF",
|
| 37 |
+
"trainer_cleanup_log": "bothranksDestroyDistributedProcessGroup at2026-10-01 00:03:21UTC; no model exception",
|
| 38 |
+
"evidence_files": [
|
| 39 |
+
"checkpoints/steps_5000_state/pytorch_model/mp_rank_00_model_states.pt",
|
| 40 |
+
"checkpoints/steps_5000_state/custom_checkpoint_0.pkl",
|
| 41 |
+
"summary.jsonl",
|
| 42 |
+
"config.full.yaml"
|
| 43 |
+
],
|
| 44 |
+
"note": "No syntheticvla.exit0; wrapperexit2preserved; upload uses explicitcompletionproof"
|
| 45 |
+
}
|
| 46 |
+
}
|