{ "cells": [ { "cell_type": "markdown", "id": "b0c11b71", "metadata": {}, "source": [ "### Denne notebooken er en modifisert versjon av en fil med samme navn: 15_gradio_and_streamlit.ipynb (se vedlegg). Notebooken som er referert til er fra den upubliserte bacheloroppgaven (dat191) til gruppen. Dato for den innleveringen er 20. mai 2026. Vi refererer derfor til; Eget arbeid (2026). Multiattributt visuell kjøretøygjenkjenning under varierende lysforhold - En sammenlignende studie av dype læringsmodeller og treningskonfigurasjoner. Høgskulen på Vestlandet. Koden som lager generelle saliency maps og capping av dem er opprinnelig fra dette dat255-prosjektet." ] }, { "cell_type": "markdown", "id": "0ede2db9", "metadata": {}, "source": [ "#### https://github.com/HVL-ML/DAT255/blob/main/notebooks/15_gradio_and_streamlit.ipynb er brukt som utgangspunkt i denne notebooken." ] }, { "cell_type": "markdown", "id": "11976aa5", "metadata": {}, "source": [ "# Gradio (and Streamlit) deployment\n", "\n", "For deploying an ML-based app there are various approaches, but [Gradio](gradio.app) and [Streamlit](https://streamlit.io/) are both quick and convenient ways to do so. Typically we would implement this in a plain python (`.py`) file rather than a `.ipynb` notebook, but Gradio works here too, so let's try that first. Streamlit needs to be run directly in python, but the code is given below, so you can try out that too.\n", "\n", "In this example we set up an image classifier, where the user can upload an image and get the top 5 class predictions in return." ] }, { "cell_type": "code", "execution_count": 1, "id": "8b4cac3c", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2026-04-27 08:44:47.877376: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:479] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", "2026-04-27 08:44:48.064482: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:10575] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", "2026-04-27 08:44:48.065911: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1442] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", "2026-04-27 08:44:48.499874: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", "To enable the following instructions: AVX2 FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", "2026-04-27 08:44:50.589928: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" ] } ], "source": [ "import numpy as np\n", "import tensorflow as tf\n", "from tensorflow import keras\n", "from keras.applications.mobilenet_v2 import (\n", " MobileNetV2,\n", " preprocess_input,\n", " decode_predictions,\n", ")\n", "from PIL import Image" ] }, { "cell_type": "markdown", "id": "a4517639", "metadata": {}, "source": [ "## Set up a pretrained model\n", "\n", "Let's download and set up a `MobileNetV2` model, trained on the 1000 classes in the ImageNet dataset. You can change this to anything you like. Remeber, however, to also use the appropriate preprocessing function." ] }, { "cell_type": "code", "execution_count": 2, "id": "9999b2b6", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2026-04-27 08:44:55.562610: I external/local_xla/xla/stream_executor/cuda/cuda_executor.cc:984] could not open file to read NUMA node: /sys/bus/pci/devices/0000:01:00.0/numa_node\n", "Your kernel may have been built without NUMA support.\n", "2026-04-27 08:44:56.005515: I external/local_xla/xla/stream_executor/cuda/cuda_executor.cc:984] could not open file to read NUMA node: /sys/bus/pci/devices/0000:01:00.0/numa_node\n", "Your kernel may have been built without NUMA support.\n", "2026-04-27 08:44:56.005628: I external/local_xla/xla/stream_executor/cuda/cuda_executor.cc:984] could not open file to read NUMA node: /sys/bus/pci/devices/0000:01:00.0/numa_node\n", "Your kernel may have been built without NUMA support.\n", "2026-04-27 08:44:56.006912: I external/local_xla/xla/stream_executor/cuda/cuda_executor.cc:984] could not open file to read NUMA node: /sys/bus/pci/devices/0000:01:00.0/numa_node\n", "Your kernel may have been built without NUMA support.\n", "2026-04-27 08:44:56.007043: I external/local_xla/xla/stream_executor/cuda/cuda_executor.cc:984] could not open file to read NUMA node: /sys/bus/pci/devices/0000:01:00.0/numa_node\n", "Your kernel may have been built without NUMA support.\n", "2026-04-27 08:44:56.007092: I external/local_xla/xla/stream_executor/cuda/cuda_executor.cc:984] could not open file to read NUMA node: /sys/bus/pci/devices/0000:01:00.0/numa_node\n", "Your kernel may have been built without NUMA support.\n", "2026-04-27 08:44:56.196173: I external/local_xla/xla/stream_executor/cuda/cuda_executor.cc:984] could not open file to read NUMA node: /sys/bus/pci/devices/0000:01:00.0/numa_node\n", "Your kernel may have been built without NUMA support.\n", "2026-04-27 08:44:56.196349: I external/local_xla/xla/stream_executor/cuda/cuda_executor.cc:984] could not open file to read NUMA node: /sys/bus/pci/devices/0000:01:00.0/numa_node\n", "Your kernel may have been built without NUMA support.\n", "2026-04-27 08:44:56.196368: I tensorflow/core/common_runtime/gpu/gpu_device.cc:2019] Could not identify NUMA node of platform GPU id 0, defaulting to 0. Your kernel may not have been built with NUMA support.\n", "2026-04-27 08:44:56.196439: I external/local_xla/xla/stream_executor/cuda/cuda_executor.cc:984] could not open file to read NUMA node: /sys/bus/pci/devices/0000:01:00.0/numa_node\n", "Your kernel may have been built without NUMA support.\n", "2026-04-27 08:44:56.197428: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1928] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 6715 MB memory: -> device: 0, name: NVIDIA GeForce GTX 1070, pci bus id: 0000:01:00.0, compute capability: 6.1\n" ] } ], "source": [ "# model = MobileNetV2(weights=\"imagenet\")\n", "\n", "# The model loading below is from Deep Learning with Python, Third edition. Chapter: 8, Fitting the model\n", "model1 = keras.models.load_model(\n", " \"Final_model.keras\"\n", ")\n", "# The model loading below is from Deep Learning with Python, Third edition. Chapter: 8, Fitting the model\n", "model2 = keras.models.load_model(\n", " \"40_unfrozen_final_test.keras\"\n", ")\n", "# The model loading below is from Deep Learning with Python, Third edition. Chapter: 8, Fitting the model\n", "# model3 = keras.models.load_model(\n", "# \"hierarchical_cnn_baseline_hybrid_crop.keras\"\n", "# )\n", "\n", "# IMG_RES = (300, 300)" ] }, { "cell_type": "markdown", "id": "90638224", "metadata": {}, "source": [ "# Cellene under kommer tilnærmet direkte fra et annet prosjekt gruppen har arbeidet med i faget, DAT255." ] }, { "cell_type": "markdown", "id": "20a15750", "metadata": {}, "source": [ "#### The two cells below are based on Deep Inside Convolutional Networks: Visualising Image Classification Models and Saliency Maps, Image-Specific Class Saliency Visualisation (https://arxiv.org/abs/1312.6034)" ] }, { "cell_type": "code", "execution_count": 3, "id": "8b3a7a30", "metadata": {}, "outputs": [], "source": [ "# This method is based on Deep Learning with Python, Third edition. Chapter: 2, Gradient computation,\n", "# and get_gradients from https://keras.io/examples/vision/integrated_gradients/\n", "def get_gradients(img_array, model, lvl2_pred_index):\n", " with tf.GradientTape() as tape:\n", " tape.watch(img_array)\n", " if lvl2_pred_index != None:\n", " score = model(img_array)[0][lvl2_pred_index]\n", " else:\n", " # Denne veiledningen på reduce_max ble brukt: https://www.tensorflow.org/api_docs/python/tf/math/reduce_max\n", " score = tf.math.reduce_max(model(img_array))\n", " gradients = tape.gradient(score, img_array)\n", " return gradients" ] }, { "cell_type": "code", "execution_count": 4, "id": "3bfc026a", "metadata": {}, "outputs": [], "source": [ "def get_heatmap(img_array, model, lvl2_pred_index=None):\n", " gradients = get_gradients(img_array, model, lvl2_pred_index)\n", " abs_gradients = np.abs(gradients[0])\n", " # np.max is from: Deep Learning with Python, Third edition. Chapter: 10, Displaying the class activation heatmap\n", " max_gradient = np.max(abs_gradients)\n", " pixel_gradients = ((abs_gradients / max_gradient) * 255.0)\n", "\n", " # Denne dokumentasjonen er brukt for å lage linjen under: https://numpy.org/doc/2.2/reference/generated/numpy.max.html\n", " return np.max(pixel_gradients, 2)" ] }, { "cell_type": "markdown", "id": "a3782b66", "metadata": {}, "source": [ "#### The idea of the method below is from: SmoothGrad: removing noise by adding noise, Capping outlying values (https://arxiv.org/pdf/1706.03825)" ] }, { "cell_type": "code", "execution_count": 5, "id": "c275f48b", "metadata": {}, "outputs": [], "source": [ "import math\n", "\n", "def cap_heatmap(heatmap):\n", " values = []\n", " for i in range(len(heatmap)):\n", " for j in range(len(heatmap[i])):\n", " values.append(heatmap[i][j])\n", " values.sort()\n", "\n", " ninty_nine_percentile = values[math.floor(len(values) * 0.99)]\n", "\n", " for i in range(len(heatmap)):\n", " for j in range(len(heatmap[i])):\n", " if (heatmap[i][j] > ninty_nine_percentile):\n", " heatmap[i][j] = ninty_nine_percentile\n", "\n", " # np.max is from: Deep Learning with Python, Third edition. Chapter: 10, Displaying the class activation heatmap\n", " heatmap = (heatmap / np.max(heatmap)) * 255.0\n", " return heatmap" ] }, { "cell_type": "markdown", "id": "c8f80166", "metadata": {}, "source": [ "### The below cell is strongly based on Deep Learning with Python, Third edition. Chapter: 10, Visualizing heatmaps of class activation" ] }, { "cell_type": "code", "execution_count": 6, "id": "398fcd17", "metadata": {}, "outputs": [], "source": [ "import matplotlib.cm as cm\n", "\n", "def superimpose(img_array, heatmap):\n", " # Uses the \"jet\" colormap to recolorize the heatmap\n", " jet = cm.get_cmap(\"jet\")\n", "\n", " jet_colors = jet(np.arange(256))[:, :3]\n", " jet_colors-=[0,0,0.5]\n", "\n", " # Convertion to int is from: https://www.w3schools.com/python/numpy/numpy_data_types.asp (Converting Data Type on Existing Arrays)\n", " jet_heatmap = jet_colors[(np.round(heatmap)).astype('i')]\n", "\n", " # Superimposes the heatmap and the original image\n", " superimposed_img = jet_heatmap / 3.0 + img_array / 3.0\n", " superimposed_img = keras.utils.array_to_img(superimposed_img)\n", " return superimposed_img" ] }, { "cell_type": "markdown", "id": "911b6222", "metadata": {}, "source": [ "# Cellene over kommer tilnærmet direkte fra et annet prosjekt gruppen har arbeidet med i faget, DAT255." ] }, { "cell_type": "code", "execution_count": 7, "id": "41fd396b", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/home/jkaste03/venvs/tf-2.16/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", " from .autonotebook import tqdm as notebook_tqdm\n" ] } ], "source": [ "# import imageio\n", "import gradio as gr\n", "\n", "def classify_image(img: Image.Image, checkbox_group):\n", " # De to linjene under kommer fra https://github.com/HVL-ML/DAT255/blob/main/notebooks/15_gradio_and_streamlit.ipynb\n", " # Resize to the input image to what MobileNet expects\n", " img = img.resize((300, 300))\n", "\n", " # Resize to the input image to what MobileNet expects\n", " # img_resized = img.resize(IMG_RES)\n", " arr = np.array(img)\n", "\n", " # Check the color channels, so we can take both grayscale, RGB, and RGBA images as input.\n", " if arr.ndim == 2:\n", " arr = np.stack([arr] * 3, axis=-1)\n", " elif arr.shape[-1] == 4:\n", " arr = arr[..., :3]\n", "\n", " arr = arr / 255.0\n", "\n", " # Linjen under er basert på: https://www.tensorflow.org/api_docs/python/tf/keras/ops/convert_to_tensor\n", " # arr = keras.ops.convert_to_tensor(arr, dtype=\"float32\")\n", "\n", " # np.max is from: Deep Learning with Python, Third edition. Chapter: 10, Displaying the class activation heatmap\n", " # arr = arr / np.max(arr)\n", "\n", " # Kodelinjen under kommer delvis fra et annet prosjekt gruppen har arbeidet med i faget, DAT255.\n", " # Kodelinjen i DAT255-prosjektet kommer i høyeste grad herfra: https://github.com/HVL-ML/DAT255/blob/main/notebooks/03_advanced_image_classification.ipynb.\n", " arr = keras.ops.expand_dims(arr, 0)\n", "\n", " # Linjen under er delvis basert på: https://www.gradio.app/docs/gradio/checkboxgroup\n", " return_array = [gr.Image(),gr.Image(),gr.Label(),gr.Image(),gr.Image(),gr.Label(),gr.Image(),gr.Image(),gr.Label(), img, gr.CheckboxGroup()]\n", "\n", " if \"Egen modell\" in checkbox_group:\n", " model = model1\n", " # Predict!\n", " preds = model.predict(arr * 255.0, verbose=0)\n", "\n", " # Linjen under kommer delvis fra et annet prosjekt gruppen har arbeidet med i faget, DAT255.\n", " # heatmap = get_heatmap(arr, \"lvl1\", model)\n", " \n", " # =====\n", " # Koden under kommer i høyeste grad fra et annet prosjekt gruppen har arbeidet med i faget, DAT255.\n", " # Koden fra DAT255-prosjektet kommer i høyeste grad herfra: SmoothGrad: removing noise by adding noise, 2.2. Smoothing noisy gradients (https://arxiv.org/pdf/1706.03825)\n", " # og herfra: https://numpy.org/doc/2.1/reference/random/generated/numpy.random.Generator.normal.html#numpy.random.Generator.normal\n", "\n", " rng = np.random.default_rng()\n", " finished_heatmap_lvl1 = np.zeros(arr[0].shape[:2])\n", " N = 50.0\n", " for n in range(int(N)):\n", " noise_map = rng.normal(0, 0.20, arr[0].shape)\n", " noisy_img = arr * noise_map * 255.0\n", " current_heatmap = get_heatmap(noisy_img, model)\n", " finished_heatmap_lvl1 += current_heatmap\n", " finished_heatmap_lvl1 /= N\n", " # Kodelinjen under kommer fra et annet prosjekt gruppen har arbeidet med i faget, DAT255.\n", " # Idéen til den kodelinjen kommer herfra: SmoothGrad: removing noise by adding noise, Capping outlying values (https://arxiv.org/pdf/1706.03825)\n", " finished_heatmap_lvl1 = cap_heatmap(finished_heatmap_lvl1)\n", "\n", " # Koden over kommer i høyeste grad fra et annet prosjekt gruppen har arbeidet med i faget, DAT255.\n", " # Koden fra DAT255-prosjektet kommer i høyeste grad herfra: SmoothGrad: removing noise by adding noise, 2.2. Smoothing noisy gradients (https://arxiv.org/pdf/1706.03825)\n", " # og herfra: https://numpy.org/doc/2.1/reference/random/generated/numpy.random.Generator.normal.html#numpy.random.Generator.normal\n", " # =====\n", "\n", " # The below line is based on Deep Learning with Python, Third edition. Chapter: 10, Visualizing heatmaps of class activation\n", " superimposed = superimpose(arr[0], finished_heatmap_lvl1)\n", "\n", " # Line below is based on https://stackoverflow.com/questions/57253048/scipy-misc-has-no-attribute-imsave and https://www.geeksforgeeks.org/python/getting-started-with-imageio-library-in-python/\n", " # imageio.imwrite(\"Neinieg.png\", superimposed)\n", "\n", " # Convertion to int is from: https://www.w3schools.com/python/numpy/numpy_data_types.asp (Converting Data Type on Existing Arrays)\n", " return_array[0:3] = [superimposed, np.round(finished_heatmap_lvl1).astype('i'), {\"Dog\": preds[0][0], \"Cat\": 1-preds[0][0]}]\n", "\n", " if \"Pretrent modell\" in checkbox_group:\n", " model = model2\n", "\n", " # Predict!\n", " preds = model.predict(arr * 255.0, verbose=0)\n", "\n", " # Linjen under kommer delvis fra et annet prosjekt gruppen har arbeidet med i faget, DAT255.\n", " # heatmap = get_heatmap(arr, \"lvl1\", model)\n", "\n", " # =====\n", " # Koden under kommer i høyeste grad fra et annet prosjekt gruppen har arbeidet med i faget, DAT255.\n", " # Koden fra DAT255-prosjektet kommer i høyeste grad herfra: SmoothGrad: removing noise by adding noise, 2.2. Smoothing noisy gradients (https://arxiv.org/pdf/1706.03825)\n", " # og herfra: https://numpy.org/doc/2.1/reference/random/generated/numpy.random.Generator.normal.html#numpy.random.Generator.normal\n", "\n", " rng = np.random.default_rng()\n", " finished_heatmap_lvl1 = np.zeros(arr[0].shape[:2])\n", " N = 50.0\n", " for n in range(int(N)):\n", " noise_map = rng.normal(0, 0.20, arr[0].shape)\n", " noisy_img = arr * noise_map * 255.0\n", " current_heatmap = get_heatmap(noisy_img, model)\n", " finished_heatmap_lvl1 += current_heatmap\n", " finished_heatmap_lvl1 /= N\n", " # Kodelinjen under kommer fra et annet prosjekt gruppen har arbeidet med i faget, DAT255.\n", " # Idéen til den kodelinjen kommer herfra: SmoothGrad: removing noise by adding noise, Capping outlying values (https://arxiv.org/pdf/1706.03825)\n", " finished_heatmap_lvl1 = cap_heatmap(finished_heatmap_lvl1)\n", "\n", " # Koden over kommer i høyeste grad fra et annet prosjekt gruppen har arbeidet med i faget, DAT255.\n", " # Koden fra DAT255-prosjektet kommer i høyeste grad herfra: SmoothGrad: removing noise by adding noise, 2.2. Smoothing noisy gradients (https://arxiv.org/pdf/1706.03825)\n", " # og herfra: https://numpy.org/doc/2.1/reference/random/generated/numpy.random.Generator.normal.html#numpy.random.Generator.normal\n", " # =====\n", "\n", " # The below line is based on Deep Learning with Python, Third edition. Chapter: 10, Visualizing heatmaps of class activation\n", " superimposed = superimpose(arr[0], finished_heatmap_lvl1)\n", "\n", " # Line below is based on https://stackoverflow.com/questions/57253048/scipy-misc-has-no-attribute-imsave and https://www.geeksforgeeks.org/python/getting-started-with-imageio-library-in-python/\n", " # imageio.imwrite(\"Neinieg.png\", superimposed)\n", "\n", " # Convertion to int is from: https://www.w3schools.com/python/numpy/numpy_data_types.asp (Converting Data Type on Existing Arrays)\n", " return_array[3:6] = [superimposed, np.round(finished_heatmap_lvl1).astype('i'), {\"Dog\": preds[0][0], \"Cat\": 1-preds[0][0]}]\n", " \n", " if \"Horribel modell\" in checkbox_group:\n", " model = model3\n", " # Predict!\n", " preds = model.predict(arr, verbose=0)\n", "\n", " # Linjen under kommer delvis fra et annet prosjekt gruppen har arbeidet med i faget, DAT255.\n", " # heatmap = get_heatmap(arr, \"lvl1\", model)\n", "\n", " # =====\n", " # Koden under kommer i høyeste grad fra et annet prosjekt gruppen har arbeidet med i faget, DAT255.\n", " # Koden fra DAT255-prosjektet kommer i høyeste grad herfra: SmoothGrad: removing noise by adding noise, 2.2. Smoothing noisy gradients (https://arxiv.org/pdf/1706.03825)\n", " # og herfra: https://numpy.org/doc/2.1/reference/random/generated/numpy.random.Generator.normal.html#numpy.random.Generator.normal\n", "\n", " rng = np.random.default_rng()\n", " finished_heatmap_lvl1 = np.zeros(arr[0].shape[:2])\n", " N = 50.0\n", " for n in range(int(N)):\n", " noise_map = rng.normal(0, 0.20, arr[0].shape)\n", " noisy_img = arr * noise_map\n", " current_heatmap = get_heatmap(noisy_img, model)\n", " finished_heatmap_lvl1 += current_heatmap\n", " finished_heatmap_lvl1 /= N\n", " # Kodelinjen under kommer fra et annet prosjekt gruppen har arbeidet med i faget, DAT255.\n", " # Idéen til den kodelinjen kommer herfra: SmoothGrad: removing noise by adding noise, Capping outlying values (https://arxiv.org/pdf/1706.03825)\n", " finished_heatmap_lvl1 = cap_heatmap(finished_heatmap_lvl1)\n", "\n", " # Koden over kommer i høyeste grad fra et annet prosjekt gruppen har arbeidet med i faget, DAT255.\n", " # Koden fra DAT255-prosjektet kommer i høyeste grad herfra: SmoothGrad: removing noise by adding noise, 2.2. Smoothing noisy gradients (https://arxiv.org/pdf/1706.03825)\n", " # og herfra: https://numpy.org/doc/2.1/reference/random/generated/numpy.random.Generator.normal.html#numpy.random.Generator.normal\n", " # =====\n", " \n", " # The below line is based on Deep Learning with Python, Third edition. Chapter: 10, Visualizing heatmaps of class activation\n", " superimposed = superimpose(arr[0], finished_heatmap_lvl1)\n", "\n", " # Line below is based on https://stackoverflow.com/questions/57253048/scipy-misc-has-no-attribute-imsave and https://www.geeksforgeeks.org/python/getting-started-with-imageio-library-in-python/\n", " # imageio.imwrite(\"Neinieg.png\", superimposed)\n", "\n", " # Convertion to int is from: https://www.w3schools.com/python/numpy/numpy_data_types.asp (Converting Data Type on Existing Arrays)\n", " return_array[6:9] = [superimposed, np.round(finished_heatmap_lvl1).astype('i'), {\"Dog\": preds[0][0], \"Cat\": 1-preds[0][0]}]\n", " return return_array\n", "\n" ] }, { "cell_type": "markdown", "id": "f2a6db03", "metadata": {}, "source": [ "#### Cellen under er basert på: https://github.com/gradio-app/gradio/issues/2066 og https://discuss.huggingface.co/t/how-to-programmatically-enable-or-disable-components/52350" ] }, { "cell_type": "code", "execution_count": 8, "id": "989254f4", "metadata": {}, "outputs": [], "source": [ "def change_visibility(checkbox_group, model_1_label1, model_2_label1, model_3_label1):\n", " return_array = [gr.Image(),gr.Image(),gr.Label(),gr.Markdown(),gr.Image(),gr.Image(),gr.Label(),gr.Markdown(),gr.Image(),gr.Image(),gr.Label(),gr.Markdown()]\n", " if \"Egen modell\" in checkbox_group:\n", " try:\n", " model_1_label1[\"Cat\"]\n", " return_array[0:4] = [gr.Image(label=\"Heatmap som viser hvorfor katt\", visible=True), gr.Image(label=\"Gråskala-heatmap som viser hvorfor katt\", visible=True), gr.Label(visible=True), gr.Markdown(visible=True)]\n", " except:\n", " return_array[0:4] = [gr.Image(label=\"Heatmap som viser hvorfor hund\", visible=True), gr.Image(label=\"Gråskala-heatmap som viser hvorfor hund\", visible=True), gr.Label(visible=True), gr.Markdown(visible=True)]\n", " else: \n", " return_array[0:4] = [gr.Image(visible=False), gr.Image(visible=False), gr.Label(visible=False), gr.Markdown(visible=False)]\n", " if \"Pretrent modell\" in checkbox_group:\n", " try:\n", " model_2_label1[\"Cat\"]\n", " return_array[4:8] = [gr.Image(label=\"Heatmap som viser hvorfor katt\", visible=True), gr.Image(label=\"Gråskala-heatmap som viser hvorfor katt\", visible=True), gr.Label(visible=True), gr.Markdown(visible=True)]\n", " except:\n", " return_array[4:8] = [gr.Image(label=\"Heatmap som viser hvorfor hund\", visible=True), gr.Image(label=\"Gråskala-heatmap som viser hvorfor hund\", visible=True), gr.Label(visible=True), gr.Markdown(visible=True)]\n", " else: \n", " return_array[4:8] = [gr.Image(visible=False), gr.Image(visible=False), gr.Label(visible=False), gr.Markdown(visible=False)]\n", " if \"Horribel modell\" in checkbox_group:\n", " try:\n", " model_3_label1[\"Cat\"]\n", " return_array[8:12] = [gr.Image(label=\"Heatmap som viser hvorfor katt\", visible=True), gr.Image(label=\"Gråskala-heatmap som viser hvorfor katt\", visible=True), gr.Label(visible=True), gr.Markdown(visible=True)]\n", " except:\n", " return_array[8:12] = [gr.Image(label=\"Heatmap som viser hvorfor hund\", visible=True), gr.Image(label=\"Gråskala-heatmap som viser hvorfor hund\", visible=True), gr.Label(visible=True), gr.Markdown(visible=True)]\n", " else: \n", " return_array[8:12] = [gr.Image(visible=False), gr.Image(visible=False), gr.Label(visible=False), gr.Markdown(visible=False)]\n", " return return_array" ] }, { "cell_type": "markdown", "id": "19384fb0", "metadata": {}, "source": [ "## Set up the Gradio interface\n", "\n", "Check the [documentation](https://www.gradio.app/docs) for the various things we can add here." ] }, { "cell_type": "code", "execution_count": null, "id": "224c1c64", "metadata": {}, "outputs": [], "source": [ "# Example images\n", "examples = [\n", " \"https://cdn.britannica.com/79/232779-050-6B0411D7/German-Shepherd-dog-Alsatian.jpg\",\n", " \"https://cdn.britannica.com/41/126641-050-E1CA0E61/cat-suns-hill-Parthenon-Athens-Greece-Acropolis.jpg\",\n", "]\n", "\n", "with gr.Blocks(title=\"Explainability methods for image classification\") as demo:\n", " gr.Markdown(\"## Explainability methods for image classification\")\n", " gr.Markdown(\n", " \"Last opp et bilde av en hund eller katt. \"\n", " )\n", " with gr.Row():\n", " components = [[0,0,0,0],[0,0,0,0],[0,0,0,0],0,0]\n", " components[3] = gr.Image(type=\"pil\", label=\"Opplastet bilde\")\n", " # Kodelinjen under er basert på: https://www.gradio.app/docs/gradio/checkboxgroup\n", " components[4] = gr.CheckboxGroup(choices=[\"Egen modell\", \"Pretrent modell\"])\n", " # components[4] = gr.CheckboxGroup(choices=[\"Egen modell\", \"Pretrent modell\", \"Horribel modell\"])\n", "\n", " # Linjen under er basert på: https://www.gradio.app/docs/gradio/blocks\n", " components[0][3] = gr.Markdown(\"Prediksjonene til Egen modell:\", visible=False)\n", " with gr.Row():\n", " # Linjen under er basert på: https://www.gradio.app/4.44.1/guides/controlling-layout\n", " with gr.Column():\n", " # De to linjene under er delvis basert på: https://github.com/gradio-app/gradio/issues/10394\n", " components[0][0] = gr.Image(type=\"pil\", label=\"Heatmap\", format=\"png\", visible=False)\n", " components[0][1] = gr.Image(type=\"pil\", label=\"Heatmap\", format=\"png\", visible=False)\n", " # Linjen under er basert på: https://www.gradio.app/4.44.1/guides/controlling-layout\n", " with gr.Column():\n", " components[0][2] = gr.Label(num_top_classes=1, label=\"Skapning\", visible=False)\n", "\n", " # Linjen under er basert på: https://www.gradio.app/docs/gradio/blocks\n", " components[1][3] = gr.Markdown(\"Prediksjonene til Pretrent modell:\", visible=False)\n", " with gr.Row():\n", " # Linjen under er basert på: https://www.gradio.app/4.44.1/guides/controlling-layout\n", " with gr.Column():\n", " # De to linjene under er delvis basert på: https://github.com/gradio-app/gradio/issues/10394\n", " components[1][0] = gr.Image(type=\"pil\", label=\"Heatmap\", format=\"png\", visible=False)\n", " components[1][1] = gr.Image(type=\"pil\", label=\"Heatmap\", format=\"png\", visible=False)\n", " # Linjen under er basert på: https://www.gradio.app/4.44.1/guides/controlling-layout\n", " with gr.Column():\n", " components[1][2] = gr.Label(num_top_classes=1, label=\"Skapning\", visible=False)\n", "\n", " # Linjen under er basert på: https://www.gradio.app/docs/gradio/blocks\n", " components[2][3] = gr.Markdown(\"Prediksjonene til Horribel modell:\", visible=False)\n", " with gr.Row():\n", " # Linjen under er basert på: https://www.gradio.app/4.44.1/guides/controlling-layout\n", " with gr.Column():\n", " # De to linjene under er delvis basert på: https://github.com/gradio-app/gradio/issues/10394\n", " components[2][0] = gr.Image(type=\"pil\", label=\"Heatmap\", format=\"png\", visible=False)\n", " components[2][1] = gr.Image(type=\"pil\", label=\"Heatmap\", format=\"png\", visible=False)\n", " # Linjen under er basert på: https://www.gradio.app/4.44.1/guides/controlling-layout\n", " with gr.Column():\n", " components[2][2] = gr.Label(num_top_classes=1, label=\"Bilmerke\", visible=False)\n", "\n", " classify_btn = gr.Button(\"Classify\", variant=\"primary\")\n", " classify_btn.click(fn=classify_image, inputs=[components[3],components[4]], outputs=[components[0][0],components[0][1],components[0][2],components[1][0],components[1][1],components[1][2],components[2][0],components[2][1],components[2][2], components[3], components[4]])\n", " # Linjen under er basert på: https://github.com/gradio-app/gradio/issues/2066 og https://discuss.huggingface.co/t/how-to-programmatically-enable-or-disable-components/52350\n", " classify_btn.click(fn=change_visibility, inputs=[components[4], components[0][2], components[1][2], components[2][2]], outputs=[components[0][0], components[0][1], components[0][2], components[0][3], components[1][0], components[1][1], components[1][2], components[1][3], components[2][0], components[2][1], components[2][2], components[2][3]])\n", "\n", " # examples = gr.Examples(\n", " # examples=examples,\n", " # inputs=components[3],\n", " # # outputs=output,\n", " # # fn=classify_image,\n", " # # cache_examples=True\n", " # )" ] }, { "cell_type": "markdown", "id": "5b2c27a1", "metadata": {}, "source": [ "Now we can run it:" ] }, { "cell_type": "code", "execution_count": null, "id": "99e1f440", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "* Running on local URL: http://127.0.0.1:7860\n", "* To create a public link, set `share=True` in `launch()`.\n" ] }, { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" }, { "name": "stderr", "output_type": "stream", "text": [ "2026-04-27 08:45:25.695829: I external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:465] Loaded cuDNN version 8907\n", "2026-04-27 08:45:29.612769: I tensorflow/core/util/cuda_solvers.cc:178] Creating GpuSolver handles for stream 0xe5c1310\n", "/tmp/ipykernel_4734/3145468918.py:5: MatplotlibDeprecationWarning: The get_cmap function was deprecated in Matplotlib 3.7 and will be removed in 3.11. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap()`` or ``pyplot.get_cmap()`` instead.\n", " jet = cm.get_cmap(\"jet\")\n", "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n", "I0000 00:00:1777272340.852520 4950 service.cc:145] XLA service 0x7741e461c190 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:\n", "I0000 00:00:1777272340.852566 4950 service.cc:153] StreamExecutor device (0): NVIDIA GeForce GTX 1070, Compute Capability 6.1\n", "2026-04-27 08:45:41.156381: I tensorflow/compiler/mlir/tensorflow/utils/dump_mlir_util.cc:268] disabling MLIR crash reproducer, set env var `MLIR_CRASH_REPRODUCER_DIRECTORY` to enable.\n", "I0000 00:00:1777272346.764656 4950 device_compiler.h:188] Compiled cluster using XLA! This line is logged at most once for the lifetime of the process.\n", "/tmp/ipykernel_4734/3145468918.py:5: MatplotlibDeprecationWarning: The get_cmap function was deprecated in Matplotlib 3.7 and will be removed in 3.11. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap()`` or ``pyplot.get_cmap()`` instead.\n", " jet = cm.get_cmap(\"jet\")\n" ] } ], "source": [ "demo.launch(share=False)" ] } ], "metadata": { "kernelspec": { "display_name": "tf220-cpu", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.10" } }, "nbformat": 4, "nbformat_minor": 5 }