Set up
Skills are installed by placing their folder where your agent loads skills.
The download comes from github.com/NEUIR/SCOPED itself, not from our server, so what you get is exactly what its author published.
Install instructions come from the README
README
synced Oct 25, 2026SCOPED: Skill-Decoupled On-Policy Expert Distillation for Unified Vision-Language Models
Source code for SCOPED: Skill-Decoupled On-Policy Expert Distillation for Unified Vision-Language Models.
📖 Overview • ⚙️ Setup • ⚡ Training • 🔧 Inference 📃 Evaluation • 🚀 Quick Start • 📧 Contact
📖 Overview
SCOPED is a framework for unifying visual understanding capabilities through skill-decoupled on-policy expert distillation. It first trains capability-specialized experts with reinforcement learning, then abstracts reusable skills from their successful and failed trajectories. These skills provide teacher-only guidance during on-policy distillation, allowing a single student model to learn from skill-conditioned experts.
The framework covers four complementary capabilities: Perception, OCR & Chart, Symbolic Reasoning, and Multi-Image Reasoning. The resulting student performs inference directly, without additional skill prompts.
⚙️ Setup
Use Python 3.12 on Linux with NVIDIA GPUs and a compatible CUDA runtime. Clone the repository first:
git clone https://github.com/NEUIR/SCOPED.git
cd SCOPED
Install two environments from the repository root: .venv-rl for expert reinforcement learning, and .venv-scoped for OPD, skill abstraction, inference and evaluation. The bundled EasyR1 and veRL backends require different dependency versions and must be installed separately.
# Expert reinforcement learning.
python3.12 -m venv .venv-rl
.venv-rl/bin/python -m pip install -r requirements-rl.txt
# OPD, skill abstraction, inference and evaluation.
python3.12 -m venv .venv-scoped
.venv-scoped/bin/python -m pip install -r requirements.txt
Launch scripts automatically select the environment for each stage; activation is not required. If the required environment is missing, the script stops with an installation reminder.
Models are downloaded from Hugging Face when a model ID is specified, and cached files are reused when available. Training and evaluation scripts automatically download the corresponding datasets. Adjust GPU settings to match your hardware; the launch scripts default to four GPUs for expert training, skill abstraction and evaluation, and eight for distillation.
⚡ Training
To use the released checkpoints, skip training and proceed to Inference or Evaluation.
Our training pipeline builds on EasyR1 and veRL and consists of three stages. Training data is available on Hugging Face. Set the base and student model paths in scripts/train.sh; stage-specific settings are provided in configs/.
Stage 1: Capability-Specialized Expert Learning
In the first stage, four experts are independently optimized on capability-specific data to learn perception, OCR and chart understanding, symbolic reasoning, and multi-image reasoning. All experts are initialized from the same base model, which defaults to Qwen/Qwen3-VL-8B-Instruct.
bash scripts/train.sh rl
# Train one expert:
bash scripts/train.sh capability1
The full RL stage automatically exports the expert checkpoints for subsequent stages. To use existing experts, set CAPABILITY1_TEACHER through CAPABILITY4_TEACHER in scripts/train.sh.
Stage 2: Capability Skill Abstraction from Expert Trajectories
In the second stage, each expert reflects on successful and failed trajectories generated from its own training data. The resulting evidence is consolidated into a capability-level skill containing reusable verification principles and failure-avoidance guidance.
bash scripts/train.sh skill
# Extract one expert's skill:
bash scripts/train.sh skill capability1
This stage produces one SKILL.md for each capability, which is loaded by the corresponding teacher during distillation.
Stage 3: Skill-Decoupled On-Policy Expert Distillation
In the final stage, the student generates on-policy responses and learns from the corresponding capability expert conditioned on its extracted skill. Skills serve as privileged guidance for teachers, while the student learns a unified policy from their supervision.
bash scripts/train.sh opd
Expert checkpoints and skills from the preceding stages are loaded automatically. Set STUDENT_MODEL in scripts/train.sh to select the student initialization.
🔧 Inference
To run inference with a released SCOPED checkpoint, start a vLLM server:
.venv-scoped/bin/vllm serve xiongyq/SCOPED-8B \
--served-model-name scoped \
--tensor-parallel-size 4 \
--port 8000
Replace the model ID with xiongyq/SCOPED-4B or a local checkpoint as needed, and adjust --tensor-parallel-size for your hardware. The Quick Start example below sends an image question to this server.
📃 Evaluation
Evaluate SCOPED on all supported benchmarks or a selected subset. The script automatically downloads SCOPED-Eval, generates predictions and reports benchmark-specific metrics.
bash scripts/eval.sh all
# Selected benchmarks:
bash scripts/eval.sh chartqa,ccocrv2
# Another checkpoint:
MODEL=xiongyq/SCOPED-4B bash scripts/eval.sh all
The default model is xiongyq/SCOPED-8B. To evaluate through the server started above:
BASE_URL=http://localhost:8000 bash scripts/eval.sh chartqa --served-model-name scoped
Set EVAL_OUT_DIR to choose the result directory, or pass --resume to continue a previous run.
🚀 Quick Start
After starting the server in Inference, replace image.png with your own PNG image and run the following example. It asks the model to reason step by step and return its final answer within <answer> tags.
import base64
import json
from pathlib import Path
from urllib.request import Request, urlopen
image = base64.b64encode(Path("image.png").read_bytes()).decode()
payload = {
"model": "scoped",
"messages": [{
"role": "user",
"content": [
{"type": "image_url", "image_url": {
"url": f"data:image/png;base64,{image}"
}},
{"type": "text", "text": (
"What is shown in this image? "
"Please reason step by step, and put your final answer "
"within <answer></answer>."
)},
],
}],
"temperature": 0.0,
"max_tokens": 2048,
}
request = Request(
"http://localhost:8000/v1/chat/completions",
data=json.dumps(payload).encode(),
headers={"Content-Type": "application/json"},
)
with urlopen(request, timeout=600) as response:
result = json.load(response)
print(result["choices"][0]["message"]["content"])
Acknowledgements
Our work builds on EasyR1, veRL, vLLM and Qwen3-VL. We thank their contributors for making these projects available.
License
SCOPED original code is released under the MIT License. Bundled EasyR1 and veRL code retains its Apache 2.0 licenses and notices; see NOTICE.
Citation
If you find our work useful in your research, please consider citing:
@article{xiong2026skill,
title={Skill-Decoupled On-Policy Expert Distillation for Unified Vision-Language Models},
author={Xiong, Yuqi and Peng, Chunyi and Xu, Zhipeng and Yang, Qing and Liu, Zhenghao and Chen, Zulong and Gu, Yu and Yu, Ge},
journal={arXiv preprint arXiv:2610.22217},
year={2026}
}
📧 Contact
If you have questions, suggestions, and bug reports, please give us an issue or email:
yqxiong54@gmail.com