|
|
|
""" |
|
Created on Sat Dec 3 18:31:26 2022 |
|
|
|
@author: gabri |
|
""" |
|
|
|
import numpy as np |
|
import tensorflow as tf |
|
import gradio as gr |
|
from huggingface_hub import from_pretrained_keras |
|
import cv2 |
|
import requests |
|
from PIL import Image |
|
import matplotlib.cm as cm |
|
|
|
|
|
|
|
|
|
models_links = { |
|
'convnext':'https://huggingface.co/gabri14el/grapevine_classification/resolve/main/experimentos/fine-tuning/huge_classifier_20varieties.h5'} |
|
|
|
model_weights = { |
|
} |
|
|
|
model_last_convolutional_layer = {'convnext': 'convnext_base_stage_3_block_2_depthwise_conv'} |
|
|
|
classes = ['Alveralhao', |
|
'Arinto do Douro', |
|
'Cercial', |
|
'Codega', |
|
'Codega do Larinho', |
|
'Donzelinho', |
|
'Folgasao', |
|
'Malvasia Fina', |
|
'Malvasia Preta', |
|
'Malvasia Rei', |
|
'Moscatel Galego', |
|
'Mourisco Tinto', |
|
'Rabigato', |
|
'Samarrinho', |
|
'Sousao', |
|
'Tinta Amarela', |
|
'Tinta Barroca', |
|
'Tinta Roriz', |
|
'Tinto Cao', |
|
'Touriga Nacional'] |
|
|
|
target_size_dimension = 224 |
|
n_classes = len(classes) |
|
|
|
def define_model(model): |
|
weights = get_weights(model) |
|
if model == 'convnext': |
|
preprocessing_function=tf.keras.applications.convnext.preprocess_input |
|
model = tf.keras.applications.ConvNeXtBase( |
|
include_top=False, |
|
input_shape= (target_size_dimension, target_size_dimension, 3), |
|
weights='imagenet', |
|
pooling='avg' |
|
) |
|
|
|
|
|
x = tf.keras.layers.Dense(512, activation='relu')(model.output) |
|
x = tf.keras.layers.Dropout(0.20)(x) |
|
x = tf.keras.layers.Dense(512, activation='relu')(x) |
|
x = tf.keras.layers.Dropout(0.20)(x) |
|
output = tf.keras.layers.Dense(n_classes, activation='softmax')(x) |
|
nmodel = tf.keras.models.Model(model.input, output) |
|
nmodel.load_weights(weights) |
|
return preprocessing_function, nmodel |
|
|
|
def get_weights(model): |
|
if not model in model_weights: |
|
r = requests.get(models_links[model], allow_redirects=True) |
|
open(model+'.h5', 'wb').write(r.content) |
|
model_weights[model] = model+'.h5' |
|
return model_weights[model] |
|
|
|
|
|
|
|
|
|
def get_img_array(img_path, size, expand=True): |
|
|
|
img = tf.keras.preprocessing.image.load_img(img_path, target_size=size) |
|
|
|
array = tf.keras.preprocessing.image.img_to_array(img) |
|
|
|
|
|
|
|
if expand: |
|
array = np.expand_dims(array, axis=0) |
|
return array |
|
|
|
|
|
def make_gradcam_heatmap(img_array, grad_model, last_conv_layer_name, pred_index=None, tresh=0.1): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with tf.GradientTape() as tape: |
|
last_conv_layer_output, preds = grad_model(img_array) |
|
if pred_index is None: |
|
pred_index = tf.argmax(preds[0]) |
|
class_channel = preds[:, pred_index] |
|
|
|
|
|
|
|
grads = tape.gradient(class_channel, last_conv_layer_output) |
|
|
|
|
|
|
|
pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2)) |
|
|
|
|
|
|
|
|
|
last_conv_layer_output = last_conv_layer_output[0] |
|
heatmap = last_conv_layer_output @ pooled_grads[..., tf.newaxis] |
|
heatmap = tf.squeeze(heatmap) |
|
|
|
|
|
heatmap = tf.maximum(heatmap, 0) / tf.math.reduce_max(heatmap) |
|
heatmap = heatmap.numpy() |
|
return heatmap |
|
|
|
def save_and_display_gradcam(img, heatmap, cam_path="cam.jpg", alpha=0.4): |
|
|
|
|
|
heatmap = np.uint8(255 * heatmap) |
|
im = Image.fromarray(heatmap) |
|
im = im.resize((img.shape[1], img.shape[0])) |
|
|
|
im = np.asarray(im) |
|
im = np.where(im > 0, 1, im) |
|
|
|
|
|
jet = cm.get_cmap("jet") |
|
|
|
|
|
jet_colors = jet(np.arange(256))[:, :3] |
|
jet_heatmap = jet_colors[heatmap] |
|
|
|
|
|
|
|
|
|
jet_heatmap = tf.keras.preprocessing.image.array_to_img(jet_heatmap) |
|
jet_heatmap = jet_heatmap.resize((img.shape[1], img.shape[0])) |
|
jet_heatmap = tf.keras.preprocessing.image.img_to_array(jet_heatmap) |
|
|
|
|
|
superimposed_img = jet_heatmap * alpha + img |
|
superimposed_img = tf.keras.preprocessing.image.array_to_img(superimposed_img) |
|
|
|
|
|
|
|
|
|
|
|
|
|
return superimposed_img, im |
|
|
|
|
|
def infer(model_name, input_image): |
|
print('#$$$$$$$$$$$$$$$$$$$$$$$$$ IN INFER $$$$$$$$$$$$$$$$$$$$$$$') |
|
print(model_name, type(input_image)) |
|
preprocess, model = define_model(model_name) |
|
|
|
|
|
img_processed = preprocess(np.expand_dims(input_image, axis=0)) |
|
|
|
predictions = model.predict(img_processed) |
|
predictions = np.squeeze(predictions) |
|
|
|
|
|
result = {} |
|
|
|
|
|
|
|
|
|
for i in range(len(classes)): |
|
result[classes[i]] = float(predictions[i]) |
|
|
|
|
|
print(input_image.shape) |
|
model.layers[-1].activation = None |
|
grad_model = tf.keras.models.Model([model.inputs], [model.get_layer(model_last_convolutional_layer[model_name]).output, model.output]) |
|
|
|
print(result) |
|
heatmap = make_gradcam_heatmap(img_processed, grad_model,model_last_convolutional_layer[model_name]) |
|
heat, mask = save_and_display_gradcam(input_image, heatmap) |
|
|
|
return result, heat |
|
|
|
gr.outputs.Image() |
|
|
|
css = css = ".output-image, .input-image, .image-preview {height: 300px !important}" |
|
inputs = [gr.Radio(["convnext"], label='Choose a model'), gr.inputs.Image(shape=(target_size_dimension, target_size_dimension), label='Select an image')] |
|
|
|
output = [gr.outputs.Label(label="Result"), gr.outputs.Image(type="numpy", label="Heatmap (Grad-CAM)")] |
|
|
|
examples = [["./content/examples/Frog.jpg"], ["./content/examples/Truck.jpg"]] |
|
title = "Grapevine image classification" |
|
description = "Upload an image to classify it. The allowed classes are - Alveralhao, Arinto do Douro, Cercial, Codega, Codega do Larinho, Donzelinho, Folgasao, Malvasia Fina, Malvasia Preta, Malvasia Rei, Moscatel Galego, Mourisco Tinto, Rabigato, Samarrinho, Sousao, Tinta Amarela, Tinta Barroca, Tinta Roriz, Tinto Cao, and Touriga Nacional <p><b>Space author: Gabriel Carneiro</b> <br><b> [email protected] </b> </p>" |
|
|
|
gr_interface = gr.Interface(infer, inputs, output, allow_flagging=False, analytics_enabled=False, css=css, title=title, description=description).launch(enable_queue=True, debug=False) |
|
|