CoolFace
Modelpublic

atlas-institute/qwen14b-code-trainer-v10-grpo

sourceHugging Faceapache-2.0updated 29d agoView on Hugging Face
0likes22downloads
Model Card

qwen14b-code-trainer-v10-grpo

LoRA adapter for Qwen/Qwen2.5-Coder-14B-Instruct, reinforcement-learned with GRPO (DeepSeekMath) on a rule-based tool-call formatting reward. This is the V10 release — the first RL stage in the pipeline, trained on top of the V9 SFT adapter with a domain-adaptive pretraining (DAPT) merge.

Part of the Code-Trainer / RTPI pipeline (GitHub).

What changed from V9

  1. 1.Domain-adaptive pretraining (DAPT) — a LoRA adapter (`qwen14b-dapt-offsec`) trained on ~10K offensive-security code documents is merged into the base model before SFT, grounding the model in security tooling patterns.
  2. 2.GRPO reinforcement learning — a fresh LoRA is trained on top of the merged DAPT + V9 SFT weights using Group Relative Policy Optimization. The reward function targets tool-call formatting quality, not task completion — teaching the model to emit structurally correct <tool_call> tags with valid tool names and clean stop signals.
  3. 3.Adapter chain architecture — the final adapter sits on a 3-stage merged base: Qwen2.5-Coder-14B-Instruct → DAPT merge → V9 SFT merge → fresh LoRA (this adapter).
  4. 4.12-tool Nexus schema — the reward function validates against the Nexus tool set: Read, Write, Edit, LS, Bash, Grep, Glob, WebFetch, TodoWrite, Skill, Task, ScopeCheck.

Adapter chain

The V10 GRPO adapter cannot be loaded directly on the base model — it expects the DAPT and V9 adapters to be merged first:

Qwen/Qwen2.5-Coder-14B-Instruct
  └─ merge: cmndcntrlcyber/qwen14b-dapt-offsec         (DAPT)
      └─ merge: cmndcntrlcyber/qwen14b-code-trainer-v9_mixed  (SFT)
          └─ LoRA: cmndcntrlcyber/qwen14b-code-trainer-v10-grpo (this adapter)

For deployment, all three are merged into the base and quantized to GGUF (see `qwen14b-code-trainer-gguf`).

Training data

SourceDescription
V10 eval scenariosCurated tool-call test cases from tool_call_eval_entry_v10.py
V9 training dataUser messages preceding tool-call assistant responses, extracted from code-trainer-v9-mixed
Synthetic templatesTemplate-generated prompts covering all 12 Nexus tools with variable fills

Each prompt is formatted via apply_chat_template with the Nexus system prompt and full tool definitions.

Reward function

Rule-based, 5-component weighted reward scoring each completion 0.0–1.0:

ComponentWeightCriterion
has_valid_tool_call_tags0.30At least one <tool_call>{"name":"...","arguments":{...}}</tool_call> with both name (str) and arguments (dict)
tool_name_in_schema0.20First valid tool call's name exists in NEXUSTOOLSV10
has_reasoning_prefix0.20≥10 chars of non-whitespace text before the first <tool_call> tag (chain-of-thought)
no_hallucinated_tools0.15Every "name" in the response matches a valid tool name
ends_cleanly_after_tag0.15≤5 chars of trailing content after the last </tool_call>

Training procedure

KnobValue
Base modelQwen/Qwen2.5-Coder-14B-Instruct (with DAPT + V9 merged in)
MethodGRPO (Group Relative Policy Optimization)
AdapterLoRA (PEFT), r = 32, alpha = 64, dropout = 0.05
Target modulesq_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj
Learning rate5.0e-7 (cosine decay)
KL coefficient (beta)0.1
Generations per prompt4
Max completion length768 tokens
Batch size × grad accum2 × 4 (effective batch = 8)
Precisionbfloat16 + gradient checkpointing
MetaValue
HardwareHF Jobs a100-large (1× A100 80 GB)
FrameworksTRL 1.3.0, Transformers 5.7.0, PyTorch 2.11.0+cu128, PEFT 0.19.1
Max steps250
Steps completed150 (epoch 0.6)
Entry pointsrc/phase4c_rl/hf_skills/grpo_entry.py

Training metrics

Logged every 10 steps. The reward signal is stable throughout training with no signs of reward hacking or distributional collapse:

MetricStep 10Step 80Step 150
reward (mean)0.1390.1460.144
reward_std0.0240.0070.012
KL0.000130.000220.00021
entropy0.9561.1001.054
grad_norm0.0030.0020.002
completions/mean_length41.462.941.7
clipped_ratio0.00.00.0

Evaluation

Version comparison

VersionMethodDataset rowsTool %Key improvement
V6 aggressiveSFT26,1260%Code-only baseline
V7 v7_mixedSFT28,86263.8%Restore tool-calling + agent
V8 v8_mixedSFT34,10457.6%Fix multilingual + native format
V9 v9_mixedSFT (curriculum)40,40164.3%Fix tag emission + curriculum
V10 `v10-grpo` (this)GRPO<1K prompts100%RL reward on tool-call formatting

Intended use

  • —Direct use: load the full adapter chain on top of Qwen/Qwen2.5-Coder-14B-Instruct for instruction-following code generation, tool calling, and multi-turn agent behaviour with improved <tool_call> tag formatting.
  • —Downstream: merge the full adapter chain into the base model and quantize to Q5KM GGUF for local serving via llama.cpp, Ollama, or LM Studio.
  • —Out of scope: this adapter was not trained for safety alignment, RLHF, or non-code tasks. The GRPO stage optimizes formatting, not factuality.

Deployment notes

  • —Recommended quant: Q5KM — preserves multi-token <tool_call> tag patterns better than Q4KM.
  • —Context length: 8,192 tokens recommended; trained at 768 max completion length but the base model supports 32K.
  • —DPO not applied: the pipeline's second RL stage (DPO on reasoning quality) was not executed for this release.

How to use

python
import torch
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer

base_id = "Qwen/Qwen2.5-Coder-14B-Instruct"
dapt_id = "cmndcntrlcyber/qwen14b-dapt-offsec"
sft_id = "cmndcntrlcyber/qwen14b-code-trainer-v9_mixed"
grpo_id = "cmndcntrlcyber/qwen14b-code-trainer-v10-grpo"

tokenizer = AutoTokenizer.from_pretrained(base_id)
model = AutoModelForCausalLM.from_pretrained(
    base_id, torch_dtype=torch.bfloat16, device_map="auto",
)

# Merge DAPT and SFT adapters into base weights
model = PeftModel.from_pretrained(model, dapt_id)
model = model.merge_and_unload()
model = PeftModel.from_pretrained(model, sft_id)
model = model.merge_and_unload()

# Load GRPO adapter (active LoRA)
model = PeftModel.from_pretrained(model, grpo_id)
model.eval()

messages = [
    {"role": "system", "content": "You are Nexus, a local-first coding agent with tool access."},
    {"role": "user", "content": "Read the file main.py and summarise its structure."},
]
inputs = tokenizer.apply_chat_template(
    messages, return_tensors="pt", add_generation_prompt=True,
).to(model.device)
out = model.generate(inputs, max_new_tokens=512, do_sample=False)
print(tokenizer.decode(out[0][inputs.shape[1]:], skip_special_tokens=True))

Reproducibility

bash
  python -m src.phase4c_rl.data.build_grpo_prompts \
      --config src/config/pipeline-50.yml
  • —Training launch:
bash
  python -m src.phase4c_rl.scripts.launch_grpo \
      --config src/config/pipeline-50.yml --wait