{
  "id": 583306,
  "title": "Public 20th / Private 26th Solution LB: 0.908",
  "url": "/competitions/birdclef-2025/discussion/583306",
  "author_name": "Salman Ahmed",
  "post_date": "2025-06-06T02:40:56.840000",
  "votes": 26,
  "comment_count": 20,
  "views": 0,
  "content": "<p>Thanks everyone for the interesting competition, and congratulations to the winners ! I am happy that as a community we were able to detect these species to that much accurate. </p>\n<p><strong>Overview</strong><br>\nMy solution is a simple 2 stage solution. </p>\n<p><strong>First Stage Models</strong></p>\n<ul>\n<li>I was able to get LB 0.865 to 0.872 with the following settings. I had 3 CNNs and 1 SED trained and ensemble achieved LB 0.886.</li>\n<li>In this stage, I filtered human sounds as everyone else in the training data but randomly augmented a CSA recording with 30% of human sound with 50% probability. </li>\n<li>Another important / thing for me was to use the following settings. <br>\n<code>{'sample_rate': 32000, 'n_mels': 384, 'f_min': 0, 'f_max': 16000, 'n_fft': 3072, 'normalized': True, 'hop_length': 420}</code><br>\n<code>{'sample_rate': 32000, 'n_mels': 448, 'f_min': 50, 'f_max': 16000, 'n_fft': 4096, 'normalized': True, 'hop_length': 334}</code></li>\n<li>After apply AmplitudeToDB, I had to clip the values b/w 0 to -80. </li>\n<li>During training, I pick 15 seconds of audio chunk from complete audio file by RMS sampling, and then divide it into 3 x 5 seconds segments. Model predicts logits on 3 x 5 seconds of recordings, 3 x 206 and then I pick the max of these 3 recordings and then back propagate on those max logits of these 3 segments.</li>\n</ul>\n<pre><code>BS, K, C, H, W = spec.size()\nspec = spec.view(BS * K, C, H, W)\nlogits = model(spec)\nlogits = logits.view(BS, K, )\nlogits, _ = torch.(logits, dim=)\n</code></pre>\n<ul>\n<li>RMS sampling worked much better than random sampling for me.</li>\n<li>Loss: FocalBCE</li>\n<li>Augmentation: Mixup (p=1), LocalGlobal Stretch, Time / Frequency Shift, Time / Frequency Masking, Gaussian Noise. [All on spectrograms]</li>\n<li>Batch Size of 32.</li>\n<li>Model Soup from 12 to 15 epochs.</li>\n</ul>\n<p><strong>Second Stage Models</strong></p>\n<ul>\n<li>I was able to get Public LB 0.909 / Private LB 0.908 with 2nd stage models.</li>\n<li>I generated probabilities for 5 second chunks all of the train audios, and filtered if max prob of the segment matches with primary label of that audio.</li>\n<li>I also generated pseudo labels of the train segments.</li>\n<li>I trained 4 CNNs here with these segmented audio chunks, where I had 96 Batch Size of Train Audio Segments, and 5 Batch Size = (5 x 12) Batch Size of Train Soundscapes. </li>\n<li>These 4 CNNs are then further fine-tuned on just pseudo labels for 7 epochs. </li>\n</ul>\n<p><strong>Missed</strong></p>\n<ul>\n<li>My model's Public LB performance was impacted when I added No Call in the training on stage 1, I tried it in multiple ways but it didn't work, and now I saw in private LB that my single stage 1 model was able to achieve 0.885 with No Call, Adding that and fine-tuning that should improve the results I think. </li>\n</ul>\n<p><a href=\"https://www.kaggle.com/code/salmanahmedtamu/fork-of-fork-of-less-smoothing-ensemble-eff-and-nf?scriptVersionId=243764033\" target=\"_blank\">Inference Notebook</a><br>\n<a href=\"https://www.kaggle.com/code/salmanahmedtamu/20th-place-training/\" target=\"_blank\">Training Notebook</a></p>",
  "messages": [
    {
      "id": 3218243,
      "postDate": "2025-06-06T02:40:56.840Z",
      "content": "<p>Thanks everyone for the interesting competition, and congratulations to the winners ! I am happy that as a community we were able to detect these species to that much accurate. </p>\n<p><strong>Overview</strong><br>\nMy solution is a simple 2 stage solution. </p>\n<p><strong>First Stage Models</strong></p>\n<ul>\n<li>I was able to get LB 0.865 to 0.872 with the following settings. I had 3 CNNs and 1 SED trained and ensemble achieved LB 0.886.</li>\n<li>In this stage, I filtered human sounds as everyone else in the training data but randomly augmented a CSA recording with 30% of human sound with 50% probability. </li>\n<li>Another important / thing for me was to use the following settings. <br>\n<code>{'sample_rate': 32000, 'n_mels': 384, 'f_min': 0, 'f_max': 16000, 'n_fft': 3072, 'normalized': True, 'hop_length': 420}</code><br>\n<code>{'sample_rate': 32000, 'n_mels': 448, 'f_min': 50, 'f_max': 16000, 'n_fft': 4096, 'normalized': True, 'hop_length': 334}</code></li>\n<li>After apply AmplitudeToDB, I had to clip the values b/w 0 to -80. </li>\n<li>During training, I pick 15 seconds of audio chunk from complete audio file by RMS sampling, and then divide it into 3 x 5 seconds segments. Model predicts logits on 3 x 5 seconds of recordings, 3 x 206 and then I pick the max of these 3 recordings and then back propagate on those max logits of these 3 segments.</li>\n</ul>\n<pre><code>BS, K, C, H, W = spec.size()\nspec = spec.view(BS * K, C, H, W)\nlogits = model(spec)\nlogits = logits.view(BS, K, )\nlogits, _ = torch.(logits, dim=)\n</code></pre>\n<ul>\n<li>RMS sampling worked much better than random sampling for me.</li>\n<li>Loss: FocalBCE</li>\n<li>Augmentation: Mixup (p=1), LocalGlobal Stretch, Time / Frequency Shift, Time / Frequency Masking, Gaussian Noise. [All on spectrograms]</li>\n<li>Batch Size of 32.</li>\n<li>Model Soup from 12 to 15 epochs.</li>\n</ul>\n<p><strong>Second Stage Models</strong></p>\n<ul>\n<li>I was able to get Public LB 0.909 / Private LB 0.908 with 2nd stage models.</li>\n<li>I generated probabilities for 5 second chunks all of the train audios, and filtered if max prob of the segment matches with primary label of that audio.</li>\n<li>I also generated pseudo labels of the train segments.</li>\n<li>I trained 4 CNNs here with these segmented audio chunks, where I had 96 Batch Size of Train Audio Segments, and 5 Batch Size = (5 x 12) Batch Size of Train Soundscapes. </li>\n<li>These 4 CNNs are then further fine-tuned on just pseudo labels for 7 epochs. </li>\n</ul>\n<p><strong>Missed</strong></p>\n<ul>\n<li>My model's Public LB performance was impacted when I added No Call in the training on stage 1, I tried it in multiple ways but it didn't work, and now I saw in private LB that my single stage 1 model was able to achieve 0.885 with No Call, Adding that and fine-tuning that should improve the results I think. </li>\n</ul>\n<p><a href=\"https://www.kaggle.com/code/salmanahmedtamu/fork-of-fork-of-less-smoothing-ensemble-eff-and-nf?scriptVersionId=243764033\" target=\"_blank\">Inference Notebook</a><br>\n<a href=\"https://www.kaggle.com/code/salmanahmedtamu/20th-place-training/\" target=\"_blank\">Training Notebook</a></p>",
      "rawMarkdown": "Thanks everyone for the interesting competition, and congratulations to the winners ! I am happy that as a community we were able to detect these species to that much accurate. \n\n**Overview**\nMy solution is a simple 2 stage solution. \n\n**First Stage Models**\n- I was able to get LB 0.865 to 0.872 with the following settings. I had 3 CNNs and 1 SED trained and ensemble achieved LB 0.886.\n- In this stage, I filtered human sounds as everyone else in the training data but randomly augmented a CSA recording with 30% of human sound with 50% probability. \n- Another important / thing for me was to use the following settings. \n`{'sample_rate': 32000, 'n_mels': 384, 'f_min': 0, 'f_max': 16000, 'n_fft': 3072, 'normalized': True, 'hop_length': 420}`\n`{'sample_rate': 32000, 'n_mels': 448, 'f_min': 50, 'f_max': 16000, 'n_fft': 4096, 'normalized': True, 'hop_length': 334}`\n- After apply AmplitudeToDB, I had to clip the values b/w 0 to -80. \n- During training, I pick 15 seconds of audio chunk from complete audio file by RMS sampling, and then divide it into 3 x 5 seconds segments. Model predicts logits on 3 x 5 seconds of recordings, 3 x 206 and then I pick the max of these 3 recordings and then back propagate on those max logits of these 3 segments.\n\n```python\nBS, K, C, H, W = spec.size()\nspec = spec.view(BS * K, C, H, W)\nlogits = model(spec)\nlogits = logits.view(BS, K, 206)\nlogits, _ = torch.max(logits, dim=1)\n```\n\n- RMS sampling worked much better than random sampling for me.\n- Loss: FocalBCE\n- Augmentation: Mixup (p=1), LocalGlobal Stretch, Time / Frequency Shift, Time / Frequency Masking, Gaussian Noise. [All on spectrograms]\n- Batch Size of 32.\n- Model Soup from 12 to 15 epochs.\n\n\n**Second Stage Models**\n- I was able to get Public LB 0.909 / Private LB 0.908 with 2nd stage models.\n- I generated probabilities for 5 second chunks all of the train audios, and filtered if max prob of the segment matches with primary label of that audio.\n- I also generated pseudo labels of the train segments.\n- I trained 4 CNNs here with these segmented audio chunks, where I had 96 Batch Size of Train Audio Segments, and 5 Batch Size = (5 x 12) Batch Size of Train Soundscapes. \n- These 4 CNNs are then further fine-tuned on just pseudo labels for 7 epochs. \n\n\n**Missed**\n- My model's Public LB performance was impacted when I added No Call in the training on stage 1, I tried it in multiple ways but it didn't work, and now I saw in private LB that my single stage 1 model was able to achieve 0.885 with No Call, Adding that and fine-tuning that should improve the results I think. \n\n[Inference Notebook](https://www.kaggle.com/code/salmanahmedtamu/fork-of-fork-of-less-smoothing-ensemble-eff-and-nf?scriptVersionId=243764033)\n[Training Notebook](https://www.kaggle.com/code/salmanahmedtamu/20th-place-training/)\n\n",
      "votes": 26
    },
    {
      "id": 3229220,
      "postDate": "2025-06-21T07:10:12.727Z",
      "content": "<p>Here are the util functions missing from the notebooks.</p>\n<p><strong>Metric Meter</strong></p>\n<pre><code> numpy  np\n sklearn  metrics\n\n ():\n    y_true = np.delete(y_true, index, axis=)\n    y_pred = np.delete(y_pred, index, axis=)\n     metrics.roc_auc_score(y_true, y_pred)\n\n ():\n     roc_auc_score_ignore_index(np.array(y_true), np.array(y_pred), indices_ignore)\n\n ():\n    \n\n     ():\n        .reset()\n\n     ():\n        .val = \n        .avg = \n        . = \n        .count = \n\n     ():\n        .val = val\n        . += val * n\n        .count += n\n        .avg = . / .count\n\n\n ():\n     ():\n        .reset()\n        .indices_ignore = indices_ignore\n\n     ():\n        .y_true = []\n        .y_pred = []\n        .y_true_scored = []\n        .y_pred_scored = []\n\n     ():\n        y_true = y_true.cpu().detach().numpy()\n        y_pred = y_pred.cpu().detach().numpy()\n        .y_true.extend(y_true.tolist())\n        .y_pred.extend(y_pred.tolist())\n\n\n     ():\n        .score = calc_score(np.array(.y_true), np.array(.y_pred), .indices_ignore)\n\n         .score\n</code></pre>\n<p><strong>Upsample and Downsample Data</strong></p>\n<pre><code> os\n random\n numpy  np\n pandas  pd\n torch\n\n ()-&gt;pd.DataFrame:\n    \n    counts = df.primary_label.value_counts()\n\n    \n    cond = df.primary_label.isin(counts[counts&lt;thr].index.tolist())\n\n    \n    df[] = \n\n    \n    df.loc[cond, ] = \n\n    \n     df\n\n ()-&gt;pd.DataFrame:\n    \n    class_dist = df[].value_counts()\n\n    \n    down_classes = class_dist[class_dist &lt; thr].index.tolist()\n\n    \n    up_dfs = []\n\n    \n     c  down_classes:\n        \n        class_df = df.query()\n        \n        num_up = thr - class_df.shape[]\n        \n        class_df = class_df.sample(n=num_up, replace=, random_state=seed)\n        \n        up_dfs.append(class_df)\n\n    \n    up_df = pd.concat([df] + up_dfs, axis=, ignore_index=)\n\n     up_df\n\n ()-&gt;pd.DataFrame:\n    \n    class_dist = df[].value_counts()\n\n    \n    up_classes = class_dist[class_dist &gt; thr].index.tolist()\n\n    \n    down_dfs = []\n\n    \n     c  up_classes:\n        \n        class_df = df.query()\n        \n        df = df.query()\n        \n        class_df = class_df.sample(n=thr, replace=, random_state=seed)\n        \n        down_dfs.append(class_df)\n\n    \n    down_df = pd.concat([df] + down_dfs, axis=, ignore_index=)\n\n     down_df\n</code></pre>",
      "rawMarkdown": "Here are the util functions missing from the notebooks.\n\n**Metric Meter**\n\n```python\nimport numpy as np\nfrom sklearn import metrics\n\ndef roc_auc_score_ignore_index(y_true, y_pred, index):\n    y_true = np.delete(y_true, index, axis=1)\n    y_pred = np.delete(y_pred, index, axis=1)\n    return metrics.roc_auc_score(y_true, y_pred)\n\ndef calc_score(y_true, y_pred, indices_ignore):\n    return roc_auc_score_ignore_index(np.array(y_true), np.array(y_pred), indices_ignore)\n\nclass AverageMeter(object):\n    \"\"\"Computes and stores the average and current value\"\"\"\n\n    def __init__(self):\n        self.reset()\n\n    def reset(self):\n        self.val = 0\n        self.avg = 0\n        self.sum = 0\n        self.count = 0\n\n    def update(self, val, n=1):\n        self.val = val\n        self.sum += val * n\n        self.count += n\n        self.avg = self.sum / self.count\n\n\nclass MetricMeter(object):\n    def __init__(self, indices_ignore):\n        self.reset()\n        self.indices_ignore = indices_ignore\n\n    def reset(self):\n        self.y_true = []\n        self.y_pred = []\n        self.y_true_scored = []\n        self.y_pred_scored = []\n\n    def update(self, y_true, y_pred):\n        y_true = y_true.cpu().detach().numpy()\n        y_pred = y_pred.cpu().detach().numpy()\n        self.y_true.extend(y_true.tolist())\n        self.y_pred.extend(y_pred.tolist())\n\n    @property\n    def avg(self):\n        self.score = calc_score(np.array(self.y_true), np.array(self.y_pred), self.indices_ignore)\n\n        return self.score\n```\n\n**Upsample and Downsample Data**\n\n```python\nimport os\nimport random\nimport numpy as np\nimport pandas as pd\nimport torch\n\ndef filter_data(df: pd.DataFrame,\n                thr: int=5\n                )->pd.DataFrame:\n    # Count the number of samples for each class\n    counts = df.primary_label.value_counts()\n\n    # Condition that selects classes with less than `thr` samples\n    cond = df.primary_label.isin(counts[counts<thr].index.tolist())\n\n    # Add a new column to select samples for cross validation\n    df['cv'] = True\n\n    # Set cv = False for those class where there is samples less than thr\n    df.loc[cond, 'cv'] = False\n\n    # Return the filtered dataframe\n    return df\n\ndef upsample_data(df: pd.DataFrame,\n                  thr: int=20,\n                  seed: int=0\n                  )->pd.DataFrame:\n    # get the class distribution\n    class_dist = df['primary_label'].value_counts()\n\n    # identify the classes that have less than the threshold number of samples\n    down_classes = class_dist[class_dist < thr].index.tolist()\n\n    # create an empty list to store the upsampled dataframes\n    up_dfs = []\n\n    # loop through the undersampled classes and upsample them\n    for c in down_classes:\n        # get the dataframe for the current class\n        class_df = df.query(\"primary_label==@c\")\n        # find number of samples to add\n        num_up = thr - class_df.shape[0]\n        # upsample the dataframe\n        class_df = class_df.sample(n=num_up, replace=True, random_state=seed)\n        # append the upsampled dataframe to the list\n        up_dfs.append(class_df)\n\n    # concatenate the upsampled dataframes and the original dataframe\n    up_df = pd.concat([df] + up_dfs, axis=0, ignore_index=True)\n\n    return up_df\n\ndef downsample_data(df: pd.DataFrame,\n                    thr: int=500,\n                    seed: int=0\n                    )->pd.DataFrame:\n    # get the class distribution\n    class_dist = df['primary_label'].value_counts()\n\n    # identify the classes that have less than the threshold number of samples\n    up_classes = class_dist[class_dist > thr].index.tolist()\n\n    # create an empty list to store the upsampled dataframes\n    down_dfs = []\n\n    # loop through the undersampled classes and upsample them\n    for c in up_classes:\n        # get the dataframe for the current class\n        class_df = df.query(\"primary_label==@c\")\n        # Remove that class data\n        df = df.query(\"primary_label!=@c\")\n        # upsample the dataframe\n        class_df = class_df.sample(n=thr, replace=False, random_state=seed)\n        # append the upsampled dataframe to the list\n        down_dfs.append(class_df)\n\n    # concatenate the upsampled dataframes and the original dataframe\n    down_df = pd.concat([df] + down_dfs, axis=0, ignore_index=True)\n\n    return down_df\n```"
    },
    {
      "id": 3229106,
      "postDate": "2025-06-21T02:47:41.263Z",
      "content": "<p>Great work ! Can you please provide the functions(upsample_data、MetricMeter). Thank you!</p>",
      "rawMarkdown": "Great work ! Can you please provide the functions(upsample_data、MetricMeter). Thank you!",
      "replies": [
        {
          "id": 3229221,
          "postDate": "2025-06-21T07:10:28.190Z",
          "content": "<p>Just posted it as a comment. </p>",
          "rawMarkdown": "Just posted it as a comment. "
        },
        {
          "id": 3229222,
          "postDate": "2025-06-21T07:10:49.717Z",
          "content": "<p><a href=\"https://www.kaggle.com/competitions/birdclef-2025/discussion/583306#3229220\" target=\"_blank\">https://www.kaggle.com/competitions/birdclef-2025/discussion/583306#3229220</a></p>",
          "rawMarkdown": "https://www.kaggle.com/competitions/birdclef-2025/discussion/583306#3229220",
          "replies": [
            {
              "id": 3230061,
              "postDate": "2025-06-22T13:14:25.977Z",
              "content": "<p>Thank you for open-sourcing your solution! (Please excuse any awkward phrasing—English isn’t my native language.) I really want to express how much this means to beginners like me.</p>\n<p>During the competition, I built upon your previous year’s code, but despite countless experiments, my single-model score stubbornly stuck at 0.83. It was incredibly frustrating—I suspect it’s because I haven’t yet developed a systematic approach to experimentation. Maybe my feature engineering was off, or perhaps my training strategy lacked refinement. Seeing your solution now gives me a chance to compare and learn where I went wrong.</p>\n<p>Your willingness to share not only helps individuals like me but also elevates the entire community. I’m deeply grateful for your contribution and hope to apply these insights in future competitions.</p>",
              "rawMarkdown": "Thank you for open-sourcing your solution! (Please excuse any awkward phrasing—English isn’t my native language.) I really want to express how much this means to beginners like me.\n\nDuring the competition, I built upon your previous year’s code, but despite countless experiments, my single-model score stubbornly stuck at 0.83. It was incredibly frustrating—I suspect it’s because I haven’t yet developed a systematic approach to experimentation. Maybe my feature engineering was off, or perhaps my training strategy lacked refinement. Seeing your solution now gives me a chance to compare and learn where I went wrong.\n\nYour willingness to share not only helps individuals like me but also elevates the entire community. I’m deeply grateful for your contribution and hope to apply these insights in future competitions."
            }
          ]
        }
      ]
    },
    {
      "id": 3219743,
      "postDate": "2025-06-08T09:07:29.917Z",
      "content": "<p>Congrats! and I truly appreciate your open-source contributions and the insightful discussions you've shared.</p>",
      "rawMarkdown": "Congrats! and I truly appreciate your open-source contributions and the insightful discussions you've shared.\n"
    },
    {
      "id": 3218798,
      "postDate": "2025-06-06T17:56:07.700Z",
      "content": "<p>Thanks for writing this up. Would you be able to share your training code? For much of this competition I tried following your suggestions to reproduce your baseline 0.872 result without any luck.</p>",
      "rawMarkdown": "Thanks for writing this up. Would you be able to share your training code? For much of this competition I tried following your suggestions to reproduce your baseline 0.872 result without any luck.",
      "replies": [
        {
          "id": 3220361,
          "postDate": "2025-06-09T07:46:23.007Z",
          "content": "<p>Sure, I'm cleaning up the notebook, will share today.</p>",
          "rawMarkdown": "Sure, I'm cleaning up the notebook, will share today."
        }
      ]
    },
    {
      "id": 3218383,
      "postDate": "2025-06-06T05:54:58.177Z",
      "content": "<p>Thanks for sharing throughout this competition I learnt so much from your discussions !</p>",
      "rawMarkdown": "Thanks for sharing throughout this competition I learnt so much from your discussions !"
    },
    {
      "id": 3218260,
      "postDate": "2025-06-06T03:14:09.910Z",
      "content": "<p>Good work on CNN!  your  CNN outperformed  my CNN a lot。 And thank you for your sharing </p>",
      "rawMarkdown": "Good work on CNN!  your  CNN outperformed  my CNN a lot。 And thank you for your sharing "
    },
    {
      "id": 3218532,
      "postDate": "2025-06-06T10:12:23.413Z",
      "content": "<p><a href=\"https://www.kaggle.com/salmanahmedtamu\" target=\"_blank\">@salmanahmedtamu</a> Hi am rooting for you to win because of you I learn so much related to audio data. Hope in some days you will share your github, Thanks again mate</p>",
      "rawMarkdown": "@salmanahmedtamu Hi am rooting for you to win because of you I learn so much related to audio data. Hope in some days you will share your github, Thanks again mate",
      "isDeleted": true,
      "replies": [
        {
          "id": 3220360,
          "postDate": "2025-06-09T07:45:49.817Z",
          "content": "<p>Sure, I'll make my training notebooks public today.</p>",
          "rawMarkdown": "Sure, I'll make my training notebooks public today.",
          "replies": [
            {
              "id": 3222430,
              "postDate": "2025-06-12T07:39:01.987Z",
              "content": "<p>Keep looking for it！</p>",
              "rawMarkdown": "Keep looking for it！"
            },
            {
              "id": 3223043,
              "postDate": "2025-06-12T19:15:38.880Z",
              "content": "<p>Here it is: <a href=\"https://www.kaggle.com/code/salmanahmedtamu/20th-place-training/\" target=\"_blank\">https://www.kaggle.com/code/salmanahmedtamu/20th-place-training/</a></p>",
              "rawMarkdown": "Here it is: [https://www.kaggle.com/code/salmanahmedtamu/20th-place-training/](https://www.kaggle.com/code/salmanahmedtamu/20th-place-training/)"
            },
            {
              "id": 3223240,
              "postDate": "2025-06-13T04:01:32.727Z",
              "content": "<p>Thank you so much. As a beginner, I have learned a lot from you.</p>",
              "rawMarkdown": "Thank you so much. As a beginner, I have learned a lot from you."
            },
            {
              "id": 3226951,
              "postDate": "2025-06-18T09:42:03.543Z",
              "content": "<p>Dear Salman, I hope to use the MetricMeter, downsample_data, and upsample_data functions from the utils in the notebook you trained. How can I find them? Thank you very much.</p>",
              "rawMarkdown": "Dear Salman, I hope to use the MetricMeter, downsample_data, and upsample_data functions from the utils in the notebook you trained. How can I find them? Thank you very much."
            },
            {
              "id": 3229223,
              "postDate": "2025-06-21T07:11:01.200Z",
              "content": "<p>Here it is: <a href=\"https://www.kaggle.com/competitions/birdclef-2025/discussion/583306#3229220\" target=\"_blank\">https://www.kaggle.com/competitions/birdclef-2025/discussion/583306#3229220</a></p>",
              "rawMarkdown": "Here it is: https://www.kaggle.com/competitions/birdclef-2025/discussion/583306#3229220"
            },
            {
              "id": 3229242,
              "postDate": "2025-06-21T07:45:30.993Z",
              "content": "<p>Extend to you the highest respect.</p>",
              "rawMarkdown": "Extend to you the highest respect."
            }
          ]
        }
      ]
    },
    {
      "id": 3222712,
      "postDate": "2025-06-12T12:27:32.417Z",
      "content": "<p>great work</p>",
      "rawMarkdown": "great work"
    },
    {
      "id": 3218990,
      "postDate": "2025-06-07T03:16:35.603Z",
      "content": "<p>Thank you for sharing!</p>",
      "rawMarkdown": "Thank you for sharing!"
    }
  ],
  "comments": [
    {
      "id": 3229220,
      "author_name": "Salman Ahmed",
      "author_url": "",
      "post_date": "2025-06-21T07:10:12.727000",
      "content": "<p>Here are the util functions missing from the notebooks.</p>\n<p><strong>Metric Meter</strong></p>\n<pre><code> numpy  np\n sklearn  metrics\n\n ():\n    y_true = np.delete(y_true, index, axis=)\n    y_pred = np.delete(y_pred, index, axis=)\n     metrics.roc_auc_score(y_true, y_pred)\n\n ():\n     roc_auc_score_ignore_index(np.array(y_true), np.array(y_pred), indices_ignore)\n\n ():\n    \n\n     ():\n        .reset()\n\n     ():\n        .val = \n        .avg = \n        . = \n        .count = \n\n     ():\n        .val = val\n        . += val * n\n        .count += n\n        .avg = . / .count\n\n\n ():\n     ():\n        .reset()\n        .indices_ignore = indices_ignore\n\n     ():\n        .y_true = []\n        .y_pred = []\n        .y_true_scored = []\n        .y_pred_scored = []\n\n     ():\n        y_true = y_true.cpu().detach().numpy()\n        y_pred = y_pred.cpu().detach().numpy()\n        .y_true.extend(y_true.tolist())\n        .y_pred.extend(y_pred.tolist())\n\n\n     ():\n        .score = calc_score(np.array(.y_true), np.array(.y_pred), .indices_ignore)\n\n         .score\n</code></pre>\n<p><strong>Upsample and Downsample Data</strong></p>\n<pre><code> os\n random\n numpy  np\n pandas  pd\n torch\n\n ()-&gt;pd.DataFrame:\n    \n    counts = df.primary_label.value_counts()\n\n    \n    cond = df.primary_label.isin(counts[counts&lt;thr].index.tolist())\n\n    \n    df[] = \n\n    \n    df.loc[cond, ] = \n\n    \n     df\n\n ()-&gt;pd.DataFrame:\n    \n    class_dist = df[].value_counts()\n\n    \n    down_classes = class_dist[class_dist &lt; thr].index.tolist()\n\n    \n    up_dfs = []\n\n    \n     c  down_classes:\n        \n        class_df = df.query()\n        \n        num_up = thr - class_df.shape[]\n        \n        class_df = class_df.sample(n=num_up, replace=, random_state=seed)\n        \n        up_dfs.append(class_df)\n\n    \n    up_df = pd.concat([df] + up_dfs, axis=, ignore_index=)\n\n     up_df\n\n ()-&gt;pd.DataFrame:\n    \n    class_dist = df[].value_counts()\n\n    \n    up_classes = class_dist[class_dist &gt; thr].index.tolist()\n\n    \n    down_dfs = []\n\n    \n     c  up_classes:\n        \n        class_df = df.query()\n        \n        df = df.query()\n        \n        class_df = class_df.sample(n=thr, replace=, random_state=seed)\n        \n        down_dfs.append(class_df)\n\n    \n    down_df = pd.concat([df] + down_dfs, axis=, ignore_index=)\n\n     down_df\n</code></pre>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 3229106,
      "author_name": "shixingkong",
      "author_url": "",
      "post_date": "2025-06-21T02:47:41.263000",
      "content": "<p>Great work ! Can you please provide the functions(upsample_data、MetricMeter). Thank you!</p>",
      "votes": 0,
      "replies": [
        {
          "id": 3229221,
          "author_name": "Salman Ahmed",
          "author_url": "",
          "post_date": "2025-06-21T07:10:28.190000",
          "content": "<p>Just posted it as a comment. </p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 3229222,
          "author_name": "Salman Ahmed",
          "author_url": "",
          "post_date": "2025-06-21T07:10:49.717000",
          "content": "<p><a href=\"https://www.kaggle.com/competitions/birdclef-2025/discussion/583306#3229220\" target=\"_blank\">https://www.kaggle.com/competitions/birdclef-2025/discussion/583306#3229220</a></p>",
          "votes": 0,
          "replies": [
            {
              "id": 3230061,
              "author_name": "shixingkong",
              "author_url": "",
              "post_date": "2025-06-22T13:14:25.977000",
              "content": "<p>Thank you for open-sourcing your solution! (Please excuse any awkward phrasing—English isn’t my native language.) I really want to express how much this means to beginners like me.</p>\n<p>During the competition, I built upon your previous year’s code, but despite countless experiments, my single-model score stubbornly stuck at 0.83. It was incredibly frustrating—I suspect it’s because I haven’t yet developed a systematic approach to experimentation. Maybe my feature engineering was off, or perhaps my training strategy lacked refinement. Seeing your solution now gives me a chance to compare and learn where I went wrong.</p>\n<p>Your willingness to share not only helps individuals like me but also elevates the entire community. I’m deeply grateful for your contribution and hope to apply these insights in future competitions.</p>",
              "votes": 0,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 3219743,
      "author_name": "Zhongkai Shangguan",
      "author_url": "",
      "post_date": "2025-06-08T09:07:29.917000",
      "content": "<p>Congrats! and I truly appreciate your open-source contributions and the insightful discussions you've shared.</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 3218798,
      "author_name": "thacrobatheskis",
      "author_url": "",
      "post_date": "2025-06-06T17:56:07.700000",
      "content": "<p>Thanks for writing this up. Would you be able to share your training code? For much of this competition I tried following your suggestions to reproduce your baseline 0.872 result without any luck.</p>",
      "votes": 0,
      "replies": [
        {
          "id": 3220361,
          "author_name": "Salman Ahmed",
          "author_url": "",
          "post_date": "2025-06-09T07:46:23.007000",
          "content": "<p>Sure, I'm cleaning up the notebook, will share today.</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 3218383,
      "author_name": "Athar Sayed",
      "author_url": "",
      "post_date": "2025-06-06T05:54:58.177000",
      "content": "<p>Thanks for sharing throughout this competition I learnt so much from your discussions !</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 3218260,
      "author_name": "lhwcv",
      "author_url": "",
      "post_date": "2025-06-06T03:14:09.910000",
      "content": "<p>Good work on CNN!  your  CNN outperformed  my CNN a lot。 And thank you for your sharing </p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 3218532,
      "author_name": "",
      "author_url": "",
      "post_date": "2025-06-06T10:12:23.413000",
      "content": "<p><a href=\"https://www.kaggle.com/salmanahmedtamu\" target=\"_blank\">@salmanahmedtamu</a> Hi am rooting for you to win because of you I learn so much related to audio data. Hope in some days you will share your github, Thanks again mate</p>",
      "votes": 0,
      "replies": [
        {
          "id": 3220360,
          "author_name": "Salman Ahmed",
          "author_url": "",
          "post_date": "2025-06-09T07:45:49.817000",
          "content": "<p>Sure, I'll make my training notebooks public today.</p>",
          "votes": 0,
          "replies": [
            {
              "id": 3222430,
              "author_name": "Benzoquinone",
              "author_url": "",
              "post_date": "2025-06-12T07:39:01.987000",
              "content": "<p>Keep looking for it！</p>",
              "votes": 0,
              "replies": []
            },
            {
              "id": 3223043,
              "author_name": "Salman Ahmed",
              "author_url": "",
              "post_date": "2025-06-12T19:15:38.880000",
              "content": "<p>Here it is: <a href=\"https://www.kaggle.com/code/salmanahmedtamu/20th-place-training/\" target=\"_blank\">https://www.kaggle.com/code/salmanahmedtamu/20th-place-training/</a></p>",
              "votes": 0,
              "replies": []
            },
            {
              "id": 3223240,
              "author_name": "Benzoquinone",
              "author_url": "",
              "post_date": "2025-06-13T04:01:32.727000",
              "content": "<p>Thank you so much. As a beginner, I have learned a lot from you.</p>",
              "votes": 0,
              "replies": []
            },
            {
              "id": 3226951,
              "author_name": "Benzoquinone",
              "author_url": "",
              "post_date": "2025-06-18T09:42:03.543000",
              "content": "<p>Dear Salman, I hope to use the MetricMeter, downsample_data, and upsample_data functions from the utils in the notebook you trained. How can I find them? Thank you very much.</p>",
              "votes": 0,
              "replies": []
            },
            {
              "id": 3229223,
              "author_name": "Salman Ahmed",
              "author_url": "",
              "post_date": "2025-06-21T07:11:01.200000",
              "content": "<p>Here it is: <a href=\"https://www.kaggle.com/competitions/birdclef-2025/discussion/583306#3229220\" target=\"_blank\">https://www.kaggle.com/competitions/birdclef-2025/discussion/583306#3229220</a></p>",
              "votes": 0,
              "replies": []
            },
            {
              "id": 3229242,
              "author_name": "Benzoquinone",
              "author_url": "",
              "post_date": "2025-06-21T07:45:30.993000",
              "content": "<p>Extend to you the highest respect.</p>",
              "votes": 0,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 3222712,
      "author_name": "102203654_Aditya_Pratap_Singh",
      "author_url": "",
      "post_date": "2025-06-12T12:27:32.417000",
      "content": "<p>great work</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 3218990,
      "author_name": "Supakit Boon",
      "author_url": "",
      "post_date": "2025-06-07T03:16:35.603000",
      "content": "<p>Thank you for sharing!</p>",
      "votes": 0,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "3218243": "Thanks everyone for the interesting competition, and congratulations to the winners ! I am happy that as a community we were able to detect these species to that much accurate. \n\n**Overview**\nMy solution is a simple 2 stage solution. \n\n**First Stage Models**\n- I was able to get LB 0.865 to 0.872 with the following settings. I had 3 CNNs and 1 SED trained and ensemble achieved LB 0.886.\n- In this stage, I filtered human sounds as everyone else in the training data but randomly augmented a CSA recording with 30% of human sound with 50% probability. \n- Another important / thing for me was to use the following settings. \n`{'sample_rate': 32000, 'n_mels': 384, 'f_min': 0, 'f_max': 16000, 'n_fft': 3072, 'normalized': True, 'hop_length': 420}`\n`{'sample_rate': 32000, 'n_mels': 448, 'f_min': 50, 'f_max': 16000, 'n_fft': 4096, 'normalized': True, 'hop_length': 334}`\n- After apply AmplitudeToDB, I had to clip the values b/w 0 to -80. \n- During training, I pick 15 seconds of audio chunk from complete audio file by RMS sampling, and then divide it into 3 x 5 seconds segments. Model predicts logits on 3 x 5 seconds of recordings, 3 x 206 and then I pick the max of these 3 recordings and then back propagate on those max logits of these 3 segments.\n\n```python\nBS, K, C, H, W = spec.size()\nspec = spec.view(BS * K, C, H, W)\nlogits = model(spec)\nlogits = logits.view(BS, K, 206)\nlogits, _ = torch.max(logits, dim=1)\n```\n\n- RMS sampling worked much better than random sampling for me.\n- Loss: FocalBCE\n- Augmentation: Mixup (p=1), LocalGlobal Stretch, Time / Frequency Shift, Time / Frequency Masking, Gaussian Noise. [All on spectrograms]\n- Batch Size of 32.\n- Model Soup from 12 to 15 epochs.\n\n\n**Second Stage Models**\n- I was able to get Public LB 0.909 / Private LB 0.908 with 2nd stage models.\n- I generated probabilities for 5 second chunks all of the train audios, and filtered if max prob of the segment matches with primary label of that audio.\n- I also generated pseudo labels of the train segments.\n- I trained 4 CNNs here with these segmented audio chunks, where I had 96 Batch Size of Train Audio Segments, and 5 Batch Size = (5 x 12) Batch Size of Train Soundscapes. \n- These 4 CNNs are then further fine-tuned on just pseudo labels for 7 epochs. \n\n\n**Missed**\n- My model's Public LB performance was impacted when I added No Call in the training on stage 1, I tried it in multiple ways but it didn't work, and now I saw in private LB that my single stage 1 model was able to achieve 0.885 with No Call, Adding that and fine-tuning that should improve the results I think. \n\n[Inference Notebook](https://www.kaggle.com/code/salmanahmedtamu/fork-of-fork-of-less-smoothing-ensemble-eff-and-nf?scriptVersionId=243764033)\n[Training Notebook](https://www.kaggle.com/code/salmanahmedtamu/20th-place-training/)\n\n",
    "3229220": "Here are the util functions missing from the notebooks.\n\n**Metric Meter**\n\n```python\nimport numpy as np\nfrom sklearn import metrics\n\ndef roc_auc_score_ignore_index(y_true, y_pred, index):\n    y_true = np.delete(y_true, index, axis=1)\n    y_pred = np.delete(y_pred, index, axis=1)\n    return metrics.roc_auc_score(y_true, y_pred)\n\ndef calc_score(y_true, y_pred, indices_ignore):\n    return roc_auc_score_ignore_index(np.array(y_true), np.array(y_pred), indices_ignore)\n\nclass AverageMeter(object):\n    \"\"\"Computes and stores the average and current value\"\"\"\n\n    def __init__(self):\n        self.reset()\n\n    def reset(self):\n        self.val = 0\n        self.avg = 0\n        self.sum = 0\n        self.count = 0\n\n    def update(self, val, n=1):\n        self.val = val\n        self.sum += val * n\n        self.count += n\n        self.avg = self.sum / self.count\n\n\nclass MetricMeter(object):\n    def __init__(self, indices_ignore):\n        self.reset()\n        self.indices_ignore = indices_ignore\n\n    def reset(self):\n        self.y_true = []\n        self.y_pred = []\n        self.y_true_scored = []\n        self.y_pred_scored = []\n\n    def update(self, y_true, y_pred):\n        y_true = y_true.cpu().detach().numpy()\n        y_pred = y_pred.cpu().detach().numpy()\n        self.y_true.extend(y_true.tolist())\n        self.y_pred.extend(y_pred.tolist())\n\n    @property\n    def avg(self):\n        self.score = calc_score(np.array(self.y_true), np.array(self.y_pred), self.indices_ignore)\n\n        return self.score\n```\n\n**Upsample and Downsample Data**\n\n```python\nimport os\nimport random\nimport numpy as np\nimport pandas as pd\nimport torch\n\ndef filter_data(df: pd.DataFrame,\n                thr: int=5\n                )->pd.DataFrame:\n    # Count the number of samples for each class\n    counts = df.primary_label.value_counts()\n\n    # Condition that selects classes with less than `thr` samples\n    cond = df.primary_label.isin(counts[counts<thr].index.tolist())\n\n    # Add a new column to select samples for cross validation\n    df['cv'] = True\n\n    # Set cv = False for those class where there is samples less than thr\n    df.loc[cond, 'cv'] = False\n\n    # Return the filtered dataframe\n    return df\n\ndef upsample_data(df: pd.DataFrame,\n                  thr: int=20,\n                  seed: int=0\n                  )->pd.DataFrame:\n    # get the class distribution\n    class_dist = df['primary_label'].value_counts()\n\n    # identify the classes that have less than the threshold number of samples\n    down_classes = class_dist[class_dist < thr].index.tolist()\n\n    # create an empty list to store the upsampled dataframes\n    up_dfs = []\n\n    # loop through the undersampled classes and upsample them\n    for c in down_classes:\n        # get the dataframe for the current class\n        class_df = df.query(\"primary_label==@c\")\n        # find number of samples to add\n        num_up = thr - class_df.shape[0]\n        # upsample the dataframe\n        class_df = class_df.sample(n=num_up, replace=True, random_state=seed)\n        # append the upsampled dataframe to the list\n        up_dfs.append(class_df)\n\n    # concatenate the upsampled dataframes and the original dataframe\n    up_df = pd.concat([df] + up_dfs, axis=0, ignore_index=True)\n\n    return up_df\n\ndef downsample_data(df: pd.DataFrame,\n                    thr: int=500,\n                    seed: int=0\n                    )->pd.DataFrame:\n    # get the class distribution\n    class_dist = df['primary_label'].value_counts()\n\n    # identify the classes that have less than the threshold number of samples\n    up_classes = class_dist[class_dist > thr].index.tolist()\n\n    # create an empty list to store the upsampled dataframes\n    down_dfs = []\n\n    # loop through the undersampled classes and upsample them\n    for c in up_classes:\n        # get the dataframe for the current class\n        class_df = df.query(\"primary_label==@c\")\n        # Remove that class data\n        df = df.query(\"primary_label!=@c\")\n        # upsample the dataframe\n        class_df = class_df.sample(n=thr, replace=False, random_state=seed)\n        # append the upsampled dataframe to the list\n        down_dfs.append(class_df)\n\n    # concatenate the upsampled dataframes and the original dataframe\n    down_df = pd.concat([df] + down_dfs, axis=0, ignore_index=True)\n\n    return down_df\n```",
    "3229106": "Great work ! Can you please provide the functions(upsample_data、MetricMeter). Thank you!",
    "3219743": "Congrats! and I truly appreciate your open-source contributions and the insightful discussions you've shared.\n",
    "3218798": "Thanks for writing this up. Would you be able to share your training code? For much of this competition I tried following your suggestions to reproduce your baseline 0.872 result without any luck.",
    "3218383": "Thanks for sharing throughout this competition I learnt so much from your discussions !",
    "3218260": "Good work on CNN!  your  CNN outperformed  my CNN a lot。 And thank you for your sharing ",
    "3218532": "@salmanahmedtamu Hi am rooting for you to win because of you I learn so much related to audio data. Hope in some days you will share your github, Thanks again mate",
    "3222712": "great work",
    "3218990": "Thank you for sharing!"
  }
}