{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":71549,"databundleVersionId":8561470,"sourceType":"competition"}],"dockerImageVersionId":30747,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## RSNA-ASNR on lumbar spine degenerative conditions. \n\nGlobal Impact: Low back pain is the leading cause of disability worldwide, affecting 619 million people in 2020.\nPrevalence: Most people experience low back pain, with its frequency increasing with age.\nConditions: Pain and restricted mobility are often due to spondylosis, which includes degeneration of intervertebral discs and narrowing of the spinal canal, subarticular recesses, or neural foramen.\nDiagnosis: MRI provides detailed images of the lumbar spine, helping radiologists diagnose and assess the severity of these conditions.\nTreatment: Proper diagnosis and grading of lumbar spine conditions guide treatment and potential surgery to alleviate pain and improve patient quality of life.\n\n\n\n<figure>\n        <img src=\"https://files.miamineurosciencecenter.com/media/filer_public_thumbnails/filer_public/51/c6/51c6ffa1-0ea5-48e4-a3a8-dbf81022dbe4/regions_of_the_spine.jpg__1331.0x1109.0_q85_subject_location-665%2C558_subsampling-2.jpg\" alt =\"Audio Art\" style='width:800px;height:500px;'>\n        <figcaption>\n\n\n\nHerniation Zones\n\nHerniated and Bulging discs can also be classified by the area of the disc they protrude into (herniation zone).\n\n    Central: When the disc extrudes into in the spinal cord.\n    Subarticular (Lateral Recess or Paracentral): When the disc extrudes between the spinal cord and the foramen (the space through which the nerves exit the spinal canal).\n    Foraminal (Lateral): Disc extrusion into the foramen.\n            \n            \n<figure>\n        <img src=\"https://files.miamineurosciencecenter.com/media/filer_public_thumbnails/filer_public/d5/08/d508ae6a-a4f2-4796-be9f-455f8df45fe1/herniation_zones.jpg__1700.0x1308.0_q85_subject_location-850%2C656_subsampling-2.jpg\" alt =\"Audio Art\" style='width:800px;height:500px;'>\n        <figcaption>            \n    \n","metadata":{}},{"cell_type":"markdown","source":"## Loading Diagnosis Information","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport os\nimport pydicom\nimport matplotlib.pyplot as plt\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms, models\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.model_selection import train_test_split\nfrom tqdm import tqdm\nimport hashlib\nimport pickle","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:06.249382Z","iopub.execute_input":"2024-07-13T03:20:06.250062Z","iopub.status.idle":"2024-07-13T03:20:12.090064Z","shell.execute_reply.started":"2024-07-13T03:20:06.250026Z","shell.execute_reply":"2024-07-13T03:20:12.089048Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load the train labels\ntrain_df = pd.read_csv('/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train.csv')\nlabel_coords_df = pd.read_csv('/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_label_coordinates.csv')\nseries_desc_df = pd.read_csv('/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_series_descriptions.csv')","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:13.799405Z","iopub.execute_input":"2024-07-13T03:20:13.800439Z","iopub.status.idle":"2024-07-13T03:20:13.949553Z","shell.execute_reply.started":"2024-07-13T03:20:13.800403Z","shell.execute_reply":"2024-07-13T03:20:13.948666Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Merge the severity information from train_df into label_coords_df","metadata":{}},{"cell_type":"code","source":"label_coords_df = pd.merge(label_coords_df, train_df, on='study_id')","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:14.642142Z","iopub.execute_input":"2024-07-13T03:20:14.643023Z","iopub.status.idle":"2024-07-13T03:20:14.696412Z","shell.execute_reply.started":"2024-07-13T03:20:14.642988Z","shell.execute_reply":"2024-07-13T03:20:14.695581Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Check the columns of the merged DataFrame","metadata":{}},{"cell_type":"code","source":"print(label_coords_df.columns)","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:16.628784Z","iopub.execute_input":"2024-07-13T03:20:16.629436Z","iopub.status.idle":"2024-07-13T03:20:16.634586Z","shell.execute_reply.started":"2024-07-13T03:20:16.629389Z","shell.execute_reply":"2024-07-13T03:20:16.633652Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Function to show sample images\n\n#### A function to display sample images using pydicom is defined.","metadata":{}},{"cell_type":"code","source":"def show_sample_image(study_id, series_id, instance_number):\n    img_path = f'/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_images/{study_id}/{series_id}/{instance_number}.dcm'\n    ds = pydicom.dcmread(img_path)\n    plt.imshow(ds.pixel_array, cmap=plt.cm.bone)\n    plt.title(f'Study ID: {study_id} Series ID: {series_id} Instance: {instance_number}')\n    plt.show()\n\nfor idx in range(3):\n    row = label_coords_df.iloc[idx]\n    show_sample_image(row['study_id'], row['series_id'], row['instance_number'])\n","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:18.724059Z","iopub.execute_input":"2024-07-13T03:20:18.724404Z","iopub.status.idle":"2024-07-13T03:20:19.856007Z","shell.execute_reply.started":"2024-07-13T03:20:18.724378Z","shell.execute_reply":"2024-07-13T03:20:19.855111Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Function to create row_id","metadata":{}},{"cell_type":"code","source":"def create_row_id(study_id, condition, level):\n    return f\"{study_id}_{condition}_{level}\"","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:22.565854Z","iopub.execute_input":"2024-07-13T03:20:22.566222Z","iopub.status.idle":"2024-07-13T03:20:22.570723Z","shell.execute_reply.started":"2024-07-13T03:20:22.566180Z","shell.execute_reply":"2024-07-13T03:20:22.569804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Use a smaller subset of the data for testing","metadata":{}},{"cell_type":"code","source":"sampled_label_coords_df = label_coords_df.sample(n=1000, random_state=42)\ntrain_df, val_df = train_test_split(sampled_label_coords_df, test_size=0.2, random_state=42)","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:24.192801Z","iopub.execute_input":"2024-07-13T03:20:24.193160Z","iopub.status.idle":"2024-07-13T03:20:24.206878Z","shell.execute_reply.started":"2024-07-13T03:20:24.193129Z","shell.execute_reply":"2024-07-13T03:20:24.205998Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data Transformations and DataLoader","metadata":{}},{"cell_type":"markdown","source":"#### Data Transformations and DataLoader with Data Augmentation.","metadata":{}},{"cell_type":"code","source":"transform_train = transforms.Compose([\n    transforms.ToPILImage(),\n    transforms.Resize((224, 224)),\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomRotation(10),\n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.2),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n])\n\ntransform_val = transforms.Compose([\n    transforms.ToPILImage(),\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n])","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:27.186043Z","iopub.execute_input":"2024-07-13T03:20:27.186406Z","iopub.status.idle":"2024-07-13T03:20:27.193542Z","shell.execute_reply.started":"2024-07-13T03:20:27.186376Z","shell.execute_reply":"2024-07-13T03:20:27.192545Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Cache directory","metadata":{}},{"cell_type":"code","source":"CACHE_DIR = '/kaggle/working/cache/'\n\ndef get_cache_path(img_path):\n    hash_key = hashlib.md5(img_path.encode()).hexdigest()\n    return os.path.join(CACHE_DIR, f\"{hash_key}.pkl\")\n\ndef cache_data(img_path, data):\n    os.makedirs(CACHE_DIR, exist_ok=True)\n    cache_path = get_cache_path(img_path)\n    with open(cache_path, 'wb') as f:\n        pickle.dump(data, f)\n\ndef load_cached_data(img_path):\n    cache_path = get_cache_path(img_path)\n    if os.path.exists(cache_path):\n        with open(cache_path, 'rb') as f:\n            return pickle.load(f)\n    return None","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:30.311393Z","iopub.execute_input":"2024-07-13T03:20:30.311769Z","iopub.status.idle":"2024-07-13T03:20:30.318882Z","shell.execute_reply.started":"2024-07-13T03:20:30.311740Z","shell.execute_reply":"2024-07-13T03:20:30.317925Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Custom Dataset Class\n\n#### A custom PyTorch Dataset class is created to handle the dataset. This class reads the DICOM images and their corresponding labels, applies transformations, and returns the images and labels in a format suitable for model training.","metadata":{}},{"cell_type":"code","source":"class SpineDataset(Dataset):\n    def __init__(self, df, img_dir, condition_col, transform=None):\n        self.df = df\n        self.img_dir = img_dir\n        self.condition_col = condition_col\n        self.transform = transform\n        self.label_encoder = LabelEncoder()\n        self.df['encoded_label'] = self.label_encoder.fit_transform(self.df[self.condition_col])\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        img_path = os.path.join(self.img_dir, f\"{row['study_id']}/{row['series_id']}/{row['instance_number']}.dcm\")\n        \n        cached_data = load_cached_data(img_path)\n        if cached_data is not None:\n            image, label = cached_data\n        else:\n            ds = pydicom.dcmread(img_path)\n            image = ds.pixel_array\n            image = np.stack((image,)*3, axis=-1)\n            image = ((image - np.min(image)) / (np.max(image) - np.min(image)) * 255).astype(np.uint8)\n            label = row['encoded_label']\n            cache_data(img_path, (image, label))\n\n        if self.transform:\n            image = self.transform(image)\n\n        return image, label","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:32.516301Z","iopub.execute_input":"2024-07-13T03:20:32.517004Z","iopub.status.idle":"2024-07-13T03:20:32.526341Z","shell.execute_reply.started":"2024-07-13T03:20:32.516973Z","shell.execute_reply":"2024-07-13T03:20:32.525359Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Use one condition column for training, e.g., 'spinal_canal_stenosis_l1_l2'","metadata":{}},{"cell_type":"code","source":"condition_col = 'spinal_canal_stenosis_l1_l2'","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:34.387766Z","iopub.execute_input":"2024-07-13T03:20:34.388548Z","iopub.status.idle":"2024-07-13T03:20:34.392649Z","shell.execute_reply.started":"2024-07-13T03:20:34.388513Z","shell.execute_reply":"2024-07-13T03:20:34.391613Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Create train and validation datasets","metadata":{}},{"cell_type":"code","source":"train_dataset = SpineDataset(train_df, '/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_images', condition_col, transform=transform_train)\nval_dataset = SpineDataset(val_df, '/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_images', condition_col, transform=transform_val)","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:36.370216Z","iopub.execute_input":"2024-07-13T03:20:36.373781Z","iopub.status.idle":"2024-07-13T03:20:36.383648Z","shell.execute_reply.started":"2024-07-13T03:20:36.373739Z","shell.execute_reply":"2024-07-13T03:20:36.382691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Create DataLoaders","metadata":{}},{"cell_type":"code","source":"train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4)\nval_loader = DataLoader(val_dataset, batch_size=32, shuffle=False, num_workers=4)","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:38.477755Z","iopub.execute_input":"2024-07-13T03:20:38.478399Z","iopub.status.idle":"2024-07-13T03:20:38.483050Z","shell.execute_reply.started":"2024-07-13T03:20:38.478367Z","shell.execute_reply":"2024-07-13T03:20:38.482064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Define and Train the CNN Model\n\n#### Define a convolutional neural network (CNN) model using a pretrained ResNet-18 architecture.\n\n#### Load pretrained weights if available.","metadata":{}},{"cell_type":"code","source":"class SpineCNN(nn.Module):\n    def __init__(self):\n        super(SpineCNN, self).__init__()\n        self.model = models.resnet18(weights=None)  # Do not use pre-trained weights\n        self.model.fc = nn.Sequential(\n            nn.Dropout(0.5),  # Dropout regularization\n            nn.Linear(self.model.fc.in_features, 3)\n        )\n\n    def forward(self, x):\n        return self.model(x)\n\nmodel = SpineCNN()\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nmodel.to(device)","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:40.677601Z","iopub.execute_input":"2024-07-13T03:20:40.678250Z","iopub.status.idle":"2024-07-13T03:20:41.122466Z","shell.execute_reply.started":"2024-07-13T03:20:40.678218Z","shell.execute_reply":"2024-07-13T03:20:41.121432Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Training the Model\n\n#### Define a function to train the model, specifying the loss function (CrossEntropyLoss) and optimizer (Adam). The training and validation losses are plotted.","metadata":{}},{"cell_type":"code","source":"criterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=1e-4)\nscheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=3, verbose=True)\n\ndef train_model(model, train_loader, val_loader, criterion, optimizer, scheduler, num_epochs=10):\n    train_losses = []\n    val_losses = []\n    early_stopping_patience = 5\n    early_stopping_counter = 0\n    best_val_loss = float('inf')\n\n    for epoch in range(num_epochs):\n        model.train()\n        train_loss = 0.0\n        for images, labels in tqdm(train_loader):\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            train_loss += loss.item()\n\n        val_loss = 0.0\n        model.eval()\n        with torch.no_grad():\n            for images, labels in val_loader:\n                images, labels = images.to(device), labels.to(device)\n                outputs = model(images)\n                loss = criterion(outputs, labels)\n                val_loss += loss.item()\n\n        train_loss /= len(train_loader)\n        val_loss /= len(val_loader)\n        train_losses.append(train_loss)\n        val_losses.append(val_loss)\n        scheduler.step(val_loss)\n\n        print(f\"Epoch {epoch+1}/{num_epochs}, Train Loss: {train_loss}, Val Loss: {val_loss}\")\n\n        # Early Stopping\n        if val_loss < best_val_loss:\n            best_val_loss = val_loss\n            early_stopping_counter = 0\n            torch.save(model.state_dict(), 'best_model.pth')\n        else:\n            early_stopping_counter += 1\n            if early_stopping_counter >= early_stopping_patience:\n                print(\"Early stopping triggered\")\n                break\n\n    # Plotting the training and validation loss\n    plt.figure(figsize=(10, 5))\n    plt.plot(range(1, len(train_losses) + 1), train_losses, label='Train Loss')\n    plt.plot(range(1, len(val_losses) + 1), val_losses, label='Val Loss')\n    plt.xlabel('Epochs')\n    plt.ylabel('Loss')\n    plt.legend()\n    plt.show()\n\ntrain_model(model, train_loader, val_loader, criterion, optimizer, scheduler, num_epochs=15)","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:20:47.502306Z","iopub.execute_input":"2024-07-13T03:20:47.502987Z","iopub.status.idle":"2024-07-13T03:21:23.879026Z","shell.execute_reply.started":"2024-07-13T03:20:47.502951Z","shell.execute_reply":"2024-07-13T03:21:23.877976Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Load the best model","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\ndef plot_images(images, titles, n_rows=2, n_cols=2):\n    fig, axes = plt.subplots(n_rows, n_cols, figsize=(12, 12))\n    axes = axes.flatten()\n    for img, title, ax in zip(images, titles, axes):\n        ax.imshow(img, cmap='gray')\n        ax.set_title(title)\n        ax.axis('off')\n    plt.tight_layout()\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:21:28.376008Z","iopub.execute_input":"2024-07-13T03:21:28.376654Z","iopub.status.idle":"2024-07-13T03:21:28.382934Z","shell.execute_reply.started":"2024-07-13T03:21:28.376619Z","shell.execute_reply":"2024-07-13T03:21:28.382045Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Test Dataset Class","metadata":{}},{"cell_type":"code","source":"class SpineTestDataset(Dataset):\n    def __init__(self, df, img_dir, transform=None):\n        self.df = df\n        self.img_dir = img_dir\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        img_path = os.path.join(self.img_dir, f\"{row['study_id']}/{row['series_id']}/1.dcm\")  # Use 1.dcm as default\n\n        cached_data = load_cached_data(img_path)\n        if cached_data is not None:\n            image = cached_data\n        else:\n            ds = pydicom.dcmread(img_path)\n            image = ds.pixel_array\n            image = np.stack((image,)*3, axis=-1)\n            image = ((image - np.min(image)) / (np.max(image) - np.min(image)) * 255).astype(np.uint8)\n            cache_data(img_path, image)\n\n        if self.transform:\n            image = self.transform(image)\n\n        return image, f\"{row['study_id']}_{row['series_id']}\"","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:21:30.092285Z","iopub.execute_input":"2024-07-13T03:21:30.092637Z","iopub.status.idle":"2024-07-13T03:21:30.101487Z","shell.execute_reply.started":"2024-07-13T03:21:30.092610Z","shell.execute_reply":"2024-07-13T03:21:30.100579Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Create test dataset and dataloader","metadata":{}},{"cell_type":"code","source":"test_df = pd.read_csv('/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/test_series_descriptions.csv')\ntest_dataset = SpineTestDataset(test_df, '/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/test_images', transform=transform_val)\ntest_loader = DataLoader(test_dataset, batch_size=32, shuffle=False, num_workers=4)\n","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:21:31.728998Z","iopub.execute_input":"2024-07-13T03:21:31.729986Z","iopub.status.idle":"2024-07-13T03:21:31.739857Z","shell.execute_reply.started":"2024-07-13T03:21:31.729952Z","shell.execute_reply":"2024-07-13T03:21:31.738973Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Prediction on Test Set","metadata":{}},{"cell_type":"code","source":"model.eval()\npredictions = []\nplot_images_list = []\nplot_titles_list = []\n\nwith torch.no_grad():\n    for images, row_ids in tqdm(test_loader):\n        images = images.to(device)\n        outputs = model(images)\n        probs = torch.softmax(outputs, dim=1)\n        for i in range(len(row_ids)):\n            row_id = row_ids[i]\n            normal_mild, moderate, severe = probs[i].cpu().numpy()\n            \n            # Collect images and titles for plotting\n            if len(plot_images_list) < 4:\n                plot_images_list.append(images[i].cpu().numpy().transpose(1, 2, 0).astype(np.uint8))\n                plot_titles_list.append(f\"{row_id}: N/M={normal_mild:.2f}, M={moderate:.2f}, S={severe:.2f}\")\n            \n            predictions.append({\n                'row_id': row_id,\n                'normal_mild': normal_mild,\n                'moderate': moderate,\n                'severe': severe\n            })\n\n# Plot images with predictions\nplot_images(plot_images_list, plot_titles_list)\n\n# Convert predictions to DataFrame\npredictions_df = pd.DataFrame(predictions)\n\n# Apply any_severe_scalar\nany_severe_scalar = 1.0\npredictions_df['any_severe'] = predictions_df['severe'].apply(lambda x: 1 if x >= any_severe_scalar else 0)\n\n# Save predictions to a CSV file in the required format\nsubmission_path = '/kaggle/working/submission.csv'\nsubmission_df = predictions_df[['row_id', 'normal_mild', 'moderate', 'severe']]\nsubmission_df.to_csv(submission_path, index=False)\n\nprint(f\"Submission file saved to {submission_path}\")","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:41:04.210632Z","iopub.execute_input":"2024-07-13T03:41:04.211015Z","iopub.status.idle":"2024-07-13T03:41:05.156793Z","shell.execute_reply.started":"2024-07-13T03:41:04.210987Z","shell.execute_reply":"2024-07-13T03:41:05.155753Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df.head()","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:41:14.819707Z","iopub.execute_input":"2024-07-13T03:41:14.820483Z","iopub.status.idle":"2024-07-13T03:41:14.831480Z","shell.execute_reply.started":"2024-07-13T03:41:14.820444Z","shell.execute_reply":"2024-07-13T03:41:14.830524Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Verify if the submission file exists and is not empty\nif os.path.isfile(submission_path):\n    file_size = os.path.getsize(submission_path)\n    if file_size > 0:\n        print(f\"The submission file {submission_path} has been created successfully and is ready for submission.\")\n    else:\n        print(f\"The submission file {submission_path} is empty. Please check for errors.\")\nelse:\n    print(f\"The submission file {submission_path} was not created. Please check for errors.\")","metadata":{"execution":{"iopub.status.busy":"2024-07-13T03:41:20.549905Z","iopub.execute_input":"2024-07-13T03:41:20.550626Z","iopub.status.idle":"2024-07-13T03:41:20.556599Z","shell.execute_reply.started":"2024-07-13T03:41:20.550581Z","shell.execute_reply":"2024-07-13T03:41:20.555713Z"},"trusted":true},"execution_count":null,"outputs":[]}]}