• 文档 >
  • 模块代码 >
  • torch >
  • torch.fx.subgraph_rewriter
快捷键

torch.fx.subgraph_rewriter 源代码

导入 复制
from dataclasses 导入 数据类
from 打字 导入 任何, 可调用, 命名元组, 可选, 类型检查, 联合

导入 火炬

from 兼容性 导入 兼容性
from 符号追踪 导入 符号化跟踪
from .graph 导入 图
from .图模块 导入 图模块
from .节点 导入 节点


如果 类型检查:
    from .passes.utils.matcher_with_name_node_map_utils 导入 内部匹配

全部 = [
    匹配,
    替换模式,
    "用过滤器替换模式",
    "替换后的模式",
]


@compatibility(兼容旧版本=是)
类 匹配(命名元组):
    匹配到的节点
    锚点: 节点
    # 将模式子图中的节点映射到更大图中
    节点映射: 字典[节点, 节点]


@compatibility(兼容旧版本=错误)
@dataclass
类 替换模式:
    # 匹配的节点来源
    锚点: 节点
    # 将模式子图中的节点映射到更大图中
    节点映射: 字典[节点, 节点]
    # 列出添加到图中的节点
    替换列表: 列表[节点]


def 替换属性(gm: GraphModule, 替换: 火炬.神经网络.模块) 翻译 无:
    gm.删除所有未使用的子模块()

    如果 isinstance(替换, GraphModule):
        替换.graph.检查()

    def 尝试获取属性(gm: 火炬.神经网络.模块, 目标: 字符串) 翻译 可选[任何]
        模块路径, _, 属性名称 = 目标.分割(“。”)
        尝试:
            模块: 火炬.神经网络.模块 = gm.获取子模块(模块路径)
        除了 属性错误:
            返回 无
        属性 = getattr(模块, 属性名称, 无)
        返回 属性

    为 节点 在 gm.graph.节点:
        如果 节点.操作符 == "调用模块" 或者 节点.操作符 == 获取属性:
            属性 = 尝试获取属性(gm, 节点.目标)
            替换属性 = try_get_attr(替换, 节点.目标)

            # CASE 1: 此目标已作为属性存在于我们的
            # 结果 GraphModule 中。无论它是否存在于
            # `replacement`中,现有的子模块优先。
            如果 gm_attr is 不是 无:
                continue

            # CASE 2: 目标作为 `replacement` 中的一个属性存在
            # 仅此,因此我们需要将其复制过来。
            如果...否则 replacement_attr is 不是 无:
                新属性 = 复制.深拷贝(替换属性)
                如果 isinstance(替换属性, 火炬.神经网络.模块):
                    gm.添加子模块(节点.目标, 新属性)
                else:
                    setattr(gm, 节点.目标, 新属性)

            # CASE 3:目标在 `gm` 中不存在作为属性
            # 或者 `replacement`
            else:
                提升 运行时错误(
                    尝试在子图重写期间创建一个 "',
                    节点.操作,
                    '" 节点
                    f的目标{节点.目标},但 "
                    "引用的属性不存在于替换的 GraphModule 中"
                    "存在",
                )

    gm.graph.检查()


[文档]@compatibility(兼容旧版本=是) def 替换模式( gm: GraphModule, 模式: 联合[可调用, GraphModule] 替换: 联合[可调用, GraphModule] ) 翻译 列表[匹配] "" 匹配所有可能的非重叠操作符及其 图模块的图中数据依赖(`pattern`) (``gm``),然后将这些匹配的子图替换为另一个 子图(`replacement`)。 参数: ``gm``: 包装图以进行操作的 GraphModule ``pattern``: 在 ``gm`` 中匹配以进行替换的子图 ``replacement``: 用以替换 ``pattern`` 的子图 返回: List[Match]: 代表匹配位置的 ``Match`` 对象列表 在原始图中匹配到 ``pattern`` 的地方。列表为空,如果没有匹配项。 如果没有匹配项,则为空。``Match`` 定义为: .. 代码块 :: python class Match(NamedTuple): # 节点来源 anchor: 节点 # 将模式子图中的节点映射到更大图中的节点 nodes_map: Dict[Node, Node] 示例: .. 代码块 :: python 导入 torch 从 torch.fx 导入 symbolic_trace 和 subgraph_rewriter class M(torch.nn.Module): def __init__(self) -> None: super().__init__() def forward(self, x, w1, w2): m1 = torch.cat([w1, w2]).sum() m2 = torch.cat([w1, w2]).sum() return x + torch.max(m1) + torch.max(m2) def pattern(w1, w2): return torch.cat([w1, w2]) def replacement(w1, w2): return torch.stack([w1, w2]) traced_module = symbolic_trace(M()) subgraph_rewriter 替换模式(traced_module, 模式, 替换) 上述代码将首先匹配“forward”中的“pattern” ``traced_module``的方法。模式匹配基于 使用定义关系,而不是节点名称。例如,如果您有 在 `pattern` 中,你可以匹配 `p = torch.cat([a, b])` 在原始 `forward` 函数中,`m = torch.cat([a, b])` 尽管变量名不同(`p` 与 `m`) `pattern` 中的 `return` 语句是根据其内容进行匹配的 仅包含值;它可能或可能不与“返回”语句匹配 换句话说,模式不必扩展到更大图的全长 当模式匹配时,它将从更大图中移除 当模式匹配时,它将从更大图中移除 函数中的“pattern”将被“replacement”替换。如果函数中有多个匹配项,则每个非重叠匹配项将被替换。在匹配重叠的情况下,重叠匹配项集中找到的第一个匹配项将被替换。 将替换。在匹配重叠的情况下,重叠匹配项集中找到的第一个匹配项将被替换。 将被替换。在匹配重叠的情况下,重叠匹配项集中找到的第一个匹配项将被替换。 将被替换。在匹配重叠的情况下,重叠匹配项集中找到的第一个匹配项将被替换。 ("First"这里定义为拓扑排序中的第一个) 节点使用-定义关系。在大多数情况下,第一个节点 是直接出现在 ``self`` 后面的参数,而 最后节点是函数返回的内容。 注意一点很重要,那就是必须在使用 Callable 时使用``pattern``参数,并且``replacement``Callable 的参数必须与模式匹配。 Callable 必须在其自身中使用,并且``replacement``Callable 的参数必须与模式匹配。 第一条规则是为什么在上面的代码块中,为什么必须使用 Callable 的参数。 规则。第一条规则是为什么在上面的代码块中,为什么必须使用 Callable 的参数。 ``forward`` 函数有参数 ``x, w1, w2``,但 ``pattern`` 函数只有参数 ``w1, w2``。``pattern`` 函数不使用 ``x``,因此不应将 ``x`` 作为参数指定。 作为第二条规则的例子,考虑将 .. 代码块 :: python def pattern(x, y): return torch.neg(x) + torch.relu(y) 的 .. 代码块 :: python def replacement(x, y): return torch.relu(x) 在这种情况下,`replacement` 需要和 `pattern`(`x` 和 `y`)相同的参数数量 即使 `y` 在 `replacement` 中没有被使用 。 在调用 `subgraph_rewriter.replace_pattern` 之后,生成的 Python 代码看起来是这样的: .. 代码块 :: python def forward(self, x, w1, w2): stack_1 = torch.stack([w1, w2]) sum_1 = stack_1.sum() stack_2 = torch.stack([w1, w2]) sum_2 = stack_2.sum() max_1 = torch.max(sum_1) add_1 = x + max_1 max_2 = torch.max(sum_2) add_2 = add_1 + max_2 return add_2 "" match_and_replacements = 替换模式(gm, 模式, 替换) 返回 [ 匹配(锚点=m.锚点, 节点映射=m.节点映射) 为 m 在 匹配与替换 ]
# 实验性 API,不向后兼容 @compatibility(兼容旧版本=错误) def 使用过滤器替换模式( gm: GraphModule, 模式: 联合[可调用, 图, GraphModule] 替换: 联合[可调用, 图, GraphModule, 无] = 无, 匹配过滤器: 可选[ 列表[可调用[[内部匹配, 图, 图] 布尔]] ] = 无, 忽略字面值: 布尔值 = 错误, # 放在末尾以避免破坏向后兼容性 替换回调: 可选[ 可调用[[内部匹配, 图, 图] 图] ] = 无, ) 翻译 列表[替换模式] "" 查看 replace_pattern 以获取文档。此函数是一个带有额外 match_filter 参数的重载。 参数: ``match_filters``: 函数列表,这些函数接收 (match: InternalMatch, original_graph: Graph, pattern_graph: Graph) 并返回一个布尔值,表示 匹配是否满足条件。 请参阅 matcher_utils.py 以获取 InternalMatch 的定义。 ``replacement_callback``: 一个接受匹配项并返回替换图的函数。 要使用的图。这允许您根据匹配项构建替换图。 基于匹配项构建替换图。 "" 返回 _replace_pattern( gm, 模式, 替换, 匹配过滤器, 忽略字面值, 替换回调函数 ) def _替换模式( gm: GraphModule, 模式: 联合[可调用, 图, GraphModule] 替换: 联合[可调用, 图, GraphModule, 无] = 无, 匹配过滤器: 可选[ 列表[可调用[[内部匹配, 图, 图] 布尔]] ] = 无, 忽略字面值: 布尔值 = 错误, # 放在末尾以避免破坏向后兼容性 替换回调: 可选[ 可调用[[内部匹配, 图, 图] 图] ] = 无, ) 翻译 列表[替换模式] from torch.fx.passes.utils 匹配工具 导入 内部匹配, 子图匹配器 如果 匹配过滤器 is 无: 匹配过滤器 = 输入文本为空,请提供需要翻译的文本 获取 `gm`、`pattern`、`replacement` 的图表 原始图表: 图 = gm.图 如果 isinstance(模式, GraphModule): 模式图表 = 模式.图 如果...否则 isinstance(模式, 图): 模式图表 = 模式 else: 模式图 = 符号追踪(模式).图 匹配器 = 子图匹配器( 模式图, 匹配输出=错误, 匹配占位符=错误, 移除重叠匹配=是, 忽略字面意思=忽略字面意思, ) 匹配: 列表[内部匹配] = 匹配器.匹配(原始图) # 过滤掉不匹配的匹配项 _匹配项 = [ m 为 m 在 匹配 如果 所有( 匹配过滤器(m, 原始图, 模式图) 为 匹配过滤器 在 匹配过滤器列表 ) ] 如果 isinstance(替换, GraphModule): 公共替换图 = 替换.图 如果...否则 isinstance(替换, 图): 公共替换图 = 替代方案 如果...否则 可调用(替换): 常见替换图 = 符号追踪(替换).图 else: 断言 ( 替换回调 is 不是 无 ), "必须提供替换 GraphModule 或替换回调" 常见替换图 = 无 随着我们逐步替换节点,我们需要跟踪匹配结果应该如何变化 匹配变更节点: 字典[节点, 节点] = {} 匹配与替换 = 输入文本为空,请提供需要翻译的文本 为 匹配 在 匹配项: 如果 替换回调 is 不是 无: 替换图 = 替换回调( 匹配, 原始图, 模式图 ) else: 断言 ( 公共替换图 is 不是 无 ), "必须提供替换的 GraphModule 或替换的回调函数" 替换图 = 公共替换图 替换占位符 = [ n 为 n 在 替换图.节点 如果 n.操作符 == 占位符 ] # 构建替换图输入与原始图输入生产节点之间的连接 # 初始化 `val_map`,将占位节点在 `replacement` 中的映射 # 与 `original_graph` 中相应的节点对应 断言 长度(匹配.占位节点) == 长度(替换占位符) 值映射: 字典[节点, 节点] = {} 为 rn, gn 在 zip(替换占位符, 匹配.占位节点): 如果 isinstance(gn, 节点): 值映射[rn] = 匹配变更节点.获取(干, 干) 如果 干 != 值映射[仁] 更新 match.placeholder_nodes 和 match.nodes_map 中的 gn 替换的节点 gn_ind = 匹配.placeholder_nodes.索引(gn) 匹配.占位节点[gn_ind] = 匹配变更节点[gn] 地图键 = 列表(匹配.节点映射.键(())) 列表(匹配.节点映射.值()).索引(gn) ] 匹配.节点映射[映射键] = 匹配变更节点[gn] else: 值映射[rn] = gn # 复制替换图 用户节点: 设置[节点] = 设置() 为 n 在 匹配.返回节点: 用户节点.更新(n.用户们) 首个用户节点 = 无 如果 长度(用户节点) == 0: 首个用户节点 = 无 如果...否则 长度(用户节点) == 1: 首个用户节点 = 下一(迭代(用户节点)) else: 如果存在多个用户节点,我们需要找到第一个用户节点 在当前`original_graph`执行顺序中 为 n 在 original_graph.节点: 如果 n 在 用户节点: 第一个用户节点 = n 断开 第一个下一节点 = 无 如果 第一个用户节点 is 无: # 无用户,因此我们在第一个 next 之前插入替换图 # 返回节点的节点 next_node = 无 为 n 在 反转(original_graph.节点): 如果 n 在 匹配.返回节点: 第一个下一个节点 = 下一个节点 断开 else: 下一个节点 = n 插入点 = ( 第一个用户节点 如果 第一个用户节点 is 不是 无 否则 第一个下一节点 ) 断言 插入点 is 不是 无, "插入点不能为空" 与 原始图.插入之前(插入点): 复制返回节点 = 原始图.graph_copy( 替换图, 值映射 ) 如果 isinstance(复制返回的节点, 节点): 复制返回的节点 = (复制返回的节点,) 获取替换到图中节点的列表 替换节点: 列表[节点] = [ v 为 v 在 值映射.值() 如果 v 不是 在 匹配.占位节点 ] # 将替换子图的输出节点连接到 # 原图正确的位置 断言 长度(匹配.返回节点) == 长度(复制返回节点) # type: ignore[arg-type] 为 gn, 复制节点 在 zip(匹配.返回节点, 复制返回节点): # type: ignore[arg-type] gn.替换所有引用(复制节点) 节点匹配更改[gn] = 复制节点 # 删除原始节点 为 节点 在 反转(模式图.节点): 如果 节点.操作符 != 占位符 和 节点.操作符 != 输出: gn = 匹配.节点映射[节点] gm.graph.删除节点(gn) 匹配与替换.append( 替换模式( 锚点=匹配.锚点[0] 节点映射=匹配.节点映射, 替换=替换节点, ) ) # 更新传入的 GraphModule 以反映新的状态 `original_graph` gm.重新编译() 如果 `replacement` 是一个 nn.Module,我们需要确保 所有子模块都已正确复制 如果 isinstance(替换, 火炬.神经网络.模块): _替换属性(gm, 替换) 返回 匹配和替换

© 版权所有 PyTorch 贡献者。

使用 Sphinx 构建,并使用 Read the Docs 提供的主题。

文档

查看 PyTorch 的全面开发者文档

查看文档

教程

深入了解初学者和高级开发者的教程

查看教程

资源

查找开发资源,获取您的疑问解答

查看资源