{
  "id": 517206,
  "title": "3rd place solution",
  "content": "<h1>vLLM with some tricks</h1>\n<p><strong><a href=\"https://www.kaggle.com/code/davidd2/3rd-place-solution-afterexams\" target=\"_blank\">Code for our final solution can be found here.</a></strong></p>\n<p>Our final selected solution was an adaptation of the notebook of <a href=\"https://www.kaggle.com/code/abdurrafae/improved-code-interpretation\" target=\"_blank\">AbdurRafae</a>. We used DeepSeek-Math-7B-RL without any finetuning and did majority voting with a scoring rule we made.</p>\n<h2>vLLM</h2>\n<p>We decided to go with vLLM due to the better speed when compared to the Huggingface Transformers.</p>\n<ul>\n<li>We generate a large number of candidate solutions (usually between than 120-160). </li>\n<li>We found that making the KV cache be in FP16 improved our score.</li>\n</ul>\n<h2>Generation</h2>\n<p>We generate the solutions in one batch using iterations. An iteration is made for each code that has to be run.</p>\n<ul>\n<li>We found that a large number of iterations &gt;6 helped the score.</li>\n<li>To ensure the model consistently outputs the answer in the \\boxed{} format, we used the following approach. When the generation finishes without an answer, we append a string such as \"The final answer is \\boxed{\" to the output and generate a few more tokens. This prompt forces the model to output the answer correctly.</li>\n<li>For each iteration we took all code that needed to be executed and did it in parallel in batches. This has reduced the amount of time we spent on code execution significantly.</li>\n</ul>\n<h2>Scoring rule</h2>\n<p>Regarding the scoring rule we found that at least on our validation, the model often had two types of errors as the final result:</p>\n<ol>\n<li>Numbers which are small (&lt;10), this often happened because of errors in the code.</li>\n<li>Numbers which were part of the problem statement. We found this to be especially pronounced and the number of times this happened outweighed the chances for the problem statement to actually contain the answer.</li>\n</ol>\n<p>We thus penalized these results as a percentage of the total number of generations we attempted. We have observed a significant boost in score by penalizing numbers from the problem statement.</p>\n<h1>What else we tried</h1>\n<p>For the final submission we chose this old version due to the possibility of having ties in the final leaderboard.<br>\nWe have also created a number of different versions.</p>\n<h3>BF16</h3>\n<p>We observed that running the model in BF16 improved performance and thus we tried to make our solution work with BF16. The problem is that vLLM does not support this by default on the T4s. One can however perform the computations in FP32 and cast back to BF16.</p>\n<p>We have thus slightly modified the vLLM library code to remove the check for BF16 support and wrapped the attention module so we convert back and forth between fp32 and bf16.</p>\n<p>We thus have two versions of the libraries:</p>\n<ul>\n<li><a href=\"https://www.kaggle.com/datasets/davidd2/vllm-0-4-0-post1-bf16/data\" target=\"_blank\">Full bf16</a></li>\n<li><a href=\"https://www.kaggle.com/datasets/davidd2/vllm-0-4-0-post1-only-attn-in-bf16/data\" target=\"_blank\">Only attention and kv cache in bf16</a><br>\nThe changes we made to vLLM were pretty minimal: <a href=\"https://github.com/RD211/vllm-bf16\" target=\"_blank\">Github</a></li>\n</ul>\n<p>We found that the making the MLP be in bf16 made the model very slow and thus we also created the version that keeps everything but the MLP in bf16.<br>\nModels with these libraries performed well but were not stable enough for our liking. They gave us the highest score we have on our validation but did not go over 25 on the public leaderboard.</p>\n<h3>Executing code during generation</h3>\n<p>We observed that making multiple calls to vllm took a significant amount of time, further one cannot early exit reliably with intermediate results of solutions. We have thus made a new version of the notebook we initially scored 26-27 with that feeds the result of the code generation directly back to the model without needing two vllm generate calls.</p>\n<p>We do this by using the logit processors and forcing the model to output the tokens of the code output. We also enforce all early breaking and pruning rules directly in the logit processor function.<br>\n<a href=\"https://www.kaggle.com/code/davidd2/vllm-continous-generation-with-code-outputs/notebook\" target=\"_blank\">Code for this can be found here</a><br>\nWe personally liked this submission more than our final one but due to time constraints we could not make it score as high as the old one</p>",
  "comments": [
    {
      "id": 2906128,
      "author_name": "Geremie Yeo",
      "author_url": "",
      "post_date": "2024-07-05T11:11:13.317000",
      "content": "<pre><code> Numbers which are small (&lt;), this often happened because  errors   code.\n Numbers which were part   problem statement. We found this  be especially pronounced     times this happened outweighed  chances   problem statement  actually contain  answer.\n</code></pre>\n<p>Nice observation! We also did something very similar for postprocessing 😀 on lucky runs it improved CV by up till 6-7 points!</p>\n<p>AIME 2022-24 we observed from a trial run that 25 out of 61 problems generated a single digit answer as the most frequent vote itself! Its not code errors but a model behaviour LOL</p>",
      "votes": 4,
      "replies": [
        {
          "id": 2906161,
          "author_name": "David Dinucu-Jianu",
          "author_url": "",
          "post_date": "2024-07-05T11:54:23.987000",
          "content": "<p>Interestingly at least from our tests most of the wrong small number solutions were also part of the problem statement.<br>\nOur other submission which only penalized 0 and applied the second rule got 20 on private instead of 21.</p>",
          "votes": 1,
          "replies": [
            {
              "id": 2908298,
              "author_name": "Geremie Yeo",
              "author_url": "",
              "post_date": "2024-07-06T08:24:51.353000",
              "content": "<p>We are using transformers.generate not vLLM so probably made a larger impact lol since the number of iterations is lower. </p>\n<p>We tried vLLM but didn’t get more than 13 (let alone the mysterious timeouts which we got from vLLM), even for runs where the CV is high (&gt;25/50 for old AIME on Kaggle kernel) - don’t know what actually went wrong 😑 2 subs per day is just not enough to trial and error by shooting in the dark. I looked at other implementations of vLLM that scored 20+ on public after the comp - still not sure how is it much different from ours that fixes the “bug” 😓 it still confuses me why it works well</p>",
              "votes": 4,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 2909770,
      "author_name": "Oleg Yaroshevskiy",
      "author_url": "",
      "post_date": "2024-07-07T09:46:51.457000",
      "content": "<p>Congratulations! Great ML engineering. \"We found that the making the MLP be in bf16 made the model very slow\" --- What profiling tools have you used to detect and troubleshoot performance issues?</p>",
      "votes": 2,
      "replies": [
        {
          "id": 2909795,
          "author_name": "David Dinucu-Jianu",
          "author_url": "",
          "post_date": "2024-07-07T10:15:45.880000",
          "content": "<p>We just measured how many generations it could do on average on our validation set on Kaggle.<br>\nThe process was a bit slow since we did not use T4s while making the modification so we had to upload it to kaggle to test it.</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 2908201,
      "author_name": "C R Suthikshn Kumar",
      "author_url": "",
      "post_date": "2024-07-06T06:11:11.443000",
      "content": "<p>Congratulations on achieving 3rd position in this competition. Thanks for sharing details of your solution.<br>\nVery interesting and innovative indeed.</p>",
      "votes": -1,
      "replies": []
    },
    {
      "id": 2906325,
      "author_name": "Tong Hui Kang",
      "author_url": "",
      "post_date": "2024-07-05T14:13:07.193000",
      "content": "<p>Seems like you batch run the inferences, and then batch run the codes, and then repeat until the time is up.</p>\n<p>If my interpretation is correct, the LLM is idle when the code is running.</p>\n<p>Have your tried building a system that runs another batch of inferences while the code is running?</p>",
      "votes": 0,
      "replies": [
        {
          "id": 2906420,
          "author_name": "David Dinucu-Jianu",
          "author_url": "",
          "post_date": "2024-07-05T15:13:44.647000",
          "content": "<p>Yes indeed the GPUs are idle during code execution. We did not try to do them asynchronously because the speed was already sufficient (on our validation set more generations did not improve the score).</p>\n<p>Although while trying to make the BF16 submission work we did experiment with the AsyncLLM thing from vLLM but abandoned it cause it was close to the competition deadline.</p>",
          "votes": 1,
          "replies": []
        }
      ]
    }
  ],
  "comment_count": 8,
  "messages": [
    {
      "id": 2906109,
      "postDate": "2024-07-05T11:01:11.183Z",
      "content": "<h1>vLLM with some tricks</h1>\n<p><strong><a href=\"https://www.kaggle.com/code/davidd2/3rd-place-solution-afterexams\" target=\"_blank\">Code for our final solution can be found here.</a></strong></p>\n<p>Our final selected solution was an adaptation of the notebook of <a href=\"https://www.kaggle.com/code/abdurrafae/improved-code-interpretation\" target=\"_blank\">AbdurRafae</a>. We used DeepSeek-Math-7B-RL without any finetuning and did majority voting with a scoring rule we made.</p>\n<h2>vLLM</h2>\n<p>We decided to go with vLLM due to the better speed when compared to the Huggingface Transformers.</p>\n<ul>\n<li>We generate a large number of candidate solutions (usually between than 120-160). </li>\n<li>We found that making the KV cache be in FP16 improved our score.</li>\n</ul>\n<h2>Generation</h2>\n<p>We generate the solutions in one batch using iterations. An iteration is made for each code that has to be run.</p>\n<ul>\n<li>We found that a large number of iterations &gt;6 helped the score.</li>\n<li>To ensure the model consistently outputs the answer in the \\boxed{} format, we used the following approach. When the generation finishes without an answer, we append a string such as \"The final answer is \\boxed{\" to the output and generate a few more tokens. This prompt forces the model to output the answer correctly.</li>\n<li>For each iteration we took all code that needed to be executed and did it in parallel in batches. This has reduced the amount of time we spent on code execution significantly.</li>\n</ul>\n<h2>Scoring rule</h2>\n<p>Regarding the scoring rule we found that at least on our validation, the model often had two types of errors as the final result:</p>\n<ol>\n<li>Numbers which are small (&lt;10), this often happened because of errors in the code.</li>\n<li>Numbers which were part of the problem statement. We found this to be especially pronounced and the number of times this happened outweighed the chances for the problem statement to actually contain the answer.</li>\n</ol>\n<p>We thus penalized these results as a percentage of the total number of generations we attempted. We have observed a significant boost in score by penalizing numbers from the problem statement.</p>\n<h1>What else we tried</h1>\n<p>For the final submission we chose this old version due to the possibility of having ties in the final leaderboard.<br>\nWe have also created a number of different versions.</p>\n<h3>BF16</h3>\n<p>We observed that running the model in BF16 improved performance and thus we tried to make our solution work with BF16. The problem is that vLLM does not support this by default on the T4s. One can however perform the computations in FP32 and cast back to BF16.</p>\n<p>We have thus slightly modified the vLLM library code to remove the check for BF16 support and wrapped the attention module so we convert back and forth between fp32 and bf16.</p>\n<p>We thus have two versions of the libraries:</p>\n<ul>\n<li><a href=\"https://www.kaggle.com/datasets/davidd2/vllm-0-4-0-post1-bf16/data\" target=\"_blank\">Full bf16</a></li>\n<li><a href=\"https://www.kaggle.com/datasets/davidd2/vllm-0-4-0-post1-only-attn-in-bf16/data\" target=\"_blank\">Only attention and kv cache in bf16</a><br>\nThe changes we made to vLLM were pretty minimal: <a href=\"https://github.com/RD211/vllm-bf16\" target=\"_blank\">Github</a></li>\n</ul>\n<p>We found that the making the MLP be in bf16 made the model very slow and thus we also created the version that keeps everything but the MLP in bf16.<br>\nModels with these libraries performed well but were not stable enough for our liking. They gave us the highest score we have on our validation but did not go over 25 on the public leaderboard.</p>\n<h3>Executing code during generation</h3>\n<p>We observed that making multiple calls to vllm took a significant amount of time, further one cannot early exit reliably with intermediate results of solutions. We have thus made a new version of the notebook we initially scored 26-27 with that feeds the result of the code generation directly back to the model without needing two vllm generate calls.</p>\n<p>We do this by using the logit processors and forcing the model to output the tokens of the code output. We also enforce all early breaking and pruning rules directly in the logit processor function.<br>\n<a href=\"https://www.kaggle.com/code/davidd2/vllm-continous-generation-with-code-outputs/notebook\" target=\"_blank\">Code for this can be found here</a><br>\nWe personally liked this submission more than our final one but due to time constraints we could not make it score as high as the old one</p>",
      "rawMarkdown": "# vLLM with some tricks\n\n**[Code for our final solution can be found here.](https://www.kaggle.com/code/davidd2/3rd-place-solution-afterexams)**\n\nOur final selected solution was an adaptation of the notebook of [AbdurRafae](https://www.kaggle.com/code/abdurrafae/improved-code-interpretation). We used DeepSeek-Math-7B-RL without any finetuning and did majority voting with a scoring rule we made.\n\n## vLLM\nWe decided to go with vLLM due to the better speed when compared to the Huggingface Transformers.\n- We generate a large number of candidate solutions (usually between than 120-160). \n- We found that making the KV cache be in FP16 improved our score.\n\n## Generation\nWe generate the solutions in one batch using iterations. An iteration is made for each code that has to be run.\n- We found that a large number of iterations >6 helped the score.\n- To ensure the model consistently outputs the answer in the \\boxed{} format, we used the following approach. When the generation finishes without an answer, we append a string such as \"The final answer is \\boxed{\" to the output and generate a few more tokens. This prompt forces the model to output the answer correctly.\n- For each iteration we took all code that needed to be executed and did it in parallel in batches. This has reduced the amount of time we spent on code execution significantly.\n\n## Scoring rule\nRegarding the scoring rule we found that at least on our validation, the model often had two types of errors as the final result:\n1. Numbers which are small (<10), this often happened because of errors in the code.\n2. Numbers which were part of the problem statement. We found this to be especially pronounced and the number of times this happened outweighed the chances for the problem statement to actually contain the answer.\n\nWe thus penalized these results as a percentage of the total number of generations we attempted. We have observed a significant boost in score by penalizing numbers from the problem statement.\n\n# What else we tried\nFor the final submission we chose this old version due to the possibility of having ties in the final leaderboard.\nWe have also created a number of different versions.\n\n### BF16\nWe observed that running the model in BF16 improved performance and thus we tried to make our solution work with BF16. The problem is that vLLM does not support this by default on the T4s. One can however perform the computations in FP32 and cast back to BF16.\n\nWe have thus slightly modified the vLLM library code to remove the check for BF16 support and wrapped the attention module so we convert back and forth between fp32 and bf16.\n\nWe thus have two versions of the libraries:\n- [Full bf16](https://www.kaggle.com/datasets/davidd2/vllm-0-4-0-post1-bf16/data)\n- [Only attention and kv cache in bf16](https://www.kaggle.com/datasets/davidd2/vllm-0-4-0-post1-only-attn-in-bf16/data)\nThe changes we made to vLLM were pretty minimal: [Github](https://github.com/RD211/vllm-bf16)\n\nWe found that the making the MLP be in bf16 made the model very slow and thus we also created the version that keeps everything but the MLP in bf16.\nModels with these libraries performed well but were not stable enough for our liking. They gave us the highest score we have on our validation but did not go over 25 on the public leaderboard.\n\n### Executing code during generation\nWe observed that making multiple calls to vllm took a significant amount of time, further one cannot early exit reliably with intermediate results of solutions. We have thus made a new version of the notebook we initially scored 26-27 with that feeds the result of the code generation directly back to the model without needing two vllm generate calls.\n\nWe do this by using the logit processors and forcing the model to output the tokens of the code output. We also enforce all early breaking and pruning rules directly in the logit processor function.\n[Code for this can be found here](https://www.kaggle.com/code/davidd2/vllm-continous-generation-with-code-outputs/notebook)\nWe personally liked this submission more than our final one but due to time constraints we could not make it score as high as the old one\n",
      "votes": 72
    },
    {
      "id": 2906128,
      "postDate": "2024-07-05T11:11:13.317Z",
      "content": "<pre><code> Numbers which are small (&lt;), this often happened because  errors   code.\n Numbers which were part   problem statement. We found this  be especially pronounced     times this happened outweighed  chances   problem statement  actually contain  answer.\n</code></pre>\n<p>Nice observation! We also did something very similar for postprocessing 😀 on lucky runs it improved CV by up till 6-7 points!</p>\n<p>AIME 2022-24 we observed from a trial run that 25 out of 61 problems generated a single digit answer as the most frequent vote itself! Its not code errors but a model behaviour LOL</p>",
      "rawMarkdown": "```\n1. Numbers which are small (<10), this often happened because of errors in the code.\n2. Numbers which were part of the problem statement. We found this to be especially pronounced and the number of times this happened outweighed the chances for the problem statement to actually contain the answer.\n```\n\nNice observation! We also did something very similar for postprocessing 😀 on lucky runs it improved CV by up till 6-7 points!\n\nAIME 2022-24 we observed from a trial run that 25 out of 61 problems generated a single digit answer as the most frequent vote itself! Its not code errors but a model behaviour LOL",
      "votes": 4,
      "replies": [
        {
          "id": 2906161,
          "postDate": "2024-07-05T11:54:23.987Z",
          "content": "<p>Interestingly at least from our tests most of the wrong small number solutions were also part of the problem statement.<br>\nOur other submission which only penalized 0 and applied the second rule got 20 on private instead of 21.</p>",
          "rawMarkdown": "Interestingly at least from our tests most of the wrong small number solutions were also part of the problem statement.\nOur other submission which only penalized 0 and applied the second rule got 20 on private instead of 21.",
          "votes": 1,
          "replies": [
            {
              "id": 2908298,
              "postDate": "2024-07-06T08:24:51.353Z",
              "content": "<p>We are using transformers.generate not vLLM so probably made a larger impact lol since the number of iterations is lower. </p>\n<p>We tried vLLM but didn’t get more than 13 (let alone the mysterious timeouts which we got from vLLM), even for runs where the CV is high (&gt;25/50 for old AIME on Kaggle kernel) - don’t know what actually went wrong 😑 2 subs per day is just not enough to trial and error by shooting in the dark. I looked at other implementations of vLLM that scored 20+ on public after the comp - still not sure how is it much different from ours that fixes the “bug” 😓 it still confuses me why it works well</p>",
              "rawMarkdown": "We are using transformers.generate not vLLM so probably made a larger impact lol since the number of iterations is lower. \n\nWe tried vLLM but didn’t get more than 13 (let alone the mysterious timeouts which we got from vLLM), even for runs where the CV is high (>25/50 for old AIME on Kaggle kernel) - don’t know what actually went wrong 😑 2 subs per day is just not enough to trial and error by shooting in the dark. I looked at other implementations of vLLM that scored 20+ on public after the comp - still not sure how is it much different from ours that fixes the “bug” 😓 it still confuses me why it works well",
              "votes": 4
            }
          ]
        }
      ]
    },
    {
      "id": 2909770,
      "postDate": "2024-07-07T09:46:51.457Z",
      "content": "<p>Congratulations! Great ML engineering. \"We found that the making the MLP be in bf16 made the model very slow\" --- What profiling tools have you used to detect and troubleshoot performance issues?</p>",
      "rawMarkdown": "Congratulations! Great ML engineering. \"We found that the making the MLP be in bf16 made the model very slow\" --- What profiling tools have you used to detect and troubleshoot performance issues?",
      "votes": 2,
      "replies": [
        {
          "id": 2909795,
          "postDate": "2024-07-07T10:15:45.880Z",
          "content": "<p>We just measured how many generations it could do on average on our validation set on Kaggle.<br>\nThe process was a bit slow since we did not use T4s while making the modification so we had to upload it to kaggle to test it.</p>",
          "rawMarkdown": "We just measured how many generations it could do on average on our validation set on Kaggle.\nThe process was a bit slow since we did not use T4s while making the modification so we had to upload it to kaggle to test it.",
          "votes": 1
        }
      ]
    },
    {
      "id": 2908201,
      "postDate": "2024-07-06T06:11:11.443Z",
      "content": "<p>Congratulations on achieving 3rd position in this competition. Thanks for sharing details of your solution.<br>\nVery interesting and innovative indeed.</p>",
      "rawMarkdown": "Congratulations on achieving 3rd position in this competition. Thanks for sharing details of your solution.\nVery interesting and innovative indeed.",
      "votes": -1
    },
    {
      "id": 2906325,
      "postDate": "2024-07-05T14:13:07.193Z",
      "content": "<p>Seems like you batch run the inferences, and then batch run the codes, and then repeat until the time is up.</p>\n<p>If my interpretation is correct, the LLM is idle when the code is running.</p>\n<p>Have your tried building a system that runs another batch of inferences while the code is running?</p>",
      "rawMarkdown": "Seems like you batch run the inferences, and then batch run the codes, and then repeat until the time is up.\n\nIf my interpretation is correct, the LLM is idle when the code is running.\n\nHave your tried building a system that runs another batch of inferences while the code is running?",
      "replies": [
        {
          "id": 2906420,
          "postDate": "2024-07-05T15:13:44.647Z",
          "content": "<p>Yes indeed the GPUs are idle during code execution. We did not try to do them asynchronously because the speed was already sufficient (on our validation set more generations did not improve the score).</p>\n<p>Although while trying to make the BF16 submission work we did experiment with the AsyncLLM thing from vLLM but abandoned it cause it was close to the competition deadline.</p>",
          "rawMarkdown": "Yes indeed the GPUs are idle during code execution. We did not try to do them asynchronously because the speed was already sufficient (on our validation set more generations did not improve the score).\n\nAlthough while trying to make the BF16 submission work we did experiment with the AsyncLLM thing from vLLM but abandoned it cause it was close to the competition deadline.",
          "votes": 1
        }
      ]
    }
  ],
  "complete": true,
  "source": "live",
  "fetched_at": "2026-10-20T06:54:20Z",
  "competition_id": 73231,
  "competition_slug": "ai-mathematical-olympiad-prize",
  "team_id": 11919070,
  "solution_url": "/competitions/ai-mathematical-olympiad-prize/writeups/after-exams-3rd-place-solution"
}