-
Notifications
You must be signed in to change notification settings - Fork 26.3k
Function Calls for MethodValues (no Interpreter support) #18367
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
746c517 to
56c51ad
Compare
c10/util/StringUtil.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.
There seems to be many different implementations of Split sprinkled all over the place. I'm not sure if we might want to consider unifying/merging them. Neither am I sure if this work needs to be a part of this PR.
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.
This seems fine.
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.
gut
torch/csrc/jit/script/compiler.cpp
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 did consider iterators, but since we need to keep track of several iteration points, it looked rather clunky.
torch/csrc/jit/script/compiler.cpp
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.
This PR doesn't support expressions like modules[i].method1() or anything else except for selectors for now 😢
torch/csrc/jit/script/compiler.cpp
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.
DCE won't touch this, since it's marked as having side effects, so we have to remove it manually.
zdevito
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.
Hi, I added some high-level comments. Let's chat more about how we will name functions, etc.
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.
Function rather than ModuleFunction might be more clear
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.
I'd expect FunctionType to have argument types and a return type, and maybe just have FunctionSchema (though with blank alias information). Is there a reason to go with just a blank Function object?
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.
given that we are inlining right away we could s tart with a blank FunctionType and add more members lazily.
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.
The simplest thing to do right now might be to make the FunctionType object contain the std::shared_ptrscript::Function object. That way we can still use prim::Constant, but it doesn't need any attributes. That should be an easy tweak to what is here now.
c10/util/StringUtil.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.
This seems fine.
torch/csrc/jit/ir.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.
Please do not expose this! I don't want it to be easy to do this because then we will end up with a ton of places where coders are lazy and didn't specify where something came from.
torch/csrc/jit/script/compiler.cpp
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 do not think this is the right approach. It replicates a bunch of the SugaredValue behavior locally just to try to get the fully-qualified name for a function relative to the module root. MethodValue should just track its fully qualified name itself. I would not expect to see many changes in compiler.cpp
torch/csrc/jit/script/compiler.cpp
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.
Separate file please. compiler.cpp is long enough. This will need to be detangled from things like the environment. Otherwise the PR is not really accomplishing its purpose.
73507a6 to
c340af9
Compare
zdevito
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.
Nice progress. This is getting close, but there are a few restructuring things I suggest:
- FunctionType can simply contain the script::Function* object
- We do not need the ivalue object in this PR, we can just directly create prim::Constant with a FunctionType return type.
- Logic for emitting the CallFunction should move into Graph::createCall, and the actual use of that function should be done in MethodValue::call. There is no need to put a special case in the compiler (and in fact, one reason for wanting first-class calls is to remove special casing in the compiler).
aten/src/ATen/core/ivalue.cpp
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 it is premature to try to add an ivalue::Function object. It is not necessary for the core of this PR since it is only being temporarily used to create a function node from a constant.
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.
The simplest thing to do right now might be to make the FunctionType object contain the std::shared_ptrscript::Function object. That way we can still use prim::Constant, but it doesn't need any attributes. That should be an easy tweak to what is here now.
torch/csrc/jit/passes/inliner.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 you comment in the code why the recurse flag exists? (not what it is but why it is)
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 am not sure what this is. Was this a bad merge? Doesn't seem related to this PR.
torch/csrc/jit/script/compiler.cpp
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 is important to catch the specific exception. Otherwise this will hide all sorts of bad errors and report them as method recursion.
torch/csrc/jit/script/compiler.cpp
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.
Following previous convention, I think it would be better if we added an insertCallFunction(Value * callee, std::vector<Value*> inputs) call to Graph. Like others, it should never do user-facing error reporting, but it should handle the details of what a CallFunction node looks like.
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.
Ok, I see the move of this code into the lower tuples pass. However, I don't think it does the same thing, because this only lowers the tuple if it is the only argument to prim::Print, while the other one appears to do it universally.
torch/csrc/jit/script/compiler.cpp
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.
This code should be in MethodValue::call and not inline in the compiler here.
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.
These shouldn't be necessary, MethodValue should handle its own call logic.
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 the current MethodValue::call is dead.
simple cases for function calls work unit tests passing all unit test passing remove schema remove dce cleanup remove std::cout and redundant headers and defs fix clang tidy smaller fixes address Zach's feedback ModuleFunction -> Function ripping out relative qualified names clean up align formatting fix tests after rebase with prints without prints remove debug prints
b9eb6fc to
df71843
Compare
zdevito
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.
Inline comments on a few places where this did not merge nicely with the current codebase.
| if (hasSideEffects(node)) { | ||
| mark(node); | ||
| } | ||
|
|
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.
Passes don't typically descend into subgraphs. Is this still needed now that the Function* is actually stored in the 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.
actually, I think I might be able to remove this particular one, but then Inliner will need to descend into subgraphs and clean up unused Function literals
| } | ||
| } | ||
|
|
||
| void unifyIfs(Block* b) |
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 this here? It is breaking loose coupling for inlining to need to think about how it would affect other statements.
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.
type unification is typically done by compiler.cpp which now doesn't have the full inlined graph (hence, no precise types) since we inline later and even later in emitModuleHook we compile the inlined graph which now will have more precise types, so we end up with different graphs again.
| next = cur->next(); | ||
| cur->destroy(); | ||
| } else { | ||
| if (cur->hasAttribute(attr::Subgraph)) { |
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.
Optimization of subgraphs should be handled by the thing inserting the subgraph. Most of our passes do not descend into subgraphs, which is why this code needs to keep modifying passes. I don't want to start mixing typical behavior and have some passes look at subgraphs but others that do 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 think that inliner is a very special case. It is more similar to compiler.cpp rather than a regular optimization. Let me check if making compiler.cpp calling Inline is good enough. I think it was still breaking some tests if Inliner didn't expect subgraphs.
| body_block->registerOutput(fn_simple_output); | ||
| node_output = fork_node->output()->setType( | ||
| FutureType::create(fn_simple_output->type())); | ||
| Inline(body_block); |
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? runCleanupPasses will run on the subgraph below and do the inlining.
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.
lambdaLiftFork does sort of DCE i.e. it only lifts values that are used in a subgraph. If we leave a function call in place we end up passing in more values than really necessary and when we recompile the same function in emitModuleHook which will contain an already inlined subgraph we end up with different graphs. It's actually a very common theme with all these test failures. We can't do inlining early enough to not hinder some of optimizations so we have to re-do 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.
i.e. running it on a lifted subgraph is too late.
| auto& schema = callee.getSchema(); | ||
|
|
||
| std::vector<NamedValue> inputsWithSelf(inputs.begin(), inputs.end()); | ||
| auto self_val = self_.value(*caller.graph()); |
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.
Self values are always present. This was refactored a few weeks ago.
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, this does not replace FunctionValue::call which the root place where function calls get inserted. MethodValue should be unmodified in this patch. This code should be in FunctionValue::call
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.
This also seems like the wrong place to put this code. We have a method on Function with the name emit_call_to. I feel like this implementation should be there. This also explains why this code seems so long: it is copying all of the logic that already exists in that function to a new place without deleting it.
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.
okay... let me see if I can move stuff around
| << "multiple returns aren't yet supported"; | ||
| } | ||
|
|
||
| auto fun_constant = graph.create(prim::Constant); |
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.
Code to correctly construct CallFunction should be in ir.h:
::createFunctionCall(Value* fn, at::ArrayRef inputs);
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.
will fix
Summary: This is a continuation of #18367 that rebases it and cleans up some of the issues that were popping up. Notes: 1. removed special handling for Python 2 print statements. Its implementation was buggy (treated inlined tuples as literal tuples), and leaving it out just means that in Python 2 printing multiple values will print different in script and python. This is ok, because it is minor formatting differences and only in Python 2. 2. --accepted internal loss of ONNX type information. We are only required to have correct input and output types for ONNX not for intermediates.
First class functions in IR, inlined eagerly Summary: This is a continuation of #18367 that rebases it and cleans up some of the issues that were popping up. Notes: 1. removed special handling for Python 2 print statements. Its implementation was buggy (treated inlined tuples as literal tuples), and leaving it out just means that in Python 2 printing multiple values will print different in script and python. This is ok, because it is minor formatting differences and only in Python 2. 2. --accepted internal loss of ONNX type information. We are only required to have correct input and output types for ONNX not for intermediates. gh-metadata: pytorch pytorch 21052 gh/zdevito/40/head
Summary: This is a continuation of #18367 that rebases it and cleans up some of the issues that were popping up. Notes: 1. removed special handling for Python 2 print statements. Its implementation was buggy (treated inlined tuples as literal tuples), and leaving it out just means that in Python 2 printing multiple values will print different in script and python. This is ok, because it is minor formatting differences and only in Python 2. 2. --accepted internal loss of ONNX type information. We are only required to have correct input and output types for ONNX not for intermediates. gh-metadata: pytorch pytorch 21052 gh/zdevito/40/head
First class functions in IR, inlined eagerly Summary: This is a continuation of #18367 that rebases it and cleans up some of the issues that were popping up. Notes: 1. removed special handling for Python 2 print statements. Its implementation was buggy (treated inlined tuples as literal tuples), and leaving it out just means that in Python 2 printing multiple values will print different in script and python. This is ok, because it is minor formatting differences and only in Python 2. 2. --accepted internal loss of ONNX type information. We are only required to have correct input and output types for ONNX not for intermediates. gh-metadata: pytorch pytorch 21052 gh/zdevito/40/head
Summary: This is a continuation of #18367 that rebases it and cleans up some of the issues that were popping up. Notes: 1. removed special handling for Python 2 print statements. Its implementation was buggy (treated inlined tuples as literal tuples), and leaving it out just means that in Python 2 printing multiple values will print different in script and python. This is ok, because it is minor formatting differences and only in Python 2. 2. --accepted internal loss of ONNX type information. We are only required to have correct input and output types for ONNX not for intermediates. gh-metadata: pytorch pytorch 21052 gh/zdevito/40/head
First class functions in IR, inlined eagerly Summary: This is a continuation of #18367 that rebases it and cleans up some of the issues that were popping up. Notes: 1. removed special handling for Python 2 print statements. Its implementation was buggy (treated inlined tuples as literal tuples), and leaving it out just means that in Python 2 printing multiple values will print different in script and python. This is ok, because it is minor formatting differences and only in Python 2. 2. --accepted internal loss of ONNX type information. We are only required to have correct input and output types for ONNX not for intermediates. gh-metadata: pytorch pytorch 21052 gh/zdevito/40/head
Summary: This is a continuation of #18367 that rebases it and cleans up some of the issues that were popping up. Notes: 1. removed special handling for Python 2 print statements. Its implementation was buggy (treated inlined tuples as literal tuples), and leaving it out just means that in Python 2 printing multiple values will print different in script and python. This is ok, because it is minor formatting differences and only in Python 2. 2. --accepted internal loss of ONNX type information. We are only required to have correct input and output types for ONNX not for intermediates. gh-metadata: pytorch pytorch 21052 gh/zdevito/40/head
|
Closing in favour of #21052 |
First class functions in IR, inlined eagerly Summary: This is a continuation of #18367 that rebases it and cleans up some of the issues that were popping up. Notes: 1. removed special handling for Python 2 print statements. Its implementation was buggy (treated inlined tuples as literal tuples), and leaving it out just means that in Python 2 printing multiple values will print different in script and python. This is ok, because it is minor formatting differences and only in Python 2. 2. --accepted internal loss of ONNX type information. We are only required to have correct input and output types for ONNX not for intermediates. gh-metadata: pytorch pytorch 21052 gh/zdevito/40/head stuff
First class functions in IR, inlined eagerly Summary: This is a continuation of #18367 that rebases it and cleans up some of the issues that were popping up. Notes: 1. removed special handling for Python 2 print statements. Its implementation was buggy (treated inlined tuples as literal tuples), and leaving it out just means that in Python 2 printing multiple values will print different in script and python. This is ok, because it is minor formatting differences and only in Python 2. 2. --accepted internal loss of ONNX type information. We are only required to have correct input and output types for ONNX not for intermediates. gh-metadata: pytorch pytorch 21052 gh/zdevito/40/head stuff no
First class functions in IR, inlined eagerly Summary: This is a continuation of #18367 that rebases it and cleans up some of the issues that were popping up. Notes: 1. removed special handling for Python 2 print statements. Its implementation was buggy (treated inlined tuples as literal tuples), and leaving it out just means that in Python 2 printing multiple values will print different in script and python. This is ok, because it is minor formatting differences and only in Python 2. 2. --accepted internal loss of ONNX type information. We are only required to have correct input and output types for ONNX not for intermediates. gh-metadata: pytorch pytorch 21052 gh/zdevito/40/head stuff no
This PR adds infrastructure for adding function calls for
MethodValues. Interpreter doesn't know how to handle function calls yet.