Skip to content

Commit 2b9499f

Browse files
authored
edit mlflow-logging() fnc
1 parent f1dd78e commit 2b9499f

File tree

1 file changed

+102
-64
lines changed

1 file changed

+102
-64
lines changed

yolov8_api/utils.py

Lines changed: 102 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
logger = logging.getLogger(__name__)
3535
logger.setLevel(cfg.LOG_LEVEL)
3636

37+
#Enable mlflow system metrics
38+
mlflow.enable_system_metrics_logging()
39+
3740
BASE_PATH = Path(__file__).resolve(strict=True).parents[1]
3841
mlflow_runs_path = os.path.join(BASE_PATH, "models/mlruns")
3942
if "MLFLOW_TRACKING_URI" not in os.environ:
@@ -198,6 +201,7 @@ def mlflow_update():
198201
stage="Archived",
199202
)
200203

204+
import pandas as pd
201205

202206
def mlflow_logging(model, num_epochs, args):
203207
mlflow.end_run() # stop any previous active mlflow run
@@ -237,15 +241,15 @@ def mlflow_logging(model, num_epochs, args):
237241
# Use mlflow.log_artifact to log the contents of data.yaml
238242
mlflow.log_artifact(data_file_path, artifact_path="artifacts")
239243

240-
# Log the Dataset
241244
# Print OpenCV version for debugging
242245
print(f"OpenCV Version: {cv2.__version__}")
243246

244247
# Ensure that no random seed is set
245-
random.seed(None)
248+
#random.seed(None)
246249

247250
# Specify the path to the folder containing images
248251
img_folder = data["train"]
252+
print ("\nImgFolder", img_folder)
249253

250254
# List all files in the folder
251255
img_files = [
@@ -272,17 +276,25 @@ def mlflow_logging(model, num_epochs, args):
272276
f"Error: Unable to read the image from {img_path}"
273277
)
274278
else:
275-
# Continue with the rest of your code using the selected image
276279
resized_img = cv2.resize(
277280
img, (640, 640), interpolation=cv2.INTER_LINEAR
278281
)
279282
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+
280288
torch_img = torch.from_numpy(normalized_img).float()
281289
torch_img = torch_img.permute(2, 0, 1).unsqueeze(0)
282290
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}
283295

284296
# 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)
286298
print("dataset_info", dataset_entity)
287299

288300
# Log the Dataset entity as input
@@ -291,37 +303,61 @@ def mlflow_logging(model, num_epochs, args):
291303
run, active_run = mlflow, mlflow.active_run()
292304
print("active run id", active_run.info.run_id)
293305

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+
294321
# logs params in mlflow
295322
if get_git_info is not None:
296323
git_repo, version = get_git_info()
297324
git_info = {"git_repo": git_repo, "git_version": version}
298325
merged_params = {
299326
**vars(model.trainer.model.args),
300327
**git_info,
328+
**summary_model_info
301329
}
302330
run.log_params(merged_params)
303331

332+
304333
# 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)
306335

307-
train_inf_np = model.trainer.model.info()
308-
print("\ntrain_inf_np", train_inf_np)
336+
# Check if GPU is available
337+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
309338

310-
# Convert the tuple to a dictionary
311-
train_inf = {"value": np.array(train_inf_np)}
312-
print("\ntrain_inf", train_inf)
313-
# print ("\npred_inf", prediction_inf)
314339

315340
# Create list of detection dictionaries
316341
results_all = []
317-
342+
if not prediction_inf:
343+
print(f"No predictions made for image: {img_path}")
344+
return
345+
318346
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+
321358
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):
325361
box = {
326362
"x1": row[0] / w,
327363
"y1": row[1] / h,
@@ -331,68 +367,70 @@ def mlflow_logging(model, num_epochs, args):
331367
conf = row[-2]
332368
class_id = int(row[-1])
333369
name = result.names[class_id]
370+
334371
detection_result = {
335372
"name": name,
336373
"class": class_id,
337374
"confidence": conf,
338375
"box": box,
339376
}
377+
print(f"Detection result: {detection_result}")
378+
379+
# Add track ID if available
340380
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
366384
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 = []
367390
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("\nSignature 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("\nexample_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()
370427
)
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-
)
386428

429+
387430
# Get the base directory of artifact_path
388431
base_dir = os.path.basename(str(model.trainer.save_dir))
389432
print("\nbase_dir", base_dir)
390433

391-
mlflow.pyfunc.log_model(
392-
artifact_path="artifacts",
393-
python_model=mlflow.pyfunc.PythonModel(),
394-
signature=signature,
395-
)
396434

397435
# Log additional artifacts
398436
mlflow.log_artifacts(

0 commit comments

Comments
 (0)