ariel-eddie commited on
Commit
61358d9
·
verified ·
1 Parent(s): 77545c6

Updated Image task with test model inference

Browse files
Files changed (1) hide show
  1. tasks/image.py +128 -25
tasks/image.py CHANGED
@@ -1,22 +1,113 @@
 
 
 
 
 
 
 
 
1
  from fastapi import APIRouter
2
  from datetime import datetime
3
  from datasets import load_dataset
4
- import numpy as np
5
  from sklearn.metrics import accuracy_score, precision_score, recall_score
6
- import random
7
- import os
8
 
9
  from .utils.evaluation import ImageEvaluationRequest
10
  from .utils.emissions import tracker, clean_emissions_data, get_space_info
11
 
 
 
 
 
 
12
  from dotenv import load_dotenv
13
- load_dotenv()
14
 
 
15
  router = APIRouter()
16
-
17
- DESCRIPTION = "Random Baseline"
18
  ROUTE = "/image"
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  def parse_boxes(annotation_string):
21
  """Parse multiple boxes from a single annotation string.
22
  Each box has 5 values: class_id, x_center, y_center, width, height"""
@@ -30,6 +121,7 @@ def parse_boxes(annotation_string):
30
  boxes.append(box)
31
  return boxes
32
 
 
33
  def compute_iou(box1, box2):
34
  """Compute Intersection over Union (IoU) between two YOLO format boxes."""
35
  # Convert YOLO format (x_center, y_center, width, height) to corners
@@ -59,6 +151,7 @@ def compute_iou(box1, box2):
59
 
60
  return intersection / (union + 1e-6)
61
 
 
62
  def compute_max_iou(true_boxes, pred_box):
63
  """Compute maximum IoU between a predicted box and all true boxes"""
64
  max_iou = 0
@@ -67,9 +160,10 @@ def compute_max_iou(true_boxes, pred_box):
67
  max_iou = max(max_iou, iou)
68
  return max_iou
69
 
 
70
  @router.post(ROUTE, tags=["Image Task"],
71
- description=DESCRIPTION)
72
- async def evaluate_image(request: ImageEvaluationRequest):
73
  """
74
  Evaluate image classification and object detection for forest fire smoke.
75
 
@@ -90,6 +184,10 @@ async def evaluate_image(request: ImageEvaluationRequest):
90
  # Split dataset
91
  train_test = dataset["train"]
92
  test_dataset = dataset["val"]
 
 
 
 
93
 
94
  # Start tracking emissions
95
  tracker.start()
@@ -104,33 +202,38 @@ async def evaluate_image(request: ImageEvaluationRequest):
104
  true_labels = []
105
  pred_boxes = []
106
  true_boxes_list = [] # List of lists, each inner list contains boxes for one image
107
-
108
- for example in test_dataset:
109
  # Parse true annotation (YOLO format: class_id x_center y_center width height)
110
  annotation = example.get("annotations", "").strip()
111
  has_smoke = len(annotation) > 0
112
  true_labels.append(int(has_smoke))
113
 
114
- # Make random classification prediction
115
- pred_has_smoke = random.random() > 0.5
 
 
 
116
  predictions.append(int(pred_has_smoke))
117
-
118
- # If there's a true box, parse it and make random box prediction
119
  if has_smoke:
 
120
  # Parse all true boxes from the annotation
121
  image_true_boxes = parse_boxes(annotation)
122
- true_boxes_list.append(image_true_boxes)
123
-
124
- # For baseline, make one random box prediction per image
125
- # In a real model, you might want to predict multiple boxes
126
- random_box = [
127
- random.random(), # x_center
128
- random.random(), # y_center
129
- random.random() * 0.5, # width (max 0.5)
130
- random.random() * 0.5 # height (max 0.5)
131
- ]
132
- pred_boxes.append(random_box)
133
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  #--------------------------------------------------------------------------------------------
135
  # YOUR MODEL INFERENCE STOPS HERE
136
  #--------------------------------------------------------------------------------------------
 
1
+ import os
2
+ import torch
3
+ import numpy as np
4
+
5
+ from loguru import logger
6
+ from tqdm import tqdm
7
+ from dotenv import load_dotenv
8
+
9
  from fastapi import APIRouter
10
  from datetime import datetime
11
  from datasets import load_dataset
 
12
  from sklearn.metrics import accuracy_score, precision_score, recall_score
 
 
13
 
14
  from .utils.evaluation import ImageEvaluationRequest
15
  from .utils.emissions import tracker, clean_emissions_data, get_space_info
16
 
17
+ from ultralytics import YOLO
18
+ from ultralytics import RTDETR
19
+ from torch.utils.data import DataLoader
20
+ from torchvision import transforms
21
+
22
  from dotenv import load_dotenv
 
23
 
24
+ load_dotenv()
25
  router = APIRouter()
26
+ DESCRIPTION = "Image to detect smoke"
 
27
  ROUTE = "/image"
28
 
29
+ device = torch.device("cuda")
30
+
31
+
32
+ def parse_boxes(annotation_string):
33
+ """Parse multiple boxes from a single annotation string.
34
+ Each box has 5 values: class_id, x_center, y_center, width, height"""
35
+ values = [float(x) for x in annotation_string.strip().split()]
36
+ boxes = []
37
+ # Each box has 5 values
38
+ for i in range(0, len(values), 5):
39
+ if i + 5 <= len(values):
40
+ # Skip class_id (first value) and take the next 4 values
41
+ box = values[i + 1:i + 5]
42
+ boxes.append(box)
43
+ return boxes
44
+
45
+
46
+ def compute_iou(box1, box2):
47
+ """Compute Intersection over Union (IoU) between two YOLO format boxes."""
48
+
49
+ # Convert YOLO format (x_center, y_center, width, height) to corners
50
+ def yolo_to_corners(box):
51
+ x_center, y_center, width, height = box
52
+ x1 = x_center - width / 2
53
+ y1 = y_center - height / 2
54
+ x2 = x_center + width / 2
55
+ y2 = y_center + height / 2
56
+ return np.array([x1, y1, x2, y2])
57
+
58
+ box1_corners = yolo_to_corners(box1)
59
+ box2_corners = yolo_to_corners(box2)
60
+
61
+ # Calculate intersection
62
+ x1 = max(box1_corners[0], box2_corners[0])
63
+ y1 = max(box1_corners[1], box2_corners[1])
64
+ x2 = min(box1_corners[2], box2_corners[2])
65
+ y2 = min(box1_corners[3], box2_corners[3])
66
+
67
+ intersection = max(0, x2 - x1) * max(0, y2 - y1)
68
+
69
+ # Calculate union
70
+ box1_area = (box1_corners[2] - box1_corners[0]) * (box1_corners[3] - box1_corners[1])
71
+ box2_area = (box2_corners[2] - box2_corners[0]) * (box2_corners[3] - box2_corners[1])
72
+ union = box1_area + box2_area - intersection
73
+
74
+ return intersection / (union + 1e-6)
75
+
76
+
77
+ def compute_max_iou(true_boxes, pred_box):
78
+ """Compute maximum IoU between a predicted box and all true boxes"""
79
+ max_iou = 0
80
+ for true_box in true_boxes:
81
+ iou = compute_iou(true_box, pred_box)
82
+ max_iou = max(max_iou, iou)
83
+ return max_iou
84
+
85
+
86
+ class ClampTransform:
87
+ def __init__(self, min_val=0.0, max_val=1.0):
88
+ self.min_val = min_val
89
+ self.max_val = max_val
90
+
91
+ def __call__(self, tensor):
92
+ return torch.clamp(tensor, min=self.min_val, max=self.max_val)
93
+
94
+
95
+ def collate_fn(batch):
96
+ images = [item['image'] for item in batch]
97
+ annotations = [item.get('annotations', '') for item in batch]
98
+
99
+ # Convert PIL Images to tensors
100
+ transform = transforms.Compose([
101
+ transforms.ToTensor(),
102
+ ClampTransform(min_val=0.0, max_val=1.0),
103
+ transforms.Resize((640, 640))
104
+ ])
105
+
106
+ images = [transform(img) for img in images]
107
+ images = torch.stack(images)
108
+ return {'image': images, 'annotations': annotations}
109
+
110
+
111
  def parse_boxes(annotation_string):
112
  """Parse multiple boxes from a single annotation string.
113
  Each box has 5 values: class_id, x_center, y_center, width, height"""
 
121
  boxes.append(box)
122
  return boxes
123
 
124
+
125
  def compute_iou(box1, box2):
126
  """Compute Intersection over Union (IoU) between two YOLO format boxes."""
127
  # Convert YOLO format (x_center, y_center, width, height) to corners
 
151
 
152
  return intersection / (union + 1e-6)
153
 
154
+
155
  def compute_max_iou(true_boxes, pred_box):
156
  """Compute maximum IoU between a predicted box and all true boxes"""
157
  max_iou = 0
 
160
  max_iou = max(max_iou, iou)
161
  return max_iou
162
 
163
+
164
  @router.post(ROUTE, tags=["Image Task"],
165
+ description=DESCRIPTION)
166
+ async def evaluate_image(model_path: str = "models/yolo11s_best.pt", request: ImageEvaluationRequest = ImageEvaluationRequest()):
167
  """
168
  Evaluate image classification and object detection for forest fire smoke.
169
 
 
184
  # Split dataset
185
  train_test = dataset["train"]
186
  test_dataset = dataset["val"]
187
+ if("yolo" in model_path):
188
+ model = YOLO(model_path, task="detect")
189
+ if("detr" in model_path):
190
+ model = RTDETR(model_path)
191
 
192
  # Start tracking emissions
193
  tracker.start()
 
202
  true_labels = []
203
  pred_boxes = []
204
  true_boxes_list = [] # List of lists, each inner list contains boxes for one image
205
+
206
+ for example in tqdm(test_dataset):
207
  # Parse true annotation (YOLO format: class_id x_center y_center width height)
208
  annotation = example.get("annotations", "").strip()
209
  has_smoke = len(annotation) > 0
210
  true_labels.append(int(has_smoke))
211
 
212
+ image=example["image"]
213
+ results = model(image, verbose=False)
214
+ boxes = results[0].boxes.xywh.tolist()
215
+
216
+ pred_has_smoke = len(boxes) > 0
217
  predictions.append(int(pred_has_smoke))
218
+
 
219
  if has_smoke:
220
+ # If there's a true box, parse it and make box prediction
221
  # Parse all true boxes from the annotation
222
  image_true_boxes = parse_boxes(annotation)
 
 
 
 
 
 
 
 
 
 
 
223
 
224
+ # Predicted bboxes
225
+ # Iterate through the results
226
+ for box in boxes:
227
+ x, y, w, h = box
228
+ image_width, image_height = image.size
229
+ x = x / image_width
230
+ y = y / image_height
231
+ w_n = w / image_width
232
+ h_n = h / image_height
233
+ formatted_box = [x, y, w_n, h_n]
234
+ pred_boxes.append(formatted_box)
235
+ true_boxes_list.append(image_true_boxes)
236
+
237
  #--------------------------------------------------------------------------------------------
238
  # YOUR MODEL INFERENCE STOPS HERE
239
  #--------------------------------------------------------------------------------------------