Enable unified multimodal models to self-improve by using their understanding module as evaluator for generation. Apply hierarchical dual rewards: global for overall semantics and local for fine-grained details.
Scanned 9/9/2026
Install to Claude Code
npx -y skills add ADu2021/skillXiv --skill srum-self-rewarding --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Srum Self Rewarding?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/adu2021-srum-self-rewarding)More formats (shields.io, HTML) on the badges page.
---
name: srum-self-rewarding
title: "SRUM: Fine-Grained Self-Rewarding for Unified Multimodal Models"
version: 0.0.2
engine: skillxiv-v0.0.2-claude-opus-4.6
license: MIT
url: "https://arxiv.org/abs/2510.12784"
keywords: [multimodal, self-rewarding, image-generation, global-local-rewards, unified-models]
description: "Enable unified multimodal models to self-improve by using their understanding module as evaluator for generation. Apply hierarchical dual rewards: global for overall semantics and local for fine-grained details."
---
# SRUM: Self-Improving Unified Multimodal Models
Unified multimodal models that handle both vision-language understanding and generation often generate lower-quality images than vision-language models optimize for understanding. SRUM enables self-improvement by leveraging the model's own understanding capabilities to evaluate and improve generation quality.
Core insight: strong understanding capability provides free supervision for generation. By using the model's own understanding as reward signal at global and local levels, unified models self-improve without external human feedback or additional models.
## Core Concept
**Understanding-as-Evaluator**: The model's understanding module becomes evaluator for the generation module, providing self-generated rewards without external supervision.
**Hierarchical Dual Rewards**: Two-tier reward system provides feedback at different granularities: global rewards for semantic correctness, local rewards for object-level detail quality.
## Architecture Overview
- **Understanding Module**: Evaluates generated images for semantic alignment
- **Generation Module**: Creates images from text
- **Global Reward Head**: Scores overall semantic correctness and layout
- **Local Reward Head**: Scores object-level details and fine-grained quality
- **RL Optimizer**: Updates generation based on rewards
## Implementation Steps
**Stage 1: Extract Rewards from Understanding Module**
Use understanding module to score generations:
```python
import torch
import torch.nn as nn
from transformers import CLIPVisionModel, CLIPTextModel
class UnifiedMultimodalModel(nn.Module):
def __init__(self, model_name='unified-mm-base'):
super().__init__()
# Shared transformer backbone
self.backbone = AutoModel.from_pretrained(model_name)
# Understanding head: evaluates images
self.understanding_head = nn.Sequential(
nn.Linear(768, 384),
nn.ReLU(),
nn.Linear(384, 1) # Global quality score
)
# Local detail scorer
self.local_scorer = nn.Sequential(
nn.Linear(768, 384),
nn.ReLU(),
nn.Linear(384, 1) # Per-region quality
)
# Generation head: creates images
self.generation_head = ImageDecoder()
def forward_understanding(self, image):
"""
Evaluate image quality using understanding module.
"""
# Encode image
image_features = self.backbone.encode_image(image)
# Global reward: semantic correctness
global_score = self.understanding_head(image_features)
return global_score
def forward_generation(self, text):
"""
Generate image from text.
"""
# Encode text
text_features = self.backbone.encode_text(text)
# Generate image
generated_image = self.generation_head(text_features)
return generated_image
class HierarchicalRewardComputer(nn.Module):
def __init__(self, understanding_model):
super().__init__()
self.understanding_model = understanding_model
def compute_global_reward(self, generated_image, text_prompt):
"""
Global reward: how well does image match text semantically?
"""
# Get image understanding
with torch.no_grad():
image_features = self.understanding_model.backbone.encode_image(
generated_image
)
global_score = self.understanding_model.understanding_head(
image_features
)
# Get text understanding
with torch.no_grad():
text_features = self.understanding_model.backbone.encode_text(
text_prompt
)
# Semantic alignment: cosine similarity
image_normalized = torch.nn.functional.normalize(
image_features, dim=-1
)
text_normalized = torch.nn.functional.normalize(
text_features, dim=-1
)
semantic_alignment = (
image_normalized * text_normalized
).sum(dim=-1)
# Global reward combines quality and alignment
global_reward = 0.5 * global_score + 0.5 * semantic_alignment
return global_reward
def compute_local_reward(
self,
generated_image,
text_prompt,
num_regions=4
):
"""
Local reward: fine-grained object-level quality.
Divide image into regions and score each independently.
"""
batch_size, channels, height, width = generated_image.shape
# Divide image into regions
region_height = height // num_regions
region_width = width // num_regions
local_scores = []
for i in range(num_regions):
for j in range(num_regions):
# Extract region
h_start = i * region_height
h_end = (i + 1) * region_height
w_start = j * region_width
w_end = (j + 1) * region_width
region = generated_image[
:, :, h_start:h_end, w_start:w_end
]
# Score region with understanding
with torch.no_grad():
region_features = (
self.understanding_model.backbone.encode_image(region)
)
region_score = (
self.understanding_model.local_scorer(
region_features
)
)
local_scores.append(region_score)
# Average local scores
local_reward = torch.stack(local_scores).mean()
return local_reward
def compute_combined_reward(
self,
generated_image,
text_prompt,
global_weight=0.6,
local_weight=0.4
):
"""
Combine global and local rewards.
"""
global_reward = self.compute_global_reward(
generated_image,
text_prompt
)
local_reward = self.compute_local_reward(
generated_image,
text_prompt
)
# Weighted combination
combined_reward = (
global_weight * global_reward +
local_weight * local_reward
)
return combined_reward, {
'global': global_reward.item(),
'local': local_reward.item()
}
```
**Stage 2: RL Training Loop**
Train generation module with self-rewards:
```python
def srum_training_loop(
unified_model,
text_image_pairs,
num_epochs=5,
batch_size=32
):
"""
Train unified model with self-rewarding.
"""
optimizer = torch.optim.AdamW(
unified_model.generation_head.parameters(),
lr=1e-4
)
reward_computer = HierarchicalRewardComputer(unified_model)
for epoch in range(num_epochs):
for batch_idx, (texts, images) in enumerate(
dataloader(text_image_pairs, batch_size)
):
# Generate images from text
generated_images = unified_model.forward_generation(texts)
# Compute self-rewards
rewards_list = []
loss_list = []
for gen_img, text, real_img in zip(
generated_images, texts, images
):
# Self-reward from understanding module
combined_reward, reward_components = (
reward_computer.compute_combined_reward(
gen_img.unsqueeze(0),
text
)
)
# Also compute reconstruction loss to reference image
recon_loss = torch.nn.functional.mse_loss(
gen_img, real_img
)
rewards_list.append(combined_reward)
loss_list.append(recon_loss)
# Policy gradient update
rewards_tensor = torch.stack(rewards_list)
loss_tensor = torch.stack(loss_list)
# Combine RL loss and reconstruction loss
rl_loss = -(
rewards_tensor.detach() *
torch.nn.functional.log_softmax(
torch.randn_like(generated_images), dim=1
)
).mean()
total_loss = loss_tensor.mean() + 0.1 * rl_loss
optimizer.zero_grad()
total_loss.backward()
optimizer.step()
if batch_idx % 10 == 0:
avg_reward = rewards_tensor.mean().item()
avg_loss = loss_tensor.mean().item()
print(
f"Epoch {epoch}, Batch {batch_idx}, "
f"Reward: {avg_reward:.4f}, Loss: {avg_loss:.4f}"
)
return unified_model
```
**Stage 3: Inference with Quality Guidance**
Generate with quality feedback:
```python
def generate_with_quality_feedback(
unified_model,
text_prompt,
num_iterations=3
):
"""
Generate image with iterative quality refinement.
"""
reward_computer = HierarchicalRewardComputer(unified_model)
best_image = None
best_reward = -float('inf')
for iteration in range(num_iterations):
# Generate initial image
generated_image = unified_model.forward_generation(
text_prompt
)
# Compute rewards
combined_reward, components = (
reward_computer.compute_combined_reward(
generated_image,
text_prompt
)
)
# Track best
if combined_reward > best_reward:
best_reward = combined_reward
best_image = generated_image
# Log quality components
print(
f"Iteration {iteration}: "
f"Global={components['global']:.3f}, "
f"Local={components['local']:.3f}"
)
return best_image
```
## Practical Guidance
**When to Use SRUM:**
- Unified multimodal models handling both understanding and generation
- When understanding quality is significantly higher than generation
- No access to external reward models or human feedback
**When NOT to Use:**
- Separate understanding-only or generation-only models
- When generation quality already matches understanding quality
- Tasks requiring diverse generation (local reward may reduce diversity)
**Reward Weight Strategies:**
| Scenario | Global Weight | Local Weight | Rationale |
|----------|---------------|--------------|-----------|
| High-level tasks | 0.8 | 0.2 | Semantic correctness paramount |
| Detail-focused | 0.4 | 0.6 | Fine details critical |
| Balanced | 0.6 | 0.4 | Standard setting |
**Common Pitfalls:**
- Local reward too strong (overly conservative details)
- Global reward misaligned with human preference (semantic errors remain)
- Region division too fine (noisy local scores)
- Not validating understanding module gives useful feedback
**Improvement Metrics:**
| Metric | Before SRUM | After SRUM |
|--------|------------|-----------|
| T2I-CompBench | 82.18 | 88.37 |
| T2I-ReasonBench | 43.82 | 46.75 |
| FID Score | Baseline | ~5% improvement |
## Reference
Based on the research at: https://arxiv.org/abs/2510.12784
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!