34
34
logger = logging .getLogger (__name__ )
35
35
logger .setLevel (cfg .LOG_LEVEL )
36
36
37
+ #Enable mlflow system metrics
38
+ mlflow .enable_system_metrics_logging ()
39
+
37
40
BASE_PATH = Path (__file__ ).resolve (strict = True ).parents [1 ]
38
41
mlflow_runs_path = os .path .join (BASE_PATH , "models/mlruns" )
39
42
if "MLFLOW_TRACKING_URI" not in os .environ :
@@ -198,6 +201,7 @@ def mlflow_update():
198
201
stage = "Archived" ,
199
202
)
200
203
204
+ import pandas as pd
201
205
202
206
def mlflow_logging (model , num_epochs , args ):
203
207
mlflow .end_run () # stop any previous active mlflow run
@@ -237,15 +241,15 @@ def mlflow_logging(model, num_epochs, args):
237
241
# Use mlflow.log_artifact to log the contents of data.yaml
238
242
mlflow .log_artifact (data_file_path , artifact_path = "artifacts" )
239
243
240
- # Log the Dataset
241
244
# Print OpenCV version for debugging
242
245
print (f"OpenCV Version: { cv2 .__version__ } " )
243
246
244
247
# Ensure that no random seed is set
245
- random .seed (None )
248
+ # random.seed(None)
246
249
247
250
# Specify the path to the folder containing images
248
251
img_folder = data ["train" ]
252
+ print ("\n ImgFolder" , img_folder )
249
253
250
254
# List all files in the folder
251
255
img_files = [
@@ -272,17 +276,25 @@ def mlflow_logging(model, num_epochs, args):
272
276
f"Error: Unable to read the image from { img_path } "
273
277
)
274
278
else :
275
- # Continue with the rest of your code using the selected image
276
279
resized_img = cv2 .resize (
277
280
img , (640 , 640 ), interpolation = cv2 .INTER_LINEAR
278
281
)
279
282
normalized_img = resized_img / 255.0
283
+
284
+ image_array = np .transpose (normalized_img , (2 , 0 , 1 )) # Rearrange to [C, H, W]
285
+ image_array = np .expand_dims (normalized_img , axis = 0 ) # Add batch dimension
286
+ print (f"Processed image shape: { image_array .shape } " )
287
+
280
288
torch_img = torch .from_numpy (normalized_img ).float ()
281
289
torch_img = torch_img .permute (2 , 0 , 1 ).unsqueeze (0 )
282
290
torch_img_cpu = torch_img .cpu ().numpy ()
291
+ img = torch_img_cpu
292
+
293
+ # Example input for infer_signature
294
+ example_input = {"image" : image_array }
283
295
284
296
# Convert the NumPy array to a MLflow Dataset entity
285
- dataset_entity = mlflow .data .from_numpy (torch_img_cpu )
297
+ dataset_entity = mlflow .data .from_numpy (image_array )
286
298
print ("dataset_info" , dataset_entity )
287
299
288
300
# Log the Dataset entity as input
@@ -291,37 +303,61 @@ def mlflow_logging(model, num_epochs, args):
291
303
run , active_run = mlflow , mlflow .active_run ()
292
304
print ("active run id" , active_run .info .run_id )
293
305
306
+ #get model info
307
+ summary_model = model .trainer .model .info ()
308
+
309
+ # Map the tuple to meaningful names
310
+ summary_model_info = {
311
+ "layers" : summary_model [0 ],
312
+ "parameters" : summary_model [1 ],
313
+ "gradients" : summary_model [2 ],
314
+ "GFLOPs" : summary_model [3 ],
315
+ }
316
+ print ("\n Summary Model: " , summary_model_info )
317
+
318
+ # Convert train_inf to DataFrame
319
+ #sum_model_info_df = pd.DataFrame(summary_model_info)
320
+
294
321
# logs params in mlflow
295
322
if get_git_info is not None :
296
323
git_repo , version = get_git_info ()
297
324
git_info = {"git_repo" : git_repo , "git_version" : version }
298
325
merged_params = {
299
326
** vars (model .trainer .model .args ),
300
327
** git_info ,
328
+ ** summary_model_info
301
329
}
302
330
run .log_params (merged_params )
303
331
332
+
304
333
# Assuming model is an instance of YOLO and img is an input image
305
- prediction_inf = model (img )
334
+ prediction_inf = model (img_path , conf = 0.2 )
306
335
307
- train_inf_np = model . trainer . model . info ()
308
- print ( " \n train_inf_np" , train_inf_np )
336
+ # Check if GPU is available
337
+ device = torch . device ( "cuda" if torch . cuda . is_available () else "cpu" )
309
338
310
- # Convert the tuple to a dictionary
311
- train_inf = {"value" : np .array (train_inf_np )}
312
- print ("\n train_inf" , train_inf )
313
- # print ("\npred_inf", prediction_inf)
314
339
315
340
# Create list of detection dictionaries
316
341
results_all = []
317
-
342
+ if not prediction_inf :
343
+ print (f"No predictions made for image: { img_path } " )
344
+ return
345
+
318
346
for result in prediction_inf :
319
- # Assuming result is an ultralytics.engine.results.Results object
320
- data = result .boxes .data .cpu ().tolist ()
347
+ print (f"Processing image: { result .path } " )
348
+
349
+ # Check if no detections were made
350
+ if result .boxes .data is None or len (result .boxes .data ) == 0 :
351
+ print ("No detections found." )
352
+ continue # Skip if no detections
353
+
354
+ # Get bounding box data
355
+ data = result .boxes .data .to (device ).tolist ()
356
+ print (f"Detected boxes: { data } " )
357
+
321
358
h , w = result .orig_shape
322
- for i , row in enumerate (
323
- data
324
- ): # xyxy, track_id if tracking, conf, class_id
359
+
360
+ for i , row in enumerate (data ):
325
361
box = {
326
362
"x1" : row [0 ] / w ,
327
363
"y1" : row [1 ] / h ,
@@ -331,68 +367,70 @@ def mlflow_logging(model, num_epochs, args):
331
367
conf = row [- 2 ]
332
368
class_id = int (row [- 1 ])
333
369
name = result .names [class_id ]
370
+
334
371
detection_result = {
335
372
"name" : name ,
336
373
"class" : class_id ,
337
374
"confidence" : conf ,
338
375
"box" : box ,
339
376
}
377
+ print (f"Detection result: { detection_result } " )
378
+
379
+ # Add track ID if available
340
380
if result .boxes .is_track :
341
- detection_result ["track_id" ] = int (
342
- row [- 3 ]
343
- ) # track ID
344
- if result .masks :
345
- x , y = (
346
- result .masks .xy [i ][:, 0 ],
347
- result .masks .xy [i ][:, 1 ],
348
- ) # numpy array
349
- detection_result ["segments" ] = {
350
- "x" : (x / w ).tolist (),
351
- "y" : (y / h ).tolist (),
352
- }
353
- if result .keypoints is not None :
354
- x , y , visible = (
355
- result .keypoints [i ]
356
- .data [0 ]
357
- .cpu ()
358
- .unbind (dim = 1 )
359
- ) # torch Tensor
360
- detection_result ["keypoints" ] = {
361
- "x" : (x / w ).tolist (),
362
- "y" : (y / h ).tolist (),
363
- "visible" : visible .tolist (),
364
- }
365
-
381
+ detection_result ["track_id" ] = int (row [- 3 ])
382
+
383
+ # Save to results
366
384
results_all .append (detection_result )
385
+
386
+ results_output = None
387
+ if results_all :
388
+ # Flatten the nested 'box' dictionary for meaningful column names
389
+ results_all_flattened = []
367
390
MODELS_PATH = os .path .join (args ["project" ], args ["name" ])
368
- output_file_path = os .path .join (
369
- MODELS_PATH , "detection_results.txt"
391
+ output_file_path = os .path .join (MODELS_PATH , "detection_results.csv" )
392
+ for entry in results_all :
393
+ flat_entry = entry .copy ()
394
+ box = flat_entry .pop ("box" )
395
+ flat_entry .update (box ) # Add x1, y1, x2, y2 as top-level columns
396
+ results_all_flattened .append (flat_entry )
397
+ results_output = pd .DataFrame (results_all_flattened )
398
+ #print("\results_output:\n", results_output)
399
+ try :
400
+ results_output .to_csv (output_file_path , index = False )
401
+ print (f"Detection results saved to { output_file_path } " )
402
+ # Log the artifact only after the file is created
403
+ mlflow .log_artifact (output_file_path , artifact_path = "artifacts" )
404
+ except Exception as e :
405
+ print (f"Error saving detection results to file: { e } " )
406
+ else :
407
+ print ("No detections to save." )
408
+ results_output = [{"detection" : value } for value in [1 , 2 , 3 , 4 ]]
409
+
410
+ # Ensure results_all has valid entries to log the signature in mlflow
411
+
412
+ # Infer signature from results_output
413
+ if results_output is not None :
414
+ signature = infer_signature (example_input , results_output )
415
+ print ("\n Signature inferred successfully." )
416
+ mlflow .pyfunc .log_model (
417
+ artifact_path = "artifacts" ,
418
+ python_model = mlflow .pyfunc .PythonModel (),
419
+ signature = signature ,
420
+ )
421
+ else :
422
+ print ("\n example_input or results_output is empty. Could not infer signature." )
423
+ #Log the model without signature
424
+ mlflow .pyfunc .log_model (
425
+ artifact_path = "artifacts" ,
426
+ python_model = mlflow .pyfunc .PythonModel ()
370
427
)
371
- with open (output_file_path , "w" ) as output_file :
372
- # Now write all results to the file after the loop
373
- for result_entry in results_all :
374
- output_file .write (f"{ str (result_entry )} \n " )
375
-
376
- # Use mlflow.log_artifact to log the contents of the detection_results
377
- mlflow .log_artifact (
378
- output_file_path , artifact_path = "artifacts"
379
- )
380
-
381
- # Use infer_signature with train_inf and results_all
382
- results_all = [str (value ) for value in results_all ]
383
- signature = infer_signature (
384
- train_inf , {"detections" : results_all }
385
- )
386
428
429
+
387
430
# Get the base directory of artifact_path
388
431
base_dir = os .path .basename (str (model .trainer .save_dir ))
389
432
print ("\n base_dir" , base_dir )
390
433
391
- mlflow .pyfunc .log_model (
392
- artifact_path = "artifacts" ,
393
- python_model = mlflow .pyfunc .PythonModel (),
394
- signature = signature ,
395
- )
396
434
397
435
# Log additional artifacts
398
436
mlflow .log_artifacts (
0 commit comments