{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":36363,"databundleVersionId":4050810,"sourceType":"competition"}],"dockerImageVersionId":30762,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install pylibjpeg\n!pip install gdcm\n!pip install pylibjpeg-libjpeg\n!pip install pillow","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:08:36.827183Z","iopub.execute_input":"2024-09-12T00:08:36.827952Z","iopub.status.idle":"2024-09-12T00:09:29.194184Z","shell.execute_reply.started":"2024-09-12T00:08:36.827896Z","shell.execute_reply":"2024-09-12T00:09:29.192978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport pydicom\nfrom tqdm import tqdm\n\n# Set up paths\nBASE_PATH = '/kaggle/input/rsna-2022-cervical-spine-fracture-detection'\nTRAIN_CSV_PATH = os.path.join(BASE_PATH, 'train.csv')\nTEST_CSV_PATH = os.path.join(BASE_PATH, 'test.csv')\nTRAIN_IMAGES_PATH = os.path.join(BASE_PATH, 'train_images')\nTEST_IMAGES_PATH = os.path.join(BASE_PATH, 'test_images')\nSEGMENTATIONS_PATH = os.path.join(BASE_PATH, 'segmentations')\nBOUNDING_BOXES_PATH = os.path.join(BASE_PATH, 'train_bounding_boxes.csv')\nSAMPLE_SUBMISSION_PATH = os.path.join(BASE_PATH, 'sample_submission.csv')\n\n# Load training data\ntrain_df = pd.read_csv(TRAIN_CSV_PATH)\nprint(\"Training data shape:\", train_df.shape)\nprint(\"\\nFirst few rows of training data:\")\nprint(train_df.head())\n\n# Explore target variables\ntarget_cols = ['patient_overall'] + [f'C{i}' for i in range(1, 8)]\nprint(\"\\nDistribution of fractures:\")\nprint(train_df[target_cols].sum())\n\n# Visualize fracture distribution\nplt.figure(figsize=(12, 6))\nsns.barplot(x=target_cols, y=train_df[target_cols].sum())\nplt.title(\"Distribution of Fractures\")\nplt.ylabel(\"Count\")\nplt.xticks(rotation=45)\nplt.tight_layout()\nplt.show()\n\n# Function to load DICOM files\ndef load_dicom(path):\n    dicom = pydicom.dcmread(path)\n    return dicom.pixel_array\n\n# Explore a sample patient's scans\ndef explore_patient_scans(patient_id):\n    patient_path = os.path.join(TRAIN_IMAGES_PATH, patient_id)\n    slices = sorted([f for f in os.listdir(patient_path) if f.endswith('.dcm')])\n    print(f\"Number of slices for patient {patient_id}: {len(slices)}\")\n    \n    # Load middle slice\n    middle_slice = load_dicom(os.path.join(patient_path, slices[len(slices)//2]))\n    print(f\"Slice shape: {middle_slice.shape}\")\n    print(f\"Pixel value range: {middle_slice.min()} to {middle_slice.max()}\")\n    \n    # Visualize middle slice\n    plt.figure(figsize=(10, 10))\n    plt.imshow(middle_slice, cmap='bone')\n    plt.title(f\"Middle slice for patient {patient_id}\")\n    plt.axis('off')\n    plt.show()\n\n# Explore a few sample patients\nsample_patients = train_df['StudyInstanceUID'].sample(3).tolist()\nfor patient in sample_patients:\n    explore_patient_scans(patient)\n\n# Load and explore bounding box data\nbounding_boxes_df = pd.read_csv(BOUNDING_BOXES_PATH)\nprint(\"\\nBounding boxes data shape:\", bounding_boxes_df.shape)\nprint(\"\\nFirst few rows of bounding boxes data:\")\nprint(bounding_boxes_df.head())\n\n# Explore segmentation files\nsegmentation_files = os.listdir(SEGMENTATIONS_PATH)\nprint(f\"\\nNumber of segmentation files: {len(segmentation_files)}\")\nprint(\"Sample segmentation file names:\")\nprint(segmentation_files[:5])\n\nprint(\"\\nInitial data exploration complete!\")","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:09:29.196554Z","iopub.execute_input":"2024-09-12T00:09:29.196892Z","iopub.status.idle":"2024-09-12T00:09:31.26696Z","shell.execute_reply.started":"2024-09-12T00:09:29.196854Z","shell.execute_reply":"2024-09-12T00:09:31.265906Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport pydicom\nfrom tqdm import tqdm\nfrom pydicom.errors import InvalidDicomError\nimport albumentations as A\nfrom scipy.ndimage import zoom\nimport gdcm\nimport pylibjpeg\n\n# Enhanced DICOM loading with error handling for compressed images\ndef load_dicom(path):\n    try:\n        dicom = pydicom.dcmread(path)\n        if dicom.file_meta.TransferSyntaxUID.is_compressed:\n            dicom.decompress()  # GDCM handles decompression\n        return dicom.pixel_array\n    except InvalidDicomError:\n        print(f\"Error loading DICOM file: {path}\")\n        return None\n    except Exception as e:\n        print(f\"Unexpected error: {e}\")\n        return None\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-09-12T00:15:48.858009Z","iopub.execute_input":"2024-09-12T00:15:48.858903Z","iopub.status.idle":"2024-09-12T00:15:53.631829Z","shell.execute_reply.started":"2024-09-12T00:15:48.858863Z","shell.execute_reply":"2024-09-12T00:15:53.630486Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_3d_volume(patient_id, image_path, target_slices=64, target_shape=(128, 128)):\n    slices = sorted([f for f in os.listdir(os.path.join(image_path, patient_id)) if f.endswith('.dcm')])\n    \n    processed_slices = []\n    for slice_file in slices:\n        slice_path = os.path.join(image_path, patient_id, slice_file)\n        slice_array = load_dicom(slice_path)\n        processed_slice = preprocess_ct_scan(slice_array, target_shape=target_shape)\n        processed_slices.append(processed_slice)\n    \n    # Stack slices to form a 3D volume\n    processed_volume = np.stack(processed_slices, axis=0)\n    \n    # Resample to target number of slices if needed\n    current_slices = processed_volume.shape[0]\n    if current_slices != target_slices:\n        resize_factor = (target_slices / current_slices, 1, 1)\n        processed_volume = zoom(processed_volume, resize_factor, order=1)\n    \n    return processed_volume","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:10:02.287095Z","iopub.execute_input":"2024-09-12T00:10:02.287965Z","iopub.status.idle":"2024-09-12T00:10:02.2974Z","shell.execute_reply.started":"2024-09-12T00:10:02.287923Z","shell.execute_reply":"2024-09-12T00:10:02.296076Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Apply windowing and clip pixel values within a given range\ndef window_image(image, window_center, window_width):\n    img_min = window_center - window_width // 2\n    img_max = window_center + window_width // 2\n    windowed_image = np.clip(image, img_min, img_max)\n    return windowed_image\n\n# Preprocess a single CT scan slice\ndef preprocess_ct_scan(scan, target_shape=(224, 224), window_width=1800, window_level=400):\n    # Check if scan is loaded\n    if scan is None:\n        return None\n    \n    # Apply windowing\n    windowed_scan = window_image(scan, window_level, window_width)\n    \n    # Resize to target shape\n    resize_factor = (target_shape[0] / scan.shape[0], target_shape[1] / scan.shape[1])\n    resized_scan = zoom(windowed_scan, resize_factor, order=1)\n    \n    # Normalize to [0, 1]\n    normalized_scan = (resized_scan - resized_scan.min()) / (resized_scan.max() - resized_scan.min())\n    \n    return normalized_scan\n","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:09:31.287057Z","iopub.execute_input":"2024-09-12T00:09:31.287404Z","iopub.status.idle":"2024-09-12T00:09:31.297918Z","shell.execute_reply.started":"2024-09-12T00:09:31.287368Z","shell.execute_reply":"2024-09-12T00:09:31.296983Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Split an image into patches, handling edge cases for non-divisible image sizes\ndef split_into_patches(image, patch_size=16):\n    patches = []\n    for i in range(0, image.shape[0] - patch_size + 1, patch_size):\n        for j in range(0, image.shape[1] - patch_size + 1, patch_size):\n            patch = image[i:i + patch_size, j:j + patch_size]\n            if patch.shape == (patch_size, patch_size):  # Check if the patch has the correct shape\n                patches.append(patch)\n    return np.array(patches)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:12:02.454413Z","iopub.execute_input":"2024-09-12T00:12:02.454772Z","iopub.status.idle":"2024-09-12T00:12:02.461853Z","shell.execute_reply.started":"2024-09-12T00:12:02.454733Z","shell.execute_reply":"2024-09-12T00:12:02.460872Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install torchio","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:11:49.223173Z","iopub.execute_input":"2024-09-12T00:11:49.224065Z","iopub.status.idle":"2024-09-12T00:12:02.452223Z","shell.execute_reply.started":"2024-09-12T00:11:49.224026Z","shell.execute_reply":"2024-09-12T00:12:02.450942Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torchio as tio\nfrom sklearn.model_selection import train_test_split\nimport numpy as np\n\n# Augmentation function using TorchIO\ndef augment_3d_volume(volume):\n    # Define augmentations\n    augmentations = tio.Compose([\n        tio.RandomAffine(scales=(0.9, 1.1), degrees=10, translation=(10, 10, 10), p=1),\n        tio.RandomFlip(axes=(0, 1), flip_probability=0.5),\n        tio.RandomElasticDeformation(num_control_points=7, max_displacement=7.5, p=0.5),\n        tio.RandomBlur(std=(0.1, 5), p=0.5),\n        tio.RandomNoise(mean=0, std=(0, 0.1), p=0.5)\n    ])\n    \n    # Apply augmentations to the volume\n    augmented_volume = augmentations(volume)\n    return augmented_volume\n\n# Updated function to apply 3D augmentation on a batch of volumes\ndef batch_augment_3d_volumes(volumes):\n    augmented_volumes = []\n    for volume in volumes:\n        # Convert NumPy array to TorchIO ScalarImage for 3D augmentation\n        volume_tio = tio.ScalarImage(tensor=volume[np.newaxis, ...])  # Add channel dimension\n        augmented_volume = augment_3d_volume(volume_tio)\n        augmented_volumes.append(augmented_volume.tensor.numpy()[0])  # Convert back to NumPy array\n    return np.array(augmented_volumes)\n\n# Main preprocessing pipeline with 3D augmentation\ndef preprocess_pipeline_3d(train_df, image_path, target_cols, test_size=0.2, balance=True):\n    print(\"Preparing data...\")\n    X, y = prepare_data(train_df, image_path, target_cols)  # Assume prepare_data handles volume loading\n    \n    print(\"Splitting data...\")\n    X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=test_size, random_state=42)\n    \n    if balance:\n        print(\"Balancing dataset...\")\n        X_train, y_train = balance_dataset(X_train, y_train)  # Balance the dataset if needed\n    \n    print(\"Augmenting training data with 3D augmentations...\")\n    X_train_aug = batch_augment_3d_volumes(X_train)  # Apply 3D augmentation to the training set\n    \n    return X_train_aug, X_val, y_train, y_val\n","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:16:06.613688Z","iopub.execute_input":"2024-09-12T00:16:06.614083Z","iopub.status.idle":"2024-09-12T00:16:06.626471Z","shell.execute_reply.started":"2024-09-12T00:16:06.614046Z","shell.execute_reply":"2024-09-12T00:16:06.625128Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nfrom torch.utils.data import Dataset, DataLoader\nimport random\nimport numpy as np\nimport torchvision.transforms as transforms\n\nclass MedicalImageDataset(Dataset):\n    def __init__(self, df, TRAIN_IMAGES_PATH, transform=None):\n        self.df = df\n        self.image_path = TRAIN_IMAGES_PATH\n        self.transform = transform\n    \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, idx):\n        # Load patient volume (you can replace this with actual 3D volume loading logic)\n        patient_id = self.df.iloc[idx]['StudyInstanceUID']\n        patient_volume = load_3d_volume(patient_id, self.image_path)  # Custom function\n        \n        # Apply transformation (augmentation) if available\n        if self.transform:\n            patient_volume = self.transform(patient_volume)\n        \n        label = self.df.iloc[idx]['label']  # Assuming labels are in the DataFrame\n        return patient_volume, label\n\n# Example augmentation using torchvision.transforms\ndef augment_3d_volume(volume):\n    # Define augmentations\n    transform = transforms.Compose([\n        transforms.RandomRotation(degrees=10),\n        transforms.RandomAffine(degrees=0, translate=(0.1, 0.1)),\n        transforms.RandomHorizontalFlip(p=0.5),\n        transforms.RandomVerticalFlip(p=0.5),\n        transforms.GaussianBlur(kernel_size=(5, 9), sigma=(0.1, 5))\n    ])\n    return transform(volume)\n\n# Load dataset and create DataLoader\ntrain_dataset = MedicalImageDataset(train_df, TRAIN_IMAGES_PATH, transform=augment_3d_volume)\ntrain_loader = DataLoader(train_dataset, batch_size=4, shuffle=True, num_workers=4)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:12:13.269998Z","iopub.execute_input":"2024-09-12T00:12:13.270842Z","iopub.status.idle":"2024-09-12T00:12:13.282853Z","shell.execute_reply.started":"2024-09-12T00:12:13.270803Z","shell.execute_reply":"2024-09-12T00:12:13.281987Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\n# Split the training data into train and validation sets\ntrain_df, val_df = train_test_split(train_df, test_size=0.2, random_state=42)\n\n# Create training and validation datasets\ntrain_dataset = MedicalImageDataset(train_df, TRAIN_IMAGES_PATH, transform=augment_3d_volume)\nval_dataset = MedicalImageDataset(val_df, TRAIN_IMAGES_PATH, transform=None)\n\n# Data loaders for training and validation\ntrain_loader = DataLoader(train_dataset, batch_size=4, shuffle=True, num_workers=4)\nval_loader = DataLoader(val_dataset, batch_size=4, shuffle=False, num_workers=4)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:12:33.266163Z","iopub.execute_input":"2024-09-12T00:12:33.266593Z","iopub.status.idle":"2024-09-12T00:12:33.275714Z","shell.execute_reply.started":"2024-09-12T00:12:33.266555Z","shell.execute_reply":"2024-09-12T00:12:33.274704Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\n\nclass Simple3DCNN(nn.Module):\n    def __init__(self):\n        super(Simple3DCNN, self).__init__()\n        self.conv1 = nn.Conv3d(1, 32, kernel_size=3, padding=1)\n        self.conv2 = nn.Conv3d(32, 64, kernel_size=3, padding=1)\n        self.fc1 = nn.Linear(64 * 28 * 28 * 28, 512)  # Adjust based on the input size\n        self.fc2 = nn.Linear(512, 1)\n\n    def forward(self, x):\n        x = torch.relu(self.conv1(x))\n        x = torch.max_pool3d(x, 2)\n        x = torch.relu(self.conv2(x))\n        x = torch.max_pool3d(x, 2)\n        x = x.view(x.size(0), -1)\n        x = torch.relu(self.fc1(x))\n        x = torch.sigmoid(self.fc2(x))\n        return x\n\n# Instantiate model\nmodel = Simple3DCNN().cuda()\n\n# Define loss and optimizer\ncriterion = nn.BCELoss()\noptimizer = optim.Adam(model.parameters(), lr=0.001)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:12:42.53632Z","iopub.execute_input":"2024-09-12T00:12:42.537229Z","iopub.status.idle":"2024-09-12T00:12:49.218611Z","shell.execute_reply.started":"2024-09-12T00:12:42.537167Z","shell.execute_reply":"2024-09-12T00:12:49.217546Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install pydicom gdcm pylibjpeg pylibjpeg-libjpeg\n","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:13:59.78382Z","iopub.execute_input":"2024-09-12T00:13:59.784207Z","iopub.status.idle":"2024-09-12T00:14:12.962615Z","shell.execute_reply.started":"2024-09-12T00:13:59.784169Z","shell.execute_reply":"2024-09-12T00:14:12.96154Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pydicom\nimport gdcm\nimport pylibjpeg\n\ndef train_one_epoch(model, loader, optimizer, criterion, device):\n    model.train()\n    running_loss = 0.0\n    for inputs, labels in loader:\n        inputs, labels = inputs.to(device), labels.to(device)\n\n        optimizer.zero_grad()\n\n        # Forward pass\n        outputs = model(inputs)\n        loss = criterion(outputs, labels)\n        running_loss += loss.item()\n\n        # Backward pass and optimization\n        loss.backward()\n        optimizer.step()\n\n    return running_loss / len(loader)\n\n\ndef validate_one_epoch(model, loader, criterion, device):\n    model.eval()\n    val_loss = 0.0\n    with torch.no_grad():\n        for inputs, labels in loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n            val_loss += loss.item()\n\n    return val_loss / len(loader)\n\n# Training loop\nnum_epochs = 10\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\nfor epoch in range(num_epochs):\n    train_loss = train_one_epoch(model, train_loader, optimizer, criterion, device)\n    val_loss = validate_one_epoch(model, val_loader, criterion, device)\n\n    print(f\"Epoch {epoch+1}/{num_epochs}, Train Loss: {train_loss:.4f}, Validation Loss: {val_loss:.4f}\")\n","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:18:05.950619Z","iopub.execute_input":"2024-09-12T00:18:05.95148Z","iopub.status.idle":"2024-09-12T00:18:08.929042Z","shell.execute_reply.started":"2024-09-12T00:18:05.951438Z","shell.execute_reply":"2024-09-12T00:18:08.927629Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_and_preprocess_patient(patient_id, image_path, target_slices=64):\n    patient_path = os.path.join(image_path, patient_id)\n    slices = sorted([f for f in os.listdir(patient_path) if f.endswith('.dcm')])\n    \n    processed_slices = []\n    for slice_file in slices:\n        slice_path = os.path.join(patient_path, slice_file)\n        slice_array = load_dicom(slice_path)\n        processed_slice = preprocess_ct_scan(slice_array)\n        if processed_slice is not None:\n            processed_slices.append(processed_slice)\n    \n    if len(processed_slices) == 0:\n        return None\n    \n    # Resample volume to target number of slices\n    processed_volume = np.array(processed_slices)\n    current_slices = processed_volume.shape[0]\n    \n    if current_slices != target_slices:\n        resize_factor = (target_slices / current_slices, 1, 1)\n        processed_volume = zoom(processed_volume, resize_factor, order=1)\n    \n    # Split each slice into patches\n    patched_volume = np.array([split_into_patches(slice) for slice in processed_volume])\n    \n    return patched_volume\n","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:09:54.658096Z","iopub.status.idle":"2024-09-12T00:09:54.658727Z","shell.execute_reply.started":"2024-09-12T00:09:54.658421Z","shell.execute_reply":"2024-09-12T00:09:54.658459Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from imblearn.over_sampling import SMOTE\nfrom sklearn.model_selection import train_test_split\n\n# Prepare data by loading and preprocessing patients' scans\ndef prepare_data(df, image_path, target_cols, n_samples=None):\n    if n_samples:\n        df = df.sample(n_samples, random_state=42)\n    \n    X = []\n    y = df[target_cols].values\n    \n    for patient_id in tqdm(df['StudyInstanceUID']):\n        patient_volume = load_and_preprocess_patient(patient_id, image_path)\n        if patient_volume is not None:\n            X.append(patient_volume)\n    \n    X = np.array(X)\n    return X, y\n\n# Balance dataset using SMOTE\ndef balance_dataset(X, y):\n    n_samples, n_slices, n_patches, h, w = X.shape\n    X_flat = X.reshape((n_samples, -1))  # Flatten for SMOTE\n    \n    smote = SMOTE(random_state=42)\n    X_resampled, y_resampled = smote.fit_resample(X_flat, y)\n    \n    # Reshape X back to original shape\n    X_balanced = X_resampled.reshape((-1, n_slices, n_patches, h, w))\n    \n    return X_balanced, y_resampled\n","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:09:54.66046Z","iopub.status.idle":"2024-09-12T00:09:54.660991Z","shell.execute_reply.started":"2024-09-12T00:09:54.660717Z","shell.execute_reply":"2024-09-12T00:09:54.660743Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Main preprocessing pipeline\ndef preprocess_pipeline(train_df, image_path, target_cols, test_size=0.2, balance=True):\n    print(\"Preparing data...\")\n    X, y = prepare_data(train_df, image_path, target_cols)\n    \n    print(\"Splitting data...\")\n    X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=test_size, random_state=42)\n    \n    if balance:\n        print(\"Balancing dataset...\")\n        X_train, y_train = balance_dataset(X_train, y_train)\n    \n    print(\"Augmenting data...\")\n    X_train_aug = batch_augment_volumes(X_train)\n    \n    return X_train_aug, X_val, y_train, y_val\n","metadata":{"execution":{"iopub.status.busy":"2024-09-12T00:09:54.663247Z","iopub.status.idle":"2024-09-12T00:09:54.663937Z","shell.execute_reply.started":"2024-09-12T00:09:54.663606Z","shell.execute_reply":"2024-09-12T00:09:54.663635Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}