Qwen3.5-4B-Soyuz-GRPO-v3 (merged bf16)

GRPO (Group Relative Policy Optimization) fine-tune of Soyuz-4B, where the reward is a separate Claude Code instance grading each answer against an explicit per-task criteria checklist. This card documents how the GRPO actually affected the model β€” including a negative transfer result, reported honestly.

Setup

  • Policy: Soyuz-4B (Qwen3_5ForCausalLM) + LoRA r=32, on-policy REINFORCE with a group baseline (G=6 rollouts/task) + KL to the frozen base (LoRA-disabled reference). Custom bare-torch loop.
  • Reward: claude -p (headless Claude Code) scores each rollout passed/total against the task's explicit criteria β†’ reward in [0,1]. Criteria-checklist grading has much lower variance than free-form quality scoring (this was the single biggest fix for a stable signal).
  • Per-turn recovery shaping: each task is a 2-turn rollout (answer β†’ self-revise). Generation and judging are interleaved so the turn-2 critique is grounded in the judge's actual reason and is harsh when the answer is bad ("scored N/10, problems: …, scrap it and rewrite"). Turn-2 reward = score + 0.5Β·(score βˆ’ score_prev) β†’ rewards climbing out of a bad answer, penalises regression.
  • Data: 44 tasks Γ— 2 epochs β€” algorithms/data-structures, library use (pandas, numpy, requests, asyncio, SQLAlchemy, pytest, click), real-code fixes (SQL-injection, async race, FastAPI pagination, vectorize, retry bug, refactor), and creative (micro-fiction, ELI5, limerick, haiku, dialogue, tone-rewrite).

How GRPO affected the model (all numbers file-backed)

On the trained distribution β€” clear gain:

metric epoch 1 epoch 2 Ξ”
reward (criteria) 0.700 0.757 +0.057 (27/44 tasks up)
turn-0 score 0.652 0.723 +0.071
recovery (climb from a bad turn-0) 0.301 0.273 βˆ’0.028

The recovery skill internalised into the first turn. Recovery fell not because the model got worse at fixing β€” but because turn-0 got better, so there were fewer bad starts left to recover from. The model learned to do it right the first time (e.g. product-description turn-0 0.23β†’0.60, cover-letter 0.3β†’0.93, ELI5 0.0β†’0.73). Biggest gains were on the hard tail (semver-compare +0.35, weighted-choice +0.27, streaming-median +0.22, SQL-injection-fix +0.18).

Negative transfer to agentic terminal tasks. Tested on the terminal-bench-2 tasks the base model partially solved, GRPO-v3 regressed: tasks-with-any-pass dropped 11/11 β†’ 4/11 (e.g. hf-model-inference 4/5β†’0/5, openssl 3/5β†’0/5, sqlite 3/5β†’0/5). General single-response coding/creative GRPO does not transfer to β€” and hurts β€” multi-step shell-agent behaviour. To improve agentic terminal performance you must run GRPO on the agentic rollouts themselves (verifier reward), not on single-shot coding questions.

App generation. Works well as a single-shot generator (one prompt β†’ full index.html), which is the model's strength; it fails inside a heavy agent loop (drowns in planning). Suppress its <think> ("output only the HTML, do not plan") or it spends its token budget reasoning and never emits the code.

Usage

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
m = AutoModelForCausalLM.from_pretrained("AlexWortega/qwen35-4b-soyuz-grpo-v3", dtype=torch.bfloat16, device_map="cuda")
tok = AutoTokenizer.from_pretrained("AlexWortega/qwen35-4b-soyuz-grpo-v3")

Best for single-response coding / writing / rewriting. For multi-step shell agents, prefer the base Soyuz-4B.

Related

Asset Link
Base qwen35-4b-soyuz-merged

W&B: https://wandb.ai/alexwortega/fast-qwen35-sft (run soyuz-4b-grpo-recovery-v3)

Downloads last month
9
Safetensors
Model size
4B params
Tensor type
BF16
Β·
Video Preview
loading

Model tree for AlexWortega/qwen35-4b-soyuz-grpo-v3

Finetuned
Qwen/Qwen3.5-4B
Finetuned
(1)
this model