{
  "id": 699347,
  "title": "AIMO3_Writeup_Preet",
  "content": "<h1>AIMO Progress Prize 3 — Technical Report</h1>\n<h2>Engineering High-Throughput LLM Inference for Competitive Mathematical Reasoning: Lessons from the AIMO Progress Prize 3 Competition</h2>\n<p><strong>Independent Research • April 2025</strong></p>\n<h2>Abstract</h2>\n<p>\nThis report documents an independent submission to the AI Mathematical Olympiad (AIMO)\nProgress Prize 3 competition. Operating under a strict 5-hour GPU budget on a single\nNVIDIA H100 80GB GPU, a comprehensive set of inference-time optimizations for\nGPT-OSS-120B were investigated.\n</p>\n<p>\nContributions include:\n</p>\n<ul>\n<li>Asynchronous concurrency scheduling</li>\n<li>Time-pressure-based global-buffer borrowing</li>\n<li>\nA Non-Step-Back prompting approach that outperformed the Step-Back variant\n(score 24 vs. 18)\n</li>\n<li>\nA dual-pass answer extraction system combining structured JSON regex with a\nmodel-based fallback\n</li>\n<li>\nSystematic ablations of serving backends (Marlin, Triton, SGLang), CUDA graph capture\nsizes, and sliding-window attention are documented across 15 configurations.\n</li></ul>\n<hr>\n<h2>1. Introduction</h2>\n<p>\nThe AIMO Progress Prize 3 competition requires solving 50 mathematical problems under\na strict 5-hour GPU constraint. Problems are competition-grade, requiring multi-step\nsymbolic and numerical reasoning.\n</p>\n<p>\nEach participant receives a single GPU allocation for the entire run, with approximately\n20 minutes consumed by environment setup and model loading, leaving roughly\n336 seconds per question.\n</p>\n<p>\nThis work is entirely inference-based — no model weights were fine-tuned.\nThe approach combines multiple factors:\n</p>\n<ul>\n<li>Model capability</li>\n<li>Prompt design</li>\n<li>Concurrency architecture</li>\n<li>Time allocation</li>\n<li>Answer extraction</li>\n</ul>\n<p>\nGPT-OSS-120B appeared to perform best when given sufficient time and token budget to\nreason through problems fully.\n</p>\n<p>\n<strong>Note:</strong> The best-performing configuration (score 24) could not be submitted to the competition because a critical library dependency was accidentally deleted just before the deadline.\n</p>\n<hr>\n<h2>2. Problem Constraints and Setup</h2>\n<h3>2.1 Hardware</h3>\n<table>\n<tbody><tr>\n<th>Component</th>\n<th>Specification</th>\n</tr>\n<tr>\n<td>GPU</td>\n<td>NVIDIA H100 80GB (SXM or PCIe; single GPU, tp_size=1)</td>\n</tr>\n<tr>\n<td>GPU Memory</td>\n<td>~60–65 GB total during inference (96% utilization)</td>\n</tr>\n<tr>\n<td>CUDA Architecture</td>\n<td>Hopper (sm_90) — required for fp8_e4m3 KV cache</td>\n</tr>\n<tr>\n<td>KV Cache dtype</td>\n<td>fp8_e4m3</td>\n</tr>\n<tr>\n<td>Model</td>\n<td>GPT-OSS-120B (MoE, 120B params, 5.1B active)</td>\n</tr>\n<tr>\n<td>Serving Framework</td>\n<td>Modified NemoSkills + vLLM 0.11.2</td>\n</tr>\n<tr>\n<td>Python</td>\n<td>Python 3.12.12</td>\n</tr>\n</tbody></table>\n<h3>2.2 Time Budget</h3>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F1563363%2Fef53d83ee10bc3abac80303a2c81184d%2FTime-Budget.png?generation=1778943579039470&amp;alt=media\" alt=\"\"></p>\n<table>\n<tbody><tr>\n<th>Parameter</th>\n<th>Value</th>\n</tr>\n<tr>\n<td>Total GPU time</td>\n<td>5 hours</td>\n</tr>\n<tr>\n<td>Setup &amp; model loading</td>\n<td>~20 minutes</td>\n</tr>\n<tr>\n<td>Effective inference window</td>\n<td>~280 minutes</td>\n</tr>\n<tr>\n<td>Base per-question budget</td>\n<td>~320 seconds + buffer borrowing</td>\n</tr>\n<tr>\n<td>Global buffer</td>\n<td>350 seconds (dynamically updated)</td>\n</tr>\n</tbody></table>\n<hr>\n<h2>3. Benchmarking Strategy</h2>\n<p>\nThree levels of benchmarking were used, applied in the order below as each revealed\na gap that motivated the next.\n</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F1563363%2F59e78444f7f0314db3ae36fc745f4ead%2FBenchmarking.png?generation=1778943755757867&amp;alt=media\" alt=\"\"></p>\n<h3>3.1 AIMO Reference Problems (First Dataset)</h3>\n<p>\nThe first benchmark consisted of 20 problems drawn from the AIMO 2 and AIMO 3\nreference problem sets. The model scored 95% accuracy (19/20).\n</p>\n<table>\n<tbody><tr>\n<th>Metric</th>\n<th>Value</th>\n</tr>\n<tr>\n<td>Total problems</td>\n<td>20</td>\n</tr>\n<tr>\n<td>Correct answers</td>\n<td>19/20 (95%)</td>\n</tr>\n<tr>\n<td>Incorrect answer</td>\n<td>Problem #10 (model: 29,443; actual: 8,687)</td>\n</tr>\n<tr>\n<td>Avg time per problem</td>\n<td>230 seconds</td>\n</tr>\n<tr>\n<td>Avg tokens generated</td>\n<td>13,543 tokens</td>\n</tr>\n</tbody></table>\n<h3>3.2 Internal Benchmark (Second Dataset)</h3>\n<p>\nAfter observing the gap between 90–95% reference accuracy and the 42% leaderboard score,\na harder benchmark was constructed from 49 problems sourced from IMO, AMC/AIME,\nand similar archives.\n</p>\n<table>\n<tbody><tr>\n<th>Property</th>\n<th>Value</th>\n</tr>\n<tr>\n<td>Total problems</td>\n<td>49</td>\n</tr>\n<tr>\n<td>Problem sources</td>\n<td></td>\n</tr>\n<tr>\n<td>Model accuracy</td>\n<td>65%</td>\n</tr>\n</tbody></table>\n<p>Internal BenchMark Dataset - <a href=\"https://huggingface.co/HarpreetK/AIMO3/blob/main/Internal_Benchmark_Final.xlsx\" target=\"_blank\">https://huggingface.co/HarpreetK/AIMO3/blob/main/Internal_Benchmark_Final.xlsx</a>\nSources - AOPS,<a href=\"https://matharena.ai/apex/\" target=\"_blank\">https://matharena.ai/apex/</a>, ARML, HMMT</p>\n<h3>3.3 10-Problem Failing Subset</h3>\n<p>\nA targeted 10-problem subset was extracted consisting of questions where the previous\nattempt had either returned 29443 (timeout/extraction failure) or produced an incorrect answer.\n</p>\n<table>\n<tbody><tr>\n<th>Benchmark</th>\n<th>Score</th>\n<th>Notes</th>\n</tr>\n<tr>\n<td>AIMO Reference (20)</td>\n<td>95% (19/20)</td>\n<td>Too easy; gap not explained</td>\n</tr>\n<tr>\n<td>Internal Benchmark (49)</td>\n<td>65%</td>\n<td>Closer to AIMO 3 difficulty</td>\n</tr>\n<tr>\n<td>AIMO 3 Leaderboard (50)</td>\n<td>21/50 (42%)</td>\n<td>Actual submission</td>\n</tr>\n<tr>\n<td>Best config (50)</td>\n<td>24/50 (48%)</td>\n<td>Not submitted — library deletion</td>\n</tr>\n</tbody></table>\n<hr>\n<h2>4. System Design</h2>\n<h3>4.1 Overall Flow Diagram</h3>\n<p>Flow Diagram is attached. Please open it independently in a new window to zoom on it</p>\n<h3>4.2 Baseline Code and Repository</h3>\n<p>\nA modified version of the NemoSkills repository (winner of AIMO 2) was used as the baseline,\nproviding a scaffold for request scheduling and Python code execution sandboxing.\nMCP and LiteLLM abstraction layers were stripped to reduce overhead.\n</p>\n<h3>4.3 Async Scheduling (Python asyncio)</h3>\n<ul>\n<li>No thread creation overhead</li>\n<li>No heavy context switching</li>\n<li>Handles thousands of concurrent tasks efficiently</li>\n<li>Confirmed by AIMO 2 winning teams</li>\n</ul>\n<p>\n<em>\nNote: These were conclusions based on research. Ideally, both approaches would have been compared directly.\n</em>\n</p>\n<h3>4.4 Dynamic Buffer Borrowing</h3>\n<p>\nThe BufferBorrower class implements a time-pressure-based allocation strategy.\nBorrowable time differed across notebooks:\n</p>\n<ul>\n<li>130 seconds in score-21</li>\n<li>95 seconds in score-24</li>\n</ul>\n<h3>4.5 Non-Step-Back Prompting (Better than Step-Back)</h3>\n<p>\nThe final best-performing approach used a single-phase prompt applied uniformly to all 50 problems.\n</p>\n<p>\n<strong>\nThe key jump was from score 18 (Step-Back) to score 24 (Non-Step-Back):\na 6-point improvement.\n</strong>\n</p>\n<h3>4.6 Majority Voting Answer Extraction</h3>\n<p>\nUp to 8 self-consistent samples are generated per problem.\nMajority voting uses frequency count only.\n</p>\n<p>\n<strong>Metric Used:</strong> Exact Match Accuracy.\n</p>\n<h3>4.7 vLLM Launch Configuration</h3>\n<pre><code>\npython -m nemo_skills.inference.server.serve_vllm \\\n --model=.../gpt-oss-120b/.../1 --port=5000 --num_gpus=1 \\\n --max_model_len=38000 --max_num_batched_tokens=65000 \\\n --max_num_seqs=11 --max-cudagraph-capture-size=2048 \\\n --gpu_memory_utilization=0.95 --kv_cache_dtype=fp8_e4m3 \\\n --enable-prefix-caching --async-scheduling\n</code></pre>\n<table>\n<tbody><tr>\n<th>Parameter</th>\n<th>Value</th>\n<th>Rationale</th>\n</tr>\n<tr>\n<td>max_tokens</td>\n<td>38,000</td>\n<td>Upper bound per problem</td>\n</tr>\n<tr>\n<td>tokens_to_generate</td>\n<td>35,940</td>\n<td>max_tokens minus overhead</td>\n</tr>\n<tr>\n<td>max_batch_size</td>\n<td>8</td>\n<td>Number of self-consistent samples</td>\n</tr>\n<tr>\n<td>global_buffer</td>\n<td>350 seconds</td>\n<td>Reserve for hard problems</td>\n</tr>\n<tr>\n<td>temperature</td>\n<td>1.0</td>\n<td>Per NVIDIA NeMo recommendation</td>\n</tr>\n<tr>\n<td>top_p</td>\n<td>1.0</td>\n<td>Per NVIDIA NeMo recommendation</td>\n</tr>\n</tbody></table>\n<hr>\n<h2>5. Backend and Systems Experiments</h2>\n<h3>5.1 Backend Comparison</h3>\n<ul>\n<li>\n<strong>vLLM:</strong> v0.10.1+gptoss failed to install due to PyTorch nightly conflicts.\n</li>\n<li>\n<strong>TensorRT-LLM:</strong> Engine compilation failed.\n</li>\n<li>\n<strong>Triton:</strong> Functional baseline: 875 tok/s prompt throughput.\n</li>\n<li>\n<strong>Marlin:</strong> Fused GPU kernels yielded 2,708 tok/s prompt throughput.\n</li>\n</ul>\n<h3>5.2 Full Experimental Configuration Table</h3>\n<p>All 15 configurations tested.</p>\n<h3>5.3 Sliding Window Attention</h3>\n<p>\nGPT-OSS alternates between full attention and sliding window attention (SWA).\n</p>\n<p>\nSliding window sizes 128, 200, and 8,000 were tested.\n</p>\n<h3>5.4 Sampling and vLLM Parameter Tuning</h3>\n<p>\nTemperature fixed at 1.0 (NVIDIA recommendation).\n</p>\n<hr>\n<h2>6. Submission History and Iterative Improvements</h2>\n<h3>6.1 Score Progression</h3>\n<table>\n<tbody><tr>\n<th>Parameter</th>\n<th>Score 18 (SB)</th>\n<th>Score 20</th>\n<th>Score 21 (SUB)</th>\n<th>Score 24 (Best)</th>\n</tr>\n<tr>\n<td>Prompting</td>\n<td>Step-Back full</td>\n<td>Non-SB + dual</td>\n<td>Non-Step-Back</td>\n<td>Non-Step-Back</td>\n</tr>\n<tr>\n<td>Temperature</td>\n<td>Fixed 1.0</td>\n<td>Varied</td>\n<td>Fixed 1.0</td>\n<td>Fixed 1.0</td>\n</tr>\n<tr>\n<td>max_model_len</td>\n<td>65,536</td>\n<td>36,000</td>\n<td>38,000</td>\n<td>80,000</td>\n</tr>\n<tr>\n<td>Leaderboard score</td>\n<td>18/50</td>\n<td>20/50</td>\n<td>21/50</td>\n<td>24/50</td>\n</tr>\n</tbody></table>\n<h3>6.2 Key Changes Between Attempts</h3>\n<h4>Score 18 → 24: Two key changes, +6 points</h4>\n<ul>\n<li>Step-Back Phase 1 removed entirely</li>\n<li>Token budget substantially increased</li>\n</ul>\n<h4>Score 24 → 21</h4>\n<p>\nReduced token budget caused score drop from 24 to 21.\n</p>\n<h4>Score 21 → 20</h4>\n<p>\nDual-prompt strategy and varied-temperature sampling hurt performance.\n</p>\n<hr>\n<h2>7. Comparison with State of the Art</h2>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F1563363%2F98ad341eccad2211873d4d0c07f0e423%2FSOTA%20Comparison.png?generation=1778953075190961&amp;alt=media\" alt=\"\"></p>\n<p>Below models were added to SOTA Comparison\nQwen (without tool calling),\nGemini Pro 3.1,\nand Claude Opus 4.7.\nOne particularly interesting observation was that Gemini Pro 3.1 and Claude Opus 4.7 appear to be highly complementary systems.</p>\n<p>Together, the two models successfully solved every question in my curated evaluation dataset.</p>\n<p>More specifically:</p>\n<p>Claude demonstrated stronger mathematical reasoning overall,\nespecially on difficult mathematical problems,\nwhile both models solved easier problems reliably,\nand on harder problems, each model solved cases that the other failed to solve.</p>\n<h2>8. Key Insights (Summary)</h2>\n<ul>\n<li>Time pressure is the primary bottleneck.</li>\n<li>Async scheduling flag in vLLM is extremely important.</li>\n<li>Token budget dominates accuracy.</li>\n<li>Backend choice significantly affects throughput.</li>\n<li>Dataset difficulty calibration is critical.</li>\n<li>Geometry-heavy problems appeared harder.</li>\n</ul>\n<hr>\n<h2>9. Limitations</h2>\n<ul>\n<li>No fine-tuning</li>\n<li>Limited benchmark coverage</li>\n<li>Single-run experiments</li>\n</ul>\n<hr>\n<h2>10. Future Work</h2>\n<ul>\n<li>Complete backend investigation</li>\n<li>Partial-response answer extraction</li>\n<li>Enable torch_compile and torch_dynamo</li>\n<li>Hybrid async-threaded scheduling</li>\n<li>Verifier models</li>\n<li>SGLang + fused MoE optimization</li>\n<li>Fine-tuning on post-June-2024 IMO data</li>\n</ul>\n<hr>\n<h2>11. Reproducibility Checklist</h2>\n<p>\nHuggingFace repo:\n<a href=\"https://huggingface.co/HarpreetK/AIMO3\">\nhttps://huggingface.co/HarpreetK/AIMO3\n</a>\n</p>\n<table>\n<tbody><tr>\n<th>Artifact</th>\n<th>Location / Value</th>\n<th>Status</th>\n</tr>\n<tr>\n<td>Base model</td>\n<td>GPT-OSS-120B</td>\n<td>Provided</td>\n</tr>\n<tr>\n<td>Submitted notebook</td>\n<td>gpt-oss-score21.ipynb</td>\n<td>Provided</td>\n</tr>\n<tr>\n<td>Best notebook (24)</td>\n<td>gpt-oss-nostepback-score24.ipynb</td>\n<td>Provided</td>\n</tr>\n<tr>\n<td>Backend</td>\n<td>Marlin (via vLLM 0.11.2)</td>\n<td>Provided</td>\n</tr>\n</tbody></table>\n<hr>\n<h2>13. Appendix</h2>\n<p>refer the pdf for the same</p>",
  "comments": [
    {
      "id": 3459320,
      "author_name": "Preet",
      "author_url": "",
      "post_date": "2026-05-17T16:48:53.103000",
      "content": "<blockquote>\n  <h3>The final pdf is updated. Please do the refer the writeup here. I did fix few sections here on the writeup but formatting here is much tougher than in a word document. This writeup does not contain the full list of edits only the pdf does. So please check the v2 pdf attached to this writeup section. The edits are mentioned on page 1 and against the sections also. Just to save time - all the edits in the pdf except \"sections  5.2 Added Note, 8(last point),12 (Prompt Appendix)\" are already part of the replies that I gave to you both below. So those edits do not provide any new information\n  <br><br>\n  Huggingface repo is also updated</h3>\n</blockquote>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 3458323,
      "author_name": "Sam Bealing",
      "author_url": "",
      "post_date": "2026-05-15T16:15:36.507000",
      "content": "<p>Following up on the questions from <a href=\"https://www.kaggle.com/philipvonderlind\" target=\"_blank\">@philipvonderlind</a>, here are some additional questions to help us assess your submission:</p>\n<ol>\n<li><strong>Global time buffer mechanics:</strong> The writeup mentions a global buffer of 350 seconds that's dynamically updated and allows time borrowing from future problems. Could you describe in more detail how the borrowing logic decides when to lend time vs hold it back, and what safeguards prevent the run from running out of time on later problems (particularly if the harder problems happen to fall near the end of the run)?</li>\n<li><strong>Step-back removal vs token budget:</strong> The 18→24 improvement bundles Step-Back removal and a token budget doubling. You explicitly note that you can't isolate their individual contributions, but from development you presumably have some intuition. Informally, which of the two felt like the larger contributor?</li>\n<li><strong>Internal benchmark construction and answer accuracy:</strong> Beyond the AIMO reference set, you reference an internal benchmark and a 10-problem failing subset used during development. Could you describe how you collected and curated these (sources, filtering criteria), and what steps you took to verify the ground-truth answers? Across the maths corpus prize submissions we've reviewed, even widely-used datasets often contain ground-truth errors that can quietly distort ablation conclusions.</li>\n</ol>\n<p>Look forward to reading your responses on these.</p>",
      "votes": 0,
      "replies": [
        {
          "id": 3458701,
          "author_name": "Preet",
          "author_url": "",
          "post_date": "2026-05-16T13:13:15.077000",
          "content": "<h1>Question 1 - Global time buffer mechanics:</h1>\n<p><strong>Context Setting</strong></p>\n<h3>Step-Back Approach</h3>\n<p>\nPhase 1 - For the Step-Back approach, three time buckets were defined based on the estimated difficulty level of the problem. Considering the total competition time available, the average time allocated per question could not realistically exceed approximately 320–340 seconds.\n</p>\n<p>\nFrom this baseline allocation, the additional time required for the Step-Back phase was subtracted. The Step-Back phase refers to an initial pass where the model is asked only to:\n</p>\n<ul>\n  <li>identify the difficulty level of the problem,</li>\n  <li>determine the techniques likely required to solve it,</li>\n  <li>and classify the problem domain.</li>\n</ul>\n<p>\nBased on the difficulty level predicted by the model, a corresponding baseline time budget was assigned. Each problem could receive time from only one of predefined categories, as shown in the corresponding if-else logic.\n</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1563363%2F2426fefee5f859d596c369fa59066f4f%2Fif-else.png?generation=1778937574722126&amp;alt=media\" alt=\"\"></p>\n<p>\nOnce the stepback approach is completed, the time-counter indicates how much time was consumed. And this time is subtracted from the baseline time (one of the 3 categories defined above) and a fraction of the global buffer was added to get the net effective inference time (<code>baseline - stepback_time + fraction_of_buffer</code>). (How to compute fraction which gets multiplied with global buffer is indicated in my answer to Philip's question -please refer that)\n</p>\n<p><br>\nAlso a dynamic prompt was chosen based on phase 1 (domain and techniques required to solve the problem)\n<br></p>\n<p>\nPhase 2 - The effective inference time and dynamic prompt was passed onto this phase of the problem solving where actual answer was produced\n(StepBack Time and tokens were capped to a maximum so that it does not eat into problem solving time)\n</p>\n<p>Once the question is attempted the actual execution time is measured using time.perf_counter(). The measured time is then compared against the allocated budget:\n</p><p></p>\n<h3>Non-Step-Back Approach</h3>\n<p>\nThe overall philosophy remained similar, but the implementation was intentionally simplified.\n</p>\n<p>\nAIMO3 was expected to contain increasingly difficult problems. In practice, distinguishing reliably between “hard,” “harder,” and “hardest” problems before fully attempting them proved difficult. Because of this, dynamically assigning substantially different budgets based on predicted difficulty was not considered reliable. \n<br>\n<br>\nInstead of categorizing problems by difficulty, a flat baseline of 320 seconds per question was used. \n<br>\nThe reasoning behind this decision was that harder problems did not necessarily benefit from significantly larger time allocations. Empirically, if the model was capable of solving a problem correctly, it typically did so within roughly the same time range.\n<br>\nAnyways the unused time would become part of the global buffer.\n</p>\n<p>\nAs with the Step-Back approach, the actual solving time for each question was also tracked using <code>time.perf_counter()</code> and compared against the allocated budget (<code>baseline + fraction_of_buffer</code>):\n</p>\n<p>The difference between this and Non-StepBack Approach was how the fraction of global buffer was calculated and how the baseline budget was determined - For Non-StepBack - flat 320 seconds were allocated as opposed to the 3 categories defined in stepback approach\n<br><br><br>\n<strong>Actual Answer of the question</strong></p>\n<h4>For Both StepBack and Non-StepBack Approach (Below is the actual answer to your question. Previous text provides contextual information)</h4>\n<ul>\n  <li>\n      If the model used less time than allocated, the remaining time was returned to the global buffer.\n  </li>\n  <li>\n      If the model exceeded the allocated budget, the excess time was deducted from the global buffer.\n  </li>\n</ul>\n<p>\nThe additional time assigned to a question was capped at the minimum of:\n<br>\n</p><ul>\n  <li>the calculated fraction of the available buffer, or</li>\n  <li>the predefined maximum allowed buffer cap.</li>\n</ul>\n<p></p>\n<p><strong>Since time per question and global buffer is checked on each question. Therefore, that prevents it from running out on later questions. This could also result in case where global buffer rans out. But if that happens then the addition time from the global buffer cannot be borrowed since it is 0 and the baseline time which is roughly approximate time per question would serve as a hard limit </strong>\n<strong>Detailed Explanation is given to Philip in the comments below to compute time pressure and global buffer borrowing in Answer 3</strong>\nSide Note: Different buffer caps were tested across the few submissions I made </p>\n<h1>Question 2 - Step-back removal vs token budget</h1>\n<p>\nI would like to clarify one point regarding the token budget. The token budget was not exactly doubled; rather, it was increased by approximately 22%.\n</p>\n<p>\nIn my view, the improvement in performance was likely driven more by the additional time available for solving each question than by the increase in token budget itself.\n</p>\n<p>\nFor reference, notebooks that scored in the 40s using the GPT-OSS model were operating with a context length of 65,536 tokens, and I used the same context length in my notebook that scored 18.\n</p>\n<p>\nLess time available per question was one of the reasons why the Step-Back approach was not used in later iterations. I had initial reservations about it but wanted to check if stepback phase resulted in quick convergence to answer compensating for the time consumed during phase 1 and also better accuracy.\n</p>\n<h1>Question 3 - Internal benchmark construction and answer accuracy</h1>\n<p>\nThese were actual problems taken from official IMO-style mathematics competitions. I handpicked the problems from both Hugging Face dataset repositories(this also had difficulty level assigned) and the official competition websites. None of the internal benchmark data was synthetically generated; therefore, the possibility of ground-truth labeling errors is close to 0\nSources Used\nMathArena (https://matharena.ai/apex/)\nAOPS\nARML2 &amp; ARML3\nHMMT\nIMO\n</p>\n<p>\nThe filtering criteria were based on two primary factors:\n</p>\n<ol>\n  <li>\n      From each of the four domains — Number Theory, Algebra, Combinatorics, and Geometry — an approximately equal number of questions was selected to ensure balanced evaluation coverage across all mathematical areas.\n  </li>\n   <li>\n      Since the AIMO3 competition overview explicitly indicated a focus on hard problems. I personally reviewed the problems to identify questions that were difficult even to begin reasoning about. I myself have participated in Mathematical Olympiad held in my country so I used my past knowledge to filter the questions.\nOther filtering criteria used was difficulty level given in the huggingface dataset repo. Few questions were marked hard.\n  </li>\n</ol>\n<p>\nThe final set of 10 problems was a subset of this curated dataset and primarily consisted of questions for which the model either failed to generate the correct answer or ran out of allocated solving time.\n</p>\n<p>\nThe objective was not to continuously expand the benchmark dataset, but rather to evaluate the model’s behavior and limitations on a carefully curated set of difficult problems.\n</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 3458097,
      "author_name": "Preet",
      "author_url": "",
      "post_date": "2026-05-15T05:04:32.700000",
      "content": "<p>Hello <a href=\"https://www.kaggle.com/sambealing\" target=\"_blank\">@sambealing</a>,</p>\n<p>I see that Philip have tagged you for questions but I do not see any questions from you I'd be happy to answer any questions that you might have.</p>\n<p>Sincerely,\nHarpreet</p>",
      "votes": 0,
      "replies": [
        {
          "id": 3458324,
          "author_name": "Sam Bealing",
          "author_url": "",
          "post_date": "2026-05-15T16:16:01.643000",
          "content": "<p>Just posted questions. I'm not as quick as Philip getting all my questions written 😉</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 3457841,
      "author_name": "Philip Vonderlind",
      "author_url": "",
      "post_date": "2026-05-14T13:04:47.323000",
      "content": "<p>Hi, thank you for your submission to the Writeup Prize. <a href=\"https://www.kaggle.com/sambealing\" target=\"_blank\">@sambealing</a> and I will post a few questions below to help us assess your submission more closely, as described in the <a href=\"https://www.kaggle.com/competitions/ai-mathematical-olympiad-progress-prize-3/discussion/689703\" target=\"_blank\">updated discussion post</a>.</p>\n<ol>\n<li><p><strong>Formatting</strong>: The formatting of this post may have become distorted when copied from your project write-up. If possible, please fix it going forward, since we cannot refer to the old copy.</p></li>\n<li><p><strong>Attention Backend</strong>: I noticed that you ran several ablations on the serving setup. However, it seems that two concepts may have been mixed together: GPU kernels, such as Marlin or Triton, and inference engines, such as vLLM or TensorRT-LLM. Could you clarify what exactly was tested? For example, was it <code>vLLM + Triton kernel</code>, <code>vLLM + Marlin kernel</code>, or another configuration? Additionally, why did you not test <a href=\"https://github.com/dao-ailab/flash-attention\" target=\"_blank\">FlashAttention kernels</a>, which are often faster in practice than Triton and are directly supported in vLLM?</p></li>\n<li><p><strong>Architecture Details</strong>: A core contribution of your work appears to be the buffer-borrowing and step-back components introduced in Sections <code>4.4</code> and <code>4.5</code> of the PDF, respectively. However, these components are currently described only at a high level. Could you add a more detailed explanation of how they work, what issues they are intended to address, and what motivated their design?</p></li>\n</ol>\n<p>Looking forward to your response :)</p>",
      "votes": 0,
      "replies": [
        {
          "id": 3457960,
          "author_name": "Preet",
          "author_url": "",
          "post_date": "2026-05-14T17:32:24.490000",
          "content": "<p>Hi Philip,</p>\n<p>Thank you for your questions. Could you please tell me if I have to provide answers directly here or in the pdf.</p>\n<p>Sincerely!</p>",
          "votes": 0,
          "replies": [
            {
              "id": 3458322,
              "author_name": "Sam Bealing",
              "author_url": "",
              "post_date": "2026-05-15T16:14:35.790000",
              "content": "<p>Please could you answer the questions here for visibility. If you are also able to update your write up, then that is also helpful so everything is in one place. Please read <a href=\"https://www.kaggle.com/competitions/ai-mathematical-olympiad-progress-prize-3/discussion/699061\" target=\"_blank\">Frieder's comments</a> about edits before doing this.</p>",
              "votes": 0,
              "replies": []
            }
          ]
        },
        {
          "id": 3458705,
          "author_name": "Preet",
          "author_url": "",
          "post_date": "2026-05-16T13:17:56.983000",
          "content": "<h1>Question 1</h1>\n<p>Formatting - I fixed it. Thank you for pointing it out.\n  <strong>Side Note</strong>: The overall system design could not be clearly included in the PDF because the diagram became too small. Therefore, the flow diagram has been attached separately so it can be zoomed in and viewed properly.\nThis was already part of the original writeup — just highlighting it here in case it was overlooked.</p>\n<h1>Question 2</h1>\n<p>\nYes, several backend-level ablations and experiments were conducted.\n</p>\n<h3>1. Inference Engine Experiments</h3>\n<p>\nOne major component of the backend was the inference engine itself. Few inference frameworks were evaluated:\n</p>\n<ul>\n   <li>\n       <strong>vLLM (v0.10.1 + GPT-OSS)</strong><br>\n       This configuration was recommended in the official model card. Tried using this in the hope this will give maximum performance. However, it depended on an older PyTorch nightly version that was not available under the PyTorch repo that hosts different pytorch release versions\n   </li>\n   <li>\n       <strong>TensorRT-LLM</strong><br>\n<p>\nInitial experiments with TensorRT-LLM. This could be easily implemented using docker but in Kaggle environment docker could not be used. I tried to implement workaround but I faced challenges while implementing the workaround. I finally did not pursue this route when I faced datatype mismatch issues with gpt-oss and tensorrt-llm framework</p>\n<p>\nThe issue may or may not be fixable, since TensorRT-LLM generally works well with many large models. I spent some time attempting to make it work, but due to competition time constraints, I decided not to pursue this direction further.\nIt may still be possible to get GPT-OSS running successfully with additional engineering effort since gpt-oss work with tensorrt installed using docker\n</p>\n   </li>\n   <li>\n       <strong>sglang</strong><br>\n       sglang was also evaluated as part of the backend experimentation process. And performance that I got with some basic knobs of sglang-0.5.8 was not as good as vllm-0.11.2. That does not mean sglang is not good enough. It just means other sglang parameters or the newer versions of sglang and vllm needs to be experimented with to provide any conclusive answer.\nBelow parameters of sglang were used:\n'--num_gpus', '1',\n       '--max-running-requests', '8',\n       '--mem-fraction-static', '0.90',\n       '--dtype', 'auto',\n       '--context-length', '49000',\n       '--random-seed', '1',\n       '--kv-cache-dtype','fp8_e4m3',\n       '--chunked-prefill-size', '32000',\n        '--cuda-graph-max-bs','16',\n       '--trust-remote-code',\n   </li>\n</ul>\n<h3>2. CUDA Kernel-Level Backend Components</h3>\n<p>\nAnother important backend component involved the CUDA kernels used internally within the transformer architecture.\n</p>\n<p>\nIf you inspect the runtime logs, you will notice that. This is a snippet from vllm logs\n</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1563363%2F6263e95693f01da4278972702d1e1a19%2Fmarlin%20backend.png?generation=1778940390118017&amp;alt=media\" alt=\"\"></p>\n<ul>\n   <li><code>Using FLASH_ATTN</code></li>\n   <li><code>Using Marlin Backend</code></li>\n</ul>\n<p>\nTo clarify, my submitted code does use FLASH Attention. However flash and marlin correspond to different optimized CUDA kernels and execution backends used for accelerating transformer operations such as attention layers, matrix multiplications, and quantized inference workloads.\n</p>\n<ul>\n   <li>\n       <strong>Marlin Backend</strong> → Optimizes quantized matrix multiplication workloads.\n   </li>\n   <li>\n       <strong>FLASH Attention</strong> → Optimizes transformer attention computation.\n   </li>\n</ul>\n<p>\nPlease refer the architecture below to understand where each of them is used. The parts of the transformer where Marlin and Flash are used is given below\n</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1563363%2Fecf0d43f2f65690e43c6af0365fb1801%2Fgpt_oss_120b_layer_with_kernels.svg?generation=1778938778997700&amp;alt=media\" alt=\"\"></p>\n<h3>a) GEMM Backend Experiment </h3>\n<p>Marlin performed better than Triton in this setup.\nThis is what was indicated in the table that I added to section 5.2 and Figure 6.</p>\n<h3>b) Attention Backend Experiments - FLASH, FLASHINFER, TRITON, FLEX</h3>\n<p>\nFor the attention component of the transformer, one of the research papers indicated that GPT-OSS-120B could operate using four different attention backends.\n</p>\n<p>\nAt the time I conducted these experiments, I had not yet seen the research you shared regarding FLASH Attention outperforming Triton. Nevertheless, it was still valuable to experimentally validate which backend performed best for this specific inference pipeline and use case.\n</p>\n<p>\nThe following attention backends were evaluated:\n</p>\n<ol>\n   <li><strong>FLASH</strong></li>\n   <li><strong>TRITON</strong></li>\n   <li>\n       <strong>FLEX</strong><br>\n       Could not be used because this attention type did not support the sink-token setting.\n   </li>\n   <li>\n       <strong>FLASHINFER</strong><br>\n       Could not be used because this attention type did not support the sink-token setting.\n   </li>\n</ol>\n<p>\n<strong>Key Observation:</strong><br>\nFLASH Attention outperformed Triton in my experiments. The remaining two attention types were ultimately not usable due to lack of support for sink-token configuration.\n</p>\n<p>\nI missed including this information in my original write-up, so thank you for asking the question. It gave me an opportunity to clarify these backend-level experiments and observations.\n</p>\n<hr>\n<h3>Explanation of Sink Tokens</h3>\n<p>\nUnder normal transformer behavior, each token primarily attends to semantically relevant tokens within the sequence.\n</p>\n<p>\nHowever, in practice, certain tokens tend to attract disproportionately high attention from many other tokens. These are commonly referred to as <strong>sink tokens</strong>.\n</p>\n<p>\nExamples of sink tokens can include:\n</p>\n<ul>\n   <li>initial tokens in long reasoning sequences,</li>\n   <li>newline tokens,</li>\n   <li>padding tokens,</li>\n   <li>BOS (Beginning of Sequence) tokens,</li>\n   <li>and special separator tokens.</li>\n</ul>\n<p>\nSink tokens can sometimes improve:\n</p>\n<ul>\n   <li>optimization stability,</li>\n   <li>training convergence,</li>\n   <li>and long-context behavior.</li>\n</ul>\n<p>\nThe sink-token configuration was already built into the GPT-OSS model itself. I intentionally chose not to disable it while testing alternative attention backends because I was concerned that changing this behavior could negatively impact model performance and long-context stability.\n</p>\n<h1>Question 3</h1>\n<h3>Dynamic Time Pressure and Buffer Borrowing Strategy</h3>\n<p>\nThe following logic was used to dynamically estimate time pressure and determine how much additional buffer time could be allocated to a question during inference.\n</p>\n<ol>\n <li>\n   <h4>Time Pressure Computation (common for step-back and non-step-back approaches)</h4>\n\n   <p>\n     The <code>compute_time_pressure()</code> function estimated the current level of time pressure based on:\n   </p>\n   <ul>\n     <li>remaining competition time,</li>\n     <li>number of questions already completed,</li>\n     <li>and the ideal pacing required to finish all remaining questions.</li>\n   </ul>\n   <p>\n     The core idea was to compare:\n   </p>\n   <ul>\n     <li>the ideal pace (<code>total_available_time / total_questions</code>)</li>\n     <li>against the currently available pace (<code>remaining_time / remaining_questions</code>)</li>\n   </ul>\n   <p>\n     A pressure score was then computed as:\n   </p>\n   <ul>\n     <li>\n       <strong>Pressure &gt; 1</strong> → The system is behind schedule and must become more conservative with time allocation.\n     </li>\n     <li>\n       <strong>Pressure &lt; 1</strong> → The system has spare time available and can afford more flexible allocation.\n     </li>\n   </ul>\n   <p>\n     To avoid extreme instability, the final pressure value was clamped between:\n   </p>\n   <ul>\n     <li><code>0.3</code> (minimum pressure)</li>\n     <li><code>1.5</code> (maximum pressure)</li>\n   </ul>\n </li>\n <br>\n   <h4>Borrow Fraction Computation (Step-Back)</h4>\n   <p>\n     The <code>compute_borrow_fraction()</code> function determined what fraction of the global time buffer\n     could be borrowed for the current question. The borrowing decision depended on several factors:\n   </p>\n   <ul>\n     <li>actual step-back execution time</li>\n     <li>allocated step-back time budget</li>\n   </ul>\n   <p>\n     <strong>Time Ratio (<code>c_ratio</code>)</strong><br>\n     Measures how much of the allocated Step-Back time budget was consumed.\n   </p>\n   <ul>\n     <li>step-back token usage</li>\n     <li>allocated token budget</li>\n   </ul>\n   <p>\n     <strong>Token Ratio (<code>s_ratio</code>)</strong><br>\n     Measures how much of the allocated Step-Back token budget was consumed.\n   </p>\n     <strong> Inverse of time pressure (Time pressure computation is given in the previous section)</strong>    <br>\n\n   <p>\n     <strong>Mathematical Logic:</strong>\n   </p>\n   <p>\n     Two normalized ratios were first computed.\n     These two signals were then combined using a Euclidean-style formulation:\n   </p>\n   <pre>combined_signal = sqrt((c_ratio² + s_ratio²) / 2)\n   </pre>\n   <p>\n     This produced a unified measure representing overall computational intensity for the current problem.\n   </p>\n   <p>\n     The system then adjusted this value using the previously computed time-pressure signal:\n   </p>\n   <ul>\n     <li>Higher time pressure reduced the fraction of buffer that could be borrowed.</li>\n     <li>Lower time pressure allowed more aggressive borrowing from the global buffer.</li>\n   </ul>\n   <p>\n     Finally, the computed borrow fraction was constrained within predefined limits:\n   </p>\n   <ul>\n     <li>minimum allowed borrow fraction = <code>0.0</code></li>\n     <li>maximum allowed borrow fraction = <code>b_max</code></li>\n   </ul>\n \n<li>\n   <h4>Borrow Fraction Computation (Non- Step-Back)</h4>\n    This was simply inverse of time pressure in case of Non-Step Back\n</li>\n</ol>\n<p>def compute_time_pressure(\n       self,\n       remaining_time: float,\n       questions_completed: int,\n    ) -&gt; float:\n        remaining_q = max(1, self.total_questions - questions_completed)\n        if remaining_time &lt;= 0:\n            return 1.5\n        ideal_pace = self.total_available_time / self.total_questions\n        available_pace = remaining_time / remaining_q\n        pressure = ideal_pace / available_pace\n        return max(0.3, min(1.5, pressure))\n   def compute_borrow_fraction(\n       self,\n       remaining_time: float,\n       questions_completed: int,\n       stepback_time: float,\n       stepback_time_budget: float,\n       stepback_tokens: int,\n       stepback_tokens_budget: int,\n       global_buffer: float = 0.0,\n     ) -&gt; float:\n       \"\"\"\n       Compute what fraction of the buffer to borrow.\n       Returns\n       -------\n       float\n           Borrow fraction in [0, b_max].\n       \"\"\"</p>\n<pre><code>   c_ratio = min(1.0, stepback_time / stepback_time_budget) if stepback_time &gt; 0 else 0.5\n   s_ratio = stepback_tokens / stepback_tokens_budget if stepback_tokens &gt; 0 else 0.0\n   combined_signal = math.sqrt((c_ratio ** 2 + s_ratio ** 2) / 2)\n   sigmoid_out = self._sigmoid(combined_signal)\n   pressure = self.compute_time_pressure(remaining_time, questions_completed)\n   pressure_mult = 1.0 / pressure\n   borrow_fraction = self.b_max * combined_signal * pressure_mult\n   borrow_fraction = max(0.0, min(self.b_max, borrow_fraction))\n</code></pre>\n<ul>\n<li>Time Allocation per question. Better Accuracy- Using same model in two different phases could result in more accurate answer (hypothesis)</li>\n</ul>\n<h3>Use of StepBack Technique</h3>\n<p>:-</p>\n<h5> Issues trying to address</h5>\n<ul>\n<li>\nThis helped in making informed decision about how much time to allocate to solve the question. The time allocation per question was not based on prior questions but based on more concrete information about the question itself\n<br><br><br>\nHypothesis - Getting to know domain of the problem or techniques used to solve the problem will nudge the model towards a more accurate answer</li>\n</ul>\n<h5> Motivation </h5>\n<p>– Much of work in the field of Artificial Intelligence and Machine Learning is inspired from how humans function. Neural network corresponds to the neurons in the brain. “Attention is all you need” is how our brains process lengthy information. Therefore, my rationale was that if us humans get guidance then we perform a task better so the llm model can behave similarly. \n<br><br>\nFurther, the principles identified during stepback phase 1 formed the basis of dynamic prompting. Prompting based on domains and techniques used would in my opinion result in better outcomes and I wanted to try this further. However, phase 1 took away from the total time to solve the problem. Therefore, this approach had to be discarded.</p>\n<h3>Additional Contributions Highlighted in the Revision</h3>\n<p>\nIn addition, I would like to highlight three further contributions and observations that were either underemphasized in the original write-up or significantly strengthened through post-submission experiments.\n</p>\n<hr>\n<h4>1. CUDA Graph Capture Size Optimization</h4>\n<p>\nvLLM generates CUDA graphs for two distinct execution phases:\n</p>\n<ul>\n   <li><strong>Mixed Prefill + Decode</strong></li>\n   <li><strong>Pure Decode</strong></li>\n</ul>\n<p>\nThese two phases exhibit very different shape distributions.\n</p>\n<p>\nThe mixed prefill+decode phase experiences progressively increasing input lengths due to:\n</p>\n<ul>\n   <li>Python tool calls,</li>\n   <li>multi-turn conversational context,</li>\n   <li>and dynamically growing reasoning traces.</li>\n</ul>\n<p>\nIn contrast, the pure decode phase typically generates one token at a time and therefore operates under a very different execution profile.\n</p>\n<p>\nTable  in Section 5.2 already includes an initial ablation study on graph capture sizing. After submission, I conducted additional experiments to support a hypothesis I had originally held on intuition alone — one I did not assert in version 1 of the write-up due to the lack of data i.e .</p>\n<ul>\n   <li>capturing the <em>correct</em> graph sizes improves throughput,</li>\n   <li>and omitting unnecessary graph captures also contributes to better runtime efficiency.</li>\n</ul>\n<p><strong> If graph_size was equal to the max-num-seqs parameter passed to vllm inference server then throughput increased atleast by 65%. This maybe due to decode graph matching the number of sequences</strong></p>\n<h4>2. Streaming Output vs. Non-Streaming Generation</h4>\n<p>\nAnother implementation detail omitted from the original write-up: the pipeline uses streaming responses rather than single-shot generation.  Non Streaming Responses resulted in frequent read timeout and connection timeout issues\n<br>\nThis was part of the work that went into building the pipeline, but I forgot to mention it\n</p>\n<p>\nDuring experimentation, non-streaming inference frequently resulted in:\n</p>\n<ul>\n   <li>read timeouts,</li>\n   <li>connection timeouts,</li>\n   <li>and instability during multi-turn tool usage.</li>\n</ul>\n<p>\nSwitching to streaming-based generation resolved these issues and significantly improved runtime stability.\n</p>\n<h4>3. State-of-the-Art (SOTA) Comparison</h4>\n<p>\nThe revised evaluation now includes additional comparisons against:\n</p>\n<ul>\n   <li><strong>Qwen</strong> (without tool calling),</li>\n   <li><strong>Gemini Pro 3.1</strong>,</li>\n</ul>\n<p>\nOne particularly interesting observation was that Gemini Pro 3.1 and Claude Opus 4.7 appear to be highly complementary systems.\n</p>\n<p>\nTogether, the two models successfully solved every question in my curated evaluation dataset at pass@1.\n</p>\n<p>However, Claude demonstrated stronger mathematical reasoning than Gemini 3.1 Pro, especially on difficult mathematical problems. While both models solved easier problems reliably and on harder problems, each model solved cases that the other failed to solve.\n</p>\n<p><br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1563363%2Fb1266b4ed3af90b5d6cbab51f7c2df76%2Fperformance_comparison_updated_2.png?generation=1779036696326203&amp;alt=media\" alt=\"\"></p>",
          "votes": 0,
          "replies": []
        }
      ]
    }
  ],
  "comment_count": 9,
  "messages": [
    {
      "id": 3459320,
      "postDate": "2026-05-17T16:48:53.103Z",
      "content": "<blockquote>\n  <h3>The final pdf is updated. Please do the refer the writeup here. I did fix few sections here on the writeup but formatting here is much tougher than in a word document. This writeup does not contain the full list of edits only the pdf does. So please check the v2 pdf attached to this writeup section. The edits are mentioned on page 1 and against the sections also. Just to save time - all the edits in the pdf except \"sections  5.2 Added Note, 8(last point),12 (Prompt Appendix)\" are already part of the replies that I gave to you both below. So those edits do not provide any new information\n  <br><br>\n  Huggingface repo is also updated</h3>\n</blockquote>",
      "rawMarkdown": "><h3>The final pdf is updated. Please do the refer the writeup here. I did fix few sections here on the writeup but formatting here is much tougher than in a word document. This writeup does not contain the full list of edits only the pdf does. So please check the v2 pdf attached to this writeup section. The edits are mentioned on page 1 and against the sections also. Just to save time - all the edits in the pdf except \"sections  5.2 Added Note, 8(last point),12 (Prompt Appendix)\" are already part of the replies that I gave to you both below. So those edits do not provide any new information\n<br><br>\nHuggingface repo is also updated</h3>"
    },
    {
      "id": 3458323,
      "postDate": "2026-05-15T16:15:36.507Z",
      "content": "<p>Following up on the questions from <a href=\"https://www.kaggle.com/philipvonderlind\" target=\"_blank\">@philipvonderlind</a>, here are some additional questions to help us assess your submission:</p>\n<ol>\n<li><strong>Global time buffer mechanics:</strong> The writeup mentions a global buffer of 350 seconds that's dynamically updated and allows time borrowing from future problems. Could you describe in more detail how the borrowing logic decides when to lend time vs hold it back, and what safeguards prevent the run from running out of time on later problems (particularly if the harder problems happen to fall near the end of the run)?</li>\n<li><strong>Step-back removal vs token budget:</strong> The 18→24 improvement bundles Step-Back removal and a token budget doubling. You explicitly note that you can't isolate their individual contributions, but from development you presumably have some intuition. Informally, which of the two felt like the larger contributor?</li>\n<li><strong>Internal benchmark construction and answer accuracy:</strong> Beyond the AIMO reference set, you reference an internal benchmark and a 10-problem failing subset used during development. Could you describe how you collected and curated these (sources, filtering criteria), and what steps you took to verify the ground-truth answers? Across the maths corpus prize submissions we've reviewed, even widely-used datasets often contain ground-truth errors that can quietly distort ablation conclusions.</li>\n</ol>\n<p>Look forward to reading your responses on these.</p>",
      "rawMarkdown": "Following up on the questions from @philipvonderlind, here are some additional questions to help us assess your submission:\n\n1. **Global time buffer mechanics:** The writeup mentions a global buffer of 350 seconds that's dynamically updated and allows time borrowing from future problems. Could you describe in more detail how the borrowing logic decides when to lend time vs hold it back, and what safeguards prevent the run from running out of time on later problems (particularly if the harder problems happen to fall near the end of the run)?\n2. **Step-back removal vs token budget:** The 18→24 improvement bundles Step-Back removal and a token budget doubling. You explicitly note that you can't isolate their individual contributions, but from development you presumably have some intuition. Informally, which of the two felt like the larger contributor?\n3. **Internal benchmark construction and answer accuracy:** Beyond the AIMO reference set, you reference an internal benchmark and a 10-problem failing subset used during development. Could you describe how you collected and curated these (sources, filtering criteria), and what steps you took to verify the ground-truth answers? Across the maths corpus prize submissions we've reviewed, even widely-used datasets often contain ground-truth errors that can quietly distort ablation conclusions.\n\nLook forward to reading your responses on these.\n",
      "replies": [
        {
          "id": 3458701,
          "postDate": "2026-05-16T13:13:15.077Z",
          "content": "<h1>Question 1 - Global time buffer mechanics:</h1>\n<p><strong>Context Setting</strong></p>\n<h3>Step-Back Approach</h3>\n<p>\nPhase 1 - For the Step-Back approach, three time buckets were defined based on the estimated difficulty level of the problem. Considering the total competition time available, the average time allocated per question could not realistically exceed approximately 320–340 seconds.\n</p>\n<p>\nFrom this baseline allocation, the additional time required for the Step-Back phase was subtracted. The Step-Back phase refers to an initial pass where the model is asked only to:\n</p>\n<ul>\n  <li>identify the difficulty level of the problem,</li>\n  <li>determine the techniques likely required to solve it,</li>\n  <li>and classify the problem domain.</li>\n</ul>\n<p>\nBased on the difficulty level predicted by the model, a corresponding baseline time budget was assigned. Each problem could receive time from only one of predefined categories, as shown in the corresponding if-else logic.\n</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1563363%2F2426fefee5f859d596c369fa59066f4f%2Fif-else.png?generation=1778937574722126&amp;alt=media\" alt=\"\"></p>\n<p>\nOnce the stepback approach is completed, the time-counter indicates how much time was consumed. And this time is subtracted from the baseline time (one of the 3 categories defined above) and a fraction of the global buffer was added to get the net effective inference time (<code>baseline - stepback_time + fraction_of_buffer</code>). (How to compute fraction which gets multiplied with global buffer is indicated in my answer to Philip's question -please refer that)\n</p>\n<p><br>\nAlso a dynamic prompt was chosen based on phase 1 (domain and techniques required to solve the problem)\n<br></p>\n<p>\nPhase 2 - The effective inference time and dynamic prompt was passed onto this phase of the problem solving where actual answer was produced\n(StepBack Time and tokens were capped to a maximum so that it does not eat into problem solving time)\n</p>\n<p>Once the question is attempted the actual execution time is measured using time.perf_counter(). The measured time is then compared against the allocated budget:\n</p><p></p>\n<h3>Non-Step-Back Approach</h3>\n<p>\nThe overall philosophy remained similar, but the implementation was intentionally simplified.\n</p>\n<p>\nAIMO3 was expected to contain increasingly difficult problems. In practice, distinguishing reliably between “hard,” “harder,” and “hardest” problems before fully attempting them proved difficult. Because of this, dynamically assigning substantially different budgets based on predicted difficulty was not considered reliable. \n<br>\n<br>\nInstead of categorizing problems by difficulty, a flat baseline of 320 seconds per question was used. \n<br>\nThe reasoning behind this decision was that harder problems did not necessarily benefit from significantly larger time allocations. Empirically, if the model was capable of solving a problem correctly, it typically did so within roughly the same time range.\n<br>\nAnyways the unused time would become part of the global buffer.\n</p>\n<p>\nAs with the Step-Back approach, the actual solving time for each question was also tracked using <code>time.perf_counter()</code> and compared against the allocated budget (<code>baseline + fraction_of_buffer</code>):\n</p>\n<p>The difference between this and Non-StepBack Approach was how the fraction of global buffer was calculated and how the baseline budget was determined - For Non-StepBack - flat 320 seconds were allocated as opposed to the 3 categories defined in stepback approach\n<br><br><br>\n<strong>Actual Answer of the question</strong></p>\n<h4>For Both StepBack and Non-StepBack Approach (Below is the actual answer to your question. Previous text provides contextual information)</h4>\n<ul>\n  <li>\n      If the model used less time than allocated, the remaining time was returned to the global buffer.\n  </li>\n  <li>\n      If the model exceeded the allocated budget, the excess time was deducted from the global buffer.\n  </li>\n</ul>\n<p>\nThe additional time assigned to a question was capped at the minimum of:\n<br>\n</p><ul>\n  <li>the calculated fraction of the available buffer, or</li>\n  <li>the predefined maximum allowed buffer cap.</li>\n</ul>\n<p></p>\n<p><strong>Since time per question and global buffer is checked on each question. Therefore, that prevents it from running out on later questions. This could also result in case where global buffer rans out. But if that happens then the addition time from the global buffer cannot be borrowed since it is 0 and the baseline time which is roughly approximate time per question would serve as a hard limit </strong>\n<strong>Detailed Explanation is given to Philip in the comments below to compute time pressure and global buffer borrowing in Answer 3</strong>\nSide Note: Different buffer caps were tested across the few submissions I made </p>\n<h1>Question 2 - Step-back removal vs token budget</h1>\n<p>\nI would like to clarify one point regarding the token budget. The token budget was not exactly doubled; rather, it was increased by approximately 22%.\n</p>\n<p>\nIn my view, the improvement in performance was likely driven more by the additional time available for solving each question than by the increase in token budget itself.\n</p>\n<p>\nFor reference, notebooks that scored in the 40s using the GPT-OSS model were operating with a context length of 65,536 tokens, and I used the same context length in my notebook that scored 18.\n</p>\n<p>\nLess time available per question was one of the reasons why the Step-Back approach was not used in later iterations. I had initial reservations about it but wanted to check if stepback phase resulted in quick convergence to answer compensating for the time consumed during phase 1 and also better accuracy.\n</p>\n<h1>Question 3 - Internal benchmark construction and answer accuracy</h1>\n<p>\nThese were actual problems taken from official IMO-style mathematics competitions. I handpicked the problems from both Hugging Face dataset repositories(this also had difficulty level assigned) and the official competition websites. None of the internal benchmark data was synthetically generated; therefore, the possibility of ground-truth labeling errors is close to 0\nSources Used\nMathArena (https://matharena.ai/apex/)\nAOPS\nARML2 &amp; ARML3\nHMMT\nIMO\n</p>\n<p>\nThe filtering criteria were based on two primary factors:\n</p>\n<ol>\n  <li>\n      From each of the four domains — Number Theory, Algebra, Combinatorics, and Geometry — an approximately equal number of questions was selected to ensure balanced evaluation coverage across all mathematical areas.\n  </li>\n   <li>\n      Since the AIMO3 competition overview explicitly indicated a focus on hard problems. I personally reviewed the problems to identify questions that were difficult even to begin reasoning about. I myself have participated in Mathematical Olympiad held in my country so I used my past knowledge to filter the questions.\nOther filtering criteria used was difficulty level given in the huggingface dataset repo. Few questions were marked hard.\n  </li>\n</ol>\n<p>\nThe final set of 10 problems was a subset of this curated dataset and primarily consisted of questions for which the model either failed to generate the correct answer or ran out of allocated solving time.\n</p>\n<p>\nThe objective was not to continuously expand the benchmark dataset, but rather to evaluate the model’s behavior and limitations on a carefully curated set of difficult problems.\n</p>",
          "rawMarkdown": "\n\n<h1>Question 1 - Global time buffer mechanics:</h1>\n**Context Setting**\n<h3>Step-Back Approach</h3>\n\n<p>\nPhase 1 - For the Step-Back approach, three time buckets were defined based on the estimated difficulty level of the problem. Considering the total competition time available, the average time allocated per question could not realistically exceed approximately 320–340 seconds.\n</p>\n\n<p>\nFrom this baseline allocation, the additional time required for the Step-Back phase was subtracted. The Step-Back phase refers to an initial pass where the model is asked only to:\n</p>\n\n<ul>\n    <li>identify the difficulty level of the problem,</li>\n    <li>determine the techniques likely required to solve it,</li>\n    <li>and classify the problem domain.</li>\n</ul>\n\n<p>\nBased on the difficulty level predicted by the model, a corresponding baseline time budget was assigned. Each problem could receive time from only one of predefined categories, as shown in the corresponding if-else logic.\n</p>\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1563363%2F2426fefee5f859d596c369fa59066f4f%2Fif-else.png?generation=1778937574722126&alt=media)\n\n<p>\nOnce the stepback approach is completed, the time-counter indicates how much time was consumed. And this time is subtracted from the baseline time (one of the 3 categories defined above) and a fraction of the global buffer was added to get the net effective inference time (<code>baseline - stepback_time + fraction_of_buffer</code>). (How to compute fraction which gets multiplied with global buffer is indicated in my answer to Philip's question -please refer that)\n</p>\n\n<br>\nAlso a dynamic prompt was chosen based on phase 1 (domain and techniques required to solve the problem)\n<br>\n<p>\nPhase 2 - The effective inference time and dynamic prompt was passed onto this phase of the problem solving where actual answer was produced\n(StepBack Time and tokens were capped to a maximum so that it does not eat into problem solving time)\n</p>\n\nOnce the question is attempted the actual execution time is measured using time.perf_counter(). The measured time is then compared against the allocated budget:\n</p>\n\n\n\n<h3>Non-Step-Back Approach</h3>\n\n<p>\nThe overall philosophy remained similar, but the implementation was intentionally simplified.\n</p>\n\n\n<p>\n AIMO3 was expected to contain increasingly difficult problems. In practice, distinguishing reliably between “hard,” “harder,” and “hardest” problems before fully attempting them proved difficult. Because of this, dynamically assigning substantially different budgets based on predicted difficulty was not considered reliable. \n<br>\n<br>\nInstead of categorizing problems by difficulty, a flat baseline of 320 seconds per question was used. \n\n<br>\nThe reasoning behind this decision was that harder problems did not necessarily benefit from significantly larger time allocations. Empirically, if the model was capable of solving a problem correctly, it typically did so within roughly the same time range.\n\n<br>\nAnyways the unused time would become part of the global buffer.\n</p>\n\n<p>\nAs with the Step-Back approach, the actual solving time for each question was also tracked using <code>time.perf_counter()</code> and compared against the allocated budget (<code>baseline + fraction_of_buffer</code>):\n</p>\n\nThe difference between this and Non-StepBack Approach was how the fraction of global buffer was calculated and how the baseline budget was determined - For Non-StepBack - flat 320 seconds were allocated as opposed to the 3 categories defined in stepback approach\n<br><br><br>\n**Actual Answer of the question**\n\n<h4>For Both StepBack and Non-StepBack Approach (Below is the actual answer to your question. Previous text provides contextual information)</h4>\n<ul>\n    <li>\n        If the model used less time than allocated, the remaining time was returned to the global buffer.\n    </li>\n    <li>\n        If the model exceeded the allocated budget, the excess time was deducted from the global buffer.\n    </li>\n</ul>\n\n\n<p>\nThe additional time assigned to a question was capped at the minimum of:\n<br>\n<ul>\n    <li>the calculated fraction of the available buffer, or</li>\n    <li>the predefined maximum allowed buffer cap.</li>\n</ul>\n</p>\n\n\n<strong>Since time per question and global buffer is checked on each question. Therefore, that prevents it from running out on later questions. This could also result in case where global buffer rans out. But if that happens then the addition time from the global buffer cannot be borrowed since it is 0 and the baseline time which is roughly approximate time per question would serve as a hard limit </strong>\n\n**Detailed Explanation is given to Philip in the comments below to compute time pressure and global buffer borrowing in Answer 3**\n \n\nSide Note: Different buffer caps were tested across the few submissions I made \n\n<h1>Question 2 - Step-back removal vs token budget</h1>\n<p>\nI would like to clarify one point regarding the token budget. The token budget was not exactly doubled; rather, it was increased by approximately 22%.\n</p>\n\n<p>\nIn my view, the improvement in performance was likely driven more by the additional time available for solving each question than by the increase in token budget itself.\n</p>\n\n<p>\nFor reference, notebooks that scored in the 40s using the GPT-OSS model were operating with a context length of 65,536 tokens, and I used the same context length in my notebook that scored 18.\n</p>\n\n<p>\nLess time available per question was one of the reasons why the Step-Back approach was not used in later iterations. I had initial reservations about it but wanted to check if stepback phase resulted in quick convergence to answer compensating for the time consumed during phase 1 and also better accuracy.\n</p>\n\n<h1>Question 3 - Internal benchmark construction and answer accuracy</h1>\n<p>\nThese were actual problems taken from official IMO-style mathematics competitions. I handpicked the problems from both Hugging Face dataset repositories(this also had difficulty level assigned) and the official competition websites. None of the internal benchmark data was synthetically generated; therefore, the possibility of ground-truth labeling errors is close to 0\nSources Used\nMathArena (https://matharena.ai/apex/)\nAOPS\nARML2 & ARML3\nHMMT\nIMO\n\n</p>\n\n<p>\nThe filtering criteria were based on two primary factors:\n</p>\n\n<ol>\n    <li>\n        From each of the four domains — Number Theory, Algebra, Combinatorics, and Geometry — an approximately equal number of questions was selected to ensure balanced evaluation coverage across all mathematical areas.\n    </li>\n\n    <li>\n        Since the AIMO3 competition overview explicitly indicated a focus on hard problems. I personally reviewed the problems to identify questions that were difficult even to begin reasoning about. I myself have participated in Mathematical Olympiad held in my country so I used my past knowledge to filter the questions.\n\nOther filtering criteria used was difficulty level given in the huggingface dataset repo. Few questions were marked hard.\n    </li>\n</ol>\n\n<p>\nThe final set of 10 problems was a subset of this curated dataset and primarily consisted of questions for which the model either failed to generate the correct answer or ran out of allocated solving time.\n</p>\n\n<p>\nThe objective was not to continuously expand the benchmark dataset, but rather to evaluate the model’s behavior and limitations on a carefully curated set of difficult problems.\n</p>"
        }
      ]
    },
    {
      "id": 3458097,
      "postDate": "2026-05-15T05:04:32.700Z",
      "content": "<p>Hello <a href=\"https://www.kaggle.com/sambealing\" target=\"_blank\">@sambealing</a>,</p>\n<p>I see that Philip have tagged you for questions but I do not see any questions from you I'd be happy to answer any questions that you might have.</p>\n<p>Sincerely,\nHarpreet</p>",
      "rawMarkdown": "Hello @sambealing,\n\n I see that Philip have tagged you for questions but I do not see any questions from you I'd be happy to answer any questions that you might have.\n\nSincerely,\nHarpreet",
      "replies": [
        {
          "id": 3458324,
          "postDate": "2026-05-15T16:16:01.643Z",
          "content": "<p>Just posted questions. I'm not as quick as Philip getting all my questions written 😉</p>",
          "rawMarkdown": "Just posted questions. I'm not as quick as Philip getting all my questions written 😉"
        }
      ]
    },
    {
      "id": 3457841,
      "postDate": "2026-05-14T13:04:47.323Z",
      "content": "<p>Hi, thank you for your submission to the Writeup Prize. <a href=\"https://www.kaggle.com/sambealing\" target=\"_blank\">@sambealing</a> and I will post a few questions below to help us assess your submission more closely, as described in the <a href=\"https://www.kaggle.com/competitions/ai-mathematical-olympiad-progress-prize-3/discussion/689703\" target=\"_blank\">updated discussion post</a>.</p>\n<ol>\n<li><p><strong>Formatting</strong>: The formatting of this post may have become distorted when copied from your project write-up. If possible, please fix it going forward, since we cannot refer to the old copy.</p></li>\n<li><p><strong>Attention Backend</strong>: I noticed that you ran several ablations on the serving setup. However, it seems that two concepts may have been mixed together: GPU kernels, such as Marlin or Triton, and inference engines, such as vLLM or TensorRT-LLM. Could you clarify what exactly was tested? For example, was it <code>vLLM + Triton kernel</code>, <code>vLLM + Marlin kernel</code>, or another configuration? Additionally, why did you not test <a href=\"https://github.com/dao-ailab/flash-attention\" target=\"_blank\">FlashAttention kernels</a>, which are often faster in practice than Triton and are directly supported in vLLM?</p></li>\n<li><p><strong>Architecture Details</strong>: A core contribution of your work appears to be the buffer-borrowing and step-back components introduced in Sections <code>4.4</code> and <code>4.5</code> of the PDF, respectively. However, these components are currently described only at a high level. Could you add a more detailed explanation of how they work, what issues they are intended to address, and what motivated their design?</p></li>\n</ol>\n<p>Looking forward to your response :)</p>",
      "rawMarkdown": "Hi, thank you for your submission to the Writeup Prize. @sambealing and I will post a few questions below to help us assess your submission more closely, as described in the [updated discussion post](https://www.kaggle.com/competitions/ai-mathematical-olympiad-progress-prize-3/discussion/689703).\n\n1. **Formatting**: The formatting of this post may have become distorted when copied from your project write-up. If possible, please fix it going forward, since we cannot refer to the old copy.\n\n2. **Attention Backend**: I noticed that you ran several ablations on the serving setup. However, it seems that two concepts may have been mixed together: GPU kernels, such as Marlin or Triton, and inference engines, such as vLLM or TensorRT-LLM. Could you clarify what exactly was tested? For example, was it `vLLM + Triton kernel`, `vLLM + Marlin kernel`, or another configuration? Additionally, why did you not test [FlashAttention kernels](https://github.com/dao-ailab/flash-attention), which are often faster in practice than Triton and are directly supported in vLLM?\n\n3. **Architecture Details**: A core contribution of your work appears to be the buffer-borrowing and step-back components introduced in Sections `4.4` and `4.5` of the PDF, respectively. However, these components are currently described only at a high level. Could you add a more detailed explanation of how they work, what issues they are intended to address, and what motivated their design?\n\nLooking forward to your response :)",
      "replies": [
        {
          "id": 3457960,
          "postDate": "2026-05-14T17:32:24.490Z",
          "content": "<p>Hi Philip,</p>\n<p>Thank you for your questions. Could you please tell me if I have to provide answers directly here or in the pdf.</p>\n<p>Sincerely!</p>",
          "rawMarkdown": "Hi Philip,\n\nThank you for your questions. Could you please tell me if I have to provide answers directly here or in the pdf.\n\nSincerely!",
          "replies": [
            {
              "id": 3458322,
              "postDate": "2026-05-15T16:14:35.790Z",
              "content": "<p>Please could you answer the questions here for visibility. If you are also able to update your write up, then that is also helpful so everything is in one place. Please read <a href=\"https://www.kaggle.com/competitions/ai-mathematical-olympiad-progress-prize-3/discussion/699061\" target=\"_blank\">Frieder's comments</a> about edits before doing this.</p>",
              "rawMarkdown": "Please could you answer the questions here for visibility. If you are also able to update your write up, then that is also helpful so everything is in one place. Please read [Frieder's comments](https://www.kaggle.com/competitions/ai-mathematical-olympiad-progress-prize-3/discussion/699061) about edits before doing this."
            }
          ]
        },
        {
          "id": 3458705,
          "postDate": "2026-05-16T13:17:56.983Z",
          "content": "<h1>Question 1</h1>\n<p>Formatting - I fixed it. Thank you for pointing it out.\n  <strong>Side Note</strong>: The overall system design could not be clearly included in the PDF because the diagram became too small. Therefore, the flow diagram has been attached separately so it can be zoomed in and viewed properly.\nThis was already part of the original writeup — just highlighting it here in case it was overlooked.</p>\n<h1>Question 2</h1>\n<p>\nYes, several backend-level ablations and experiments were conducted.\n</p>\n<h3>1. Inference Engine Experiments</h3>\n<p>\nOne major component of the backend was the inference engine itself. Few inference frameworks were evaluated:\n</p>\n<ul>\n   <li>\n       <strong>vLLM (v0.10.1 + GPT-OSS)</strong><br>\n       This configuration was recommended in the official model card. Tried using this in the hope this will give maximum performance. However, it depended on an older PyTorch nightly version that was not available under the PyTorch repo that hosts different pytorch release versions\n   </li>\n   <li>\n       <strong>TensorRT-LLM</strong><br>\n<p>\nInitial experiments with TensorRT-LLM. This could be easily implemented using docker but in Kaggle environment docker could not be used. I tried to implement workaround but I faced challenges while implementing the workaround. I finally did not pursue this route when I faced datatype mismatch issues with gpt-oss and tensorrt-llm framework</p>\n<p>\nThe issue may or may not be fixable, since TensorRT-LLM generally works well with many large models. I spent some time attempting to make it work, but due to competition time constraints, I decided not to pursue this direction further.\nIt may still be possible to get GPT-OSS running successfully with additional engineering effort since gpt-oss work with tensorrt installed using docker\n</p>\n   </li>\n   <li>\n       <strong>sglang</strong><br>\n       sglang was also evaluated as part of the backend experimentation process. And performance that I got with some basic knobs of sglang-0.5.8 was not as good as vllm-0.11.2. That does not mean sglang is not good enough. It just means other sglang parameters or the newer versions of sglang and vllm needs to be experimented with to provide any conclusive answer.\nBelow parameters of sglang were used:\n'--num_gpus', '1',\n       '--max-running-requests', '8',\n       '--mem-fraction-static', '0.90',\n       '--dtype', 'auto',\n       '--context-length', '49000',\n       '--random-seed', '1',\n       '--kv-cache-dtype','fp8_e4m3',\n       '--chunked-prefill-size', '32000',\n        '--cuda-graph-max-bs','16',\n       '--trust-remote-code',\n   </li>\n</ul>\n<h3>2. CUDA Kernel-Level Backend Components</h3>\n<p>\nAnother important backend component involved the CUDA kernels used internally within the transformer architecture.\n</p>\n<p>\nIf you inspect the runtime logs, you will notice that. This is a snippet from vllm logs\n</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1563363%2F6263e95693f01da4278972702d1e1a19%2Fmarlin%20backend.png?generation=1778940390118017&amp;alt=media\" alt=\"\"></p>\n<ul>\n   <li><code>Using FLASH_ATTN</code></li>\n   <li><code>Using Marlin Backend</code></li>\n</ul>\n<p>\nTo clarify, my submitted code does use FLASH Attention. However flash and marlin correspond to different optimized CUDA kernels and execution backends used for accelerating transformer operations such as attention layers, matrix multiplications, and quantized inference workloads.\n</p>\n<ul>\n   <li>\n       <strong>Marlin Backend</strong> → Optimizes quantized matrix multiplication workloads.\n   </li>\n   <li>\n       <strong>FLASH Attention</strong> → Optimizes transformer attention computation.\n   </li>\n</ul>\n<p>\nPlease refer the architecture below to understand where each of them is used. The parts of the transformer where Marlin and Flash are used is given below\n</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1563363%2Fecf0d43f2f65690e43c6af0365fb1801%2Fgpt_oss_120b_layer_with_kernels.svg?generation=1778938778997700&amp;alt=media\" alt=\"\"></p>\n<h3>a) GEMM Backend Experiment </h3>\n<p>Marlin performed better than Triton in this setup.\nThis is what was indicated in the table that I added to section 5.2 and Figure 6.</p>\n<h3>b) Attention Backend Experiments - FLASH, FLASHINFER, TRITON, FLEX</h3>\n<p>\nFor the attention component of the transformer, one of the research papers indicated that GPT-OSS-120B could operate using four different attention backends.\n</p>\n<p>\nAt the time I conducted these experiments, I had not yet seen the research you shared regarding FLASH Attention outperforming Triton. Nevertheless, it was still valuable to experimentally validate which backend performed best for this specific inference pipeline and use case.\n</p>\n<p>\nThe following attention backends were evaluated:\n</p>\n<ol>\n   <li><strong>FLASH</strong></li>\n   <li><strong>TRITON</strong></li>\n   <li>\n       <strong>FLEX</strong><br>\n       Could not be used because this attention type did not support the sink-token setting.\n   </li>\n   <li>\n       <strong>FLASHINFER</strong><br>\n       Could not be used because this attention type did not support the sink-token setting.\n   </li>\n</ol>\n<p>\n<strong>Key Observation:</strong><br>\nFLASH Attention outperformed Triton in my experiments. The remaining two attention types were ultimately not usable due to lack of support for sink-token configuration.\n</p>\n<p>\nI missed including this information in my original write-up, so thank you for asking the question. It gave me an opportunity to clarify these backend-level experiments and observations.\n</p>\n<hr>\n<h3>Explanation of Sink Tokens</h3>\n<p>\nUnder normal transformer behavior, each token primarily attends to semantically relevant tokens within the sequence.\n</p>\n<p>\nHowever, in practice, certain tokens tend to attract disproportionately high attention from many other tokens. These are commonly referred to as <strong>sink tokens</strong>.\n</p>\n<p>\nExamples of sink tokens can include:\n</p>\n<ul>\n   <li>initial tokens in long reasoning sequences,</li>\n   <li>newline tokens,</li>\n   <li>padding tokens,</li>\n   <li>BOS (Beginning of Sequence) tokens,</li>\n   <li>and special separator tokens.</li>\n</ul>\n<p>\nSink tokens can sometimes improve:\n</p>\n<ul>\n   <li>optimization stability,</li>\n   <li>training convergence,</li>\n   <li>and long-context behavior.</li>\n</ul>\n<p>\nThe sink-token configuration was already built into the GPT-OSS model itself. I intentionally chose not to disable it while testing alternative attention backends because I was concerned that changing this behavior could negatively impact model performance and long-context stability.\n</p>\n<h1>Question 3</h1>\n<h3>Dynamic Time Pressure and Buffer Borrowing Strategy</h3>\n<p>\nThe following logic was used to dynamically estimate time pressure and determine how much additional buffer time could be allocated to a question during inference.\n</p>\n<ol>\n <li>\n   <h4>Time Pressure Computation (common for step-back and non-step-back approaches)</h4>\n\n   <p>\n     The <code>compute_time_pressure()</code> function estimated the current level of time pressure based on:\n   </p>\n   <ul>\n     <li>remaining competition time,</li>\n     <li>number of questions already completed,</li>\n     <li>and the ideal pacing required to finish all remaining questions.</li>\n   </ul>\n   <p>\n     The core idea was to compare:\n   </p>\n   <ul>\n     <li>the ideal pace (<code>total_available_time / total_questions</code>)</li>\n     <li>against the currently available pace (<code>remaining_time / remaining_questions</code>)</li>\n   </ul>\n   <p>\n     A pressure score was then computed as:\n   </p>\n   <ul>\n     <li>\n       <strong>Pressure &gt; 1</strong> → The system is behind schedule and must become more conservative with time allocation.\n     </li>\n     <li>\n       <strong>Pressure &lt; 1</strong> → The system has spare time available and can afford more flexible allocation.\n     </li>\n   </ul>\n   <p>\n     To avoid extreme instability, the final pressure value was clamped between:\n   </p>\n   <ul>\n     <li><code>0.3</code> (minimum pressure)</li>\n     <li><code>1.5</code> (maximum pressure)</li>\n   </ul>\n </li>\n <br>\n   <h4>Borrow Fraction Computation (Step-Back)</h4>\n   <p>\n     The <code>compute_borrow_fraction()</code> function determined what fraction of the global time buffer\n     could be borrowed for the current question. The borrowing decision depended on several factors:\n   </p>\n   <ul>\n     <li>actual step-back execution time</li>\n     <li>allocated step-back time budget</li>\n   </ul>\n   <p>\n     <strong>Time Ratio (<code>c_ratio</code>)</strong><br>\n     Measures how much of the allocated Step-Back time budget was consumed.\n   </p>\n   <ul>\n     <li>step-back token usage</li>\n     <li>allocated token budget</li>\n   </ul>\n   <p>\n     <strong>Token Ratio (<code>s_ratio</code>)</strong><br>\n     Measures how much of the allocated Step-Back token budget was consumed.\n   </p>\n     <strong> Inverse of time pressure (Time pressure computation is given in the previous section)</strong>    <br>\n\n   <p>\n     <strong>Mathematical Logic:</strong>\n   </p>\n   <p>\n     Two normalized ratios were first computed.\n     These two signals were then combined using a Euclidean-style formulation:\n   </p>\n   <pre>combined_signal = sqrt((c_ratio² + s_ratio²) / 2)\n   </pre>\n   <p>\n     This produced a unified measure representing overall computational intensity for the current problem.\n   </p>\n   <p>\n     The system then adjusted this value using the previously computed time-pressure signal:\n   </p>\n   <ul>\n     <li>Higher time pressure reduced the fraction of buffer that could be borrowed.</li>\n     <li>Lower time pressure allowed more aggressive borrowing from the global buffer.</li>\n   </ul>\n   <p>\n     Finally, the computed borrow fraction was constrained within predefined limits:\n   </p>\n   <ul>\n     <li>minimum allowed borrow fraction = <code>0.0</code></li>\n     <li>maximum allowed borrow fraction = <code>b_max</code></li>\n   </ul>\n \n<li>\n   <h4>Borrow Fraction Computation (Non- Step-Back)</h4>\n    This was simply inverse of time pressure in case of Non-Step Back\n</li>\n</ol>\n<p>def compute_time_pressure(\n       self,\n       remaining_time: float,\n       questions_completed: int,\n    ) -&gt; float:\n        remaining_q = max(1, self.total_questions - questions_completed)\n        if remaining_time &lt;= 0:\n            return 1.5\n        ideal_pace = self.total_available_time / self.total_questions\n        available_pace = remaining_time / remaining_q\n        pressure = ideal_pace / available_pace\n        return max(0.3, min(1.5, pressure))\n   def compute_borrow_fraction(\n       self,\n       remaining_time: float,\n       questions_completed: int,\n       stepback_time: float,\n       stepback_time_budget: float,\n       stepback_tokens: int,\n       stepback_tokens_budget: int,\n       global_buffer: float = 0.0,\n     ) -&gt; float:\n       \"\"\"\n       Compute what fraction of the buffer to borrow.\n       Returns\n       -------\n       float\n           Borrow fraction in [0, b_max].\n       \"\"\"</p>\n<pre><code>   c_ratio = min(1.0, stepback_time / stepback_time_budget) if stepback_time &gt; 0 else 0.5\n   s_ratio = stepback_tokens / stepback_tokens_budget if stepback_tokens &gt; 0 else 0.0\n   combined_signal = math.sqrt((c_ratio ** 2 + s_ratio ** 2) / 2)\n   sigmoid_out = self._sigmoid(combined_signal)\n   pressure = self.compute_time_pressure(remaining_time, questions_completed)\n   pressure_mult = 1.0 / pressure\n   borrow_fraction = self.b_max * combined_signal * pressure_mult\n   borrow_fraction = max(0.0, min(self.b_max, borrow_fraction))\n</code></pre>\n<ul>\n<li>Time Allocation per question. Better Accuracy- Using same model in two different phases could result in more accurate answer (hypothesis)</li>\n</ul>\n<h3>Use of StepBack Technique</h3>\n<p>:-</p>\n<h5> Issues trying to address</h5>\n<ul>\n<li>\nThis helped in making informed decision about how much time to allocate to solve the question. The time allocation per question was not based on prior questions but based on more concrete information about the question itself\n<br><br><br>\nHypothesis - Getting to know domain of the problem or techniques used to solve the problem will nudge the model towards a more accurate answer</li>\n</ul>\n<h5> Motivation </h5>\n<p>– Much of work in the field of Artificial Intelligence and Machine Learning is inspired from how humans function. Neural network corresponds to the neurons in the brain. “Attention is all you need” is how our brains process lengthy information. Therefore, my rationale was that if us humans get guidance then we perform a task better so the llm model can behave similarly. \n<br><br>\nFurther, the principles identified during stepback phase 1 formed the basis of dynamic prompting. Prompting based on domains and techniques used would in my opinion result in better outcomes and I wanted to try this further. However, phase 1 took away from the total time to solve the problem. Therefore, this approach had to be discarded.</p>\n<h3>Additional Contributions Highlighted in the Revision</h3>\n<p>\nIn addition, I would like to highlight three further contributions and observations that were either underemphasized in the original write-up or significantly strengthened through post-submission experiments.\n</p>\n<hr>\n<h4>1. CUDA Graph Capture Size Optimization</h4>\n<p>\nvLLM generates CUDA graphs for two distinct execution phases:\n</p>\n<ul>\n   <li><strong>Mixed Prefill + Decode</strong></li>\n   <li><strong>Pure Decode</strong></li>\n</ul>\n<p>\nThese two phases exhibit very different shape distributions.\n</p>\n<p>\nThe mixed prefill+decode phase experiences progressively increasing input lengths due to:\n</p>\n<ul>\n   <li>Python tool calls,</li>\n   <li>multi-turn conversational context,</li>\n   <li>and dynamically growing reasoning traces.</li>\n</ul>\n<p>\nIn contrast, the pure decode phase typically generates one token at a time and therefore operates under a very different execution profile.\n</p>\n<p>\nTable  in Section 5.2 already includes an initial ablation study on graph capture sizing. After submission, I conducted additional experiments to support a hypothesis I had originally held on intuition alone — one I did not assert in version 1 of the write-up due to the lack of data i.e .</p>\n<ul>\n   <li>capturing the <em>correct</em> graph sizes improves throughput,</li>\n   <li>and omitting unnecessary graph captures also contributes to better runtime efficiency.</li>\n</ul>\n<p><strong> If graph_size was equal to the max-num-seqs parameter passed to vllm inference server then throughput increased atleast by 65%. This maybe due to decode graph matching the number of sequences</strong></p>\n<h4>2. Streaming Output vs. Non-Streaming Generation</h4>\n<p>\nAnother implementation detail omitted from the original write-up: the pipeline uses streaming responses rather than single-shot generation.  Non Streaming Responses resulted in frequent read timeout and connection timeout issues\n<br>\nThis was part of the work that went into building the pipeline, but I forgot to mention it\n</p>\n<p>\nDuring experimentation, non-streaming inference frequently resulted in:\n</p>\n<ul>\n   <li>read timeouts,</li>\n   <li>connection timeouts,</li>\n   <li>and instability during multi-turn tool usage.</li>\n</ul>\n<p>\nSwitching to streaming-based generation resolved these issues and significantly improved runtime stability.\n</p>\n<h4>3. State-of-the-Art (SOTA) Comparison</h4>\n<p>\nThe revised evaluation now includes additional comparisons against:\n</p>\n<ul>\n   <li><strong>Qwen</strong> (without tool calling),</li>\n   <li><strong>Gemini Pro 3.1</strong>,</li>\n</ul>\n<p>\nOne particularly interesting observation was that Gemini Pro 3.1 and Claude Opus 4.7 appear to be highly complementary systems.\n</p>\n<p>\nTogether, the two models successfully solved every question in my curated evaluation dataset at pass@1.\n</p>\n<p>However, Claude demonstrated stronger mathematical reasoning than Gemini 3.1 Pro, especially on difficult mathematical problems. While both models solved easier problems reliably and on harder problems, each model solved cases that the other failed to solve.\n</p>\n<p><br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1563363%2Fb1266b4ed3af90b5d6cbab51f7c2df76%2Fperformance_comparison_updated_2.png?generation=1779036696326203&amp;alt=media\" alt=\"\"></p>",
          "rawMarkdown": "\n<h1>Question 1</h1>\n\n   Formatting - I fixed it. Thank you for pointing it out.\n\n   **Side Note**: The overall system design could not be clearly included in the PDF because the diagram became too small. Therefore, the flow diagram has been attached separately so it can be zoomed in and viewed properly.\nThis was already part of the original writeup — just highlighting it here in case it was overlooked.\n\n<h1>Question 2</h1>\n\n<p>\nYes, several backend-level ablations and experiments were conducted.\n</p>\n\n<h3>1. Inference Engine Experiments</h3>\n\n<p>\nOne major component of the backend was the inference engine itself. Few inference frameworks were evaluated:\n</p>\n\n<ul>\n    <li>\n        <strong>vLLM (v0.10.1 + GPT-OSS)</strong><br>\n        This configuration was recommended in the official model card. Tried using this in the hope this will give maximum performance. However, it depended on an older PyTorch nightly version that was not available under the PyTorch repo that hosts different pytorch release versions\n    </li>\n\n    <li>\n        <strong>TensorRT-LLM</strong><br>\n<p>\n Initial experiments with TensorRT-LLM. This could be easily implemented using docker but in Kaggle environment docker could not be used. I tried to implement workaround but I faced challenges while implementing the workaround. I finally did not pursue this route when I faced datatype mismatch issues with gpt-oss and tensorrt-llm framework</p>\n\n<p>\nThe issue may or may not be fixable, since TensorRT-LLM generally works well with many large models. I spent some time attempting to make it work, but due to competition time constraints, I decided not to pursue this direction further.\nIt may still be possible to get GPT-OSS running successfully with additional engineering effort since gpt-oss work with tensorrt installed using docker\n</p>\n    </li>\n\n    <li>\n        <strong>sglang</strong><br>\n        sglang was also evaluated as part of the backend experimentation process. And performance that I got with some basic knobs of sglang-0.5.8 was not as good as vllm-0.11.2. That does not mean sglang is not good enough. It just means other sglang parameters or the newer versions of sglang and vllm needs to be experimented with to provide any conclusive answer.\nBelow parameters of sglang were used:\n'--num_gpus', '1',\n        '--max-running-requests', '8',\n        '--mem-fraction-static', '0.90',\n        '--dtype', 'auto',\n        '--context-length', '49000',\n        '--random-seed', '1',\n        '--kv-cache-dtype','fp8_e4m3',\n        '--chunked-prefill-size', '32000',\n         '--cuda-graph-max-bs','16',\n        '--trust-remote-code',\n\n    </li>\n</ul>\n\n<h3>2. CUDA Kernel-Level Backend Components</h3>\n\n<p>\nAnother important backend component involved the CUDA kernels used internally within the transformer architecture.\n</p>\n\n<p>\nIf you inspect the runtime logs, you will notice that. This is a snippet from vllm logs\n</p>\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1563363%2F6263e95693f01da4278972702d1e1a19%2Fmarlin%20backend.png?generation=1778940390118017&alt=media)\n<ul>\n    <li><code>Using FLASH_ATTN</code></li>\n    <li><code>Using Marlin Backend</code></li>\n</ul>\n\n<p>\nTo clarify, my submitted code does use FLASH Attention. However flash and marlin correspond to different optimized CUDA kernels and execution backends used for accelerating transformer operations such as attention layers, matrix multiplications, and quantized inference workloads.\n</p>\n\n<ul>\n    <li>\n        <strong>Marlin Backend</strong> → Optimizes quantized matrix multiplication workloads.\n    </li>\n    <li>\n        <strong>FLASH Attention</strong> → Optimizes transformer attention computation.\n    </li>\n</ul>\n\n<p>\nPlease refer the architecture below to understand where each of them is used. The parts of the transformer where Marlin and Flash are used is given below\n</p>\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1563363%2Fecf0d43f2f65690e43c6af0365fb1801%2Fgpt_oss_120b_layer_with_kernels.svg?generation=1778938778997700&alt=media)\n\n<h3>a) GEMM Backend Experiment </h3>\n\nMarlin performed better than Triton in this setup.\n\nThis is what was indicated in the table that I added to section 5.2 and Figure 6.\n\n\n\n<h3>b) Attention Backend Experiments - FLASH, FLASHINFER, TRITON, FLEX</h3>\n\n<p>\nFor the attention component of the transformer, one of the research papers indicated that GPT-OSS-120B could operate using four different attention backends.\n</p>\n\n<p>\nAt the time I conducted these experiments, I had not yet seen the research you shared regarding FLASH Attention outperforming Triton. Nevertheless, it was still valuable to experimentally validate which backend performed best for this specific inference pipeline and use case.\n</p>\n\n<p>\nThe following attention backends were evaluated:\n</p>\n\n<ol>\n    <li><strong>FLASH</strong></li>\n    <li><strong>TRITON</strong></li>\n    <li>\n        <strong>FLEX</strong><br>\n        Could not be used because this attention type did not support the sink-token setting.\n    </li>\n    <li>\n        <strong>FLASHINFER</strong><br>\n        Could not be used because this attention type did not support the sink-token setting.\n    </li>\n</ol>\n\n<p>\n<strong>Key Observation:</strong><br>\nFLASH Attention outperformed Triton in my experiments. The remaining two attention types were ultimately not usable due to lack of support for sink-token configuration.\n</p>\n\n<p>\nI missed including this information in my original write-up, so thank you for asking the question. It gave me an opportunity to clarify these backend-level experiments and observations.\n</p>\n\n<hr>\n\n<h3>Explanation of Sink Tokens</h3>\n\n<p>\nUnder normal transformer behavior, each token primarily attends to semantically relevant tokens within the sequence.\n</p>\n\n<p>\nHowever, in practice, certain tokens tend to attract disproportionately high attention from many other tokens. These are commonly referred to as <strong>sink tokens</strong>.\n</p>\n\n<p>\nExamples of sink tokens can include:\n</p>\n\n<ul>\n    <li>initial tokens in long reasoning sequences,</li>\n    <li>newline tokens,</li>\n    <li>padding tokens,</li>\n    <li>BOS (Beginning of Sequence) tokens,</li>\n    <li>and special separator tokens.</li>\n</ul>\n\n<p>\nSink tokens can sometimes improve:\n</p>\n\n<ul>\n    <li>optimization stability,</li>\n    <li>training convergence,</li>\n    <li>and long-context behavior.</li>\n</ul>\n\n<p>\nThe sink-token configuration was already built into the GPT-OSS model itself. I intentionally chose not to disable it while testing alternative attention backends because I was concerned that changing this behavior could negatively impact model performance and long-context stability.\n</p>\n\n<h1>Question 3</h1>\n<h3>Dynamic Time Pressure and Buffer Borrowing Strategy</h3>\n\n<p>\nThe following logic was used to dynamically estimate time pressure and determine how much additional buffer time could be allocated to a question during inference.\n</p>\n\n\n<ol>\n  <li>\n    <h4>Time Pressure Computation (common for step-back and non-step-back approaches)</h4>\n\n  \n    <p>\n      The <code>compute_time_pressure()</code> function estimated the current level of time pressure based on:\n    </p>\n\n    <ul>\n      <li>remaining competition time,</li>\n      <li>number of questions already completed,</li>\n      <li>and the ideal pacing required to finish all remaining questions.</li>\n    </ul>\n\n    <p>\n      The core idea was to compare:\n    </p>\n\n    <ul>\n      <li>the ideal pace (<code>total_available_time / total_questions</code>)</li>\n      <li>against the currently available pace (<code>remaining_time / remaining_questions</code>)</li>\n    </ul>\n\n    <p>\n      A pressure score was then computed as:\n    </p>\n\n    <ul>\n      <li>\n        <strong>Pressure &gt; 1</strong> → The system is behind schedule and must become more conservative with time allocation.\n      </li>\n      <li>\n        <strong>Pressure &lt; 1</strong> → The system has spare time available and can afford more flexible allocation.\n      </li>\n    </ul>\n\n    <p>\n      To avoid extreme instability, the final pressure value was clamped between:\n    </p>\n\n    <ul>\n      <li><code>0.3</code> (minimum pressure)</li>\n      <li><code>1.5</code> (maximum pressure)</li>\n    </ul>\n  </li>\n\n  <br>\n\n    <h4>Borrow Fraction Computation (Step-Back)</h4>\n\n    <p>\n      The <code>compute_borrow_fraction()</code> function determined what fraction of the global time buffer\n      could be borrowed for the current question. The borrowing decision depended on several factors:\n    </p>\n\n    <ul>\n      <li>actual step-back execution time</li>\n      <li>allocated step-back time budget</li>\n    </ul>\n\n    <p>\n      <strong>Time Ratio (<code>c_ratio</code>)</strong><br>\n      Measures how much of the allocated Step-Back time budget was consumed.\n    </p>\n\n    <ul>\n      <li>step-back token usage</li>\n      <li>allocated token budget</li>\n    </ul>\n\n    <p>\n      <strong>Token Ratio (<code>s_ratio</code>)</strong><br>\n      Measures how much of the allocated Step-Back token budget was consumed.\n    </p>\n\n      <strong> Inverse of time pressure (Time pressure computation is given in the previous section)</strong>    <br>\n   \n\n    <p>\n      <strong>Mathematical Logic:</strong>\n    </p>\n\n    <p>\n      Two normalized ratios were first computed.\n      These two signals were then combined using a Euclidean-style formulation:\n    </p>\n\n    <pre>\ncombined_signal = sqrt((c_ratio² + s_ratio²) / 2)\n    </pre>\n\n    <p>\n      This produced a unified measure representing overall computational intensity for the current problem.\n    </p>\n\n    <p>\n      The system then adjusted this value using the previously computed time-pressure signal:\n    </p>\n\n    <ul>\n      <li>Higher time pressure reduced the fraction of buffer that could be borrowed.</li>\n      <li>Lower time pressure allowed more aggressive borrowing from the global buffer.</li>\n    </ul>\n\n    <p>\n      Finally, the computed borrow fraction was constrained within predefined limits:\n    </p>\n\n    <ul>\n      <li>minimum allowed borrow fraction = <code>0.0</code></li>\n      <li>maximum allowed borrow fraction = <code>b_max</code></li>\n    </ul>\n  </li>\n\n\n <li>\n    <h4>Borrow Fraction Computation (Non- Step-Back)</h4>\n     This was simply inverse of time pressure in case of Non-Step Back\n</li>\n</ol>\n\n    def compute_time_pressure(\n        self,\n        remaining_time: float,\n        questions_completed: int,\n     ) -> float:\n         remaining_q = max(1, self.total_questions - questions_completed)\n         if remaining_time <= 0:\n             return 1.5\n         ideal_pace = self.total_available_time / self.total_questions\n         available_pace = remaining_time / remaining_q\n         pressure = ideal_pace / available_pace\n         return max(0.3, min(1.5, pressure))\n\n\n    def compute_borrow_fraction(\n        self,\n        remaining_time: float,\n        questions_completed: int,\n        stepback_time: float,\n        stepback_time_budget: float,\n        stepback_tokens: int,\n        stepback_tokens_budget: int,\n        global_buffer: float = 0.0,\n      ) -> float:\n        \"\"\"\n        Compute what fraction of the buffer to borrow.\n\n        Returns\n        -------\n        float\n            Borrow fraction in [0, b_max].\n        \"\"\"\n        \n        c_ratio = min(1.0, stepback_time / stepback_time_budget) if stepback_time > 0 else 0.5\n        s_ratio = stepback_tokens / stepback_tokens_budget if stepback_tokens > 0 else 0.0\n\n        combined_signal = math.sqrt((c_ratio ** 2 + s_ratio ** 2) / 2)\n\n        sigmoid_out = self._sigmoid(combined_signal)\n        pressure = self.compute_time_pressure(remaining_time, questions_completed)\n        pressure_mult = 1.0 / pressure\n\n        borrow_fraction = self.b_max * combined_signal * pressure_mult\n        borrow_fraction = max(0.0, min(self.b_max, borrow_fraction))\n\n- Time Allocation per question. Better Accuracy- Using same model in two different phases could result in more accurate answer (hypothesis)\n\n<h3>Use of StepBack Technique</h3>:-\n\n<h5> Issues trying to address</h5> - \n\nThis helped in making informed decision about how much time to allocate to solve the question. The time allocation per question was not based on prior questions but based on more concrete information about the question itself\n<br><br><br>\nHypothesis - Getting to know domain of the problem or techniques used to solve the problem will nudge the model towards a more accurate answer\n\n<h5> Motivation </h5> – Much of work in the field of Artificial Intelligence and Machine Learning is inspired from how humans function. Neural network corresponds to the neurons in the brain. “Attention is all you need” is how our brains process lengthy information. Therefore, my rationale was that if us humans get guidance then we perform a task better so the llm model can behave similarly. \n<br><br>\nFurther, the principles identified during stepback phase 1 formed the basis of dynamic prompting. Prompting based on domains and techniques used would in my opinion result in better outcomes and I wanted to try this further. However, phase 1 took away from the total time to solve the problem. Therefore, this approach had to be discarded.\n\n\n<h3>Additional Contributions Highlighted in the Revision</h3>\n<p>\nIn addition, I would like to highlight three further contributions and observations that were either underemphasized in the original write-up or significantly strengthened through post-submission experiments.\n</p>\n\n<hr>\n\n<h4>1. CUDA Graph Capture Size Optimization</h4>\n\n<p>\nvLLM generates CUDA graphs for two distinct execution phases:\n</p>\n\n<ul>\n    <li><strong>Mixed Prefill + Decode</strong></li>\n    <li><strong>Pure Decode</strong></li>\n</ul>\n\n<p>\nThese two phases exhibit very different shape distributions.\n</p>\n\n<p>\nThe mixed prefill+decode phase experiences progressively increasing input lengths due to:\n</p>\n\n<ul>\n    <li>Python tool calls,</li>\n    <li>multi-turn conversational context,</li>\n    <li>and dynamically growing reasoning traces.</li>\n</ul>\n\n<p>\nIn contrast, the pure decode phase typically generates one token at a time and therefore operates under a very different execution profile.\n</p>\n\n\n\n<p>\nTable  in Section 5.2 already includes an initial ablation study on graph capture sizing. After submission, I conducted additional experiments to support a hypothesis I had originally held on intuition alone — one I did not assert in version 1 of the write-up due to the lack of data i.e .</p>\n\n<ul>\n    <li>capturing the <em>correct</em> graph sizes improves throughput,</li>\n    <li>and omitting unnecessary graph captures also contributes to better runtime efficiency.</li>\n</ul>\n<strong> If graph_size was equal to the max-num-seqs parameter passed to vllm inference server then throughput increased atleast by 65%. This maybe due to decode graph matching the number of sequences</strong>\n\n\n<h4>2. Streaming Output vs. Non-Streaming Generation</h4>\n\n<p>\nAnother implementation detail omitted from the original write-up: the pipeline uses streaming responses rather than single-shot generation.  Non Streaming Responses resulted in frequent read timeout and connection timeout issues\n<br>\nThis was part of the work that went into building the pipeline, but I forgot to mention it\n</p>\n\n<p>\nDuring experimentation, non-streaming inference frequently resulted in:\n</p>\n\n<ul>\n    <li>read timeouts,</li>\n    <li>connection timeouts,</li>\n    <li>and instability during multi-turn tool usage.</li>\n</ul>\n\n<p>\nSwitching to streaming-based generation resolved these issues and significantly improved runtime stability.\n</p>\n\n<h4>3. State-of-the-Art (SOTA) Comparison</h4>\n\n<p>\nThe revised evaluation now includes additional comparisons against:\n</p>\n\n<ul>\n    <li><strong>Qwen</strong> (without tool calling),</li>\n    <li><strong>Gemini Pro 3.1</strong>,</li>\n</ul>\n\n<p>\nOne particularly interesting observation was that Gemini Pro 3.1 and Claude Opus 4.7 appear to be highly complementary systems.\n</p>\n\n<p>\nTogether, the two models successfully solved every question in my curated evaluation dataset at pass@1.\n</p>\n\n\n<p>However, Claude demonstrated stronger mathematical reasoning than Gemini 3.1 Pro, especially on difficult mathematical problems. While both models solved easier problems reliably and on harder problems, each model solved cases that the other failed to solve.\n</p>\n<br>\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1563363%2Fb1266b4ed3af90b5d6cbab51f7c2df76%2Fperformance_comparison_updated_2.png?generation=1779036696326203&alt=media)"
        }
      ]
    },
    {
      "id": 3457399,
      "postDate": "2026-05-13T17:46:53.927Z",
      "content": "<h1>AIMO Progress Prize 3 — Technical Report</h1>\n<h2>Engineering High-Throughput LLM Inference for Competitive Mathematical Reasoning: Lessons from the AIMO Progress Prize 3 Competition</h2>\n<p><strong>Independent Research • April 2025</strong></p>\n<h2>Abstract</h2>\n<p>\nThis report documents an independent submission to the AI Mathematical Olympiad (AIMO)\nProgress Prize 3 competition. Operating under a strict 5-hour GPU budget on a single\nNVIDIA H100 80GB GPU, a comprehensive set of inference-time optimizations for\nGPT-OSS-120B were investigated.\n</p>\n<p>\nContributions include:\n</p>\n<ul>\n<li>Asynchronous concurrency scheduling</li>\n<li>Time-pressure-based global-buffer borrowing</li>\n<li>\nA Non-Step-Back prompting approach that outperformed the Step-Back variant\n(score 24 vs. 18)\n</li>\n<li>\nA dual-pass answer extraction system combining structured JSON regex with a\nmodel-based fallback\n</li>\n<li>\nSystematic ablations of serving backends (Marlin, Triton, SGLang), CUDA graph capture\nsizes, and sliding-window attention are documented across 15 configurations.\n</li></ul>\n<hr>\n<h2>1. Introduction</h2>\n<p>\nThe AIMO Progress Prize 3 competition requires solving 50 mathematical problems under\na strict 5-hour GPU constraint. Problems are competition-grade, requiring multi-step\nsymbolic and numerical reasoning.\n</p>\n<p>\nEach participant receives a single GPU allocation for the entire run, with approximately\n20 minutes consumed by environment setup and model loading, leaving roughly\n336 seconds per question.\n</p>\n<p>\nThis work is entirely inference-based — no model weights were fine-tuned.\nThe approach combines multiple factors:\n</p>\n<ul>\n<li>Model capability</li>\n<li>Prompt design</li>\n<li>Concurrency architecture</li>\n<li>Time allocation</li>\n<li>Answer extraction</li>\n</ul>\n<p>\nGPT-OSS-120B appeared to perform best when given sufficient time and token budget to\nreason through problems fully.\n</p>\n<p>\n<strong>Note:</strong> The best-performing configuration (score 24) could not be submitted to the competition because a critical library dependency was accidentally deleted just before the deadline.\n</p>\n<hr>\n<h2>2. Problem Constraints and Setup</h2>\n<h3>2.1 Hardware</h3>\n<table>\n<tbody><tr>\n<th>Component</th>\n<th>Specification</th>\n</tr>\n<tr>\n<td>GPU</td>\n<td>NVIDIA H100 80GB (SXM or PCIe; single GPU, tp_size=1)</td>\n</tr>\n<tr>\n<td>GPU Memory</td>\n<td>~60–65 GB total during inference (96% utilization)</td>\n</tr>\n<tr>\n<td>CUDA Architecture</td>\n<td>Hopper (sm_90) — required for fp8_e4m3 KV cache</td>\n</tr>\n<tr>\n<td>KV Cache dtype</td>\n<td>fp8_e4m3</td>\n</tr>\n<tr>\n<td>Model</td>\n<td>GPT-OSS-120B (MoE, 120B params, 5.1B active)</td>\n</tr>\n<tr>\n<td>Serving Framework</td>\n<td>Modified NemoSkills + vLLM 0.11.2</td>\n</tr>\n<tr>\n<td>Python</td>\n<td>Python 3.12.12</td>\n</tr>\n</tbody></table>\n<h3>2.2 Time Budget</h3>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F1563363%2Fef53d83ee10bc3abac80303a2c81184d%2FTime-Budget.png?generation=1778943579039470&amp;alt=media\" alt=\"\"></p>\n<table>\n<tbody><tr>\n<th>Parameter</th>\n<th>Value</th>\n</tr>\n<tr>\n<td>Total GPU time</td>\n<td>5 hours</td>\n</tr>\n<tr>\n<td>Setup &amp; model loading</td>\n<td>~20 minutes</td>\n</tr>\n<tr>\n<td>Effective inference window</td>\n<td>~280 minutes</td>\n</tr>\n<tr>\n<td>Base per-question budget</td>\n<td>~320 seconds + buffer borrowing</td>\n</tr>\n<tr>\n<td>Global buffer</td>\n<td>350 seconds (dynamically updated)</td>\n</tr>\n</tbody></table>\n<hr>\n<h2>3. Benchmarking Strategy</h2>\n<p>\nThree levels of benchmarking were used, applied in the order below as each revealed\na gap that motivated the next.\n</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F1563363%2F59e78444f7f0314db3ae36fc745f4ead%2FBenchmarking.png?generation=1778943755757867&amp;alt=media\" alt=\"\"></p>\n<h3>3.1 AIMO Reference Problems (First Dataset)</h3>\n<p>\nThe first benchmark consisted of 20 problems drawn from the AIMO 2 and AIMO 3\nreference problem sets. The model scored 95% accuracy (19/20).\n</p>\n<table>\n<tbody><tr>\n<th>Metric</th>\n<th>Value</th>\n</tr>\n<tr>\n<td>Total problems</td>\n<td>20</td>\n</tr>\n<tr>\n<td>Correct answers</td>\n<td>19/20 (95%)</td>\n</tr>\n<tr>\n<td>Incorrect answer</td>\n<td>Problem #10 (model: 29,443; actual: 8,687)</td>\n</tr>\n<tr>\n<td>Avg time per problem</td>\n<td>230 seconds</td>\n</tr>\n<tr>\n<td>Avg tokens generated</td>\n<td>13,543 tokens</td>\n</tr>\n</tbody></table>\n<h3>3.2 Internal Benchmark (Second Dataset)</h3>\n<p>\nAfter observing the gap between 90–95% reference accuracy and the 42% leaderboard score,\na harder benchmark was constructed from 49 problems sourced from IMO, AMC/AIME,\nand similar archives.\n</p>\n<table>\n<tbody><tr>\n<th>Property</th>\n<th>Value</th>\n</tr>\n<tr>\n<td>Total problems</td>\n<td>49</td>\n</tr>\n<tr>\n<td>Problem sources</td>\n<td></td>\n</tr>\n<tr>\n<td>Model accuracy</td>\n<td>65%</td>\n</tr>\n</tbody></table>\n<p>Internal BenchMark Dataset - <a href=\"https://huggingface.co/HarpreetK/AIMO3/blob/main/Internal_Benchmark_Final.xlsx\" target=\"_blank\">https://huggingface.co/HarpreetK/AIMO3/blob/main/Internal_Benchmark_Final.xlsx</a>\nSources - AOPS,<a href=\"https://matharena.ai/apex/\" target=\"_blank\">https://matharena.ai/apex/</a>, ARML, HMMT</p>\n<h3>3.3 10-Problem Failing Subset</h3>\n<p>\nA targeted 10-problem subset was extracted consisting of questions where the previous\nattempt had either returned 29443 (timeout/extraction failure) or produced an incorrect answer.\n</p>\n<table>\n<tbody><tr>\n<th>Benchmark</th>\n<th>Score</th>\n<th>Notes</th>\n</tr>\n<tr>\n<td>AIMO Reference (20)</td>\n<td>95% (19/20)</td>\n<td>Too easy; gap not explained</td>\n</tr>\n<tr>\n<td>Internal Benchmark (49)</td>\n<td>65%</td>\n<td>Closer to AIMO 3 difficulty</td>\n</tr>\n<tr>\n<td>AIMO 3 Leaderboard (50)</td>\n<td>21/50 (42%)</td>\n<td>Actual submission</td>\n</tr>\n<tr>\n<td>Best config (50)</td>\n<td>24/50 (48%)</td>\n<td>Not submitted — library deletion</td>\n</tr>\n</tbody></table>\n<hr>\n<h2>4. System Design</h2>\n<h3>4.1 Overall Flow Diagram</h3>\n<p>Flow Diagram is attached. Please open it independently in a new window to zoom on it</p>\n<h3>4.2 Baseline Code and Repository</h3>\n<p>\nA modified version of the NemoSkills repository (winner of AIMO 2) was used as the baseline,\nproviding a scaffold for request scheduling and Python code execution sandboxing.\nMCP and LiteLLM abstraction layers were stripped to reduce overhead.\n</p>\n<h3>4.3 Async Scheduling (Python asyncio)</h3>\n<ul>\n<li>No thread creation overhead</li>\n<li>No heavy context switching</li>\n<li>Handles thousands of concurrent tasks efficiently</li>\n<li>Confirmed by AIMO 2 winning teams</li>\n</ul>\n<p>\n<em>\nNote: These were conclusions based on research. Ideally, both approaches would have been compared directly.\n</em>\n</p>\n<h3>4.4 Dynamic Buffer Borrowing</h3>\n<p>\nThe BufferBorrower class implements a time-pressure-based allocation strategy.\nBorrowable time differed across notebooks:\n</p>\n<ul>\n<li>130 seconds in score-21</li>\n<li>95 seconds in score-24</li>\n</ul>\n<h3>4.5 Non-Step-Back Prompting (Better than Step-Back)</h3>\n<p>\nThe final best-performing approach used a single-phase prompt applied uniformly to all 50 problems.\n</p>\n<p>\n<strong>\nThe key jump was from score 18 (Step-Back) to score 24 (Non-Step-Back):\na 6-point improvement.\n</strong>\n</p>\n<h3>4.6 Majority Voting Answer Extraction</h3>\n<p>\nUp to 8 self-consistent samples are generated per problem.\nMajority voting uses frequency count only.\n</p>\n<p>\n<strong>Metric Used:</strong> Exact Match Accuracy.\n</p>\n<h3>4.7 vLLM Launch Configuration</h3>\n<pre><code>\npython -m nemo_skills.inference.server.serve_vllm \\\n --model=.../gpt-oss-120b/.../1 --port=5000 --num_gpus=1 \\\n --max_model_len=38000 --max_num_batched_tokens=65000 \\\n --max_num_seqs=11 --max-cudagraph-capture-size=2048 \\\n --gpu_memory_utilization=0.95 --kv_cache_dtype=fp8_e4m3 \\\n --enable-prefix-caching --async-scheduling\n</code></pre>\n<table>\n<tbody><tr>\n<th>Parameter</th>\n<th>Value</th>\n<th>Rationale</th>\n</tr>\n<tr>\n<td>max_tokens</td>\n<td>38,000</td>\n<td>Upper bound per problem</td>\n</tr>\n<tr>\n<td>tokens_to_generate</td>\n<td>35,940</td>\n<td>max_tokens minus overhead</td>\n</tr>\n<tr>\n<td>max_batch_size</td>\n<td>8</td>\n<td>Number of self-consistent samples</td>\n</tr>\n<tr>\n<td>global_buffer</td>\n<td>350 seconds</td>\n<td>Reserve for hard problems</td>\n</tr>\n<tr>\n<td>temperature</td>\n<td>1.0</td>\n<td>Per NVIDIA NeMo recommendation</td>\n</tr>\n<tr>\n<td>top_p</td>\n<td>1.0</td>\n<td>Per NVIDIA NeMo recommendation</td>\n</tr>\n</tbody></table>\n<hr>\n<h2>5. Backend and Systems Experiments</h2>\n<h3>5.1 Backend Comparison</h3>\n<ul>\n<li>\n<strong>vLLM:</strong> v0.10.1+gptoss failed to install due to PyTorch nightly conflicts.\n</li>\n<li>\n<strong>TensorRT-LLM:</strong> Engine compilation failed.\n</li>\n<li>\n<strong>Triton:</strong> Functional baseline: 875 tok/s prompt throughput.\n</li>\n<li>\n<strong>Marlin:</strong> Fused GPU kernels yielded 2,708 tok/s prompt throughput.\n</li>\n</ul>\n<h3>5.2 Full Experimental Configuration Table</h3>\n<p>All 15 configurations tested.</p>\n<h3>5.3 Sliding Window Attention</h3>\n<p>\nGPT-OSS alternates between full attention and sliding window attention (SWA).\n</p>\n<p>\nSliding window sizes 128, 200, and 8,000 were tested.\n</p>\n<h3>5.4 Sampling and vLLM Parameter Tuning</h3>\n<p>\nTemperature fixed at 1.0 (NVIDIA recommendation).\n</p>\n<hr>\n<h2>6. Submission History and Iterative Improvements</h2>\n<h3>6.1 Score Progression</h3>\n<table>\n<tbody><tr>\n<th>Parameter</th>\n<th>Score 18 (SB)</th>\n<th>Score 20</th>\n<th>Score 21 (SUB)</th>\n<th>Score 24 (Best)</th>\n</tr>\n<tr>\n<td>Prompting</td>\n<td>Step-Back full</td>\n<td>Non-SB + dual</td>\n<td>Non-Step-Back</td>\n<td>Non-Step-Back</td>\n</tr>\n<tr>\n<td>Temperature</td>\n<td>Fixed 1.0</td>\n<td>Varied</td>\n<td>Fixed 1.0</td>\n<td>Fixed 1.0</td>\n</tr>\n<tr>\n<td>max_model_len</td>\n<td>65,536</td>\n<td>36,000</td>\n<td>38,000</td>\n<td>80,000</td>\n</tr>\n<tr>\n<td>Leaderboard score</td>\n<td>18/50</td>\n<td>20/50</td>\n<td>21/50</td>\n<td>24/50</td>\n</tr>\n</tbody></table>\n<h3>6.2 Key Changes Between Attempts</h3>\n<h4>Score 18 → 24: Two key changes, +6 points</h4>\n<ul>\n<li>Step-Back Phase 1 removed entirely</li>\n<li>Token budget substantially increased</li>\n</ul>\n<h4>Score 24 → 21</h4>\n<p>\nReduced token budget caused score drop from 24 to 21.\n</p>\n<h4>Score 21 → 20</h4>\n<p>\nDual-prompt strategy and varied-temperature sampling hurt performance.\n</p>\n<hr>\n<h2>7. Comparison with State of the Art</h2>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F1563363%2F98ad341eccad2211873d4d0c07f0e423%2FSOTA%20Comparison.png?generation=1778953075190961&amp;alt=media\" alt=\"\"></p>\n<p>Below models were added to SOTA Comparison\nQwen (without tool calling),\nGemini Pro 3.1,\nand Claude Opus 4.7.\nOne particularly interesting observation was that Gemini Pro 3.1 and Claude Opus 4.7 appear to be highly complementary systems.</p>\n<p>Together, the two models successfully solved every question in my curated evaluation dataset.</p>\n<p>More specifically:</p>\n<p>Claude demonstrated stronger mathematical reasoning overall,\nespecially on difficult mathematical problems,\nwhile both models solved easier problems reliably,\nand on harder problems, each model solved cases that the other failed to solve.</p>\n<h2>8. Key Insights (Summary)</h2>\n<ul>\n<li>Time pressure is the primary bottleneck.</li>\n<li>Async scheduling flag in vLLM is extremely important.</li>\n<li>Token budget dominates accuracy.</li>\n<li>Backend choice significantly affects throughput.</li>\n<li>Dataset difficulty calibration is critical.</li>\n<li>Geometry-heavy problems appeared harder.</li>\n</ul>\n<hr>\n<h2>9. Limitations</h2>\n<ul>\n<li>No fine-tuning</li>\n<li>Limited benchmark coverage</li>\n<li>Single-run experiments</li>\n</ul>\n<hr>\n<h2>10. Future Work</h2>\n<ul>\n<li>Complete backend investigation</li>\n<li>Partial-response answer extraction</li>\n<li>Enable torch_compile and torch_dynamo</li>\n<li>Hybrid async-threaded scheduling</li>\n<li>Verifier models</li>\n<li>SGLang + fused MoE optimization</li>\n<li>Fine-tuning on post-June-2024 IMO data</li>\n</ul>\n<hr>\n<h2>11. Reproducibility Checklist</h2>\n<p>\nHuggingFace repo:\n<a href=\"https://huggingface.co/HarpreetK/AIMO3\">\nhttps://huggingface.co/HarpreetK/AIMO3\n</a>\n</p>\n<table>\n<tbody><tr>\n<th>Artifact</th>\n<th>Location / Value</th>\n<th>Status</th>\n</tr>\n<tr>\n<td>Base model</td>\n<td>GPT-OSS-120B</td>\n<td>Provided</td>\n</tr>\n<tr>\n<td>Submitted notebook</td>\n<td>gpt-oss-score21.ipynb</td>\n<td>Provided</td>\n</tr>\n<tr>\n<td>Best notebook (24)</td>\n<td>gpt-oss-nostepback-score24.ipynb</td>\n<td>Provided</td>\n</tr>\n<tr>\n<td>Backend</td>\n<td>Marlin (via vLLM 0.11.2)</td>\n<td>Provided</td>\n</tr>\n</tbody></table>\n<hr>\n<h2>13. Appendix</h2>\n<p>refer the pdf for the same</p>",
      "rawMarkdown": "<h1>AIMO Progress Prize 3 — Technical Report</h1>\n\n<h2>Engineering High-Throughput LLM Inference for Competitive Mathematical Reasoning: Lessons from the AIMO Progress Prize 3 Competition</h2>\n\n<p><strong>Independent Research • April 2025</strong></p>\n\n<h2>Abstract</h2>\n\n<p>\nThis report documents an independent submission to the AI Mathematical Olympiad (AIMO)\nProgress Prize 3 competition. Operating under a strict 5-hour GPU budget on a single\nNVIDIA H100 80GB GPU, a comprehensive set of inference-time optimizations for\nGPT-OSS-120B were investigated.\n</p>\n\n<p>\nContributions include:\n</p>\n\n<ul>\n<li>Asynchronous concurrency scheduling</li>\n<li>Time-pressure-based global-buffer borrowing</li>\n<li>\nA Non-Step-Back prompting approach that outperformed the Step-Back variant\n(score 24 vs. 18)\n</li>\n<li>\nA dual-pass answer extraction system combining structured JSON regex with a\nmodel-based fallback\n</li>\n<li>\nSystematic ablations of serving backends (Marlin, Triton, SGLang), CUDA graph capture\nsizes, and sliding-window attention are documented across 15 configurations.\n</li></ul>\n\n<hr>\n\n<h2>1. Introduction</h2>\n\n<p>\nThe AIMO Progress Prize 3 competition requires solving 50 mathematical problems under\na strict 5-hour GPU constraint. Problems are competition-grade, requiring multi-step\nsymbolic and numerical reasoning.\n</p>\n\n<p>\nEach participant receives a single GPU allocation for the entire run, with approximately\n20 minutes consumed by environment setup and model loading, leaving roughly\n336 seconds per question.\n</p>\n\n<p>\nThis work is entirely inference-based — no model weights were fine-tuned.\nThe approach combines multiple factors:\n</p>\n\n<ul>\n<li>Model capability</li>\n<li>Prompt design</li>\n<li>Concurrency architecture</li>\n<li>Time allocation</li>\n<li>Answer extraction</li>\n</ul>\n\n<p>\nGPT-OSS-120B appeared to perform best when given sufficient time and token budget to\nreason through problems fully.\n</p>\n\n<p>\n<strong>Note:</strong> The best-performing configuration (score 24) could not be submitted to the competition because a critical library dependency was accidentally deleted just before the deadline.\n</p>\n\n<hr>\n\n<h2>2. Problem Constraints and Setup</h2>\n\n<h3>2.1 Hardware</h3>\n\n<table border=\"1\" cellpadding=\"6\" cellspacing=\"0\">\n<tr>\n<th>Component</th>\n<th>Specification</th>\n</tr>\n<tr>\n<td>GPU</td>\n<td>NVIDIA H100 80GB (SXM or PCIe; single GPU, tp_size=1)</td>\n</tr>\n<tr>\n<td>GPU Memory</td>\n<td>~60–65 GB total during inference (96% utilization)</td>\n</tr>\n<tr>\n<td>CUDA Architecture</td>\n<td>Hopper (sm_90) — required for fp8_e4m3 KV cache</td>\n</tr>\n<tr>\n<td>KV Cache dtype</td>\n<td>fp8_e4m3</td>\n</tr>\n<tr>\n<td>Model</td>\n<td>GPT-OSS-120B (MoE, 120B params, 5.1B active)</td>\n</tr>\n<tr>\n<td>Serving Framework</td>\n<td>Modified NemoSkills + vLLM 0.11.2</td>\n</tr>\n<tr>\n<td>Python</td>\n<td>Python 3.12.12</td>\n</tr>\n</table>\n\n<h3>2.2 Time Budget</h3>\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F1563363%2Fef53d83ee10bc3abac80303a2c81184d%2FTime-Budget.png?generation=1778943579039470&alt=media)\n<table border=\"1\" cellpadding=\"6\" cellspacing=\"0\">\n<tr>\n<th>Parameter</th>\n<th>Value</th>\n</tr>\n<tr>\n<td>Total GPU time</td>\n<td>5 hours</td>\n</tr>\n<tr>\n<td>Setup &amp; model loading</td>\n<td>~20 minutes</td>\n</tr>\n<tr>\n<td>Effective inference window</td>\n<td>~280 minutes</td>\n</tr>\n<tr>\n<td>Base per-question budget</td>\n<td>~320 seconds + buffer borrowing</td>\n</tr>\n<tr>\n<td>Global buffer</td>\n<td>350 seconds (dynamically updated)</td>\n</tr>\n</table>\n\n<hr>\n\n<h2>3. Benchmarking Strategy</h2>\n\n<p>\nThree levels of benchmarking were used, applied in the order below as each revealed\na gap that motivated the next.\n</p>\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F1563363%2F59e78444f7f0314db3ae36fc745f4ead%2FBenchmarking.png?generation=1778943755757867&alt=media)\n<h3>3.1 AIMO Reference Problems (First Dataset)</h3>\n\n<p>\nThe first benchmark consisted of 20 problems drawn from the AIMO 2 and AIMO 3\nreference problem sets. The model scored 95% accuracy (19/20).\n</p>\n\n<table border=\"1\" cellpadding=\"6\" cellspacing=\"0\">\n<tr>\n<th>Metric</th>\n<th>Value</th>\n</tr>\n<tr>\n<td>Total problems</td>\n<td>20</td>\n</tr>\n<tr>\n<td>Correct answers</td>\n<td>19/20 (95%)</td>\n</tr>\n<tr>\n<td>Incorrect answer</td>\n<td>Problem #10 (model: 29,443; actual: 8,687)</td>\n</tr>\n<tr>\n<td>Avg time per problem</td>\n<td>230 seconds</td>\n</tr>\n<tr>\n<td>Avg tokens generated</td>\n<td>13,543 tokens</td>\n</tr>\n</table>\n\n<h3>3.2 Internal Benchmark (Second Dataset)</h3>\n\n<p>\nAfter observing the gap between 90–95% reference accuracy and the 42% leaderboard score,\na harder benchmark was constructed from 49 problems sourced from IMO, AMC/AIME,\nand similar archives.\n</p>\n\n<table border=\"1\" cellpadding=\"6\" cellspacing=\"0\">\n<tr>\n<th>Property</th>\n<th>Value</th>\n</tr>\n<tr>\n<td>Total problems</td>\n<td>49</td>\n</tr>\n<tr>\n<td>Problem sources</td>\n<td></td>\n</tr>\n<tr>\n<td>Model accuracy</td>\n<td>65%</td>\n</tr>\n</table>\nInternal BenchMark Dataset - https://huggingface.co/HarpreetK/AIMO3/blob/main/Internal_Benchmark_Final.xlsx\nSources - AOPS,https://matharena.ai/apex/, ARML, HMMT\n\n<h3>3.3 10-Problem Failing Subset</h3>\n\n<p>\nA targeted 10-problem subset was extracted consisting of questions where the previous\nattempt had either returned 29443 (timeout/extraction failure) or produced an incorrect answer.\n</p>\n\n<table border=\"1\" cellpadding=\"6\" cellspacing=\"0\">\n<tr>\n<th>Benchmark</th>\n<th>Score</th>\n<th>Notes</th>\n</tr>\n<tr>\n<td>AIMO Reference (20)</td>\n<td>95% (19/20)</td>\n<td>Too easy; gap not explained</td>\n</tr>\n<tr>\n<td>Internal Benchmark (49)</td>\n<td>65%</td>\n<td>Closer to AIMO 3 difficulty</td>\n</tr>\n<tr>\n<td>AIMO 3 Leaderboard (50)</td>\n<td>21/50 (42%)</td>\n<td>Actual submission</td>\n</tr>\n<tr>\n<td>Best config (50)</td>\n<td>24/50 (48%)</td>\n<td>Not submitted — library deletion</td>\n</tr>\n</table>\n\n<hr>\n\n<h2>4. System Design</h2>\n\n<h3>4.1 Overall Flow Diagram</h3>\n\nFlow Diagram is attached. Please open it independently in a new window to zoom on it\n\n<h3>4.2 Baseline Code and Repository</h3>\n\n<p>\nA modified version of the NemoSkills repository (winner of AIMO 2) was used as the baseline,\nproviding a scaffold for request scheduling and Python code execution sandboxing.\nMCP and LiteLLM abstraction layers were stripped to reduce overhead.\n</p>\n\n<h3>4.3 Async Scheduling (Python asyncio)</h3>\n\n<ul>\n<li>No thread creation overhead</li>\n<li>No heavy context switching</li>\n<li>Handles thousands of concurrent tasks efficiently</li>\n<li>Confirmed by AIMO 2 winning teams</li>\n</ul>\n\n<p>\n<em>\nNote: These were conclusions based on research. Ideally, both approaches would have been compared directly.\n</em>\n</p>\n\n<h3>4.4 Dynamic Buffer Borrowing</h3>\n\n<p>\nThe BufferBorrower class implements a time-pressure-based allocation strategy.\nBorrowable time differed across notebooks:\n</p>\n\n<ul>\n<li>130 seconds in score-21</li>\n<li>95 seconds in score-24</li>\n</ul>\n\n<h3>4.5 Non-Step-Back Prompting (Better than Step-Back)</h3>\n\n<p>\nThe final best-performing approach used a single-phase prompt applied uniformly to all 50 problems.\n</p>\n\n<p>\n<strong>\nThe key jump was from score 18 (Step-Back) to score 24 (Non-Step-Back):\na 6-point improvement.\n</strong>\n</p>\n\n<h3>4.6 Majority Voting Answer Extraction</h3>\n\n<p>\nUp to 8 self-consistent samples are generated per problem.\nMajority voting uses frequency count only.\n</p>\n\n<p>\n<strong>Metric Used:</strong> Exact Match Accuracy.\n</p>\n\n<h3>4.7 vLLM Launch Configuration</h3>\n\n<pre><code>\npython -m nemo_skills.inference.server.serve_vllm \\\n --model=.../gpt-oss-120b/.../1 --port=5000 --num_gpus=1 \\\n --max_model_len=38000 --max_num_batched_tokens=65000 \\\n --max_num_seqs=11 --max-cudagraph-capture-size=2048 \\\n --gpu_memory_utilization=0.95 --kv_cache_dtype=fp8_e4m3 \\\n --enable-prefix-caching --async-scheduling\n</code></pre>\n\n<table border=\"1\" cellpadding=\"6\" cellspacing=\"0\">\n<tr>\n<th>Parameter</th>\n<th>Value</th>\n<th>Rationale</th>\n</tr>\n<tr>\n<td>max_tokens</td>\n<td>38,000</td>\n<td>Upper bound per problem</td>\n</tr>\n<tr>\n<td>tokens_to_generate</td>\n<td>35,940</td>\n<td>max_tokens minus overhead</td>\n</tr>\n<tr>\n<td>max_batch_size</td>\n<td>8</td>\n<td>Number of self-consistent samples</td>\n</tr>\n<tr>\n<td>global_buffer</td>\n<td>350 seconds</td>\n<td>Reserve for hard problems</td>\n</tr>\n<tr>\n<td>temperature</td>\n<td>1.0</td>\n<td>Per NVIDIA NeMo recommendation</td>\n</tr>\n<tr>\n<td>top_p</td>\n<td>1.0</td>\n<td>Per NVIDIA NeMo recommendation</td>\n</tr>\n</table>\n\n<hr>\n\n<h2>5. Backend and Systems Experiments</h2>\n\n<h3>5.1 Backend Comparison</h3>\n\n<ul>\n<li>\n<strong>vLLM:</strong> v0.10.1+gptoss failed to install due to PyTorch nightly conflicts.\n</li>\n<li>\n<strong>TensorRT-LLM:</strong> Engine compilation failed.\n</li>\n<li>\n<strong>Triton:</strong> Functional baseline: 875 tok/s prompt throughput.\n</li>\n<li>\n<strong>Marlin:</strong> Fused GPU kernels yielded 2,708 tok/s prompt throughput.\n</li>\n</ul>\n\n<h3>5.2 Full Experimental Configuration Table</h3>\n\n<p>All 15 configurations tested.</p>\n\n<h3>5.3 Sliding Window Attention</h3>\n\n<p>\nGPT-OSS alternates between full attention and sliding window attention (SWA).\n</p>\n\n<p>\nSliding window sizes 128, 200, and 8,000 were tested.\n</p>\n\n<h3>5.4 Sampling and vLLM Parameter Tuning</h3>\n\n<p>\nTemperature fixed at 1.0 (NVIDIA recommendation).\n</p>\n\n<hr>\n\n<h2>6. Submission History and Iterative Improvements</h2>\n\n<h3>6.1 Score Progression</h3>\n\n<table border=\"1\" cellpadding=\"6\" cellspacing=\"0\">\n<tr>\n<th>Parameter</th>\n<th>Score 18 (SB)</th>\n<th>Score 20</th>\n<th>Score 21 (SUB)</th>\n<th>Score 24 (Best)</th>\n</tr>\n<tr>\n<td>Prompting</td>\n<td>Step-Back full</td>\n<td>Non-SB + dual</td>\n<td>Non-Step-Back</td>\n<td>Non-Step-Back</td>\n</tr>\n<tr>\n<td>Temperature</td>\n<td>Fixed 1.0</td>\n<td>Varied</td>\n<td>Fixed 1.0</td>\n<td>Fixed 1.0</td>\n</tr>\n<tr>\n<td>max_model_len</td>\n<td>65,536</td>\n<td>36,000</td>\n<td>38,000</td>\n<td>80,000</td>\n</tr>\n<tr>\n<td>Leaderboard score</td>\n<td>18/50</td>\n<td>20/50</td>\n<td>21/50</td>\n<td>24/50</td>\n</tr>\n</table>\n\n<h3>6.2 Key Changes Between Attempts</h3>\n\n<h4>Score 18 → 24: Two key changes, +6 points</h4>\n\n<ul>\n<li>Step-Back Phase 1 removed entirely</li>\n<li>Token budget substantially increased</li>\n</ul>\n\n<h4>Score 24 → 21</h4>\n\n<p>\nReduced token budget caused score drop from 24 to 21.\n</p>\n\n<h4>Score 21 → 20</h4>\n\n<p>\nDual-prompt strategy and varied-temperature sampling hurt performance.\n</p>\n\n<hr>\n\n<h2>7. Comparison with State of the Art</h2>\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F1563363%2F98ad341eccad2211873d4d0c07f0e423%2FSOTA%20Comparison.png?generation=1778953075190961&alt=media)\n\nBelow models were added to SOTA Comparison\nQwen (without tool calling),\nGemini Pro 3.1,\nand Claude Opus 4.7.\nOne particularly interesting observation was that Gemini Pro 3.1 and Claude Opus 4.7 appear to be highly complementary systems.\n\nTogether, the two models successfully solved every question in my curated evaluation dataset.\n\nMore specifically:\n\nClaude demonstrated stronger mathematical reasoning overall,\nespecially on difficult mathematical problems,\nwhile both models solved easier problems reliably,\nand on harder problems, each model solved cases that the other failed to solve.\n<h2>8. Key Insights (Summary)</h2>\n\n<ul>\n<li>Time pressure is the primary bottleneck.</li>\n<li>Async scheduling flag in vLLM is extremely important.</li>\n<li>Token budget dominates accuracy.</li>\n<li>Backend choice significantly affects throughput.</li>\n<li>Dataset difficulty calibration is critical.</li>\n<li>Geometry-heavy problems appeared harder.</li>\n</ul>\n\n<hr>\n\n<h2>9. Limitations</h2>\n\n<ul>\n<li>No fine-tuning</li>\n<li>Limited benchmark coverage</li>\n<li>Single-run experiments</li>\n</ul>\n\n<hr>\n\n<h2>10. Future Work</h2>\n\n<ul>\n<li>Complete backend investigation</li>\n<li>Partial-response answer extraction</li>\n<li>Enable torch_compile and torch_dynamo</li>\n<li>Hybrid async-threaded scheduling</li>\n<li>Verifier models</li>\n<li>SGLang + fused MoE optimization</li>\n<li>Fine-tuning on post-June-2024 IMO data</li>\n</ul>\n\n<hr>\n\n<h2>11. Reproducibility Checklist</h2>\n\n<p>\nHuggingFace repo:\n<a href=\"https://huggingface.co/HarpreetK/AIMO3\">\nhttps://huggingface.co/HarpreetK/AIMO3\n</a>\n</p>\n\n<table border=\"1\" cellpadding=\"6\" cellspacing=\"0\">\n<tr>\n<th>Artifact</th>\n<th>Location / Value</th>\n<th>Status</th>\n</tr>\n<tr>\n<td>Base model</td>\n<td>GPT-OSS-120B</td>\n<td>Provided</td>\n</tr>\n<tr>\n<td>Submitted notebook</td>\n<td>gpt-oss-score21.ipynb</td>\n<td>Provided</td>\n</tr>\n<tr>\n<td>Best notebook (24)</td>\n<td>gpt-oss-nostepback-score24.ipynb</td>\n<td>Provided</td>\n</tr>\n<tr>\n<td>Backend</td>\n<td>Marlin (via vLLM 0.11.2)</td>\n<td>Provided</td>\n</tr>\n</table>\n\n<hr>\n\n<h2>13. Appendix</h2>\nrefer the pdf for the same"
    }
  ],
  "complete": true,
  "source": "live",
  "fetched_at": "2026-10-20T04:26:12Z",
  "competition_id": 118448,
  "competition_slug": "ai-mathematical-olympiad-progress-prize-3",
  "team_id": 15126705,
  "solution_url": "/competitions/ai-mathematical-olympiad-progress-prize-3/writeups/aimo3-writeup-preet"
}