Help-YOLOv8n Custom Model: Training to Hailo HEF Conversion Failure

Help Request: YOLOv8n Custom Model to Hailo-8L Conversion Issue

Environment Setup

  • Primary Environment: Using official hailo_ai_sw_suite_2024-10_docker.zip for all Hailo-related operations
  • Exception: Model training was done separately using PyCharm Community Edition 2023.1.2 (training from scratch with custom dataset)

Current Issue

When attempting to compile the custom-trained ONNX model to Hailo format, encountering error:

NMSConfigPostprocessException: The layer yolov8n/conv41 doesn't have one output layer

My Process Step by Step

1. Model Training

  • Starting with: YOLOv8n configuration (training from scratch, not using pretrained weights)
  • Custom dataset with three classes: “Open_Box”, “Ice_Pack”, “Closed_Box”
  • Training code (using PyCharm Community Edition 2023.1.2):

python

from ultralytics import YOLO
import multiprocessing
def main():
  
   import os
   os.makedirs('yolomodel', exist_ok=True)
   os.chdir('yolomodel')
   
   model = YOLO('yolov8n.yaml')
   
   results = model.train(
       data='custom_data.yaml',
       epochs=100,
       batch=16,
       name='retrain_yolov8n'
   )
if __name__ == "__main__":
    multiprocessing.freeze_support()
    main()

2. Conversion Steps

# Export trained model to ONNX format
yolo export model=best.pt imgsz=640 format=onnx opset=11

# Parse with Hailo
hailomz parse --hw-arch hailo8l --ckpt best.onnx yolov8n

# Prepare calibration data
mkdir -p calibration_images
mv Closed_Box.jpg Ice_Pack.jpg Open_Box.jpg calibration_images/

# Attempt compilation (this step failed)
hailomz compile yolov8n --hw-arch hailo8l --ckpt best.onnx --calib-path calibration_images

Important Note

The conversion process works successfully with the original COCO-trained YOLOv8n.pt model (without custom training). I previously tested with this CLI command:

mkdir yolomodel && cd yolomodel
yolo detect train data=coco128.yaml model=yolov8n.pt name=retrain_yolov8n epochs=100 batch=16

This COCO dataset training converted successfully to .hef format. However, the issue appears when trying to convert my custom-trained model (trained from scratch with my own dataset).

Questions

  1. Are there specific configurations or parameters needed for custom-trained models?
  2. Could the NMS (Non-Maximum Suppression) layer configuration be causing this issue?
  3. What are the recommended steps or modifications for converting custom-trained models?
  4. Are there any specific requirements for the calibration images?

System Information

  • Hardware: AMD Ryzen 9 7950X, NVIDIA GeForce RTX 3080
  • Target Device: Hailo-8L
  • Environment: Docker container with Hailo SDK

Error Stack Trace

Traceback (most recent call last):
  File "/local/workspace/hailo_virtualenv/bin/hailomz", line 33, in <module>
    sys.exit(load_entry_point('hailo-model-zoo', 'console_scripts', 'hailomz')())
  ...
  File "/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_sdk_client/tools/core_postprocess/nms_postprocess.py", line 1040, in add_postprocess_layer_to_hn
    raise NMSConfigPostprocessException(f"The layer {encoded_layer.name} doesn't have one output layer")
hailo_sdk_client.tools.core_postprocess.nms_postprocess.NMSConfigPostprocessException: The layer yolov8n/conv41 doesn't have one output layer

Any assistance or guidance would be greatly appreciated. Thank you in advance!

Please run a search in the forum using “layer yolov8n/conv41” . Click the magnification glass icon :mag: next to your forum profile icon.

There are a few posts where this question was asked before with some answers that should help you.

@klausk
Thank you for your suggestion. I have gone through many articles about multi-head or extra layer issues, and possible training dataset size problems. However, I would prefer to prevent this error from the beginning during model training.

I found that my model trained from scratch uses depthwise DWConv, while the official YOLOv8n.pt only uses standard Conv and Conv2d. I suspect this architectural difference might be causing incompatibility with Hailo.

Currently, I’m trying to disable the automatic use of DWConv (which might be auto-enabled due to insufficient training data size), but I haven’t found a way to disable DWConv usage. Would you happen to know how to configure the model to use only standard convolutions?

(post deleted by author)

I encountered another error during this conversion
(hailo_virtualenv) hailo@c60c28dd7465:/local/workspace/models$ hailomz compile yolov8n --hw-arch hailo8 --ckpt yolov8n.onnx --calib-path calibration_images
Start run for network yolov8n …
Initializing the hailo8 runner…
[info] Translation started on ONNX model yolov8n
[info] Restored ONNX model yolov8n (completion time: 00:00:00.05)
WARNING: failed to run “Add” op (name is “/model.22/Add”), skip…
WARNING: failed to run “Div” op (name is “/model.22/Div”), skip…
WARNING: failed to run “Mul” op (name is “/model.22/Mul_1”), skip…
WARNING: failed to run “Add” op (name is “/model.22/Add”), skip…
WARNING: failed to run “Div” op (name is “/model.22/Div”), skip…
WARNING: failed to run “Mul” op (name is “/model.22/Mul_1”), skip…
[info] Extracted ONNXRuntime meta-data for Hailo model (completion time: 00:00:00.30)
[info] NMS structure of yolov8 (or equivalent architecture) was detected.
[info] In order to use HailoRT post-processing capabilities, these end node names should be used: /model.22/cv2.0/cv2.0.2/Conv /model.22/cv3.0/cv3.0.2/Conv /model.22/cv2.1/cv2.1.2/Conv /model.22/cv3.1/cv3.1.2/Conv /model.22/cv2.2/cv2.2.2/Conv /model.22/cv3.2/cv3.2.2/Conv.
[info] Start nodes mapped from original model: ‘images’: ‘yolov8n/input_layer1’.
[info] End nodes mapped from original model: ‘/model.22/cv2.0/cv2.0.2/Conv’, ‘/model.22/cv3.0/cv3.0.2/Conv’, ‘/model.22/cv2.1/cv2.1.2/Conv’, ‘/model.22/cv3.1/cv3.1.2/Conv’, ‘/model.22/cv2.2/cv2.2.2/Conv’, ‘/model.22/cv3.2/cv3.2.2/Conv’.
[info] Translation completed on ONNX model yolov8n (completion time: 00:00:00.72)
[info] Saved HAR to: /local/workspace/models/yolov8n.har
Preparing calibration data…
[info] Loading model script commands to yolov8n from /local/workspace/hailo_model_zoo/hailo_model_zoo/cfg/alls/generic/yolov8n.alls
[info] Starting Model Optimization
[warning] Reducing optimization level to 0 (the accuracy won’t be optimized and compression won’t be used) because there’s no available GPU
[warning] Running model optimization with zero level of optimization is not recommended for production use and might lead to suboptimal accuracy results
[info] Model received quantization params from the hn
Traceback (most recent call last):
File “/local/workspace/hailo_virtualenv/bin/hailomz”, line 33, in
sys.exit(load_entry_point(‘hailo-model-zoo’, ‘console_scripts’, ‘hailomz’)())
File “/local/workspace/hailo_model_zoo/hailo_model_zoo/main.py”, line 122, in main
run(args)
File “/local/workspace/hailo_model_zoo/hailo_model_zoo/main.py”, line 111, in run
return handlersargs.command
File “/local/workspace/hailo_model_zoo/hailo_model_zoo/main_driver.py”, line 250, in compile
ensure_optimized(runner, logger, args, network_info)
File “/local/workspace/hailo_model_zoo/hailo_model_zoo/main_driver.py”, line 91, in ensure_optimized
optimize_model(
File “/local/workspace/hailo_model_zoo/hailo_model_zoo/core/main_utils.py”, line 326, in optimize_model
runner.optimize(calib_feed_callback)
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_sdk_common/states/states.py”, line 16, in wrapped_func
return func(self, *args, **kwargs)
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_sdk_client/runner/client_runner.py”, line 2093, in optimize
self.optimize(calib_data, data_type=data_type, work_dir=work_dir)
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_sdk_common/states/states.py”, line 16, in wrapped_func
return func(self, *args, **kwargs)
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_sdk_client/runner/client_runner.py”, line 1935, in optimize
self.sdk_backend.full_quantization(calib_data, data_type=data_type, work_dir=work_dir)
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_sdk_client/sdk_backend/sdk_backend.py”, line 1045, in full_quantization
self.full_acceleras_run(self.calibration_data, data_type)
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_sdk_client/sdk_backend/sdk_backend.py”, line 1229, in full_acceleras_run
optimization_flow.run()
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_model_optimization/tools/orchestator.py”, line 306, in wrapper
return func(self, *args, **kwargs)
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_model_optimization/flows/optimization_flow.py”, line 326, in run
step_func()
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_model_optimization/tools/orchestator.py”, line 250, in wrapped
result = method(*args, **kwargs)
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_model_optimization/tools/subprocess_wrapper.py”, line 123, in parent_wrapper
self.build_model()
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_model_optimization/tools/orchestator.py”, line 250, in wrapped
result = method(*args, **kwargs)
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_model_optimization/flows/optimization_flow.py”, line 240, in build_model
model.compute_output_shape(shapes)
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_model_optimization/acceleras/model/hailo_model/hailo_model.py”, line 1039, in compute_output_shape
return self.compute_and_verify_output_shape(input_shape, verify_layer_inputs_shape=False)
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_model_optimization/acceleras/model/hailo_model/hailo_model.py”, line 1073, in compute_and_verify_output_shape
layer_output_shape = layer.compute_output_shape(layer_input_shapes)
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/keras/engine/base_layer.py”, line 917, in compute_output_shape
outputs = self(inputs, training=False)
File “/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/keras/utils/traceback_utils.py”, line 70, in error_handler
raise e.with_traceback(filtered_tb) from None
File "/tmp/autograph_generated_filei08vuyih.py", line 41, in tf__call
outputs = ag
.converted_call(ag
.ld(self).call_core, (ag
.ld(inputs), ag
.ld(training)), dict(**ag
_.ld(kwargs)), fscope)
File "/tmp/autograph_generated_file43p4dg2j.py", line 90, in tf__call_core
ag
.if_stmt(ag__.ld(self).postprocess_type in [ag__.ld(PostprocessType).NMS, ag__.ld(PostprocessType).BBOX_DECODER], if_body_3, else_body_3, get_state_3, set_state_3, (‘do_return’, ‘retval_’), 2)
File "/tmp/autograph_generated_file43p4dg2j.py", line 22, in if_body_3
retval
= ag
_.converted_call(ag__.ld(self).bbox_decoding_and_nms_call, (ag__.ld(inputs),), dict(is_bbox_decoding_only=ag__.ld(self).postprocess_type == ag__.ld(PostprocessType).BBOX_DECODER), fscope)
File "/tmp/autograph_generated_filegtn2arj4.py", line 99, in tf__bbox_decoding_and_nms_call
ag
.if_stmt(ag__.ld(self).meta_arch in [ag__.ld(NMSOnCpuMetaArchitectures).YOLOV5, ag__.ld(NMSOnCpuMetaArchitectures).YOLOX], if_body_4, else_body_4, get_state_4, set_state_4, (‘decoded_bboxes’, ‘detection_score’, ‘do_return’, ‘retval_’, ‘inputs’), 4)
File "/tmp/autograph_generated_filegtn2arj4.py", line 96, in else_body_4
ag
.if_stmt(ag__.ld(self).meta_arch == ag__.ld(NMSOnCpuMetaArchitectures).YOLOV5_SEG, if_body_3, else_body_3, get_state_3, set_state_3, (‘decoded_bboxes’, ‘detection_score’, ‘do_return’, ‘retval_’), 4)
File "/tmp/autograph_generated_filegtn2arj4.py", line 93, in else_body_3
ag
.if_stmt(ag__.ld(self).meta_arch == ag__.ld(NMSOnCpuMetaArchitectures).YOLOV8, if_body_2, else_body_2, get_state_2, set_state_2, (‘decoded_bboxes’, ‘detection_score’), 2)
File "/tmp/autograph_generated_filegtn2arj4.py", line 69, in if_body_2
(decoded_bboxes, detection_score) = ag
.converted_call(ag__.ld(self).yolov8_decoding_call, (ag__.ld(inputs),), None, fscope)
File "/tmp/autograph_generated_filers_jxv4z.py", line 82, in tf__yolov8_decoding_call
decoded_bboxes = ag
.converted_call(ag__.ld(tf).expand_dims, (ag__.ld(decoded_bboxes),), dict(axis=2), fscope)
ValueError: Exception encountered when calling layer “yolov8_nms_postprocess” (type HailoPostprocess).

in user code:

File "/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_model_optimization/acceleras/hailo_layers/base_hailo_none_nn_core_layer.py", line 45, in call  *
    outputs = self.call_core(inputs, training, **kwargs)
File "/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_model_optimization/acceleras/hailo_layers/hailo_postprocess.py", line 123, in call_core  *
    is_bbox_decoding_only=self.postprocess_type == PostprocessType.BBOX_DECODER,
File "/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_model_optimization/acceleras/hailo_layers/hailo_postprocess.py", line 157, in bbox_decoding_and_nms_call  *
    decoded_bboxes, detection_score = self.yolov8_decoding_call(inputs)
File "/local/workspace/hailo_virtualenv/lib/python3.10/site-packages/hailo_model_optimization/acceleras/hailo_layers/hailo_postprocess.py", line 367, in yolov8_decoding_call  *
    decoded_bboxes = tf.expand_dims(decoded_bboxes, axis=2)

ValueError: Tried to convert 'input' to a tensor and failed. Error: None values not supported.

Call arguments received by layer “yolov8_nms_postprocess” (type HailoPostprocess):
• inputs=[‘tf.Tensor(shape=(None, 80, 80, 64), dtype=float32)’, ‘tf.Tensor(shape=(None, 80, 80, 3), dtype=float32)’, ‘tf.Tensor(shape=(None, 40, 40, 64), dtype=float32)’, ‘tf.Tensor(shape=(None, 40, 40, 3), dtype=float32)’, ‘tf.Tensor(shape=(None, 20, 20, 64), dtype=float32)’, ‘tf.Tensor(shape=(None, 20, 20, 3), dtype=float32)’]
• training=False
• kwargs=<class ‘inspect._empty’>