{"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 numpy as np\nimport pandas as pd\nimport tensorflow as tf\nimport SimpleITK as sitk\nimport cv2\nimport os\nimport glob\nfrom sklearn.model_selection import train_test_split\nimport yaml\nimport datetime\nfrom skimage.transform import resize\nfrom scipy import stats\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\nimport matplotlib.pyplot as plt","metadata":{"id":"ejpyG2_OiSGq","execution":{"iopub.status.busy":"2023-03-16T01:17:41.441826Z","iopub.execute_input":"2023-03-16T01:17:41.442767Z","iopub.status.idle":"2023-03-16T01:17:47.937265Z","shell.execute_reply.started":"2023-03-16T01:17:41.442575Z","shell.execute_reply":"2023-03-16T01:17:47.936223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"input_path = \"../input/rsna-intracranial-hemorrhage-detection/rsna-intracranial-hemorrhage-detection/\"\noutput_path = \"../working/\"\ntrain_dir_processed = \"../input/rsna-processed/rsna_2022-12-20_07-18-12\"\ntrain_dir = input_path + \"/stage_2_train/\"\nclasses = 6 # 5 types & any\nbatch_size = 32\nrun_preprocessing = False\nfinding_lr = False","metadata":{"id":"hLEe1JLziSGw","execution":{"iopub.status.busy":"2023-03-16T01:17:50.078683Z","iopub.execute_input":"2023-03-16T01:17:50.079292Z","iopub.status.idle":"2023-03-16T01:17:50.085725Z","shell.execute_reply.started":"2023-03-16T01:17:50.079257Z","shell.execute_reply":"2023-03-16T01:17:50.084131Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_train_df():\n    df = pd.read_csv(input_path + \"stage_2_train.csv\")\n\n    df[\"Image\"] = df[\"ID\"].str.slice(stop=12)\n    df[\"Diagnosis\"] = df[\"ID\"].str.slice(start=13)\n    \n    df = df.drop_duplicates()\n    df = df.reset_index(drop=True)\n\n    df = df.loc[:, [\"Label\", \"Diagnosis\", \"Image\"]]\n    df = df.set_index(['Image', 'Diagnosis']).unstack(level=-1)\n    \n    return df\n\ntrain_df = get_train_df()\n\n# Only from the processed dataset\nvalid_names = set(os.listdir(train_dir_processed))\ntrain_df = train_df[train_df.index.map(lambda id: f\"{id}.npy\" in valid_names)]\n\n# # Only any column\n# train_df = train_df.iloc[:, train_df.columns.get_level_values(\"Diagnosis\") == 'any']\n\n# Equal number of both classes\ntrain_df = train_df.drop(np.random.choice(train_df[train_df[\"Label\"][\"any\"] == 0].index, len(train_df[train_df[\"Label\"][\"any\"] == 0]) - len(train_df[train_df[\"Label\"][\"any\"] == 1]), replace=False))\n# Sort to help with creating batches\ntrain_df = train_df.sort_values([('Label', 'any')])\n\n# Alternate each class to help with creating batches\ntrain_df_sorted = pd.DataFrame()\nfor i in range(0, int(len(train_df) / 2 * 0.4)): # ~43k of each class\n    train_df_sorted = train_df_sorted.append(train_df.iloc[[i]])\n    train_df_sorted = train_df_sorted.append(train_df.iloc[[i + int(len(train_df) / 2)]])\ntrain_df = train_df_sorted\n\ntrain_df","metadata":{"id":"y7J3Dx6ViSGx","execution":{"iopub.status.busy":"2023-03-16T01:17:51.774109Z","iopub.execute_input":"2023-03-16T01:17:51.774505Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_count = int(len(train_df) * 0.7)\nval_count = int(len(train_df) * 0) # Not using right now, so use it for testing instead\ntest_count = int(len(train_df) * 0.3)\n\ntrain_split = train_df.iloc[0:train_count]\nvalidation_split = train_df.iloc[train_count: train_count + val_count]\ntest_split = train_df.iloc[train_count + val_count: train_count + test_count + val_count]","metadata":{"id":"mm_7Qqf8Zla9","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_single_dcm(dcm_path):\n    reader = sitk.ImageFileReader()\n    reader.SetFileName(dcm_path)\n    reader.ReadImageInformation()\n    image = reader.Execute()\n    sitk_image = sitk.ReadImage(dcm_path)\n    return sitk_image\n\ndef windowing_imgs(sitk_image, win_dict):\n    center = win_dict['level']\n    width = win_dict['width']\n    lower_bound = center - (width) / 2\n    upper_bound = center + (width) / 2\n    image_3D_win = sitk.IntensityWindowing(sitk_image, lower_bound, upper_bound, 0, 255)\n    img_nd_array = sitk.GetArrayFromImage(image_3D_win)\n    return img_nd_array\n\n\nclass Preprocessing:\n    def __init__(self, args):\n        yaml_file = args[\"yaml_file\"]\n        with open(yaml_file, 'r') as stream:\n            try:\n                self.cfg = yaml.load(stream, Loader=yaml.Loader)\n                print(self.cfg)\n            except yaml.YAMLError as exc:\n                print(exc)\n        self.in_path = args[\"input\"]\n        self.out_path = args[\"output\"]\n\n        self.resize = self.cfg[\"preprocessing\"][\"resize\"]\n        self.windows = self.cfg[\"preprocessing\"][\"windows\"]\n        time_str = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')\n        self.out_dir = os.path.join(self.out_path, args[\"prefix\"]+\"_\"+time_str)\n        os.makedirs(self.out_dir, exist_ok=True)\n        with open(os.path.join(self.out_dir, \"run_yaml.yaml\"), \"w\") as file:\n            yaml.dump(self.cfg, file)\n\n    def do_preprocessing(self):\n        for idx, dcm_path in enumerate(train_df.iterrows()):\n            sitk_image = load_single_dcm(train_dir + dcm_path[0] + \".dcm\")\n            if self.cfg[\"preprocessing\"][\"windows\"] is not None:\n                img_full_array = self.__windowing__(sitk_image)\n                img_full_array = np.array(img_full_array, dtype='uint8')\n                img_full_array = cv2.resize(img_full_array, dsize=self.resize)\n                np.save(file=os.path.join(self.out_dir, dcm_path[0] +\".npy\"), arr=img_full_array)\n                \n                if idx % 2000 == 0:\n                    print(idx)\n\n    def __windowing__(self, sitk_image):\n        img_full_array = []\n        for win_name, win_dict in self.cfg[\"preprocessing\"][\"windows\"].items():\n            img_arr = windowing_imgs(sitk_image, win_dict)\n            img_full_array.append(img_arr)\n        img_full_array = np.array(img_full_array)\n        img_full_array = np.squeeze(img_full_array)\n        # Moveaxis to send the channel dimension to the end\n        img_full_array = np.moveaxis(img_full_array, 0, -1)\n        return img_full_array\n\nif run_preprocessing:\n    pre = Preprocessing({\"input\": input_path, \"output\": output_path, \"yaml_file\": \"../input/rsnaconfig/config.yaml\", \"prefix\": \"rsna\"});\n    pre.do_preprocessing()\n    train_dir_processed = os.path.join(input_path, pre.out_dir)","metadata":{"id":"0qYPIUBIefqb","outputId":"af975196-8474-471c-8632-d2974d711921","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DataGen(tf.keras.utils.Sequence):\n  def __init__(self, image_filenames, batch_size) :\n        self.image_filenames = image_filenames\n        self.batch_size = batch_size\n    \n  def __len__(self) :\n        return (np.ceil(len(self.image_filenames) / float(self.batch_size))).astype(int)\n  \n  def __getitem__(self, idx):\n        df_subset = self.image_filenames[idx * self.batch_size : (idx + 1) * self.batch_size]\n        df_subset = df_subset.sample(frac=1)\n        \n        X_out = []\n        Y_out = []\n\n        for ele in df_subset.iterrows():\n            arr = np.array(np.load(train_dir_processed + \"/\" + ele[0] + \".npy\"), dtype=\"float\")\n            arr /= 255.0\n            X_out.append(arr)\n            Y_out.append(ele[1])\n       \n        X = np.stack(X_out) # (batch_size, 256, 256, 3)\n        Y = np.array(Y_out) # (batch_size, classes)\n        return X, Y\n    \n  def __iter__(self):\n    for idx in range(self.__len__()):\n        yield self.__getitem__(idx)\n\ntrain_gen = DataGen(train_split, batch_size)\nvalidation_gen = DataGen(validation_split, batch_size)","metadata":{"id":"B2_0nwSBiSG0","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def custom_loss_function(y_true, y_pred):     \n    y_true_new = tf.reshape(y_true, shape = [-1])\n    y_pred_new = tf.reshape(y_pred, shape = [-1])\n\n    y_true_new = tf.expand_dims(y_true_new, axis = -1)\n    y_pred_new = tf.expand_dims(y_pred_new, axis = -1)\n\n    loss = tf.keras.losses.binary_crossentropy(y_true_new, y_pred_new, axis = -1)\n    loss = tf.math.reduce_mean(loss)\n    \n    return loss\n\ndef get_model():\n    classes = 6\n    base_model = tf.keras.applications.vgg16.VGG16(input_shape=(256, 256, 3), weights='imagenet', include_top=False, classes=classes)\n    x = base_model.output\n    x = tf.keras.layers.GlobalAveragePooling2D()(x)\n    prediction_layer = tf.keras.layers.Dense(classes)(x)\n    prediction_layer = tf.keras.layers.Lambda(lambda x: x + tf.constant(1e-7))(prediction_layer)\n    prediction_layer_3 = tf.keras.activations.sigmoid(prediction_layer)\n    model = tf.keras.Model(inputs=base_model.input, outputs=prediction_layer_3)\n    return model\n\nget_model().summary()","metadata":{"id":"dliqGwLJiSG1","outputId":"513262c3-6f4b-4ef3-bcda-7a5aaff80207","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if finding_lr:\n    from clr_script.notebookdfb5ed17de import LRFinder\n    \n    model = get_model()\n    model.compile(optimizer=tf.keras.optimizers.SGD(), loss=custom_loss_function, metrics=['accuracy', tf.keras.metrics.Precision(), tf.keras.metrics.Recall()])\n    lr_callback = LRFinder(len(train_split), batch_size, save_dir=output_path)\n    model.fit(train_gen, epochs = 1, callbacks = [lr_callback])   ","metadata":{"id":"ZG_DwA0UiSG2","outputId":"ad74b686-6229-4bcb-d283-502ace1e1464","_kg_hide-output":false,"_kg_hide-input":false,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if finding_lr:\n    LRFinder.plot_schedule_from_file(output_path, clip_beginning=25)\n    # Learning rate of min loss\n    print(np.where(lr_callback.losses == lr_callback.best_loss_)[0][0])\n    print(pow(10, lr_callback.lrs[np.where(lr_callback.losses == lr_callback.best_loss_)[0][0]]))  ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# from clr_script.notebookdfb5ed17de import OneCycleLR\n\n# # num_samples, batch_size, max_lr\n# lr_manager = OneCycleLR(len(train_split), batch_size, 0.00059181)\n\n# model = get_model()\n# history = model.fit(train_gen, epochs = 15, steps_per_epoch = 256, callbacks = [lr_manager, tf.keras.callbacks.ModelCheckpoint(output_path + 'model{epoch:03d}.h5')]) \n# np.save(file=os.path.join(output_path, \"history.npy\"), arr=history.history)\n\nmodel = get_model()\nmodel.compile(optimizer=tf.keras.optimizers.SGD(), loss=custom_loss_function, metrics=['accuracy', tf.keras.metrics.Precision(), tf.keras.metrics.Recall()])\nhistory = model.fit(train_gen, epochs = 15, steps_per_epoch = 50, callbacks = [tf.keras.callbacks.ModelCheckpoint(output_path + 'model{epoch:03d}.h5')]) \nmodel.save(os.path.join(output_path, \"model\"))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_metric(key):\n    plt.plot(history.history[key])\n    plt.ylabel(key)\n    plt.xlabel('Epoch')\n    plt.show()\n    \nplot_metric('precision')\nplot_metric('recall')\nplot_metric('accuracy')\nplot_metric('loss')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_gen = DataGen(test_split, batch_size)\ntest_y = np.array(test_split)\n\nresults = model.evaluate(test_gen)\nresults","metadata":{"id":"zP_kMo6JiSG3","outputId":"388149cd-b046-440c-db1e-075434aa52e7","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions = model.predict(test_gen)\nprint(\"Predictions:\\n\", predictions)\nprint(\"Actual:\\n\", test_y)","metadata":{"id":"0zRghTTgTuyt","outputId":"c859ae23-640f-4c6f-9fbd-be2d24b6184f","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions_binary = np.where(predictions > 0.5, 1, 0)\nprint(\"Predictions:\\n\", predictions_binary) \nprint(\"Actual:\\n\", test_y)","metadata":{"id":"y1fbdJ3cUuee","outputId":"1207d864-8891-45eb-bbd6-04d48bd2fd2c","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import multilabel_confusion_matrix\nmultilabel_confusion_matrix(test_y, predictions_binary)","metadata":{"id":"VaLiu45PB_t_","outputId":"91435a74-b6cb-46e8-a5ce-238a640edca3","trusted":true},"execution_count":null,"outputs":[]}]}