{"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":"nvidiaTeslaT4","dataSources":[{"sourceId":15768,"databundleVersionId":700263,"sourceType":"competition"},{"sourceId":34686,"sourceType":"datasetVersion","datasetId":27201},{"sourceId":685139,"sourceType":"datasetVersion","datasetId":347168}],"dockerImageVersionId":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Semantic Segmentation","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport os\nfrom torch.utils.data import Dataset\nimport torch\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nfrom albumentations.pytorch import ToTensorV2\nimport albumentations as A\nimport torch.nn.functional as F\nimport torch.nn as nn\nfrom torch.optim import Adam\nfrom tqdm import tqdm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T06:39:51.344303Z","iopub.execute_input":"2025-05-01T06:39:51.344590Z","iopub.status.idle":"2025-05-01T06:39:51.349154Z","shell.execute_reply.started":"2025-05-01T06:39:51.344568Z","shell.execute_reply":"2025-05-01T06:39:51.348164Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Dataset","metadata":{}},{"cell_type":"code","source":"class LyftUdacity(Dataset):\n    def __init__(self,img_dir,transform = None):\n        self.transforms = transform\n        image_paths = [i+'/CameraRGB' for i in img_dir]\n        seg_paths = [i+'/CameraSeg' for i in img_dir]\n        self.images,self.masks = [],[]\n        for i in image_paths:\n            imgs = os.listdir(i)\n            self.images.extend([i+'/'+img for img in imgs])\n        for i in seg_paths:\n            masks = os.listdir(i)\n            self.masks.extend([i+'/'+mask for mask in masks])\n    def __len__(self):\n        return len(self.images)\n    def __getitem__(self,index):\n        img = np.array(Image.open(self.images[index]))\n        mask = np.array(Image.open(self.masks[index]))\n        if self.transforms is not None:\n            aug = self.transforms(image=img,mask=mask)\n            img = aug['image']\n            mask = aug['mask']\n            mask = torch.max(mask,dim=2)[0]\n        return img,mask","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T06:39:53.552004Z","iopub.execute_input":"2025-05-01T06:39:53.552460Z","iopub.status.idle":"2025-05-01T06:39:53.561997Z","shell.execute_reply.started":"2025-05-01T06:39:53.552419Z","shell.execute_reply":"2025-05-01T06:39:53.561025Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_dir = ['../input/lyft-udacity-challenge/data'+i+'/data'+i for i in ['A','B','C','D','E']]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T06:39:57.340181Z","iopub.execute_input":"2025-05-01T06:39:57.340476Z","iopub.status.idle":"2025-05-01T06:39:57.344272Z","shell.execute_reply.started":"2025-05-01T06:39:57.340454Z","shell.execute_reply":"2025-05-01T06:39:57.343346Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_images(image_dir,transform = None,batch_size=1,shuffle=True,pin_memory=True):\n    data = LyftUdacity(image_dir,transform = t1)\n    train_size = int(0.8 * data.__len__())\n    test_size = data.__len__() - train_size\n    train_dataset, test_dataset = torch.utils.data.random_split(data, [train_size, test_size])\n    train_batch = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=shuffle, pin_memory=pin_memory)\n    test_batch = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=shuffle, pin_memory=pin_memory)\n    return train_batch,test_batch","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T06:39:59.703610Z","iopub.execute_input":"2025-05-01T06:39:59.703940Z","iopub.status.idle":"2025-05-01T06:39:59.708969Z","shell.execute_reply.started":"2025-05-01T06:39:59.703916Z","shell.execute_reply":"2025-05-01T06:39:59.707944Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Transforms (Data Augmentations)","metadata":{}},{"cell_type":"code","source":"t1 = A.Compose([\n    A.Resize(160,240),\n    A.augmentations.transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)),\n    ToTensorV2()\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T06:40:01.900654Z","iopub.execute_input":"2025-05-01T06:40:01.900955Z","iopub.status.idle":"2025-05-01T06:40:01.905689Z","shell.execute_reply.started":"2025-05-01T06:40:01.900930Z","shell.execute_reply":"2025-05-01T06:40:01.904609Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_batch,test_batch = get_images(data_dir,transform =t1,batch_size=8)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T06:40:04.001212Z","iopub.execute_input":"2025-05-01T06:40:04.001505Z","iopub.status.idle":"2025-05-01T06:40:04.017456Z","shell.execute_reply.started":"2025-05-01T06:40:04.001482Z","shell.execute_reply":"2025-05-01T06:40:04.016575Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for img,mask in train_batch:\n    img1 = np.transpose(img[0,:,:,:],(1,2,0))\n    mask1 = np.array(mask[0,:,:])\n    img2 = np.transpose(img[1,:,:,:],(1,2,0))\n    mask2 = np.array(mask[1,:,:])\n    img3 = np.transpose(img[2,:,:,:],(1,2,0))\n    mask3 = np.array(mask[2,:,:])\n    fig , ax =  plt.subplots(3, 2, figsize=(18, 18))\n    ax[0][0].imshow(img1)\n    ax[0][1].imshow(mask1)\n    ax[1][0].imshow(img2)\n    ax[1][1].imshow(mask2)\n    ax[2][0].imshow(img3)\n    ax[2][1].imshow(mask3)\n    break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T06:40:05.964016Z","iopub.execute_input":"2025-05-01T06:40:05.964369Z","iopub.status.idle":"2025-05-01T06:40:07.615902Z","shell.execute_reply.started":"2025-05-01T06:40:05.964341Z","shell.execute_reply":"2025-05-01T06:40:07.614900Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Architecture (DeepLabV3)","metadata":{}},{"cell_type":"code","source":"class ASPP(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super(ASPP, self).__init__()\n        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=1)\n        self.conv6 = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=6, dilation=6)\n        self.conv12 = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=12, dilation=12)\n        self.conv18 = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=18, dilation=18)\n        self.pool = nn.AdaptiveAvgPool2d(1)\n        self.conv1x1 = nn.Conv2d(out_channels * 5, out_channels, kernel_size=1)\n\n    def forward(self, x):\n        x1 = F.relu(self.conv1(x))\n        x2 = F.relu(self.conv6(x))\n        x3 = F.relu(self.conv12(x))\n        x4 = F.relu(self.conv18(x))\n        x5 = self.pool(x)\n        x5 = F.relu(self.conv1(x5))\n        x5 = F.interpolate(x5, size=x.shape[2:], mode='bilinear', align_corners=False)\n        x = torch.cat((x1, x2, x3, x4, x5), dim=1)\n        return self.conv1x1(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T13:33:30.903332Z","iopub.execute_input":"2025-03-18T13:33:30.903660Z","iopub.status.idle":"2025-03-18T13:33:30.910094Z","shell.execute_reply.started":"2025-03-18T13:33:30.903634Z","shell.execute_reply":"2025-03-18T13:33:30.909197Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# DeepLabV3 Model\nclass DeepLabV3(nn.Module):\n    def __init__(self, num_classes=23):\n        super(DeepLabV3, self).__init__()\n        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, padding=1, stride=2)\n        self.bn1 = nn.BatchNorm2d(64)\n        self.conv2 = nn.Conv2d(64, 128, kernel_size=3, padding=1, stride=2)\n        self.bn2 = nn.BatchNorm2d(128)\n        self.conv3 = nn.Conv2d(128, 256, kernel_size=3, padding=1, stride=2)\n        self.bn3 = nn.BatchNorm2d(256)\n        self.conv4 = nn.Conv2d(256, 512, kernel_size=3, padding=1, stride=2)\n        self.bn4 = nn.BatchNorm2d(512)\n        self.aspp = ASPP(512, 256)\n        self.up1 = nn.ConvTranspose2d(256, 128, kernel_size=2, stride=2)\n        self.up2 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2)\n        self.up3 = nn.ConvTranspose2d(64, 32, kernel_size=2, stride=2)\n        self.up4 = nn.ConvTranspose2d(32, 32, kernel_size=2, stride=2)\n        self.final_layer = nn.Conv2d(32, num_classes, kernel_size=1)\n\n    def forward(self, x):\n        x = F.relu(self.bn1(self.conv1(x)))\n        x = F.relu(self.bn2(self.conv2(x)))\n        x = F.relu(self.bn3(self.conv3(x)))\n        x = F.relu(self.bn4(self.conv4(x)))\n        x = self.aspp(x)\n        x = F.relu(self.up1(x))\n        x = F.relu(self.up2(x))\n        x = F.relu(self.up3(x))\n        x = self.up4(x)\n        x = self.final_layer(x)\n        return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T13:33:42.288114Z","iopub.execute_input":"2025-03-18T13:33:42.288457Z","iopub.status.idle":"2025-03-18T13:33:42.295829Z","shell.execute_reply.started":"2025-03-18T13:33:42.288427Z","shell.execute_reply":"2025-03-18T13:33:42.294999Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchsummary import summary\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nmodel = DeepLabV3().to(DEVICE)\nsummary(model, (3, 256, 256))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T13:33:51.388938Z","iopub.execute_input":"2025-03-18T13:33:51.389239Z","iopub.status.idle":"2025-03-18T13:33:51.486080Z","shell.execute_reply.started":"2025-03-18T13:33:51.389215Z","shell.execute_reply":"2025-03-18T13:33:51.485340Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Training\nLEARNING_RATE = 1e-4\nnum_epochs = 10\nloss_fn = nn.CrossEntropyLoss()\noptimizer = Adam(model.parameters(), lr=LEARNING_RATE)\nscaler = torch.cuda.amp.GradScaler()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T13:34:07.183577Z","iopub.execute_input":"2025-03-18T13:34:07.183872Z","iopub.status.idle":"2025-03-18T13:34:07.190498Z","shell.execute_reply.started":"2025-03-18T13:34:07.183849Z","shell.execute_reply":"2025-03-18T13:34:07.189525Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Training (DeepLabV3)","metadata":{}},{"cell_type":"code","source":"for epoch in range(num_epochs):\n    loop = tqdm(enumerate(train_batch), total=len(train_batch))\n    for batch_idx, (data, targets) in loop:\n        data, targets = data.to(DEVICE), targets.to(DEVICE).type(torch.long)\n        with torch.cuda.amp.autocast():\n            predictions = model(data)\n            loss = loss_fn(predictions, targets)\n        optimizer.zero_grad()\n        scaler.scale(loss).backward()\n        scaler.step(optimizer)\n        scaler.update()\n        loop.set_postfix(loss=loss.item())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T13:34:17.353626Z","iopub.execute_input":"2025-03-18T13:34:17.353904Z","iopub.status.idle":"2025-03-18T13:51:31.504230Z","shell.execute_reply.started":"2025-03-18T13:34:17.353883Z","shell.execute_reply":"2025-03-18T13:51:31.503395Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Metrics (DeepLabV3)","metadata":{}},{"cell_type":"code","source":"def check_accuracy(loader, model):\n    num_correct = 0\n    num_pixels = 0\n    dice_score = 0\n    model.eval()\n\n    with torch.no_grad():\n        for x, y in loader:\n            x = x.to(DEVICE)\n            y = y.to(DEVICE)\n            softmax = nn.Softmax(dim=1)\n            preds = torch.argmax(softmax(model(x)),axis=1)\n            num_correct += (preds == y).sum()\n            num_pixels += torch.numel(preds)\n            dice_score += (2 * (preds * y).sum()) / ((preds + y).sum() + 1e-8)\n\n    print(f\"Got {num_correct}/{num_pixels} with acc {num_correct/num_pixels*100:.2f}\")\n    print(f\"Dice score: {dice_score/len(loader)}\")\n    model.train()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T13:51:31.505451Z","iopub.execute_input":"2025-03-18T13:51:31.505742Z","iopub.status.idle":"2025-03-18T13:51:31.513620Z","shell.execute_reply.started":"2025-03-18T13:51:31.505717Z","shell.execute_reply":"2025-03-18T13:51:31.512777Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_accuracy(train_batch, model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T13:51:31.515344Z","iopub.execute_input":"2025-03-18T13:51:31.515564Z","iopub.status.idle":"2025-03-18T13:53:02.427173Z","shell.execute_reply.started":"2025-03-18T13:51:31.515545Z","shell.execute_reply":"2025-03-18T13:53:02.426403Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_accuracy(test_batch, model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T13:53:02.428237Z","iopub.execute_input":"2025-03-18T13:53:02.428571Z","iopub.status.idle":"2025-03-18T13:53:27.540990Z","shell.execute_reply.started":"2025-03-18T13:53:02.428537Z","shell.execute_reply":"2025-03-18T13:53:27.540243Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for x,y in test_batch:\n    x = x.to(DEVICE)\n    fig , ax =  plt.subplots(3, 3, figsize=(18, 18))\n    softmax = nn.Softmax(dim=1)\n    preds = torch.argmax(softmax(model(x)),axis=1).to('cpu')\n    img1 = np.transpose(np.array(x[0,:,:,:].to('cpu')),(1,2,0))\n    preds1 = np.array(preds[0,:,:])\n    mask1 = np.array(y[0,:,:])\n    img2 = np.transpose(np.array(x[1,:,:,:].to('cpu')),(1,2,0))\n    preds2 = np.array(preds[1,:,:])\n    mask2 = np.array(y[1,:,:])\n    img3 = np.transpose(np.array(x[2,:,:,:].to('cpu')),(1,2,0))\n    preds3 = np.array(preds[2,:,:])\n    mask3 = np.array(y[2,:,:])\n    ax[0,0].set_title('Image')\n    ax[0,1].set_title('Prediction')\n    ax[0,2].set_title('Mask')\n    ax[1,0].set_title('Image')\n    ax[1,1].set_title('Prediction')\n    ax[1,2].set_title('Mask')\n    ax[2,0].set_title('Image')\n    ax[2,1].set_title('Prediction')\n    ax[2,2].set_title('Mask')\n    ax[0][0].axis(\"off\")\n    ax[1][0].axis(\"off\")\n    ax[2][0].axis(\"off\")\n    ax[0][1].axis(\"off\")\n    ax[1][1].axis(\"off\")\n    ax[2][1].axis(\"off\")\n    ax[0][2].axis(\"off\")\n    ax[1][2].axis(\"off\")\n    ax[2][2].axis(\"off\")\n    ax[0][0].imshow(img1)\n    ax[0][1].imshow(preds1)\n    ax[0][2].imshow(mask1)\n    ax[1][0].imshow(img2)\n    ax[1][1].imshow(preds2)\n    ax[1][2].imshow(mask2)\n    ax[2][0].imshow(img3)\n    ax[2][1].imshow(preds3)\n    ax[2][2].imshow(mask3)   \n    break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T13:53:27.541727Z","iopub.execute_input":"2025-03-18T13:53:27.541931Z","iopub.status.idle":"2025-03-18T13:53:28.688471Z","shell.execute_reply.started":"2025-03-18T13:53:27.541913Z","shell.execute_reply":"2025-03-18T13:53:28.687563Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Architecture (U-Net)","metadata":{}},{"cell_type":"code","source":"class encoding_block(nn.Module):\n    def __init__(self,in_channels, out_channels):\n        super(encoding_block,self).__init__()\n        model = []\n        model.append(nn.Conv2d(in_channels, out_channels, 3, 1, 1, bias=False))\n        model.append(nn.BatchNorm2d(out_channels))\n        model.append(nn.ReLU(inplace=True))\n        model.append(nn.Conv2d(out_channels, out_channels, 3, 1, 1, bias=False))\n        model.append(nn.BatchNorm2d(out_channels))\n        model.append(nn.ReLU(inplace=True))\n        self.conv = nn.Sequential(*model)\n    def forward(self, x):\n        return self.conv(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T06:40:18.127503Z","iopub.execute_input":"2025-05-01T06:40:18.127804Z","iopub.status.idle":"2025-05-01T06:40:18.133472Z","shell.execute_reply.started":"2025-05-01T06:40:18.127778Z","shell.execute_reply":"2025-05-01T06:40:18.132583Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class unet_model(nn.Module):\n    def __init__(self,out_channels=23,features=[64, 128, 256, 512]):\n        super(unet_model,self).__init__()\n        self.pool = nn.MaxPool2d(kernel_size=(2,2),stride=(2,2))\n        self.conv1 = encoding_block(3,features[0])\n        self.conv2 = encoding_block(features[0],features[1])\n        self.conv3 = encoding_block(features[1],features[2])\n        self.conv4 = encoding_block(features[2],features[3])\n        self.conv5 = encoding_block(features[3]*2,features[3])\n        self.conv6 = encoding_block(features[3],features[2])\n        self.conv7 = encoding_block(features[2],features[1])\n        self.conv8 = encoding_block(features[1],features[0])        \n        self.tconv1 = nn.ConvTranspose2d(features[-1]*2, features[-1], kernel_size=2, stride=2)\n        self.tconv2 = nn.ConvTranspose2d(features[-1], features[-2], kernel_size=2, stride=2)\n        self.tconv3 = nn.ConvTranspose2d(features[-2], features[-3], kernel_size=2, stride=2)\n        self.tconv4 = nn.ConvTranspose2d(features[-3], features[-4], kernel_size=2, stride=2)        \n        self.bottleneck = encoding_block(features[3],features[3]*2)\n        self.final_layer = nn.Conv2d(features[0],out_channels,kernel_size=1)\n    def forward(self,x):\n        skip_connections = []\n        x = self.conv1(x)\n        skip_connections.append(x)\n        x = self.pool(x)\n        x = self.conv2(x)\n        skip_connections.append(x)\n        x = self.pool(x)\n        x = self.conv3(x)\n        skip_connections.append(x)\n        x = self.pool(x)\n        x = self.conv4(x)\n        skip_connections.append(x)\n        x = self.pool(x)\n        x = self.bottleneck(x)\n        skip_connections = skip_connections[::-1]\n        x = self.tconv1(x)\n        x = torch.cat((skip_connections[0], x), dim=1)\n        x = self.conv5(x)\n        x = self.tconv2(x)\n        x = torch.cat((skip_connections[1], x), dim=1)\n        x = self.conv6(x)\n        x = self.tconv3(x)\n        x = torch.cat((skip_connections[2], x), dim=1)\n        x = self.conv7(x)        \n        x = self.tconv4(x)\n        x = torch.cat((skip_connections[3], x), dim=1)\n        x = self.conv8(x)\n        x = self.final_layer(x)\n        return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T06:40:20.477219Z","iopub.execute_input":"2025-05-01T06:40:20.477508Z","iopub.status.idle":"2025-05-01T06:40:20.487459Z","shell.execute_reply.started":"2025-05-01T06:40:20.477485Z","shell.execute_reply":"2025-05-01T06:40:20.486522Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T12:16:36.512331Z","iopub.execute_input":"2025-03-17T12:16:36.512648Z","iopub.status.idle":"2025-03-17T12:16:36.533657Z","shell.execute_reply.started":"2025-03-17T12:16:36.512619Z","shell.execute_reply":"2025-03-17T12:16:36.532962Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = unet_model().to(DEVICE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T12:16:36.534532Z","iopub.execute_input":"2025-03-17T12:16:36.534821Z","iopub.status.idle":"2025-03-17T12:16:36.920253Z","shell.execute_reply.started":"2025-03-17T12:16:36.534793Z","shell.execute_reply":"2025-03-17T12:16:36.919633Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchsummary import summary\nsummary(model, (3, 256, 256))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T12:16:36.921010Z","iopub.execute_input":"2025-03-17T12:16:36.921286Z","iopub.status.idle":"2025-03-17T12:16:38.390430Z","shell.execute_reply.started":"2025-03-17T12:16:36.921257Z","shell.execute_reply":"2025-03-17T12:16:38.389596Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"LEARNING_RATE = 1e-4\nnum_epochs = 10\nloss_fn = nn.CrossEntropyLoss()\noptimizer = Adam(model.parameters(), lr=LEARNING_RATE)\nscaler = torch.cuda.amp.GradScaler()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T12:16:38.391455Z","iopub.execute_input":"2025-03-17T12:16:38.391796Z","iopub.status.idle":"2025-03-17T12:16:40.694994Z","shell.execute_reply.started":"2025-03-17T12:16:38.391764Z","shell.execute_reply":"2025-03-17T12:16:40.694152Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Training (U-Net)","metadata":{}},{"cell_type":"code","source":"for epoch in range(num_epochs):\n    loop = tqdm(enumerate(train_batch),total=len(train_batch))\n    for batch_idx, (data, targets) in loop:\n        data = data.to(DEVICE)\n        targets = targets.to(DEVICE)\n        targets = targets.type(torch.long)\n        # forward\n        with torch.cuda.amp.autocast():\n            predictions = model(data)\n            loss = loss_fn(predictions, targets)\n        # backward\n        optimizer.zero_grad()\n        scaler.scale(loss).backward()\n        scaler.step(optimizer)\n        scaler.update()\n\n        # update tqdm loop\n        loop.set_postfix(loss=loss.item())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T12:16:40.695734Z","iopub.execute_input":"2025-03-17T12:16:40.696169Z","iopub.status.idle":"2025-03-17T12:46:08.532749Z","shell.execute_reply.started":"2025-03-17T12:16:40.696133Z","shell.execute_reply":"2025-03-17T12:46:08.531825Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Metrics (U-Net)","metadata":{}},{"cell_type":"code","source":"def check_accuracy(loader, model):\n    num_correct = 0\n    num_pixels = 0\n    dice_score = 0\n    model.eval()\n\n    with torch.no_grad():\n        for x, y in loader:\n            x = x.to(DEVICE)\n            y = y.to(DEVICE)\n            softmax = nn.Softmax(dim=1)\n            preds = torch.argmax(softmax(model(x)),axis=1)\n            num_correct += (preds == y).sum()\n            num_pixels += torch.numel(preds)\n            dice_score += (2 * (preds * y).sum()) / ((preds + y).sum() + 1e-8)\n\n    print(f\"Got {num_correct}/{num_pixels} with acc {num_correct/num_pixels*100:.2f}\")\n    print(f\"Dice score: {dice_score/len(loader)}\")\n    model.train()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T12:46:08.533758Z","iopub.execute_input":"2025-03-17T12:46:08.534078Z","iopub.status.idle":"2025-03-17T12:46:08.539668Z","shell.execute_reply.started":"2025-03-17T12:46:08.534045Z","shell.execute_reply":"2025-03-17T12:46:08.538781Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_accuracy(train_batch, model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T12:46:08.540551Z","iopub.execute_input":"2025-03-17T12:46:08.540869Z","iopub.status.idle":"2025-03-17T12:47:54.022506Z","shell.execute_reply.started":"2025-03-17T12:46:08.540840Z","shell.execute_reply":"2025-03-17T12:47:54.021555Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_accuracy(test_batch, model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T12:47:54.023415Z","iopub.execute_input":"2025-03-17T12:47:54.023674Z","iopub.status.idle":"2025-03-17T12:48:44.112156Z","shell.execute_reply.started":"2025-03-17T12:47:54.023652Z","shell.execute_reply":"2025-03-17T12:48:44.111476Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for x,y in test_batch:\n    x = x.to(DEVICE)\n    fig , ax =  plt.subplots(3, 3, figsize=(18, 18))\n    softmax = nn.Softmax(dim=1)\n    preds = torch.argmax(softmax(model(x)),axis=1).to('cpu')\n    img1 = np.transpose(np.array(x[0,:,:,:].to('cpu')),(1,2,0))\n    preds1 = np.array(preds[0,:,:])\n    mask1 = np.array(y[0,:,:])\n    img2 = np.transpose(np.array(x[1,:,:,:].to('cpu')),(1,2,0))\n    preds2 = np.array(preds[1,:,:])\n    mask2 = np.array(y[1,:,:])\n    img3 = np.transpose(np.array(x[2,:,:,:].to('cpu')),(1,2,0))\n    preds3 = np.array(preds[2,:,:])\n    mask3 = np.array(y[2,:,:])\n    ax[0,0].set_title('Image')\n    ax[0,1].set_title('Prediction')\n    ax[0,2].set_title('Mask')\n    ax[1,0].set_title('Image')\n    ax[1,1].set_title('Prediction')\n    ax[1,2].set_title('Mask')\n    ax[2,0].set_title('Image')\n    ax[2,1].set_title('Prediction')\n    ax[2,2].set_title('Mask')\n    ax[0][0].axis(\"off\")\n    ax[1][0].axis(\"off\")\n    ax[2][0].axis(\"off\")\n    ax[0][1].axis(\"off\")\n    ax[1][1].axis(\"off\")\n    ax[2][1].axis(\"off\")\n    ax[0][2].axis(\"off\")\n    ax[1][2].axis(\"off\")\n    ax[2][2].axis(\"off\")\n    ax[0][0].imshow(img1)\n    ax[0][1].imshow(preds1)\n    ax[0][2].imshow(mask1)\n    ax[1][0].imshow(img2)\n    ax[1][1].imshow(preds2)\n    ax[1][2].imshow(mask2)\n    ax[2][0].imshow(img3)\n    ax[2][1].imshow(preds3)\n    ax[2][2].imshow(mask3)   \n    break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T12:48:44.112923Z","iopub.execute_input":"2025-03-17T12:48:44.113172Z","iopub.status.idle":"2025-03-17T12:48:45.551841Z","shell.execute_reply.started":"2025-03-17T12:48:44.113141Z","shell.execute_reply":"2025-03-17T12:48:45.550836Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Architecture (Attention U-Net)","metadata":{}},{"cell_type":"code","source":"class SelfAttention(nn.Module):\n    def __init__(self, in_dim):\n        super(SelfAttention, self).__init__()\n        self.query_conv = nn.Conv2d(in_dim, in_dim//8, kernel_size=1)\n        self.key_conv = nn.Conv2d(in_dim, in_dim//8, kernel_size=1)\n        self.value_conv = nn.Conv2d(in_dim, in_dim, kernel_size=1)\n        self.gamma = nn.Parameter(torch.zeros(1))\n\n    def forward(self, x):\n        m_batchsize, C, width, height = x.size()\n        proj_query = self.query_conv(x).view(m_batchsize, -1, width * height).permute(0, 2, 1)\n        proj_key = self.key_conv(x).view(m_batchsize, -1, width * height)\n        energy = torch.bmm(proj_query, proj_key) / (width * height)  # Normalize to reduce large values\n        attention = torch.softmax(energy, dim=-1)\n        proj_value = self.value_conv(x).view(m_batchsize, -1, width * height)\n        out = torch.bmm(proj_value, attention.permute(0, 2, 1)).view(m_batchsize, C, width, height)\n        return self.gamma * out + x, attention\n\nclass DoubleConv(nn.Module):\n    def __init__(self, in_channels, out_channels, mid_channels=None):\n        super().__init__()\n        if not mid_channels:\n            mid_channels = out_channels\n        self.double_conv = nn.Sequential(\n            nn.Conv2d(in_channels, mid_channels, kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm2d(mid_channels),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(mid_channels, out_channels, kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm2d(out_channels),\n            nn.ReLU(inplace=True)\n        )\n\n    def forward(self, x):\n        return self.double_conv(x)\n\nclass Down(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super().__init__()\n        self.maxpool_conv = nn.Sequential(nn.MaxPool2d(2), DoubleConv(in_channels, out_channels))\n\n    def forward(self, x):\n        return self.maxpool_conv(x)\n\nclass Up(nn.Module):\n    def __init__(self, in_channels, out_channels, bilinear=True):\n        super().__init__()\n        if bilinear:\n            self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)\n            self.conv = DoubleConv(in_channels, out_channels, in_channels // 2)\n        else:\n            self.up = nn.ConvTranspose2d(in_channels, in_channels // 2, kernel_size=2, stride=2)\n            self.conv = DoubleConv(in_channels, out_channels)\n\n    def forward(self, x1, x2):\n        x1 = self.up(x1)\n        diffY, diffX = x2.size()[2] - x1.size()[2], x2.size()[3] - x1.size()[3]\n        x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2, diffY // 2, diffY - diffY // 2])\n        x = torch.cat([x2, x1], dim=1)\n        return self.conv(x)\n\nclass OutConv(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super().__init__()\n        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=1)\n\n    def forward(self, x):\n        return self.conv(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T13:39:36.537831Z","iopub.execute_input":"2025-03-17T13:39:36.538125Z","iopub.status.idle":"2025-03-17T13:39:36.550258Z","shell.execute_reply.started":"2025-03-17T13:39:36.538103Z","shell.execute_reply":"2025-03-17T13:39:36.549600Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class unet_model(nn.Module):\n    def __init__(self, n_channels=64, n_classes=23, bilinear=False):\n        super(unet_model, self).__init__()\n        self.n_channels = n_channels\n        self.n_classes = n_classes\n        self.bilinear = bilinear\n\n        self.inc = DoubleConv(3, 64)\n        self.down1 = Down(64, 128)\n        self.down2 = Down(128, 256)\n        self.down3 = Down(256, 512)\n\n        # Apply attention only to deeper layers to save memory\n        self.attention_3 = SelfAttention(256)\n        self.attention_4 = SelfAttention(512)\n\n        factor = 2 if bilinear else 1\n        self.down4 = Down(512, 1024 // factor)\n        self.up1 = Up(1024, 512 // factor, bilinear)\n        self.up2 = Up(512, 256 // factor, bilinear)\n        self.up3 = Up(256, 128 // factor, bilinear)\n        self.up4 = Up(128, 64, bilinear)\n        self.outc = OutConv(64, n_classes)\n\n    def forward(self, x):\n        x1 = self.inc(x)\n        x2 = self.down1(x1)\n        x3 = self.down2(x2)\n        x4 = self.down3(x3)\n        x5 = self.down4(x4)\n\n        v1, _ = self.attention_4(x4)\n        v2, _ = self.attention_3(x3)\n\n        x = self.up1(x5, v1)\n        x = self.up2(x, v2)\n        x = self.up3(x, x2)  # No attention for shallow layers\n        x = self.up4(x, x1)\n        return self.outc(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T13:39:39.662176Z","iopub.execute_input":"2025-03-17T13:39:39.662529Z","iopub.status.idle":"2025-03-17T13:39:39.669635Z","shell.execute_reply.started":"2025-03-17T13:39:39.662492Z","shell.execute_reply":"2025-03-17T13:39:39.668693Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T13:39:43.457455Z","iopub.execute_input":"2025-03-17T13:39:43.457877Z","iopub.status.idle":"2025-03-17T13:39:43.461741Z","shell.execute_reply.started":"2025-03-17T13:39:43.457844Z","shell.execute_reply":"2025-03-17T13:39:43.460769Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = unet_model().to(DEVICE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T13:39:46.398834Z","iopub.execute_input":"2025-03-17T13:39:46.399246Z","iopub.status.idle":"2025-03-17T13:39:46.775945Z","shell.execute_reply.started":"2025-03-17T13:39:46.399208Z","shell.execute_reply":"2025-03-17T13:39:46.775143Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"LEARNING_RATE = 1e-4\nnum_epochs = 10\nloss_fn = nn.CrossEntropyLoss()\noptimizer = Adam(model.parameters(), lr=LEARNING_RATE)\nscaler = torch.cuda.amp.GradScaler()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T13:39:48.452607Z","iopub.execute_input":"2025-03-17T13:39:48.452962Z","iopub.status.idle":"2025-03-17T13:39:50.459413Z","shell.execute_reply.started":"2025-03-17T13:39:48.452932Z","shell.execute_reply":"2025-03-17T13:39:50.458390Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Training (Attention U-Net)","metadata":{}},{"cell_type":"code","source":"for epoch in range(num_epochs):\n    loop = tqdm(enumerate(train_batch),total=len(train_batch))\n    for batch_idx, (data, targets) in loop:\n        data = data.to(DEVICE)\n        targets = targets.to(DEVICE)\n        targets = targets.type(torch.long)\n        # forward\n        with torch.cuda.amp.autocast():\n            predictions = model(data)\n            loss = loss_fn(predictions, targets)\n        # backward\n        optimizer.zero_grad()\n        scaler.scale(loss).backward()\n        scaler.step(optimizer)\n        scaler.update()\n\n        # update tqdm loop\n        loop.set_postfix(loss=loss.item())","metadata":{"execution":{"iopub.status.busy":"2025-03-17T13:39:52.852426Z","iopub.execute_input":"2025-03-17T13:39:52.852956Z","iopub.status.idle":"2025-03-17T14:10:54.299240Z","shell.execute_reply.started":"2025-03-17T13:39:52.852926Z","shell.execute_reply":"2025-03-17T14:10:54.298495Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Metrics (Attention U-Net)","metadata":{}},{"cell_type":"code","source":"def check_accuracy(loader, model):\n    num_correct = 0\n    num_pixels = 0\n    dice_score = 0\n    model.eval()\n\n    with torch.no_grad():\n        for x, y in loader:\n            x = x.to(DEVICE)\n            y = y.to(DEVICE)\n            softmax = nn.Softmax(dim=1)\n            preds = torch.argmax(softmax(model(x)),axis=1)\n            num_correct += (preds == y).sum()\n            num_pixels += torch.numel(preds)\n            dice_score += (2 * (preds * y).sum()) / ((preds + y).sum() + 1e-8)\n\n    print(f\"Got {num_correct}/{num_pixels} with acc {num_correct/num_pixels*100:.2f}\")\n    print(f\"Dice score: {dice_score/len(loader)}\")\n    model.train()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T14:10:59.898431Z","iopub.execute_input":"2025-03-17T14:10:59.898727Z","iopub.status.idle":"2025-03-17T14:10:59.904322Z","shell.execute_reply.started":"2025-03-17T14:10:59.898703Z","shell.execute_reply":"2025-03-17T14:10:59.903532Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_accuracy(train_batch, model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T14:11:04.653084Z","iopub.execute_input":"2025-03-17T14:11:04.653399Z","iopub.status.idle":"2025-03-17T14:12:43.339739Z","shell.execute_reply.started":"2025-03-17T14:11:04.653374Z","shell.execute_reply":"2025-03-17T14:12:43.338980Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_accuracy(test_batch, model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T14:12:43.340715Z","iopub.execute_input":"2025-03-17T14:12:43.341004Z","iopub.status.idle":"2025-03-17T14:13:24.752157Z","shell.execute_reply.started":"2025-03-17T14:12:43.340975Z","shell.execute_reply":"2025-03-17T14:13:24.751259Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for x,y in test_batch:\n    x = x.to(DEVICE)\n    fig , ax =  plt.subplots(3, 3, figsize=(18, 18))\n    softmax = nn.Softmax(dim=1)\n    preds = torch.argmax(softmax(model(x)),axis=1).to('cpu')\n    img1 = np.transpose(np.array(x[0,:,:,:].to('cpu')),(1,2,0))\n    preds1 = np.array(preds[0,:,:])\n    mask1 = np.array(y[0,:,:])\n    img2 = np.transpose(np.array(x[1,:,:,:].to('cpu')),(1,2,0))\n    preds2 = np.array(preds[1,:,:])\n    mask2 = np.array(y[1,:,:])\n    img3 = np.transpose(np.array(x[2,:,:,:].to('cpu')),(1,2,0))\n    preds3 = np.array(preds[2,:,:])\n    mask3 = np.array(y[2,:,:])\n    ax[0,0].set_title('Image')\n    ax[0,1].set_title('Prediction')\n    ax[0,2].set_title('Mask')\n    ax[1,0].set_title('Image')\n    ax[1,1].set_title('Prediction')\n    ax[1,2].set_title('Mask')\n    ax[2,0].set_title('Image')\n    ax[2,1].set_title('Prediction')\n    ax[2,2].set_title('Mask')\n    ax[0][0].axis(\"off\")\n    ax[1][0].axis(\"off\")\n    ax[2][0].axis(\"off\")\n    ax[0][1].axis(\"off\")\n    ax[1][1].axis(\"off\")\n    ax[2][1].axis(\"off\")\n    ax[0][2].axis(\"off\")\n    ax[1][2].axis(\"off\")\n    ax[2][2].axis(\"off\")\n    ax[0][0].imshow(img1)\n    ax[0][1].imshow(preds1)\n    ax[0][2].imshow(mask1)\n    ax[1][0].imshow(img2)\n    ax[1][1].imshow(preds2)\n    ax[1][2].imshow(mask2)\n    ax[2][0].imshow(img3)\n    ax[2][1].imshow(preds3)\n    ax[2][2].imshow(mask3)   \n    break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T14:13:24.753451Z","iopub.execute_input":"2025-03-17T14:13:24.753673Z","iopub.status.idle":"2025-03-17T14:13:26.210089Z","shell.execute_reply.started":"2025-03-17T14:13:24.753654Z","shell.execute_reply":"2025-03-17T14:13:26.209154Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Architecture (Inception U-Net)","metadata":{}},{"cell_type":"code","source":"class InceptionBlock(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super(InceptionBlock, self).__init__()\n        self.conv1x1 = nn.Conv2d(in_channels, out_channels, kernel_size=1, padding=0)\n        self.conv3x3 = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)\n        self.conv5x5 = nn.Conv2d(in_channels, out_channels, kernel_size=5, padding=2)\n        self.batch_norm = nn.BatchNorm2d(out_channels * 3)\n\n    def forward(self, x):\n        x1 = F.relu(self.conv1x1(x))\n        x2 = F.relu(self.conv3x3(x))\n        x3 = F.relu(self.conv5x5(x))\n        x = torch.cat([x1, x2, x3], dim=1)\n        return self.batch_norm(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T15:35:48.741952Z","iopub.execute_input":"2025-03-17T15:35:48.742316Z","iopub.status.idle":"2025-03-17T15:35:48.748173Z","shell.execute_reply.started":"2025-03-17T15:35:48.742278Z","shell.execute_reply":"2025-03-17T15:35:48.747278Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class InceptionUNet(nn.Module):\n    def __init__(self, out_channels=23):\n        super(InceptionUNet, self).__init__()\n        self.pool = nn.MaxPool2d(2, 2)\n        self.enc1 = InceptionBlock(3, 64)\n        self.enc2 = InceptionBlock(64 * 3, 128)\n        self.enc3 = InceptionBlock(128 * 3, 256)\n        self.enc4 = InceptionBlock(256 * 3, 512)\n        self.bottleneck = InceptionBlock(512 * 3, 1024)\n        self.up6 = nn.ConvTranspose2d(1024 * 3, 512, kernel_size=2, stride=2)\n        self.dec6 = InceptionBlock(512 + 512 * 3, 512)\n        self.up7 = nn.ConvTranspose2d(512 * 3, 256, kernel_size=2, stride=2)\n        self.dec7 = InceptionBlock(256 + 256 * 3, 256)\n        self.up8 = nn.ConvTranspose2d(256 * 3, 128, kernel_size=2, stride=2)\n        self.dec8 = InceptionBlock(128 + 128 * 3, 128)\n        self.up9 = nn.ConvTranspose2d(128 * 3, 64, kernel_size=2, stride=2)\n        self.dec9 = InceptionBlock(64 + 64 * 3, 64)\n        self.final_layer = nn.Conv2d(64 * 3, out_channels, kernel_size=1)\n\n    def forward(self, x):\n        skip_connections = []\n        x = self.enc1(x)\n        skip_connections.append(x)\n        x = self.pool(x)\n        x = self.enc2(x)\n        skip_connections.append(x)\n        x = self.pool(x)\n        x = self.enc3(x)\n        skip_connections.append(x)\n        x = self.pool(x)\n        x = self.enc4(x)\n        skip_connections.append(x)\n        x = self.pool(x)\n        x = self.bottleneck(x)\n        skip_connections = skip_connections[::-1]\n        x = self.up6(x)\n        x = torch.cat((skip_connections[0], x), dim=1)\n        x = self.dec6(x)\n        x = self.up7(x)\n        x = torch.cat((skip_connections[1], x), dim=1)\n        x = self.dec7(x)\n        x = self.up8(x)\n        x = torch.cat((skip_connections[2], x), dim=1)\n        x = self.dec8(x)\n        x = self.up9(x)\n        x = torch.cat((skip_connections[3], x), dim=1)\n        x = self.dec9(x)\n        x = self.final_layer(x)\n        return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T15:36:13.897766Z","iopub.execute_input":"2025-03-17T15:36:13.898083Z","iopub.status.idle":"2025-03-17T15:36:13.906936Z","shell.execute_reply.started":"2025-03-17T15:36:13.898060Z","shell.execute_reply":"2025-03-17T15:36:13.906239Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchsummary import summary\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nmodel = InceptionUNet().to(DEVICE)\nsummary(model, (3, 256, 256))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T15:37:04.910180Z","iopub.execute_input":"2025-03-17T15:37:04.910538Z","iopub.status.idle":"2025-03-17T15:37:06.219195Z","shell.execute_reply.started":"2025-03-17T15:37:04.910506Z","shell.execute_reply":"2025-03-17T15:37:06.218253Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Training\nLEARNING_RATE = 1e-4\nnum_epochs = 10\nloss_fn = nn.CrossEntropyLoss()\noptimizer = Adam(model.parameters(), lr=LEARNING_RATE)\nscaler = torch.cuda.amp.GradScaler()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T15:37:19.820473Z","iopub.execute_input":"2025-03-17T15:37:19.820788Z","iopub.status.idle":"2025-03-17T15:37:19.826358Z","shell.execute_reply.started":"2025-03-17T15:37:19.820765Z","shell.execute_reply":"2025-03-17T15:37:19.825520Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Training (Inception U-Net)","metadata":{}},{"cell_type":"code","source":"for epoch in range(num_epochs):\n    loop = tqdm(enumerate(train_batch), total=len(train_batch))\n    for batch_idx, (data, targets) in loop:\n        data, targets = data.to(DEVICE), targets.to(DEVICE).type(torch.long)\n        with torch.cuda.amp.autocast():\n            predictions = model(data)\n            loss = loss_fn(predictions, targets)\n        optimizer.zero_grad()\n        scaler.scale(loss).backward()\n        scaler.step(optimizer)\n        scaler.update()\n        loop.set_postfix(loss=loss.item())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T15:37:27.594476Z","iopub.execute_input":"2025-03-17T15:37:27.594801Z","iopub.status.idle":"2025-03-17T16:35:53.905967Z","shell.execute_reply.started":"2025-03-17T15:37:27.594773Z","shell.execute_reply":"2025-03-17T16:35:53.904987Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Metrics (Inception U-Net)","metadata":{}},{"cell_type":"code","source":"def check_accuracy(loader, model):\n    num_correct = 0\n    num_pixels = 0\n    dice_score = 0\n    model.eval()\n\n    with torch.no_grad():\n        for x, y in loader:\n            x = x.to(DEVICE)\n            y = y.to(DEVICE)\n            softmax = nn.Softmax(dim=1)\n            preds = torch.argmax(softmax(model(x)),axis=1)\n            num_correct += (preds == y).sum()\n            num_pixels += torch.numel(preds)\n            dice_score += (2 * (preds * y).sum()) / ((preds + y).sum() + 1e-8)\n\n    print(f\"Got {num_correct}/{num_pixels} with acc {num_correct/num_pixels*100:.2f}\")\n    print(f\"Dice score: {dice_score/len(loader)}\")\n    model.train()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T16:36:05.389362Z","iopub.execute_input":"2025-03-17T16:36:05.389647Z","iopub.status.idle":"2025-03-17T16:36:05.394727Z","shell.execute_reply.started":"2025-03-17T16:36:05.389625Z","shell.execute_reply":"2025-03-17T16:36:05.393890Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_accuracy(train_batch, model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T16:36:10.146787Z","iopub.execute_input":"2025-03-17T16:36:10.147070Z","iopub.status.idle":"2025-03-17T16:39:21.504436Z","shell.execute_reply.started":"2025-03-17T16:36:10.147046Z","shell.execute_reply":"2025-03-17T16:39:21.503497Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_accuracy(test_batch, model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T16:39:21.505624Z","iopub.execute_input":"2025-03-17T16:39:21.505957Z","iopub.status.idle":"2025-03-17T16:40:09.723543Z","shell.execute_reply.started":"2025-03-17T16:39:21.505925Z","shell.execute_reply":"2025-03-17T16:40:09.722620Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for x,y in test_batch:\n    x = x.to(DEVICE)\n    fig , ax =  plt.subplots(3, 3, figsize=(18, 18))\n    softmax = nn.Softmax(dim=1)\n    preds = torch.argmax(softmax(model(x)),axis=1).to('cpu')\n    img1 = np.transpose(np.array(x[0,:,:,:].to('cpu')),(1,2,0))\n    preds1 = np.array(preds[0,:,:])\n    mask1 = np.array(y[0,:,:])\n    img2 = np.transpose(np.array(x[1,:,:,:].to('cpu')),(1,2,0))\n    preds2 = np.array(preds[1,:,:])\n    mask2 = np.array(y[1,:,:])\n    img3 = np.transpose(np.array(x[2,:,:,:].to('cpu')),(1,2,0))\n    preds3 = np.array(preds[2,:,:])\n    mask3 = np.array(y[2,:,:])\n    ax[0,0].set_title('Image')\n    ax[0,1].set_title('Prediction')\n    ax[0,2].set_title('Mask')\n    ax[1,0].set_title('Image')\n    ax[1,1].set_title('Prediction')\n    ax[1,2].set_title('Mask')\n    ax[2,0].set_title('Image')\n    ax[2,1].set_title('Prediction')\n    ax[2,2].set_title('Mask')\n    ax[0][0].axis(\"off\")\n    ax[1][0].axis(\"off\")\n    ax[2][0].axis(\"off\")\n    ax[0][1].axis(\"off\")\n    ax[1][1].axis(\"off\")\n    ax[2][1].axis(\"off\")\n    ax[0][2].axis(\"off\")\n    ax[1][2].axis(\"off\")\n    ax[2][2].axis(\"off\")\n    ax[0][0].imshow(img1)\n    ax[0][1].imshow(preds1)\n    ax[0][2].imshow(mask1)\n    ax[1][0].imshow(img2)\n    ax[1][1].imshow(preds2)\n    ax[1][2].imshow(mask2)\n    ax[2][0].imshow(img3)\n    ax[2][1].imshow(preds3)\n    ax[2][2].imshow(mask3)   \n    break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-17T16:40:09.724984Z","iopub.execute_input":"2025-03-17T16:40:09.725328Z","iopub.status.idle":"2025-03-17T16:40:11.249191Z","shell.execute_reply.started":"2025-03-17T16:40:09.725275Z","shell.execute_reply":"2025-03-17T16:40:11.248309Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Architecture (Residual U-Net)","metadata":{}},{"cell_type":"code","source":"class ResidualBlock(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super(ResidualBlock, self).__init__()\n        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)\n        self.bn1 = nn.BatchNorm2d(out_channels)\n        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1)\n        self.bn2 = nn.BatchNorm2d(out_channels)\n        self.shortcut = nn.Conv2d(in_channels, out_channels, kernel_size=1, padding=0)\n\n    def forward(self, x):\n        residual = self.shortcut(x)\n        x = F.relu(self.bn1(self.conv1(x)))\n        x = self.bn2(self.conv2(x))\n        x += residual\n        return F.relu(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T12:46:37.673354Z","iopub.execute_input":"2025-03-18T12:46:37.673750Z","iopub.status.idle":"2025-03-18T12:46:37.679224Z","shell.execute_reply.started":"2025-03-18T12:46:37.673714Z","shell.execute_reply":"2025-03-18T12:46:37.678391Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Residual U-Net Model\nclass ResidualUNet(nn.Module):\n    def __init__(self, out_channels=23):\n        super(ResidualUNet, self).__init__()\n        self.pool = nn.MaxPool2d(2, 2)\n        self.enc1 = ResidualBlock(3, 64)\n        self.enc2 = ResidualBlock(64, 128)\n        self.enc3 = ResidualBlock(128, 256)\n        self.enc4 = ResidualBlock(256, 512)\n        self.bottleneck = ResidualBlock(512, 1024)\n        self.up6 = nn.ConvTranspose2d(1024, 512, kernel_size=2, stride=2)\n        self.dec6 = ResidualBlock(1024, 512)\n        self.up7 = nn.ConvTranspose2d(512, 256, kernel_size=2, stride=2)\n        self.dec7 = ResidualBlock(512, 256)\n        self.up8 = nn.ConvTranspose2d(256, 128, kernel_size=2, stride=2)\n        self.dec8 = ResidualBlock(256, 128)\n        self.up9 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2)\n        self.dec9 = ResidualBlock(128, 64)\n        self.final_layer = nn.Conv2d(64, out_channels, kernel_size=1)\n\n    def forward(self, x):\n        skip_connections = []\n        x = self.enc1(x)\n        skip_connections.append(x)\n        x = self.pool(x)\n        x = self.enc2(x)\n        skip_connections.append(x)\n        x = self.pool(x)\n        x = self.enc3(x)\n        skip_connections.append(x)\n        x = self.pool(x)\n        x = self.enc4(x)\n        skip_connections.append(x)\n        x = self.pool(x)\n        x = self.bottleneck(x)\n        skip_connections = skip_connections[::-1]\n        x = self.up6(x)\n        x = torch.cat((skip_connections[0], x), dim=1)\n        x = self.dec6(x)\n        x = self.up7(x)\n        x = torch.cat((skip_connections[1], x), dim=1)\n        x = self.dec7(x)\n        x = self.up8(x)\n        x = torch.cat((skip_connections[2], x), dim=1)\n        x = self.dec8(x)\n        x = self.up9(x)\n        x = torch.cat((skip_connections[3], x), dim=1)\n        x = self.dec9(x)\n        x = self.final_layer(x)\n        return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T12:46:50.287228Z","iopub.execute_input":"2025-03-18T12:46:50.287595Z","iopub.status.idle":"2025-03-18T12:46:50.297554Z","shell.execute_reply.started":"2025-03-18T12:46:50.287566Z","shell.execute_reply":"2025-03-18T12:46:50.296652Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchsummary import summary\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nmodel = ResidualUNet().to(DEVICE)\nsummary(model, (3, 256, 256))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T12:47:34.982806Z","iopub.execute_input":"2025-03-18T12:47:34.983097Z","iopub.status.idle":"2025-03-18T12:47:35.926324Z","shell.execute_reply.started":"2025-03-18T12:47:34.983076Z","shell.execute_reply":"2025-03-18T12:47:35.925595Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Training\nLEARNING_RATE = 1e-4\nnum_epochs = 10\nloss_fn = nn.CrossEntropyLoss()\noptimizer = Adam(model.parameters(), lr=LEARNING_RATE)\nscaler = torch.cuda.amp.GradScaler()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T12:47:47.662023Z","iopub.execute_input":"2025-03-18T12:47:47.662339Z","iopub.status.idle":"2025-03-18T12:47:49.473680Z","shell.execute_reply.started":"2025-03-18T12:47:47.662313Z","shell.execute_reply":"2025-03-18T12:47:49.472890Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Training (Residual U-Net)","metadata":{}},{"cell_type":"code","source":"for epoch in range(num_epochs):\n    loop = tqdm(enumerate(train_batch), total=len(train_batch))\n    for batch_idx, (data, targets) in loop:\n        data, targets = data.to(DEVICE), targets.to(DEVICE).type(torch.long)\n        with torch.cuda.amp.autocast():\n            predictions = model(data)\n            loss = loss_fn(predictions, targets)\n        optimizer.zero_grad()\n        scaler.scale(loss).backward()\n        scaler.step(optimizer)\n        scaler.update()\n        loop.set_postfix(loss=loss.item())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T12:48:17.983094Z","iopub.execute_input":"2025-03-18T12:48:17.983650Z","iopub.status.idle":"2025-03-18T13:18:00.894904Z","shell.execute_reply.started":"2025-03-18T12:48:17.983617Z","shell.execute_reply":"2025-03-18T13:18:00.893980Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Metrics (Residual U-Net)","metadata":{}},{"cell_type":"code","source":"def check_accuracy(loader, model):\n    num_correct = 0\n    num_pixels = 0\n    dice_score = 0\n    model.eval()\n\n    with torch.no_grad():\n        for x, y in loader:\n            x = x.to(DEVICE)\n            y = y.to(DEVICE)\n            softmax = nn.Softmax(dim=1)\n            preds = torch.argmax(softmax(model(x)),axis=1)\n            num_correct += (preds == y).sum()\n            num_pixels += torch.numel(preds)\n            dice_score += (2 * (preds * y).sum()) / ((preds + y).sum() + 1e-8)\n\n    print(f\"Got {num_correct}/{num_pixels} with acc {num_correct/num_pixels*100:.2f}\")\n    print(f\"Dice score: {dice_score/len(loader)}\")\n    model.train()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T13:18:00.896214Z","iopub.execute_input":"2025-03-18T13:18:00.896555Z","iopub.status.idle":"2025-03-18T13:18:00.901958Z","shell.execute_reply.started":"2025-03-18T13:18:00.896525Z","shell.execute_reply":"2025-03-18T13:18:00.901245Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_accuracy(train_batch, model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T13:18:00.903588Z","iopub.execute_input":"2025-03-18T13:18:00.903789Z","iopub.status.idle":"2025-03-18T13:19:36.911923Z","shell.execute_reply.started":"2025-03-18T13:18:00.903771Z","shell.execute_reply":"2025-03-18T13:19:36.911144Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_accuracy(test_batch, model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T13:19:36.912830Z","iopub.execute_input":"2025-03-18T13:19:36.913113Z","iopub.status.idle":"2025-03-18T13:20:23.223764Z","shell.execute_reply.started":"2025-03-18T13:19:36.913079Z","shell.execute_reply":"2025-03-18T13:20:23.222949Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for x,y in test_batch:\n    x = x.to(DEVICE)\n    fig , ax =  plt.subplots(3, 3, figsize=(18, 18))\n    softmax = nn.Softmax(dim=1)\n    preds = torch.argmax(softmax(model(x)),axis=1).to('cpu')\n    img1 = np.transpose(np.array(x[0,:,:,:].to('cpu')),(1,2,0))\n    preds1 = np.array(preds[0,:,:])\n    mask1 = np.array(y[0,:,:])\n    img2 = np.transpose(np.array(x[1,:,:,:].to('cpu')),(1,2,0))\n    preds2 = np.array(preds[1,:,:])\n    mask2 = np.array(y[1,:,:])\n    img3 = np.transpose(np.array(x[2,:,:,:].to('cpu')),(1,2,0))\n    preds3 = np.array(preds[2,:,:])\n    mask3 = np.array(y[2,:,:])\n    ax[0,0].set_title('Image')\n    ax[0,1].set_title('Prediction')\n    ax[0,2].set_title('Mask')\n    ax[1,0].set_title('Image')\n    ax[1,1].set_title('Prediction')\n    ax[1,2].set_title('Mask')\n    ax[2,0].set_title('Image')\n    ax[2,1].set_title('Prediction')\n    ax[2,2].set_title('Mask')\n    ax[0][0].axis(\"off\")\n    ax[1][0].axis(\"off\")\n    ax[2][0].axis(\"off\")\n    ax[0][1].axis(\"off\")\n    ax[1][1].axis(\"off\")\n    ax[2][1].axis(\"off\")\n    ax[0][2].axis(\"off\")\n    ax[1][2].axis(\"off\")\n    ax[2][2].axis(\"off\")\n    ax[0][0].imshow(img1)\n    ax[0][1].imshow(preds1)\n    ax[0][2].imshow(mask1)\n    ax[1][0].imshow(img2)\n    ax[1][1].imshow(preds2)\n    ax[1][2].imshow(mask2)\n    ax[2][0].imshow(img3)\n    ax[2][1].imshow(preds3)\n    ax[2][2].imshow(mask3)   \n    break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-18T13:20:23.224579Z","iopub.execute_input":"2025-03-18T13:20:23.224803Z","iopub.status.idle":"2025-03-18T13:20:24.580935Z","shell.execute_reply.started":"2025-03-18T13:20:23.224775Z","shell.execute_reply":"2025-03-18T13:20:24.580094Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Object Detection","metadata":{}},{"cell_type":"code","source":"DATA_PATH = '/kaggle/input/3d-object-detection-for-autonomous-vehicles'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T12:50:47.654951Z","iopub.execute_input":"2025-04-23T12:50:47.655345Z","iopub.status.idle":"2025-04-23T12:50:47.660125Z","shell.execute_reply.started":"2025-04-23T12:50:47.655314Z","shell.execute_reply":"2025-04-23T12:50:47.659288Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import struct\nimport numpy as np\nfrom keras.layers import Conv2D\nfrom keras.layers import Input\nfrom keras.layers import BatchNormalization\nfrom keras.layers import LeakyReLU\nfrom keras.layers import ZeroPadding2D\nfrom keras.layers import UpSampling2D\nfrom keras.layers import Add, Concatenate\nfrom keras.models import Model\nfrom keras.layers import add\nfrom keras.layers import concatenate","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:00:03.163859Z","iopub.execute_input":"2025-04-23T13:00:03.164194Z","iopub.status.idle":"2025-04-23T13:00:03.168753Z","shell.execute_reply.started":"2025-04-23T13:00:03.164167Z","shell.execute_reply":"2025-04-23T13:00:03.167773Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def _conv_block(inp, convs, skip=True):\n    x = inp\n    count = 0\n    for conv in convs:\n        if count == (len(convs) - 2) and skip:\n            skip_connection = x\n        count += 1\n        if conv['stride'] > 1: x = ZeroPadding2D(((1,0),(1,0)))(x) # peculiar padding as darknet prefer left and top\n        x = Conv2D(conv['filter'],\n                   conv['kernel'],\n                   strides=conv['stride'],\n                   padding='valid' if conv['stride'] > 1 else 'same', # peculiar padding as darknet prefer left and top\n                   name='conv_' + str(conv['layer_idx']),\n                   use_bias=False if conv['bnorm'] else True)(x)\n        if conv['bnorm']: x = BatchNormalization(epsilon=0.001, name='bnorm_' + str(conv['layer_idx']))(x)\n        if conv['leaky']: x = LeakyReLU(alpha=0.1, name='leaky_' + str(conv['layer_idx']))(x)\n    return add([skip_connection, x]) if skip else x\n\ndef make_yolov3_model():\n    input_image = Input(shape=(None, None, 3))\n    # Layer  0 => 4\n    x = _conv_block(input_image, [{'filter': 32, 'kernel': 3, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 0},\n                                  {'filter': 64, 'kernel': 3, 'stride': 2, 'bnorm': True, 'leaky': True, 'layer_idx': 1},\n                                  {'filter': 32, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 2},\n                                  {'filter': 64, 'kernel': 3, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 3}])\n    # Layer  5 => 8\n    x = _conv_block(x, [{'filter': 128, 'kernel': 3, 'stride': 2, 'bnorm': True, 'leaky': True, 'layer_idx': 5},\n                        {'filter':  64, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 6},\n                        {'filter': 128, 'kernel': 3, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 7}])\n    # Layer  9 => 11\n    x = _conv_block(x, [{'filter':  64, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 9},\n                        {'filter': 128, 'kernel': 3, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 10}])\n    # Layer 12 => 15\n    x = _conv_block(x, [{'filter': 256, 'kernel': 3, 'stride': 2, 'bnorm': True, 'leaky': True, 'layer_idx': 12},\n                        {'filter': 128, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 13},\n                        {'filter': 256, 'kernel': 3, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 14}])\n    # Layer 16 => 36\n    for i in range(7):\n        x = _conv_block(x, [{'filter': 128, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 16+i*3},\n                            {'filter': 256, 'kernel': 3, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 17+i*3}])\n    skip_36 = x\n    # Layer 37 => 40\n    x = _conv_block(x, [{'filter': 512, 'kernel': 3, 'stride': 2, 'bnorm': True, 'leaky': True, 'layer_idx': 37},\n                        {'filter': 256, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 38},\n                        {'filter': 512, 'kernel': 3, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 39}])\n    # Layer 41 => 61\n    for i in range(7):\n        x = _conv_block(x, [{'filter': 256, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 41+i*3},\n                            {'filter': 512, 'kernel': 3, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 42+i*3}])\n    skip_61 = x\n    # Layer 62 => 65\n    x = _conv_block(x, [{'filter': 1024, 'kernel': 3, 'stride': 2, 'bnorm': True, 'leaky': True, 'layer_idx': 62},\n                        {'filter':  512, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 63},\n                        {'filter': 1024, 'kernel': 3, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 64}])\n    # Layer 66 => 74\n    for i in range(3):\n        x = _conv_block(x, [{'filter':  512, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 66+i*3},\n                            {'filter': 1024, 'kernel': 3, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 67+i*3}])\n    # Layer 75 => 79\n    x = _conv_block(x, [{'filter':  512, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 75},\n                        {'filter': 1024, 'kernel': 3, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 76},\n                        {'filter':  512, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 77},\n                        {'filter': 1024, 'kernel': 3, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 78},\n                        {'filter':  512, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 79}], skip=False)\n    # Layer 80 => 82\n    yolo_82 = _conv_block(x, [{'filter': 1024, 'kernel': 3, 'stride': 1, 'bnorm': True,  'leaky': True,  'layer_idx': 80},\n                              {'filter':  255, 'kernel': 1, 'stride': 1, 'bnorm': False, 'leaky': False, 'layer_idx': 81}], skip=False)\n    # Layer 83 => 86\n    x = _conv_block(x, [{'filter': 256, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 84}], skip=False)\n    x = UpSampling2D(2)(x)\n    x = concatenate([x, skip_61])\n    # Layer 87 => 91\n    x = _conv_block(x, [{'filter': 256, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 87},\n                        {'filter': 512, 'kernel': 3, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 88},\n                        {'filter': 256, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 89},\n                        {'filter': 512, 'kernel': 3, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 90},\n                        {'filter': 256, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True, 'layer_idx': 91}], skip=False)\n    # Layer 92 => 94\n    yolo_94 = _conv_block(x, [{'filter': 512, 'kernel': 3, 'stride': 1, 'bnorm': True,  'leaky': True,  'layer_idx': 92},\n                              {'filter': 255, 'kernel': 1, 'stride': 1, 'bnorm': False, 'leaky': False, 'layer_idx': 93}], skip=False)\n    # Layer 95 => 98\n    x = _conv_block(x, [{'filter': 128, 'kernel': 1, 'stride': 1, 'bnorm': True, 'leaky': True,   'layer_idx': 96}], skip=False)\n    x = UpSampling2D(2)(x)\n    x = concatenate([x, skip_36])\n    # Layer 99 => 106\n    yolo_106 = _conv_block(x, [{'filter': 128, 'kernel': 1, 'stride': 1, 'bnorm': True,  'leaky': True,  'layer_idx': 99},\n                               {'filter': 256, 'kernel': 3, 'stride': 1, 'bnorm': True,  'leaky': True,  'layer_idx': 100},\n                               {'filter': 128, 'kernel': 1, 'stride': 1, 'bnorm': True,  'leaky': True,  'layer_idx': 101},\n                               {'filter': 256, 'kernel': 3, 'stride': 1, 'bnorm': True,  'leaky': True,  'layer_idx': 102},\n                               {'filter': 128, 'kernel': 1, 'stride': 1, 'bnorm': True,  'leaky': True,  'layer_idx': 103},\n                               {'filter': 256, 'kernel': 3, 'stride': 1, 'bnorm': True,  'leaky': True,  'layer_idx': 104},\n                               {'filter': 255, 'kernel': 1, 'stride': 1, 'bnorm': False, 'leaky': False, 'layer_idx': 105}], skip=False)\n    model = Model(input_image, [yolo_82, yolo_94, yolo_106])\n    return model\n\nclass WeightReader:\n    def __init__(self, weight_file):\n        with open(weight_file, 'rb') as w_f:\n            major,\t= struct.unpack('i', w_f.read(4))\n            minor,\t= struct.unpack('i', w_f.read(4))\n            revision, = struct.unpack('i', w_f.read(4))\n            if (major*10 + minor) >= 2 and major < 1000 and minor < 1000:\n                w_f.read(8)\n            else:\n                w_f.read(4)\n            transpose = (major > 1000) or (minor > 1000)\n            binary = w_f.read()\n        self.offset = 0\n        self.all_weights = np.frombuffer(binary, dtype='float32')\n \n    def read_bytes(self, size):\n        self.offset = self.offset + size\n        return self.all_weights[self.offset-size:self.offset]\n\n    def load_weights(self, model):\n        for i in range(106):\n            try:\n                conv_layer = model.get_layer('conv_' + str(i))\n                print(\"loading weights of convolution #\" + str(i))\n                if i not in [81, 93, 105]:\n                    norm_layer = model.get_layer('bnorm_' + str(i))\n                    size = np.prod(norm_layer.get_weights()[0].shape)\n                    beta  = self.read_bytes(size) # bias\n                    gamma = self.read_bytes(size) # scale\n                    mean  = self.read_bytes(size) # mean\n                    var   = self.read_bytes(size) # variance\n                    weights = norm_layer.set_weights([gamma, beta, mean, var])\n                if len(conv_layer.get_weights()) > 1:\n                    bias   = self.read_bytes(np.prod(conv_layer.get_weights()[1].shape))\n                    kernel = self.read_bytes(np.prod(conv_layer.get_weights()[0].shape))\n                    kernel = kernel.reshape(list(reversed(conv_layer.get_weights()[0].shape)))\n                    kernel = kernel.transpose([2,3,1,0])\n                    conv_layer.set_weights([kernel, bias])\n                else:\n                    kernel = self.read_bytes(np.prod(conv_layer.get_weights()[0].shape))\n                    kernel = kernel.reshape(list(reversed(conv_layer.get_weights()[0].shape)))\n                    kernel = kernel.transpose([2,3,1,0])\n                    conv_layer.set_weights([kernel])\n            except ValueError:\n                print(\"no convolution #\" + str(i))\n\n    def reset(self):\n        self.offset = 0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:00:04.179361Z","iopub.execute_input":"2025-04-23T13:00:04.179636Z","iopub.status.idle":"2025-04-23T13:00:04.204808Z","shell.execute_reply.started":"2025-04-23T13:00:04.179615Z","shell.execute_reply":"2025-04-23T13:00:04.204079Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from matplotlib import pyplot\nfrom matplotlib.patches import Rectangle\n\nlabel_map = {\n    \"person\": \"blue\",\n    \"bicycle\": \"yellow\", \n    \"car\": \"red\",\n    \"truck\": \"green\",\n    \"motorbike\": \"white\", \n    \"aeroplane\": \"white\", \n    \"bus\": \"white\",\n    \"train\": \"white\", \n    \"boat\": \"white\"\n}\n \nclass BoundBox:\n    def __init__(self, xmin, ymin, xmax, ymax, objness = None, classes = None):\n        self.xmin = xmin\n        self.ymin = ymin\n        self.xmax = xmax\n        self.ymax = ymax\n        self.objness = objness\n        self.classes = classes\n        self.label = -1\n        self.score = -1\n\n    def get_label(self):\n        if self.label == -1:\n            self.label = np.argmax(self.classes)\n\n        return self.label\n\n    def get_score(self):\n        if self.score == -1:\n            self.score = self.classes[self.get_label()]\n \n        return self.score\n \ndef _sigmoid(x):\n    return 1. / (1. + np.exp(-x))\n \ndef decode_netout(netout, anchors, obj_thresh, net_h, net_w):\n    grid_h, grid_w = netout.shape[:2]\n    nb_box = 3\n    netout = netout.reshape((grid_h, grid_w, nb_box, -1))\n    nb_class = netout.shape[-1] - 5\n    boxes = []\n    netout[..., :2]  = _sigmoid(netout[..., :2])\n    netout[..., 4:]  = _sigmoid(netout[..., 4:])\n    netout[..., 5:]  = netout[..., 4][..., np.newaxis] * netout[..., 5:]\n    netout[..., 5:] *= netout[..., 5:] > obj_thresh\n \n    for i in range(grid_h*grid_w):\n        row = i / grid_w\n        col = i % grid_w\n        for b in range(nb_box):\n            # 4th element is objectness score\n            objectness = netout[int(row)][int(col)][b][4]\n            if(objectness.all() <= obj_thresh): continue\n            # first 4 elements are x, y, w, and h\n            x, y, w, h = netout[int(row)][int(col)][b][:4]\n            x = (col + x) / grid_w # center position, unit: image width\n            y = (row + y) / grid_h # center position, unit: image height\n            w = anchors[2 * b + 0] * np.exp(w) / net_w # unit: image width\n            h = anchors[2 * b + 1] * np.exp(h) / net_h # unit: image height\n            # last elements are class probabilities\n            classes = netout[int(row)][col][b][5:]\n            box = BoundBox(x-w/2, y-h/2, x+w/2, y+h/2, objectness, classes)\n            boxes.append(box)\n    return boxes\n \ndef correct_yolo_boxes(boxes, image_h, image_w, net_h, net_w):\n    new_w, new_h = net_w, net_h\n    for i in range(len(boxes)):\n        x_offset, x_scale = (net_w - new_w)/2./net_w, float(new_w)/net_w\n        y_offset, y_scale = (net_h - new_h)/2./net_h, float(new_h)/net_h\n        boxes[i].xmin = int((boxes[i].xmin - x_offset) / x_scale * image_w)\n        boxes[i].xmax = int((boxes[i].xmax - x_offset) / x_scale * image_w)\n        boxes[i].ymin = int((boxes[i].ymin - y_offset) / y_scale * image_h)\n        boxes[i].ymax = int((boxes[i].ymax - y_offset) / y_scale * image_h)\n\ndef _interval_overlap(interval_a, interval_b):\n    x1, x2 = interval_a\n    x3, x4 = interval_b\n    if x3 < x1:\n        if x4 < x1:\n            return 0\n        else:\n            return min(x2,x4) - x1\n    else:\n        if x2 < x3:\n            return 0\n        else:\n            return min(x2,x4) - x3\n\ndef bbox_iou(box1, box2):\n    intersect_w = _interval_overlap([box1.xmin, box1.xmax], [box2.xmin, box2.xmax])\n    intersect_h = _interval_overlap([box1.ymin, box1.ymax], [box2.ymin, box2.ymax])\n    intersect = intersect_w * intersect_h\n    w1, h1 = box1.xmax-box1.xmin, box1.ymax-box1.ymin\n    w2, h2 = box2.xmax-box2.xmin, box2.ymax-box2.ymin\n    union = w1*h1 + w2*h2 - intersect\n    return float(intersect) / union\n \ndef do_nms(boxes, nms_thresh):\n    if len(boxes) > 0:\n        nb_class = len(boxes[0].classes)\n    else:\n        return\n    for c in range(nb_class):\n        sorted_indices = np.argsort([-box.classes[c] for box in boxes])\n        for i in range(len(sorted_indices)):\n            index_i = sorted_indices[i]\n            if boxes[index_i].classes[c] == 0: continue\n            for j in range(i+1, len(sorted_indices)):\n                index_j = sorted_indices[j]\n                if bbox_iou(boxes[index_i], boxes[index_j]) >= nms_thresh:\n                    boxes[index_j].classes[c] = 0\n\n# load and prepare an image\ndef load_image_pixels(filename, shape):\n    # load the image to get its shape\n    image = load_img(filename)\n    width, height = image.size\n    # load the image with the required size\n    image = load_img(filename, target_size=shape)\n    # convert to numpy array\n    image = img_to_array(image)\n    # scale pixel values to [0, 1]\n    image = image.astype('float32')\n    image /= 255.0\n    # add a dimension so that we have one sample\n    image = expand_dims(image, 0)\n    return image, width, height\n \n# get all of the results above a threshold\ndef get_boxes(boxes, labels, thresh):\n    v_boxes, v_labels, v_scores = list(), list(), list()\n    # enumerate all boxes\n    for box in boxes:\n        # enumerate all possible labels\n        for i in range(len(labels)):\n            # check if the threshold for this label is high enough\n            if box.classes[i] > thresh:\n                v_boxes.append(box)\n                v_labels.append(labels[i])\n                v_scores.append(box.classes[i]*100)\n                # don't break, many labels may trigger for one box\n    return v_boxes, v_labels, v_scores\n \n# draw all results\ndef draw_boxes(filename, v_boxes, v_labels, v_scores):\n    # load the image\n    data = pyplot.imread(filename)\n    # plot the image\n    pyplot.imshow(data)\n    # get the context for drawing boxes\n    ax = pyplot.gca()\n    # plot each box\n    for i in range(len(v_boxes)):\n        box = v_boxes[i]\n        # get coordinates\n        y1, x1, y2, x2 = box.ymin, box.xmin, box.ymax, box.xmax\n        # calculate width and height of the box\n        width, height = x2 - x1, y2 - y1\n        # create the shape\n        rect = Rectangle((x1, y1), width, height, fill=False, color=label_map[v_labels[i]])\n        # draw the box\n        ax.add_patch(rect)\n        # draw text and score in top left corner\n        label = \"%s (%.3f)\" % (v_labels[i], v_scores[i])\n        pyplot.text(x1, y1, label, color=label_map[v_labels[i]])\n    # show the plot\n    pyplot.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:26:32.570467Z","iopub.execute_input":"2025-04-23T13:26:32.570855Z","iopub.status.idle":"2025-04-23T13:26:32.591831Z","shell.execute_reply.started":"2025-04-23T13:26:32.570832Z","shell.execute_reply":"2025-04-23T13:26:32.590759Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# define the model\nmodel = make_yolov3_model()\n\n# load the model weights\n# I have loaded the pretrained weights in a separate dataset\nweight_reader = WeightReader('../input/lyft-3d-recognition/yolov3.weights')\n\n# set the model weights into the model\nweight_reader.load_weights(model)\n\n# save the model to file\nmodel.save('model.h5')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:26:44.038601Z","iopub.execute_input":"2025-04-23T13:26:44.038893Z","iopub.status.idle":"2025-04-23T13:26:47.442617Z","shell.execute_reply.started":"2025-04-23T13:26:44.038871Z","shell.execute_reply":"2025-04-23T13:26:47.441569Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# load yolov3 model\nfrom keras.models import load_model\nmodel = load_model('model.h5')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:27:00.455314Z","iopub.execute_input":"2025-04-23T13:27:00.455615Z","iopub.status.idle":"2025-04-23T13:27:01.917329Z","shell.execute_reply.started":"2025-04-23T13:27:00.455593Z","shell.execute_reply":"2025-04-23T13:27:01.916355Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:27:04.134794Z","iopub.execute_input":"2025-04-23T13:27:04.135117Z","iopub.status.idle":"2025-04-23T13:27:04.390772Z","shell.execute_reply.started":"2025-04-23T13:27:04.135095Z","shell.execute_reply":"2025-04-23T13:27:04.389924Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Parameters used in the Dataset, on which YOLOv3 was pretrained\nanchors = [[116,90, 156,198, 373,326], [30,61, 62,45, 59,119], [10,13, 16,30, 33,23]]\n\n# define the expected input shape for the model\nWIDTH, HEIGHT = 416, 416\n\n# define the probability threshold for detected objects\nclass_threshold = 0.3","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:27:29.589966Z","iopub.execute_input":"2025-04-23T13:27:29.590312Z","iopub.status.idle":"2025-04-23T13:27:29.594464Z","shell.execute_reply.started":"2025-04-23T13:27:29.590287Z","shell.execute_reply":"2025-04-23T13:27:29.593670Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nfrom matplotlib import pyplot as plt\nimages = os.listdir('/kaggle/input/3d-object-detection-for-autonomous-vehicles/train_images')[:10]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:27:37.999599Z","iopub.execute_input":"2025-04-23T13:27:37.999936Z","iopub.status.idle":"2025-04-23T13:27:38.947151Z","shell.execute_reply.started":"2025-04-23T13:27:37.999907Z","shell.execute_reply":"2025-04-23T13:27:38.946227Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from numpy import expand_dims\nfrom tensorflow.keras.utils import load_img, img_to_array\n\n# load and prepare an image\ndef load_image_pixels(filename, shape):\n    '''\n    Function preprocess the images to 416x416, which is the standard input shape for YOLOv3, \n    and also keeps track of the originl shape, which is later used to draw the boxes.\n    \n    paramters:\n    filename {String}: path to the image\n    shape {tuple}: shape of the input dimensions of the network\n    \n    returns:\n    image {PIL}: image of shape 'shape'\n    width {int}: original width of the picture\n    height {int}: original height of the picture\n    '''\n    # load the image to get its shape\n    image = load_img(filename)\n    width, height = image.size\n    \n    # load the image with the required size\n    image = load_img(filename, target_size=shape)\n    \n    # convert to numpy array\n    image = img_to_array(image)\n    \n    # scale pixel values to [0, 1]\n    image = image.astype('float32')\n    image /= 255.0\n    \n    # add a dimension so that we have one sample\n    image = expand_dims(image, 0)\n    return image, width, height","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:27:53.405062Z","iopub.execute_input":"2025-04-23T13:27:53.405355Z","iopub.status.idle":"2025-04-23T13:27:53.478170Z","shell.execute_reply.started":"2025-04-23T13:27:53.405335Z","shell.execute_reply":"2025-04-23T13:27:53.477494Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for file in images:\n    photo_filename = os.path.join(DATA_PATH, 'train_images', file)\n    \n    # load picture with old dimensions\n    image, image_w, image_h = load_image_pixels(photo_filename, (WIDTH, HEIGHT))\n    \n    # Predict image\n    yhat = model.predict(image)\n    \n    # Create boxes\n    boxes = list()\n    for i in range(len(yhat)):\n        # decode the output of the network\n        boxes += decode_netout(yhat[i][0], anchors[i], class_threshold, HEIGHT, WIDTH)\n\n    # correct the sizes of the bounding boxes for the shape of the image\n    correct_yolo_boxes(boxes, image_h, image_w, HEIGHT, WIDTH)\n\n    # suppress non-maximal boxes\n    do_nms(boxes, 0.5)\n\n    # define the labels (Filtered only the ones relevant for this task, which were used in pretraining the YOLOv3 model)\n    labels = [\"person\", \"bicycle\", \"car\", \"motorbike\", \"aeroplane\", \"bus\", \"train\", \"truck\",\"boat\"]\n\n    # get the details of the detected objects\n    v_boxes, v_labels, v_scores = get_boxes(boxes, labels, class_threshold)\n\n    # summarize what we found\n    for i in range(len(v_boxes)):\n\n        print(v_labels[i], v_scores[i])\n\n    # draw what we found\n    draw_boxes(photo_filename, v_boxes, v_labels, v_scores)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:32:14.145059Z","iopub.execute_input":"2025-04-23T13:32:14.145387Z","iopub.status.idle":"2025-04-23T13:32:45.314436Z","shell.execute_reply.started":"2025-04-23T13:32:14.145366Z","shell.execute_reply":"2025-04-23T13:32:45.313477Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# YOLOv8 is part of ultralytics package\n!pip install ultralytics  #The ultralytics package has the YOLO class","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:48:19.864650Z","iopub.execute_input":"2025-04-23T13:48:19.864984Z","iopub.status.idle":"2025-04-23T13:48:26.483047Z","shell.execute_reply.started":"2025-04-23T13:48:19.864962Z","shell.execute_reply":"2025-04-23T13:48:26.481927Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import libraries\nimport numpy as np\nimport pandas as pd\nfrom ultralytics import YOLO\nimport cv2\nimport PIL \nfrom PIL import Image\nfrom IPython.display import display\nimport matplotlib.pyplot as plt\nimport os \nimport pathlib ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:48:33.079928Z","iopub.execute_input":"2025-04-23T13:48:33.080289Z","iopub.status.idle":"2025-04-23T13:48:37.902896Z","shell.execute_reply.started":"2025-04-23T13:48:33.080263Z","shell.execute_reply":"2025-04-23T13:48:37.902061Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# create model using pretrained yolov8\nmodel = YOLO(\"yolov8m.pt\") ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:48:45.525405Z","iopub.execute_input":"2025-04-23T13:48:45.526201Z","iopub.status.idle":"2025-04-23T13:48:46.209425Z","shell.execute_reply.started":"2025-04-23T13:48:45.526167Z","shell.execute_reply":"2025-04-23T13:48:46.208687Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"results=model.predict(source=\"/kaggle/input/3d-object-detection-for-autonomous-vehicles/test_images/host-a004_cam0_1231810077351067006.jpeg\",save=True, conf=0.2,iou=0.5)\n# conf: object confidence threshold for detection\n#Iou: intersection over union threshold for Non Max Supression","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:49:00.400425Z","iopub.execute_input":"2025-04-23T13:49:00.400743Z","iopub.status.idle":"2025-04-23T13:49:04.754874Z","shell.execute_reply.started":"2025-04-23T13:49:00.400719Z","shell.execute_reply":"2025-04-23T13:49:04.753958Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"results\n#as you can see below, Results object contains 5 components:\n# boxes : they are object with properties for manipulating bounding boxes.\n# masks : masks object indexing masks or getting segment coordinates\n# keypoints : keypoint object for with properties and methods for manipulating predicted keypoints\n# probs : pobs object for containing class probabilities\n# orig_img : original image loaded in memory\n# path :  path to the input image ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:49:12.375156Z","iopub.execute_input":"2025-04-23T13:49:12.375528Z","iopub.status.idle":"2025-04-23T13:49:12.382627Z","shell.execute_reply.started":"2025-04-23T13:49:12.375499Z","shell.execute_reply":"2025-04-23T13:49:12.381778Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"result = results[0]\n\n# finding the detailed result(Class, Coordinates, Prob)\n\nfor box in result.boxes:\n    class_id = result.names[box.cls[0].item()]\n    cords = box.xyxy[0].tolist()\n    cords = [round(x) for x in cords]\n    conf = round(box.conf[0].item(), 2)\n    print(\"Object type:\", class_id)\n    print(\"Coordinates:\", cords)\n    print(\"Probability:\", conf)\n    print(\"---\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:49:24.442624Z","iopub.execute_input":"2025-04-23T13:49:24.442932Z","iopub.status.idle":"2025-04-23T13:49:24.465638Z","shell.execute_reply.started":"2025-04-23T13:49:24.442906Z","shell.execute_reply":"2025-04-23T13:49:24.464941Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Plotting results\nres_plotted = results[0].plot()\nres_plotted = cv2.cvtColor(res_plotted, cv2.COLOR_BGR2RGB)   #opencv uses BGR color format, while other image libraries (e.g. Image) uses RGB. So we need a conversion from BGR to RGB\ndisplay(Image.fromarray(res_plotted)) # .fromarray is used to create image from numpy array","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-23T13:49:37.251404Z","iopub.execute_input":"2025-04-23T13:49:37.251734Z","iopub.status.idle":"2025-04-23T13:49:37.461679Z","shell.execute_reply.started":"2025-04-23T13:49:37.251707Z","shell.execute_reply":"2025-04-23T13:49:37.460706Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}