kraiskil/onnx2c

Error non-constant input (limit) to Range node

Closed this issue · 3 comments

I just discovered this project and I am attempting to convert a vits speech synthesis model from onnx to C. I am running into the following error message:

[FATAL] (resolve) Unimplemented: non-constant input (limit) to Range node

Looking at the implementation of the Range node it seems fairly simple, but I don't know what the best/cleanest way to lift this limitation would be. Are there any similar nodes that I could use as a starting point for how to receive non-const floats and generating the appropriate output C code? Presumably I would want to generate a C function that takes this as an input parameter, rather than printing out the actual number in the code as a literal? Any tips would be highly appreciated.

This is, unfortunately, a fundamental limitation for onnx2c. The target for the tool is embedded microcontrollers, where dynamic memory allocation notoriously can make programming more difficult.

In this case, the Range node's input limit is the output of some other node, i.e. it is content is not known at compile time.
This means Range would produce a tensor, the size of which is known only at runtime ( https://github.com/onnx/onnx/blob/main/docs/Operators.md#Range ) And this Range's output tensor would then need to be allocated dynamically.

I think there are a few alternatives to solving this.

  1. Check if your model really needs run-time definition of tensor sizes. Can it be changed to e.g. putting a constant upper limit to the size of tensors it produces?
  2. If the model already does not use dynamically sized tensors, some intermediate library maybe adds a dynamically sized tensor as an optimization? Can this creating/optimizing/saving step be found and coerced not to produce a run-time value for the limit input for Range? Maybe the limit actually is already constant, but just not marked as one? You can also pass constant values on the command line (./onnx2c -d foo:3) for variables in the model (but I think this is implemented only for the inference batch size...). But this would require the limit to be a variable, not the output of some other node.
  3. I'm not against adding dynamic memory allocation support to onnx2c. It's just a lot of work to implement and test. Pull requests welcome :)
  4. the catch-all... find a more suitable tool than onnx2c

It's difficult to say which is the best approach here. Maybe seeing the .onnx file, or the image of it generated by e.g. netron would help? (or at least a small zoomed in part around the Range node, if the model is huge or secret)

Right, I can see how generating audio would benefit from dynamically sized tensors.

Looking forward to seeing your solution. Especially if there is something that can be incorporated into onnx2c.

From how I can foresee what an onnx2c-based solution looks like, supporting dynamic size tensors would require passing the tensor size info with the kernel function arguments, i.e. most likely wrapping the raw data and size info in a struct (like a light weight C++ class/object, really), and passing these to the functions instead of a raw pointer. This would require quite a bit of refactoring of the onnx2c codegen parts (i.e. always query the tensor for it's sizes - in every node implementation...). Somehow I feel such a restructuring would actually make the onnx2c code base a bit cleaner though :)
If you decide to give this approach a go, please keep in touch early to design on how the new onnx2c internals would look like.

Good luck :)