{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport os\nfrom matplotlib import pyplot as plt\nimport pydicom\nfrom tqdm import tqdm\nimport cv2\nfrom sklearn.utils import shuffle\nfrom sklearn.model_selection import train_test_split\nfrom albumentations import (\n    HorizontalFlip, IAAPerspective, ShiftScaleRotate, CLAHE, RandomRotate90,\n    Transpose, ShiftScaleRotate, Blur, OpticalDistortion, GridDistortion, HueSaturationValue,\n    IAAAdditiveGaussianNoise, GaussNoise, MotionBlur, MedianBlur, RandomBrightnessContrast, IAAPiecewiseAffine,\n    IAASharpen, IAAEmboss, Flip, OneOf, Compose,VerticalFlip\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Some Variables**"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"train_df_path='../input/rsna-intracranial-hemorrhage-detection/stage_1_train.csv'\ntest_df_path='../input/rsna-intracranial-hemorrhage-detection/stage_1_sample_submission.csv'\ntrain_img_path='../input/rsna-intracranial-hemorrhage-detection/stage_1_train_images/'\ntest_img_path='../input/rsna-intracranial-hemorrhage-detection/stage_1_test_images/'\n###########\nBATCH_SIZE=128\nres_h=res_w=96","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Read Data**"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df=pd.read_csv(train_df_path)\ntest_df=pd.read_csv(test_df_path)\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Some Stuff done with dataframe**"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Reformat CSV\n#Number of Classes=6\nclass_dict={0:'epidural',1:'intraparenchymal',2:'intraventricular',3:'subarachnoid',4:'subdural',5:'any'}\ndata_=[] #Format (img_id,class0,...,class6)\nfor ix in tqdm(range(0,len(train_df),6)):\n    tmp=[]\n    id_=train_df.loc[ix,'ID'].split('_')\n    id_=id_[0]+'_'+id_[1]\n    if id_=='ID_6431af929': #Remove corrupt file\n        continue\n    else:\n        tmp.append(id_)\n        for i in range(ix,ix+6):\n            tmp.append(train_df.loc[i,'Label'])\n        data_.append(tmp)\n#Lets Check if we got what we wanted\ndata_[:10]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Lets check the balance of labels i.e., how many images belongs to some class and and how many belong to none of them.\nids_ones=[]\nids_zeros=[]\nfor id_ in tqdm(data_):\n    if 1 in id_[1:]:\n        ids_ones.append([id_[0],id_[1:]])\n    else:\n        ids_zeros.append(id_[0])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print('Number of Images Belonging to Either of Class: {}'.format(len(ids_ones)))\nprint('Number of Images belonging to none of the class: {}'.format(len(ids_zeros)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**PRINT FEW SAMPLES**"},{"metadata":{"trusted":true},"cell_type":"code","source":"rows,cols=4,4\nfig=plt.figure(figsize=(15,15))\nfor i in range(1,rows*cols+1):\n    tmp=[]\n    img_id=data_[100+i]\n    id_=img_id[0]\n    img=pydicom.read_file(os.path.join(train_img_path,id_+'.dcm')).pixel_array\n    fig.add_subplot(rows,cols,i)\n    plt.imshow(img,cmap=plt.cm.bone)    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Now Lets separate ids and labels \ntrain_labels=np.zeros((len(data_),6))\ntrain_ids=[]\nfor ix in tqdm(range(len(data_))):\n    train_ids.append(data_[ix][0])\n    train_labels[ix]=data_[ix][1:]\ntrain_ids,train_labels=shuffle(train_ids,train_labels)\n\n#Split Dataset\nt_ids,v_ids,t_labels,v_labels=train_test_split(train_ids,train_labels,test_size=0.2)\nprint('Size of Train: {}'.format(len(t_ids)))\nprint('Size of Test: {}'.format(len(v_ids)))\ndel data_,train_ids,train_labels","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**DataGenerator**"},{"metadata":{"trusted":true},"cell_type":"code","source":"def augment_fx(image):\n    randx=np.random.randint(0,3)\n    if randx==0:\n        aug = HorizontalFlip(p=1)\n        image = aug(image=image)['image']\n        aug = RandomRotate90()\n        image = aug(image=image)['image']\n        return image\n    \n    elif randx==1:\n        aug = VerticalFlip(p=1)\n        image = aug(image=image)['image']\n        aug = Transpose() \n        image = aug(image=image)['image']\n        return image\n    \n    elif randx==2:\n        aug = VerticalFlip(p=1)\n        image = aug(image=image)['image']\n        aug = ShiftScaleRotate(p=1)\n        image = aug(image=image)['image']\n        aug = GridDistortion()\n        image = aug(image=image)['image']\n        return image\n    \n    else:\n        aug = VerticalFlip(p=1)\n        image = aug(image=image)['image']\n        aug = HueSaturationValue()\n        image = aug(image=image)['image']\n        return image","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.utils import Sequence\n\nclass CustomGenerator(Sequence):\n    #Custom Generator for Dataset\n    def __init__(self,data,batch_size,res_h,res_w,shuffle=True,image_path=train_img_path,is_train=True):\n        self.img_ids=data[0]\n        self.label_ids=data[1]\n        self.batch_size=batch_size\n        self.res_h=res_h\n        self.res_w=res_w\n        self.shuffle=shuffle\n        self.image_path=image_path\n        self.is_train=is_train\n        self.on_epoch_end()\n    \n    def __len__(self):\n        return int(np.floor(len(self.img_ids)/self.batch_size))\n    \n    def __getitem__(self,index):\n        indexes=self.indexes[index*self.batch_size:(index+1)*self.batch_size]\n        tmp_img_ids=[self.img_ids[i] for i in indexes]\n        tmp_lbl_ids=[self.label_ids[i] for i in indexes]\n        X,y=self.__data_generation(tmp_img_ids,tmp_lbl_ids)\n        return X,y\n    \n    def on_epoch_end(self):\n        self.indexes = np.arange(len(self.img_ids))\n        if self.shuffle == True:\n            np.random.shuffle(self.indexes)\n    \n    def __data_generation(self,image_ids,label_ids):\n        image_batch=np.zeros((self.batch_size,self.res_h,self.res_w,1))\n        label_batch=np.zeros((self.batch_size,6))\n        \n        # Read Images\n        for ix,img in enumerate(image_ids):\n            img=os.path.join(self.image_path,img+'.dcm')\n            img=pydicom.read_file(img).pixel_array\n            img=img.astype(np.float32)/255.\n            img=cv2.resize(img,(self.res_h,self.res_w))\n            if self.is_train:\n                img=augment_fx(img)\n            img=np.expand_dims(img,2)\n            image_batch[ix]=img\n            \n        for ix,lbl in enumerate(label_ids):\n            label_batch[ix]=lbl\n        \n        return image_batch,label_batch","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_generator=CustomGenerator([t_ids,t_labels],BATCH_SIZE,res_h,res_w)\nval_generator=CustomGenerator([v_ids,v_labels],BATCH_SIZE,res_h,res_w,is_train=False)\n#\ntrain_steps=train_generator.__len__()\nval_steps=val_generator.__len__()\nprint('Train Steps: {}'.format(train_steps))\nprint('Val Steps: {}'.format(val_steps))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Model**"},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.layers import Conv2D,Dense,Concatenate,Input,GlobalAveragePooling2D,Activation,BatchNormalization\nfrom keras.applications.densenet import DenseNet121\nfrom keras.optimizers import Adam\nfrom keras.models import Model\nfrom keras import backend as K\nimport tensorflow as tf\nfrom keras.callbacks import ModelCheckpoint,ReduceLROnPlateau\nmodel_weights='../input/densenet-keras/DenseNet-BC-121-32-no-top.h5'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def categorical_focal_loss(gamma=2., alpha=.25):\n    \"\"\"\n    Softmax version of focal loss.\n           m\n      FL = ∑  -alpha * (1 - p_o,c)^gamma * y_o,c * log(p_o,c)\n          c=1\n      where m = number of classes, c = class and o = observation\n    Parameters:\n      alpha -- the same as weighing factor in balanced cross entropy\n      gamma -- focusing parameter for modulating factor (1-p)\n    Default value:\n      gamma -- 2.0 as mentioned in the paper\n      alpha -- 0.25 as mentioned in the paper\n    References:\n        Official paper: https://arxiv.org/pdf/1708.02002.pdf\n        https://www.tensorflow.org/api_docs/python/tf/keras/backend/categorical_crossentropy\n    Usage:\n     model.compile(loss=[categorical_focal_loss(alpha=.25, gamma=2)], metrics=[\"accuracy\"], optimizer=adam)\n    \"\"\"\n    def categorical_focal_loss_fixed(y_true, y_pred):\n        \"\"\"\n        :param y_true: A tensor of the same shape as `y_pred`\n        :param y_pred: A tensor resulting from a softmax\n        :return: Output tensor.\n        \"\"\"\n\n        # Scale predictions so that the class probas of each sample sum to 1\n        y_pred /= K.sum(y_pred, axis=-1, keepdims=True)\n\n        # Clip the prediction value to prevent NaN's and Inf's\n        epsilon = K.epsilon()\n        y_pred = K.clip(y_pred, epsilon, 1. - epsilon)\n\n        # Calculate Cross Entropy\n        cross_entropy = -y_true * K.log(y_pred)\n\n        # Calculate Focal Loss\n        loss = alpha * K.pow(1 - y_pred, gamma) * cross_entropy\n\n        # Sum the losses in mini_batch\n        return K.sum(loss, axis=1)\n\n    return categorical_focal_loss_fixed","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"mc=ModelCheckpoint('../input/rsna_clf.h5',monitor='val_loss',mode='min',period=1,save_best_only=True)\nrlr=ReduceLROnPlateau(monitor='val_loss',min_lr=0.000001,factor=0.2,patience=2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"inp=Input(shape=(res_h,res_w,1))\nconv_=Conv2D(3,(5,5),strides=1,padding='same',kernel_initializer='he_normal')(inp)\nconv_=Activation('relu')(conv_)\nfeat_model=DenseNet121(weights=model_weights,include_top=False)(conv_)\ngap=GlobalAveragePooling2D()(feat_model)\nout=Dense(6,activation='sigmoid')(gap)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model=Model(inp,out)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(loss='binary_crossentropy',optimizer=Adam(0.001),metrics=['acc'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history=model.fit_generator(train_generator,steps_per_epoch=train_steps,epochs=3,\n                    validation_data=val_generator,validation_steps=val_steps,\n                   use_multiprocessing=True,callbacks=[mc,rlr])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\nacc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\nepochs = range(1, len(acc) + 1)\nplt.plot(epochs, acc, 'b',color='red', label='Training acc')\nplt.plot(epochs, val_acc, 'b',color='blue', label='Validation acc')\nplt.title('Training and validation accuracy')\nplt.legend()\nplt.figure()\nplt.plot(epochs, loss, 'b',color='red', label='Training loss')\nplt.plot(epochs, val_loss, 'b',color='blue', label='Validation loss')\nplt.title('Training and validation loss')\nplt.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Test Predictions**"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Read IDs\ntest_ids=[]\nfor ix in tqdm(range(0,len(test_df),6)):\n    tmp=[]\n    id_=test_df.loc[ix,'ID'].split('_')\n    id_=id_[0]+'_'+id_[1]\n    test_ids.append(id_)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Load Model\nmodel.load_weights('../input/rsna_clf.h5')\npreds=[]\nfor id_ in tqdm(test_ids):\n    img=os.path.join(test_img_path,id_+'.dcm')\n    img=pydicom.read_file(img).pixel_array\n    img=img.astype(np.float32)/255.\n    img=cv2.resize(img,(res_h,res_w))\n    img=np.expand_dims(img,0)\n    img=np.expand_dims(img,3)\n    preds.append(model.predict(img))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Submission File\npreds=np.reshape(preds,-1)\nsub=pd.DataFrame({'ID':test_df['ID'],'Label':preds})\nsub.to_csv('submission.csv',index=False)","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":1}