-
Notifications
You must be signed in to change notification settings - Fork 58
[Discuss][Parsing][IR] Parsing _
shape dimensions as tir::Any
#259
Comments
One of the main challenge here is that we might need to think about language semantics here. We know that match shape to a fresh var makes sense, and we can have equality comparison and other symbolic stuffs through airthmetic prover. Likely code generator needs to be able to deal with scenarios where Any (e.g. discard the value) The main issue to consider is when we do code rewrites. Say we take a program and do a transformation that inserts relu before x Before@tvm.script.ir_module
class TestShape:
@R.function
def main(x : Tensor((m, n, _), _)):
s = (m, n)
return s After@tvm.script.ir_module
class TestShape:
@R.function
def main(x : Tensor((m, n, v_), _)):
v0 : Tensor(m, n, v_), _) = relu(x)
s = (m, n)
return (s, v0) After relu is inserted, we want to preserve the invariance that x's shape equals v0, as a result |
That's an interesting example. I would argue that if it's important for two variables to match, they should probably have explicit names--a wildcard signifies that the dimension shouldn't be matched at all. In the given example, It is true, though, that shape inference rules for operators may encounter some complexity in dealing with It might be reasonable to treat (Semantically, the only difference between a wildcard and a fresh variable is that a wildcard is literally a no-op during matching whereas a fresh var results in a var being added to the namespace.) |
agree about the reasonings pt wildcard, the main tradeoff is the cost of introducing any and their handling, and clarify how passes handle them and possible usecases around them. In the particular example, the before indeed signifies that user do not intend to use the vaiable. So as if the code is written by the user indeed having wildcard helps to signify that intention. The main question is how can followup passes(e.g. those that insert relu) take that additional intention into consideration (which adds complexity to the passes. Ideally should ideally want to be able to keep tracks of invariant shape relations as much as possible. So the after is not the code that is written by the user, but generated by a pass. If it implicitly have the same shape as RHS with wildcard, then it could leads to a missed opportunity in future optimizatoins. So we cannot prove v0.shape[2] == x.shape[2] because both of them are wildcard(Any). We cannot allow say for example memory sharing after proving the shapes are equal. |
You could prove that the shapes are equal by adding a |
agreed with all the analysis, great discussions :) |
I did think of one case that becomes a lot tougher without an explicit wildcard construct: Annotating explicit return shapes. If we have a function with a signature like We would have to define some semantics for dealing with the unbound shape variable in the return shape (which would matter if we try to construct "shape functions" to figure out the shapes of call results). |
Another case where this kind of complexity can come up is (Arguably neither way is satisfying, but letting shape variables escape the scope in which they were defined would be hard to reason about.) |
Indeed, in the case of return type the wildcard gives more info(about rest of the dims) In the particular case it becomes the RuntimeDep in this case. |
Relaxing the entire shape to |
I agree, just some design tradeoffs to consider, e.g. the extra info and the overhead on introducing passes. |
Presently, any wildcard dimension in a shape annotation (namely, written as
_
) is parsed as a fresh shape variable.For example, let us consider the following function:
If we dump its AST using
relax.testing.dump_ast
, we see that the shape ofx
is parsed like so:In particular, the
_
dimension is parsed as an ordinary TIR variable with a mangled name. In terms of the semantics, this would still work out because the variable will never be used again.However, I think it might make more sense to parse wildcard dimensions using
tir::Any
. This will avoid adding new variables to the namespace that aren't meant to be used and convey the intent that the dimension is not meant to be checked. Additionally, it will be easier to generate shape expressions programmatically (generating anAny
node to represent a wildcard instead of using an ordainry variable with an unused name). It's a minor issue, but it could be helpful for writing passes and dealing with shape expressions in general.Any thoughts from those working on the parser? @Hzfengsy @MasterJH5574 @yongwww
The text was updated successfully, but these errors were encountered: