Problem with translation of Segformer to HAR

Hi,

I’m trying to convert my Seformer model, which I have trained. After simplification of the ONNX file and a few modifications, I have got the following error:

NetworkXUnfeasible: Graph contains a cycle or graph changed during iteration

Execution code:

runner = ClientRunner(hw_arch="hailo8")
hn, npz = runner.translate_onnx_model(
    onnx_path,
    onnx_model_name,
    start_node_names=INPUT_NODES_NAMES,
    end_node_names=OUTPUT_NODES_NAMES,
    net_input_shapes=INPUT_SHAPES,
)

Parameters:

INPUT_NODES_NAMES = ["input"]
OUTPUT_NODES_NAMES = ['Resize_2022']
INPUT_SHAPES = {'input': [1, 3, 800, 800]}

Could you give me any tips on where to look and what is wrong with the model, since I am stuck?
What is the convenient way to attach onnx file to the post?

Full error log:

      1 runner = ClientRunner(hw_arch=chosen_hw_arch)
----> 2 hn, npz = runner.translate_onnx_model(
      3     onnx_path,
      4     onnx_model_name,
      5     start_node_names=INPUT_NODES_NAMES,
      6     end_node_names=OUTPUT_NODES_NAMES,
      7     net_input_shapes=INPUT_SHAPES,
      8 )

File ~/miniconda3/envs/hailo_env/lib/python3.10/site-packages/hailo_sdk_common/states/states.py:16, in allowed_states.<locals>.wrap.<locals>.wrapped_func(self, *args, **kwargs)
     12 if self._state not in states:
     13     raise InvalidStateException(
     14         f"The execution of {func.__name__} is not available under the state: {self._state.value}",
     15     )
---> 16 return func(self, *args, **kwargs)

File ~/miniconda3/envs/hailo_env/lib/python3.10/site-packages/hailo_sdk_client/runner/client_runner.py:1187, in ClientRunner.translate_onnx_model(self, model, net_name, start_node_names, end_node_names, net_input_shapes, augmented_path, disable_shape_inference, disable_rt_metadata_extraction, net_input_format, **kwargs)
   1144 """
   1145 DFC API for parsing an ONNX model. This creates a runner with loaded HN (model) and
   1146 parameters.
   (...)
   1184 
   1185 """
   1186 parser = Parser()
-> 1187 parser.translate_onnx_model(
   1188     model=model,
   1189     net_name=net_name,
   1190     start_node_names=start_node_names,
   1191     end_node_names=end_node_names,
   1192     net_input_shapes=net_input_shapes,
   1193     augmented_path=augmented_path,
   1194     disable_shape_inference=disable_shape_inference,
   1195     disable_rt_metadata_extraction=disable_rt_metadata_extraction,
   1196     net_input_format=net_input_format,
   1197     **kwargs,
   1198 )
   1199 return self._finalize_parsing(parser.return_data)

File ~/miniconda3/envs/hailo_env/lib/python3.10/site-packages/hailo_sdk_client/sdk_backend/parser/parser.py:262, in Parser.translate_onnx_model(self, model, net_name, start_node_names, end_node_names, net_input_shapes, augmented_path, disable_shape_inference, disable_rt_metadata_extraction, net_input_format, **kwargs)
    260 except Exception:
    261     self._logger.info(f"Unable to simplify the model: {e!s}")
--> 262     raise e from None
    264 for node in simplified_model.graph.node:
    265     if not node.name:

File ~/miniconda3/envs/hailo_env/lib/python3.10/site-packages/hailo_sdk_client/sdk_backend/parser/parser.py:239, in Parser.translate_onnx_model(self, model, net_name, start_node_names, end_node_names, net_input_shapes, augmented_path, disable_shape_inference, disable_rt_metadata_extraction, net_input_format, **kwargs)
    236     onnx.save_model(onnx_model, augmented_path)
    238 try:
--> 239     parsing_results = self._parse_onnx_model_to_hn(
    240         onnx_model=onnx_model,
    241         net_name=valid_net_name,
    242         start_node_names=start_node_names,
    243         end_node_names=end_node_names,
    244         net_input_shapes=net_input_shapes,
    245         disable_shape_inference=disable_shape_inference,
    246         net_input_format=net_input_format,
    247     )
    249 except Exception as e:
    250     irrelevant_exception = isinstance(e, (MisspellNodeError, UnsupportedInputFormatError))

File ~/miniconda3/envs/hailo_env/lib/python3.10/site-packages/hailo_sdk_client/sdk_backend/parser/parser.py:320, in Parser._parse_onnx_model_to_hn(self, onnx_model, net_name, start_node_names, end_node_names, net_input_shapes, disable_shape_inference, net_input_format, **kwargs)
    317     except Exception as e:
    318         self._logger.warning(f"ONNX shape inference failed: {e!s}")
--> 320 return self.parse_model_to_hn(
    321     onnx_model,
    322     None,
    323     net_name,
    324     start_node_names,
    325     end_node_names,
    326     nn_framework=NNFramework.ONNX,
    327     output_shapes=output_shapes,
    328     net_input_format=net_input_format,
    329     **kwargs,
    330 )

File ~/miniconda3/envs/hailo_env/lib/python3.10/site-packages/hailo_sdk_client/sdk_backend/parser/parser.py:371, in Parser.parse_model_to_hn(self, model, values, net_name, start_node_names, end_node_names, nn_framework, output_shapes, net_input_format, rename_layers_by_blocks)
    368 else:
    369     raise BackendRuntimeException(f"Unsupported NN framework {nn_framework}")
--> 371 fuser = HailoNNFuser(converter.convert_model(), net_name, converter.end_node_names)
    372 hailo_nn = fuser.convert_model()
    373 hailo_nn.validate_stage(HnStage.HN)

File ~/miniconda3/envs/hailo_env/lib/python3.10/site-packages/hailo_sdk_client/model_translator/translator.py:85, in HailoNNConverter.convert_model(self)
     83 self._create_layers()
     84 self._add_layers_connections()
---> 85 self._layers_graph.set_names_and_indices()
     86 self._update_input_indices()
     87 self._update_output_indices()

File ~/miniconda3/envs/hailo_env/lib/python3.10/site-packages/hailo_sdk_common/hailo_nn/hailo_nn.py:849, in HailoNN.set_names_and_indices(self, force)
    846 # we can't have a stable order easily without relying on indices. We try to rely on names
    847 # and on insertion order
    848 sort_key = "name" if all(layer.name is not None for layer in self.nodes()) else "insertion_order"
--> 849 for index, layer in enumerate(self.stable_toposort(key=sort_key)):
    850     if layer.index != INDEX_NOT_SET:
    851         old_index_to_layer[layer.index] = layer

File ~/miniconda3/envs/hailo_env/lib/python3.10/site-packages/networkx/algorithms/dag.py:434, in lexicographical_topological_sort(G, key)
    432 if indegree_map:
    433     msg = "Graph contains a cycle or graph changed during iteration"
--> 434     raise nx.NetworkXUnfeasible(msg)

NetworkXUnfeasible: Graph contains a cycle or graph changed during iteration

Hey @Kamil_Lelowicz,

Welcome to the Hailo Community!

When you’re hitting that NetworkXUnfeasible: Graph contains a cycle or graph changed during iteration error during runner.translate_onnx_model(...), it’s almost always because there’s still some kind of loop or recurrent operator in your graph that our parser can’t flatten into a straight dataflow, even after ONNX simplification.

Here’s what I’d recommend checking:

First, take a look at your ONNX graph visually. Load up the simplified ONNX in Netron and scan for any Loop, Scan operators, or residual connections that might be feeding outputs back to earlier operations. If you’re using the augmented_path argument, you can save the simplified model and examine it directly:

hn, npz = runner.translate_onnx_model(
    onnx_path, "seformer", …,
    augmented_path="seformer_simplified.onnx",
)

Then open seformer_simplified.onnx in Netron to see what’s going on.

Try turning off ONNX-RT shape inference. Sometimes the shape inference pass introduces identity nodes or reshape loops that confuse our parser. You can disable it with:

hn, npz = runner.translate_onnx_model(
    onnx_path, model_name,
    start_node_names=["input"], end_node_names=["Resize_2022"],
    net_input_shapes={'input':[1,3,800,800]},
    disable_shape_inference=True,
)

This often clears up artifacts that create cycles.

Double-check your start and end nodes. Make sure the names in start_node_names and end_node_names actually bracket a purely feed-forward section of your graph. If you accidentally include a node that’s part of a control-flow loop, the parser will try to include the whole loop. Generally you want to pick the very first real input (like "input") and the very last real output of your backbone (like the final softmax or resize).

Once you get a successful parse, you can also dump a Hailo Archive and visualize the internal graph to confirm everything looks right:

runner.save_har("seformer.har")
!hailo visualizer seformer.har --no-browser

This will generate an SVG of the Hailo-internal graph so you can verify it’s acyclic.

Hope this helps! Let me know if you’re still running into issues.