-
Notifications
You must be signed in to change notification settings - Fork 26.3k
[1/N] Implement Enum JIT support #41390
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
Conversation
💊 CI failures summary and remediationsAs of commit c642907 (more details on the Dr. CI page):
ci.pytorch.org: 1 failedThis 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 127 times. |
facebook-github-bot
left a comment
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.
@gmagogsfm has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
facebook-github-bot
left a comment
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.
@gmagogsfm has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
facebook-github-bot
left a comment
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.
@gmagogsfm has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
facebook-github-bot
left a comment
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.
@gmagogsfm has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
facebook-github-bot
left a comment
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.
@gmagogsfm has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
eellison
left a comment
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.
Looks like a great start!! Just a few comments here or there. Overall looks great though. LMK if you need any pointers for serialization / attribute access.
aten/src/ATen/core/jit_type.h
Outdated
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.
Didn't think of this earlier, but I don't think we should support mutable Enum values. I don't think it's a common use case, and we would have to maintain one singleton IValue.
class Color(Enum):
RED = torch.tensor(1)
# all Color.RED instances would have to be updated, or we have to maintain a single instance
Color.RED += 2
For the same reason, I don't know if we should support Any because it could be a mutable type (and it's also not a common use case).
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.
Yeah, current implementation would break with mutable values. Removed Tensor and Any type.
aten/src/ATen/core/jit_type.h
Outdated
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 force the QualifiedName to always be 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.
Good point. Added an assert to enforce that.
torch/_jit_internal.py
Outdated
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 did we need to make this change ? Seems a little strange
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.
Enum class doesn't have "__name__" attr, instead they use "name", I am not sure why the inconsistency.
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.
Weird. nit: maybe elif isinstance(obj, Enum) in elif conditional instead so it's a little more clear why this is needed
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.
Indeed very weird. Done.
torch/jit/annotations.py
Outdated
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.
see comment above about supporting mutable types for enum value
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.
So AnyType is no longer appropriate. Should I create another type that is super-type of int, float and string for this case?
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 think we should just throw an error instead. If users complain we can get back to this, but the common case is one type of value for an enum.
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.
Good point. Done.
gmagogsfm
left a comment
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.
Thanks for the suggestions, I have modified accordingly. Please take another look.
aten/src/ATen/core/jit_type.h
Outdated
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.
Yeah, current implementation would break with mutable values. Removed Tensor and Any type.
aten/src/ATen/core/jit_type.h
Outdated
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.
Good point. Added an assert to enforce that.
torch/_jit_internal.py
Outdated
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.
Enum class doesn't have "__name__" attr, instead they use "name", I am not sure why the inconsistency.
torch/jit/annotations.py
Outdated
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.
So AnyType is no longer appropriate. Should I create another type that is super-type of int, float and string for this case?
facebook-github-bot
left a comment
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.
@gmagogsfm has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
eellison
left a comment
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.
Looks good as far as logic in this PR. I think we should wait to land this until the rest of the stack is implemented, bc otherwise someone could try to use Enums and get half-implemented version (as we have sometimes done with other features :C)
torch/_jit_internal.py
Outdated
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.
Weird. nit: maybe elif isinstance(obj, Enum) in elif conditional instead so it's a little more clear why this is needed
torch/jit/annotations.py
Outdated
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 think we should just throw an error instead. If users complain we can get back to this, but the common case is one type of value for an enum.
SplitInfinity
left a comment
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.
Some initial comments
aten/src/ATen/core/ivalue.h
Outdated
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 seems like there are formatting changes included with your addition below. I recommend undoing the formatting changes.
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.
Yeah, I actually intentionally added them. These are all at or near codes that I touched in this PR, in the spirit of leaving the camp ground cleaner. Let me know if this complies with project convention or not.
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 personally prefer to make separate commits to clean up formatting but it's not a big deal.
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.
Ack. Thanks.
aten/src/ATen/core/ivalue.h
Outdated
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.
Nit: undo formatting
aten/src/ATen/core/ivalue.h
Outdated
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.
Nit: undo formatting
aten/src/ATen/core/ivalue_inl.h
Outdated
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.
Was this intentionally added?
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.
Yeah, I noticed some of these functions are separated by empty lines but some are not, so made them more consistent.
aten/src/ATen/core/ivalue_inl.h
Outdated
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.
Was this intentionally added?
aten/src/ATen/core/ivalue_inl.h
Outdated
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.
Consider storing this as a c10::QualifiedName. That class has useful methods for extracting the prefix, unqualified name, etc. that might be useful later.
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.
Ah, nice! Done.
aten/src/ATen/core/jit_type.h
Outdated
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 is the name allowed to be optional? All enum types must have names, right?
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.
Also weren't there plans to support heterogeneous enums with mixed value types? Or is that coming later or out of scope?
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.
Name isn't allowed to be empty. "optional" was originally added to conform to NamedType's convention, but now I realized constructor can take concrete value and then create "optional" to make NamedType happy. Changed.
To answer your second question, Elias gave feedback that heterogeneous enum value types is quite uncommon and makes enum logic a lot more complicated, so we decided to mark it out of scope for now.
test/jit/test_enum.py
Outdated
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.
Perhaps this is coming in the future but you should consider adding a test that checks that enums can be returned from scripted functions (i.e. copied back correctly from TS to Python).
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.
Definitely, this is listed as a TODO in the PR description.
aten/src/ATen/core/jit_type.h
Outdated
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.
| value_type_(value_type), cu_(cu) { | |
| value_type_(std::move(value_type)), cu_(cu) { |
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.
Done. But out of curiosity, value_type is already a light-weight TypePtr, does it still benefit from std::move?
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.
TypePtr is defined as using TypePtr = std::shared_ptr<Type> so I think std::move is a good idea here. Copying it requires atomically incrementing the reference count.
I see your point, but I am a bit concerned about the tsunami of merge conflicts because these PRs combined will touch a lot of files. How about this? I can hide this functionality behind say a environment variable-based config knob, so that no users would "accidentally" access this feature, and we can avoid merge conflicts. |
facebook-github-bot
left a comment
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.
@gmagogsfm has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
eellison
left a comment
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 think there'll probably be less merge conflicts than you think, but sure sounds good to land.
Could you add two tests to make sure this is properly guarded:
Something like this fails:
def enum_comp(x: Color, y: Color) -> bool:
return x == y
torch.jit.script(enum_comp)
and something like this fails:
class Mod(Module):
def __init__(self):
...
self.enum_attribute = Color....
def forward(self, x):
return self.enum_attribute
torch.jit.script(Mod())
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.
AnyEnumType will never show up as an instantiated type, it can go with AnyTupleType::Kind in set of cases
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.
Done.
torch/jit/annotations.py
Outdated
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'd be better to use https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/core/jit_type.h#L1513 so that we get a good error message here ("Type str did not match type int...") . you'd need to convert the types to jit type first with ann_to_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.
Done.
torch/jit/annotations.py
Outdated
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.
Return None here to disable
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 a check here, but raised an exception instead of returning None so that user gets a clearer error.
gmagogsfm
left a comment
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 a feature guard to prevent users from accidentally using it.
aten/src/ATen/core/ivalue.h
Outdated
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.
Ack. Thanks.
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.
Done.
torch/jit/annotations.py
Outdated
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.
Done.
torch/jit/annotations.py
Outdated
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 a check here, but raised an exception instead of returning None so that user gets a clearer error.
facebook-github-bot
left a comment
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.
@gmagogsfm has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
facebook-github-bot
left a comment
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.
@gmagogsfm has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
facebook-github-bot
left a comment
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.
@gmagogsfm has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
|
@gmagogsfm not sure if you requested review intentionally, but generally the workflow on pytorch is a reviewer will accept a PR with small outstanding fixes if they think they're easily addressable / nits that dont necessarily have to be addressed. Can take another look if you'd like but you're good to land without me looking |
Yeah, I clicked requested review to be on the safe side. But now that I think about it, the additional changes are tiny, so I will and now. Thanks eelison and splitinfinity for reviewing. |
facebook-github-bot
left a comment
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.
@gmagogsfm has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
* Enum support tempoartily hidden behind environemnt variable EXPERIMENTAL_ENUM_SUPPORT to avoid misuse * Add EnumType and AnyEnumType as first-class jit type * Add Enum-typed IValue * Enhanced aten::eq to support Enum Supported: Enum-typed function arguments using Enum type and comparing them TODO: Add PyThon sugared value for Enum Support getting name/value attrs of enums Support Enum-typed return values Support enum values of different types in same Enum class Support serialization and deserialization
facebook-github-bot
left a comment
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.
@gmagogsfm has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
|
@gmagogsfm merged this pull request in 4a3aad3. |
Supported:
Enum-typed function targuments
using Enum type and comparing them
TODO:
Add PyThon sugared value for Enum
Support getting name/value attrs of enums
Support Enum-typed return values
Support enum values of different types in same Enum class
Support serialization and deserialization