From b81a38a4e6085557466c8c9da94d924185513f64 Mon Sep 17 00:00:00 2001 From: Shubham Bhokare <32080845+shubhambhokare1@users.noreply.github.com> Date: Thu, 2 May 2024 14:40:18 -0700 Subject: [PATCH] [rewriter][docs] Add Tutorial for Pattern-based Rewrites (#1413) Add Tutorial for Pattern-based Rewrites --- docs/index.md | 1 + docs/rewriter/examples/broadcast_matmul.py | 198 ++++++++++++++++++ docs/rewriter/examples/erfgelu.py | 161 ++++++++++++++ docs/rewriter/examples/img/broadcast_01.png | Bin 0 -> 16379 bytes docs/rewriter/examples/img/broadcast_02.png | Bin 0 -> 11790 bytes docs/rewriter/examples/img/erfgelu_01.png | Bin 0 -> 16282 bytes docs/rewriter/examples/img/erfgelu_02.png | Bin 0 -> 7956 bytes .../examples/img/erfgelu_03_commute.png | Bin 0 -> 43255 bytes .../examples/img/erfgelu_04_commute.png | Bin 0 -> 14035 bytes .../examples/img/erfgelu_05_commute.png | Bin 0 -> 13807 bytes .../examples/img/erfgelu_06_commute.png | Bin 0 -> 29391 bytes .../examples/img/erfgelu_07_commute.png | Bin 0 -> 10449 bytes docs/rewriter/index.md | 5 + docs/rewriter/rewrite_patterns.md | 198 ++++++++++++++++++ docs/test/test_documentation_examples.py | 1 + onnxscript/rewriter/broadcast_to_matmul.py | 13 +- .../instance_to_group_normalization.py | 49 ++--- onnxscript/rewriter/onnxruntime/softmax.py | 8 +- onnxscript/rewriter/pattern.py | 7 +- onnxscript/rewriter/pattern_test.py | 5 +- 20 files changed, 597 insertions(+), 49 deletions(-) create mode 100644 docs/rewriter/examples/broadcast_matmul.py create mode 100644 docs/rewriter/examples/erfgelu.py create mode 100644 docs/rewriter/examples/img/broadcast_01.png create mode 100644 docs/rewriter/examples/img/broadcast_02.png create mode 100644 docs/rewriter/examples/img/erfgelu_01.png create mode 100644 docs/rewriter/examples/img/erfgelu_02.png create mode 100644 docs/rewriter/examples/img/erfgelu_03_commute.png create mode 100644 docs/rewriter/examples/img/erfgelu_04_commute.png create mode 100644 docs/rewriter/examples/img/erfgelu_05_commute.png create mode 100644 docs/rewriter/examples/img/erfgelu_06_commute.png create mode 100644 docs/rewriter/examples/img/erfgelu_07_commute.png create mode 100644 docs/rewriter/index.md create mode 100644 docs/rewriter/rewrite_patterns.md diff --git a/docs/index.md b/docs/index.md index e80d6b327..ed1bab77b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -100,6 +100,7 @@ tutorial/index api/index intermediate_representation/index auto_examples/index +rewriter/index articles/index ``` diff --git a/docs/rewriter/examples/broadcast_matmul.py b/docs/rewriter/examples/broadcast_matmul.py new file mode 100644 index 000000000..e64984092 --- /dev/null +++ b/docs/rewriter/examples/broadcast_matmul.py @@ -0,0 +1,198 @@ +"""Onnx Pattern Rewriting with match condition parameter. + +This script shows how to define a rewriting rule based on patterns while +utilizing the match condition parameter. + +First we write a dummy model with a several Reshape nodes and a Matmul node +=================== +""" + +import logging + +import numpy as np +import onnx + +import onnxscript +from onnxscript import FLOAT, ir, opset18, script +from onnxscript.rewriter import _ir_utils, pattern + +logger = logging.getLogger(__name__) + + +@script() +def original_model(A: FLOAT[1, 4, 512, 512], B: FLOAT[1, 4, 512, 64]) -> FLOAT[1, 4, 512, 64]: + # NOTE: Modified from `value_ints` to `value` + shape_a = opset18.Constant(value=[4, 512, 512]) + reshape_a = opset18.Reshape(A, shape_a) + shape_b = opset18.Constant(value=[4, 512, 64]) + reshape_b = opset18.Reshape(B, shape_b) + matmul = opset18.MatMul(reshape_a, reshape_b) + shape_c = opset18.Constant(value=[1, 4, 512, 64]) + result = opset18.Reshape(matmul, shape_c) + return result + + +_model = original_model.to_model_proto() +onnx.checker.check_model(_model) + + +#################################### +# The target pattern +# ===================== + +_op = pattern.onnxop + + +def two_reshapes_matmul_reshape_pattern(input_a, input_b, shape_a, shape_b, shape_c): + reshape_a = _op.Reshape(input_a, shape_a) + reshape_b = _op.Reshape(input_b, shape_b) + matmul = _op.MatMul(reshape_a, reshape_b) + return _op.Reshape(matmul, shape_c) + + +#################################### +# The replacement pattern +# ===================== + + +def matmul_pattern(op, input_a: ir.Value, input_b: ir.Value, **_): + return op.MatMul(input_a, input_b) + + +#################################### +# Write condition to check if we need to replace the pattern +# ===================== + + +def check_if_need_reshape(input_a, input_b, shape_c, **_) -> bool: + """If matmul broadcasting is enough, then we don't need the reshapes. + + To validate this, we need to check the following: + 1. Input shapes check: input_a and input_b should be broadcastable + 2. Output shape check: shape_c should be the same as the output shape from the matmul(input_a, input_b) + + If the above are true, then we don't need the reshapes. + """ + input_a_shape = input_a.shape + input_b_shape = input_b.shape + # TODO: Get a helper func to get const_value + shape_c_value = _ir_utils.propagate_const_value(shape_c) + shape_c = shape_c_value.const_value.numpy() # type: ignore[union-attr] + if shape_c is None: + return False + if not isinstance(shape_c, np.ndarray): + logger.info("Unexpected shape_c value. Expected np.ndarray, got %s", type(shape_c)) + return False + if len(shape_c.shape) != 1: + logger.info( + "Unexpected final shape. The shape of 'shape' value is %s", + shape_c.shape, + ) + return False + shape_c = shape_c.tolist() + + # NOTE: When there is a subset match with a pattern. The MatchResult won't have the shape + # information. So, we need to check if the shape is None and return False. + if input_a_shape is None or input_b_shape is None or shape_c is None: + logger.info("Shape information is not available for the inputs and outputs.") + return False + input_a_shape = list(input_a_shape) + input_b_shape = list(input_b_shape) + + dim_a = len(input_a_shape) + dim_b = len(input_b_shape) + + # 1. Check if input shapes are broadcastable + # 1.a. If the first input is 1-D, check whether + # the dim matches the last second dim of the second input. + mimic_matmul_broadcast_behavior = False + if dim_a < 2: + if input_a_shape[-1] != input_b_shape[-2]: + logger.info("Original shape is not MatMul compatible.") + return False + else: + input_a_shape = [1, *input_a_shape] + dim_a = len(input_a_shape) + mimic_matmul_broadcast_behavior = True + # 1.b. If the second input is 1-D, check whether + # the dim matches the last dim of the first input. + if dim_b < 2: + if input_b_shape[-1] != input_a_shape[-1]: + logger.info("Original shape is not MatMul compatible.") + return False + else: + input_b_shape = [*input_b_shape, 1] + dim_b = len(input_b_shape) + mimic_matmul_broadcast_behavior = True + # 1.c. If both inputs are at least 2-D, check whether + # the last dimension of the first input matches the second + # last dimension of the second input, and shape[:-2] are + # broadcastable. + input_a_shape_except_second_last_dim = input_a_shape[:-2] + [input_a_shape[-1]] + input_b_shape_except_last_dim = input_b_shape[:-1] + broadcast_matmul_output_shape = [input_a_shape[-2], input_b_shape[-1]] + for idx, (dim_from_a, dim_from_b) in enumerate( + zip( + reversed(input_a_shape_except_second_last_dim), + reversed(input_b_shape_except_last_dim), + ) + ): + if dim_from_a not in {1, dim_from_b}: + logger.info("Original shape is not broadcastable.") + return False + elif idx > 0: + broadcast_matmul_output_shape = [ + max(dim_from_a, dim_from_b), + *broadcast_matmul_output_shape, + ] + + # 2. Check if output shape is the same as the output shape from the matmul(input_a, input_b) + # Prepend the broadcast_matmul_output_shape with the longer shape of input + if dim_a > dim_b: + longer_shape = input_a_shape + shorter_shape = input_b_shape + else: + longer_shape = input_b_shape + shorter_shape = input_a_shape + broadcast_matmul_output_shape = ( + longer_shape[: -len(shorter_shape)] + broadcast_matmul_output_shape + ) + if mimic_matmul_broadcast_behavior and dim_b == 2: + broadcast_matmul_output_shape = broadcast_matmul_output_shape[:-1] + if mimic_matmul_broadcast_behavior and dim_a == 2: + broadcast_matmul_output_shape.pop(-2) + if shape_c != broadcast_matmul_output_shape: + logger.info( + "Final output shape is not the same. Expected %s vs actual %s", + shape_c, + broadcast_matmul_output_shape, + ) + return False + + return True + + +#################################### +# Create Rewrite Rule and Apply to Model +# ===================== + + +def apply_rewrite(model): + # Create rewrite rules + two_reshapes_matmul_reshape_rule = pattern.RewriteRule( + two_reshapes_matmul_reshape_pattern, # target pattern + matmul_pattern, # replacement pattern + check_if_need_reshape, # match_condition function + ) + # Create a Rewrite Rule Set + rewrite_rule_set = pattern.RewriteRuleSet([two_reshapes_matmul_reshape_rule]) + # Apply rewrite while passing match_condition + model_with_rewrite = onnxscript.rewriter.rewrite( + model, + pattern_rewrite_rules=rewrite_rule_set, + ) + return model_with_rewrite + + +_model_with_rewrite = apply_rewrite(_model) +onnx.checker.check_model(_model_with_rewrite) diff --git a/docs/rewriter/examples/erfgelu.py b/docs/rewriter/examples/erfgelu.py new file mode 100644 index 000000000..f8723da59 --- /dev/null +++ b/docs/rewriter/examples/erfgelu.py @@ -0,0 +1,161 @@ +"""Onnx Pattern Rewriting. + +This script shows how to define a rewriting rule based on patterns. + +First a dummy model with a GELU activation +=================== +""" + +import math + +import onnx + +import onnxscript +from onnxscript import FLOAT, ir, opset18, script +from onnxscript.rewriter import pattern + + +@script() +def original_model(X: FLOAT[64, 128], Y: FLOAT[64, 128]) -> FLOAT[64, 128]: + input_add = opset18.Add(X, Y) + sqrt2 = opset18.Constant(value_float=math.sqrt(2)) + erf = opset18.Erf(input_add / sqrt2) + add_const = opset18.Constant(value_float=1.0) + plus_one = erf + add_const + mul1 = input_add * plus_one + mul_const = opset18.Constant(value_float=0.5) + result = mul_const * mul1 + return result + + +_model = original_model.to_model_proto() +onnx.checker.check_model(_model) + + +#################################### +# Model demonstrating multiple patterns and variations of GELU activation +# ===================== + + +@script() +def commute_model(X: FLOAT[64, 128], Y: FLOAT[64, 128]) -> FLOAT[64, 128]: + # Create first GELU variant + sqrt2_v1 = opset18.Constant(value_float=math.sqrt(2)) + erf_v1 = opset18.Erf(X / sqrt2_v1) + add_const_v1 = opset18.Constant(value_float=1.0) + plus_one_v1 = erf_v1 + add_const_v1 + mul1_v1 = X * plus_one_v1 + mul_const_v1 = opset18.Constant(value_float=0.5) + gelu1 = mul_const_v1 * mul1_v1 + + # Create second GELU variant + sqrt2_v2 = opset18.Constant(value_float=math.sqrt(2)) + erf_v2 = opset18.Erf(Y / sqrt2_v2) + add_const_v2 = opset18.Constant(value_float=1.0) + plus_one_v2 = erf_v2 + add_const_v2 + mul1_v2 = Y * plus_one_v2 + mul_const_v2 = opset18.Constant(value_float=0.5) + gelu2 = mul1_v2 * mul_const_v2 + + # Add both GELU functions + result = opset18.Add(gelu1, gelu2) + return result + + +commute_model = commute_model.to_model_proto() +onnx.checker.check_model(commute_model) + + +#################################### +# The target pattern +# ===================== + +_op = pattern.onnxop + + +def erf_gelu_pattern(x): + return 0.5 * (x * (_op.Erf(x / math.sqrt(2)) + 1.0)) + + +def erf_gelu_pattern_2(x): + return (x * (_op.Erf(x / math.sqrt(2)) + 1.0)) * 0.5 + + +#################################### +# The replacement pattern +# ===================== + + +def gelu(op, x: ir.Value): + return op.Gelu(x, domain="com.microsoft") + + +#################################### +# Create Rewrite Rule and Apply to Model +# ===================== + + +def apply_rewrite(model): + rule = pattern.RewriteRule( + erf_gelu_pattern, # Target Pattern + gelu, # Replacement Pattern + ) + model_with_rewrite_applied = onnxscript.rewriter.rewrite( + model, + pattern_rewrite_rules=[rule], + ) + return model_with_rewrite_applied + + +def apply_rewrite_with_ruleset(model): + # Create multiple rules + rule1 = pattern.RewriteRule( + erf_gelu_pattern, # Target Pattern + gelu, # Replacement Pattern + ) + rule2 = pattern.RewriteRule( + erf_gelu_pattern_2, # Target Pattern + gelu, # Replacement Pattern + ) + # Create a Rewrite Rule Set with multiple rules. + rewrite_rule_set = pattern.RewriteRuleSet([rule1, rule2]) + # Apply rewrites + model_with_rewrite_applied = onnxscript.rewriter.rewrite( + model, + pattern_rewrite_rules=rewrite_rule_set, + # pattern_rewrite_rules=[rule1, rule2], # Alternative method of passing multiple rules + ) + return model_with_rewrite_applied + + +def apply_rewrite_with_commute(model): + rule = pattern.RewriteRule( + erf_gelu_pattern, # Target Pattern + gelu, # Replacement Pattern + ) + # Create a Rewrite Rule Set with commute=True + rewrite_rule_set = pattern.RewriteRuleSet([rule], commute=True) + # Apply rewrites + model_with_rewrite_applied = onnxscript.rewriter.rewrite( + model, + pattern_rewrite_rules=rewrite_rule_set, + ) + return model_with_rewrite_applied + + +# Rewrite-Simple +model_with_rewrite = apply_rewrite(_model) +onnx.checker.check_model(model_with_rewrite) + +# Rewrite-Single-Patterns +# Incorrect number of rewrites +model_with_single_rewrite_ruleset = apply_rewrite(commute_model) +onnx.checker.check_model(model_with_single_rewrite_ruleset) + +# Rewrite-Multiple-Patterns-RuleSet +model_with_rewrite_ruleset = apply_rewrite_with_ruleset(commute_model) +onnx.checker.check_model(model_with_rewrite_ruleset) + +# Rewrite-Multiple-Patterns-Commute +model_with_rewrite_commute = apply_rewrite_with_commute(commute_model) +onnx.checker.check_model(model_with_rewrite_commute) diff --git a/docs/rewriter/examples/img/broadcast_01.png b/docs/rewriter/examples/img/broadcast_01.png new file mode 100644 index 0000000000000000000000000000000000000000..58df18ff7a6234b456719f9457c18e296287325d GIT binary patch literal 16379 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 ScYuL?6lHl0xf+>wpZ-4>0n=Il literal 0 HcmV?d00001 diff --git a/docs/rewriter/examples/img/broadcast_02.png b/docs/rewriter/examples/img/broadcast_02.png new file mode 100644 index 0000000000000000000000000000000000000000..61601397478ee561ecd0ed3ecabf3137ff24b7b0 GIT binary patch literal 11790 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 CZ?@3@ literal 0 HcmV?d00001 diff --git a/docs/rewriter/examples/img/erfgelu_01.png b/docs/rewriter/examples/img/erfgelu_01.png new file mode 100644 index 0000000000000000000000000000000000000000..53992ce3d383d1b2db821f4131d9b9be12190454 GIT binary patch literal 16282 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 literal 0 HcmV?d00001 diff --git a/docs/rewriter/examples/img/erfgelu_02.png b/docs/rewriter/examples/img/erfgelu_02.png new file mode 100644 index 0000000000000000000000000000000000000000..ab000c95fa7e45869cfac316418297cbcf1955f9 GIT binary patch literal 7956 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 R08X+=G*xv~5K1-?{{fX99B=>t literal 0 HcmV?d00001 diff --git a/docs/rewriter/examples/img/erfgelu_03_commute.png b/docs/rewriter/examples/img/erfgelu_03_commute.png new file mode 100644 index 0000000000000000000000000000000000000000..cf51724e7d44c54417eadaafdb4e976737a29a11 GIT binary patch literal 43255 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 G^uGW*M>=Hy literal 0 HcmV?d00001 diff --git a/docs/rewriter/examples/img/erfgelu_05_commute.png b/docs/rewriter/examples/img/erfgelu_05_commute.png new file mode 100644 index 0000000000000000000000000000000000000000..c31fb9b790f153e037bec44905d13c7e9a95b785 GIT binary patch literal 13807 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 JO|Sm(e*o-2mW==a literal 0 HcmV?d00001 diff --git a/docs/rewriter/examples/img/erfgelu_06_commute.png b/docs/rewriter/examples/img/erfgelu_06_commute.png new file mode 100644 index 0000000000000000000000000000000000000000..e60849b109eb85ddeb1e06fc36d531eecb101fa2 GIT binary patch literal 29391 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 literal 0 HcmV?d00001 diff --git a/docs/rewriter/examples/img/erfgelu_07_commute.png b/docs/rewriter/examples/img/erfgelu_07_commute.png new file mode 100644 index 0000000000000000000000000000000000000000..34176f695cb4955a87019ea640134d4de8951a52 GIT binary patch literal 10449 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 L>8Qe$--P`SxGq6- literal 0 HcmV?d00001 diff --git a/docs/rewriter/index.md b/docs/rewriter/index.md new file mode 100644 index 000000000..3b4e01e14 --- /dev/null +++ b/docs/rewriter/index.md @@ -0,0 +1,5 @@ +# Rewriter Tutorials + +```{toctree} +rewrite_patterns +``` diff --git a/docs/rewriter/rewrite_patterns.md b/docs/rewriter/rewrite_patterns.md new file mode 100644 index 000000000..87a5e31af --- /dev/null +++ b/docs/rewriter/rewrite_patterns.md @@ -0,0 +1,198 @@ +# Pattern-based Rewrite Using Rules + +## Introduction + +The ONNX Rewriter tool provides the user with the functionality to replace certain patterns in an ONNX graph with another pattern based on rewrite rules provided by the user. + +## Usage + +There are three main components needed when rewriting patterns in the graph: + +1. `target_pattern` : Original pattern to match against. This pattern is written as a function using ONNXScript-like operators. +2. `replacement_pattern` : Pattern to replace the original pattern with. This pattern is also written as a function using ONNXScript-like operators. +3. `match_condition` (optional) : Pattern rewrite will occur only if the match condition is satisfied. + +(heading-target-simple)= +## A Simple Example + +An simple example demonstrating the usage of this functionality using the `GELU` activation function: + +`GELU` activation function can be computed using a Gauss Error Function using the given formula: + +
+ +
+ +We will show how we can find a subgraph matching this computation and replace it by a call to the function. + +Firstly, include all the rewriter relevant imports. + +```python + from onnxscript.rewriter import pattern + from onnxscript import ir + + _op = pattern.onnxop +``` + +Then create a target pattern that needs to be replaced using onnxscript operators. + +```{literalinclude} examples/erfgelu.py +:pyobject: erf_gelu_pattern +``` + +After this, create a replacement pattern that consists of the GELU onnxscript operator. + +```{literalinclude} examples/erfgelu.py +:pyobject: gelu +``` +:::{note} +:name: type annotate ir.Value + +The inputs to the replacement pattern are of type `ir.Value`. For detailed usage of `ir.Value` refer to the {py:class}`ir.Value ` class. +::: + + +For this example, we do not require a `match_condition` so that option is skipped for now. Then the rewrite rule is created using the `RewriteRule` function. + +```python + rule = pattern.RewriteRule( + erf_gelu_pattern, # Target Pattern + gelu, # Replacement Pattern + ) +``` + +Now that the rewrite rule has been created, the next step is to apply these pattern-based rewrite rules. The `rewriter.rewrite` call consists of three main components: + +1. `model` : The original model on which the pattern rewrite rules are to be applied. This is of type `onnx.ModelProto`. +2. `function_rewrite_rules` : `(Optional)` This parameter is used to pass rewrite rules based on function names. Steps on how to use this parameter will be covered in a different tutorial. This parameter is of type `Sequence[type[FunctionRewriteRule]]` +3. `pattern_rewrite_rules` : `(Optional)` This parameter is used to pass rewrite rules based on a provided replacement pattern. For the purpose of this tutorial, we will be using only this parameter in conjunction with `model`. This parameter is of either one of these types: + - `Sequence[PatternRewriteRule]` + - `RewriteRuleSet` + +:::{note} +:name: pattern_rewrite_rules input formatting + +`pattern_rewrite_rules` takes a sequence of `PatternRewriteRule` types or a RewriteRuleSet which is also essentially a rule set created using a sequence of `PatternRewriteRule` types, so if only a singular rewrite rule is to be passed, it needs to passed as part of a sequence. For steps on how to create and use Rule-sets, refer to the example in the section [Creating a rule-set with different patterns](#heading-target-commute-ruleset). +::: + +The snippet below below demonstrates how to use the `rewriter.rewrite` call for the rewrite rule created above: + +```{literalinclude} examples/erfgelu.py +:pyobject: apply_rewrite +``` + +The graph (on the left) consists of the target pattern before the rewrite rule is applied. Once the rewrite rule is applied, the graph (on the right) shows that the target pattern has been successfully replaced by a GELU node as intended. + +![target_pattern](examples/img/erfgelu_01.png) ![replacement_pattern](examples/img/erfgelu_02.png) + + +(heading-target-commute)= +## Utilizing `commute` parameter for pattern-matching +Extending the previous [simple example](heading-target-simple), assumming a scenario where we have a graph with the following structure. + +![commute](examples/img/erfgelu_03_commute.png){align=center width=500px} + +In this graph, there exist two node pattern that constitute a `GELU` op. However, there is a subtle difference between the two. Focusing on the parent `Mul` nodes in either patterns, the order of the input values being multiplied is switched. + +![gelu_pattern_1](examples/img/erfgelu_04_commute.png){width=330px align=left} ![gelu_pattern_2](examples/img/erfgelu_05_commute.png){width=330px align=center} + + +If we utilize the same `target_pattern` created for the earlier [simple example](heading-target-simple) (shown below), only one of two `GELU` pattern will be matched. + +```{literalinclude} examples/erfgelu.py +:pyobject: erf_gelu_pattern +``` + +```{image} examples/img/erfgelu_06_commute.png +:alt: The resulting graph after matching. +:width: 400px +:align: center +``` + +Only one of the patterns has been successfully matched and replaced by a `GELU` node. In order to rewrite both the existing patterns in the graph, there are two methods. + +(heading-target-commute-ruleset)= +### 1. Creating a rule-set with different patterns. + +This method requires creating two separate rules and packing them into either a sequence of `PatternRewriteRule`s or a `RewriteRuleSet`. Creating a `RewriteRuleSet` is the preferable option but either can be used. In order to create a `RewriteRuleSet` with multiple rules `rule1` and `rule2` for example: + +```python + from onnxscript.rewriter import pattern + rewrite_rule_set = pattern.RewriteRuleSet(rules=[rule1, rule2]) +``` + +In order to apply this method to the example above, first create the two separate target patterns as follows: + +```{literalinclude} examples/erfgelu.py +:pyobject: erf_gelu_pattern +``` +```{literalinclude} examples/erfgelu.py +:pyobject: erf_gelu_pattern_2 +``` + +Then, create two separate `PatternRewriteRule`s, one for each target pattern. Pack these rules into a `RewriteRuleSet` object and apply rewrites by passing the created `RewriteRuleSet` for the `pattern_rewrite_rules` parameter. + +```{literalinclude} examples/erfgelu.py +:pyobject: apply_rewrite_with_ruleset +``` + + +### 2. Using the `commute` parameter while creating a rule. + +Creating multiple target patterns for similar patterns can be tedious. In order to avoid this, the `commute` parameter can be utilized while creating the `RewriteRuleSet`. Simply set `commute=True` in order to avoid creating multiple target pattern for cases where patterns are different due to commutativity. Multiple rules with the different patterns emerging due to satisfying the commutativity property are automatically packed into a `RewriteRuleSet` object. Then apply rewrites by passing the created `RewriteRuleSet` for the `pattern_rewrite_rules` parameter. + +```{literalinclude} examples/erfgelu.py +:pyobject: apply_rewrite_with_commute +``` + +For the both of the aforementioned methods, the final graph with both rewrites applied should look as follows: + +![commute](examples/img/erfgelu_07_commute.png){align=center width=300px} + +## Using the `match_condition` parameter for pattern-matching + +This section talks about how to utilize the `match_condition` parameter. The `match_condition` parameter checks if the pattern matches the target pattern with certain constraints in consideration. + +Let us consider a model which consists of the following pattern. + +![target_pattern](examples/img/broadcast_01.png){align=center} + +Based on the [ONNX Matmul spec](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MatMul), onnx `Matmul` behaves like `numpy.matmul` and also follows numpy broadcasting. So in this particular pattern if matmul broadcasting is enough, then we don't need the reshapes. To validate this, we need to check the following: + +1. Input shapes check: `input_a` and `input_b` should be broadcastable +2. Output shape check: `shape_c` should be the same as the output shape from the `matmul(input_a, input_b)` + +If the above are true, then we don't need the reshapes and we can eliminate them using a pattern based rewrite. + +First, write a target pattern and replacement pattern in a similar way to the first example. + +```{literalinclude} examples/broadcast_matmul.py +:pyobject: two_reshapes_matmul_reshape_pattern +``` + +```{literalinclude} examples/broadcast_matmul.py +:pyobject: matmul +``` + +:::{note} +:name: omitting inputs in signature + +The target pattern in this case has 5 inputs `input_a`, `input_b`, `shape_a`, `shape_b`, `shape_c`. However, the replacement pattern only utilizes `input_a` and `input_b`. To avoid referencing all the unused parameters in the replacement pattern signature, pass only `input_a` and `input_b` and use `**_` to represent all the unused parameters. + +Similarly for writing the condition checking function, we require only `input_a`, `input_b` and `shape_c`. Use `**_` to represent all the unused parameters in the condition matching function signature. +::: + +In order to validate whether matmul broadcast is sufficient, we write a condition checking function as follows: + +```{literalinclude} examples/broadcast_matmul.py +:pyobject: check_if_need_reshape +``` + +With all the necessary components in place, the pattern rewrite rule with the `match_condition` function is created and then the `rewriter.rewrite` is called to apply the rewrite. + +```{literalinclude} examples/broadcast_matmul.py +:pyobject: apply_rewrite +``` + +The final graph with the applied rewrite looks as follows: +![broadcast_rewrite](examples/img/broadcast_02.png){align=center} diff --git a/docs/test/test_documentation_examples.py b/docs/test/test_documentation_examples.py index 6645882c8..368025ab6 100644 --- a/docs/test/test_documentation_examples.py +++ b/docs/test/test_documentation_examples.py @@ -50,6 +50,7 @@ def test(*relpath): test("..", "..", "docs", "examples") test("..", "..", "docs", "tutorial", "examples") + test("..", "..", "docs", "rewriter", "examples") if __name__ == "__main__": diff --git a/onnxscript/rewriter/broadcast_to_matmul.py b/onnxscript/rewriter/broadcast_to_matmul.py index 8e5ee638e..20071f3a8 100644 --- a/onnxscript/rewriter/broadcast_to_matmul.py +++ b/onnxscript/rewriter/broadcast_to_matmul.py @@ -1,11 +1,9 @@ from __future__ import annotations import logging -from typing import Any import numpy as np -from onnxscript import ir from onnxscript.rewriter import _ir_utils, pattern op = pattern.onnxop @@ -13,7 +11,7 @@ # condition to check if we need to replace the pattern -def check_if_need_reshape(match_bindings: dict[str, ir.Value | Any]) -> bool: +def check_if_need_reshape(input_a, input_b, shape_c, **_) -> bool: """If matmul broadcasting is enough, then we don't need the reshapes. To validate this, we need to check the following: @@ -22,17 +20,14 @@ def check_if_need_reshape(match_bindings: dict[str, ir.Value | Any]) -> bool: If the above are true, then we don't need the reshapes. - Args: - match_bindings: The match binding dictionary from a MatchResult. - Returns: bool: True if we need to replace the pattern, False otherwise. """ - input_a_shape = match_bindings["input_a"].shape - input_b_shape = match_bindings["input_b"].shape + input_a_shape = input_a.shape + input_b_shape = input_b.shape # TODO: Get a helper func to get const_value - shape_c_value = _ir_utils.propagate_const_value(match_bindings["shape_c"]) + shape_c_value = _ir_utils.propagate_const_value(shape_c) shape_c = shape_c_value.const_value.numpy() # type: ignore[union-attr] if shape_c is None: return False diff --git a/onnxscript/rewriter/onnxruntime/instance_to_group_normalization.py b/onnxscript/rewriter/onnxruntime/instance_to_group_normalization.py index e15954d24..1a53d59d3 100644 --- a/onnxscript/rewriter/onnxruntime/instance_to_group_normalization.py +++ b/onnxscript/rewriter/onnxruntime/instance_to_group_normalization.py @@ -1,12 +1,10 @@ from __future__ import annotations import logging -from typing import Any import numpy as np import onnx -from onnxscript import ir from onnxscript.rewriter import _ir_utils, pattern op = pattern.onnxop @@ -16,7 +14,7 @@ logger = logging.getLogger(__name__) -def _check_if_simulated_instance_norm_is_used_impl( +def check_if_simulated_instance_norm_is_used( input_x, adjusted_input_shape, original_input_shape, @@ -24,8 +22,25 @@ def _check_if_simulated_instance_norm_is_used_impl( bias_for_norm, weight_full, bias_full, - **kwargs, + **_, ) -> bool: + """Check if the simulated instance normalization is used. + + In torchlib with opset18, onnx.GroupNorm is using wrong definition, so + we use InstanceNormalization to simulate GroupNormalization. We need to check if there are arguments created to simulation. + If there are, then we need to replace the pattern. If they are not used, then we don't need to replace the pattern. + + To validate this, we need to check the following: + 1. weight_for_norm are all 1 and bias_for_norm are all 0, as they are created for the simulation. + 2. weight_full and bias_full are unsqueezed to be easily broadcastable. + 3. input rank should be 4 + 4. weight_full and bias_full should have ones except first dim. + 5. adjusted_input_shape is a constant tensor of form [0, g, -1] + 6. original_input_shape is the same as input_x shape. + + Returns: + bool: True if the simulated instance normalization is used, False otherwise. + """ weight_for_norm = _ir_utils.propagate_const_value(weight_for_norm) weight_for_norm = _ir_utils.get_numpy_from_ir_value(weight_for_norm) @@ -70,32 +85,6 @@ def _check_if_simulated_instance_norm_is_used_impl( return True -def check_if_simulated_instance_norm_is_used( - match_bindings: dict[str, ir.Value | Any], -) -> bool: - """Check if the simulated instance normalization is used. - - In torchlib with opset18, onnx.GroupNorm is using wrong definition, so - we use InstanceNormalization to simulate GroupNormalization. We need to check if there are arguments created to simulation. - If there are, then we need to replace the pattern. If they are not used, then we don't need to replace the pattern. - - To validate this, we need to check the following: - 1. weight_for_norm are all 1 and bias_for_norm are all 0, as they are created for the simulation. - 2. weight_full and bias_full are unsqueezed to be easily broadcastable. - 3. input rank should be 4 - 4. weight_full and bias_full should have ones except first dim. - 5. adjusted_input_shape is a constant tensor of form [0, g, -1] - 6. original_input_shape is the same as input_x shape. - - Args: - match_bindings: The match binding dictionary from a MatchResult. - - Returns: - bool: True if the simulated instance normalization is used, False otherwise. - """ - return _check_if_simulated_instance_norm_is_used_impl(**match_bindings) - - def instance_simulates_group_normalization_pattern( input_x, adjusted_input_shape, diff --git a/onnxscript/rewriter/onnxruntime/softmax.py b/onnxscript/rewriter/onnxruntime/softmax.py index 682550e18..df868f134 100644 --- a/onnxscript/rewriter/onnxruntime/softmax.py +++ b/onnxscript/rewriter/onnxruntime/softmax.py @@ -1,7 +1,6 @@ from __future__ import annotations import logging -from typing import Any import onnx @@ -32,15 +31,14 @@ def softmax_without_axis(op, input): return op.Softmax(input) -def check_if_fp16_input(match_bindings: dict[str, ir.Value | Any]) -> bool: - input_val = match_bindings.get("input") - if input_val is None: +def check_if_fp16_input(input, **_) -> bool: + if input is None: logger.warning( "Cannot perform softmax upcast removal: " "cannot retrieve match_bindings for 'input' for dtype validation." ) return False - return input_val.dtype == ir.DataType.FLOAT16 + return input.dtype == ir.DataType.FLOAT16 # pylint: disable=pointless-string-statement diff --git a/onnxscript/rewriter/pattern.py b/onnxscript/rewriter/pattern.py index d144502ed..7e38651db 100644 --- a/onnxscript/rewriter/pattern.py +++ b/onnxscript/rewriter/pattern.py @@ -807,10 +807,15 @@ def matches(self, node: ir.Node, model: ir.Model) -> MatchResult: if len(node.outputs) != self._target_num_outputs: return MatchResult.FAIL() match = self._target_node_pattern.matches_node(node, model) + # NOTE: migrating to a simpler interface for match_condition signature. + # Ideally, the caller should pass in match_bindings as **match_bindings. + # This makes it easier to define this as a function with inputs like + # (input_a, input_b, **_) and omit all references to match_bindings. + # **_ refers to all the unused parameters in the match_condition function. if ( self._condition_function is not None and match - and not self._condition_function(match.bindings) + and not self._condition_function(**match.bindings) ): return MatchResult.FAIL() return match diff --git a/onnxscript/rewriter/pattern_test.py b/onnxscript/rewriter/pattern_test.py index a30a2341c..45bdcd6ad 100644 --- a/onnxscript/rewriter/pattern_test.py +++ b/onnxscript/rewriter/pattern_test.py @@ -245,7 +245,7 @@ def identity(op, x, newshape): del newshape # Unused return op.Identity(x) - def _check_for_redundant_reshape(x, newshape): + def check_for_redundant_reshape(x, newshape): oldshape = x.shape newshape = _ir_utils.propagate_const_value(newshape) newshape = _ir_utils.get_numpy_from_ir_value(newshape) @@ -257,9 +257,6 @@ def _check_for_redundant_reshape(x, newshape): return False return all(not (d1 != d2 and d2 != -1) for d1, d2 in zip(oldshape, newshape)) # pylint: disable=consider-using-in - def check_for_redundant_reshape(bindings): - return _check_for_redundant_reshape(**bindings) - rule = pattern.RewriteRule(reshape, identity, check_for_redundant_reshape) model_proto = onnx.parser.parse_model(