mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-20 21:14:14 +08:00
[dynamo] unimplemented -> unimplemented_v2 for user_defined.py (#156652)
For https://github.com/pytorch/pytorch/issues/147913 Pull Request resolved: https://github.com/pytorch/pytorch/pull/156652 Approved by: https://github.com/zou3519 Co-authored-by: Sidharth <ssubbarao8@meta.com>
This commit is contained in:
committed by
PyTorch MergeBot
parent
204eb4da5e
commit
6fcb2b4413
@ -355,7 +355,7 @@ class GraphModule(torch.nn.Module):
|
||||
ctx = whoo()
|
||||
next(ctx)
|
||||
with self.assertRaisesRegex(
|
||||
Unsupported, "Generator as graph argument is not supported"
|
||||
Unsupported, "Detected a method call to a user-defined generator object."
|
||||
):
|
||||
fn(t, ctx)
|
||||
|
||||
@ -374,7 +374,7 @@ class GraphModule(torch.nn.Module):
|
||||
ctx = whoo(t)
|
||||
next(ctx)
|
||||
with self.assertRaisesRegex(
|
||||
Unsupported, "Generator as graph argument is not supported"
|
||||
Unsupported, "Detected a method call to a user-defined generator object."
|
||||
):
|
||||
fn(t, ctx)
|
||||
|
||||
@ -395,7 +395,7 @@ class GraphModule(torch.nn.Module):
|
||||
t = torch.randn(2)
|
||||
ctx = whoo()
|
||||
with self.assertRaisesRegex(
|
||||
Unsupported, "Generator as graph argument is not supported"
|
||||
Unsupported, "Detected a method call to a user-defined generator object."
|
||||
):
|
||||
fn(t, ctx)
|
||||
|
||||
@ -413,7 +413,8 @@ class GraphModule(torch.nn.Module):
|
||||
t = torch.randn(2)
|
||||
ctx = whoo(t)
|
||||
with self.assertRaisesRegex(
|
||||
Unsupported, "Generator as graph argument is not supported"
|
||||
Unsupported,
|
||||
"Detected a method call to a user-defined generator object.",
|
||||
):
|
||||
fn(t, ctx)
|
||||
|
||||
|
@ -2509,5 +2509,133 @@
|
||||
"It may be possible to write Dynamo tracing rules for this code. Please report an issue to PyTorch if you encounter this graph break often and it is causing performance issues."
|
||||
]
|
||||
}
|
||||
],
|
||||
"GB0252": [
|
||||
{
|
||||
"Gb_type": "could not find name in object's mro",
|
||||
"Context": "name={name}, object type={type(self.value)}, mro={type(self.value).__mro__}",
|
||||
"Explanation": "Could not find name `{name}` in mro {type(self.value).__mro__}",
|
||||
"Hints": [
|
||||
"Ensure the name `{name}` is defined somewhere in {self.value}'s type hierarchy.",
|
||||
"Dynamo has detected that tracing the code will result in an error when running in eager. Please double check that your code doesn't contain a similar error when actually running eager/uncompiled."
|
||||
]
|
||||
}
|
||||
],
|
||||
"GB0253": [
|
||||
{
|
||||
"Gb_type": "call_method on generator",
|
||||
"Context": "object={self.value}, method={name}, args={args}, kwargs={kwargs}",
|
||||
"Explanation": "Detected a method call to a user-defined generator object. This is not fully supported.",
|
||||
"Hints": [
|
||||
"Set `torch._dynamo.config.enable_faithful_generator_behavior = False`. Note that this ",
|
||||
"may cause silent incorrectness, since we will eagerly unpack generators instead of lazily ",
|
||||
"evaluating them."
|
||||
]
|
||||
}
|
||||
],
|
||||
"GB0254": [
|
||||
{
|
||||
"Gb_type": "non-const setattr name on user-defined object",
|
||||
"Context": "object={self}, name={name}, value={value}",
|
||||
"Explanation": "Detected a call to `setattr` of a user-defined object with a non-constant name.",
|
||||
"Hints": [
|
||||
"Ensure that the name is a string."
|
||||
]
|
||||
}
|
||||
],
|
||||
"GB0255": [
|
||||
{
|
||||
"Gb_type": "attempted to call sourceless user-defined object as a method",
|
||||
"Context": "object={self.value}, function={func}, args={args}, kwargs={kwargs}",
|
||||
"Explanation": "Dynamo does not support this.",
|
||||
"Hints": [
|
||||
"Ensure the user-defined object {self.value} is constructed outside the compiled region."
|
||||
]
|
||||
}
|
||||
],
|
||||
"GB0256": [
|
||||
{
|
||||
"Gb_type": "User-defined object with non-function __getattr__",
|
||||
"Context": "object={self.value}, name={name}, getattr_fn={getattr_fn}",
|
||||
"Explanation": "Found a non-function __getattr__ {getattr_fn} from a user-defined object {self.value} when attempting to getattr `{name}`",
|
||||
"Hints": [
|
||||
"Ensure the object's __getattr__ is a function type."
|
||||
]
|
||||
}
|
||||
],
|
||||
"GB0257": [
|
||||
{
|
||||
"Gb_type": "TypedDict with optional keys",
|
||||
"Context": "str(self.value)",
|
||||
"Explanation": "Dyanmo does not support tracing TypedDict with optional keys",
|
||||
"Hints": [
|
||||
"Avoid using TypedDict with optional keys",
|
||||
"It may be possible to write Dynamo tracing rules for this code. Please report an issue to PyTorch if you encounter this graph break often and it is causing performance issues."
|
||||
]
|
||||
}
|
||||
],
|
||||
"GB0258": [
|
||||
{
|
||||
"Gb_type": "collections.deque() with bad arguments",
|
||||
"Context": "args={args}, kwargs={kwargs}",
|
||||
"Explanation": "Detected call to collections.deque() with bad arguments.",
|
||||
"Hints": [
|
||||
"Fix the call to collections.deque().",
|
||||
"Dynamo has detected that tracing the code will result in an error when running in eager. Please double check that your code doesn't contain a similar error when actually running eager/uncompiled."
|
||||
]
|
||||
}
|
||||
],
|
||||
"GB0259": [
|
||||
{
|
||||
"Gb_type": "collections.deque() with bad iterable argument",
|
||||
"Context": "args={args}, kwargs={kwargs}",
|
||||
"Explanation": "Call to collections.deque() has an iterable argument that Dynamo cannot convert to a list.",
|
||||
"Hints": [
|
||||
"Use a simpler sequence type that Dynamo can convert to a list ",
|
||||
"(e.g. list, tuple, list iterator, etc.)",
|
||||
"Dynamo has detected that tracing the code will result in an error when running in eager. Please double check that your code doesn't contain a similar error when actually running eager/uncompiled."
|
||||
]
|
||||
}
|
||||
],
|
||||
"GB0260": [
|
||||
{
|
||||
"Gb_type": "missing args to functools.partial",
|
||||
"Context": "",
|
||||
"Explanation": "functools.partial requires at least one argument",
|
||||
"Hints": [
|
||||
"Fix the functools.partial call.",
|
||||
"Dynamo has detected that tracing the code will result in an error when running in eager. Please double check that your code doesn't contain a similar error when actually running eager/uncompiled."
|
||||
]
|
||||
}
|
||||
],
|
||||
"GB0261": [
|
||||
{
|
||||
"Gb_type": "User-defined object method with non-function __func__",
|
||||
"Context": "object={self.value}, name={name}, method={dynamic_subobj}, method.__self__={dynamic_subobj.__self__}, method.__func__={dynamic_subobj.__func__}",
|
||||
"Explanation": "Method {dynamic_subobj} (name={name}) of user-defined object {self.value} has a __func__ ({dynamic_subobj.__func__}) that is not a function type.",
|
||||
"Hints": [
|
||||
"Ensure that the method's __func__ is a function type."
|
||||
]
|
||||
}
|
||||
],
|
||||
"GB0262": [
|
||||
{
|
||||
"Gb_type": "unsupported contextlib.* API",
|
||||
"Context": "{self.value}",
|
||||
"Explanation": "{self.value} not supported. This may be due to its use of context-specific operations that are not supported in Dynamo yet (i.e. Exception handling)",
|
||||
"Hints": [
|
||||
"It may be possible to write Dynamo tracing rules for this code. Please report an issue to PyTorch if you encounter this graph break often and it is causing performance issues."
|
||||
]
|
||||
}
|
||||
],
|
||||
"GB0263": [
|
||||
{
|
||||
"Gb_type": "attempted to trace contextlib.contextmanager",
|
||||
"Context": "args={args}",
|
||||
"Explanation": "Tracing contextlib.contextmanager is disabled.",
|
||||
"Hints": [
|
||||
"Set torch._dynamo.config.enable_trace_contextlib = True"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -46,14 +46,14 @@ import torch.nn
|
||||
from torch._guards import TracingContext
|
||||
from torch.utils._python_dispatch import is_traceable_wrapper_subclass_type
|
||||
|
||||
from .. import polyfills, variables
|
||||
from .. import graph_break_hints, polyfills, variables
|
||||
from ..bytecode_transformation import create_call_function
|
||||
from ..create_parameter_op import do_not_convert_to_tracable_parameter
|
||||
from ..exc import (
|
||||
handle_observed_exception,
|
||||
ObservedAttributeError,
|
||||
raise_observed_exception,
|
||||
unimplemented,
|
||||
unimplemented_v2,
|
||||
)
|
||||
from ..guards import GuardBuilder, install_guard
|
||||
from ..source import (
|
||||
@ -479,30 +479,58 @@ class UserDefinedClassVariable(UserDefinedVariable):
|
||||
)
|
||||
elif is_typeddict(self.value):
|
||||
if self.value.__optional_keys__:
|
||||
unimplemented("TypedDict with optional keys not supported")
|
||||
unimplemented_v2(
|
||||
gb_type="TypedDict with optional keys",
|
||||
context=str(self.value),
|
||||
explanation="Dyanmo does not support tracing TypedDict with optional keys",
|
||||
hints=[
|
||||
"Avoid using TypedDict with optional keys",
|
||||
*graph_break_hints.SUPPORTABLE,
|
||||
],
|
||||
)
|
||||
return variables.BuiltinVariable(dict).call_dict(tx, *args, **kwargs)
|
||||
elif self.value is collections.deque:
|
||||
maxlen = variables.ConstantVariable.create(None)
|
||||
if not kwargs:
|
||||
if len(args) == 0:
|
||||
items = []
|
||||
elif len(args) == 1 and args[0].has_force_unpack_var_sequence(tx):
|
||||
items = args[0].force_unpack_var_sequence(tx)
|
||||
elif len(args) == 2 and args[0].has_force_unpack_var_sequence(tx):
|
||||
items = args[0].force_unpack_var_sequence(tx)
|
||||
maxlen = args[1]
|
||||
else:
|
||||
unimplemented("deque() with more than 2 arg not supported")
|
||||
elif tuple(kwargs) == ("maxlen",):
|
||||
maxlen = kwargs["maxlen"]
|
||||
if len(args) == 0:
|
||||
items = []
|
||||
if len(args) == 1 and args[0].has_force_unpack_var_sequence(tx):
|
||||
items = args[0].force_unpack_var_sequence(tx)
|
||||
else:
|
||||
unimplemented("deque() with more than 1 arg not supported")
|
||||
|
||||
def deque_signature(iterable=None, maxlen=None):
|
||||
pass
|
||||
|
||||
try:
|
||||
bound_args = inspect.signature(deque_signature).bind(*args, **kwargs)
|
||||
except TypeError as e:
|
||||
unimplemented_v2(
|
||||
gb_type="collections.deque() with bad arguments",
|
||||
context=f"args={args}, kwargs={kwargs}",
|
||||
explanation="Detected call to collections.deque() with bad arguments.",
|
||||
hints=[
|
||||
"Fix the call to collections.deque().",
|
||||
*graph_break_hints.USER_ERROR,
|
||||
],
|
||||
from_exc=e,
|
||||
)
|
||||
|
||||
if "iterable" in bound_args.arguments:
|
||||
if not bound_args.arguments["iterable"].has_force_unpack_var_sequence(
|
||||
tx
|
||||
):
|
||||
unimplemented_v2(
|
||||
gb_type="collections.deque() with bad iterable argument",
|
||||
context=f"args={args}, kwargs={kwargs}",
|
||||
explanation="Call to collections.deque() has an iterable argument that Dynamo cannot "
|
||||
"convert to a list.",
|
||||
hints=[
|
||||
"Use a simpler sequence type that Dynamo can convert to a list "
|
||||
"(e.g. list, tuple, list iterator, etc.)",
|
||||
*graph_break_hints.USER_ERROR,
|
||||
],
|
||||
)
|
||||
items = bound_args.arguments["iterable"].force_unpack_var_sequence(tx)
|
||||
else:
|
||||
unimplemented("deque() with invalid kwargs not supported")
|
||||
items = []
|
||||
|
||||
if "maxlen" in bound_args.arguments:
|
||||
maxlen = bound_args.arguments["maxlen"]
|
||||
|
||||
return variables.lists.DequeVariable(
|
||||
items, maxlen=maxlen, mutation_type=ValueMutationNew()
|
||||
)
|
||||
@ -514,7 +542,15 @@ class UserDefinedClassVariable(UserDefinedVariable):
|
||||
return variables.WeakRefVariable(args[0], callback)
|
||||
elif self.value is functools.partial:
|
||||
if not args:
|
||||
unimplemented("functools.partial malformed")
|
||||
unimplemented_v2(
|
||||
gb_type="missing args to functools.partial",
|
||||
context="",
|
||||
explanation="functools.partial requires at least one argument",
|
||||
hints=[
|
||||
"Fix the functools.partial call.",
|
||||
*graph_break_hints.USER_ERROR,
|
||||
],
|
||||
)
|
||||
# The first arg, a callable (the ctor below will assert on types)
|
||||
fn = args[0]
|
||||
rest_args = args[1:]
|
||||
@ -560,17 +596,29 @@ class UserDefinedClassVariable(UserDefinedVariable):
|
||||
):
|
||||
# We are not changing the behavior of Dynamo as these function were
|
||||
# already ignored on trace_rules.py before #136033 landed
|
||||
unimplemented(
|
||||
f"{self.value} not supported. This may be due to its use of "
|
||||
unimplemented_v2(
|
||||
gb_type="unsupported contextlib.* API",
|
||||
context=f"{self.value}",
|
||||
explanation=f"{self.value} not supported. This may be due to its use of "
|
||||
"context-specific operations that are not supported in "
|
||||
"Dynamo yet (i.e. Exception handling)"
|
||||
"Dynamo yet (i.e. Exception handling)",
|
||||
hints=[
|
||||
*graph_break_hints.SUPPORTABLE,
|
||||
],
|
||||
)
|
||||
|
||||
if self.value is contextlib._GeneratorContextManager and isinstance(
|
||||
args[0], BaseUserFunctionVariable
|
||||
):
|
||||
if not torch._dynamo.config.enable_trace_contextlib:
|
||||
unimplemented("contextlib.contextmanager")
|
||||
unimplemented_v2(
|
||||
gb_type="attempted to trace contextlib.contextmanager",
|
||||
context=f"args={args}",
|
||||
explanation="Tracing contextlib.contextmanager is disabled.",
|
||||
hints=[
|
||||
"Set torch._dynamo.config.enable_trace_contextlib = True",
|
||||
],
|
||||
)
|
||||
# Wrap UserFunctionVariable in FunctionDecoratedByContextlibContextManagerVariable
|
||||
# if the function is annotated with @contextlib.contextmanager
|
||||
# This shouldn't be necessary once generator functions are fully
|
||||
@ -936,7 +984,17 @@ class UserDefinedObjectVariable(UserDefinedVariable):
|
||||
if torch._dynamo.config.enable_faithful_generator_behavior and isinstance(
|
||||
self.value, types.GeneratorType
|
||||
):
|
||||
unimplemented("Generator as graph argument is not supported")
|
||||
unimplemented_v2(
|
||||
gb_type="call_method on generator",
|
||||
context=f"object={self.value}, method={name}, args={args}, kwargs={kwargs}",
|
||||
explanation="Detected a method call to a user-defined generator object. "
|
||||
"This is not fully supported.",
|
||||
hints=[
|
||||
"Set `torch._dynamo.config.enable_faithful_generator_behavior = False`. Note that this "
|
||||
"may cause silent incorrectness, since we will eagerly unpack generators instead of lazily "
|
||||
"evaluating them.",
|
||||
],
|
||||
)
|
||||
|
||||
# check for methods implemented in C++
|
||||
if isinstance(method, types.FunctionType):
|
||||
@ -966,9 +1024,16 @@ class UserDefinedObjectVariable(UserDefinedVariable):
|
||||
try:
|
||||
name = name.as_python_constant()
|
||||
except NotImplementedError:
|
||||
unimplemented(f"non-const setattr name: {name}")
|
||||
if not tx.output.side_effects.is_attribute_mutation(self):
|
||||
unimplemented(f"setattr({self}, {name}, ...)")
|
||||
unimplemented_v2(
|
||||
gb_type="non-const setattr name on user-defined object",
|
||||
context=f"object={self}, name={name}, value={value}",
|
||||
explanation="Detected a call to `setattr` of a user-defined object with a non-constant name.",
|
||||
hints=["Ensure that the name is a string."],
|
||||
)
|
||||
assert tx.output.side_effects.is_attribute_mutation(self), (
|
||||
"Attempted setattr on a user-defined object that does not have "
|
||||
"an AttributeMutation mutation_type"
|
||||
)
|
||||
|
||||
if directly_update_dict:
|
||||
self.attrs_directly_modifed_on_dict.add(name)
|
||||
@ -1064,8 +1129,13 @@ class UserDefinedObjectVariable(UserDefinedVariable):
|
||||
).call_function(tx, [var], kwargs)
|
||||
|
||||
if self.source is None:
|
||||
unimplemented(
|
||||
"Sourceless UserDefinedObjectVariable method not supported"
|
||||
unimplemented_v2(
|
||||
gb_type="attempted to call sourceless user-defined object as a method",
|
||||
context=f"object={self.value}, function={func}, args={args}, kwargs={kwargs}",
|
||||
explanation="Dynamo does not support this.",
|
||||
hints=[
|
||||
f"Ensure the user-defined object {self.value} is constructed outside the compiled region.",
|
||||
],
|
||||
)
|
||||
func_src = AttrSource(self.source, "__func__")
|
||||
func_var = VariableTracker.build(tx, func, func_src)
|
||||
@ -1161,7 +1231,15 @@ class UserDefinedObjectVariable(UserDefinedVariable):
|
||||
# should use DictGetItemSource here.
|
||||
return GetItemSource(dict_source, name)
|
||||
|
||||
unimplemented(f"Could not find {name} in {type(self.value).__mro__}")
|
||||
unimplemented_v2(
|
||||
gb_type="could not find name in object's mro",
|
||||
context=f"name={name}, object type={type(self.value)}, mro={type(self.value).__mro__}",
|
||||
explanation=f"Could not find name `{name}` in mro {type(self.value).__mro__}",
|
||||
hints=[
|
||||
f"Ensure the name `{name}` is defined somewhere in {self.value}'s type hierarchy.",
|
||||
*graph_break_hints.USER_ERROR,
|
||||
],
|
||||
)
|
||||
|
||||
def var_getattr(self, tx: "InstructionTranslator", name):
|
||||
from .. import trace_rules
|
||||
@ -1246,7 +1324,15 @@ class UserDefinedObjectVariable(UserDefinedVariable):
|
||||
return out
|
||||
|
||||
elif getattr_fn is not None:
|
||||
unimplemented("UserDefined with non-function __getattr__")
|
||||
unimplemented_v2(
|
||||
gb_type="User-defined object with non-function __getattr__",
|
||||
context=f"object={self.value}, name={name}, getattr_fn={getattr_fn}",
|
||||
explanation=f"Found a non-function __getattr__ {getattr_fn} from a user-defined object {self.value} "
|
||||
f" when attempting to getattr `{name}`",
|
||||
hints=[
|
||||
"Ensure the object's __getattr__ is a function type.",
|
||||
],
|
||||
)
|
||||
|
||||
from ..mutation_guard import unpatched_nn_module_init
|
||||
|
||||
@ -1339,8 +1425,15 @@ class UserDefinedObjectVariable(UserDefinedVariable):
|
||||
if isinstance(subobj, types.MethodType):
|
||||
if dynamic_subobj.__self__ is not self.value:
|
||||
if not isinstance(dynamic_subobj.__func__, types.FunctionType):
|
||||
unimplemented(
|
||||
f"Found a method whose __func__ is not of FunctionType - {dynamic_subobj}"
|
||||
unimplemented_v2(
|
||||
gb_type="User-defined object method with non-function __func__",
|
||||
context=f"object={self.value}, name={name}, method={dynamic_subobj}, "
|
||||
f"method.__self__={dynamic_subobj.__self__}, method.__func__={dynamic_subobj.__func__}",
|
||||
explanation=f"Method {dynamic_subobj} (name={name}) of user-defined object {self.value} has a "
|
||||
f"__func__ ({dynamic_subobj.__func__}) that is not a function type.",
|
||||
hints=[
|
||||
"Ensure that the method's __func__ is a function type.",
|
||||
],
|
||||
)
|
||||
|
||||
# Use the __self__ attribute of the method to find the
|
||||
|
Reference in New Issue
Block a user