From 2e5458246c6c8d881a058dec212290e981a51cba Mon Sep 17 00:00:00 2001
From: "michael.divia" <michael.divia@etu.hesge.ch>
Date: Wed, 9 Apr 2025 16:34:03 +0200
Subject: [PATCH] Standartise everything

---
 Python/convert_onnx.py                        | 42 -------------
 python/convert_onnx.py                        | 37 ++++++++++++
 python/hailo_compile.py                       | 59 +++++++++++++++++++
 {Python => python}/pokedex_ResNet50.py        |  2 +-
 {Python => python}/pokedex_Xception.py        |  2 +-
 .../pokedex_rpi.py                            | 18 +++++-
 .../pokedex_test.py                           | 32 +++++++---
 7 files changed, 136 insertions(+), 56 deletions(-)
 delete mode 100644 Python/convert_onnx.py
 create mode 100644 python/convert_onnx.py
 create mode 100644 python/hailo_compile.py
 rename {Python => python}/pokedex_ResNet50.py (98%)
 rename {Python => python}/pokedex_Xception.py (98%)
 rename Python/predict_pokemon.py => python/pokedex_rpi.py (71%)
 rename Python/test_ResNet50.py => python/pokedex_test.py (67%)

diff --git a/Python/convert_onnx.py b/Python/convert_onnx.py
deleted file mode 100644
index d59ebff..0000000
--- a/Python/convert_onnx.py
+++ /dev/null
@@ -1,42 +0,0 @@
-import tensorflow as tf
-import tf2onnx
-import argparse
-
-# WHAT ?
-parser = argparse.ArgumentParser(description="WHAT ?!")
-parser.add_argument("--model", choices=["1", "2"], default="1",
-                    help="1 = ResNet50, 2 = Xception")
-args = parser.parse_args()
-
-# Load Sequential model
-if args.model == "1":
-    seq_model = tf.keras.models.load_model("../models/ResNet50/pokemon_resnet50.h5", compile=False)
-elif args.model == "2":
-    seq_model = tf.keras.models.load_model("../models/ResNet50/pokemon_xception.h5", compile=False)
-
-# Create input layer with same shape
-inputs = tf.keras.Input(shape=(224, 224, 3), name="input")
-
-# Call the Sequential model as a function
-outputs = seq_model(inputs)
-
-# Wrap in Functional model
-model = tf.keras.Model(inputs=inputs, outputs=outputs)
-
-# Convert to ONNX
-spec = (tf.TensorSpec((1, 224, 224, 3), tf.float32, name="input"),)
-
-if args.model == "1":
-    onnx_model, _ = tf2onnx.convert.from_keras(
-        model,
-        input_signature=spec,
-        opset=13,
-        output_path="../models/ResNet50/pokemon_resnet50.onnx"
-    )
-elif args.model == "2":
-    onnx_model, _ = tf2onnx.convert.from_keras(
-        model,
-        input_signature=spec,
-        opset=13,
-        output_path="../models/ResNet50/pokemon_xception.onnx"
-    )
\ No newline at end of file
diff --git a/python/convert_onnx.py b/python/convert_onnx.py
new file mode 100644
index 0000000..5cc6061
--- /dev/null
+++ b/python/convert_onnx.py
@@ -0,0 +1,37 @@
+import tensorflow as tf
+import tf2onnx
+import argparse
+
+# --- WHAT ? ---
+parser = argparse.ArgumentParser(description="WHAT ?!")
+parser.add_argument("--model", choices=["1", "2"], required=True, help="1 = ResNet50, 2 = Xception")
+args = parser.parse_args()
+
+# Paths
+if args.model == "1":
+    h5_path = "../models/ResNet50/pokedex_ResNet50.h5"
+    onnx_path = "../models/ResNet50/pokedex_ResNet50.onnx"
+elif args.model == "2":
+    h5_path = "../models/Xception/pokedex_Xception.h5"
+    onnx_path = "../models/ResNet50/pokedex_Xception.onnx"
+
+# --- Load Sequential model ---
+seq_model = tf.keras.models.load_model(h5_path, compile=False)
+
+# --- Create input layer with same shape ---
+inputs = tf.keras.Input(shape=(224, 224, 3), name="input")
+
+# --- Call the Sequential model as a function ---
+outputs = seq_model(inputs)
+
+# --- Wrap in Functional model ---
+model = tf.keras.Model(inputs=inputs, outputs=outputs)
+
+# --- Convert to ONNX ---
+spec = (tf.TensorSpec((1, 224, 224, 3), tf.float32, name="input"),)
+onnx_model, _ = tf2onnx.convert.from_keras(
+    model,
+    input_signature=spec,
+    opset=13,
+    output_path=onnx_path
+)
\ No newline at end of file
diff --git a/python/hailo_compile.py b/python/hailo_compile.py
new file mode 100644
index 0000000..2f25e2c
--- /dev/null
+++ b/python/hailo_compile.py
@@ -0,0 +1,59 @@
+import os
+import subprocess
+import argparse
+import onnx
+
+parser = argparse.ArgumentParser(description="Convert, parse, optimize and compile model for Hailo.")
+parser.add_argument("--model", choices=["1", "2"], required=True, help="1 = ResNet50, 2 = Xception")
+parser.add_argument("--calib", default="--use-random-calib-set", help="Calibration data path or '--use-random-calib-set'")
+args = parser.parse_args()
+
+def get_onnx_io_names(onnx_path):
+    model = onnx.load(onnx_path)
+    input_name = model.graph.input[0].name
+    output_name = model.graph.output[0].name
+    return input_name, output_name
+
+# Paths
+if args.model == "1":
+    base_model_path = "../models/ResNet50"
+    model = "pokedex_ResNet50"
+elif args.model == "2":
+    base_model_path = "../models/Xception"
+    model = "pokedex_Xception"
+    
+onnx_path = os.path.join(base_model_path, f"pokedex_{model}.onnx")
+har_path = os.path.join(base_model_path, f"{model}.har")
+optimized_har_path = os.path.join(base_model_path, f"{model}_optimized.har")
+hef_path = os.path.join(base_model_path, f"{model}.hef")
+
+# Node names
+start_node, end_node = get_onnx_io_names(onnx_path)
+print(f"-- Using start_node: {start_node}, end_node: {end_node}")
+
+# Step 1: Parse
+print(f"-- Parsing {onnx_path}...")
+subprocess.run([
+    "hailo", "parser", "onnx", onnx_path,
+    "--start-node-names", start_node,
+    "--end-nodes-names", end_node,
+    "--hw-arch", "hailo8l"
+])
+
+# Step 2: Optimize
+print(f"-- Optimizing to {optimized_har_path}...")
+optimize_cmd = [
+    "hailo", "optimize", har_path,
+    "--hw-arch", "hailo8l",
+    "--use-random-calib-set"
+]
+subprocess.run(optimize_cmd)
+
+# Step 3: Compile
+print(f"-- Compiling to {hef_path}...")
+subprocess.run([
+    "hailo", "compiler", optimized_har_path,
+    "--hw-arch", "hailo8l",
+    "--performance",
+])
+print("-- Done.")
diff --git a/Python/pokedex_ResNet50.py b/python/pokedex_ResNet50.py
similarity index 98%
rename from Python/pokedex_ResNet50.py
rename to python/pokedex_ResNet50.py
index 5724038..dad6c96 100644
--- a/Python/pokedex_ResNet50.py
+++ b/python/pokedex_ResNet50.py
@@ -117,7 +117,7 @@ model.fit(
 )
 
 # --- Save the model ---
-model_h5_path = os.path.join(model_output_path, "pokemon_resnet50.h5")
+model_h5_path = os.path.join(model_output_path, "pokedex_ResNet50.h5")
 model.save(model_h5_path)
 print(f"Model saved to {model_h5_path}")
 
diff --git a/Python/pokedex_Xception.py b/python/pokedex_Xception.py
similarity index 98%
rename from Python/pokedex_Xception.py
rename to python/pokedex_Xception.py
index 9878540..55d425c 100644
--- a/Python/pokedex_Xception.py
+++ b/python/pokedex_Xception.py
@@ -135,7 +135,7 @@ model.fit(
 )
 
 # --- Save the model ---
-model_h5_path = os.path.join(model_output_path, "pokemon_xception.h5")
+model_h5_path = os.path.join(model_output_path, "pokedex_Xception.h5")
 model.save(model_h5_path)
 print(f"Model saved to {model_h5_path}")
 
diff --git a/Python/predict_pokemon.py b/python/pokedex_rpi.py
similarity index 71%
rename from Python/predict_pokemon.py
rename to python/pokedex_rpi.py
index d4a931a..3f197ca 100644
--- a/Python/predict_pokemon.py
+++ b/python/pokedex_rpi.py
@@ -2,13 +2,25 @@ import cv2
 import numpy as np
 import json
 from hailo_platform.pyhailort import HailoRT
+import argparse
+
+# --- WHAT ? ---
+parser = argparse.ArgumentParser(description="WHAT ?!")
+parser.add_argument("--model", choices=["1", "2"], required=True, help="1 = ResNet50, 2 = Xception")
+args = parser.parse_args()
+
+# Paths
+if args.model == "1":
+    hef_path = "../models/ResNet50/pokedex_ResNet50.hef"
+    json_path = "../models/ResNet50/class_names.json"
+elif args.model == "2":
+    hef_path = "../models/Xception/pokedex_Xception.hef"
+    json_path = "../models/Xception/class_names.json"
 
 # Load class names
-with open("../models/ResNet50/class_names.json", "r") as f:
+with open(json_path, "r") as f:
     class_names = json.load(f)
 
-# --- Load HEF and configure device ---
-hef_path = "../models/ResNet50/resnet50.hef"
 device = HailoRT.Device()
 hef = HailoRT.Hef(hef_path)
 configured_network_group = device.create_hef_group(hef)
diff --git a/Python/test_ResNet50.py b/python/pokedex_test.py
similarity index 67%
rename from Python/test_ResNet50.py
rename to python/pokedex_test.py
index 04dd172..4d3e1b8 100644
--- a/Python/test_ResNet50.py
+++ b/python/pokedex_test.py
@@ -5,19 +5,33 @@ import numpy as np
 import os
 import random
 import json
+import argparse
 
-# === Load class names from JSON ===
-with open("../models/ResNet50/class_names.json", "r") as f:
+# --- WHAT ? ---
+parser = argparse.ArgumentParser(description="WHAT ?!")
+parser.add_argument("--model", choices=["1", "2"], required=True, help="1 = ResNet50, 2 = Xception")
+args = parser.parse_args()
+
+# Paths
+if args.model == "1":
+    h5_path = "../models/ResNet50/pokedex_ResNet50.h5"
+    json_path = "../models/ResNet50/class_names.json"
+elif args.model == "2":
+    h5_path = "../models/Xception/pokedex_Xception.h5"
+    json_path = "../models/Xception/class_names.json"
+
+# --- Load class names from JSON ---
+with open(json_path, "r") as f:
     class_names = json.load(f)
     class_names = [class_names[i] for i in range(len(class_names))]  # convert to list
 
-# === Load trained model ===
-model = keras.models.load_model("../models/ResNet50/pokemon_resnet50.h5")
+# --- Load trained model ---
+model = keras.models.load_model(h5_path)
 
-# === Paths ===
+# --- Paths ---
 base_path = "../Combined_Dataset"
 
-# === Prepare 2x2 Plot ===
+# --- Prepare 2x2 Plot ---
 plt.figure(figsize=(10, 10))
 
 for i in range(4):
@@ -30,13 +44,13 @@ for i in range(4):
     ])
     img_path = os.path.join(class_folder, random_image)
 
-    # === Load & Preprocess Image ===
+    # --- Load & Preprocess Image ---
     img = keras.utils.load_img(img_path, target_size=(224, 224))  # resize to match model input
     img_array = keras.utils.img_to_array(img)
     img_array = img_array / 255.0  # normalize if your model expects it
     img_array = tf.expand_dims(img_array, 0)
 
-    # === Predict ===
+    # --- Predict ---
     predictions = model.predict(img_array, verbose=0)
     probabilities = tf.nn.softmax(predictions[0])
     predicted_class_index = np.argmax(probabilities)
@@ -46,7 +60,7 @@ for i in range(4):
     # Compare with actual
     is_correct = predicted_label == random_class
 
-    # === Plot ===
+    # --- Plot ---
     ax = plt.subplot(2, 2, i + 1)
     plt.imshow(img)
     plt.axis("off")
-- 
GitLab