CoolFace
Apppublic

Niharmahesh/Decoding-CNN

sourceHugging Facemitupdated 2y agoView on Hugging Face
0likes
app.py160 linesDownload Raw Back to root
1import streamlit as st2import numpy as np3from PIL import Image, ImageDraw, ImageFont4from tensorflow.keras.models import Sequential5from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dropout, Layer6from tensorflow.keras.layers import LeakyReLU, ELU7import imageio8import json9from streamlit_lottie import st_lottie10import tensorflow.keras.activations as activations11from tensorflow.keras.layers import Activation12 13# Function to load a Lottie animation from a local file14def load_lottiefile(filepath: str):15    with open(filepath, "r") as file:16        return json.load(file)17 18# Function to display a Lottie animation in the sidebar19def display_lottiefile_sidebar(lottie_json, unique_key):20    st_lottie(lottie_json, speed=1, width=250, height=250, key=unique_key)21 22# Function to parse and preprocess the uploaded image23def parse_image(uploaded_file):24    img = Image.open(uploaded_file)25    img = img.resize((64, 64)).convert('L')  # Convert to grayscale26    img = np.array(img)27    img = np.expand_dims(img, axis=0)  # Shape (1, 64, 64)28    img = np.expand_dims(img, axis=-1)  # Shape (1, 64, 64, 1)29    img = img / 255.0  # Normalize30    return img31 32# Function to dynamically add an activation layer based on user selection33def add_activation_layer(model, activation_name):34    if activation_name == 'leakyrelu':35        model.add(LeakyReLU())36    elif activation_name == 'elu':37        model.add(ELU())38    else:39        # For 'relu', 'sigmoid', 'tanh', 'softmax', 'selu'40        if hasattr(activations, activation_name):41            activation_function = getattr(activations, activation_name)42            model.add(Activation(activation_function))43        else:44            raise ValueError(f"Unsupported activation function: {activation_name}")45 46# Function to create a model and return the feature map47def display_feature_map(img, num_filters, kernel_size, activation, dropout_rate):48    model = Sequential()49    model.add(Conv2D(num_filters, (kernel_size, kernel_size), input_shape=(64, 64, 1)))50    add_activation_layer(model, activation)51    model.add(MaxPooling2D(pool_size=(2, 2)))52    model.add(Dropout(dropout_rate))53    conv2d_output = model.predict(img)54    return conv2d_output55 56def main():57    st.title("Convolutional Neural Network Visualizer")58    with st.sidebar:59        lottie_animation = load_lottiefile("Animation - 1707640885996.json")60        display_lottiefile_sidebar(lottie_animation, "lottie_animation_key")61    st.sidebar.markdown("""62    # Interactive CNN Visualizer Explanation63    This interactive tool allows you to visualize how different parameters of a Convolutional Neural Network (CNN) affect the features detected in an input image. Here's a brief overview of the parameters you can adjust:64    65    ## Filters/Kernels66    - **What they are**: Small matrices of weights that slide over the input image to produce a feature map. Each filter is trained to detect a specific feature in the image, such as edges, corners, or textures.67    68    ## Kernel Size69    - **What it is**: Determines the size of the filter. For example, a kernel size of 3 means the filter is a 3x3 matrix. The kernel size affects the level of detail the filter can capture. Smaller kernels can capture fine-grained details, while larger kernels capture more abstract features.70    71    ## Number of Filters72    - **What it is**: Determines the number of feature maps that will be produced by a Conv2D layer. Each filter is trained to detect a different feature, so having more filters allows the model to recognize a wider variety of features.73    74    ## Activation Function75    - **What it is**: Applied to the feature maps after the convolution operation. It introduces non-linearity into the model, which allows the model to learn more complex patterns. Common choices include ReLU (Rectified Linear Unit), sigmoid, and tanh.76    77    ## MaxPooling78    - **What it is**: This operation reduces the spatial dimensions (i.e., width and height) of the input by taking the maximum value in each window of a certain size. This helps to make the model invariant to small translations and reduces the computational complexity of the model.79    80    In the interactive visualization you've created, you can adjust the number of filters, the kernel size, and the activation function to see how these parameters affect the features that the model detects in the input image.81""", unsafe_allow_html=True)82 83 84    # Architecture parameters input85    num_filters = st.slider('Number of Filters:', 16, 256, 32)86    kernel_size = st.slider('Kernel Size:', 2, 7, 3)87    activation = st.selectbox('Activation Function:', ['relu', 'sigmoid', 'tanh', 'leakyrelu', 'elu'])88    dropout_rate = st.slider('Dropout Rate:', 0.0, 0.5, 0.25)89 90    # Image upload section91    st.subheader("Upload Image")92    uploaded_file = st.file_uploader("", type=["png", "jpg", "jpeg"], help="Choose an image to upload")93    if uploaded_file is not None:94        img = parse_image(uploaded_file)95        st.session_state['uploaded_image'] = img96        st.success("Image uploaded successfully!")97 98    # Process button to visualize the model99    if st.button("Process"):100        if 'uploaded_image' in st.session_state:101            visualize_activation_overlays(st.session_state['uploaded_image'], num_filters, kernel_size, activation, dropout_rate)102        else:103            st.error("Please upload an image first.")104 105    # Reset button to clear session state and start over106    if st.button("Reset"):107        st.session_state.clear()108        st.rerun()109 110def visualize_activation_overlays(img, num_filters, kernel_size, activation, dropout_rate):111    conv2d_output = display_feature_map(img, num_filters, kernel_size, activation, dropout_rate)112    113    # Define the new size for the output images114    new_size = (800, 800)  # Example new size, adjust as needed115    116    # Assuming img was normalized to [0, 1], convert back to [0, 255], RGB, and resize117    original_img = np.squeeze(img) * 255.0118    original_img = Image.fromarray(np.uint8(original_img)).convert('RGB').resize(new_size)119    120    frames = []  # To hold each frame for the GIF121    122    for i in range(conv2d_output.shape[-1]):  # Iterate through each feature map123        feature_map = conv2d_output[0, :, :, i]124        125        # Normalize the feature map to enhance visualization126        normalized_feature_map = (feature_map - np.min(feature_map)) / (np.max(feature_map) - np.min(feature_map))127        128        # Resize to new output size129        resized_feature_map = Image.fromarray(np.uint8(normalized_feature_map * 255)).resize(new_size, Image.NEAREST)130        131        # Create a mask where high activations are marked132        mask = np.array(resized_feature_map) > 128  # Threshold to identify high activations133        134        # Create an overlay image with red color in the high activation areas135        overlay = np.array(original_img).copy()136        overlay[mask] = [255, 0, 0]  # Red color for high activation areas137        138        # Convert numpy array back to PIL Image for display139        overlay_img = Image.fromarray(overlay)140        141        # Draw filter number or text on the image142        draw = ImageDraw.Draw(overlay_img)143        # Specify font size and type (default font here, you can specify a path to a .ttf file for custom fonts)144        font = ImageFont.load_default()145        # Position for the text (bottom left corner in this case)146        text_position = (100, new_size[1] - 30)147        # Drawing text148        draw.text(text_position, f"Filter {i+1}", fill=(255,255,255), font=font)149        150        frames.append(overlay_img)151    152    # Create a GIF from the frames153    gif_path = 'activation_overlay_large.gif'154    imageio.mimsave(gif_path, frames, fps=1)  # Adjust fps as needed155    156    # Display the GIF in Streamlit157    st.image(gif_path)158if __name__ == "__main__":159    main()160