{"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":"# Imports","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport pathlib\nfrom PIL import Image\nimport ast\nimport matplotlib\nimport matplotlib.pyplot as plt\n%matplotlib inline","metadata":{"execution":{"iopub.status.busy":"2021-06-16T17:37:38.251435Z","iopub.execute_input":"2021-06-16T17:37:38.251819Z","iopub.status.idle":"2021-06-16T17:37:38.265581Z","shell.execute_reply.started":"2021-06-16T17:37:38.251729Z","shell.execute_reply":"2021-06-16T17:37:38.263917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# [OPTIONAL] Working with DICOM files","metadata":{}},{"cell_type":"code","source":"# Install libraries for DICOM files\n\n# #!wget 'https://anaconda.org/conda-forge/gdcm/2.8.9/download/linux-64/gdcm-2.8.9-py37h500ead1_1.tar.bz2' -q\n# #!conda install 'gdcm-2.8.9-py37h500ead1_1.tar.bz2' -c conda-forge -y\n# !conda install -c conda-forge gdcm -y\n# !conda install -c conda-forge pydicom -y","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:44:06.893961Z","iopub.execute_input":"2021-06-16T14:44:06.894305Z","iopub.status.idle":"2021-06-16T14:44:06.903723Z","shell.execute_reply.started":"2021-06-16T14:44:06.894272Z","shell.execute_reply":"2021-06-16T14:44:06.902944Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# import pydicom\n# from pydicom.pixel_data_handlers.util import apply_voi_lut","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:44:06.906501Z","iopub.execute_input":"2021-06-16T14:44:06.906835Z","iopub.status.idle":"2021-06-16T14:44:06.912793Z","shell.execute_reply.started":"2021-06-16T14:44:06.906811Z","shell.execute_reply":"2021-06-16T14:44:06.912015Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\n# CONVERTING DICOM FILES TO NP ARRAYS PROPERLY\n# Ref : https://www.kaggle.com/raddar/convert-dicom-to-np-array-the-correct-way\n\n# def dicom2arr(path, voi_lut = True, fix_monochrome = True):\n\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#         arr = apply_voi_lut(dicom.pixel_array, dicom)\n#     else:\n#         arr = 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#         arr = np.amax(arr) - arr\n        \n#     arr = arr - np.min(arr)\n#     arr = arr / np.max(arr)\n#     arr = (arr * 255).astype(np.uint8)\n        \n#     return arr","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:44:06.91377Z","iopub.execute_input":"2021-06-16T14:44:06.914041Z","iopub.status.idle":"2021-06-16T14:44:06.92345Z","shell.execute_reply.started":"2021-06-16T14:44:06.914018Z","shell.execute_reply":"2021-06-16T14:44:06.922548Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# [OPTIONAL] Convert dcm to jpg\nI did this for two reasons:\n1. Because TF OD API explicitly states so in their docs:\n\"Dataset Requirements\nFor every example in your dataset, you should have the following information: An RGB image for the dataset **encoded as jpeg or png**.\n2. Because it's easier to work with jpg's.","metadata":{}},{"cell_type":"code","source":"# def 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    \n#     return im","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:44:06.924922Z","iopub.execute_input":"2021-06-16T14:44:06.92543Z","iopub.status.idle":"2021-06-16T14:44:06.93315Z","shell.execute_reply.started":"2021-06-16T14:44:06.925371Z","shell.execute_reply":"2021-06-16T14:44:06.932262Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# image_id = []\n# dim0 = []\n# dim1 = []\n# splits = []\n\n# for split in ['test', 'train']:\n#     save_dir = f'/kaggle/tmp/{split}/'\n\n#     os.makedirs(save_dir, exist_ok=True)\n    \n#     for dirname, _, filenames in os.walk(f'../input/siim-covid19-detection/{split}'):\n#         for file in filenames:\n#             # set keep_ratio=True to have original aspect ratio\n#             xray = dicom2arr(os.path.join(dirname, file))\n#             im = resize(xray, size=256)  \n#             im.save(os.path.join(save_dir, file.replace('dcm', 'jpg')))\n\n#             image_id.append(file.replace('.dcm', ''))\n#             dim0.append(xray.shape[0])\n#             dim1.append(xray.shape[1])\n#             splits.append(split)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:44:07.012128Z","iopub.execute_input":"2021-06-16T14:44:07.012747Z","iopub.status.idle":"2021-06-16T14:44:07.017216Z","shell.execute_reply.started":"2021-06-16T14:44:07.012694Z","shell.execute_reply":"2021-06-16T14:44:07.016274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# for dirname, _, filenames in os.walk('../input/siim-covid19-resized-to-256px-jpg/train'):\n#     for filename in filenames:\n#         #print(dirname, filename)\n#         path = os.path.join(dirname, filename)\n#         #print(path)\n#         img= Image.open(path)  \n#         image = np.array(img)\n#         print(image)\n#         print(image.shape)\n#         img_arr = dicom2arr(path)\n#         print(img_arr)\n#         print(np.max(img_arr))\n#         print(img_arr.shape)\n#         print(type(img_arr))\n        \n","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:44:07.01915Z","iopub.execute_input":"2021-06-16T14:44:07.019836Z","iopub.status.idle":"2021-06-16T14:44:07.029019Z","shell.execute_reply.started":"2021-06-16T14:44:07.019795Z","shell.execute_reply":"2021-06-16T14:44:07.028096Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Install TF Object detection API","metadata":{}},{"cell_type":"code","source":"# Clone the tensorflow models repository if it doesn't already exist\nif \"models\" in pathlib.Path.cwd().parts:\n    while \"models\" in pathlib.Path.cwd().parts:\n        os.chdir('..')\nelif not pathlib.Path('models').exists():\n    !git clone --depth 1 https://github.com/tensorflow/models","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:44:07.031652Z","iopub.execute_input":"2021-06-16T14:44:07.032551Z","iopub.status.idle":"2021-06-16T14:44:11.381532Z","shell.execute_reply.started":"2021-06-16T14:44:07.032468Z","shell.execute_reply":"2021-06-16T14:44:11.380623Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!wget -O protobuf.zip https://github.com/google/protobuf/releases/download/v3.17.2/protoc-3.17.2-linux-x86_64.zip -q\n!unzip -o protobuf.zip\n!rm protobuf.zip","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:44:11.383428Z","iopub.execute_input":"2021-06-16T14:44:11.383747Z","iopub.status.idle":"2021-06-16T14:44:14.137141Z","shell.execute_reply.started":"2021-06-16T14:44:11.383713Z","shell.execute_reply":"2021-06-16T14:44:14.136068Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%cd /kaggle/working/models/research\n!protoc object_detection/protos/*.proto --python_out=.\n!cp object_detection/packages/tf2/setup.py .\n!python -m pip install .","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:44:14.138696Z","iopub.execute_input":"2021-06-16T14:44:14.139031Z","iopub.status.idle":"2021-06-16T14:45:54.16383Z","shell.execute_reply.started":"2021-06-16T14:44:14.13899Z","shell.execute_reply":"2021-06-16T14:45:54.162871Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#run model builder test\n!python object_detection/builders/model_builder_tf2_test.py","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:45:54.165433Z","iopub.execute_input":"2021-06-16T14:45:54.165764Z","iopub.status.idle":"2021-06-16T14:46:28.897288Z","shell.execute_reply.started":"2021-06-16T14:45:54.165722Z","shell.execute_reply":"2021-06-16T14:46:28.896367Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nfrom object_detection.utils import ops as utils_ops\nfrom object_detection.utils import label_map_util\nfrom object_detection.utils import visualization_utils as vis_util\n\n# The following two imports are for creating TFRecord files\nfrom object_detection.utils import dataset_util\nfrom object_detection.dataset_tools import tf_record_creation_util","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:28.900565Z","iopub.execute_input":"2021-06-16T14:46:28.900836Z","iopub.status.idle":"2021-06-16T14:46:30.663312Z","shell.execute_reply.started":"2021-06-16T14:46:28.900805Z","shell.execute_reply":"2021-06-16T14:46:30.662442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create annotations","metadata":{}},{"cell_type":"code","source":"!mkdir /kaggle/working/Annotations\n%cd /kaggle/working/","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:30.664485Z","iopub.execute_input":"2021-06-16T14:46:30.664814Z","iopub.status.idle":"2021-06-16T14:46:31.310763Z","shell.execute_reply.started":"2021-06-16T14:46:30.66478Z","shell.execute_reply":"2021-06-16T14:46:31.309796Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%writefile Annotations/label_map.pbtxt\nitem {\n    id: 1\n    name: 'negative for pneumonia'\n}\n\nitem {\n    id: 2\n    name: 'typical'\n}\n\nitem {\n    id: 3\n    name: 'indeterminate'\n}\n\nitem {\n    id: 4\n    name: 'atypical'\n}","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:31.314142Z","iopub.execute_input":"2021-06-16T14:46:31.314411Z","iopub.status.idle":"2021-06-16T14:46:31.320713Z","shell.execute_reply.started":"2021-06-16T14:46:31.314381Z","shell.execute_reply":"2021-06-16T14:46:31.319674Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Working with bboxes and labels","metadata":{}},{"cell_type":"code","source":"import pandas as pd\n!pwd\npath = '../input/siim-covid19-detection/'\ntrain_image = pd.read_csv(path+'train_image_level.csv')\ntrain_study = pd.read_csv(path+'train_study_level.csv')\nsample_submission = pd.read_csv(path+'sample_submission.csv')","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:31.323015Z","iopub.execute_input":"2021-06-16T14:46:31.323697Z","iopub.status.idle":"2021-06-16T14:46:32.021913Z","shell.execute_reply.started":"2021-06-16T14:46:31.323658Z","shell.execute_reply":"2021-06-16T14:46:32.020989Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(len(train_image))\nprint(len(train_study))","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.02336Z","iopub.execute_input":"2021-06-16T14:46:32.023708Z","iopub.status.idle":"2021-06-16T14:46:32.028079Z","shell.execute_reply.started":"2021-06-16T14:46:32.023668Z","shell.execute_reply":"2021-06-16T14:46:32.027247Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"NOTES: \n* Some of the values in the **StudyInstanceUID** column in **train_image** are related (point) to several images - therefore there are 6334 images but only 6054 StudyInstanceUID's. (Does it mean that multiple images have identical bboxes and labels and this was done just to save time and space for identical boxes/labels?)\n* **StudyInstanceUID** column in **train_image** are identical to the **id** column in **train_study** (but without the _study suffix)","metadata":{}},{"cell_type":"code","source":"train_study.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.029356Z","iopub.execute_input":"2021-06-16T14:46:32.0299Z","iopub.status.idle":"2021-06-16T14:46:32.064605Z","shell.execute_reply.started":"2021-06-16T14:46:32.029865Z","shell.execute_reply":"2021-06-16T14:46:32.063818Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_study['id'] = train_study['id'].str.replace('_study', '')\n","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.065905Z","iopub.execute_input":"2021-06-16T14:46:32.066394Z","iopub.status.idle":"2021-06-16T14:46:32.077796Z","shell.execute_reply.started":"2021-06-16T14:46:32.066358Z","shell.execute_reply":"2021-06-16T14:46:32.07698Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_study.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.080557Z","iopub.execute_input":"2021-06-16T14:46:32.080804Z","iopub.status.idle":"2021-06-16T14:46:32.094769Z","shell.execute_reply.started":"2021-06-16T14:46:32.08078Z","shell.execute_reply":"2021-06-16T14:46:32.093846Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_study.rename(columns={'id': 'StudyInstanceUID'}, inplace=True)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.096022Z","iopub.execute_input":"2021-06-16T14:46:32.096514Z","iopub.status.idle":"2021-06-16T14:46:32.103174Z","shell.execute_reply.started":"2021-06-16T14:46:32.096476Z","shell.execute_reply":"2021-06-16T14:46:32.102359Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_study.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.104542Z","iopub.execute_input":"2021-06-16T14:46:32.104971Z","iopub.status.idle":"2021-06-16T14:46:32.118904Z","shell.execute_reply.started":"2021-06-16T14:46:32.104934Z","shell.execute_reply":"2021-06-16T14:46:32.117782Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_image.info()\nprint('\\n')\ntrain_study.info()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.119984Z","iopub.execute_input":"2021-06-16T14:46:32.120352Z","iopub.status.idle":"2021-06-16T14:46:32.144551Z","shell.execute_reply.started":"2021-06-16T14:46:32.120315Z","shell.execute_reply":"2021-06-16T14:46:32.143647Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_result = train_image.merge(train_study, on='StudyInstanceUID', how='left')","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.145855Z","iopub.execute_input":"2021-06-16T14:46:32.146237Z","iopub.status.idle":"2021-06-16T14:46:32.159704Z","shell.execute_reply.started":"2021-06-16T14:46:32.146201Z","shell.execute_reply":"2021-06-16T14:46:32.158665Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_result.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.161202Z","iopub.execute_input":"2021-06-16T14:46:32.161755Z","iopub.status.idle":"2021-06-16T14:46:32.173497Z","shell.execute_reply.started":"2021-06-16T14:46:32.161718Z","shell.execute_reply":"2021-06-16T14:46:32.172518Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_result.describe()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.174834Z","iopub.execute_input":"2021-06-16T14:46:32.17553Z","iopub.status.idle":"2021-06-16T14:46:32.201739Z","shell.execute_reply.started":"2021-06-16T14:46:32.175463Z","shell.execute_reply":"2021-06-16T14:46:32.200824Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_result['id'] = train_result['id'].str.replace('_image', '')","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.203081Z","iopub.execute_input":"2021-06-16T14:46:32.203448Z","iopub.status.idle":"2021-06-16T14:46:32.214146Z","shell.execute_reply.started":"2021-06-16T14:46:32.20341Z","shell.execute_reply":"2021-06-16T14:46:32.212885Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"original_dims = pd.read_csv('../input/siim-covid19-resized-to-256px-jpg/meta.csv')","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.215543Z","iopub.execute_input":"2021-06-16T14:46:32.216025Z","iopub.status.idle":"2021-06-16T14:46:32.239509Z","shell.execute_reply.started":"2021-06-16T14:46:32.215991Z","shell.execute_reply":"2021-06-16T14:46:32.23882Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"original_dims.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.240636Z","iopub.execute_input":"2021-06-16T14:46:32.240962Z","iopub.status.idle":"2021-06-16T14:46:32.250801Z","shell.execute_reply.started":"2021-06-16T14:46:32.240928Z","shell.execute_reply":"2021-06-16T14:46:32.250023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"original_dims.rename(columns={'image_id': 'id'}, inplace=True)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.252321Z","iopub.execute_input":"2021-06-16T14:46:32.25301Z","iopub.status.idle":"2021-06-16T14:46:32.259216Z","shell.execute_reply.started":"2021-06-16T14:46:32.252852Z","shell.execute_reply":"2021-06-16T14:46:32.258437Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_result_final = train_result.merge(original_dims, on='id', how='left')","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.260393Z","iopub.execute_input":"2021-06-16T14:46:32.260814Z","iopub.status.idle":"2021-06-16T14:46:32.275191Z","shell.execute_reply.started":"2021-06-16T14:46:32.260776Z","shell.execute_reply":"2021-06-16T14:46:32.274358Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_result_final.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.27656Z","iopub.execute_input":"2021-06-16T14:46:32.276984Z","iopub.status.idle":"2021-06-16T14:46:32.29176Z","shell.execute_reply.started":"2021-06-16T14:46:32.276948Z","shell.execute_reply":"2021-06-16T14:46:32.290854Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Scale bboxes proportionally","metadata":{}},{"cell_type":"code","source":"train_result_final[\"boxes\"] = train_result_final[\"boxes\"].fillna(\"[{'x':0, 'y':0, 'width':1, 'height':1}]\")","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.29589Z","iopub.execute_input":"2021-06-16T14:46:32.296147Z","iopub.status.idle":"2021-06-16T14:46:32.301983Z","shell.execute_reply.started":"2021-06-16T14:46:32.296123Z","shell.execute_reply":"2021-06-16T14:46:32.300989Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import ast\ntrain_result_final[\"boxes\"] = train_result_final[\"boxes\"].apply(lambda x: ast.literal_eval(x))","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.304245Z","iopub.execute_input":"2021-06-16T14:46:32.304606Z","iopub.status.idle":"2021-06-16T14:46:32.497259Z","shell.execute_reply.started":"2021-06-16T14:46:32.30457Z","shell.execute_reply":"2021-06-16T14:46:32.496454Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_result_final.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.498437Z","iopub.execute_input":"2021-06-16T14:46:32.498776Z","iopub.status.idle":"2021-06-16T14:46:32.515769Z","shell.execute_reply.started":"2021-06-16T14:46:32.498741Z","shell.execute_reply":"2021-06-16T14:46:32.514999Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def unpack_bboxes(df):\n    \"\"\" go from xmin,ymin,width,height --> xmin,ymin,xmax,ymax \"\"\"\n    for dictionary in df[\"boxes\"]:\n        df[\"xmin\"] = dictionary[\"x\"]\n        df[\"ymin\"] = dictionary[\"y\"]\n        df[\"xmax\"] = dictionary[\"x\"] + dictionary[\"width\"]\n        df[\"ymax\"] = dictionary[\"y\"] + dictionary[\"height\"]\n    return df","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.516999Z","iopub.execute_input":"2021-06-16T14:46:32.517535Z","iopub.status.idle":"2021-06-16T14:46:32.526104Z","shell.execute_reply.started":"2021-06-16T14:46:32.517498Z","shell.execute_reply":"2021-06-16T14:46:32.525353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def scale_bbox_coor(df):\n    if df['xmin'] != 0:\n        df['xmin'] *= (256 / df['dim1'])\n        df['xmax'] *= (256 / df['dim1'])\n        df['ymin'] *= (256 / df['dim0'])\n        df['ymax'] *= (256 / df['dim0'])\n    return df","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.528791Z","iopub.execute_input":"2021-06-16T14:46:32.529125Z","iopub.status.idle":"2021-06-16T14:46:32.536007Z","shell.execute_reply.started":"2021-06-16T14:46:32.529088Z","shell.execute_reply":"2021-06-16T14:46:32.535192Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Unpacking bboxes into separate columns. This will take ~20 secs\")\ntrain_result_final = train_result_final.apply(unpack_bboxes, axis=1)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:32.53722Z","iopub.execute_input":"2021-06-16T14:46:32.537624Z","iopub.status.idle":"2021-06-16T14:46:49.280907Z","shell.execute_reply.started":"2021-06-16T14:46:32.53759Z","shell.execute_reply":"2021-06-16T14:46:49.279991Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_result_final = train_result_final.apply(scale_bbox_coor, axis=1)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:49.282268Z","iopub.execute_input":"2021-06-16T14:46:49.282608Z","iopub.status.idle":"2021-06-16T14:46:50.135534Z","shell.execute_reply.started":"2021-06-16T14:46:49.282571Z","shell.execute_reply":"2021-06-16T14:46:50.134656Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_result_final.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:50.136732Z","iopub.execute_input":"2021-06-16T14:46:50.137002Z","iopub.status.idle":"2021-06-16T14:46:50.161866Z","shell.execute_reply.started":"2021-06-16T14:46:50.136975Z","shell.execute_reply":"2021-06-16T14:46:50.161039Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels_dict = {'Negative for Pneumonia': [\"negative\", 1], 'Typical Appearance': [\"typical\", 2], 'Indeterminate Appearance': [\"indeterminate\", 3], 'Atypical Appearance': [\"atypical\", 4]}","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:50.162864Z","iopub.execute_input":"2021-06-16T14:46:50.163122Z","iopub.status.idle":"2021-06-16T14:46:50.167419Z","shell.execute_reply.started":"2021-06-16T14:46:50.163095Z","shell.execute_reply":"2021-06-16T14:46:50.166285Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def convert_and_combine_classes(df):\n    for lbl in labels_dict:\n        if df[lbl]:\n            df['class'] = labels_dict[lbl][0]\n            df['class_num'] = labels_dict[lbl][1]\n    return df","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:50.16897Z","iopub.execute_input":"2021-06-16T14:46:50.169399Z","iopub.status.idle":"2021-06-16T14:46:50.178171Z","shell.execute_reply.started":"2021-06-16T14:46:50.169356Z","shell.execute_reply":"2021-06-16T14:46:50.177421Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_result_final = train_result_final.apply(convert_and_combine_classes, axis=1)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:50.17942Z","iopub.execute_input":"2021-06-16T14:46:50.179783Z","iopub.status.idle":"2021-06-16T14:46:59.105548Z","shell.execute_reply.started":"2021-06-16T14:46:50.179746Z","shell.execute_reply":"2021-06-16T14:46:59.104664Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_result_final.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:59.106764Z","iopub.execute_input":"2021-06-16T14:46:59.10712Z","iopub.status.idle":"2021-06-16T14:46:59.133847Z","shell.execute_reply.started":"2021-06-16T14:46:59.107076Z","shell.execute_reply":"2021-06-16T14:46:59.132774Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Split train DataFrame into train/validation","metadata":{}},{"cell_type":"code","source":"import sklearn\nfrom sklearn.model_selection import train_test_split\n\ntrain_df, val_df = train_test_split(train_result_final, test_size=0.1)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:59.136703Z","iopub.execute_input":"2021-06-16T14:46:59.136978Z","iopub.status.idle":"2021-06-16T14:46:59.161403Z","shell.execute_reply.started":"2021-06-16T14:46:59.136952Z","shell.execute_reply":"2021-06-16T14:46:59.16068Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = train_df.filter(['id','class', 'class_num', 'xmin', 'ymin', 'xmax', 'ymax'], axis=1)\nval_df = val_df.filter(['id','class', 'class_num', 'xmin', 'ymin', 'xmax', 'ymax'], axis=1)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:59.162567Z","iopub.execute_input":"2021-06-16T14:46:59.162917Z","iopub.status.idle":"2021-06-16T14:46:59.170005Z","shell.execute_reply.started":"2021-06-16T14:46:59.162882Z","shell.execute_reply":"2021-06-16T14:46:59.168957Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:59.171216Z","iopub.execute_input":"2021-06-16T14:46:59.171662Z","iopub.status.idle":"2021-06-16T14:46:59.189559Z","shell.execute_reply.started":"2021-06-16T14:46:59.171626Z","shell.execute_reply":"2021-06-16T14:46:59.188501Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:59.191758Z","iopub.execute_input":"2021-06-16T14:46:59.192153Z","iopub.status.idle":"2021-06-16T14:46:59.208992Z","shell.execute_reply.started":"2021-06-16T14:46:59.192114Z","shell.execute_reply":"2021-06-16T14:46:59.208009Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Split train images into train/validation datasets","metadata":{}},{"cell_type":"code","source":"# Move 10% of images from train to validation directory\n!pwd\n!mkdir -p /kaggle/working/dataset/train\n!mkdir -p /kaggle/working/dataset/validation\n\nimport os\nimport shutil\n\noriginal_dataset_path = '../input/siim-covid19-resized-to-256px-jpg/train'\n\ndef copy_split_dataset(df, split):\n    for _, row in df.iterrows():\n        source_file_path = os.path.join(original_dataset_path, (row['id'] + '.jpg'))\n        dest_file_path = os.path.join(('./dataset/' + split), (row['id'] +'.jpg'))\n        shutil.copy(source_file_path, dest_file_path)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:46:59.210637Z","iopub.execute_input":"2021-06-16T14:46:59.21104Z","iopub.status.idle":"2021-06-16T14:47:01.18095Z","shell.execute_reply.started":"2021-06-16T14:46:59.211002Z","shell.execute_reply":"2021-06-16T14:47:01.179908Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"copy_split_dataset(train_df, 'train')\ncopy_split_dataset(val_df, 'validation')\n","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:47:01.184223Z","iopub.execute_input":"2021-06-16T14:47:01.184496Z","iopub.status.idle":"2021-06-16T14:47:24.48102Z","shell.execute_reply.started":"2021-06-16T14:47:01.184467Z","shell.execute_reply":"2021-06-16T14:47:24.480153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(len(os.listdir('/kaggle/working/dataset/train/')))\nprint(len(os.listdir('/kaggle/working/dataset/validation/')))","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:47:24.482386Z","iopub.execute_input":"2021-06-16T14:47:24.482732Z","iopub.status.idle":"2021-06-16T14:47:24.492715Z","shell.execute_reply.started":"2021-06-16T14:47:24.482694Z","shell.execute_reply":"2021-06-16T14:47:24.491625Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.to_csv('train_df.csv', encoding='utf-8')\nval_df.to_csv('val_df.csv', encoding='utf-8')","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:47:24.494034Z","iopub.execute_input":"2021-06-16T14:47:24.494643Z","iopub.status.idle":"2021-06-16T14:47:24.689028Z","shell.execute_reply.started":"2021-06-16T14:47:24.494605Z","shell.execute_reply":"2021-06-16T14:47:24.688259Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create TFRecord files","metadata":{}},{"cell_type":"code","source":"import io\nfrom collections import namedtuple\n\ndef split(df, group):\n    data = namedtuple('data', ['filename', 'object'])\n    gb = df.groupby(group)\n    return [data(filename, gb.get_group(x)) for filename, x in zip(gb.groups.keys(), gb.groups)]","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:47:24.690249Z","iopub.execute_input":"2021-06-16T14:47:24.690772Z","iopub.status.idle":"2021-06-16T14:47:24.696261Z","shell.execute_reply.started":"2021-06-16T14:47:24.690732Z","shell.execute_reply":"2021-06-16T14:47:24.695159Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_tf_example(group, path):\n    with tf.io.gfile.GFile(os.path.join(path, '{}'.format(group.filename + '.jpg')), 'rb') as fid:\n        encoded_jpg = fid.read()\n    encoded_jpg_io = io.BytesIO(encoded_jpg)\n    image = Image.open(encoded_jpg_io)\n    width, height = image.size\n\n    filename = group.filename.encode('utf8')\n    image_format = b'jpg'\n    xmins = []\n    xmaxs = []\n    ymins = []\n    ymaxs = []\n    classes_text = []\n    classes = []\n\n    for index, row in group.object.iterrows():\n        xmins.append(row['xmin'])\n        xmaxs.append(row['xmax'])\n        ymins.append(row['ymin'])\n        ymaxs.append(row['ymax'])\n        classes_text.append(row['class'].encode('utf8'))\n        classes.append(row['class_num'])\n\n    tf_example = tf.train.Example(features=tf.train.Features(feature={\n        #'image/height': dataset_util.int64_feature(height),\n        #'image/width': dataset_util.int64_feature(width),\n        'image/filename': dataset_util.bytes_feature(filename),\n        #'image/source_id': dataset_util.bytes_feature(filename),\n        'image/encoded': dataset_util.bytes_feature(encoded_jpg),\n        'image/format': dataset_util.bytes_feature(image_format),\n        'image/object/bbox/xmin': dataset_util.float_list_feature(xmins),\n        'image/object/bbox/xmax': dataset_util.float_list_feature(xmaxs),\n        'image/object/bbox/ymin': dataset_util.float_list_feature(ymins),\n        'image/object/bbox/ymax': dataset_util.float_list_feature(ymaxs),\n        'image/object/class/text': dataset_util.bytes_list_feature(classes_text),\n        'image/object/class/label': dataset_util.int64_list_feature(classes),\n    }))\n    return tf_example","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:47:24.697733Z","iopub.execute_input":"2021-06-16T14:47:24.69827Z","iopub.status.idle":"2021-06-16T14:47:24.710206Z","shell.execute_reply.started":"2021-06-16T14:47:24.698233Z","shell.execute_reply":"2021-06-16T14:47:24.709161Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_to_dirnames_dict = {'train': train_df, 'validation': val_df}\n\ndir_path = './dataset/'\nfor dirname in next(os.walk(dir_path))[1]:\n    # if dirname != 'test':\n    writer = tf.io.TFRecordWriter(f'tfrecord_{dirname}.tfrec')\n    path = os.path.join(dir_path, dirname)\n    examples = df_to_dirnames_dict[dirname]\n    grouped = split(examples, 'id')\n    for group in grouped:\n        tf_example = create_tf_example(group, path)\n        writer.write(tf_example.SerializeToString())\n    writer.close()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:47:24.711771Z","iopub.execute_input":"2021-06-16T14:47:24.712255Z","iopub.status.idle":"2021-06-16T14:47:29.547241Z","shell.execute_reply.started":"2021-06-16T14:47:24.712214Z","shell.execute_reply":"2021-06-16T14:47:29.546342Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Using pre-trained models from the zoo","metadata":{}},{"cell_type":"code","source":"# !mkdir pre-trained-models\n# !mkdir models/my_ssd_resnet50_v1_fpn","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:47:29.548603Z","iopub.execute_input":"2021-06-16T14:47:29.548949Z","iopub.status.idle":"2021-06-16T14:47:29.554488Z","shell.execute_reply.started":"2021-06-16T14:47:29.548911Z","shell.execute_reply":"2021-06-16T14:47:29.553712Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !wget http://download.tensorflow.org/models/object_detection/tf2/20200711/ssd_resnet50_v1_fpn_640x640_coco17_tpu-8.tar.gz  \n# !tar xvf ssd_resnet50_v1_fpn_640x640_coco17_tpu-8.tar.gz --directory=pre-trained-models\n\n# %cd ~\n# # !cp /kaggle/input/tfodpipelineconfig/pipeline.config /kaggle/working/models/my_ssd_resnet50_v1_fpn","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:47:29.55575Z","iopub.execute_input":"2021-06-16T14:47:29.556256Z","iopub.status.idle":"2021-06-16T14:47:29.566097Z","shell.execute_reply.started":"2021-06-16T14:47:29.556216Z","shell.execute_reply":"2021-06-16T14:47:29.565339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !cp /kaggle/working/models/research/object_detection/model_main_tf2.py /kaggle/working/\n# %cd /kaggle/working/\n# !python model_main_tf2.py --model_dir=models/my_ssd_resnet50_v1_fpn --pipeline_config_path=models/my_ssd_resnet50_v1_fpn/pipeline.config","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:47:29.567446Z","iopub.execute_input":"2021-06-16T14:47:29.567849Z","iopub.status.idle":"2021-06-16T14:47:29.57651Z","shell.execute_reply.started":"2021-06-16T14:47:29.567813Z","shell.execute_reply":"2021-06-16T14:47:29.575723Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Using Keras","metadata":{}},{"cell_type":"code","source":"def prepare_sample(features):\n    image = tf.image.resize(features[\"image/encoded\"], size=(256, 256))\n    return image, features[\"image/object/class/label\"]\n\n\ndef get_dataset(filenames, batch_size):\n    dataset = (\n        tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE)\n        .map(parse_tfrecord_fn, num_parallel_calls=AUTOTUNE)\n        .shuffle(batch_size * 10)\n        .batch(batch_size)\n        .prefetch(AUTOTUNE)\n    )\n    return dataset\n\n\ndef parse_tfrecord_fn(example):\n    feature_description = {\n        \"image/encoded\": tf.io.FixedLenFeature([], tf.string),\n        \"image/format\": tf.io.FixedLenFeature([], tf.string),\n        \"image/object/bbox/xmin\": tf.io.FixedLenFeature([], tf.float32),\n        \"image/object/bbox/xmax\": tf.io.FixedLenFeature([], tf.float32),\n        \"image/object/bbox/ymin\": tf.io.FixedLenFeature([], tf.float32),\n        \"image/object/bbox/ymax\": tf.io.FixedLenFeature([], tf.float32),   \n        \"image/object/class/text\": tf.io.FixedLenFeature([], tf.string),\n        \"image/object/class/label\": tf.io.FixedLenFeature([], tf.int64),\n    }\n    example = tf.io.parse_single_example(example, feature_description)\n    example[\"image/encoded\"] = tf.io.decode_jpeg(example[\"image/encoded\"], channels=1)\n#     example[\"image/object/bbox/xmin\"] = tf.sparse.to_dense(example[\"image/object/bbox/xmin\"])\n#     example[\"image/object/bbox/xmax\"] = tf.sparse.to_dense(example[\"image/object/bbox/xmax\"])\n#     example[\"image/object/bbox/ymin\"] = tf.sparse.to_dense(example[\"image/object/bbox/ymin\"])\n#     example[\"image/object/bbox/ymax\"] = tf.sparse.to_dense(example[\"image/object/bbox/ymax\"])\n    return example","metadata":{"execution":{"iopub.status.busy":"2021-06-16T15:15:29.203342Z","iopub.execute_input":"2021-06-16T15:15:29.203712Z","iopub.status.idle":"2021-06-16T15:15:29.214581Z","shell.execute_reply.started":"2021-06-16T15:15:29.203678Z","shell.execute_reply":"2021-06-16T15:15:29.213251Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Explore one sample from the generated TFRecord","metadata":{}},{"cell_type":"code","source":"raw_dataset = tf.data.TFRecordDataset(\"tfrecord_train.tfrec\")\nparsed_dataset = raw_dataset.map(parse_tfrecord_fn)\n\nfor features in parsed_dataset.take(1):\n    for key in features.keys():\n        if key != \"image/encoded\":\n            print(f\"{key}: {features[key]}\")\n\n    print(f\"Image shape: {features['image/encoded'].shape}\")\n    fig, ax = plt.subplots(1,1, figsize=(7,7))\n    # plt.figure(figsize=(7, 7))\n    \n    width = features['image/object/bbox/xmax'] - features['image/object/bbox/xmin']\n    height = features['image/object/bbox/ymax'] - features['image/object/bbox/ymin']\n    p = matplotlib.patches.Rectangle((features['image/object/bbox/xmin'], features['image/object/bbox/ymin']),\n                                     width, height,\n                                     ec='r', fc='none', lw=1.5)\n    ax.add_patch(p)\n    ax.imshow(features[\"image/encoded\"].numpy())\n    \n    #plt.imshow(features[\"image/encoded\"].numpy())\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T15:52:52.737199Z","iopub.execute_input":"2021-06-16T15:52:52.73753Z","iopub.status.idle":"2021-06-16T15:52:52.981887Z","shell.execute_reply.started":"2021-06-16T15:52:52.737496Z","shell.execute_reply":"2021-06-16T15:52:52.981123Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_filenames = tf.io.gfile.glob(\"tfrecord_train.tfrec\")\nbatch_size = 32\nepochs = 1\nsteps_per_epoch = 50\nAUTOTUNE = tf.data.experimental.AUTOTUNE\n\ninput_tensor = tf.keras.layers.Input(shape=(256, 256, 1), name=\"image/encoded\")\nmodel = tf.keras.applications.EfficientNetB0(\n    input_tensor=input_tensor, weights=None, classes=4\n)\n\n\nmodel.compile(\n    optimizer=tf.keras.optimizers.Adam(),\n    loss=tf.keras.losses.CategoricalCrossentropy(),\n    metrics=[tf.keras.metrics.CategoricalAccuracy()],\n)\n\n\nmodel.fit(\n    x=get_dataset(train_filenames, batch_size),\n    epochs=epochs,\n    steps_per_epoch=steps_per_epoch,\n    verbose=1,\n)\n","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:01:56.188242Z","iopub.execute_input":"2021-06-16T16:01:56.188583Z","iopub.status.idle":"2021-06-16T16:01:58.467536Z","shell.execute_reply.started":"2021-06-16T16:01:56.188552Z","shell.execute_reply":"2021-06-16T16:01:58.463389Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Appendix","metadata":{}},{"cell_type":"markdown","source":"# Write all jpg's into a single 'dataset' numpy array","metadata":{}},{"cell_type":"code","source":"# dataset = np.ndarray(shape=(len(train_image), 1, 256, 256), dtype=np.float32)\n\n# for dirname, _, filenames in os.walk('../input/siim-covid19-resized-to-256px-jpg/train'):\n#     i = 0\n#     for filename in filenames:\n#         path = os.path.join(dirname, filename)\n#         img= Image.open(path)  \n#         np_arr_image = np.array(img)\n#         dataset[i] = np_arr_image\n#         i += 1\n        \n#         if i % 500 == 0:\n#             print(f\"{i} images added to dataset\")\n#     print(\"All images added to dataset!\")","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:47:29.919547Z","iopub.status.idle":"2021-06-16T14:47:29.920339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# dataset.shape","metadata":{"execution":{"iopub.status.busy":"2021-06-16T14:47:29.92162Z","iopub.status.idle":"2021-06-16T14:47:29.92239Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}