{"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":"gpu","dataSources":[{"sourceId":91844,"databundleVersionId":11361821,"sourceType":"competition"},{"sourceId":11421084,"sourceType":"datasetVersion","datasetId":7152767}],"dockerImageVersionId":31011,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# import os\n# import gc\n# import logging\n# import numpy as np\n# import pandas as pd\n# import librosa\n# import torch\n# from sklearn.model_selection import KFold\n# import cv2\n# from tqdm.auto import tqdm\n\n# # Configure logging\n# logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')\n\n# class CFG:\n#     data_root = '/kaggle/input/birdclef-2025'\n#     train_audio = f'{data_root}/train_audio'\n#     train_csv = f'{data_root}/train.csv'\n#     taxonomy_csv = f'{data_root}/taxonomy.csv'\n#     output_dir = '/kaggle/working/processed_data'\n    \n#     FS = 32000\n#     WINDOW_SIZE = 5\n#     N_FFT = 1024\n#     HOP_LENGTH = 512\n#     N_MELS = 128\n#     FMIN = 50\n#     FMAX = 14000\n#     TARGET_SHAPE = (256, 256)\n    \n#     n_folds = 5\n#     selected_folds = [0, 1]\n#     seed = 42\n#     aug_prob = 0.5\n\n# def set_seed(seed):\n#     np.random.seed(seed)\n#     torch.manual_seed(seed)\n#     torch.cuda.manual_seed_all(seed)\n#     torch.backends.cudnn.deterministic = True\n#     torch.backends.cudnn.benchmark = False\n\n# def audio2melspec(audio_data, cfg):\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#     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#     return mel_spec_norm\n\n# def spec_augment(mel_spec, cfg):\n#     if np.random.rand() > cfg.aug_prob:\n#         return mel_spec\n#     max_time_mask = int(mel_spec.shape[1] * 0.1)\n#     time_mask = np.random.randint(0, max(1, mel_spec.shape[1] - max_time_mask))\n#     mel_spec[:, time_mask:time_mask + max_time_mask] = 0\n#     max_freq_mask = int(mel_spec.shape[0] * 0.1)\n#     freq_mask = np.random.randint(0, max(1, mel_spec.shape[0] - max_freq_mask))\n#     mel_spec[freq_mask:freq_mask + max_freq_mask, :] = 0\n#     return mel_spec\n\n# def preprocess_data(cfg):\n#     os.makedirs(cfg.output_dir, exist_ok=True)\n#     train_df = pd.read_csv(cfg.train_csv)\n#     species = pd.read_csv(cfg.taxonomy_csv)['primary_label'].tolist()\n#     num_classes = len(species)\n    \n#     # Create labels\n#     labels = np.zeros((len(train_df), num_classes), dtype=np.float32)\n#     for idx, row in train_df.iterrows():\n#         primary_label = row['primary_label']\n#         label_idx = species.index(primary_label)\n#         labels[idx, label_idx] = 1.0\n    \n#     # Process audio files\n#     spectrograms = []\n#     audio_paths = [os.path.join(cfg.train_audio, fname) for fname in train_df['filename']]\n#     for idx, audio_path in enumerate(tqdm(audio_paths, desc=\"Processing audio\")):\n#         try:\n#             audio_data, _ = librosa.load(audio_path, sr=cfg.FS)\n#             target_samples = cfg.FS * cfg.WINDOW_SIZE\n#             if len(audio_data) < target_samples:\n#                 audio_data = np.pad(audio_data, (0, target_samples - len(audio_data)), mode='constant')\n#             else:\n#                 start_idx = np.random.randint(0, max(1, len(audio_data) - target_samples))\n#                 audio_data = audio_data[start_idx:start_idx + target_samples]\n            \n#             mel_spec = audio2melspec(audio_data, cfg)\n#             mel_spec = spec_augment(mel_spec, cfg)\n#             if mel_spec.shape != cfg.TARGET_SHAPE:\n#                 mel_spec = cv2.resize(mel_spec, cfg.TARGET_SHAPE, interpolation=cv2.INTER_LINEAR)\n            \n#             mel_spec = mel_spec.astype(np.float32)\n#             spectrograms.append(mel_spec)\n#         except Exception as e:\n#             logging.error(f\"Error processing sample {idx}: {e}\")\n#             mel_spec = np.zeros(cfg.TARGET_SHAPE, dtype=np.float32)\n#             spectrograms.append(mel_spec)\n    \n#     # Save spectrograms and labels\n#     spectrograms = np.array(spectrograms)  # Shape: (num_samples, 256, 256)\n#     np.save(os.path.join(cfg.output_dir, 'spectrograms.npy'), spectrograms)\n#     np.save(os.path.join(cfg.output_dir, 'labels.npy'), labels)\n    \n#     # Save k-fold indices\n#     kf = KFold(n_splits=cfg.n_folds, shuffle=True, random_state=cfg.seed)\n#     fold_indices = {}\n#     for fold, (train_idx, val_idx) in enumerate(kf.split(train_df)):\n#         fold_indices[f'fold_{fold}'] = {'train_idx': train_idx, 'val_idx': val_idx}\n#     np.save(os.path.join(cfg.output_dir, 'fold_indices.npy'), fold_indices)\n    \n#     logging.info(f\"Processed data saved to {cfg.output_dir}\")\n\n# if __name__ == \"__main__\":\n#     cfg = CFG()\n#     set_seed(cfg.seed)\n#     preprocess_data(cfg)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-15T08:57:26.913518Z","iopub.execute_input":"2025-04-15T08:57:26.913751Z","iopub.status.idle":"2025-04-15T09:25:28.787395Z","shell.execute_reply.started":"2025-04-15T08:57:26.913728Z","shell.execute_reply":"2025-04-15T09:25:28.786696Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import os\n# import gc\n# import logging\n# import numpy as np\n# import torch\n# import torch.nn as nn\n# import torch.optim as optim\n# from torch.utils.data import Dataset, DataLoader\n# from sklearn.metrics import average_precision_score\n# from tqdm.auto import tqdm\n# import timm\n# from torch.cuda.amp import autocast, GradScaler\n\n# # Configure logging\n# logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')\n\n# class CFG:\n#     output_dir = '/kaggle/working/checkpoints'\n#     processed_data_dir = '/kaggle/input/bird-regnet/processed_data'\n    \n#     model_name = 'regnety_008'\n#     in_channels = 1\n#     device = 'cuda' if torch.cuda.is_available() else 'cpu'\n    \n#     n_folds = 5\n#     selected_folds = [0, 1]\n#     epochs = 10\n#     batch_size = 32\n#     num_workers = 0\n#     lr = 1e-4\n#     weight_decay = 1e-5\n#     early_stopping_patience = 3\n#     seed = 42\n\n# def set_seed(seed):\n#     torch.manual_seed(seed)\n#     torch.cuda.manual_seed_all(seed)\n#     np.random.seed(seed)\n#     torch.backends.cudnn.deterministic = True\n#     torch.backends.cudnn.benchmark = False\n\n# class PreprocessedBirdCLEFDataset(Dataset):\n#     def __init__(self, spectrograms, labels, indices):\n#         self.spectrograms = spectrograms[indices]\n#         self.labels = labels[indices]\n    \n#     def __len__(self):\n#         return len(self.spectrograms)\n    \n#     def __getitem__(self, idx):\n#         mel_spec = self.spectrograms[idx]\n#         mel_spec = torch.tensor(mel_spec, dtype=torch.float32).unsqueeze(0)\n#         label = torch.tensor(self.labels[idx], dtype=torch.float32)\n#         return mel_spec, label\n\n# class BirdCLEFModel(nn.Module):\n#     def __init__(self, cfg, num_classes):\n#         super().__init__()\n#         self.cfg = cfg\n#         self.backbone = timm.create_model(\n#             cfg.model_name,\n#             pretrained=True,\n#             in_chans=cfg.in_channels,\n#             drop_rate=0.3,\n#             drop_path_rate=0.2\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#         if isinstance(features, dict):\n#             features = features['features']\n#         if len(features.shape) == 4:\n#             features = self.pooling(features)\n#             features = features.view(features.size(0), -1)\n#         logits = self.classifier(features)\n#         return logits\n\n# def train_epoch(model, loader, criterion, optimizer, scaler, device):\n#     model.train()\n#     total_loss = 0\n#     for batch_idx, (spectrograms, labels) in enumerate(tqdm(loader, desc=\"Training\")):\n#         spectrograms, labels = spectrograms.to(device), labels.to(device)\n#         optimizer.zero_grad()\n#         with autocast():\n#             outputs = model(spectrograms)\n#             loss = criterion(outputs, labels)\n#         scaler.scale(loss).backward()\n#         scaler.step(optimizer)\n#         scaler.update()\n#         total_loss += loss.item()\n#     return total_loss / len(loader)\n\n# def validate_epoch(model, loader, criterion, device):\n#     model.eval()\n#     total_loss = 0\n#     all_preds, all_labels = [], []\n#     with torch.no_grad():\n#         for spectrograms, labels in tqdm(loader, desc=\"Validating\"):\n#             spectrograms, labels = spectrograms.to(device), labels.to(device)\n#             outputs = model(spectrograms)\n#             loss = criterion(outputs, labels)\n#             total_loss += loss.item()\n#             probs = torch.sigmoid(outputs).cpu().numpy()\n#             all_preds.append(probs)\n#             all_labels.append(labels.cpu().numpy())\n#     all_preds = np.concatenate(all_preds)\n#     all_labels = np.concatenate(all_labels)\n#     mAP = average_precision_score(all_labels, all_preds, average='macro')\n#     return total_loss / len(loader), mAP\n\n# def save_checkpoint(model, optimizer, epoch, fold, val_mAP, path):\n#     torch.save({\n#         'model_state_dict': model.state_dict(),\n#         'optimizer_state_dict': optimizer.state_dict(),\n#         'epoch': epoch,\n#         'fold': fold,\n#         'val_mAP': val_mAP\n#     }, path)\n#     logging.info(f\"Saved checkpoint for fold {fold} at epoch {epoch}\")\n\n# def train_model(cfg):\n#     os.makedirs(cfg.output_dir, exist_ok=True)\n    \n#     # Load preprocessed data\n#     spectrograms = np.load(os.path.join(cfg.processed_data_dir, 'spectrograms.npy'))\n#     labels = np.load(os.path.join(cfg.processed_data_dir, 'labels.npy'))\n#     fold_indices = np.load(os.path.join(cfg.processed_data_dir, 'fold_indices.npy'), allow_pickle=True).item()\n#     num_classes = labels.shape[1]\n    \n#     for fold in cfg.selected_folds:\n#         logging.info(f\"Training fold {fold}\")\n#         train_idx = fold_indices[f'fold_{fold}']['train_idx']\n#         val_idx = fold_indices[f'fold_{fold}']['val_idx']\n        \n#         train_dataset = PreprocessedBirdCLEFDataset(spectrograms, labels, train_idx)\n#         val_dataset = PreprocessedBirdCLEFDataset(spectrograms, labels, val_idx)\n        \n#         train_loader = DataLoader(\n#             train_dataset,\n#             batch_size=cfg.batch_size,\n#             shuffle=True,\n#             num_workers=0,\n#             pin_memory=True\n#         )\n#         val_loader = DataLoader(\n#             val_dataset,\n#             batch_size=cfg.batch_size,\n#             shuffle=False,\n#             num_workers=0,\n#             pin_memory=True\n#         )\n        \n#         model = BirdCLEFModel(cfg, num_classes).to(cfg.device)\n#         criterion = nn.BCEWithLogitsLoss()\n#         optimizer = optim.AdamW(model.parameters(), lr=cfg.lr, weight_decay=cfg.weight_decay)\n#         scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=cfg.epochs)\n#         scaler = GradScaler()\n        \n#         best_mAP = 0\n#         epochs_without_improvement = 0\n        \n#         try:\n#             for epoch in range(cfg.epochs):\n#                 train_loss = train_epoch(model, train_loader, criterion, optimizer, scaler, cfg.device)\n#                 val_loss, val_mAP = validate_epoch(model, val_loader, criterion, cfg.device)\n                \n#                 logging.info(f\"Fold {fold} Epoch {epoch+1}/{cfg.epochs} | Train Loss: {train_loss:.4f} | Val Loss: {val_loss:.4f} | Val mAP: {val_mAP:.4f}\")\n                \n#                 if val_mAP > best_mAP:\n#                     best_mAP = val_mAP\n#                     epochs_without_improvement = 0\n#                     save_checkpoint(model, optimizer, epoch, fold, val_mAP, os.path.join(cfg.output_dir, f'fold{fold}_best.pth'))\n#                 else:\n#                     epochs_without_improvement += 1\n                \n#                 scheduler.step()\n                \n#                 if epochs_without_improvement >= cfg.early_stopping_patience:\n#                     logging.info(f\"Early stopping triggered for fold {fold} after epoch {epoch+1}\")\n#                     break\n#         finally:\n#             del train_loader, val_loader\n#             gc.collect()\n#             torch.cuda.empty_cache()\n        \n#         save_checkpoint(model, optimizer, cfg.epochs, fold, best_mAP, os.path.join(cfg.output_dir, f'fold{fold}_final.pth'))\n\n# if __name__ == \"__main__\":\n#     cfg = CFG()\n#     set_seed(cfg.seed)\n#     train_model(cfg)","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":"# import os\n# import gc\n# import logging\n# import numpy as np\n# import torch\n# import torch.nn as nn\n# import torch.optim as optim\n# from torch.utils.data import Dataset, DataLoader\n# from sklearn.metrics import average_precision_score\n# from sklearn.model_selection import KFold\n# from tqdm.auto import tqdm\n# import timm\n# from torch.amp import GradScaler, autocast\n\n# # 配置日志\n# logging.basicConfig(\n#     level=logging.INFO,\n#     format='%(asctime)s - %(levelname)s - %(message)s',\n#     handlers=[\n#         logging.StreamHandler()\n#     ]\n# )\n# logging.getLogger().setLevel(logging.INFO)\n\n# class CFG:\n#     output_dir = '/kaggle/working/checkpoints'\n#     processed_data_dir = '/kaggle/input/bird-regnet/processed_data'\n    \n#     model_name = 'regnety_008'\n#     in_channels = 1\n#     device = 'cuda' if torch.cuda.is_available() else 'cpu'\n    \n#     n_folds = 3  # 减少折数以增加验证集规模\n#     selected_folds = [0, 1]\n#     epochs = 10\n#     batch_size = 32\n#     num_workers = 0\n#     lr = 1e-4\n#     weight_decay = 1e-5\n#     early_stopping_patience = 5  # 增加早停耐心\n#     seed = 42\n#     subset_ratio = 0.2  # 使用 20% 的数据\n\n# def set_seed(seed):\n#     torch.manual_seed(seed)\n#     torch.cuda.manual_seed_all(seed)\n#     np.random.seed(seed)\n#     torch.backends.cudnn.deterministic = True\n#     torch.backends.cudnn.benchmark = False\n\n# class PreprocessedBirdCLEFDataset(Dataset):\n#     def __init__(self, spectrograms, labels, indices):\n#         self.spectrograms = spectrograms[indices]\n#         self.labels = labels[indices]\n    \n#     def __len__(self):\n#         return len(self.spectrograms)\n    \n#     def __getitem__(self, idx):\n#         mel_spec = self.spectrograms[idx]\n#         mel_spec = torch.tensor(mel_spec, dtype=torch.float32).unsqueeze(0)\n#         label = torch.tensor(self.labels[idx], dtype=torch.float32)\n#         return mel_spec, label\n\n# class BirdCLEFModel(nn.Module):\n#     def __init__(self, cfg, num_classes):\n#         super().__init__()\n#         self.cfg = cfg\n#         self.backbone = timm.create_model(\n#             cfg.model_name,\n#             pretrained=True,\n#             in_chans=cfg.in_channels,\n#             drop_rate=0.3,\n#             drop_path_rate=0.2\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#         if isinstance(features, dict):\n#             features = features['features']\n#         if len(features.shape) == 4:\n#             features = self.pooling(features)\n#             features = features.view(features.size(0), -1)\n#         logits = self.classifier(features)\n#         return logits\n\n# def train_epoch(model, loader, criterion, optimizer, scaler, device):\n#     if scaler is None:\n#         raise ValueError(\"Scaler 未定义，请确保 GradScaler 已正确初始化。\")\n#     model.train()\n#     total_loss = 0\n#     for batch_idx, (spectrograms, labels) in enumerate(tqdm(loader, desc=\"Training\")):\n#         spectrograms, labels = spectrograms.to(device), labels.to(device)\n#         optimizer.zero_grad()\n#         with autocast(device_type='cuda'):\n#             outputs = model(spectrograms)\n#             loss = criterion(outputs, labels)\n#         scaler.scale(loss).backward()\n#         scaler.step(optimizer)\n#         scaler.update()\n#         total_loss += loss.item()\n#     avg_loss = total_loss / len(loader)\n#     print(f\"DEBUG: train_epoch 完成, avg_loss={avg_loss}\")\n#     return avg_loss\n\n# def validate_epoch(model, loader, criterion, device):\n#     model.eval()\n#     total_loss = 0\n#     all_preds, all_labels = [], []\n#     with torch.no_grad():\n#         for spectrograms, labels in tqdm(loader, desc=\"Validating\"):\n#             spectrograms, labels = spectrograms.to(device), labels.to(device)\n#             outputs = model(spectrograms)\n#             loss = criterion(outputs, labels)\n#             total_loss += loss.item()\n#             probs = torch.sigmoid(outputs).cpu().numpy()\n#             all_preds.append(probs)\n#             all_labels.append(labels.cpu().numpy())\n#     all_preds = np.concatenate(all_preds)\n#     all_labels = np.concatenate(all_labels)\n    \n#     ap_scores = []\n#     for i in range(all_labels.shape[1]):\n#         if np.sum(all_labels[:, i]) > 0:\n#             ap = average_precision_score(all_labels[:, i], all_preds[:, i])\n#             ap_scores.append(ap)\n#         else:\n#             logging.warning(f\"类别 {i} 在验证集中没有正样本，跳过。\")\n    \n#     mAP = np.mean(ap_scores) if ap_scores else 0.0\n#     avg_loss = total_loss / len(loader)\n#     print(f\"DEBUG: validate_epoch 完成, avg_loss={avg_loss}, mAP={mAP}\")\n#     return avg_loss, mAP\n\n# def save_checkpoint(model, optimizer, epoch, fold, val_mAP, path):\n#     torch.save({\n#         'model_state_dict': model.state_dict(),\n#         'optimizer_state_dict': optimizer.state_dict(),\n#         'epoch': epoch,\n#         'fold': fold,\n#         'val_mAP': val_mAP\n#     }, path)\n#     print(f\"已保存检查点：fold {fold} 在 epoch {epoch}\")\n\n# def select_subset(spectrograms, labels, subset_ratio, seed):\n#     num_samples = len(spectrograms)\n#     subset_size = int(num_samples * subset_ratio)\n#     np.random.seed(seed)\n#     label_sums = np.sum(labels, axis=0)\n    \n#     # 确保每个类别至少有 1 个样本（如果存在）\n#     subset_indices = []\n#     for cls in range(labels.shape[1]):\n#         cls_indices = np.where(labels[:, cls] == 1)[0]\n#         if len(cls_indices) > 0:\n#             subset_indices.append(np.random.choice(cls_indices, size=1, replace=False))\n    \n#     subset_indices = np.unique(subset_indices)\n#     remaining_size = max(0, subset_size - len(subset_indices))\n#     other_indices = np.setdiff1d(np.arange(num_samples), subset_indices)\n#     if remaining_size > 0 and len(other_indices) > 0:\n#         other_subset = np.random.choice(other_indices, size=remaining_size, replace=False)\n#         subset_indices = np.concatenate([subset_indices, other_subset])\n    \n#     return subset_indices\n\n# def train_model(cfg):\n#     os.makedirs(cfg.output_dir, exist_ok=True)\n    \n#     spectrograms = np.load(os.path.join(cfg.processed_data_dir, 'spectrograms.npy'))\n#     labels = np.load(os.path.join(cfg.processed_data_dir, 'labels.npy'))\n    \n#     subset_indices = select_subset(spectrograms, labels, cfg.subset_ratio, cfg.seed)\n#     spectrograms = spectrograms[subset_indices]\n#     labels = labels[subset_indices]\n#     num_classes = labels.shape[1]\n    \n#     class_counts = np.sum(labels, axis=0)\n#     print(f\"子集类别分布: {class_counts}\")\n#     zero_classes = np.where(class_counts == 0)[0]\n#     if len(zero_classes) > 0:\n#         print(f\"子集中没有样本的类别: {zero_classes}\")\n    \n#     kf = KFold(n_splits=cfg.n_folds, shuffle=True, random_state=cfg.seed)\n#     fold_indices = {}\n#     for fold, (train_idx, val_idx) in enumerate(kf.split(range(len(spectrograms)))):\n#         fold_indices[f'fold_{fold}'] = {'train_idx': train_idx, 'val_idx': val_idx}\n    \n#     for fold in cfg.selected_folds:\n#         print(f\"训练 fold {fold}\")\n#         train_idx = fold_indices[f'fold_{fold}']['train_idx']\n#         val_idx = fold_indices[f'fold_{fold}']['val_idx']\n        \n#         train_dataset = PreprocessedBirdCLEFDataset(spectrograms, labels, train_idx)\n#         val_dataset = PreprocessedBirdCLEFDataset(spectrograms, labels, val_idx)\n        \n#         train_loader = DataLoader(\n#             train_dataset,\n#             batch_size=cfg.batch_size,\n#             shuffle=True,\n#             num_workers=0,\n#             pin_memory=True\n#         )\n#         val_loader = DataLoader(\n#             val_dataset,\n#             batch_size=cfg.batch_size,\n#             shuffle=False,\n#             num_workers=0,\n#             pin_memory=True\n#         )\n        \n#         model = BirdCLEFModel(cfg, num_classes).to(cfg.device)\n#         criterion = nn.BCEWithLogitsLoss()\n#         optimizer = optim.AdamW(model.parameters(), lr=cfg.lr, weight_decay=cfg.weight_decay)\n#         scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=cfg.epochs)\n#         scaler = GradScaler()\n        \n#         best_mAP = 0\n#         epochs_without_improvement = 0\n#         min_mAP_improvement = 0.001  # 最小 mAP 提升阈值\n        \n#         try:\n#             for epoch in range(cfg.epochs):\n#                 train_loss = train_epoch(model, train_loader, criterion, optimizer, scaler, cfg.device)\n#                 val_loss, val_mAP = validate_epoch(model, val_loader, criterion, cfg.device)\n                \n#                 print(f\"Fold {fold} Epoch {epoch+1}/{cfg.epochs} | Train Loss: {train_loss:.4f} | Val Loss: {val_loss:.4f} | Val mAP: {val_mAP:.4f}\", flush=True)\n                \n#                 if val_mAP > best_mAP + min_mAP_improvement:\n#                     best_mAP = val_mAP\n#                     epochs_without_improvement = 0\n#                     save_checkpoint(model, optimizer, epoch, fold, val_mAP, os.path.join(cfg.output_dir, f'fold{fold}_best.pth'))\n#                 else:\n#                     epochs_without_improvement += 1\n#                     print(f\"没有提升的 epoch 数量: {epochs_without_improvement}\", flush=True)\n                \n#                 scheduler.step()\n                \n#                 if epochs_without_improvement >= cfg.early_stopping_patience:\n#                     print(f\"早停触发：fold {fold} 在 epoch {epoch+1} 后停止\")\n#                     break\n#         finally:\n#             del train_loader, val_loader\n#             gc.collect()\n#             torch.cuda.empty_cache()\n        \n#         save_checkpoint(model, optimizer, cfg.epochs, fold, best_mAP, os.path.join(cfg.output_dir, f'fold{fold}_final.pth'))\n\n# if __name__ == \"__main__\":\n#     cfg = CFG()\n#     set_seed(cfg.seed)\n#     train_model(cfg)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T03:24:27.433441Z","iopub.execute_input":"2025-04-16T03:24:27.433747Z","iopub.status.idle":"2025-04-16T03:32:16.792698Z","shell.execute_reply.started":"2025-04-16T03:24:27.433724Z","shell.execute_reply":"2025-04-16T03:32:16.791847Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import os\n# import gc\n# import logging\n# import numpy as np\n# import torch\n# import torch.nn as nn\n# import torch.optim as optim\n# from torch.utils.data import Dataset, DataLoader\n# from sklearn.metrics import average_precision_score\n# from sklearn.model_selection import KFold\n# from tqdm.auto import tqdm\n# import timm\n# from torch.amp import GradScaler, autocast\n# import shutil\n# import psutil\n\n# # 配置日志，写入文件\n# logging.basicConfig(\n#     level=logging.INFO,\n#     format='%(asctime)s - %(levelname)s - %(message)s',\n#     handlers=[\n#         logging.FileHandler(os.path.join('/kaggle/working', 'training_log.txt'))\n#     ]\n# )\n# logging.getLogger().setLevel(logging.INFO)\n\n# class CFG:\n#     output_dir = '/kaggle/working/model'\n#     processed_data_dir = '/kaggle/input/bird-regnet/processed_data'\n    \n#     model_name = 'regnety_008'\n#     in_channels = 1\n#     device = 'cuda' if torch.cuda.is_available() else 'cpu'\n    \n#     n_folds = 5  # 增加到 5 折\n#     selected_folds = [0]\n#     epochs = 20  # 增加到 20 个 epoch\n#     batch_size = 32\n#     num_workers = 0\n#     lr = 1e-4  # 微调学习率\n#     weight_decay = 1e-5\n#     early_stopping_patience = 5\n#     seed = 42\n#     subset_ratio = 1.0\n\n# def set_seed(seed):\n#     torch.manual_seed(seed)\n#     torch.cuda.manual_seed_all(seed)\n#     np.random.seed(seed)\n#     torch.backends.cudnn.deterministic = True\n#     torch.backends.cudnn.benchmark = False\n\n# class PreprocessedBirdCLEFDataset(Dataset):\n#     def __init__(self, spectrograms, labels, indices):\n#         self.spectrograms = spectrograms[indices]\n#         self.labels = labels[indices]\n    \n#     def __len__(self):\n#         return len(self.spectrograms)\n    \n#     def spec_augment(self, mel_spec, aug_prob=0.5):\n#         if np.random.rand() > aug_prob:\n#             return mel_spec\n#         max_time_mask = int(mel_spec.shape[1] * 0.1)\n#         time_mask = np.random.randint(0, max(1, mel_spec.shape[1] - max_time_mask))\n#         mel_spec[:, time_mask:time_mask + max_time_mask] = 0\n#         max_freq_mask = int(mel_spec.shape[0] * 0.1)\n#         freq_mask = np.random.randint(0, max(1, mel_spec.shape[0] - max_freq_mask))\n#         mel_spec[freq_mask:freq_mask + max_freq_mask, :] = 0\n#         return mel_spec\n    \n#     def __getitem__(self, idx):\n#         mel_spec = self.spectrograms[idx].copy()\n#         mel_spec = self.spec_augment(mel_spec)\n#         mel_spec = torch.tensor(mel_spec, dtype=torch.float32).unsqueeze(0)\n#         label = torch.tensor(self.labels[idx], dtype=torch.float32)\n#         return mel_spec, label\n\n# class BirdCLEFModel(nn.Module):\n#     def __init__(self, cfg, num_classes):\n#         super().__init__()\n#         self.cfg = cfg\n#         self.backbone = timm.create_model(\n#             cfg.model_name,\n#             pretrained=True,\n#             in_chans=cfg.in_channels,\n#             drop_rate=0.3,\n#             drop_path_rate=0.3\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#         if isinstance(features, dict):\n#             features = features['features']\n#         if len(features.shape) == 4:\n#             features = self.pooling(features)\n#             features = features.view(features.size(0), -1)\n#         logits = self.classifier(features)\n#         return logits\n\n# def train_epoch(model, loader, criterion, optimizer, scaler, device):\n#     if scaler is None:\n#         raise ValueError(\"Scaler 未定义，请确保 GradScaler 已正确初始化。\")\n#     model.train()\n#     total_loss = 0\n#     for batch_idx, (spectrograms, labels) in enumerate(tqdm(loader, desc=\"Training\", disable=True)):\n#         spectrograms, labels = spectrograms.to(device), labels.to(device)\n#         optimizer.zero_grad()\n#         with autocast(device_type='cuda'):\n#             outputs = model(spectrograms)\n#             loss = criterion(outputs, labels)\n#         scaler.scale(loss).backward()\n#         scaler.step(optimizer)\n#         scaler.update()\n#         total_loss += loss.item()\n#     avg_loss = total_loss / len(loader)\n#     return avg_loss\n\n# def validate_epoch(model, loader, criterion, device):\n#     model.eval()\n#     total_loss = 0\n#     all_preds, all_labels = [], []\n#     with torch.no_grad():\n#         for spectrograms, labels in tqdm(loader, desc=\"Validating\", disable=True):\n#             spectrograms, labels = spectrograms.to(device), labels.to(device)\n#             outputs = model(spectrograms)\n#             loss = criterion(outputs, labels)\n#             total_loss += loss.item()\n#             probs = torch.sigmoid(outputs).cpu().numpy()\n#             all_preds.append(probs)\n#             all_labels.append(labels.cpu().numpy())\n#     all_preds = np.concatenate(all_preds)\n#     all_labels = np.concatenate(all_labels)\n    \n#     ap_scores = []\n#     for i in range(all_labels.shape[1]):\n#         if np.sum(all_labels[:, i]) > 0:\n#             ap = average_precision_score(all_labels[:, i], all_preds[:, i])\n#             ap_scores.append(ap)\n#         else:\n#             logging.warning(f\"类别 {i} 在验证集中没有正样本，跳过。\")\n    \n#     mAP = np.mean(ap_scores) if ap_scores else 0.0\n#     avg_loss = total_loss / len(loader)\n#     return avg_loss, mAP\n\n# def save_checkpoint(model, optimizer, epoch, fold, val_mAP, path):\n#     try:\n#         os.makedirs(os.path.dirname(path), exist_ok=True)\n#         temp_path = os.path.join('/tmp', os.path.basename(path))\n#         torch.save({\n#             'model_state_dict': model.state_dict(),\n#             'optimizer_state_dict': optimizer.state_dict(),\n#             'epoch': epoch,\n#             'fold': fold,\n#             'val_mAP': val_mAP\n#         }, temp_path)\n#         shutil.copy(temp_path, path)\n#         print(f\"成功保存检查点：{path}\", flush=True)\n#     except Exception as e:\n#         print(f\"保存检查点失败：{path}，错误: {e}\", flush=True)\n#     finally:\n#         if os.path.exists(temp_path):\n#             os.remove(temp_path)\n\n# def get_disk_space(path):\n#     disk = psutil.disk_usage(path)\n#     return disk.free / (1024**3)\n\n# def select_subset(spectrograms, labels, subset_ratio, seed):\n#     num_samples = len(spectrograms)\n#     subset_size = int(num_samples * subset_ratio)\n#     np.random.seed(seed)\n#     label_sums = np.sum(labels, axis=0)\n    \n#     subset_indices = []\n#     for cls in range(labels.shape[1]):\n#         cls_indices = np.where(labels[:, cls] == 1)[0]\n#         if len(cls_indices) > 0:\n#             subset_indices.append(np.random.choice(cls_indices, size=1, replace=False))\n    \n#     subset_indices = np.unique(subset_indices)\n#     remaining_size = max(0, subset_size - len(subset_indices))\n#     other_indices = np.setdiff1d(np.arange(num_samples), subset_indices)\n#     if remaining_size > 0 and len(other_indices) > 0:\n#         other_subset = np.random.choice(other_indices, size=remaining_size, replace=False)\n#         subset_indices = np.concatenate([subset_indices, other_subset])\n    \n#     return subset_indices\n\n# def train_model(cfg):\n#     os.makedirs(cfg.output_dir, exist_ok=True)\n    \n#     free_space = get_disk_space('/kaggle/working')\n#     print(f\"/kaggle/working 可用磁盘空间: {free_space:.2f} GB\")\n#     free_space_tmp = get_disk_space('/tmp')\n#     print(f\"/tmp 可用磁盘空间: {free_space_tmp:.2f} GB\")\n    \n#     if not os.access(cfg.output_dir, os.W_OK):\n#         print(f\"警告：{cfg.output_dir} 不可写，将尝试使用 /tmp 目录\")\n#         cfg.output_dir = '/tmp/model'\n#         os.makedirs(cfg.output_dir, exist_ok=True)\n    \n#     spectrograms = np.load(os.path.join(cfg.processed_data_dir, 'spectrograms.npy'))\n#     labels = np.load(os.path.join(cfg.processed_data_dir, 'labels.npy'))\n    \n#     subset_indices = select_subset(spectrograms, labels, cfg.subset_ratio, cfg.seed)\n#     spectrograms = spectrograms[subset_indices]\n#     labels = labels[subset_indices]\n#     num_classes = labels.shape[1]\n    \n#     class_counts = np.sum(labels, axis=0)\n#     print(f\"子集类别分布: {class_counts}\")\n#     zero_classes = np.where(class_counts == 0)[0]\n#     if len(zero_classes) > 0:\n#         print(f\"子集中没有样本的类别: {zero_classes}\")\n    \n#     kf = KFold(n_splits=cfg.n_folds, shuffle=True, random_state=cfg.seed)\n#     fold_indices = {}\n#     for fold, (train_idx, val_idx) in enumerate(kf.split(range(len(spectrograms)))):\n#         fold_indices[f'fold_{fold}'] = {'train_idx': train_idx, 'val_idx': val_idx}\n    \n#     for fold in cfg.selected_folds:\n#         print(f\"训练 fold {fold}\")\n#         train_idx = fold_indices[f'fold_{fold}']['train_idx']\n#         val_idx = fold_indices[f'fold_{fold}']['val_idx']\n        \n#         train_dataset = PreprocessedBirdCLEFDataset(spectrograms, labels, train_idx)\n#         val_dataset = PreprocessedBirdCLEFDataset(spectrograms, labels, val_idx)\n        \n#         train_loader = DataLoader(\n#             train_dataset,\n#             batch_size=cfg.batch_size,\n#             shuffle=True,\n#             num_workers=0,\n#             pin_memory=True\n#         )\n#         val_loader = DataLoader(\n#             val_dataset,\n#             batch_size=cfg.batch_size,\n#             shuffle=False,\n#             num_workers=0,\n#             pin_memory=True\n#         )\n        \n#         model = BirdCLEFModel(cfg, num_classes).to(cfg.device)\n#         label_sums = np.sum(labels, axis=0)\n#         pos_weight = torch.tensor(np.clip((len(labels) - label_sums) / (label_sums + 1e-8), 0.1, 100.0), device=cfg.device)\n#         criterion = nn.BCEWithLogitsLoss(pos_weight=pos_weight)\n#         optimizer = optim.AdamW(model.parameters(), lr=cfg.lr, weight_decay=cfg.weight_decay)\n#         scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=2, verbose=False)\n#         scaler = GradScaler()\n        \n#         best_mAP = 0\n#         epochs_without_improvement = 0\n#         min_mAP_improvement = 0.001\n        \n#         try:\n#             for epoch in range(cfg.epochs):\n#                 train_loss = train_epoch(model, train_loader, criterion, optimizer, scaler, cfg.device)\n#                 val_loss, val_mAP = validate_epoch(model, val_loader, criterion, cfg.device)\n                \n#                 print(f\"Fold {fold} Epoch {epoch+1}/{cfg.epochs} | Train Loss: {train_loss:.4f} | Val Loss: {val_loss:.4f} | Val mAP: {val_mAP:.4f}\", flush=True)\n#                 print(f\"当前学习率: {scheduler.get_last_lr()}\", flush=True)\n                \n#                 if val_mAP > best_mAP + min_mAP_improvement:\n#                     best_mAP = val_mAP\n#                     epochs_without_improvement = 0\n#                     save_checkpoint(model, optimizer, epoch, fold, val_mAP, os.path.join(cfg.output_dir, f'fold{fold}_best.pth'))\n#                 else:\n#                     epochs_without_improvement += 1\n#                     print(f\"没有提升的 epoch 数量: {epochs_without_improvement}\", flush=True)\n                \n#                 scheduler.step(val_loss)\n                \n#                 if epochs_without_improvement >= cfg.early_stopping_patience:\n#                     print(f\"早停触发：fold {fold} 在 epoch {epoch+1} 后停止\")\n#                     break\n#         finally:\n#             del train_loader, val_loader\n#             gc.collect()\n#             torch.cuda.empty_cache()\n        \n#         save_checkpoint(model, optimizer, cfg.epochs, fold, best_mAP, os.path.join(cfg.output_dir, f'fold{fold}_final.pth'))\n        \n#         if cfg.output_dir.startswith('/tmp'):\n#             final_output_dir = '/kaggle/working/model'\n#             os.makedirs(final_output_dir, exist_ok=True)\n#             for file_name in os.listdir(cfg.output_dir):\n#                 src_path = os.path.join(cfg.output_dir, file_name)\n#                 dst_path = os.path.join(final_output_dir, file_name)\n#                 shutil.copy(src_path, dst_path)\n#                 print(f\"复制文件：{src_path} 到 {dst_path}\", flush=True)\n\n# if __name__ == \"__main__\":\n#     cfg = CFG()\n#     set_seed(cfg.seed)\n#     train_model(cfg)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-18T14:01:33.477769Z","iopub.execute_input":"2025-04-18T14:01:33.478040Z","iopub.status.idle":"2025-04-18T14:31:35.686342Z","shell.execute_reply.started":"2025-04-18T14:01:33.478018Z","shell.execute_reply":"2025-04-18T14:31:35.685555Z"}},"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":"# import os\n# import gc\n# import logging\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.optim as optim\n# from torch.utils.data import Dataset, DataLoader\n# from sklearn.model_selection import KFold\n# from sklearn.metrics import average_precision_score\n# import cv2\n# from tqdm.auto import tqdm\n# import timm\n# from torch.cuda.amp import autocast, GradScaler\n\n# # Configure logging\n# logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')\n\n# class CFG:\n#     data_root = '/kaggle/input/birdclef-2025'\n#     train_audio = f'{data_root}/train_audio'\n#     train_csv = f'{data_root}/train.csv'\n#     taxonomy_csv = f'{data_root}/taxonomy.csv'\n#     output_dir = '/kaggle/working/checkpoints'\n#     model_path = '/kaggle/input/regnrty008/pytorch/default/1'\n    \n#     FS = 32000\n#     WINDOW_SIZE = 5\n#     N_FFT = 1024\n#     HOP_LENGTH = 512\n#     N_MELS = 128\n#     FMIN = 50\n#     FMAX = 14000\n#     TARGET_SHAPE = (256, 256)\n    \n#     model_name = 'regnety_008'\n#     in_channels = 1\n#     device = 'cuda' if torch.cuda.is_available() else 'cpu'\n    \n#     n_folds = 5\n#     selected_folds = [0, 1]\n#     epochs = 10\n#     batch_size = 32\n#     num_workers = 0\n#     lr = 1e-4\n#     weight_decay = 1e-5\n#     early_stopping_patience = 3\n#     seed = 42\n#     aug_prob = 0.5\n\n# def set_seed(seed):\n#     torch.manual_seed(seed)\n#     torch.cuda.manual_seed_all(seed)\n#     np.random.seed(seed)\n#     torch.backends.cudnn.deterministic = True\n#     torch.backends.cudnn.benchmark = False\n\n# set_seed(CFG.seed)\n\n# class BirdCLEFDataset(Dataset):\n#     def __init__(self, df, cfg, mode='train'):\n#         self.df = df\n#         self.cfg = cfg\n#         self.mode = mode\n#         self.audio_paths = [os.path.join(self.cfg.train_audio, fname) for fname in df['filename']]\n#         self.labels = self.create_labels(df)\n    \n#     def create_labels(self, df):\n#         species = pd.read_csv(self.cfg.taxonomy_csv)['primary_label'].tolist()\n#         num_classes = len(species)\n#         labels = np.zeros((len(df), num_classes), dtype=np.float32)\n#         for idx, row in df.iterrows():\n#             primary_label = row['primary_label']\n#             label_idx = species.index(primary_label)\n#             labels[idx, label_idx] = 1.0\n#         return labels\n    \n#     def __len__(self):\n#         return len(self.df)\n    \n#     def audio2melspec(self, audio_data):\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=self.cfg.FS,\n#             n_fft=self.cfg.N_FFT,\n#             hop_length=self.cfg.HOP_LENGTH,\n#             n_mels=self.cfg.N_MELS,\n#             fmin=self.cfg.FMIN,\n#             fmax=self.cfg.FMAX,\n#             power=2.0\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#         return mel_spec_norm\n    \n#     def spec_augment(self, mel_spec):\n#         if self.mode != 'train' or np.random.rand() > self.cfg.aug_prob:\n#             return mel_spec\n#         max_time_mask = int(mel_spec.shape[1] * 0.1)\n#         time_mask = np.random.randint(0, max(1, mel_spec.shape[1] - max_time_mask))\n#         mel_spec[:, time_mask:time_mask + max_time_mask] = 0\n#         max_freq_mask = int(mel_spec.shape[0] * 0.1)\n#         freq_mask = np.random.randint(0, max(1, mel_spec.shape[0] - max_freq_mask))\n#         mel_spec[freq_mask:freq_mask + max_freq_mask, :] = 0\n#         return mel_spec\n    \n#     def __getitem__(self, idx):\n#         try:\n#             audio_data, _ = librosa.load(self.audio_paths[idx], sr=self.cfg.FS)\n#             target_samples = self.cfg.FS * self.cfg.WINDOW_SIZE\n#             if len(audio_data) < target_samples:\n#                 audio_data = np.pad(audio_data, (0, target_samples - len(audio_data)), mode='constant')\n#             else:\n#                 start_idx = np.random.randint(0, max(1, len(audio_data) - target_samples))\n#                 audio_data = audio_data[start_idx:start_idx + target_samples]\n            \n#             mel_spec = self.audio2melspec(audio_data)\n#             mel_spec = self.spec_augment(mel_spec)\n#             if mel_spec.shape != self.cfg.TARGET_SHAPE:\n#                 mel_spec = cv2.resize(mel_spec, self.cfg.TARGET_SHAPE, interpolation=cv2.INTER_LINEAR)\n            \n#             mel_spec = mel_spec.astype(np.float32)\n#             mel_spec = torch.tensor(mel_spec).unsqueeze(0)\n#             label = torch.tensor(self.labels[idx], dtype=torch.float32)\n#             return mel_spec, label\n#         except Exception as e:\n#             logging.error(f\"Error loading sample {idx}: {e}\")\n#             mel_spec = np.zeros(self.cfg.TARGET_SHAPE, dtype=np.float32)\n#             mel_spec = cv2.resize(mel_spec, self.cfg.TARGET_SHAPE, interpolation=cv2.INTER_LINEAR)\n#             mel_spec = torch.tensor(mel_spec).unsqueeze(0)\n#             label = torch.zeros(len(self.labels[0]), dtype=torch.float32)\n#             return mel_spec, label\n\n# class BirdCLEFModel(nn.Module):\n#     def __init__(self, cfg, num_classes):\n#         super().__init__()\n#         self.cfg = cfg\n#         self.backbone = timm.create_model(\n#             cfg.model_name,\n#             pretrained=True,\n#             in_chans=cfg.in_channels,\n#             drop_rate=0.3,\n#             drop_path_rate=0.2\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#         if isinstance(features, dict):\n#             features = features['features']\n#         if len(features.shape) == 4:\n#             features = self.pooling(features)\n#             features = features.view(features.size(0), -1)\n#         logits = self.classifier(features)\n#         return logits\n\n# def train_epoch(model, loader, criterion, optimizer, scaler, device):\n#     model.train()\n#     total_loss = 0\n#     for batch_idx, (spectrograms, labels) in enumerate(tqdm(loader, desc=\"Training\")):\n#         spectrograms, labels = spectrograms.to(device), labels.to(device)\n#         optimizer.zero_grad()\n#         with autocast():\n#             outputs = model(spectrograms)\n#             loss = criterion(outputs, labels)\n#         scaler.scale(loss).backward()\n#         scaler.step(optimizer)\n#         scaler.update()\n#         total_loss += loss.item()\n#     return total_loss / len(loader)\n\n# def validate_epoch(model, loader, criterion, device):\n#     model.eval()\n#     total_loss = 0\n#     all_preds, all_labels = [], []\n#     with torch.no_grad():\n#         for spectrograms, labels in tqdm(loader, desc=\"Validating\"):\n#             spectrograms, labels = spectrograms.to(device), labels.to(device)\n#             outputs = model(spectrograms)\n#             loss = criterion(outputs, labels)\n#             total_loss += loss.item()\n#             probs = torch.sigmoid(outputs).cpu().numpy()\n#             all_preds.append(probs)\n#             all_labels.append(labels.cpu().numpy())\n#     all_preds = np.concatenate(all_preds)\n#     all_labels = np.concatenate(all_labels)\n#     mAP = average_precision_score(all_labels, all_preds, average='macro')\n#     return total_loss / len(loader), mAP\n\n# def save_checkpoint(model, optimizer, epoch, fold, val_mAP, path):\n#     torch.save({\n#         'model_state_dict': model.state_dict(),\n#         'optimizer_state_dict': optimizer.state_dict(),\n#         'epoch': epoch,\n#         'fold': fold,\n#         'val_mAP': val_mAP\n#     }, path)\n#     logging.info(f\"Saved checkpoint for fold {fold} at epoch {epoch}\")\n\n# def train_model(cfg):\n#     os.makedirs(cfg.output_dir, exist_ok=True)\n#     train_df = pd.read_csv(cfg.train_csv)\n#     species = pd.read_csv(cfg.taxonomy_csv)['primary_label'].tolist()\n#     num_classes = len(species)\n    \n#     kf = KFold(n_splits=cfg.n_folds, shuffle=True, random_state=cfg.seed)\n#     for fold, (train_idx, val_idx) in enumerate(kf.split(train_df)):\n#         if fold not in cfg.selected_folds:\n#             continue\n        \n#         logging.info(f\"Training fold {fold}\")\n#         train_subset = train_df.iloc[train_idx].reset_index(drop=True)\n#         val_subset = train_df.iloc[val_idx].reset_index(drop=True)\n        \n#         train_dataset = BirdCLEFDataset(train_subset, cfg, mode='train')\n#         val_dataset = BirdCLEFDataset(val_subset, cfg, mode='val')\n        \n#         train_loader = DataLoader(\n#             train_dataset,\n#             batch_size=cfg.batch_size,\n#             shuffle=True,\n#             num_workers=0,\n#             pin_memory=True\n#         )\n#         val_loader = DataLoader(\n#             val_dataset,\n#             batch_size=cfg.batch_size,\n#             shuffle=False,\n#             num_workers=0,\n#             pin_memory=True\n#         )\n        \n#         model = BirdCLEFModel(cfg, num_classes).to(cfg.device)\n#         criterion = nn.BCEWithLogitsLoss()\n#         optimizer = optim.AdamW(model.parameters(), lr=cfg.lr, weight_decay=cfg.weight_decay)\n#         scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=cfg.epochs)\n#         scaler = GradScaler()\n        \n#         best_mAP = 0\n#         epochs_without_improvement = 0\n        \n#         try:\n#             for epoch in range(cfg.epochs):\n#                 train_loss = train_epoch(model, train_loader, criterion, optimizer, scaler, cfg.device)\n#                 val_loss, val_mAP = validate_epoch(model, val_loader, criterion, cfg.device)\n                \n#                 logging.info(f\"Fold {fold} Epoch {epoch+1}/{cfg.epochs} | Train Loss: {train_loss:.4f} | Val Loss: {val_loss:.4f} | Val mAP: {val_mAP:.4f}\")\n                \n#                 if val_mAP > best_mAP:\n#                     best_mAP = val_mAP\n#                     epochs_without_improvement = 0\n#                     save_checkpoint(model, optimizer, epoch, fold, val_mAP, os.path.join(cfg.output_dir, f'fold{fold}_best.pth'))\n#                 else:\n#                     epochs_without_improvement += 1\n                \n#                 scheduler.step()\n                \n#                 if epochs_without_improvement >= cfg.early_stopping_patience:\n#                     logging.info(f\"Early stopping triggered for fold {fold} after epoch {epoch+1}\")\n#                     break\n#         finally:\n#             del train_loader, val_loader\n#             gc.collect()\n#             torch.cuda.empty_cache()\n        \n#         save_checkpoint(model, optimizer, cfg.epochs, fold, best_mAP, os.path.join(cfg.output_dir, f'fold{fold}_final.pth'))\n\n# if __name__ == \"__main__\":\n#     cfg = CFG()\n#     train_model(cfg)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-04-14T08:11:08.797733Z","iopub.execute_input":"2025-04-14T08:11:08.798439Z","execution_failed":"2025-04-14T11:28:29.667Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import os\n# import psutil\n# print(f\"Available CPU cores: {os.cpu_count()}\")\n# mem = psutil.virtual_memory()\n# print(f\"Memory usage: {mem.percent}%\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-14T08:04:47.832709Z","iopub.execute_input":"2025-04-14T08:04:47.832903Z","iopub.status.idle":"2025-04-14T08:04:47.840945Z","shell.execute_reply.started":"2025-04-14T08:04:47.832885Z","shell.execute_reply":"2025-04-14T08:04:47.840062Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}