{
  "id": 581175,
  "title": "84th Place Solution: SDXL-Turbo -> GPU SVG Conversion + OCR Decoy",
  "content": "<p>After hanging out in the top couple places for a long time - wish I ranked higher than 84th place - but happy to see other folks make progress!</p>\n<p>My solution:<br>\n<a href=\"https://www.kaggle.com/code/richolson/sdxl-turbo-svg-new-scoring-metric\" target=\"_blank\">https://www.kaggle.com/code/richolson/sdxl-turbo-svg-new-scoring-metric</a></p>\n<p>Short version:<br>\n<strong>SDXL-Turbo -&gt; GPU Powered SVG Conversion + OCR Decoy -&gt; Grade with Scoring Metric</strong></p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F13585160%2Fbe0f79d086fb0c0d16d72482f562b94b%2FScreenshot%202025-05-28%20at%201.16.42PM.png?generation=1748463425395096&amp;alt=media\" alt=\"\"></p>\n<p>I really wanted to explore actually using an LLM and adversarial approaches more - but life got busy…</p>\n<h1>General Approach</h1>\n<pre><code> Use SDXL-Turbo  generate images  prompts\n Convert images  SVGs (GPU powered!)\n Append  OCR decoy   SVGs  prevent hallucination\n Use competition metric  grade\n Repeat steps   many times  possible  ~ minute -  choose best scoring image\n</code></pre>\n<p>All steps combined take about 5 seconds - so up to about 12 attempts are possible per prompt.</p>\n<h1>Bitmap Generation: SDXL Turbo</h1>\n<p>I tried a few different image models - but none worked better for me than SDXL turbo.  I credit this partially due to SDXL Turbo being able to crank out images in ~700ms.</p>\n<p>When creating the image prompt - I rotate through various prefixes to both optimize for SVG conversion and increase output variety:</p>\n<pre><code>.prompt_prefixes = [,\n                            ,\n                            ,\n                            ,\n                            ,\n                            \n                           ]\n</code></pre>\n<p>Flux Schnell produced nicer images - but was much slower than SDXL Turbo (~6 seconds).  This reduced number of possible attempts per prompt - and was not able to use it to improve score.</p>\n<p>Sana Sprint also produced nicer images than SDXL Turbo while only being maybe 2x slower (around 1.6 seconds).  Only had slight impact on number of attempts possible per prompt - but again - did not help with LB.</p>\n<h1>GPU Accelerated SVG Conversion</h1>\n<p>This code is an updated version of what I'd shared earlier in my baseline notebook - but I did a bunch of tweaks to improve quality and performance.  I was thinking we should be able to use GPU for this - so I got a little help…. Here's Claude Sonnet 3.7 to explain:</p>\n<blockquote>\n  <p>Thanks Rich - here's what I did for the GPU-accelerated SVG conversion!</p>\n  <h2>GPU-Accelerated SVG Conversion Overview</h2>\n  <p>The code implements a fast bitmap-to-SVG pipeline using GPU acceleration and smart feature extraction.</p>\n  <h2>Key Components:</h2>\n  <p>GPU-Accelerated K-means Clustering - Uses CUDA kernels to quickly reduce images to 12 colors while maintaining visual quality.<br>\n  Hierarchical Feature Extraction - Identifies the most important visual elements by analyzing color <br>\n  frequency, area, and proximity to center, ensuring key features are preserved.<br>\n  Adaptive Space Management - Two-pass approach that first adds critical features at full quality, then fills remaining space with simplified versions of other elements.<br>\n  Smart Polygon Simplification - Numba-accelerated functions offer multiple simplification levels to balance file size with visual fidelity.</p>\n  <h2>Performance:</h2>\n  <p>CuPy for GPU computations<br>\n  Numba JIT compilation<br>\n  Pre-compiled kernels via init_svg_gpu()</p>\n  <h2>Result</h2>\n  <p>Sub-second SVG conversion producing compact, visually accurate vectors - perfect for your rapid iteration approach where you needed multiple candidates within tight time constraints!</p>\n</blockquote>\n<p>(ChatGPT also chipped in a bit)</p>\n<h1>OCR Decoy</h1>\n<p>I also implement an anti-OCR hallucination decoy I shared earlier here: <a href=\"https://www.kaggle.com/code/richolson/let-s-defeat-ocr-easy-lb-boost\" target=\"_blank\">https://www.kaggle.com/code/richolson/let-s-defeat-ocr-easy-lb-boost</a></p>\n<p>A small \"o\" shape to the SVG - which uses something around 300 bytes (so we limit SVG conversion to 9650 bytes).</p>\n<pre><code>This gives  OCR detection something  look  -  hopefully reliably count   ( opposed   positives)\nUses nd darkest  nd lightest colors  minimize visual impact (avoid hurting aesthetic score)\nRandomized  bit - so exact additional  varies  bit\n</code></pre>\n<p>It's not perfect - but it addresses the vast majority of hallucination issues.  I tried higher contrast and more obvious shapes like an 'A' - but it didn't further improve score (possibly due to decreases in aesthetic score.)</p>\n<h1>Scoring / Prompt Questions</h1>\n<p>Each image is passed through the scoring metric to see how well it scores against the prompt.</p>\n<p>I had the best LB results using these 2 questions:</p>\n<pre><code>questions = [\n        ,\n        ,\n    ]\n</code></pre>\n<p>With the 10B / 448x448 verison of PaliGemma time for scoring both questions is about 3.8 seconds.  Going to a single question allows more images to be processed - but resulted in lower LB scores.  </p>\n<p>I also experimented with the 3B Paligemma and 10B / 224x224 version.  Both scored much faster - but reduced LB scores even though they were able to evaluate more images.</p>\n<p>I did create several versions of my notebook that used Qwen for TIFA question generation based on <a href=\"https://www.kaggle.com/code/richolson/tifa-question-generation-qwen-vs-tuned-llama\" target=\"_blank\">https://www.kaggle.com/code/richolson/tifa-question-generation-qwen-vs-tuned-llama</a> - but I never managed to improve LB performance vs. just using the static questions.</p>\n<h1>Thanks!</h1>\n<p>Thanks for the great competition everyone!  I had a lot of fun.  Special thanks to <a href=\"https://www.kaggle.com/ryanholbrook\" target=\"_blank\">@ryanholbrook</a> for putting this together.</p>\n<p>Let's figure out a way to -really- limit to just LLMs and do this again!</p>",
  "comments": [
    {
      "id": 3211963,
      "author_name": "Mikhail Golubchik",
      "author_url": "",
      "post_date": "2025-05-29T05:39:18.610000",
      "content": "<p>Great idea to use gpu for svg conversation! And thanks for your notebooks. A now regret not using your small and aes saving ocr decoy. It was very usefull on private LB.</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 3211943,
      "author_name": "",
      "author_url": "",
      "post_date": "2025-05-29T04:46:52.123000",
      "content": "",
      "votes": 0,
      "replies": []
    }
  ],
  "comment_count": 2,
  "messages": [
    {
      "id": 3211775,
      "postDate": "2025-05-28T20:22:55.820Z",
      "content": "<p>After hanging out in the top couple places for a long time - wish I ranked higher than 84th place - but happy to see other folks make progress!</p>\n<p>My solution:<br>\n<a href=\"https://www.kaggle.com/code/richolson/sdxl-turbo-svg-new-scoring-metric\" target=\"_blank\">https://www.kaggle.com/code/richolson/sdxl-turbo-svg-new-scoring-metric</a></p>\n<p>Short version:<br>\n<strong>SDXL-Turbo -&gt; GPU Powered SVG Conversion + OCR Decoy -&gt; Grade with Scoring Metric</strong></p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F13585160%2Fbe0f79d086fb0c0d16d72482f562b94b%2FScreenshot%202025-05-28%20at%201.16.42PM.png?generation=1748463425395096&amp;alt=media\" alt=\"\"></p>\n<p>I really wanted to explore actually using an LLM and adversarial approaches more - but life got busy…</p>\n<h1>General Approach</h1>\n<pre><code> Use SDXL-Turbo  generate images  prompts\n Convert images  SVGs (GPU powered!)\n Append  OCR decoy   SVGs  prevent hallucination\n Use competition metric  grade\n Repeat steps   many times  possible  ~ minute -  choose best scoring image\n</code></pre>\n<p>All steps combined take about 5 seconds - so up to about 12 attempts are possible per prompt.</p>\n<h1>Bitmap Generation: SDXL Turbo</h1>\n<p>I tried a few different image models - but none worked better for me than SDXL turbo.  I credit this partially due to SDXL Turbo being able to crank out images in ~700ms.</p>\n<p>When creating the image prompt - I rotate through various prefixes to both optimize for SVG conversion and increase output variety:</p>\n<pre><code>.prompt_prefixes = [,\n                            ,\n                            ,\n                            ,\n                            ,\n                            \n                           ]\n</code></pre>\n<p>Flux Schnell produced nicer images - but was much slower than SDXL Turbo (~6 seconds).  This reduced number of possible attempts per prompt - and was not able to use it to improve score.</p>\n<p>Sana Sprint also produced nicer images than SDXL Turbo while only being maybe 2x slower (around 1.6 seconds).  Only had slight impact on number of attempts possible per prompt - but again - did not help with LB.</p>\n<h1>GPU Accelerated SVG Conversion</h1>\n<p>This code is an updated version of what I'd shared earlier in my baseline notebook - but I did a bunch of tweaks to improve quality and performance.  I was thinking we should be able to use GPU for this - so I got a little help…. Here's Claude Sonnet 3.7 to explain:</p>\n<blockquote>\n  <p>Thanks Rich - here's what I did for the GPU-accelerated SVG conversion!</p>\n  <h2>GPU-Accelerated SVG Conversion Overview</h2>\n  <p>The code implements a fast bitmap-to-SVG pipeline using GPU acceleration and smart feature extraction.</p>\n  <h2>Key Components:</h2>\n  <p>GPU-Accelerated K-means Clustering - Uses CUDA kernels to quickly reduce images to 12 colors while maintaining visual quality.<br>\n  Hierarchical Feature Extraction - Identifies the most important visual elements by analyzing color <br>\n  frequency, area, and proximity to center, ensuring key features are preserved.<br>\n  Adaptive Space Management - Two-pass approach that first adds critical features at full quality, then fills remaining space with simplified versions of other elements.<br>\n  Smart Polygon Simplification - Numba-accelerated functions offer multiple simplification levels to balance file size with visual fidelity.</p>\n  <h2>Performance:</h2>\n  <p>CuPy for GPU computations<br>\n  Numba JIT compilation<br>\n  Pre-compiled kernels via init_svg_gpu()</p>\n  <h2>Result</h2>\n  <p>Sub-second SVG conversion producing compact, visually accurate vectors - perfect for your rapid iteration approach where you needed multiple candidates within tight time constraints!</p>\n</blockquote>\n<p>(ChatGPT also chipped in a bit)</p>\n<h1>OCR Decoy</h1>\n<p>I also implement an anti-OCR hallucination decoy I shared earlier here: <a href=\"https://www.kaggle.com/code/richolson/let-s-defeat-ocr-easy-lb-boost\" target=\"_blank\">https://www.kaggle.com/code/richolson/let-s-defeat-ocr-easy-lb-boost</a></p>\n<p>A small \"o\" shape to the SVG - which uses something around 300 bytes (so we limit SVG conversion to 9650 bytes).</p>\n<pre><code>This gives  OCR detection something  look  -  hopefully reliably count   ( opposed   positives)\nUses nd darkest  nd lightest colors  minimize visual impact (avoid hurting aesthetic score)\nRandomized  bit - so exact additional  varies  bit\n</code></pre>\n<p>It's not perfect - but it addresses the vast majority of hallucination issues.  I tried higher contrast and more obvious shapes like an 'A' - but it didn't further improve score (possibly due to decreases in aesthetic score.)</p>\n<h1>Scoring / Prompt Questions</h1>\n<p>Each image is passed through the scoring metric to see how well it scores against the prompt.</p>\n<p>I had the best LB results using these 2 questions:</p>\n<pre><code>questions = [\n        ,\n        ,\n    ]\n</code></pre>\n<p>With the 10B / 448x448 verison of PaliGemma time for scoring both questions is about 3.8 seconds.  Going to a single question allows more images to be processed - but resulted in lower LB scores.  </p>\n<p>I also experimented with the 3B Paligemma and 10B / 224x224 version.  Both scored much faster - but reduced LB scores even though they were able to evaluate more images.</p>\n<p>I did create several versions of my notebook that used Qwen for TIFA question generation based on <a href=\"https://www.kaggle.com/code/richolson/tifa-question-generation-qwen-vs-tuned-llama\" target=\"_blank\">https://www.kaggle.com/code/richolson/tifa-question-generation-qwen-vs-tuned-llama</a> - but I never managed to improve LB performance vs. just using the static questions.</p>\n<h1>Thanks!</h1>\n<p>Thanks for the great competition everyone!  I had a lot of fun.  Special thanks to <a href=\"https://www.kaggle.com/ryanholbrook\" target=\"_blank\">@ryanholbrook</a> for putting this together.</p>\n<p>Let's figure out a way to -really- limit to just LLMs and do this again!</p>",
      "rawMarkdown": "After hanging out in the top couple places for a long time - wish I ranked higher than 84th place - but happy to see other folks make progress!\n\nMy solution:\nhttps://www.kaggle.com/code/richolson/sdxl-turbo-svg-new-scoring-metric\n\nShort version:\n**SDXL-Turbo -> GPU Powered SVG Conversion + OCR Decoy -> Grade with Scoring Metric**\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F13585160%2Fbe0f79d086fb0c0d16d72482f562b94b%2FScreenshot%202025-05-28%20at%201.16.42PM.png?generation=1748463425395096&alt=media)\n\nI really wanted to explore actually using an LLM and adversarial approaches more - but life got busy...\n\n# General Approach\n\n    1. Use SDXL-Turbo to generate images for prompts\n    2. Convert images to SVGs (GPU powered!)\n    3. Append an OCR decoy to the SVGs to prevent hallucination\n    4. Use competition metric to grade\n    5. Repeat steps 1-4 as many times as possible within ~1 minute - and choose best scoring image\n\nAll steps combined take about 5 seconds - so up to about 12 attempts are possible per prompt.\n    \n# Bitmap Generation: SDXL Turbo\n\nI tried a few different image models - but none worked better for me than SDXL turbo.  I credit this partially due to SDXL Turbo being able to crank out images in ~700ms.\n\nWhen creating the image prompt - I rotate through various prefixes to both optimize for SVG conversion and increase output variety:\n\n```python\nself.prompt_prefixes = [\"\",\n                            \"Flat color block, ultrasimple, solid colors only:\",\n                            \"dramatic high-contrast:\",\n                            \"simple oil painting, close-up:\",\n                            \"in cartoon style:\",\n                            \"close-up unfocused photograph - but containing all described elements:\"\n                           ]\n\n```\nFlux Schnell produced nicer images - but was much slower than SDXL Turbo (~6 seconds).  This reduced number of possible attempts per prompt - and was not able to use it to improve score.\n\nSana Sprint also produced nicer images than SDXL Turbo while only being maybe 2x slower (around 1.6 seconds).  Only had slight impact on number of attempts possible per prompt - but again - did not help with LB.\n\n# GPU Accelerated SVG Conversion\n\nThis code is an updated version of what I'd shared earlier in my baseline notebook - but I did a bunch of tweaks to improve quality and performance.  I was thinking we should be able to use GPU for this - so I got a little help.... Here's Claude Sonnet 3.7 to explain:\n\n>Thanks Rich - here's what I did for the GPU-accelerated SVG conversion!\n## GPU-Accelerated SVG Conversion Overview\nThe code implements a fast bitmap-to-SVG pipeline using GPU acceleration and smart feature extraction.\n##Key Components:\nGPU-Accelerated K-means Clustering - Uses CUDA kernels to quickly reduce images to 12 colors while maintaining visual quality.\nHierarchical Feature Extraction - Identifies the most important visual elements by analyzing color \nfrequency, area, and proximity to center, ensuring key features are preserved.\nAdaptive Space Management - Two-pass approach that first adds critical features at full quality, then fills remaining space with simplified versions of other elements.\nSmart Polygon Simplification - Numba-accelerated functions offer multiple simplification levels to balance file size with visual fidelity.\n##Performance:\nCuPy for GPU computations\nNumba JIT compilation\nPre-compiled kernels via init_svg_gpu()\n##Result\nSub-second SVG conversion producing compact, visually accurate vectors - perfect for your rapid iteration approach where you needed multiple candidates within tight time constraints!\n\n(ChatGPT also chipped in a bit)\n\n# OCR Decoy\n\nI also implement an anti-OCR hallucination decoy I shared earlier here: https://www.kaggle.com/code/richolson/let-s-defeat-ocr-easy-lb-boost\n\nA small \"o\" shape to the SVG - which uses something around 300 bytes (so we limit SVG conversion to 9650 bytes).\n\n    This gives the OCR detection something to look at - and hopefully reliably count 1 character (as opposed to false positives)\n    Uses 2nd darkest and 2nd lightest colors to minimize visual impact (avoid hurting aesthetic score)\n    Randomized a bit - so exact additional length varies a bit\n\nIt's not perfect - but it addresses the vast majority of hallucination issues.  I tried higher contrast and more obvious shapes like an 'A' - but it didn't further improve score (possibly due to decreases in aesthetic score.)\n\n\n# Scoring / Prompt Questions\n\nEach image is passed through the scoring metric to see how well it scores against the prompt.\n\nI had the best LB results using these 2 questions:\n```python\nquestions = [\n        f\"Image includes all of: {prompt}?\",\n        f\"Does this image show all elements of: {prompt}?\",\n    ]\n\n```\nWith the 10B / 448x448 verison of PaliGemma time for scoring both questions is about 3.8 seconds.  Going to a single question allows more images to be processed - but resulted in lower LB scores.  \n\nI also experimented with the 3B Paligemma and 10B / 224x224 version.  Both scored much faster - but reduced LB scores even though they were able to evaluate more images.\n    \nI did create several versions of my notebook that used Qwen for TIFA question generation based on https://www.kaggle.com/code/richolson/tifa-question-generation-qwen-vs-tuned-llama - but I never managed to improve LB performance vs. just using the static questions.\n\n# Thanks!\n\nThanks for the great competition everyone!  I had a lot of fun.  Special thanks to @ryanholbrook for putting this together.\n\nLet's figure out a way to -really- limit to just LLMs and do this again!",
      "votes": 25
    },
    {
      "id": 3211963,
      "postDate": "2025-05-29T05:39:18.610Z",
      "content": "<p>Great idea to use gpu for svg conversation! And thanks for your notebooks. A now regret not using your small and aes saving ocr decoy. It was very usefull on private LB.</p>",
      "rawMarkdown": "Great idea to use gpu for svg conversation! And thanks for your notebooks. A now regret not using your small and aes saving ocr decoy. It was very usefull on private LB."
    },
    {
      "id": 3211943,
      "postDate": "2025-05-29T04:46:52.123Z",
      "rawMarkdown": "",
      "isDeleted": true
    }
  ],
  "complete": true,
  "source": "live",
  "fetched_at": "2026-10-20T09:10:33Z",
  "competition_id": 89659,
  "competition_slug": "drawing-with-llms",
  "team_id": 13464400,
  "solution_url": "/competitions/drawing-with-llms/writeups/rich-olson-84th-place-solution-sdxl-turbo-gpu-svg-"
}