{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","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":11075449,"sourceType":"datasetVersion","datasetId":6902504},{"sourceId":238265967,"sourceType":"kernelVersion"}],"dockerImageVersionId":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 2025.5.6： 生成梅尔频谱图的pkl\n","metadata":{}},{"cell_type":"code","source":"import os\nimport cv2\nimport math\nimport time\nimport librosa\nimport pandas as pd\nimport numpy as np\nfrom tqdm.notebook import tqdm\nimport warnings\nimport gc\nimport pickle\nimport logging\nfrom pathlib import Path\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport timm\n\nlogging.basicConfig(level=logging.ERROR)\nwarnings.filterwarnings(\"ignore\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T06:59:44.937834Z","iopub.execute_input":"2025-05-06T06:59:44.938385Z","iopub.status.idle":"2025-05-06T06:59:44.944212Z","shell.execute_reply.started":"2025-05-06T06:59:44.938346Z","shell.execute_reply":"2025-05-06T06:59:44.943203Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CFG:\n    DEBUG_MODE = False\n    OUTPUT_DIR = '/kaggle/working/'\n    DATA_ROOT = '/kaggle/input/birdclef-2025'\n    audio_datadir = '/kaggle/input/birdclef-2025/train_audio'\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\n\n\n    # Audio parameters\n    FS = 32000  \n    N_FFT = 1024\n    HOP_LENGTH = 512\n    N_MELS = 128\n    FMIN = 50\n    FMAX = 16000\n\n    TARGET_DURATION = 5.0\n    TARGET_SHAPE = (256,256)  \n\n\n    \n    \n    in_channels = 1\n    device = 'cpu'  \n    \n    # Inference parameters\n    batch_size = 16\n\n    \n    use_specific_folds = False  # If False, use all found models\n    folds = [0,1,2,3]  # Used only if use_specific_folds is True\n    \n    debug = False\n    debug_count = 3\n    N_MAX = 20 if DEBUG_MODE else None  \n\ncfg = CFG()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T06:59:44.945589Z","iopub.execute_input":"2025-05-06T06:59:44.945912Z","iopub.status.idle":"2025-05-06T06:59:44.960887Z","shell.execute_reply.started":"2025-05-06T06:59:44.945887Z","shell.execute_reply":"2025-05-06T06:59:44.959899Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f\"Using device: {cfg.device}\")\nprint(f\"Loading taxonomy data...\")\ntaxonomy_df = pd.read_csv(cfg.taxonomy_csv)\nspecies_ids = taxonomy_df['primary_label'].tolist()\nnum_classes = len(species_ids)\nprint(f\"Number of classes: {num_classes}\")\n\nlabel_to_idx = {label: idx for idx, label in enumerate(species_ids)}\nspecies_class_map = dict(zip(taxonomy_df['primary_label'], taxonomy_df['class_name']))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T06:59:44.962635Z","iopub.execute_input":"2025-05-06T06:59:44.962982Z","iopub.status.idle":"2025-05-06T06:59:44.98614Z","shell.execute_reply.started":"2025-05-06T06:59:44.962948Z","shell.execute_reply":"2025-05-06T06:59:44.98486Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"'''\n压缩动态范围： 分贝值可以压缩能量值的动态范围，使得信号的细节更加明显。\n归一化： 归一化可以将所有值都缩放到 0 到 1 的范围内，这可以提高模型的训练效果，并减少梯度消失或爆炸的问题。\n'''\n\ndef audio2melspec(audio_data):\n    '''音频数据转换为归一化的梅尔频谱图'''\n    '''插值方法是否可以更改？？'''\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        pad_mode=\"reflect\",\n        norm='slaney',\n        htk=True,\n        center=True\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","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T06:59:44.987626Z","iopub.execute_input":"2025-05-06T06:59:44.988032Z","iopub.status.idle":"2025-05-06T06:59:44.994306Z","shell.execute_reply.started":"2025-05-06T06:59:44.987995Z","shell.execute_reply":"2025-05-06T06:59:44.993362Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def make_work_df():\n    '''\n    创建类别标签到ID的映射（Label Mapping）\n    构建工作 DataFrame (Working DF)，包含必要的训练信息\n\n    '''\n    train_csv_path = f'{cfg.DATA_ROOT}/train.csv'\n    train_df=pd.read_csv(train_csv_path)\n\n    label_list = sorted(train_df['primary_label'].unique())\n    print(f'found {len(label_list)} unique species')    #train.csv中有206个类别\n    #创建work_df   包含列名：primary_label，filename，class_name\n    \n    working_df = train_df[['primary_label','secondary_labels','filename']].copy()\n    working_df['filepath'] = cfg.audio_datadir + '/' + working_df.filename\n    \n    working_df[\"class_name\"] = train_df['primary_label'].apply(lambda x : species_class_map.get(x))\n\n    working_df['samplename'] = working_df['filename'].map(lambda x: x.split('/')[0] + '-' + x.split('/')[-1].split('.')[0])\n    return  working_df\n\nworking_df = make_work_df()\n\nworking_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T06:59:44.995272Z","iopub.execute_input":"2025-05-06T06:59:44.995614Z","iopub.status.idle":"2025-05-06T06:59:45.197373Z","shell.execute_reply.started":"2025-05-06T06:59:44.995582Z","shell.execute_reply":"2025-05-06T06:59:45.196349Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Starting audio processing...\")\nstart_time = time.time()\n\nall_bird_data = {}\nerrors = []\n\nfor i, row in tqdm(working_df.iterrows(), total=working_df.shape[0]):\n    if cfg.N_MAX is not None and i >= cfg.N_MAX:\n        break\n    \n    try:\n        audio_data, _ = librosa.load(row.filepath, sr=cfg.FS)\n\n        target_samples = int(cfg.TARGET_DURATION * cfg.FS)\n        # 目标音频时长\n\n        if len(audio_data) < target_samples:\n            n_copy = math.ceil(target_samples / len(audio_data))\n            if n_copy > 1:\n                audio_data = np.concatenate([audio_data] * n_copy)\n\n        start_idx = max(0, int(len(audio_data) / 2 - target_samples / 2))\n        #从中间取五秒\n        \n        end_idx = min(len(audio_data), start_idx + target_samples)\n        center_audio = audio_data[start_idx:end_idx]\n\n        if len(center_audio) < target_samples:\n            center_audio = np.pad(center_audio, \n                                 (0, target_samples - len(center_audio)), \n                                 mode='constant')\n\n        mel_spec = audio2melspec(center_audio)\n\n        if mel_spec.shape != cfg.TARGET_SHAPE:\n            mel_spec = cv2.resize(mel_spec, cfg.TARGET_SHAPE, interpolation=cv2.INTER_CUBIC)  \n            #通过cv2 resize进行缩放，使用双三次插值\n\n        all_bird_data[row.samplename] = mel_spec.astype(np.float32)\n        \n    except Exception as e:\n        print(f\"Error processing {row.filepath}: {e}\")\n        errors.append((row.filepath, str(e)))\n\nend_time = time.time()\nprint(f\"Processing completed in {end_time - start_time:.2f} seconds\")\nprint(f\"Successfully processed {len(all_bird_data)}\")\nprint(f\"Failed to process {len(errors)} files\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T06:59:45.198519Z","iopub.execute_input":"2025-05-06T06:59:45.198888Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pkl_name = \"likely_best_audio.pkl\"\n\npath = os.path.join(\"/kaggle/working/\",pkl_name)\nwith open(path, \"wb\") as f:\n    pickle.dump(all_bird_data, f)\n    print(\"Save %s.\" % path)","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":"# new_audio_data","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":"   # if not cfg.LOAD_DATA:\n   #      print(\"run_training：Will generate spectrograms on-the-fly during training.\")\n   #      if 'filepath' not in df.columns:\n   #          df['filepath'] = cfg.train_datadir + '/' + df.filename\n   #      if 'samplename' not in df.columns:\n   #          df['samplename'] = df.filename.map(lambda x: x.split('/')[0] + '-' + x.split('/')[-1].split('.')[0])\n\n\n   # self.primary_to_class = dict(zip(taxonomy_df['primary_label'],taxonomy_df['class_name']))\n\n\n\n\n   #      if 'samplename' not in self.df.columns:\n   #          self.df['samplename'] = self.df.filename.map(lambda x: x.split('/')[0] + '-' + x.split('/')[-1].split('.')[0])\n\n   #      sample_names = set(self.df['samplename'])","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}