BlueSR's picture
Update app.py
d48c40a verified
Raw
History Blame Contribute Delete
11.2 kB
import torch
import torch.nn as nn
from torchvision import transforms
from torchvision.models import efficientnet_b0, mobilenet_v2, resnet18
import gradio as gr
import numpy as np
from PIL import Image
import joblib
import os
# Constants
NUM_CLASSES = 4
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
CLASS_NAMES = ['Cracked_road', 'Flooded_muddy', 'Good_condition', 'Potholes']
# Model paths with fallbacks for different deployment environments
MODEL_PATHS = {
"efficientnet": [
"best_efficientnet_model.pth",
"models/best_efficientnet_model.pth",
"assign2_Latest/models/best_efficientnet_model.pth"
],
"mobilenet": [
"best_mobilenetv2_model.pth",
"models/best_mobilenetv2_model.pth",
"assign2_Latest/models/best_mobilenetv2_model.pth"
],
"resnet": [
"best_resnet18_model.pth",
"models/best_resnet18_model.pth",
"assign2_Latest/models/best_resnet18_model.pth"
],
"rf": [
"rf_model.pkl",
"models/rf_model.pkl",
"assign2_Latest/models/rf_model.pkl"
]
}
# Build EfficientNet model
def build_efficientnet(num_classes=NUM_CLASSES):
"""Build EfficientNet-B0 based model"""
model = efficientnet_b0(weights=None)
# Replace classifier
in_features = model.classifier[1].in_features
model.classifier = nn.Sequential(
nn.Linear(in_features, 256),
nn.BatchNorm1d(256),
nn.ReLU(),
nn.Dropout(p=0.2),
nn.Linear(256, num_classes)
)
return model
# Build MobileNetV2 model
def build_mobilenet(num_classes=NUM_CLASSES):
"""Build MobileNetV2 model"""
model = mobilenet_v2(weights=None)
# Replace classifier
last_channel = model.last_channel
model.classifier = nn.Sequential(
nn.Dropout(p=0.2),
nn.Linear(last_channel, 512),
nn.BatchNorm1d(512),
nn.LeakyReLU(0.2),
nn.Dropout(p=0.2),
nn.Linear(512, 256),
nn.BatchNorm1d(256),
nn.LeakyReLU(0.2),
nn.Dropout(p=0.1),
nn.Linear(256, num_classes)
)
return model
# Build ResNet18 model
def build_resnet(num_classes=NUM_CLASSES):
"""Build ResNet18 model"""
model = resnet18(weights=None)
# Replace classifier
in_features = model.fc.in_features
model.fc = nn.Sequential(
nn.Linear(in_features, 256),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(256, num_classes)
)
return model
# Load model with fallback paths
def load_model(model_type):
"""Load trained model with fallback paths"""
if model_type == "efficientnet":
model = build_efficientnet()
elif model_type == "mobilenet":
model = build_mobilenet()
elif model_type == "resnet":
model = build_resnet()
elif model_type == "rf":
# For Random Forest, handled differently below
return load_rf_model()
else:
raise ValueError(f"Unknown model type: {model_type}")
# Try loading from various possible paths
paths = MODEL_PATHS[model_type]
model_loaded = False
for path in paths:
if os.path.exists(path):
try:
model.load_state_dict(torch.load(path, map_location=DEVICE))
model_loaded = True
print(f"{model_type} model loaded from {path}")
break
except Exception as e:
print(f"Failed to load {model_type} from {path}: {e}")
continue
if not model_loaded:
raise FileNotFoundError(f"Could not find or load {model_type} model file")
model.to(DEVICE)
model.eval()
return model
# Load Random Forest model
def load_rf_model():
"""Load Random Forest model"""
paths = MODEL_PATHS["rf"]
for path in paths:
if os.path.exists(path):
try:
model = joblib.load(path)
print(f"Random Forest model loaded from {path}")
return model
except Exception as e:
print(f"Failed to load RF model from {path}: {e}")
continue
raise FileNotFoundError("Could not find or load Random Forest model file")
# Extract features for Random Forest
def extract_features_single(model, image_tensor):
"""Extract features from a single image for Random Forest"""
model.eval()
# Create feature extractor (using EfficientNet)
feature_extractor = nn.Sequential(
model.features,
model.avgpool,
nn.Flatten()
).to(DEVICE)
with torch.no_grad():
features = feature_extractor(image_tensor).cpu().numpy()
return features
# Preprocess image for neural networks
def preprocess_image(image):
"""Preprocess image for model prediction"""
preprocess = transforms.Compose([
transforms.Resize((224, 224)),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
return preprocess(image).unsqueeze(0)
# Prediction function
def predict(img, model_choice, models):
"""Make prediction using selected model"""
if img is None:
return "No image provided", "Please upload an image"
try:
# Convert to RGB if needed
if img.mode != "RGB":
img = img.convert("RGB")
# Preprocess image
img_tensor = preprocess_image(img)
img_tensor = img_tensor.to(DEVICE)
if model_choice == "EfficientNet":
model = models["efficientnet"]
# Make prediction
with torch.no_grad():
outputs = model(img_tensor)
probabilities = torch.nn.functional.softmax(outputs, dim=1)[0]
predicted_class = torch.argmax(probabilities).item()
# Format confidence scores
confidence_scores = {CLASS_NAMES[i]: f"{probabilities[i].item()*100:.2f}%"
for i in range(len(CLASS_NAMES))}
confidence_text = "\n".join([f"{cls}: {score}" for cls, score in confidence_scores.items()])
return CLASS_NAMES[predicted_class], confidence_text
elif model_choice == "MobileNetV2":
model = models["mobilenet"]
# Make prediction
with torch.no_grad():
outputs = model(img_tensor)
probabilities = torch.nn.functional.softmax(outputs, dim=1)[0]
predicted_class = torch.argmax(probabilities).item()
# Format confidence scores
confidence_scores = {CLASS_NAMES[i]: f"{probabilities[i].item()*100:.2f}%"
for i in range(len(CLASS_NAMES))}
confidence_text = "\n".join([f"{cls}: {score}" for cls, score in confidence_scores.items()])
return CLASS_NAMES[predicted_class], confidence_text
elif model_choice == "ResNet18":
model = models["resnet"]
# Make prediction
with torch.no_grad():
outputs = model(img_tensor)
probabilities = torch.nn.functional.softmax(outputs, dim=1)[0]
predicted_class = torch.argmax(probabilities).item()
# Format confidence scores
confidence_scores = {CLASS_NAMES[i]: f"{probabilities[i].item()*100:.2f}%"
for i in range(len(CLASS_NAMES))}
confidence_text = "\n".join([f"{cls}: {score}" for cls, score in confidence_scores.items()])
return CLASS_NAMES[predicted_class], confidence_text
elif model_choice == "Random Forest":
# Extract features using EfficientNet
features = extract_features_single(models["efficientnet"], img_tensor)
# Make prediction with Random Forest
rf_model = models["rf"]
predicted_class = rf_model.predict(features)[0]
probabilities = rf_model.predict_proba(features)[0]
# Format confidence scores
confidence_scores = {CLASS_NAMES[i]: f"{probabilities[i]*100:.2f}%"
for i in range(len(CLASS_NAMES))}
confidence_text = "\n".join([f"{cls}: {score}" for cls, score in confidence_scores.items()])
return CLASS_NAMES[predicted_class], confidence_text
else:
return "Invalid model selection", "Please select a valid model"
except Exception as e:
return f"Error: {str(e)}", "An error occurred during prediction."
# Initialize models
print("Loading models...")
models = {}
try:
models["efficientnet"] = load_model("efficientnet")
models["mobilenet"] = load_model("mobilenet")
models["resnet"] = load_model("resnet")
models["rf"] = load_model("rf")
print("All models loaded successfully!")
except Exception as e:
print(f"Error loading models: {e}")
# In case of error, models will be empty or partial
# Create Gradio interface
with gr.Blocks(title="Road Surface Classification") as demo:
gr.Markdown("# Road Surface Classification")
gr.Markdown("Upload an image of a road surface to classify its condition using various models.")
with gr.Row():
with gr.Column():
image_input = gr.Image(type="pil", label="Upload Road Image")
model_selector = gr.Radio(
choices=["EfficientNet", "MobileNetV2", "ResNet18", "Random Forest"],
value="EfficientNet",
label="Select Model"
)
classify_btn = gr.Button("Classify", variant="primary")
with gr.Column():
label_output = gr.Textbox(label="Predicted Class", interactive=False)
confidence_output = gr.Textbox(
label="Confidence Scores",
lines=5,
interactive=False
)
# Event handler
classify_btn.click(
fn=lambda img, model_choice: predict(img, model_choice, models),
inputs=[image_input, model_selector],
outputs=[label_output, confidence_output]
)
# Add information about classes and models
with gr.Row():
with gr.Column():
gr.Markdown("### Classes")
gr.Markdown("- **Cracked_road**: Roads with visible cracks")
gr.Markdown("- **Flooded_muddy**: Roads affected by flooding or mud")
gr.Markdown("- **Good_condition**: Roads in good condition")
gr.Markdown("- **Potholes**: Roads with potholes")
with gr.Column():
gr.Markdown("### Models")
gr.Markdown("- **EfficientNet**: Efficient deep learning model")
gr.Markdown("- **MobileNetV2**: Lightweight mobile-friendly model")
gr.Markdown("- **ResNet18**: Residual network architecture")
gr.Markdown("- **Random Forest**: Traditional ML using CNN features")
# Launch the app
if __name__ == "__main__":
demo.launch()