Source code for experimental_experiment.xoptim.patterns_ort.activation

import inspect
from typing import List, Optional
from onnx import NodeProto
from ..patterns_api import MatchResult, PatternOptimization, EasyPatternOptimization
from ..patterns.onnx_functions import GeluPattern


[docs] class BiasGeluPattern(PatternOptimization): """ Replaces by ``y = BiasGelu(x, B)``:: t = x + B y = t ( Erf(1 / t) + 1) Model with nodes to be fused: .. gdot:: :script: DOT-SECTION :process: from experimental_experiment.doc import to_dot import numpy as np import ml_dtypes import onnx import onnx.helper as oh import onnx.numpy_helper as onh opset_imports = [ oh.make_opsetid("", 18), oh.make_opsetid("com.microsoft", 1), ] inputs = [] outputs = [] nodes = [] initializers = [] sparse_initializers = [] functions = [] inputs.append(oh.make_tensor_value_info("B", onnx.TensorProto.FLOAT, shape=(8,))) inputs.append( oh.make_tensor_value_info("X", onnx.TensorProto.FLOAT, shape=(2, 2, 4, 8)) ) nodes.append( oh.make_node( "Constant", [], ["B"], value=onh.from_array( np.array( [ 0.10000000149011612, 0.20000000298023224, 0.30000001192092896, 0.4000000059604645, 0.5, 0.6000000238418579, -0.4000000059604645, -0.10000000149011612, ], dtype=np.float32, ), name="value", ), ) ) nodes.append( oh.make_node( "Constant", [], ["sq2"], value=onh.from_array(np.array([1.4140625], dtype=np.float32), name="value"), ) ) nodes.append( oh.make_node( "Constant", [], ["one"], value=onh.from_array(np.array([1.0], dtype=np.float32), name="value"), ) ) nodes.append( oh.make_node( "Constant", [], ["half"], value=onh.from_array(np.array([0.5], dtype=np.float32), name="value"), ) ) nodes.append(oh.make_node("Add", ["X", "B"], ["xb"])) nodes.append(oh.make_node("Div", ["xb", "sq2"], ["xbinv"])) nodes.append(oh.make_node("Erf", ["xbinv"], ["xerf"])) nodes.append(oh.make_node("Add", ["xerf", "one"], ["xerf1"])) nodes.append(oh.make_node("Mul", ["xb", "xerf1"], ["y2"])) nodes.append(oh.make_node("Mul", ["y2", "half"], ["Y"])) outputs.append( oh.make_tensor_value_info("Y", onnx.TensorProto.FLOAT, shape=(2, 2, 4, 8)) ) graph = oh.make_graph( nodes, "pattern", inputs, outputs, initializers, sparse_initializer=sparse_initializers, ) model = oh.make_model(graph, functions=functions, opset_imports=opset_imports) print("DOT-SECTION", to_dot(model)) Outcome of the fusion: .. gdot:: :script: DOT-SECTION :process: from experimental_experiment.doc import to_dot import numpy as np import ml_dtypes import onnx import onnx.helper as oh import onnx.numpy_helper as onh opset_imports = [ oh.make_opsetid("", 18), oh.make_opsetid("com.microsoft", 1), ] inputs = [] outputs = [] nodes = [] initializers = [] sparse_initializers = [] functions = [] inputs.append(oh.make_tensor_value_info("B", onnx.TensorProto.FLOAT, shape=(8,))) inputs.append( oh.make_tensor_value_info("X", onnx.TensorProto.FLOAT, shape=(2, 2, 4, 8)) ) nodes.append(oh.make_node("BiasGelu", ["X", "B"], ["Y"], domain="com.microsoft")) outputs.append( oh.make_tensor_value_info("Y", onnx.TensorProto.FLOAT, shape=(2, 2, 4, 8)) ) graph = oh.make_graph( nodes, "pattern", inputs, outputs, initializers, sparse_initializer=sparse_initializers, ) model = oh.make_model(graph, functions=functions, opset_imports=opset_imports) print("DOT-SECTION", to_dot(model)) """
[docs] def match( self, g: "GraphBuilderPatternOptimization", # noqa: F821 node: NodeProto, matched: List[MatchResult], ) -> Optional[MatchResult]: if node.op_type != "Erf" or node.domain != "": return self.none() if g.is_used_more_than_once(node.input[0]): return self.none(node, inspect.currentframe().f_lineno) div = g.node_before(node.input[0]) if ( not g.is_constant_scalar(div.input[1]) or g.get_constant_scalar(div.input[1]) != 1.4140625 ): return self.none(node, inspect.currentframe().f_lineno) add = g.node_before(div.input[0]) if add.op_type != "Add" or add.domain != "": return self.none(node, inspect.currentframe().f_lineno) if not g.is_constant(add.input[1]): return self.none(node, inspect.currentframe().f_lineno) add1_nexts = g.next_nodes(add.output[0]) if len(add1_nexts) != 2: return self.none(node, inspect.currentframe().f_lineno) add_next = g.next_nodes(node.output[0]) if len(add_next) != 1: return self.none(node, inspect.currentframe().f_lineno) add_1 = add_next[0] if add_1.op_type != "Add" or add_1.domain != "": return self.none(node, inspect.currentframe().f_lineno) if not g.is_constant_scalar(add_1.input[1]) or g.get_constant_scalar(add_1.input[1]) != 1: return self.none(node, inspect.currentframe().f_lineno) muls = g.next_nodes(add_1.output[0]) if len(muls) != 1: return self.none(node, inspect.currentframe().f_lineno) mul = muls[0] if mul.op_type != "Mul" or mul.domain != "": return self.none(node, inspect.currentframe().f_lineno) if set(mul.input) != {add.output[0], add_1.output[0]}: return self.none(node, inspect.currentframe().f_lineno) halfs = g.next_nodes(mul.output[0]) if len(halfs) != 1: return self.none(node, inspect.currentframe().f_lineno) half = halfs[0] if half.op_type != "Mul" or half.domain != "": return self.none(node, inspect.currentframe().f_lineno) index = 1 if half.input[0] == mul.output[0] else 0 if ( not g.is_constant_scalar(half.input[index]) or g.get_constant_scalar(half.input[index]) != 0.5 ): return self.none(node, inspect.currentframe().f_lineno) return MatchResult(self, [add, div, node, add_1, mul, half], self.apply, insert_at=node)
[docs] def apply( self, g: "GraphBuilder", # noqa: F821 add_node: NodeProto, div_node: NodeProto, erf_node: NodeProto, add_1_node: NodeProto, mul_node: NodeProto, half_node: NodeProto, ) -> List[NodeProto]: return [ g.make_node( "BiasGelu", add_node.input, half_node.output, domain="com.microsoft", doc_string=erf_node.doc_string, name=f"{self.__class__.__name__}--{erf_node.name}", ) ]
[docs] class GeluOrtPattern(GeluPattern): """ Detects the decomposed version of Gelu with Tanh .. math:: y = \\frac{x}{2} \\left(1 + \\tanh\\left(\\sqrt{\\frac{2}{\\pi}} (x + 0.044715 * x^3)\\right)\\right) Model with nodes to be fused: .. gdot:: :script: DOT-SECTION :process: from experimental_experiment.doc import to_dot import numpy as np import ml_dtypes import onnx import onnx.helper as oh import onnx.numpy_helper as onh opset_imports = [ oh.make_opsetid("", 18), oh.make_opsetid("com.microsoft", 1), ] inputs = [] outputs = [] nodes = [] initializers = [] sparse_initializers = [] functions = [] inputs.append( oh.make_tensor_value_info( "linear_73", onnx.TensorProto.FLOAT16, shape=(4, 512, 128) ) ) nodes.append( oh.make_node( "Constant", [], ["init10_s1_63"], value=onh.from_array(np.array([3.0], dtype=np.float16), name="value"), ) ) nodes.append( oh.make_node( "Constant", [], ["init10_s_89"], value=onh.from_array( np.array(0.044708251953125, dtype=np.float16), name="value" ), ) ) nodes.append( oh.make_node( "Constant", [], ["init10_s_90"], value=onh.from_array(np.array(0.7978515625, dtype=np.float16), name="value"), ) ) nodes.append( oh.make_node( "Constant", [], ["init10_s_91"], value=onh.from_array(np.array(1.0, dtype=np.float16), name="value"), ) ) nodes.append( oh.make_node( "Constant", [], ["init10_s_88"], value=onh.from_array(np.array(0.5, dtype=np.float16), name="value"), ) ) nodes.append(oh.make_node("Pow", ["linear_73", "init10_s1_63"], ["pow_13"])) nodes.append(oh.make_node("Mul", ["pow_13", "init10_s_89"], ["_onx_mul064"])) nodes.append(oh.make_node("Add", ["linear_73", "_onx_mul064"], ["add_62"])) nodes.append(oh.make_node("Mul", ["add_62", "init10_s_90"], ["_onx_mul065"])) nodes.append(oh.make_node("Tanh", ["_onx_mul065"], ["tanh_12"])) nodes.append(oh.make_node("Add", ["tanh_12", "init10_s_91"], ["add_63"])) nodes.append(oh.make_node("Mul", ["linear_73", "init10_s_88"], ["_onx_mul063"])) nodes.append(oh.make_node("Mul", ["_onx_mul063", "add_63"], ["mul_52"])) outputs.append( oh.make_tensor_value_info("mul_52", onnx.TensorProto.FLOAT16, shape=(4, 512, 128)) ) graph = oh.make_graph( nodes, "pattern", inputs, outputs, initializers, sparse_initializer=sparse_initializers, ) model = oh.make_model(graph, functions=functions, opset_imports=opset_imports) print("DOT-SECTION", to_dot(model)) Outcome of the fusion: .. gdot:: :script: DOT-SECTION :process: from experimental_experiment.doc import to_dot import numpy as np import ml_dtypes import onnx import onnx.helper as oh import onnx.numpy_helper as onh opset_imports = [ oh.make_opsetid("", 18), oh.make_opsetid("com.microsoft", 1), ] inputs = [] outputs = [] nodes = [] initializers = [] sparse_initializers = [] functions = [] inputs.append( oh.make_tensor_value_info( "linear_73", onnx.TensorProto.FLOAT16, shape=(4, 512, 128) ) ) nodes.append( oh.make_node( "Gelu", ["linear_73"], ["mul_52"], domain="com.microsoft", approximate="tanh" ) ) outputs.append( oh.make_tensor_value_info("mul_52", onnx.TensorProto.FLOAT16, shape=(4, 512, 128)) ) graph = oh.make_graph( nodes, "pattern", inputs, outputs, initializers, sparse_initializer=sparse_initializers, ) model = oh.make_model(graph, functions=functions, opset_imports=opset_imports) print("DOT-SECTION", to_dot(model)) """ def __init__( self, verbose: int = 0, priority: int = 0, min_opset: int = 1, domain: str = "com.microsoft", ): super().__init__(verbose, priority, min_opset=min_opset) self.domain = domain
[docs] class GeluErfPattern(EasyPatternOptimization): """ Detects the decomposed version of Gelu with Erf. Model with nodes to be fused: .. gdot:: :script: DOT-SECTION :process: from experimental_experiment.doc import to_dot import numpy as np import ml_dtypes import onnx import onnx.helper as oh import onnx.numpy_helper as onh opset_imports = [ oh.make_opsetid("", 18), oh.make_opsetid("com.microsoft", 1), ] inputs = [] outputs = [] nodes = [] initializers = [] sparse_initializers = [] functions = [] inputs.append( oh.make_tensor_value_info("X", onnx.TensorProto.FLOAT, shape=(2, 2, 4, 8)) ) nodes.append( oh.make_node( "Constant", [], ["sq2"], value=onh.from_array(np.array([1.4140625], dtype=np.float32), name="value"), ) ) nodes.append( oh.make_node( "Constant", [], ["one"], value=onh.from_array(np.array([1.0], dtype=np.float32), name="value"), ) ) nodes.append( oh.make_node( "Constant", [], ["half"], value=onh.from_array(np.array([0.5], dtype=np.float32), name="value"), ) ) nodes.append(oh.make_node("Div", ["X", "sq2"], ["xd"])) nodes.append(oh.make_node("Erf", ["xd"], ["exd"])) nodes.append(oh.make_node("Add", ["exd", "one"], ["aexd"])) nodes.append(oh.make_node("Mul", ["X", "aexd"], ["y2"])) nodes.append(oh.make_node("Mul", ["half", "y2"], ["Y"])) outputs.append( oh.make_tensor_value_info("Y", onnx.TensorProto.FLOAT, shape=(2, 2, 4, 8)) ) graph = oh.make_graph( nodes, "pattern", inputs, outputs, initializers, sparse_initializer=sparse_initializers, ) model = oh.make_model(graph, functions=functions, opset_imports=opset_imports) print("DOT-SECTION", to_dot(model)) Outcome of the fusion: .. gdot:: :script: DOT-SECTION :process: from experimental_experiment.doc import to_dot import numpy as np import ml_dtypes import onnx import onnx.helper as oh import onnx.numpy_helper as onh opset_imports = [ oh.make_opsetid("", 18), oh.make_opsetid("com.microsoft", 1), ] inputs = [] outputs = [] nodes = [] initializers = [] sparse_initializers = [] functions = [] inputs.append( oh.make_tensor_value_info("X", onnx.TensorProto.FLOAT, shape=(2, 2, 4, 8)) ) nodes.append(oh.make_node("Gelu", ["X"], ["Y"], domain="com.microsoft")) outputs.append( oh.make_tensor_value_info("Y", onnx.TensorProto.FLOAT, shape=(2, 2, 4, 8)) ) graph = oh.make_graph( nodes, "pattern", inputs, outputs, initializers, sparse_initializer=sparse_initializers, ) model = oh.make_model(graph, functions=functions, opset_imports=opset_imports) print("DOT-SECTION", to_dot(model)) """ def __init__(self, verbose: int = 0, priority: int = 0, min_opset: int = 1): super().__init__(verbose, priority, min_opset=min_opset)
[docs] def match_pattern(self, g: "GraphBuilder", x, cst2, one, c05): # noqa: F821 xd = g.op.Div(x, cst2) # 1.4140625 exd = g.op.Erf(xd) aexd = g.op.Add(exd, one) # 1 mul = g.op.Mul(x, aexd) return g.op.Mul(c05, mul) # 0.5
[docs] def apply_pattern(self, g: "GraphBuilder", x, cst2, one, c05): # noqa: F821 return g.anyop.Gelu(x, domain="com.microsoft")
[docs] def validate_mapping( self, g: "GraphBuilderPatternOptimization", # noqa: F821 deleted_nodes: List[NodeProto], pattern_nodes: Optional[List[NodeProto]] = None, ) -> bool: assert len(deleted_nodes) == 5, f"Unexpected pattern length {len(deleted_nodes)}" assert deleted_nodes[0].op_type == "Div", f"-- {deleted_nodes[0]}" cst2 = deleted_nodes[0].input[1] assert deleted_nodes[2].op_type == "Add", f"-- {deleted_nodes[2]}" one = deleted_nodes[2].input[1] assert deleted_nodes[4].op_type == "Mul", f"-- {deleted_nodes[4]}" c05 = deleted_nodes[4].input[0] node = deleted_nodes[1] if not g.is_constant_scalar(cst2) or g.get_constant_scalar(cst2) != 1.4140625: return self.none(node, inspect.currentframe().f_lineno) if not g.is_constant_scalar(one) or g.get_constant_scalar(one) != 1: return self.none(node, inspect.currentframe().f_lineno) if not g.is_constant_scalar(c05) or g.get_constant_scalar(c05) != 0.5: return self.none(node, inspect.currentframe().f_lineno) return True
[docs] class FastGeluPattern(PatternOptimization): """ Replaces Gelu by FastGelu. Model with nodes to be fused: .. gdot:: :script: DOT-SECTION :process: from experimental_experiment.doc import to_dot import numpy as np import ml_dtypes import onnx import onnx.helper as oh import onnx.numpy_helper as onh opset_imports = [ oh.make_opsetid("", 20), oh.make_opsetid("com.microsoft", 1), ] inputs = [] outputs = [] nodes = [] initializers = [] sparse_initializers = [] functions = [] inputs.append( oh.make_tensor_value_info( "linear_65", onnx.TensorProto.FLOAT16, shape=(4, 512, 16384) ) ) nodes.append(oh.make_node("Gelu", ["linear_65"], ["mul_44"], approximate="tanh")) outputs.append( oh.make_tensor_value_info("mul_44", onnx.TensorProto.FLOAT16, shape=(4, 512, 16384)) ) graph = oh.make_graph( nodes, "pattern", inputs, outputs, initializers, sparse_initializer=sparse_initializers, ) model = oh.make_model(graph, functions=functions, opset_imports=opset_imports) print("DOT-SECTION", to_dot(model)) Outcome of the fusion: .. gdot:: :script: DOT-SECTION :process: from experimental_experiment.doc import to_dot import numpy as np import ml_dtypes import onnx import onnx.helper as oh import onnx.numpy_helper as onh opset_imports = [ oh.make_opsetid("", 20), oh.make_opsetid("com.microsoft", 1), ] inputs = [] outputs = [] nodes = [] initializers = [] sparse_initializers = [] functions = [] inputs.append( oh.make_tensor_value_info( "linear_65", onnx.TensorProto.FLOAT16, shape=(4, 512, 16384) ) ) nodes.append( oh.make_node("FastGelu", ["linear_65"], ["mul_44"], domain="com.microsoft") ) outputs.append( oh.make_tensor_value_info("mul_44", onnx.TensorProto.FLOAT16, shape=(4, 512, 16384)) ) graph = oh.make_graph( nodes, "pattern", inputs, outputs, initializers, sparse_initializer=sparse_initializers, ) model = oh.make_model(graph, functions=functions, opset_imports=opset_imports) print("DOT-SECTION", to_dot(model)) """
[docs] def match( self, g: "GraphBuilderPatternOptimization", # noqa: F821 node: NodeProto, matched: List[MatchResult], ) -> Optional[MatchResult]: if node.op_type != "Gelu" or node.domain not in ("", "com.microsoft"): return self.none() return MatchResult(self, [node], self.apply, insert_at=node)
[docs] def apply( self, g: "GraphBuilder", # noqa: F821 gelu_node: NodeProto, ) -> List[NodeProto]: return [ g.make_node( "FastGelu", gelu_node.input, gelu_node.output, domain="com.microsoft", doc_string=gelu_node.doc_string, name=f"{self.__class__.__name__}--{gelu_node.name}", ) ]
[docs] class BiasSoftmaxPattern(PatternOptimization): """ Replaces Softmax(Add(x,y), axis=-1) by BiasSoftmax(x,y,axis=-1) Model with nodes to be fused: .. gdot:: :script: DOT-SECTION :process: from experimental_experiment.doc import to_dot import numpy as np import ml_dtypes import onnx import onnx.helper as oh import onnx.numpy_helper as onh opset_imports = [ oh.make_opsetid("", 18), oh.make_opsetid("com.microsoft", 1), ] inputs = [] outputs = [] nodes = [] initializers = [] sparse_initializers = [] functions = [] inputs.append( oh.make_tensor_value_info("X", onnx.TensorProto.FLOAT, shape=(16, 8, 4, 8)) ) inputs.append( oh.make_tensor_value_info("Y", onnx.TensorProto.FLOAT, shape=(16, 1, 4, 8)) ) nodes.append(oh.make_node("Add", ["X", "Y"], ["xy"])) nodes.append(oh.make_node("Softmax", ["xy"], ["Z"], axis=-1)) outputs.append( oh.make_tensor_value_info("Z", onnx.TensorProto.FLOAT, shape=(16, 8, 4, 8)) ) graph = oh.make_graph( nodes, "pattern", inputs, outputs, initializers, sparse_initializer=sparse_initializers, ) model = oh.make_model(graph, functions=functions, opset_imports=opset_imports) print("DOT-SECTION", to_dot(model)) Outcome of the fusion: .. gdot:: :script: DOT-SECTION :process: from experimental_experiment.doc import to_dot import numpy as np import ml_dtypes import onnx import onnx.helper as oh import onnx.numpy_helper as onh opset_imports = [ oh.make_opsetid("", 18), oh.make_opsetid("com.microsoft", 1), ] inputs = [] outputs = [] nodes = [] initializers = [] sparse_initializers = [] functions = [] inputs.append( oh.make_tensor_value_info("X", onnx.TensorProto.FLOAT, shape=(16, 8, 4, 8)) ) inputs.append( oh.make_tensor_value_info("Y", onnx.TensorProto.FLOAT, shape=(16, 1, 4, 8)) ) nodes.append( oh.make_node( "BiasSoftmax", ["X", "Y"], ["Z"], domain="com.microsoft", axis=-1, is_inner_broadcast=0, ) ) outputs.append( oh.make_tensor_value_info("Z", onnx.TensorProto.FLOAT, shape=(16, 8, 4, 8)) ) graph = oh.make_graph( nodes, "pattern", inputs, outputs, initializers, sparse_initializer=sparse_initializers, ) model = oh.make_model(graph, functions=functions, opset_imports=opset_imports) print("DOT-SECTION", to_dot(model)) """
[docs] def match( self, g: "GraphBuilderPatternOptimization", # noqa: F821 node: NodeProto, matched: List[MatchResult], ) -> Optional[MatchResult]: if not g.has_processor("CUDA"): return self.none() if node.op_type != "Softmax" or node.domain != "": return self.none() if g.is_used_more_than_once(node.input[0]): return self.none(node, inspect.currentframe().f_lineno) atts = g.get_attributes_with_default(node, axis=-1) if atts["axis"] != -1: return self.none(node, inspect.currentframe().f_lineno) before = g.node_before(node.input[0]) if before is None or before.op_type != "Add": return self.none(node, inspect.currentframe().f_lineno) return MatchResult(self, [before, node], self.apply, insert_at=node)
[docs] def apply( self, g: "GraphBuilder", # noqa: F821 add_node: NodeProto, softmax_node: NodeProto, ) -> List[NodeProto]: return [ g.make_node( "BiasSoftmax", add_node.input, softmax_node.output, axis=-1, is_inner_broadcast=0, domain="com.microsoft", doc_string=softmax_node.doc_string, name=f"{self.__class__.__name__}--{softmax_node.name}", ) ]
[docs] class QuickGeluPattern(PatternOptimization): """ Replaces Mul(x, Sigmoid(x)) by QuickGelu(x, alpha=1) Model with nodes to be fused: .. gdot:: :script: DOT-SECTION :process: from experimental_experiment.doc import to_dot import numpy as np import ml_dtypes import onnx import onnx.helper as oh import onnx.numpy_helper as onh opset_imports = [ oh.make_opsetid("", 18), oh.make_opsetid("com.microsoft", 1), ] inputs = [] outputs = [] nodes = [] initializers = [] sparse_initializers = [] functions = [] inputs.append( oh.make_tensor_value_info("X", onnx.TensorProto.FLOAT, shape=(1, 8, 6, 6)) ) nodes.append(oh.make_node("Sigmoid", ["X"], ["S"])) nodes.append(oh.make_node("Mul", ["X", "S"], ["Y"])) outputs.append( oh.make_tensor_value_info("Y", onnx.TensorProto.FLOAT, shape=(1, 8, 6, 6)) ) graph = oh.make_graph( nodes, "pattern", inputs, outputs, initializers, sparse_initializer=sparse_initializers, ) model = oh.make_model(graph, functions=functions, opset_imports=opset_imports) print("DOT-SECTION", to_dot(model)) Outcome of the fusion: .. gdot:: :script: DOT-SECTION :process: from experimental_experiment.doc import to_dot import numpy as np import ml_dtypes import onnx import onnx.helper as oh import onnx.numpy_helper as onh opset_imports = [ oh.make_opsetid("", 18), oh.make_opsetid("com.microsoft", 1), ] inputs = [] outputs = [] nodes = [] initializers = [] sparse_initializers = [] functions = [] inputs.append( oh.make_tensor_value_info("X", onnx.TensorProto.FLOAT, shape=(1, 8, 6, 6)) ) nodes.append( oh.make_node("QuickGelu", ["X"], ["Y"], domain="com.microsoft", alpha=1.0) ) outputs.append( oh.make_tensor_value_info("Y", onnx.TensorProto.FLOAT, shape=(1, 8, 6, 6)) ) graph = oh.make_graph( nodes, "pattern", inputs, outputs, initializers, sparse_initializer=sparse_initializers, ) model = oh.make_model(graph, functions=functions, opset_imports=opset_imports) print("DOT-SECTION", to_dot(model)) """
[docs] def match( self, g: "GraphBuilderPatternOptimization", # noqa: F821 node: NodeProto, matched: List[MatchResult], ) -> Optional[MatchResult]: if node.op_type != "Sigmoid" or node.domain != "": return self.none() if g.is_used_more_than_once(node.output[0]): return self.none(node, inspect.currentframe().f_lineno) after = g.next_nodes(node.output[0]) if not after or after[0].op_type != "Mul": return self.none(node, inspect.currentframe().f_lineno) mul_node = after[0] if node.input[0] not in mul_node.input: return self.none(node, inspect.currentframe().f_lineno) return MatchResult(self, [node, mul_node], self.apply, insert_at=node)
[docs] def apply( self, g: "GraphBuilder", # noqa: F821 sigmoid: NodeProto, mul_node: NodeProto, ) -> List[NodeProto]: return [ g.make_node( "QuickGelu", sigmoid.input, mul_node.output, alpha=1.0, domain="com.microsoft", doc_string=sigmoid.doc_string, name=f"{self.__class__.__name__}--{sigmoid.name}", ) ]