|
import gradio as gr |
|
from PIL import Image |
|
import numpy as np |
|
import json |
|
from torchvision import models |
|
import torch.nn.functional as F |
|
from torch import nn |
|
import torch |
|
import matplotlib.pyplot as plt |
|
import matplotlib.ticker as ticker |
|
from huggingface_hub import HfApi |
|
|
|
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") |
|
|
|
def load_checkpoint(filepath): |
|
"""Builds PyTorch Model from saved model |
|
Returns built model |
|
|
|
Arguments: string, filepath of saved PyTorch model |
|
""" |
|
|
|
|
|
weights = "IMAGENET1K_V1" |
|
|
|
|
|
model = models.maxvit_t(weights=weights) |
|
|
|
|
|
checkpoint = torch.load(filepath, map_location=torch.device("cpu")) |
|
|
|
|
|
new_classifier = checkpoint["classifier"] |
|
|
|
|
|
model.classifier[5] = new_classifier |
|
|
|
|
|
model.load_state_dict(checkpoint["state_dict"]) |
|
|
|
|
|
model.class_to_idx = checkpoint["class_to_idx"] |
|
|
|
return model |
|
|
|
|
|
class Network(nn.Module): |
|
def __init__(self, input_size, hidden_layers, output_size=102, drop_p=0.2): |
|
"""Builds a feedforward network with arbitrary hidden layers. |
|
|
|
Arguments |
|
--------- |
|
input_size: integer, size of the input layer |
|
output_size: integer, size of the output layer |
|
hidden_layers: list of integers, the sizes of the hidden layers |
|
drop_p: float, dropout probability |
|
""" |
|
super().__init__() |
|
|
|
self.drop_p = drop_p |
|
|
|
|
|
self.hidden_layers = nn.ModuleList([nn.Linear(input_size, hidden_layers[0])]) |
|
|
|
|
|
layer_sizes = zip(hidden_layers[:-1], hidden_layers[1:]) |
|
self.hidden_layers.extend([nn.Linear(h1, h2) for h1, h2 in layer_sizes]) |
|
|
|
self.output = nn.Linear(hidden_layers[-1], output_size) |
|
|
|
print( |
|
f"\nNumber of layers: {len(self.hidden_layers)}" |
|
f"\nNumber of units in layers:{hidden_layers}" |
|
) |
|
|
|
def forward(self, x): |
|
"""Forward pass through the network, returns the output logits""" |
|
|
|
for each in self.hidden_layers: |
|
x = F.relu(each(x)) |
|
x = F.dropout(x, self.drop_p) |
|
x = self.output(x) |
|
|
|
return F.log_softmax(x, dim=1) |
|
|
|
def process_image(img_path): |
|
"""Scales, crops, and normalizes a PIL image for a PyTorch model, |
|
returns a Numpy array |
|
|
|
Arguments |
|
--------- |
|
image: path of the image to be processed |
|
""" |
|
inp = Image.open(img_path) |
|
exif = inp.getexif() |
|
|
|
|
|
w, h = inp.size |
|
|
|
|
|
os.makedirs("inference", exist_ok=True) |
|
|
|
|
|
image_path = re.sub(r"\W+", "", img_path) |
|
image_path = str(datetime.now()) + ".png" |
|
|
|
|
|
inf_image = os.path.join("inference", img_path) |
|
|
|
|
|
inp.save(inf_image, exif=exif) |
|
HfApi().upload_file( |
|
path_or_fileobj=inf_image, |
|
path_in_repo=image_path, |
|
repo_id="DanielPFlorian/flower-image-classifier", |
|
repo_type="dataset", |
|
token=HF_TOKEN, |
|
) |
|
|
|
|
|
if w > h: |
|
inp.thumbnail((10000, 256)) |
|
elif h > w: |
|
inp.thumbnail((256, 10000)) |
|
else: |
|
inp.thumbnail((256, 256)) |
|
|
|
|
|
w, h = inp.size |
|
left = (w - 224) // 2 |
|
top = (h - 224) // 2 |
|
right = (w + 224) // 2 |
|
bottom = (h + 224) // 2 |
|
image = inp.crop((left, top, right, bottom)) |
|
|
|
|
|
np_image = np.array(image) / 255 |
|
|
|
|
|
mean = np.array([0.485, 0.456, 0.406]) |
|
std = np.array([0.229, 0.224, 0.225]) |
|
np_image = (np_image - mean) / std |
|
|
|
|
|
np_image = np_image.transpose((2, 0, 1)) |
|
|
|
return np_image |
|
|
|
def predict(image_path, model=model, category_names=cat_to_name, topk=5): |
|
"""Predict the class (or classes) of an image using a trained deep learning model. |
|
Arguments |
|
--------- |
|
image_path: path of the image to be processed |
|
model: model to be used for prediction |
|
topk: number of top predicted classes to return |
|
""" |
|
|
|
image = process_image(image_path) |
|
|
|
|
|
image = torch.as_tensor(image).view((1, 3, 224, 224)).float() |
|
|
|
|
|
model.eval() |
|
|
|
|
|
with torch.no_grad(): |
|
|
|
log_ps = model.forward(image) |
|
|
|
|
|
ps = torch.exp(log_ps) |
|
|
|
|
|
top_probs, idx = ps.topk(topk, dim=1) |
|
|
|
|
|
top_probs, idx = top_probs.tolist()[0], idx.tolist()[0] |
|
|
|
|
|
percentages = [round(prob * 100.00, 2) for prob in top_probs] |
|
|
|
|
|
idx_to_class = {val: key for key, val in model.class_to_idx.items()} |
|
|
|
|
|
top_labels = [idx_to_class[lab] for lab in idx] |
|
|
|
|
|
if category_names: |
|
top_labels = [category_names[str(lab)] for lab in top_labels] |
|
|
|
|
|
|
|
image = Image.open(image_path) |
|
fig, (ax1, ax2) = plt.subplots(ncols=2) |
|
ax1.imshow(image) |
|
ax1.axis("off") |
|
ax2.barh(np.arange(len(top_labels)), percentages) |
|
asp = np.diff(ax2.get_xlim())[0] / np.diff(ax2.get_ylim())[0] |
|
ax2.set_aspect(asp) |
|
ax2.set_yticks(np.arange(len(top_labels))) |
|
ax2.set_yticklabels(top_labels) |
|
ax2.invert_yaxis() |
|
ax2.xaxis.set_major_formatter(ticker.PercentFormatter()) |
|
plt.tight_layout() |
|
ax2.set_title("Class Probability") |
|
plt.show() |
|
|
|
return fig |
|
|
|
gr.Interface( |
|
predict, |
|
inputs=gr.inputs.Image(label="Upload a flower image", type="filepath"), |
|
outputs=gr.outputs.Label(num_top_classes=5), |
|
title="What kind of flower is this?", |
|
).launch() |