skin-type-api / model.py
anismizi's picture
"Modify model.py file to match training methodology"
da4fa03
import numpy as np
import torch
from torchvision import transforms
from PIL import Image
import pickle
import os
def load_model():
"""
Load the trained PyTorch model and class labels.
"""
# Get the directory where this script is located
script_dir = os.path.dirname(os.path.abspath(__file__))
model_dir = os.path.join(script_dir, "model")
# Load label mapping
label_maps_path = os.path.join(model_dir, "label_maps.pkl")
with open(label_maps_path, "rb") as f:
label_maps = pickle.load(f)
# Extract class names using the correct structure from training
# The label_maps.pkl contains: {'label_index': {'dry': 0, 'normal': 1, 'oily': 2}, 'index_label': {0: 'dry', 1: 'normal', 2: 'oily'}}
if 'index_label' in label_maps:
# Use index_label mapping to get class names in correct order
index_label = label_maps['index_label']
class_names = [index_label[i] for i in sorted(index_label.keys())]
else:
# Fallback for different format
if isinstance(next(iter(label_maps.values())), str):
# Example: {0: "dry", 1: "normal", 2: "oily"}
class_names = [label_maps[i] for i in sorted(label_maps.keys())]
elif isinstance(next(iter(label_maps.values())), dict):
# Example: {"dry": 0, "normal": 1, "oily": 2}
class_names = list(next(iter(label_maps.values())).keys())
else:
raise ValueError("Unexpected format in label_maps.pkl")
# Load the trained PyTorch model
model_path = os.path.join(model_dir, "best_skin_model_entire.pth")
model = torch.load(model_path, map_location="cpu")
model.eval()
print(f"✅ Model loaded with {len(class_names)} classes: {class_names}")
print(f"✅ Class order: {class_names}")
return model, class_names
# Image preprocessing pipeline (matches training setup)
preprocess = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
def predict(model, image: Image.Image, class_names):
"""
Perform prediction on a single image and return top class and probabilities.
"""
img_tensor = preprocess(image).unsqueeze(0) # Add batch dimension
with torch.no_grad():
outputs = model(img_tensor)
# Fix: Apply softmax to the entire batch output, not individual element
probs = torch.nn.functional.softmax(outputs, dim=1)[0] # Get first (and only) batch item
# Ensure number of classes matches model output size
num_classes = probs.shape[0]
# Ensure class_names are in the correct order (should already be fixed in load_model)
if len(class_names) != num_classes:
print(f"Warning: class_names length ({len(class_names)}) != model output classes ({num_classes})")
class_names = class_names[:num_classes]
predictions = [
{"class": class_names[i], "confidence": round(float(probs[i]), 4)}
for i in range(num_classes)
]
predictions.sort(key=lambda x: x["confidence"], reverse=True)
return {
"predictions": predictions,
"top_class": predictions[0]["class"],
"raw_scores": [round(float(probs[i]), 6) for i in range(num_classes)] # For debugging
}