{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<div class=\"alert alert-block alert-success\" style=\"font-size:30px\">\n[infer] Pytorch:auxilliary targets+weighted loss+thresholds\n</div>\n\n\n<div class=\"alert alert-block alert-info\">\n    📌 Note, that this is the inference part. Refer to the training part for more details: <a href=\"https://www.kaggle.com/vslaykovsky/train-effnetv2-aux-targets-weighted-loss-thres\">[train] Pytorch:aux targets+weighted loss+thres</a>\n</div>\n\nThis is a PyTorch implementation of multi-model ensemble classifier.\n\nHere is a high level explanation of the **inference** flow:\n1. Images are loaded from test folder and transformed to `3x1024x512` tensors using the same transformations used in training.\n2. Images are passed to an ensemble of trained `seresnext50`-based classifiers. The classifier produces probability of cancer.\n3. Thresholds produced by the training pipeline are applied in inference to improve the target metric (pF1)\n4. Ensemble is implemented with majority voting (`np.median`). This is because predictions are binary after step (3). votes are collected accross different views and different base models (e.g. 2 views * 5 models)\n\n<div class=\"alert alert-block alert-danger\" style=\"text-align:center; font-size:16px;\">\n    ❤️ Dont forget to ▲upvote▲ if you find this notebook usefull!  ❤️\n</div>","metadata":{"papermill":{"duration":0.008357,"end_time":"2022-12-05T00:21:16.53746","exception":false,"start_time":"2022-12-05T00:21:16.529103","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"<div class=\"alert alert-block alert-success\" style=\"font-size:25px\">\n 1. Imports, constants and dependencies \n</div>","metadata":{"papermill":{"duration":0.008671,"end_time":"2022-12-05T00:21:16.552675","exception":false,"start_time":"2022-12-05T00:21:16.544004","status":"completed"},"tags":[]}},{"cell_type":"code","source":"\ntry:\n    import pylibjpeg\nexcept:\n    !pip install -q /kaggle/input/rsna-2022-whl/{pydicom-2.3.0-py3-none-any.whl,pylibjpeg-1.4.0-py3-none-any.whl,python_gdcm-3.0.15-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl}\n    !pip install -q /kaggle/input/rsna-bcd-whl-ds/python_gdcm-3.0.20-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\n    # !pip install -q /kaggle/input/rsna-bcd-whl-ds/pylibjpeg-1.4.0-py3-none-any.whl\n    !pip install -q /kaggle/input/rsna-bcd-whl-ds/dicomsdl-0.109.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl","metadata":{"papermill":{"duration":112.187954,"end_time":"2022-12-05T00:23:08.74552","exception":false,"start_time":"2022-12-05T00:21:16.557566","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-12-13T22:58:45.301953Z","iopub.execute_input":"2022-12-13T22:58:45.302361Z","iopub.status.idle":"2022-12-13T23:00:28.246882Z","shell.execute_reply.started":"2022-12-13T22:58:45.302274Z","shell.execute_reply":"2022-12-13T23:00:28.245666Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import glob\nimport os\n\nimport cv2\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport torch\nimport sys\nsys.path.append('../input/timm-pytorch-image-models/pytorch-image-models-master')\nfrom timm import create_model\nfrom tqdm.notebook import tqdm\nfrom joblib import Parallel, delayed\nimport cv2\nimport dicomsdl\n\npd.set_option('display.max_rows', 1000)\npd.set_option('display.max_columns', 1000)\nplt.rcParams['figure.figsize'] = (20, 5)\n\n\n\nRSNA_2022_PATH = '/kaggle/input/rsna-breast-cancer-detection'\nPNG_TEST_IMAGES_PATH = f'test'\nMODELS_PATH = '/kaggle/input/wandb-models/models'\nDCM_TEST_IMAGES_PATH = f'/kaggle/input/rsna-breast-cancer-detection/test_images'\n\nAUX_TARGET_NCLASSES = [2, 2, 6, 2, 2, 2, 4, 5, 2, 10, 10]\n\n\ntry:\n    from kaggle_secrets import UserSecretsClient\n    IS_KAGGLE = True\nexcept:\n    IS_KAGGLE = False\n\nDEBUG = True\n\nif not IS_KAGGLE:\n    print('Running locally')\n    RSNA_2022_PATH = 'data'\n    DCM_TEST_IMAGES_PATH = f'data/test_images'\n    MODELS_PATH = 'models_roi_1024_v2'\n\n\nDEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'\nif DEVICE == 'cuda':\n    BATCH_SIZE = 16\nelse:\n    BATCH_SIZE = 2\n\n     \n    \nclass CFG:\n    resize_dim = 1024\n    aspect_ratio = True\n    img_size = [1024, 512]","metadata":{"execution":{"iopub.status.busy":"2022-12-13T23:00:28.25126Z","iopub.execute_input":"2022-12-13T23:00:28.251602Z","iopub.status.idle":"2022-12-13T23:00:31.045207Z","shell.execute_reply.started":"2022-12-13T23:00:28.251566Z","shell.execute_reply":"2022-12-13T23:00:31.044057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div class=\"alert alert-block alert-success\" style=\"font-size:25px\">\n    2. Loading test dataframe\n</div>\n ","metadata":{"papermill":{"duration":0.005183,"end_time":"2022-12-05T00:23:12.335995","exception":false,"start_time":"2022-12-05T00:23:12.330812","status":"completed"},"tags":[]}},{"cell_type":"code","source":"def load_df_test():\n    df_test = pd.read_csv(f'{RSNA_2022_PATH}/test.csv')\n    return df_test\n\ndf_test = load_df_test()\n\ndf_test","metadata":{"papermill":{"duration":0.047641,"end_time":"2022-12-05T00:23:12.38885","exception":false,"start_time":"2022-12-05T00:23:12.341209","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-12-13T23:00:31.046896Z","iopub.execute_input":"2022-12-13T23:00:31.047806Z","iopub.status.idle":"2022-12-13T23:00:31.080376Z","shell.execute_reply.started":"2022-12-13T23:00:31.047765Z","shell.execute_reply":"2022-12-13T23:00:31.079509Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div class=\"alert alert-block alert-success\" style=\"font-size:25px\">\n    3. Dataset class\n</div>\n\n`BreastCancerDataset` class returns individual images. It uses a dataframe parameter `df` as a source of metadata to locate and load images from `path` folder. ","metadata":{"papermill":{"duration":0.005225,"end_time":"2022-12-05T00:23:12.399738","exception":false,"start_time":"2022-12-05T00:23:12.394513","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"### Preprocess images ROI","metadata":{}},{"cell_type":"code","source":"!rm -rf test","metadata":{"execution":{"iopub.status.busy":"2022-12-13T23:00:31.083907Z","iopub.execute_input":"2022-12-13T23:00:31.084242Z","iopub.status.idle":"2022-12-13T23:00:32.201413Z","shell.execute_reply.started":"2022-12-13T23:00:31.084217Z","shell.execute_reply":"2022-12-13T23:00:32.200039Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor\nimport re\nimport pydicom\n\ndef fit_image(fname, size=1024):\n    # 1. Read, resize\n    \n    \n    patient = fname.split('/')[-2]\n    image = fname.split('/')[-1][:-4]\n    dicom = pydicom.dcmread(fname)\n    img = dicom.pixel_array\n    img = (img - img.min()) / (img.max() - img.min())\n    if dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        img = 1 - img\n    img = cv2.resize(img, (size, size))\n    \n    # 2. Crop\n    X = img\n    # Some images have narrow exterior \"frames\" that complicate selection of the main data. Cutting off the frame\n    X = X[5:-5, 5:-5]\n    \n    \n    # regions of non-empty pixels\n    output= cv2.connectedComponentsWithStats((X > 0.05).astype(np.uint8)[:, :], 8, cv2.CV_32S)\n\n    # stats.shape == (N, 5), where N is the number of regions, 5 dimensions correspond to:\n    # left, top, width, height, area_size\n    stats = output[2]\n    \n    # finding max area which always corresponds to the breast data. \n    idx = stats[1:, 4].argmax() + 1\n    x1, y1, w, h = stats[idx][:4]\n    x2 = x1 + w\n    y2 = y1 + h\n    \n    # cutting out the breast data\n    X_fit = X[y1: y2, x1: x2]\n    \n    patient_id, im_id = os.path.basename(os.path.dirname(fname)), os.path.basename(fname)[:-4]\n    os.makedirs(f'{PNG_TEST_IMAGES_PATH}/test_images/{patient_id}', exist_ok=True)\n    cv2.imwrite(f'{PNG_TEST_IMAGES_PATH}/test_images/{patient_id}/{im_id}.png', (X_fit[:, :] * 255).astype(np.uint8))\n\ndef fit_all_images(all_images):\n    with ThreadPoolExecutor(2) as p:\n        for i in tqdm(p.map(fit_image, all_images), total=len(all_images)):\n            pass\n\nall_images = glob.glob('/kaggle/input/rsna-breast-cancer-detection/test_images/*/*') \n# all_images = glob.glob('/kaggle/input/rsna-breast-cancer-detection/train_images/10006/*')\nfit_all_images(all_images)","metadata":{"execution":{"iopub.status.busy":"2022-12-13T23:00:32.206736Z","iopub.execute_input":"2022-12-13T23:00:32.209321Z","iopub.status.idle":"2022-12-13T23:00:34.931326Z","shell.execute_reply.started":"2022-12-13T23:00:32.209274Z","shell.execute_reply":"2022-12-13T23:00:34.93028Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!find test | head","metadata":{"execution":{"iopub.status.busy":"2022-12-13T23:00:34.932727Z","iopub.execute_input":"2022-12-13T23:00:34.933843Z","iopub.status.idle":"2022-12-13T23:00:35.885151Z","shell.execute_reply.started":"2022-12-13T23:00:34.933801Z","shell.execute_reply":"2022-12-13T23:00:35.883881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torchvision\nfrom PIL import Image\n\ndef get_transforms(aug=False):\n\n    def transforms(img):\n        img = img.convert('RGB')#.resize((512, 512))\n        if aug:\n            tfm = [\n                torchvision.transforms.RandomHorizontalFlip(0.5),\n                torchvision.transforms.RandomRotation(degrees=(-5, 5)), \n                torchvision.transforms.RandomResizedCrop((1024, 512), scale=(0.8, 1), ratio=(0.45, 0.55)) \n            ]\n        else:\n            tfm = [\n                torchvision.transforms.RandomHorizontalFlip(0.5),\n                torchvision.transforms.Resize((1024, 512))\n            ]\n        img = torchvision.transforms.Compose(tfm + [            \n            torchvision.transforms.ToTensor(),\n            torchvision.transforms.Normalize(mean=0.2179, std=0.0529),\n            \n        ])(img)\n        return img\n\n    return lambda img: transforms(img)\n\nif DEBUG:\n    tfm = get_transforms(aug=False)\n    img = Image.open(f\"{PNG_TEST_IMAGES_PATH}/test_images/10008/68070693.png\")\n    plt.imshow(np.array(img), cmap='gray')\n    plt.show()\n\n    plt.figure(figsize=(20, 20))\n    for i in range(8):\n        v = tfm(img).permute(1, 2, 0)\n        v -= v.min()\n        v /= v.max()\n        # plt.imshow(v)\n        # break\n        plt.subplot(2, 4, i + 1).imshow(v)\n    plt.tight_layout()","metadata":{"collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2022-12-13T23:00:35.888178Z","iopub.execute_input":"2022-12-13T23:00:35.888628Z","iopub.status.idle":"2022-12-13T23:00:38.778728Z","shell.execute_reply.started":"2022-12-13T23:00:35.888578Z","shell.execute_reply":"2022-12-13T23:00:38.777365Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from PIL import Image\n\n\nclass BreastCancerDataSet(torch.utils.data.Dataset):\n    def __init__(self, df, path, transforms=None):\n        super().__init__()\n        self.df = df\n        self.path = path\n        self.transforms = transforms\n\n    def __getitem__(self, i):\n\n        path = f'{self.path}/test_images/{self.df.iloc[i].patient_id}/{self.df.iloc[i].image_id}.png'\n        try:\n            img = Image.open(path).convert('RGB')\n        except Exception as ex:\n            print(path, ex)\n            return None\n\n        if self.transforms is not None:\n            img = self.transforms(img)\n\n\n        return img\n\n    def __len__(self):\n        return len(self.df)\n\nds_test = BreastCancerDataSet(df_test, PNG_TEST_IMAGES_PATH, get_transforms(False))\nif DEBUG:\n    X, y_cancer, y_aux = ds_test[2]\n    print(X.shape, y_cancer.shape, y_aux.shape)","metadata":{"papermill":{"duration":0.091858,"end_time":"2022-12-05T00:23:19.183339","exception":false,"start_time":"2022-12-05T00:23:19.091481","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-12-13T23:00:38.780127Z","iopub.execute_input":"2022-12-13T23:00:38.781775Z","iopub.status.idle":"2022-12-13T23:00:38.826857Z","shell.execute_reply.started":"2022-12-13T23:00:38.781735Z","shell.execute_reply":"2022-12-13T23:00:38.825769Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div class=\"alert alert-block alert-success\" style=\"font-size:25px\">\n     4. Model \n</div>\n","metadata":{"papermill":{"duration":0.006036,"end_time":"2022-12-05T00:23:19.195636","exception":false,"start_time":"2022-12-05T00:23:19.1896","status":"completed"},"tags":[]}},{"cell_type":"code","source":"class BreastCancerModel(torch.nn.Module):\n    def __init__(self, aux_classes, model_type='seresnext50_32x4d', dropout=0.):\n        super().__init__()\n        self.model = create_model(model_type, pretrained=False, num_classes=0, drop_rate=dropout)\n\n        self.backbone_dim = self.model(torch.randn(1, 3, 512, 512)).shape[-1]\n\n        self.nn_cancer = torch.nn.Sequential(\n            torch.nn.Linear(self.backbone_dim, 1),\n        )\n        self.nn_aux = torch.nn.ModuleList([\n            torch.nn.Linear(self.backbone_dim, n) for n in aux_classes\n        ])\n\n    def forward(self, x):\n        # returns logits\n        x = self.model(x)\n\n        cancer = self.nn_cancer(x).squeeze()\n        aux = []\n        for nn in self.nn_aux:\n            aux.append(nn(x).squeeze())\n        return cancer, aux\n\n    def predict(self, x):\n        cancer, aux = self.forward(x)\n        sigaux = []\n        for a in aux:\n            sigaux.append(torch.softmax(a, dim=-1))\n        return torch.sigmoid(cancer), sigaux\n\nif DEBUG:\n    with torch.no_grad():\n        model = BreastCancerModel(AUX_TARGET_NCLASSES, model_type='seresnext50_32x4d')\n        pred, aux = model.predict(torch.randn(2, 3, 512, 512))\n        print('seresnext', pred.shape, len(aux))\n\n        model = BreastCancerModel(AUX_TARGET_NCLASSES, model_type='efficientnet_b4')\n        pred, aux = model.predict(torch.randn(2, 3, 512, 512))\n        print('efficientnet_b4', pred.shape, len(aux))\n\n        # model = BreastCancerModel(AUX_TARGET_NCLASSES, model_type='efficientnetv2_rw_s')\n        # pred, aux = model.predict(torch.randn(2, 3, 512, 512))\n        # print('efficientnetv2_rw_s', pred.shape, len(aux))\n\n    del model","metadata":{"papermill":{"duration":2.459131,"end_time":"2022-12-05T00:23:21.660809","exception":false,"start_time":"2022-12-05T00:23:19.201678","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-12-13T23:00:38.82843Z","iopub.execute_input":"2022-12-13T23:00:38.829067Z","iopub.status.idle":"2022-12-13T23:00:45.024538Z","shell.execute_reply.started":"2022-12-13T23:00:38.829016Z","shell.execute_reply":"2022-12-13T23:00:45.023463Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_model(name, dir='.', model=None):\n    data = torch.load(os.path.join(dir, f'{name}'), map_location=DEVICE)\n    if model is None:\n        model = BreastCancerModel(AUX_TARGET_NCLASSES, data['model_type'])\n    model.load_state_dict(data['model'])\n    # print(data['threshold'], data['model_type'])\n    return model, data['threshold'], data['model_type']\n","metadata":{"papermill":{"duration":0.014644,"end_time":"2022-12-05T00:23:21.681888","exception":false,"start_time":"2022-12-05T00:23:21.667244","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-12-13T23:00:45.028355Z","iopub.execute_input":"2022-12-13T23:00:45.028916Z","iopub.status.idle":"2022-12-13T23:00:45.035233Z","shell.execute_reply.started":"2022-12-13T23:00:45.028883Z","shell.execute_reply":"2022-12-13T23:00:45.034059Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"models = []\nfor fname in tqdm(sorted(os.listdir(MODELS_PATH))):\n    model, thres, model_type = load_model(fname, MODELS_PATH)\n    model = model.to(DEVICE)\n    models.append((model, thres))\n    print(f'fname:{fname}, model_type:{model_type}, thres:{thres}')\n","metadata":{"papermill":{"duration":12.829022,"end_time":"2022-12-05T00:23:34.516853","exception":false,"start_time":"2022-12-05T00:23:21.687831","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-12-13T23:00:45.037048Z","iopub.execute_input":"2022-12-13T23:00:45.037444Z","iopub.status.idle":"2022-12-13T23:00:54.192199Z","shell.execute_reply.started":"2022-12-13T23:00:45.037405Z","shell.execute_reply":"2022-12-13T23:00:54.191186Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div class=\"alert alert-block alert-success\" style=\"font-size:25px\">\n     5. Submission \n</div>\n\nApparently, `pF1` metric can be improved by binarization of predicted values.\nSo we run all base model on every image from the test set, apply thresholds and then run majority voting by selecting the `median` value.","metadata":{"papermill":{"duration":0.005913,"end_time":"2022-12-05T00:23:34.529375","exception":false,"start_time":"2022-12-05T00:23:34.523462","status":"completed"},"tags":[]}},{"cell_type":"code","source":"THRES = 0.69 # mean\n\nTHRES = 0.91 #max\n","metadata":{"execution":{"iopub.status.busy":"2022-12-13T23:00:54.193869Z","iopub.execute_input":"2022-12-13T23:00:54.194602Z","iopub.status.idle":"2022-12-13T23:00:54.199584Z","shell.execute_reply.started":"2022-12-13T23:00:54.19456Z","shell.execute_reply":"2022-12-13T23:00:54.198367Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def models_predict(models, ds, max_batches=1e9):\n    dl_test = torch.utils.data.DataLoader(ds, batch_size=BATCH_SIZE, shuffle=False, num_workers=os.cpu_count())\n    for m, thres in models:\n        m.eval()\n\n    with torch.no_grad():\n        predictions = []\n        for idx, X in enumerate(tqdm(dl_test, mininterval=30)):\n            pred = torch.zeros(len(X), len(models))\n            for idx, (m, thres) in enumerate(models):\n                preds = m.predict(X.to(DEVICE))[0].squeeze()\n                pred[:, idx] = preds.cpu()\n            predictions.append(pred.mean(dim=-1))\n            \n            if idx >= max_batches:\n                break\n        return torch.concat(predictions).numpy()\n\n# Quick test\nif DEBUG:\n    print(models_predict([(BreastCancerModel(AUX_TARGET_NCLASSES, 'seresnext50_32x4d').to(DEVICE), 0.5),\n                    (BreastCancerModel(AUX_TARGET_NCLASSES, 'seresnext50_32x4d').to(DEVICE), 0.1)], ds_test, max_batches=2))","metadata":{"collapsed":false,"jupyter":{"outputs_hidden":false},"papermill":{"duration":2.339608,"end_time":"2022-12-05T00:23:36.875001","exception":false,"start_time":"2022-12-05T00:23:34.535393","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-12-13T23:00:54.201364Z","iopub.execute_input":"2022-12-13T23:00:54.202132Z","iopub.status.idle":"2022-12-13T23:01:04.202132Z","shell.execute_reply.started":"2022-12-13T23:00:54.202094Z","shell.execute_reply":"2022-12-13T23:01:04.200854Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"models_pred = models_predict(models, ds_test)","metadata":{"execution":{"iopub.status.busy":"2022-12-13T23:01:04.207386Z","iopub.execute_input":"2022-12-13T23:01:04.208119Z","iopub.status.idle":"2022-12-13T23:01:04.930871Z","shell.execute_reply.started":"2022-12-13T23:01:04.208073Z","shell.execute_reply":"2022-12-13T23:01:04.929595Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_test['cancer'] = models_pred\n\n\ndf_sub = df_test.groupby('prediction_id')[['cancer']].max()\ndf_sub","metadata":{"execution":{"iopub.status.busy":"2022-12-13T23:01:04.932595Z","iopub.execute_input":"2022-12-13T23:01:04.933666Z","iopub.status.idle":"2022-12-13T23:01:04.958358Z","shell.execute_reply.started":"2022-12-13T23:01:04.933617Z","shell.execute_reply":"2022-12-13T23:01:04.957148Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sub['cancer'] = (df_sub.cancer > THRES).astype(float)\ndf_sub","metadata":{"execution":{"iopub.status.busy":"2022-12-13T23:01:04.96045Z","iopub.execute_input":"2022-12-13T23:01:04.961045Z","iopub.status.idle":"2022-12-13T23:01:04.974162Z","shell.execute_reply.started":"2022-12-13T23:01:04.961007Z","shell.execute_reply":"2022-12-13T23:01:04.972404Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sub.to_csv('submission.csv', index=True)\n!head submission.csv","metadata":{"papermill":{"duration":0.018763,"end_time":"2022-12-05T00:23:37.564404","exception":false,"start_time":"2022-12-05T00:23:37.545641","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-12-13T23:01:04.975693Z","iopub.execute_input":"2022-12-13T23:01:04.976221Z","iopub.status.idle":"2022-12-13T23:01:05.984049Z","shell.execute_reply.started":"2022-12-13T23:01:04.97618Z","shell.execute_reply":"2022-12-13T23:01:05.982716Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div class=\"alert alert-block alert-danger\" style=\"text-align:center; font-size:20px;\">\n    ❤️ Dont forget to ▲upvote▲ if you find this notebook usefull!  ❤️\n</div>","metadata":{"execution":{"iopub.execute_input":"2022-08-20T13:17:18.762083Z","iopub.status.busy":"2022-08-20T13:17:18.761536Z","iopub.status.idle":"2022-08-20T13:17:18.76993Z","shell.execute_reply":"2022-08-20T13:17:18.768312Z","shell.execute_reply.started":"2022-08-20T13:17:18.762038Z"},"papermill":{"duration":0.006828,"end_time":"2022-12-05T00:23:37.578569","exception":false,"start_time":"2022-12-05T00:23:37.571741","status":"completed"},"tags":[]}}]}