You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by GitBox <gi...@apache.org> on 2022/11/16 06:58:47 UTC

[GitHub] [tvm] chunit-quic opened a new pull request, #13402: [Relay][Frontend] Span filling common API

chunit-quic opened a new pull request, #13402:
URL: https://github.com/apache/tvm/pull/13402

   - Expose and add span attribute of Expr-derived types from C++ to Python
   - Add common API of span filling
   - Add test cases of span filling
   - Add function to control whether to fill span via environment variable
   - Modify the way of pretty-print to print span


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] chunit-quic commented on pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
chunit-quic commented on PR #13402:
URL: https://github.com/apache/tvm/pull/13402#issuecomment-1318120438

   @FrozenGene @areusch @mbs-octoml 
   Tag reviewers in the forum thread and previously reverted PR.
   It would be a big help to have your advices. Thank you! :D 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] areusch merged pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
areusch merged PR #13402:
URL: https://github.com/apache/tvm/pull/13402


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] areusch commented on a diff in pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
areusch commented on code in PR #13402:
URL: https://github.com/apache/tvm/pull/13402#discussion_r1044893998


##########
src/relay/ir/expr.cc:
##########
@@ -72,8 +72,8 @@ Constant::Constant(runtime::NDArray data, Span span) {
 
 TVM_REGISTER_NODE_TYPE(ConstantNode);
 
-TVM_REGISTER_GLOBAL("relay.ir.Constant").set_body_typed([](runtime::NDArray data) {
-  return Constant(data);
+TVM_REGISTER_GLOBAL("relay.ir.Constant").set_body_typed([](runtime::NDArray data, Span span) {

Review Comment:
   ah okay that makes sense now, i think the point of this PR is very clear to me. thanks for explaining and sorry for the long delay here!



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] chunit-quic commented on a diff in pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
chunit-quic commented on code in PR #13402:
URL: https://github.com/apache/tvm/pull/13402#discussion_r1030068767


##########
python/tvm/relay/frontend/common.py:
##########
@@ -997,3 +1002,167 @@ def try_resolve_var_to_const(x, graph_params):
         return _op.const(value, dtype)
 
     return x
+
+
+class _SpanFiller(ExprMutator):

Review Comment:
   I see. Currently we don't have plan to migrate them to a C++ pass. There are two reasons. 
   
   1. First of all, considering the profiling result in the preRFC, the frontend conversion time is not increased too much. 
   2. Second, the fill() and \_\_init\_\_() function heavily interact with different frontends. We would like to keep the flexibility to modify them via python script quickly. For example, in the [min_max_common ](https://github.com/apache/tvm/blob/b2058f4dd2e0ae1fc5ab51ac9f84b372a389a65a/python/tvm/relay/frontend/pytorch.py#L275)conversion of PyTorch, it might end up being a None, which is not common in other frontends. 
   
   	
   However, if the performance of frontend conversion is significantly decreased by SpanFiller in some cases, we can arrange a patch to move the mutator part (visitor funcions) to C++ pass. :)
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] areusch commented on a diff in pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
areusch commented on code in PR #13402:
URL: https://github.com/apache/tvm/pull/13402#discussion_r1029444355


##########
tests/python/frontend/test_common.py:
##########
@@ -27,6 +32,203 @@ def test_key_is_not_present():
     assert not attrs.has_attr("b")
 
 
+def test_set_span():
+    def _verify_env_var_switch():
+        def _res(should_fill):
+            if should_fill:
+                with testing.enable_span_filling():
+                    return set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var")
+            else:
+                with testing.disable_span_filling():
+                    return set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var")
+
+        disable = relay.var("x", shape=(1, 64, 56, 56))
+        enable = relay.var("x", shape=(1, 64, 56, 56), span=_create_span("x_var"))
+
+        assert _verify_structural_equal_with_span(_res(False), disable)
+        assert _verify_structural_equal_with_span(_res(True), enable)
+
+    # Should tag all exprs without span, and stop when expr is span-tagged
+    def _verify_builtin_tuple():
+        def _res():
+            a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a"))
+            b = relay.const(np.zeros([1, 1, 1]), dtype="int64")
+            return set_span(tuple([a, b]), "tuple")
+
+        def _golden():
+            a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a"))
+            b = relay.const(np.zeros([1, 1, 1]), dtype="int64", span=_create_span("tuple"))
+            return tuple([a, b])
+
+        res_tuple, golden_tuple = _res(), _golden()
+        assert len(res_tuple) == len(golden_tuple)
+        for i in range(len(res_tuple)):
+            assert _verify_structural_equal_with_span(res_tuple[i], golden_tuple[i])
+
+    def _verify_builtin_list():
+        def _res():
+            a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a"))
+            b = relay.const(np.zeros([1, 1, 1]), dtype="int64")
+            t = relay.Tuple([a, b])
+            t_a = relay.TupleGetItem(t, 0)
+            t_b = relay.TupleGetItem(t, 1)
+            return set_span([t_a, t_b], "list")
+
+        def _golden():
+            a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a"))
+            b = relay.const(np.zeros([1, 1, 1]), dtype="int64", span=_create_span("list"))
+            t = relay.Tuple([a, b], span=_create_span("list"))
+            t_a = relay.TupleGetItem(t, 0, span=_create_span("list"))
+            t_b = relay.TupleGetItem(t, 1, span=_create_span("list"))
+            return [t_a, t_b]
+
+        res_list, golden_list = _res(), _golden()
+        assert len(res_list) == len(golden_list)
+        for i in range(len(res_list)):
+            assert _verify_structural_equal_with_span(res_list[i], golden_list[i])
+
+    def _verify_var():
+        x = set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var")
+        x_expected = relay.var("x", shape=(1, 64, 56, 56), span=_create_span("x_var"))
+        assert _verify_structural_equal_with_span(x, x_expected)
+
+    def _verify_constant():
+        c = set_span(relay.const(np.ones([64, 64, 3, 3]), dtype="int64"), "const_c")
+        c_expected = relay.const(
+            np.ones([64, 64, 3, 3]), dtype="int64", span=_create_span("const_c")
+        )
+        assert _verify_structural_equal_with_span(c, c_expected)
+
+    def _verify_call():
+        def _res():
+            x = set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var")
+            w = relay.const(np.ones([64, 64, 3, 3]), dtype="int64")
+            y = set_span(
+                relay.nn.conv2d(x, w, channels=64, kernel_size=(3, 3), padding=(1, 1)), "conv2d"
+            )
+            return relay.Function([x], y)
+
+        def _golden():
+            x = relay.var("x", shape=(1, 64, 56, 56), span=_create_span("x_var"))
+            w = relay.const(np.ones([64, 64, 3, 3]), dtype="int64", span=_create_span("conv2d"))
+            y = _set_span(
+                relay.nn.conv2d(x, w, channels=64, kernel_size=(3, 3), padding=(1, 1)), "conv2d"
+            )
+            return relay.Function([x], y)
+
+        assert _verify_structural_equal_with_span(_res(), _golden())
+
+    def _verify_tuple():
+        def _res():
+            a = set_span(relay.const(np.ones([1, 1, 1]), dtype="int64"), "a")
+            b = relay.const(np.ones([1, 1, 1]), dtype="int64")
+            t = set_span(relay.Tuple([a, b]), "t")
+            return relay.Function([], t)
+
+        def _golden():
+            a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a"))
+            b = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("t"))
+            t = relay.Tuple([a, b], span=_create_span("t"))
+            return relay.Function([], t)
+
+        assert _verify_structural_equal_with_span(_res(), _golden())
+
+    def _verify_tuple_getitem():
+        def _res():
+            a = set_span(relay.const(np.ones([1, 1, 1]), dtype="int64"), "a")
+            b = relay.const(np.ones([1, 1, 1]), dtype="int64")
+            t = relay.Tuple([a, b])
+            i = set_span(relay.TupleGetItem(t, 0), "i")
+            return relay.Function([], i)
+
+        def _golden():
+            a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a"))
+            b = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("i"))
+            t = relay.Tuple([a, b], span=_create_span("i"))
+            i = relay.TupleGetItem(t, 0, span=_create_span("i"))
+            return relay.Function([], i)
+
+        assert _verify_structural_equal_with_span(_res(), _golden())
+
+    def _verify_let():
+        def _res():
+            x = set_span(relay.Var("x"), "x_var")
+            c_1 = relay.const(np.ones(10))
+            add = relay.add(x, x)
+            body = set_span(relay.Let(x, c_1, add), "let")
+
+            c_2 = set_span(relay.const(np.zeros(10)), "zeros")
+            y = set_span(relay.add(body, c_2), "add_2")
+            return relay.Function([x], y)
+
+        def _golden():
+            x = relay.Var("x", span=_create_span("x_var"))
+            c_1 = relay.const(np.ones(10), span=_create_span("let"))
+            add = _set_span(relay.add(x, x), "let")
+            body = relay.Let(x, c_1, add, span=_create_span("let"))
+
+            c_2 = relay.const(np.zeros(10), span=_create_span("zeros"))
+            y = _set_span(relay.add(body, c_2), "add_2")
+            return relay.Function([x], y)
+
+        assert _verify_structural_equal_with_span(_res(), _golden())
+
+    def _verify_if():
+        def _res():
+            x = set_span(relay.var("x", shape=[], dtype="float32"), "x_var")
+            y = set_span(relay.var("y", shape=[], dtype="float32"), "y_var")
+            eq = relay.equal(x, y)
+
+            true_branch = set_span(relay.add(x, y), "true_branch")
+            false_branch = relay.subtract(x, y)
+            ife = set_span(relay.If(eq, true_branch, false_branch), "if")
+            return relay.Function([x, y], ife)
+
+        def _golden():
+            x = relay.var("x", shape=[], dtype="float32", span=_create_span("x_var"))
+            y = relay.var("y", shape=[], dtype="float32", span=_create_span("y_var"))
+            eq = _set_span(relay.equal(x, y), "if")
+
+            true_branch = _set_span(relay.add(x, y), "true_branch")
+            false_branch = _set_span(relay.subtract(x, y), "if")
+            ife = relay.If(eq, true_branch, false_branch, span=_create_span("if"))
+            return relay.Function([x, y], ife)
+
+        assert _verify_structural_equal_with_span(_res(), _golden())
+
+    def _verify_fn():
+        def _res():
+            x = set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var")
+            w = relay.const(np.ones([64, 64, 3, 3]), dtype="int64")
+            y = relay.nn.conv2d(x, w, channels=64, kernel_size=(3, 3), padding=(1, 1))
+            f = set_span(relay.Function([x], y), "func")
+            return f
+
+        def _golden():
+            x = relay.var("x", shape=(1, 64, 56, 56), span=_create_span("x_var"))
+            w = relay.const(np.ones([64, 64, 3, 3]), dtype="int64", span=_create_span("func"))
+            y = _set_span(
+                relay.nn.conv2d(x, w, channels=64, kernel_size=(3, 3), padding=(1, 1)), "func"
+            )
+            f = relay.Function([x], y, span=_create_span("func"))
+            return f
+
+        assert _verify_structural_equal_with_span(_res(), _golden())
+
+    _verify_env_var_switch()
+    _verify_builtin_tuple()
+    _verify_builtin_list()
+    _verify_var()
+    _verify_constant()
+    _verify_call()
+    _verify_tuple()
+    _verify_tuple_getitem()
+    _verify_let()
+    _verify_if()
+    _verify_fn()
+
+
 if __name__ == "__main__":
     test_key_is_present()

Review Comment:
   can you change this to `tvm.testing.main()` so the test cases are split out ?



##########
tests/python/relay/utils/tag_span.py:
##########
@@ -0,0 +1,106 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import tvm
+from tvm import relay, tir
+from tvm.relay.expr_functor import ExprVisitor
+
+
+def _set_span(expr, src):
+    if isinstance(expr, relay.Call):
+        return relay.Call(expr.op, expr.args, expr.attrs, expr.type_args, _create_span(src))
+    elif isinstance(expr, relay.Var):
+        return relay.var(expr.name_hint, expr.type_annotation, None, None, _create_span(src))
+    elif isinstance(expr, relay.TupleGetItem):
+        return relay.TupleGetItem(expr.tuple_value, expr.index, _create_span(src))
+    elif isinstance(expr, relay.Constant):
+        return relay.Constant(expr.data, _create_span(src))
+    elif isinstance(expr, relay.TupleWrapper):
+        return relay.TupleWrapper(_set_span(expr.tuple_value, src), expr.size)
+    elif isinstance(expr, relay.Tuple):
+        return relay.Tuple(expr.fields, _create_span(src))
+    elif isinstance(expr, tir.AttrStmt):
+        return tir.AttrStmt(expr.node, expr.attr_key, expr.value, expr.body, _create_span(src))
+
+    assert False, f"unsupported type {type(expr)}"
+
+
+def _create_span(src):
+    if isinstance(src, list):
+        tmp_list = []
+        for s in src:
+            if isinstance(s, str):
+                tmp_list.append(_create_span(s))
+            elif isinstance(s, relay.Span):
+                tmp_list.append(s)
+            elif isinstance(s, relay.SequentialSpan):
+                tmp_list.extend(s.spans)
+            elif s is None:
+                tmp_list.append(s)
+            else:
+                assert False, f"unsupported type {type(s)}"
+        return relay.SequentialSpan(tmp_list)
+    return relay.Span(relay.SourceName(src), 0, 0, 0, 0)
+
+
+def _collect_spans(objref):
+    class Collector:
+        def __init__(self):
+            self._spans = []
+
+        def collect(self, objref):
+            if hasattr(objref, "span"):
+                self._spans.append(objref.span)
+
+        @property
+        def get_spans(self):
+            return self._spans
+
+    pov = None
+    if isinstance(objref, relay.Expr):
+        pov = relay.analysis.post_order_visit
+    elif isinstance(objref, (tir.Stmt, tir.expr.PrimExprWithOp)):
+        pov = tir.stmt_functor.post_order_visit
+    else:
+        assert False, f"unsupported type {type(objref)}"
+
+    c = Collector()
+    pov(objref, c.collect)
+    return c.get_spans
+
+
+def _verify_span(lhs, rhs):
+    lhs_spans, rhs_spans = _collect_spans(lhs), _collect_spans(rhs)
+
+    if len(lhs_spans) != len(rhs_spans):
+        return False
+
+    for i in range(len(lhs_spans)):
+        if not tvm.ir.structural_equal(lhs_spans[i], rhs_spans[i]):
+            return False
+    return True

Review Comment:
   this style is a bit different than the typical pytest style e.g. `assert foo == bar` rather than `return foo == bar`.



##########
python/tvm/testing/utils.py:
##########
@@ -2081,3 +2081,28 @@ def pprint(name, obj):
                 f"or an instance of `tvm.tir.PrimFunc`.  "
                 f"Instead, received {type(expected)}."
             )
+
+
+class _control_span_filling:
+    def __init__(self, on=True):
+        self._old_state = os.environ["TVM_SPANFILLING"] if "TVM_SPANFILLING" in os.environ else None

Review Comment:
   just curious why you are consulting os.envrion here?



##########
src/relay/ir/expr.cc:
##########
@@ -72,8 +72,8 @@ Constant::Constant(runtime::NDArray data, Span span) {
 
 TVM_REGISTER_NODE_TYPE(ConstantNode);
 
-TVM_REGISTER_GLOBAL("relay.ir.Constant").set_body_typed([](runtime::NDArray data) {
-  return Constant(data);
+TVM_REGISTER_GLOBAL("relay.ir.Constant").set_body_typed([](runtime::NDArray data, Span span) {

Review Comment:
   i'm not sure this concern should block this review, but one thing i notice here is that this now adds Span as a required field to the Relay IR constructor. personally, i think that's reasonable--you can always explicitly provide `Span()` i think if you want to provide an undefined span. it is slightly more burdensome, so i could see some differing opinions around the community here. but personally, i think that's the tradeoff we have to live with, so I wouldn't block this review over it.



##########
tests/python/frontend/test_common.py:
##########
@@ -27,6 +32,203 @@ def test_key_is_not_present():
     assert not attrs.has_attr("b")
 
 
+def test_set_span():

Review Comment:
   suggest to make this a TestCase class and promote the various e.g. `_verify_env_var_switch` functions to class methods e.g. `test_env_var_switch`, so they are separate test cases



##########
python/tvm/relay/frontend/common.py:
##########
@@ -997,3 +1002,167 @@ def try_resolve_var_to_const(x, graph_params):
         return _op.const(value, dtype)
 
     return x
+
+
+class _SpanFiller(ExprMutator):

Review Comment:
   we had been implementing a bunch of passes in C++, since the Python visitor infra involves a lot of calls that cross the FFI. I wonder if you'd be up for moving this into C++?



##########
tests/python/relay/utils/tag_span.py:
##########
@@ -0,0 +1,106 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import tvm
+from tvm import relay, tir
+from tvm.relay.expr_functor import ExprVisitor
+
+
+def _set_span(expr, src):

Review Comment:
   we have an analogue `WithFields` in the C++, I think this would be better placed there. for now, see [FunctionWithFields](https://github.com/apache/tvm/blob/main/python/tvm/relay/function.py#L68).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] chunit-quic commented on a diff in pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
chunit-quic commented on code in PR #13402:
URL: https://github.com/apache/tvm/pull/13402#discussion_r1040363248


##########
src/relay/ir/expr.cc:
##########
@@ -72,8 +72,8 @@ Constant::Constant(runtime::NDArray data, Span span) {
 
 TVM_REGISTER_NODE_TYPE(ConstantNode);
 
-TVM_REGISTER_GLOBAL("relay.ir.Constant").set_body_typed([](runtime::NDArray data) {
-  return Constant(data);
+TVM_REGISTER_GLOBAL("relay.ir.Constant").set_body_typed([](runtime::NDArray data, Span span) {

Review Comment:
   Hi areusch,
   
   Thanks for replying!
   About the question "Is the plan to invoke this via PackedFunc between each pass?". 
   
   No, this SpanFiller will not be triggered between each pass. Perhaps there are some misunderstandings. Please allow me to describe more. :D 
   
   This PR, and the SpanFiller is for "frontend conversion" specifically. Take the upcomming PR of TFLite span filling for example, the function "set_span()" is invoked after a [conversion of an operator only](https://github.com/chunit-quic/tvm/blob/cee1703b4be6ac0e1ed3fb7c493432c95e7a5231/python/tvm/relay/frontend/tflite.py#L282).
   
   About the [span filling mechanism for the passes](https://discuss.tvm.apache.org/t/pre-rfc-tvm-explorer-infrastructure/13457#pass-source-information-builder-6), we will use the SequentialSpan and source information builder to deal with. They are another set of classes and function to propagate span between passes specifically.
   
   If there is any confusing part please feel free to let me know, I will try to make it clear. :)
   Thank you!



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] tvm-bot commented on pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
tvm-bot commented on PR #13402:
URL: https://github.com/apache/tvm/pull/13402#issuecomment-1316470418

   <!---bot-comment-->
   
   Thanks for contributing to TVM! Please refer to the contributing guidelines https://tvm.apache.org/docs/contribute/ for useful information and tips. Please request code reviews from [Reviewers](https://github.com/apache/incubator-tvm/blob/master/CONTRIBUTORS.md#reviewers) by @-ing them in a comment.
   
   <!--bot-comment-ccs-start-->
    * No users to tag found in teams: `relay`, `frontend` <sub>See [#10317](https://github.com/apache/tvm/issues/10317) for details</sub><!--bot-comment-ccs-end-->
   
   <sub>Generated by [tvm-bot](https://github.com/apache/tvm/blob/main/ci/README.md#github-actions)</sub>


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] chunit-quic commented on a diff in pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
chunit-quic commented on code in PR #13402:
URL: https://github.com/apache/tvm/pull/13402#discussion_r1024777388


##########
python/tvm/relay/frontend/common.py:
##########
@@ -304,13 +306,17 @@ def __init__(self):
         self.const_ctr = 1
         self.in_padding = False
 
-    def new_const(self, value, shape=None, dtype="float32"):
+    def new_const(self, value, shape=None, dtype="float32", source_name=None):
+        """Construct a new var expr and add to exprs dictionary"""
         name = "_param_%d" % (self.const_ctr)
         if hasattr(value, "shape"):
             shape = value.shape
         self.const_ctr += 1
         self.params[name] = value
-        self.exprs[name] = _expr.var(name_hint=name, shape=shape, dtype=dtype)
+        tmp_var = _expr.var(name_hint=name, shape=shape, dtype=dtype)
+        if source_name:
+            tmp_var = set_span(tmp_var, source_name)
+        self.exprs[name] = tmp_var

Review Comment:
   Fixed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] areusch commented on a diff in pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
areusch commented on code in PR #13402:
URL: https://github.com/apache/tvm/pull/13402#discussion_r1038612698


##########
src/relay/ir/expr.cc:
##########
@@ -72,8 +72,8 @@ Constant::Constant(runtime::NDArray data, Span span) {
 
 TVM_REGISTER_NODE_TYPE(ConstantNode);
 
-TVM_REGISTER_GLOBAL("relay.ir.Constant").set_body_typed([](runtime::NDArray data) {
-  return Constant(data);
+TVM_REGISTER_GLOBAL("relay.ir.Constant").set_body_typed([](runtime::NDArray data, Span span) {

Review Comment:
   okay cool--just wondering, since most of the passes are in C++, is the plan to invoke this via PackedFunc between each pass?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] chunit-quic commented on a diff in pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
chunit-quic commented on code in PR #13402:
URL: https://github.com/apache/tvm/pull/13402#discussion_r1046835230


##########
tests/python/relay/utils/tag_span.py:
##########
@@ -0,0 +1,106 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import tvm
+from tvm import relay, tir
+from tvm.relay.expr_functor import ExprVisitor
+
+
+def _set_span(expr, src):

Review Comment:
   Sure thing! I have exposed them from C++ and change the functions.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] chunit-quic commented on a diff in pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
chunit-quic commented on code in PR #13402:
URL: https://github.com/apache/tvm/pull/13402#discussion_r1046840499


##########
python/tvm/relay/frontend/common.py:
##########
@@ -997,3 +1002,167 @@ def try_resolve_var_to_const(x, graph_params):
         return _op.const(value, dtype)
 
     return x
+
+
+class _SpanFiller(ExprMutator):
+    """SpanFiller"""
+
+    def __init__(self, span):
+        ExprMutator.__init__(self)
+        if isinstance(span, tvm.relay.Span):
+            self._span = span
+        elif isinstance(span, str):
+            self._span = tvm.relay.Span(tvm.relay.SourceName(span), 0, 0, 0, 0)
+        elif isinstance(span, bytes):
+            self._span = tvm.relay.Span(tvm.relay.SourceName(span.decode("utf-8")), 0, 0, 0, 0)
+        else:
+            assert False, f"unsupported span type: {type(span)}"
+
+    def visit(self, expr):
+        if hasattr(expr, "span") and expr.span:
+            return expr
+
+        return super().visit(expr)
+
+    def visit_function(self, fn):
+        new_params = [self.visit(x) for x in fn.params]
+        new_body = self.visit(fn.body)
+        return _function.Function(

Review Comment:
   Yes, I have changed them in the latest patch. 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] areusch commented on a diff in pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
areusch commented on code in PR #13402:
URL: https://github.com/apache/tvm/pull/13402#discussion_r1044908822


##########
python/tvm/relay/frontend/common.py:
##########
@@ -997,3 +1002,167 @@ def try_resolve_var_to_const(x, graph_params):
         return _op.const(value, dtype)
 
     return x
+
+
+class _SpanFiller(ExprMutator):
+    """SpanFiller"""
+
+    def __init__(self, span):
+        ExprMutator.__init__(self)
+        if isinstance(span, tvm.relay.Span):
+            self._span = span
+        elif isinstance(span, str):
+            self._span = tvm.relay.Span(tvm.relay.SourceName(span), 0, 0, 0, 0)
+        elif isinstance(span, bytes):
+            self._span = tvm.relay.Span(tvm.relay.SourceName(span.decode("utf-8")), 0, 0, 0, 0)
+        else:
+            assert False, f"unsupported span type: {type(span)}"
+
+    def visit(self, expr):
+        if hasattr(expr, "span") and expr.span:
+            return expr
+
+        return super().visit(expr)
+
+    def visit_function(self, fn):
+        new_params = [self.visit(x) for x in fn.params]
+        new_body = self.visit(fn.body)
+        return _function.Function(

Review Comment:
   want to use FunctionWithFields here too? (and similar below)



##########
python/tvm/relay/frontend/common.py:
##########
@@ -997,3 +1002,167 @@ def try_resolve_var_to_const(x, graph_params):
         return _op.const(value, dtype)
 
     return x
+
+
+class _SpanFiller(ExprMutator):

Review Comment:
   ok, given for now we want to invoke this after the import, we can keep it as Python for now



##########
python/tvm/testing/utils.py:
##########
@@ -2081,3 +2081,28 @@ def pprint(name, obj):
                 f"or an instance of `tvm.tir.PrimFunc`.  "
                 f"Instead, received {type(expected)}."
             )
+
+
+class _control_span_filling:
+    def __init__(self, on=True):
+        self._old_state = os.environ["TVM_SPANFILLING"] if "TVM_SPANFILLING" in os.environ else None

Review Comment:
   right--sorry perhaps I should have commented on _should_fill_span in python/tvm/relay/frontend/common.py. what I mean is--could we consider a global variable or a PassContext option which can be initialized from the env should a driver script want, rather than forcing this control to be in the environment?



##########
tests/python/relay/utils/tag_span.py:
##########
@@ -0,0 +1,106 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import tvm
+from tvm import relay, tir
+from tvm.relay.expr_functor import ExprVisitor
+
+
+def _set_span(expr, src):

Review Comment:
   i think if you're going to do something like this, it would be great to just add e.g. CallWithFields and TupleWithFields properly to the FFI now. no need to migrate any other code, but keeping this code in test here seems like it's asking for two implementations to surface. lmk if this is too much of a burden.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] chunit-quic commented on a diff in pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
chunit-quic commented on code in PR #13402:
URL: https://github.com/apache/tvm/pull/13402#discussion_r1024777157


##########
python/tvm/relay/frontend/common.py:
##########
@@ -997,3 +1003,135 @@ def try_resolve_var_to_const(x, graph_params):
         return _op.const(value, dtype)
 
     return x
+
+
+class _SpanFiller(ExprMutator):
+    """SpanFiller"""
+
+    def __init__(self, span):
+        ExprMutator.__init__(self)
+        if isinstance(span, tvm.relay.Span):
+            self._span = span
+        elif isinstance(span, str):
+            self._span = tvm.relay.Span(tvm.relay.SourceName(span), 0, 0, 0, 0)
+        elif isinstance(span, bytes):
+            self._span = tvm.relay.Span(tvm.relay.SourceName(span.decode("utf-8")), 0, 0, 0, 0)
+        else:
+            assert False, f"unsupported span type: {type(span)}"
+
+    def visit(self, expr):
+        if hasattr(expr, "span") and expr.span:
+            return expr
+
+        return super().visit(expr)
+
+    def visit_function(self, fn):
+        new_params = [self.visit(x) for x in fn.params]
+        new_body = self.visit(fn.body)
+        return _function.Function(
+            list(new_params), new_body, fn.ret_type, fn.type_params, fn.attrs, self._span
+        )
+
+    def visit_let(self, let):
+        new_variable = self.visit(let.var)
+        new_value = self.visit(let.value)
+        new_body = self.visit(let.body)
+        return _expr.Let(new_variable, new_value, new_body, self._span)
+
+    def visit_call(self, call):
+        new_args = [self.visit(arg) for arg in call.args]
+        # call.op might be RelayExpr or Op type
+        # ExprMutator will return directly if subject belongs to Op type
+        new_op = self.visit(call.op)
+        return _expr.Call(new_op, new_args, call.attrs, call.type_args, self._span)
+
+    def visit_var(self, var):
+        return _expr.Var(var.name_hint, var.type_annotation, self._span)
+
+    def visit_if(self, ite):
+        return _expr.If(
+            self.visit(ite.cond),
+            self.visit(ite.true_branch),
+            self.visit(ite.false_branch),
+            self._span,
+        )
+
+    def visit_tuple(self, tup):
+        return _expr.Tuple([self.visit(field) for field in tup.fields], self._span)
+
+    def visit_tuple_getitem(self, op):
+        return _expr.TupleGetItem(self.visit(op.tuple_value), op.index, self._span)
+
+    def visit_constant(self, const):
+        return _expr.Constant(const.data, self._span)
+
+    # TODO: Frontend model translation could not use following relay expressions so far,
+    #       enable them when new models/impls leverage these kinds of relay expressions.
+    def visit_ref_create(self, _):
+        raise NotImplementedError()
+
+    def visit_ref_write(self, _):
+        raise NotImplementedError()
+
+    def visit_ref_read(self, _):
+        raise NotImplementedError()
+
+    def visit_match(self, _):
+        raise NotImplementedError()
+
+    def fill(self, sym):
+        """Fill span to sym when it is an expr, or return it without change
+
+        Parameters
+        ----------
+        sym :
+            A symbol which is generated from the conversion of a frontend operator.
+
+        Returns
+        -------
+        sym:
+            A expr with span-filled or the original sym.
+        """
+        if isinstance(sym, _expr.TupleWrapper):
+            return _expr.TupleWrapper(self.visit(sym.tuple_value), sym.size)
+        elif isinstance(sym, _expr.RelayExpr):
+            return self.visit(sym)
+        elif isinstance(sym, list):
+            assert all(
+                isinstance(expr, _expr.RelayExpr) for expr in sym
+            ), f"unexpected relay expressions in {sym}"
+            return [self.visit(expr) for expr in sym]
+        elif isinstance(sym, tuple):
+            # some op conversion may return dummy elements
+            # e.g. op in frontend/pytorch.py: min_max_common
+            assert all(
+                isinstance(expr, (_expr.RelayExpr, type(None))) for expr in sym
+            ), f"unexpected relay expressions in {sym}"
+            return tuple(self.visit(expr) if expr else None for expr in sym)
+        elif isinstance(sym, (float, int)):
+            return sym
+        elif isinstance(sym, np.ndarray):
+            return sym
+
+        raise RuntimeError(f"unsupported type {type(sym)}")
+
+
+def _should_fill_span():
+    should_fill_span = os.environ.get("TVM_SPANFILLING", "1")

Review Comment:
   Thank you for point out. :D
   I have pushed a patch with documentation below set_span(). This document includes environment variable setting, how to use and example.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] chunit-quic commented on pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
chunit-quic commented on PR #13402:
URL: https://github.com/apache/tvm/pull/13402#issuecomment-1316473284

   Hi community,
   
   This is the very first PR of the RFC, TVM Explorer Infrastructure. We spend a while to extract the code blocks, and verify them after rebasing. Feel free to give us and comment. Thank you! :D
   
   For your reference, here is the related links.
   [PreRFC in forum](https://discuss.tvm.apache.org/t/pre-rfc-tvm-explorer-infrastructure/13457/24)
   [RFC in git](https://github.com/apache/tvm-rfcs/pull/92)
   [Tracking issue](https://github.com/apache/tvm/issues/13116)
   
   @haowhsu-quic, @zack-ch
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] echuraev commented on a diff in pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
echuraev commented on code in PR #13402:
URL: https://github.com/apache/tvm/pull/13402#discussion_r1023597049


##########
python/tvm/relay/frontend/common.py:
##########
@@ -997,3 +1003,135 @@ def try_resolve_var_to_const(x, graph_params):
         return _op.const(value, dtype)
 
     return x
+
+
+class _SpanFiller(ExprMutator):
+    """SpanFiller"""
+
+    def __init__(self, span):
+        ExprMutator.__init__(self)
+        if isinstance(span, tvm.relay.Span):
+            self._span = span
+        elif isinstance(span, str):
+            self._span = tvm.relay.Span(tvm.relay.SourceName(span), 0, 0, 0, 0)
+        elif isinstance(span, bytes):
+            self._span = tvm.relay.Span(tvm.relay.SourceName(span.decode("utf-8")), 0, 0, 0, 0)
+        else:
+            assert False, f"unsupported span type: {type(span)}"
+
+    def visit(self, expr):
+        if hasattr(expr, "span") and expr.span:
+            return expr
+
+        return super().visit(expr)
+
+    def visit_function(self, fn):
+        new_params = [self.visit(x) for x in fn.params]
+        new_body = self.visit(fn.body)
+        return _function.Function(
+            list(new_params), new_body, fn.ret_type, fn.type_params, fn.attrs, self._span
+        )
+
+    def visit_let(self, let):
+        new_variable = self.visit(let.var)
+        new_value = self.visit(let.value)
+        new_body = self.visit(let.body)
+        return _expr.Let(new_variable, new_value, new_body, self._span)
+
+    def visit_call(self, call):
+        new_args = [self.visit(arg) for arg in call.args]
+        # call.op might be RelayExpr or Op type
+        # ExprMutator will return directly if subject belongs to Op type
+        new_op = self.visit(call.op)
+        return _expr.Call(new_op, new_args, call.attrs, call.type_args, self._span)
+
+    def visit_var(self, var):
+        return _expr.Var(var.name_hint, var.type_annotation, self._span)
+
+    def visit_if(self, ite):
+        return _expr.If(
+            self.visit(ite.cond),
+            self.visit(ite.true_branch),
+            self.visit(ite.false_branch),
+            self._span,
+        )
+
+    def visit_tuple(self, tup):
+        return _expr.Tuple([self.visit(field) for field in tup.fields], self._span)
+
+    def visit_tuple_getitem(self, op):
+        return _expr.TupleGetItem(self.visit(op.tuple_value), op.index, self._span)
+
+    def visit_constant(self, const):
+        return _expr.Constant(const.data, self._span)
+
+    # TODO: Frontend model translation could not use following relay expressions so far,
+    #       enable them when new models/impls leverage these kinds of relay expressions.
+    def visit_ref_create(self, _):
+        raise NotImplementedError()
+
+    def visit_ref_write(self, _):
+        raise NotImplementedError()
+
+    def visit_ref_read(self, _):
+        raise NotImplementedError()
+
+    def visit_match(self, _):
+        raise NotImplementedError()
+
+    def fill(self, sym):
+        """Fill span to sym when it is an expr, or return it without change
+
+        Parameters
+        ----------
+        sym :
+            A symbol which is generated from the conversion of a frontend operator.
+
+        Returns
+        -------
+        sym:
+            A expr with span-filled or the original sym.
+        """
+        if isinstance(sym, _expr.TupleWrapper):
+            return _expr.TupleWrapper(self.visit(sym.tuple_value), sym.size)
+        elif isinstance(sym, _expr.RelayExpr):
+            return self.visit(sym)
+        elif isinstance(sym, list):
+            assert all(
+                isinstance(expr, _expr.RelayExpr) for expr in sym
+            ), f"unexpected relay expressions in {sym}"
+            return [self.visit(expr) for expr in sym]
+        elif isinstance(sym, tuple):
+            # some op conversion may return dummy elements
+            # e.g. op in frontend/pytorch.py: min_max_common
+            assert all(
+                isinstance(expr, (_expr.RelayExpr, type(None))) for expr in sym
+            ), f"unexpected relay expressions in {sym}"
+            return tuple(self.visit(expr) if expr else None for expr in sym)
+        elif isinstance(sym, (float, int)):
+            return sym
+        elif isinstance(sym, np.ndarray):
+            return sym
+
+        raise RuntimeError(f"unsupported type {type(sym)}")
+
+
+def _should_fill_span():
+    should_fill_span = os.environ.get("TVM_SPANFILLING", "1")

Review Comment:
   Will we document somewhere how to use span filling and describe variable `TVM_SPANFILLING`?
   At least, probably we should add information about this variable to the `set_span` method?



##########
python/tvm/relay/frontend/common.py:
##########
@@ -304,13 +306,17 @@ def __init__(self):
         self.const_ctr = 1
         self.in_padding = False
 
-    def new_const(self, value, shape=None, dtype="float32"):
+    def new_const(self, value, shape=None, dtype="float32", source_name=None):
+        """Construct a new var expr and add to exprs dictionary"""
         name = "_param_%d" % (self.const_ctr)
         if hasattr(value, "shape"):
             shape = value.shape
         self.const_ctr += 1
         self.params[name] = value
-        self.exprs[name] = _expr.var(name_hint=name, shape=shape, dtype=dtype)
+        tmp_var = _expr.var(name_hint=name, shape=shape, dtype=dtype)
+        if source_name:
+            tmp_var = set_span(tmp_var, source_name)
+        self.exprs[name] = tmp_var

Review Comment:
   ```suggestion
           self.exprs[name] = _expr.var(name_hint=name, shape=shape, dtype=dtype)
           if source_name:
               self.exprs[name] = set_span(tmp_var, source_name)
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] chunit-quic commented on a diff in pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
chunit-quic commented on code in PR #13402:
URL: https://github.com/apache/tvm/pull/13402#discussion_r1030068605


##########
tests/python/frontend/test_common.py:
##########
@@ -27,6 +32,203 @@ def test_key_is_not_present():
     assert not attrs.has_attr("b")
 
 
+def test_set_span():

Review Comment:
   No problem!



##########
tests/python/relay/utils/tag_span.py:
##########
@@ -0,0 +1,106 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import tvm
+from tvm import relay, tir
+from tvm.relay.expr_functor import ExprVisitor
+
+
+def _set_span(expr, src):

Review Comment:
   Thank you for let us know that we can leverage this function. :D
   Yet about this _set_span, it is just a simple helper function and only used in the tests. Would you hope to add the functions like CallWithFields or TupleWithFields in C++ and expose them to python side in this patch? Or perhaps this _set_span is enough for the test cases?



##########
tests/python/relay/utils/tag_span.py:
##########
@@ -0,0 +1,106 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import tvm
+from tvm import relay, tir
+from tvm.relay.expr_functor import ExprVisitor
+
+
+def _set_span(expr, src):
+    if isinstance(expr, relay.Call):
+        return relay.Call(expr.op, expr.args, expr.attrs, expr.type_args, _create_span(src))
+    elif isinstance(expr, relay.Var):
+        return relay.var(expr.name_hint, expr.type_annotation, None, None, _create_span(src))
+    elif isinstance(expr, relay.TupleGetItem):
+        return relay.TupleGetItem(expr.tuple_value, expr.index, _create_span(src))
+    elif isinstance(expr, relay.Constant):
+        return relay.Constant(expr.data, _create_span(src))
+    elif isinstance(expr, relay.TupleWrapper):
+        return relay.TupleWrapper(_set_span(expr.tuple_value, src), expr.size)
+    elif isinstance(expr, relay.Tuple):
+        return relay.Tuple(expr.fields, _create_span(src))
+    elif isinstance(expr, tir.AttrStmt):
+        return tir.AttrStmt(expr.node, expr.attr_key, expr.value, expr.body, _create_span(src))
+
+    assert False, f"unsupported type {type(expr)}"
+
+
+def _create_span(src):
+    if isinstance(src, list):
+        tmp_list = []
+        for s in src:
+            if isinstance(s, str):
+                tmp_list.append(_create_span(s))
+            elif isinstance(s, relay.Span):
+                tmp_list.append(s)
+            elif isinstance(s, relay.SequentialSpan):
+                tmp_list.extend(s.spans)
+            elif s is None:
+                tmp_list.append(s)
+            else:
+                assert False, f"unsupported type {type(s)}"
+        return relay.SequentialSpan(tmp_list)
+    return relay.Span(relay.SourceName(src), 0, 0, 0, 0)
+
+
+def _collect_spans(objref):
+    class Collector:
+        def __init__(self):
+            self._spans = []
+
+        def collect(self, objref):
+            if hasattr(objref, "span"):
+                self._spans.append(objref.span)
+
+        @property
+        def get_spans(self):
+            return self._spans
+
+    pov = None
+    if isinstance(objref, relay.Expr):
+        pov = relay.analysis.post_order_visit
+    elif isinstance(objref, (tir.Stmt, tir.expr.PrimExprWithOp)):
+        pov = tir.stmt_functor.post_order_visit
+    else:
+        assert False, f"unsupported type {type(objref)}"
+
+    c = Collector()
+    pov(objref, c.collect)
+    return c.get_spans
+
+
+def _verify_span(lhs, rhs):
+    lhs_spans, rhs_spans = _collect_spans(lhs), _collect_spans(rhs)
+
+    if len(lhs_spans) != len(rhs_spans):
+        return False
+
+    for i in range(len(lhs_spans)):
+        if not tvm.ir.structural_equal(lhs_spans[i], rhs_spans[i]):
+            return False
+    return True

Review Comment:
   Will change.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] chunit-quic commented on a diff in pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
chunit-quic commented on code in PR #13402:
URL: https://github.com/apache/tvm/pull/13402#discussion_r1030068464


##########
python/tvm/testing/utils.py:
##########
@@ -2081,3 +2081,28 @@ def pprint(name, obj):
                 f"or an instance of `tvm.tir.PrimFunc`.  "
                 f"Instead, received {type(expected)}."
             )
+
+
+class _control_span_filling:
+    def __init__(self, on=True):
+        self._old_state = os.environ["TVM_SPANFILLING"] if "TVM_SPANFILLING" in os.environ else None

Review Comment:
   Because we can command like the following way to get rid of span without modifying the code. It would be a bit more convenient. 
   ```bash
   TVM_SPANFILLING=0 python ${your_program.py}
   ````
   



##########
src/relay/ir/expr.cc:
##########
@@ -72,8 +72,8 @@ Constant::Constant(runtime::NDArray data, Span span) {
 
 TVM_REGISTER_NODE_TYPE(ConstantNode);
 
-TVM_REGISTER_GLOBAL("relay.ir.Constant").set_body_typed([](runtime::NDArray data) {
-  return Constant(data);
+TVM_REGISTER_GLOBAL("relay.ir.Constant").set_body_typed([](runtime::NDArray data, Span span) {

Review Comment:
    Thank you for point out this concern. :D
   Just a gentle reminder that we do have the default value of span for these types. Because currently the constructors in header ([include/tvm/relay/expr.h](https://github.com/apache/tvm/blob/b2058f4dd2e0ae1fc5ab51ac9f84b372a389a65a/include/tvm/relay/expr.h#L107)) have already been assigned with Span() to its attribute. We simply make span attribute be modifiable here.
   
   



##########
tests/python/frontend/test_common.py:
##########
@@ -27,6 +32,203 @@ def test_key_is_not_present():
     assert not attrs.has_attr("b")
 
 
+def test_set_span():
+    def _verify_env_var_switch():
+        def _res(should_fill):
+            if should_fill:
+                with testing.enable_span_filling():
+                    return set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var")
+            else:
+                with testing.disable_span_filling():
+                    return set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var")
+
+        disable = relay.var("x", shape=(1, 64, 56, 56))
+        enable = relay.var("x", shape=(1, 64, 56, 56), span=_create_span("x_var"))
+
+        assert _verify_structural_equal_with_span(_res(False), disable)
+        assert _verify_structural_equal_with_span(_res(True), enable)
+
+    # Should tag all exprs without span, and stop when expr is span-tagged
+    def _verify_builtin_tuple():
+        def _res():
+            a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a"))
+            b = relay.const(np.zeros([1, 1, 1]), dtype="int64")
+            return set_span(tuple([a, b]), "tuple")
+
+        def _golden():
+            a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a"))
+            b = relay.const(np.zeros([1, 1, 1]), dtype="int64", span=_create_span("tuple"))
+            return tuple([a, b])
+
+        res_tuple, golden_tuple = _res(), _golden()
+        assert len(res_tuple) == len(golden_tuple)
+        for i in range(len(res_tuple)):
+            assert _verify_structural_equal_with_span(res_tuple[i], golden_tuple[i])
+
+    def _verify_builtin_list():
+        def _res():
+            a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a"))
+            b = relay.const(np.zeros([1, 1, 1]), dtype="int64")
+            t = relay.Tuple([a, b])
+            t_a = relay.TupleGetItem(t, 0)
+            t_b = relay.TupleGetItem(t, 1)
+            return set_span([t_a, t_b], "list")
+
+        def _golden():
+            a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a"))
+            b = relay.const(np.zeros([1, 1, 1]), dtype="int64", span=_create_span("list"))
+            t = relay.Tuple([a, b], span=_create_span("list"))
+            t_a = relay.TupleGetItem(t, 0, span=_create_span("list"))
+            t_b = relay.TupleGetItem(t, 1, span=_create_span("list"))
+            return [t_a, t_b]
+
+        res_list, golden_list = _res(), _golden()
+        assert len(res_list) == len(golden_list)
+        for i in range(len(res_list)):
+            assert _verify_structural_equal_with_span(res_list[i], golden_list[i])
+
+    def _verify_var():
+        x = set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var")
+        x_expected = relay.var("x", shape=(1, 64, 56, 56), span=_create_span("x_var"))
+        assert _verify_structural_equal_with_span(x, x_expected)
+
+    def _verify_constant():
+        c = set_span(relay.const(np.ones([64, 64, 3, 3]), dtype="int64"), "const_c")
+        c_expected = relay.const(
+            np.ones([64, 64, 3, 3]), dtype="int64", span=_create_span("const_c")
+        )
+        assert _verify_structural_equal_with_span(c, c_expected)
+
+    def _verify_call():
+        def _res():
+            x = set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var")
+            w = relay.const(np.ones([64, 64, 3, 3]), dtype="int64")
+            y = set_span(
+                relay.nn.conv2d(x, w, channels=64, kernel_size=(3, 3), padding=(1, 1)), "conv2d"
+            )
+            return relay.Function([x], y)
+
+        def _golden():
+            x = relay.var("x", shape=(1, 64, 56, 56), span=_create_span("x_var"))
+            w = relay.const(np.ones([64, 64, 3, 3]), dtype="int64", span=_create_span("conv2d"))
+            y = _set_span(
+                relay.nn.conv2d(x, w, channels=64, kernel_size=(3, 3), padding=(1, 1)), "conv2d"
+            )
+            return relay.Function([x], y)
+
+        assert _verify_structural_equal_with_span(_res(), _golden())
+
+    def _verify_tuple():
+        def _res():
+            a = set_span(relay.const(np.ones([1, 1, 1]), dtype="int64"), "a")
+            b = relay.const(np.ones([1, 1, 1]), dtype="int64")
+            t = set_span(relay.Tuple([a, b]), "t")
+            return relay.Function([], t)
+
+        def _golden():
+            a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a"))
+            b = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("t"))
+            t = relay.Tuple([a, b], span=_create_span("t"))
+            return relay.Function([], t)
+
+        assert _verify_structural_equal_with_span(_res(), _golden())
+
+    def _verify_tuple_getitem():
+        def _res():
+            a = set_span(relay.const(np.ones([1, 1, 1]), dtype="int64"), "a")
+            b = relay.const(np.ones([1, 1, 1]), dtype="int64")
+            t = relay.Tuple([a, b])
+            i = set_span(relay.TupleGetItem(t, 0), "i")
+            return relay.Function([], i)
+
+        def _golden():
+            a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a"))
+            b = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("i"))
+            t = relay.Tuple([a, b], span=_create_span("i"))
+            i = relay.TupleGetItem(t, 0, span=_create_span("i"))
+            return relay.Function([], i)
+
+        assert _verify_structural_equal_with_span(_res(), _golden())
+
+    def _verify_let():
+        def _res():
+            x = set_span(relay.Var("x"), "x_var")
+            c_1 = relay.const(np.ones(10))
+            add = relay.add(x, x)
+            body = set_span(relay.Let(x, c_1, add), "let")
+
+            c_2 = set_span(relay.const(np.zeros(10)), "zeros")
+            y = set_span(relay.add(body, c_2), "add_2")
+            return relay.Function([x], y)
+
+        def _golden():
+            x = relay.Var("x", span=_create_span("x_var"))
+            c_1 = relay.const(np.ones(10), span=_create_span("let"))
+            add = _set_span(relay.add(x, x), "let")
+            body = relay.Let(x, c_1, add, span=_create_span("let"))
+
+            c_2 = relay.const(np.zeros(10), span=_create_span("zeros"))
+            y = _set_span(relay.add(body, c_2), "add_2")
+            return relay.Function([x], y)
+
+        assert _verify_structural_equal_with_span(_res(), _golden())
+
+    def _verify_if():
+        def _res():
+            x = set_span(relay.var("x", shape=[], dtype="float32"), "x_var")
+            y = set_span(relay.var("y", shape=[], dtype="float32"), "y_var")
+            eq = relay.equal(x, y)
+
+            true_branch = set_span(relay.add(x, y), "true_branch")
+            false_branch = relay.subtract(x, y)
+            ife = set_span(relay.If(eq, true_branch, false_branch), "if")
+            return relay.Function([x, y], ife)
+
+        def _golden():
+            x = relay.var("x", shape=[], dtype="float32", span=_create_span("x_var"))
+            y = relay.var("y", shape=[], dtype="float32", span=_create_span("y_var"))
+            eq = _set_span(relay.equal(x, y), "if")
+
+            true_branch = _set_span(relay.add(x, y), "true_branch")
+            false_branch = _set_span(relay.subtract(x, y), "if")
+            ife = relay.If(eq, true_branch, false_branch, span=_create_span("if"))
+            return relay.Function([x, y], ife)
+
+        assert _verify_structural_equal_with_span(_res(), _golden())
+
+    def _verify_fn():
+        def _res():
+            x = set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var")
+            w = relay.const(np.ones([64, 64, 3, 3]), dtype="int64")
+            y = relay.nn.conv2d(x, w, channels=64, kernel_size=(3, 3), padding=(1, 1))
+            f = set_span(relay.Function([x], y), "func")
+            return f
+
+        def _golden():
+            x = relay.var("x", shape=(1, 64, 56, 56), span=_create_span("x_var"))
+            w = relay.const(np.ones([64, 64, 3, 3]), dtype="int64", span=_create_span("func"))
+            y = _set_span(
+                relay.nn.conv2d(x, w, channels=64, kernel_size=(3, 3), padding=(1, 1)), "func"
+            )
+            f = relay.Function([x], y, span=_create_span("func"))
+            return f
+
+        assert _verify_structural_equal_with_span(_res(), _golden())
+
+    _verify_env_var_switch()
+    _verify_builtin_tuple()
+    _verify_builtin_list()
+    _verify_var()
+    _verify_constant()
+    _verify_call()
+    _verify_tuple()
+    _verify_tuple_getitem()
+    _verify_let()
+    _verify_if()
+    _verify_fn()
+
+
 if __name__ == "__main__":
     test_key_is_present()

Review Comment:
   Will do.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] chunit-quic commented on pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
chunit-quic commented on PR #13402:
URL: https://github.com/apache/tvm/pull/13402#issuecomment-1325848010

   > thanks @chunit-quic and sorry for the delay--i've been out on PTO for a while. i've left some comments here, overall this is a great addition!
   
   Hi @areusch,
   Thank you for reviewing! 
   We have modified several parts based on your previous comments. :D 
   Take your time (It's thanks giving recently.) We will wait for your reply.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [tvm] chunit-quic commented on a diff in pull request #13402: [Relay][Frontend] Span filling common API

Posted by GitBox <gi...@apache.org>.
chunit-quic commented on code in PR #13402:
URL: https://github.com/apache/tvm/pull/13402#discussion_r1046834872


##########
python/tvm/testing/utils.py:
##########
@@ -2081,3 +2081,28 @@ def pprint(name, obj):
                 f"or an instance of `tvm.tir.PrimFunc`.  "
                 f"Instead, received {type(expected)}."
             )
+
+
+class _control_span_filling:
+    def __init__(self, on=True):
+        self._old_state = os.environ["TVM_SPANFILLING"] if "TVM_SPANFILLING" in os.environ else None

Review Comment:
   No problem, I change the way from using the environment variable to the passContext config. :)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org