{"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":"!pip install tf_keras_vis tensorflow lime","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-12-08T01:51:38.418860Z","iopub.execute_input":"2022-12-08T01:51:38.419271Z","iopub.status.idle":"2022-12-08T01:51:50.267591Z","shell.execute_reply.started":"2022-12-08T01:51:38.419182Z","shell.execute_reply":"2022-12-08T01:51:50.265826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping\nfrom tf_keras_vis.saliency import Saliency\nfrom tf_keras_vis.utils.model_modifiers import ReplaceToLinear\nfrom tf_keras_vis.utils.scores import CategoricalScore, BinaryScore\nfrom tf_keras_vis.gradcam_plus_plus import GradcamPlusPlus\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\nfrom skimage.transform import resize\nimport matplotlib.pyplot as plt\nimport imageio.v3 as iio\nimport pandas as pd\nimport numpy as np\nimport time\nimport cv2\nimport os\n# Plot libs\nfrom lime import lime_image\nfrom skimage.segmentation import felzenszwalb, slic, mark_boundaries\nimport matplotlib.pyplot as plt\nfrom matplotlib import cm\nfrom mpl_toolkits.axes_grid1 import make_axes_locatable\nimport seaborn as sns","metadata":{"execution":{"iopub.status.busy":"2022-12-08T01:51:50.269833Z","iopub.execute_input":"2022-12-08T01:51:50.271357Z","iopub.status.idle":"2022-12-08T01:51:53.322718Z","shell.execute_reply.started":"2022-12-08T01:51:50.271270Z","shell.execute_reply":"2022-12-08T01:51:53.321597Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(\"/kaggle/input/siim-isic-melanoma-classification/train.csv\")","metadata":{"execution":{"iopub.status.busy":"2022-12-08T01:51:53.324578Z","iopub.execute_input":"2022-12-08T01:51:53.325866Z","iopub.status.idle":"2022-12-08T01:51:53.390180Z","shell.execute_reply.started":"2022-12-08T01:51:53.325816Z","shell.execute_reply":"2022-12-08T01:51:53.388966Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_clean_df(filename, filepath):\n    \"\"\"\n    Função utilizada para remover as colunas não utilizadas e padronizar o DataFrame.\n    Parametros\n    ----------\n        filepath : str\n            Caminho até o arquivo contendo os metadados das instâncias.\n    Returns\n    -------\n    DataFrame\n        DataFrame contendo as informações necessárias para o treinamento.\n    \"\"\"\n    df = pd.read_csv(filename)\n    df = df[[\"image_name\", \"benign_malignant\"]]\n    columns = [\"image\", \"label\"]\n    df.columns = columns\n    df[\"image\"] = df[\"image\"].apply(lambda x: f\"{filepath}/{x}.jpg\")\n\n    return df\n\n\ndef get_data_iterator(df, img_size=(224, 224), mode=\"binary\"):\n    \"\"\"\n    Função utilizada para gerar um DataFrameIterator com as instâncias a serem explicadas.\n    Parametros\n    ----------\n        df : pd.DataFrame\n            DataFrame contendo as instâncias.\n        img_size : tuple\n            Tupla contendo as dimensões das imagens\n        mode: str\n            String contendo o class_mode para gerar o DataFrameIterator\n    Returns\n    -------\n        DataFrameIterator\n            Um iterador contendo tanto as instâncias.\n    \"\"\"\n\n    gen = ImageDataGenerator(rescale=1.0 / 255)\n    data_iterator = gen.flow_from_dataframe(\n        df,\n        x_col=\"image\",\n        y_col=\"label\",\n        target_size=img_size,\n        class_mode=mode,\n        color_mode=\"rgb\",\n        shuffle=False,\n        batch_size=df.shape[0],\n    )\n\n    return data_iterator","metadata":{"execution":{"iopub.status.busy":"2022-12-08T01:51:53.393725Z","iopub.execute_input":"2022-12-08T01:51:53.394142Z","iopub.status.idle":"2022-12-08T01:51:53.403612Z","shell.execute_reply.started":"2022-12-08T01:51:53.394105Z","shell.execute_reply":"2022-12-08T01:51:53.402359Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = get_clean_df(\"/kaggle/input/siim-isic-melanoma-classification/train.csv\", \"/kaggle/input/siim-isic-melanoma-classification/jpeg/train\")\ndf[\"image\"].iloc[0]","metadata":{"execution":{"iopub.status.busy":"2022-12-08T01:51:53.405509Z","iopub.execute_input":"2022-12-08T01:51:53.405997Z","iopub.status.idle":"2022-12-08T01:51:53.498253Z","shell.execute_reply.started":"2022-12-08T01:51:53.405961Z","shell.execute_reply":"2022-12-08T01:51:53.496952Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"malignant_df = df.loc[df[\"label\"] == \"malignant\"].sample(400)\nbenign_df =  df.loc[df[\"label\"] == \"benign\"].sample(malignant_df.shape[0])\nprint(benign_df[\"label\"].value_counts(),\"\\n\", malignant_df[\"label\"].value_counts())","metadata":{"execution":{"iopub.status.busy":"2022-12-08T01:51:53.499567Z","iopub.execute_input":"2022-12-08T01:51:53.500039Z","iopub.status.idle":"2022-12-08T01:51:53.521926Z","shell.execute_reply.started":"2022-12-08T01:51:53.500004Z","shell.execute_reply":"2022-12-08T01:51:53.520449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_final = pd.concat([malignant_df, benign_df],ignore_index=True)\ndf_final","metadata":{"execution":{"iopub.status.busy":"2022-12-08T01:51:53.523868Z","iopub.execute_input":"2022-12-08T01:51:53.524669Z","iopub.status.idle":"2022-12-08T01:51:53.543601Z","shell.execute_reply.started":"2022-12-08T01:51:53.524617Z","shell.execute_reply":"2022-12-08T01:51:53.541984Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_iter = get_data_iterator(df_final)","metadata":{"execution":{"iopub.status.busy":"2022-12-08T01:51:53.545407Z","iopub.execute_input":"2022-12-08T01:51:53.545927Z","iopub.status.idle":"2022-12-08T01:51:54.728075Z","shell.execute_reply.started":"2022-12-08T01:51:53.545874Z","shell.execute_reply":"2022-12-08T01:51:54.726755Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_hit_miss(image_gen, preds, mode=\"binary\"):\n    \"\"\"\n    Função utilizada para pegar os erros e acertos das predições.\n    Parametros\n    ----------\n        image_gen : DirectoryIterator, DataFrameIterator\n            Iterador das imagens usadas na predição\n        preds : np.ndarray\n            Predições geradas pelo modelo\n    Returns\n    -------\n    dict\n        Um dicionário contendo todos os erros\n    dict\n        Outro dicionário contendo todos os acertos\n    \"\"\"\n\n    labels = image_gen.classes\n    predicts = []\n    file_paths = image_gen.filepaths\n    map_class = {v: k for k, v in image_gen.class_indices.items()}\n    misses_list = []\n    misses_true_class = []\n    misses_pred_class = []\n    hit_list = []\n    hit_pred_class = []\n\n    for i, p in enumerate(preds):\n        if mode == \"binary\":\n            pred_index = 1 if p[0] >= 0.5 else 0\n        else:\n            pred_index = np.argmax[p]\n        predicts.append(pred_index)\n        true_index = labels[i]\n        if pred_index != true_index:\n            misses_list.append(file_paths[i])\n            misses_true_class.append(map_class[true_index])\n            misses_pred_class.append(map_class[pred_index])\n        else:\n            hit_list.append(file_paths[i])\n            hit_pred_class.append(map_class[pred_index])\n    cm = confusion_matrix(labels, predicts)\n    disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=np.array([\"benign\", \"malignant\"]))\n    disp.plot(cmap=plt.cm.Blues)\n\n    plt.show()\n    return (\n        {\n            \"hits\": hit_list,\n            \"hits_pred\": hit_pred_class,\n        },\n        {\n            \"misses\": misses_list,\n            \"misses_pred\": misses_pred_class,\n            \"misses_true\": misses_true_class,\n        },\n    )\ndef make_gradCAM_vis(\n    vis_ds,\n    model,\n    score=\"binary\",\n    gradcam=None,\n    explanations=10,\n    prefix=\"GradCAM\",\n    out_dir=None,\n    color=None\n):\n    \"\"\"\n    Função utilizada para gerar explicações usando GradCAM.\n    Parametros\n    ----------\n        vis_ds: DirectoryIterator, DataFrameIterator\n            Iterador das instâncias a serem explicadas.\n        model: tf.keras.Model\n            Modelo treinado a ser explicado\n        gradcam: GradcamPlusPlus\n            Gerador das explicações\n        explanations: int\n            Quantidade de explicações a serem geradas.\n        prefix: str\n            Nome que será colocado antes do nome da instância ao salvar\n        out_dir:\n            Diretório onde será armazenado as explicações.\n    \"\"\"\n    map_class = {v: k for k, v in vis_ds.class_indices.items()}\n\n    if gradcam is None:\n        gradcam = GradcamPlusPlus(model, clone=True)\n\n    images, labels = vis_ds.next()\n\n    explanations = explanations if explanations < len(images) else len(images)\n\n    images, labels = images[:explanations], labels[:explanations]\n    if score == \"binary\":\n        score = BinaryScore(list(labels))\n    else:\n        score = CategoricalScore(list(labels))\n\n    cam = gradcam(score, images)\n\n    for j in range(explanations):\n        heatmap = np.uint8(cm.jet(cam[j])[..., :3] * 255)\n        fig, ax = plt.subplots()\n        ax.imshow(images[j])\n        ax.imshow(heatmap, cmap=\"jet\", alpha=0.35)\n\n        ax.set_title(f\"Predicted:{map_class[labels[j]]}\", color=color)\n        plt.tight_layout()\n        fig.savefig(\n            f\"./{out_dir}/{prefix}_{vis_ds.filenames[j].split('/')[-1].split('.')[0]}\"\n        )\n        plt.show()\n        plt.close(fig)","metadata":{"execution":{"iopub.status.busy":"2022-12-08T01:51:54.729616Z","iopub.execute_input":"2022-12-08T01:51:54.730292Z","iopub.status.idle":"2022-12-08T01:51:54.748061Z","shell.execute_reply.started":"2022-12-08T01:51:54.730254Z","shell.execute_reply":"2022-12-08T01:51:54.746671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = tf.keras.models.load_model(\"/kaggle/input/trained-models/Xception.h5\")","metadata":{"execution":{"iopub.status.busy":"2022-12-08T01:51:54.749708Z","iopub.execute_input":"2022-12-08T01:51:54.750418Z","iopub.status.idle":"2022-12-08T01:51:59.817206Z","shell.execute_reply.started":"2022-12-08T01:51:54.750381Z","shell.execute_reply":"2022-12-08T01:51:59.815997Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"preds = model.predict(df_iter)","metadata":{"execution":{"iopub.status.busy":"2022-12-08T01:51:59.819339Z","iopub.execute_input":"2022-12-08T01:51:59.819708Z","iopub.status.idle":"2022-12-08T01:57:09.711249Z","shell.execute_reply.started":"2022-12-08T01:51:59.819654Z","shell.execute_reply":"2022-12-08T01:57:09.710128Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"hits_dict, misses_dict = get_hit_miss(df_iter, preds)\nmisses_df = pd.DataFrame(zip(misses_dict[\"misses\"], misses_dict[\"misses_pred\"]), columns=[\"image\", \"label\"])\nprint(misses_df['label'].value_counts())\nhits_df = pd.DataFrame(zip(hits_dict[\"hits\"], hits_dict[\"hits_pred\"]), columns=[\"image\", \"label\"])\nprint(hits_df['label'].value_counts())","metadata":{"execution":{"iopub.status.busy":"2022-12-08T01:57:09.713056Z","iopub.execute_input":"2022-12-08T01:57:09.713607Z","iopub.status.idle":"2022-12-08T01:57:10.230621Z","shell.execute_reply.started":"2022-12-08T01:57:09.713573Z","shell.execute_reply":"2022-12-08T01:57:10.229226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"hits_iter = get_data_iterator(hits_df)","metadata":{"execution":{"iopub.status.busy":"2022-12-08T02:29:02.550201Z","iopub.execute_input":"2022-12-08T02:29:02.552532Z","iopub.status.idle":"2022-12-08T02:29:02.993880Z","shell.execute_reply.started":"2022-12-08T02:29:02.552465Z","shell.execute_reply":"2022-12-08T02:29:02.992262Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"misses_iter.reset()","metadata":{"execution":{"iopub.status.busy":"2022-12-08T02:29:04.864537Z","iopub.execute_input":"2022-12-08T02:29:04.865240Z","iopub.status.idle":"2022-12-08T02:29:05.012393Z","shell.execute_reply.started":"2022-12-08T02:29:04.865202Z","shell.execute_reply":"2022-12-08T02:29:05.010246Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"make_gradCAM_vis(misses_iter, model,prefix=\"Xception-misse\",out_dir=\"./gradCAM/Xception\",explanations=30, color=\"red\")","metadata":{"execution":{"iopub.status.busy":"2022-12-08T01:57:10.627746Z","iopub.status.idle":"2022-12-08T01:57:10.628161Z","shell.execute_reply.started":"2022-12-08T01:57:10.627963Z","shell.execute_reply":"2022-12-08T01:57:10.627984Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"hits_iter.reset()","metadata":{"execution":{"iopub.status.busy":"2022-12-08T01:57:10.630255Z","iopub.status.idle":"2022-12-08T01:57:10.630668Z","shell.execute_reply.started":"2022-12-08T01:57:10.630473Z","shell.execute_reply":"2022-12-08T01:57:10.630492Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"make_gradCAM_vis(hits_iter, model,prefix=\"Xception-hit\",out_dir=\"./gradCAM/Xception\",explanations=30, color=\"green\")","metadata":{"execution":{"iopub.status.busy":"2022-12-08T02:29:09.052078Z","iopub.execute_input":"2022-12-08T02:29:09.052672Z","iopub.status.idle":"2022-12-08T02:31:11.496344Z","shell.execute_reply.started":"2022-12-08T02:29:09.052624Z","shell.execute_reply":"2022-12-08T02:31:11.494913Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nshutil.make_archive(\"grandCAM\", 'zip', \"/kaggle/working/gradCAM\")","metadata":{"execution":{"iopub.status.busy":"2022-12-08T02:32:18.786897Z","iopub.execute_input":"2022-12-08T02:32:18.787382Z","iopub.status.idle":"2022-12-08T02:32:20.377090Z","shell.execute_reply.started":"2022-12-08T02:32:18.787342Z","shell.execute_reply":"2022-12-08T02:32:20.375660Z"},"trusted":true},"execution_count":null,"outputs":[]}]}