{"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,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":351451,"sourceType":"modelInstanceVersion","isSourceIdPinned":false,"modelInstanceId":293327,"modelId":313963},{"sourceId":351501,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":293368,"modelId":314004},{"sourceId":351564,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":293415,"modelId":314048},{"sourceId":353133,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":294599,"modelId":315213},{"sourceId":354631,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":295803,"modelId":316411},{"sourceId":356360,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":297116,"modelId":317728}],"dockerImageVersionId":31012,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\n# import os\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n#     for filename in filenames:\n#         print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import os\n# import gc\n# import warnings\n# import logging\n# import time\n# import math\n# import cv2\n# from pathlib import Path\n\n# import numpy as np\n# import pandas as pd\n# import librosa\n# import torch\n# import torch.nn as nn\n# import torch.nn.functional as F\n# import timm\n# from tqdm.auto import tqdm\n\n# warnings.filterwarnings(\"ignore\")\n# logging.basicConfig(level=logging.ERROR)\n\n# class CFG:\n \n#     test_soundscapes = '/kaggle/input/birdclef-2025/test_soundscapes'\n#     submission_csv = '/kaggle/input/birdclef-2025/sample_submission.csv'\n#     taxonomy_csv = '/kaggle/input/birdclef-2025/taxonomy.csv'\n#     model_path = '/kaggle/input/mobile-test/pytorch/default/1' \n    \n#     # Audio parameters\n#     FS = 32000  \n#     WINDOW_SIZE = 5  \n    \n#     # Mel spectrogram parameters\n#     N_FFT = 1024\n#     HOP_LENGTH = 512\n#     N_MELS = 148\n#     FMIN = 50\n#     FMAX = 14000\n#     TARGET_SHAPE = (256, 256)\n    \n#     # model_name = 'resnet18'\n#     # model_name = 'efficientnet_b0'\n#     model_name = 'mobilenetv2_100'\n#     in_channels = 1\n#     device = 'cpu'  \n    \n#     # Inference parameters\n#     batch_size = 16\n#     use_tta = False  \n#     tta_count = 3   \n#     threshold = 0.5\n    \n#     use_specific_folds = False  # If False, use all found models\n#     folds = [0, 1]  # Used only if use_specific_folds is True\n    \n#     debug = False\n#     debug_count = 3\n\n# cfg = CFG()\n\n# taxonomy_df = pd.read_csv(cfg.taxonomy_csv)\n# species_ids = taxonomy_df['primary_label'].tolist()\n# num_classes = len(species_ids)\n# class BirdCLEFModel(nn.Module):\n#     def __init__(self, cfg, num_classes):\n#         super().__init__()\n#         self.cfg = cfg\n        \n#         self.backbone = timm.create_model(\n#             cfg.model_name,\n#             pretrained=False,  \n#             in_chans=cfg.in_channels,\n#             drop_rate=0.0,    \n#             drop_path_rate=0.0\n#         )\n        \n#         if 'efficientnet' in cfg.model_name:\n#             backbone_out = self.backbone.classifier.in_features\n#             self.backbone.classifier = nn.Identity()\n#         elif 'resnet' in cfg.model_name:\n#             backbone_out = self.backbone.fc.in_features\n#             self.backbone.fc = nn.Identity()\n#         else:\n#             backbone_out = self.backbone.get_classifier().in_features\n#             self.backbone.reset_classifier(0, '')\n        \n#         self.pooling = nn.AdaptiveAvgPool2d(1)\n#         self.feat_dim = backbone_out\n#         self.classifier = nn.Linear(backbone_out, num_classes)\n        \n#     def forward(self, x):\n#         features = self.backbone(x)\n        \n#         if isinstance(features, dict):\n#             features = features['features']\n            \n#         if len(features.shape) == 4:\n#             features = self.pooling(features)\n#             features = features.view(features.size(0), -1)\n        \n#         logits = self.classifier(features)\n#         return logits\n        \n# def audio2melspec(audio_data, cfg):\n#     \"\"\"Convert audio data to mel spectrogram\"\"\"\n#     if np.isnan(audio_data).any():\n#         mean_signal = np.nanmean(audio_data)\n#         audio_data = np.nan_to_num(audio_data, nan=mean_signal)\n\n#     mel_spec = librosa.feature.melspectrogram(\n#         y=audio_data,\n#         sr=cfg.FS,\n#         n_fft=cfg.N_FFT,\n#         hop_length=cfg.HOP_LENGTH,\n#         n_mels=cfg.N_MELS,\n#         fmin=cfg.FMIN,\n#         fmax=cfg.FMAX,\n#         power=2.0\n#     )\n\n#     mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max)\n#     mel_spec_norm = (mel_spec_db - mel_spec_db.min()) / (mel_spec_db.max() - mel_spec_db.min() + 1e-8)\n    \n#     return mel_spec_norm\n\n# def process_audio_segment(audio_data, cfg):\n#     \"\"\"Process audio segment to get mel spectrogram\"\"\"\n#     if len(audio_data) < cfg.FS * cfg.WINDOW_SIZE:\n#         audio_data = np.pad(audio_data, \n#                           (0, cfg.FS * cfg.WINDOW_SIZE - len(audio_data)), \n#                           mode='constant')\n    \n#     mel_spec = audio2melspec(audio_data, cfg)\n    \n#     # Resize if needed\n#     if mel_spec.shape != cfg.TARGET_SHAPE:\n#         mel_spec = cv2.resize(mel_spec, cfg.TARGET_SHAPE, interpolation=cv2.INTER_LINEAR)\n        \n#     return mel_spec.astype(np.float32)\n# def find_model_files(cfg):\n#     \"\"\"\n#     Find all .pth model files in the specified model directory\n#     \"\"\"\n#     model_files = []\n    \n#     model_dir = Path(cfg.model_path)\n    \n#     for path in model_dir.glob('**/*.pth'):\n#         model_files.append(str(path))\n    \n#     return model_files\n\n# def load_models(cfg, num_classes):\n#     \"\"\"\n#     Load all found model files and prepare them for ensemble\n#     \"\"\"\n#     models = []\n    \n#     model_files = find_model_files(cfg)\n    \n#     if not model_files:\n#         print(f\"Warning: No model files found under {cfg.model_path}!\")\n#         return models\n    \n#     print(f\"Found a total of {len(model_files)} model files.\")\n    \n#     if cfg.use_specific_folds:\n#         filtered_files = []\n#         for fold in cfg.folds:\n#             fold_files = [f for f in model_files if f\"fold{fold}\" in f]\n#             filtered_files.extend(fold_files)\n#         model_files = filtered_files\n#         print(f\"Using {len(model_files)} model files for the specified folds ({cfg.folds}).\")\n    \n#     for model_path in model_files:\n#         # try:\n#         print(f\"Loading model: {model_path}\")\n#         import os\n#         print(os.path.isfile(model_path))\n#         with open(model_path, \"rb\") as f:\n#             checkpoint = torch.load(f, map_location=\"cpu\")\n#         from collections import OrderedDict\n#         temp = OrderedDict()\n#         for k, v in checkpoint[\"model_state_dict\"].items():\n#             temp[k.replace(\"module.\", \"\")] = v\n#         model = BirdCLEFModel(cfg, num_classes)\n#         model.load_state_dict(temp)\n#         model = model.to(cfg.device)\n#         model.eval()\n        \n#         models.append(model)\n#         # except Exception as e:\n#         #     print(f\"Error loading model {model_path}: {e}\")\n    \n#     return models\n\n# def predict_on_spectrogram(audio_path, models, cfg, species_ids):\n#     \"\"\"Process a single audio file and predict species presence for each 5-second segment\"\"\"\n#     predictions = []\n#     row_ids = []\n#     soundscape_id = Path(audio_path).stem\n    \n#     try:\n#         print(f\"Processing {soundscape_id}\")\n#         audio_data, _ = librosa.load(audio_path, sr=cfg.FS)\n        \n#         total_segments = int(len(audio_data) / (cfg.FS * cfg.WINDOW_SIZE))\n        \n#         for segment_idx in range(total_segments):\n#             start_sample = segment_idx * cfg.FS * cfg.WINDOW_SIZE\n#             end_sample = start_sample + cfg.FS * cfg.WINDOW_SIZE\n#             segment_audio = audio_data[start_sample:end_sample]\n            \n#             end_time_sec = (segment_idx + 1) * cfg.WINDOW_SIZE\n#             row_id = f\"{soundscape_id}_{end_time_sec}\"\n#             row_ids.append(row_id)\n\n#             if cfg.use_tta:\n#                 all_preds = []\n                \n#                 for tta_idx in range(cfg.tta_count):\n#                     mel_spec = process_audio_segment(segment_audio, cfg)\n#                     mel_spec = apply_tta(mel_spec, tta_idx)\n\n#                     mel_spec = torch.tensor(mel_spec, dtype=torch.float32).unsqueeze(0).unsqueeze(0)\n#                     mel_spec = mel_spec.to(cfg.device)\n\n#                     if len(models) == 1:\n#                         with torch.no_grad():\n#                             outputs = models[0](mel_spec)\n#                             probs = torch.sigmoid(outputs).cpu().numpy().squeeze()\n#                             all_preds.append(probs)\n#                     else:\n#                         segment_preds = []\n#                         for model in models:\n#                             with torch.no_grad():\n#                                 outputs = model(mel_spec)\n#                                 probs = torch.sigmoid(outputs).cpu().numpy().squeeze()\n#                                 segment_preds.append(probs)\n                        \n#                         avg_preds = np.mean(segment_preds, axis=0)\n#                         all_preds.append(avg_preds)\n\n#                 final_preds = np.mean(all_preds, axis=0)\n#             else:\n#                 mel_spec = process_audio_segment(segment_audio, cfg)\n                \n#                 mel_spec = torch.tensor(mel_spec, dtype=torch.float32).unsqueeze(0).unsqueeze(0)\n#                 mel_spec = mel_spec.to(cfg.device)\n                \n#                 if len(models) == 1:\n#                     with torch.no_grad():\n#                         outputs = models[0](mel_spec)\n#                         final_preds = torch.sigmoid(outputs).cpu().numpy().squeeze()\n#                 else:\n#                     segment_preds = []\n#                     for model in models:\n#                         with torch.no_grad():\n#                             outputs = model(mel_spec)\n#                             probs = torch.sigmoid(outputs).cpu().numpy().squeeze()\n#                             segment_preds.append(probs)\n\n#                     final_preds = np.mean(segment_preds, axis=0)\n                    \n#             predictions.append(final_preds)\n            \n#     except Exception as e:\n#         print(f\"Error processing {audio_path}: {e}\")\n    \n#     return row_ids, predictions\n# def apply_tta(spec, tta_idx):\n#     \"\"\"Apply test-time augmentation\"\"\"\n#     if tta_idx == 0:\n#         # Original spectrogram\n#         return spec\n#     elif tta_idx == 1:\n#         # Time shift (horizontal flip)\n#         return np.flip(spec, axis=1)\n#     elif tta_idx == 2:\n#         # Frequency shift (vertical flip)\n#         return np.flip(spec, axis=0)\n#     else:\n#         return spec\n\n# def run_inference(cfg, models, species_ids):\n#     \"\"\"Run inference on all test soundscapes\"\"\"\n#     test_files = list(Path(cfg.test_soundscapes).glob('*.ogg'))\n    \n#     if cfg.debug:\n#         print(f\"Debug mode enabled, using only {cfg.debug_count} files\")\n#         test_files = test_files[:cfg.debug_count]\n    \n#     print(f\"Found {len(test_files)} test soundscapes\")\n\n#     all_row_ids = []\n#     all_predictions = []\n\n#     for audio_path in tqdm(test_files):\n#         row_ids, predictions = predict_on_spectrogram(str(audio_path), models, cfg, species_ids)\n#         all_row_ids.extend(row_ids)\n#         all_predictions.extend(predictions)\n    \n#     return all_row_ids, all_predictions\n\n# def create_submission(row_ids, predictions, species_ids, cfg):\n#     \"\"\"Create submission dataframe\"\"\"\n#     print(\"Creating submission dataframe...\")\n\n#     submission_dict = {'row_id': row_ids}\n    \n#     for i, species in enumerate(species_ids):\n#         submission_dict[species] = [pred[i] for pred in predictions]\n\n#     submission_df = pd.DataFrame(submission_dict)\n\n#     submission_df.set_index('row_id', inplace=True)\n\n#     sample_sub = pd.read_csv(cfg.submission_csv, index_col='row_id')\n\n#     missing_cols = set(sample_sub.columns) - set(submission_df.columns)\n#     if missing_cols:\n#         print(f\"Warning: Missing {len(missing_cols)} species columns in submission\")\n#         for col in missing_cols:\n#             submission_df[col] = 0.0\n\n#     submission_df = submission_df[sample_sub.columns]\n\n#     submission_df = submission_df.reset_index()\n    \n#     return submission_df\n\n# def main():\n#     start_time = time.time()\n#     print(\"Starting BirdCLEF-2025 inference...\")\n#     print(f\"TTA enabled: {cfg.use_tta} (variations: {cfg.tta_count if cfg.use_tta else 0})\")\n\n#     models = load_models(cfg, num_classes)\n    \n#     if not models:\n#         print(\"No models found! Please check model paths.\")\n#         return\n    \n#     print(f\"Model usage: {'Single model' if len(models) == 1 else f'Ensemble of {len(models)} models'}\")\n\n#     row_ids, predictions = run_inference(cfg, models, species_ids)\n\n#     submission_df = create_submission(row_ids, predictions, species_ids, cfg)\n\n#     submission_path = 'submission.csv'\n#     submission_df.to_csv(submission_path, index=False)\n#     print(f\"Submission saved to {submission_path}\")\n    \n#     end_time = time.time()\n#     print(f\"Inference completed in {(end_time - start_time)/60:.2f} minutes\")\n\n# if __name__ == \"__main__\":\n#     main()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-22T11:38:43.261050Z","iopub.execute_input":"2025-04-22T11:38:43.261329Z","iopub.status.idle":"2025-04-22T11:38:58.595193Z","shell.execute_reply.started":"2025-04-22T11:38:43.261308Z","shell.execute_reply":"2025-04-22T11:38:58.594399Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import os\n# import gc\n# import warnings\n# import logging\n# import time\n# import math\n# import cv2\n# from pathlib import Path\n# from collections import OrderedDict\n\n# import numpy as np\n# import pandas as pd\n# import librosa\n# import torch\n# import torch.nn as nn\n# import torch.nn.functional as F\n# import timm\n# from tqdm.auto import tqdm\n\n# warnings.filterwarnings(\"ignore\")\n# logging.basicConfig(level=logging.ERROR)\n\n# class CFG:\n#     test_soundscapes = '/kaggle/input/birdclef-2025/test_soundscapes'\n#     submission_csv = '/kaggle/input/birdclef-2025/sample_submission.csv'\n#     taxonomy_csv = '/kaggle/input/birdclef-2025/taxonomy.csv'\n#     model_path = '/kaggle/input/efficient-mfcc-test/pytorch/default/1' \n\n#     # Audio parameters\n#     FS = 32000  \n#     WINDOW_SIZE = 5  \n\n#     # Mel spectrogram parameters\n#     N_FFT = 1024\n#     HOP_LENGTH = 512\n#     N_MELS = 148\n#     FMIN = 50\n#     FMAX = 14000\n#     TARGET_SHAPE = (256, 256)\n\n#     model_name = 'efficientnet_b0'\n#     # model_name = 'resnet18'\n#     in_channels = 3  # 修改为 3 以适应多尺度特征\n#     device = 'cpu'  \n\n#     # Inference parameters\n#     batch_size = 16\n#     use_tta = False  \n#     tta_count = 3   \n#     threshold = 0.5\n\n#     use_specific_folds = False  # If False, use all found models\n#     folds = [0, 1]  # Used only if use_specific_folds is True\n\n#     debug = False\n#     debug_count = 3\n\n# cfg = CFG()\n\n# taxonomy_df = pd.read_csv(cfg.taxonomy_csv)\n# species_ids = taxonomy_df['primary_label'].tolist()\n# num_classes = len(species_ids)\n\n# class BirdCLEFModel(nn.Module):\n#     def __init__(self, cfg, num_classes):\n#         super().__init__()\n#         self.cfg = cfg\n\n#         self.backbone = timm.create_model(\n#             cfg.model_name,\n#             pretrained=False,  \n#             in_chans=cfg.in_channels,\n#             drop_rate=0.0,    \n#             drop_path_rate=0.0\n#         )\n\n#         if 'efficientnet' in cfg.model_name:\n#             backbone_out = self.backbone.classifier.in_features\n#             self.backbone.classifier = nn.Identity()\n#         elif 'resnet' in cfg.model_name:\n#             backbone_out = self.backbone.fc.in_features\n#             self.backbone.fc = nn.Identity()\n#         else:\n#             backbone_out = self.backbone.get_classifier().in_features\n#             self.backbone.reset_classifier(0, '')\n\n#         self.pooling = nn.AdaptiveAvgPool2d(1)\n#         self.feat_dim = backbone_out\n#         self.classifier = nn.Linear(backbone_out, num_classes)\n\n#     def forward(self, x):\n#         features = self.backbone(x)\n\n#         if isinstance(features, dict):\n#             features = features['features']\n\n#         if len(features.shape) == 4:\n#             features = self.pooling(features)\n#             features = features.view(features.size(0), -1)\n\n#         logits = self.classifier(features)\n#         return logits\n\n\n# def audio2melspec(audio_data, cfg):\n#     \"\"\"Convert audio data to mel spectrogram\"\"\"\n#     if np.isnan(audio_data).any():\n#         mean_signal = np.nanmean(audio_data)\n#         audio_data = np.nan_to_num(audio_data, nan=mean_signal)\n\n#     mel_spec = librosa.feature.melspectrogram(\n#         y=audio_data,\n#         sr=cfg.FS,\n#         n_fft=cfg.N_FFT,\n#         hop_length=cfg.HOP_LENGTH,\n#         n_mels=cfg.N_MELS,\n#         fmin=cfg.FMIN,\n#         fmax=cfg.FMAX,\n#         power=2.0\n#     )\n\n#     mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max)\n#     mel_spec_norm = (mel_spec_db - mel_spec_db.min()) / (mel_spec_db.max() - mel_spec_db.min() + 1e-8)\n\n#     return mel_spec_norm\n\n\n# def audio2mfcc(audio_data, cfg):\n#     \"\"\"Convert audio data to MFCC\"\"\"\n#     mfcc = librosa.feature.mfcc(y=audio_data, sr=cfg.FS, n_mfcc=cfg.N_MELS)\n#     mfcc_norm = (mfcc - np.mean(mfcc)) / (np.std(mfcc) + 1e-8)\n#     return mfcc_norm\n\n\n# def audio2chroma(audio_data, cfg):\n#     \"\"\"Convert audio data to chroma feature\"\"\"\n#     chroma = librosa.feature.chroma_stft(y=audio_data, sr=cfg.FS, n_fft=cfg.N_FFT, hop_length=cfg.HOP_LENGTH)\n#     chroma_norm = (chroma - np.mean(chroma)) / (np.std(chroma) + 1e-8)\n#     return chroma_norm\n\n\n# def process_audio_segment(audio_data, cfg):\n#     \"\"\"Process audio segment to get multi - scale features\"\"\"\n#     if len(audio_data) < cfg.FS * cfg.WINDOW_SIZE:\n#         audio_data = np.pad(audio_data,\n#                             (0, cfg.FS * cfg.WINDOW_SIZE - len(audio_data)),\n#                             mode='constant')\n\n#     mel_spec = audio2melspec(audio_data, cfg)\n#     mfcc = audio2mfcc(audio_data, cfg)\n#     chroma = audio2chroma(audio_data, cfg)\n\n#     # Resize if needed\n#     if mel_spec.shape != cfg.TARGET_SHAPE:\n#         mel_spec = cv2.resize(mel_spec, cfg.TARGET_SHAPE, interpolation=cv2.INTER_LINEAR)\n#     if mfcc.shape != cfg.TARGET_SHAPE:\n#         mfcc = cv2.resize(mfcc, cfg.TARGET_SHAPE, interpolation=cv2.INTER_LINEAR)\n#     if chroma.shape != cfg.TARGET_SHAPE:\n#         chroma = cv2.resize(chroma, cfg.TARGET_SHAPE, interpolation=cv2.INTER_LINEAR)\n\n#     multi_scale_features = np.stack([mel_spec, mfcc, chroma], axis=0)\n#     return multi_scale_features.astype(np.float32)\n\n\n# def find_model_files(cfg):\n#     \"\"\"\n#     Find all .pth model files in the specified model directory\n#     \"\"\"\n#     model_files = []\n\n#     model_dir = Path(cfg.model_path)\n\n#     for path in model_dir.glob('**/*.pth'):\n#         model_files.append(str(path))\n\n#     return model_files\n\n\n# def load_models(cfg, num_classes):\n#     \"\"\"\n#     Load all found model files and prepare them for ensemble\n#     \"\"\"\n#     models = []\n\n#     model_files = find_model_files(cfg)\n\n#     if not model_files:\n#         print(f\"Warning: No model files found under {cfg.model_path}!\")\n#         return models\n\n#     print(f\"Found a total of {len(model_files)} model files.\")\n\n#     if cfg.use_specific_folds:\n#         filtered_files = []\n#         for fold in cfg.folds:\n#             fold_files = [f for f in model_files if f\"fold{fold}\" in f]\n#             filtered_files.extend(fold_files)\n#         model_files = filtered_files\n#         print(f\"Using {len(model_files)} model files for the specified folds ({cfg.folds}).\")\n\n#     for model_path in model_files:\n#         try:\n#             print(f\"Loading model: {model_path}\")\n#             checkpoint = torch.load(model_path, map_location=torch.device(cfg.device))\n\n#             new_ckpt = OrderedDict()\n#             for k, v in checkpoint[\"model_state_dict\"].items():\n#                 new_ckpt[k.replace(\"module.\", \"\")] = v\n\n#             model = BirdCLEFModel(cfg, num_classes)\n#             model.load_state_dict(new_ckpt)\n#             model = model.to(cfg.device)\n#             model.eval()\n\n#             models.append(model)\n#         except Exception as e:\n#             print(f\"Error loading model {model_path}: {e}\")\n\n#     return models\n\n\n# def predict_on_spectrogram(audio_path, models, cfg, species_ids):\n#     \"\"\"Process a single audio file and predict species presence for each 5 - second segment\"\"\"\n#     predictions = []\n#     row_ids = []\n#     soundscape_id = Path(audio_path).stem\n\n#     try:\n#         print(f\"Processing {soundscape_id}\")\n#         audio_data, _ = librosa.load(audio_path, sr=cfg.FS)\n\n#         total_segments = int(len(audio_data) / (cfg.FS * cfg.WINDOW_SIZE))\n\n#         for segment_idx in range(total_segments):\n#             start_sample = segment_idx * cfg.FS * cfg.WINDOW_SIZE\n#             end_sample = start_sample + cfg.FS * cfg.WINDOW_SIZE\n#             segment_audio = audio_data[start_sample:end_sample]\n\n#             end_time_sec = (segment_idx + 1) * cfg.WINDOW_SIZE\n#             row_id = f\"{soundscape_id}_{end_time_sec}\"\n#             row_ids.append(row_id)\n\n#             if cfg.use_tta:\n#                 all_preds = []\n\n#                 for tta_idx in range(cfg.tta_count):\n#                     multi_scale_features = process_audio_segment(segment_audio, cfg)\n#                     multi_scale_features = apply_tta(multi_scale_features, tta_idx)\n\n#                     multi_scale_features = torch.tensor(multi_scale_features, dtype=torch.float32).unsqueeze(0)\n#                     multi_scale_features = multi_scale_features.to(cfg.device)\n\n#                     if len(models) == 1:\n#                         with torch.no_grad():\n#                             outputs = models[0](multi_scale_features)\n#                             probs = torch.sigmoid(outputs).cpu().numpy().squeeze()\n#                             all_preds.append(probs)\n#                     else:\n#                         segment_preds = []\n#                         for model in models:\n#                             with torch.no_grad():\n#                                 outputs = model(multi_scale_features)\n#                                 probs = torch.sigmoid(outputs).cpu().numpy().squeeze()\n#                                 segment_preds.append(probs)\n\n#                         avg_preds = np.mean(segment_preds, axis=0)\n#                         all_preds.append(avg_preds)\n\n#                 final_preds = np.mean(all_preds, axis=0)\n#             else:\n#                 multi_scale_features = process_audio_segment(segment_audio, cfg)\n\n#                 multi_scale_features = torch.tensor(multi_scale_features, dtype=torch.float32).unsqueeze(0)\n#                 multi_scale_features = multi_scale_features.to(cfg.device)\n\n#                 if len(models) == 1:\n#                     with torch.no_grad():\n#                         outputs = models[0](multi_scale_features)\n#                         final_preds = torch.sigmoid(outputs).cpu().numpy().squeeze()\n#                 else:\n#                     segment_preds = []\n#                     for model in models:\n#                         with torch.no_grad():\n#                             outputs = model(multi_scale_features)\n#                             probs = torch.sigmoid(outputs).cpu().numpy().squeeze()\n#                             segment_preds.append(probs)\n\n#                     final_preds = np.mean(segment_preds, axis=0)\n\n#             predictions.append(final_preds)\n\n#     except Exception as e:\n#         print(f\"Error processing {audio_path}: {e}\")\n\n#     return row_ids, predictions\n\n\n# def apply_tta(spec, tta_idx):\n#     \"\"\"Apply test - time augmentation\"\"\"\n#     if tta_idx == 0:\n#         # Original spectrogram\n#         return spec\n#     elif tta_idx == 1:\n#         # Time shift (horizontal flip)\n#         return np.flip(spec, axis=2)\n#     elif tta_idx == 2:\n#         # Frequency shift (vertical flip)\n#         return np.flip(spec, axis=1)\n#     else:\n#         return spec\n\n\n# def run_inference(cfg, models, species_ids):\n#     \"\"\"Run inference on all test soundscapes\"\"\"\n#     test_files = list(Path(cfg.test_soundscapes).glob('*.ogg'))\n\n#     if cfg.debug:\n#         print(f\"Debug mode enabled, using only {cfg.debug_count} files\")\n#         test_files = test_files[:cfg.debug_count]\n\n#     print(f\"Found {len(test_files)} test soundscapes\")\n\n#     all_row_ids = []\n#     all_predictions = []\n\n#     for audio_path in tqdm(test_files):\n#         row_ids, predictions = predict_on_spectrogram(str(audio_path), models, cfg, species_ids)\n#         all_row_ids.extend(row_ids)\n#         all_predictions.extend(predictions)\n\n#     return all_row_ids, all_predictions\n\n\n# def create_submission(row_ids, predictions, species_ids, cfg):\n#     \"\"\"Create submission dataframe\"\"\"\n#     print(\"Creating submission dataframe...\")\n\n#     submission_dict = {'row_id': row_ids}\n\n#     for i, species in enumerate(species_ids):\n#         submission_dict[species] = [pred[i] for pred in predictions]\n\n#     submission_df = pd.DataFrame(submission_dict)\n\n#     submission_df.set_index('row_id', inplace=True)\n\n#     sample_sub = pd.read_csv(cfg.submission_csv, index_col='row_id')\n\n#     missing_cols = set(sample_sub.columns) - set(submission_df.columns)\n#     if missing_cols:\n#         print(f\"Warning: Missing {len(missing_cols)} species columns in submission\")\n#         for col in missing_cols:\n#             submission_df[col] = 0.0\n\n#     submission_df = submission_df[sample_sub.columns]\n\n#     submission_df = submission_df.reset_index()\n\n#     return submission_df\n\n\n# def main():\n#     start_time = time.time()\n#     print(\"Starting BirdCLEF - 2025 inference...\")\n#     print(f\"TTA enabled: {cfg.use_tta} (variations: {cfg.tta_count if cfg.use_tta else 0})\")\n\n#     models = load_models(cfg, num_classes)\n\n#     if not models:\n#         print(\"No models found! Please check model paths.\")\n#         return\n\n#     print(f\"Model usage: {'Single model' if len(models) == 1 else f'Ensemble of {len(models)} models'}\")\n\n#     row_ids, predictions = run_inference(cfg, models, species_ids)\n\n#     submission_df = create_submission(row_ids, predictions, species_ids, cfg)\n\n#     submission_path = 'submission.csv'\n#     submission_df.to_csv(submission_path, index=False)\n#     print(f\"Submission saved to {submission_path}\")\n\n#     end_time = time.time()\n#     print(f\"Inference completed in {(end_time - start_time) / 60:.2f} minutes\")\n\n\n# if __name__ == \"__main__\":\n#     main()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T08:55:54.781483Z","iopub.execute_input":"2025-04-23T08:55:54.781806Z","iopub.status.idle":"2025-04-23T08:55:55.012580Z","shell.execute_reply.started":"2025-04-23T08:55:54.781782Z","shell.execute_reply":"2025-04-23T08:55:55.011716Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport gc\nimport warnings\nimport logging\nimport time\nimport math\nimport cv2\nfrom pathlib import Path\nfrom collections import OrderedDict\n\nimport numpy as np\nimport pandas as pd\nimport librosa\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport timm\nfrom tqdm.auto import tqdm\n\nwarnings.filterwarnings(\"ignore\")\nlogging.basicConfig(level=logging.ERROR)\n\nclass CFG:\n    test_soundscapes = '/kaggle/input/birdclef-2025/test_soundscapes'\n    submission_csv = '/kaggle/input/birdclef-2025/sample_submission.csv'\n    taxonomy_csv = '/kaggle/input/birdclef-2025/taxonomy.csv'\n    model_path = '/kaggle/input/noise-efficient-test/pytorch/default/1' \n\n    # Audio parameters\n    FS = 32000  \n    WINDOW_SIZE = 5  \n\n    # Mel spectrogram parameters\n    N_FFT = 1024\n    HOP_LENGTH = 512\n    N_MELS = 148\n    FMIN = 50\n    FMAX = 14000\n    TARGET_SHAPE = (256, 256)\n\n    # model_name = 'mobilenetv2_100'\n    model_name = 'efficientnet_b0'\n    in_channels = 1\n    device = 'cpu'  \n\n    # Inference parameters\n    batch_size = 16\n    use_tta = False  \n    tta_count = 3   \n    threshold = 0.5\n\n    use_specific_folds = False  # If False, use all found models\n    folds = [0, 1]  # Used only if use_specific_folds is True\n\n    debug = False\n    debug_count = 3\n\ncfg = CFG()\n\ntaxonomy_df = pd.read_csv(cfg.taxonomy_csv)\nspecies_ids = taxonomy_df['primary_label'].tolist()\nnum_classes = len(species_ids)\n\nclass BirdCLEFModel(nn.Module):\n    def __init__(self, cfg, num_classes):\n        super().__init__()\n        self.cfg = cfg\n\n        self.backbone = timm.create_model(\n            cfg.model_name,\n            pretrained=False,  \n            in_chans=cfg.in_channels,\n            drop_rate=0.0,    \n            drop_path_rate=0.0\n        )\n\n        if 'efficientnet' in cfg.model_name:\n            backbone_out = self.backbone.classifier.in_features\n            self.backbone.classifier = nn.Identity()\n        elif 'resnet' in cfg.model_name:\n            backbone_out = self.backbone.fc.in_features\n            self.backbone.fc = nn.Identity()\n        else:\n            backbone_out = self.backbone.get_classifier().in_features\n            self.backbone.reset_classifier(0, '')\n\n        self.pooling = nn.AdaptiveAvgPool2d(1)\n        self.feat_dim = backbone_out\n        self.classifier = nn.Linear(backbone_out, num_classes)\n\n    def forward(self, x):\n        features = self.backbone(x)\n\n        if isinstance(features, dict):\n            features = features['features']\n\n        if len(features.shape) == 4:\n            features = self.pooling(features)\n            features = features.view(features.size(0), -1)\n\n        logits = self.classifier(features)\n        return logits\n\n\ndef audio2melspec(audio_data, cfg):\n    \"\"\"Convert audio data to mel spectrogram\"\"\"\n    if np.isnan(audio_data).any():\n        mean_signal = np.nanmean(audio_data)\n        audio_data = np.nan_to_num(audio_data, nan=mean_signal)\n\n    mel_spec = librosa.feature.melspectrogram(\n        y=audio_data,\n        sr=cfg.FS,\n        n_fft=cfg.N_FFT,\n        hop_length=cfg.HOP_LENGTH,\n        n_mels=cfg.N_MELS,\n        fmin=cfg.FMIN,\n        fmax=cfg.FMAX,\n        power=2.0\n    )\n\n    mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max)\n    mel_spec_norm = (mel_spec_db - mel_spec_db.min()) / (mel_spec_db.max() - mel_spec_db.min() + 1e-8)\n\n    return mel_spec_norm\n\n\ndef process_audio_segment(audio_data, cfg):\n    \"\"\"Process audio segment to get mel spectrogram\"\"\"\n    if len(audio_data) < cfg.FS * cfg.WINDOW_SIZE:\n        audio_data = np.pad(audio_data,\n                            (0, cfg.FS * cfg.WINDOW_SIZE - len(audio_data)),\n                            mode='constant')\n\n    mel_spec = audio2melspec(audio_data, cfg)\n\n    # Resize if needed\n    if mel_spec.shape != cfg.TARGET_SHAPE:\n        mel_spec = cv2.resize(mel_spec, cfg.TARGET_SHAPE, interpolation=cv2.INTER_LINEAR)\n\n    return mel_spec.astype(np.float32)\n\n\ndef find_model_files(cfg):\n    \"\"\"\n    Find all .pth model files in the specified model directory\n    \"\"\"\n    model_files = []\n\n    model_dir = Path(cfg.model_path)\n\n    for path in model_dir.glob('**/*.pth'):\n        model_files.append(str(path))\n\n    return model_files\n\n\ndef load_models(cfg, num_classes):\n    \"\"\"\n    Load all found model files and prepare them for ensemble\n    \"\"\"\n    models = []\n\n    model_files = find_model_files(cfg)\n\n    if not model_files:\n        print(f\"Warning: No model files found under {cfg.model_path}!\")\n        return models\n\n    print(f\"Found a total of {len(model_files)} model files.\")\n\n    if cfg.use_specific_folds:\n        filtered_files = []\n        for fold in cfg.folds:\n            fold_files = [f for f in model_files if f\"fold{fold}\" in f]\n            filtered_files.extend(fold_files)\n        model_files = filtered_files\n        print(f\"Using {len(model_files)} model files for the specified folds ({cfg.folds}).\")\n\n    for model_path in model_files:\n        try:\n            print(f\"Loading model: {model_path}\")\n            checkpoint = torch.load(model_path, map_location=torch.device(cfg.device))\n\n            new_ckpt = OrderedDict()\n            for k, v in checkpoint[\"model_state_dict\"].items():\n                new_ckpt[k.replace(\"module.\", \"\")] = v\n\n            model = BirdCLEFModel(cfg, num_classes)\n            model.load_state_dict(new_ckpt)\n            model = model.to(cfg.device)\n            model.eval()\n\n            models.append(model)\n        except Exception as e:\n            print(f\"Error loading model {model_path}: {e}\")\n\n    return models\n\n\ndef predict_on_spectrogram(audio_path, models, cfg, species_ids):\n    \"\"\"Process a single audio file and predict species presence for each 5 - second segment\"\"\"\n    predictions = []\n    row_ids = []\n    soundscape_id = Path(audio_path).stem\n\n    try:\n        print(f\"Processing {soundscape_id}\")\n        audio_data, _ = librosa.load(audio_path, sr=cfg.FS)\n\n        total_segments = int(len(audio_data) / (cfg.FS * cfg.WINDOW_SIZE))\n\n        for segment_idx in range(total_segments):\n            start_sample = segment_idx * cfg.FS * cfg.WINDOW_SIZE\n            end_sample = start_sample + cfg.FS * cfg.WINDOW_SIZE\n            segment_audio = audio_data[start_sample:end_sample]\n\n            end_time_sec = (segment_idx + 1) * cfg.WINDOW_SIZE\n            row_id = f\"{soundscape_id}_{end_time_sec}\"\n            row_ids.append(row_id)\n\n            mel_spec = process_audio_segment(segment_audio, cfg)\n            mel_spec = torch.tensor(mel_spec, dtype=torch.float32).unsqueeze(0).unsqueeze(0)\n            mel_spec = mel_spec.to(cfg.device)\n\n            if len(models) == 1:\n                with torch.no_grad():\n                    outputs = models[0](mel_spec)\n                    probs = torch.sigmoid(outputs).cpu().numpy().squeeze()\n            else:\n                segment_preds = []\n                for model in models:\n                    with torch.no_grad():\n                        outputs = model(mel_spec)\n                        probs = torch.sigmoid(outputs).cpu().numpy().squeeze()\n                        segment_preds.append(probs)\n\n                probs = np.mean(segment_preds, axis=0)\n\n            predictions.append(probs)\n\n    except Exception as e:\n        print(f\"Error processing {audio_path}: {e}\")\n\n    return row_ids, predictions\n\n\ndef run_inference(cfg, models, species_ids):\n    \"\"\"Run inference on all test soundscapes\"\"\"\n    test_files = list(Path(cfg.test_soundscapes).glob('*.ogg'))\n\n    if cfg.debug:\n        print(f\"Debug mode enabled, using only {cfg.debug_count} files\")\n        test_files = test_files[:cfg.debug_count]\n\n    print(f\"Found {len(test_files)} test soundscapes\")\n\n    all_row_ids = []\n    all_predictions = []\n\n    for audio_path in tqdm(test_files):\n        row_ids, predictions = predict_on_spectrogram(str(audio_path), models, cfg, species_ids)\n        all_row_ids.extend(row_ids)\n        all_predictions.extend(predictions)\n\n    return all_row_ids, all_predictions\n\n\ndef create_submission(row_ids, predictions, species_ids, cfg):\n    \"\"\"Create submission dataframe\"\"\"\n    print(\"Creating submission dataframe...\")\n\n    submission_dict = {'row_id': row_ids}\n\n    for i, species in enumerate(species_ids):\n        submission_dict[species] = [pred[i] for pred in predictions]\n\n    submission_df = pd.DataFrame(submission_dict)\n\n    submission_df.set_index('row_id', inplace=True)\n\n    sample_sub = pd.read_csv(cfg.submission_csv, index_col='row_id')\n\n    missing_cols = set(sample_sub.columns) - set(submission_df.columns)\n    if missing_cols:\n        print(f\"Warning: Missing {len(missing_cols)} species columns in submission\")\n        for col in missing_cols:\n            submission_df[col] = 0.0\n\n    submission_df = submission_df[sample_sub.columns]\n\n    submission_df = submission_df.reset_index()\n\n    return submission_df\n\n\ndef main():\n    start_time = time.time()\n    print(\"Starting BirdCLEF - 2025 inference...\")\n    print(f\"TTA enabled: {cfg.use_tta} (variations: {cfg.tta_count if cfg.use_tta else 0})\")\n\n    models = load_models(cfg, num_classes)\n\n    if not models:\n        print(\"No models found! Please check model paths.\")\n        return\n\n    print(f\"Model usage: {'Single model' if len(models) == 1 else f'Ensemble of {len(models)} models'}\")\n\n    row_ids, predictions = run_inference(cfg, models, species_ids)\n\n    submission_df = create_submission(row_ids, predictions, species_ids, cfg)\n\n    submission_path = 'submission.csv'\n    submission_df.to_csv(submission_path, index=False)\n    print(f\"Submission saved to {submission_path}\")\n\n    end_time = time.time()\n    print(f\"Inference completed in {(end_time - start_time) / 60:.2f} minutes\")\n\n\nif __name__ == \"__main__\":\n    main()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-25T04:37:24.040785Z","iopub.execute_input":"2025-04-25T04:37:24.041110Z","iopub.status.idle":"2025-04-25T04:37:24.506453Z","shell.execute_reply.started":"2025-04-25T04:37:24.041082Z","shell.execute_reply":"2025-04-25T04:37:24.505516Z"}},"outputs":[],"execution_count":null}]}