{"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":11772766,"sourceType":"datasetVersion","datasetId":7391251},{"sourceId":386646,"sourceType":"modelInstanceVersion","isSourceIdPinned":false,"modelInstanceId":318802,"modelId":339376}],"dockerImageVersionId":31012,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## 🐦 1. Introduction\n\nBirdCLEF 2025 is an audio classification competition where the goal is to identify bird species based on their vocalizations.\n\nThis notebook builds a complete starter pipeline: from audio preprocessing to submission.\n\nKey preprocessing step: **converting raw audio (.ogg) files into Mel-spectrogram images**, which can then be used for CNN-based classification models.\n","metadata":{}},{"cell_type":"markdown","source":"## 2. Library importation and Data Overview","metadata":{}},{"cell_type":"code","source":"# Comment modules import\nimport os\nimport numpy as np\nimport pandas as pd\nfrom pathlib import Path\nimport io\nimport sys\n\n# Display import\n# from IPython.display import Image, display\nfrom PIL import Image\nimport random","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.354140Z","iopub.execute_input":"2025-05-12T03:35:59.354535Z","iopub.status.idle":"2025-05-12T03:35:59.361272Z","shell.execute_reply.started":"2025-05-12T03:35:59.354509Z","shell.execute_reply":"2025-05-12T03:35:59.359799Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Mel-Spectrogram processing import\nimport librosa\nimport librosa.display\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.363234Z","iopub.execute_input":"2025-05-12T03:35:59.363570Z","iopub.status.idle":"2025-05-12T03:35:59.390255Z","shell.execute_reply.started":"2025-05-12T03:35:59.363545Z","shell.execute_reply":"2025-05-12T03:35:59.388781Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Model import\nimport torch\nimport torch\nimport torch.nn as nn\nimport torchvision.transforms as transforms\nfrom torchvision import models\nfrom torch.utils.data import Dataset, DataLoader","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.391668Z","iopub.execute_input":"2025-05-12T03:35:59.392026Z","iopub.status.idle":"2025-05-12T03:35:59.419088Z","shell.execute_reply.started":"2025-05-12T03:35:59.392000Z","shell.execute_reply":"2025-05-12T03:35:59.417851Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Label encoding\nfrom sklearn.preprocessing import LabelEncoder","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.421473Z","iopub.execute_input":"2025-05-12T03:35:59.421846Z","iopub.status.idle":"2025-05-12T03:35:59.454867Z","shell.execute_reply.started":"2025-05-12T03:35:59.421819Z","shell.execute_reply":"2025-05-12T03:35:59.453720Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Gabage collector for optimizing memories\nimport gc","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.456104Z","iopub.execute_input":"2025-05-12T03:35:59.456394Z","iopub.status.idle":"2025-05-12T03:35:59.486212Z","shell.execute_reply.started":"2025-05-12T03:35:59.456372Z","shell.execute_reply":"2025-05-12T03:35:59.485054Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import warnings\nimport logging\nwarnings.filterwarnings(\"ignore\")\nlogging.basicConfig(level=logging.ERROR)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.487603Z","iopub.execute_input":"2025-05-12T03:35:59.488016Z","iopub.status.idle":"2025-05-12T03:35:59.510835Z","shell.execute_reply.started":"2025-05-12T03:35:59.487983Z","shell.execute_reply":"2025-05-12T03:35:59.509667Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# input_dir = '/kaggle/input/birdclef-2025/train_audio'\n\n# print(\"Folders in train_audio:\", os.listdir(input_dir)[:5])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.512075Z","iopub.execute_input":"2025-05-12T03:35:59.512383Z","iopub.status.idle":"2025-05-12T03:35:59.538105Z","shell.execute_reply.started":"2025-05-12T03:35:59.512357Z","shell.execute_reply":"2025-05-12T03:35:59.536541Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 🎧 3. Convert Audio to Spectrogram (Pre-trained)\n\nTo generate spectrograms, we use:\n- `librosa` to load and compute Mel-spectrograms\n- `matplotlib` to render and save the images\n- `os.walk()` to recursively gather all files\n- `tqdm` for progress tracking\n\nEach spectrogram is saved as a 256×256 `.png` file.  \nWe've added safety features like `try/except` error handling and `os.path.exists()` checks to prevent reprocessing and memory overflows.\n","metadata":{}},{"cell_type":"code","source":"# def audio_to_melspectrogram(file_path, save_path):\n#     try:\n#         y, sr = librosa.load(file_path, sr=None)\n#         S = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=128)\n#         S_DB = librosa.power_to_db(S, ref=np.max)\n\n#         plt.figure(figsize=(2.56, 2.56), dpi=100)\n#         librosa.display.specshow(S_DB, sr=sr, cmap='magma')\n#         plt.axis('off')\n#         plt.tight_layout(pad=0)\n#         plt.savefig(save_path, bbox_inches='tight', pad_inches=0)\n#         plt.close()\n#     except Exception as e:\n#         print(f\"⚠️ Error on {file_path}: {e}\")\n\n# # Limit number of files to avoid long runtime (e.g., for Starter demonstration)\n# file_list = []\n# for root, _, files in os.walk(input_dir):\n#     for file in files:\n#         if file.endswith('.ogg'):\n#             full_path = os.path.join(root, file)\n#             file_list.append(full_path)\n\n# # Only use first 50 files for demo purposes\n# file_list = file_list[21000:22000]\n# print(f\"Number of files used for conversion: {len(file_list)}\")\n\n# output_dir = '/kaggle/working/train_images'\n# os.makedirs(output_dir, exist_ok=True)\n\n# for input_path in tqdm(file_list):\n#     base_name = os.path.basename(input_path).replace('.ogg', '.png')\n#     output_path = os.path.join(output_dir, base_name)\n#     if not os.path.exists(output_path):\n#         audio_to_melspectrogram(input_path, output_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.539528Z","iopub.execute_input":"2025-05-12T03:35:59.539862Z","iopub.status.idle":"2025-05-12T03:35:59.567232Z","shell.execute_reply.started":"2025-05-12T03:35:59.539837Z","shell.execute_reply":"2025-05-12T03:35:59.565485Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 🖼 4. Example Spectrogram\n\nBelow is a sample Mel-spectrogram generated from one of the training `.ogg` files:\n\n- Format: 256 × 256 pixels\n- Color map: `magma` (helps highlight low-amplitude sound patterns)\n- Horizontal axis = time, vertical axis = frequency\n- Bright areas indicate higher energy\n\nThese images can now be used as input to CNN models for classification.","metadata":{}},{"cell_type":"code","source":"# image_folder = '/kaggle/input/processed-audio-file/train_images'\n# image_files = os.listdir(image_folder)\n# sample_image_path = os.path.join(image_folder, image_files[0])  \n# display(Image(filename=sample_image_path))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.568278Z","iopub.execute_input":"2025-05-12T03:35:59.568571Z","iopub.status.idle":"2025-05-12T03:35:59.603820Z","shell.execute_reply.started":"2025-05-12T03:35:59.568549Z","shell.execute_reply":"2025-05-12T03:35:59.602373Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 🧠 5. CNN Model Training \nNow that we have spectrogram images, we can train a simple CNN model using PyTorch.\n","metadata":{}},{"cell_type":"code","source":"taxonomy_path = '/kaggle/input/birdclef-2025/taxonomy.csv'\ntaxonomy_df = pd.read_csv(taxonomy_path)\nspecies_ids = taxonomy_df['primary_label'].tolist()\n# labels = taxonomy_df['primary_label'].tolist()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.608392Z","iopub.execute_input":"2025-05-12T03:35:59.608835Z","iopub.status.idle":"2025-05-12T03:35:59.641404Z","shell.execute_reply.started":"2025-05-12T03:35:59.608789Z","shell.execute_reply":"2025-05-12T03:35:59.640119Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# encoder = LabelEncoder()\n# encoded_labels = encoder.fit_transform(labels)\n\n# for idx in encoded_labels:\n#     encoded_labels\n# print(\"Encoded Labels:\", encoded_labels)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.642844Z","iopub.execute_input":"2025-05-12T03:35:59.643315Z","iopub.status.idle":"2025-05-12T03:35:59.650059Z","shell.execute_reply.started":"2025-05-12T03:35:59.643277Z","shell.execute_reply":"2025-05-12T03:35:59.649043Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Set up a basic transform\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.0, 0.0, 0.0], std=[1.0, 1.0, 1.0]),\n    transforms.Lambda(lambda x: torch.clamp(x, min=0.0)),\n    transforms.Lambda(lambda x: torch.clamp(x, max=1.0))\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.651334Z","iopub.execute_input":"2025-05-12T03:35:59.651707Z","iopub.status.idle":"2025-05-12T03:35:59.680188Z","shell.execute_reply.started":"2025-05-12T03:35:59.651677Z","shell.execute_reply":"2025-05-12T03:35:59.678828Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Define a dummy dataset using 10 random images\n# class SpectrogramDataset(Dataset):\n#     def __init__(self, image_dir, transform=None):\n#         self.image_dir = image_dir\n#         self.image_files = os.listdir(image_dir)\n#         # self.image_files = random.sample(self.image_files,1000)  # select 10 files\n#         self.transform = transform\n\n#     def __len__(self):\n#         return len(self.image_files)\n\n#     def __getitem__(self, idx):\n#         img_path = os.path.join(self.image_dir, self.image_files[idx])\n#         image = Image.open(img_path).convert(\"RGB\")\n\n#         index = 0\n#         if self.transform:\n#             image = self.transform(image)\n\n#         one_hot_tensor = torch.zeros(206)\n#         finder = self.image_files[idx].replace('.png', '.ogg')\n#         audio_folders_path = '/kaggle/input/birdclef-2025/train_audio'\n#         audio_folders = [f for f in os.listdir(audio_folders_path) if os.path.isdir(os.path.join(audio_folders_path, f))]\n#         for bird_id in audio_folders:\n#             bird_id_audio_path = audio_folders_path + \"/\" + bird_id\n#             file_list = [f for f in os.listdir(bird_id_audio_path) if os.path.isfile(os.path.join(bird_id_audio_path, f))]\n#             if finder in file_list:\n#                 index = list(encoder.classes_).index(bird_id)\n#                 break\n        \n#         one_hot_tensor[index] = 1.0\n#         label = one_hot_tensor \n#         return image, label\n\n# dataset = SpectrogramDataset('/kaggle/input/processed-audio-file/train_images', transform=transform)\n# dataloader = DataLoader(dataset, batch_size=4, shuffle=True)\n\n# # Load pretrained ResNet18 and modify the output layer\n# model = models.resnet18(weights=None)\n# model.fc = nn.Linear(model.fc.in_features, 206)\n\n# device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n# model.to(device)\n\n# # Define optimizer and loss\n# criterion = nn.BCEWithLogitsLoss()\n# optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.681388Z","iopub.execute_input":"2025-05-12T03:35:59.681737Z","iopub.status.idle":"2025-05-12T03:35:59.716158Z","shell.execute_reply.started":"2025-05-12T03:35:59.681707Z","shell.execute_reply":"2025-05-12T03:35:59.714468Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Training loop (100 epochs)\n# model.train()\n# for epoch in range(50):\n#     total_loss = 0.0\n#     for images, labels in dataloader:\n#         images, labels = images.to(device), labels.to(device)\n#         optimizer.zero_grad()\n#         outputs = model(images)\n#         loss = criterion(outputs, labels)\n#         loss.backward()\n#         optimizer.step()\n#         total_loss += loss.item()\n#     print(f\"Epoch {epoch+1}, Loss: {total_loss:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.717479Z","iopub.execute_input":"2025-05-12T03:35:59.717870Z","iopub.status.idle":"2025-05-12T03:35:59.747528Z","shell.execute_reply.started":"2025-05-12T03:35:59.717842Z","shell.execute_reply":"2025-05-12T03:35:59.746229Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# torch.save(model.state_dict(), 'model1.pth')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.748761Z","iopub.execute_input":"2025-05-12T03:35:59.749167Z","iopub.status.idle":"2025-05-12T03:35:59.780605Z","shell.execute_reply.started":"2025-05-12T03:35:59.749139Z","shell.execute_reply":"2025-05-12T03:35:59.779109Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 🧠 6. CNN Model loading\nNow that we have CNN models, we can apply and make inferences on Mel-spectrogram images in previously pretrain ","metadata":{}},{"cell_type":"code","source":"model = models.resnet18(weights=None)\nmodel.fc = nn.Linear(model.fc.in_features, 206)\nmodel.load_state_dict(torch.load('/kaggle/input/resnet18_001/pytorch/debug_model/1/model1.pth'))\nmodel.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:35:59.781972Z","iopub.execute_input":"2025-05-12T03:35:59.782469Z","iopub.status.idle":"2025-05-12T03:36:00.104817Z","shell.execute_reply.started":"2025-05-12T03:35:59.782432Z","shell.execute_reply":"2025-05-12T03:36:00.103671Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 🔮 7. Inference & Submission File Generation\n\nHere, we use our trained ResNet18 model to generate predictions for the submission file.\n","metadata":{}},{"cell_type":"code","source":"def predict_on_spectrogram(audio_path):\n    \"\"\"\n    Process a single audio file and predict species presence for each 5-second segment.\n    \n    :param audio_path: Path to the audio file.\n    :return: Tuple of (row_id, predictions) for each segment.\n    \"\"\"\n    FS = 32000  # Sampling frequency (32kHz)\n    WINDOW_SIZE = 5  # Window size (in seconds)\n    \n    predictions = []\n    row_ids = []\n    soundscape_id = Path(audio_path).stem\n    \n    try:\n        print(f\"Processing {soundscape_id}...\")\n        audio_data, sr = librosa.load(audio_path, sr=FS)\n\n        if len(audio_data) < FS * WINDOW_SIZE:\n            audio_data = np.pad(\n                audio_data,\n                (0, FS * WINDOW_SIZE - len(audio_data)),\n                mode='constant'\n            )\n        \n        segment_samples = int(WINDOW_SIZE * sr)\n        total_segments = int(len(audio_data) / (FS * WINDOW_SIZE))\n\n        \n        for segment_idx in range(total_segments):\n            start_sample = segment_idx * FS * WINDOW_SIZE\n            end_sample = start_sample + FS * WINDOW_SIZE\n            end_time_sec = (segment_idx + 1) * WINDOW_SIZE\n            row_id = f\"{soundscape_id}_{end_time_sec}\"\n            row_ids.append(row_id)\n            \n            segment_audio = audio_data[start_sample:end_sample]\n            S = librosa.feature.melspectrogram(y=segment_audio, sr=sr, n_mels=128, fmax=FS)\n            S_DB = librosa.power_to_db(S, ref=np.max)\n\n            plt.figure(figsize=(2.56, 2.56), dpi=20)\n            librosa.display.specshow(S_DB, sr=sr, cmap='magma')\n            plt.axis('off')\n            plt.tight_layout(pad=0)\n\n            buf = io.BytesIO()\n            plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0)\n            plt.close()\n            \n            buf.seek(0)\n            img = Image.open(buf).convert('RGB')\n            img_tensor = transform(img).unsqueeze(0).to('cpu')\n            img = None\n            buf.close()\n\n            S = None\n            S_DB = None\n            gc.collect()\n            \n            final_preds = []\n            # if len(models) == 1:\n            #     with torch.no_grad():\n            #         outputs = models[0](img_tensor)\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(img_tensor)\n            #             probs = torch.sigmoid(outputs).cpu().numpy().squeeze()\n            #             segment_preds.append(probs)\n            #     final_preds = np.mean(segment_preds, axis=0) \n            with torch.no_grad():\n                outputs = model(img_tensor)\n                final_preds = torch.sigmoid(outputs).cpu().numpy().squeeze()\n            predictions.append(final_preds)\n    except Exception as e:\n        print(f\"Error processing {audio_path}: {e}\")\n    \n    return row_ids, predictions","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:36:00.106113Z","iopub.execute_input":"2025-05-12T03:36:00.106391Z","iopub.status.idle":"2025-05-12T03:36:00.120957Z","shell.execute_reply.started":"2025-05-12T03:36:00.106371Z","shell.execute_reply":"2025-05-12T03:36:00.119626Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def run_inference():\n        \"\"\"\n        Perform inference on all test soundscape audio files.\n        \n        :return: Tuple of (row_ids, predictions) aggregated from all files.\n        \"\"\"\n        test_soundscapes_path = '/kaggle/input/birdclef-2025/test_soundscapes'\n        debug = '/kaggle/input/birdclef-2025/train_audio/65373'\n        test_files = list(Path(test_soundscapes_path).glob('*.ogg'))  # Get the test soundscape file\n        print(f\"Found {len(test_files)} test soundscape files.\")\n\n        all_row_ids = []\n        all_predictions = []\n\n        for audio_path in tqdm(test_files, disable = True):\n            row_ids, predictions = predict_on_spectrogram(str(audio_path))\n            all_row_ids.extend(row_ids)\n            all_predictions.extend(predictions)\n        \n        return all_row_ids, all_predictions\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:36:00.122247Z","iopub.execute_input":"2025-05-12T03:36:00.122557Z","iopub.status.idle":"2025-05-12T03:36:00.155593Z","shell.execute_reply.started":"2025-05-12T03:36:00.122536Z","shell.execute_reply":"2025-05-12T03:36:00.154393Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_submission(row_ids, predictions):\n        \"\"\"\n        Create a submission DataFrame based on prediction results.\n        \n        :param row_ids: List of row identifiers for each segment.\n        :param predictions: List of prediction arrays for each segment.\n        :return: Submission formatted pandas DataFrame.\n        \"\"\"\n        print(\"Creating submission DataFrame...\")\n        submission_dict = {'row_id': row_ids}\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        submission_df.set_index('row_id', inplace=True)\n\n        submission_csv_path = '/kaggle/input/birdclef-2025/sample_submission.csv'\n        sample_sub = pd.read_csv(submission_csv_path, index_col='row_id')\n        missing_cols = set(sample_sub.columns) - set(submission_df.columns)\n        if missing_cols:\n            print(f\"Warning: {len(missing_cols)} species are missing in the submission.\")\n            for col in missing_cols:\n                submission_df[col] = 0.0\n\n        submission_df = submission_df[sample_sub.columns]  # Align columns with the sample submission\n        submission_df = submission_df.reset_index()\n        \n        return submission_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:36:00.156846Z","iopub.execute_input":"2025-05-12T03:36:00.157211Z","iopub.status.idle":"2025-05-12T03:36:00.191162Z","shell.execute_reply.started":"2025-05-12T03:36:00.157185Z","shell.execute_reply":"2025-05-12T03:36:00.189679Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def smooth_submission(submission_path):\n    \"\"\"\n    Smooth the predictions in the submission file to maintain temporal consistency.\n    \n    :param submission_path: Path to the submission CSV file.\n    \"\"\"\n    print(\"Smoothing predictions in submission file...\")\n    sub = pd.read_csv(submission_path)\n    cols = sub.columns[1:]\n    # Extract group based on 'row_id'\n    groups = sub['row_id'].str.rsplit('_', n=1).str[0].values\n    unique_groups = np.unique(groups)\n    \n    for group in unique_groups:\n        idx = np.where(groups == group)[0]\n        sub_group = sub.iloc[idx].copy()\n        predictions = sub_group[cols].values\n        new_predictions = predictions.copy()\n        \n        if predictions.shape[0] > 1:\n            # Smooth by averaging predictions with adjacent segments\n            new_predictions[0] = (predictions[0] * 0.8) + (predictions[1] * 0.2)\n            new_predictions[-1] = (predictions[-1] * 0.8) + (predictions[-2] * 0.2)\n            for i in range(1, predictions.shape[0]-1):\n                new_predictions[i] = (predictions[i-1] * 0.2) + (predictions[i] * 0.6) + (predictions[i+1] * 0.2)\n        sub.iloc[idx, 1:] = new_predictions\n    \n    sub.to_csv(submission_path, index=False)\n    sub = None\n    gc.collect()\n    print(f\"Smoothed submission saved at {submission_path}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:36:00.192492Z","iopub.execute_input":"2025-05-12T03:36:00.193630Z","iopub.status.idle":"2025-05-12T03:36:00.238866Z","shell.execute_reply.started":"2025-05-12T03:36:00.193584Z","shell.execute_reply":"2025-05-12T03:36:00.237050Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"row_ids, predictions = run_inference()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:36:00.240363Z","iopub.execute_input":"2025-05-12T03:36:00.240980Z","iopub.status.idle":"2025-05-12T03:37:15.798151Z","shell.execute_reply.started":"2025-05-12T03:36:00.240942Z","shell.execute_reply":"2025-05-12T03:37:15.797019Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# print(row_ids)\n# print(predictions)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:37:15.799544Z","iopub.execute_input":"2025-05-12T03:37:15.799964Z","iopub.status.idle":"2025-05-12T03:37:15.805006Z","shell.execute_reply.started":"2025-05-12T03:37:15.799936Z","shell.execute_reply":"2025-05-12T03:37:15.803704Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission_df = create_submission(row_ids, predictions)\n\nsubmission_path = 'submission.csv'\nsubmission_df.to_csv(submission_path, index=False)\nsubmission_df = None\ngc.collect()\nsmooth_submission(submission_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:37:15.806175Z","iopub.execute_input":"2025-05-12T03:37:15.806512Z","iopub.status.idle":"2025-05-12T03:37:17.829275Z","shell.execute_reply.started":"2025-05-12T03:37:15.806487Z","shell.execute_reply":"2025-05-12T03:37:17.828042Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 📤 8. Submit This Notebook\n\nOnce `submission.csv` is saved to `/kaggle/working/`,  \nyou can click the **\"Submit\"** button at the right of this notebook to send your prediction to the leaderboard.\n","metadata":{}},{"cell_type":"code","source":"# import shutil\n\n# # Nén toàn bộ thư mục working thành file ZIP\n# shutil.make_archive('/kaggle/working/working_folder_backup', 'zip', '/kaggle/working')\n\n# print(\"Folder has been zipped. You can now download it.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:37:17.830630Z","iopub.execute_input":"2025-05-12T03:37:17.831007Z","iopub.status.idle":"2025-05-12T03:37:17.836860Z","shell.execute_reply.started":"2025-05-12T03:37:17.830975Z","shell.execute_reply":"2025-05-12T03:37:17.835340Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import os\n# import psutil\n# import numpy as np\n\n# def cpu_stats():\n#     pid = os.getpid()\n#     py = psutil.Process(pid)\n#     memory_use = py.memory_info()[0] / 2. ** 30  # Chuyển đổi sang GB\n#     return 'memory GB:' + str(np.round(memory_use, 2))\n\n# print(cpu_stats())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T03:37:17.838351Z","iopub.execute_input":"2025-05-12T03:37:17.838951Z","iopub.status.idle":"2025-05-12T03:37:17.868867Z","shell.execute_reply.started":"2025-05-12T03:37:17.838912Z","shell.execute_reply":"2025-05-12T03:37:17.867755Z"}},"outputs":[],"execution_count":null}]}