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
[JIT] Add API for ignoring arbitrary module attributes #45262
Conversation
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. [ghstack-poisoned]
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. ghstack-source-id: b9fcadc0f56ffe932250905f1c31743ef9de9a0c Pull Request resolved: #45262
💊 CI failures summary and remediationsAs of commit ded8d28 (more details on the Dr. CI page): Commit ded8d28 was recently pushed. Waiting for builds... This comment was automatically generated by Dr. CI (expand for details).Follow this link to opt-out of these comments for your Pull Requests.Please report bugs/suggestions on the GitHub issue tracker or post in the (internal) Dr. CI Users group. This comment has been revised 68 times. |
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. [ghstack-poisoned]
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. [ghstack-poisoned]
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. ghstack-source-id: 7f7e38a6ab760e5f7cf1195dbca468eb80d5d6a4 Pull Request resolved: #45262
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.
Cool! This is definitely needed as we're adding compilation of a few types of module attributes that we didn't previously (properties, enums, class types).
I guess there's some question about __unused__
vs __ignored__
- I think ignore'd makes since here bc we're attaching it to the model but maybe not.
We could potentially allow attribute access in scripted methods but probably not worth the effort for this PR.
Bikeshedding: wdyt of __jit_ignored__attributes__
? __constants__
doesnt explicitly mention jit, but I think maybe it'd be clearer if it did.
ping @suo for another person to look at API.
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. [ghstack-poisoned]
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. ghstack-source-id: 62642931355508cc7e76ff6b15e1225e8bfa0494 Pull Request resolved: #45262
I like |
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. [ghstack-poisoned]
We haven’t done a release yet so I think it’s good to get the best api even if we have to switch it once. We can also let the old api still work if we want |
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. [ghstack-poisoned]
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. [ghstack-poisoned]
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. [ghstack-poisoned]
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. [ghstack-poisoned]
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. [ghstack-poisoned]
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.
Conventionally, unused
means that the function can be used in a script'd function and will error if it's being invoked but the model can still be exported. ignore
means we retain the python function, it can be invoked in the module, but will error if export'd. Here we're retaining python attributes, but not allowing them to be invoked and still the model can be exported.
It might make more sense for this to be unused
instead of ignored
, although on the other hand we could just as easily extend __jit_ignored_attributes__
to allow accessing them in scripted functions.
I don't think this should block landing just something to think about.
Hm, but the |
Codecov Report
@@ Coverage Diff @@
## gh/splitinfinity/53/base #45262 +/- ##
===========================================================
Coverage ? 68.20%
===========================================================
Files ? 410
Lines ? 53257
Branches ? 0
===========================================================
Hits ? 36323
Misses ? 16934
Partials ? 0 Continue to review full report at Codecov.
|
@@ -123,6 +125,10 @@ def infer_type(name, item): | |||
added_names = set() | |||
|
|||
for name, item in nn_module._parameters.items(): | |||
if name in user_annotated_ignored_attributes: |
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 don't think we need to check user_annotated_ignored_attributes
for each present attribute, we can just add it all to the concrete type right away, e.g.
concrete_type_builder.add_ignored_attributes(user_annotated_ignored_attributes)
The only difference would be that ignored attributes would be added even if they aren't present in the module object, but that won't make a difference in practice I think.
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.
But we still need to skip adding attributes if they are ignored, right? So instead of
if name in user_annotated_ignored_attributes:
concrete_type_builder.add_ignored_attribute(name)
continue
we'd have
if name in user_annotated_ignored_attributes:
continue
or
if {existing_condition} and name not in user_annotated_ignored_attributes:
concrete_type_builder.add_xxx(...)
torch/jit/_recursive.py
Outdated
@@ -104,6 +104,8 @@ def infer_concrete_type_builder(nn_module, share_types=True): | |||
concrete_type_builder.set_module_list() | |||
|
|||
class_annotations = getattr(nn_module, '__annotations__', {}) | |||
# Get user-annotated ignored attributes. | |||
user_annotated_ignored_attributes = getattr(nn_module, "__jit_ignored_attributes__", set()) |
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.
__torchscript_ignored__
? JIT is a little overloaded.
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 just landed a change to name the equivalent class attribute for unused properties __jit_unused_properties__
. I'm good with either, but I just want to make sure they're consistent. So I can either keep this or change both to __torchscript_ignored_xxx__
.
@@ -186,6 +186,10 @@ c10::optional<std::string> ConcreteModuleType::findFailedAttribute( | |||
return c10::nullopt; | |||
} | |||
|
|||
bool ConcreteModuleType::isIgnoredAttribute(const std::string& name) const { |
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.
You need to edit ConcreteModuleTypeBuilder::equals
so that this field gets used to disambiguate instances of a concrete type.
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 added this but it's hard to test because ignoring an attribute changes the list of attributes on the ConcreteModuleTypeBuilder
instance. The equality check between ConcreteModuleTypeBuilder
instances (also ConcreteModuleType
and Builder
instances) fails when when an attribute is ignored even if there is no ignoredAttributes_ == other.ignoredAttributes_
condition added to ConcreteModuleTypeBuilder::equals
because attributes_ == other.attributes_
is false
.
I'm not saying we shouldn't have it, but I can't prove that it works.
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.
As far as I understand, ConcreteMuduleType::equals is to disambiguate between different instantiations of an nn.Module which can result in a different type. __jit_ignored_attributes__
is a class-level attribute, I don't see how it could differ between different instantiations.
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.
That's my understanding too, but as per one of my tests, the class attribute can be edited between invocations to torch.jit.script
. I don't think it's a realistic use case, but it is possible. But as I mentioned in my earlier comment, unintended type sharing does not happen because modifying that class attribute changes which attributes are included/excluded in ConcreteModuleTypeBuilder
.
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 can be edited, or we can set it in the body of the __init__
, e.g.
def __init__(self, ignored):
self.__ignored__ = ignored
Both happen with some degree of regularity for other elements of ConcreteModuleType. But good point that it changes the available attributes, so checking ignored attrs is somewhat redundant. I think we should do it still for consistency, since all other attributes of ConcreteModuleType should participate in equality.
@@ -678,6 +678,56 @@ def attr(self): | |||
with self.assertRaisesRegex(torch.nn.modules.module.ModuleAttributeError, "has no attribute"): | |||
scripted_mod.ignored_attr | |||
|
|||
def test_ignoring_module_attributes(self): |
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.
- can we add tests to
test_type_sharing.py
to make sure we are not improperly sharing types with different ignored attributes sets? - I think we should stop adding to
test_jit_py3.py
. This file originally existed because it let us use py3 syntax, but that no longer has a purpose now that we are py3 only.
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 added tests to
test_type_sharing.py
to test that types are shared if ignoring attrs make them equal and not shared if the ignored attributes list is modified and the types of modules before and after the modification should be different. - Where should I move them?
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.
For 2: not sure, I wish we had the tests that exercise "compilation customization" APIs, but they have not yet been factored out of test_jit.py
.
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. Differential Revision: [D23971882](https://our.internmc.facebook.com/intern/diff/D23971882) [ghstack-poisoned]
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. Differential Revision: [D23971882](https://our.internmc.facebook.com/intern/diff/D23971882) [ghstack-poisoned]
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.
Changes LGTM, bikeshedding was addressed, and this is improvement to the codebase so accepting. It'd also be good to land the API change for the upcoming release to reduce API churn so any remaining outstanding comments can be addressed in a follow up
@@ -186,6 +186,10 @@ c10::optional<std::string> ConcreteModuleType::findFailedAttribute( | |||
return c10::nullopt; | |||
} | |||
|
|||
bool ConcreteModuleType::isIgnoredAttribute(const std::string& name) const { |
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.
As far as I understand, ConcreteMuduleType::equals is to disambiguate between different instantiations of an nn.Module which can result in a different type. __jit_ignored_attributes__
is a class-level attribute, I don't see how it could differ between different instantiations.
**Summary** This commit adds an API for ignoring arbitrary module attributes during scripting. A class attribute named `ignored_attributes` containing names of attributes to ignore can be added to the class of the instance being scripted. Attributes ignored in this fashion cannot be used in `forward`, methods used by `forward` or by `@exported` methods. They are, however, copied to the `RecursiveScriptModule` wrapper and can be used by `@ignored` methods and regular Python code. **Test Plan** This commit adds unit tests to `TestScriptPy3` to test this new API. Differential Revision: [D23971882](https://our.internmc.facebook.com/intern/diff/D23971882) [ghstack-poisoned]
@SplitInfinity merged this pull request in 4fdba30. |
Stack from ghstack:
Summary
This commit adds an API for ignoring arbitrary module attributes during
scripting. A class attribute named
ignored_attributes
containing namesof attributes to ignore can be added to the class of the instance being
scripted. Attributes ignored in this fashion cannot be used in
forward
, methods used byforward
or by@exported
methods. Theyare, however, copied to the
RecursiveScriptModule
wrapper and can beused by
@ignored
methods and regular Python code.Test Plan
This commit adds unit tests to
TestScriptPy3
to test this new API.Differential Revision: D23971882