{
  "id": 418466,
  "title": "6th place solution - deplot & UNet postprocessing",
  "url": "/competitions/benetech-making-graphs-accessible/writeups/dd-6th-place-solution-deplot-unet-postprocessing",
  "author_name": "",
  "post_date": "2023-06-21T20:55:09.320Z",
  "votes": 40,
  "comment_count": 28,
  "views": 0,
  "content": "<p>Thanks to kaggle and benetech for hosting an interesting problem. It was a great team effort with <a href=\"https://www.kaggle.com/darraghdog\" target=\"_blank\">@darraghdog</a> </p>\n<h2>TLDR</h2>\n<p>Our solution is a 4 seed blend of a single deplot model for all chart types. For scatter plots we run additional post processing by using the number of scatter points predicted by a U-Net point segmentation model. </p>\n<h2>Data preprocessing</h2>\n<h3>Benetech dataset</h3>\n<p>For training we used all of benetech extracted data, and approx 20% of the generated data which was selected based on the hardest samples. This helped speed up the training pipeline significantly. <br>\nNumerical values had a lot of digits in ground truth which did not match well with our loss function (cross entropy) in pix2struct based models. Therefore, it was important to round these numerical values. For this, we bucketed the labels to approx 5 buckets within the tick label axis. So, for example, the buckets in the below would be <code>0, 40000, 80000, 120000, 160000, 200000, 240000… etc.</code> and the y-axis label to learn would be <code>840000, 960000, 760000, 700000, 580000, 460000, etc.</code>. For ground truth labels which had no tick labels, similar rounding was performed based on the min-max range of the data series, using approximately 40 buckets. </p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1424766%2Fdd90fda19f8e33c767b75e32188a0c29%2FScreenshot%202023-06-20%20at%2021.37.57.png?generation=1687289889671066&amp;alt=media\" alt=\"\"></p>\n<p>Within the pix2struct model, the labels were learned as key-value sequences, similar to the training of deplot. For the example above, that would be<br>\n <code>&lt;pad&gt;Malaysia;960000|Malawi;840000|Maldives;760000|Mali;700000|Mauritania;660000|Melanesia;580000|Malta;580000|Mauritius;540000|Martinique;460000|Mayotte;420000&lt;\\s&gt;</code></p>\n<p>A separate decoder was used to learn the reversed key-value sequence. This was linked to the same encoder and added as an auxiliary loss so the model would not focus more on either side of the image. Since the heavy part of deplot is the encoder, a double decoder did not create much overhead.</p>\n<h3>External data</h3>\n<p>For this competition, we utilized a commercially available subset of PubMed articles to train our models. Approximately 80% of the labeled samples in the ICDAR dataset were found to originate from this commercial dataset. We ensured that the use of this dataset complied with the applicable licensing terms. To expand our training data, we applied pseudo-labeling techniques followed by manual review. Specifically, we pseudo-labeled and manually reviewed around 8,000 bar and line graph samples from PubMed articles. The pseudo-labeling results were quite accurate on bars, requiring only verification that the identified charts were the correct type (e.g. removing box plots). Lines needed some corrections. We also used our U-Net model to pseudo-label approximately 1,000 scatter plot samples from PubMed, and then manually added any missing data points. Using the VGG Image Annotator tool, this manual annotation process was surprisingly fast and efficient. </p>\n<h3>Data generation</h3>\n<p>We used the great <a href=\"https://www.kaggle.com/code/brendanartley/benetech-5-chart-types-generator\" target=\"_blank\">public kernel</a> by <a href=\"https://www.kaggle.com/brendanartley\" target=\"_blank\">@brendanartley</a> in two ways</p>\n<p>We pretrained our deplot models using the 500k images downloadable the public kernel, which gave a small improvement, compared to using the original checkpoint from huggingface. </p>\n<p>We also tweaked the kernel a bit to generate more sophisticated scatter plots (more points, different markers, more overlap etc) and output x/y coordinates of each scatter point. We generated 50k scatter plots with that script and used them additionally for training the segmentation model</p>\n<h2>Models</h2>\n<p>Deplot was used for predicting bars, lines and scatter; for scatter, we additionally used a u-net model. </p>\n<p>Deplot was trained for 20 epochs, with a learning rate of approx 5e-5 and batchsize 8. <a href=\"https://github.com/albumentations-team/albumentations/blob/master/albumentations/augmentations/transforms.py#L2413\" target=\"_blank\">Pixeldropout augmentation</a> was found to prevent overfitting. No other image augmentations were used. For experimentation, 1024 patches were used which decreased training time 2X with only a slight degradation in scores. The loss was a combination of cross entropy on the key value sequences mentioned above and the chart type. A linear layer on top of the first token of deplot was used to predict the chart type as an auxiliary.</p>\n<p>For scatter plots we used a U-Net (EfficientNet-B7 encoder) + non maximum suppression (NMS) to predict number of scatter points and performed a simple yet effective postprocessing where deplot predicted a different number of points:</p>\n<ul>\n<li>If deplot predicted too many points, disregard the last ones</li>\n<li>If deplot predicted too few points, fill missing with the mean value</li>\n</ul>\n<p>Below you can see the segmentation mask for U-Net training. Using the scatter point annotation we created “smooth” points with 10 pixel gaussian radius and drew onto an empty image. </p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1424766%2Fe0cbc56d90a54892ee8a4365b03d2f59%2FScreenshot%202023-06-20%20at%2021.44.38.png?generation=1687290294572628&amp;alt=media\" alt=\"\"></p>\n<h2>Ensembling</h2>\n<p>For deplot we did inner ensembling by averaging decoder prediction in each greedy decoding step. For Unet we simply averaged predicted masks before performing NMS.</p>\n<h2>Ablation study (Public LB Scores)</h2>\n<p>The following table gives a quick overview, how much each component contributed to our solution</p>\n<table>\n<thead>\n<tr>\n<th>component</th>\n<th>score</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Baseline deplot@1024 tokens</td>\n<td>0.71</td>\n</tr>\n<tr>\n<td>using fullfit</td>\n<td>+0.01</td>\n</tr>\n<tr>\n<td>1024 -&gt; 2048 tokens</td>\n<td>+0.03</td>\n</tr>\n<tr>\n<td>Scatter pp Unet@512x512</td>\n<td>+0.05</td>\n</tr>\n<tr>\n<td>Pixeldropout</td>\n<td>+0.01</td>\n</tr>\n<tr>\n<td>External data</td>\n<td>+0.02</td>\n</tr>\n<tr>\n<td>Pretrain on 500k</td>\n<td>+0.01</td>\n</tr>\n<tr>\n<td>Unet@512x512 -&gt; 768x768</td>\n<td>+0.01</td>\n</tr>\n<tr>\n<td>3x Unet@768x768</td>\n<td>+0.01</td>\n</tr>\n<tr>\n<td>4x seed blend of deplots</td>\n<td>+0.01</td>\n</tr>\n<tr>\n<td><strong>final score</strong></td>\n<td><strong>0.87</strong></td>\n</tr>\n</tbody>\n</table>\n<h2>Used tools/ repos</h2>\n<ul>\n<li>Unet:<a href=\"https://github.com/qubvel/segmentation_models.pytorch\" target=\"_blank\"> Segmentation models pytorch</a> + <a href=\"https://github.com/huggingface/pytorch-image-models/tree/main/timm\" target=\"_blank\">timm encoder</a></li>\n<li>Deplot: <a href=\"https://huggingface.co/google/deplot\" target=\"_blank\">huggingface</a></li>\n<li>logging/ visualization: <a href=\"https://neptune.ai/\" target=\"_blank\">neptune.ai</a></li>\n<li>augmentation: <a href=\"https://albumentations.ai/\" target=\"_blank\">albumentations</a></li>\n<li>labelling: <a href=\"https://www.robots.ox.ac.uk/~vgg/software/via/\" target=\"_blank\">VGG Image Annotator tool</a></li>\n</ul>\n<p>Thank you for reading, questions welcome</p>\n<p>edit:</p>\n<p>June 21st: inference kernel made public: <a href=\"https://www.kaggle.com/code/christofhenkel/benetech-6th-place-dd/notebook\" target=\"_blank\">https://www.kaggle.com/code/christofhenkel/benetech-6th-place-dd/notebook</a></p>",
  "messages": [
    {
      "id": "2311018",
      "postDate": "06/20/2023 20:14:51",
      "content": "<p>Thanks to kaggle and benetech for hosting an interesting problem. It was a great team effort with <a href=\"https://www.kaggle.com/darraghdog\" target=\"_blank\">@darraghdog</a> </p>\n<h2>TLDR</h2>\n<p>Our solution is a 4 seed blend of a single deplot model for all chart types. For scatter plots we run additional post processing by using the number of scatter points predicted by a U-Net point segmentation model. </p>\n<h2>Data preprocessing</h2>\n<h3>Benetech dataset</h3>\n<p>For training we used all of benetech extracted data, and approx 20% of the generated data which was selected based on the hardest samples. This helped speed up the training pipeline significantly. <br>\nNumerical values had a lot of digits in ground truth which did not match well with our loss function (cross entropy) in pix2struct based models. Therefore, it was important to round these numerical values. For this, we bucketed the labels to approx 5 buckets within the tick label axis. So, for example, the buckets in the below would be <code>0, 40000, 80000, 120000, 160000, 200000, 240000… etc.</code> and the y-axis label to learn would be <code>840000, 960000, 760000, 700000, 580000, 460000, etc.</code>. For ground truth labels which had no tick labels, similar rounding was performed based on the min-max range of the data series, using approximately 40 buckets. </p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1424766%2Fdd90fda19f8e33c767b75e32188a0c29%2FScreenshot%202023-06-20%20at%2021.37.57.png?generation=1687289889671066&amp;alt=media\" alt=\"\"></p>\n<p>Within the pix2struct model, the labels were learned as key-value sequences, similar to the training of deplot. For the example above, that would be<br>\n <code>&lt;pad&gt;Malaysia;960000|Malawi;840000|Maldives;760000|Mali;700000|Mauritania;660000|Melanesia;580000|Malta;580000|Mauritius;540000|Martinique;460000|Mayotte;420000&lt;\\s&gt;</code></p>\n<p>A separate decoder was used to learn the reversed key-value sequence. This was linked to the same encoder and added as an auxiliary loss so the model would not focus more on either side of the image. Since the heavy part of deplot is the encoder, a double decoder did not create much overhead.</p>\n<h3>External data</h3>\n<p>For this competition, we utilized a commercially available subset of PubMed articles to train our models. Approximately 80% of the labeled samples in the ICDAR dataset were found to originate from this commercial dataset. We ensured that the use of this dataset complied with the applicable licensing terms. To expand our training data, we applied pseudo-labeling techniques followed by manual review. Specifically, we pseudo-labeled and manually reviewed around 8,000 bar and line graph samples from PubMed articles. The pseudo-labeling results were quite accurate on bars, requiring only verification that the identified charts were the correct type (e.g. removing box plots). Lines needed some corrections. We also used our U-Net model to pseudo-label approximately 1,000 scatter plot samples from PubMed, and then manually added any missing data points. Using the VGG Image Annotator tool, this manual annotation process was surprisingly fast and efficient. </p>\n<h3>Data generation</h3>\n<p>We used the great <a href=\"https://www.kaggle.com/code/brendanartley/benetech-5-chart-types-generator\" target=\"_blank\">public kernel</a> by <a href=\"https://www.kaggle.com/brendanartley\" target=\"_blank\">@brendanartley</a> in two ways</p>\n<p>We pretrained our deplot models using the 500k images downloadable the public kernel, which gave a small improvement, compared to using the original checkpoint from huggingface. </p>\n<p>We also tweaked the kernel a bit to generate more sophisticated scatter plots (more points, different markers, more overlap etc) and output x/y coordinates of each scatter point. We generated 50k scatter plots with that script and used them additionally for training the segmentation model</p>\n<h2>Models</h2>\n<p>Deplot was used for predicting bars, lines and scatter; for scatter, we additionally used a u-net model. </p>\n<p>Deplot was trained for 20 epochs, with a learning rate of approx 5e-5 and batchsize 8. <a href=\"https://github.com/albumentations-team/albumentations/blob/master/albumentations/augmentations/transforms.py#L2413\" target=\"_blank\">Pixeldropout augmentation</a> was found to prevent overfitting. No other image augmentations were used. For experimentation, 1024 patches were used which decreased training time 2X with only a slight degradation in scores. The loss was a combination of cross entropy on the key value sequences mentioned above and the chart type. A linear layer on top of the first token of deplot was used to predict the chart type as an auxiliary.</p>\n<p>For scatter plots we used a U-Net (EfficientNet-B7 encoder) + non maximum suppression (NMS) to predict number of scatter points and performed a simple yet effective postprocessing where deplot predicted a different number of points:</p>\n<ul>\n<li>If deplot predicted too many points, disregard the last ones</li>\n<li>If deplot predicted too few points, fill missing with the mean value</li>\n</ul>\n<p>Below you can see the segmentation mask for U-Net training. Using the scatter point annotation we created “smooth” points with 10 pixel gaussian radius and drew onto an empty image. </p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1424766%2Fe0cbc56d90a54892ee8a4365b03d2f59%2FScreenshot%202023-06-20%20at%2021.44.38.png?generation=1687290294572628&amp;alt=media\" alt=\"\"></p>\n<h2>Ensembling</h2>\n<p>For deplot we did inner ensembling by averaging decoder prediction in each greedy decoding step. For Unet we simply averaged predicted masks before performing NMS.</p>\n<h2>Ablation study (Public LB Scores)</h2>\n<p>The following table gives a quick overview, how much each component contributed to our solution</p>\n<table>\n<thead>\n<tr>\n<th>component</th>\n<th>score</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Baseline deplot@1024 tokens</td>\n<td>0.71</td>\n</tr>\n<tr>\n<td>using fullfit</td>\n<td>+0.01</td>\n</tr>\n<tr>\n<td>1024 -&gt; 2048 tokens</td>\n<td>+0.03</td>\n</tr>\n<tr>\n<td>Scatter pp Unet@512x512</td>\n<td>+0.05</td>\n</tr>\n<tr>\n<td>Pixeldropout</td>\n<td>+0.01</td>\n</tr>\n<tr>\n<td>External data</td>\n<td>+0.02</td>\n</tr>\n<tr>\n<td>Pretrain on 500k</td>\n<td>+0.01</td>\n</tr>\n<tr>\n<td>Unet@512x512 -&gt; 768x768</td>\n<td>+0.01</td>\n</tr>\n<tr>\n<td>3x Unet@768x768</td>\n<td>+0.01</td>\n</tr>\n<tr>\n<td>4x seed blend of deplots</td>\n<td>+0.01</td>\n</tr>\n<tr>\n<td><strong>final score</strong></td>\n<td><strong>0.87</strong></td>\n</tr>\n</tbody>\n</table>\n<h2>Used tools/ repos</h2>\n<ul>\n<li>Unet:<a href=\"https://github.com/qubvel/segmentation_models.pytorch\" target=\"_blank\"> Segmentation models pytorch</a> + <a href=\"https://github.com/huggingface/pytorch-image-models/tree/main/timm\" target=\"_blank\">timm encoder</a></li>\n<li>Deplot: <a href=\"https://huggingface.co/google/deplot\" target=\"_blank\">huggingface</a></li>\n<li>logging/ visualization: <a href=\"https://neptune.ai/\" target=\"_blank\">neptune.ai</a></li>\n<li>augmentation: <a href=\"https://albumentations.ai/\" target=\"_blank\">albumentations</a></li>\n<li>labelling: <a href=\"https://www.robots.ox.ac.uk/~vgg/software/via/\" target=\"_blank\">VGG Image Annotator tool</a></li>\n</ul>\n<p>Thank you for reading, questions welcome</p>\n<p>edit:</p>\n<p>June 21st: inference kernel made public: <a href=\"https://www.kaggle.com/code/christofhenkel/benetech-6th-place-dd/notebook\" target=\"_blank\">https://www.kaggle.com/code/christofhenkel/benetech-6th-place-dd/notebook</a></p>",
      "rawMarkdown": "Thanks to kaggle and benetech for hosting an interesting problem. It was a great team effort with @darraghdog \n\n## TLDR\nOur solution is a 4 seed blend of a single deplot model for all chart types. For scatter plots we run additional post processing by using the number of scatter points predicted by a U-Net point segmentation model. \n\n## Data preprocessing\n\n### Benetech dataset\n\nFor training we used all of benetech extracted data, and approx 20% of the generated data which was selected based on the hardest samples. This helped speed up the training pipeline significantly. \nNumerical values had a lot of digits in ground truth which did not match well with our loss function (cross entropy) in pix2struct based models. Therefore, it was important to round these numerical values. For this, we bucketed the labels to approx 5 buckets within the tick label axis. So, for example, the buckets in the below would be `0, 40000, 80000, 120000, 160000, 200000, 240000… etc.` and the y-axis label to learn would be `840000, 960000, 760000, 700000, 580000, 460000, etc.`. For ground truth labels which had no tick labels, similar rounding was performed based on the min-max range of the data series, using approximately 40 buckets. \n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1424766%2Fdd90fda19f8e33c767b75e32188a0c29%2FScreenshot%202023-06-20%20at%2021.37.57.png?generation=1687289889671066&alt=media)\n\nWithin the pix2struct model, the labels were learned as key-value sequences, similar to the training of deplot. For the example above, that would be\n `<pad>Malaysia;960000|Malawi;840000|Maldives;760000|Mali;700000|Mauritania;660000|Melanesia;580000|Malta;580000|Mauritius;540000|Martinique;460000|Mayotte;420000<\\s>`\n\nA separate decoder was used to learn the reversed key-value sequence. This was linked to the same encoder and added as an auxiliary loss so the model would not focus more on either side of the image. Since the heavy part of deplot is the encoder, a double decoder did not create much overhead.\n\n### External data \n\nFor this competition, we utilized a commercially available subset of PubMed articles to train our models. Approximately 80% of the labeled samples in the ICDAR dataset were found to originate from this commercial dataset. We ensured that the use of this dataset complied with the applicable licensing terms. To expand our training data, we applied pseudo-labeling techniques followed by manual review. Specifically, we pseudo-labeled and manually reviewed around 8,000 bar and line graph samples from PubMed articles. The pseudo-labeling results were quite accurate on bars, requiring only verification that the identified charts were the correct type (e.g. removing box plots). Lines needed some corrections. We also used our U-Net model to pseudo-label approximately 1,000 scatter plot samples from PubMed, and then manually added any missing data points. Using the VGG Image Annotator tool, this manual annotation process was surprisingly fast and efficient. \n\n### Data generation\nWe used the great [public kernel](https://www.kaggle.com/code/brendanartley/benetech-5-chart-types-generator) by @brendanartley in two ways\n\nWe pretrained our deplot models using the 500k images downloadable the public kernel, which gave a small improvement, compared to using the original checkpoint from huggingface. \n\nWe also tweaked the kernel a bit to generate more sophisticated scatter plots (more points, different markers, more overlap etc) and output x/y coordinates of each scatter point. We generated 50k scatter plots with that script and used them additionally for training the segmentation model\n\n## Models\n\nDeplot was used for predicting bars, lines and scatter; for scatter, we additionally used a u-net model. \n\nDeplot was trained for 20 epochs, with a learning rate of approx 5e-5 and batchsize 8. [Pixeldropout augmentation](https://github.com/albumentations-team/albumentations/blob/master/albumentations/augmentations/transforms.py#L2413) was found to prevent overfitting. No other image augmentations were used. For experimentation, 1024 patches were used which decreased training time 2X with only a slight degradation in scores. The loss was a combination of cross entropy on the key value sequences mentioned above and the chart type. A linear layer on top of the first token of deplot was used to predict the chart type as an auxiliary.\n\nFor scatter plots we used a U-Net (EfficientNet-B7 encoder) + non maximum suppression (NMS) to predict number of scatter points and performed a simple yet effective postprocessing where deplot predicted a different number of points:\n\n- If deplot predicted too many points, disregard the last ones\n- If deplot predicted too few points, fill missing with the mean value\n\nBelow you can see the segmentation mask for U-Net training. Using the scatter point annotation we created “smooth” points with 10 pixel gaussian radius and drew onto an empty image. \n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1424766%2Fe0cbc56d90a54892ee8a4365b03d2f59%2FScreenshot%202023-06-20%20at%2021.44.38.png?generation=1687290294572628&alt=media)\n\n## Ensembling\n\nFor deplot we did inner ensembling by averaging decoder prediction in each greedy decoding step. For Unet we simply averaged predicted masks before performing NMS.\n\n## Ablation study (Public LB Scores)\n\nThe following table gives a quick overview, how much each component contributed to our solution\n\n| component | score |\n| --- | --- |\n| Baseline deplot@1024 tokens | 0.71 |\n| using fullfit | +0.01 |\n| 1024 -> 2048 tokens | +0.03 |\n| Scatter pp Unet@512x512 | +0.05 |\n| Pixeldropout | +0.01 |\n| External data | +0.02 |\n| Pretrain on 500k | +0.01 |\n| Unet@512x512 -> 768x768 | +0.01 |\n| 3x Unet@768x768 | +0.01 |\n| 4x seed blend of deplots | +0.01 |\n **final score** | **0.87** \n\n## Used tools/ repos\n\n- Unet:[ Segmentation models pytorch](https://github.com/qubvel/segmentation_models.pytorch) + [timm encoder](https://github.com/huggingface/pytorch-image-models/tree/main/timm)\n- Deplot: [huggingface](https://huggingface.co/google/deplot)\n- logging/ visualization: [neptune.ai](https://neptune.ai/)\n- augmentation: [albumentations](https://albumentations.ai/)\n- labelling: [VGG Image Annotator tool](https://www.robots.ox.ac.uk/~vgg/software/via/)\n\nThank you for reading, questions welcome\n\nedit:\n\nJune 21st: inference kernel made public: https://www.kaggle.com/code/christofhenkel/benetech-6th-place-dd/notebook",
      "votes": null
    },
    {
      "id": "2311030",
      "postDate": "06/20/2023 20:49:03",
      "content": "<p>Did you try out matcha? We used it with the ground truth format similar to <a href=\"https://www.kaggle.com/nbroad\" target=\"_blank\">@nbroad</a>'s donut approach.<br>\ndeplot worked with the ground truth format like you used, but performed slightly worse than matcha overall.</p>\n<p>matcha didn't work well on scatter though … so we didn't use it at all for scatter.</p>",
      "rawMarkdown": "Did you try out matcha? We used it with the ground truth format similar to @nbroad's donut approach.\ndeplot worked with the ground truth format like you used, but performed slightly worse than matcha overall.\n\nmatcha didn't work well on scatter though ... so we didn't use it at all for scatter.",
      "votes": null
    },
    {
      "id": "2311032",
      "postDate": "06/20/2023 20:51:53",
      "content": "<p>In the beginning matcha was way worse for us. But after we found that pretraining helps, matcha was roughly same as deplot. We also tried Pix2Struct Large. But no luck there.  </p>",
      "rawMarkdown": "In the beginning matcha was way worse for us. But after we found that pretraining helps, matcha was roughly same as deplot. We also tried Pix2Struct Large. But no luck there.",
      "votes": null
    },
    {
      "id": "2311035",
      "postDate": "06/20/2023 20:53:03",
      "content": "<p>Strange. It was always the other way around for us. matcha was always better than deplot.</p>",
      "rawMarkdown": "Strange. It was always the other way around for us. matcha was always better than deplot.",
      "votes": null
    },
    {
      "id": "2311036",
      "postDate": "06/20/2023 20:57:44",
      "content": "<p>Noob question here (not an expert in object detection), how did you manage your object detector to predict the right number of data series points? For instance, I selected a probability threshold which optimized the correct number of exact matches. However, sometimes I could get false positives (longer sequences) or get a shorter sequence. Also, which <code>timm</code> backbone did you use? </p>\n<p>Thanks and congratulations</p>",
      "rawMarkdown": "Noob question here (not an expert in object detection), how did you manage your object detector to predict the right number of data series points? For instance, I selected a probability threshold which optimized the correct number of exact matches. However, sometimes I could get false positives (longer sequences) or get a shorter sequence. Also, which `timm` backbone did you use? \n\nThanks and congratulations",
      "votes": null
    },
    {
      "id": "2311037",
      "postDate": "06/20/2023 21:04:49",
      "content": "<p>Say x_seg is your predicted segmentation mask. Run non maximum supression and count number of remaining positive pixels</p>\n<pre><code>            x_pred = x_seg.sigmoid()\n            x_pooled = F.max_pool2d(x_pred, kernel_size=self.nms_kernel_size, stride=, padding=self.nms_padding)\n            x_pred[x_pred != x_pooled] = \n            n_pred = (x_pred[:,] &gt; self.n_threshold).((,))\n</code></pre>\n<blockquote>\n  <p>Also, which timm backbone did you use?</p>\n</blockquote>\n<p>Stated in the modeling section: U-Net (EfficientNet-B7 encoder) Segmentation models pytorch enables using most of encoders from timm. So for us it was tf_efficientnet_b7_ns</p>",
      "rawMarkdown": "Say x_seg is your predicted segmentation mask. Run non maximum supression and count number of remaining positive pixels\n\n```python\n            x_pred = x_seg.sigmoid()\n            x_pooled = F.max_pool2d(x_pred, kernel_size=self.nms_kernel_size, stride=1, padding=self.nms_padding)\n            x_pred[x_pred != x_pooled] = 0\n            n_pred = (x_pred[:,0] > self.n_threshold).sum((1,2))\n```\n\n>Also, which timm backbone did you use?\n\nStated in the modeling section: U-Net (EfficientNet-B7 encoder) Segmentation models pytorch enables using most of encoders from timm. So for us it was tf_efficientnet_b7_ns",
      "votes": null
    },
    {
      "id": "2311038",
      "postDate": "06/20/2023 21:09:07",
      "content": "<p>Awesome job!</p>\n<p>If you had an additional week or two, what else would you have tried?</p>",
      "rawMarkdown": "Awesome job!\n\nIf you had an additional week or two, what else would you have tried?",
      "votes": null
    },
    {
      "id": "2311040",
      "postDate": "06/20/2023 21:13:38",
      "content": "<p>I am extremely happy there was no more additional weeks. This one extra was too much 🤣</p>",
      "rawMarkdown": "I am extremely happy there was no more additional weeks. This one extra was too much 🤣",
      "votes": null
    },
    {
      "id": "2311041",
      "postDate": "06/20/2023 21:16:09",
      "content": "<p>True! I'm just curious what ideas never got explored</p>",
      "rawMarkdown": "True! I'm just curious what ideas never got explored",
      "votes": null
    },
    {
      "id": "2311042",
      "postDate": "06/20/2023 21:23:05",
      "content": "<p>I wanted to try to change the vision model and the text model from Pix2Struct and see if other backbones performed better but didnt find out how. Do you happen to know how to do this?</p>",
      "rawMarkdown": "I wanted to try to change the vision model and the text model from Pix2Struct and see if other backbones performed better but didnt find out how. Do you happen to know how to do this?",
      "votes": null
    },
    {
      "id": "2311043",
      "postDate": "06/20/2023 21:27:21",
      "content": "<p>Thanks for the comprehensive write-up and nice use of the double decoder, nice approach.</p>\n<p>How were you able to output the x/y coordinates of generated scatter plots?</p>",
      "rawMarkdown": "Thanks for the comprehensive write-up and nice use of the double decoder, nice approach.\n\nHow were you able to output the x/y coordinates of generated scatter plots?",
      "votes": null
    },
    {
      "id": "2311047",
      "postDate": "06/20/2023 21:30:56",
      "content": "<p>Our best submission doesn't use external data. I tried to incorporate ICDAR on the night of the license change announcment, but who knows what was the quality of those labels. I didn't have the time to go over them. I had to spawn new gpus as fast as I could 😅 training on 4gpus would take more than 1 day.</p>\n<p>I'd add cleanly labeled external data.</p>",
      "rawMarkdown": "Our best submission doesn't use external data. I tried to incorporate ICDAR on the night of the license change announcment, but who knows what was the quality of those labels. I didn't have the time to go over them. I had to spawn new gpus as fast as I could 😅 training on 4gpus would take more than 1 day.\n\nI'd add cleanly labeled external data.",
      "votes": null
    },
    {
      "id": "2311051",
      "postDate": "06/20/2023 21:36:29",
      "content": "<p>Thank you <a href=\"https://www.kaggle.com/vishnus\" target=\"_blank\">@vishnus</a> for jarvislabs. I think I spent 500 USD in the last 2 days trying to retrain models due to license change announcment. Saved me on icecube as well. It was impossible to get instances immediately on gcp or aws.</p>",
      "rawMarkdown": "Thank you @vishnus for jarvislabs. I think I spent 500 USD in the last 2 days trying to retrain models due to license change announcment. Saved me on icecube as well. It was impossible to get instances immediately on gcp or aws.",
      "votes": null
    },
    {
      "id": "2311052",
      "postDate": "06/20/2023 21:37:46",
      "content": "<p><a href=\"https://www.kaggle.com/alejopaullier\" target=\"_blank\">@alejopaullier</a> <br>\nThere is a generic <a href=\"https://huggingface.co/docs/transformers/model_doc/vision-encoder-decoder\" target=\"_blank\">VisionEncoderDecoderModel</a> that could potentially do what you want. MatCha/DePlot have the advantage that they already had a significant amount of training, so I would assume a new pair would struggle without that.</p>",
      "rawMarkdown": "alejopaullier \nThere is a generic [VisionEncoderDecoderModel](https://huggingface.co/docs/transformers/model_doc/vision-encoder-decoder) that could potentially do what you want. MatCha/DePlot have the advantage that they already had a significant amount of training, so I would assume a new pair would struggle without that.",
      "votes": null
    },
    {
      "id": "2311059",
      "postDate": "06/20/2023 21:51:00",
      "content": "<p>Right, you wouldn't be able to use pretrained weights :(</p>",
      "rawMarkdown": "Right, you wouldn't be able to use pretrained weights :(",
      "votes": null
    },
    {
      "id": "2311068",
      "postDate": "06/20/2023 22:16:47",
      "content": "<p><a href=\"https://huggingface.co/docs/transformers/model_doc/vision-encoder-decoder#initialising-visionencoderdecodermodel-from-a-pretrained-encoder-and-a-pretrained-decoder\" target=\"_blank\">You can use pretrained weights</a>. The cross attention ones will be newly initialized but everything else will be fine</p>",
      "rawMarkdown": "[You can use pretrained weights](https://huggingface.co/docs/transformers/model_doc/vision-encoder-decoder#initialising-visionencoderdecodermodel-from-a-pretrained-encoder-and-a-pretrained-decoder). The cross attention ones will be newly initialized but everything else will be fine",
      "votes": null
    },
    {
      "id": "2311148",
      "postDate": "06/21/2023 00:36:30",
      "content": "<p>add those two lines </p>\n<pre><code>xy_pixels = ax.transData.transform(np.vstack([xs,ys]).T)\nnp.save(config.out_file + .(fnum), xy_pixels)\n</code></pre>\n<p>after </p>\n<pre><code>fig.savefig(config.out_file + .(fnum))\n</code></pre>\n<p>thanks to <br>\n<a href=\"https://stackoverflow.com/questions/13662525/how-to-get-pixel-coordinates-for-matplotlib-generated-scatterplot/13662938\" target=\"_blank\">https://stackoverflow.com/questions/13662525/how-to-get-pixel-coordinates-for-matplotlib-generated-scatterplot/13662938</a></p>",
      "rawMarkdown": "add those two lines \n\n```python\nxy_pixels = ax.transData.transform(np.vstack([xs,ys]).T)\nnp.save(config.out_file + 'pixel_xy/{}.npy'.format(fnum), xy_pixels)\n```\n\nafter \n```python\nfig.savefig(config.out_file + 'images/{}.jpg'.format(fnum))#, bbox_inches='tight')\n```\n\nthanks to \nhttps://stackoverflow.com/questions/13662525/how-to-get-pixel-coordinates-for-matplotlib-generated-scatterplot/13662938",
      "votes": null
    },
    {
      "id": "2311192",
      "postDate": "06/21/2023 02:17:57",
      "content": "<p>Now I know why I was unable to reserve a100 gpus in Jarvislabs for last few days 😅</p>",
      "rawMarkdown": "Now I know why I was unable to reserve a100 gpus in Jarvislabs for last few days 😅",
      "votes": null
    },
    {
      "id": "2311196",
      "postDate": "06/21/2023 02:22:27",
      "content": "<p>I wanted to try finetuning pix2struct-large directly (google/pix2struct-chartqa-large would be better starting point, but strangely this checkpoint is missing in HF, although it was trained by google), since matcha/deplot had only base models. Data also wasn't a problem since we could have generated as many synthetic plots as necessary. But it would have been too expensive…</p>",
      "rawMarkdown": "I wanted to try finetuning pix2struct-large directly (google/pix2struct-chartqa-large would be better starting point, but strangely this checkpoint is missing in HF, although it was trained by google), since matcha/deplot had only base models. Data also wasn't a problem since we could have generated as many synthetic plots as necessary. But it would have been too expensive...",
      "votes": null
    },
    {
      "id": "2311203",
      "postDate": "06/21/2023 02:31:29",
      "content": "<p>In my training runs, Matcha did better in initial stages, however validation scores for Matcha/Deplot converge with longer training</p>",
      "rawMarkdown": "In my training runs, Matcha did better in initial stages, however validation scores for Matcha/Deplot converge with longer training",
      "votes": null
    },
    {
      "id": "2311207",
      "postDate": "06/21/2023 02:35:15",
      "content": "<p><a href=\"https://www.kaggle.com/crodoc\" target=\"_blank\">@crodoc</a> </p>\n<blockquote>\n  <p>I think I spent 500 USD in the last 2 days</p>\n</blockquote>\n<p>It's good that you get prize money to cover that 😄</p>",
      "rawMarkdown": "crodoc \n\n> I think I spent 500 USD in the last 2 days\n\nIt's good that you get prize money to cover that 😄",
      "votes": null
    },
    {
      "id": "2311466",
      "postDate": "06/21/2023 07:13:42",
      "content": "<p><a href=\"https://www.kaggle.com/christofhenkel\" target=\"_blank\">@christofhenkel</a> Congrats for prize!<br>\nI have a question, the nms (max_pool2d) you mentioned above seems that it is hard to process the situation when two or more scatters overlap together?</p>",
      "rawMarkdown": "christofhenkel Congrats for prize!\nI have a question, the nms (max_pool2d) you mentioned above seems that it is hard to process the situation when two or more scatters overlap together?",
      "votes": null
    },
    {
      "id": "2311516",
      "postDate": "06/21/2023 07:53:25",
      "content": "<p>Yes, I took them all. Along with all A6000s and even 4x A5000 🤣</p>",
      "rawMarkdown": "Yes, I took them all. Along with all A6000s and even 4x A5000 🤣",
      "votes": null
    },
    {
      "id": "2311520",
      "postDate": "06/21/2023 07:55:22",
      "content": "<p><a href=\"https://www.kaggle.com/conjuring92\" target=\"_blank\">@conjuring92</a> did you use different ground truth format for marcha and deplot? Or it didn't matter? For us, deplot was more sensitive to the format.</p>",
      "rawMarkdown": "conjuring92 did you use different ground truth format for marcha and deplot? Or it didn't matter? For us, deplot was more sensitive to the format.",
      "votes": null
    },
    {
      "id": "2311564",
      "postDate": "06/21/2023 08:38:10",
      "content": "<p>nms_kernel_size of 3 will keep maximum within distance of 3. As long as the center pixel of both scatter points is more than 3 pixels away its fine.</p>\n<p>A good practice is to check the model capability by using the gt segmentation mask. performing NMS with kernel size 3 on those will get the number of scatter points correct with an accuracy 99.7%. If you increase NMS kenrel to 5 the accuracy drops to 95% because of exactly the issue you mentioned: overlapping points</p>",
      "rawMarkdown": "nms_kernel_size of 3 will keep maximum within distance of 3. As long as the center pixel of both scatter points is more than 3 pixels away its fine.\n\nA good practice is to check the model capability by using the gt segmentation mask. performing NMS with kernel size 3 on those will get the number of scatter points correct with an accuracy 99.7%. If you increase NMS kenrel to 5 the accuracy drops to 95% because of exactly the issue you mentioned: overlapping points",
      "votes": null
    },
    {
      "id": "2311573",
      "postDate": "06/21/2023 08:44:32",
      "content": "<p>Thanks for your reply!</p>",
      "rawMarkdown": "Thanks for your reply!",
      "votes": null
    },
    {
      "id": "2312019",
      "postDate": "06/21/2023 15:56:22",
      "content": "<p>Impressive 6th place solution combining deplot and UNet models. Effective data preprocessing, including rounding numerical values and bucketing labels. Utilized external data and pseudo-labeling techniques. Ensembling through averaging decoder predictions and mask averaging. Achieved a high score of 0.87 in the competition. Well done!</p>",
      "rawMarkdown": "Impressive 6th place solution combining deplot and UNet models. Effective data preprocessing, including rounding numerical values and bucketing labels. Utilized external data and pseudo-labeling techniques. Ensembling through averaging decoder predictions and mask averaging. Achieved a high score of 0.87 in the competition. Well done!",
      "votes": null
    },
    {
      "id": "2313479",
      "postDate": "06/22/2023 17:53:56",
      "content": "<p>useful thks </p>",
      "rawMarkdown": "useful thks",
      "votes": null
    },
    {
      "id": "2319396",
      "postDate": "06/27/2023 05:28:42",
      "content": "<p><a href=\"https://www.kaggle.com/christofhenkel\" target=\"_blank\">@christofhenkel</a> very interesting solution! Thanks!</p>",
      "rawMarkdown": "christofhenkel very interesting solution! Thanks!",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 2311030,
      "author_name": "crodoc",
      "author_url": "",
      "post_date": "06/20/2023 20:49:03",
      "content": "<p>Did you try out matcha? We used it with the ground truth format similar to <a href=\"https://www.kaggle.com/nbroad\" target=\"_blank\">@nbroad</a>'s donut approach.<br>\ndeplot worked with the ground truth format like you used, but performed slightly worse than matcha overall.</p>\n<p>matcha didn't work well on scatter though … so we didn't use it at all for scatter.</p>",
      "votes": null,
      "replies": [
        {
          "id": 2311032,
          "author_name": "christofhenkel",
          "author_url": "",
          "post_date": "06/20/2023 20:51:53",
          "content": "<p>In the beginning matcha was way worse for us. But after we found that pretraining helps, matcha was roughly same as deplot. We also tried Pix2Struct Large. But no luck there.  </p>",
          "votes": null,
          "replies": [
            {
              "id": 2311035,
              "author_name": "crodoc",
              "author_url": "",
              "post_date": "06/20/2023 20:53:03",
              "content": "<p>Strange. It was always the other way around for us. matcha was always better than deplot.</p>",
              "votes": null,
              "replies": []
            },
            {
              "id": 2311203,
              "author_name": "conjuring92",
              "author_url": "",
              "post_date": "06/21/2023 02:31:29",
              "content": "<p>In my training runs, Matcha did better in initial stages, however validation scores for Matcha/Deplot converge with longer training</p>",
              "votes": null,
              "replies": [
                {
                  "id": 2311520,
                  "author_name": "crodoc",
                  "author_url": "",
                  "post_date": "06/21/2023 07:55:22",
                  "content": "<p><a href=\"https://www.kaggle.com/conjuring92\" target=\"_blank\">@conjuring92</a> did you use different ground truth format for marcha and deplot? Or it didn't matter? For us, deplot was more sensitive to the format.</p>",
                  "votes": null,
                  "replies": []
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "id": 2311036,
      "author_name": "alejopaullier",
      "author_url": "",
      "post_date": "06/20/2023 20:57:44",
      "content": "<p>Noob question here (not an expert in object detection), how did you manage your object detector to predict the right number of data series points? For instance, I selected a probability threshold which optimized the correct number of exact matches. However, sometimes I could get false positives (longer sequences) or get a shorter sequence. Also, which <code>timm</code> backbone did you use? </p>\n<p>Thanks and congratulations</p>",
      "votes": null,
      "replies": [
        {
          "id": 2311037,
          "author_name": "christofhenkel",
          "author_url": "",
          "post_date": "06/20/2023 21:04:49",
          "content": "<p>Say x_seg is your predicted segmentation mask. Run non maximum supression and count number of remaining positive pixels</p>\n<pre><code>            x_pred = x_seg.sigmoid()\n            x_pooled = F.max_pool2d(x_pred, kernel_size=self.nms_kernel_size, stride=, padding=self.nms_padding)\n            x_pred[x_pred != x_pooled] = \n            n_pred = (x_pred[:,] &gt; self.n_threshold).((,))\n</code></pre>\n<blockquote>\n  <p>Also, which timm backbone did you use?</p>\n</blockquote>\n<p>Stated in the modeling section: U-Net (EfficientNet-B7 encoder) Segmentation models pytorch enables using most of encoders from timm. So for us it was tf_efficientnet_b7_ns</p>",
          "votes": null,
          "replies": [
            {
              "id": 2311466,
              "author_name": "fankaixie",
              "author_url": "",
              "post_date": "06/21/2023 07:13:42",
              "content": "<p><a href=\"https://www.kaggle.com/christofhenkel\" target=\"_blank\">@christofhenkel</a> Congrats for prize!<br>\nI have a question, the nms (max_pool2d) you mentioned above seems that it is hard to process the situation when two or more scatters overlap together?</p>",
              "votes": null,
              "replies": [
                {
                  "id": 2311564,
                  "author_name": "christofhenkel",
                  "author_url": "",
                  "post_date": "06/21/2023 08:38:10",
                  "content": "<p>nms_kernel_size of 3 will keep maximum within distance of 3. As long as the center pixel of both scatter points is more than 3 pixels away its fine.</p>\n<p>A good practice is to check the model capability by using the gt segmentation mask. performing NMS with kernel size 3 on those will get the number of scatter points correct with an accuracy 99.7%. If you increase NMS kenrel to 5 the accuracy drops to 95% because of exactly the issue you mentioned: overlapping points</p>",
                  "votes": null,
                  "replies": [
                    {
                      "id": 2311573,
                      "author_name": "fankaixie",
                      "author_url": "",
                      "post_date": "06/21/2023 08:44:32",
                      "content": "<p>Thanks for your reply!</p>",
                      "votes": null,
                      "replies": []
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "id": 2311038,
      "author_name": "nbroad",
      "author_url": "",
      "post_date": "06/20/2023 21:09:07",
      "content": "<p>Awesome job!</p>\n<p>If you had an additional week or two, what else would you have tried?</p>",
      "votes": null,
      "replies": [
        {
          "id": 2311040,
          "author_name": "crodoc",
          "author_url": "",
          "post_date": "06/20/2023 21:13:38",
          "content": "<p>I am extremely happy there was no more additional weeks. This one extra was too much 🤣</p>",
          "votes": null,
          "replies": [
            {
              "id": 2311041,
              "author_name": "nbroad",
              "author_url": "",
              "post_date": "06/20/2023 21:16:09",
              "content": "<p>True! I'm just curious what ideas never got explored</p>",
              "votes": null,
              "replies": [
                {
                  "id": 2311047,
                  "author_name": "crodoc",
                  "author_url": "",
                  "post_date": "06/20/2023 21:30:56",
                  "content": "<p>Our best submission doesn't use external data. I tried to incorporate ICDAR on the night of the license change announcment, but who knows what was the quality of those labels. I didn't have the time to go over them. I had to spawn new gpus as fast as I could 😅 training on 4gpus would take more than 1 day.</p>\n<p>I'd add cleanly labeled external data.</p>",
                  "votes": null,
                  "replies": [
                    {
                      "id": 2311051,
                      "author_name": "crodoc",
                      "author_url": "",
                      "post_date": "06/20/2023 21:36:29",
                      "content": "<p>Thank you <a href=\"https://www.kaggle.com/vishnus\" target=\"_blank\">@vishnus</a> for jarvislabs. I think I spent 500 USD in the last 2 days trying to retrain models due to license change announcment. Saved me on icecube as well. It was impossible to get instances immediately on gcp or aws.</p>",
                      "votes": null,
                      "replies": [
                        {
                          "id": 2311192,
                          "author_name": "conjuring92",
                          "author_url": "",
                          "post_date": "06/21/2023 02:17:57",
                          "content": "<p>Now I know why I was unable to reserve a100 gpus in Jarvislabs for last few days 😅</p>",
                          "votes": null,
                          "replies": [
                            {
                              "id": 2311516,
                              "author_name": "crodoc",
                              "author_url": "",
                              "post_date": "06/21/2023 07:53:25",
                              "content": "<p>Yes, I took them all. Along with all A6000s and even 4x A5000 🤣</p>",
                              "votes": null,
                              "replies": []
                            }
                          ]
                        },
                        {
                          "id": 2311207,
                          "author_name": "nbroad",
                          "author_url": "",
                          "post_date": "06/21/2023 02:35:15",
                          "content": "<p><a href=\"https://www.kaggle.com/crodoc\" target=\"_blank\">@crodoc</a> </p>\n<blockquote>\n  <p>I think I spent 500 USD in the last 2 days</p>\n</blockquote>\n<p>It's good that you get prize money to cover that 😄</p>",
                          "votes": null,
                          "replies": []
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "id": 2311042,
          "author_name": "alejopaullier",
          "author_url": "",
          "post_date": "06/20/2023 21:23:05",
          "content": "<p>I wanted to try to change the vision model and the text model from Pix2Struct and see if other backbones performed better but didnt find out how. Do you happen to know how to do this?</p>",
          "votes": null,
          "replies": [
            {
              "id": 2311052,
              "author_name": "nbroad",
              "author_url": "",
              "post_date": "06/20/2023 21:37:46",
              "content": "<p><a href=\"https://www.kaggle.com/alejopaullier\" target=\"_blank\">@alejopaullier</a> <br>\nThere is a generic <a href=\"https://huggingface.co/docs/transformers/model_doc/vision-encoder-decoder\" target=\"_blank\">VisionEncoderDecoderModel</a> that could potentially do what you want. MatCha/DePlot have the advantage that they already had a significant amount of training, so I would assume a new pair would struggle without that.</p>",
              "votes": null,
              "replies": [
                {
                  "id": 2311059,
                  "author_name": "alejopaullier",
                  "author_url": "",
                  "post_date": "06/20/2023 21:51:00",
                  "content": "<p>Right, you wouldn't be able to use pretrained weights :(</p>",
                  "votes": null,
                  "replies": [
                    {
                      "id": 2311068,
                      "author_name": "nbroad",
                      "author_url": "",
                      "post_date": "06/20/2023 22:16:47",
                      "content": "<p><a href=\"https://huggingface.co/docs/transformers/model_doc/vision-encoder-decoder#initialising-visionencoderdecodermodel-from-a-pretrained-encoder-and-a-pretrained-decoder\" target=\"_blank\">You can use pretrained weights</a>. The cross attention ones will be newly initialized but everything else will be fine</p>",
                      "votes": null,
                      "replies": [
                        {
                          "id": 2311196,
                          "author_name": "conjuring92",
                          "author_url": "",
                          "post_date": "06/21/2023 02:22:27",
                          "content": "<p>I wanted to try finetuning pix2struct-large directly (google/pix2struct-chartqa-large would be better starting point, but strangely this checkpoint is missing in HF, although it was trained by google), since matcha/deplot had only base models. Data also wasn't a problem since we could have generated as many synthetic plots as necessary. But it would have been too expensive…</p>",
                          "votes": null,
                          "replies": []
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "id": 2311043,
      "author_name": "brendanartley",
      "author_url": "",
      "post_date": "06/20/2023 21:27:21",
      "content": "<p>Thanks for the comprehensive write-up and nice use of the double decoder, nice approach.</p>\n<p>How were you able to output the x/y coordinates of generated scatter plots?</p>",
      "votes": null,
      "replies": [
        {
          "id": 2311148,
          "author_name": "christofhenkel",
          "author_url": "",
          "post_date": "06/21/2023 00:36:30",
          "content": "<p>add those two lines </p>\n<pre><code>xy_pixels = ax.transData.transform(np.vstack([xs,ys]).T)\nnp.save(config.out_file + .(fnum), xy_pixels)\n</code></pre>\n<p>after </p>\n<pre><code>fig.savefig(config.out_file + .(fnum))\n</code></pre>\n<p>thanks to <br>\n<a href=\"https://stackoverflow.com/questions/13662525/how-to-get-pixel-coordinates-for-matplotlib-generated-scatterplot/13662938\" target=\"_blank\">https://stackoverflow.com/questions/13662525/how-to-get-pixel-coordinates-for-matplotlib-generated-scatterplot/13662938</a></p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 2312019,
      "author_name": "poojach7611",
      "author_url": "",
      "post_date": "06/21/2023 15:56:22",
      "content": "<p>Impressive 6th place solution combining deplot and UNet models. Effective data preprocessing, including rounding numerical values and bucketing labels. Utilized external data and pseudo-labeling techniques. Ensembling through averaging decoder predictions and mask averaging. Achieved a high score of 0.87 in the competition. Well done!</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2313479,
      "author_name": "vandittyagi0909",
      "author_url": "",
      "post_date": "06/22/2023 17:53:56",
      "content": "<p>useful thks </p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2319396,
      "author_name": "serangu",
      "author_url": "",
      "post_date": "06/27/2023 05:28:42",
      "content": "<p><a href=\"https://www.kaggle.com/christofhenkel\" target=\"_blank\">@christofhenkel</a> very interesting solution! Thanks!</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "2311018": "Thanks to kaggle and benetech for hosting an interesting problem. It was a great team effort with @darraghdog \n\n## TLDR\nOur solution is a 4 seed blend of a single deplot model for all chart types. For scatter plots we run additional post processing by using the number of scatter points predicted by a U-Net point segmentation model. \n\n## Data preprocessing\n\n### Benetech dataset\n\nFor training we used all of benetech extracted data, and approx 20% of the generated data which was selected based on the hardest samples. This helped speed up the training pipeline significantly. \nNumerical values had a lot of digits in ground truth which did not match well with our loss function (cross entropy) in pix2struct based models. Therefore, it was important to round these numerical values. For this, we bucketed the labels to approx 5 buckets within the tick label axis. So, for example, the buckets in the below would be `0, 40000, 80000, 120000, 160000, 200000, 240000… etc.` and the y-axis label to learn would be `840000, 960000, 760000, 700000, 580000, 460000, etc.`. For ground truth labels which had no tick labels, similar rounding was performed based on the min-max range of the data series, using approximately 40 buckets. \n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1424766%2Fdd90fda19f8e33c767b75e32188a0c29%2FScreenshot%202023-06-20%20at%2021.37.57.png?generation=1687289889671066&alt=media)\n\nWithin the pix2struct model, the labels were learned as key-value sequences, similar to the training of deplot. For the example above, that would be\n `<pad>Malaysia;960000|Malawi;840000|Maldives;760000|Mali;700000|Mauritania;660000|Melanesia;580000|Malta;580000|Mauritius;540000|Martinique;460000|Mayotte;420000<\\s>`\n\nA separate decoder was used to learn the reversed key-value sequence. This was linked to the same encoder and added as an auxiliary loss so the model would not focus more on either side of the image. Since the heavy part of deplot is the encoder, a double decoder did not create much overhead.\n\n### External data \n\nFor this competition, we utilized a commercially available subset of PubMed articles to train our models. Approximately 80% of the labeled samples in the ICDAR dataset were found to originate from this commercial dataset. We ensured that the use of this dataset complied with the applicable licensing terms. To expand our training data, we applied pseudo-labeling techniques followed by manual review. Specifically, we pseudo-labeled and manually reviewed around 8,000 bar and line graph samples from PubMed articles. The pseudo-labeling results were quite accurate on bars, requiring only verification that the identified charts were the correct type (e.g. removing box plots). Lines needed some corrections. We also used our U-Net model to pseudo-label approximately 1,000 scatter plot samples from PubMed, and then manually added any missing data points. Using the VGG Image Annotator tool, this manual annotation process was surprisingly fast and efficient. \n\n### Data generation\nWe used the great [public kernel](https://www.kaggle.com/code/brendanartley/benetech-5-chart-types-generator) by @brendanartley in two ways\n\nWe pretrained our deplot models using the 500k images downloadable the public kernel, which gave a small improvement, compared to using the original checkpoint from huggingface. \n\nWe also tweaked the kernel a bit to generate more sophisticated scatter plots (more points, different markers, more overlap etc) and output x/y coordinates of each scatter point. We generated 50k scatter plots with that script and used them additionally for training the segmentation model\n\n## Models\n\nDeplot was used for predicting bars, lines and scatter; for scatter, we additionally used a u-net model. \n\nDeplot was trained for 20 epochs, with a learning rate of approx 5e-5 and batchsize 8. [Pixeldropout augmentation](https://github.com/albumentations-team/albumentations/blob/master/albumentations/augmentations/transforms.py#L2413) was found to prevent overfitting. No other image augmentations were used. For experimentation, 1024 patches were used which decreased training time 2X with only a slight degradation in scores. The loss was a combination of cross entropy on the key value sequences mentioned above and the chart type. A linear layer on top of the first token of deplot was used to predict the chart type as an auxiliary.\n\nFor scatter plots we used a U-Net (EfficientNet-B7 encoder) + non maximum suppression (NMS) to predict number of scatter points and performed a simple yet effective postprocessing where deplot predicted a different number of points:\n\n- If deplot predicted too many points, disregard the last ones\n- If deplot predicted too few points, fill missing with the mean value\n\nBelow you can see the segmentation mask for U-Net training. Using the scatter point annotation we created “smooth” points with 10 pixel gaussian radius and drew onto an empty image. \n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1424766%2Fe0cbc56d90a54892ee8a4365b03d2f59%2FScreenshot%202023-06-20%20at%2021.44.38.png?generation=1687290294572628&alt=media)\n\n## Ensembling\n\nFor deplot we did inner ensembling by averaging decoder prediction in each greedy decoding step. For Unet we simply averaged predicted masks before performing NMS.\n\n## Ablation study (Public LB Scores)\n\nThe following table gives a quick overview, how much each component contributed to our solution\n\n| component | score |\n| --- | --- |\n| Baseline deplot@1024 tokens | 0.71 |\n| using fullfit | +0.01 |\n| 1024 -> 2048 tokens | +0.03 |\n| Scatter pp Unet@512x512 | +0.05 |\n| Pixeldropout | +0.01 |\n| External data | +0.02 |\n| Pretrain on 500k | +0.01 |\n| Unet@512x512 -> 768x768 | +0.01 |\n| 3x Unet@768x768 | +0.01 |\n| 4x seed blend of deplots | +0.01 |\n **final score** | **0.87** \n\n## Used tools/ repos\n\n- Unet:[ Segmentation models pytorch](https://github.com/qubvel/segmentation_models.pytorch) + [timm encoder](https://github.com/huggingface/pytorch-image-models/tree/main/timm)\n- Deplot: [huggingface](https://huggingface.co/google/deplot)\n- logging/ visualization: [neptune.ai](https://neptune.ai/)\n- augmentation: [albumentations](https://albumentations.ai/)\n- labelling: [VGG Image Annotator tool](https://www.robots.ox.ac.uk/~vgg/software/via/)\n\nThank you for reading, questions welcome\n\nedit:\n\nJune 21st: inference kernel made public: https://www.kaggle.com/code/christofhenkel/benetech-6th-place-dd/notebook",
    "2311030": "Did you try out matcha? We used it with the ground truth format similar to @nbroad's donut approach.\ndeplot worked with the ground truth format like you used, but performed slightly worse than matcha overall.\n\nmatcha didn't work well on scatter though ... so we didn't use it at all for scatter.",
    "2311032": "In the beginning matcha was way worse for us. But after we found that pretraining helps, matcha was roughly same as deplot. We also tried Pix2Struct Large. But no luck there.",
    "2311035": "Strange. It was always the other way around for us. matcha was always better than deplot.",
    "2311036": "Noob question here (not an expert in object detection), how did you manage your object detector to predict the right number of data series points? For instance, I selected a probability threshold which optimized the correct number of exact matches. However, sometimes I could get false positives (longer sequences) or get a shorter sequence. Also, which `timm` backbone did you use? \n\nThanks and congratulations",
    "2311037": "Say x_seg is your predicted segmentation mask. Run non maximum supression and count number of remaining positive pixels\n\n```python\n            x_pred = x_seg.sigmoid()\n            x_pooled = F.max_pool2d(x_pred, kernel_size=self.nms_kernel_size, stride=1, padding=self.nms_padding)\n            x_pred[x_pred != x_pooled] = 0\n            n_pred = (x_pred[:,0] > self.n_threshold).sum((1,2))\n```\n\n>Also, which timm backbone did you use?\n\nStated in the modeling section: U-Net (EfficientNet-B7 encoder) Segmentation models pytorch enables using most of encoders from timm. So for us it was tf_efficientnet_b7_ns",
    "2311038": "Awesome job!\n\nIf you had an additional week or two, what else would you have tried?",
    "2311040": "I am extremely happy there was no more additional weeks. This one extra was too much 🤣",
    "2311041": "True! I'm just curious what ideas never got explored",
    "2311042": "I wanted to try to change the vision model and the text model from Pix2Struct and see if other backbones performed better but didnt find out how. Do you happen to know how to do this?",
    "2311043": "Thanks for the comprehensive write-up and nice use of the double decoder, nice approach.\n\nHow were you able to output the x/y coordinates of generated scatter plots?",
    "2311047": "Our best submission doesn't use external data. I tried to incorporate ICDAR on the night of the license change announcment, but who knows what was the quality of those labels. I didn't have the time to go over them. I had to spawn new gpus as fast as I could 😅 training on 4gpus would take more than 1 day.\n\nI'd add cleanly labeled external data.",
    "2311051": "Thank you @vishnus for jarvislabs. I think I spent 500 USD in the last 2 days trying to retrain models due to license change announcment. Saved me on icecube as well. It was impossible to get instances immediately on gcp or aws.",
    "2311052": "alejopaullier \nThere is a generic [VisionEncoderDecoderModel](https://huggingface.co/docs/transformers/model_doc/vision-encoder-decoder) that could potentially do what you want. MatCha/DePlot have the advantage that they already had a significant amount of training, so I would assume a new pair would struggle without that.",
    "2311059": "Right, you wouldn't be able to use pretrained weights :(",
    "2311068": "[You can use pretrained weights](https://huggingface.co/docs/transformers/model_doc/vision-encoder-decoder#initialising-visionencoderdecodermodel-from-a-pretrained-encoder-and-a-pretrained-decoder). The cross attention ones will be newly initialized but everything else will be fine",
    "2311148": "add those two lines \n\n```python\nxy_pixels = ax.transData.transform(np.vstack([xs,ys]).T)\nnp.save(config.out_file + 'pixel_xy/{}.npy'.format(fnum), xy_pixels)\n```\n\nafter \n```python\nfig.savefig(config.out_file + 'images/{}.jpg'.format(fnum))#, bbox_inches='tight')\n```\n\nthanks to \nhttps://stackoverflow.com/questions/13662525/how-to-get-pixel-coordinates-for-matplotlib-generated-scatterplot/13662938",
    "2311192": "Now I know why I was unable to reserve a100 gpus in Jarvislabs for last few days 😅",
    "2311196": "I wanted to try finetuning pix2struct-large directly (google/pix2struct-chartqa-large would be better starting point, but strangely this checkpoint is missing in HF, although it was trained by google), since matcha/deplot had only base models. Data also wasn't a problem since we could have generated as many synthetic plots as necessary. But it would have been too expensive...",
    "2311203": "In my training runs, Matcha did better in initial stages, however validation scores for Matcha/Deplot converge with longer training",
    "2311207": "crodoc \n\n> I think I spent 500 USD in the last 2 days\n\nIt's good that you get prize money to cover that 😄",
    "2311466": "christofhenkel Congrats for prize!\nI have a question, the nms (max_pool2d) you mentioned above seems that it is hard to process the situation when two or more scatters overlap together?",
    "2311516": "Yes, I took them all. Along with all A6000s and even 4x A5000 🤣",
    "2311520": "conjuring92 did you use different ground truth format for marcha and deplot? Or it didn't matter? For us, deplot was more sensitive to the format.",
    "2311564": "nms_kernel_size of 3 will keep maximum within distance of 3. As long as the center pixel of both scatter points is more than 3 pixels away its fine.\n\nA good practice is to check the model capability by using the gt segmentation mask. performing NMS with kernel size 3 on those will get the number of scatter points correct with an accuracy 99.7%. If you increase NMS kenrel to 5 the accuracy drops to 95% because of exactly the issue you mentioned: overlapping points",
    "2311573": "Thanks for your reply!",
    "2312019": "Impressive 6th place solution combining deplot and UNet models. Effective data preprocessing, including rounding numerical values and bucketing labels. Utilized external data and pseudo-labeling techniques. Ensembling through averaging decoder predictions and mask averaging. Achieved a high score of 0.87 in the competition. Well done!",
    "2313479": "useful thks",
    "2319396": "christofhenkel very interesting solution! Thanks!"
  },
  "source": "existing_discussion",
  "complete": true,
  "competition_id": 43873,
  "competition_slug": "benetech-making-graphs-accessible",
  "team_id": 10322235,
  "solution_url": "/competitions/benetech-making-graphs-accessible/writeups/dd-6th-place-solution-deplot-unet-postprocessing"
}