{"cells":[{"metadata":{"_kg_hide-output":true,"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"!cp -r /kaggle/input/efficientnet-keras-dataset/efficientnet_kaggle /kaggle/efficientnet_kaggle \n! pip install /kaggle/efficientnet_kaggle","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# RANZCR - Simple Grad-cam viewer\n\nBased on [Grad-CAM class activation visualization](https://github.com/keras-team/keras-io/blob/master/examples/vision/grad_cam.py)."},{"metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\n\nimport matplotlib.cm as cm\nimport plotly.express as px\nimport plotly.graph_objects as go\n\nimport tensorflow as tf\nfrom tensorflow import keras\n\nimport json\n\nimport efficientnet.tfkeras # needed by our model","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"model = tf.keras.models.load_model('../input/ranzcr-efn-models/effn_B4_TPU_2.h5')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Configurable parameters\nYou can change these to another model.\nTo get the values for `last_conv_layer_name` and `classifier_layer_names`, use\n `model.summary()` to see the names of all layers in the model.\n\n\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"\nimg_size = (380, 380)\n\nlast_conv_layer_name = \"efficientnet-b4\"\nclassifier_layer_names = [\n    \"global_average_pooling2d\",\n    \"dense\",\n]\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def make_gradcam_heatmap(\n    img_array, model, last_conv_layer_name, classifier_layer_names\n):\n    # First, we create a model that maps the input image to the activations\n    # of the last conv layer\n    last_conv_layer = model.get_layer(last_conv_layer_name)\n    #last_conv_layer_model = keras.Model(model.inputs, last_conv_layer.output)\n\n    # Second, we create a model that maps the activations of the last conv\n    # layer to the final class predictions\n    classifier_input = keras.Input(shape=last_conv_layer.output.shape[1:])\n    x = classifier_input\n    for layer_name in classifier_layer_names:\n        x = model.get_layer(layer_name)(x)\n    classifier_model = keras.Model(classifier_input, x)\n\n    # Then, we compute the gradient of the top predicted class for our input image\n    # with respect to the activations of the last conv layer\n    with tf.GradientTape() as tape:\n        # Compute activations of the last conv layer and make the tape watch it\n        #last_conv_layer_output = last_conv_layer_model(img_array)\n        last_conv_layer_output = last_conv_layer(img_array)\n        tape.watch(last_conv_layer_output)\n        # Compute class predictions\n        preds = classifier_model(last_conv_layer_output)\n        top_pred_index = tf.argmax(preds[0])\n        top_class_channel = preds[:, top_pred_index]\n\n    # This is the gradient of the top predicted class with regard to\n    # the output feature map of the last conv layer\n    grads = tape.gradient(top_class_channel, last_conv_layer_output)\n\n    # This is a vector where each entry is the mean intensity of the gradient\n    # over a specific feature map channel\n    pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))\n\n    # We multiply each channel in the feature map array\n    # by \"how important this channel is\" with regard to the top predicted class\n    last_conv_layer_output = last_conv_layer_output.numpy()[0]\n    pooled_grads = pooled_grads.numpy()\n    for i in range(pooled_grads.shape[-1]):\n        last_conv_layer_output[:, :, i] *= pooled_grads[i]\n\n    # The channel-wise mean of the resulting feature map\n    # is our heatmap of class activation\n    heatmap = np.mean(last_conv_layer_output, axis=-1)\n\n    # For visualization purpose, we will also normalize the heatmap between 0 & 1\n    heatmap = np.maximum(heatmap, 0) / np.max(heatmap)\n    return heatmap\n\ndef superimpose(image, heatmap):\n    # We rescale heatmap to a range 0-255\n    heatmap = np.uint8(255 * heatmap)\n\n    # We use jet colormap to colorize heatmap\n    jet = cm.get_cmap(\"jet\")\n\n    # We use RGB values of the colormap\n    jet_colors = jet(np.arange(256))[:, :3]\n    jet_heatmap = jet_colors[heatmap]\n\n    # We create an image with RGB colorized heatmap\n    jet_heatmap = keras.preprocessing.image.array_to_img(jet_heatmap)\n    jet_heatmap = jet_heatmap.resize((image.shape[1], image.shape[0]))\n    jet_heatmap = keras.preprocessing.image.img_to_array(jet_heatmap)\n\n    # Superimpose the heatmap on original image\n    superimposed_img = jet_heatmap * 0.4 + image / 2\n    superimposed_img = keras.preprocessing.image.array_to_img(superimposed_img)\n    \n    return(superimposed_img)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-output":false,"_kg_hide-input":true},"cell_type":"code","source":"def read_image(file):\n    return(tf.image.decode_jpeg(tf.io.read_file(file), channels=3))\n\ndef preprocess_image(image):\n    image = tf.image.resize(image, img_size)\n    return(image / 255.0)\n\n\ndef plot(UID, img, r, annotations, preds):\n    fig = px.imshow(img, height=800)\n    if annotations.isnull().values.any() == False:\n        for i, ann in annotations.iterrows():\n            df = pd.DataFrame(json.loads(ann.data),columns=['x', 'y'])\n            fig.add_trace(go.Scatter(x=df.x, y=df.y, name=ann.label))\n    \n    title = 'L: '\n    for name, value in r.iteritems():\n        if value == 1:\n            title += ' ' + name\n\n    title += ' P:'\n    for (name, _), pred in zip(r.iteritems(), preds):\n        title += f' {name}: {pred:.1f}'\n\n\n    fig.update_layout(title_text=UID, xaxis_title=title) \n    fig.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"df_train = pd.read_csv('../input/ranzcr-clip-catheter-line-classification/train.csv')\ndf_train.columns = ['UID','ETTA','ETTB','ETTN','NGTA','NGTB','NGTI','NGTN','CVCA','CVCB','CVCN','SGCP','PID']\ndf_annotations = pd.read_csv('../input/ranzcr-clip-catheter-line-classification/train_annotations.csv')\ndf_annotations.columns = ['UID','label','data']\n\ndef xray(query):\n    df = df_train.query(query).sample(1)\n    an = df.join(df_annotations.set_index('UID'),how='left',on='UID')\n    image = read_image('../input/ranzcr-clip-catheter-line-classification/train/' + df.iloc[0].UID + '.jpg')\n    \n    # Prepare image\n    img_array = np.expand_dims(preprocess_image(image), axis=0)\n\n    # Print what the top predicted class is\n    preds = model.predict(img_array)\n    \n    # Generate class activation heatmap\n    heatmap = make_gradcam_heatmap(img_array, model, last_conv_layer_name, classifier_layer_names)\n\n    image = superimpose(image, heatmap)\n    plot(df.iloc[0].UID, image, df.iloc[0,1:12], an[['label','data']], preds[0])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# examples:\n# xray('CVCA == 1') # -- view a random X-Ray with CVC abnormal\n# xray(\"UID == '1.2.826.0.1.3680043.8.498.59757398491099579448057921213132792160'\") # -- view a specific X-Ray by UID\n# xray('SGCP == 1') # -- view a random X-Ray with Swan Ganz catheter\n# xray('SGCP == 1 and CVCA == 1') # -- view a random X-Ray with Swan Ganz catheter and CVC abnormal\n\nxray(\"UID == '1.2.826.0.1.3680043.8.498.80711700719709146740499380132484057461'\")\n","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":4}