{"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":"package_paths = ['../input/timm-module']\nimport sys;\nfor pth in package_paths:\n    sys.path.append(pth)\n\nimport os\nimport pandas as pd\nimport torch\nimport timm\nimport albumentations as A\nimport matplotlib.pyplot as plt\nimport wandb\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport glob\nimport cv2\n\nfrom tqdm import tqdm\nfrom torch.utils.data import Dataset, DataLoader\nfrom albumentations.pytorch import ToTensorV2\nfrom sklearn.metrics import multilabel_confusion_matrix\nfrom timm import *\nfrom fastai.vision.learner import _add_norm\nfrom fastai.vision.all import *\nfrom fastai.vision.learner import _update_first_layer\nfrom fastai.callback.wandb import *","metadata":{"execution":{"iopub.status.busy":"2021-07-27T10:38:10.555943Z","iopub.execute_input":"2021-07-27T10:38:10.556382Z","iopub.status.idle":"2021-07-27T10:38:17.481796Z","shell.execute_reply.started":"2021-07-27T10:38:10.556296Z","shell.execute_reply":"2021-07-27T10:38:17.480932Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!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/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-07-27T10:39:08.406651Z","iopub.execute_input":"2021-07-27T10:39:08.407065Z","iopub.status.idle":"2021-07-27T10:40:16.740696Z","shell.execute_reply.started":"2021-07-27T10:39:08.407018Z","shell.execute_reply":"2021-07-27T10:40:16.739746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\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\n    if device == 'cuda:0':\n        torch.cuda.manual_seed(seed)\n        torch.backends.cudnn.deterministic = True","metadata":{"execution":{"iopub.status.busy":"2021-07-27T10:40:20.699704Z","iopub.execute_input":"2021-07-27T10:40:20.700090Z","iopub.status.idle":"2021-07-27T10:40:20.709017Z","shell.execute_reply.started":"2021-07-27T10:40:20.700031Z","shell.execute_reply":"2021-07-27T10:40:20.707932Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Config:\n    seed_val = 111\n    seed_everything(seed_val)\n    fold_num = 0\n    job = 1\n    num_classes = 4\n    input_dims = 512\n    model_arch = 'tf_efficientnetv2_m_in21ft1k'\n    batch_size = 3\n    num_workers = 0\n    kfold = 5\n    loss_func = nn.BCEWithLogitsLoss()  # CrossEntropyLossFlat() or LabelSmoothingCrossEntropyFlat() for multi-class\n    metrics = [accuracy_multi, RocAucMulti(average='macro'), F1ScoreMulti(average='macro')]\n    job_name = f'{model_arch}_fold{fold_num}_job{job}'\n    print(\"Job Name:\", job_name)\n\n    wandb_project = 'SIIM_classifier_public'\n    wandb_run_name = job_name\n\n    if str(device) == 'cuda:0':\n        fp16 = True\n    else:\n        fp16 = False\n\n\ncfg = Config()\nconfig_dict = dict(vars(Config))\nconfig_dict = {k:(v if type(v)==int else str(v)) for (k,v) in config_dict.items() if '__' not in k}","metadata":{"execution":{"iopub.status.busy":"2021-07-27T10:40:22.273840Z","iopub.execute_input":"2021-07-27T10:40:22.274174Z","iopub.status.idle":"2021-07-27T10:40:22.283641Z","shell.execute_reply.started":"2021-07-27T10:40:22.274142Z","shell.execute_reply":"2021-07-27T10:40:22.282591Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_timm_body(arch:str, pretrained=True, cut=None, n_in=3):\n    \"Creates a body from any model in the `timm` library.\"\n    model = create_model(arch, pretrained=pretrained, num_classes=0, global_pool='')\n    _update_first_layer(model, n_in, pretrained)\n    if cut is None:\n        ll = list(enumerate(model.children()))\n        cut = next(i for i,o in reversed(ll) if has_pool_type(o))\n    if isinstance(cut, int): return nn.Sequential(*list(model.children())[:cut])\n    elif callable(cut): return cut(model)\n    else: raise NamedError(\"cut must be either integer or function\")\n\n\ndef create_timm_model(arch: str, n_out, cut=None, pretrained=True, n_in=3,\n                      init=nn.init.kaiming_normal_, custom_head=None,\n                      concat_pool=True, **kwargs):\n    \"Create custom architecture using `arch`, `n_in` and `n_out` from the `timm` library\"\n    body = create_timm_body(arch, pretrained, None, n_in)\n    if custom_head is None:\n        nf = num_features_model(nn.Sequential(*body.children()))\n        head = create_head(nf, n_out, concat_pool=concat_pool, **kwargs)\n    else:\n        head = custom_head\n    model = nn.Sequential(body, head)\n    if init is not None: apply_init(model[1], init)\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-07-27T10:40:24.415636Z","iopub.execute_input":"2021-07-27T10:40:24.415969Z","iopub.status.idle":"2021-07-27T10:40:24.425205Z","shell.execute_reply.started":"2021-07-27T10:40:24.415941Z","shell.execute_reply":"2021-07-27T10:40:24.424097Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class PlantDataset(Dataset):\n    def __init__(self, df, transform=None):\n        self.image_id = df['study_id'].values\n        self.transform = transform\n        self.path = df['image_path'].values\n\n    def __len__(self):\n        return len(self.image_id)\n\n    def __getitem__(self, idx):\n        image_id = self.image_id[idx]\n        image_name = image_id\n\n        image_path = self.path[idx]\n        image = cv2.imread(image_path)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n\n        augmented = self.transform(image=image)\n        image = augmented['image']\n        return image, image_name\n\n\ndef get_transform():\n        return A.Compose([A.Resize(cfg.input_dims, cfg.input_dims, p=1.0), ToTensorV2()], p=1.0)","metadata":{"execution":{"iopub.status.busy":"2021-07-27T10:40:28.478638Z","iopub.execute_input":"2021-07-27T10:40:28.479011Z","iopub.status.idle":"2021-07-27T10:40:28.487305Z","shell.execute_reply.started":"2021-07-27T10:40:28.478980Z","shell.execute_reply":"2021-07-27T10:40:28.486201Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class PlantPredictor():\n    def __init__(self, net, test_df, df_labels_idx, dataloaders, device):\n        self.net = net\n        self.df_labels_idx = df_labels_idx\n        self.dataloaders = dataloaders\n        self.df_submit = pd.DataFrame(columns = ['id', 'labels'])\n        self.device = device\n        self.net.to(self.device)\n    \n    \n    def inference(self):\n        self.net.eval()\n        labels_pre = []\n        image_name_all = []\n        for inputs, image_name in self.dataloaders:\n            # torch.cuda.empty_cache()\n            pre_list = []\n            image_name_all.append(image_name)\n            inputs = inputs.float()\n            inputs = inputs.to(self.device)\n\n            with torch.no_grad():\n                out = self.net(inputs)\n            out = out.cpu()\n            pre_list.append(out.detach().sigmoid().numpy() > 0.41)\n            pre_list = pd.DataFrame(np.concatenate(pre_list).astype(np.int), columns=labels)\n            multi_labels = pre_list.columns\n            for i, row in pre_list.iterrows():\n                if ((row['negative'] == 1) or row.sum() == 0):\n                    tmp = multi_labels[np.argmax(torch.nn.functional.softmax(out[i].reshape(1, len(out[i])), dim=1)).item()]\n                else:\n                    tmp = ' '.join(multi_labels[row==row.max()])\n                labels_pre.append(tmp + ' 1 0 0 1 1')\n        image_name_list = np.concatenate(image_name_all)\n        self.df_submit['id'] = image_name_list\n        self.df_submit['labels'] = labels_pre","metadata":{"execution":{"iopub.status.busy":"2021-07-27T10:40:30.886967Z","iopub.execute_input":"2021-07-27T10:40:30.887379Z","iopub.status.idle":"2021-07-27T10:40:30.897849Z","shell.execute_reply.started":"2021-07-27T10:40:30.887348Z","shell.execute_reply":"2021-07-27T10:40:30.897060Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_df = pd.read_csv('/kaggle/input/siim-covid19-detection/sample_submission.csv')\n\n# Form study and image dataframes\nsub_df['level'] = sub_df.id.map(lambda idx: idx[-5:])\nstudy_df = sub_df[sub_df.level=='study'].rename({'id':'study_id'}, axis=1)\nimage_df = sub_df[sub_df.level=='image'].rename({'id':'image_id'}, axis=1)\n\ndcm_path = glob.glob('/kaggle/input/siim-covid19-detection/test/**/*dcm', recursive=True)\ntest_meta = pd.DataFrame({'dcm_path':dcm_path})\ntest_meta['image_id'] = test_meta.dcm_path.map(lambda x: x.split('/')[-1].replace('.dcm', '')+'_image')\ntest_meta['study_id'] = test_meta.dcm_path.map(lambda x: x.split('/')[-3].replace('.dcm', '')+'_study')\n\nstudy_df = study_df.merge(test_meta, on='study_id', how='left')\nimage_df = image_df.merge(test_meta, on='image_id', how='left')\n\n# Remove duplicates study_ids from study_df\nstudy_df.drop_duplicates(subset=\"study_id\",keep='first', inplace=True)","metadata":{"execution":{"iopub.status.busy":"2021-07-27T10:40:34.548556Z","iopub.execute_input":"2021-07-27T10:40:34.548874Z","iopub.status.idle":"2021-07-27T10:40:39.044211Z","shell.execute_reply.started":"2021-07-27T10:40:34.548846Z","shell.execute_reply":"2021-07-27T10:40:39.043382Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\n\nSTUDY_DIMS = (512, 512)\nIMAGE_DIMS = (256, 256)\n\nstudy_dir = f'/kaggle/tmp/test/study/'\nos.makedirs(study_dir, exist_ok=True)\n\nimage_dir = f'/kaggle/tmp/test/image/'\nos.makedirs(image_dir, exist_ok=True)\n\ndef 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    return data\n\ndef resize(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    return im\n\nimage_df['dim0'] = -1\nimage_df['dim1'] = -1\n\nfor index, row in tqdm(image_df[['image_id', 'dcm_path', 'dim0', 'dim1']].iterrows(), total=image_df.shape[0]):\n    # set keep_ratio=True to have original aspect ratio\n    xray = read_xray(row['dcm_path'])\n    im = resize(xray, size=IMAGE_DIMS[0])  \n    im.save(os.path.join(image_dir, row['image_id']+'.png'))\n    image_df.loc[image_df.image_id==row.image_id, 'dim0'] = xray.shape[0]\n    image_df.loc[image_df.image_id==row.image_id, 'dim1'] = xray.shape[1]\n\n\n\nfor index, row in tqdm(study_df[['study_id', 'dcm_path']].iterrows(), total=study_df.shape[0]):\n    # set keep_ratio=True to have original aspect ratio\n    xray = read_xray(row['dcm_path'])\n    im = resize(xray, size=STUDY_DIMS[0])\n    im.save(os.path.join(study_dir, row['study_id']+'.png'))\n\n","metadata":{"execution":{"iopub.status.busy":"2021-07-27T10:40:54.105806Z","iopub.execute_input":"2021-07-27T10:40:54.106150Z","iopub.status.idle":"2021-07-27T10:56:12.916404Z","shell.execute_reply.started":"2021-07-27T10:40:54.106118Z","shell.execute_reply":"2021-07-27T10:56:12.914703Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"study_df['image_path'] = study_dir+study_df['study_id']+'.png'\nimage_df['image_path'] = image_dir+image_df['image_id']+'.png'","metadata":{"execution":{"iopub.status.busy":"2021-07-27T10:58:25.487251Z","iopub.execute_input":"2021-07-27T10:58:25.487590Z","iopub.status.idle":"2021-07-27T10:58:25.503387Z","shell.execute_reply.started":"2021-07-27T10:58:25.487559Z","shell.execute_reply":"2021-07-27T10:58:25.502559Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"net =  create_timm_model(arch=cfg.model_arch, n_out=4, pretrained=False, n_in=3)\nnet.load_state_dict({k.replace('', ''): v for k, v in torch.load('../input/efficientnet0/e43ae05e11713613365669a4e1cb010d.pth').items()})\n\nlabels = ['negative', 'typical', 'indeterminate', 'atypical']\nlabels_n = [1, 2, 3, 4]\ndf_labels_idx = pd.DataFrame({'labels_n':labels_n, 'labels':labels})\ntest_dataset = PlantDataset(study_df, transform=get_transform())\ntest_loader =  DataLoader(test_dataset, batch_size=2, shuffle=False)\npre = PlantPredictor(net, study_df, df_labels_idx, test_loader,device)\npre.inference()\ndf_submit = pre.df_submit.copy()","metadata":{"execution":{"iopub.status.busy":"2021-07-27T10:58:27.547561Z","iopub.execute_input":"2021-07-27T10:58:27.547868Z","iopub.status.idle":"2021-07-27T10:59:27.393663Z","shell.execute_reply.started":"2021-07-27T10:58:27.547839Z","shell.execute_reply":"2021-07-27T10:59:27.392793Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TEST_PATH = '/kaggle/tmp/test/image/'\nMODEL_PATH = '/kaggle/input/yolov5/YOLOV5.pt'","metadata":{"execution":{"iopub.status.busy":"2021-07-27T11:00:13.775638Z","iopub.execute_input":"2021-07-27T11:00:13.775965Z","iopub.status.idle":"2021-07-27T11:00:13.782160Z","shell.execute_reply.started":"2021-07-27T11:00:13.775934Z","shell.execute_reply":"2021-07-27T11:00:13.781331Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"shutil.copytree('/kaggle/input/kaggle/tmp/yolov5', '/kaggle/working/yolov5')\nos.chdir('/kaggle/working/yolov5')","metadata":{"execution":{"iopub.status.busy":"2021-07-27T11:00:15.378048Z","iopub.execute_input":"2021-07-27T11:00:15.378390Z","iopub.status.idle":"2021-07-27T11:00:16.545569Z","shell.execute_reply.started":"2021-07-27T11:00:15.378362Z","shell.execute_reply":"2021-07-27T11:00:16.544699Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMG_SIZE = 256\n!python detect.py --weights {MODEL_PATH} \\\n                  --source {TEST_PATH} \\\n                  --img {IMG_SIZE} \\\n                  --conf 0.281 \\\n                  --iou-thres 0.5 \\\n                  --max-det 3 \\\n                  --save-txt \\\n                  --save-conf","metadata":{"execution":{"iopub.status.busy":"2021-07-27T11:00:19.580628Z","iopub.execute_input":"2021-07-27T11:00:19.580988Z","iopub.status.idle":"2021-07-27T11:01:02.616039Z","shell.execute_reply.started":"2021-07-27T11:00:19.580956Z","shell.execute_reply":"2021-07-27T11:01:02.614761Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"PRED_PATH = 'runs/detect/exp/labels'\n# %cat /kaggle/working/yolov5/runs/detect/exp/labels/c6c9bf98487a_image.txt\nprediction_files = os.listdir(PRED_PATH)\n","metadata":{"execution":{"iopub.status.busy":"2021-07-27T11:09:12.007978Z","iopub.execute_input":"2021-07-27T11:09:12.008351Z","iopub.status.idle":"2021-07-27T11:09:12.013614Z","shell.execute_reply.started":"2021-07-27T11:09:12.008316Z","shell.execute_reply":"2021-07-27T11:09:12.012668Z"},"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        xmax = xc + int(np.round(w/2))\n        ymin = yc - int(np.round(h/2))\n        ymax = yc + int(np.round(h/2))\n        \n        correct_bboxes.append([xmin, xmax, ymin, ymax])\n        \n    return correct_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":{"execution":{"iopub.status.busy":"2021-07-27T11:09:13.498332Z","iopub.execute_input":"2021-07-27T11:09:13.498657Z","iopub.status.idle":"2021-07-27T11:09:13.507414Z","shell.execute_reply.started":"2021-07-27T11:09:13.498628Z","shell.execute_reply":"2021-07-27T11:09:13.506316Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_df = pd.read_csv('/kaggle/input/siim-covid19-detection/sample_submission.csv')\nsub_df.tail()","metadata":{"execution":{"iopub.status.busy":"2021-07-27T11:09:15.851584Z","iopub.execute_input":"2021-07-27T11:09:15.851901Z","iopub.status.idle":"2021-07-27T11:09:15.884731Z","shell.execute_reply.started":"2021-07-27T11:09:15.851868Z","shell.execute_reply":"2021-07-27T11:09:15.883970Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions = []\n\nfor i in tqdm(range(len(sub_df))):\n    row = sub_df.loc[i]\n    id_name = row.id.split('_')[0]\n    id_level = row.id.split('_')[-1]\n    \n    if id_level == 'study':\n        # do study-level classification\n\n        predictions.append(df_submit.loc[df_submit['id'] == row.id].labels.tolist()[0]) # dummy prediction\n        \n        \n    elif id_level == 'image':\n        # we can do image-level classification here.\n        # also we can rely on the object detector's classification head.\n        # for this example submisison we will use YOLO's classification head. \n        # since we already ran the inference we know which test images belong to opacity.\n        id_name = id_name + '_image'\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            pred_string = ''\n            for j, conf in enumerate(confidence):\n                pred_string += f'opacity {conf} ' + ' '.join(map(str, bboxes[j])) + ' '\n            predictions.append(pred_string[:-1]) \n        else:\n            predictions.append(\"None 1 0 0 1 1\")","metadata":{"execution":{"iopub.status.busy":"2021-07-27T11:09:17.617262Z","iopub.execute_input":"2021-07-27T11:09:17.617575Z","iopub.status.idle":"2021-07-27T11:09:19.048868Z","shell.execute_reply.started":"2021-07-27T11:09:17.617547Z","shell.execute_reply":"2021-07-27T11:09:19.047928Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_df['PredictionString'] = predictions\nsub_df.to_csv('/kaggle/working/submission.csv',index = False)  \nsub_df.tail()","metadata":{"execution":{"iopub.status.busy":"2021-07-27T11:09:21.295073Z","iopub.execute_input":"2021-07-27T11:09:21.295416Z","iopub.status.idle":"2021-07-27T11:09:21.317025Z","shell.execute_reply.started":"2021-07-27T11:09:21.295370Z","shell.execute_reply":"2021-07-27T11:09:21.315966Z"},"trusted":true},"execution_count":null,"outputs":[]}]}