{
  "id": 418477,
  "title": "5th place solution",
  "url": "/competitions/benetech-making-graphs-accessible/writeups/qaln-5th-place-solution",
  "author_name": "",
  "post_date": "2023-06-29T07:23:22.397Z",
  "votes": 28,
  "comment_count": 8,
  "views": 0,
  "content": "<p>Many thanks to Kaggle and Benetech for this interesting competition where many different approaches are possible and ideas are endless. Given the strong distribution shift in the private test set, we are quite happy with our finish.</p>\n<p><strong>Summary</strong></p>\n<p>Our solution consists of 3 main components:</p>\n<ul>\n<li>Synthetic data generation.</li>\n<li>3-stage training of matcha models.</li>\n<li>Separate process to handle scatter plot.</li>\n</ul>\n<p><strong>1. Synthetic data generation</strong></p>\n<p>Early on we realized this competition is unique in the sense that we are not limited to the available dataset. If the model struggles with certain plot patterns, we can generate a large number of plots with these patterns and as the model (matcha) is very strong, it will learn.</p>\n<p>We started by building upon this amazing repo: <a href=\"https://github.com/rakutentech/chart-synthesizer\" target=\"_blank\">https://github.com/rakutentech/chart-synthesizer</a>.  We used both competition’s extracted data and ICDAR data as validation and try to emulate as many patterns from them as possible. For example:</p>\n<ul>\n<li>Different fonts, tick orientations, tick styles, background colors, grid styles etc.</li>\n<li>Add error bars to bar and line plots.</li>\n<li>Generate histogram plots as a separate chart type.</li>\n<li>Difficult line plot patterns, such as when the line starts very close to a tick mark but doesn’t touch it, the model without additional training data will very likely include this tick value in the prediction. </li>\n<li>Add blur and noise effects to reproduce the look of extracted plots.</li>\n</ul>\n<p>Some examples of our generated data:<br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F9250575%2F93bb591a9717e095b9f422c224b31c02%2Fline61.jpg?generation=1687298963057596&amp;alt=media\" alt=\"“”\"><br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F9250575%2F6f24a6ba2660e0440b150164d6390ab6%2Fvbar3.jpg?generation=1687298981955314&amp;alt=media\" alt=\"“”\"></p>\n<p>With each round of training, we would analyze the validation set, locate the patterns that give low score, and add these patterns to our chart generation code. We made the rise from 0.74 to 0.82 public LB simply by repeating this process multiple times.</p>\n<p>With our generation code we can create as many bar, line and scatter plots as necessary for each training stage. For dot plot we sampled 10k images from the great dataset provided by <a href=\"https://www.kaggle.com/brendanartley\" target=\"_blank\">@brendanartley</a> </p>\n<p><strong>2. Three-stage training of matcha models</strong></p>\n<p>Thanks to the kind sharing by <a href=\"https://www.kaggle.com/nbroad\" target=\"_blank\">@nbroad</a> , we started the competition training <code>matcha-base</code> models and quickly reached a good score.</p>\n<p>The training is done in 3 stages:</p>\n<ul>\n<li>Train from <code>matcha-base</code> checkpoint as a chart classifier. The model is trained for 5 epochs, using little synthetic data and oversampling extracted data.</li>\n<li>Use the weight from stage 1, continue training for 10 epochs to extract data series from all chart types. In this step we add a lot of our own synthetic data (~150k images) to combine with the original dataset.</li>\n<li>Use the weight from stage 2, finetune separate models for 5 epochs with each chart type group:<ul>\n<li>vertical bar/dot (add 50k synthetic vertical bar plots, 5k histograms, 5k dot plots)</li>\n<li>horizontal bar (add 50k synthetic plots)</li>\n<li>line (add 200k synthetic plots)</li>\n<li>scatter (add 30k synthetic plots)</li></ul></li>\n</ul>\n<p>At inference time, the chart classifier is run first and then each group of charts will be handled by its dedicated model.</p>\n<p>At the beginning our process had only step 2 and 3, and we used model from step 2 as classifier. But then we observed that adding a lot of synthetic data decreases the performance of classifying task. As a result, training for the classifier was separated.</p>\n<p>It is also possible to perform classifying task with a simple CNN, however from our early experiments we saw that using matcha gave a little better performance, so we sticked with its usage.</p>\n<p><strong>Some training details:</strong></p>\n<ul>\n<li>Learning rate 3e-5 for 1st and 2nd stages, 2e-5 for 3rd stage, using cosine schedule with warmup.</li>\n<li>Adafactor optimizer.</li>\n<li>Max patches 2048, max length 512.</li>\n<li>Freeze first 4 layers of encoder.</li>\n<li>Prediction string: <code>&lt;chart_type&gt;&lt;start&gt;x1|y1;…;xn|yn&lt;end&gt;</code></li>\n<li>Histogram is treated as a separated chart type in training and mapped back to vertical bar at inference.</li>\n<li>Dynamic rounding based on the range of data series. </li>\n</ul>\n<p><strong>3. Scatter plots processing</strong></p>\n<p>While the mentioned above method helped us reach good results for bar, dot and line charts, we found scatter plots much harder for matcha to handle. As a result, we developed a separate scheme only for scatter:</p>\n<ul>\n<li>Plot area and tick label detection: use outputs from <a href=\"https://github.com/pengyu965/ChartDete\" target=\"_blank\">CACHED</a> .</li>\n<li>Textline Rotation : use MobilenetV2 backbone to train angle classification task.</li>\n<li>Textline OCR: use <a href=\"https://github.com/pbcquoc/vietocr\" target=\"_blank\">vietocr</a> ’s seq2seq model to train textline reading task. We modified the encoder to use ResNeXt50 with dilated convolution.</li>\n<li>Scatter marker detection: use Mask-RCNN with <a href=\"https://github.com/mlpc-ucsd/CoaT\" target=\"_blank\">CoaT</a> backbone for this task. We trained the model with detectron2. </li>\n<li>Final values of each marker are deduced from marker position, tick label position and tick values.</li>\n</ul>\n<p>This process helped us score 0.09 public and 0.28 private for scatter and is the key for us to survive the private test set.</p>\n<p>Thank you for reading and please let us know if you have any questions.</p>\n<p>Edit: Inference notebook for our solution now available: <a href=\"https://www.kaggle.com/code/qdv206/benetech-5th-place-inference\" target=\"_blank\">https://www.kaggle.com/code/qdv206/benetech-5th-place-inference</a></p>",
  "messages": [
    {
      "id": "2311069",
      "postDate": "06/20/2023 22:18:53",
      "content": "<p>Many thanks to Kaggle and Benetech for this interesting competition where many different approaches are possible and ideas are endless. Given the strong distribution shift in the private test set, we are quite happy with our finish.</p>\n<p><strong>Summary</strong></p>\n<p>Our solution consists of 3 main components:</p>\n<ul>\n<li>Synthetic data generation.</li>\n<li>3-stage training of matcha models.</li>\n<li>Separate process to handle scatter plot.</li>\n</ul>\n<p><strong>1. Synthetic data generation</strong></p>\n<p>Early on we realized this competition is unique in the sense that we are not limited to the available dataset. If the model struggles with certain plot patterns, we can generate a large number of plots with these patterns and as the model (matcha) is very strong, it will learn.</p>\n<p>We started by building upon this amazing repo: <a href=\"https://github.com/rakutentech/chart-synthesizer\" target=\"_blank\">https://github.com/rakutentech/chart-synthesizer</a>.  We used both competition’s extracted data and ICDAR data as validation and try to emulate as many patterns from them as possible. For example:</p>\n<ul>\n<li>Different fonts, tick orientations, tick styles, background colors, grid styles etc.</li>\n<li>Add error bars to bar and line plots.</li>\n<li>Generate histogram plots as a separate chart type.</li>\n<li>Difficult line plot patterns, such as when the line starts very close to a tick mark but doesn’t touch it, the model without additional training data will very likely include this tick value in the prediction. </li>\n<li>Add blur and noise effects to reproduce the look of extracted plots.</li>\n</ul>\n<p>Some examples of our generated data:<br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F9250575%2F93bb591a9717e095b9f422c224b31c02%2Fline61.jpg?generation=1687298963057596&amp;alt=media\" alt=\"“”\"><br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F9250575%2F6f24a6ba2660e0440b150164d6390ab6%2Fvbar3.jpg?generation=1687298981955314&amp;alt=media\" alt=\"“”\"></p>\n<p>With each round of training, we would analyze the validation set, locate the patterns that give low score, and add these patterns to our chart generation code. We made the rise from 0.74 to 0.82 public LB simply by repeating this process multiple times.</p>\n<p>With our generation code we can create as many bar, line and scatter plots as necessary for each training stage. For dot plot we sampled 10k images from the great dataset provided by <a href=\"https://www.kaggle.com/brendanartley\" target=\"_blank\">@brendanartley</a> </p>\n<p><strong>2. Three-stage training of matcha models</strong></p>\n<p>Thanks to the kind sharing by <a href=\"https://www.kaggle.com/nbroad\" target=\"_blank\">@nbroad</a> , we started the competition training <code>matcha-base</code> models and quickly reached a good score.</p>\n<p>The training is done in 3 stages:</p>\n<ul>\n<li>Train from <code>matcha-base</code> checkpoint as a chart classifier. The model is trained for 5 epochs, using little synthetic data and oversampling extracted data.</li>\n<li>Use the weight from stage 1, continue training for 10 epochs to extract data series from all chart types. In this step we add a lot of our own synthetic data (~150k images) to combine with the original dataset.</li>\n<li>Use the weight from stage 2, finetune separate models for 5 epochs with each chart type group:<ul>\n<li>vertical bar/dot (add 50k synthetic vertical bar plots, 5k histograms, 5k dot plots)</li>\n<li>horizontal bar (add 50k synthetic plots)</li>\n<li>line (add 200k synthetic plots)</li>\n<li>scatter (add 30k synthetic plots)</li></ul></li>\n</ul>\n<p>At inference time, the chart classifier is run first and then each group of charts will be handled by its dedicated model.</p>\n<p>At the beginning our process had only step 2 and 3, and we used model from step 2 as classifier. But then we observed that adding a lot of synthetic data decreases the performance of classifying task. As a result, training for the classifier was separated.</p>\n<p>It is also possible to perform classifying task with a simple CNN, however from our early experiments we saw that using matcha gave a little better performance, so we sticked with its usage.</p>\n<p><strong>Some training details:</strong></p>\n<ul>\n<li>Learning rate 3e-5 for 1st and 2nd stages, 2e-5 for 3rd stage, using cosine schedule with warmup.</li>\n<li>Adafactor optimizer.</li>\n<li>Max patches 2048, max length 512.</li>\n<li>Freeze first 4 layers of encoder.</li>\n<li>Prediction string: <code>&lt;chart_type&gt;&lt;start&gt;x1|y1;…;xn|yn&lt;end&gt;</code></li>\n<li>Histogram is treated as a separated chart type in training and mapped back to vertical bar at inference.</li>\n<li>Dynamic rounding based on the range of data series. </li>\n</ul>\n<p><strong>3. Scatter plots processing</strong></p>\n<p>While the mentioned above method helped us reach good results for bar, dot and line charts, we found scatter plots much harder for matcha to handle. As a result, we developed a separate scheme only for scatter:</p>\n<ul>\n<li>Plot area and tick label detection: use outputs from <a href=\"https://github.com/pengyu965/ChartDete\" target=\"_blank\">CACHED</a> .</li>\n<li>Textline Rotation : use MobilenetV2 backbone to train angle classification task.</li>\n<li>Textline OCR: use <a href=\"https://github.com/pbcquoc/vietocr\" target=\"_blank\">vietocr</a> ’s seq2seq model to train textline reading task. We modified the encoder to use ResNeXt50 with dilated convolution.</li>\n<li>Scatter marker detection: use Mask-RCNN with <a href=\"https://github.com/mlpc-ucsd/CoaT\" target=\"_blank\">CoaT</a> backbone for this task. We trained the model with detectron2. </li>\n<li>Final values of each marker are deduced from marker position, tick label position and tick values.</li>\n</ul>\n<p>This process helped us score 0.09 public and 0.28 private for scatter and is the key for us to survive the private test set.</p>\n<p>Thank you for reading and please let us know if you have any questions.</p>\n<p>Edit: Inference notebook for our solution now available: <a href=\"https://www.kaggle.com/code/qdv206/benetech-5th-place-inference\" target=\"_blank\">https://www.kaggle.com/code/qdv206/benetech-5th-place-inference</a></p>",
      "rawMarkdown": "Many thanks to Kaggle and Benetech for this interesting competition where many different approaches are possible and ideas are endless. Given the strong distribution shift in the private test set, we are quite happy with our finish.\n\n**Summary**\n\nOur solution consists of 3 main components:\n-\tSynthetic data generation.\n-\t3-stage training of matcha models.\n-\tSeparate process to handle scatter plot.\n\n**1. Synthetic data generation**\n\nEarly on we realized this competition is unique in the sense that we are not limited to the available dataset. If the model struggles with certain plot patterns, we can generate a large number of plots with these patterns and as the model (matcha) is very strong, it will learn.\n\nWe started by building upon this amazing repo: https://github.com/rakutentech/chart-synthesizer.  We used both competition’s extracted data and ICDAR data as validation and try to emulate as many patterns from them as possible. For example:\n-\tDifferent fonts, tick orientations, tick styles, background colors, grid styles etc.\n-\tAdd error bars to bar and line plots.\n-\tGenerate histogram plots as a separate chart type.\n-\tDifficult line plot patterns, such as when the line starts very close to a tick mark but doesn’t touch it, the model without additional training data will very likely include this tick value in the prediction. \n-\tAdd blur and noise effects to reproduce the look of extracted plots.\n\nSome examples of our generated data:\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F9250575%2F93bb591a9717e095b9f422c224b31c02%2Fline61.jpg?generation=1687298963057596&alt=media\" alt= “” width=\"320\" height=\"240\">\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F9250575%2F6f24a6ba2660e0440b150164d6390ab6%2Fvbar3.jpg?generation=1687298981955314&alt=media\" alt= “” width=\"320\" height=\"240\">\n\nWith each round of training, we would analyze the validation set, locate the patterns that give low score, and add these patterns to our chart generation code. We made the rise from 0.74 to 0.82 public LB simply by repeating this process multiple times.\n\nWith our generation code we can create as many bar, line and scatter plots as necessary for each training stage. For dot plot we sampled 10k images from the great dataset provided by @brendanartley \n\n**2. Three-stage training of matcha models**\n\nThanks to the kind sharing by @nbroad , we started the competition training `matcha-base` models and quickly reached a good score.\n\nThe training is done in 3 stages:\n-\tTrain from `matcha-base` checkpoint as a chart classifier. The model is trained for 5 epochs, using little synthetic data and oversampling extracted data.\n-\tUse the weight from stage 1, continue training for 10 epochs to extract data series from all chart types. In this step we add a lot of our own synthetic data (~150k images) to combine with the original dataset.\n-\tUse the weight from stage 2, finetune separate models for 5 epochs with each chart type group:\n    + vertical bar/dot (add 50k synthetic vertical bar plots, 5k histograms, 5k dot plots)\n    + horizontal bar (add 50k synthetic plots)\n    + line (add 200k synthetic plots)\n    + scatter (add 30k synthetic plots)\n\nAt inference time, the chart classifier is run first and then each group of charts will be handled by its dedicated model.\n\nAt the beginning our process had only step 2 and 3, and we used model from step 2 as classifier. But then we observed that adding a lot of synthetic data decreases the performance of classifying task. As a result, training for the classifier was separated.\n\nIt is also possible to perform classifying task with a simple CNN, however from our early experiments we saw that using matcha gave a little better performance, so we sticked with its usage.\n\n**Some training details:**\n-\tLearning rate 3e-5 for 1st and 2nd stages, 2e-5 for 3rd stage, using cosine schedule with warmup.\n-\tAdafactor optimizer.\n-\tMax patches 2048, max length 512.\n-\tFreeze first 4 layers of encoder.\n-\tPrediction string: `<chart_type><start>x1|y1;…;xn|yn<end>`\n-\tHistogram is treated as a separated chart type in training and mapped back to vertical bar at inference.\n-\tDynamic rounding based on the range of data series. \n\n**3. Scatter plots processing**\n\nWhile the mentioned above method helped us reach good results for bar, dot and line charts, we found scatter plots much harder for matcha to handle. As a result, we developed a separate scheme only for scatter:\n\n-\tPlot area and tick label detection: use outputs from [CACHED](https://github.com/pengyu965/ChartDete) .\n-      Textline Rotation : use MobilenetV2 backbone to train angle classification task.\n-\tTextline OCR: use [vietocr](https://github.com/pbcquoc/vietocr) ’s seq2seq model to train textline reading task. We modified the encoder to use ResNeXt50 with dilated convolution.\n-      Scatter marker detection: use Mask-RCNN with [CoaT](https://github.com/mlpc-ucsd/CoaT) backbone for this task. We trained the model with detectron2. \n-      Final values of each marker are deduced from marker position, tick label position and tick values.\n\nThis process helped us score 0.09 public and 0.28 private for scatter and is the key for us to survive the private test set.\n\nThank you for reading and please let us know if you have any questions.\n\nEdit: Inference notebook for our solution now available: https://www.kaggle.com/code/qdv206/benetech-5th-place-inference",
      "votes": null
    },
    {
      "id": "2311081",
      "postDate": "06/20/2023 22:30:14",
      "content": "<p>Nice work!</p>\n<p>What was your CV/LB for each type? </p>",
      "rawMarkdown": "Nice work!\n\nWhat was your CV/LB for each type?",
      "votes": null
    },
    {
      "id": "2311585",
      "postDate": "06/21/2023 09:03:08",
      "content": "<p>A very thorough approach! Great job of finding information and code</p>",
      "rawMarkdown": "A very thorough approach! Great job of finding information and code",
      "votes": null
    },
    {
      "id": "2312092",
      "postDate": "06/21/2023 17:00:54",
      "content": "<p>Thank you very much! Without your sharing on matcha we probably would have had a much harder time with this competition.</p>\n<p>Here is our result by chart type: (CV/Public/Private)</p>\n<ul>\n<li>Vertical bar: 0.95/0.39/0.26</li>\n<li>Horizontal bar: 0.95/0.04/0.01</li>\n<li>Dot: 0.98/0/0 (not really reliable as we only used a subset of generated plots as validation)</li>\n<li>Line: 0.87/0.32/0.13</li>\n<li>Scatter: 0.66/0.09/0.28</li>\n</ul>",
      "rawMarkdown": "Thank you very much! Without your sharing on matcha we probably would have had a much harder time with this competition.\n\nHere is our result by chart type: (CV/Public/Private)\n- Vertical bar: 0.95/0.39/0.26\n- Horizontal bar: 0.95/0.04/0.01\n- Dot: 0.98/0/0 (not really reliable as we only used a subset of generated plots as validation)\n- Line: 0.87/0.32/0.13\n- Scatter: 0.66/0.09/0.28",
      "votes": null
    },
    {
      "id": "2312304",
      "postDate": "06/21/2023 19:50:43",
      "content": "<p>Nice work! Congratulations on getting 5th position!! <a href=\"https://www.kaggle.com/qdv206\" target=\"_blank\">@qdv206</a> </p>",
      "rawMarkdown": "Nice work! Congratulations on getting 5th position!! @qdv206",
      "votes": null
    },
    {
      "id": "2313947",
      "postDate": "06/23/2023 04:26:53",
      "content": "<p>Amazing approach, thank <a href=\"https://www.kaggle.com/qdv206\" target=\"_blank\">@qdv206</a> .</p>",
      "rawMarkdown": "Amazing approach, thank @qdv206 .",
      "votes": null
    },
    {
      "id": "2313964",
      "postDate": "06/23/2023 04:53:12",
      "content": "<p>Superb work, Congratulations on achieving the fifth spot! <a href=\"https://www.kaggle.com/qdv206\" target=\"_blank\">@qdv206</a> </p>",
      "rawMarkdown": "Superb work, Congratulations on achieving the fifth spot! @qdv206",
      "votes": null
    },
    {
      "id": "2317193",
      "postDate": "06/25/2023 13:57:22",
      "content": "<p>nice work, thanks for sharing</p>",
      "rawMarkdown": "nice work, thanks for sharing",
      "votes": null
    },
    {
      "id": "2319390",
      "postDate": "06/27/2023 05:26:54",
      "content": "<p><a href=\"https://www.kaggle.com/qdv206\" target=\"_blank\">@qdv206</a> good solution! Thank you!</p>",
      "rawMarkdown": "qdv206 good solution! Thank you!",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 2311081,
      "author_name": "nbroad",
      "author_url": "",
      "post_date": "06/20/2023 22:30:14",
      "content": "<p>Nice work!</p>\n<p>What was your CV/LB for each type? </p>",
      "votes": null,
      "replies": [
        {
          "id": 2312092,
          "author_name": "qdv206",
          "author_url": "",
          "post_date": "06/21/2023 17:00:54",
          "content": "<p>Thank you very much! Without your sharing on matcha we probably would have had a much harder time with this competition.</p>\n<p>Here is our result by chart type: (CV/Public/Private)</p>\n<ul>\n<li>Vertical bar: 0.95/0.39/0.26</li>\n<li>Horizontal bar: 0.95/0.04/0.01</li>\n<li>Dot: 0.98/0/0 (not really reliable as we only used a subset of generated plots as validation)</li>\n<li>Line: 0.87/0.32/0.13</li>\n<li>Scatter: 0.66/0.09/0.28</li>\n</ul>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 2311585,
      "author_name": "anuarsenk",
      "author_url": "",
      "post_date": "06/21/2023 09:03:08",
      "content": "<p>A very thorough approach! Great job of finding information and code</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2312304,
      "author_name": "akshitsharma1",
      "author_url": "",
      "post_date": "06/21/2023 19:50:43",
      "content": "<p>Nice work! Congratulations on getting 5th position!! <a href=\"https://www.kaggle.com/qdv206\" target=\"_blank\">@qdv206</a> </p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2313947,
      "author_name": "danghieuan",
      "author_url": "",
      "post_date": "06/23/2023 04:26:53",
      "content": "<p>Amazing approach, thank <a href=\"https://www.kaggle.com/qdv206\" target=\"_blank\">@qdv206</a> .</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2313964,
      "author_name": "pushkar007",
      "author_url": "",
      "post_date": "06/23/2023 04:53:12",
      "content": "<p>Superb work, Congratulations on achieving the fifth spot! <a href=\"https://www.kaggle.com/qdv206\" target=\"_blank\">@qdv206</a> </p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2317193,
      "author_name": "joek47",
      "author_url": "",
      "post_date": "06/25/2023 13:57:22",
      "content": "<p>nice work, thanks for sharing</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2319390,
      "author_name": "serangu",
      "author_url": "",
      "post_date": "06/27/2023 05:26:54",
      "content": "<p><a href=\"https://www.kaggle.com/qdv206\" target=\"_blank\">@qdv206</a> good solution! Thank you!</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "2311069": "Many thanks to Kaggle and Benetech for this interesting competition where many different approaches are possible and ideas are endless. Given the strong distribution shift in the private test set, we are quite happy with our finish.\n\n**Summary**\n\nOur solution consists of 3 main components:\n-\tSynthetic data generation.\n-\t3-stage training of matcha models.\n-\tSeparate process to handle scatter plot.\n\n**1. Synthetic data generation**\n\nEarly on we realized this competition is unique in the sense that we are not limited to the available dataset. If the model struggles with certain plot patterns, we can generate a large number of plots with these patterns and as the model (matcha) is very strong, it will learn.\n\nWe started by building upon this amazing repo: https://github.com/rakutentech/chart-synthesizer.  We used both competition’s extracted data and ICDAR data as validation and try to emulate as many patterns from them as possible. For example:\n-\tDifferent fonts, tick orientations, tick styles, background colors, grid styles etc.\n-\tAdd error bars to bar and line plots.\n-\tGenerate histogram plots as a separate chart type.\n-\tDifficult line plot patterns, such as when the line starts very close to a tick mark but doesn’t touch it, the model without additional training data will very likely include this tick value in the prediction. \n-\tAdd blur and noise effects to reproduce the look of extracted plots.\n\nSome examples of our generated data:\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F9250575%2F93bb591a9717e095b9f422c224b31c02%2Fline61.jpg?generation=1687298963057596&alt=media\" alt= “” width=\"320\" height=\"240\">\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F9250575%2F6f24a6ba2660e0440b150164d6390ab6%2Fvbar3.jpg?generation=1687298981955314&alt=media\" alt= “” width=\"320\" height=\"240\">\n\nWith each round of training, we would analyze the validation set, locate the patterns that give low score, and add these patterns to our chart generation code. We made the rise from 0.74 to 0.82 public LB simply by repeating this process multiple times.\n\nWith our generation code we can create as many bar, line and scatter plots as necessary for each training stage. For dot plot we sampled 10k images from the great dataset provided by @brendanartley \n\n**2. Three-stage training of matcha models**\n\nThanks to the kind sharing by @nbroad , we started the competition training `matcha-base` models and quickly reached a good score.\n\nThe training is done in 3 stages:\n-\tTrain from `matcha-base` checkpoint as a chart classifier. The model is trained for 5 epochs, using little synthetic data and oversampling extracted data.\n-\tUse the weight from stage 1, continue training for 10 epochs to extract data series from all chart types. In this step we add a lot of our own synthetic data (~150k images) to combine with the original dataset.\n-\tUse the weight from stage 2, finetune separate models for 5 epochs with each chart type group:\n    + vertical bar/dot (add 50k synthetic vertical bar plots, 5k histograms, 5k dot plots)\n    + horizontal bar (add 50k synthetic plots)\n    + line (add 200k synthetic plots)\n    + scatter (add 30k synthetic plots)\n\nAt inference time, the chart classifier is run first and then each group of charts will be handled by its dedicated model.\n\nAt the beginning our process had only step 2 and 3, and we used model from step 2 as classifier. But then we observed that adding a lot of synthetic data decreases the performance of classifying task. As a result, training for the classifier was separated.\n\nIt is also possible to perform classifying task with a simple CNN, however from our early experiments we saw that using matcha gave a little better performance, so we sticked with its usage.\n\n**Some training details:**\n-\tLearning rate 3e-5 for 1st and 2nd stages, 2e-5 for 3rd stage, using cosine schedule with warmup.\n-\tAdafactor optimizer.\n-\tMax patches 2048, max length 512.\n-\tFreeze first 4 layers of encoder.\n-\tPrediction string: `<chart_type><start>x1|y1;…;xn|yn<end>`\n-\tHistogram is treated as a separated chart type in training and mapped back to vertical bar at inference.\n-\tDynamic rounding based on the range of data series. \n\n**3. Scatter plots processing**\n\nWhile the mentioned above method helped us reach good results for bar, dot and line charts, we found scatter plots much harder for matcha to handle. As a result, we developed a separate scheme only for scatter:\n\n-\tPlot area and tick label detection: use outputs from [CACHED](https://github.com/pengyu965/ChartDete) .\n-      Textline Rotation : use MobilenetV2 backbone to train angle classification task.\n-\tTextline OCR: use [vietocr](https://github.com/pbcquoc/vietocr) ’s seq2seq model to train textline reading task. We modified the encoder to use ResNeXt50 with dilated convolution.\n-      Scatter marker detection: use Mask-RCNN with [CoaT](https://github.com/mlpc-ucsd/CoaT) backbone for this task. We trained the model with detectron2. \n-      Final values of each marker are deduced from marker position, tick label position and tick values.\n\nThis process helped us score 0.09 public and 0.28 private for scatter and is the key for us to survive the private test set.\n\nThank you for reading and please let us know if you have any questions.\n\nEdit: Inference notebook for our solution now available: https://www.kaggle.com/code/qdv206/benetech-5th-place-inference",
    "2311081": "Nice work!\n\nWhat was your CV/LB for each type?",
    "2311585": "A very thorough approach! Great job of finding information and code",
    "2312092": "Thank you very much! Without your sharing on matcha we probably would have had a much harder time with this competition.\n\nHere is our result by chart type: (CV/Public/Private)\n- Vertical bar: 0.95/0.39/0.26\n- Horizontal bar: 0.95/0.04/0.01\n- Dot: 0.98/0/0 (not really reliable as we only used a subset of generated plots as validation)\n- Line: 0.87/0.32/0.13\n- Scatter: 0.66/0.09/0.28",
    "2312304": "Nice work! Congratulations on getting 5th position!! @qdv206",
    "2313947": "Amazing approach, thank @qdv206 .",
    "2313964": "Superb work, Congratulations on achieving the fifth spot! @qdv206",
    "2317193": "nice work, thanks for sharing",
    "2319390": "qdv206 good solution! Thank you!"
  },
  "source": "meta"
}