Skip to main content 首页 创作者 adu2021 skillxiv openvlthinker-vision-reasoning
openvlthinker-vision-reasoning Train vision-language models for complex reasoning by alternating SFT (supervised fine-tuning via text-only reasoning models) and curriculum RL (Group Relative Policy Optimization). Progressively improve through iterative cycles where each iteration generates better training data.
跳到安装 Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/ADu2021/skillXiv --skill openvlthinker-vision-reasoning命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... 同仓库更多 Skills meaningful-kebab-case-name Convert arXiv papers into ready-to-use agent skills using category-aware extraction. First classifies the paper into one or more of 11 research categories, then applies a specialized extraction pipeline for each category — because different types of papers produce different types of usable knowledge. A single paper can yield multiple skills if it spans categories. Use this skill whenever the user wants to turn a paper into a skill, extract practical techniques from research, build a skill library from papers, convert arXiv papers into reusable agent instructions, or batch-process multiple papers into skills. Also trigger when someone asks about extracting actionable knowledge from papers, making research practical for LLM agents, or systematically converting academic contributions into structured agent capabilities.
action-quantization-behavior-cloning Establish regret bounds for behavior cloning with discretized actions combining statistical error and quantization error terms. Prove smoothness requirements for safe quantizer design, show that learning-based quantizers fail these requirements, and propose model-based augmentation to reduce error dependence from H² to H.
adaptive-lora-personalized-ranks Dynamically allocate LoRA ranks per-layer during fine-tuning instead of using fixed uniform ranks. Learn optimal rank for each layer and subject via variational framework with discretized exponential distribution, reducing memory footprint while maintaining fidelity and text-alignment.
name openvlthinker-vision-reasoning title OpenVLThinker: An Early Exploration to Complex Vision-Language Reasoning via Iterative Self-Improvement version 0.0.2 engine skillxiv-v0.0.2-claude-opus-4.6 license MIT url https://arxiv.org/abs/2503.17352 keywords ["Vision-Language","Reasoning","SFT","RL","Self-Improvement","Chain-of-Thought"] description Train vision-language models for complex reasoning by alternating SFT (supervised fine-tuning via text-only reasoning models) and curriculum RL (Group Relative Policy Optimization). Progressively improve through iterative cycles where each iteration generates better training data.
Core Concept
Vision-language models struggle with complex reasoning tasks because distilling reasoning from text-only models like DeepSeek-R1 often degrades visual understanding. OpenVLThinker solves this through iterative SFT-RL cycles : alternate between lightweight SFT (using text models to generate reasoning demonstrations) and curriculum RL (applying Group Relative Policy Optimization with difficulty-based scheduling). Each cycle improves training data quality, enabling self-improvement with minimal total examples.
Architecture Overview
SFT Phase : Text-only reasoning models (QwQ-32B) generate chain-of-thought demos from image captions
RL Phase : Group Relative Policy Optimization (GRPO) with difficulty-based curriculum learning
Curriculum Scheduler : Progressively increase difficulty: medium → hard → hardest data
Iterative Refinement : Each cycle's improved model generates better training data for next cycle
Minimal Data Requirement : Only 12K total examples across three cycles
Implementation Steps
Step 1: Prepare Training Data with Text-Only Reasoning Models
Use a capable text-only model to generate chain-of-thought demonstrations from image captions and questions.
import torch
from typing import List , Dict
class ReasoningDataGeneration :
"""
Generate chain-of-thought reasoning using a text-only model
(e.g., QwQ-32B) from image captions and task questions.
"""
def __init__ (self, text_model, device='cuda' ):
self .text_model = text_model
self .device = device
def generate_reasoning (
self,
image_caption: str ,
question: str ,
max_length: int = 512
) -> str :
prompt =
inputs = .text_model.tokenize(prompt)
torch.no_grad():
outputs = .text_model.generate(
inputs,
max_length=max_length,
temperature= ,
top_p=
)
reasoning = .text_model.decode(outputs[ ])
reasoning
( ) -> [ ]:
sft_examples = []
caption, question, answer (captions, questions, answers):
reasoning = .generate_reasoning(caption, question)
example = {
: caption,
: question,
: reasoning,
: answer,
:
}
sft_examples.append(example)
sft_examples
"""
Generate step-by-step reasoning for a VQA task.
image_caption: Textual description of image
question: Question about the image
Returns: Chain-of-thought reasoning text
"""
f"""Given the following image description and question,
provide step-by-step reasoning to answer the question.
Image: {image_caption}
Question: {question}
Let me think through this step by step:"""
self
with
self
0.7
0.9
self
0
return
def
create_sft_examples
self,
captions: List [str ],
questions: List [str ],
answers: List [str ]
List
Dict
"""
Create SFT training examples with reasoning.
Returns list of (instruction, reasoning+answer) pairs.
"""
for
in
zip
self
'image_caption'
'instruction'
'reasoning'
'answer'
'full_response'
f"{reasoning} \n\nAnswer: {answer} "
return
Step 2: Identify Reasoning Keywords and SFT Efficacy Analyze whether SFT successfully induces reasoning behaviors by examining keyword frequencies in model outputs.
import re
from collections import Counter
def analyze_reasoning_keywords (model_outputs: List [str ] ) -> Dict [str , float ]:
"""
Count reasoning-related keywords to verify SFT effectiveness.
Keywords indicate reflection, step-by-step thinking, and uncertainty.
"""
reasoning_keywords = [
'let me' , 'think' , 'step' , 'first' , 'next' , 'then' ,
'because' , 'thus' , 'therefore' , 'however' , 'although' ,
'observe' , 'notice' , 'identify' , 'reason' , 'conclusion'
]
keyword_counts = Counter()
for output in model_outputs:
output_lower = output.lower()
for keyword in reasoning_keywords:
count = len (re.findall(r'\b' + keyword + r'\b' , output_lower))
keyword_counts[keyword] += count
total_keywords = sum (keyword_counts.values())
keyword_frequencies = {
k: v / max (total_keywords, 1 ) for k, v in keyword_counts.items()
}
return keyword_frequencies
def sft_efficacy_score (
base_model_outputs: List [str ],
sft_model_outputs: List [str ]
) -> float :
"""
Measure SFT effectiveness by comparing keyword distribution.
Higher score indicates SFT successfully induced reasoning.
"""
base_keywords = analyze_reasoning_keywords(base_model_outputs)
sft_keywords = analyze_reasoning_keywords(sft_model_outputs)
improvements = [
sft_keywords.get(k, 0 ) / max (base_keywords.get(k, 0 ), 1e-6 )
for k in base_keywords.keys()
]
avg_improvement = sum (improvements) / len (improvements) if improvements else 1.0
return min (avg_improvement, 2.0 )
Step 3: Implement Curriculum RL with GRPO Apply Group Relative Policy Optimization with progressive difficulty scheduling.
import torch.nn.functional as F
class CurriculumGRPO :
"""
Group Relative Policy Optimization with curriculum learning.
Progressively train on harder examples: medium → hard → hardest.
"""
def __init__ (self, model, reference_model, device='cuda' ):
self .model = model
self .reference_model = reference_model
self .device = device
def compute_difficulty_score (
self,
base_model_accuracy: float ,
gpt4_rating: float
) -> float :
"""
Composite difficulty score combining two signals:
- Base model error rate (1 - accuracy)
- GPT-4 quality rating (normalized to [0,1])
"""
error_rate = 1.0 - base_model_accuracy
difficulty = (error_rate + (1 - gpt4_rating)) / 2
return difficulty
def group_by_difficulty (
self,
examples: List [Dict ],
base_model_accuracy: List [float ],
gpt4_ratings: List [float ]
) -> Dict [str , List [Dict ]]:
"""
Partition examples into difficulty tiers.
Returns: {'easy': [...], 'medium': [...], 'hard': [...]}
"""
difficulties = [
self .compute_difficulty_score(acc, rating)
for acc, rating in zip (base_model_accuracy, gpt4_ratings)
]
sorted_indices = sorted (range (len (difficulties)), key=lambda i: difficulties[i])
n = len (sorted_indices)
easy_idx = sorted_indices[:n // 3 ]
medium_idx = sorted_indices[n // 3 :2 * n // 3 ]
hard_idx = sorted_indices[2 * n // 3 :]
return {
'easy' : [examples[i] for i in easy_idx],
'medium' : [examples[i] for i in medium_idx],
'hard' : [examples[i] for i in hard_idx]
}
def grpo_loss (
self,
log_probs: torch.Tensor,
ref_log_probs: torch.Tensor,
rewards: torch.Tensor,
beta: float = 0.5
) -> torch.Tensor:
"""
GRPO loss: scales log probability ratios by reward advantage.
log_probs: current model log probabilities (batch,)
ref_log_probs: reference model log probabilities (batch,)
rewards: reward signal (batch,) - higher is better
"""
log_ratio = log_probs - ref_log_probs
rewards = (rewards - rewards.mean()) / (rewards.std() + 1e-8 )
advantage = rewards
loss = -torch.mean(log_ratio * advantage)
kl_div = (log_probs - ref_log_probs).mean()
total_loss = loss + beta * kl_div
return total_loss
def train_curriculum_rl (
self,
training_examples: List [Dict ],
base_accuracies: List [float ],
gpt4_ratings: List [float ],
num_epochs: int = 3 ,
batch_size: int = 8
):
"""
Train with curriculum: easy → medium → hard.
Each stage trains for one epoch on increasingly difficult examples.
"""
grouped = self .group_by_difficulty(
training_examples, base_accuracies, gpt4_ratings
)
curriculum_order = ['medium' , 'hard' ]
for stage_idx, difficulty in enumerate (curriculum_order):
print (f"Training on {difficulty} examples (stage {stage_idx + 1 } )" )
examples = grouped[difficulty]
for epoch in range (num_epochs):
total_loss = 0
num_batches = 0
for i in range (0 , len (examples), batch_size):
batch = examples[i:i + batch_size]
prompts = [ex['instruction' ] for ex in batch]
responses = [ex['full_response' ] for ex in batch]
rewards = torch.tensor(
[ex.get('reward' , 1.0 ) for ex in batch],
dtype=torch.float32,
device=self .device
)
log_probs = self ._compute_log_probs(prompts, responses)
with torch.no_grad():
ref_log_probs = self ._compute_log_probs_ref(prompts, responses)
loss = self .grpo_loss(log_probs, ref_log_probs, rewards)
self .model.zero_grad()
loss.backward()
torch.nn.utils.clip_grad_norm_(self .model.parameters(), 1.0 )
self .model.optimizer.step()
total_loss += loss.item()
num_batches += 1
avg_loss = total_loss / max (num_batches, 1 )
print (f" Epoch {epoch + 1 } - Loss: {avg_loss:.4 f} " )
def _compute_log_probs (self, prompts: List [str ], responses: List [str ] ) -> torch.Tensor:
"""Compute log probabilities from current model."""
return torch.randn(len (prompts), device=self .device)
def _compute_log_probs_ref (self, prompts: List [str ], responses: List [str ] ) -> torch.Tensor:
"""Compute log probabilities from reference model."""
with torch.no_grad():
return torch.randn(len (prompts), device=self .device)
Step 4: Iterative Cycle Management Orchestrate multiple SFT-RL cycles where each iteration improves training data and model quality.
class IterativeSelfImprovement :
"""
Manage iterative SFT-RL cycles: cycle 1, 2, 3.
Each cycle generates better training data from improved model.
"""
def __init__ (self, vlm_model, text_model, num_cycles: int = 3 ):
self .vlm_model = vlm_model
self .text_model = text_model
self .num_cycles = num_cycles
self .cycle_metrics = []
def run_full_pipeline (
self,
initial_examples: List [Dict ],
validation_set: List [Dict ]
):
"""
Execute full iterative pipeline: SFT → RL → evaluate → repeat.
initial_examples: Starting training data (images + captions + questions)
validation_set: Hold-out validation benchmarks
"""
training_data = initial_examples
for cycle in range (self .num_cycles):
print (f"\n===== Cycle {cycle + 1 } / {self.num_cycles} =====" )
print (f"Phase 1: Supervised Fine-Tuning on {len (training_data)} examples" )
self .run_sft(training_data)
sft_metrics = self .evaluate(validation_set)
print (f" SFT Metrics: {sft_metrics} " )
print (f"Phase 2: Curriculum RL" )
self .run_curriculum_rl(training_data)
rl_metrics = self .evaluate(validation_set)
print (f" RL Metrics: {rl_metrics} " )
self .cycle_metrics.append({
'cycle' : cycle + 1 ,
'sft_metrics' : sft_metrics,
'rl_metrics' : rl_metrics
})
if cycle < self .num_cycles - 1 :
print (f"Phase 3: Generating training data for cycle {cycle + 2 } " )
training_data = self .generate_next_cycle_data(
training_data, rl_metrics
)
def run_sft (self, training_data: List [Dict ] ):
"""Supervised fine-tuning phase."""
pass
def run_curriculum_rl (self, training_data: List [Dict ] ):
"""Curriculum RL phase."""
grpo = CurriculumGRPO(self .vlm_model, self .vlm_model)
pass
def evaluate (self, validation_set: List [Dict ] ) -> Dict :
"""Evaluate on validation benchmarks."""
accuracies = []
for example in validation_set:
output = self .vlm_model.generate(
image=example['image' ],
prompt=example['question' ]
)
correct = self ._match_answer(output, example['answer' ])
accuracies.append(float (correct))
return {
'accuracy' : sum (accuracies) / len (accuracies) if accuracies else 0.0 ,
'count' : len (validation_set)
}
def generate_next_cycle_data (
self,
current_data: List [Dict ],
metrics: Dict
) -> List [Dict ]:
"""
Generate training data for next cycle using improved model.
Reuse successful examples and add new harder examples.
"""
num_new = len (current_data) // 3
new_data = current_data[:2 * len (current_data) // 3 ]
data_gen = ReasoningDataGeneration(self .text_model)
new_examples = data_gen.create_sft_examples(
captions=[ex['caption' ] for ex in current_data[-num_new:]],
questions=[ex['question' ] for ex in current_data[-num_new:]],
answers=[ex['answer' ] for ex in current_data[-num_new:]]
)
new_data.extend(new_examples)
return new_data
def _match_answer (self, output: str , ground_truth: str ) -> bool :
"""Simple string matching for answer evaluation."""
return output.strip().lower() == ground_truth.strip().lower()
Step 5: Inference Integration Combine trained components for efficient inference on reasoning tasks.
class OpenVLThinkerInference :
"""
Production inference pipeline combining trained VLM with optional
reasoning generation for transparent answer production.
"""
def __init__ (self, vlm_model, generate_reasoning: bool = True ):
self .vlm_model = vlm_model
self .generate_reasoning = generate_reasoning
def answer_question (
self,
image: torch.Tensor,
question: str ,
return_reasoning: bool = False
) -> Dict :
"""
Answer visual question with optional reasoning.
image: PIL Image or tensor (batch, 3, H, W)
question: Text question about image
"""
if self .generate_reasoning:
prompt = f"Question: {question} \n\nLet me think through this step by step:"
else :
prompt = f"Question: {question} \nAnswer:"
inputs = self .vlm_model.process(image, prompt)
with torch.no_grad():
outputs = self .vlm_model.generate(
**inputs,
max_length=256 ,
temperature=0.7 ,
top_p=0.9
)
response = self .vlm_model.decode(outputs[0 ])
if self .generate_reasoning:
parts = response.split('Answer:' )
reasoning = parts[0 ] if len (parts) > 0 else ""
answer = parts[1 ].strip() if len (parts) > 1 else response.strip()
else :
reasoning = ""
answer = response.strip()
result = {
'answer' : answer,
'full_response' : response
}
if return_reasoning:
result['reasoning' ] = reasoning
return result
Practical Guidance
Training vision-language models for complex reasoning tasks (MathVista, visual reasoning)
Scenarios with limited labeled reasoning data (few thousand examples)
Cases where reasoning transparency is important (education, scientific analysis)
Projects where iterative self-improvement through synthetic data generation is viable
Simple visual classification or object detection (overkill)
Scenarios where text-only reasoning models aren't available or high quality
Real-time inference systems where chain-of-thought verbosity is unacceptable
Domain-specific reasoning where text models haven't seen your specific domain
num_cycles : 3 standard; 2 for fast iteration, 4-5 for maximum quality if data is abundant
difficulty_ratio : 70% easy / medium, 30% hard; adjust based on validation plateau
SFT_epochs : 1-2; use 1 for computational efficiency, 2 for better convergence
RL_beta (KL weight) : 0.5 standard; increase to 1.0 if model diverges from reference
curriculum_order : ['medium', 'hard']; skip 'easy' unless validation accuracy is very low
Weak text-only reasoning model produces garbage reasoning demonstrations; use QwQ-32B or DeepSeek-R1
Insufficient validation data; GPT-4 ratings required for accurate difficulty scoring
Over-training on narrow difficulty tier; rotate through curriculum stages gradually
RL divergence: monitor KL divergence between model and reference; increase beta if KL > 0.2
References