Conversation
This lets you put `@torch.jit.script` on an `nn.Module`, which then will wrap any instantiations of the module with a `script` call. This lets users make classes that will always be used as `ScriptModule`s without having to call `script()` every time
|
|
||
| # Since we don't return the module itself from this wrapper, its `__init__` | ||
| # is never automatically called, so we have to do it explicitly here | ||
| nn_module.__init__(*args, **kwargs) |
There was a problem hiding this comment.
I do not think is not correct to make __new__ call __init__ and will break assumptions in other parts of python (e.g. things that try to copy the object by calling __new__).
There was a problem hiding this comment.
The point of the decorator is that it compiles your module automatically, which it can't do if it hasn't been initialized. Does it make sense to break those cases since they wouldn't work with ScriptModules anyways?
There was a problem hiding this comment.
maybe? What do people typically do in class decorators. It seems like there is at least some precedent because it doesn't all init if another object is returned.
There was a problem hiding this comment.
Class decorators seem pretty rare, the associated PEP is also light on details. Most usages seem to be people returning some kind of wrapper class type from the decorator, but returning anything other than the class type itself breaks super(T, self) calls (they have to be changed to super(type(self), self) which makes that a non-starter for us.
There was a problem hiding this comment.
Why not wrap the __init__ instead?
|
I think it's good since it makes |
|
If the problem you're trying to solve is to avoid having to call the recursive scripting func all the time, why can't we just recommend something like I don't think it's a big deal either way, but we should minimize the number of ways to do the same thing I think. |
That's a pretty good argument, I'm fine with it either way I think. |
Having a function like that is the same as having a decorator (it just calls the function with the decorated type under the hood), similar to how you can use |
|
I would really really hope that this can be updated and get through some day! |
|
For me, the following simple patch works: import functools
import torch
import torch.nn as nn
def compile(kind='script', *args, **kwargs):
if isinstance(kind, type) and issubclass(kind, nn.Module):
raise RuntimeError('Use @torch.jit.compile(kind, ...) as decorator')
if callable(kind):
compiler = kind
elif kind == 'script':
compiler = torch.jit.script
else:
assert kind == 'trace'
compiler = torch.jit.trace
class CompiledModuleMeta(type(nn.Module)):
def __call__(cls, *ctor_args, **ctor_kwargs):
return torch.jit.script(super(CompiledModuleMeta, cls).__call__(*ctor_args, **ctor_kwargs), *args, **kwargs)
def decorator(cls):
return CompiledModuleMeta(cls.__name__, (cls,), {})
return decorator
assert not hasattr(torch.jit, 'compile')
torch.jit.compile = compile
@torch.jit.compile()
class MLP(nn.Module):
r"""my mlp"""
def __init__(self):
super().__init__()
self.model = nn.Sequential(nn.Linear(3, 4), nn.ReLU(True), nn.Linear(4, 3))
def forward(self, x):
return self.model(x) |
|
@ssnl We’re going with the contract everything under |
|
@driazati That is reasonable, but results in a really ugly API. Could another API with a different name be added? |
This lets you put
@torch.jit.scripton annn.Module, which then willwrap any instantiations of the module with a
scriptcall. This letsusers make classes that will always be used as
ScriptModules withouthaving to call
script()every time