-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Opaque disruptive handling of variable axes of ONNX-models #5293
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi, @UlrichSuess . Thank you very much for your feedback. I'm very interested in the workaround you mention, and have some questions I'll make below. But first, let me explain some points:
[VectorType(2, 3)]
public float[,] input { get; set; } // use arrays of dimensions 2, 3 And actually what ML.NET needs is: [VectorType(2, 3)]
public float[] input { get; set; } // use arrays of size 6 This means ML.NET does expect the user to "flatten" their input multidimensional array into a one-dimensional array.
Regarding your workaround.So I was wondering if it's possible for you to share a .zip file containing your code, onnx model and some sample data to understand the workaround you're describing. This could be helpful to understand more about how users use Onnx in ML.NET, and also provide us ideas when we get to plan future enhancements to the If you're not able to share it, then a description of the shapes of the input and output of your onnx model, along with the code of your input and output classes and (perhaps) the code of how you flatten your input array, would be useful. In particular I'd be interested in these points: 2. Does your workaround let you use variable length "sequences"?. From reading your issue I'm not sure if this is required to you, and if your workaround handles this. In particular, what do you mean when you say "The DataView has to be reset for each sequence, too, of course, to contain the specific sequence length." Does every row in your input dataset have "sequences" of different size? 3. Is your output of variable length too? If so, how do you handle it? |
Hi Antonio, thanks for your fast and very informative response. Alas, I cannot give you the project itself, there is company IP in the model and test data, but probably that won't be necessary, anyway. The code is in a rather unpresentable proof of concept state, too, right now. For starters, though, here a few explanations and code snippets hopefully clarifying the approach.
After unsuccessfully trying multidimensional approaches, in the end we arrived at the simple but sufficient input class
There is nothing special about the flattening itself. There is a data loader class that produces InputSequence objects from a test set file, right now always assuming batch size 1 and just concatenating the features of all sequence tokens into one array. This is stuffed into an IEnumerable called "sequence" and used later on (see following section).
As for variable sequences and setting up DataView and the model: for the batchSize=1-scenario consider the following snippets: for the DataView:
for the model:
This extra code has to be run for each sequence before actually inferring from the model. So there is no real variable length, right now it is rather "always reset to the proper fixed size". There are loads of task cancel exceptions, by the way, when running this through a few hundred sequences. These exceptions are caught by ML.NET-code, apparently, and cause no visible functional problems.
Yes, our input data has sequences of different size, but as stated above, the DataView is reset for each new sequence (in the batchSize=1-scenario).
I have just been able to extend the workaround to use batch sizes > 1 with a very useful speedup in raw inference time at a currently rather high cost for additional data preparation, especially padding shorter sequenes. In the specific case, batch size 10 reduces total inference time to a third. Work in progress. By the way, all on cpu. Using batch size > 1 in this case means setting up the model and the DataView only once per whole batch, with all sequences padded to the length of the longest in the batch. So for a batch, all sequences have to be of same length. That is the same as in PyTorch, though.
Our output contains one large float[]. Knowing the output size (here four labels), each sequence length (unpadded!) within the current batch and the current batch size (which may vary, even for intended fixed size, as the very last badge may be smaller), it's easy to split that to obtain the proper outputs for each sequence. Feel free to ask for further explanations if necessary. Uli EDIT: in snippet for DataView-adjusment
|
Thanks for your detailed answer, @UlrichSuess . Your workaround for making Your workaround for working with variable length dimensions is also interesting. As of now I can't think of any other way of accomplishing this on ML.NET, so maybe your approach of needing to "reset" the schema definition is the best workaround there is. |
Thanks for your assessment, Antonio. We will stick to this approach for the time being, then, and keep an eye on coming ML-NET changes. |
### System information
### Issue
remark: I do have a functional workaround solution, but it requires quite some nasty additional code and probably is a bit slower than optimal.
The main point of critique here concerns the OnnxTransform class.
What did you do?
Tried to do inference with an ONNX-model for sequence labeling with two variable input axes (batch and sequence).
The whole input (3 dimensions: batch, sequence, features) were put into one big float[]. Still not sure whether this is really the correct way. All attempts to use multidimensional input fields failed.
What happened?
As stated in source code (OnnxTransform.MakeRowMapper(...), see below), dimensions of variable input axes were set to 1, resulting in incorrect batches and sequences of size 1 each, regardless of specified DataView.
There is no explicit hint leading to the dimensionality reduction, however. The problem is documented, but that's in a private method. You only get an exception when feeding your whole sequence (as stated as one big float[]), because due to the dimension reduction the set up model expects length 1 * 1 * FeatureLength, and the input vector gets is large for that. At least that exception tells you that the product of the dimensions is relevant.
The workaround consists of setting up the "model" for each sequence by using the ApplyOnnxModel-overload with the input size dictionary "shapesDictionary". The documentation for that overload method is a bit cryptic, though (see below). It does allow to override the reduction to 1 of the variable axes (and only for those!) by using the values in the dictionary, but I learned that from the source code, not from the documentation.
The DataView has to be reset for each sequence, too, of course, to contain the specific sequence length.
Took unnecessarily long to find the source of the problem and the workaround solution.
What did you expect?
Best case: Full support for variable input dimensions, which should extend to the DataView and the model.
2nd best: Even for my chosen workaround of adjusting everything for each sequence to contain specific sequence length, the model-row-mapper should infer the correct dimensions instead of reducing them to 1 (there IS a todo comment for that). Fortunately, the time for the resets still make the workaround kind of usable. (although at batch size 1, so far, for more padding will probably be necessary, the effect of which remains to be checked)
At least: Output some kind of hint that the reduction takes place, at least in the public documentation for ApplyOnnxModel(...) or with further information in the exception when the sizes don't fit.
Source code / logs
From OnnxTransform.cs:
From OnnxCatalog.ApplyOnnxModel(...) not too helpful documentation:
suggestion:
The text was updated successfully, but these errors were encountered: