Eight-token score centering vs importance-sampled policy gradient, 4-step-stale rollouts
Redo
RL on openai/gsm8k with Qwen/Qwen3.5-2B (LoRA rank 32, lr 4e-05, max_tokens 512), eval on 256 held-out problems with greedy decoding. grpo (group_mean, 16 prompts x 8 rollouts, 100 steps): train reward 0.4844 -> 0.8359, eval accuracy 0.7266 -> 0.8633.
Full summary
RL on openai/gsm8k with Qwen/Qwen3.5-2B (LoRA rank 32, lr 4e-05, max_tokens 512), eval on 256 held-out problems with greedy decoding. grpo (group_mean, 16 prompts x 8 rollouts, 100 steps): train reward 0.4844 -> 0.8359, eval accuracy 0.7266 -> 0.8633. Wall time 27.3 min. Success criterion from the spec: Validated if the treatment's GSM8K accuracy at step 100 exceeds the baseline by at least 4 points (about 2x the standard error at n=500), or if the baseline's accuracy drops more than 10 points from its peak while the treatment's does not. Failed if the gap is under 2 points with no collapse difference.
Result eval_accuracy_before
| arm | eval_accuracy_before | train_reward_first | train_reward_last | train_reward_mean | eval_accuracy_after | steps | n_prompts_per_step | group_size |
|---|---|---|---|---|---|---|---|---|
| grpo | 0.7266 | 0.4844 | 0.8359 | 0.7444 | 0.8633 | 100 | 16 | 8 |
Changes from the spec 0
Checks · activation unverified · evaluator unknown · feasibility unknown
Spec exp_80fe2820a1
Hypothesis
With rollouts generated by a policy 4 optimizer steps stale, the eight-token centered-backward loss reaches at least 4 points higher GSM8K test accuracy at step 100 than the importance-sampling policy-gradient loss, or avoids a collapse that the baseline shows.
Success criterion
Validated if the treatment's GSM8K accuracy at step 100 exceeds the baseline by at least 4 points (about 2x the standard error at n=500), or if the baseline's accuracy drops more than 10 points from its peak while the treatment's does not. Failed if the gap is under 2 points with no collapse difference.
Method
Baseline
Full spec
{
"base_model": "Qwen/Qwen3.5-0.8B",
"baseline": "The same RL loop, staleness, seeds and hyperparameters, but using Tinker's built-in importance_sampling policy-gradient loss instead of the centered-backward surrogate.",
"batch_size": 128,
"budget": {
"gpu_hours": 2.0,
"max_wall_minutes": 120
},
"command": "# custom tinker SDK script (custom parts: stale sampler refresh, auxiliary-token datums, centered loss)\nimport os, tinker, torch\nsc = tinker.ServiceClient(base_url=os.environ[\"TINKER_BASE_URL\"])\ntc = sc.create_lora_training_client(base_model=\"Qwen/Qwen3.5-0.8B\", rank=32)\nsampler = tc.save_weights_and_get_sampling_client(name=\"step0\")\n\ndef centered_loss(data, logprobs_list):\n # data grouped as [target, aux1..aux8] per sequence; per-token advantages A in each target datum's loss_fn_inputs\n loss = 0.0\n for i in range(0, len(logprobs_list), 9):\n tgt = logprobs_list[i]\n aux = torch.stack(logprobs_list[i+1:i+9]).mean(0)\n A = data[i].loss_fn_inputs[\"advantages\"].to_torch()\n loss = loss + (-A * tgt + A * (aux - aux.detach())).sum()\n return loss, {}\n\nfor step in range(100):\n if step % 4 == 0:\n sampler = tc.save_weights_and_get_sampling_client(name=f\"s{step}\")\n batch = rollout_gsm8k(sampler, group_size=8, groups=16, max_tokens=512, topk_prompt_logprobs=20) # cookbook gsm8k env + reward\n datums = build_target_and_aux_datums(batch, n_aux=8) # 8 sampled tokens per position from renormalized top-20\n tc.forward_backward_custom(datums, centered_loss).result()\n tc.optim_step(tinker.AdamParams(learning_rate=4e-5)).result()\n# baseline arm: same loop with tc.forward_backward(target_datums, loss_fn=\"importance_sampling\")",
"dataset": {
"hf_path": "openai/gsm8k",
"n_examples": 12800,
"name": "GSM8K",
"split": "main/train"
},
"eval": {
"benchmark": "GSM8K test",
"metric": "exact-match accuracy (greedy)",
"n_examples": 500
},
"hypothesis": "With rollouts generated by a policy 4 optimizer steps stale, the eight-token centered-backward loss reaches at least 4 points higher GSM8K test accuracy at step 100 than the importance-sampling policy-gradient loss, or avoids a collapse that the baseline shows.",
"lora_rank": 32,
"max_seq_len": 1024,
"method": "Train a LoRA policy on GSM8K train with a 0/1 exact-match reward and group-mean advantages (group_size 8, 16 groups per batch). To make training off-policy, refresh the sampler weights only every 4 optimizer steps, so rollouts come from a policy up to 4 steps stale.\n\nAuxiliary tokens: for each completion position, request the sampler's top-20 prompt logprobs, renormalize them, and draw 8 auxiliary tokens. This approximates true sampler draws and is a documented deviation from the original algorithm.\n\nTreatment loss (custom, via forward_backward_custom): sum over tokens of -A*logp(target) + A*(mean_aux_logp - stopgrad(mean_aux_logp)). kl_coeff is set to 0 so only the centering differs from the baseline. Auxiliary logprobs come from 8 extra datums per sequence that share model_input but use the auxiliary tokens as target_tokens.\n\nBaseline loss: the built-in importance_sampling loss with sampler logprobs. All other settings are identical: model, data order, seeds, advantages, staleness, LR and renderer.\n\nEvaluation: sample greedily from saved checkpoints every 25 steps. Also log grad norm and mean policy/sampler logprob gap as stability signals.",
"optimizer": {
"lr": 4e-05,
"name": "adam"
},
"steps": 100,
"success_criterion": "Validated if the treatment's GSM8K accuracy at step 100 exceeds the baseline by at least 4 points (about 2x the standard error at n=500), or if the baseline's accuracy drops more than 10 points from its peak while the treatment's does not. Failed if the gap is under 2 points with no collapse difference.",
"title": "Eight-token score centering vs importance-sampled policy gradient, 4-step-stale rollouts",
"training_type": "rl"
}Script
"""LoRA RL with a verifiable reward on a Spindle server through the stock Tinker SDK.
Reads TINKER_BASE_URL, TINKER_API_KEY, MODAL_PROXY_TOKEN_ID and
MODAL_PROXY_TOKEN_SECRET. Each arm in CONFIG["arms"] trains a fresh LoRA on
GSM8K train prompts: sample answers from the current weights, grade them by
exact match on the final number, turn rewards into advantages with the arm's
baseline, and train with the "importance_sampling" loss. Exact-match accuracy
on the test split (greedy decoding) is measured before and after each arm.
Prints one final line `RESULT {...}`: the last arm's metrics at the top level
and every arm under "arms".
Baselines:
- group_mean: GRPO style, reward minus the mean reward of the prompt's group.
- loo_similarity: GS1 style, reward minus a leave-one-out mean over the batch
weighted by softmax(cosine(TF-IDF(prompt_i), TF-IDF(prompt_j)) / temperature).
- batch_mean: reward minus the plain leave-one-out batch mean.
"""
import json
import math
import os
import re
import time
from collections import Counter
import tinker
from datasets import load_dataset
from tinker import types
# CONFIG-START
CONFIG = {
"base_model": "Qwen/Qwen3.5-2B",
"lora_rank": 32,
"dataset": "openai/gsm8k",
"dataset_config": "main",
"split": "train",
"eval_split": "test",
"n_eval": 256,
"steps": 100,
"lr": 4e-05,
"max_tokens": 512,
"temperature": 1.0,
"similarity_temperature": 0.1,
"max_wall_seconds": 2700,
"arms": [
{
"name": "grpo",
"baseline": "group_mean",
"n_prompts_per_step": 16,
"group_size": 8
}
]
}
# CONFIG-END
STARTED = time.monotonic()
INSTRUCTION = "\n\nSolve the problem step by step, then write the final answer on its own line as '#### <number>'."
def elapsed():
return time.monotonic() - STARTED
def load_problems(split, n):
"""Return n (question, gold answer) pairs; GSM8K keeps the gold number after '####'."""
rows = load_dataset(CONFIG["dataset"], CONFIG["dataset_config"], split=split, streaming=True)
problems = []
for row in rows:
question = row.get("question") or row.get("problem") or row.get("prompt")
answer = row.get("answer") or row.get("solution") or ""
gold = answer.split("####")[-1].strip() if "####" in answer else last_number(answer)
if question and gold:
problems.append((question, normalize_number(gold)))
if len(problems) == n:
break
return problems
def last_number(text):
numbers = re.findall(r"-?\d[\d,]*\.?\d*", text)
return numbers[-1] if numbers else ""
def normalize_number(text):
text = text.replace(",", "").replace("$", "").strip().rstrip(".")
try:
value = float(text)
except ValueError:
return text
return str(int(value)) if value == int(value) else str(value)
def grade(completion, gold):
"""1.0 if the completion's final answer matches the gold number exactly, else 0.0."""
answer = completion.split("####")[-1] if "####" in completion else completion
predicted = last_number(answer)
return 1.0 if predicted and normalize_number(predicted) == gold else 0.0
def prompt_tokens(tokenizer, question):
ids = tokenizer.apply_chat_template(
[{"role": "user", "content": question + INSTRUCTION}],
tokenize=True,
add_generation_prompt=True,
enable_thinking=False,
)
return list(ids["input_ids"] if hasattr(ids, "keys") else ids)
def stop_tokens(tokenizer):
ids = {tokenizer.eos_token_id}
im_end = tokenizer.convert_tokens_to_ids("<|im_end|>")
if isinstance(im_end, int) and im_end != tokenizer.unk_token_id:
ids.add(im_end)
return sorted(i for i in ids if i is not None)
def sample_all(sampler, tokenizer, prompts, num_samples, temperature):
"""Sample num_samples completions per prompt concurrently; returns one list of sequences per prompt."""
params = types.SamplingParams(
max_tokens=CONFIG["max_tokens"], temperature=temperature, stop=stop_tokens(tokenizer)
)
futures = [
sampler.sample(prompt=types.ModelInput.from_ints(ids), num_samples=num_samples, sampling_params=params)
for ids in prompts
]
return [future.result().sequences for future in futures]
def eval_accuracy(training, tokenizer, problems):
sampler = training.save_weights_and_get_sampling_client()
prompts = [prompt_tokens(tokenizer, q) for q, _ in problems]
groups = sample_all(sampler, tokenizer, prompts, 1, 0.0)
correct = sum(
grade(tokenizer.decode(group[0].tokens, skip_special_tokens=True), gold)
for group, (_, gold) in zip(groups, problems)
)
return correct / len(problems)
def tfidf_vectors(texts):
docs = [Counter(re.findall(r"[a-z0-9]+", text.lower())) for text in texts]
df = Counter(term for doc in docs for term in doc)
n = len(docs)
vectors = []
for doc in docs:
total = sum(doc.values()) or 1
vectors.append({t: (c / total) * (math.log((n + 1) / (df[t] + 1)) + 1) for t, c in doc.items()})
return vectors
def cosine(a, b):
dot = sum(a[t] * b[t] for t in a if t in b)
norm = math.sqrt(sum(v * v for v in a.values())) * math.sqrt(sum(v * v for v in b.values()))
return dot / norm if norm else 0.0
def advantages_for(arm, questions, rewards):
"""One advantage per rollout. questions[i] is the prompt text of rollout i."""
baseline = arm["baseline"]
n = len(rewards)
if n < 2:
return [0.0] * n
if baseline == "group_mean":
advantages = []
group = arm["group_size"]
for start in range(0, n, group):
chunk = rewards[start : start + group]
mean = sum(chunk) / len(chunk)
advantages.extend(r - mean for r in chunk)
return advantages
if baseline == "batch_mean":
total = sum(rewards)
return [r - (total - r) / (n - 1) for r in rewards]
if baseline == "loo_similarity":
vectors = tfidf_vectors(questions)
tau = CONFIG["similarity_temperature"]
advantages = []
for i in range(n):
weights = [0.0 if j == i else math.exp((cosine(vectors[i], vectors[j]) - 1.0) / tau) for j in range(n)]
total = sum(weights)
if total == 0:
weights, total = [0.0 if j == i else 1.0 for j in range(n)], n - 1
advantages.append(rewards[i] - sum(w * r for w, r in zip(weights, rewards)) / total)
return advantages
raise ValueError(f"unknown baseline {baseline!r}")
def make_datum(prompt_ids, sequence, advantage):
full = prompt_ids + list(sequence.tokens)
n_prompt = len(prompt_ids) - 1
return types.Datum(
model_input=types.ModelInput.from_ints(full[:-1]),
loss_fn_inputs={
"target_tokens": full[1:],
"logprobs": [0.0] * n_prompt + list(sequence.logprobs),
"advantages": [0.0] * n_prompt + [advantage] * len(sequence.tokens),
},
)
def train_arm(service, arm, train_problems, eval_problems, budget_seconds, eval_before):
"""Train one arm; its wall budget starts once the training client is ready (trainer cold start is not charged)."""
name = arm["name"]
training = service.create_lora_training_client(base_model=CONFIG["base_model"], rank=CONFIG["lora_rank"])
tokenizer = training.get_tokenizer()
deadline = time.monotonic() + budget_seconds
print(f"[{name}] training client ready after {elapsed():.0f}s; {budget_seconds:.0f}s budget for this arm", flush=True)
if eval_before is None:
eval_before = eval_accuracy(training, tokenizer, eval_problems)
print(f"[{name}] eval accuracy before training: {eval_before:.3f} ({elapsed():.0f}s)", flush=True)
n_prompts, group = arm["n_prompts_per_step"], arm["group_size"]
rewards_per_step, completion_lengths = [], []
cursor = 0
for step in range(CONFIG["steps"]):
if time.monotonic() > deadline:
print(f"[{name}] stopping at step {step}: wall-time budget reached", flush=True)
break
step_started = time.monotonic()
batch = [train_problems[(cursor + i) % len(train_problems)] for i in range(n_prompts)]
cursor += n_prompts
prompts = [prompt_tokens(tokenizer, q) for q, _ in batch]
sampler = training.save_weights_and_get_sampling_client()
groups = sample_all(sampler, tokenizer, prompts, group, CONFIG["temperature"])
sampled = time.monotonic()
rollouts, questions, rewards = [], [], []
for (question, gold), ids, sequences in zip(batch, prompts, groups):
for sequence in sequences:
rollouts.append((ids, sequence))
questions.append(question)
rewards.append(grade(tokenizer.decode(sequence.tokens, skip_special_tokens=True), gold))
completion_lengths.append(len(sequence.tokens))
advantages = advantages_for(arm, questions, rewards)
datums = [make_datum(ids, seq, adv) for (ids, seq), adv in zip(rollouts, advantages) if adv != 0.0]
mean_reward = sum(rewards) / len(rewards)
rewards_per_step.append(mean_reward)
if datums:
output = training.forward_backward(datums, "importance_sampling").result()
training.optim_step(types.AdamParams(learning_rate=CONFIG["lr"])).result()
loss = output.metrics.get("loss:sum")
else:
loss = None
print(
f"[{name}] step {step}: mean reward {mean_reward:.3f} over {len(rewards)} rollouts, "
f"{len(datums)} with nonzero advantage, loss:sum {loss}, "
f"sampling {sampled - step_started:.1f}s, total {time.monotonic() - step_started:.1f}s",
flush=True,
)
eval_after = eval_accuracy(training, tokenizer, eval_problems)
print(f"[{name}] eval accuracy after training: {eval_after:.3f} ({elapsed():.0f}s)", flush=True)
return {
"train_reward_first": rewards_per_step[0] if rewards_per_step else None,
"train_reward_last": rewards_per_step[-1] if rewards_per_step else None,
"train_reward_mean": sum(rewards_per_step) / len(rewards_per_step) if rewards_per_step else None,
"eval_accuracy_before": eval_before,
"eval_accuracy_after": eval_after,
"steps": len(rewards_per_step),
"n_prompts_per_step": n_prompts,
"group_size": group,
"rollouts_per_step": n_prompts * group,
"baseline": arm["baseline"],
"mean_completion_tokens": sum(completion_lengths) / len(completion_lengths) if completion_lengths else None,
}
def main():
service = tinker.ServiceClient(
base_url=os.environ["TINKER_BASE_URL"],
api_key=os.environ["TINKER_API_KEY"],
default_headers_overrides={
"Modal-Key": os.environ["MODAL_PROXY_TOKEN_ID"],
"Modal-Secret": os.environ["MODAL_PROXY_TOKEN_SECRET"],
},
)
rollouts = max(arm["n_prompts_per_step"] * arm["group_size"] for arm in CONFIG["arms"])
n_train = max(arm["n_prompts_per_step"] for arm in CONFIG["arms"]) * CONFIG["steps"]
train_problems = load_problems(CONFIG["split"], n_train)
eval_problems = load_problems(CONFIG["eval_split"], CONFIG["n_eval"])
print(f"loaded {len(train_problems)} train / {len(eval_problems)} eval problems; up to {rollouts} rollouts per step", flush=True)
arms = {}
eval_before = None
per_arm_seconds = CONFIG["max_wall_seconds"] / len(CONFIG["arms"])
for arm in CONFIG["arms"]:
arms[arm["name"]] = train_arm(service, arm, train_problems, eval_problems, per_arm_seconds, eval_before)
eval_before = arms[arm["name"]]["eval_accuracy_before"]
last = arms[CONFIG["arms"][-1]["name"]]
result = {
**last,
"arms": arms,
"base_model": CONFIG["base_model"],
"lora_rank": CONFIG["lora_rank"],
"lr": CONFIG["lr"],
"max_tokens": CONFIG["max_tokens"],
"dataset": CONFIG["dataset"],
"n_eval": len(eval_problems),
"wall_seconds": round(elapsed(), 1),
}
print("RESULT " + json.dumps(result), flush=True)
if __name__ == "__main__":
main()
Evidence
All metrics
| metric | grpo |
|---|---|
| train_reward_first | 0.4844 |
| train_reward_last | 0.8359 |
| train_reward_mean | 0.7444 |
| eval_accuracy_before | 0.7266 |
| eval_accuracy_after | 0.8633 |
| steps | 100 |
| n_prompts_per_step | 16 |
| group_size | 8 |
| rollouts_per_step | 128 |
| mean_completion_tokens | 304.1 |
- lora_rank
- 32
- lr
- 4e-05
- max_tokens
- 512
- n_eval
- 256
- wall_seconds
- 1,637.4
- baseline
- group_mean
- base_model
- Qwen/Qwen3.5-2B
- dataset
- openai/gsm8k
Artifacts
- command
- python experiment_run_bffef575d5.py
- config
- {'base_model': 'Qwen/Qwen3.5-2B', 'lora_rank': 32, 'dataset': 'openai/gsm8k', 'dataset_config': 'main', 'split': 'train', 'eval_split': 'test', 'n_eval': 256, 'steps': 100, 'lr': 4e-05, 'max_tokens': 512, 'temperature': 1.0, 'similarity_temperature': 0.1, 'max_wall_seconds': 2700, 'arms': [{'name': 'grpo', 'baseline': 'group_mean', 'n_prompts_per_step': 16, 'group_size': 8}]}
- modal_call_id
- fc-01M6FQEKREWRWXA5YMTSW9G3G3
- script_source
- default script (Claude script rejected: contains 'import torch')
Log
Claude script rejected: contains 'import torch'script source: default script (Claude script rejected: contains 'import torch')running /tmp/rx-run_bffef575d5-uohw39uz/experiment_run_bffef575d5.py (timeout 3540s)Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads.loaded 1600 train / 256 eval problems; up to 128 rollouts per step[transformers] PyTorch was not found. Models won't be available and only tokenizers, configuration and file/data utilities can be used.[grpo] training client ready after 164s; 2700s budget for this armSampling is paused for sampler sample-1f0e9e7445a798c316aa9735460fcc1b. Reason: starting a sampler for Qwen/Qwen3.5-2B (33s so far). The first request for a model starts GPUs and loads weights, which can take several minutesSampling is paused for sampler sample-1f0e9e7445a798c316aa9735460fcc1b. Reason: starting a sampler for Qwen/Qwen3.5-2B (1m 32s so far). The first request for a model starts GPUs and loads weights, which can take several minutes[grpo] eval accuracy before training: 0.727 (313s)[grpo] step 0: mean reward 0.484 over 128 rollouts, 72 with nonzero advantage, loss:sum 954.5865821838379, sampling 15.2s, total 63.3s[grpo] step 1: mean reward 0.531 over 128 rollouts, 96 with nonzero advantage, loss:sum 755.9313354492188, sampling 12.5s, total 39.9s[grpo] step 2: mean reward 0.688 over 128 rollouts, 80 with nonzero advantage, loss:sum 940.4000091552734, sampling 12.7s, total 31.8s[grpo] step 3: mean reward 0.547 over 128 rollouts, 96 with nonzero advantage, loss:sum 1014.0491561889648, sampling 11.5s, total 13.8s[grpo] step 4: mean reward 0.688 over 128 rollouts, 80 with nonzero advantage, loss:sum 1003.6305809020996, sampling 11.2s, total 13.3s[grpo] step 5: mean reward 0.492 over 128 rollouts, 120 with nonzero advantage, loss:sum 1768.254596710205, sampling 11.8s, total 31.3s[grpo] step 6: mean reward 0.594 over 128 rollouts, 72 with nonzero advantage, loss:sum 538.442943572998, sampling 9.7s, total 11.9s[grpo] step 7: mean reward 0.586 over 128 rollouts, 72 with nonzero advantage, loss:sum 1246.675437927246, sampling 8.4s, total 10.4s[grpo] step 8: mean reward 0.570 over 128 rollouts, 88 with nonzero advantage, loss:sum 1067.7584762573242, sampling 9.7s, total 28.0s[grpo] step 9: mean reward 0.742 over 128 rollouts, 88 with nonzero advantage, loss:sum 1806.7864799499512, sampling 7.8s, total 9.8s[grpo] step 10: mean reward 0.516 over 128 rollouts, 104 with nonzero advantage, loss:sum 1704.176462173462, sampling 7.8s, total 10.1s[grpo] step 11: mean reward 0.516 over 128 rollouts, 56 with nonzero advantage, loss:sum 682.2223320007324, sampling 7.7s, total 26.1s[grpo] step 12: mean reward 0.727 over 128 rollouts, 56 with nonzero advantage, loss:sum 279.8251266479492, sampling 7.9s, total 26.4s[grpo] step 13: mean reward 0.523 over 128 rollouts, 56 with nonzero advantage, loss:sum 778.0148372650146, sampling 9.1s, total 11.2s[grpo] step 14: mean reward 0.438 over 128 rollouts, 80 with nonzero advantage, loss:sum 640.9949607849121, sampling 9.1s, total 11.4s[grpo] step 15: mean reward 0.773 over 128 rollouts, 104 with nonzero advantage, loss:sum 695.26149559021, sampling 8.9s, total 11.3s[grpo] step 16: mean reward 0.672 over 128 rollouts, 64 with nonzero advantage, loss:sum 758.9013824462891, sampling 8.5s, total 10.6s[grpo] step 17: mean reward 0.727 over 128 rollouts, 64 with nonzero advantage, loss:sum 1089.3722648620605, sampling 8.8s, total 10.8s[grpo] step 18: mean reward 0.539 over 128 rollouts, 112 with nonzero advantage, loss:sum 919.0350131988525, sampling 9.1s, total 11.6s[grpo] step 19: mean reward 0.602 over 128 rollouts, 64 with nonzero advantage, loss:sum 449.8424129486084, sampling 9.8s, total 11.9s[grpo] step 20: mean reward 0.461 over 128 rollouts, 64 with nonzero advantage, loss:sum 213.30652618408203, sampling 9.1s, total 11.1s[grpo] step 21: mean reward 0.742 over 128 rollouts, 80 with nonzero advantage, loss:sum 770.1305751800537, sampling 9.5s, total 28.6s[grpo] step 22: mean reward 0.477 over 128 rollouts, 80 with nonzero advantage, loss:sum 827.8632583618164, sampling 9.5s, total 11.7s[grpo] step 23: mean reward 0.812 over 128 rollouts, 32 with nonzero advantage, loss:sum 180.5084571838379, sampling 7.9s, total 11.6s[grpo] step 24: mean reward 0.609 over 128 rollouts, 64 with nonzero advantage, loss:sum 821.734203338623, sampling 7.5s, total 9.5s[grpo] step 25: mean reward 0.539 over 128 rollouts, 72 with nonzero advantage, loss:sum 108.8638687133789, sampling 7.8s, total 9.9s[grpo] step 26: mean reward 0.797 over 128 rollouts, 88 with nonzero advantage, loss:sum 838.9936237335205, sampling 8.2s, total 10.3s[grpo] step 27: mean reward 0.758 over 128 rollouts, 72 with nonzero advantage, loss:sum 659.4858798980713, sampling 9.4s, total 11.4s[grpo] step 28: mean reward 0.602 over 128 rollouts, 72 with nonzero advantage, loss:sum 342.77046394348145, sampling 7.5s, total 9.6s[grpo] step 29: mean reward 0.664 over 128 rollouts, 72 with nonzero advantage, loss:sum 192.16751670837402, sampling 7.8s, total 9.9s[grpo] step 30: mean reward 0.680 over 128 rollouts, 48 with nonzero advantage, loss:sum 253.72054862976074, sampling 7.5s, total 12.2s[grpo] step 31: mean reward 0.789 over 128 rollouts, 32 with nonzero advantage, loss:sum -282.6690044403076, sampling 16.6s, total 19.2s[grpo] step 32: mean reward 0.812 over 128 rollouts, 56 with nonzero advantage, loss:sum 392.216028213501, sampling 7.3s, total 25.7s[grpo] step 33: mean reward 0.805 over 128 rollouts, 64 with nonzero advantage, loss:sum 1132.3411979675293, sampling 8.7s, total 10.8s[grpo] step 34: mean reward 0.828 over 128 rollouts, 72 with nonzero advantage, loss:sum 204.1390552520752, sampling 7.2s, total 9.5s[grpo] step 35: mean reward 0.703 over 128 rollouts, 64 with nonzero advantage, loss:sum 603.2449703216553, sampling 7.5s, total 9.5s[grpo] step 36: mean reward 0.719 over 128 rollouts, 64 with nonzero advantage, loss:sum 802.2580699920654, sampling 8.0s, total 10.2s[grpo] step 37: mean reward 0.766 over 128 rollouts, 64 with nonzero advantage, loss:sum 226.2504711151123, sampling 7.8s, total 9.8s[grpo] step 38: mean reward 0.688 over 128 rollouts, 56 with nonzero advantage, loss:sum 590.6939163208008, sampling 7.9s, total 9.8s[grpo] step 39: mean reward 0.844 over 128 rollouts, 40 with nonzero advantage, loss:sum 37.004695892333984, sampling 7.9s, total 9.6s[grpo] step 40: mean reward 0.922 over 128 rollouts, 32 with nonzero advantage, loss:sum 453.6518745422363, sampling 7.6s, total 9.4s[grpo] step 41: mean reward 0.805 over 128 rollouts, 64 with nonzero advantage, loss:sum 1115.4270935058594, sampling 8.4s, total 10.3s[grpo] step 42: mean reward 0.711 over 128 rollouts, 72 with nonzero advantage, loss:sum 713.6975154876709, sampling 7.7s, total 9.7s[grpo] step 43: mean reward 0.805 over 128 rollouts, 56 with nonzero advantage, loss:sum 907.3668689727783, sampling 8.3s, total 10.1s[grpo] step 44: mean reward 0.789 over 128 rollouts, 64 with nonzero advantage, loss:sum 571.0823764801025, sampling 7.2s, total 9.1s[grpo] step 45: mean reward 0.891 over 128 rollouts, 48 with nonzero advantage, loss:sum 719.9716186523438, sampling 7.4s, total 9.2s[grpo] step 46: mean reward 0.836 over 128 rollouts, 56 with nonzero advantage, loss:sum 394.20207595825195, sampling 7.2s, total 9.2s[grpo] step 47: mean reward 0.898 over 128 rollouts, 48 with nonzero advantage, loss:sum 470.9459171295166, sampling 9.0s, total 10.9s[grpo] step 48: mean reward 0.859 over 128 rollouts, 32 with nonzero advantage, loss:sum 272.6463088989258, sampling 7.8s, total 9.6s[grpo] step 49: mean reward 0.828 over 128 rollouts, 56 with nonzero advantage, loss:sum 400.91523361206055, sampling 6.8s, total 8.8s[grpo] step 50: mean reward 0.758 over 128 rollouts, 64 with nonzero advantage, loss:sum 787.7232341766357, sampling 7.1s, total 9.0s[grpo] step 51: mean reward 0.875 over 128 rollouts, 56 with nonzero advantage, loss:sum 201.14261627197266, sampling 7.1s, total 9.1s[grpo] step 52: mean reward 0.734 over 128 rollouts, 32 with nonzero advantage, loss:sum 431.53229904174805, sampling 7.1s, total 8.8s[grpo] step 53: mean reward 0.766 over 128 rollouts, 72 with nonzero advantage, loss:sum 383.6535224914551, sampling 7.4s, total 9.5s[grpo] step 54: mean reward 0.742 over 128 rollouts, 40 with nonzero advantage, loss:sum 254.37164878845215, sampling 7.6s, total 9.5s[grpo] step 55: mean reward 0.789 over 128 rollouts, 48 with nonzero advantage, loss:sum -177.6482105255127, sampling 7.2s, total 9.2s[grpo] step 56: mean reward 0.758 over 128 rollouts, 40 with nonzero advantage, loss:sum 302.48490715026855, sampling 7.6s, total 9.6s[grpo] step 57: mean reward 0.727 over 128 rollouts, 48 with nonzero advantage, loss:sum 54.03257751464844, sampling 7.2s, total 9.0s[grpo] step 58: mean reward 0.859 over 128 rollouts, 40 with nonzero advantage, loss:sum 415.6060447692871, sampling 7.5s, total 9.3s[grpo] step 59: mean reward 0.828 over 128 rollouts, 56 with nonzero advantage, loss:sum 761.0609817504883, sampling 8.1s, total 9.9s[grpo] step 60: mean reward 0.859 over 128 rollouts, 32 with nonzero advantage, loss:sum 229.17776489257812, sampling 7.1s, total 8.8s[grpo] step 61: mean reward 0.758 over 128 rollouts, 72 with nonzero advantage, loss:sum -371.70118522644043, sampling 7.4s, total 9.4s[grpo] step 62: mean reward 0.656 over 128 rollouts, 40 with nonzero advantage, loss:sum 387.7624206542969, sampling 8.1s, total 10.2s[grpo] step 63: mean reward 0.836 over 128 rollouts, 40 with nonzero advantage, loss:sum 185.81954193115234, sampling 8.6s, total 10.7s[grpo] step 64: mean reward 0.750 over 128 rollouts, 56 with nonzero advantage, loss:sum 158.5655460357666, sampling 7.9s, total 9.7s[grpo] step 65: mean reward 0.883 over 128 rollouts, 32 with nonzero advantage, loss:sum -140.2154951095581, sampling 7.3s, total 9.1s[grpo] step 66: mean reward 0.781 over 128 rollouts, 56 with nonzero advantage, loss:sum 337.5029239654541, sampling 7.8s, total 9.8s[grpo] step 67: mean reward 0.664 over 128 rollouts, 96 with nonzero advantage, loss:sum 936.5171318054199, sampling 7.9s, total 10.2s[grpo] step 68: mean reward 0.750 over 128 rollouts, 64 with nonzero advantage, loss:sum 171.1912384033203, sampling 7.8s, total 9.9s[grpo] step 69: mean reward 0.648 over 128 rollouts, 56 with nonzero advantage, loss:sum 671.3530197143555, sampling 8.1s, total 10.2s[grpo] step 70: mean reward 0.742 over 128 rollouts, 72 with nonzero advantage, loss:sum 96.39751434326172, sampling 8.1s, total 10.4s[grpo] step 71: mean reward 0.773 over 128 rollouts, 48 with nonzero advantage, loss:sum -89.66376876831055, sampling 54.7s, total 56.7s[grpo] step 72: mean reward 0.867 over 128 rollouts, 48 with nonzero advantage, loss:sum 87.82363891601562, sampling 9.4s, total 11.6s[grpo] step 73: mean reward 0.859 over 128 rollouts, 40 with nonzero advantage, loss:sum -255.05417823791504, sampling 6.8s, total 8.9s[grpo] step 74: mean reward 0.773 over 128 rollouts, 56 with nonzero advantage, loss:sum 210.8087673187256, sampling 7.8s, total 9.8s[grpo] step 75: mean reward 0.727 over 128 rollouts, 56 with nonzero advantage, loss:sum 349.5944633483887, sampling 35.0s, total 37.1s[grpo] step 76: mean reward 0.812 over 128 rollouts, 32 with nonzero advantage, loss:sum 253.31482696533203, sampling 8.2s, total 10.2s[grpo] step 77: mean reward 0.859 over 128 rollouts, 24 with nonzero advantage, loss:sum 249.12313079833984, sampling 8.6s, total 10.6s[grpo] step 78: mean reward 0.828 over 128 rollouts, 64 with nonzero advantage, loss:sum 843.4686260223389, sampling 7.5s, total 9.7s[grpo] step 79: mean reward 0.844 over 128 rollouts, 48 with nonzero advantage, loss:sum 342.24943923950195, sampling 8.0s, total 10.1s[grpo] step 80: mean reward 0.820 over 128 rollouts, 40 with nonzero advantage, loss:sum 65.87721061706543, sampling 8.2s, total 10.4s[grpo] step 81: mean reward 0.805 over 128 rollouts, 24 with nonzero advantage, loss:sum -124.27051544189453, sampling 7.8s, total 9.8s[grpo] step 82: mean reward 0.750 over 128 rollouts, 48 with nonzero advantage, loss:sum 373.91913986206055, sampling 7.8s, total 9.8s[grpo] step 83: mean reward 0.844 over 128 rollouts, 64 with nonzero advantage, loss:sum 71.49538230895996, sampling 8.8s, total 11.0s[grpo] step 84: mean reward 0.883 over 128 rollouts, 48 with nonzero advantage, loss:sum -75.11136054992676, sampling 7.5s, total 9.4s[grpo] step 85: mean reward 0.836 over 128 rollouts, 56 with nonzero advantage, loss:sum 239.45961952209473, sampling 8.4s, total 10.5s[grpo] step 86: mean reward 0.672 over 128 rollouts, 64 with nonzero advantage, loss:sum 376.38819694519043, sampling 7.4s, total 9.5s[grpo] step 87: mean reward 0.852 over 128 rollouts, 56 with nonzero advantage, loss:sum 590.9779605865479, sampling 8.8s, total 10.9s[grpo] step 88: mean reward 0.891 over 128 rollouts, 40 with nonzero advantage, loss:sum 97.04498863220215, sampling 7.7s, total 9.7s[grpo] step 89: mean reward 0.930 over 128 rollouts, 48 with nonzero advantage, loss:sum 311.6809959411621, sampling 7.9s, total 9.9s[grpo] step 90: mean reward 0.844 over 128 rollouts, 16 with nonzero advantage, loss:sum 293.730770111084, sampling 7.9s, total 11.9s[grpo] step 91: mean reward 0.766 over 128 rollouts, 64 with nonzero advantage, loss:sum 230.85948753356934, sampling 8.8s, total 11.0s[grpo] step 92: mean reward 0.742 over 128 rollouts, 48 with nonzero advantage, loss:sum 221.12081718444824, sampling 7.2s, total 9.1s[grpo] step 93: mean reward 0.875 over 128 rollouts, 40 with nonzero advantage, loss:sum 21.661273956298828, sampling 7.8s, total 9.7s[grpo] step 94: mean reward 0.797 over 128 rollouts, 64 with nonzero advantage, loss:sum 245.83827781677246, sampling 7.8s, total 9.9s[grpo] step 95: mean reward 0.938 over 128 rollouts, 32 with nonzero advantage, loss:sum 543.9210433959961, sampling 7.6s, total 9.5s[grpo] step 96: mean reward 0.867 over 128 rollouts, 40 with nonzero advantage, loss:sum 416.2718334197998, sampling 9.2s, total 11.2s[grpo] step 97: mean reward 0.688 over 128 rollouts, 80 with nonzero advantage, loss:sum 353.09184646606445, sampling 8.0s, total 10.4s[grpo] step 98: mean reward 0.906 over 128 rollouts, 24 with nonzero advantage, loss:sum 343.73168182373047, sampling 8.6s, total 10.5s[grpo] step 99: mean reward 0.836 over 128 rollouts, 48 with nonzero advantage, loss:sum 234.16997718811035, sampling 7.3s, total 9.5s[grpo] eval accuracy after training: 0.863 (1637s)RESULT {"train_reward_first": 0.484375, "train_reward_last": 0.8359375, "train_reward_mean": 0.744375, "eval_accuracy_before": 0.7265625, "eval_accuracy_after": 0.86328125, "steps": 100, "n_prompts_per_step": 16, "group_size": 8, "rollouts_per_step": 128, "baseline": "group_mean", "mean_completion_tokens": 304.141796875, "arms": {"grpo": {"train_reward_first": 0.484375, "train_reward_last": 0.8359375, "train_reward_mean": 0.744375, "eval_accuracy_before": 0.7265625, "eval_accuracy_after": 0.86328125, "steps": 100, "n_prompts_per_step": 16, "group_size": 8, "rollouts_per_step": 128, "baseline": "group_mean", "mean_completion_tokens": 304.141796875}}, "base_model": "Qwen/Qwen3.5-2B", "lora_rank": 32, "lr": 4e-05, "max_tokens": 512, "dataset": "openai/gsm8k", "n_eval": 256, "wall_seconds": 1637.4}
Details
- run
- run_bffef575d5
- backend
- Modal runner
- experiment
- exp_80fe2820a1
- redone as
- run_83ec69d4f2 no result
- created
- Nov 3, 03:32 UTC
- started
- Nov 3, 03:32 UTC
- finished
- Nov 3, 04:01 UTC
- duration
- 28m 27s
- GPU-h budget
- 2.0
- wall budget
- 120 min
- base model
- Qwen/Qwen3.5-0.8B
- training
- RL
- dataset
- GSM8K
- run_83ec69d4f2 no result 1d ago