{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":30892,"databundleVersionId":2715462,"sourceType":"competition"}],"dockerImageVersionId":30580,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install torchsummary\n!pip install torchgeometry\n\nfrom torchsummary import summary\nfrom torchgeometry.losses import one_hot\nimport os\nimport pandas as pd\nimport numpy as np\nfrom PIL import Image\nimport cv2\nimport time\nimport imageio\nimport matplotlib.pyplot as plt\nimport time\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom torch.optim import lr_scheduler\nfrom torch import Tensor\nfrom torch.utils.data import Dataset, DataLoader, random_split\nfrom torchvision.transforms import Resize, PILToTensor, ToPILImage, Compose, InterpolationMode, CenterCrop\nfrom collections import OrderedDict\nfrom PIL import ImageFilter\nimport random\nimport wandb\n","metadata":{"_uuid":"1464907c-2d4f-4afb-9e0b-59c585a1494f","_cell_guid":"bb84faf7-9dce-4f90-a4d3-a8c05e26e1c2","execution":{"iopub.status.busy":"2023-11-17T10:30:05.610664Z","iopub.execute_input":"2023-11-17T10:30:05.611171Z","iopub.status.idle":"2023-11-17T10:30:35.070088Z","shell.execute_reply.started":"2023-11-17T10:30:05.611142Z","shell.execute_reply":"2023-11-17T10:30:35.069223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# import tensorflow as tf\n# from tensorflow.compat.v1 import InteractiveSession\n\n# # Clear any logs from previous runs\n# tf.keras.backend.clear_session()\n# config = tf.compat.v1.ConfigProto()\n# config.gpu_options.allow_growth = True\n# session = InteractiveSession(config=config)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:35.071582Z","iopub.execute_input":"2023-11-17T10:30:35.071858Z","iopub.status.idle":"2023-11-17T10:30:35.076041Z","shell.execute_reply.started":"2023-11-17T10:30:35.071833Z","shell.execute_reply":"2023-11-17T10:30:35.075092Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!nvidia-smi -L\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\ndevice","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:35.077081Z","iopub.execute_input":"2023-11-17T10:30:35.077321Z","iopub.status.idle":"2023-11-17T10:30:36.051157Z","shell.execute_reply.started":"2023-11-17T10:30:35.077299Z","shell.execute_reply":"2023-11-17T10:30:36.050052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Number of class in the data set (3: neoplastic, non neoplastic, background)\nnum_classes = 3\n\n# Number of epoch\nepochs = 30\n\n# Hyperparameters for training \nlearning_rate = 2e-04\nbatch_size = 4\ndisplay_step = 50\n\n# Model path\ncheckpoint_path = '/kaggle/working/unet_model.pth'\npretrained_path = \"/kaggle/input/unet-checkpoint/unet_model.pth\"\n# Initialize lists to keep track of loss and accuracy\nloss_epoch_array = []\ntrain_accuracy = []\ntest_accuracy = []\nvalid_accuracy = []","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.054433Z","iopub.execute_input":"2023-11-17T10:30:36.054844Z","iopub.status.idle":"2023-11-17T10:30:36.060046Z","shell.execute_reply.started":"2023-11-17T10:30:36.054807Z","shell.execute_reply":"2023-11-17T10:30:36.059230Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"transform = Compose([CenterCrop(1024),\n                     Resize((512, 512), interpolation=InterpolationMode.BILINEAR),\n                     PILToTensor()])","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.061250Z","iopub.execute_input":"2023-11-17T10:30:36.061852Z","iopub.status.idle":"2023-11-17T10:30:36.076665Z","shell.execute_reply.started":"2023-11-17T10:30:36.061819Z","shell.execute_reply":"2023-11-17T10:30:36.075811Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class UNetDataClass(Dataset):\n    def __init__(self, images_path, masks_path, transform, blur_radius=2, rotation_angle = 180):\n        super(UNetDataClass, self).__init__()\n        \n        images_list = os.listdir(images_path)\n        masks_list = os.listdir(masks_path)\n        \n        images_list = [images_path + image_name for image_name in images_list]\n        masks_list = [masks_path + mask_name for mask_name in masks_list]\n        \n        self.images_list = images_list\n        self.masks_list = masks_list\n        self.transform = transform\n        self.blur_radius = blur_radius\n        self.rotation_angle = rotation_angle\n    def __getitem__(self, index):\n        img_path = self.images_list[index]\n        mask_path = self.masks_list[index]\n        \n        # Open image and mask\n        data = Image.open(img_path)\n        label = Image.open(mask_path)\n        \n        #Additional Gaussian blur\n        data = data.filter(ImageFilter.GaussianBlur(self.blur_radius))\n        \n        # Additional Random Rotation\n        if self.rotation_angle > 0:\n            random_angle = random.uniform(-self.rotation_angle, self.rotation_angle)\n            data = data.rotate(random_angle)\n            label = label.rotate(random_angle)\n        \n        # Normalize\n        data = self.transform(data) / 255\n        label = self.transform(label) / 255\n        \n        label = torch.where(label>0.65, 1.0, 0.0)\n        \n        label[2, :, :] = 0.0001\n        label = torch.argmax(label, 0).type(torch.int64)\n        \n        return data, label\n    \n    def __len__(self):\n        return len(self.images_list)\n","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.077661Z","iopub.execute_input":"2023-11-17T10:30:36.077888Z","iopub.status.idle":"2023-11-17T10:30:36.088901Z","shell.execute_reply.started":"2023-11-17T10:30:36.077867Z","shell.execute_reply":"2023-11-17T10:30:36.088110Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images_path = \"/kaggle/input/bkai-igh-neopolyp/train/train/\"\nmasks_path =  \"/kaggle/input/bkai-igh-neopolyp/train_gt/train_gt/\"\n\nunet_dataset = UNetDataClass(images_path, masks_path, transform)\n\ntrain_size = 0.8\nvalid_size = 0.2\n\ntrain_set, valid_set = random_split(unet_dataset, \n                                    [int(train_size * len(unet_dataset)) , \n                                     int(valid_size * len(unet_dataset))])","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.089859Z","iopub.execute_input":"2023-11-17T10:30:36.090106Z","iopub.status.idle":"2023-11-17T10:30:36.380562Z","shell.execute_reply.started":"2023-11-17T10:30:36.090083Z","shell.execute_reply":"2023-11-17T10:30:36.379606Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataloader = DataLoader(train_set, batch_size=batch_size, shuffle=True)\nvalid_dataloader = DataLoader(valid_set, batch_size=batch_size, shuffle=True)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.381803Z","iopub.execute_input":"2023-11-17T10:30:36.382090Z","iopub.status.idle":"2023-11-17T10:30:36.386983Z","shell.execute_reply.started":"2023-11-17T10:30:36.382064Z","shell.execute_reply":"2023-11-17T10:30:36.386103Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class inception_block_same(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super(inception_block_same, self).__init__()\n        #[inp]->[conv 5x5]->[out]\n        self.conv5_1 = nn.Conv2d(in_channels, out_channels//16, kernel_size=1, stride=1, padding='same')\n        self.conv5 = nn.Conv2d(out_channels//16, out_channels//4, kernel_size=5, stride=1, padding='same')\n        #[inp]->[conv 3x3]->[out]\n        self.conv3_1 = nn.Conv2d(in_channels, out_channels//4, kernel_size=1, stride=1, padding='same')\n        self.conv3 = nn.Conv2d(out_channels//4, out_channels//4, kernel_size=3, stride=1, padding='same')\n        #[inp]->([conv 3x1]+[conv 1x3])->[conv 3x3]->[out]\n        self.conv33_1 = nn.Conv2d(in_channels, out_channels//8, kernel_size=1, stride=1, padding='same')\n        self.conv33_h = nn.Conv2d(out_channels//8, out_channels//4, kernel_size=(3,1), stride=1, padding='same')\n        self.conv33_v = nn.Conv2d(out_channels//8, out_channels//4, kernel_size=(1,3), stride=1, padding='same')\n        self.conv33_c = nn.Conv2d(out_channels//2, out_channels//4, kernel_size=(3,3), stride=1, padding='same')\n        #[inp]->[maxpool]->[out]\n        self.pool_1 = nn.Conv2d(in_channels, out_channels//8, kernel_size=1, stride=1, padding='same')\n        self.pool = nn.MaxPool2d(kernel_size=(3,3), stride=1, padding = 1)\n        #[inp]->[out]\n        self.conv1_1 = nn.Conv2d(in_channels, out_channels//8, kernel_size=1, stride=1, padding='same')\n        self.ReLU = nn.ReLU()\n        \n        \n    def forward(self, x):\n        #[inp]->[conv 5x5]->[out]        \n        l1 = self.conv5_1(x)\n        l1 = self.conv5(l1)\n        l1 = self.ReLU(l1)\n        #[inp]->[conv 3x3]->[out]\n        l2 = self.conv3_1(x)\n        l2 = self.conv3(l2)\n        l2 = self.ReLU(l2)\n        #[inp]->([conv 3x1]+[conv 1x3])->[conv 3x3]->[out]\n        l3 = self.conv33_1(x)\n        \n        l31 = self.conv33_h(l3)\n        l31 = self.ReLU(l31)\n        l32 = self.conv33_v(l3)\n        l32 = self.ReLU(l32)\n        \n        l3 = torch.cat([l31,l32],axis=1)\n        l3 = self.conv33_c(l3)\n        l3 = self.ReLU(l3)\n        #[inp]->[maxpool]->[out]\n        l4 = self.pool_1(x)\n        l4 = self.ReLU(l4)\n        l4 = self.pool(l4)\n        #[inp]->[out]\n        l5 = self.conv1_1(x)\n        l5 = self.ReLU(l5)\n        out = torch.cat([l1,l2,l3,l4,l5],axis=1)\n        return out","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.388195Z","iopub.execute_input":"2023-11-17T10:30:36.388454Z","iopub.status.idle":"2023-11-17T10:30:36.405740Z","shell.execute_reply.started":"2023-11-17T10:30:36.388431Z","shell.execute_reply":"2023-11-17T10:30:36.404888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#TeSt = inception_block_same(3, 16)\n#summary(TeSt, (64,512,512))","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.409014Z","iopub.execute_input":"2023-11-17T10:30:36.409281Z","iopub.status.idle":"2023-11-17T10:30:36.419479Z","shell.execute_reply.started":"2023-11-17T10:30:36.409257Z","shell.execute_reply":"2023-11-17T10:30:36.418661Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class inception_block_down(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super(inception_block_down, self).__init__()\n        #[inp]->[conv 5x5]->[out]\n        self.conv5_1 = nn.Conv2d(in_channels, out_channels//16, kernel_size=1, stride=1, padding='same')\n        self.conv5 = nn.Conv2d(out_channels//16, out_channels//4, kernel_size=5, stride=2, padding=2)\n        #[inp]->[conv 3x3]->[out]\n        self.conv3_1 = nn.Conv2d(in_channels, out_channels//4, kernel_size=1, stride=1, padding='same')\n        self.conv3 = nn.Conv2d(out_channels//4, out_channels//4, kernel_size=3, stride=2, padding=1)\n        #[inp]->([conv 3x1]+[conv 1x3])->[conv 3x3]->[out]\n        self.conv33_1 = nn.Conv2d(in_channels, out_channels//8, kernel_size=1, stride=1, padding='same')\n        self.conv33_h = nn.Conv2d(out_channels//8, out_channels//4, kernel_size=(3,1), stride=1, padding='same')\n        self.conv33_v = nn.Conv2d(out_channels//8, out_channels//4, kernel_size=(1,3), stride=1, padding='same')\n        self.conv33_c = nn.Conv2d(out_channels//2, out_channels//4, kernel_size=(3,3), stride=2, padding=1)\n        #[inp]->[maxpool]->[out]\n        self.pool_1 = nn.Conv2d(in_channels, out_channels//4, kernel_size=1, stride=1, padding='same')\n        self.pool = nn.MaxPool2d(kernel_size=2, stride=2,return_indices=True)\n        \n        self.ReLU = nn.ReLU()\n        \n        \n    def forward(self, x):\n        #[inp]->[conv 5x5]->[out]\n        l1 = self.conv5_1(x)\n        l1 = self.conv5(l1)\n        l1 = self.ReLU(l1)\n        #[inp]->[conv 3x3]->[out]\n        l2 = self.conv3_1(x)\n        l2 = self.conv3(l2)\n        l2 = self.ReLU(l2)\n        #[inp]->([conv 3x1]+[conv 1x3])->[conv 3x3]->[out]\n        l3 = self.conv33_1(x)\n        \n        l31 = self.conv33_h(l3)\n        l31 = self.ReLU(l31)\n        l32 = self.conv33_v(l3)\n        l32 = self.ReLU(l32)\n        \n        l3 = torch.cat([l31,l32],axis=1)\n        l3 = self.conv33_c(l3)\n        l3 = self.ReLU(l3)\n        #[inp]->[maxpool]->[out]\n        l4 = self.pool_1(x)\n        l4 = self.ReLU(l4)\n        l4, indices = self.pool(l4)\n        \n        out = torch.cat([l1,l2,l3,l4],axis=1)\n        return out, indices","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.420598Z","iopub.execute_input":"2023-11-17T10:30:36.420854Z","iopub.status.idle":"2023-11-17T10:30:36.434865Z","shell.execute_reply.started":"2023-11-17T10:30:36.420832Z","shell.execute_reply":"2023-11-17T10:30:36.433989Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class inception_block_up(nn.Module):\n    def __init__(self, in_channels, out_channels, skip_channels):\n        super(inception_block_up, self).__init__()\n        #[inp]->[transposeconv 5x5]->[out]\n        self.conv5_1 = nn.Conv2d(in_channels, out_channels//16, kernel_size=(1,1), stride=1, padding='same')\n        self.conv5 = nn.ConvTranspose2d(out_channels//16, out_channels//4, kernel_size=(5,5), stride=2, padding=2, output_padding=1)\n        #[inp]->[transposeconv 2x2]->[out]\n        self.conv2_1 = nn.Conv2d(in_channels, out_channels//4, kernel_size=(1,1), stride=1, padding='same')\n        self.conv2 = nn.ConvTranspose2d(out_channels//4, out_channels//2, kernel_size=(2,2), stride=2)\n        #[inp]->[unmaxpool 2x2]->[out]\n        self.pool_1 = nn.Conv2d(in_channels, skip_channels//4, kernel_size=(1,1), stride=1, padding='same')\n        self.pool = nn.MaxUnpool2d(kernel_size=(2,2), stride=2)\n        self.pool_a = nn.Conv2d(skip_channels//4, out_channels//4, kernel_size=1, stride=1, padding='same')\n        \n        self.ReLU = nn.ReLU()\n        \n        \n    def forward(self, x, indices):\n        #[inp]->[transposeconv 5x5]->[out]\n        l1 = self.conv5_1(x)\n        l1 = self.conv5(l1)\n        l1 = self.ReLU(l1)\n        #[inp]->[transposeconv 2x2]->[out]\n        l2 = self.conv2_1(x)\n        l2 = self.conv2(l2)\n        l2 = self.ReLU(l2)\n        #[inp]->[unmaxpool 2x2]->[out]        \n        l3 = self.pool_1(x)\n        l3 = self.ReLU(l3)\n        l3 = self.pool(l3, indices)\n        l3 = self.pool_a(l3)\n        l3 = self.ReLU(l3)\n        \n        out = torch.cat([l1,l2,l3],axis=1)\n        return out","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.436209Z","iopub.execute_input":"2023-11-17T10:30:36.436461Z","iopub.status.idle":"2023-11-17T10:30:36.450390Z","shell.execute_reply.started":"2023-11-17T10:30:36.436439Z","shell.execute_reply":"2023-11-17T10:30:36.449537Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class encoder(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super(encoder, self).__init__()\n        self.same = inception_block_same(in_channels, out_channels)\n        self.down = inception_block_down(out_channels, out_channels)\n    def forward(self, x):\n        skip = self.same(x)\n        out, indices = self.down(skip)\n        return out, skip, indices\n        \n        \nclass decoder(nn.Module):\n    def __init__(self, in_channels, out_channels, skip_channels):\n        super(decoder, self).__init__()\n        self.up = inception_block_up(in_channels, out_channels, skip_channels)\n        self.same = inception_block_same(out_channels+skip_channels, out_channels)\n    def forward(self, x, skip, indices):\n        x = self.up(x, indices)\n        catted = torch.cat([x, skip], axis=1)\n        out = self.same(catted)\n        return out\n        ","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.451596Z","iopub.execute_input":"2023-11-17T10:30:36.451913Z","iopub.status.idle":"2023-11-17T10:30:36.463744Z","shell.execute_reply.started":"2023-11-17T10:30:36.451882Z","shell.execute_reply":"2023-11-17T10:30:36.463054Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class UnetModel(nn.Module):\n    def __init__(self, n_class=3):\n        super(UnetModel, self).__init__()\n        #5 encoder:\n        self.enc1 = encoder(3,16)\n        self.enc2 = encoder(16,32)\n        self.enc3 = encoder(32,64)\n        self.enc4 = encoder(64,128)\n        self.enc5 = encoder(128,256)\n        #2 same block\n        self.same1 = inception_block_same(256,512)\n        self.same2 = inception_block_same(512,1024)\n        #5 decoder\n        self.dec5 = decoder(1024,512,256)\n        self.dec4 = decoder(512,256,128)\n        self.dec3 = decoder(256,128,64)\n        self.dec2 = decoder(128,64,32)\n        self.dec1 = decoder(64,32,16)\n        #conv 1x1\n        self.out = nn.Conv2d(32, n_class, kernel_size=1, padding='same')\n    \n    def forward(self, image):\n        o1, s1, i1 = self.enc1(image)\n        o2, s2, i2 = self.enc2(o1)\n        o3, s3, i3 = self.enc3(o2)\n        o4, s4, i4 = self.enc4(o3)\n        o5, s5, i5 = self.enc5(o4)\n        \n        b1 = self.same1(o5)\n        b2 = self.same2(b1)\n        \n        d5 = self.dec5(b2, s5, i5)\n        d4 = self.dec4(d5, s4, i4)\n        d3 = self.dec3(d4, s3, i3)\n        d2 = self.dec2(d3, s2, i2)\n        d1 = self.dec1(d2, s1, i1)\n        \n        ret = self.out(d1)\n        \n        return ret\n        ","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.464751Z","iopub.execute_input":"2023-11-17T10:30:36.465020Z","iopub.status.idle":"2023-11-17T10:30:36.478612Z","shell.execute_reply.started":"2023-11-17T10:30:36.464990Z","shell.execute_reply":"2023-11-17T10:30:36.477775Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"class encoder_block(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super(encoder_block, self).__init__()\n        \n        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding='same')\n        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding='same')\n        \n        self.bn1 = nn.BatchNorm2d(out_channels)\n        self.bn2 = nn.BatchNorm2d(out_channels)\n        \n        self.relu = nn.ReLU()\n        self.dropout = nn.Dropout(p=0.3)\n        self.max_pool = nn.MaxPool2d(kernel_size=2, stride=2)\n        \n    def forward(self, x):\n        x = self.conv1(x)\n        x = self.bn1(x)\n        x = self.relu(x)\n        \n        x = self.dropout(x)\n        \n        x = self.conv2(x)\n        x = self.bn2(x)\n        x = self.relu(x)\n        \n        next_layer = self.max_pool(x)\n        skip_layer = x\n        \n        return next_layer, skip_layer","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:21:38.694569Z","iopub.execute_input":"2023-11-16T06:21:38.694981Z","iopub.status.idle":"2023-11-16T06:21:38.707585Z","shell.execute_reply.started":"2023-11-16T06:21:38.694942Z","shell.execute_reply":"2023-11-16T06:21:38.706628Z"}}},{"cell_type":"markdown","source":"class decoder_block(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super(decoder_block, self).__init__()\n        \n        self.transpose_conv = nn.ConvTranspose2d(in_channels, out_channels, kernel_size=2, stride=2)\n        \n        self.conv1 = nn.Conv2d(2 * out_channels, out_channels, kernel_size=3, stride=1, padding='same')\n        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding='same')\n        \n        self.bn1 = nn.BatchNorm2d(out_channels)\n        self.bn2 = nn.BatchNorm2d(out_channels)\n        \n        self.relu = nn.ReLU() \n        self.dropout = nn.Dropout(p=0.3)\n    \n    def forward(self, x, skip_layer):\n        x = self.transpose_conv(x)\n        x = torch.cat([x, skip_layer], axis=1)\n        \n        x = self.conv1(x)\n        x = self.bn1(x)\n        x = self.relu(x)\n        \n        x = self.dropout(x)\n        \n        x = self.conv2(x)\n        x = self.bn2(x)\n        x = self.relu(x)\n        \n        return x","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:21:38.712799Z","iopub.execute_input":"2023-11-16T06:21:38.713125Z","iopub.status.idle":"2023-11-16T06:21:38.723087Z","shell.execute_reply.started":"2023-11-16T06:21:38.713074Z","shell.execute_reply":"2023-11-16T06:21:38.722164Z"}}},{"cell_type":"markdown","source":"class bottleneck_block(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super(bottleneck_block, self).__init__()\n        \n        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding='same')\n        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding='same')\n        \n        self.bn1 = nn.BatchNorm2d(out_channels)\n        self.bn2 = nn.BatchNorm2d(out_channels)\n        \n        self.relu = nn.ReLU()\n        self.dropout = nn.Dropout(p=0.3)\n        \n    def forward(self, x):\n        x = self.conv1(x)\n        x = self.bn1(x)\n        x = self.relu(x)\n        \n        x = self.dropout(x)\n        \n        x = self.conv2(x)\n        x = self.bn2(x)\n        x = self.relu(x)\n        \n        return x","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:21:38.724468Z","iopub.execute_input":"2023-11-16T06:21:38.724791Z","iopub.status.idle":"2023-11-16T06:21:38.734701Z","shell.execute_reply.started":"2023-11-16T06:21:38.724764Z","shell.execute_reply":"2023-11-16T06:21:38.733853Z"}}},{"cell_type":"markdown","source":"# UNet model\nclass UNet(nn.Module):\n    def __init__(self, n_class=3):\n        super(UNet, self).__init__()\n        # Encoder blocks\n        self.enc1 = encoder_block(3, 64)\n        self.enc2 = encoder_block(64, 128)\n        self.enc3 = encoder_block(128, 256)\n        self.enc4 = encoder_block(256, 512)\n        \n        # Bottleneck block\n        self.bottleneck = bottleneck_block(512, 1024)\n        \n        # Decoder blocks\n        self.dec1 = decoder_block(1024, 512)\n        self.dec2 = decoder_block(512, 256)\n        self.dec3 = decoder_block(256, 128)\n        self.dec4 = decoder_block(128, 64)\n        \n        # 1x1 convolution\n        self.out = nn.Conv2d(64, n_class, kernel_size=1, padding='same')\n        \n    def forward(self, image):\n        n1, s1 = self.enc1(image)\n        n2, s2 = self.enc2(n1)\n        n3, s3 = self.enc3(n2)\n        n4, s4 = self.enc4(n3)\n        \n        n5 = self.bottleneck(n4)\n        \n        n6 = self.dec1(n5, s4)\n        n7 = self.dec2(n6, s3)\n        n8 = self.dec3(n7, s2)\n        n9 = self.dec4(n8, s1)\n        \n        output = self.out(n9)\n        \n        return output","metadata":{"execution":{"iopub.status.busy":"2023-11-17T09:02:54.797801Z","iopub.execute_input":"2023-11-17T09:02:54.798097Z","iopub.status.idle":"2023-11-17T09:02:54.811414Z","shell.execute_reply.started":"2023-11-17T09:02:54.798072Z","shell.execute_reply":"2023-11-17T09:02:54.810568Z"}}},{"cell_type":"code","source":"class CEDiceLoss(nn.Module):\n    def __init__(self, weights) -> None:\n        super(CEDiceLoss, self).__init__()\n        self.eps: float = 1e-6\n        self.weights: torch.Tensor = weights\n\n    def forward(\n            self,\n            input: torch.Tensor,\n            target: torch.Tensor) -> torch.Tensor:\n        if not torch.is_tensor(input):\n            raise TypeError(\"Input type is not a torch.Tensor. Got {}\"\n                            .format(type(input)))\n        if not len(input.shape) == 4:\n            raise ValueError(\"Invalid input shape, we expect BxNxHxW. Got: {}\"\n                             .format(input.shape))\n        if not input.shape[-2:] == target.shape[-2:]:\n            raise ValueError(\"input and target shapes must be the same. Got: {}\"\n                             .format(input.shape, input.shape))\n        if not input.device == target.device:\n            raise ValueError(\n                \"input and target must be in the same device. Got: {}\" .format(\n                    input.device, target.device))\n        if not self.weights.shape[1] == input.shape[1]:\n            raise ValueError(\"The number of weights must equal the number of classes\")\n        if not torch.sum(self.weights).item() == 1:\n            raise ValueError(\"The sum of all weights must equal 1\")\n            \n        # cross entropy loss\n        celoss = nn.CrossEntropyLoss(self.weights)(input, target)\n        \n        # compute softmax over the classes axis\n        input_soft = F.softmax(input, dim=1)\n\n        # create the labels one hot tensor\n        target_one_hot = one_hot(target, num_classes=input.shape[1],\n                                 device=input.device, dtype=input.dtype)\n\n        # compute the actual dice score\n        dims = (2, 3)\n        intersection = torch.sum(input_soft * target_one_hot, dims)\n        cardinality = torch.sum(input_soft + target_one_hot, dims)\n\n        dice_score = 2. * intersection / (cardinality + self.eps)\n        \n        dice_score = torch.sum(dice_score * self.weights, dim=1)\n        \n        return torch.mean(1. - dice_score) + celoss\n","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.482045Z","iopub.execute_input":"2023-11-17T10:30:36.482286Z","iopub.status.idle":"2023-11-17T10:30:36.495576Z","shell.execute_reply.started":"2023-11-17T10:30:36.482265Z","shell.execute_reply":"2023-11-17T10:30:36.494628Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def weights_init(model):\n    if isinstance(model, nn.Linear):\n        # Xavier Distribution\n        torch.nn.init.xavier_uniform_(model.weight)\n\ndef save_model(model, optimizer, path):\n    checkpoint = {\n        \"model\": model.state_dict(),\n        \"optimizer\": optimizer.state_dict(),\n    }\n    torch.save(checkpoint, path)\n\ndef load_model(model, optimizer, path):\n    checkpoint = torch.load(path)\n    model.load_state_dict(checkpoint[\"model\"])\n    optimizer.load_state_dict(checkpoint['optimizer'])\n    return model, optimizer","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.496907Z","iopub.execute_input":"2023-11-17T10:30:36.497537Z","iopub.status.idle":"2023-11-17T10:30:36.509389Z","shell.execute_reply.started":"2023-11-17T10:30:36.497485Z","shell.execute_reply":"2023-11-17T10:30:36.508677Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Train function for each epoch\ndef train(train_dataloader, valid_dataloader,learing_rate_scheduler, epoch, display_step):\n    print(f\"Start epoch #{epoch+1}, learning rate for this epoch: {learing_rate_scheduler.get_last_lr()}\")\n    start_time = time.time()\n    train_loss_epoch = 0\n    test_loss_epoch = 0\n    last_loss = 999999999\n    model.train()\n    for i, (data,targets) in enumerate(train_dataloader):\n        \n        # Load data into GPU\n        data, targets = data.to(device), targets.to(device)\n\n        optimizer.zero_grad()\n        outputs = model(data)\n\n        # Backpropagation, compute gradients\n        loss = loss_function(outputs, targets.long())\n        loss.backward()\n\n        # Apply gradients\n        optimizer.step()\n        \n        # Save loss\n        train_loss_epoch += loss.item()\n        if (i+1) % display_step == 0:\n#             accuracy = float(test(test_loader))\n            print('Train Epoch: {} [{}/{} ({}%)]\\tLoss: {:.4f}'.format(\n                epoch + 1, (i+1) * len(data), len(train_dataloader.dataset), 100 * (i+1) * len(data) / len(train_dataloader.dataset), \n                loss.item()))\n                  \n    print(f\"Done epoch #{epoch+1}, time for this epoch: {time.time()-start_time}s\")\n    train_loss_epoch/= (i + 1)\n    \n    # Evaluate the validation set\n    model.eval()\n    with torch.no_grad():\n        for data, target in valid_dataloader:\n            data, target = data.to(device), target.to(device)\n            test_output = model(data)\n            test_loss = loss_function(test_output, target)\n            test_loss_epoch += test_loss.item()\n            \n    test_loss_epoch/= (i+1)\n    \n    return train_loss_epoch , test_loss_epoch","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.510774Z","iopub.execute_input":"2023-11-17T10:30:36.511422Z","iopub.status.idle":"2023-11-17T10:30:36.524174Z","shell.execute_reply.started":"2023-11-17T10:30:36.511391Z","shell.execute_reply":"2023-11-17T10:30:36.523279Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Test function\ndef test(dataloader):\n    test_loss = 0\n    correct = 0\n    with torch.no_grad():\n        for i, (data, targets) in enumerate(dataloader):\n            data, targets = data.to(device), targets.to(device)\n            outputs = model(data)\n            _, pred = torch.max(outputs, 1)\n            test_loss += targets.size(0)\n            correct += torch.sum(pred == targets).item()\n    return 100.0 * correct / test_loss","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.525270Z","iopub.execute_input":"2023-11-17T10:30:36.525704Z","iopub.status.idle":"2023-11-17T10:30:36.537405Z","shell.execute_reply.started":"2023-11-17T10:30:36.525672Z","shell.execute_reply":"2023-11-17T10:30:36.536536Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = UnetModel()\nmodel.apply(weights_init)\n# model = nn.DataParallel(model)\n#checkpoint = torch.load(pretrained_path)\n\n#new_state_dict = OrderedDict()\n#for k, v in checkpoint['model'].items():\n#    name = k[7:] # remove `module.`\n#    new_state_dict[name] = v\n# load params\n#model.load_state_dict(new_state_dict)\nmodel = nn.DataParallel(model)\nmodel.to(device)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:36.538575Z","iopub.execute_input":"2023-11-17T10:30:36.539728Z","iopub.status.idle":"2023-11-17T10:30:39.478439Z","shell.execute_reply.started":"2023-11-17T10:30:36.539696Z","shell.execute_reply":"2023-11-17T10:30:39.477528Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"weights = torch.Tensor([[0.4, 0.55, 0.05]]).cuda()\nloss_function = CEDiceLoss(weights)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:39.479536Z","iopub.execute_input":"2023-11-17T10:30:39.479797Z","iopub.status.idle":"2023-11-17T10:30:39.484644Z","shell.execute_reply.started":"2023-11-17T10:30:39.479774Z","shell.execute_reply":"2023-11-17T10:30:39.483649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define the optimizer (Adam optimizer)\noptimizer = optim.Adam(params=model.parameters(), lr=learning_rate)\n#optimizer.load_state_dict(checkpoint['optimizer'])\n\n# Learning rate scheduler\nlearing_rate_scheduler = lr_scheduler.StepLR(optimizer, step_size=4, gamma=0.6)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:39.485837Z","iopub.execute_input":"2023-11-17T10:30:39.486100Z","iopub.status.idle":"2023-11-17T10:30:39.497828Z","shell.execute_reply.started":"2023-11-17T10:30:39.486076Z","shell.execute_reply":"2023-11-17T10:30:39.496977Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"save_model(model, optimizer, checkpoint_path)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:39.498794Z","iopub.execute_input":"2023-11-17T10:30:39.499043Z","iopub.status.idle":"2023-11-17T10:30:39.579830Z","shell.execute_reply.started":"2023-11-17T10:30:39.499021Z","shell.execute_reply":"2023-11-17T10:30:39.579035Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"wandb.login(\n    # set the wandb project where this run will be logged\n#     project= \"PolypSegment\", \n    key = \"58347058cb54d574bc86f5bfd5f80134db7ec5cd\",\n)\nwandb.init(\n    project = \"bkao-neopolyp\"\n)\n# Training loop\ntrain_loss_array = []\ntest_loss_array = []\nlast_loss = 9999999999999\nfor epoch in range(epochs):\n    train_loss_epoch = 0\n    test_loss_epoch = 0\n    (train_loss_epoch, test_loss_epoch) = train(train_dataloader, \n                                              valid_dataloader, \n                                              learing_rate_scheduler, epoch, display_step)\n    \n    if test_loss_epoch < last_loss:\n        save_model(model, optimizer, checkpoint_path)\n        last_loss = test_loss_epoch\n        \n    learing_rate_scheduler.step()\n    train_loss_array.append(train_loss_epoch)\n    test_loss_array.append(test_loss_epoch)\n    wandb.log({\"Train loss\": train_loss_epoch, \"Valid loss\": test_loss_epoch})\n#     train_accuracy.append(test(train_loader))\n#     valid_accuracy.append(test(test_loader))\n#     print(\"Epoch {}: loss: {:.4f}, train accuracy: {:.4f}, valid accuracy:{:.4f}\".format(epoch + 1, \n#                                         train_loss_array[-1], train_accuracy[-1], valid_accuracy[-1]))","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:30:39.580962Z","iopub.execute_input":"2023-11-17T10:30:39.581303Z","iopub.status.idle":"2023-11-17T10:39:20.403045Z","shell.execute_reply.started":"2023-11-17T10:30:39.581270Z","shell.execute_reply":"2023-11-17T10:39:20.402100Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.cuda.empty_cache()","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:39:20.404448Z","iopub.execute_input":"2023-11-17T10:39:20.404806Z","iopub.status.idle":"2023-11-17T10:39:20.529179Z","shell.execute_reply.started":"2023-11-17T10:39:20.404773Z","shell.execute_reply":"2023-11-17T10:39:20.527897Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# load_model(model, checkpoint)\n\nplt.rcParams['figure.dpi'] = 90\nplt.rcParams['figure.figsize'] = (6, 4)\nepochs_array = range(epochs)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:39:20.530561Z","iopub.execute_input":"2023-11-17T10:39:20.530923Z","iopub.status.idle":"2023-11-17T10:39:20.539775Z","shell.execute_reply.started":"2023-11-17T10:39:20.530886Z","shell.execute_reply":"2023-11-17T10:39:20.538747Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plot Training and Test loss\nplt.plot(epochs_array, train_loss_array, 'g', label='Training loss')\n# plt.plot(epochs_array, test_loss_array, 'b', label='Test loss')\nplt.title('Training and Test loss')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.legend()\nplt.show()\n\n# from torch.jit import load\n# model = UNet()\n# optimizer = optim.Adam(params=model.parameters(), lr=learning_rate)\n\n# checkpoint = torch.load(pretrained_path)\n\n# optimizer.load_state_dict(checkpoint['optimizer'])\n\n# from collections import OrderedDict\n# new_state_dict = OrderedDict()\n# for k, v in checkpoint['model'].items():\n#     name = k[7:] # remove `module.`\n#     new_state_dict[name] = v\n# # load params\n# model.load_state_dict(new_state_dict)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:39:20.543180Z","iopub.execute_input":"2023-11-17T10:39:20.543440Z","iopub.status.idle":"2023-11-17T10:39:20.856553Z","shell.execute_reply.started":"2023-11-17T10:39:20.543418Z","shell.execute_reply":"2023-11-17T10:39:20.855036Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for i, (data, label) in enumerate(train_dataloader):\n    img = data\n    mask = label\n    break","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:39:20.857914Z","iopub.execute_input":"2023-11-17T10:39:20.858293Z","iopub.status.idle":"2023-11-17T10:39:21.292565Z","shell.execute_reply.started":"2023-11-17T10:39:20.858255Z","shell.execute_reply":"2023-11-17T10:39:21.290883Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, arr = plt.subplots(4, 3, figsize=(16, 12))\narr[0][0].set_title('Image')\narr[0][1].set_title('Segmentation')\narr[0][2].set_title('Predict')\n\nmodel.eval()\nwith torch.no_grad():\n    predict = model(img)\n\nfor i in range(4):\n    arr[i][0].imshow(img[i].permute(1, 2, 0));\n    \n    arr[i][1].imshow(F.one_hot(mask[i]).float())\n    \n    arr[i][2].imshow(F.one_hot(torch.argmax(predict[i], 0).cpu()).float())","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:39:21.298614Z","iopub.execute_input":"2023-11-17T10:39:21.298986Z","iopub.status.idle":"2023-11-17T10:39:23.812318Z","shell.execute_reply.started":"2023-11-17T10:39:21.298955Z","shell.execute_reply":"2023-11-17T10:39:23.811363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class UNetTestDataClass(Dataset):\n    def __init__(self, images_path, transform):\n        super(UNetTestDataClass, self).__init__()\n        \n        images_list = os.listdir(images_path)\n        images_list = [images_path+i for i in images_list]\n        \n        self.images_list = images_list\n        self.transform = transform\n        \n    def __getitem__(self, index):\n        img_path = self.images_list[index]\n        data = Image.open(img_path)\n        h = data.size[1]\n        w = data.size[0]\n        data = self.transform(data) / 255        \n        return data, img_path, h, w\n    \n    def __len__(self):\n        return len(self.images_list)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:39:23.813412Z","iopub.execute_input":"2023-11-17T10:39:23.813788Z","iopub.status.idle":"2023-11-17T10:39:23.822786Z","shell.execute_reply.started":"2023-11-17T10:39:23.813754Z","shell.execute_reply":"2023-11-17T10:39:23.821812Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path = '/kaggle/input/bkai-igh-neopolyp/test/test/'\nunet_test_dataset = UNetTestDataClass(path, transform)\ntest_dataloader = DataLoader(unet_test_dataset, batch_size=8, shuffle=True)\n","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:39:23.823936Z","iopub.execute_input":"2023-11-17T10:39:23.824281Z","iopub.status.idle":"2023-11-17T10:39:23.947186Z","shell.execute_reply.started":"2023-11-17T10:39:23.824247Z","shell.execute_reply":"2023-11-17T10:39:23.946156Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for i, (data, path, h, w) in enumerate(test_dataloader):\n    img = data\n    break","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:39:23.948513Z","iopub.execute_input":"2023-11-17T10:39:23.948862Z","iopub.status.idle":"2023-11-17T10:39:24.239626Z","shell.execute_reply.started":"2023-11-17T10:39:23.948829Z","shell.execute_reply":"2023-11-17T10:39:24.238558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, arr = plt.subplots(5, 2, figsize=(16, 12))\narr[0][0].set_title('Image');\narr[0][1].set_title('Predict');\n\nmodel.eval()\nwith torch.no_grad():\n    predict = model(img)\n\nfor i in range(5):\n    arr[i][0].imshow(img[i].permute(1, 2, 0));\n    arr[i][1].imshow(F.one_hot(torch.argmax(predict[i], 0).cpu()).float())","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:39:24.241281Z","iopub.execute_input":"2023-11-17T10:39:24.242120Z","iopub.status.idle":"2023-11-17T10:39:26.479236Z","shell.execute_reply.started":"2023-11-17T10:39:24.242082Z","shell.execute_reply":"2023-11-17T10:39:26.478074Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.eval()\nif not os.path.isdir(\"/kaggle/working/predicted_masks\"):\n    os.mkdir(\"/kaggle/working/predicted_masks\")\nfor _, (img, path, H, W) in enumerate(test_dataloader):\n    a = path\n    b = img\n    h = H\n    w = W\n    \n    with torch.no_grad():\n        predicted_mask = model(b)\n    for i in range(len(a)):\n        image_id = a[i].split('/')[-1].split('.')[0]\n        filename = image_id + \".png\"\n        \n        mask2img = (ToPILImage()(F.one_hot(torch.argmax(predicted_mask[i], 0)).permute(2, 0, 1).float()))\n        \n        mask2img = Resize((1024,1024), interpolation=InterpolationMode.NEAREST)(mask2img)\n        mask2img = CenterCrop((h[i].item(), w[i].item()))(mask2img)\n        \n        mask2img.save(os.path.join(\"/kaggle/working/predicted_masks/\", filename))","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:39:26.480647Z","iopub.execute_input":"2023-11-17T10:39:26.480996Z","iopub.status.idle":"2023-11-17T10:39:46.839135Z","shell.execute_reply.started":"2023-11-17T10:39:26.480963Z","shell.execute_reply":"2023-11-17T10:39:46.837987Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def rle_to_string(runs):\n    return ' '.join(str(x) for x in runs)\n\ndef rle_encode_one_mask(mask):\n    pixels = mask.flatten()\n    pixels[pixels > 0] = 255\n    use_padding = False\n    if pixels[0] or pixels[-1]:\n        use_padding = True\n        pixel_padded = np.zeros([len(pixels) + 2], dtype=pixels.dtype)\n        pixel_padded[1:-1] = pixels\n        pixels = pixel_padded\n    \n    rle = np.where(pixels[1:] != pixels[:-1])[0] + 2\n    if use_padding:\n        rle = rle - 1\n    rle[1::2] = rle[1::2] - rle[:-1:2]\n    return rle_to_string(rle)\n\ndef mask2string(dir):\n    ## mask --> string\n    strings = []\n    ids = []\n    ws, hs = [[] for i in range(2)]\n    for image_id in os.listdir(dir):\n        id = image_id.split('.')[0]\n        path = os.path.join(dir, image_id)\n        print(path)\n        img = cv2.imread(path)[:,:,::-1]\n        h, w = img.shape[0], img.shape[1]\n        for channel in range(2):\n            ws.append(w)\n            hs.append(h)\n            ids.append(f'{id}_{channel}')\n            string = rle_encode_one_mask(img[:,:,channel])\n            strings.append(string)\n    r = {\n        'ids': ids,\n        'strings': strings,\n    }\n    return r\n\n\nMASK_DIR_PATH = '/kaggle/working/predicted_masks' # change this to the path to your output mask folder\ndir = MASK_DIR_PATH\nres = mask2string(dir)\ndf = pd.DataFrame(columns=['Id', 'Expected'])\ndf['Id'] = res['ids']\ndf['Expected'] = res['strings']\ndf.to_csv(r'output.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T10:39:46.840761Z","iopub.execute_input":"2023-11-17T10:39:46.841173Z","iopub.status.idle":"2023-11-17T10:39:50.438526Z","shell.execute_reply.started":"2023-11-17T10:39:46.841134Z","shell.execute_reply":"2023-11-17T10:39:50.437557Z"},"trusted":true},"execution_count":null,"outputs":[]}]}