{"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":"gpu","dataSources":[{"sourceId":91844,"databundleVersionId":11361821,"sourceType":"competition"},{"sourceId":15853,"sourceType":"modelInstanceVersion","modelInstanceId":2739,"modelId":319}],"dockerImageVersionId":30919,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"Adapted from [Google Bird Model: Embeddings/Predict/Score](https://www.kaggle.com/code/robbynevels/bc24-google-bird-model-embeddings-predict-score?kernelSessionId=172204890)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2025-03-14T02:59:56.090034Z","iopub.execute_input":"2025-03-14T02:59:56.090423Z","iopub.status.idle":"2025-03-14T02:59:56.094624Z","shell.execute_reply.started":"2025-03-14T02:59:56.090394Z","shell.execute_reply":"2025-03-14T02:59:56.093721Z"}}},{"cell_type":"code","source":"import pandas as pd\nfrom pathlib import Path\nfrom tqdm import tqdm\nimport numpy as np\nimport os\n\nimport tensorflow_hub as hub\nimport tensorflow as tf\n\nimport torchaudio\nimport torch\nfrom torch.utils.data import DataLoader, Dataset, SequentialSampler\n\n\ndf = pd.read_csv('/kaggle/input/birdclef-2025/train.csv')\nAUDIO_PATH = Path('/kaggle/input/birdclef-2025/train_audio')\nSOUNDSCAPE_PATH = Path('/kaggle/input/birdclef-2025/train_soundscapes')\nmodel_path = 'https://kaggle.com/models/google/bird-vocalization-classifier/frameworks/TensorFlow2/variations/bird-vocalization-classifier/versions/8'\nmodel = hub.load(model_path)\nmodel_labels_df = pd.read_csv(hub.resolve(model_path) + \"/assets/label.csv\")\n\nSAMPLE_RATE = 32000\nWINDOW = 5*SAMPLE_RATE","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-21T13:34:11.104516Z","iopub.execute_input":"2025-03-21T13:34:11.104761Z","iopub.status.idle":"2025-03-21T13:34:33.876208Z","shell.execute_reply.started":"2025-03-21T13:34:11.104738Z","shell.execute_reply":"2025-03-21T13:34:33.875508Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"index_to_label = sorted(df.primary_label.unique())\nlabel_to_index = {v: k for k, v in enumerate(index_to_label)}\nmodel_labels = {v: k for k, v in enumerate(model_labels_df.ebird2021)}\nmodel_bc_indexes = [model_labels[label] if label in model_labels else -1 for label in index_to_label]\n\n# filter out birds that the model doesn't predict\nmissing_birds = set(np.array(index_to_label)[np.array(model_bc_indexes) == -1])\nlen(missing_birds)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-21T13:34:33.877052Z","iopub.execute_input":"2025-03-21T13:34:33.877253Z","iopub.status.idle":"2025-03-21T13:34:33.901660Z","shell.execute_reply.started":"2025-03-21T13:34:33.877236Z","shell.execute_reply":"2025-03-21T13:34:33.900964Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# use a torch dataloader to decode audio in parallel on CPU while GPU is running\nclass SoundScapeDataset(Dataset):\n    def __init__(self):\n        self.path = SOUNDSCAPE_PATH\n        self.files = [f for f in os.listdir(self.path) if f.endswith('.ogg')]\n    def __len__(self):\n        return len(self.files)\n    def __getitem__(self, i):\n        try:\n            file_path = os.path.join(self.path, self.files[i])\n            audio, sr = torchaudio.load(file_path)\n            return audio[0], self.files[i]\n        except Exception as e:\n            print(f\"Error loading {self.files[i]}: {str(e)}\")\n            return torch.zeros(1, 16000), \"error_file\"  # 返回空数据\ndataloader = DataLoader(\n    SoundScapeDataset(),\n    batch_size=1,\n    # sampler=SequentialSampler(range(10)),\n    num_workers=os.cpu_count()\n)\n\n# embeddings are formated like {\"filename\": np.array(nx1280)} \n# (where n = the number of non overlapping 5 sec chunks in the audio)\nall_embeddings = {}\n\n# predictiones formated like {\"filename\": np.array(nx264)} \nall_predictions = {}\n\nwith tf.device('/gpu:0'):\n    for audio, filename in tqdm(dataloader):\n        audio = audio[0]\n        filename = filename[0]\n        file_embeddings = []\n        file_predictions = []\n        for i in range(0, len(audio), WINDOW):\n            clip = audio[i:i+WINDOW]\n            if len(clip) < WINDOW:\n                clip = np.concatenate([clip, np.zeros(WINDOW - len(clip))])\n            result = model.infer_tf(clip[np.newaxis, :])\n            file_embeddings.append(result['embedding'].numpy())\n            prediction = np.concatenate([result['label'].numpy(), -100], axis=None) # add -100 logit for unpredicted birds\n            file_predictions.append(prediction[model_bc_indexes])\n        all_embeddings[filename] = np.stack(file_embeddings)\n        all_predictions[filename] = np.stack(file_predictions)\n\ntorch.save(all_embeddings, 'train_soundscape_embeddings.pt')\ntorch.save(all_predictions, 'train_soundscape_predictions.pt')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-21T13:34:33.902343Z","iopub.execute_input":"2025-03-21T13:34:33.902600Z","iopub.status.idle":"2025-03-21T13:34:42.294641Z","shell.execute_reply.started":"2025-03-21T13:34:33.902579Z","shell.execute_reply":"2025-03-21T13:34:42.293818Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# use a torch dataloader to decode audio in parallel on CPU while GPU is running\nclass AudioDataset(Dataset):\n    def __len__(self):\n        return len(df)\n    def __getitem__(self, i):\n        filename = df.filename[i]\n        audio = torchaudio.load(AUDIO_PATH / filename)[0].numpy()[0]\n        return audio, filename\ndataloader = DataLoader(\n    AudioDataset(),\n    batch_size=1,\n    # sampler=SequentialSampler(range(10)),\n    num_workers=os.cpu_count()\n)\n\n# embeddings are formated like {\"filename\": np.array(nx1280)} \n# (where n = the number of non overlapping 5 sec chunks in the audio)\nall_embeddings = {}\n\n# predictiones formated like {\"filename\": np.array(nx264)} \nall_predictions = {}\n\nwith tf.device('/gpu:0'):\n    for audio, filename in tqdm(dataloader):\n        audio = audio[0]\n        filename = filename[0]\n        file_embeddings = []\n        file_predictions = []\n        for i in range(0, len(audio), WINDOW):\n            clip = audio[i:i+WINDOW]\n            if len(clip) < WINDOW:\n                clip = np.concatenate([clip, np.zeros(WINDOW - len(clip))])\n            result = model.infer_tf(clip[np.newaxis, :])\n            file_embeddings.append(result['embedding'].numpy())\n            prediction = np.concatenate([result['label'].numpy(), -100], axis=None) # add -100 logit for unpredicted birds\n            file_predictions.append(prediction[model_bc_indexes])\n        all_embeddings[filename] = np.stack(file_embeddings)\n        all_predictions[filename] = np.stack(file_predictions)\n\ntorch.save(all_embeddings, 'train_audio_embeddings.pt')\ntorch.save(all_predictions, 'train_audio_predictions.pt')","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}