{"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":"!conda install '/kaggle/input/pydicom-conda-helper/libjpeg-turbo-2.1.0-h7f98852_0.tar.bz2' -c conda-forge -y\n!conda install '/kaggle/input/pydicom-conda-helper/libgcc-ng-9.3.0-h2828fa1_19.tar.bz2' -c conda-forge -y\n!conda install '/kaggle/input/pydicom-conda-helper/gdcm-2.8.9-py37h500ead1_1.tar.bz2' -c conda-forge -y\n!conda install '/kaggle/input/pydicom-conda-helper/conda-4.10.1-py37h89c1867_0.tar.bz2' -c conda-forge -y\n!conda install '/kaggle/input/pydicom-conda-helper/certifi-2020.12.5-py37h89c1867_1.tar.bz2' -c conda-forge -y\n!conda install '/kaggle/input/pydicom-conda-helper/openssl-1.1.1k-h7f98852_0.tar.bz2' -c conda-forge -y","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:09:32.561957Z","iopub.execute_input":"2021-08-01T14:09:32.562328Z","iopub.status.idle":"2021-08-01T14:10:41.113055Z","shell.execute_reply.started":"2021-08-01T14:09:32.562252Z","shell.execute_reply":"2021-08-01T14:10:41.112123Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sys; \n\npackage_paths = [\n    '../input/timm-pytorch-image-models/pytorch-image-models-master',\n]\n\nfor pth in package_paths:\n    sys.path.append(pth)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-08-01T14:10:41.114663Z","iopub.execute_input":"2021-08-01T14:10:41.114986Z","iopub.status.idle":"2021-08-01T14:10:41.123295Z","shell.execute_reply.started":"2021-08-01T14:10:41.114950Z","shell.execute_reply":"2021-08-01T14:10:41.122583Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import glob \nimport gc\nimport os\nimport time\nimport random\n\nimport numpy as np  # linear algebra!\nimport pandas as pd  # data processing, CSV file I/O (e.g. pd.read_csv)\nimport PIL\n\nfrom sklearn.model_selection import GroupKFold, StratifiedKFold\nfrom sklearn.metrics import confusion_matrix\nfrom sklearn.metrics import classification_report\nfrom sklearn.metrics import roc_auc_score\n\nimport cv2\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nfrom tqdm import tqdm\nfrom tqdm.contrib.concurrent import process_map\n\nimport torch\nimport torchvision\nfrom torch.utils.data.dataset import Dataset\nimport torch.cuda.amp as amp\n\nimport timm\n\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nfrom collections import namedtuple\n\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nSIZE = (384, 384)\n\nMODEL_DIRS = (\"../input/vit-study-training-384x384px\", \"../input/vit-study-training-384x384px-wrs\")\nDATA_DIR = RESIZE_DIR = \"/kaggle/working/\"\nFOLDS = 5\nNUM_CLASSES = 4\nBATCHSIZE = 64\nSEED = 420\nMODEL_NAMES = \"vit_small_r26_s32_384\"","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:10:41.126499Z","iopub.execute_input":"2021-08-01T14:10:41.126798Z","iopub.status.idle":"2021-08-01T14:10:45.551049Z","shell.execute_reply.started":"2021-08-01T14:10:41.126772Z","shell.execute_reply":"2021-08-01T14:10:45.550205Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_df = pd.read_csv('/kaggle/input/siim-covid19-detection/sample_submission.csv')\nprint(len(sub_df))\nsub_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:10:45.552583Z","iopub.execute_input":"2021-08-01T14:10:45.552959Z","iopub.status.idle":"2021-08-01T14:10:45.599032Z","shell.execute_reply.started":"2021-08-01T14:10:45.552919Z","shell.execute_reply":"2021-08-01T14:10:45.597653Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"study_df = sub_df.loc[sub_df.id.str.contains('_study')]\nlen(study_df)","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:10:45.600281Z","iopub.execute_input":"2021-08-01T14:10:45.600638Z","iopub.status.idle":"2021-08-01T14:10:45.679641Z","shell.execute_reply.started":"2021-08-01T14:10:45.600602Z","shell.execute_reply":"2021-08-01T14:10:45.678555Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_df = sub_df.loc[sub_df.id.str.contains('_image')]\nlen(image_df)","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:10:45.680849Z","iopub.execute_input":"2021-08-01T14:10:45.681212Z","iopub.status.idle":"2021-08-01T14:10:45.694236Z","shell.execute_reply.started":"2021-08-01T14:10:45.681158Z","shell.execute_reply":"2021-08-01T14:10:45.691237Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def read_xray(path, voi_lut = True, fix_monochrome = True):\n    # Original from: https://www.kaggle.com/raddar/convert-dicom-to-np-array-the-correct-way\n    dicom = pydicom.read_file(path)\n    \n    # VOI LUT (if available by DICOM device) is used to transform raw DICOM data to \n    # \"human-friendly\" view\n    if voi_lut:\n        data = apply_voi_lut(dicom.pixel_array, dicom)\n    else:\n        data = dicom.pixel_array\n               \n    # depending on this value, X-ray may look inverted - fix that:\n    if fix_monochrome and dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        data = np.amax(data) - data\n        \n    data = data - np.min(data)\n    data = data / np.max(data)\n    data = (data * 255).astype(np.uint8)\n        \n    return data\n\ndef resize_xray(array, size, keep_ratio=False, resample=Image.LANCZOS):\n    # Original from: https://www.kaggle.com/xhlulu/vinbigdata-process-and-resize-to-image\n    im = Image.fromarray(array)\n    \n    if keep_ratio:\n        im.thumbnail((size, size), resample)\n    else:\n        im = im.resize((size, size), resample)\n    \n    return im","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:10:56.185100Z","iopub.execute_input":"2021-08-01T14:10:56.185524Z","iopub.status.idle":"2021-08-01T14:10:56.195450Z","shell.execute_reply.started":"2021-08-01T14:10:56.185471Z","shell.execute_reply":"2021-08-01T14:10:56.193741Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ImageMeta = namedtuple(\"ImageMeta\", (\"dim0\", \"dim1\", \"image_id\"))","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:18:17.014172Z","iopub.execute_input":"2021-08-01T14:18:17.014499Z","iopub.status.idle":"2021-08-01T14:18:17.019258Z","shell.execute_reply.started":"2021-08-01T14:18:17.014467Z","shell.execute_reply":"2021-08-01T14:18:17.018465Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nSAVE_DIR = TEST_PATH = f'/kaggle/working/test_{SIZE[0]}x{SIZE[1]}'\nfor split in [\"test\"]:\n    filenames = glob.glob(\"/kaggle/input/siim-covid19-detection/{}/*/*/*.dcm\".format(split))\n#     SAVE_DIR = f\"/kaggle/tmp/{split}\"\n    os.makedirs(SAVE_DIR, exist_ok=True)\n    def persist_image(path):\n        xray = read_xray(path)\n        height = xray.shape[0]\n        width = xray.shape[1]\n        im = resize_xray(xray, size=SIZE[0])\n        fname = os.path.basename(os.path.splitext(path)[-2])\n        jpg_fname = os.path.join(SAVE_DIR, \"{}.jpg\".format(fname))\n        im.save(jpg_fname)\n        return ImageMeta(height, width, fname)\n    split_imgs = process_map(persist_image, filenames, max_workers=8, chunksize=1)\n    test_imgs_study_mapping= pd.DataFrame.from_records(split_imgs, columns=ImageMeta._fields)\n    test_imgs_study_mapping.to_csv(\"/kaggle/working/{}_meta.csv\".format(split), index=False)\n    print(\"No. of Images in split {}: {}\".format(split, len(split_imgs)))","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:18:17.353375Z","iopub.execute_input":"2021-08-01T14:18:17.353743Z","iopub.status.idle":"2021-08-01T14:22:04.480687Z","shell.execute_reply.started":"2021-08-01T14:18:17.353711Z","shell.execute_reply":"2021-08-01T14:22:04.479615Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Associate image-level id with study-level ids.\n# Note that a study-level might have more than one image-level ids.\nfor study_dir in os.listdir('../input/siim-covid19-detection/test'):\n    for series in os.listdir(f'../input/siim-covid19-detection/test/{study_dir}'):\n        for image in os.listdir(f'../input/siim-covid19-detection/test/{study_dir}/{series}/'):\n            image_id = image[:-4]\n            test_imgs_study_mapping.loc[test_imgs_study_mapping['image_id'] == image_id, 'study_id'] = study_dir\n        \ntest_imgs_study_mapping.head()","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:22:11.092641Z","iopub.execute_input":"2021-08-01T14:22:11.093030Z","iopub.status.idle":"2021-08-01T14:22:13.105494Z","shell.execute_reply.started":"2021-08-01T14:22:11.092977Z","shell.execute_reply":"2021-08-01T14:22:13.104718Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !mkdir \"/kaggle/working/test_{SIZE[0]}x{SIZE[1]}\"\n# !tar -xzf \"/kaggle/input/train-{SIZE[0]}x{SIZE[1]}/test_{SIZE[0]}x{SIZE[1]}.tar.gz\" -C \"/kaggle/working/test_{SIZE[0]}x{SIZE[1]}\" .","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:22:33.464880Z","iopub.execute_input":"2021-08-01T14:22:33.465208Z","iopub.status.idle":"2021-08-01T14:22:33.469780Z","shell.execute_reply.started":"2021-08-01T14:22:33.465179Z","shell.execute_reply":"2021-08-01T14:22:33.467707Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Make results reproducible\ndef seed_everything(seed):\n    random.seed(seed)\n    os.environ[\"PYTHONHASHSEED\"] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.benchmark = False\n    torch.backends.cudnn.deterministic = True\n\n\nseed_everything(SEED)","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:22:33.879927Z","iopub.execute_input":"2021-08-01T14:22:33.880281Z","iopub.status.idle":"2021-08-01T14:22:33.913019Z","shell.execute_reply.started":"2021-08-01T14:22:33.880250Z","shell.execute_reply":"2021-08-01T14:22:33.912030Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"modelnames = []\nfor MODEL_DIR in MODEL_DIRS:\n    print(MODEL_DIR)\n    for MODEL_NAME in MODEL_NAMES:\n        modelnames.extend(glob.glob(os.path.join(MODEL_DIR, f\"{MODEL_NAME}*\", \"*.pth\")))\nprint(f\"{len(modelnames)}: Models Found\")","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:22:55.291057Z","iopub.execute_input":"2021-08-01T14:22:55.291422Z","iopub.status.idle":"2021-08-01T14:22:55.571605Z","shell.execute_reply.started":"2021-08-01T14:22:55.291376Z","shell.execute_reply":"2021-08-01T14:22:55.570656Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# test_imgs_study_mapping = pd.read_csv(\"/kaggle/input/test-image-to-study-mapping/test_study_id_to_image_mapping.csv\")","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:22:57.162150Z","iopub.execute_input":"2021-08-01T14:22:57.162473Z","iopub.status.idle":"2021-08-01T14:22:57.168839Z","shell.execute_reply.started":"2021-08-01T14:22:57.162441Z","shell.execute_reply":"2021-08-01T14:22:57.167938Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# TEST_DATA_PATH = os.path.join(RESIZE_DIR, f\"test_{SIZE[0]}x{SIZE[1]}\")\nprint(\"Test Data Path {}\".format(TEST_PATH))\ndef get_img_path(row):\n    study_id = row[\"study_id\"]\n    img_id = row[\"image_id\"]\n    paths = glob.glob(os.path.join(TEST_PATH, \"{}*.jpg\".format(img_id)))\n    for path in paths:\n        if img_id in path:\n            return path\n    return None","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:22:57.586828Z","iopub.execute_input":"2021-08-01T14:22:57.587153Z","iopub.status.idle":"2021-08-01T14:22:57.592804Z","shell.execute_reply.started":"2021-08-01T14:22:57.587122Z","shell.execute_reply":"2021-08-01T14:22:57.591941Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_imgs_study_mapping[\"path\"] = test_imgs_study_mapping.apply(get_img_path, axis=1)","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:22:58.636754Z","iopub.execute_input":"2021-08-01T14:22:58.637066Z","iopub.status.idle":"2021-08-01T14:23:01.275576Z","shell.execute_reply.started":"2021-08-01T14:22:58.637038Z","shell.execute_reply":"2021-08-01T14:23:01.274699Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_imgs_study_mapping[test_imgs_study_mapping[\"path\"].isna()]","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:23:01.276955Z","iopub.execute_input":"2021-08-01T14:23:01.277283Z","iopub.status.idle":"2021-08-01T14:23:01.294241Z","shell.execute_reply.started":"2021-08-01T14:23:01.277248Z","shell.execute_reply":"2021-08-01T14:23:01.293435Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_model(modelname):\n    summary = torch.load(modelname)\n    print(f\"Loaded model {modelname}\")\n    print(f\"Epoch {summary['epoch']}\")\n    print(f\"Map@2 {summary['map_at_2']}\")\n    print(f\"AUC@2 {summary['auc']}\")\n    model = timm.create_model(model_name=modelname.split(\"/\")[-2][:-2], pretrained=False, in_chans=3)\n    if type(model) == timm.models.vision_transformer.VisionTransformer:\n        model.head = torch.nn.Linear(in_features=model.head.in_features, out_features=NUM_CLASSES)\n    else:\n        model.classifier = torch.nn.Linear(\n            in_features=model.classifier.in_features, out_features=NUM_CLASSES\n        )\n    model.load_state_dict(summary[\"state_dict\"], strict=True)\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:23:01.296008Z","iopub.execute_input":"2021-08-01T14:23:01.296583Z","iopub.status.idle":"2021-08-01T14:23:01.304377Z","shell.execute_reply.started":"2021-08-01T14:23:01.296545Z","shell.execute_reply":"2021-08-01T14:23:01.303554Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class XRayDatasetFromDF(Dataset):\n    def __init__(self, df, train=True, augment=True, normalize=False, size=(384, 384)):\n        self.df = df\n        self.name_to_label_map = {\n            \"Negative\": 0,\n            \"Typical\": 1,\n            \"Indeterminate\": 2,\n            \"Atypical\": 3,\n        }\n        self.study_ids = df.index.sort_values()\n        self.path_suffix = (\n            os.path.join(DATA_DIR, \"train\") if train else os.path.join(DATA_DIR, \"test\")\n        )\n        self._train = train\n        self._augment = augment\n        self._normalize = normalize\n        self._size = size\n        self._transform_list = [\n            # A.Resize(size[0], size[1], p=1)\n        ]\n\n        if self._augment:\n            self._transform_list.extend(\n                [\n                    A.VerticalFlip(p=0.5),\n                    A.HorizontalFlip(p=0.5),\n                    A.ShiftScaleRotate(\n                        scale_limit=0.20,\n                        rotate_limit=10,\n                        shift_limit=0.1,\n                        p=0.5,\n                        border_mode=cv2.BORDER_CONSTANT,\n                        value=0,\n                    ),\n                    A.RandomBrightnessContrast(p=0.5),\n                    A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),\n                    ToTensorV2(),\n                ]\n            )\n        elif self._normalize and not self._augment:  # test mode\n            self._transform_list.extend(\n                [\n                    A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),\n                    ToTensorV2(),\n                ]\n            )\n        self._transforms = A.Compose(self._transform_list)\n\n    def __len__(self):\n        return len(self.study_ids)\n\n    def assign_label(self, row):\n        for k in self.name_to_label_map:\n            if row[k]:\n                return self.name_to_label_map[k]\n\n    def __getitem__(self, idx):\n        study_id = self.study_ids[idx]\n        study_imgs = self.df.loc[study_id]\n        path = None\n        label = None\n\n        path = study_imgs[\"path\"]\n        label = study_imgs[\"int_label\"] if self._train else -1\n\n        # ideally, we'd clean up the df,\n        # but may be we use it to produce predictions as well.\n        dicom_arr = (\n            cv2.imread(path)\n            if path.endswith(\".jpg\")\n            else dicom2array(path, size=self._size)\n        )\n        img = cv2.cvtColor(dicom_arr, cv2.COLOR_BGR2RGB)\n        img = self._transforms(image=img)[\"image\"]\n\n        return img, label","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:23:01.306292Z","iopub.execute_input":"2021-08-01T14:23:01.306580Z","iopub.status.idle":"2021-08-01T14:23:01.322693Z","shell.execute_reply.started":"2021-08-01T14:23:01.306555Z","shell.execute_reply":"2021-08-01T14:23:01.321877Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_ds = XRayDatasetFromDF(df=test_imgs_study_mapping, train=False, augment=True, normalize=False, size=SIZE)\ntest_dl = torch.utils.data.DataLoader(\n        dataset=test_ds,\n        batch_size=BATCHSIZE * 2,\n        pin_memory=True,\n        num_workers=8,\n        drop_last=False,\n        shuffle=False,\n        prefetch_factor=8,\n    )","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:23:01.849457Z","iopub.execute_input":"2021-08-01T14:23:01.849845Z","iopub.status.idle":"2021-08-01T14:23:01.857099Z","shell.execute_reply.started":"2021-08-01T14:23:01.849813Z","shell.execute_reply":"2021-08-01T14:23:01.856049Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def predict(model, slide_dl, tta_times=5):\n    sample_size = len(slide_dl.dataset)\n    print(\"Predicting on {} Images {} times\".format(sample_size, tta_times))\n    probs = np.zeros((sample_size, NUM_CLASSES))\n    loss_sum = 0\n\n    loss_fn = torch.nn.BCEWithLogitsLoss(reduction=\"none\").to(dev)\n\n    for i in range(tta_times):\n\n        offset = 0\n\n        for i, grid in enumerate(tqdm(slide_dl)):\n            with torch.no_grad():\n                img, _ = grid\n                curr_batch_size = img.shape[0]\n\n                pred = model(img.to(dev))\n                # remove the redundant dimension added by\n                # pytorch's collate_fn\n\n                prob = pred.sigmoid()\n                probs[offset : offset + curr_batch_size, :] += prob.cpu().numpy()\n                offset += curr_batch_size\n\n\n    return probs / tta_times","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:23:03.153131Z","iopub.execute_input":"2021-08-01T14:23:03.153449Z","iopub.status.idle":"2021-08-01T14:23:03.160147Z","shell.execute_reply.started":"2021-08-01T14:23:03.153419Z","shell.execute_reply":"2021-08-01T14:23:03.159329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dev = torch.device(\"cuda\") if torch.cuda.is_available() else torch.device(\"cpu\")\nprint(dev)","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:23:04.360657Z","iopub.execute_input":"2021-08-01T14:23:04.360989Z","iopub.status.idle":"2021-08-01T14:23:04.477128Z","shell.execute_reply.started":"2021-08-01T14:23:04.360960Z","shell.execute_reply":"2021-08-01T14:23:04.476235Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions = []\nfor modelname in modelnames:\n    model = load_model(modelname)\n    model = model.to(dev)\n    model = model.eval()\n    probs = predict(model, test_dl)\n    # probs = torch.from_numpy(probs)\n    # probs = probs.softmax(dim=1)\n\n    for k in test_ds.name_to_label_map:\n        col_idx = test_ds.name_to_label_map[k]\n        test_imgs_study_mapping[k] = probs[:, col_idx]\n    test_imgs_study_mapping[\"modelname\"] = modelname\n    predictions.append(test_imgs_study_mapping.copy())\n    del model\n    torch.cuda.empty_cache()\n    gc.collect()","metadata":{"execution":{"iopub.status.busy":"2021-08-01T14:23:05.398287Z","iopub.execute_input":"2021-08-01T14:23:05.398639Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions_df = pd.concat(predictions)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mean_predictions_df = predictions_df.groupby(\"study_id\").agg({\n    \"Negative\":\"mean\",\n    \"Typical\":\"mean\",\n    \"Indeterminate\":\"mean\",\n    \"Atypical\":\"mean\"\n}).reset_index()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mean_predictions_df[\"id\"] = mean_predictions_df[\"study_id\"] + \"_study\"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mean_predictions_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"OPBB = \"0 0 1 1\"\ndef generate_cls_prediction_strings(row):\n    predictions = []\n\n    for k in test_ds.name_to_label_map:\n        \n        p_k = row[k]\n        predictions.append(k.lower())\n        predictions.append(str(p_k))\n        predictions.append(OPBB)\n    return \" \".join(predictions)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mean_predictions_df[\"PredictionString\"] = mean_predictions_df.apply(generate_cls_prediction_strings, axis=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cls_submission_df = mean_predictions_df[[\"id\", \"PredictionString\"]]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nprint(tf.__version__)\nimport torch\nprint(f\"Setup complete. Using torch {torch.__version__} ({torch.cuda.get_device_properties(0).name if torch.cuda.is_available() else 'CPU'})\")\n\nimport gc\nimport glob\nfrom tqdm import tqdm\nfrom shutil import copyfile","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"gpus = tf.config.list_physical_devices('GPU')\nif gpus:\n    try:\n    # Currently, memory growth needs to be the same across GPUs\n        for gpu in gpus:\n            tf.config.experimental.set_memory_growth(gpu, True)\n            logical_gpus = tf.config.experimental.list_logical_devices('GPU')\n            print(len(gpus), \"Physical GPUs,\", len(logical_gpus), \"Logical GPUs\")\n    except RuntimeError as e:\n    # Memory growth must be set before GPUs have been initialized\n        print(e)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_df = pd.read_csv('/kaggle/input/siim-covid19-detection/sample_submission.csv')\nprint(len(sub_df))\nsub_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"study_df = sub_df.loc[sub_df.id.str.contains('_study')]\nlen(study_df)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_df = sub_df.loc[sub_df.id.str.contains('_image')]\nlen(image_df)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def read_xray(path, voi_lut = True, fix_monochrome = True):\n    # Original from: https://www.kaggle.com/raddar/convert-dicom-to-np-array-the-correct-way\n    dicom = pydicom.read_file(path)\n    \n    # VOI LUT (if available by DICOM device) is used to transform raw DICOM data to \n    # \"human-friendly\" view\n    if voi_lut:\n        data = apply_voi_lut(dicom.pixel_array, dicom)\n    else:\n        data = dicom.pixel_array\n               \n    # depending on this value, X-ray may look inverted - fix that:\n    if fix_monochrome and dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        data = np.amax(data) - data\n        \n    data = data - np.min(data)\n    data = data / np.max(data)\n    data = (data * 255).astype(np.uint8)\n        \n    return data\n\ndef resize_xray(array, size, keep_ratio=False, resample=Image.LANCZOS):\n    # Original from: https://www.kaggle.com/xhlulu/vinbigdata-process-and-resize-to-image\n    im = Image.fromarray(array)\n    \n    if keep_ratio:\n        im.thumbnail((size, size), resample)\n    else:\n        im = im.resize((size, size), resample)\n    \n    return im","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TEST_PATH = f'/kaggle/tmp/test/'\nIMG_SIZE = 512\n\ndef prepare_test_images():\n    image_id = []\n    dim0 = []\n    dim1 = []\n\n    os.makedirs(TEST_PATH, exist_ok=True)\n\n    for dirname, _, filenames in tqdm(os.walk(f'../input/siim-covid19-detection/test')):\n        for file in filenames:\n            # set keep_ratio=True to have original aspect ratio\n            xray = read_xray(os.path.join(dirname, file))\n            im = resize_xray(xray, size=IMG_SIZE)  \n            im.save(os.path.join(TEST_PATH, file.replace('dcm', 'png')))\n\n            image_id.append(file.replace('.dcm', ''))\n            dim0.append(xray.shape[0])\n            dim1.append(xray.shape[1])\n            \n    return image_id, dim0, dim1","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_ids, dim0, dim1 = prepare_test_images()\nprint(f'Number of test images: {len(os.listdir(TEST_PATH))}')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"meta_df = pd.DataFrame.from_dict({'image_id': image_ids, 'dim0': dim0, 'dim1': dim1})\n\n# Associate image-level id with study-level ids.\n# Note that a study-level might have more than one image-level ids.\nfor study_dir in os.listdir('../input/siim-covid19-detection/test'):\n    for series in os.listdir(f'../input/siim-covid19-detection/test/{study_dir}'):\n        for image in os.listdir(f'../input/siim-covid19-detection/test/{study_dir}/{series}/'):\n            image_id = image[:-4]\n            meta_df.loc[meta_df['image_id'] == image_id, 'study_id'] = study_dir\n        \nmeta_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%cp /kaggle/input/yolomodels-obj/yolov5L512_1607.pt /kaggle/working\n%cp /kaggle/input/yolomodels-obj/yolov5m6_512.pt /kaggle/working","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!python /kaggle/input/siimcovidyolov5l/yolov5/detect.py --weights /kaggle/working/yolov5L512_1607.pt /kaggle/working/yolov5m6_512.pt \\\n                                      --source {TEST_PATH} \\\n                                      --img 512 \\\n                                      --conf 0.22 \\\n                                      --iou-thres 0.5 \\\n                                      --max-det 10 \\\n                                      --save-txt \\\n                                      --save-conf \\\n                                      --augment","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"PRED_PATH = 'runs/detect/exp/labels'\nprediction_files = os.listdir(PRED_PATH)\nprint(f'Number of opacity predicted by YOLOv5: {len(prediction_files)}')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def correct_bbox_format(bboxes):\n    correct_bboxes = []\n    for b in bboxes:\n        xc, yc = int(np.round(b[0]*IMG_SIZE)), int(np.round(b[1]*IMG_SIZE))\n        w, h = int(np.round(b[2]*IMG_SIZE)), int(np.round(b[3]*IMG_SIZE))\n\n        xmin = xc - int(np.round(w/2))\n        ymin = yc - int(np.round(h/2))\n        xmax = xc + int(np.round(w/2))\n        ymax = yc + int(np.round(h/2))\n        \n        correct_bboxes.append([xmin, ymin, xmax, ymax])\n        \n    return correct_bboxes\n\ndef scale_bboxes_to_original(row, bboxes):\n    # Get scaling factor\n    scale_x = IMG_SIZE/row.dim1\n    scale_y = IMG_SIZE/row.dim0\n    \n    scaled_bboxes = []\n    for bbox in bboxes:\n        xmin, ymin, xmax, ymax = bbox\n        \n        xmin = int(np.round(xmin/scale_x))\n        ymin = int(np.round(ymin/scale_y))\n        xmax = int(np.round(xmax/scale_x))\n        ymax = int(np.round(ymax/scale_y))\n        \n        scaled_bboxes.append([xmin, ymin, xmax, ymax])\n        \n    return scaled_bboxes\n\n# Read the txt file generated by YOLOv5 during inference and extract \n# confidence and bounding box coordinates.\ndef get_conf_bboxes(file_path):\n    confidence = []\n    bboxes = []\n    with open(file_path, 'r') as file:\n        for line in file:\n            preds = line.strip('\\n').split(' ')\n            preds = list(map(float, preds))\n            confidence.append(preds[-1])\n            bboxes.append(preds[1:-1])\n    return confidence, bboxes","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_pred_strings = []\nctr = 0\nfor i in tqdm(range(len(image_df))):\n    row = meta_df.loc[i]\n    id_name = row.image_id\n    \n    if f'{id_name}.txt' in prediction_files:\n        # opacity label\n        confidence, bboxes = get_conf_bboxes(f'{PRED_PATH}/{id_name}.txt')\n        bboxes = correct_bbox_format(bboxes)\n        ori_bboxes = scale_bboxes_to_original(row, bboxes)\n        \n        pred_string = ''\n        for j, conf in enumerate(confidence):\n            pred_string += f'opacity {conf} ' + ' '.join(map(str, ori_bboxes[j])) + ' '\n        \n        row = mean_predictions_df.loc[mean_predictions_df['study_id'] == row.study_id]\n        neg = row.Negative.item()\n        typ = row.Typical.item()\n        ind = row.Indeterminate.item()\n        atp = row.Atypical.item()\n        output_class = np.argmax(np.array([neg,typ,ind,atp]))\n        if output_class == 0 and neg > 0.7:\n            ctr+=1\n            image_pred_strings.append(\"none 1 0 0 1 1\")\n        else:\n            image_pred_strings.append(pred_string[:-1])\n    else:\n        image_pred_strings.append(\"none 1 0 0 1 1\")\nprint('Number of images that were detected as opacity but are forced to none on the basis of classification output are :' + str(ctr))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"meta_df['PredictionString'] = image_pred_strings\nimage_df = meta_df[['study_id','image_id', 'PredictionString']]\n# image_df.insert(0, 'id', image_df.apply(lambda row: row.image_id+'_image', axis=1))\n# image_df = image_df.drop('image_id', axis=1)\nimage_df.head(20)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_df.insert(0, 'id', image_df.apply(lambda row: row.image_id+'_image', axis=1))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_df_new = image_df[['id','PredictionString']]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cls_submission_df = cls_submission_df.append(image_df_new).reset_index(drop=True)\ncls_submission_df.to_csv('/kaggle/working/submission.csv',index = False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%rm -rf runs\n%rm -rf test_384x384\n%rm yolov5L512_1607.pt\n%rm yolov5m6_512.pt","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}