Unable to optimize custom yolov7 with additional output layer

I have a modified yolov7 model with additional output layer (a classification output). when translating onnx, i have added 4 conv layers as output nodes (3 for yolo detection, 1 for classification). I wanted to add nms for the 3 layers in optimization step, and leave the other layer as is. was able to add nms_postprocess in the script. But during the optimize process, it stops with error

[warning] output_layers_order in net_params don't match actual output layers in HN. InvalidHNError: There are multiple outputs found in the HN, but only one layer in output_layers_order.

here is the parsing part:

start_node =[‘images’]
end_nodes = [“/model.77/detect_head/m.0/Conv”,“/model.77/detect_head/m.1/Conv”,“/model.77/detect_head/m.2/Conv”,“550”]
runner = ClientRunner(hw_arch=‘hailo8’)
hn, npz = runner.translate_onnx_model(model=yolo_onnx_model_path,
net_name=yolo_model_name,
start_node_names=start_node,
end_node_names=end_nodes,
net_input_shapes={‘images’:[4, 3, 512,512]})

this is the model script and optimization:

alls_lines_yolo= [
    'normalization1 = normalization([0.0, 0.0, 0.0], [255.0, 255.0, 255.0])\n',
    'nms_postprocess("nms_config_yolov7.json",meta_arch=yolov5)\n',
    'model_optimization_config(calibration, batch_size=4, calibset_size=30)\n',

]

open('yolo_script.alls','w').writelines(alls_lines_yolo)

runner.load_model_script('yolo_script.alls')

runner.optimize_full_precision(calib_set)
1 Like

Hey @nmitikiri,

Welcome to the Hailo Community!

The issue you’re running into is pretty straightforward - after applying NMS postprocessing, your network has two outputs (the NMS detection results + your classification head), but your output_layers_order still only lists one entry. That’s what’s causing the error.

Here’s what’s happening:

When you run nms_postprocess() on your 3 YOLO detection heads, it merges them into a single post-NMS output tensor. But you’ve still got your 4th output (the classification branch - your “550” node) sitting there untouched. So now your network has 2 outputs total, but your configuration only accounts for 1.

The fix is simple - you need to update your output_layers_order to include both outputs:

# After applying NMS to your detection heads
nms_postprocess("nms_config_yolov7.json", meta_arch=yolov5,
                inputs=[
                    "/model.77/detect_head/m.0/Conv",
                    "/model.77/detect_head/m.1/Conv", 
                    "/model.77/detect_head/m.2/Conv",
                ])

# Make sure your classification output stays exposed
keep_outputs(["550"])

# Update the output order to match both outputs
set_output_layers_order(["nms", "550"])  # Use the actual tensor names from your network

Key points to remember:

  • The exact function names might vary slightly depending on your SDK version, but the concept is the same
  • Make sure the names in output_layers_order exactly match the actual tensor names in your network after NMS processing
  • The number of entries in output_layers_order must match the actual number of outputs your network has

You can check the actual output tensor names by looking at your network summary after applying the model script. Just copy those exact names into your output_layers_order list.

Hope this helps!

Hi, thanks for the solution. But I got multiple errors when running the model script updated with what you mentioned. When I add the inputs=[] argument in the nms_postprocess I ger the below error.

~/hailo_sdk_32/sdk_32/lib/python3.10/site-packages/hailo_sdk_client/sdk_backend/script_parser/nms_postprocess_command.py:283, in NMSPostprocessCommand.from_tokens(cls, tokens, script_path, provided_config_file)
    281         arg_enum = NMSProperties(arg_name) if arg_name in NMSProperties._value2member_map_ else None
    282         if arg_enum is None or arg_enum not in NMS_ARGUMENTS_ORDER:
--> 283             raise AllocatorScriptParserException(
    284                 f"No argument named {arg_name}. Please make sure to use the "
    285                 f"argument name as it appears in the command description.",
    286             )
    288         args_dict.update({arg_enum: arg[arg_name]})
    290 return cls(args_dict, script_path, provided_config_file)

AllocatorScriptParserException: No argument named inputs. Please make sure to use the argument name as it appears in the command description.

And also error for both keep_outputs() and set_output_layers_order() functions

File ~/hailo_sdk_23/sdk_23/lib/python3.10/site-packages/hailo_sdk_client/sdk_backend/script_parser/model_script_parser.py:312, in ModelScriptParser.parse_script(self, input_script)
    309     return self.commands
    311 except pp.ParseException as e:
--> 312     raise BackendScriptParserException('Parsing failed at:\n{}'.format(e.markInputline()))

BackendScriptParserException: Parsing failed at:
>!<keep_outputs(["550"])

BackendScriptParserException: Parsing failed at: >!<set_output_layers_order(["nms_output_layer", "550"])

I tried this on sdk 23 and 32. I could not find any functions similar to that in both the version documentations. Also, the inputs argument is not present for nms the below one are the only arguments I found in sdk_client / hailo_model_optimization libraries.

class NMSProperties(Enum):
    """Enum-like class for NMS post-process command arguments"""

    CONFIG_PATH = "config_path"
    META_ARCH = "meta_arch"
    ENGINE = "engine"
    ENFORCE_IOU_THRESHOLD = "enforce_iou_threshold"
    BBOX_DECODING_ONLY = "bbox_decoding_only"
    DFL_ON_NN_CORE = "dfl_on_nn_core"
    OUTPUT_ORIGINAL_NAME = "output_original_name"

    # The members below can be also configured via the json
    SCORES_TH = "nms_scores_th"
    IOU_TH = "nms_iou_th"
    IMAGE_DIMS = "image_dims"
    CLASSES = "classes"
    MAX_TOTAL_OUTPUT_PROPOSALS = "max_total_output_proposals"
    MAX_PROPOSALS_PER_CLASS = "max_proposals_per_class"
    MASK_THRESHOLD = "mask_threshold"
    REGRESSION_LENGTH = "regression_length"