{"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":"### **import dependencies**","metadata":{}},{"cell_type":"code","source":"import os\nimport shutil\nimport cv2\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nfrom tensorflow.keras.applications.vgg16 import preprocess_input, VGG16\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\nfrom sklearn.model_selection import train_test_split\nimport yaml\n\nfrom kaggle_secrets import UserSecretsClient\nimport wandb\nfrom wandb.keras import WandbCallback\n\nimport cv2\nimport pydicom\n\nfrom pathlib import Path\nfrom tqdm.auto import tqdm","metadata":{"execution":{"iopub.status.busy":"2021-06-16T20:15:39.468963Z","iopub.execute_input":"2021-06-16T20:15:39.469416Z","iopub.status.idle":"2021-06-16T20:15:47.534957Z","shell.execute_reply.started":"2021-06-16T20:15:39.469385Z","shell.execute_reply":"2021-06-16T20:15:47.533955Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **configuration and initialization**","metadata":{}},{"cell_type":"code","source":"SIIM_COVID19_DETECTION_DIR = '/kaggle/input/siim-covid19-detection/'\nPART0_RESIZED_DIR = '/kaggle/input/part0-siim-covid19-first-look-resized-512px/'\n\n\nTEMP_DIR = '/kaggle/temp/'\n\nINPUT_DIR = PART0_RESIZED_DIR+'data/'\n\nOUTPUT_DIR = DATASET_DIR = TEMP_DIR+'data/'\nTRAIN_DIR = DATASET_DIR + 'train/'\nTA_DIR = TRAIN_DIR+'ta/'\nIA_DIR = TRAIN_DIR+'ia/'\nAA_DIR = TRAIN_DIR+'aa/'\nNP_DIR = TRAIN_DIR+'np/'\n\nWORKING_DIR = '/kaggle/working/'\n\nWANDB_PROJECT_NAME = 'project8-kaggle-covid19'\nWANDB_ENTITY_NAME = ''\n\nTRAIN_IMAGE_LEVEL_PATH = SIIM_COVID19_DETECTION_DIR+'train_image_level.csv'\nTRAIN_STUDY_LEVEL_PATH = SIIM_COVID19_DETECTION_DIR+'train_study_level.csv'\nMETA_PATH = PART0_RESIZED_DIR+'meta.csv'\n\nBATCH_SIZE = 32\nEPOCHS = 25\nIMG_SIZE = WIDTH = HEIGHT = 224\nLEARNING_RATE = 0.00008\n\nINTERPOLATION = cv2.INTER_LANCZOS4","metadata":{"execution":{"iopub.status.busy":"2021-06-16T20:15:47.536956Z","iopub.execute_input":"2021-06-16T20:15:47.537332Z","iopub.status.idle":"2021-06-16T20:15:47.544916Z","shell.execute_reply.started":"2021-06-16T20:15:47.537296Z","shell.execute_reply":"2021-06-16T20:15:47.543534Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"user_secrets = UserSecretsClient()\nsecret_value_0 = user_secrets.get_secret(\"WANDB_API_KEY2\")\nos.environ['WANDB_API_KEY'] = secret_value_0\n\nos.makedirs(TRAIN_DIR, exist_ok=True)\n\n%cd ../../\n%ls","metadata":{"execution":{"iopub.status.busy":"2021-06-16T20:15:47.547340Z","iopub.execute_input":"2021-06-16T20:15:47.547765Z","iopub.status.idle":"2021-06-16T20:15:48.662953Z","shell.execute_reply.started":"2021-06-16T20:15:47.547721Z","shell.execute_reply":"2021-06-16T20:15:48.661661Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"wandb.login()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T20:15:48.664910Z","iopub.execute_input":"2021-06-16T20:15:48.665308Z","iopub.status.idle":"2021-06-16T20:15:48.916849Z","shell.execute_reply.started":"2021-06-16T20:15:48.665261Z","shell.execute_reply":"2021-06-16T20:15:48.915030Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **load train/study csv file and merge**","metadata":{}},{"cell_type":"code","source":"df_train_image_level = pd.read_csv(TRAIN_IMAGE_LEVEL_PATH)\ndf_train_study_level = pd.read_csv(TRAIN_STUDY_LEVEL_PATH)\n\ndf_train_image_level['id'] = df_train_image_level.apply(lambda row: row.id.split('_')[0], axis=1)\ndf_train_image_level['path'] = df_train_image_level.apply(lambda row: INPUT_DIR+row.id+'.jpg', axis=1)\ndf_train_image_level['image_level'] = df_train_image_level.apply(lambda row: row.label.split(' ')[0], axis=1)\n\ndf_train_study_level['id'] = df_train_study_level.apply(lambda row: row.id.split('_')[0], axis=1)\ndf_train_study_level.columns = ['StudyInstanceUID', 'Negative for Pneumonia', 'Typical Appearance', 'Indeterminate Appearance', 'Atypical Appearance']","metadata":{"execution":{"iopub.status.busy":"2021-06-16T20:15:48.918751Z","iopub.execute_input":"2021-06-16T20:15:48.919328Z","iopub.status.idle":"2021-06-16T20:15:49.306363Z","shell.execute_reply.started":"2021-06-16T20:15:48.919280Z","shell.execute_reply":"2021-06-16T20:15:49.305519Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train_image_level = df_train_image_level.merge(df_train_study_level, on='StudyInstanceUID',how=\"left\")\ndf_train_image_level = df_train_image_level[['id','StudyInstanceUID','path','Negative for Pneumonia','Typical Appearance','Indeterminate Appearance','Atypical Appearance']]\ndf_train_image_level = df_train_image_level.dropna()\ndf_train_image_level = df_train_image_level[~df_train_image_level.duplicated(subset=['StudyInstanceUID'], keep='first')]\ndf_train_image_level = df_train_image_level.reset_index(drop=True)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T20:15:49.307838Z","iopub.execute_input":"2021-06-16T20:15:49.308126Z","iopub.status.idle":"2021-06-16T20:15:49.366238Z","shell.execute_reply.started":"2021-06-16T20:15:49.308097Z","shell.execute_reply":"2021-06-16T20:15:49.365097Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **classification study with VGG16**","metadata":{}},{"cell_type":"markdown","source":"**create dir and copy train images in 4 dir classes**","metadata":{}},{"cell_type":"code","source":"[os.makedirs(dir, exist_ok=True) for dir in [TA_DIR,IA_DIR,AA_DIR,NP_DIR]]\nfor i in tqdm(range(len(df_train_image_level))):\n    row = df_train_image_level.loc[i]\n    if row['Typical Appearance']:\n        shutil.copy(row.path, f'{TA_DIR}{row.id}.jpg')\n    elif row['Indeterminate Appearance']:\n        shutil.copy(row.path, f'{IA_DIR}{row.id}.jpg')\n    elif row['Atypical Appearance']:\n        shutil.copy(row.path, f'{AA_DIR}{row.id}.jpg')\n    elif row['Negative for Pneumonia']:\n        shutil.copy(row.path, f'{NP_DIR}{row.id}.jpg')\n    else:\n        print('Error: check df_train_image_level')","metadata":{"execution":{"iopub.status.busy":"2021-06-16T20:19:46.727798Z","iopub.execute_input":"2021-06-16T20:19:46.728285Z","iopub.status.idle":"2021-06-16T20:19:52.291750Z","shell.execute_reply.started":"2021-06-16T20:19:46.728252Z","shell.execute_reply":"2021-06-16T20:19:52.290263Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**datagen / data augmentation**","metadata":{}},{"cell_type":"code","source":"datagen_kwargs = dict(validation_split=.20,\n                      preprocessing_function=preprocess_input\n                     )\ndataflow_kwargs = dict(target_size=(IMG_SIZE, IMG_SIZE),\n                       batch_size=BATCH_SIZE,\n                       interpolation=\"lanczos\"\n                      )\n\nvalid_datagen = tf.keras.preprocessing.image.ImageDataGenerator(**datagen_kwargs)\nvalid_generator = valid_datagen.flow_from_directory(TRAIN_DIR,\n                                                    subset=\"validation\",\n                                                    shuffle=False,\n                                                    **dataflow_kwargs)\n\ntrain_datagen = tf.keras.preprocessing.image.ImageDataGenerator(\n    rotation_range=40,\n    horizontal_flip=True,\n    width_shift_range=0.2,\n    height_shift_range=0.2,\n    shear_range=0.2,\n    zoom_range=0.2,\n    **datagen_kwargs)\ntrain_generator = train_datagen.flow_from_directory(TRAIN_DIR,\n                                                    subset=\"training\",\n                                                    shuffle=True,\n                                                    **dataflow_kwargs)\n\nprint('classes :', train_generator.class_indices)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**training model vgg16**","metadata":{}},{"cell_type":"code","source":"tf.keras.backend.clear_session()\n\nwandb.init(project=\"project8-kaggle-covid19\")\nconfig = wandb.config \nconfig.learning_rate = LEARNING_RATE\nconfig.batch_size = BATCH_SIZE\n\nvgg_model = VGG16(weights='imagenet', include_top=False, input_shape=(224, 224, 3))\n\nfor layer in vgg_model.layers[:15]:\n    layer.trainable = False\n\nfor i, layer in enumerate(vgg_model.layers):\n    print(i, layer.name, layer.trainable)\n\nx = vgg_model.output\nx = tf.keras.layers.Flatten()(x)\nx = tf.keras.layers.Dense(32, activation='relu')(x)\nx = tf.keras.layers.Dense(16, activation='relu')(x)\nx = tf.keras.layers.Dense(train_generator.num_classes, activation='softmax')(x) \n\nmodel = tf.keras.Model(inputs=vgg_model.input, outputs=x)\n\nmodel.build((None, IMG_SIZE, IMG_SIZE, 3))\n\nmodel.summary()\n\nmodel.compile(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=LEARNING_RATE),\n    loss=tf.keras.losses.CategoricalCrossentropy(),\n    metrics=['accuracy'])\n\nsteps_per_epoch = train_generator.samples // train_generator.batch_size\nvalidation_steps = valid_generator.samples // valid_generator.batch_size\n\nhist = model.fit(\n    train_generator,\n    epochs=EPOCHS,\n    steps_per_epoch=steps_per_epoch,\n    validation_data=valid_generator,\n    validation_steps=validation_steps,\n    callbacks=[WandbCallback(),\n              tf.keras.callbacks.EarlyStopping(patience=5, restore_best_weights=True)\n              ]).history","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_confusion_matrix(generator, model, figsize=(15,15)):\n    n_steps = len(generator)\n    y_true = None\n    y_pred = None\n\n    # evaluation\n    for step in range(n_steps):\n        imgs, labels = next(generator)\n        preds = model.predict(imgs)\n        preds = np.argmax(preds, axis=1)\n        if y_true is None:\n            y_true = labels\n        if y_pred is None:\n            y_pred = preds\n        else:\n            y_true = np.concatenate((y_true, labels))\n            y_pred = np.concatenate((y_pred, preds))\n\n    y_pred = y_pred.astype(np.float64)\n    y_true = y_true.astype(np.float64)\n\n    # conversion inverse pour multiclass\n    categories = list(generator.class_indices.keys())\n    categories_idx = [[element] for element in list(generator.class_indices.values())]\n    onehot_encoder = OneHotEncoder(sparse=False)\n    onehot_encoder.fit(categories_idx)\n    y_true = onehot_encoder.inverse_transform(y_true)\n    y_true = [element[0] for element in y_true]\n\n    fig, ax = plt.subplots(figsize=figsize)\n    cm = ConfusionMatrixDisplay(confusion_matrix(y_true, y_pred),\n                           display_labels=categories\n                          ).plot(ax=ax,\n                                 colorbar=None,\n                                 cmap=plt.cm.Blues)\n    \n    # ameliore l'affichage des labels en pivotants\n    for label in ax.get_xticklabels():\n        label.set_ha(\"right\")\n        label.set_rotation(45)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_confusion_matrix(valid_generator, model, figsize=(15,15))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **export**","metadata":{}},{"cell_type":"code","source":"%cd {WORKING_DIR}\nmodel.save('vgg16')\n%cd ../../","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}