cameron-d/CNN_Intermediate_Activations_Visualizer
0
1import keras2from keras import layers3import gradio as gr4import numpy as np5from PIL import Image6import io7import contextlib8 9# Load model10model = keras.models.load_model("dogs_and_cats_CNN.keras")11 12def get_model_summary(model):13 """Return the model summary as a string."""14 stream = io.StringIO()15 with contextlib.redirect_stdout(stream):16 model.summary()17 summary_str = stream.getvalue()18 return summary_str19 20def get_img_array(image, target_size):21 """Resize the image and return it as an array."""22 image = image.resize(target_size)23 array = keras.utils.img_to_array(image)24 array = np.expand_dims(array, axis=0)25 return array26 27def predict(image):28 img_tensor = get_img_array(image, target_size=(180, 180))29 30 # predict class31 predictions = model.predict(img_tensor)32 if predictions[0][0] > 0.5:33 predicted_class = "Dog"34 confidence = predictions[0][0]35 else:36 predicted_class = "Cat"37 confidence = 1 - predictions[0][0]38 39 prediction_text = f"## **Prediction:** {predicted_class} **Confidence:** {confidence:.2%}"40 41 42 # Collect convolution and pooling layers43 layer_outputs = []44 layer_names = []45 for layer in model.layers:46 if isinstance(layer, (layers.Conv2D, layers.MaxPooling2D)):47 # If a layer of a convolution or max pooling layers, append it's outputs to the visualization48 layer_outputs.append(layer.output)49 layer_names.append(layer.name)50 51 activation_model = keras.Model(inputs=model.input, outputs=layer_outputs)52 activations = activation_model.predict(img_tensor)53 54 # Build visualization grids for each layer55 images = []56 images_per_row = 1657 58 for layer_name, layer_activation in zip(layer_names, activations):59 n_features = layer_activation.shape[-1]60 size = layer_activation.shape[1]61 n_cols = max(1, n_features // images_per_row)62 display_grid = np.zeros(63 ((size + 1) * n_cols - 1, images_per_row * (size + 1) - 1)64 )65 66 for col in range(n_cols):67 for row in range(images_per_row):68 channel_index = col * images_per_row + row69 if channel_index >= n_features:70 break71 channel_image = layer_activation[0, :, :, channel_index].copy()72 if channel_image.std() > 1e-6:73 channel_image -= channel_image.mean()74 channel_image /= channel_image.std()75 channel_image *= 6476 channel_image += 12877 channel_image = np.clip(channel_image, 0, 255).astype("uint8")78 display_grid[79 col * (size + 1):(col + 1) * size + col,80 row * (size + 1):(row + 1) * size + row,81 ] = channel_image82 83 display_grid = display_grid / 255.084 images.append((display_grid, layer_name))85 86 summary_text = get_model_summary(model)87 return images, summary_text, prediction_text88 89 90 91# Gradio interface with examples92with gr.Blocks() as demo:93 gr.Markdown("# CNN Intermediate Activations Visualizer")94 gr.Markdown("Visualizes activations of all convolutional and pooling layers and displays the model summary.")95 gr.Markdown("Model is trained on a subset of kaggle's dogs vs cats dataset: https://www.kaggle.com/c/dogs-vs-cats/data")96 gr.Markdown("Adapted from: https://deeplearningwithpython.io/chapters/chapter10_interpreting-what-convnets-learn/#visualizing-intermediate-activations")97 98 with gr.Row():99 with gr.Column():100 input_image = gr.Image(type="pil", label="Upload an image")101 submit_btn = gr.Button("Analyze")102 103 # Example images104 gr.Examples(105 examples=[106 ["images/cat_1.jpg"],107 ["images/dog.jpg"],108 ["images/cat_2.jpg"],109 ["images/cat_and_dog.jpg"]110 ],111 inputs=input_image,112 label="Try an example:"113 )114 115 with gr.Column():116 output_gallery = gr.Gallery(label="Layer Activations", show_label=True, columns=1)117 output_prediction = gr.Markdown(label="Prediction")118 119 gr.Markdown("As you go deeper through the neural network, the activations become more abstract and relate more to the class prediction")120 121 output_summary = gr.Textbox(label="Model Summary", lines=20)122 123 124 submit_btn.click(125 fn=predict,126 inputs=input_image,127 outputs=[output_gallery, output_summary, output_prediction]128 )129 130demo.launch()131 