{"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":384417,"sourceType":"modelInstanceVersion","isSourceIdPinned":false,"modelInstanceId":317219,"modelId":337734},{"sourceId":384420,"sourceType":"modelInstanceVersion","isSourceIdPinned":false,"modelInstanceId":317222,"modelId":337737}],"dockerImageVersionId":31011,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch.nn as nn\nimport torchvision.models as models\n\nimport pytorch_lightning as pl\nfrom torchvision.models import regnet_y_400mf, RegNet_Y_400MF_Weights","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T02:46:55.216422Z","iopub.execute_input":"2025-05-10T02:46:55.216840Z","iopub.status.idle":"2025-05-10T02:47:14.152306Z","shell.execute_reply.started":"2025-05-10T02:46:55.216807Z","shell.execute_reply":"2025-05-10T02:47:14.151251Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# the efficientnet model\nclass BirdClassifier(nn.Module):\n    def __init__(self, backbone_name, num_classes, pretrained=True):\n        super(BirdClassifier, self).__init__()\n        \n        # Get the EfficientNet backbone\n        if backbone_name == \"efficientnet_b3\":\n            weights = models.EfficientNet_B3_Weights.DEFAULT if pretrained else None\n            backbone = models.efficientnet_b3(weights=weights)\n            backbone_features = backbone.features\n            num_ftrs = 1536  # For EfficientNet B3\n        \n        # Extract the feature extractor (everything except the classifier)\n        self.backbone = backbone_features\n        \n        # Global Average Pooling\n        self.gap = nn.AdaptiveAvgPool2d(1)\n        \n        # Custom classifier with an additional hidden layer\n        self.classifier = nn.Sequential(\n            nn.Dropout(0.2),\n            nn.Linear(num_ftrs, 512),  # Add a hidden layer\n            nn.ReLU(),\n            nn.Dropout(0.3),\n            nn.Linear(512, num_classes)\n        )\n        \n        # Softmax activation for final layer (not included in training since CrossEntropyLoss has it)\n        self.softmax = nn.Softmax(dim=1)\n    \n    def forward(self, x):\n        # Extract features using the backbone\n        x = self.backbone(x)\n        \n        # Global Average Pooling\n        x = self.gap(x)\n        x = torch.flatten(x, 1)\n        \n        # Classification head\n        x = self.classifier(x)\n        \n        # Note: We don't apply softmax during training since CrossEntropyLoss includes it\n        # We only apply it during inference or when raw probabilities are needed\n        return x\n    \n    def predict_proba(self, x):\n        # For getting probabilities during inference\n        logits = self.forward(x)\n        return self.softmax(logits)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T02:47:14.153841Z","iopub.execute_input":"2025-05-10T02:47:14.154357Z","iopub.status.idle":"2025-05-10T02:47:14.162809Z","shell.execute_reply.started":"2025-05-10T02:47:14.154317Z","shell.execute_reply":"2025-05-10T02:47:14.161679Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# the regnet model\nclass RegNetClassifier(pl.LightningModule):\n    def __init__(self, num_classes=4, lr=1e-4):\n        super().__init__()\n        self.save_hyperparameters()\n\n        # RegNet setup\n        self.model = regnet_y_400mf(weights=None)\n        self.model.fc = nn.Linear(self.model.fc.in_features, num_classes)\n        self.criterion = nn.CrossEntropyLoss()\n\n        # For manual tracking\n        self.val_losses = []\n        self.val_accuracies = []\n        self._val_loss_batches = []\n        self._val_acc_batches = []\n\n    def forward(self, x):\n        return self.model(x)\n\n    def training_step(self, batch, batch_idx):\n        x, y = batch\n        logits = self(x)\n        loss = self.criterion(logits, y)\n        acc = (logits.argmax(dim=1) == y).float().mean()\n        self.log(\"train_loss\", loss)\n        self.log(\"train_acc\", acc, prog_bar=True)\n        return loss\n\n    def validation_step(self, batch, batch_idx):\n        x, y = batch\n        logits = self(x)\n        loss = self.criterion(logits, y)\n        acc = (logits.argmax(dim=1) == y).float().mean()\n\n        # Save to temporary lists for epoch-end aggregation\n        self._val_loss_batches.append(loss)\n        self._val_acc_batches.append(acc)\n\n        # Log per batch for trainer bar\n        self.log(\"val_loss\", loss, prog_bar=True, on_step=False, on_epoch=True)\n        self.log(\"val_acc\", acc, prog_bar=True, on_step=False, on_epoch=True)\n\n    def on_validation_epoch_end(self):\n        # Average batch metrics for this epoch\n        avg_loss = torch.stack(self._val_loss_batches).mean().item()\n        avg_acc = torch.stack(self._val_acc_batches).mean().item()\n\n        # Store for plotting\n        self.val_losses.append(avg_loss)\n        self.val_accuracies.append(avg_acc)\n\n        # Log epoch-level values\n        self.log(\"val_loss\", avg_loss, prog_bar=True)\n        self.log(\"val_acc\", avg_acc, prog_bar=True)\n\n        # Clear lists for next epoch\n        self._val_loss_batches.clear()\n        self._val_acc_batches.clear()\n\n    def configure_optimizers(self):\n        optimizer = optim.Adam(self.parameters(), lr=self.hparams.lr)\n        scheduler = StepLR(optimizer, step_size=2, gamma=0.8)\n        return [optimizer], [scheduler]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T02:47:14.164182Z","iopub.execute_input":"2025-05-10T02:47:14.164707Z","iopub.status.idle":"2025-05-10T02:47:14.218204Z","shell.execute_reply.started":"2025-05-10T02:47:14.164670Z","shell.execute_reply":"2025-05-10T02:47:14.217222Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\n\ndevice = torch.device('cpu')\nprint(device)\n\nefficient_net_model = BirdClassifier('efficientnet_b3', 206, pretrained=False)\nefficient_net_model.load_state_dict(torch.load('/kaggle/input/efficientnet/pytorch/default/1/best_custom_efficientnet_b3_model.pth', map_location=device))\nefficient_net_model.eval()\n\nreg_net_model = RegNetClassifier()\nreg_net_model.load_state_dict(torch.load('/kaggle/input/regnet/pytorch/default/1/regnet_final_weights_20.pth', map_location=device))\nreg_net_model.eval()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport librosa\nimport numpy as np\nimport pandas as pd\nimport torch.nn.functional as F\n\nSAMPLE_RATE = 32000\nDURATION = 5\nN_MELS = 128 # EfficientNet works well with larger image sizes, 128 or 224 are common\nFMIN = 20\nFMAX = 16000\nHOP_LENGTH = 512\nN_FFT = 2048\n\n# Set seed\nnp.random.seed(42)\n\n# Class labels from train audio\nclass_labels = sorted(os.listdir('/kaggle/input/birdclef-2025/train_audio/'))\n\n# List of test soundscapes (only visible during submission)\ntest_soundscape_path = '/kaggle/input/birdclef-2025/test_soundscapes'\ntest_soundscapes = [os.path.join(test_soundscape_path, afile) for afile in sorted(os.listdir(test_soundscape_path)) if afile.endswith('.ogg')]\n# Open each soundscape and make predictions for 5-second segments\n# Use pandas df with 'row_id' plus class labels as columns\npredictions = pd.DataFrame(columns=['row_id'] + class_labels)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T02:47:21.396961Z","iopub.execute_input":"2025-05-10T02:47:21.397325Z","iopub.status.idle":"2025-05-10T02:47:21.897967Z","shell.execute_reply.started":"2025-05-10T02:47:21.397296Z","shell.execute_reply":"2025-05-10T02:47:21.896769Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for soundscape in test_soundscapes:\n\n    # Load audio\n    sig, rate = librosa.load(path=soundscape, sr=None)\n\n    # Split into 5-second chunks\n    chunks = []\n    for i in range(0, len(sig), rate*5):\n        chunk = sig[i:i+rate*5]\n        chunks.append(chunk)\n        \n        \n    # Make predictions for each chunk\n    for i, chunk in enumerate(chunks):\n        \n        # Get row id  (soundscape id + end time of 5s chunk)      \n        row_id = os.path.basename(soundscape).split('.')[0] + f'_{i * 5 + 5}'\n        \n        # Make prediction (let's use random scores for now)\n        target_length = len(chunk)\n\n        mel_spec = librosa.feature.melspectrogram(\n            y=chunk, sr=32000, n_fft=N_FFT, hop_length=HOP_LENGTH,\n            n_mels=N_MELS, fmin=FMIN, fmax=FMAX\n        )\n        mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max)\n\n        # --- Normalization (Optional but recommended for pre-trained models) ---\n        # Normalize to roughly [0, 1] or [-1, 1] range if needed,\n        # or use ImageNet stats if model expects that.\n        # Simple min-max scaling to [0, 1]:\n        min_val = np.min(mel_spec_db)\n        max_val = np.max(mel_spec_db)\n        if max_val > min_val:\n             mel_spec_db = (mel_spec_db - min_val) / (max_val - min_val)\n            # Convert to PyTorch Tensor and add channel dimension\n        spectrogram_tensor = torch.tensor(mel_spec_db, dtype=torch.float32).unsqueeze(0)\n            \n            # Repeat channel 3 times to mimic RGB\n        spectrogram_tensor_3channel = spectrogram_tensor.repeat(3, 1, 1)  # Output shape: (3, H, W)\n        spectrogram_tensor_3channel = spectrogram_tensor_3channel.unsqueeze(0)\n        scores = F.softmax(efficient_net_model(spectrogram_tensor_3channel), dim=1)\n        \n        # Append to predictions as new row\n        # Flatten the scores tensor and convert to a list of floats\n        scores_list = scores.squeeze().detach().cpu().numpy().tolist()\n        # print(scores_list.index(max(scores_list)))\n        # Create the DataFrame row\n        new_row = pd.DataFrame([[row_id] + scores_list], columns=['row_id'] + class_labels)\n        predictions = pd.concat([predictions, new_row], axis=0, ignore_index=True)\n# Save prediction as csv\npredictions.to_csv('submission1.csv', index=False)\npredictions.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T02:47:27.550426Z","iopub.execute_input":"2025-05-10T02:47:27.550922Z","iopub.status.idle":"2025-05-10T02:47:59.543767Z","shell.execute_reply.started":"2025-05-10T02:47:27.550897Z","shell.execute_reply":"2025-05-10T02:47:59.542799Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom torchvision.datasets import ImageFolder\nfrom torch.utils.data import DataLoader\nfrom torchvision import transforms\nfrom tqdm import tqdm\nimport cv2\n\ntaxonomy_df = pd.read_csv('/kaggle/input/birdclef-2025/taxonomy.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T02:48:03.686315Z","iopub.execute_input":"2025-05-10T02:48:03.686684Z","iopub.status.idle":"2025-05-10T02:48:04.102789Z","shell.execute_reply.started":"2025-05-10T02:48:03.686656Z","shell.execute_reply":"2025-05-10T02:48:04.101817Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def save_chunked_rgb_images_trimmed(df, speech_info, audio_root, output_dir, chunk_duration=5, img_size=(224, 224)):\n    os.makedirs(output_dir, exist_ok=True)\n    speech_map = {entry['filename']: entry['speech_timestamps'] for entry in speech_info}\n\n    for _, row in tqdm(df.iterrows(), total=len(df)):\n        filename = row['filename']\n        animal_class = row['animal_class']\n        input_path = os.path.join(audio_root, filename)\n\n        try:\n            y, sr = librosa.load(input_path, sr=None)\n        except Exception as e:\n            print(f\"[ERROR] loading {filename}: {e}\")\n            continue\n\n        duration_sec = len(y) / sr\n\n        # Trim human speech if found\n        if filename in speech_map:\n            speech = speech_map[filename]\n            if speech:\n                speech_starts = [mmss_to_seconds(seg['start']) for seg in speech]\n                speech_ends = [mmss_to_seconds(seg['end']) for seg in speech]\n                earliest = min(speech_starts)\n                latest = max(speech_ends)\n\n                if latest < duration_sec / 2:\n                    trim_sec = int(np.ceil(latest / chunk_duration) * chunk_duration)\n                    y = y[int(trim_sec * sr):]\n                elif earliest > duration_sec / 2:\n                    trim_sec = int(np.floor(earliest / chunk_duration) * chunk_duration)\n                    y = y[:int(trim_sec * sr)]\n                else:\n                    # Mid-speech → skip\n                    pass\n\n        # 5-second chunking\n        samples_per_chunk = int(sr * chunk_duration)\n        n_chunks = int(len(y) / samples_per_chunk)\n        if n_chunks == 0:\n            pass\n\n        base_name = os.path.splitext(os.path.basename(filename))[0]\n        class_dir = os.path.join(output_dir, animal_class)\n        os.makedirs(class_dir, exist_ok=True)\n\n        for i in range(n_chunks):\n            start = i * samples_per_chunk\n            end = start + samples_per_chunk\n            chunk = y[start:end]\n\n            rgb_img = extract_rgb_features(chunk, sr, img_size=img_size)\n            if rgb_img is None:\n                continue\n\n            out_name = f\"{base_name}_clip_{i}.png\"\n            out_path = os.path.join(class_dir, out_name)\n\n            try:\n                cv2.imwrite(out_path, rgb_img)\n            except Exception as e:\n                print(f\"[ERROR] saving {out_path}: {e}\")\n\ndef extract_rgb_features(y, sr, img_size=(224, 224)):\n    try:\n        # Compute features\n        mel = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=128)\n        log_mel = librosa.power_to_db(mel, ref=np.max)\n        delta = librosa.feature.delta(log_mel)\n        chroma = librosa.feature.chroma_cqt(y=y, sr=sr)\n\n        # Resize features\n        log_mel_resized = resize_feat(log_mel, img_size)\n        delta_resized = resize_feat(delta, img_size)\n        chroma_resized = resize_feat(chroma, img_size)\n\n        # Normalize\n        log_mel_norm = normalize(log_mel_resized)\n        delta_norm = normalize(delta_resized)\n        chroma_norm = normalize(chroma_resized)\n\n        # Stack to form RGB image\n        rgb_image = np.stack([log_mel_norm, delta_norm, chroma_norm], axis=-1)\n        rgb_image_uint8 = (rgb_image * 255).astype(np.uint8)\n\n        return rgb_image_uint8\n\n    except Exception as e:\n        print(f\"[ERROR in feature extraction]: {e}\")\n        return None\n\ndef normalize(x):\n    return (x - x.min()) / (x.max() - x.min() + 1e-8)\n    \ndef resize_feat(feat, target_shape):\n    from cv2 import resize, INTER_LINEAR\n    return resize(feat, target_shape, interpolation=INTER_LINEAR)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T02:48:06.660386Z","iopub.execute_input":"2025-05-10T02:48:06.660749Z","iopub.status.idle":"2025-05-10T02:48:06.678473Z","shell.execute_reply.started":"2025-05-10T02:48:06.660725Z","shell.execute_reply":"2025-05-10T02:48:06.677546Z"},"jupyter":{"source_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Đọc các file trong test_soundscapes và tiến hành dự đoán\nchunk_dir = \"/kaggle/working/test_soundscapes_chunked\"\nos.makedirs(chunk_dir, exist_ok=True)\n\ntest_dir = \"/kaggle/input/birdclef-2025/test_soundscapes\"\ntest_files = [f for f in sorted(os.listdir(test_dir)) if f.endswith(\".ogg\")]\n#test_dir = get_soundscape_dir()\n#all_files = [f for f in os.listdir(test_dir) if f.endswith(\".ogg\")]\n#test_files = all_files[:100]\n\n# Nếu có file .ogg thì xử lý như bình thường\nif test_files:\n    test_df = pd.DataFrame({'filename': test_files, 'animal_class': 'Unknown'})\n\n    save_chunked_rgb_images_trimmed(\n        df=test_df,\n        speech_info=[],\n        audio_root=test_dir,\n        output_dir=chunk_dir,\n        chunk_duration=5,\n        img_size=(224, 224)\n    )\nelse:\n    print(\"⚠️ No test soundscape files found. Skipping chunking. Will create empty submission.\")\n\n# Tiếp tục nếu thư mục chứa ảnh đã được tạo\nif os.path.exists(chunk_dir) and any(os.scandir(chunk_dir)):\n    transform = transforms.Compose([\n        transforms.Resize((224, 224)),\n        transforms.ToTensor(),\n        transforms.Normalize(mean=[0.5]*3, std=[0.5]*3),\n    ])\n\n    test_ds = ImageFolder(chunk_dir, transform=transform)\n    test_loader = DataLoader(test_ds, batch_size=32, shuffle=False)\n\n    predictions = []\n    file_names = []\n\n    with torch.no_grad():\n        for batch, _ in test_loader:\n            batch = batch.to(reg_net_model.device)\n            logits = reg_net_model(batch)\n            probs = torch.softmax(logits, dim=1).cpu().numpy()\n            predictions.extend(probs)\n\n            batch_indices = test_loader.dataset.samples[\n                len(file_names):len(file_names)+len(batch)\n            ]\n            file_names.extend([os.path.basename(path[0]) for path in batch_indices])\n\n    # Tạo row_ids\n    row_ids = []\n    for name in file_names:\n        base = name.replace('.png', '')\n        parts = base.split('_clip_')\n        if len(parts) == 2:\n            row_id = f\"{parts[0]}_{(int(parts[1]) + 1) * 5}\"\n            row_ids.append(row_id)\n        else:\n            row_ids.append(name)\n\nelse:\n    # Nếu không có ảnh nào thì tạo row_id & predict rỗng từ sample_submission\n    #sample_sub = pd.read_csv('/kaggle/input/birdclef-2025/sample_submission.csv')\n    #row_ids = sample_sub['row_id'].tolist()\n    #predictions = [[0.0] * len(taxonomy_df['primary_label'])] * len(row_ids)\n    row_ids = []\n    predictions = []\n\n\n# Hàm tạo submission\ndef create_submission(row_ids, predictions, submission_template_path, species_ids):\n    submission_dict = {'row_id': row_ids}\n    for i, species in enumerate(species_ids):\n        submission_dict[species] = [pred[i] if i < len(pred) else 0.0 for pred in predictions]\n\n    submission_df = pd.DataFrame(submission_dict)\n    submission_df.set_index('row_id', inplace=True)\n\n    sample_sub = pd.read_csv(submission_template_path, index_col='row_id')\n    for col in sample_sub.columns:\n        if col not in submission_df.columns:\n            submission_df[col] = 0.0\n    submission_df = submission_df[sample_sub.columns]\n    return submission_df.reset_index()\n\nspecies_ids = taxonomy_df['primary_label'].tolist()\nsubmission_df = create_submission(\n    row_ids=row_ids,\n    predictions=predictions,\n    submission_template_path='/kaggle/input/birdclef-2025/sample_submission.csv',\n    species_ids=species_ids\n)\n\nsubmission_df.to_csv(\"submission2.csv\", index=False)\n\n# ✅ In kết quả\nprint(\"✅ Submission preview:\")\ndisplay(submission_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T02:48:08.677208Z","iopub.execute_input":"2025-05-10T02:48:08.677555Z","iopub.status.idle":"2025-05-10T02:48:36.141998Z","shell.execute_reply.started":"2025-05-10T02:48:08.677532Z","shell.execute_reply":"2025-05-10T02:48:36.140387Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# !rm -rf /kaggle/working/*","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T02:48:36.144316Z","iopub.execute_input":"2025-05-10T02:48:36.144773Z","iopub.status.idle":"2025-05-10T02:48:36.151367Z","shell.execute_reply.started":"2025-05-10T02:48:36.144741Z","shell.execute_reply":"2025-05-10T02:48:36.150104Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"FILES_SUBM = [\n    '/kaggle/working/submission1.csv',\n    '/kaggle/working/submission2.csv'\n]\nENSEMBLE_SOLUTIONS = ['SOLUTION_1', 'SOLUTION_2']  # arbitrary names\nWEIGHTS = [0.9, 0.1]  # or any custom weights (must sum to 1)\nLB = ['N/A', 'N/A']   # leaderboard scores (optional)\nOPTION = 'weighted'\n\n\ndef ens2(lbs        = LB,\n         solution   = ENSEMBLE_SOLUTIONS,\n         wts        = WEIGHTS,\n         files_subm = FILES_SUBM,\n         option     = OPTION):\n\n    soluts = [solut.replace(\"SOLUTION_\", \"\") for solut in solution]\n    print(f'Ensemble: {soluts},   LB: {lbs},   weights: {wts}')\n    \n    list_TARGETs = sorted(os.listdir('/kaggle/input/birdclef-2025/train_audio/'))\n\n    list_targets_0 = [f'{TARGET} 0' for TARGET in list_TARGETs]\n    list_targets_1 = [f'{TARGET} 1' for TARGET in list_TARGETs]\n\n    df0 = pd.read_csv(files_subm[0])\n    df1 = pd.read_csv(files_subm[1])\n\n    # Rename columns to avoid collisions\n    df0 = df0.rename(columns={TARGET: f'{TARGET} 0' for TARGET in list_TARGETs})\n    print('df0:', df0)\n    df1 = df1.rename(columns={TARGET: f'{TARGET} 1' for TARGET in list_TARGETs})\n    print('df1:', df1)\n    \n    dfs = pd.merge(df0, df1, on='row_id')\n    print('dfs: ', dfs)\n\n    if option == 'weighted':\n        # Efficiently compute ensembled targets using dictionary comprehension\n        new_targets_df = pd.DataFrame({\n            tgt: dfs[tgt0] * wts[0] + dfs[tgt1] * wts[1]\n            for tgt, tgt0, tgt1 in zip(list_TARGETs, list_targets_0, list_targets_1)\n        })\n\n    if option == 'max':\n        new_targets_df = pd.DataFrame({\n            tgt: dfs[[tgt0, tgt1]].max(axis=1)\n            for tgt, tgt0, tgt1 in zip(list_TARGETs, list_targets_0, list_targets_1)\n        })\n\n    print('new_targets_df: ', new_targets_df)\n\n    # Concatenate with 'row_id' column only\n    dfs = pd.concat([dfs[['row_id']], new_targets_df], axis=1)\n\n    return dfs\n\n\n# Now call the function\nensemble_submission = ens2(\n    lbs=LB,\n    solution=ENSEMBLE_SOLUTIONS,\n    wts=WEIGHTS,\n    files_subm=FILES_SUBM,\n    option=OPTION\n)\n\nensemble_submission.to_csv('/kaggle/working/submission.csv', index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T02:49:55.657451Z","iopub.execute_input":"2025-05-10T02:49:55.657912Z","iopub.status.idle":"2025-05-10T02:49:55.976013Z","shell.execute_reply.started":"2025-05-10T02:49:55.657883Z","shell.execute_reply":"2025-05-10T02:49:55.974912Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"a = pd.read_csv('/kaggle/working/submission.csv')\na","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T02:50:00.005364Z","iopub.execute_input":"2025-05-10T02:50:00.006169Z","iopub.status.idle":"2025-05-10T02:50:00.046485Z","shell.execute_reply.started":"2025-05-10T02:50:00.006132Z","shell.execute_reply":"2025-05-10T02:50:00.045256Z"}},"outputs":[],"execution_count":null}]}