{
  "id": 418321,
  "title": "#13th place solution",
  "url": "/competitions/benetech-making-graphs-accessible/writeups/the-nam-13th-place-solution",
  "author_name": "",
  "post_date": "2023-06-20T02:21:41.690Z",
  "votes": 43,
  "comment_count": 8,
  "views": 0,
  "content": "<p>Thank Kaggle and the host to organize the competition. I want to do a quick write-up of my simple solution. Everything is basic, all steps can be done using Kaggle and Google Colab (Pro) computing resources.</p>\n<p>Final Submission notebook: <a href=\"https://www.kaggle.com/code/namgalielei/benetech-eval-and-infer-v12/notebook\" target=\"_blank\">https://www.kaggle.com/code/namgalielei/benetech-eval-and-infer-v12/notebook</a></p>\n<h2>1. Overview</h2>\n<p>Chart type classification + Plot BBox prediction -&gt;  OCR -&gt; Chart data instance detection / segmentation (line) -&gt; Data association </p>\n<h2>2. Modules</h2>\n<h3>a. Chart type classification + Plot BBox prediction:</h3>\n<ul>\n<li>Segmentation model pytorch Unet with backbone eca nfnet l1, auxilary classification head. I do binary segmentation for Plot BBox prediction, and softmax classifcation for Chart type classification </li>\n<li>Ensemble 3 folds.<br>\nTraining code: <a href=\"https://colab.research.google.com/drive/1WdlqUr1ONcntWfaIksDp6Z6BD4MXDJg4?usp=sharing\" target=\"_blank\">https://colab.research.google.com/drive/1WdlqUr1ONcntWfaIksDp6Z6BD4MXDJg4?usp=sharing</a></li>\n</ul>\n<h3>b. OCR:</h3>\n<ul>\n<li>Based on Paddle ppOCRv3</li>\n<li>Text detection: Fine tune the light weighted mobilenetv3-dbnet on the competition's data. The target is at word group level. The ground-truth for this is provided on the json file.</li>\n<li>Text recognition: Use the pretrained model. </li>\n<li>Modify some logic: First, the default post processing of Paddle TextDet (mask to quad) may result in some polygons with only 3 points (triangle instead of quadrilateral). I fixed this by finding the minimum bounding rotated rectangle. Second, when perspective-transform a cropped text, it might be rotated, so the text recognition is not able to read them well. I predict twice (no rotation and clock-wise 90deg rotation) and take the one with higher confidence score. </li>\n</ul>\n<h3>c. Chart data detection:</h3>\n<ul>\n<li>VBar, HBar, Scatter and Dot detector: Mask RCNN Resnet50 model. Training code: <a href=\"https://colab.research.google.com/drive/14X97mTwAU9kxS__xaehDU7SQbe_2ivP0?usp=sharing\" target=\"_blank\">https://colab.research.google.com/drive/14X97mTwAU9kxS__xaehDU7SQbe_2ivP0?usp=sharing</a></li>\n<li>Line detector: a single Unet++ model with backbone efficientnet b5. Training code: <a href=\"https://drive.google.com/file/d/1OFoogWWWP3vHAHe9g0UsY0cCfiHKOeMp/view?usp=sharing\" target=\"_blank\">https://drive.google.com/file/d/1OFoogWWWP3vHAHe9g0UsY0cCfiHKOeMp/view?usp=sharing</a><br>\nI annotated some images and train these models.</li>\n</ul>\n<h3>d. Data association:</h3>\n<ul>\n<li>Some rule-based logic to associate the chart data (bar, scatter, dot) to its corresponding ticks. </li>\n<li>Project the pixel coordinates of ticks and chart data onto the axes-relative scale.</li>\n</ul>\n<p>Some thing not having time to try yet: External dataset, a wider range of instance segmentation / object detection models, Generative models</p>",
  "messages": [
    {
      "id": "2309931",
      "postDate": "06/20/2023 02:02:15",
      "content": "<p>Thank Kaggle and the host to organize the competition. I want to do a quick write-up of my simple solution. Everything is basic, all steps can be done using Kaggle and Google Colab (Pro) computing resources.</p>\n<p>Final Submission notebook: <a href=\"https://www.kaggle.com/code/namgalielei/benetech-eval-and-infer-v12/notebook\" target=\"_blank\">https://www.kaggle.com/code/namgalielei/benetech-eval-and-infer-v12/notebook</a></p>\n<h2>1. Overview</h2>\n<p>Chart type classification + Plot BBox prediction -&gt;  OCR -&gt; Chart data instance detection / segmentation (line) -&gt; Data association </p>\n<h2>2. Modules</h2>\n<h3>a. Chart type classification + Plot BBox prediction:</h3>\n<ul>\n<li>Segmentation model pytorch Unet with backbone eca nfnet l1, auxilary classification head. I do binary segmentation for Plot BBox prediction, and softmax classifcation for Chart type classification </li>\n<li>Ensemble 3 folds.<br>\nTraining code: <a href=\"https://colab.research.google.com/drive/1WdlqUr1ONcntWfaIksDp6Z6BD4MXDJg4?usp=sharing\" target=\"_blank\">https://colab.research.google.com/drive/1WdlqUr1ONcntWfaIksDp6Z6BD4MXDJg4?usp=sharing</a></li>\n</ul>\n<h3>b. OCR:</h3>\n<ul>\n<li>Based on Paddle ppOCRv3</li>\n<li>Text detection: Fine tune the light weighted mobilenetv3-dbnet on the competition's data. The target is at word group level. The ground-truth for this is provided on the json file.</li>\n<li>Text recognition: Use the pretrained model. </li>\n<li>Modify some logic: First, the default post processing of Paddle TextDet (mask to quad) may result in some polygons with only 3 points (triangle instead of quadrilateral). I fixed this by finding the minimum bounding rotated rectangle. Second, when perspective-transform a cropped text, it might be rotated, so the text recognition is not able to read them well. I predict twice (no rotation and clock-wise 90deg rotation) and take the one with higher confidence score. </li>\n</ul>\n<h3>c. Chart data detection:</h3>\n<ul>\n<li>VBar, HBar, Scatter and Dot detector: Mask RCNN Resnet50 model. Training code: <a href=\"https://colab.research.google.com/drive/14X97mTwAU9kxS__xaehDU7SQbe_2ivP0?usp=sharing\" target=\"_blank\">https://colab.research.google.com/drive/14X97mTwAU9kxS__xaehDU7SQbe_2ivP0?usp=sharing</a></li>\n<li>Line detector: a single Unet++ model with backbone efficientnet b5. Training code: <a href=\"https://drive.google.com/file/d/1OFoogWWWP3vHAHe9g0UsY0cCfiHKOeMp/view?usp=sharing\" target=\"_blank\">https://drive.google.com/file/d/1OFoogWWWP3vHAHe9g0UsY0cCfiHKOeMp/view?usp=sharing</a><br>\nI annotated some images and train these models.</li>\n</ul>\n<h3>d. Data association:</h3>\n<ul>\n<li>Some rule-based logic to associate the chart data (bar, scatter, dot) to its corresponding ticks. </li>\n<li>Project the pixel coordinates of ticks and chart data onto the axes-relative scale.</li>\n</ul>\n<p>Some thing not having time to try yet: External dataset, a wider range of instance segmentation / object detection models, Generative models</p>",
      "rawMarkdown": "Thank Kaggle and the host to organize the competition. I want to do a quick write-up of my simple solution. Everything is basic, all steps can be done using Kaggle and Google Colab (Pro) computing resources.\n\nFinal Submission notebook: https://www.kaggle.com/code/namgalielei/benetech-eval-and-infer-v12/notebook\n\n## 1. Overview\nChart type classification + Plot BBox prediction ->  OCR -> Chart data instance detection / segmentation (line) -> Data association \n\n## 2. Modules\n### a. Chart type classification + Plot BBox prediction:\n- Segmentation model pytorch Unet with backbone eca nfnet l1, auxilary classification head. I do binary segmentation for Plot BBox prediction, and softmax classifcation for Chart type classification \n- Ensemble 3 folds.\nTraining code: https://colab.research.google.com/drive/1WdlqUr1ONcntWfaIksDp6Z6BD4MXDJg4?usp=sharing\n### b. OCR:\n- Based on Paddle ppOCRv3\n+ Text detection: Fine tune the light weighted mobilenetv3-dbnet on the competition's data. The target is at word group level. The ground-truth for this is provided on the json file.\n+ Text recognition: Use the pretrained model. \n+ Modify some logic: First, the default post processing of Paddle TextDet (mask to quad) may result in some polygons with only 3 points (triangle instead of quadrilateral). I fixed this by finding the minimum bounding rotated rectangle. Second, when perspective-transform a cropped text, it might be rotated, so the text recognition is not able to read them well. I predict twice (no rotation and clock-wise 90deg rotation) and take the one with higher confidence score. \n### c. Chart data detection: \n- VBar, HBar, Scatter and Dot detector: Mask RCNN Resnet50 model. Training code: https://colab.research.google.com/drive/14X97mTwAU9kxS__xaehDU7SQbe_2ivP0?usp=sharing\n- Line detector: a single Unet++ model with backbone efficientnet b5. Training code: https://drive.google.com/file/d/1OFoogWWWP3vHAHe9g0UsY0cCfiHKOeMp/view?usp=sharing\nI annotated some images and train these models.\n### d. Data association:\n- Some rule-based logic to associate the chart data (bar, scatter, dot) to its corresponding ticks. \n- Project the pixel coordinates of ticks and chart data onto the axes-relative scale.\n\nSome thing not having time to try yet: External dataset, a wider range of instance segmentation / object detection models, Generative models",
      "votes": null
    },
    {
      "id": "2309960",
      "postDate": "06/20/2023 02:46:38",
      "content": "<p><a href=\"https://www.kaggle.com/namgalielei\" target=\"_blank\">@namgalielei</a> Nice solution, can you tell me the reason why you use \"eca_nfnet_l1\" backbone?. It's not famous and popular.</p>",
      "rawMarkdown": "namgalielei Nice solution, can you tell me the reason why you use \"eca_nfnet_l1\" backbone?. It's not famous and popular.",
      "votes": null
    },
    {
      "id": "2309974",
      "postDate": "06/20/2023 02:59:09",
      "content": "<p>I have used it several times in the past and it showed good result. The architecture does not use batch norm which has some limitation. However, if you have time, you can try various model types in timm package and see what works with your data</p>",
      "rawMarkdown": "I have used it several times in the past and it showed good result. The architecture does not use batch norm which has some limitation. However, if you have time, you can try various model types in timm package and see what works with your data",
      "votes": null
    },
    {
      "id": "2309992",
      "postDate": "06/20/2023 03:42:30",
      "content": "<p>Thank you. when everyone use unet architecture, they often use se-resnext, efficientnet or some popular architectures,<br>\nI'm so surprised when you use an old and strange architecture backbone. </p>",
      "rawMarkdown": "Thank you. when everyone use unet architecture, they often use se-resnext, efficientnet or some popular architectures,\nI'm so surprised when you use an old and strange architecture backbone.",
      "votes": null
    },
    {
      "id": "2310097",
      "postDate": "06/20/2023 05:32:21",
      "content": "<p><a href=\"https://www.kaggle.com/namgalielei\" target=\"_blank\">@namgalielei</a> cool solution! Thanks for sharing notebook!</p>",
      "rawMarkdown": "namgalielei cool solution! Thanks for sharing notebook!",
      "votes": null
    },
    {
      "id": "2310361",
      "postDate": "06/20/2023 10:03:53",
      "content": "<p>Thank you for sharing your solution <a href=\"https://www.kaggle.com/namgalielei\" target=\"_blank\">@namgalielei</a> and congrats on your strong finish! That's a really good pipeline to study CV in general. A lot of things included. Also thank you for sharing your training code! </p>",
      "rawMarkdown": "Thank you for sharing your solution @namgalielei and congrats on your strong finish! That's a really good pipeline to study CV in general. A lot of things included. Also thank you for sharing your training code!",
      "votes": null
    },
    {
      "id": "2315075",
      "postDate": "06/23/2023 19:45:16",
      "content": "<p>Thanks for sharing.<br>\nHow did you generate segmentation mask for line plots? </p>",
      "rawMarkdown": "Thanks for sharing.\nHow did you generate segmentation mask for line plots?",
      "votes": null
    },
    {
      "id": "2317199",
      "postDate": "06/25/2023 14:00:31",
      "content": "<p>i am surprised about that as well. I should also give these less popular models a try.</p>",
      "rawMarkdown": "i am surprised about that as well. I should also give these less popular models a try.",
      "votes": null
    },
    {
      "id": "2317247",
      "postDate": "06/25/2023 14:32:56",
      "content": "<p>I use semi-auto mask generation. First, I notice that by using Opencv image processing, I can group out those pixels belong to the line with some heuristic thresholds (binarization), then use cv2.contours to retrieve those polygons of that line. Second, there are some lines which cannot be extracted automatically, I manually annotate them. </p>",
      "rawMarkdown": "I use semi-auto mask generation. First, I notice that by using Opencv image processing, I can group out those pixels belong to the line with some heuristic thresholds (binarization), then use cv2.contours to retrieve those polygons of that line. Second, there are some lines which cannot be extracted automatically, I manually annotate them.",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 2309960,
      "author_name": "hidngnguyna",
      "author_url": "",
      "post_date": "06/20/2023 02:46:38",
      "content": "<p><a href=\"https://www.kaggle.com/namgalielei\" target=\"_blank\">@namgalielei</a> Nice solution, can you tell me the reason why you use \"eca_nfnet_l1\" backbone?. It's not famous and popular.</p>",
      "votes": null,
      "replies": [
        {
          "id": 2309974,
          "author_name": "namgalielei",
          "author_url": "",
          "post_date": "06/20/2023 02:59:09",
          "content": "<p>I have used it several times in the past and it showed good result. The architecture does not use batch norm which has some limitation. However, if you have time, you can try various model types in timm package and see what works with your data</p>",
          "votes": null,
          "replies": [
            {
              "id": 2309992,
              "author_name": "hidngnguyna",
              "author_url": "",
              "post_date": "06/20/2023 03:42:30",
              "content": "<p>Thank you. when everyone use unet architecture, they often use se-resnext, efficientnet or some popular architectures,<br>\nI'm so surprised when you use an old and strange architecture backbone. </p>",
              "votes": null,
              "replies": [
                {
                  "id": 2317199,
                  "author_name": "joek47",
                  "author_url": "",
                  "post_date": "06/25/2023 14:00:31",
                  "content": "<p>i am surprised about that as well. I should also give these less popular models a try.</p>",
                  "votes": null,
                  "replies": []
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "id": 2310097,
      "author_name": "serangu",
      "author_url": "",
      "post_date": "06/20/2023 05:32:21",
      "content": "<p><a href=\"https://www.kaggle.com/namgalielei\" target=\"_blank\">@namgalielei</a> cool solution! Thanks for sharing notebook!</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2310361,
      "author_name": "snnclsr",
      "author_url": "",
      "post_date": "06/20/2023 10:03:53",
      "content": "<p>Thank you for sharing your solution <a href=\"https://www.kaggle.com/namgalielei\" target=\"_blank\">@namgalielei</a> and congrats on your strong finish! That's a really good pipeline to study CV in general. A lot of things included. Also thank you for sharing your training code! </p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2315075,
      "author_name": "tanjiroll",
      "author_url": "",
      "post_date": "06/23/2023 19:45:16",
      "content": "<p>Thanks for sharing.<br>\nHow did you generate segmentation mask for line plots? </p>",
      "votes": null,
      "replies": [
        {
          "id": 2317247,
          "author_name": "namgalielei",
          "author_url": "",
          "post_date": "06/25/2023 14:32:56",
          "content": "<p>I use semi-auto mask generation. First, I notice that by using Opencv image processing, I can group out those pixels belong to the line with some heuristic thresholds (binarization), then use cv2.contours to retrieve those polygons of that line. Second, there are some lines which cannot be extracted automatically, I manually annotate them. </p>",
          "votes": null,
          "replies": []
        }
      ]
    }
  ],
  "raw_markdown_by_id": {
    "2309931": "Thank Kaggle and the host to organize the competition. I want to do a quick write-up of my simple solution. Everything is basic, all steps can be done using Kaggle and Google Colab (Pro) computing resources.\n\nFinal Submission notebook: https://www.kaggle.com/code/namgalielei/benetech-eval-and-infer-v12/notebook\n\n## 1. Overview\nChart type classification + Plot BBox prediction ->  OCR -> Chart data instance detection / segmentation (line) -> Data association \n\n## 2. Modules\n### a. Chart type classification + Plot BBox prediction:\n- Segmentation model pytorch Unet with backbone eca nfnet l1, auxilary classification head. I do binary segmentation for Plot BBox prediction, and softmax classifcation for Chart type classification \n- Ensemble 3 folds.\nTraining code: https://colab.research.google.com/drive/1WdlqUr1ONcntWfaIksDp6Z6BD4MXDJg4?usp=sharing\n### b. OCR:\n- Based on Paddle ppOCRv3\n+ Text detection: Fine tune the light weighted mobilenetv3-dbnet on the competition's data. The target is at word group level. The ground-truth for this is provided on the json file.\n+ Text recognition: Use the pretrained model. \n+ Modify some logic: First, the default post processing of Paddle TextDet (mask to quad) may result in some polygons with only 3 points (triangle instead of quadrilateral). I fixed this by finding the minimum bounding rotated rectangle. Second, when perspective-transform a cropped text, it might be rotated, so the text recognition is not able to read them well. I predict twice (no rotation and clock-wise 90deg rotation) and take the one with higher confidence score. \n### c. Chart data detection: \n- VBar, HBar, Scatter and Dot detector: Mask RCNN Resnet50 model. Training code: https://colab.research.google.com/drive/14X97mTwAU9kxS__xaehDU7SQbe_2ivP0?usp=sharing\n- Line detector: a single Unet++ model with backbone efficientnet b5. Training code: https://drive.google.com/file/d/1OFoogWWWP3vHAHe9g0UsY0cCfiHKOeMp/view?usp=sharing\nI annotated some images and train these models.\n### d. Data association:\n- Some rule-based logic to associate the chart data (bar, scatter, dot) to its corresponding ticks. \n- Project the pixel coordinates of ticks and chart data onto the axes-relative scale.\n\nSome thing not having time to try yet: External dataset, a wider range of instance segmentation / object detection models, Generative models",
    "2309960": "namgalielei Nice solution, can you tell me the reason why you use \"eca_nfnet_l1\" backbone?. It's not famous and popular.",
    "2309974": "I have used it several times in the past and it showed good result. The architecture does not use batch norm which has some limitation. However, if you have time, you can try various model types in timm package and see what works with your data",
    "2309992": "Thank you. when everyone use unet architecture, they often use se-resnext, efficientnet or some popular architectures,\nI'm so surprised when you use an old and strange architecture backbone.",
    "2310097": "namgalielei cool solution! Thanks for sharing notebook!",
    "2310361": "Thank you for sharing your solution @namgalielei and congrats on your strong finish! That's a really good pipeline to study CV in general. A lot of things included. Also thank you for sharing your training code!",
    "2315075": "Thanks for sharing.\nHow did you generate segmentation mask for line plots?",
    "2317199": "i am surprised about that as well. I should also give these less popular models a try.",
    "2317247": "I use semi-auto mask generation. First, I notice that by using Opencv image processing, I can group out those pixels belong to the line with some heuristic thresholds (binarization), then use cv2.contours to retrieve those polygons of that line. Second, there are some lines which cannot be extracted automatically, I manually annotate them."
  },
  "source": "existing_discussion",
  "complete": true,
  "competition_id": 43873,
  "competition_slug": "benetech-making-graphs-accessible",
  "team_id": 10116840,
  "solution_url": "/competitions/benetech-making-graphs-accessible/writeups/the-nam-13th-place-solution"
}