LeonOverload/primo-rl-json

Dataset

PRIMO RL Data

0

5 commits

1 linked in READMEs

updated Sep 3, 2026

See the code

README

PRIMO RL Data

Stage-2 (GRPO reinforcement learning) training annotations for PRIMO R1 (paper). Unlike the SFT data, these records carry no chain-of-thought traces β€” RL optimizes against a verifiable progress reward, so only the ground-truth answer is needed. That is the point of the method: the model discovers its own reasoning instead of imitating someone else's.

328,454 records across 6 subsets. Annotations only (1.7 GB); videos are in primo-video-media.

Subsets

SubsetRecordsShareJSONVideo group
behavior-1k206,02963%1.2 GB5,981 GB
agibot38,53612%102 MB349 GB
robotwin-randomized38,14212%90 MB12.5 GB (shared with robotwin-clean)
robovqa26,4538%169 MB9.8 GB
sharerobot12,0004%33 MB0.97 GB
robotwin-clean7,2942%18 MB12.5 GB (shared with robotwin-randomized)

Download by subset β€” start here

behavior-1k dominates this repo twice over. It is 206,029 of the 328,454 records (63%), and its video archive is 5,981 GB β€” 91% of the entire 6.58 TB media release. The JSON is cheap to fetch; the video behind it is not.

Recommendation: skip behavior-1k unless you specifically need the long-horizon task-progress results. Its episodes are the longest in the release, so add it if long-horizon progress estimation is what you are after. The other five subsets together are 122,425 records and about 372 GB of video β€” and without agibot, under 25 GB.

The launchers read the mixture from an environment variable, so dropping a subset needs no code change:

# Full mixture minus behavior-1k
export RL_DATASET=primo-rl-agibot,primo-rl-robovqa,primo-rl-robotwin-clean,primo-rl-robotwin-randomized,primo-rl-sharerobot

# Or something small to start with: ~23 GB of video total
export RL_DATASET=primo-rl-robotwin-clean,primo-rl-robotwin-randomized,primo-rl-sharerobot,primo-rl-robovqa

GRPO generates num_generations=8 completions per prompt, so step count matters more than raw dataset size. A subset of the mixture still trains; the released checkpoint stopped at step 2500.

One subset

hf download LeonOverload/primo-rl-json --repo-type dataset \
    --include "jsonl_subsets/agibot/*" --local-dir ./primo-rl

Training-ready layout

The training entry points read raw_json/, not the JSONL shards. Download into $VIDEO_DATA_ROOT so the paths the dataset registry expects (primo-rl/<source>/train.json) line up:

export VIDEO_DATA_ROOT=/path/to/PRIMO-Data

# All 6 subsets, 1.7 GB
hf download LeonOverload/primo-rl-json --repo-type dataset \
    --include "raw_json/*" --local-dir /tmp/primo-rl
cp -r /tmp/primo-rl/raw_json/primo-rl "$VIDEO_DATA_ROOT/"

# Or skip the 1.2 GB behavior-1k file
hf download LeonOverload/primo-rl-json --repo-type dataset \
    --include "raw_json/*" --exclude "raw_json/primo-rl/behavior-1k/*" \
    --local-dir /tmp/primo-rl

Use --include / --exclude on their own β€” passing filenames positionally makes the client ignore both.

Browsing

from datasets import load_dataset

ds = load_dataset("LeonOverload/primo-rl-json", "agibot", split="train")
print(ds[0]["problem"], ds[0]["solution"])

Convenient for inspection, but use raw_json/ for training.

Videos

Match each subset to its group and pull only those:

hf download LeonOverload/primo-video-media --repo-type dataset \
    --include "robotwin.z*" --include "sharerobot.z*" \
    --local-dir /tmp/primo-video-zips

Extract into $VIDEO_DATA_ROOT/primo-video/. See primo-video-media for reassembly β€” the archives are multipart, and they already include the pre-extracted anchor frames.

Record format

{
  "problem": "Task info:\nSort in the warehouse\n\nInit Scene:\n...",
  "problem_type": "numerical",          # numerical | regression | multiple choice | boolean | free-form
  "data_type": "video",
  "path": "./agibot/observation/361/667819/100.0/head_color.mp4",
  "solution": "<answer>100.0</answer>", # the verifiable target the reward is computed against
  "options": [],
  "done_actions": [...],
  "meta_data": {...},

  # interleaved-input anchors, read directly during training
  "init_frame_path": "./primo-video/agibot/frames/observation/361/667819/100.0/head_color_init.jpg",
  "current_frame_path": "./primo-video/agibot/frames/observation/361/667819/100.0/head_color_current.jpg"
}

No select, process, planning, observation, or reasoning fields β€” those are SFT-only. Progress targets are percentages on a 0–100 scale.

Unlike evaluation β€” which re-derives anchor frames with OpenCV at run time β€” training reads init_frame_path and current_frame_path from the JSON. Those files ship inside the video archives, so no preprocessing step is needed. src/preprocess_video_frames.py exists for datasets you add yourself.

Training

Stage 2 starts from a stage-1 checkpoint. Use the published one to skip SFT entirely:

git clone https://github.com/10-OASIS-01/PRIMO-R1 && cd PRIMO-R1
conda create -n primo-r1 python=3.11 && conda activate primo-r1
bash setup.sh

hf download LeonOverload/PRIMO-COT-SFT-7B --local-dir models/PRIMO-COT-SFT-7B

export VIDEO_DATA_ROOT=/path/to/PRIMO-Data
export MODEL_ROOT=/path/to/models
export SFT_CKPT=models/PRIMO-COT-SFT-7B
export RL_DATASET=primo-rl-robotwin-clean,primo-rl-sharerobot   # see above

bash src/scripts/run_rl_7b.sh      # or run_rl_3b.sh

Defaults follow the paper: learning rate 1e-6, num_generations=8 (GRPO group size G), max_completion_length=4096, max_pixels=401408, beta=0.04, DeepSpeed ZeRO-3. Keep per_device_train_batch_size=1 β€” an invariant inherited from R1-V. Lower max_completion_length if you hit OOM; lowering num_generations is cheaper but raises gradient variance.

--temporal selects T-GRPO over plain GRPO and --len_control toggles the length-control reward. Reward functions live in reward_funcs_registry in grpo_interleave.py (accuracy_reward, format_reward); add new ones there so --reward_funcs can select them.

The 3B launcher is scaled from the 7B recipe and has not been validated; the released checkpoint is 7B.

Why RL, briefly

Both stages are needed (paper Table 2, MRA↑):

ModelID avgOOD avgOverall
Qwen2.5-VL-7B (base)70.3865.2667.46
SFT only81.4677.7779.35
RL only (no SFT)81.7172.9776.72
PRIMO R1 (SFT+RL)88.4782.9085.28

Training with this data alone, from the base model, gives the "RL only" row β€” competitive in domain but noticeably weaker out of domain, because the model has to discover the output format and reasoning structure from scratch. Pair it with the SFT data or start from the published cold start.

Resources

Repo contents

  • raw_json/ β€” the files the training entry points read, in release layout
  • jsonl/ β€” flattened shards for the Dataset Viewer
  • jsonl_subsets/ β€” per-subset shards backing the viewer's subset selector
  • summary.json β€” row and shard counts generated at build time

The authoritative dataset registry is the cfg dict in src/r1-v/src/open_r1/DatasetLoader.py.

Citations

If you find our work helpful for your research, please consider citing our work.

@misc{liu2026passiveobserveractivecritic,
      title={From Passive Observer to Active Critic: Reinforcement Learning Elicits Process Reasoning for Robotic Manipulation}, 
      author={Yibin Liu and Yaxing Lyu and Daqi Gao and Zhixuan Liang and Weiliang Tang and Shilong Mu and Xiaokang Yang and Yao Mu},
      year={2026},
      eprint={2603.15600},
      archivePrefix={arXiv},
      primaryClass={cs.RO},
      url={https://arxiv.org/abs/2603.15600}, 
}

Contributors

LeonOverload

5 commits

LeonOverload/primo-rl-json

Dataset

PRIMO RL Data

0

5 commits

1 linked in READMEs

updated Sep 3, 2026

See the code

README

PRIMO RL Data

Stage-2 (GRPO reinforcement learning) training annotations for PRIMO R1 (paper). Unlike the SFT data, these records carry no chain-of-thought traces β€” RL optimizes against a verifiable progress reward, so only the ground-truth answer is needed. That is the point of the method: the model discovers its own reasoning instead of imitating someone else's.

328,454 records across 6 subsets. Annotations only (1.7 GB); videos are in primo-video-media.

Subsets

SubsetRecordsShareJSONVideo group
behavior-1k206,02963%1.2 GB5,981 GB
agibot38,53612%102 MB349 GB
robotwin-randomized38,14212%90 MB12.5 GB (shared with robotwin-clean)
robovqa26,4538%169 MB9.8 GB
sharerobot12,0004%33 MB0.97 GB
robotwin-clean7,2942%18 MB12.5 GB (shared with robotwin-randomized)

Download by subset β€” start here

behavior-1k dominates this repo twice over. It is 206,029 of the 328,454 records (63%), and its video archive is 5,981 GB β€” 91% of the entire 6.58 TB media release. The JSON is cheap to fetch; the video behind it is not.

Recommendation: skip behavior-1k unless you specifically need the long-horizon task-progress results. Its episodes are the longest in the release, so add it if long-horizon progress estimation is what you are after. The other five subsets together are 122,425 records and about 372 GB of video β€” and without agibot, under 25 GB.

The launchers read the mixture from an environment variable, so dropping a subset needs no code change:

# Full mixture minus behavior-1k
export RL_DATASET=primo-rl-agibot,primo-rl-robovqa,primo-rl-robotwin-clean,primo-rl-robotwin-randomized,primo-rl-sharerobot

# Or something small to start with: ~23 GB of video total
export RL_DATASET=primo-rl-robotwin-clean,primo-rl-robotwin-randomized,primo-rl-sharerobot,primo-rl-robovqa

GRPO generates num_generations=8 completions per prompt, so step count matters more than raw dataset size. A subset of the mixture still trains; the released checkpoint stopped at step 2500.

One subset

hf download LeonOverload/primo-rl-json --repo-type dataset \
    --include "jsonl_subsets/agibot/*" --local-dir ./primo-rl

Training-ready layout

The training entry points read raw_json/, not the JSONL shards. Download into $VIDEO_DATA_ROOT so the paths the dataset registry expects (primo-rl/<source>/train.json) line up:

export VIDEO_DATA_ROOT=/path/to/PRIMO-Data

# All 6 subsets, 1.7 GB
hf download LeonOverload/primo-rl-json --repo-type dataset \
    --include "raw_json/*" --local-dir /tmp/primo-rl
cp -r /tmp/primo-rl/raw_json/primo-rl "$VIDEO_DATA_ROOT/"

# Or skip the 1.2 GB behavior-1k file
hf download LeonOverload/primo-rl-json --repo-type dataset \
    --include "raw_json/*" --exclude "raw_json/primo-rl/behavior-1k/*" \
    --local-dir /tmp/primo-rl

Use --include / --exclude on their own β€” passing filenames positionally makes the client ignore both.

Browsing

from datasets import load_dataset

ds = load_dataset("LeonOverload/primo-rl-json", "agibot", split="train")
print(ds[0]["problem"], ds[0]["solution"])

Convenient for inspection, but use raw_json/ for training.

Videos

Match each subset to its group and pull only those:

hf download LeonOverload/primo-video-media --repo-type dataset \
    --include "robotwin.z*" --include "sharerobot.z*" \
    --local-dir /tmp/primo-video-zips

Extract into $VIDEO_DATA_ROOT/primo-video/. See primo-video-media for reassembly β€” the archives are multipart, and they already include the pre-extracted anchor frames.

Record format

{
  "problem": "Task info:\nSort in the warehouse\n\nInit Scene:\n...",
  "problem_type": "numerical",          # numerical | regression | multiple choice | boolean | free-form
  "data_type": "video",
  "path": "./agibot/observation/361/667819/100.0/head_color.mp4",
  "solution": "<answer>100.0</answer>", # the verifiable target the reward is computed against
  "options": [],
  "done_actions": [...],
  "meta_data": {...},

  # interleaved-input anchors, read directly during training
  "init_frame_path": "./primo-video/agibot/frames/observation/361/667819/100.0/head_color_init.jpg",
  "current_frame_path": "./primo-video/agibot/frames/observation/361/667819/100.0/head_color_current.jpg"
}

No select, process, planning, observation, or reasoning fields β€” those are SFT-only. Progress targets are percentages on a 0–100 scale.

Unlike evaluation β€” which re-derives anchor frames with OpenCV at run time β€” training reads init_frame_path and current_frame_path from the JSON. Those files ship inside the video archives, so no preprocessing step is needed. src/preprocess_video_frames.py exists for datasets you add yourself.

Training

Stage 2 starts from a stage-1 checkpoint. Use the published one to skip SFT entirely:

git clone https://github.com/10-OASIS-01/PRIMO-R1 && cd PRIMO-R1
conda create -n primo-r1 python=3.11 && conda activate primo-r1
bash setup.sh

hf download LeonOverload/PRIMO-COT-SFT-7B --local-dir models/PRIMO-COT-SFT-7B

export VIDEO_DATA_ROOT=/path/to/PRIMO-Data
export MODEL_ROOT=/path/to/models
export SFT_CKPT=models/PRIMO-COT-SFT-7B
export RL_DATASET=primo-rl-robotwin-clean,primo-rl-sharerobot   # see above

bash src/scripts/run_rl_7b.sh      # or run_rl_3b.sh

Defaults follow the paper: learning rate 1e-6, num_generations=8 (GRPO group size G), max_completion_length=4096, max_pixels=401408, beta=0.04, DeepSpeed ZeRO-3. Keep per_device_train_batch_size=1 β€” an invariant inherited from R1-V. Lower max_completion_length if you hit OOM; lowering num_generations is cheaper but raises gradient variance.

--temporal selects T-GRPO over plain GRPO and --len_control toggles the length-control reward. Reward functions live in reward_funcs_registry in grpo_interleave.py (accuracy_reward, format_reward); add new ones there so --reward_funcs can select them.

The 3B launcher is scaled from the 7B recipe and has not been validated; the released checkpoint is 7B.

Why RL, briefly

Both stages are needed (paper Table 2, MRA↑):

ModelID avgOOD avgOverall
Qwen2.5-VL-7B (base)70.3865.2667.46
SFT only81.4677.7779.35
RL only (no SFT)81.7172.9776.72
PRIMO R1 (SFT+RL)88.4782.9085.28

Training with this data alone, from the base model, gives the "RL only" row β€” competitive in domain but noticeably weaker out of domain, because the model has to discover the output format and reasoning structure from scratch. Pair it with the SFT data or start from the published cold start.

Resources

Repo contents

  • raw_json/ β€” the files the training entry points read, in release layout
  • jsonl/ β€” flattened shards for the Dataset Viewer
  • jsonl_subsets/ β€” per-subset shards backing the viewer's subset selector
  • summary.json β€” row and shard counts generated at build time

The authoritative dataset registry is the cfg dict in src/r1-v/src/open_r1/DatasetLoader.py.

Citations

If you find our work helpful for your research, please consider citing our work.

@misc{liu2026passiveobserveractivecritic,
      title={From Passive Observer to Active Critic: Reinforcement Learning Elicits Process Reasoning for Robotic Manipulation}, 
      author={Yibin Liu and Yaxing Lyu and Daqi Gao and Zhixuan Liang and Weiliang Tang and Shilong Mu and Xiaokang Yang and Yao Mu},
      year={2026},
      eprint={2603.15600},
      archivePrefix={arXiv},
      primaryClass={cs.RO},
      url={https://arxiv.org/abs/2603.15600}, 
}

Contributors

LeonOverload

5 commits