From: ibidyouadu Date: Wed, 24 Jul 2024 04:39:18 +0000 (-0500) Subject: Add loading and making predictions with model, reporting prediction results X-Git-Url: http://git.angelumana.com/?a=commitdiff_plain;ds=sidebyside;p=wu-api%2F.git Add loading and making predictions with model, reporting prediction results --- diff --git a/app/data.py b/app/data.py index 4640904..5df7cce 100644 --- a/app/data.py +++ b/app/data.py @@ -1 +1,49 @@ -# TODO +from PIL import Image +from io import BytesIO +import base64 +import tensorflow as tf +from tensorflow import keras +from sklearn.preprocessing import LabelEncoder + +def load_image(contents): + """ + Given a base64 decoded image from a POST request to /result, return a tensorflow tensor + representation of the image data. + + Parameters + ---------- + contents : bytes + Output from UploadFile.read() + + Returns + ------- + image : tf.Tensor + Tensor representation of the image data + """ + bytes_image = BytesIO(contents) + + # Load image as batch tensor + # https://www.tensorflow.org/api_docs/python/tf/keras/utils/load_img + pil_image = keras.utils.load_img(bytes_image) + array_image = keras.utils.img_to_array(pil_image) + image = tf.convert_to_tensor(array_image) + + return image + +def preprocess_image(image): + """ + Normalize pixel values, reshape image if necessary, and convert to greyscale. + """ + # Normalize pixel values + image = image/255 + image = tf.cast(image, tf.float32) + + # Reshape + if image.shape != (400, 400, 3): + image = tf.image.resize(image, [400, 400]) + + # Convert to greyscale + image = tf.tensordot(image, tf.constant([0.299, 0.587, 0.114]), axes=[[2], [0]]) + # grey_image = tf.expand_dims(grey_image, -1) + + return image \ No newline at end of file diff --git a/app/inference.py b/app/inference.py index 4640904..3b6fa4d 100644 --- a/app/inference.py +++ b/app/inference.py @@ -1 +1,47 @@ -# TODO +from datasets import load_dataset +from tensorflow import keras +import tensorflow as tf +import numpy as np +from sklearn.preprocessing import LabelEncoder +from params import DATASET_REPO_ID, label_names_to_english + + +def get_label_encoder(): + """ + Create LabelEncoder object to translate integers to text. + """ + dataset_info = load_dataset(DATASET_REPO_ID, split="train", streaming=True)._info + labels = dataset_info.features['label'].names + labels = [label_names_to_english[l] for l in labels] + le = LabelEncoder() + le.fit(labels) + + return le + +def make_prediction(model, input): + """ + Make prediction for image and return the label and associated probability. + + Parameters + ---------- + model : keras.Sequential + The cloud identifier model + input : tf.Tensor + Output from preproceess_data() + + Returns + ------- + predicted_label_name : str + Name of the most likely label + predicted_proba : np.float64 + Probability of the most likely label + """ + batch = tf.expand_dims(input, axis=0) + probabilities = model.predict(batch) + predicted = np.argmax(probabilities) + predicted_proba = round(np.max(probabilities) * 100, 1) + + le = get_label_encoder() + predicted_label_name = le.inverse_transform(predicted.reshape(1,))[0] + + return predicted_label_name, predicted_proba \ No newline at end of file diff --git a/app/main.py b/app/main.py index 4088493..0d3e7b4 100644 --- a/app/main.py +++ b/app/main.py @@ -4,11 +4,14 @@ from fastapi.templating import Jinja2Templates from tempfile import NamedTemporaryFile import os import base64 +from data import load_image, preprocess_image +from model import get_model +from inference import make_prediction, get_label_encoder app = FastAPI() templates = Jinja2Templates("templates") -@app.get("/", response_class=HTMLResponse) +@app.get("/", response_class = HTMLResponse) def index(request: Request): context = {"request": request} response = templates.TemplateResponse("index.html", context) @@ -19,8 +22,17 @@ def index(request: Request): def show_image(request: Request, background_tasks: BackgroundTasks, input_image: UploadFile = File(...)): contents = input_image.file.read() encoded_image = base64.b64encode(contents).decode("utf-8") - - context = {"request": request, "image": encoded_image} + raw_image = load_image(contents) + image = preprocess_image(raw_image) + model = get_model() + predicted_label, predicted_probability = make_prediction(model, image) + + context = { + "request": request, + "image": encoded_image, + "predicted_label": predicted_label, + "predicted_probability": f"{predicted_probability}%" + } response = templates.TemplateResponse("result.html", context) return response diff --git a/app/model.py b/app/model.py index 4640904..8104469 100644 --- a/app/model.py +++ b/app/model.py @@ -1 +1,11 @@ -# TODO +from huggingface_hub import hf_hub_download +from tensorflow import keras +from params import MODEL_REPO_ID, MODEL_FILENAME +def get_model(): + """ + Download and load the model from huggingface + """ + model_path = hf_hub_download(repo_id=MODEL_REPO_ID, filename=MODEL_FILENAME) + model = keras.models.load_model(model_path) + + return model \ No newline at end of file diff --git a/app/params.py b/app/params.py new file mode 100644 index 0000000..a78bce1 --- /dev/null +++ b/app/params.py @@ -0,0 +1,16 @@ +DATASET_REPO_ID = "aduuuuuu/CCSN" +MODEL_REPO_ID = "aduuuuuu/wu" +MODEL_FILENAME = "model.h5" +label_names_to_english = { + "Ac": "altocumulus", + "As": "altostratus", + "Cb": "cumulonimbus", + "Cc": "cumulus", + "Ci": "cirrus", + "Cs": "cirrostratuss", + "Ct": "contrail", + "Cu": "cumulus", + "Ns": "nimbostratus", + "Sc": "stratocumulus", + "St": "stratus" +} \ No newline at end of file diff --git a/app/templates/result.html b/app/templates/result.html index 635ff30..dbe2148 100644 --- a/app/templates/result.html +++ b/app/templates/result.html @@ -1,6 +1,6 @@ -

Wow what a lovely pic !!!

+

Wu say this is a {{ predicted_label }} with probability {{ predicted_probability }}

Do it again, do it again! \ No newline at end of file