{"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":"# Final Notebook\n\n## references:\n\n## [How To Create TFRecords](https://www.kaggle.com/cdeotte/how-to-create-tfrecords)\n\n## [How to properly split folds](https://www.kaggle.com/code/underwearfitting/how-to-properly-split-folds/notebook)\n","metadata":{}},{"cell_type":"markdown","source":"## Import and EDA","metadata":{}},{"cell_type":"code","source":"!conda install '../input/rsna2022-pydicom-conda-helper/libjpeg-turbo-2.1.0-h7f98852_0.tar.bz2' -c conda-forge -y\n!conda install '../input/rsna2022-pydicom-conda-helper/libgcc-ng-9.3.0-h2828fa1_19.tar.bz2' -c conda-forge -y\n!conda install '../input/rsna2022-pydicom-conda-helper/gdcm-2.8.9-py37h500ead1_1.tar.bz2' -c conda-forge -y\n!conda install '../input/rsna2022-pydicom-conda-helper/conda-4.10.1-py37h89c1867_0.tar.bz2' -c conda-forge -y\n!conda install '../input/rsna2022-pydicom-conda-helper/certifi-2020.12.5-py37h89c1867_1.tar.bz2' -c conda-forge -y\n!conda install '../input/rsna2022-pydicom-conda-helper/openssl-1.1.1k-h7f98852_0.tar.bz2' -c conda-forge -y","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:29:34.366632Z","iopub.execute_input":"2022-10-27T05:29:34.367094Z","iopub.status.idle":"2022-10-27T05:30:42.691161Z","shell.execute_reply.started":"2022-10-27T05:29:34.366996Z","shell.execute_reply":"2022-10-27T05:30:42.689712Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# LOAD LIBRARIES\nimport numpy as np, pandas as pd, os, shutil\nimport matplotlib.pyplot as plt, cv2\nimport tensorflow as tf, re, math, gc\nimport glob\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.utils import check_random_state\nimport nibabel as nib\nimport pydicom as dicom\nfrom collections import Counter, defaultdict, OrderedDict\nfrom tqdm import tqdm\nimport tensorflow.keras.backend as K\nfrom kaggle_datasets import KaggleDatasets\nfrom tensorflow import keras\nfrom functools import partial\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.model_selection import KFold\nprint(\"Tensorflow version \" + tf.__version__)","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:30:42.693373Z","iopub.execute_input":"2022-10-27T05:30:42.693778Z","iopub.status.idle":"2022-10-27T05:30:49.001357Z","shell.execute_reply.started":"2022-10-27T05:30:42.69374Z","shell.execute_reply":"2022-10-27T05:30:48.99998Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"FOLDS = 5\nIMGS_PER_CHANNEL = 16 \nN_CHANNEL = 3\nIMG_SIZE = int(512 // (IMGS_PER_CHANNEL**0.5)) \nSEED = 42","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:30:49.002971Z","iopub.execute_input":"2022-10-27T05:30:49.004125Z","iopub.status.idle":"2022-10-27T05:30:49.010129Z","shell.execute_reply.started":"2022-10-27T05:30:49.004068Z","shell.execute_reply":"2022-10-27T05:30:49.008792Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import math\ndef tileImage(imgs):\n    d = int(math.sqrt(IMGS_PER_CHANNEL))\n    h = imgs[0].shape[0]\n    w = imgs[0].shape[1]\n    r = np.zeros((h*d,w*d,1),dtype=np.uint8)\n    for idx,img in enumerate(imgs):\n        idx_y = int(idx/d)\n        idx_x = idx-idx_y*d\n        r[idx_y*h:(idx_y+1)*h,idx_x*w:(idx_x+1)*w,:] = img\n    return r","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:30:49.01294Z","iopub.execute_input":"2022-10-27T05:30:49.013319Z","iopub.status.idle":"2022-10-27T05:30:49.030935Z","shell.execute_reply.started":"2022-10-27T05:30:49.013287Z","shell.execute_reply":"2022-10-27T05:30:49.029537Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BASE = '../input/rsna-2022-cervical-spine-fracture-detection'","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:30:49.033107Z","iopub.execute_input":"2022-10-27T05:30:49.033524Z","iopub.status.idle":"2022-10-27T05:30:49.044882Z","shell.execute_reply.started":"2022-10-27T05:30:49.033478Z","shell.execute_reply":"2022-10-27T05:30:49.043803Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = pd.read_csv(\"../input/rsna-2022-cervical-spine-fracture-detection/train.csv\")\ntest = pd.read_csv(\"../input/rsna-2022-cervical-spine-fracture-detection/test.csv\")\nsamplesub = pd.read_csv(\"../input/rsna-2022-cervical-spine-fracture-detection/sample_submission.csv\")","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:30:49.046961Z","iopub.execute_input":"2022-10-27T05:30:49.047387Z","iopub.status.idle":"2022-10-27T05:30:49.085897Z","shell.execute_reply.started":"2022-10-27T05:30:49.047325Z","shell.execute_reply":"2022-10-27T05:30:49.084619Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(train)","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:30:49.087231Z","iopub.execute_input":"2022-10-27T05:30:49.088076Z","iopub.status.idle":"2022-10-27T05:30:49.098158Z","shell.execute_reply.started":"2022-10-27T05:30:49.088018Z","shell.execute_reply":"2022-10-27T05:30:49.096708Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.head()","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:30:49.099899Z","iopub.execute_input":"2022-10-27T05:30:49.100312Z","iopub.status.idle":"2022-10-27T05:30:49.124692Z","shell.execute_reply.started":"2022-10-27T05:30:49.100278Z","shell.execute_reply":"2022-10-27T05:30:49.123431Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test.head()","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:30:49.126169Z","iopub.execute_input":"2022-10-27T05:30:49.126791Z","iopub.status.idle":"2022-10-27T05:30:49.138641Z","shell.execute_reply.started":"2022-10-27T05:30:49.126749Z","shell.execute_reply":"2022-10-27T05:30:49.13779Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"samplesub.head()","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:30:49.142719Z","iopub.execute_input":"2022-10-27T05:30:49.143125Z","iopub.status.idle":"2022-10-27T05:30:49.156153Z","shell.execute_reply.started":"2022-10-27T05:30:49.143089Z","shell.execute_reply":"2022-10-27T05:30:49.155254Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Loading the dicom images","metadata":{}},{"cell_type":"code","source":"def load_dicom(path, size = IMG_SIZE):\n    try:\n        img=dicom.dcmread(path)\n        img.PhotometricInterpretation = 'YBR_FULL'\n        data=img.pixel_array\n        data=data-np.min(data)\n        if np.max(data) != 0:\n            data=data/np.max(data)\n        data=(data*255).astype(np.uint8)\n        data = cv2.resize(data, (IMG_SIZE, IMG_SIZE))\n        data = np.expand_dims(data, -1)\n        return data\n    except:        \n        return np.zeros((IMG_SIZE, IMG_SIZE, 1))\n\ndef listdirs(folder):\n    return [d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d))]    \n\ntrain_dir = f'{BASE}/train_images'\ntest_dir = f'{BASE}/test_images'\npatients = sorted(os.listdir(train_dir))\nlen(patients), patients[:5]","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:30:49.157577Z","iopub.execute_input":"2022-10-27T05:30:49.158126Z","iopub.status.idle":"2022-10-27T05:30:49.271005Z","shell.execute_reply.started":"2022-10-27T05:30:49.15809Z","shell.execute_reply":"2022-10-27T05:30:49.270013Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## split Multilabeled-Stratificated-KFold","metadata":{}},{"cell_type":"code","source":"class RepeatedStratifiedGroupKFold():\n\n    def __init__(self, n_splits=5, n_repeats=1, random_state=None):\n        self.n_splits = n_splits\n        self.n_repeats = n_repeats\n        self.random_state = random_state\n        \n    def split(self, X, y=None, groups=None):\n        k = self.n_splits\n        def eval_y_counts_per_fold(y_counts, fold):\n            y_counts_per_fold[fold] += y_counts\n            std_per_label = []\n            for label in range(labels_num):\n                label_std = np.std(\n                    [y_counts_per_fold[i][label] / y_distr[label] for i in range(k)]\n                )\n                std_per_label.append(label_std)\n            y_counts_per_fold[fold] -= y_counts\n            return np.mean(std_per_label)\n            \n        rnd = check_random_state(self.random_state)\n        for repeat in range(self.n_repeats):\n            labels_num = np.max(y) + 1\n            y_counts_per_group = defaultdict(lambda: np.zeros(labels_num))\n            y_distr = Counter()\n            for label, g in zip(y, groups):\n                y_counts_per_group[g][label] += 1\n                y_distr[label] += 1\n\n            y_counts_per_fold = defaultdict(lambda: np.zeros(labels_num))\n            groups_per_fold = defaultdict(set)\n        \n            groups_and_y_counts = list(y_counts_per_group.items())\n            rnd.shuffle(groups_and_y_counts)\n\n            for g, y_counts in sorted(groups_and_y_counts, key=lambda x: -np.std(x[1])):\n                best_fold = None\n                min_eval = None\n                for i in range(k):\n                    fold_eval = eval_y_counts_per_fold(y_counts, i)\n                    if min_eval is None or fold_eval < min_eval:\n                        min_eval = fold_eval\n                        best_fold = i\n                y_counts_per_fold[best_fold] += y_counts\n                groups_per_fold[best_fold].add(g)\n            \n            all_groups = set(groups)\n            for i in range(k):\n                train_groups = all_groups - groups_per_fold[i]\n                test_groups = groups_per_fold[i]\n\n                train_indices = [i for i, g in enumerate(groups) if g in train_groups]\n                test_indices = [i for i, g in enumerate(groups) if g in test_groups]\n\n                yield train_indices, test_indices","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:30:49.272716Z","iopub.execute_input":"2022-10-27T05:30:49.273062Z","iopub.status.idle":"2022-10-27T05:30:49.288092Z","shell.execute_reply.started":"2022-10-27T05:30:49.273031Z","shell.execute_reply":"2022-10-27T05:30:49.286891Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# let's first concat all the labels \n# e.g 00000000010   \ntarget_cols = train.drop(['StudyInstanceUID'],axis=1).columns.values.tolist()\ntargets = train[target_cols].astype(str)\n# create a new col to store the label\ntrain['combined_tar'] = ''\nfor i in tqdm(range(targets.shape[1])):\n    train['combined_tar'] += targets.iloc[:,i]\ntrain.combined_tar.value_counts()","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:30:49.289543Z","iopub.execute_input":"2022-10-27T05:30:49.290606Z","iopub.status.idle":"2022-10-27T05:30:49.341995Z","shell.execute_reply.started":"2022-10-27T05:30:49.290562Z","shell.execute_reply":"2022-10-27T05:30:49.341061Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train['combined_tar'] = LabelEncoder().fit_transform(train['combined_tar'])\ntrain","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:30:49.343234Z","iopub.execute_input":"2022-10-27T05:30:49.344133Z","iopub.status.idle":"2022-10-27T05:30:49.363835Z","shell.execute_reply.started":"2022-10-27T05:30:49.34409Z","shell.execute_reply":"2022-10-27T05:30:49.362413Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train['fold'] = -1\nrskf = RepeatedStratifiedGroupKFold(n_splits=FOLDS, random_state=SEED)\nfor i, (train_idx, valid_idx) in enumerate(rskf.split(train, train.combined_tar, train.StudyInstanceUID)): #(df, targets, group)\n    train.loc[valid_idx, 'fold'] = int(i)","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:30:49.365466Z","iopub.execute_input":"2022-10-27T05:30:49.366913Z","iopub.status.idle":"2022-10-27T05:31:10.625081Z","shell.execute_reply.started":"2022-10-27T05:30:49.366865Z","shell.execute_reply":"2022-10-27T05:31:10.623804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.query('fold==0').combined_tar.value_counts()","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:31:10.626594Z","iopub.execute_input":"2022-10-27T05:31:10.626951Z","iopub.status.idle":"2022-10-27T05:31:10.644943Z","shell.execute_reply.started":"2022-10-27T05:31:10.62692Z","shell.execute_reply":"2022-10-27T05:31:10.643816Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.drop('combined_tar', axis=1)","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:31:10.64637Z","iopub.execute_input":"2022-10-27T05:31:10.646735Z","iopub.status.idle":"2022-10-27T05:31:10.664874Z","shell.execute_reply.started":"2022-10-27T05:31:10.646705Z","shell.execute_reply":"2022-10-27T05:31:10.663754Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.drop('combined_tar', axis=1).to_csv('train_folds.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:31:10.666762Z","iopub.execute_input":"2022-10-27T05:31:10.667284Z","iopub.status.idle":"2022-10-27T05:31:10.688582Z","shell.execute_reply.started":"2022-10-27T05:31:10.667248Z","shell.execute_reply":"2022-10-27T05:31:10.687315Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## create TF-Records","metadata":{}},{"cell_type":"code","source":"def _bytes_feature(value):\n   \"\"\"Returns a bytes_list from a string / byte.\"\"\"\n    if isinstance(value, type(tf.constant(0))):\n        value = value.numpy() # BytesList won't unpack a string from an EagerTensor.\n    return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))\n\ndef _float_feature(value):\n  \"\"\"Returns a float_list from a float / double.\"\"\"\n  return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))\n\ndef _int64_feature(value):\n \"\"\"Returns an int64_list from a bool / enum / int / uint.\"\"\"\n  return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:34:09.601315Z","iopub.execute_input":"2022-10-27T05:34:09.601766Z","iopub.status.idle":"2022-10-27T05:34:09.61075Z","shell.execute_reply.started":"2022-10-27T05:34:09.601721Z","shell.execute_reply":"2022-10-27T05:34:09.609328Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def serialize_example(img, pati_oa, c1, c2, c3, c4, c5, c6, c7):\n    feature = {\n      'image': _bytes_feature(img),\n      'patient_overall': _int64_feature(pati_oa),\n      'C1': _int64_feature(c1),\n      'C2': _int64_feature(c2),\n      'C3': _int64_feature(c3),\n      'C4': _int64_feature(c4),\n      'C5': _int64_feature(c5),\n      'C6': _int64_feature(c6),\n      'C7': _int64_feature(c7),\n    }\n    example_proto = tf.train.Example(features=tf.train.Features(feature=feature))\n    return example_proto.SerializeToString()","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:34:15.533734Z","iopub.execute_input":"2022-10-27T05:34:15.534784Z","iopub.status.idle":"2022-10-27T05:34:15.541432Z","shell.execute_reply.started":"2022-10-27T05:34:15.534737Z","shell.execute_reply":"2022-10-27T05:34:15.540266Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"folds = train","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:34:19.493441Z","iopub.execute_input":"2022-10-27T05:34:19.494184Z","iopub.status.idle":"2022-10-27T05:34:19.498801Z","shell.execute_reply.started":"2022-10-27T05:34:19.494141Z","shell.execute_reply":"2022-10-27T05:34:19.497606Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"folds","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:34:20.60469Z","iopub.execute_input":"2022-10-27T05:34:20.605092Z","iopub.status.idle":"2022-10-27T05:34:20.624828Z","shell.execute_reply.started":"2022-10-27T05:34:20.60505Z","shell.execute_reply":"2022-10-27T05:34:20.623538Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Saving TF-Records","metadata":{}},{"cell_type":"code","source":"for f in range(FOLDS):\n    ct = (folds['fold'] == f).sum()\n    idx = folds[folds['fold'] == f].index\n    print(idx)\n    print(ct)\n    print('Writing TFRecord %i of %i...'%(f,ct))\n    flg = 0\n    flg2 = 1\n    with tf.io.TFRecordWriter('train%.2i-%i.tfrec'%(f,ct)) as writer:\n        for k in tqdm(range(ct)):\n            imgs = glob.glob(BASE+'/train_images/'+folds['StudyInstanceUID'][idx[k]]+'/*')\n            n_imgs = len(imgs)\n            stride = n_imgs // (N_CHANNEL * IMGS_PER_CHANNEL)\n            if k==0 : print(\"n_images\",n_imgs, stride, n_imgs//stride)\n            for j in range(1, stride, 1):\n                pimgs = range(j, n_imgs, stride)\n                img_arr_b = []\n                img_arr_g = []\n                img_arr_r = []\n                for impath in pimgs:        \n                    img = load_dicom(BASE+'/train_images/'+folds['StudyInstanceUID'][idx[k]]+f'/{impath}.dcm')                   \n                    \n                    if len(img_arr_b)<IMGS_PER_CHANNEL:img_arr_b.append(img)\n                    elif len(img_arr_g)<IMGS_PER_CHANNEL:img_arr_g.append(img)\n                    elif len(img_arr_r)<IMGS_PER_CHANNEL:img_arr_r.append(img)\n                    \n                imgB = tileImage(img_arr_b)\n                imgG = tileImage(img_arr_g)\n                imgR = tileImage(img_arr_r)\n                img_cat = np.concatenate([imgB, imgG, imgR], axis=-1)\n                \n                if k==0 and flg<1: \n                    print(img_cat.shape)\n                    plt.imshow(img_cat),plt.show()\n                    flg += 1\n                    print(np.max(img_cat), np.min(img_cat))\n                    \n                if np.max(img_cat)==0: continue\n                    \n                img_cat = cv2.imencode('.jpg', img_cat, (cv2.IMWRITE_JPEG_QUALITY,94))[1].tostring()\n                \n                example = serialize_example(\n                    img_cat, \n                    folds['patient_overall'][idx[k]],\n                    folds['C1'][idx[k]],\n                    folds['C2'][idx[k]],\n                    folds['C3'][idx[k]],\n                    folds['C4'][idx[k]],\n                    folds['C5'][idx[k]],\n                    folds['C6'][idx[k]],\n                    folds['C7'][idx[k]],\n                    )\n                writer.write(example)","metadata":{"execution":{"iopub.status.busy":"2022-10-27T05:34:25.83825Z","iopub.execute_input":"2022-10-27T05:34:25.83966Z","iopub.status.idle":"2022-10-27T08:48:41.100154Z","shell.execute_reply.started":"2022-10-27T05:34:25.839611Z","shell.execute_reply":"2022-10-27T08:48:41.095839Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install -q efficientnet >> /dev/null\nimport efficientnet.tfkeras as efn","metadata":{"execution":{"iopub.status.busy":"2022-10-27T08:53:24.089828Z","iopub.execute_input":"2022-10-27T08:53:24.090832Z","iopub.status.idle":"2022-10-27T08:53:24.107488Z","shell.execute_reply.started":"2022-10-27T08:53:24.090748Z","shell.execute_reply":"2022-10-27T08:53:24.105882Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Detect TPU","metadata":{}},{"cell_type":"code","source":"try:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    print('Device:', tpu.master())\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nexcept:\n    strategy = tf.distribute.get_strategy()\nprint('Number of replicas:', strategy.num_replicas_in_sync)\nAUTO = tf.data.experimental.AUTOTUNE","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Set up variables for training","metadata":{}},{"cell_type":"code","source":"AUTOTUNE = tf.data.experimental.AUTOTUNE\nGCS_PATH_STRATIFICATED = KaggleDatasets().get_gcs_path('rsna2022-split-fold-id-wise-tfr')\nBATCH_SIZE = 16 if strategy.num_replicas_in_sync==8 else 1\nBATCH_SIZE *= strategy.num_replicas_in_sync\nAUG_BATCH = BATCH_SIZE\nIMAGE_SIZE = [512,512]\nEPOCHS = 50\nFOLDS = 5\nl_type = tf.int64\nGCS_PATH_STRATIFICATED","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Decode the data and Define data loading methods","metadata":{}},{"cell_type":"code","source":"def decode_image(image_data):\n    image = tf.image.decode_jpeg(image_data, channels=3)\n    image = tf.cast(image, tf.float32) / 255.0  # convert image to floats in [0, 1] range\n    image = tf.reshape(image, [*IMAGE_SIZE, 3]) # explicit size needed for TPU\n    return image\n\ndef read_labeled_tfrecord(example):\n    LABELED_TFREC_FORMAT = {\n        \"image\": tf.io.FixedLenFeature([], tf.string), # tf.string means bytestring\n        \"patient_overall\": tf.io.FixedLenFeature([], l_type),\n        \"C1\": tf.io.FixedLenFeature([], l_type),\n        \"C2\": tf.io.FixedLenFeature([], l_type),  # shape [] means single element\n        \"C3\": tf.io.FixedLenFeature([], l_type),\n        \"C4\": tf.io.FixedLenFeature([], l_type),\n        \"C5\": tf.io.FixedLenFeature([], l_type),\n        \"C6\": tf.io.FixedLenFeature([], l_type),\n        \"C7\": tf.io.FixedLenFeature([], l_type),\n    }\n    example = tf.io.parse_single_example(example, LABELED_TFREC_FORMAT)\n    image = decode_image(example['image'])\n    patient_overall = tf.cast(example['patient_overall'], tf.float32)\n    c1 = tf.cast(example['C1'], tf.float32)\n    c2 = tf.cast(example['C2'], tf.float32)\n    c3 = tf.cast(example['C3'], tf.float32)\n    c4 = tf.cast(example['C4'], tf.float32)\n    c5 = tf.cast(example['C5'], tf.float32)\n    c6 = tf.cast(example['C6'], tf.float32)\n    c7 = tf.cast(example['C7'], tf.float32)\n    return image, [patient_overall, c1, c2, c3, c4, c5, c6, c7]# returns a dataset of (image, label) pairs\n\ndef read_unlabeled_tfrecord(example):\n    UNLABELED_TFREC_FORMAT = {\n        \"image\": tf.io.FixedLenFeature([], tf.string), # tf.string means bytestring\n    }\n    example = tf.io.parse_single_example(example, UNLABELED_TFREC_FORMAT)\n    image = decode_image(example['image'])\n    return image # returns a dataset of image(s)\n\ndef load_dataset(filenames, labeled = True, ordered = False):\n    # Read from TFRecords. For optimal performance, reading from multiple files at once and\n    # Diregarding data order. Order does not matter since we will be shuffling the data anyway\n    \n    ignore_order = tf.data.Options()\n    if not ordered:\n        ignore_order.experimental_deterministic = False # disable order, increase speed\n        \n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads = AUTO) # automatically interleaves reads from multiple files\n    dataset = dataset.with_options(ignore_order) # use data as soon as it streams in, rather than in its original order\n    dataset = dataset.map(read_labeled_tfrecord if labeled else read_unlabeled_tfrecord, num_parallel_calls = AUTO) # returns a dataset of (image, label) pairs if labeled = True or (image, id) pair if labeld = False\n    return dataset\n\ndef data_augment(img, label):\n    # data augmentation. Thanks to the dataset.prefetch(AUTO) statement in the next function (below),\n    # this happens essentially for free on TPU. Data pipeline code is executed on the \"CPU\" part\n    # of the TPU while the TPU itself is computing gradients.\n    img = tf.image.random_flip_left_right(img)\n    img = tf.image.random_saturation(img, 0.8, 1.2)\n    img = tf.image.random_contrast(img, 0.9, 1.1)\n    img = tf.image.random_brightness(img, 0.1)\n    return img, label\n\ndef get_training_dataset(dataset, do_aug=True):\n    dataset = dataset.map(data_augment, num_parallel_calls=AUTO)\n    dataset = dataset.repeat() # the training dataset must repeat for several epochs\n    dataset = dataset.batch(AUG_BATCH)\n    #if do_aug: dataset = dataset.map(transform, num_parallel_calls=AUTO) # note we put AFTER batching\n    dataset = dataset.unbatch()\n    dataset = dataset.shuffle(2048 if strategy.num_replicas_in_sync==8 else 384)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTO) # prefetch next batch while training (autotune prefetch buffer size)\n    return dataset\n\ndef get_validation_dataset(dataset, do_onehot=False, shuffle=True):\n    dataset = dataset.batch(BATCH_SIZE)\n    if do_onehot: dataset = dataset.map(onehot, num_parallel_calls=AUTO) # we must use one hot like augmented train data\n    if shuffle: dataset = dataset.shuffle(2048 if strategy.num_replicas_in_sync==8 else 384)\n    #dataset = dataset.repeat()\n    dataset = dataset.prefetch(AUTO) # prefetch next batch while training (autotune prefetch buffer size)\n    dataset = dataset.cache()\n    return dataset\n\ndef get_test_dataset(ordered=False):\n    dataset = load_dataset(TEST_FILENAMES, labeled=False, ordered=ordered)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTO) # prefetch next batch while training (autotune prefetch buffer size)\n    return dataset\n\ndef count_data_items(filenames):\n    # the number of data items is written in the name of the .tfrec files, i.e. flowers00-230.tfrec = 230 data items\n    n = [int(re.compile(r\"-([0-9]*)\\.\").search(filename).group(1)) for filename in filenames]\n    #print(n)\n    return np.sum(n)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Building our model","metadata":{}},{"cell_type":"code","source":"def get_model():\n    with strategy.scope():\n        model = tf.keras.Sequential([\n            efn.EfficientNetB7(input_shape=(*IMAGE_SIZE,3),weights='noisy-student',include_top=False),\n            tf.keras.layers.GlobalAveragePooling2D(),\n            tf.keras.layers.Dropout(0.25),\n            tf.keras.layers.Dense(256, activation='swish'),\n            tf.keras.layers.Dropout(0.25),\n            tf.keras.layers.Dense(512, activation='swish'),\n            tf.keras.layers.Dropout(0.25),\n            tf.keras.layers.Dense(8, activation='sigmoid')\n        ])\n        model.compile(\n            optimizer=tf.keras.optimizers.Adam(),\n            loss='binary_crossentropy',\n            metrics=[tf.keras.metrics.AUC(multi_label=True), 'acc'])\n        model.summary()\n    return model\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"skf = KFold(n_splits=FOLDS,shuffle=False)\nfor fold,(idxT,idxV) in enumerate(skf.split(np.arange(FOLDS))):\n    if fold==(FOLDS-1):\n        idxTT = idxT; idxVV = idxV\n        print('### Using fold',fold,'for experiments')\n    print('Fold',fold,'has TRAIN:',idxT,'VALID:',idxV)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Train loop","metadata":{}},{"cell_type":"code","source":"for fold,(idxT,idxV) in enumerate(skf.split(np.arange(FOLDS))):\n    print(); print('#'*25)\n    print('### FOLD',fold+1)\n    print('#'*25)\n    files_train = tf.io.gfile.glob([GCS_PATH_STRATIFICATED + '/train%.2i*.tfrec'%x for x in idxT])\n    files_valid = tf.io.gfile.glob([GCS_PATH_STRATIFICATED + '/train%.2i*.tfrec'%x for x in idxV])\n\n    NUM_TRAINING_IMAGES = int( count_data_items(files_train))\n    NUM_VALIDATION_IMAGES = int( count_data_items(files_valid) )\n    STEPS_PER_EPOCH = NUM_TRAINING_IMAGES // BATCH_SIZE\n    print('Dataset: {} training images, {} validation images,'.format(NUM_TRAINING_IMAGES, NUM_VALIDATION_IMAGES))\n\n    train_dataset = load_dataset(list(pd.DataFrame({'TRAINING_FILENAMES': files_train}).loc[:]['TRAINING_FILENAMES']), labeled = True)\n    val_dataset = load_dataset(list(pd.DataFrame({'VALIDATION_FILENAMES': files_valid}).loc[:]['VALIDATION_FILENAMES']), labeled = True, ordered = True)\n    sv = tf.keras.callbacks.ModelCheckpoint(\n        'fold-%i.h5'%fold, monitor='val_loss', verbose=0, save_best_only=True,\n        save_weights_only=True, mode='min', save_freq='epoch')\n    lrs = tf.keras.callbacks.ReduceLROnPlateau(\n        monitor=\"val_loss\", patience=3, min_lr=1e-5, factor=0.5, verbose=1)\n    es = tf.keras.callbacks.EarlyStopping(\n        monitor='val_loss',\n        min_delta=0,\n        patience=10,\n        verbose=1,\n        mode='auto',\n        )\n\n    model = get_model()\n    history = model.fit(\n        get_training_dataset(train_dataset), \n        steps_per_epoch = STEPS_PER_EPOCH,\n        epochs = EPOCHS,\n        callbacks = [sv, lrs, es],\n        validation_data = get_validation_dataset(val_dataset, shuffle=False),\n        verbose=2\n    )\n    del model\n    gc.collect()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Locally install eff-net and pydicom helper","metadata":{}},{"cell_type":"code","source":"shutil.copytree('/kaggle/input/efficientnet-keras-source-code', '/kaggle/efficientnet-keras-source-code/')\n# Pip install required packages\nos.system(\"pip install -q /kaggle/input/keras-applications/Keras_Applications-1.0.8-py3-none-any.whl\")\nos.system(\"pip install -q /kaggle/efficientnet-keras-source-code\")\nimport efficientnet.tfkeras as efn","metadata":{"execution":{"iopub.status.busy":"2022-10-28T05:02:44.163799Z","iopub.execute_input":"2022-10-28T05:02:44.164216Z","iopub.status.idle":"2022-10-28T05:02:44.241787Z","shell.execute_reply.started":"2022-10-28T05:02:44.164128Z","shell.execute_reply":"2022-10-28T05:02:44.240518Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BASE = '../input/rsna-2022-cervical-spine-fracture-detection'","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_df = pd.read_csv(f'{BASE}/sample_submission.csv')\ntest_df = pd.read_csv(f'{BASE}/test.csv')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"bad = np.array([['1.2.826.0.1.3680043.10197_C1', '1.2.826.0.1.3680043.10197','C1'],['1.2.826.0.1.3680043.10454_C1', '1.2.826.0.1.3680043.10454','C1'],['1.2.826.0.1.3680043.10690_C1', '1.2.826.0.1.3680043.10690','C1']], dtype=np.object)\n\ntrain_df = pd.read_csv(\"../input/rsna-2022-cervical-spine-fracture-detection/train.csv\").head(10000)\ntest_df = pd.read_csv(\"../input/rsna-2022-cervical-spine-fracture-detection/test.csv\")\nif(test_df.values[0][0] == bad[0][0]):\n    test_df = pd.DataFrame({\"row_id\": ['1.2.826.0.1.3680043.22327_C1', '1.2.826.0.1.3680043.25399_C1', '1.2.826.0.1.3680043.5876_C1'],\n                           \"StudyInstanceUID\": ['1.2.826.0.1.3680043.22327', '1.2.826.0.1.3680043.25399', '1.2.826.0.1.3680043.5876'],\n                           \"prediction_type\": [\"C1\", \"C1\", \"C1\"]})\ndirs = [\"../input/rsna-2022-cervical-spine-fracture-detection/train_images\",  \"../input/rsna-2022-cervical-spine-fracture-detection/test_images\"]\nmeans = list(train_df.mean(numeric_only=True).to_dict().values())\ntest_df","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_dir = f'{BASE}/test_images'\npatients = sorted(os.listdir(test_dir))\nlen(patients), patients[:5]","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def preprocess(stuid):\n    imgs = glob.glob(BASE+'/test_images/'+stuid+'/*')\n    n_imgs = len(imgs)\n    stride = n_imgs // (N_CHANNEL * IMGS_PER_CHANNEL)\n    pimgs = range(1, n_imgs+1, stride)\n    img_arr_b = []\n    img_arr_g = []\n    img_arr_r = []\n    for impath in pimgs:        \n        img = load_dicom(BASE+'/test_images/'+stuid+f'/{impath}.dcm')\n\n        if len(img_arr_b)<IMGS_PER_CHANNEL:img_arr_b.append(img)\n        elif len(img_arr_g)<IMGS_PER_CHANNEL:img_arr_g.append(img)\n        elif len(img_arr_r)<IMGS_PER_CHANNEL:img_arr_r.append(img)\n            \n    imgB = tileImage(img_arr_b)\n    imgG = tileImage(img_arr_g)\n    imgR = tileImage(img_arr_r)\n    img_cat = np.concatenate([imgB, imgG, imgR], axis=-1)\n    \n    if len(test_df)<5: \n        print(img_cat.shape)\n        plt.imshow((img_cat*255).astype(np.uint8)),plt.show()\n        print(np.max(img_cat), np.min(img_cat))\n    return img_cat","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred_cols = ['patient_overall']\nfor i in range(1,8): pred_cols += [f'C{i}']\npred_dict = {pred_cols[i]:i for i in range(8)}\npred_dict","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Build our Model","metadata":{}},{"cell_type":"code","source":"def get_model():\n    model = tf.keras.Sequential([\n        efn.EfficientNetB7(\n        weights=None, \n        input_shape=(512, 512, 3), include_top=False\n        ),\n        tf.keras.layers.GlobalAveragePooling2D(),\n        tf.keras.layers.Dropout(0.25),\n        tf.keras.layers.Dense(256, activation='swish'),\n        tf.keras.layers.Dropout(0.25),\n        tf.keras.layers.Dense(512, activation='swish'),\n        tf.keras.layers.Dropout(0.25),\n        tf.keras.layers.Dense(8, activation='sigmoid')\n    ])\n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(),\n        loss='binary_crossentropy',\n        metrics=[tf.keras.metrics.AUC(multi_label=True)])\n    model.summary()\n    return model","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = get_model()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Inference Loop","metadata":{}},{"cell_type":"code","source":"pred_all = np.zeros((test_df.shape[0]))\n\nfor fold in range(FOLDS):\n    print(); print('#'*25)\n    print('### FOLD',fold+1)\n    print('#'*25)\n\n    print('Loading best model...')\n    #../input/inputrsna2022splitfoldidwiseefnetb716\n    #../input/inputinputrsna2022splitfoldidwiseefnetb7161\n    model.load_weights('../input/inputinputrsna2022splitfoldidwiseefnetb7161/fold-%i.h5'%fold)\n\n    predictions = []\n    \n    pred_n2s = OrderedDict() \n    for stuid, pred_type in zip(test_df['StudyInstanceUID'], test_df['prediction_type']):\n        pred_n2s[stuid+'_'+pred_type]=-1\n\n    for stuid, pred_type in zip(test_df['StudyInstanceUID'], test_df['prediction_type']):\n        if pred_n2s[stuid+'_'+pred_type]==-1:\n            img = np.expand_dims(preprocess(stuid), axis=0)\n            preds = model.predict(img, verbose=1)[0]\n            for j, (k, v) in enumerate(pred_dict.items()):\n                pred_n2s[stuid+'_'+k]= preds[j]\n            predictions.append(pred_n2s[stuid+'_'+pred_type])     \n        else:\n            predictions.append(pred_n2s[stuid+'_'+pred_type])\n        \n    pred_all += predictions","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Submission","metadata":{}},{"cell_type":"code","source":"sub_df['fractured'] = pred_all / FOLDS\nsub_df.to_csv('submission.csv',index=False)\nsub_df","metadata":{},"execution_count":null,"outputs":[]}]}