# So… We cooked a model 🤷

Congratulations to the winners and huge thanks to the AIMO team for hosting such an intense competition that pushed the frontier of open-source reasoning models. I'd like to express my deep gratitude to the best teammates I could have ever asked for, especially
[@yeoyunsianggeremie](https://www.kaggle.com/yeoyunsianggeremie)
,
[@xyzdivergence](https://www.kaggle.com/xyzdivergence)
, and
[@conjuring92](https://www.kaggle.com/conjuring92)
. They did most of the hard heavy lifting work.
The results were released on 4/9, and we got rank 49 — what a coincidence 😭. Although we didn't achieve the leaderboard results we hoped for, it has been incredibly fun working on this competition, so we'd like to share what we learned and enjoyed tinkering with.
![Majority voting accuracy (Maj@32) on the uncontaminated AIME 2025 math olympiad of our models compared to the base DeepSeek-R1-Distill models. Token budget for all models is set to 16384 (CoTs are cut at this length).](assets/84c35e75f2134705a5ac9b2f.png)
Evaluation
Let's start with evaluation results first, since most people are too lazy to scroll down 😅. Like many teams, our local CV consists of 40 problems:
[30 problems from AIME 2025](https://huggingface.co/datasets/opencompass/AIME2025)
and
[10 problems from AIMO2 reference](https://www.kaggle.com/competitions/ai-mathematical-olympiad-progress-prize-2/data?select=reference.csv)
. For each model, we collect 64 reasoning traces per question for evaluation.
14B models
Merged-14B:
the model we submitted to the Private LB for both of our final submissions. It's a merge of several SFT trained at 16K context and GRPO on top of SFT with 6K context checkpoints. We uploaded the AWQ on Huggingface:
[bogoconic1/aimo2-final-merged-model-14b](https://huggingface.co/bogoconic1/aimo2-final-merged-model-14b)
Last-GRPO-14B:
trained in the final days of the competition, 16K context. It showed slightly worse results on our local End-to-End whole pipeline validation, so we never submitted it to LB.
Token budget
Model Name
CV Pass@1
CV Maj@8
CV Maj@32
AIME'25 Pass@1
AIME'25 Maj@8
AIME'25 Maj@32
Avg. length
12800
DeepSeek-R1-Distill-14B
0.412
0.575
0.613
0.41
0.596
0.648
9473.66
Light-R1-14B-DS
0.442
0.613
0.664
0.45
0.625
0.671
9787.01
Our Merged 14B
0.477
0.686
0.747
0.455
0.673
0.731
9251.56
Our Last GRPO 14B
0.482
0.684
0.736
0.468
0.679
0.738
9312.03
16384
DeepSeek-R1-Distill-14B
0.449
0.614
0.664
0.447
0.625
0.671
10910.2
Light-R1-14B-DS
0.498
0.664
0.713
0.502
0.679
0.731
11432.1
Our Merged 14B
0.525
0.706
0.759
0.504
0.698
0.746
10552.1
Our Last GRPO 14B
0.541
0.717
0.762
0.521
0.704
0.758
10511.6
We built on top of
[Light-R1](https://huggingface.co/datasets/qihoo360/Light-R1-SFTData)
by using a subset of their stage 2 data. We are incredibly grateful to the Light-R1 team for their open-source contributions. This comparison is done only to show how much we were able to improve upon our baselines.
7B models
We trained our 7B GRPO on top of SFT in 2 stages: first with 8K context, then with 16K context. Our best 7B model is a merge of the SFT and GRPO models, but we never submitted it to the LB as we moved on to 14B models.
Token budget
Model name
CV Pass@1
CV Maj@8
CV Maj@32
AIME'25 Pass@1
AIME'25 Maj@8
AIME'25 Maj@32
Avg. length
12800
DeepSeek-R1-Distill-7B
0.345
0.502
0.55
0.353
0.512
0.562
9553.74
Light-R1-7B-DS
0.36
0.539
0.606
0.371
0.531
0.606
9831.07
Our Final SFT 7B
0.379
0.569
0.627
0.374
0.523
0.604
9751
Our Merged 7B
0.383
0.575
0.658
0.38
0.558
0.637
9583.42
16384
DeepSeek-R1-Distill-7B
0.368
0.519
0.58
0.377
0.537
0.583
11104.1
Light-R1-7B-DS
0.391
0.564
0.611
0.401
0.565
0.631
11511.7
Our Final SFT 7B
0.412
0.592
0.678
0.398
0.567
0.658
11449.6
Our Merged 7B
0.422
0.619
0.686
0.409
0.575
0.654
11145.9
Evaluation setting
Solutions are generated in
BFloat16
. Length and
Pass@1
metrics were averaged across 64 solutions per question. For
Maj@K
(majority voting), we sampled
K
traces per problem from our generated solutions. We repeat this process 16 times and reported the average to reduce noise. You can reproduce our evals scorecard using our
[evaluation code](https://www.kaggle.com/code/chankhavu/aime25-aimo2-evals)
and our
[dataset of collected reasoning traces](https://www.kaggle.com/datasets/chankhavu/reasoning-traces-aime25-aimo25)
.
Data
First, we filtered math word problems from
[NuminaMath-1.5](https://huggingface.co/datasets/AI-MO/NuminaMath-1.5)
, keeping only integer-answer problems from olympiads, AoPS forums, AMC, AIME of previous years, olympiad references, and number theory sources. Our goal was to get harder problems in topics that DeepSeek models would likely struggle with. We then joined with correct R1 reasoning traces from
[OpenR1-Math-220k](https://huggingface.co/datasets/open-r1/OpenR1-Math-220k)
. This filtered 800K problems down to 27K.
To filter further, we sampled 8 solutions per problem with
max_len
of 8K tokens using
[deepseek-r1-distill-qwen-7b-awq](https://huggingface.co/casperhansen/deepseek-r1-distill-qwen-7b-awq)
and removed easy problems. We kept only problems with 7 or fewer correct solutions, leaving 8K problems. To get harder problems for GRPO, we used the 14B AWQ model for similar filtering.
Later, we added a subset of
[Light-R1](https://huggingface.co/datasets/qihoo360/Light-R1-SFTData)
stage 2 data (after filtering out non-integer answers and removing CoT with more than 16K tokens) and removed duplicates with our dataset.
Modeling
SFT
We used
[DeepSeek-R1-Distill-Qwen-14B](https://huggingface.co/deepseek-ai/DeepSeek-R1-Distill-Qwen-14B)
and
[DeepSeek-R1-Distill-Qwen-7B](https://huggingface.co/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B)
as our base models and fine-tuned them for 6 epochs at 16K context length.
GRPO
Like other teams, we identified generation length as the main problem with SFT models. During the Reinforcement Learning process, we tried to steer our model's behavior toward shorter reasoning CoTs. We applied these improvements to GRPO:
Removed rewards scaling, following the
[Dr. GRPO paper](https://arxiv.org/abs/2503.20783)
, to eliminate length bias.
Actor rollouts is the most painful part of GRPO. For quicker convergence, we re-used each batch twice during training.
We spent considerable time on 7B models, hoping our findings would translate to 14B, only to relearn the bitter lesson repeatedly — good tricks at smaller scales don't always work at larger ones.
For the 7B model, we performed GRPO in two stages: first on 8K context, then on 16K context. We found LoRA converged faster than FFT while being more VRAM-efficient. We used DAPO's clipping and online sample filtering, and length penalty worked well for 7B.
For 14B, length penalty severely hurts accuracy, so we removed it. Also, training on much shorter contexts significantly reduced accuracy at intended inference lengths. Model merging helped regain some accuracy, so our final submission is a merged SFT and GRPO on 6K context. As mentioned, we had another 14B GRPO on 16K context trained on the last day.
Merging
For 7B models, merging improved overall performance: the merged model outperformed both SFT and all GRPO checkpoints in accuracy and token economy. With 14B, merging became more of a trade-off — we gained back some accuracy compared to GRPO but lost some token efficiency.
Inference post-mortem
We used SGLang since it proved faster than vLLM in our tests. Quantization is a major issue we faced — we lose a lot of our gains during training after quantization. We did not use early stopping of reasoning rollouts in our sub.
If you've read the whole post, thanks a ton! Anyways, see you all again in AIMO3 this Autumn 👋