-
Notifications
You must be signed in to change notification settings - Fork 496
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
Add vision encoder decoder model in exporters #588
Add vision encoder decoder model in exporters #588
Conversation
The documentation is not available anymore as the PR was closed or merged. |
d6fef2f
to
7e5932e
Compare
d333eb4
to
7f3b18f
Compare
tests/exporters/exporters_utils.py
Outdated
@@ -110,6 +110,7 @@ | |||
"speech-to-text": "hf-internal-testing/tiny-random-Speech2TextModel", | |||
"xlm": "hf-internal-testing/tiny-random-XLMModel", | |||
"xlm-roberta": "hf-internal-testing/tiny-xlm-roberta", | |||
"vision-encoder-decoder": "hf-internal-testing/tiny-random-VisionEncoderDecoderModel-vit-gpt2", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a test for trocr
and donut-swin
as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added for trocr, donut-skin has threshold issue while exporting would look into it separately
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then could we not add it in tasks.py? And handle adding donut-swin in a separate PR altogether?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test model has high atol requirement (4e-2). The export for the model in doc is slow but works with 1e-3 threshold, so not putting that here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean by the model in doc
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd just like that what is said to be supported in tasks.py
is actually supported, and we can make sure of it by adding an unit test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented Donut. Will handle this separately
behavior=behavior, | ||
) | ||
|
||
from ..tasks import TasksManager |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would we have it at the top level?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It causes circular export on top
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could mean that some refactor is needed, I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deferring import would still be ok IMO. But if there is a better way would look into it.
optimum/utils/normalized_config.py
Outdated
def __getattr__(self, attr_name): | ||
if ( | ||
self.ENCODER_CONFIG is not None | ||
and self.ENCODER_NORMALIZED_CONFIG_CLASS is not None | ||
and attr_name.upper() in dir(self.ENCODER_NORMALIZED_CONFIG_CLASS) | ||
): | ||
return self.ENCODER_NORMALIZED_CONFIG_CLASS.__getattr__(attr_name) | ||
if ( | ||
self.DECODER_CONFIG is not None | ||
and self.DECODER_NORMALIZED_CONFIG_CLASS is not None | ||
and attr_name.upper() in dir(self.DECODER_NORMALIZED_CONFIG_CLASS) | ||
): | ||
return self.DECODER_NORMALIZED_CONFIG_CLASS.__getattr__(attr_name) | ||
|
||
return super().__getattr__(attr_name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These type of models can have any decoder and encoder head and it is difficult to manage every normalised class. So created this helper class to work with these models
DummySeq2SeqDecoderTextInputGenerator, | ||
DummyPastKeyValuesGenerator, | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add the nromalized config creation here instead of setting attributes in the if branches. I would also add a type check on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to set the values in constructor than setting attribute? Plus why would type check be necessary?
Co-authored-by: fxmarty <9808326+fxmarty@users.noreply.github.com>
d949251
to
9b32631
Compare
class NormalizedEncoderDecoderConfig(NormalizedConfig): | ||
ENCODER_NORMALIZED_CONFIG_CLASS = None | ||
DECODER_NORMALIZED_CONFIG_CLASS = None | ||
|
||
def __getattr__(self, attr_name): | ||
if self.ENCODER_NORMALIZED_CONFIG_CLASS is not None and attr_name.upper() in dir( | ||
self.ENCODER_NORMALIZED_CONFIG_CLASS | ||
): | ||
return self.ENCODER_NORMALIZED_CONFIG_CLASS.__getattr__(attr_name) | ||
if self.DECODER_NORMALIZED_CONFIG_CLASS is not None and attr_name.upper() in dir( | ||
self.DECODER_NORMALIZED_CONFIG_CLASS | ||
): | ||
return self.DECODER_NORMALIZED_CONFIG_CLASS.__getattr__(attr_name) | ||
|
||
return super().__getattr__(attr_name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't the attr_name
be in both the encoder and decoder config? e.g. bos_token_id
in https://huggingface.co/microsoft/trocr-small-handwritten/blob/main/config.json . Could this result in unexpected behavior? We should rather be able to access attributes recursively no, like normalized_config.encoder.bos_token_id
or normalized_config.decoder.bos_token_id
, if this makes sense!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it could be possible. This seems to be a common problem for the other hybrid configs also. Would make a note of it and handle it separately.
Having something like this normalized_config.encoder.bos_token_id
or normalized_config.decoder.bos_token_id
would require change in the entire input_generator so would need to think of a better way.
Currently, this would not affect the ORT export (where we export the encoder and decoder separately) as one of the configs would always be None. So considering it low priority.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
Hi @mht-sharma can you kindly provide some insights about how to remove the following limitation from the above issue:
|
@Mir-Umar Feel free to open an issue as well. |
@Mir-Umar There is an existing issue for this #744. I did not got the time to work on this yet. The |
What does this PR do?
Supports vision-encoder-decoder export to onnx in optimum
Changes
vision-encoder-decoder
models using the above classLimitation
Fixes # (issue)
Before submitting