{"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 catalyst\nfrom catalyst import utils\ncatalyst.utils.torch.get_device()","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:36:36.104233Z","iopub.execute_input":"2023-01-25T17:36:36.105609Z","iopub.status.idle":"2023-01-25T17:36:42.401934Z","shell.execute_reply.started":"2023-01-25T17:36:36.105498Z","shell.execute_reply":"2023-01-25T17:36:42.400403Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd \nfrom torch.utils.data import DataLoader, Dataset\nfrom torchvision import transforms\nimport os\nimport cv2\nimport torch\nfrom torch import nn, optim\nfrom kaggle_secrets import UserSecretsClient\n\nN_SPLIT = 3\n\nmodels_folder = '/kaggle/input/ses-brtchen/'\nprojections = ['CC', 'MLO']","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-01-25T17:36:42.404168Z","iopub.execute_input":"2023-01-25T17:36:42.404551Z","iopub.status.idle":"2023-01-25T17:36:42.412159Z","shell.execute_reply.started":"2023-01-25T17:36:42.404503Z","shell.execute_reply":"2023-01-25T17:36:42.410826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"INTERNET = False\n\nPROJECT_NAME = \"RSNAMammo\"\nuser_secrets = UserSecretsClient()\nWANDB_API_KEY = None\nif INTERNET:\n    WANDB_API_KEY = user_secrets.get_secret(\"VVV\")\n    os.environ['WANDB_API_KEY'] = WANDB_API_KEY\n\n\nTRAIN_PATH = \"/kaggle/input/rsna-mammography-images-as-pngs/images_as_pngs_512/train_images_processed_512\"\nTEST_PATH = \"/kaggle/input/rsna-breast-cancer-detection/test_images\"\n\n\n# SPLIT_FRACTION = 0.95\nBATCH_SIZE = 128 \nMODEL = 'resnet50'\nEPOCHS = 20\nLR = 10e-4\nNUM_CLASS = 1\ndebug = False","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:36:42.413883Z","iopub.execute_input":"2023-01-25T17:36:42.414635Z","iopub.status.idle":"2023-01-25T17:36:42.441911Z","shell.execute_reply.started":"2023-01-25T17:36:42.414589Z","shell.execute_reply":"2023-01-25T17:36:42.440782Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def img2roi(img, is_dicom=False):\n    \"\"\"\n    Returns ROI area in other words \n    cuts the image to a desired one\n    \n    Because there are machine label tags,\n    undesired details out of the breast image.\n    \"\"\"\n    if not is_dicom:\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n        \n    img = np.array(img * 255, dtype = np.uint8)\n    bin_img = cv2.threshold(img, 20, 255, cv2.THRESH_BINARY)[1]\n\n    contours, _ = cv2.findContours(bin_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)\n    if len(contours) > 0:\n        contour = max(contours, key=cv2.contourArea)\n\n        ys = contour.squeeze()[:, 0]\n        xs = contour.squeeze()[:, 1]\n        if np.min(xs) == np.max(xs) or np.min(ys) == np.max(ys):\n            roi = img\n        else:\n            roi =  img[np.min(xs):np.max(xs), np.min(ys):np.max(ys)]\n    else:\n        roi = img\n    \n    return roi","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:36:42.445163Z","iopub.execute_input":"2023-01-25T17:36:42.446005Z","iopub.status.idle":"2023-01-25T17:36:42.457186Z","shell.execute_reply.started":"2023-01-25T17:36:42.445955Z","shell.execute_reply":"2023-01-25T17:36:42.456359Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class RSNADataset(Dataset):\n    def __init__(self, df, img_folder, transform, is_test=False):\n        self.df = df\n        self.img_folder = img_folder\n        self.transform = transform\n        self.is_test = is_test\n    \n    def __getitem__(self, idx):\n        if self.is_test:\n            dcm_path = os.path.join(self.img_folder, self.df[\"dcm_path\"][idx])\n            img = read_dicom(dcm_path)\n            img = img2roi(img, is_dicom=True) \n            \n            #print(img.shape)\n        else:\n            img_path = os.path.join(self.img_folder, self.df[\"img_name\"][idx])\n#             print(img_path)\n            img = cv2.imread(img_path)\n            img = img2roi(img, is_dicom=False)\n            \n            #print(img.shape)\n        img = cv2.resize(img, (224, 224))\n        if self.transform is not None:\n            img = self.transform(img)    \n        img = torch.tensor(img, dtype=torch.float)\n        #img = img.permute(2, 1, 0)\n        if not self.is_test:\n            target = self.df[\"cancer\"][idx]\n            target = torch.tensor(target, dtype=torch.float)\n            return img, target\n        img = img.unsqueeze(0)\n        #print(img.shape)\n        return img, -1.0\n    \n    def __len__(self):\n        return len(self.df)","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:36:42.458629Z","iopub.execute_input":"2023-01-25T17:36:42.459365Z","iopub.status.idle":"2023-01-25T17:36:42.47088Z","shell.execute_reply.started":"2023-01-25T17:36:42.459298Z","shell.execute_reply":"2023-01-25T17:36:42.469918Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_transforms():\n    transform = transforms.Compose([\n            transforms.ToPILImage(),\n#             transforms.ColorJitter(brightness=0.3, contrast=0.3, saturation=0.2, hue=0.2),\n#             transforms.GaussianBlur(kernel_size=3, sigma=(0.1, 2.0)),\n            transforms.RandomVerticalFlip(0.5),\n            transforms.RandomRotation(degrees=(-10, 10)),\n#             transforms.RandomEqualize(),\n            transforms.ToTensor(), \n            transforms.Normalize(mean=0.2179, std=0.0529)\n        ])\n    return transform","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:36:42.472025Z","iopub.execute_input":"2023-01-25T17:36:42.472614Z","iopub.status.idle":"2023-01-25T17:36:42.489327Z","shell.execute_reply.started":"2023-01-25T17:36:42.472582Z","shell.execute_reply":"2023-01-25T17:36:42.488002Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def pfbeta(predictions, labels, beta=1.):\n    y_true_count = 0\n    ctp = 0\n    cfp = 0\n\n    for idx in range(len(labels)):\n        prediction = min(max(predictions[idx], 0), 1)\n        if (labels[idx]):\n            y_true_count += 1\n            ctp += prediction\n        else:\n            cfp += prediction\n\n    beta_squared = beta * beta\n    c_precision = ctp / (ctp + cfp)\n    c_recall = ctp / max(y_true_count, 1)  # avoid / 0\n    if (c_precision > 0 and c_recall > 0):\n        result = (1 + beta_squared) * (c_precision * c_recall) / (beta_squared * c_precision + c_recall)\n        return result\n    else:\n        return 0","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:36:42.490725Z","iopub.execute_input":"2023-01-25T17:36:42.49138Z","iopub.status.idle":"2023-01-25T17:36:42.502625Z","shell.execute_reply.started":"2023-01-25T17:36:42.491333Z","shell.execute_reply":"2023-01-25T17:36:42.501353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# read raw file\ndf = pd.read_csv(\"/kaggle/input/rsna-breast-cancer-detection/train.csv\")\n# add image filename columns\ndf[\"img_name\"] = df[\"patient_id\"].astype(str) + \"/\" + df[\"image_id\"].astype(str) + \".png\"\n# shuffle it\ndf = df.sample(frac=1).reset_index(drop=True)\n\n# undersample according to the cancer patients since they are minority\n# undersample_amount = len(df[df[\"cancer\"]==1])\n\n# dfnotcancer = df[df[\"cancer\"]==0].sample(undersample_amount).reset_index(drop=True)\n# dfcancer = df[df[\"cancer\"]==1].reset_index(drop=True)\n\n# # concat and then shuffle, reset index\n# dff = pd.concat([dfcancer, dfnotcancer]).sample(frac=1).reset_index(drop=True)\n\n# print(f\"Old data shape is {df.shape} and new data shape is: {dff.shape}\")\n\n# dff.head()","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:36:42.504145Z","iopub.execute_input":"2023-01-25T17:36:42.504815Z","iopub.status.idle":"2023-01-25T17:36:42.781969Z","shell.execute_reply.started":"2023-01-25T17:36:42.504766Z","shell.execute_reply":"2023-01-25T17:36:42.780536Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sys\nsys.path.append('../input/timm-pytorch-image-models/pytorch-image-models-master')\n\nimport catalyst\n\ncatalyst.__version__ \n\nimport timm\nimport copy\nimport catalyst\nfrom catalyst.callbacks.metrics.classification import MultilabelPrecisionRecallF1SupportCallback\nif catalyst.__version__ == '21.08':\n    from catalyst.contrib.nn.criterion.focal import FocalLossBinary\nelse:\n    from catalyst.contrib.losses import FocalLossBinary\n\nfrom catalyst.runners import SupervisedRunner\nfrom typing import Any, Mapping\nfrom catalyst.loggers.wandb import WandbLogger\nimport catalyst.callbacks as dl\nfrom catalyst.metrics.functional._f1_score import fbeta_score\n\nfrom catalyst import metrics\n\nclass RSNAMammoRunner(SupervisedRunner):\n    def forward(self, batch: Mapping[str, Any], **kwargs) -> Mapping[str, Any]:\n        output = self._process_input(batch, **kwargs).squeeze()\n        output = self._process_output(output)\n        return output\n    \n    def get_loggers(self):\n        loggers = {}\n        if WANDB_API_KEY:\n            loggers[\"wandb\"] = WandbLogger(project=PROJECT_NAME, \n                                           group=f\"MODEL:{MODEL}|\" + self._type + \"|\" + self._name + self.get_criterion()._get_name(),\n                                           name=f\"LR:{LR}|EPOCHS:{EPOCHS}|{self.split_}\")\n        return loggers\n    \n    def get_criterion(self, **stuff):\n#         return FocalLossBinary()\n        return nn.BCEWithLogitsLoss()\n    \n    def get_callbacks(self, *params):\n        callbacks = {\n            \"criterion\": dl.CriterionCallback(\n                metric_key=\"loss\", input_key=\"logits\", target_key=\"targets\"\n            ),\n            \"checkpoint\": dl.CheckpointCallback(\n                self._logdir, loader_key=\"valid\", metric_key=\"loss\", minimize=True\n            ),\n            \"optimizer\": dl.OptimizerCallback(\n                metric_key=\"loss\",\n            ),\n            \"tqdm\": dl.TqdmCallback(),\n            \"F_score\" : dl.PrecisionRecallF1SupportCallback(\n                input_key=\"logits\", target_key=\"targets\", num_classes=NUM_CLASS\n            ),\n            \"AUC\" : dl.AUCCallback(\n                input_key=\"logits\", target_key=\"targets\", #num_classes=NUM_CLASS\n            ),\n#             \"FBETA\": SklearnLoaderCallback(pfbeta, beta=1.0, \n#                                           input_key=\"logits\", \n#                                           target_key=\"targets\",)\n            \n        }\n        if catalyst.__version__ != '21.08':\n            callbacks['backward'] = dl.BackwardCallback(metric_key=\"loss\")\n        return callbacks\n\n    def get_optimizer(self, model, **stuff):\n#         if '1.7.1+cpu':\n#             return torch.optim.SGD(model.parameters(), lr=LR)\n#         else:\n        return torch.optim.Adam(model.parameters(), lr=LR)\n        \n    def get_sampler(self):\n        raise ValueError()\n\ndef get_model():\n    out_dim = 1\n    backbone = timm.create_model(MODEL, pretrained=False, in_chans=1)\n    if 'resnet' in MODEL or 'resnext' in MODEL:\n        backbone.fc = nn.Linear(backbone.fc.in_features, \n                             out_dim)\n    else:\n        backbone.classifier = nn.Linear(backbone.classifier.in_features, \n                                 out_dim)\n    return backbone","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:36:42.783875Z","iopub.execute_input":"2023-01-25T17:36:42.784429Z","iopub.status.idle":"2023-01-25T17:36:45.019678Z","shell.execute_reply.started":"2023-01-25T17:36:42.784381Z","shell.execute_reply":"2023-01-25T17:36:45.018421Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_loader(df, sampler=None, shuffle=False, drop_last=False):\n    dataset = RSNADataset(df=df.reset_index(drop=True), \n                          img_folder=TRAIN_PATH, \n                          transform=get_transforms(),\n                         )\n    loader = DataLoader(dataset, \n                        batch_size=BATCH_SIZE, \n                        shuffle=shuffle, \n                        sampler=sampler,\n                        num_workers=2,\n                        drop_last=drop_last\n                       )\n    return loader","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:36:45.026028Z","iopub.execute_input":"2023-01-25T17:36:45.026657Z","iopub.status.idle":"2023-01-25T17:36:45.032914Z","shell.execute_reply.started":"2023-01-25T17:36:45.026619Z","shell.execute_reply":"2023-01-25T17:36:45.031642Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"VERSION = \"1.5\"  # possible version: [\"1.5\" , \"20200325\", \"nightly\"]\n!curl https://raw.githubusercontent.com/pytorch/xla/master/contrib/scripts/env-setup.py -o pytorch-xla-env-setup.py > /dev/null","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:36:45.034734Z","iopub.execute_input":"2023-01-25T17:36:45.035254Z","iopub.status.idle":"2023-01-25T17:37:06.360101Z","shell.execute_reply.started":"2023-01-25T17:36:45.035205Z","shell.execute_reply":"2023-01-25T17:37:06.358592Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"timm# Inference","metadata":{}},{"cell_type":"code","source":"!pip install /kaggle/input/rsna-bcd-whl-ds/dicomsdl-0.109.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:37:06.362048Z","iopub.execute_input":"2023-01-25T17:37:06.362546Z","iopub.status.idle":"2023-01-25T17:37:39.847104Z","shell.execute_reply.started":"2023-01-25T17:37:06.362505Z","shell.execute_reply":"2023-01-25T17:37:39.845899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import dicomsdl\n\ndef read_dicom(path, fix_monochrome = True):\n    dicom = dicomsdl.open(path)\n    data = dicom.pixelData(storedvalue=True)  # storedvalue = True for int16 return otherwise float32\n    data = data - np.min(data)\n    data = data / np.max(data)\n    if fix_monochrome and dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        data = 1.0 - data\n    return data","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:37:39.848822Z","iopub.execute_input":"2023-01-25T17:37:39.849216Z","iopub.status.idle":"2023-01-25T17:37:39.867218Z","shell.execute_reply.started":"2023-01-25T17:37:39.849175Z","shell.execute_reply":"2023-01-25T17:37:39.866225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_model_paths(projection_models_dir):\n    folds = os.listdir(projection_models_dir)\n    return [os.path.join(projection_models_dir, fold) for fold in folds]\n\ndef get_model_name(path:str):\n    name = \"_\".join(path.split('/')[-2:]) + \"_pred\"\n    return name\n\npredictors = dict()\ntrain_predictions = dict()\nfor projection in projections:\n    projection_models_dirs = [os.path.join(models_folder, dir_name) for dir_name in filter(lambda x: projection in x and \".\" not in x, os.listdir(models_folder))]\n    predictors[projection] = [model_fold for model_path in projection_models_dirs for model_fold in sorted(get_model_paths(model_path))]\n    \n    train_predictions_paths = [os.path.join(models_folder, file_name) for file_name in filter(lambda x: projection in x and \".\" in x, os.listdir(models_folder))]\n    train_predictions[projection] = []\n    for fold_pred_path in sorted(train_predictions_paths):\n        fold_preds = pd.read_csv(fold_pred_path)\n        fold_preds['oof_fold'] = fold_pred_path.split(\"/\")[-1].split(\".\")[0]\n        train_predictions[projection].append(fold_preds)","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:37:39.871144Z","iopub.execute_input":"2023-01-25T17:37:39.872775Z","iopub.status.idle":"2023-01-25T17:37:40.122343Z","shell.execute_reply.started":"2023-01-25T17:37:39.87272Z","shell.execute_reply":"2023-01-25T17:37:40.121181Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tqdm import tqdm\n\ndef create_loader(df, projection, is_test=True, folder_path=TEST_PATH):\n    projection_df = df[df['view'] == projection].copy().reset_index(drop=True)\n    projection_test_dataset=RSNADataset(df=projection_df, \n                                        img_folder=folder_path, \n                                        transform=None, \n                                        is_test=is_test)\n    projection_test_loader = DataLoader(projection_test_dataset, \n                                        batch_size=BATCH_SIZE, \n                                        shuffle=False,\n                                        num_workers=4)\n    return projection_test_loader\n\ndef preprocess_model(model):\n    return model\n\ndef load_model(path):\n    model = get_model()\n    model.load_state_dict(torch.load(path) if torch.cuda.is_available() else torch.load(path, map_location=torch.device('cpu')))\n    model = preprocess_model(model)\n    return model\n\ndef sigmoid(x):\n    return 1/(1+np.exp(-x))\n\ndef predict_df(df, is_test=True, mean_proba = df['cancer'].mean(), folder_path=TEST_PATH):\n    df = df.copy()\n    results = {}\n    for projection in predictors:\n        loader = create_loader(df, projection, is_test=is_test, folder_path=folder_path)\n        fold_preds = []\n        for model_path in predictors[projection]:\n            preds = []\n            print(model_path)\n            model = load_model(os.path.join(model_path, 'model.best.pth'))\n            for pred in runner.predict_loader(loader = loader, \n                                              model=model, \n                                              cpu=not torch.cuda.is_available(), \n                                              fp16=True, ):\n                preds.extend(pred['logits'].detach().cpu().numpy().tolist())\n            fold_preds.append(preds)\n            df[get_model_name(model_path)] = 0\n            df.loc[df['view'] == projection, get_model_name(model_path)] = sigmoid(np.array(preds))\n    return df","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:37:40.124018Z","iopub.execute_input":"2023-01-25T17:37:40.124529Z","iopub.status.idle":"2023-01-25T17:37:40.141815Z","shell.execute_reply.started":"2023-01-25T17:37:40.124482Z","shell.execute_reply":"2023-01-25T17:37:40.14017Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_test = pd.read_csv(\"/kaggle/input/rsna-breast-cancer-detection/test.csv\")\ndf_test[\"img_name\"] = df_test[\"patient_id\"].astype(str) + \"/\" + df_test[\"image_id\"].astype(str) + \".png\"\ndf_test[\"dcm_path\"] = df_test[\"patient_id\"].astype(str) + \"/\" + df_test[\"image_id\"].astype(str) + \".dcm\"\n\ndebug=True\nif debug:\n    from tqdm import trange\n    for i in trange(8):\n        next_test = df_test.copy()\n        next_test['patient_id'] += next_test['patient_id'].max()\n        df_test = pd.concat([df_test, next_test]).reset_index(drop=True)\n        \ndf_test['patient_id'].nunique()","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:37:40.143288Z","iopub.execute_input":"2023-01-25T17:37:40.143707Z","iopub.status.idle":"2023-01-25T17:37:40.202906Z","shell.execute_reply.started":"2023-01-25T17:37:40.143674Z","shell.execute_reply":"2023-01-25T17:37:40.201703Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"4 45s\n\n8 1min 24s\n\n32 5min 39s\n\n256 20min 29s\n\n1024 1h 30m 36s","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.plot(np.log2([4,8,32,256, 1024]), np.log2([45, 89, 339, 1229, 5436]))","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:37:40.204643Z","iopub.execute_input":"2023-01-25T17:37:40.205877Z","iopub.status.idle":"2023-01-25T17:37:40.704992Z","shell.execute_reply.started":"2023-01-25T17:37:40.205826Z","shell.execute_reply":"2023-01-25T17:37:40.703527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def preprocess_model(model, df_test=None):\n    if df_test is not None:\n        loader = create_loader(df_test, 'MLO', \n                               is_test=True, \n                               folder_path=TEST_PATH)\n        batch = next(iter(loader))[0]\n        _ = utils.trace_model(model=model, batch=batch)\n        print('Model is being JIT compilled')\n#     utils.quantize_model(model=model)\n#     utils.prune_model(model=model, pruning_fn=\"l1_unstructured\", amount=0.8)\n#     utils.onnx_export(model=model, batch=batch, file=\"./logs/mnist.onnx\", verbose=True)\n    return model","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:37:40.70896Z","iopub.execute_input":"2023-01-25T17:37:40.709369Z","iopub.status.idle":"2023-01-25T17:37:40.717886Z","shell.execute_reply.started":"2023-01-25T17:37:40.709335Z","shell.execute_reply":"2023-01-25T17:37:40.715605Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"m_test = get_model()","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:37:40.720142Z","iopub.execute_input":"2023-01-25T17:37:40.720562Z","iopub.status.idle":"2023-01-25T17:37:41.186096Z","shell.execute_reply.started":"2023-01-25T17:37:40.720522Z","shell.execute_reply":"2023-01-25T17:37:41.184863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\nret = preprocess_model(m_test, df_test)","metadata":{"execution":{"iopub.status.busy":"2023-01-25T18:00:56.994608Z","iopub.execute_input":"2023-01-25T18:00:56.995119Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"5 17","metadata":{}},{"cell_type":"code","source":"%%time\ndf_test.head()\n\nrunner = RSNAMammoRunner()\nprediction_df = predict_df(df_test)","metadata":{"execution":{"iopub.status.busy":"2023-01-25T17:39:13.558533Z","iopub.execute_input":"2023-01-25T17:39:13.558914Z","iopub.status.idle":"2023-01-25T18:00:48.350734Z","shell.execute_reply.started":"2023-01-25T17:39:13.558875Z","shell.execute_reply":"2023-01-25T18:00:48.349532Z"},"trusted":true},"execution_count":null,"outputs":[]}]}