This is an automated email from the ASF dual-hosted git repository.
masahi pushed a commit to branch unity
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/unity by this push:
new 8a6184ccfa [Unity, BYOC] Add check for leaking intemediate variables
for cublas and cudnn (#16175)
8a6184ccfa is described below
commit 8a6184ccfac972e1954c30671af67074962da4ee
Author: Wuwei Lin <[email protected]>
AuthorDate: Tue Nov 28 20:38:27 2023 -0800
[Unity, BYOC] Add check for leaking intemediate variables for cublas and
cudnn (#16175)
---
python/tvm/relax/backend/contrib/cublas.py | 3 ++
python/tvm/relax/backend/contrib/cudnn.py | 3 ++
python/tvm/relax/backend/contrib/cutlass.py | 32 +++-------------
python/tvm/relax/backend/utils.py | 43 ++++++++++++++++++++++
.../relax/test_transform_fuse_ops_by_pattern.py | 23 ++++++++++++
5 files changed, 77 insertions(+), 27 deletions(-)
diff --git a/python/tvm/relax/backend/contrib/cublas.py
b/python/tvm/relax/backend/contrib/cublas.py
index bc53158181..eecd531e74 100644
--- a/python/tvm/relax/backend/contrib/cublas.py
+++ b/python/tvm/relax/backend/contrib/cublas.py
@@ -25,6 +25,7 @@ from tvm.relax.transform import PatternCheckContext
from ..pattern_registry import get_patterns_with_prefix, register_patterns
from ..patterns import make_matmul_pattern
+from ..utils import has_leaking_intermediate_variables
def _is_supported_dtype(lhs_dtype, rhs_dtype):
@@ -37,6 +38,8 @@ def _is_supported_dtype(lhs_dtype, rhs_dtype):
def _check_matmul(context: PatternCheckContext) -> bool:
+ if has_leaking_intermediate_variables(context):
+ return False
lhs = context.annotated_expr["lhs"]
rhs = context.annotated_expr["rhs"]
diff --git a/python/tvm/relax/backend/contrib/cudnn.py
b/python/tvm/relax/backend/contrib/cudnn.py
index e3df0b8711..f730d4e5be 100644
--- a/python/tvm/relax/backend/contrib/cudnn.py
+++ b/python/tvm/relax/backend/contrib/cudnn.py
@@ -21,6 +21,7 @@ from tvm.relax.transform import PatternCheckContext
from ..pattern_registry import get_patterns_with_prefix, register_patterns
from ..patterns import make_conv2d_pattern
+from ..utils import has_leaking_intermediate_variables
def _is_supported_dtype(lhs_dtype, rhs_dtype):
@@ -38,6 +39,8 @@ def _is_supported_format(data_layout, kernel_layout):
def _check_conv2d(context: PatternCheckContext) -> bool:
+ if has_leaking_intermediate_variables(context):
+ return False
# Retrieve the annotated expression from context
conv2d_call = context.annotated_expr["root"]
input_expr = context.annotated_expr["input"]
diff --git a/python/tvm/relax/backend/contrib/cutlass.py
b/python/tvm/relax/backend/contrib/cutlass.py
index c7780b7c67..de7eb54b99 100644
--- a/python/tvm/relax/backend/contrib/cutlass.py
+++ b/python/tvm/relax/backend/contrib/cutlass.py
@@ -24,7 +24,6 @@ import tvm
from tvm.contrib.cutlass.build import is_shape_valid_for_cutlass_matmul
from tvm.relax import (
Call,
- DataflowVar,
ExternFunc,
Function,
PyExprMutator,
@@ -47,6 +46,7 @@ from ..patterns import (
make_rms_norm_pattern,
make_stacked_attention_pattern,
)
+from ..utils import has_leaking_intermediate_variables
def _is_supported_dtype(lhs_dtype, rhs_dtype):
@@ -62,28 +62,6 @@ def _shape_1d(shape):
return reduce(operator.mul, shape, 1)
-def _has_leaking_intermediate_variables(context: PatternCheckContext) -> bool:
- """
- Check whether intermediate variables in the region to be fused are used
outside
- the fused region.
- """
- defined_vars = set(context.matched_bindings.keys())
- output_var = context.value_to_bound_var[context.matched_expr]
- intermediate_vars = {v for v in context.matched_bindings if v !=
output_var}
-
- if any(not isinstance(v, DataflowVar) for v in intermediate_vars):
- # If intermediate variable is not a DataflowVar, it can be accessed
and potentially
- # used outside the DataflowBlock.
- return True
-
- # Check whether all users of an intermediate variable are inside the fused
region.
- for var in intermediate_vars:
- if any(var_user not in defined_vars for var_user in
context.var_usages[var]):
- return True
-
- return False
-
-
def _has_dependency(from_var: Var, to_var: Var, var_usages: Mapping[Var,
Sequence[Var]]):
if from_var == to_var:
return True
@@ -137,7 +115,7 @@ def _check_residual(root_call: Call, context:
PatternCheckContext) -> bool:
def _check_conv2d(context: PatternCheckContext) -> bool:
"""Check if the given conv2d workload can be offloaded to CUTLASS."""
- if _has_leaking_intermediate_variables(context):
+ if has_leaking_intermediate_variables(context):
return False
conv2d_call = context.annotated_expr["root"]
@@ -163,7 +141,7 @@ def _check_conv2d(context: PatternCheckContext) -> bool:
def _check_matmul(context: PatternCheckContext) -> bool:
"""Check if the given matmul workload can be offloaded to CUTLASS."""
- if _has_leaking_intermediate_variables(context):
+ if has_leaking_intermediate_variables(context):
return False
lhs = context.annotated_expr["lhs"]
@@ -229,7 +207,7 @@ def matmul_patterns():
def _check_decode_matmul(ctx):
"""Check if the given decode -> matmul workload can be offloaded to
CUTLASS."""
- if _has_leaking_intermediate_variables(ctx):
+ if has_leaking_intermediate_variables(ctx):
return False
root = ctx.annotated_expr["root"]
@@ -391,7 +369,7 @@ def residual_block_patterns():
def _check_stacked_attention(context: PatternCheckContext) -> bool:
"""Check if the given stacked attention workload can be offloaded to
CUTLASS."""
- if _has_leaking_intermediate_variables(context):
+ if has_leaking_intermediate_variables(context):
return False
if not context.annotated_expr["stacked_qkv"].struct_info.ndim == 3:
return False
diff --git a/python/tvm/relax/backend/utils.py
b/python/tvm/relax/backend/utils.py
new file mode 100644
index 0000000000..e5ecb7c5f4
--- /dev/null
+++ b/python/tvm/relax/backend/utils.py
@@ -0,0 +1,43 @@
+# 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.
+# pylint: disable=invalid-name
+"""Utils for BYOC pattern matching"""
+
+from tvm.relax import DataflowVar
+from tvm.relax.transform import PatternCheckContext
+
+
+def has_leaking_intermediate_variables(context: PatternCheckContext) -> bool:
+ """
+ Check whether intermediate variables in the region to be fused are used
outside
+ the fused region.
+ """
+ defined_vars = set(context.matched_bindings.keys())
+ output_var = context.value_to_bound_var[context.matched_expr]
+ intermediate_vars = {v for v in context.matched_bindings if v !=
output_var}
+
+ if any(not isinstance(v, DataflowVar) for v in intermediate_vars):
+ # If intermediate variable is not a DataflowVar, it can be accessed
and potentially
+ # used outside the DataflowBlock.
+ return True
+
+ # Check whether all users of an intermediate variable are inside the fused
region.
+ for var in intermediate_vars:
+ if any(var_user not in defined_vars for var_user in
context.var_usages[var]):
+ return True
+
+ return False
diff --git a/tests/python/relax/test_transform_fuse_ops_by_pattern.py
b/tests/python/relax/test_transform_fuse_ops_by_pattern.py
index 048d0550b8..bd434864a0 100644
--- a/tests/python/relax/test_transform_fuse_ops_by_pattern.py
+++ b/tests/python/relax/test_transform_fuse_ops_by_pattern.py
@@ -27,6 +27,7 @@ from tvm.relax.dpl.pattern import (
)
from tvm.relax.transform import PatternCheckContext
from tvm.relax.backend.contrib.cutlass import partition_for_cutlass
+from tvm.relax.backend.contrib.cublas import partition_for_cublas
from tvm.script import ir as I
from tvm.script import relax as R
from tvm.script import tir as T
@@ -1023,5 +1024,27 @@ def test_matmul_add3():
assert "fused_relax_matmul_relax_add_relax_add_cutlass" in func_names
+def test_intermediate_var_to_var_binding():
+ """test the intermediate binding y1 will break the fusion"""
+
+ @I.ir_module
+ class Module:
+ @R.function
+ def main(
+ x: R.Tensor((1, 16), dtype="float16"), w: R.Tensor((16, 16),
dtype="float16")
+ ) -> R.Tensor((1, 16), dtype="float16"):
+ with R.dataflow():
+ w1: R.Tensor((16, 16), dtype="float16") = R.permute_dims(w,
axes=None)
+ y: R.Tensor((1, 16), dtype="float16") = R.matmul(x, w1)
+ y1: R.Tensor((1, 16), dtype="float16") = y
+ out: R.Tensor((1, 16), dtype="float16") = R.add(x, y1)
+ R.output(out)
+ return out
+
+ mod = partition_for_cublas(Module)
+ func_names = [name.name_hint for (name, _) in mod.functions.items()]
+ assert "fused_relax_permute_dims_relax_matmul_cublas" in func_names # add
is not fused
+
+
if __name__ == "__main__":
pytest.main([__file__])