{"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 pandas as pd\nfrom tqdm.auto import tqdm\nimport cv2\nimport os\nfrom os import listdir\nfrom os.path import isdir, join\nimport keras\nimport numpy as np","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-07-22T02:44:16.091644Z","iopub.execute_input":"2021-07-22T02:44:16.092010Z","iopub.status.idle":"2021-07-22T02:44:16.236373Z","shell.execute_reply.started":"2021-07-22T02:44:16.091982Z","shell.execute_reply":"2021-07-22T02:44:16.235350Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"You can see the training section in [this tutorial](https://etrain.xyz/en/posts/siim-covid19-detection)\n\n![EfficientNetV2](https://raw.githubusercontent.com/google/automl/master/efficientnetv2/g3doc/train_params.png)","metadata":{}},{"cell_type":"markdown","source":"### Convert to JPG","metadata":{}},{"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-07-22T02:12:58.072986Z","iopub.execute_input":"2021-07-22T02:12:58.073322Z","iopub.status.idle":"2021-07-22T02:14:13.233522Z","shell.execute_reply.started":"2021-07-22T02:12:58.073295Z","shell.execute_reply":"2021-07-22T02:14:13.232354Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nfrom PIL import Image\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        \n    return data","metadata":{"execution":{"iopub.status.busy":"2021-07-22T02:14:13.235484Z","iopub.execute_input":"2021-07-22T02:14:13.235767Z","iopub.status.idle":"2021-07-22T02:14:13.529786Z","shell.execute_reply.started":"2021-07-22T02:14:13.235736Z","shell.execute_reply":"2021-07-22T02:14:13.528498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_id_arr = []\ndim0_arr = []\ndim1_arr = []\n\nsave_dir = f'/kaggle/working/test/'\n\nos.makedirs(save_dir, exist_ok=True)\n    \nfor dirname, _, filenames in tqdm(os.walk(f'../input/siim-covid19-detection/test')):\n    for file in filenames:\n        xray = read_xray(os.path.join(dirname, file))\n        im = Image.fromarray(xray)\n        im.save(os.path.join(save_dir, file.replace('dcm', 'jpg')))\n\n        image_id_arr.append(file.replace('.dcm', ''))\n        dim0_arr.append(xray.shape[0])\n        dim1_arr.append(xray.shape[1])","metadata":{"execution":{"iopub.status.busy":"2021-07-22T02:14:13.531374Z","iopub.execute_input":"2021-07-22T02:14:13.531689Z","iopub.status.idle":"2021-07-22T02:25:24.442703Z","shell.execute_reply.started":"2021-07-22T02:14:13.531643Z","shell.execute_reply":"2021-07-22T02:25:24.440935Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"meta_test = pd.DataFrame.from_dict({'image_id': image_id_arr, 'dim0': dim0_arr, 'dim1': dim1_arr})\nmeta_test","metadata":{"execution":{"iopub.status.busy":"2021-07-22T02:25:24.446375Z","iopub.execute_input":"2021-07-22T02:25:24.446742Z","iopub.status.idle":"2021-07-22T02:25:24.516861Z","shell.execute_reply.started":"2021-07-22T02:25:24.446689Z","shell.execute_reply":"2021-07-22T02:25:24.515743Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_path = \"/kaggle/input/siim-covid19-detection/test\"\nstudies = [f for f in listdir(test_path) if isdir(join(test_path, f))]\nstudy_lst = []\nimage_lst = []\nfor study in studies:\n    study_id = study + \"_study\"\n    study_path = join(test_path, study)\n    onlyfiles = [name.split(\".\")[0] for path, subdirs, files in os.walk(study_path) for name in files]\n    for file in onlyfiles:\n        image_id = file\n        study_lst.append(study_id)\n        image_lst.append(image_id)\ndf = pd.DataFrame(list(zip(study_lst, image_lst)), columns =['StudyInstanceUID', 'image_id'])\ndf","metadata":{"execution":{"iopub.status.busy":"2021-07-22T02:40:48.279559Z","iopub.execute_input":"2021-07-22T02:40:48.280053Z","iopub.status.idle":"2021-07-22T02:40:50.722834Z","shell.execute_reply.started":"2021-07-22T02:40:48.280018Z","shell.execute_reply":"2021-07-22T02:40:50.721778Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df = meta_test.merge(df, on='image_id')\ntest_df","metadata":{"execution":{"iopub.status.busy":"2021-07-22T02:40:53.323555Z","iopub.execute_input":"2021-07-22T02:40:53.323920Z","iopub.status.idle":"2021-07-22T02:40:53.360979Z","shell.execute_reply.started":"2021-07-22T02:40:53.323890Z","shell.execute_reply":"2021-07-22T02:40:53.359981Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Study level","metadata":{}},{"cell_type":"code","source":"import itertools\n\nimport matplotlib.pylab as plt\nimport numpy as np\n\nimport tensorflow as tf\nimport tensorflow_hub as hub\n\nprint('TF version:', tf.__version__)\nprint('Hub version:', hub.__version__)\nprint('Phsical devices:', tf.config.list_physical_devices())","metadata":{"execution":{"iopub.status.busy":"2021-07-22T02:40:55.727035Z","iopub.execute_input":"2021-07-22T02:40:55.727418Z","iopub.status.idle":"2021-07-22T02:40:55.891798Z","shell.execute_reply.started":"2021-07-22T02:40:55.727385Z","shell.execute_reply":"2021-07-22T02:40:55.890762Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Build model\nhub_url = '/kaggle/input/efficientnetv2-tf-hub/efficientnetv2-l-21k-ft1k/feature-vector'\nimage_size = 480","metadata":{"execution":{"iopub.status.busy":"2021-07-22T02:40:59.093542Z","iopub.execute_input":"2021-07-22T02:40:59.093969Z","iopub.status.idle":"2021-07-22T02:40:59.097943Z","shell.execute_reply.started":"2021-07-22T02:40:59.093933Z","shell.execute_reply":"2021-07-22T02:40:59.096985Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels = [\"negative\", \"typical\", \"indeterminate\", \"atypical\"]\n\ntf.keras.backend.clear_session()\nbase_model = hub.KerasLayer(hub_url, trainable=False)\nmodel = tf.keras.Sequential([\n    tf.keras.layers.InputLayer(input_shape=[image_size, image_size, 3]),\n    base_model,\n    tf.keras.layers.Dense(\n        len(labels),\n        kernel_regularizer=tf.keras.regularizers.l2(0.0001),\n        activation='sigmoid'\n    )\n])\nmodel.load_weights('/kaggle/input/k/duythanhng/siim-covid-19-efficientnetv2/efficientnetv2-l-21k-ft1k-study-level.h5')","metadata":{"execution":{"iopub.status.busy":"2021-07-22T02:41:00.872388Z","iopub.execute_input":"2021-07-22T02:41:00.872966Z","iopub.status.idle":"2021-07-22T02:41:48.144875Z","shell.execute_reply.started":"2021-07-22T02:41:00.872914Z","shell.execute_reply":"2021-07-22T02:41:48.143833Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_image_name(image_id):\n    image_name = image_id + \".jpg\"\n    return image_name\n\ntest_df[\"image\"] = test_df[\"image_id\"].apply(get_image_name)\nfor label in labels:\n    conf = [0] * test_df.shape[0]\n    test_df[label] = conf\ntest_df","metadata":{"execution":{"iopub.status.busy":"2021-07-22T02:41:48.147692Z","iopub.execute_input":"2021-07-22T02:41:48.148055Z","iopub.status.idle":"2021-07-22T02:41:48.182456Z","shell.execute_reply.started":"2021-07-22T02:41:48.148021Z","shell.execute_reply":"2021-07-22T02:41:48.181328Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_type(row):\n    _label = 0\n    for c in labels:\n        if row[c]==1:\n            _label = labels.index(c)\n    return _label\ntest_df[\"type\"] = test_df.apply(get_type, axis=1)","metadata":{"execution":{"iopub.status.busy":"2021-07-22T02:43:58.700992Z","iopub.execute_input":"2021-07-22T02:43:58.701429Z","iopub.status.idle":"2021-07-22T02:43:58.751537Z","shell.execute_reply.started":"2021-07-22T02:43:58.701385Z","shell.execute_reply":"2021-07-22T02:43:58.750833Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DataGenerator(keras.utils.Sequence):\n    def __init__(self,\n                 _X,\n                 _y, \n                 batch_size=32,\n                 dim=(256,256),\n                 n_channels=3,\n                 n_classes=4,\n                 image_path=\"\",\n                 shuffle=True):\n        self.dim = dim\n        self.batch_size = batch_size\n        self.y = _y\n        self.X = _X\n        self.n_channels = n_channels\n        self.n_classes = n_classes\n        self.image_path = image_path\n        self.shuffle = shuffle\n        self.img_indexes = np.arange(len(self.X))\n        self.on_epoch_end()\n        \n    def __len__(self):\n        'Denotes the number of batches per epoch'\n        return int(np.floor(len(self.img_indexes) / self.batch_size))\n\n    def __getitem__(self, index):\n        'Generate one batch of data'\n        # Generate indexes of the batch\n        indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]\n        # Find list of IDs\n        list_IDs_temps = [self.img_indexes[k] for k in indexes]\n\n        # Generate data\n        X, y = self.__data_generation(list_IDs_temps)\n        return X, y\n\n    def on_epoch_end(self):\n        'Updates indexes after each epoch'\n        self.indexes = np.arange(len(self.X))\n        if self.shuffle == True:\n            np.random.shuffle(self.indexes)\n\n    def __data_generation(self, list_IDs_temps):\n        X = np.empty((self.batch_size, *self.dim, self.n_channels))\n        y = np.empty((self.batch_size), dtype=int)\n        for i, ID in enumerate(list_IDs_temps):\n            full_path = os.path.join(self.image_path, self.X[\"image\"].iloc[ID])\n            \n            im = cv2.imread(full_path)\n            old_size = im.shape[:2] # old_size is in (height, width) format\n\n            desired_size = self.dim[0]\n            # desired_size = max([h, w])\n\n            ratio = float(desired_size)/max(old_size)\n            new_size = tuple([int(x*ratio) for x in old_size])\n\n            im = cv2.resize(im, (new_size[1], new_size[0]))\n\n            delta_w = desired_size - new_size[1]\n            delta_h = desired_size - new_size[0]\n            top, bottom = delta_h//2, delta_h-(delta_h//2)\n            left, right = delta_w//2, delta_w-(delta_w//2)\n            color = [0, 0, 0]\n            new_im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT,\n                value=color)\n            \n            X[i,] = new_im\n            y[i] = self.y[\"type\"].iloc[ID]\n\n        X = np.stack(X).astype('uint8')\n        X = X / np.max(X)\n        y_convert = keras.utils.to_categorical(y, num_classes=self.n_classes)\n        return X, y_convert","metadata":{"execution":{"iopub.status.busy":"2021-07-22T02:44:00.377063Z","iopub.execute_input":"2021-07-22T02:44:00.377563Z","iopub.status.idle":"2021-07-22T02:44:00.395793Z","shell.execute_reply.started":"2021-07-22T02:44:00.377531Z","shell.execute_reply":"2021-07-22T02:44:00.394896Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dim = (image_size, image_size)\n\nparams = dict(\n    dim=dim,\n    batch_size=1,\n    n_classes=4,\n    n_channels=3\n)\nparams_valid = dict(\n    image_path=save_dir,\n    shuffle=False,\n    **params\n)\ntest_generator = DataGenerator(test_df[[\"image\"]], test_df[[\"type\"]], **params_valid)","metadata":{"execution":{"iopub.status.busy":"2021-07-22T03:16:49.251393Z","iopub.execute_input":"2021-07-22T03:16:49.251763Z","iopub.status.idle":"2021-07-22T03:16:49.260823Z","shell.execute_reply.started":"2021-07-22T03:16:49.251734Z","shell.execute_reply":"2021-07-22T03:16:49.259925Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predicts = model.predict(test_generator)","metadata":{"execution":{"iopub.status.busy":"2021-07-22T03:16:53.052024Z","iopub.execute_input":"2021-07-22T03:16:53.052418Z","iopub.status.idle":"2021-07-22T03:47:17.259841Z","shell.execute_reply.started":"2021-07-22T03:16:53.052383Z","shell.execute_reply":"2021-07-22T03:47:17.258937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"confidences = {}\nfor i in range(predicts.shape[0]):\n    for j, c in enumerate(labels):\n        if c not in confidences:\n            confidences[c] = []\n        if predicts[i, j]:\n            confidences[c].append(predicts[i, j])\n        else:\n            confidences[c].append(0.0)","metadata":{"execution":{"iopub.status.busy":"2021-07-22T04:34:17.485260Z","iopub.execute_input":"2021-07-22T04:34:17.485670Z","iopub.status.idle":"2021-07-22T04:34:17.561492Z","shell.execute_reply.started":"2021-07-22T04:34:17.485589Z","shell.execute_reply":"2021-07-22T04:34:17.560180Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(confidences['negative'])","metadata":{"execution":{"iopub.status.busy":"2021-07-22T03:16:06.024861Z","iopub.execute_input":"2021-07-22T03:16:06.025205Z","iopub.status.idle":"2021-07-22T03:16:06.030991Z","shell.execute_reply.started":"2021-07-22T03:16:06.025176Z","shell.execute_reply":"2021-07-22T03:16:06.029801Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(test_df)","metadata":{"execution":{"iopub.status.busy":"2021-07-22T03:16:16.914420Z","iopub.execute_input":"2021-07-22T03:16:16.914795Z","iopub.status.idle":"2021-07-22T03:16:16.920407Z","shell.execute_reply.started":"2021-07-22T03:16:16.914759Z","shell.execute_reply":"2021-07-22T03:16:16.919439Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for label in labels:\n    test_df[label] = confidences[label]\n\ntest_df","metadata":{"execution":{"iopub.status.busy":"2021-07-22T03:15:42.133877Z","iopub.execute_input":"2021-07-22T03:15:42.134354Z","iopub.status.idle":"2021-07-22T03:15:42.165038Z","shell.execute_reply.started":"2021-07-22T03:15:42.134302Z","shell.execute_reply":"2021-07-22T03:15:42.163552Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"study_df = test_df.groupby(['StudyInstanceUID']).mean().reset_index()\nstudy_df = study_df[['StudyInstanceUID', 'negative', 'typical', 'indeterminate', 'atypical']]\nstudy_df","metadata":{"execution":{"iopub.status.busy":"2021-06-10T18:29:20.017944Z","iopub.execute_input":"2021-06-10T18:29:20.0183Z","iopub.status.idle":"2021-06-10T18:29:20.043244Z","shell.execute_reply.started":"2021-06-10T18:29:20.018265Z","shell.execute_reply":"2021-06-10T18:29:20.042438Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_PredictionString(row):\n    string = ''\n    for label in labels:\n        conf =  row[label]\n        string+=f'{label} {conf:0.5f} 0 0 1 1 '\n    string = string.strip()\n    return string\n\nstudy_df['PredictionString'] = study_df.apply(get_PredictionString, axis=1)\nstudy_df = study_df.drop(labels, axis=1)\nstudy_df = study_df.rename(columns={\n    'StudyInstanceUID': 'id'\n})\nstudy_df","metadata":{"execution":{"iopub.status.busy":"2021-06-10T18:29:27.526935Z","iopub.execute_input":"2021-06-10T18:29:27.527278Z","iopub.status.idle":"2021-06-10T18:29:27.577909Z","shell.execute_reply.started":"2021-06-10T18:29:27.527245Z","shell.execute_reply":"2021-06-10T18:29:27.576931Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Image level","metadata":{}},{"cell_type":"code","source":"def convert_id(x):\n    return x + \"_image\"\nimage_df = test_df[['image_id']].apply(convert_id)\nimage_df = image_df.rename(columns={\n    'image_id': 'id'\n})\nimage_df[\"PredictionString\"] = [\"none 1 0 0 1 1\"] * test_df.shape[0]\nimage_df","metadata":{"execution":{"iopub.status.busy":"2021-06-10T18:33:08.394693Z","iopub.execute_input":"2021-06-10T18:33:08.395236Z","iopub.status.idle":"2021-06-10T18:33:08.433244Z","shell.execute_reply.started":"2021-06-10T18:33:08.395168Z","shell.execute_reply":"2021-06-10T18:33:08.432225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Submission","metadata":{}},{"cell_type":"code","source":"sub_df = pd.concat([study_df, image_df])\nsub_df.to_csv('/kaggle/working/submission.csv',index=False)\nprint(sub_df.shape)\nsub_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-10T18:33:57.189806Z","iopub.execute_input":"2021-06-10T18:33:57.190138Z","iopub.status.idle":"2021-06-10T18:33:57.474416Z","shell.execute_reply.started":"2021-06-10T18:33:57.190106Z","shell.execute_reply":"2021-06-10T18:33:57.473619Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nshutil.rmtree('/kaggle/working/test')","metadata":{},"execution_count":null,"outputs":[]}]}