| name | play-to-generalize |
| title | Play to Generalize: Learning to Reason Through Game Play |
| version | 0.0.2 |
| engine | skillxiv-v0.0.2-claude-opus-4.6 |
| license | MIT |
| url | https://arxiv.org/abs/2506.08011 |
| keywords | ["visual game learning","multimodal reasoning","reinforcement learning","generalization"] |
| description | Develop reasoning capabilities in multimodal models through interactive gameplay rather than supervised learning, achieving superior transfer to diverse reasoning tasks. |
Play to Generalize
Core Concept
Rather than training on benchmark data directly, Visual Game Learning (ViGaL) develops reasoning abilities through reinforcement learning on arcade-like games. The approach demonstrates that gameplay provides a more generalizable learning signal for reasoning tasks compared to traditional supervised learning on benchmark-specific content.
Architecture Overview
- Game environment: Arcade-style games (e.g., Snake) serve as reasoning task proxies
- Multimodal RL training: 7B parameter MLLM learns through interactive gameplay rewards
- Transfer to diverse tasks: Skills from gameplay transfer to math reasoning, spatial reasoning, and multidisciplinary questions
- Preserved general capability: Maintains general visual understanding while improving reasoning
Implementation
Step 1: Design Reasoning-Aligned Game Environment
Create games that reward systematic thinking and planning:
class ReasoningGameEnvironment:
def __init__(self, game_type: str = "snake",
episode_length: int = 100):
self.game_type = game_type
self.episode_length = episode_length
self.state = None
self.step_count = 0
def reset(self) -> tuple:
"""Initialize game and return initial observation."""
self.state = self._init_game_state()
self.step_count = 0
return self.render_observation()
def step(self, action: int) -> tuple:
"""Execute action and return observation, reward, done."""
self.step_count += 1
success = self._execute_action(action)
reward = self._compute_reasoning_reward(success)
done = (self.step_count >= self.episode_length or
self._is_terminal_state())
return .render_observation(), reward, done, {}
() -> :
reward =
success:
reward +=
reward += * .step_count / .episode_length
reward
Step 2: Implement Multimodal RL Training Loop
Train MLLM with PPO on game rewards:
class ViGaLTrainer:
def __init__(self, model, env, learning_rate: float = 1e-5):
self.model = model
self.env = env
self.optimizer = torch.optim.Adam(
model.parameters(),
lr=learning_rate
)
def collect_rollout(self, num_episodes: int = 32) -> list:
"""Collect experience from environment."""
trajectories = []
for _ in range(num_episodes):
obs, _ = self.env.reset()
trajectory = []
for step in range(self.env.episode_length):
with torch.no_grad():
logits = self.model.forward_with_vision(
obs,
return_logits=True
)
action_dist = torch.distributions.Categorical(
logits=logits
)
action = action_dist.sample()
log_prob = action_dist.log_prob(action)
obs, reward, done, _ = self.env.step(action.item())
trajectory.append({
"obs": obs,
"action": action.item(),
"log_prob": log_prob,
"reward": reward,
: done
})
done:
trajectories.append(trajectory)
trajectories
() -> :
returns = []
g =
t (trajectory):
g = t[] + gamma * g
returns.insert(, g)
returns
():
all_log_probs = []
all_returns = []
trajectory trajectories:
returns = .compute_returns(trajectory)
t, ret (trajectory, returns):
all_log_probs.append(t[])
all_returns.append(ret)
returns_tensor = torch.tensor(
all_returns,
dtype=torch.float32
).unsqueeze(-)
returns_tensor = (returns_tensor - returns_tensor.mean()) / (
returns_tensor.std() +
)
log_probs_tensor = torch.stack(all_log_probs)
loss = -(log_probs_tensor * returns_tensor.squeeze(-)).mean()
.optimizer.zero_grad()
loss.backward()
.optimizer.step()
Step 3: Evaluate Transfer to Benchmark Tasks
Assess generalization without benchmark-specific training:
def evaluate_on_benchmarks(model, benchmark_tasks: dict) -> dict:
"""Test reasoning transfer on MathVista, MMMU, VSI-Bench."""
results = {}
for task_name, task_instances in benchmark_tasks.items():
correct = 0
for instance in task_instances:
prompt = instance["question"]
image = instance["image"]
response = model.generate_with_vision(
prompt,
image,
max_tokens=512
)
is_correct = evaluate_response(
response,
instance["answer"]
)
if is_correct:
correct += 1
results[task_name] = {
"accuracy": correct / len(task_instances),
"num_samples": len(task_instances)
}
return results
Practical Guidance
Game Selection: Choose games requiring multi-step planning and spatial reasoning—properties that transfer to math and spatial reasoning benchmarks. Games should have clear reward signals and support diverse strategies.
Generalization Strategy: The key insight is that gameplay provides surrogate task structure without benchmark contamination. Train thoroughly on games, then evaluate on unseen benchmarks to avoid distribution matching.
Preservation of General Capabilities: Monitor performance on general visual understanding tasks throughout training. Use regularization to prevent catastrophic forgetting of pre-trained knowledge.
When to Apply: Use gameplay RL when you want to improve reasoning without access to benchmark solutions, or when avoiding benchmark-specific overfitting is critical.
Reference
ViGaL demonstrates that multimodal reasoning can emerge from gameplay. The approach outperforms specialist models trained on benchmark-oriented content while preserving general visual understanding. This suggests surrogate task design through interactive environments represents a promising direction for reasoning capability development.