Spaces:
Running
on
Zero
Running
on
Zero
import os | |
import numpy as np | |
import torch | |
import torch.nn as nn | |
import gradio as gr | |
from torchvision.models import efficientnet_v2_m, EfficientNet_V2_M_Weights | |
import torch.nn.functional as F | |
from torchvision import transforms | |
from PIL import Image | |
#from data_manager import get_dog_description | |
dog_breeds = ["Afghan_Hound(้ฟๅฏๆฑ็ต็ฌ)", "African_Hunting_Dog(้ๆดฒ้็ฌ)", "Airedale(่พ็พ่ฐท็ฌ)", | |
"American_Staffordshire_Terrier(็พๅๆฏๅก็ฆ้กๆข)", "Appenzeller(ไบ่ณๆพค็พ็ฌ)", | |
"Australian_Terrier(ๆพณๅคงๅฉไบๆข)", "Bedlington_Terrier(่ฒๅพท้้ ๆข)", | |
"Bernese_Mountain_Dog(ไผฏๆฉๅฑฑ็ฌ)", "Blenheim_Spaniel(ๅธ่ๅฐผๅง็ต็ฌ)", | |
"Border_Collie(้ๅข็ง็พ็ฌ)", "Border_Terrier(้ๅขๆข)", "Boston_Bull(ๆณขๅฃซ้ ๆข)", | |
"Bouvier_Des_Flandres(ๆณ่ญๅพทๆฏ็ง็พ็ฌ)", "Brabancon_Griffon(ๅธ้ญฏๅก็พๆ ผ้่ฌ็ฌ)", | |
"Brittany_Spaniel(ๅธๅๅกๅฐผ็ต็ฌ)", "Cardigan(ๅก่ฟชๆ นๅจ็พๅฃซๆฏๅบ็ฌ)", | |
"Chesapeake_Bay_Retriever(ๅ่ฉ็ฎๅ ็ฃ็ต็ฌ)", "Chihuahua(ๅๅจๅจ)", | |
"Dandie_Dinmont(ไธน็ฌฌไธ่ๆข)", "Doberman(ๆ่ณ็ฌ)", "English_Foxhound(่ฑๅ็ต็็ฌ)", | |
"English_Setter(่ฑๅ้ช้็ฌ)", "English_Springer(่ฑๅ่ทณ็ต็ฌ)", | |
"EntleBucher(ๆฉ็น้ทๅธ่ตซๅฑฑๅฐ็ฌ)", "Eskimo_Dog(ๆๆฏๅบๆฉ็ฌ)", "French_Bulldog(ๆณๅ้ฌฅ็็ฌ)", | |
"German_Shepherd(ๅพทๅ็ง็พ็ฌ)", "German_Short-Haired_Pointer(ๅพทๅ็ญๆฏๆ็คบ็ฌ)", | |
"Gordon_Setter(ๆ็ป้ช้็ฌ)", "Great_Dane(ๅคงไธน็ฌ)", "Great_Pyrenees(ๅคง็ฝ็็ฌ)", | |
"Greater_Swiss_Mountain_Dog(ๅคง็ๅฃซๅฑฑๅฐ็ฌ)", "Ibizan_Hound(ไพๆฏๆฒ็ต็ฌ)", | |
"Irish_Setter(ๆ็พ่ญ้ช้็ฌ)", "Irish_Terrier(ๆ็พ่ญๆข)", | |
"Irish_Water_Spaniel(ๆ็พ่ญๆฐด็ต็ฌ)", "Irish_Wolfhound(ๆ็พ่ญ็ต็ผ็ฌ)", | |
"Italian_Greyhound(็พฉๅคงๅฉ็ฐ็)", "Japanese_Spaniel(ๆฅๆฌ็)", | |
"Kerry_Blue_Terrier(ๅฑๅฉ่ๆข)", "Labrador_Retriever(ๆๅธๆๅคๅฐๅ็ฌ)", | |
"Lakeland_Terrier(ๆน็ๆข)", "Leonberg(็ ๆฏ็)", "Lhasa(ๆ่ฉ็ฌ)", | |
"Maltese_Dog(้ฆฌ็พๆฟๆฏ็ฌ)", "Mexican_Hairless(ๅขจ่ฅฟๅฅ็กๆฏ็ฌ)", "Newfoundland(็ด่ฌ่ญ็ฌ)", | |
"Norfolk_Terrier(่ซพ็ฆๅ ๆข)", "Norwegian_Elkhound(ๆชๅจ็ต้บ็ฌ)", | |
"Norwich_Terrier(่ซพๅฉๆฒปๆข)", "Old_English_Sheepdog(ๅคไปฃ่ฑๅ็ง็พ็ฌ)", | |
"Pekinese(ๅไบฌ็ฌ)", "Pembroke(ๅจ็พๅฃซๆฏๅบ็ฌ)", "Pomeranian(ๅ็พ็ฌ)", | |
"Rhodesian_Ridgeback(็พ ๅพ่ฅฟไบ่่็ฌ)", "Rottweiler(็พ ๅจ็ด็ฌ)", | |
"Saint_Bernard(่ไผฏ็ด็ฌ)", "Saluki(่ฉ่ทฏๅบ็ต็ฌ)", "Samoyed(่ฉๆฉ่ถ็ฌ)", | |
"Scotch_Terrier(่ๆ ผ่ญๆข)", "Scottish_Deerhound(่ๆ ผ่ญ็ต้นฟ็ฌ)", | |
"Sealyham_Terrier(้ซๅฉๅๅงๆข)", "Shetland_Sheepdog(่จญๅพ่ญ็ง็พ็ฌ)", | |
"Shih-Tzu(่ฅฟๆฝ็ฌ)", "Siberian_Husky(่ฅฟไผฏๅฉไบๅๅฃซๅฅ)", | |
"Staffordshire_Bullterrier(ๆฏๅก็ฆ้ก้ฌฅ็ๆข)", "Sussex_Spaniel(่ๅกๅ ๆฏ็ต็ฌ)", | |
"Tibetan_Mastiff(่็)", "Tibetan_Terrier(่ฅฟ่ๆข)", "Walker_Hound(ๆฒๅ ็ต็ฌ)", | |
"Weimaraner(ๅจ็ช็ฌ)", "Welsh_Springer_Spaniel(ๅจ็พๅฃซ่ทณ็ต็ฌ)", | |
"West_Highland_White_Terrier(่ฅฟ้ซๅฐ็ฝๆข)", "Yorkshire_Terrier(็ดๅ ๅคๆข)", | |
"Affenpinscher(็ด็ฌ)", "Basenji(ๅทด่พๅ็ฌ)", "Basset(ๅทดๅๅบฆ็ต็ฌ)", "Beagle(ๆฏๆ ผ็ฌ)", | |
"Black-and-Tan_Coonhound(้ป่ค็ตๆตฃ็็ฌ)", "Bloodhound(ๅฐ่ก็ต็ฌ)", | |
"Bluetick(ๅธ้ญฏๆๅ ็ต็ฌ)", "Borzoi(ไฟ็พ ๆฏ็ต็ผ็ฌ)", "Boxer(ๆณๅธซ็ฌ)", "Briard(ๅธ้ไบ็ฌ)", | |
"Bull_Mastiff(็็ฌ)", "Cairn(ๅฑๆฉๆข)", "Chow(้ฌ็ ็ฌ)", "Clumber(ๅ ๅซไผฏ็ต็ฌ)", | |
"Cocker_Spaniel(ๅฏๅก็ต็ฌ)", "Collie(ๆฏๅฉ็ง็พ็ฌ)", "Curly-Coated_Retriever(ๆฒๆฏๅฐๅ็ฌ)", | |
"Dhole(่ฑบ)", "Dingo(ๆพณๆดฒ้็ฌ)", "Flat-Coated_Retriever(ๅนณๆฏๅฐๅ็ฌ)", | |
"Giant_Schnauzer(ๅคงๅ้ช็ด็็ฌ)", "Golden_Retriever(้ป้็ต็ฌ)", | |
"Groenendael(ๆฏๅฉๆ็ง็พ็ฌ)", "Keeshond(่ท่ญๆฏ็ ็ฌ)", "Kelpie(ๆพณๆดฒๅก็พๆฏ็ฌ)", | |
"Komondor(ๅ็ๅฉ็ง็พ็ฌ)", "Kuvasz(ๅบซ็ฆ่ฒ็ฌ)", "Malamute(้ฟๆๆฏๅ ้ชๆฉ็ฌ)", | |
"Malinois(ๆฏๅฉๆ็ชๅฉ่ซพ็ฌ)", "Miniature_Pinscher(่ฟทไฝ ๆ่ณ็ฌ)", | |
"Miniature_Poodle(่ฟทไฝ ่ฒด่ณ็ฌ)", "Miniature_Schnauzer(่ฟทไฝ ้ช็ด็็ฌ)", | |
"Otterhound(ๆฐด็บ็ต็ฌ)", "Papillon(่ด่ถ็ฌ)", "Pug(ๅทดๅฅ็ฌ)", "Redbone(็ด ้ชจ็ตๆตฃ็็ฌ)", | |
"Schipperke(่ๆๅฅ็ฌ)", "Silky_Terrier(็ตฒๆฏๆข)", | |
"Soft-Coated_Wheaten_Terrier(ๆ็พ่ญ่ปๆฏๆข)", "Standard_Poodle(ๆจๆบ่ฒด่ณ็ฌ)", | |
"Standard_Schnauzer(ๆจๆบ้ช็ด็็ฌ)", "Toy_Poodle(็ฉๅ ท่ฒด่ณ็ฌ)", "Toy_Terrier(็ฉๅ ทๆข)", | |
"Vizsla(็ถญ่ฒๆ็ฌ)", "Whippet(ๆ ๆฏ็น็ฌ)", "Wire-Haired_Fox_Terrier(็กฌๆฏ็ต็ๆข)"] | |
class MultiHeadAttention(nn.Module): | |
def __init__(self, in_dim, num_heads=8): | |
super().__init__() | |
self.num_heads = num_heads | |
self.head_dim = max(1, in_dim // num_heads) | |
self.scaled_dim = self.head_dim * num_heads | |
self.fc_in = nn.Linear(in_dim, self.scaled_dim) | |
self.query = nn.Linear(self.scaled_dim, self.scaled_dim) | |
self.key = nn.Linear(self.scaled_dim, self.scaled_dim) | |
self.value = nn.Linear(self.scaled_dim, self.scaled_dim) | |
self.fc_out = nn.Linear(self.scaled_dim, in_dim) | |
def forward(self, x): | |
N = x.shape[0] | |
x = self.fc_in(x) | |
q = self.query(x).view(N, self.num_heads, self.head_dim) | |
k = self.key(x).view(N, self.num_heads, self.head_dim) | |
v = self.value(x).view(N, self.num_heads, self.head_dim) | |
energy = torch.einsum("nqd,nkd->nqk", [q, k]) | |
attention = F.softmax(energy / (self.head_dim ** 0.5), dim=2) | |
out = torch.einsum("nqk,nvd->nqd", [attention, v]) | |
out = out.reshape(N, self.scaled_dim) | |
out = self.fc_out(out) | |
return out | |
class BaseModel(nn.Module): | |
def __init__(self, num_classes, device='cuda' if torch.cuda.is_available() else 'cpu'): | |
super().__init__() | |
self.device = device | |
self.backbone = efficientnet_v2_m(weights=EfficientNet_V2_M_Weights.IMAGENET1K_V1) | |
self.feature_dim = self.backbone.classifier[1].in_features | |
self.backbone.classifier = nn.Identity() | |
# ๅๆ ่จ็ฎ num_heads | |
self.num_heads = max(1, min(8, self.feature_dim // 64)) | |
self.attention = MultiHeadAttention(self.feature_dim, num_heads=self.num_heads) | |
self.classifier = nn.Sequential( | |
nn.LayerNorm(self.feature_dim), | |
nn.Dropout(0.3), | |
nn.Linear(self.feature_dim, num_classes) | |
) | |
self.to(device) | |
def forward(self, x): | |
x = x.to(self.device) | |
features = self.backbone(x) | |
attended_features = self.attention(features) | |
logits = self.classifier(attended_features) | |
return logits, attended_features | |
num_classes = 120 | |
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') | |
model = BaseModel(num_classes=num_classes, device=device) | |
checkpoint = torch.load('/content/drive/Othercomputers/ๆ็ MacBook Pro/Learning/Cats_Dogs_Detector/best_model/best_model_81_dog.pth', map_location=torch.device('cpu')) | |
model.load_state_dict(checkpoint['model_state_dict']) | |
# ๅฐๆจกๅ่จญ็ฝฎ็บ่ฉไผฐๆจกๅผ | |
model.eval() | |
# Image preprocessing function | |
def preprocess_image(image): | |
# ๅฆๆๅ็ๆฏ numpy.ndarray ่ฝๆ็บ PIL.Image | |
if isinstance(image, np.ndarray): | |
image = Image.fromarray(image) | |
# ไฝฟ็จ torchvision.transforms ้ฒ่ก้ ่็ | |
transform = transforms.Compose([ | |
transforms.Resize((224, 224)), | |
transforms.ToTensor(), | |
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), | |
]) | |
return transform(image).unsqueeze(0) | |
def predict(image): | |
try: | |
image_tensor = preprocess_image(image) | |
with torch.no_grad(): | |
logits, _ = model(image_tensor) | |
_, predicted = torch.max(logits, 1) | |
breed = dog_breeds[predicted.item()] # Map label to breed name | |
# Retrieve breed description | |
description = get_dog_description(breed) | |
# Formatting the description for better display | |
if isinstance(description, dict): | |
description_str = f"**Breed**: {description['Breed']}\n\n" | |
description_str += f"**Size**: {description['Size']}\n\n" | |
description_str += f"**Lifespan**: {description['Lifespan']}\n\n" | |
description_str += f"**Temperament**: {description['Temperament']}\n\n" | |
description_str += f"**Care Level**: {description['Care Level']}\n\n" | |
description_str += f"**Good with Children**: {description['Good with Children']}\n\n" | |
description_str += f"**Exercise Needs**: {description['Exercise Needs']}\n\n" | |
description_str += f"**Grooming Needs**: {description['Grooming Needs']}\n\n" | |
description_str += f"**Description**: {description['Description']}\n\n" | |
else: | |
description_str = description | |
return description_str | |
except Exception as e: | |
return f"An error occurred: {e}" | |
iface = gr.Interface( | |
fn=predict, | |
inputs=gr.Image(label="Upload an image", type="numpy"), # ๆฏๆๆๆพๅๅ็็ทจ่ผฏ | |
outputs="markdown", | |
title="<span style='font-family:Roboto; font-weight:bold; color:#2C3E50;'>Dog Breed Classifier</span>", | |
description="<span style='font-family:Open Sans; color:#34495E;'>Upload an image, and the system will predict the breed and provide detailed information from the database.</span>", | |
examples=['/content/drive/Othercomputers/ๆ็ MacBook Pro/Learning/Cats_Dogs_Detector/Border_Collie.jpg', | |
'/content/drive/Othercomputers/ๆ็ MacBook Pro/Learning/Cats_Dogs_Detector/Golden_Retriever.jpeg', | |
'/content/drive/Othercomputers/ๆ็ MacBook Pro/Learning/Cats_Dogs_Detector/Saint_Bernard.jpeg', | |
'/content/drive/Othercomputers/ๆ็ MacBook Pro/Learning/Cats_Dogs_Detector/French_Bulldog.jpeg', | |
'/content/drive/Othercomputers/ๆ็ MacBook Pro/Learning/Cats_Dogs_Detector/Samoyed.jpg'], | |
css=""" | |
.output-markdown { | |
font-family: Noto Sans, sans-serif; | |
line-height: 1.6; | |
} | |
.gr-button { | |
background-color: #3498DB; | |
color: white; | |
border-radius: 8px; | |
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.2); | |
padding: 10px 20px; | |
} | |
.gr-button:hover { | |
background-color: #2980B9; | |
} | |
.gr-box { | |
background: linear-gradient(to bottom, #f2f4f5, #ffffff); | |
border-radius: 10px; | |
padding: 20px; | |
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1); | |
} | |
""", | |
theme="default" | |
) | |
# Launch the app | |
if __name__ == "__main__": | |
iface.launch() | |