{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":91844,"databundleVersionId":11361821,"sourceType":"competition"},{"sourceId":11839243,"sourceType":"datasetVersion","datasetId":7438404},{"sourceId":11839829,"sourceType":"datasetVersion","datasetId":7438816},{"sourceId":11839917,"sourceType":"datasetVersion","datasetId":7438881},{"sourceId":397346,"sourceType":"modelInstanceVersion","modelInstanceId":325820,"modelId":346673},{"sourceId":397432,"sourceType":"modelInstanceVersion","modelInstanceId":325871,"modelId":346730},{"sourceId":397434,"sourceType":"modelInstanceVersion","modelInstanceId":325873,"modelId":346732},{"sourceId":397452,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":325884,"modelId":346747},{"sourceId":397459,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":325888,"modelId":346753},{"sourceId":401127,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":328226,"modelId":349077},{"sourceId":401180,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":328268,"modelId":349119},{"sourceId":401255,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":328324,"modelId":349174},{"sourceId":402832,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":329455,"modelId":350281},{"sourceId":402832,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":329455,"modelId":350281},{"sourceId":402951,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":329534,"modelId":350365},{"sourceId":407138,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":332666,"modelId":353595},{"sourceId":407241,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":332754,"modelId":353682}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"from torch import nn\nimport torch\nimport torchaudio\nimport librosa\n\nfrom torchvision import transforms\nfrom torchaudio.transforms import Resample\nimport datasets\nimport warnings\nimport pandas as pd\nimport json\nimport os\nimport glob\nfrom typing import Dict, Optional\nimport random\nimport numpy as np\nimport datasets\nimport torch\nfrom torch import nn\nfrom transformers import AutoConfig, ConvNextForImageClassification","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-19T09:01:58.027412Z","iopub.execute_input":"2025-05-19T09:01:58.028582Z","iopub.status.idle":"2025-05-19T09:02:40.716524Z","shell.execute_reply.started":"2025-05-19T09:01:58.028479Z","shell.execute_reply":"2025-05-19T09:02:40.715577Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Config","metadata":{}},{"cell_type":"code","source":"class Config:\n    train_dir = \"/kaggle/input/birdclef-2025/train_audio\"\n    seed = 42\n    train_csv = \"/kaggle/input/birdclef-2025/train.csv\"\n    train_soundscapes = \"/kaggle/input/birdclef-2025/train_soundscapes\"\n    test_soundscapes = \"/kaggle/input/birdclef-2025/test_soundscapes/\"\n    sample_submission_csv = \"/kaggle/input/birdclef-2025/sample_submission.csv\"\n    num_classes = 206\n    submission_mode = len(glob.glob(\"/kaggle/input/birdclef-2025/test_soundscapes/*.ogg\")) > 0\n\n\ncheckpoint_path = \"/kaggle/input/multi-label-epoch-1/pytorch/default/1/birdset_epoch1.pt\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T09:02:44.364286Z","iopub.execute_input":"2025-05-19T09:02:44.364950Z","iopub.status.idle":"2025-05-19T09:02:44.375389Z","shell.execute_reply.started":"2025-05-19T09:02:44.364920Z","shell.execute_reply":"2025-05-19T09:02:44.373926Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def set_seed(seed: int=42):\n    random.seed(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n\n    if torch.cuda.is_available():\n        torch.cuda.manual_seed(seed)\n        torch.cuda.manual_seed_all(seed)\n    torch.backends.cudnn.deterministic=True\n    torch.backends.cudnn.benchmark=False\n\n    print(f\"Setting seed : {seed}\")\nset_seed()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T09:02:46.193095Z","iopub.execute_input":"2025-05-19T09:02:46.193423Z","iopub.status.idle":"2025-05-19T09:02:46.208345Z","shell.execute_reply.started":"2025-05-19T09:02:46.193397Z","shell.execute_reply":"2025-05-19T09:02:46.206845Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Preprocessing","metadata":{}},{"cell_type":"code","source":"import os\nimport torch\nimport torchaudio\nfrom torchaudio.transforms import Resample\n\ndef preprocess_audio(audio_path, window_size=5, sample_rate=32000):\n    audio, sr = torchaudio.load(audio_path, normalize=True)\n    if sr != sample_rate:\n        audio = Resample(orig_freq=sr, new_freq=sample_rate)(audio)\n\n    window_size_samples = window_size * sample_rate\n    one_sec_samples = sample_rate\n\n    total_samples = audio.size(1)\n    num_segments = (total_samples) // window_size_samples  # ceil division\n\n    segments = {}\n    for i in range(num_segments):\n        start = i * window_size_samples\n        end = start + window_size_samples\n        segment = audio[:, start:end]\n\n        if segment.size(1) < window_size_samples:\n            # Get last 1 second\n            repeat_part = segment[:, -one_sec_samples:] if segment.size(1) >= one_sec_samples else segment\n            repeats_needed = (window_size_samples - segment.size(1) + one_sec_samples - 1) // one_sec_samples\n            repeated = repeat_part.repeat(1, repeats_needed)\n            segment = torch.cat([segment, repeated], dim=1)[:, :window_size_samples]  # Trim extra if needed\n\n        end_second = (i + 1) * window_size\n        filename_key = f\"{os.path.splitext(os.path.basename(audio_path))[0]}_{end_second}\"\n        segment =  segment.mean(dim=0, keepdim=True)\n        segments[filename_key] = segment.squeeze(-1)\n\n    return segments","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T09:10:14.839040Z","iopub.execute_input":"2025-05-19T09:10:14.839333Z","iopub.status.idle":"2025-05-19T09:10:14.852016Z","shell.execute_reply.started":"2025-05-19T09:10:14.839313Z","shell.execute_reply":"2025-05-19T09:10:14.850753Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Augmentations","metadata":{}},{"cell_type":"code","source":"class PowerToDB(nn.Module):\n    def __init__(self, ref=1.0, amin=1e-10, top_db=80.0):\n        super(PowerToDB, self).__init__()\n        # Initialize parameters\n        self.ref = ref\n        self.amin = amin\n        self.top_db = top_db\n\n    def forward(self, S):\n        # Convert S to a PyTorch tensor if it is not already\n        S = torch.as_tensor(S, dtype=torch.float32)\n\n        if self.amin <= 0:\n            raise ValueError(\"amin must be strictly positive\")\n\n        if torch.is_complex(S):\n            warnings.warn(\n                \"power_to_db was called on complex input so phase \"\n                \"information will be discarded. To suppress this warning, \"\n                \"call power_to_db(S.abs()**2) instead.\",\n                stacklevel=2,\n            )\n            magnitude = S.abs()\n        else:\n            magnitude = S\n\n        # Check if ref is a callable function or a scalar\n        if callable(self.ref):\n            ref_value = self.ref(magnitude)\n        else:\n            ref_value = torch.abs(torch.tensor(self.ref, dtype=S.dtype))\n\n        # Compute the log spectrogram\n        log_spec = 10.0 * torch.log10(\n            torch.maximum(magnitude, torch.tensor(self.amin, device=magnitude.device))\n        )\n        log_spec -= 10.0 * torch.log10(\n            torch.maximum(ref_value, torch.tensor(self.amin, device=magnitude.device))\n        )\n\n        # Apply top_db threshold if necessary\n        if self.top_db is not None:\n            if self.top_db < 0:\n                raise ValueError(\"top_db must be non-negative\")\n            log_spec = torch.maximum(log_spec, log_spec.max() - self.top_db)\n\n        return log_spec","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-17T07:14:49.780636Z","iopub.execute_input":"2025-05-17T07:14:49.781034Z","iopub.status.idle":"2025-05-17T07:14:49.788249Z","shell.execute_reply.started":"2025-05-17T07:14:49.780992Z","shell.execute_reply":"2025-05-17T07:14:49.787278Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### ConvNextClassifier","metadata":{}},{"cell_type":"code","source":"class ConvNextClassifier(nn.Module):\n    \"\"\"\n    ConvNext model for audio classification.\n    \"\"\"\n\n    def __init__(\n        self,\n        num_channels: int = 1,\n        num_classes: Optional[int] = None,\n        checkpoint: Optional[str] = None,\n        local_checkpoint: Optional[str] = None,\n        cache_dir: Optional[str] = None,\n        pretrain_info= None #PretrainInfoConfig = None,\n    ):\n        \"\"\"\n        Note: Either num_classes or pretrain_info must be given\n        Args:\n            num_channels: Number of input channels.\n            checkpoint: huggingface checkpoint path of any model of correct type\n            num_classes: number of classification heads to be used in the model\n            local_checkpoint: local path to checkpoint file\n            cache_dir: specified cache dir to save model files at\n            pretrain_info: hf_path and hf_name of info will be used to infer if num_classes is None\n        \"\"\"\n        super().__init__()\n\n        if pretrain_info:\n            self.hf_path = pretrain_info.hf_path\n            self.hf_name = (\n                pretrain_info.hf_name\n                if not pretrain_info.hf_pretrain_name\n                else pretrain_info.hf_pretrain_name\n            )\n            self.num_classes = len(\n                datasets.load_dataset_builder(self.hf_path, self.hf_name)\n                .info.features[\"ebird_code\"]\n                .names\n            )\n        else:\n            self.hf_path = None\n            self.hf_name = None\n            self.num_classes = num_classes\n\n        self.num_channels = num_channels\n        self.checkpoint = checkpoint\n        self.local_checkpoint = local_checkpoint\n        self.cache_dir = cache_dir\n\n        self.model = None\n\n        self._initialize_model()\n\n    def _initialize_model(self):\n        \"\"\"Initializes the ConvNext model based on specified attributes.\"\"\"\n\n        adjusted_state_dict = None\n\n        if self.checkpoint:\n            if self.local_checkpoint:\n                state_dict = torch.load(self.local_checkpoint)[\"state_dict\"]\n\n                # Update this part to handle the necessary key replacements\n                adjusted_state_dict = {}\n                for key, value in state_dict.items():\n                    # Handle 'model.model.' prefix\n                    new_key = key.replace(\"model.model.\", \"\")\n\n                    # Handle 'model._orig_mod.model.' prefix\n                    new_key = new_key.replace(\"model._orig_mod.model.\", \"\")\n\n                    # Assign the adjusted key\n                    adjusted_state_dict[new_key] = value\n\n            self.model = ConvNextForImageClassification.from_pretrained(\n                self.checkpoint,\n                num_labels=self.num_classes,\n                num_channels=self.num_channels,\n                cache_dir=self.cache_dir,\n                state_dict=adjusted_state_dict,\n                ignore_mismatched_sizes=True,\n            )\n        else:\n            config = AutoConfig.from_pretrained(\n                \"/kaggle/input/fb/pytorch/default/1/convnext-base-224-22k\",\n                num_labels=self.num_classes,\n                num_channels=self.num_channels,\n            )\n            self.model = ConvNextForImageClassification(config)\n\n    def forward(\n        self, input_values: torch.Tensor, labels: Optional[torch.Tensor] = None\n    ) -> torch.Tensor:\n        \"\"\"\n        Defines the forward pass of the ConvNext model.\n\n        Args:\n            input_values (torch.Tensor): An input batch.\n            labels (Optional[torch.Tensor]): The corresponding labels. Default is None.\n\n        Returns:\n            torch.Tensor: The output of the ConvNext model.\n        \"\"\"\n        output = self.model(input_values)\n        logits = output.logits\n\n        return logits\n\n    @torch.inference_mode()\n    def get_logits(self, dataloader, device):\n        pass\n\n    @torch.inference_mode()\n    def get_probas(self, dataloader, device):\n        pass\n\n    @torch.inference_mode()\n    def get_representations(self, dataloader, device):\n        pass","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-17T07:14:50.263858Z","iopub.execute_input":"2025-05-17T07:14:50.264120Z","iopub.status.idle":"2025-05-17T07:14:50.273652Z","shell.execute_reply.started":"2025-05-17T07:14:50.264101Z","shell.execute_reply":"2025-05-17T07:14:50.272783Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class ConvNextBirdSet(nn.Module):\n    \"\"\"\n    BirdSet ConvNext model trained on BirdSet XCL dataset.\n    The model expects a raw 1 channel 5s waveform with sample rate of 32kHz as an input.\n    Its preprocess function will:\n        - convert the waveform to a spectrogram: n_fft: 1024, hop_length: 320, power: 2.0\n        - melscale the spectrogram: n_mels: 128, n_stft: 513\n        - dbscale with top_db: 80\n        - normalize the spectrogram mean: -4.268, std: 4.569 (from esc-50)\n    \"\"\"\n\n    def __init__(\n        self,\n        PowerToDB,\n        num_classes=9736,\n    ):\n        super().__init__()\n        self.model = ConvNextClassifier(\n            checkpoint=\"/kaggle/input/convnext-xcl-transformers-model\",\n            num_classes=num_classes,\n        )\n        self.spectrogram_converter = torchaudio.transforms.Spectrogram(\n            n_fft=1024, hop_length=320, power=2.0\n        )\n        self.mel_converter = torchaudio.transforms.MelScale(\n            n_mels=128, n_stft=513, sample_rate=32_000\n        )\n        self.normalizer = transforms.Normalize((-4.268,), (4.569,))\n        self.powerToDB = PowerToDB(top_db=80)\n        self.config = self.model.model.config\n\n    def preprocess(self, waveform: torch.Tensor):\n        # convert waveform to spectrogram\n        spectrogram = self.spectrogram_converter(waveform)\n        spectrogram = spectrogram.to(torch.float32)\n        melspec = self.mel_converter(spectrogram)\n        dbscale = self.powerToDB(melspec)\n        normalized_dbscale = self.normalizer(dbscale)\n        # add dimension 3 from left\n        normalized_dbscale = normalized_dbscale.unsqueeze(-3)\n\n        return normalized_dbscale\n\n    def forward(self, input: torch.Tensor):\n        # spectrogram = self.preprocess(waveform)\n        return self.model(input)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-17T07:14:50.301255Z","iopub.execute_input":"2025-05-17T07:14:50.301509Z","iopub.status.idle":"2025-05-17T07:14:50.307697Z","shell.execute_reply.started":"2025-05-17T07:14:50.301492Z","shell.execute_reply":"2025-05-17T07:14:50.306880Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Inference","metadata":{}},{"cell_type":"code","source":"audio_dir = glob.glob(Config.test_soundscapes + \"/*.ogg\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-17T07:15:02.793891Z","iopub.execute_input":"2025-05-17T07:15:02.794141Z","iopub.status.idle":"2025-05-17T07:15:02.798966Z","shell.execute_reply.started":"2025-05-17T07:15:02.794126Z","shell.execute_reply":"2025-05-17T07:15:02.798090Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class BirdsetModule(torch.nn.Module):\n    def __init__(self,PowerToDB,num_classes=206):\n        super().__init__()\n        self.model = ConvNextBirdSet(PowerToDB, num_classes=num_classes)\n\n    def forward(self, x):\n        preprocessed = self.model.preprocess(x)\n        return self.model(preprocessed)\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = BirdsetModule(PowerToDB, num_classes=206).to(device)\nmodel.load_state_dict(torch.load(checkpoint_path, map_location=device))\nmodel.eval()\nmodel.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-17T07:15:03.127115Z","iopub.execute_input":"2025-05-17T07:15:03.128273Z","iopub.status.idle":"2025-05-17T07:15:09.087607Z","shell.execute_reply.started":"2025-05-17T07:15:03.128237Z","shell.execute_reply":"2025-05-17T07:15:09.086798Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#test_dir = \"/kaggle/input/birdclef-2025/test_soundscapes\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-17T07:15:09.088970Z","iopub.execute_input":"2025-05-17T07:15:09.089216Z","iopub.status.idle":"2025-05-17T07:15:09.092861Z","shell.execute_reply.started":"2025-05-17T07:15:09.089194Z","shell.execute_reply":"2025-05-17T07:15:09.091939Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def inference(model, audio_tensor, device):\n    model.eval()\n    with torch.no_grad():\n        audio_tensor = audio_tensor.to(device)\n        logits = model(audio_tensor)  # add batch dim\n        probs = torch.softmax(logits, dim=1)\n        #top_probs, top_indices = torch.topk(probs, k=top_k)\n        return probs.squeeze(0).tolist() #top_indices.squeeze(0).tolist(), top_probs.squeeze(0).tolist()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-17T07:15:09.093632Z","iopub.execute_input":"2025-05-17T07:15:09.093870Z","iopub.status.idle":"2025-05-17T07:15:09.106763Z","shell.execute_reply.started":"2025-05-17T07:15:09.093850Z","shell.execute_reply":"2025-05-17T07:15:09.106025Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with open(\"/kaggle/input/map-class-idx/map.txt\",\"r\") as file:\n    content = file.read()\nprint(\"Taking \",audio_dir)\nmap_text = json.loads(content)\nprobabilities=[]\nrows = []\nfor index, audio_path in enumerate(audio_dir):\n    #extension = os.path.splitext(os.path.basename(file_path))[1]  # returns '.safetensors'\n    \n    #if extension !=\".txt\":\n    audio_tensor_dict = preprocess_audio(audio_path)\n    for key, value in audio_tensor_dict.items():\n        probs = inference(model,value,device)\n        probabilities.append(probs)\n        rows.append(key)\ncolumns = list(map_text.values())\ndf = pd.DataFrame(probabilities,columns=columns)\ndf.insert(0,\"row_id\",rows)\nprint(\"Writing Submission...\")\ndf.to_csv(\"submission.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-17T07:15:09.107907Z","iopub.execute_input":"2025-05-17T07:15:09.108122Z","iopub.status.idle":"2025-05-17T07:15:09.149656Z","shell.execute_reply.started":"2025-05-17T07:15:09.108103Z","shell.execute_reply":"2025-05-17T07:15:09.148872Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}