Skip to content
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

Dynamically load model code from the Hub #13467

Merged
merged 10 commits into from
Sep 20, 2021
Merged

Dynamically load model code from the Hub #13467

merged 10 commits into from
Sep 20, 2021

Conversation

sgugger
Copy link
Collaborator

@sgugger sgugger commented Sep 7, 2021

What does this PR do?

This PR allows a user to upload a modeling file along their model weights, and then lets the Auto classes load that model. The API is still a bit manual for now, it will be smoothed in follow-up PRs.

In terms of user of the model, the only thing to add is the flag trust_remote_code=True when using an auto class:

from transformers import AutoModel

model = AutoModel.from_pretrained("sgugger/test_dynamic_model", trust_remote_code=True)

This will load a FakeModel as defined in this file.

For the person uploading the model there is a tiny bit more work. First save the code of the model (with all necessary imports) in a single python file, for instance modeling.py. In the rest of this PR description, I'll use MODELING_FILE to represent the name of that file without the suffix (so in my example of modeling.py, MODELING_FILE is "modeling"). That file needs to be in the repository you upload.

Second, add a filed auto_map to the configuration of the model you want to upload. This needs to be a dictionary with the name of auto classes as keys, and the full name of the corresponding modeling class as values. By full name, I mean MODELING_FILE.CLASS_NAME. For instance modeling.FakeModel for a class FakeModel defined in the modeling.py module. Here is an example:

config.auto_map = {"AutoModel": "modeling.FakeModel"}

This needs to be done before the model is saved, so that when doing the model.save_pretrained call, the config is saved with that field. Once this is done, push everything to the Hub, and you should be good!

@flozi00
Copy link
Contributor

flozi00 commented Sep 7, 2021

Forgive me for interjecting and asking, but does this allow custom modules to be uploaded to modelhub and loaded and run with the official Transformers library ? just to be sure.

If that's the case, do you plan to add some code scanning ? I think on some cases where this would be an security vulnerability for remote code execution

@sgugger
Copy link
Collaborator Author

sgugger commented Sep 8, 2021

The PR requires an extra argument in the call to from_pretrained: allow_custom_model=True to execute the code from the hub. A user should not pass along that flag without having scanned the code of the repo to make sure they trust it.

@flozi00
Copy link
Contributor

flozi00 commented Sep 8, 2021

Great, thanks for clearing this

Copy link
Member

@LysandreJik LysandreJik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm having a few failures so I'll wait until you have updated the description of the PR before finishing my review

src/transformers/models/auto/auto_factory.py Outdated Show resolved Hide resolved
src/transformers/models/auto/auto_factory.py Outdated Show resolved Hide resolved
src/transformers/models/auto/auto_factory.py Outdated Show resolved Hide resolved
src/transformers/models/auto/auto_factory.py Outdated Show resolved Hide resolved
src/transformers/models/auto/auto_factory.py Outdated Show resolved Hide resolved
src/transformers/models/auto/auto_factory.py Outdated Show resolved Hide resolved
src/transformers/models/auto/dynamic.py Outdated Show resolved Hide resolved
src/transformers/models/auto/dynamic.py Outdated Show resolved Hide resolved
init_path.touch()


def check_imports(filename):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's extremely useful!


if type(config) in cls._model_mapping.keys():
if hasattr(config, "auto_map") and cls.__name__ in config.auto_map:
if not trust_remote_code:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it wouldn't be good practice to force a revision here too. Either through raising an error (best) or through logging a warning (ok): if a public repository becomes trendy, it wouldn't be surprising to see the user update the code and for it to, at best break systems running the code, at worst run arbitrary code through torch.load

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the API harder to use, no?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then let's go with a warning?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After discussing with @LysandreJik, we will need to remember to parse this auto_map attribute in the hub so we know which models are custom code models

@sgugger sgugger changed the title [WiP] Dynamically load model code from the Hub Dynamically load model code from the Hub Sep 16, 2021
Copy link
Member

@LysandreJik LysandreJik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in very good shape! I tried to break it as hard as I could but couldn't manage to do so!

Following our IRL discussions, the following point stood out: if defining a model that has a significantly different architecture than the original model (for example using a BertConfig as the model configuration, and then defining a totally different model to BERT), then the model can still be loaded in traditional BERT architectures; this is quite an edge case here, but we should keep that in mind as new configurations are allowed -> we should then make sure that models error out when loaded in architectures that don't support them.

Fantastic that it works out of the box for private models too. This should enable a myriad of use-cases.

Looks good to me, eagerly awaiting the next update enabling configuration/tokenizer creation!


if type(config) in cls._model_mapping.keys():
if hasattr(config, "auto_map") and cls.__name__ in config.auto_map:
if not trust_remote_code:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then let's go with a warning?

Copy link
Member

@LysandreJik LysandreJik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, feel free to merge!

src/transformers/models/auto/auto_factory.py Outdated Show resolved Hide resolved
Co-authored-by: Lysandre Debut <lysandre@huggingface.co>
@sgugger sgugger merged commit 002a078 into master Sep 20, 2021
@sgugger sgugger deleted the dynamic_model branch September 20, 2021 17:59
Albertobegue pushed a commit to Albertobegue/transformers that referenced this pull request Jan 13, 2022
* Dynamic model

* Use defensive flag

* Style

* Doc and arg rename

* Arg rename

* Add tests

* Apply suggestions from code review

Co-authored-by: Lysandre Debut <lysandre@huggingface.co>

* Apply suggestions from code review

Co-authored-by: Lysandre Debut <lysandre@huggingface.co>

* Address review comments

* Apply suggestions from code review

Co-authored-by: Lysandre Debut <lysandre@huggingface.co>

Co-authored-by: Lysandre Debut <lysandre@huggingface.co>
@p-christ
Copy link

hi, quick question about this PR:

It lets people upload a custom model to the hub great, but it seems that in order to call that model using the API it still requires the model to be using one of the provided Pipelines? Is there any way of also allowing a custom pipeline when calling the custom models?

@sgugger
Copy link
Collaborator Author

sgugger commented Jan 24, 2022

Custom pipelines is something we will add support for, it's on the roadmap, but for now you can't use the custom model in the API indeed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants