{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"Hello fellow Kagglers,\n\nThis notebook demonstrates the inference process using an EfficientNetV2T model training on a TPU.\n\nThe inference process consists of 2 steps.\n\n1) Preprocess and save all images in parallel, images are cropped, padded to correct aspect ratio and resized to the target size.\n\n2) Prediction on preprocessed images in a simple loop, final cancer score is mean of all images.\n\n[RSNA ConvNextV2 Training Tensorflow TPU](https://www.kaggle.com/code/markwijkhuizen/rsna-efficientnetv2-training-tensorflow-tpu/notebook)\n\n[RSNA Cropped TFRecords 768x1344 Dataset](https://www.kaggle.com/code/markwijkhuizen/rsna-cropped-tfrecords-768x1344-dataset/notebook)\n\n**V3**\n\n* Switch to ConvNextV2 models","metadata":{"papermill":{"duration":0.008697,"end_time":"2023-01-18T12:58:12.988301","exception":false,"start_time":"2023-01-18T12:58:12.979604","status":"completed"},"tags":[]}},{"cell_type":"code","source":"%%capture\n# Source: https://www.kaggle.com/code/remekkinas/fast-dicom-processing-1-6-2x-faster?scriptVersionId=113360473\n!pip install /kaggle/input/rsnamodules/dicomsdl-0.109.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl \n\ntry:\n    import pylibjpeg\nexcept:\n   !pip install /kaggle/input/rsna-2022-whl/{pylibjpeg-1.4.0-py3-none-any.whl,python_gdcm-3.0.15-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl}","metadata":{"papermill":{"duration":71.417751,"end_time":"2023-01-18T12:59:24.413754","exception":false,"start_time":"2023-01-18T12:58:12.996003","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:44:32.748369Z","iopub.execute_input":"2023-02-01T21:44:32.748847Z","iopub.status.idle":"2023-02-01T21:45:34.645974Z","shell.execute_reply.started":"2023-02-01T21:44:32.74877Z","shell.execute_reply":"2023-02-01T21:45:34.644721Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Install Keras CV Attention Model Pip Package for ConvNextV2 Models\n!pip install --no-deps /kaggle/input/keras-cv-attention-models/keras_cv_attention_models-1.3.5-py3-none-any.whl","metadata":{"papermill":{"duration":23.841168,"end_time":"2023-01-18T12:59:48.267822","exception":false,"start_time":"2023-01-18T12:59:24.426654","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:46:38.953038Z","iopub.execute_input":"2023-02-01T21:46:38.95342Z","iopub.status.idle":"2023-02-01T21:47:01.534631Z","shell.execute_reply.started":"2023-02-01T21:46:38.953385Z","shell.execute_reply":"2023-02-01T21:47:01.533261Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport pylibjpeg\nimport pydicom\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nimport dicomsdl as dicoml\nimport pydicom\n\nfrom joblib import Parallel, delayed\nfrom tqdm.notebook import tqdm\nfrom multiprocessing import cpu_count\nfrom keras_cv_attention_models import convnext\n\nimport cv2\nimport glob\nimport importlib\nimport os\nimport joblib\nimport time\n\n# Tensorflow and CV2 set number of threads to 1 for speedup in parallell function mapping\ntf.config.threading.set_inter_op_parallelism_threads(num_threads=1)\ncv2.setNumThreads(1)\n\n# Pandas DataFrame Display Options\npd.options.display.max_colwidth = 99","metadata":{"papermill":{"duration":8.793502,"end_time":"2023-01-18T12:59:57.074488","exception":false,"start_time":"2023-01-18T12:59:48.280986","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:47:01.540663Z","iopub.execute_input":"2023-02-01T21:47:01.543184Z","iopub.status.idle":"2023-02-01T21:47:07.426917Z","shell.execute_reply.started":"2023-02-01T21:47:01.543126Z","shell.execute_reply":"2023-02-01T21:47:07.425919Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Config","metadata":{"papermill":{"duration":0.010929,"end_time":"2023-01-18T12:59:57.097744","exception":false,"start_time":"2023-01-18T12:59:57.086815","status":"completed"},"tags":[]}},{"cell_type":"code","source":"IS_INTERACTIVE = os.environ['KAGGLE_KERNEL_RUN_TYPE'] == 'Interactive'\n\nTARGET_HEIGHT = 1344\nTARGET_WIDTH = 768\nN_CHANNELS = 1\nINPUT_SHAPE = (TARGET_HEIGHT, TARGET_WIDTH, N_CHANNELS)\nTARGET_HEIGHT_WIDTH_RATIO = TARGET_HEIGHT / TARGET_WIDTH\nTHRESHOLD_BEST = 0.60\n\nCLAHE = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(32, 32))\n\nCROP_IMAGE = True\nAPPLY_CLAHE = False\nAPPLY_EQ_HIST = False","metadata":{"papermill":{"duration":0.039792,"end_time":"2023-01-18T12:59:57.149433","exception":false,"start_time":"2023-01-18T12:59:57.109641","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:47:07.428588Z","iopub.execute_input":"2023-02-01T21:47:07.429268Z","iopub.status.idle":"2023-02-01T21:47:07.44132Z","shell.execute_reply.started":"2023-02-01T21:47:07.429229Z","shell.execute_reply":"2023-02-01T21:47:07.439669Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Crop Image","metadata":{"papermill":{"duration":0.010886,"end_time":"2023-01-18T12:59:57.172411","exception":false,"start_time":"2023-01-18T12:59:57.161525","status":"completed"},"tags":[]}},{"cell_type":"code","source":"def smooth(l):\n    kernel_size = int(len(l) * 0.01)\n    kernel = np.ones(kernel_size) / kernel_size\n    return np.convolve(l, kernel, mode='same')\n\ndef get_x_offset(image, max_col_sum_ratio_threshold=0.05):\n    margin = 0\n    sums = smooth(image.sum(axis=0).squeeze())\n    sums_argmax = sums[:int(image.shape[1] * 0.75)].argmax()\n    sums_threshold = sums.max() * max_col_sum_ratio_threshold\n    first_non_zoro_column_found = False\n    \n    for offset, s in enumerate(sums):\n        if s < sums_threshold and first_non_zoro_column_found:\n            return min(image.shape[1], offset + margin)\n        elif s > sums_threshold and offset > sums_argmax:\n            first_non_zoro_column_found = True\n        \n    return offset\n\ndef get_y_offsets(image, max_row_sum_ratio_threshold=0.10):\n    margin = 0\n    sums = smooth(image.sum(axis=1).squeeze())\n    sums_argmax = int(image.shape[0] * 0.25) + sums[int(image.shape[0] * 0.25):int(image.shape[0] * 0.75)].argmax()\n    sum_threshold = sums.max() * max_row_sum_ratio_threshold\n    offset_bottom = 0\n    offset_top = image.shape[0]\n    offset_top_set = False\n\n    # Bottom offset\n    for offset, s in enumerate(sums):\n        if s < sum_threshold and not offset_top_set:\n            offset_bottom += 1\n        else:\n            break\n            \n    for offset, s in enumerate(reversed(sums)):\n        if s > sum_threshold and not offset_top_set:\n            offset_top = image.shape[0] - (offset + 1)\n            break\n            \n    return max(0, offset_bottom - margin), min(image.shape[0], offset_top + margin)\n\ndef crop(image, debug=False):\n    x_offset = get_x_offset(image)\n    offset_bottom, offset_top = get_y_offsets(image[:,:x_offset])\n    \n    image = image[offset_bottom:offset_top:,:x_offset]\n        \n    return image","metadata":{"papermill":{"duration":0.0422,"end_time":"2023-01-18T12:59:57.226219","exception":false,"start_time":"2023-01-18T12:59:57.184019","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:47:45.827978Z","iopub.execute_input":"2023-02-01T21:47:45.82835Z","iopub.status.idle":"2023-02-01T21:47:45.842678Z","shell.execute_reply.started":"2023-02-01T21:47:45.828317Z","shell.execute_reply":"2023-02-01T21:47:45.840671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Process Image","metadata":{"papermill":{"duration":0.011027,"end_time":"2023-01-18T12:59:57.249282","exception":false,"start_time":"2023-01-18T12:59:57.238255","status":"completed"},"tags":[]}},{"cell_type":"code","source":"def process(file_path, size=(TARGET_WIDTH, TARGET_HEIGHT), crop_image=CROP_IMAGE, apply_clahe=APPLY_CLAHE, apply_eq_hist=APPLY_EQ_HIST, debug=False, save=True):\n    # Read Dicom File\n    dicom = pydicom.dcmread(file_path)\n    image = dicom.pixel_array\n\n    # Normalize [0,1] range\n    image = (image - image.min()) / (image.max() - image.min())\n\n    if dicom.PhotometricInterpretation == \"MONOCHROME1\":  \n        image = 1 - image\n\n    # Convert to uint8 image in range [0, 255]\n    image = (image * 255).astype(np.uint8)\n    \n    # Flip T0 Left/Right Orientation\n    h0, w0 = image.shape\n    if image[:,int(-w0 * 0.10):].sum() > image[:,:int(w0 * 0.10)].sum():\n        image = np.flip(image, axis=1)\n    \n    # Save original image\n    if debug:\n        image0 = np.copy(image)\n    \n    # Always crop 10 pixels for weird border noise/lines\n    image = image[int(h0 * 2e-2):-int(h0 * 2e-2),int(w0 * 2e-2):-int(w0 * 2e-2)]\n    \n    # Crop Image\n    if crop_image:\n        image = crop(image, debug=debug)\n        \n    # Resize\n    if size is not None:\n        # Pad black pixels to make square image\n        h, w = image.shape\n        if (h / w) > TARGET_HEIGHT_WIDTH_RATIO:\n            pad = int(h / TARGET_HEIGHT_WIDTH_RATIO - w)\n            image = np.pad(image, [[0,0], [0, pad]])\n            h, w = image.shape\n        else:\n            pad = int(0.50 * (w * TARGET_HEIGHT_WIDTH_RATIO - h))\n            image = np.pad(image, [[pad, pad], [0,0]])\n            h, w = image.shape\n        # Resize\n        image = cv2.resize(image, size, interpolation=cv2.INTER_AREA)\n        \n    # Apply CLAHE contrast enhancement\n    if apply_clahe:\n        image = CLAHE.apply(image)\n        \n     # Apply Histogram Equalization\n    if apply_eq_hist:\n        image = cv2.equalizeHist(image)\n        \n    # Save Only\n    if save:\n        image_id = file_path.split('/')[-1].split('.')[0]\n        cv2.imwrite(f'{image_id}.png', image)","metadata":{"papermill":{"duration":0.04272,"end_time":"2023-01-18T12:59:57.303708","exception":false,"start_time":"2023-01-18T12:59:57.260988","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:47:47.530946Z","iopub.execute_input":"2023-02-01T21:47:47.531335Z","iopub.status.idle":"2023-02-01T21:47:47.543428Z","shell.execute_reply.started":"2023-02-01T21:47:47.531302Z","shell.execute_reply":"2023-02-01T21:47:47.542098Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{"papermill":{"duration":0.011277,"end_time":"2023-01-18T12:59:57.32719","exception":false,"start_time":"2023-01-18T12:59:57.315913","status":"completed"},"tags":[]}},{"cell_type":"code","source":"def normalize(image):\n    image = tf.repeat(image, repeats=3, axis=3)\n    image = tf.cast(image, tf.float32)\n    image = tf.keras.applications.imagenet_utils.preprocess_input(image, mode='torch')\n\n    return image","metadata":{"papermill":{"duration":0.028226,"end_time":"2023-01-18T12:59:57.36697","exception":false,"start_time":"2023-01-18T12:59:57.338744","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:47:49.220937Z","iopub.execute_input":"2023-02-01T21:47:49.222465Z","iopub.status.idle":"2023-02-01T21:47:49.228486Z","shell.execute_reply.started":"2023-02-01T21:47:49.222417Z","shell.execute_reply":"2023-02-01T21:47:49.227444Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_model():\n    # Inputs, note the names are equal to the dictionary keys in the dataset\n    image = tf.keras.layers.Input(INPUT_SHAPE, name='image', dtype=tf.uint8)\n\n    # Normalize Input\n    image_norm = normalize(image)\n\n    # CNN Feature Maps\n    x = convnext.ConvNeXtV2Tiny(\n        input_shape=(TARGET_HEIGHT, TARGET_WIDTH, 3),\n        pretrained=None,\n        num_classes=0,\n    )(image_norm)\n\n    # Average Pooling BxHxWxC -> BxC\n    x = tf.keras.layers.GlobalAveragePooling2D()(x)\n    # Dropout to prevent Overfitting\n    x = tf.keras.layers.Dropout(0.30)(x)\n    # Output value between [0, 1] using Sigmoid function\n    outputs = tf.keras.layers.Dense(1, activation='sigmoid')(x)\n\n    model = tf.keras.models.Model(inputs=image, outputs=outputs)\n\n    model.load_weights('/kaggle/input/rsna-convnextv2-training-jitshil/model.h5')\n\n    model.trainable = False\n\n    model.compile()\n\n    return model","metadata":{"papermill":{"duration":0.033796,"end_time":"2023-01-18T12:59:57.412331","exception":false,"start_time":"2023-01-18T12:59:57.378535","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:47:50.814945Z","iopub.execute_input":"2023-02-01T21:47:50.815794Z","iopub.status.idle":"2023-02-01T21:47:50.824424Z","shell.execute_reply.started":"2023-02-01T21:47:50.815747Z","shell.execute_reply":"2023-02-01T21:47:50.823081Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Pretrained File Path: '/kaggle/input/sartorius-training-dataset/model.h5'\ntf.keras.backend.clear_session()\n# enable XLA optmizations\ntf.config.optimizer.set_jit(True)\n\nmodel = get_model()","metadata":{"papermill":{"duration":8.892152,"end_time":"2023-01-18T13:00:06.315873","exception":false,"start_time":"2023-01-18T12:59:57.423721","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:47:51.282038Z","iopub.execute_input":"2023-02-01T21:47:51.282807Z","iopub.status.idle":"2023-02-01T21:47:59.031194Z","shell.execute_reply.started":"2023-02-01T21:47:51.282769Z","shell.execute_reply":"2023-02-01T21:47:59.030213Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plot model summary\nmodel.summary()","metadata":{"papermill":{"duration":0.032152,"end_time":"2023-01-18T13:00:06.357238","exception":false,"start_time":"2023-01-18T13:00:06.325086","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:48:02.505276Z","iopub.execute_input":"2023-02-01T21:48:02.505715Z","iopub.status.idle":"2023-02-01T21:48:02.520692Z","shell.execute_reply.started":"2023-02-01T21:48:02.505667Z","shell.execute_reply":"2023-02-01T21:48:02.519533Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Test","metadata":{"papermill":{"duration":0.007808,"end_time":"2023-01-18T13:00:06.373858","exception":false,"start_time":"2023-01-18T13:00:06.36605","status":"completed"},"tags":[]}},{"cell_type":"code","source":"test = pd.read_csv('/kaggle/input/rsna-breast-cancer-detection/test.csv')\n\ndef get_file_path(args):\n    patient_id, image_id = args\n    return f'/kaggle/input/rsna-breast-cancer-detection/test_images/{patient_id}/{image_id}.dcm'\n    \ntest['file_path'] = test[['patient_id', 'image_id']].apply(get_file_path, axis=1)\n\ndisplay(test.info())\ndisplay(test.head())","metadata":{"papermill":{"duration":0.083997,"end_time":"2023-01-18T13:00:06.466279","exception":false,"start_time":"2023-01-18T13:00:06.382282","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:48:03.728891Z","iopub.execute_input":"2023-02-01T21:48:03.729258Z","iopub.status.idle":"2023-02-01T21:48:03.777505Z","shell.execute_reply.started":"2023-02-01T21:48:03.729226Z","shell.execute_reply":"2023-02-01T21:48:03.776464Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Sample Submission","metadata":{"papermill":{"duration":0.008828,"end_time":"2023-01-18T13:00:06.483555","exception":false,"start_time":"2023-01-18T13:00:06.474727","status":"completed"},"tags":[]}},{"cell_type":"code","source":"sample_submission = pd.read_csv('/kaggle/input/rsna-breast-cancer-detection/sample_submission.csv')\n\ndisplay(sample_submission.info())\ndisplay(sample_submission.head())","metadata":{"papermill":{"duration":0.049207,"end_time":"2023-01-18T13:00:06.541526","exception":false,"start_time":"2023-01-18T13:00:06.492319","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:48:05.11883Z","iopub.execute_input":"2023-02-01T21:48:05.119217Z","iopub.status.idle":"2023-02-01T21:48:05.143813Z","shell.execute_reply.started":"2023-02-01T21:48:05.119182Z","shell.execute_reply":"2023-02-01T21:48:05.142617Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Parallel Image Processing","metadata":{"papermill":{"duration":0.008545,"end_time":"2023-01-18T13:00:06.559712","exception":false,"start_time":"2023-01-18T13:00:06.551167","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Preprocess a single image and saves it\ndef preprocess_and_save_image(args):\n    (patient_id, laterality), g = args\n    cancer = 0.0\n    for row_idx, row in g.iterrows():\n        process(row['file_path'])","metadata":{"papermill":{"duration":0.020208,"end_time":"2023-01-18T13:00:06.588886","exception":false,"start_time":"2023-01-18T13:00:06.568678","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:48:07.495201Z","iopub.execute_input":"2023-02-01T21:48:07.495618Z","iopub.status.idle":"2023-02-01T21:48:07.505455Z","shell.execute_reply.started":"2023-02-01T21:48:07.495584Z","shell.execute_reply":"2023-02-01T21:48:07.504381Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Preprocess all images in parallel using Joblib\njobs = [joblib.delayed(preprocess_and_save_image)(args) for args in test.groupby(['patient_id', 'laterality'])]\nSUBMISSION_ROWS = joblib.Parallel(\n    n_jobs=cpu_count(),\n    verbose=IS_INTERACTIVE,\n    backend='multiprocessing',\n    prefer='threads',\n)(jobs)","metadata":{"papermill":{"duration":4.064878,"end_time":"2023-01-18T13:00:10.662604","exception":false,"start_time":"2023-01-18T13:00:06.597726","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:48:08.447977Z","iopub.execute_input":"2023-02-01T21:48:08.448817Z","iopub.status.idle":"2023-02-01T21:48:11.358983Z","shell.execute_reply.started":"2023-02-01T21:48:08.448776Z","shell.execute_reply":"2023-02-01T21:48:11.357202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference","metadata":{"papermill":{"duration":0.014494,"end_time":"2023-01-18T13:00:10.691993","exception":false,"start_time":"2023-01-18T13:00:10.677499","status":"completed"},"tags":[]}},{"cell_type":"code","source":"SUBMISSION_ROWS = []\n\nfor idx, ((patient_id, laterality), g) in enumerate(tqdm(test.groupby(['patient_id', 'laterality']))):\n    cancer = 0\n    for row_idx, row in g.iterrows():\n        # Load Image\n        image_id = row['image_id']\n        image = cv2.imread(f'{image_id}.png', -1)\n        # Show First Few Images\n        if idx < 2:\n            plt.figure(figsize=(5,8))\n            plt.imshow(image)\n            plt.show()\n        \n        # Expand to Batch HxW -> 1xHxWx1\n        image = np.expand_dims(image, [0, 3])\n        # Make Prediction\n        cancer += model.predict_on_batch(image).squeeze() / len(g)\n        # Remove Image PNG\n        os.remove(f'{image_id}.png')\n        \n    # Add Submission Row\n    SUBMISSION_ROWS.append({\n        'prediction_id': f'{patient_id}_{laterality}',\n        'cancer': np.int8(cancer > THRESHOLD_BEST),\n    })","metadata":{"papermill":{"duration":19.346332,"end_time":"2023-01-18T13:00:30.052377","exception":false,"start_time":"2023-01-18T13:00:10.706045","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:48:12.188205Z","iopub.execute_input":"2023-02-01T21:48:12.189724Z","iopub.status.idle":"2023-02-01T21:48:26.61446Z","shell.execute_reply.started":"2023-02-01T21:48:12.189676Z","shell.execute_reply":"2023-02-01T21:48:26.613358Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Save Submission","metadata":{"papermill":{"duration":0.018426,"end_time":"2023-01-18T13:00:30.090525","exception":false,"start_time":"2023-01-18T13:00:30.072099","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Create DataFrame from submission rows\nsubmission_df = pd.DataFrame(SUBMISSION_ROWS)\n\ndisplay(submission_df.info())\ndisplay(submission_df.head())","metadata":{"papermill":{"duration":0.055172,"end_time":"2023-01-18T13:00:30.164946","exception":false,"start_time":"2023-01-18T13:00:30.109774","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:48:30.549781Z","iopub.execute_input":"2023-02-01T21:48:30.550171Z","iopub.status.idle":"2023-02-01T21:48:30.573834Z","shell.execute_reply.started":"2023-02-01T21:48:30.550124Z","shell.execute_reply":"2023-02-01T21:48:30.572737Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Save submission as CSV\nsubmission_df.to_csv('submission.csv', index=False)","metadata":{"papermill":{"duration":0.034625,"end_time":"2023-01-18T13:00:30.218237","exception":false,"start_time":"2023-01-18T13:00:30.183612","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:48:31.362909Z","iopub.execute_input":"2023-02-01T21:48:31.363322Z","iopub.status.idle":"2023-02-01T21:48:31.372505Z","shell.execute_reply.started":"2023-02-01T21:48:31.363286Z","shell.execute_reply":"2023-02-01T21:48:31.371508Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Sanity Check\ndisplay(pd.read_csv('submission.csv').head())","metadata":{"papermill":{"duration":0.040609,"end_time":"2023-01-18T13:00:30.278095","exception":false,"start_time":"2023-01-18T13:00:30.237486","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-02-01T21:48:47.646292Z","iopub.execute_input":"2023-02-01T21:48:47.646675Z","iopub.status.idle":"2023-02-01T21:48:47.660822Z","shell.execute_reply.started":"2023-02-01T21:48:47.646642Z","shell.execute_reply":"2023-02-01T21:48:47.659683Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"papermill":{"duration":0.019305,"end_time":"2023-01-18T13:00:30.316404","exception":false,"start_time":"2023-01-18T13:00:30.297099","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]}]}