BlueSR commited on
Commit
d48c40a
·
verified ·
1 Parent(s): 3f35e21

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +191 -83
app.py CHANGED
@@ -1,7 +1,7 @@
1
  import torch
2
  import torch.nn as nn
3
  from torchvision import transforms
4
- from torchvision.models import efficientnet_b0
5
  import gradio as gr
6
  import numpy as np
7
  from PIL import Image
@@ -13,12 +13,36 @@ NUM_CLASSES = 4
13
  DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
14
  CLASS_NAMES = ['Cracked_road', 'Flooded_muddy', 'Good_condition', 'Potholes']
15
 
16
- # Build CNN model architecture (from train_cnn.py)
17
- def build_model(num_classes=4):
18
- """Build EfficientNet-B0 based model for road surface classification"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  model = efficientnet_b0(weights=None)
20
 
21
- # Replace classifier with custom layers
22
  in_features = model.classifier[1].in_features
23
  model.classifier = nn.Sequential(
24
  nn.Linear(in_features, 256),
@@ -30,71 +54,118 @@ def build_model(num_classes=4):
30
 
31
  return model
32
 
33
- # Load the CNN model
34
- def load_cnn_model():
35
- """Load the trained CNN model"""
36
- model = build_model(NUM_CLASSES)
37
-
38
- # Try different possible paths for the model file
39
- model_paths = [
40
- "best_cnn_model.pth",
41
- "models/best_cnn_model.pth",
42
- "assign2_Latest/models/best_cnn_model.pth"
43
- ]
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  model_loaded = False
46
- for path in model_paths:
 
47
  if os.path.exists(path):
48
  try:
49
  model.load_state_dict(torch.load(path, map_location=DEVICE))
50
  model_loaded = True
51
- print(f"CNN model loaded from {path}")
52
  break
53
  except Exception as e:
54
- print(f"Failed to load from {path}: {e}")
55
  continue
56
 
57
  if not model_loaded:
58
- raise FileNotFoundError("Could not find or load CNN model file")
59
 
60
  model.to(DEVICE)
61
  model.eval()
62
  return model
63
 
64
- # Load the Random Forest model
65
  def load_rf_model():
66
- """Load the trained Random Forest model"""
67
- rf_paths = [
68
- "rf_model.pkl",
69
- "models/rf_model.pkl",
70
- "assign2_Latest/models/rf_model.pkl"
71
- ]
72
 
73
- for path in rf_paths:
74
  if os.path.exists(path):
75
  try:
76
- return joblib.load(path)
 
 
77
  except Exception as e:
78
  print(f"Failed to load RF model from {path}: {e}")
79
  continue
80
 
81
  raise FileNotFoundError("Could not find or load Random Forest model file")
82
 
83
- # Extract features using CNN for Random Forest
84
- def extract_features_single(cnn_model, image_tensor):
85
- """Extract features from a single image using CNN for Random Forest"""
86
- cnn_model.eval()
 
 
 
 
 
 
 
 
87
  with torch.no_grad():
88
- # Extract raw 1280-dim features (matching how the RF model was trained)
89
- features = cnn_model.features(image_tensor)
90
- features = cnn_model.avgpool(features)
91
- features = torch.flatten(features, 1)
92
-
93
- return features.cpu().numpy()
94
 
95
- # Preprocess image for CNN
96
- def preprocess_image_cnn(image):
97
- """Preprocess image for CNN prediction"""
98
  preprocess = transforms.Compose([
99
  transforms.Resize((224, 224)),
100
  transforms.CenterCrop(224),
@@ -103,32 +174,26 @@ def preprocess_image_cnn(image):
103
  ])
104
  return preprocess(image).unsqueeze(0)
105
 
106
- # Preprocess image for RF
107
- def preprocess_image_rf(image, cnn_model):
108
- """Preprocess image for Random Forest prediction using CNN features"""
109
- # First preprocess for CNN
110
- img_tensor = preprocess_image_cnn(image)
111
- img_tensor = img_tensor.to(DEVICE)
112
-
113
- # Extract features using CNN
114
- features = extract_features_single(cnn_model, img_tensor)
115
- return features
116
-
117
  # Prediction function
118
- def predict(img, model_choice, cnn_model, rf_model):
119
  """Make prediction using selected model"""
120
  if img is None:
121
  return "No image provided", "Please upload an image"
122
 
123
  try:
124
- if model_choice == "CNN":
125
- # Preprocess for CNN
126
- img_tensor = preprocess_image_cnn(img)
127
- img_tensor = img_tensor.to(DEVICE)
128
 
129
- # Get prediction
 
 
 
 
 
 
130
  with torch.no_grad():
131
- outputs = cnn_model(img_tensor)
132
  probabilities = torch.nn.functional.softmax(outputs, dim=1)[0]
133
  predicted_class = torch.argmax(probabilities).item()
134
 
@@ -138,14 +203,45 @@ def predict(img, model_choice, cnn_model, rf_model):
138
  confidence_text = "\n".join([f"{cls}: {score}" for cls, score in confidence_scores.items()])
139
 
140
  return CLASS_NAMES[predicted_class], confidence_text
141
-
142
- else: # Random Forest
143
- # Preprocess for RF using CNN features
144
- img_features = preprocess_image_rf(img, cnn_model)
145
 
146
- # Get prediction
147
- predicted_class = rf_model.predict(img_features)[0]
148
- probabilities = rf_model.predict_proba(img_features)[0]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
 
150
  # Format confidence scores
151
  confidence_scores = {CLASS_NAMES[i]: f"{probabilities[i]*100:.2f}%"
@@ -153,33 +249,36 @@ def predict(img, model_choice, cnn_model, rf_model):
153
  confidence_text = "\n".join([f"{cls}: {score}" for cls, score in confidence_scores.items()])
154
 
155
  return CLASS_NAMES[predicted_class], confidence_text
 
 
156
 
157
  except Exception as e:
158
  return f"Error: {str(e)}", "An error occurred during prediction."
159
 
160
  # Initialize models
161
  print("Loading models...")
 
162
  try:
163
- cnn_model = load_cnn_model()
164
- rf_model = load_rf_model()
165
- print("Models loaded successfully!")
 
 
166
  except Exception as e:
167
  print(f"Error loading models: {e}")
168
- # Create dummy models for testing
169
- cnn_model = None
170
- rf_model = None
171
 
172
  # Create Gradio interface
173
  with gr.Blocks(title="Road Surface Classification") as demo:
174
  gr.Markdown("# Road Surface Classification")
175
- gr.Markdown("Upload an image of a road surface to classify its condition using either CNN or Random Forest models.")
176
 
177
  with gr.Row():
178
  with gr.Column():
179
  image_input = gr.Image(type="pil", label="Upload Road Image")
180
  model_selector = gr.Radio(
181
- choices=["CNN", "Random Forest"],
182
- value="CNN",
183
  label="Select Model"
184
  )
185
  classify_btn = gr.Button("Classify", variant="primary")
@@ -194,17 +293,26 @@ with gr.Blocks(title="Road Surface Classification") as demo:
194
 
195
  # Event handler
196
  classify_btn.click(
197
- fn=lambda img, model_choice: predict(img, model_choice, cnn_model, rf_model),
198
  inputs=[image_input, model_selector],
199
  outputs=[label_output, confidence_output]
200
  )
201
 
202
- # Add information about classes
203
- gr.Markdown("### Classes")
204
- gr.Markdown("- **Cracked_road**: Roads with visible cracks")
205
- gr.Markdown("- **Flooded_muddy**: Roads affected by flooding or mud")
206
- gr.Markdown("- **Good_condition**: Roads in good condition")
207
- gr.Markdown("- **Potholes**: Roads with potholes")
 
 
 
 
 
 
 
 
 
208
 
209
  # Launch the app
210
  if __name__ == "__main__":
 
1
  import torch
2
  import torch.nn as nn
3
  from torchvision import transforms
4
+ from torchvision.models import efficientnet_b0, mobilenet_v2, resnet18
5
  import gradio as gr
6
  import numpy as np
7
  from PIL import Image
 
13
  DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
14
  CLASS_NAMES = ['Cracked_road', 'Flooded_muddy', 'Good_condition', 'Potholes']
15
 
16
+ # Model paths with fallbacks for different deployment environments
17
+ MODEL_PATHS = {
18
+ "efficientnet": [
19
+ "best_efficientnet_model.pth",
20
+ "models/best_efficientnet_model.pth",
21
+ "assign2_Latest/models/best_efficientnet_model.pth"
22
+ ],
23
+ "mobilenet": [
24
+ "best_mobilenetv2_model.pth",
25
+ "models/best_mobilenetv2_model.pth",
26
+ "assign2_Latest/models/best_mobilenetv2_model.pth"
27
+ ],
28
+ "resnet": [
29
+ "best_resnet18_model.pth",
30
+ "models/best_resnet18_model.pth",
31
+ "assign2_Latest/models/best_resnet18_model.pth"
32
+ ],
33
+ "rf": [
34
+ "rf_model.pkl",
35
+ "models/rf_model.pkl",
36
+ "assign2_Latest/models/rf_model.pkl"
37
+ ]
38
+ }
39
+
40
+ # Build EfficientNet model
41
+ def build_efficientnet(num_classes=NUM_CLASSES):
42
+ """Build EfficientNet-B0 based model"""
43
  model = efficientnet_b0(weights=None)
44
 
45
+ # Replace classifier
46
  in_features = model.classifier[1].in_features
47
  model.classifier = nn.Sequential(
48
  nn.Linear(in_features, 256),
 
54
 
55
  return model
56
 
57
+ # Build MobileNetV2 model
58
+ def build_mobilenet(num_classes=NUM_CLASSES):
59
+ """Build MobileNetV2 model"""
60
+ model = mobilenet_v2(weights=None)
 
 
 
 
 
 
 
61
 
62
+ # Replace classifier
63
+ last_channel = model.last_channel
64
+ model.classifier = nn.Sequential(
65
+ nn.Dropout(p=0.2),
66
+ nn.Linear(last_channel, 512),
67
+ nn.BatchNorm1d(512),
68
+ nn.LeakyReLU(0.2),
69
+ nn.Dropout(p=0.2),
70
+ nn.Linear(512, 256),
71
+ nn.BatchNorm1d(256),
72
+ nn.LeakyReLU(0.2),
73
+ nn.Dropout(p=0.1),
74
+ nn.Linear(256, num_classes)
75
+ )
76
+
77
+ return model
78
+
79
+ # Build ResNet18 model
80
+ def build_resnet(num_classes=NUM_CLASSES):
81
+ """Build ResNet18 model"""
82
+ model = resnet18(weights=None)
83
+
84
+ # Replace classifier
85
+ in_features = model.fc.in_features
86
+ model.fc = nn.Sequential(
87
+ nn.Linear(in_features, 256),
88
+ nn.ReLU(),
89
+ nn.Dropout(0.3),
90
+ nn.Linear(256, num_classes)
91
+ )
92
+
93
+ return model
94
+
95
+ # Load model with fallback paths
96
+ def load_model(model_type):
97
+ """Load trained model with fallback paths"""
98
+ if model_type == "efficientnet":
99
+ model = build_efficientnet()
100
+ elif model_type == "mobilenet":
101
+ model = build_mobilenet()
102
+ elif model_type == "resnet":
103
+ model = build_resnet()
104
+ elif model_type == "rf":
105
+ # For Random Forest, handled differently below
106
+ return load_rf_model()
107
+ else:
108
+ raise ValueError(f"Unknown model type: {model_type}")
109
+
110
+ # Try loading from various possible paths
111
+ paths = MODEL_PATHS[model_type]
112
  model_loaded = False
113
+
114
+ for path in paths:
115
  if os.path.exists(path):
116
  try:
117
  model.load_state_dict(torch.load(path, map_location=DEVICE))
118
  model_loaded = True
119
+ print(f"{model_type} model loaded from {path}")
120
  break
121
  except Exception as e:
122
+ print(f"Failed to load {model_type} from {path}: {e}")
123
  continue
124
 
125
  if not model_loaded:
126
+ raise FileNotFoundError(f"Could not find or load {model_type} model file")
127
 
128
  model.to(DEVICE)
129
  model.eval()
130
  return model
131
 
132
+ # Load Random Forest model
133
  def load_rf_model():
134
+ """Load Random Forest model"""
135
+ paths = MODEL_PATHS["rf"]
 
 
 
 
136
 
137
+ for path in paths:
138
  if os.path.exists(path):
139
  try:
140
+ model = joblib.load(path)
141
+ print(f"Random Forest model loaded from {path}")
142
+ return model
143
  except Exception as e:
144
  print(f"Failed to load RF model from {path}: {e}")
145
  continue
146
 
147
  raise FileNotFoundError("Could not find or load Random Forest model file")
148
 
149
+ # Extract features for Random Forest
150
+ def extract_features_single(model, image_tensor):
151
+ """Extract features from a single image for Random Forest"""
152
+ model.eval()
153
+
154
+ # Create feature extractor (using EfficientNet)
155
+ feature_extractor = nn.Sequential(
156
+ model.features,
157
+ model.avgpool,
158
+ nn.Flatten()
159
+ ).to(DEVICE)
160
+
161
  with torch.no_grad():
162
+ features = feature_extractor(image_tensor).cpu().numpy()
163
+
164
+ return features
 
 
 
165
 
166
+ # Preprocess image for neural networks
167
+ def preprocess_image(image):
168
+ """Preprocess image for model prediction"""
169
  preprocess = transforms.Compose([
170
  transforms.Resize((224, 224)),
171
  transforms.CenterCrop(224),
 
174
  ])
175
  return preprocess(image).unsqueeze(0)
176
 
 
 
 
 
 
 
 
 
 
 
 
177
  # Prediction function
178
+ def predict(img, model_choice, models):
179
  """Make prediction using selected model"""
180
  if img is None:
181
  return "No image provided", "Please upload an image"
182
 
183
  try:
184
+ # Convert to RGB if needed
185
+ if img.mode != "RGB":
186
+ img = img.convert("RGB")
 
187
 
188
+ # Preprocess image
189
+ img_tensor = preprocess_image(img)
190
+ img_tensor = img_tensor.to(DEVICE)
191
+
192
+ if model_choice == "EfficientNet":
193
+ model = models["efficientnet"]
194
+ # Make prediction
195
  with torch.no_grad():
196
+ outputs = model(img_tensor)
197
  probabilities = torch.nn.functional.softmax(outputs, dim=1)[0]
198
  predicted_class = torch.argmax(probabilities).item()
199
 
 
203
  confidence_text = "\n".join([f"{cls}: {score}" for cls, score in confidence_scores.items()])
204
 
205
  return CLASS_NAMES[predicted_class], confidence_text
 
 
 
 
206
 
207
+ elif model_choice == "MobileNetV2":
208
+ model = models["mobilenet"]
209
+ # Make prediction
210
+ with torch.no_grad():
211
+ outputs = model(img_tensor)
212
+ probabilities = torch.nn.functional.softmax(outputs, dim=1)[0]
213
+ predicted_class = torch.argmax(probabilities).item()
214
+
215
+ # Format confidence scores
216
+ confidence_scores = {CLASS_NAMES[i]: f"{probabilities[i].item()*100:.2f}%"
217
+ for i in range(len(CLASS_NAMES))}
218
+ confidence_text = "\n".join([f"{cls}: {score}" for cls, score in confidence_scores.items()])
219
+
220
+ return CLASS_NAMES[predicted_class], confidence_text
221
+
222
+ elif model_choice == "ResNet18":
223
+ model = models["resnet"]
224
+ # Make prediction
225
+ with torch.no_grad():
226
+ outputs = model(img_tensor)
227
+ probabilities = torch.nn.functional.softmax(outputs, dim=1)[0]
228
+ predicted_class = torch.argmax(probabilities).item()
229
+
230
+ # Format confidence scores
231
+ confidence_scores = {CLASS_NAMES[i]: f"{probabilities[i].item()*100:.2f}%"
232
+ for i in range(len(CLASS_NAMES))}
233
+ confidence_text = "\n".join([f"{cls}: {score}" for cls, score in confidence_scores.items()])
234
+
235
+ return CLASS_NAMES[predicted_class], confidence_text
236
+
237
+ elif model_choice == "Random Forest":
238
+ # Extract features using EfficientNet
239
+ features = extract_features_single(models["efficientnet"], img_tensor)
240
+
241
+ # Make prediction with Random Forest
242
+ rf_model = models["rf"]
243
+ predicted_class = rf_model.predict(features)[0]
244
+ probabilities = rf_model.predict_proba(features)[0]
245
 
246
  # Format confidence scores
247
  confidence_scores = {CLASS_NAMES[i]: f"{probabilities[i]*100:.2f}%"
 
249
  confidence_text = "\n".join([f"{cls}: {score}" for cls, score in confidence_scores.items()])
250
 
251
  return CLASS_NAMES[predicted_class], confidence_text
252
+ else:
253
+ return "Invalid model selection", "Please select a valid model"
254
 
255
  except Exception as e:
256
  return f"Error: {str(e)}", "An error occurred during prediction."
257
 
258
  # Initialize models
259
  print("Loading models...")
260
+ models = {}
261
  try:
262
+ models["efficientnet"] = load_model("efficientnet")
263
+ models["mobilenet"] = load_model("mobilenet")
264
+ models["resnet"] = load_model("resnet")
265
+ models["rf"] = load_model("rf")
266
+ print("All models loaded successfully!")
267
  except Exception as e:
268
  print(f"Error loading models: {e}")
269
+ # In case of error, models will be empty or partial
 
 
270
 
271
  # Create Gradio interface
272
  with gr.Blocks(title="Road Surface Classification") as demo:
273
  gr.Markdown("# Road Surface Classification")
274
+ gr.Markdown("Upload an image of a road surface to classify its condition using various models.")
275
 
276
  with gr.Row():
277
  with gr.Column():
278
  image_input = gr.Image(type="pil", label="Upload Road Image")
279
  model_selector = gr.Radio(
280
+ choices=["EfficientNet", "MobileNetV2", "ResNet18", "Random Forest"],
281
+ value="EfficientNet",
282
  label="Select Model"
283
  )
284
  classify_btn = gr.Button("Classify", variant="primary")
 
293
 
294
  # Event handler
295
  classify_btn.click(
296
+ fn=lambda img, model_choice: predict(img, model_choice, models),
297
  inputs=[image_input, model_selector],
298
  outputs=[label_output, confidence_output]
299
  )
300
 
301
+ # Add information about classes and models
302
+ with gr.Row():
303
+ with gr.Column():
304
+ gr.Markdown("### Classes")
305
+ gr.Markdown("- **Cracked_road**: Roads with visible cracks")
306
+ gr.Markdown("- **Flooded_muddy**: Roads affected by flooding or mud")
307
+ gr.Markdown("- **Good_condition**: Roads in good condition")
308
+ gr.Markdown("- **Potholes**: Roads with potholes")
309
+
310
+ with gr.Column():
311
+ gr.Markdown("### Models")
312
+ gr.Markdown("- **EfficientNet**: Efficient deep learning model")
313
+ gr.Markdown("- **MobileNetV2**: Lightweight mobile-friendly model")
314
+ gr.Markdown("- **ResNet18**: Residual network architecture")
315
+ gr.Markdown("- **Random Forest**: Traditional ML using CNN features")
316
 
317
  # Launch the app
318
  if __name__ == "__main__":