{"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":"# [RSNA Screening Mammography Breast Cancer Detection](https://www.kaggle.com/c/petfinder-pawpularity-score)\n> Find breast cancers in screening mammograms\n\n![](https://storage.googleapis.com/kaggle-competitions/kaggle/39272/logos/header.png?t=2022-11-28-17-29-35)","metadata":{}},{"cell_type":"markdown","source":"# Idea:\n* In this notebook will do inference for `breast cancer` detection from Mammography images.\n* Dicom images are saved to `1024` dim with aspect ratio. Modify `resize_dim` and `aspect_ratio` in config file to change them.\n* Batch Size is chosen adaptly depending on the image_size, you can change it on the `inference` cell\n* You can play with notebook by simply changing `tta` and `thr` parameter in config.","metadata":{}},{"cell_type":"markdown","source":"# Notebooks\n* Only Image:\n    * ROI:\n        * train: [RSNA-BCD: EfficientNet [TF][TPU-1VM][Train]](https://www.kaggle.com/code/awsaf49/rsna-bcd-efficientnet-tf-tpu-1vm-train)\n        * infer: [RSNA-BCD: EfficientNet [TF][TPU-1VM][Infer]](https://www.kaggle.com/code/awsaf49/rsna-bcd-efficientnet-tf-tpu-1vm-infer)\n    * NoROI + KerasCV: \n        * train: [RSNA-BCD: NoROI KerasCV [TF][Train]](https://www.kaggle.com/awsaf49/rsna-bcd-noroi-kerascv-tf-train/)\n        * infer: [RSNA-BCD: NoROI KerasCV [TF][Infer]](https://www.kaggle.com/awsaf49/rsna-bcd-noroi-kerascv-tf-infer/)\n* Dataset:\n    * ROI:\n        * [RSNA-BCD: ROI 1024x PNG Dataset](https://www.kaggle.com/datasets/awsaf49/rsna-bcd-roi-1024x-png-dataset)\n    * NoROI:\n        * [RSNA-BCD: 512 PNG v2 PNG Dataset](https://www.kaggle.com/datasets/awsaf49/rsnabcd-512-png-v2-dataset)","metadata":{}},{"cell_type":"markdown","source":"# Install Libraries","metadata":{}},{"cell_type":"code","source":"!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\n# !pip install -q /kaggle/input/rsna-bcd-whl-ds/keras_cv-0.3.4-py3-none-any.whl\n!cp -r /kaggle/input/efficientnet-keras-dataset/efficientnet_kaggle /tmp/ && pip install -q /tmp/efficientnet_kaggle","metadata":{"_kg_hide-output":true,"_kg_hide-input":false,"execution":{"iopub.status.busy":"2022-12-14T05:34:59.70353Z","iopub.execute_input":"2022-12-14T05:34:59.703962Z","iopub.status.idle":"2022-12-14T05:37:00.749112Z","shell.execute_reply.started":"2022-12-14T05:34:59.70388Z","shell.execute_reply":"2022-12-14T05:37:00.747952Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Import Libraries","metadata":{}},{"cell_type":"code","source":"import os\nos.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'  # to avoid too many logging messages\nimport pandas as pd, numpy as np, random, shutil\nimport tensorflow as tf, re, math\nimport tensorflow.keras.backend as K\nimport efficientnet.tfkeras as efn\nimport sklearn\nimport matplotlib.pyplot as plt\nimport cv2\nimport tensorflow_addons as tfa\nimport yaml\n\nfrom IPython import display as ipd\nfrom glob import glob\nfrom tqdm import tqdm","metadata":{"execution":{"iopub.status.busy":"2022-12-14T05:37:00.75155Z","iopub.execute_input":"2022-12-14T05:37:00.751935Z","iopub.status.idle":"2022-12-14T05:37:06.380465Z","shell.execute_reply.started":"2022-12-14T05:37:00.751898Z","shell.execute_reply":"2022-12-14T05:37:06.379533Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Version Check","metadata":{}},{"cell_type":"code","source":"print('np:', np.__version__)\nprint('pd:', pd.__version__)\nprint('sklearn:', sklearn.__version__)\nprint('tf:',tf.__version__)\nprint('tfa:', tfa.__version__)","metadata":{"execution":{"iopub.status.busy":"2022-12-14T05:37:06.381879Z","iopub.execute_input":"2022-12-14T05:37:06.382594Z","iopub.status.idle":"2022-12-14T05:37:06.389268Z","shell.execute_reply.started":"2022-12-14T05:37:06.382562Z","shell.execute_reply":"2022-12-14T05:37:06.388167Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Configuration","metadata":{}},{"cell_type":"code","source":"class CFG:\n    debug         = False\n    \n    # use verbose=0 for silent, vebose=1 for interactive,\n    verbose      = 1 if debug else 0\n    \n    # device\n    device = \"GPU\" # or \"GPU\"\n\n    # seed for data-split, layer init, augs\n    seed = 42\n\n    # number of folds for data-split\n    folds = 5\n    \n    # which folds to train\n    selected_folds = [0, 1, 2, 3, 4]\n\n    # dicom to png size\n    resize_dim = 1024\n    aspect_ratio = False\n    \n    # size of training image\n    img_size = [1024, 1024]\n\n    # batch_size and epochs\n    batch_size = 32\n    epochs = 12\n    \n    # upsample\n    upsample = 10\n\n    # loss and optimizer\n    loss      = 'Focal'  # BCE, Focal\n    optimizer = 'Adam'\n\n    # augmentation\n    augment = False\n    \n    # flip\n    hflip = True\n    vflip = False\n    \n    # pixel-augment\n    pixel_aug = True\n    sat  = [0.7, 1.3]\n    cont = [0.8, 1.2]\n    bri  = 0.15\n    hue  = 0.05\n\n\n    # clip\n    clip = False\n\n    # lr-scheduler\n    scheduler   = 'exp' # cosine\n\n    # test-time augs\n    tta = 1\n    \n    # threhold\n    thr = 0.6\n    \n    # target column\n    target_col  = ['cancer']","metadata":{"execution":{"iopub.status.busy":"2022-12-14T05:37:06.392464Z","iopub.execute_input":"2022-12-14T05:37:06.393173Z","iopub.status.idle":"2022-12-14T05:37:06.4025Z","shell.execute_reply.started":"2022-12-14T05:37:06.393132Z","shell.execute_reply":"2022-12-14T05:37:06.401439Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Reproducibility","metadata":{}},{"cell_type":"code","source":"def seeding(SEED):\n    np.random.seed(SEED)\n    random.seed(SEED)\n    os.environ['PYTHONHASHSEED'] = str(SEED)\n#     os.environ['TF_CUDNN_DETERMINISTIC'] = str(SEED)\n    tf.random.set_seed(SEED)\n    print('seeding done!!!')\nseeding(CFG.seed)","metadata":{"execution":{"iopub.status.busy":"2022-12-14T05:37:06.404103Z","iopub.execute_input":"2022-12-14T05:37:06.40453Z","iopub.status.idle":"2022-12-14T05:37:06.41728Z","shell.execute_reply.started":"2022-12-14T05:37:06.404496Z","shell.execute_reply":"2022-12-14T05:37:06.416223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Device Configs\nThis notebook is compatible for **remote-tpu**, **local-tpu**, **multi-gpu** and **single-gpu**. Simple change to `device=\"TPU\"` for **remote-tpu** and `device=\"TPU-1VM\"` for **local-tpu** and finally, `device=\"GPU\"` for single or multi-gpu.","metadata":{}},{"cell_type":"code","source":"if \"TPU\" in CFG.device:\n    tpu = 'local' if CFG.device=='TPU-1VM' else None\n    print(\"connecting to TPU...\")\n    try:\n        tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect(tpu=tpu)\n        strategy = tf.distribute.TPUStrategy(tpu)\n    except:\n        CFG.device = \"GPU\"\n        \nif CFG.device == \"GPU\"  or CFG.device==\"CPU\":\n    ngpu = len(tf.config.experimental.list_physical_devices('GPU'))\n    if ngpu>1:\n        print(\"Using multi GPU\")\n        strategy = tf.distribute.MirroredStrategy()\n    elif ngpu==1:\n        print(\"Using single GPU\")\n        strategy = tf.distribute.get_strategy()\n    else:\n        print(\"Using CPU\")\n        strategy = tf.distribute.get_strategy()\n        CFG.device = \"CPU\"\n\nif CFG.device == \"GPU\":\n    print(\"Num GPUs Available: \", ngpu)\n    \n\nAUTO     = tf.data.experimental.AUTOTUNE\nREPLICAS = strategy.num_replicas_in_sync\nprint(f'REPLICAS: {REPLICAS}')","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-12-14T05:37:06.418851Z","iopub.execute_input":"2022-12-14T05:37:06.419258Z","iopub.status.idle":"2022-12-14T05:37:06.63714Z","shell.execute_reply.started":"2022-12-14T05:37:06.419224Z","shell.execute_reply":"2022-12-14T05:37:06.636093Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Meta Data","metadata":{}},{"cell_type":"code","source":"BASE_PATH = '/kaggle/input/rsna-breast-cancer-detection'\nIMG_DIR = '/tmp/dataset/rsna-bcd'","metadata":{"execution":{"iopub.status.busy":"2022-12-14T05:37:06.640252Z","iopub.execute_input":"2022-12-14T05:37:06.640555Z","iopub.status.idle":"2022-12-14T05:37:06.646615Z","shell.execute_reply.started":"2022-12-14T05:37:06.640527Z","shell.execute_reply":"2022-12-14T05:37:06.645787Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train\ndf = pd.read_csv(f'{BASE_PATH}/train.csv')\ndf['dicom_path'] = f'{BASE_PATH}/train_images'\\\n                    + '/' + df.patient_id.astype(str)\\\n                    + '/' + df.image_id.astype(str)\\\n                    + '.dcm'\ndf['image_path'] = df.dicom_path.str.replace('.dcm','.png').str.replace(BASE_PATH, IMG_DIR)\nprint('Train:')\ndisplay(df.head(2))\n\n# test\ntest_df = pd.read_csv(f'{BASE_PATH}/test.csv')\ntest_df['dicom_path'] = f'{BASE_PATH}/test_images'\\\n                    + '/' + test_df.patient_id.astype(str)\\\n                    + '/' + test_df.image_id.astype(str)\\\n                    + '.dcm'\ntest_df['image_path'] = test_df.dicom_path.str.replace('.dcm','.png').str.replace(BASE_PATH, IMG_DIR)\nprint('\\nTest:')\ndisplay(test_df.head(2))","metadata":{"execution":{"iopub.status.busy":"2022-12-14T05:37:06.648273Z","iopub.execute_input":"2022-12-14T05:37:06.649083Z","iopub.status.idle":"2022-12-14T05:37:07.008556Z","shell.execute_reply.started":"2022-12-14T05:37:06.649049Z","shell.execute_reply":"2022-12-14T05:37:07.007482Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Check If Data Exist?","metadata":{}},{"cell_type":"code","source":"tf.io.gfile.exists(df.dicom_path.iloc[0]), tf.io.gfile.exists(test_df.dicom_path.iloc[0])","metadata":{"execution":{"iopub.status.busy":"2022-12-14T05:37:07.01032Z","iopub.execute_input":"2022-12-14T05:37:07.013337Z","iopub.status.idle":"2022-12-14T05:37:07.044151Z","shell.execute_reply.started":"2022-12-14T05:37:07.013298Z","shell.execute_reply":"2022-12-14T05:37:07.041909Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Train-Test Ditribution","metadata":{}},{"cell_type":"code","source":"print('train_files:',df.shape[0])\nprint('test_files:',test_df.shape[0])","metadata":{"execution":{"iopub.status.busy":"2022-12-14T05:37:07.050855Z","iopub.execute_input":"2022-12-14T05:37:07.053092Z","iopub.status.idle":"2022-12-14T05:37:07.063854Z","shell.execute_reply.started":"2022-12-14T05:37:07.053056Z","shell.execute_reply":"2022-12-14T05:37:07.06247Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# DICOM to PNG","metadata":{}},{"cell_type":"markdown","source":"## Create Directory","metadata":{}},{"cell_type":"code","source":"!rm -r {IMG_DIR}\nos.makedirs(F'{IMG_DIR}/train_images', exist_ok = True)\nos.makedirs(F'{IMG_DIR}/test_images', exist_ok = True)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-12-14T05:37:07.067883Z","iopub.execute_input":"2022-12-14T05:37:07.06822Z","iopub.status.idle":"2022-12-14T05:37:08.151368Z","shell.execute_reply.started":"2022-12-14T05:37:07.068189Z","shell.execute_reply":"2022-12-14T05:37:08.150067Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Dicom Utils","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport dicomsdl\n\n\ndef read_xray(path, fix_monochrome = True):\n    dicom = dicomsdl.open(path)\n    data = dicom.pixelData(storedvalue=False)  # 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\n\ndef resize_and_save(file_path):\n    img = read_xray(file_path)\n    h, w = img.shape[:2]  # orig hw\n    img = cv2.resize(img, (CFG.resize_dim, CFG.resize_dim), cv2.INTER_LINEAR)\n    img = (img * 65536).astype(np.uint16)\n    \n    sub_path = file_path.split(\"/\",4)[-1].split('.dcm')[0] + '.png'\n    infos = sub_path.split('/')\n    pid = infos[-2]\n    iid = infos[-1]; iid = iid.replace('.png','')\n    new_path = os.path.join(IMG_DIR, sub_path)\n    os.makedirs(new_path.rsplit('/',1)[0], exist_ok=True)\n    cv2.imwrite(new_path, img)\n    return pid,iid,w,h","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-12-14T05:37:08.15354Z","iopub.execute_input":"2022-12-14T05:37:08.15394Z","iopub.status.idle":"2022-12-14T05:37:08.170565Z","shell.execute_reply.started":"2022-12-14T05:37:08.1539Z","shell.execute_reply":"2022-12-14T05:37:08.169458Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Conversion","metadata":{}},{"cell_type":"code","source":"%%time\nfrom joblib import Parallel, delayed\nfile_paths = test_df.dicom_path.tolist()\nimgsize = Parallel(n_jobs=2,backend='threading')(delayed(resize_and_save)(file_path)\\\n                                                  for file_path in tqdm(file_paths, leave=True, position=0))","metadata":{"execution":{"iopub.status.busy":"2022-12-14T05:37:08.172155Z","iopub.execute_input":"2022-12-14T05:37:08.172737Z","iopub.status.idle":"2022-12-14T05:37:10.882931Z","shell.execute_reply.started":"2022-12-14T05:37:08.172701Z","shell.execute_reply":"2022-12-14T05:37:10.881934Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data Pipeline\n* Reads the raw file and then decodes it to tf.Tensor\n* Resizes the image in desired size\n* Chages the datatype to **float32**\n* Caches the Data for boosting up the speed.\n* Uses Augmentations to reduce overfitting and make model more robust.\n* Finally, splits the data into batches.\n","metadata":{}},{"cell_type":"code","source":"def build_decoder(with_labels=True, target_size=CFG.img_size, ext='png'):\n    def decode(path):\n        file_bytes = tf.io.read_file(path)\n        if ext == 'png':\n            img = tf.image.decode_png(file_bytes, channels=3, dtype=tf.uint16)\n        elif ext in ['jpg', 'jpeg']:\n            img = tf.image.decode_jpeg(file_bytes, channels=3)\n        else:\n            raise ValueError(\"Image extension not supported\")\n\n#         img = tf.image.resize(img, target_size)\n        img = tf.cast(img, tf.float32) / 65536.0\n        img = tf.reshape(img, [*target_size, 3])\n\n        return img\n    \n    def decode_with_labels(path, label):\n        return decode(path), tf.cast(label, tf.float32)\n    \n    return decode_with_labels if with_labels else decode\n\n\ndef build_augmenter(with_labels=True, dim=CFG.img_size):\n    def augment(img, dim=dim):\n        img = tf.image.random_flip_left_right(img) if CFG.hflip else img\n        img = tf.image.random_flip_up_down(img) if CFG.vflip else img\n        if CFG.pixel_aug:\n            img = tf.image.random_hue(img, CFG.hue)\n            img = tf.image.random_saturation(img, CFG.sat[0], CFG.sat[1])\n            img = tf.image.random_contrast(img, CFG.cont[0], CFG.cont[1])\n            img = tf.image.random_brightness(img, CFG.bri)\n        img = tf.clip_by_value(img, 0, 1)  if CFG.clip else img         \n        img = tf.reshape(img, [*dim, 3])\n        return img\n    \n    def augment_with_labels(img, label):    \n        return augment(img), label\n    \n    return augment_with_labels if with_labels else augment\n\n\ndef build_dataset(paths, labels=None, batch_size=32, cache=True,\n                  decode_fn=None, augment_fn=None,\n                  augment=True, repeat=True, shuffle=1024, \n                  cache_dir=\"\", drop_remainder=False):\n    if cache_dir != \"\" and cache is True:\n        os.makedirs(cache_dir, exist_ok=True)\n    \n    if decode_fn is None:\n        decode_fn = build_decoder(labels is not None)\n    \n    if augment_fn is None:\n        augment_fn = build_augmenter(labels is not None)\n    \n    AUTO = tf.data.experimental.AUTOTUNE\n    slices = paths if labels is None else (paths, labels)\n    \n    ds = tf.data.Dataset.from_tensor_slices(slices)\n    ds = ds.map(decode_fn, num_parallel_calls=AUTO)\n    ds = ds.cache(cache_dir) if cache else ds\n    ds = ds.repeat() if repeat else ds\n    if shuffle: \n        ds = ds.shuffle(shuffle, seed=CFG.seed)\n        opt = tf.data.Options()\n        opt.experimental_deterministic = False\n        ds = ds.with_options(opt)\n    ds = ds.map(augment_fn, num_parallel_calls=AUTO) if augment else ds\n    ds = ds.batch(batch_size, drop_remainder=drop_remainder)\n    ds = ds.prefetch(AUTO)\n    return ds","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-12-14T05:37:10.884582Z","iopub.execute_input":"2022-12-14T05:37:10.885034Z","iopub.status.idle":"2022-12-14T05:37:10.902314Z","shell.execute_reply.started":"2022-12-14T05:37:10.884968Z","shell.execute_reply":"2022-12-14T05:37:10.901426Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Visualization\n* Check if augmentation is working properly or not.","metadata":{}},{"cell_type":"code","source":"def display_batch(batch, size=2):\n    imgs = batch\n    plt.figure(figsize=(size*10, 10))\n    for img_idx in range(size):\n        plt.subplot(1, size, img_idx+1)\n        plt.imshow(imgs[img_idx,:, :, :])\n        plt.xticks([])\n        plt.yticks([])\n    plt.tight_layout()\n    plt.show() ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-12-14T05:37:10.904142Z","iopub.execute_input":"2022-12-14T05:37:10.904546Z","iopub.status.idle":"2022-12-14T05:37:10.913534Z","shell.execute_reply.started":"2022-12-14T05:37:10.904511Z","shell.execute_reply":"2022-12-14T05:37:10.912623Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fold = 0\nfold_df = test_df.copy()\npaths  = fold_df.image_path.tolist()[:100]\nlabels = None\nds = build_dataset(paths, labels, cache=False, batch_size=32,\n                   repeat=True, shuffle=True, augment=True)\nds = ds.unbatch().batch(20)\nbatch = next(iter(ds))\ndisplay_batch(batch, 5);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-12-14T05:37:10.915112Z","iopub.execute_input":"2022-12-14T05:37:10.915507Z","iopub.status.idle":"2022-12-14T05:37:18.510839Z","shell.execute_reply.started":"2022-12-14T05:37:10.915466Z","shell.execute_reply":"2022-12-14T05:37:18.509915Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model Configs","metadata":{}},{"cell_type":"code","source":"CKPT_DIRS = [\n    ([1024, 1024], '/kaggle/input/rsnabcd-noroi-kerascv-tftrain-ds'),\n]\n\nMODEL_CONFIGS = []\nfor img_size, ckpt_dir in  CKPT_DIRS:\n    paths = sorted(glob(os.path.join(ckpt_dir, '*h5')))[0:2]\n    if len(paths)==0:\n        print('no model found for :',base_dir)\n    MODEL_CONFIGS.append([img_size, paths])\ndisplay(MODEL_CONFIGS)","metadata":{"execution":{"iopub.status.busy":"2022-12-14T05:37:18.511881Z","iopub.execute_input":"2022-12-14T05:37:18.512207Z","iopub.status.idle":"2022-12-14T05:37:18.526432Z","shell.execute_reply.started":"2022-12-14T05:37:18.512178Z","shell.execute_reply":"2022-12-14T05:37:18.525281Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference","metadata":{}},{"cell_type":"code","source":"print('='*35)\nprint('### Predicting')\nprint('='*35)\npreds=[]\nfor img_size, model_paths in tqdm(MODEL_CONFIGS):\n    dim = np.prod(img_size)**0.5\n    test_paths = test_df.image_path.tolist()\n    if len(test_paths)<=4:\n        CFG.batch_size = 1\n    elif dim>=1024:\n        CFG.batch_size = REPLICAS * 8\n    elif dim>=768:\n        CFG.batch_size = REPLICAS * 24\n    elif dim>=640:\n        CFG.batch_size = REPLICAS * 32\n    else:\n        CFG.batch_size = REPLICAS * 64\n    dtest = build_dataset(\n        test_paths, \n        batch_size=CFG.batch_size, repeat=True, \n        shuffle=False, augment=CFG.tta>1, cache=False,\n        decode_fn=build_decoder(with_labels=False, target_size=img_size),\n        augment_fn=build_augmenter(with_labels=False, dim=img_size)\n    )\n    for model_path in model_paths:\n        print(f'Model: {model_path}')\n        with strategy.scope():\n            print('Loading Model...')\n            model = tf.keras.models.load_model(model_path, compile=False)\n        print('Predicting...');\n        pred = model.predict(dtest, steps = CFG.tta*len(test_paths)/CFG.batch_size, verbose=1)\n        pred = pred[:CFG.tta*len(test_paths),:]\n        pred = np.mean(pred.reshape(CFG.tta, len(test_paths), -1), axis=0)\n        preds.append(pred)\n        print()\npreds = np.mean(preds, axis=0)","metadata":{"execution":{"iopub.status.busy":"2022-12-14T05:37:18.527864Z","iopub.execute_input":"2022-12-14T05:37:18.528243Z","iopub.status.idle":"2022-12-14T05:37:39.434006Z","shell.execute_reply.started":"2022-12-14T05:37:18.528207Z","shell.execute_reply":"2022-12-14T05:37:39.432892Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"pred_df = pd.DataFrame({'prediction_id':test_df.prediction_id,\n                        'cancer':preds.reshape(-1)})\nsub_df = pd.read_csv(f'{BASE_PATH}/sample_submission.csv')\ndel sub_df['cancer']\nsub_df = sub_df.merge(pred_df, on='prediction_id', how='left')\nsub_df = sub_df.groupby('prediction_id')['cancer'].max().reset_index()  # merge duplicate prediction_id\nsub_df['cancer'] = (sub_df.cancer>CFG.thr).astype('float32') # thresholding\nsub_df.to_csv('submission.csv',index=False)\nsub_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-12-14T05:37:39.435864Z","iopub.execute_input":"2022-12-14T05:37:39.436707Z","iopub.status.idle":"2022-12-14T05:37:39.48249Z","shell.execute_reply.started":"2022-12-14T05:37:39.436663Z","shell.execute_reply":"2022-12-14T05:37:39.481436Z"},"trusted":true},"execution_count":null,"outputs":[]}]}