(
gm: GraphModule,
pattern: Union[Callable, Graph, GraphModule],
replacement: Union[Callable, Graph, GraphModule],
match_filters: Optional[List[Callable[["InternalMatch", Graph, Graph], bool]]] = None, # type: ignore[name-defined]
ignore_literals: bool = False,
)
| 219 | |
| 220 | |
| 221 | def _replace_pattern( |
| 222 | gm: GraphModule, |
| 223 | pattern: Union[Callable, Graph, GraphModule], |
| 224 | replacement: Union[Callable, Graph, GraphModule], |
| 225 | match_filters: Optional[List[Callable[["InternalMatch", Graph, Graph], bool]]] = None, # type: ignore[name-defined] |
| 226 | ignore_literals: bool = False, |
| 227 | ) -> List[ReplacedPatterns]: |
| 228 | |
| 229 | from torch.fx.passes.utils.matcher_utils import SubgraphMatcher, InternalMatch |
| 230 | |
| 231 | if match_filters is None: |
| 232 | match_filters = [] |
| 233 | |
| 234 | # Get the graphs for `gm`, `pattern`, `replacement` |
| 235 | original_graph: Graph = gm.graph |
| 236 | |
| 237 | if isinstance(pattern, GraphModule): |
| 238 | pattern_graph = pattern.graph |
| 239 | elif isinstance(pattern, Graph): |
| 240 | pattern_graph = pattern |
| 241 | else: |
| 242 | pattern_graph = symbolic_trace(pattern).graph |
| 243 | |
| 244 | if isinstance(replacement, GraphModule): |
| 245 | replacement_graph = replacement.graph |
| 246 | elif isinstance(replacement, Graph): |
| 247 | replacement_graph = replacement |
| 248 | else: |
| 249 | replacement_graph = symbolic_trace(replacement).graph |
| 250 | |
| 251 | matcher = SubgraphMatcher(pattern_graph, match_output=False, match_placeholder=False, |
| 252 | remove_overlapping_matches=True, ignore_literals=ignore_literals) |
| 253 | _matches: List[InternalMatch] = matcher.match(original_graph) |
| 254 | |
| 255 | # Filter out matches that don't match the filter |
| 256 | _matches = [ |
| 257 | m for m in _matches |
| 258 | if all(match_filter(m, original_graph, pattern_graph) |
| 259 | for match_filter in match_filters) |
| 260 | ] |
| 261 | |
| 262 | replacement_placeholders = [n for n in replacement_graph.nodes if n.op == "placeholder"] |
| 263 | |
| 264 | # As we progressively replace nodes, we'll need to keep track of how the match results should change |
| 265 | match_changed_node: Dict[Node, Node] = {} |
| 266 | |
| 267 | match_and_replacements = [] |
| 268 | for match in _matches: |
| 269 | |
| 270 | # Build connecting between replacement graph's input and original graph input producer node |
| 271 | |
| 272 | # Initialize `val_map` with mappings from placeholder nodes in |
| 273 | # `replacement` to their corresponding node in `original_graph` |
| 274 | assert len(match.placeholder_nodes) == len(replacement_placeholders) |
| 275 | val_map: Dict[Node, Node] = {} |
| 276 | for rn, gn in zip(replacement_placeholders, match.placeholder_nodes): |
| 277 | if isinstance(gn, Node): |
| 278 | val_map[rn] = match_changed_node.get(gn, gn) |
no test coverage detected
searching dependent graphs…