{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport pandas as pd\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 as nn\nfrom torch.optim import Adam\nfrom tqdm import tqdm","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-08-05T19:56:01.069379Z","iopub.execute_input":"2022-08-05T19:56:01.070185Z","iopub.status.idle":"2022-08-05T19:56:05.719610Z","shell.execute_reply.started":"2022-08-05T19:56:01.070094Z","shell.execute_reply":"2022-08-05T19:56:05.718543Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DATA_ROOT ='../input/bundesliga'","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:56:07.930312Z","iopub.execute_input":"2022-08-05T19:56:07.930859Z","iopub.status.idle":"2022-08-05T19:56:07.936529Z","shell.execute_reply.started":"2022-08-05T19:56:07.930825Z","shell.execute_reply":"2022-08-05T19:56:07.935327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Show Mask\nimg = plt.imread(DATA_ROOT + '/masks/bundesliga10.png')\nprint(img.shape)\n#Put off RGB\nplt.imshow(img[..., 0])\nimg2=img[..., 0]\nprint(img2.shape)\nprint(np.unique(img * 255))","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:56:10.982786Z","iopub.execute_input":"2022-08-05T19:56:10.983300Z","iopub.status.idle":"2022-08-05T19:56:11.402374Z","shell.execute_reply.started":"2022-08-05T19:56:10.983258Z","shell.execute_reply":"2022-08-05T19:56:11.401290Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.unique(img * 255)","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:56:13.933625Z","iopub.execute_input":"2022-08-05T19:56:13.934024Z","iopub.status.idle":"2022-08-05T19:56:13.984085Z","shell.execute_reply.started":"2022-08-05T19:56:13.933992Z","shell.execute_reply":"2022-08-05T19:56:13.982972Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# labels\nlabels = ['bleachers','ball','field']","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:56:16.089984Z","iopub.execute_input":"2022-08-05T19:56:16.090990Z","iopub.status.idle":"2022-08-05T19:56:16.096140Z","shell.execute_reply.started":"2022-08-05T19:56:16.090946Z","shell.execute_reply":"2022-08-05T19:56:16.094866Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from albumentations.pytorch import ToTensorV2\nimport albumentations as A\nfrom albumentations import (\n    HorizontalFlip, VerticalFlip, IAAPerspective, ShiftScaleRotate, CLAHE, RandomRotate90,ToGray,\n    Transpose, ShiftScaleRotate, Blur, OpticalDistortion, GridDistortion, HueSaturationValue,\n    IAAAdditiveGaussianNoise, GaussNoise, MotionBlur, MedianBlur, IAAPiecewiseAffine, RandomResizedCrop,\n    IAASharpen, IAAEmboss, RandomBrightnessContrast, Flip, OneOf, Compose, Normalize, Cutout, CoarseDropout, ShiftScaleRotate, CenterCrop, Resize\n)\n\nt1 = A.Compose([\n    A.Resize(256,256),\n    #ToGray(p=0.3),\n    #ShiftScaleRotate(p=0.1),\n    #HorizontalFlip(),\n    #RandomBrightnessContrast(p=0.2),\n    A.augmentations.transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)),\n    ToTensorV2()\n])","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:56:18.365748Z","iopub.execute_input":"2022-08-05T19:56:18.366119Z","iopub.status.idle":"2022-08-05T19:56:18.374383Z","shell.execute_reply.started":"2022-08-05T19:56:18.366089Z","shell.execute_reply":"2022-08-05T19:56:18.373163Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_masks=[0,50,100]","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:56:23.667837Z","iopub.execute_input":"2022-08-05T19:56:23.668327Z","iopub.status.idle":"2022-08-05T19:56:23.673381Z","shell.execute_reply.started":"2022-08-05T19:56:23.668291Z","shell.execute_reply":"2022-08-05T19:56:23.672351Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#separate mask in channels\n\nfor i in range(3):\n    \n    mask = plt.imread(DATA_ROOT + '/masks/bundesliga3.png') * 255\n    #Lo que sea igual a i lo pone en 255 lo que no lo pone en 0    \n    mask = np.where(mask == num_masks[i], 255, 0)\n    #solo la capa Red \n    mask = mask[:,:,0]\n    #print(mask)\n    plt.title(f'class: {i} {labels[i]}')\n    plt.imshow(mask)\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:56:25.669306Z","iopub.execute_input":"2022-08-05T19:56:25.669873Z","iopub.status.idle":"2022-08-05T19:56:26.362307Z","shell.execute_reply.started":"2022-08-05T19:56:25.669833Z","shell.execute_reply":"2022-08-05T19:56:26.360065Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Generate list of images\nimages = []\nmasks = []\n\nfor root, dirs, files in os.walk(DATA_ROOT):\n    for name in files:\n        f = os.path.join(root, name)\n        if 'images' in f:\n            images.append(f)\n        elif 'masks' in f:\n            masks.append(f)\n        else:\n            break","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:56:39.140080Z","iopub.execute_input":"2022-08-05T19:56:39.140514Z","iopub.status.idle":"2022-08-05T19:56:39.168501Z","shell.execute_reply.started":"2022-08-05T19:56:39.140482Z","shell.execute_reply":"2022-08-05T19:56:39.167487Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(images),len(masks)","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:56:41.677251Z","iopub.execute_input":"2022-08-05T19:56:41.677733Z","iopub.status.idle":"2022-08-05T19:56:41.687371Z","shell.execute_reply.started":"2022-08-05T19:56:41.677692Z","shell.execute_reply":"2022-08-05T19:56:41.686404Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Generate Panda Dataframe Images and Masks\ndf = pd.DataFrame({'images': images, 'masks': masks})\n\ndf.sort_values(by='images',inplace=True)\n\ndf.reset_index(drop=True, inplace=True)\n\ndf.head(5)","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:56:43.399952Z","iopub.execute_input":"2022-08-05T19:56:43.401018Z","iopub.status.idle":"2022-08-05T19:56:43.424818Z","shell.execute_reply.started":"2022-08-05T19:56:43.400971Z","shell.execute_reply":"2022-08-05T19:56:43.423766Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import Dataset, DataLoader\nfrom PIL import Image\nimport torch\nfrom torch.nn import functional as F","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:56:46.001569Z","iopub.execute_input":"2022-08-05T19:56:46.001959Z","iopub.status.idle":"2022-08-05T19:56:46.007696Z","shell.execute_reply.started":"2022-08-05T19:56:46.001906Z","shell.execute_reply":"2022-08-05T19:56:46.005540Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Segmentation(Dataset):\n    def __init__(self, data,transform = None):\n        self.transforms = transform \n        self.data = data\n        #Separate list of images[:,0] and list of masks[:,1]\n        self.image_arr = self.data.iloc[:,0]        \n        self.label_arr = self.data.iloc[:,1]              \n        self.data_len = len(self.data.index)\n\n        \n    def __getitem__(self, index):\n        \n        #convert image to numpy array\n        img = cv2.cvtColor(cv2.imread(self.image_arr[index]), cv2.COLOR_BGR2RGB)        \n        \n        img = np.asarray(img)        \n       \n        #convert mask to numpy array    \n        mask = cv2.cvtColor(cv2.imread(self.label_arr[index]), cv2.COLOR_BGR2RGB)\n        mask = np.asarray(mask)\n        \n        #********************************************* \n        #*******Separate channel 3 options  *********\n        #*******  YOU CAN CHANGE THE CHANNEL *********\n        #***** bleachers= 0 ball= 50 or field=100 ********************\n        #*********************************************     \n           \n        # Select mask ==0 bleachers,  mask ==50 ball, mask ==100 field\n        cls_mask_1 = np.where(mask == 0, 1, 0)[:,:,0]\n        \n        #Apply albumentations in image and mask\n        if self.transforms is not None:\n            aug = self.transforms(image=img,mask=cls_mask_1)\n            img = aug['image']\n            mask = aug['mask'] \n            \n        return img, mask\n\n    def __len__(self):\n        return self.data_len","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:56:47.882739Z","iopub.execute_input":"2022-08-05T19:56:47.883131Z","iopub.status.idle":"2022-08-05T19:56:47.893270Z","shell.execute_reply.started":"2022-08-05T19:56:47.883099Z","shell.execute_reply":"2022-08-05T19:56:47.892275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_images(image_dir,transform = None,batch_size=1,shuffle=True,pin_memory=True):\n    data = Segmentation(image_dir,transform = t1)\n    \n    #70% train 30 % test\n    train_size = int(0.7 * data.__len__())\n    test_size = data.__len__() - train_size\n    \n    train_dataset, test_dataset = torch.utils.data.random_split(data, [train_size, test_size])\n    \n    #Generate Dataloader\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":{"execution":{"iopub.status.busy":"2022-08-05T19:56:59.644076Z","iopub.execute_input":"2022-08-05T19:56:59.644683Z","iopub.status.idle":"2022-08-05T19:56:59.651975Z","shell.execute_reply.started":"2022-08-05T19:56:59.644647Z","shell.execute_reply":"2022-08-05T19:56:59.650949Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_batch,test_batch = get_images(df,transform =t1,batch_size=5)","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:57:02.049836Z","iopub.execute_input":"2022-08-05T19:57:02.050292Z","iopub.status.idle":"2022-08-05T19:57:02.059751Z","shell.execute_reply.started":"2022-08-05T19:57:02.050253Z","shell.execute_reply":"2022-08-05T19:57:02.058763Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Show images and Masks\nfor img,mask in train_batch:   \n    \n    img1 = np.transpose(img[1,:,:,:],(1,2,0))\n    print(img1.shape)    \n    print(mask.shape)\n    mask1 = np.array(mask[1,:,:])\n    print(mask1.shape)\n    fig, ax = plt.subplots(1, 2, figsize=(15, 7))\n    ax[0].imshow(img1)\n    ax[1].imshow(mask1)\n    \n    break","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:57:03.829575Z","iopub.execute_input":"2022-08-05T19:57:03.829972Z","iopub.status.idle":"2022-08-05T19:57:07.552883Z","shell.execute_reply.started":"2022-08-05T19:57:03.829916Z","shell.execute_reply":"2022-08-05T19:57:07.551962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pip install torchsummary ","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:57:11.292556Z","iopub.execute_input":"2022-08-05T19:57:11.292954Z","iopub.status.idle":"2022-08-05T19:57:22.234080Z","shell.execute_reply.started":"2022-08-05T19:57:11.292903Z","shell.execute_reply":"2022-08-05T19:57:22.232917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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":{"execution":{"iopub.status.busy":"2022-08-05T19:57:24.585847Z","iopub.execute_input":"2022-08-05T19:57:24.586504Z","iopub.status.idle":"2022-08-05T19:57:24.594879Z","shell.execute_reply.started":"2022-08-05T19:57:24.586467Z","shell.execute_reply":"2022-08-05T19:57:24.593687Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Two channels\nclass unet_model(nn.Module):\n    def __init__(self,out_channels=2,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":{"execution":{"iopub.status.busy":"2022-08-05T19:57:27.227155Z","iopub.execute_input":"2022-08-05T19:57:27.227522Z","iopub.status.idle":"2022-08-05T19:57:27.244261Z","shell.execute_reply.started":"2022-08-05T19:57:27.227491Z","shell.execute_reply":"2022-08-05T19:57:27.242521Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:57:33.761671Z","iopub.execute_input":"2022-08-05T19:57:33.762071Z","iopub.status.idle":"2022-08-05T19:57:33.766694Z","shell.execute_reply.started":"2022-08-05T19:57:33.762039Z","shell.execute_reply":"2022-08-05T19:57:33.765638Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = unet_model().to(DEVICE)","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:57:35.504909Z","iopub.execute_input":"2022-08-05T19:57:35.505624Z","iopub.status.idle":"2022-08-05T19:57:35.861669Z","shell.execute_reply.started":"2022-08-05T19:57:35.505589Z","shell.execute_reply":"2022-08-05T19:57:35.860675Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torchsummary import summary\nsummary(model, (3, 256, 256))","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:57:38.067225Z","iopub.execute_input":"2022-08-05T19:57:38.067604Z","iopub.status.idle":"2022-08-05T19:57:43.375361Z","shell.execute_reply.started":"2022-08-05T19:57:38.067572Z","shell.execute_reply":"2022-08-05T19:57:43.373983Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"LEARNING_RATE = 1e-4\nnum_epochs = 50","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:57:47.177763Z","iopub.execute_input":"2022-08-05T19:57:47.178156Z","iopub.status.idle":"2022-08-05T19:57:47.183333Z","shell.execute_reply.started":"2022-08-05T19:57:47.178124Z","shell.execute_reply":"2022-08-05T19:57:47.182187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loss_fn = nn.CrossEntropyLoss()\noptimizer = Adam(model.parameters(), lr=LEARNING_RATE)\nscaler = torch.cuda.amp.GradScaler()","metadata":{"execution":{"iopub.status.busy":"2022-08-05T19:57:49.020105Z","iopub.execute_input":"2022-08-05T19:57:49.021317Z","iopub.status.idle":"2022-08-05T19:57:49.028108Z","shell.execute_reply.started":"2022-08-05T19:57:49.021274Z","shell.execute_reply":"2022-08-05T19:57:49.026520Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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":"2022-08-05T19:57:51.543546Z","iopub.execute_input":"2022-08-05T19:57:51.544080Z","iopub.status.idle":"2022-08-05T19:58:13.303850Z","shell.execute_reply.started":"2022-08-05T19:57:51.544040Z","shell.execute_reply":"2022-08-05T19:58:13.302794Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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":{"execution":{"iopub.status.busy":"2022-08-05T19:59:54.087875Z","iopub.execute_input":"2022-08-05T19:59:54.088621Z","iopub.status.idle":"2022-08-05T19:59:54.096445Z","shell.execute_reply.started":"2022-08-05T19:59:54.088581Z","shell.execute_reply":"2022-08-05T19:59:54.095190Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"check_accuracy(test_batch, model)","metadata":{"execution":{"iopub.status.busy":"2022-08-05T20:00:08.742816Z","iopub.execute_input":"2022-08-05T20:00:08.743550Z","iopub.status.idle":"2022-08-05T20:00:09.260319Z","shell.execute_reply.started":"2022-08-05T20:00:08.743512Z","shell.execute_reply":"2022-08-05T20:00:09.259288Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#you can update these cells to see other images and masks \nfor x,y in train_batch:\n    x = x.to(DEVICE)\n    fig , ax =  plt.subplots(1, 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    \n    ax[0].set_title('Image')\n    ax[1].set_title('Prediction')\n    ax[2].set_title('Mask')\n    \n    ax[0].axis(\"off\")\n    ax[1].axis(\"off\")\n    ax[2].axis(\"off\")\n    \n    ax[0].imshow(img1)\n    ax[1].imshow(preds1)\n    ax[2].imshow(mask1)\n    \n    break","metadata":{"execution":{"iopub.status.busy":"2022-08-05T20:00:20.967418Z","iopub.execute_input":"2022-08-05T20:00:20.967842Z","iopub.status.idle":"2022-08-05T20:00:21.499781Z","shell.execute_reply.started":"2022-08-05T20:00:20.967809Z","shell.execute_reply":"2022-08-05T20:00:21.498859Z"},"trusted":true},"execution_count":null,"outputs":[]}]}