快捷键

torch.jit._trace 的源代码

# mypy: 允许未类型化定义
追踪

此模块包含支持 JIT 追踪前端的函数,特别是:
    * torch.jit.trace
    * torch.jit.trace_module

不建议直接导入;请使用`torch.jit`中公开的功能。
请使用`torch.jit`中公开的功能。
""

导入 contextlib
导入 复制
导入 functools
导入 检查
导入 操作系统
导入 正则表达式
导入 警告
from 枚举 导入 枚举
from 打字 导入 任何, 可调用, 可选, 类型变量
from typing_extensions 导入 参数规范

导入 火炬
from torch._jit_internal 导入 (
    _获取模型 ID,
    _qualified_name,
    获取可调用参数名称,
    是否正在脚本化,
)
from torch 自动微分 导入 函数
from torch.jit._script 导入 已缓存的前向, 脚本, 脚本模块
from torch.jit._state 导入 启用, _python_cu
from torch.nn 导入 模块
from torch 测试._比较 导入 默认容差


_扁平化 = 火炬._C._jit 扁平化
_unflatten = 火炬._C._jit_unflatten

R = 类型变量("R", 协变=是)  # 返回类型(总是协变)
P = 参数规范("P")


def 创建解释器名称查找函数(帧上移=1):
    def 获取变量对应的解释器名称(变量):
        框架 = 检查.currentframe()
        如果 不 frame:
            提升 运行时错误(检查帧失败)

        i = 0
        当 i < frames_up + 1:
            框架 = frame.f_back
            如果 不 frame:
                提升 运行时错误(获取帧失败)
            i += 1

        f_locals = frame.f_locals

        为 k, v 在 局部变量.项目():
            如果 isinstance(v, 火炬.张量) 和 变量 is v:
                返回 k 如果 k != "自我" 否则 请提供需要翻译的文本
        返回 请提供需要翻译的文本

    返回 _获取变量解释器名称


def 唯一状态字典(模块, 保留变量=错误):
    # 由于 Parameter.detach()始终创建一个新的 torch.Tensor 实例,
    # id(v)无法与它一起使用。所以我们总是得到参数或缓冲区
    将参数作为值,并使用参数和缓冲区去重
    状态字典 = 模块.状态字典(保留变量=是)
    过滤后的字典 = 类型(状态字典)()
    已见 ID: 设置[int] = 设置()
    为 k, v 在 状态字典.项目():
        如果 id(v) 在 已见 ID:
            continue
        已见 ID.添加(id(v))
        如果 保留变量:
            过滤字典[k] = v
        else:
            过滤字典[k] = v.detach()
    返回 过滤后的字典


类 ONNX 跟踪模块(火炬.神经网络.模块):
    def __init__(
        我,
        内部,
        严格的=是,
        force_outplace=错误,
        返回输入=错误,
        返回输入状态=错误,
    ):
        超级().__init__()
        # 内部可能是一个模块,也可能是一个任意的可调用对象
        # 如果它是一个模块,我们会自动获取其参数,这让我们可以
        # 避免对函数和模块进行特殊处理。
        我.内部 = 内部
        我.严格的 = 严格的
        我._强制输出位置 = force_outplace
        我._return_inputs = return_inputs
        我._return_inputs_states = 返回输入状态

    def 前向(我, *参数: 火炬.张量):
        输入变量, 输入描述 = _flatten(参数)
        # 注意:使用完整状态,因为我们需要它用于 BatchNorm 导出
        目前编译器路径不支持此功能。
        模块状态 = 列表(唯一状态字典(我, 保留变量=是).值())

        返回输入 = 输入文本为空,请提供需要翻译的文本
        输入状态 = 输入文本为空,请提供需要翻译的文本
        输出:outs = 输入文本为空,请提供需要翻译的文本

        def 包装器(*参数):
            输入参数: 列表[火炬.张量] = 输入文本为空,请提供需要翻译的文本
            为 i 在 范围(长度(输入变量)):
                如果 不 isinstance(参数[i] 火炬.张量):
                    提升 运行时错误(预期张量参数)
                输入参数.append(参数[i])

            trace_inputs = _unflatten(输入参数, 输入描述)

            如果 我._return_inputs:
                ret_inputs.append(
                    元组(x.克隆(内存格式=火炬.保留格式) 为 x 在 参数)
                )
            如果 我._return_inputs_states:
                输入状态.append(_unflatten(输入参数, 输入描述))
            输出.append(我.内部(*跟踪输入))
            如果 我._return_inputs_states:
                输入状态[0] = (输入状态[0] 跟踪输入)
            输出变量, _ = _flatten(输出)
            如果 长度(输出变量) == 1:
                返回 输出变量[0]
            else:
                返回 元组(输出变量)

        graph, _输出 = 火炬._C.通过追踪创建图(
            包装器,
            输入变量 + 模块状态,
            创建解释器名称查找函数(),
            我.严格的,
            我._force_outplace,
        )

        如果 我._return_inputs:
            返回 graph, 输出[0] ret_inputs[0]
        如果 我._return_inputs_states:
            返回 graph, 输出[0] 输入状态[0]
        else:
            返回 graph, 输出[0]


def _clone_inputs(参数):
    def clone_input(a):
        如果 a is 无:
            返回 无
        如果...否则 isinstance(a, 火炬.张量):
            # TODO: 想出一个单行来 .clone() 并设置 requires_grad
            v = (
                a.detach()
                .克隆(内存格式=无 如果 a.is_mkldnn 否则 火炬.保留格式)
                .需要梯度_(a.需要梯度)
            )
            如果 a.梯度 is 不 无:
                v.梯度 = clone_input(v.研究生)
            返回 v
        else:
            返回 a.克隆(内存格式=火炬.保留格式)

    返回 函数._nested_map(
        lambda x: isinstance(x, 火炬.张量), clone_input, 条件消息=张量
    )(参数)


仅用于开发者调试。我们不会进行宣传。
JIT 时间 = os.环境.获取("PyTorch JIT 时间", 错误)  仅 CUDA 计时
JIT_DISABLE = os.环境.获取(PYTORCH_JIT_DISABLE, 错误)
_JIT_STATS = os.环境.获取(PYTORCH_JIT_STATS, 错误)


@contextlib.contextmanager
def 时间(跟踪名称, 名称, 时间=是):
    如果 (不 JIT 时间 和 不 时间) 或者 不 火炬.cuda.是否可用():
        产生
        返回
    流 = 火炬.cuda.current_stream()
    开始 = 火炬.cuda.活动(启用计时=是)
    末端 = 火炬.cuda.活动(启用计时=是)
    流.记录事件(开始)
    尝试:
        产生
    最后:
        流.记录事件(结束)
        结束.同步()
        打印(f"{跟踪名称} {名称}时间:{开始.已用时间(结束)}毫秒")


def 核实(模型, 参数, 损失函数=火炬.总和, 设备=无):
    ""
验证即时编译模型与其未编译版本及其反向传播的行为是否一致。

如果您的模型返回多个输出,
您还必须指定一个 `loss_fn` 以产生反向传播将计算的损失。
的损失。

这个函数有副作用(例如,它执行你的模型/保存和加载参数),因此不要期望模型与原始模型完全相同
因此不要期望模型与原始模型完全相同
你传递进来的。

参数:
模型(编译后的 torch.nn.Module 或函数):要运行的模块/函数。
已验证。模块/函数定义必须使用 `@torch.jit.compile` 装饰。
`@torch.jit.compile`。
args(元组或张量):传递给编译的函数/模块的位置参数。
要验证的编译的函数/模块。非元组将被假定为。
模型需要传递的单个位置参数。
loss_fn(函数,可选):在调用 backwards 之前应用于模型输出的损失函数。默认情况下,
我们假设模型返回单个结果,并使用 :func:`torch.sum`。
我们假设模型返回单个结果,并使用 :func:`torch.sum`。
在调用反向操作之前;如果这不适合,你可以传递自己的
损失函数。注意,如果模型返回一个结果元组,
这些将作为单独的位置参数传递给 `loss_fn`。
设备(设备 ID 的可迭代对象,可选):用于模型的 GPU 设备
编译后的模块将在其上运行。这决定了在运行编译和未编译版本时必须保存的 RNG 状态。
必须保存当运行编译和未编译版本时。
"文档"
    原则上,我们在跟踪中记录设备信息,所以理论上应该可以检查我们的执行是否遵守了用户提供的 '设备' 指令。
    # 应该可以检查我们的执行是否遵守了用户提供的 '设备' 指令。
    # 用户提供的 '设备' 指令。

    # 考虑为 torch.jit 添加一个实用函数来测试
    # 对于这种情况
    如果 不 isinstance(模型, 火炬._C.编译函数):  # 类型: 忽略[attr-defined]
        提升 类型错误(
            "无法验证未编译的模块。请添加 @torch.jit.compile 来编译它"
        )
    是模块 = isinstance(模型, 模块)

    如果 不 isinstance(参数, 元组):
        args = (参数,)

    如果 是否是模块:
        保存状态 = 复制.深拷贝(模型.状态字典())

    def 运行前向和反向(参数, 强制跟踪=错误, 断言编译=错误):
        params = 列表(模型.参数()) 如果 is_module 否则 输入文本为空,请提供需要翻译的文本
        输入变量, _ = _flatten((参数, 参数))
        我们使用一个特殊的 API 来重置跟踪并从头开始编译。
        compiled_fn = 模型
        如果 强制跟踪:
            编译函数.clear_cache()
        如果 断言编译:
            命中次数 = 编译函数.命中次数
        out = 模型(*参数)
        如果 断言编译 和 编译函数.命中次数 == 点击数:  # type: ignore[possibly-undefined]
            提升 运行时错误("无法使用编译后的函数")
        如果 不 isinstance(输出, 元组):
            out = (输出,)
        如果 损失函数 == 火炬.求和 和 长度(输出) != 1:
            提升 ValueError(
                f"模型返回"{长度(输出)}输出,但默认损失函数
                "(torch.sum)只能处理单个输出"
            )
        输出变量, _ = _flatten(输出)
        已保存输出 = [
            v.detach().克隆(内存格式=火炬.保留格式) 为 v 在 输出变量
        ]
        损失 = 损失函数(*输出)
        梯度 = 火炬.自动微分.研究生[损失] 输入变量)
        # TODO: 我不确定这里克隆是否必要,但这样做更安全
        保存的梯度 = [
            v.detach().克隆(内存格式=火炬.保留格式) 为 v 在 梯度
        ]
        返回 (保存输出, 保存梯度)

    与 火炬.随机.fork_rng(设备, _caller=torch.jit.verify):
        未编译输出, 未编译的梯度 = 运行前向和反向(参数, 强制跟踪=是)
        断言 模型.存在跟踪信息为(*参数)

    如果 是否是模块:
        模型.加载状态字典(保存状态)  # type: ignore[possibly-undefined]
    已编译输出, 编译梯度 = 运行前向和反向(参数, 断言编译=是)

    验证相等(未编译输出, 已编译输出)
    验证相等(未编译的梯度, 编译后的梯度)


def 验证相等(xs, ys):
    为 x, y 在 zip(xs, ys):
        如果 x.子(y).绝对值().最大值() > 1e-6:
            提升 运行时错误(JIT 与实际计算不匹配)


def 缩进(s):
    返回 "输入文本翻译为简体中文为:\n".连接["制表符" + 行 为 行 在 s.按行分割()])


类 追踪检查错误(异常):
    def __init__(我, 图差分错误, 矩阵比较错误, 额外消息=无):
        我.消息 = 追踪失败,通过 sanity 检查!输入文本翻译为简体中文为:\n"
        如果 额外消息 is 不 无:
            我.消息 += 额外消息 + "输入文本翻译为简体中文为:\n"
        如果 图形差异错误 is 不 无:
            我.消息 += "错误:调用间图形不同!"输入文本翻译为简体中文为:\n"
            我.消息 += 缩进(图差分错误) + "输入文本翻译为简体中文为:\n"
        如果 张量比较错误 is 不 无:
            我.消息 += (
                "错误:张量常量节点在调用间值不同 "
                "这通常表明追踪器有"
                遇到无法追踪的代码。输入文本翻译为简体中文为:\n"
            )
            我.消息 += 缩进(矩阵比较错误) + "输入文本翻译为简体中文为:\n"
        超级().__init__(我.消息)


# 将追踪的模块与用户提供的验证输入集进行比对
@torch.不梯度()
def _检查追踪(
    检查输入,
    函数,
    跟踪函数,
    检查公差,
    严格的,
    force_outplace,
    is_trace_module,
    _module_class,
    example_inputs_is_kwarg 参数=错误,
):
    # 注意:跟踪与优化独立,优化消耗跟踪
    为 输入 在 检查输入:
        如果 isinstance(输入, 火炬.张量):
            输入 = (输入,)

        如果 is_trace_module:
            copied_dict = {}
            为 名称, 数据 在 输入.项目():
                复制字典[名称] = _clone_inputs(数据)
            检查模块 = 火炬.算子.跟踪模块(
                getattr(函数, "__self__", 函数),
                复制字典,
                检查跟踪=错误,
                严格的=严格的,
                _force_outplace=force_outplace,
                _module_class=_module_class,
                编译单元=火炬._C.编译单元(),
                example_inputs_is_kwarg 参数=example_inputs_is_kwarg 参数,
                _store_inputs=错误,
            )
            检查模块函数 = 检查模块._c._获取方法(跟踪函数.名称)
            输入 = 输入[跟踪函数.名称]
            如果 (
                isinstance(输入, (火炬.张量))
                或者 isinstance(输入, 字典)
                和 不 example_inputs_is_kwarg 参数
            ):
                输入 = (输入,)
        else:
            如果 example_inputs_is_kwarg 参数:
                检查模块 = 火炬.算子.跟踪(
                    函数,
                    检查跟踪=错误,
                    严格的=严格的,
                    _force_outplace=force_outplace,
                    _module_class=_module_class,
                    示例关键字输入=_clone_inputs(输入),
                    _store_inputs=错误,
                )
            else:
                检查模块 = 火炬.算子.跟踪(
                    函数,
                    _clone_inputs(输入),
                    检查跟踪=错误,
                    严格的=严格的,
                    _force_outplace=force_outplace,
                    _module_class=_module_class,
                    _store_inputs=错误,
                )
            检查模块函数 = 检查模块

        def 图诊断信息():
            模块规范形式化 = 火炬._C._jit_pass_canonicalize(跟踪函数.graph)
            火炬._C._jit_pass_inline(标准化)
            火炬._C.删除形状信息(标准化)
            mod_str = 字符串(标准化)
            mod_str = 正则表达式.子(r___torch_mangle_数字+., 输入文本翻译为简体中文为:"", mod_str)
            检查规范化 = 火炬._C._jit_pass_canonicalize(check_mod_func.graph)
            火炬._C._jit_pass_inline(标准化检查)
            火炬._C.删除形状信息(标准化检查)
            检查_str = 字符串(标准化检查)
            检查_str = 正则表达式.子(r___torch_mangle_数字+., 输入文本翻译为简体中文为:"", check_str)

            图差异错误 = 无
            如果 mod_str != check_str:
                导入 difflib

                graph_diff = 差分库.ndiff(
                    mod_str.按行分割(是), check_str.按行分割(是)
                )
                图差异错误 = "图差异:"输入文本翻译为简体中文为:\n" + 缩进(输入文本翻译为简体中文为:"".连接(图差分)) + "输入文本翻译为简体中文为:\n"

                为 n_mod, 检查 在 zip(
                    标准化.节点(), 标准化检查.节点()
                ):
                    如果 字符串(n_mod) != 字符串(n_check):
                        图差异错误 += "首次分叉运算符:"输入文本翻译为简体中文为:\n"
                        节点差异 = 差分库.ndiff(
                            字符串(n_mod).按行分割(是), 字符串(n_check).按行分割(是)
                        )
                        源打印输出 = (
                            "节点差异:输入文本翻译为简体中文为:\n" + 缩进(输入文本翻译为简体中文为:"".连接(节点差异)) + "输入文本翻译为简体中文为:\n"
                        )
                        模块栈 = n_mod.源范围()
                        如果 模块栈:
                            源打印输出 += (
                                跟踪源位置:输入文本翻译为简体中文为:\n" + 缩进(模块栈) + "输入文本翻译为简体中文为:\n"
                            )
                        检查栈 = n_check.源范围()
                        如果 检查栈:
                            源打印输出 += (
                                检查源位置:输入文本翻译为简体中文为:\n" + 缩进(检查栈) + "输入文本翻译为简体中文为:\n"
                            )
                        图差异错误 += 源打印输出

                        断开  # For now, only print out the first pair of nodes that diverges

            张量比较错误 = 无
            检查张量常量节点
            为 n_mod, 检查 在 zip(
                标准化.节点(), 标准化检查.节点()
            ):
                如果 n_mod.类型() != n_check.类型():
                    断开  # 图已发散

                如果 n_mod.类型() == prim::常量 和 不 (
                    n_mod.必须为 None() 或者 n_check.必须为 None()
                ):
                    如果 不 n_mod.hasAttribute("值"):
                        continue
                    如果 n_mod.类似("值") != "t" 或者 n_check.类似("值") != "t":
                        continue

                    调整张量值 = n_mod.t("值")
                    检查张量值 = n_check.t("值")

                    尝试:
                        火炬.测试.断言关闭(
                            调整张量值, 检查张量值, 等于 NaN=真实
                        )
                    除了 (运行时错误, 断言错误) 是 e:
                        如果 张量比较错误 is 无:
                            张量比较错误 = 请提供需要翻译的文本
                        张量比较错误 += 节点:输入文本翻译为简体中文为:\n" + 缩进(字符串(n_mod)) + "输入文本翻译为简体中文为:\n"
                        compare_stack = n_mod.源范围()
                        如果 compare_stack:
                            张量比较错误 += (
                                "源位置:"输入文本翻译为简体中文为:\n" + 缩进(compare_stack) + "输入文本翻译为简体中文为:\n"
                            )
                        张量比较错误 += "比较异常:" + 缩进(
                            字符串(e)
                        )

                        断开  # 目前仅打印第一个差异对

            返回 图差错误, 张量比较错误

        def wrap_retval(x):
            返回 x 如果 isinstance(x, 元组) 否则 (x,)

        def 运行模块并过滤张量输出(模块, 输入, 运行什么):
            尝试:
                如果 isinstance(输入, 字典) 和 example_inputs_is_kwarg 参数:
                    输出:outs = 包装返回值(模块(**输入))
                else:
                    输出:outs = 包装返回值(模块(*_clone_inputs(输入)))
                输出:outs = [out 为 out 在 输出:outs 如果 isinstance(输出, 火炬.张量)]
                返回 输出:outs
            除了 异常 是 e:
                图差错误, 张量比较错误 = 图诊断信息()
                msg = f遇到运行时异常{运行什么}使用测试输入。输入文本翻译为简体中文为:\n异常:输入文本翻译为简体中文为:\n{缩进(字符串(e))}"
                提升 追踪检查错误(
                    图差错误,
                    张量比较错误,
                    额外消息=信息,
                ) from e

        已警告 = [错误]

        def 可能警告非确定性():
            如果 已警告[0]:
                返回
            已警告[0] = 真实
            非确定性操作 = [
                操作符 为 操作符 在 跟踪函数.graph.节点() 如果 操作.非确定性的()
            ]
            如果 长度(非确定性操作) > 0:
                非确定性操作警告 = "Trace 存在非确定性节点。"
                非确定性操作警告 += (
                    "你忘记在模型上调用.eval()了吗?节点:"输入文本翻译为简体中文为:\n"
                )
                非确定性操作警告 += "输入文本翻译为简体中文为:\n".连接(
                    [缩进(字符串(操作)) 为 操作符 在 非确定性操作]
  :20]
                )
                非确定性操作警告 += (
                    "输入文本翻译为简体中文为:\n这可能会导致跟踪检查出错。要禁用跟踪检查,
                    将`check_trace=False`传递给`torch.jit.trace()`
                )
                警告.警告(
                    非确定性操作警告, 分类=跟踪警告, 栈级别=5
                )

        def 比较输出(原始, 参考, 匹配什么):
            都好 = 真实
            为 i, (原始, ref) 在 列举(zip(原始, 参考)):
                尝试:
                    如果 原始.是否量化:
                        原始 = 原始.反量化()
                    如果 ref.是否量化:
                        分支 = ref.反量化()
                    如果 原始.is_mkldnn:
                        原始 = 原始.转换为稠密格式()
                    如果 ref.is_mkldnn:
                        分支 = ref.转换为稠密格式()
                    如果 ref.是复杂的() 或者 原始.是复杂的():
                        火炬.测试.断言关闭(
                            原始.到(火炬.cdouble),
                            ref.到(火炬.cdouble),
                            相对误差=检查公差,
                            精度=默认公差(原始, ref)1]
                            等于 NaN=是,
                        )
                    else:
                        如果 原始.是_mps 或者 ref.是 mps:
                            火炬.测试.断言关闭(
                                原始.float(),
                                ref.float(),
                                相对误差=检查公差,
                                精度=默认公差(原始, ref)1]
                                等于 NaN=是,
                            )
                        如果...否则 getattr(原始, 是嵌套的, 无) 或者 getattr(
                            ref, 是嵌套的, 无
                        ):
                            断言 getattr(原始, 是嵌套的, 无) == getattr(
                                ref, 是嵌套的, 无
                            )
                            为 原始文本, t_ref 在 zip(原始.解绑(), ref.解绑()):
                                火炬.测试.断言关闭(
                                    原始文本.double(),
                                    参考文本.double(),
                                    相对误差=检查公差,
                                    精度=默认公差(原始文本, 参考文本)1]
                                    等于 NaN=是,
                                )
                        else:
                            火炬.测试.断言关闭(
                                原始.double(),
                                ref.double(),
                                相对误差=检查公差,
                                精度=默认公差(原始, ref)1]
                                等于 NaN=是,
                            )
                除了 断言错误 是 e:
                    可能警告非确定性()
                    警告.警告(
                        输出编号
                        + 字符串(i + 1)
                        + 的追踪函数的输出不匹配
                        对应的输出
                        + 匹配什么
                        + ". 详细错误:输入文本翻译为简体中文为:\n"
                        + 字符串(e),
                        分类=跟踪警告,
                        栈级别=4,
                    )
                    都好 = 假

            返回 都好

        跟踪输出 = 运行模块并过滤张量输出(跟踪函数, 输入, "跟踪")
        函数输出 = 运行模块并过滤张量输出(函数, 输入, "Python 函数")
        如果 比较输出(traced_outs, 函数输出, "Python 函数"):
            检查输出 = 运行模块并过滤张量输出(
                check_mod_func, 输入, "重复跟踪"
            )
            比较输出(traced_outs, 检查输出, 重复跟踪)

        诊断信息 = 图诊断信息()
        如果 任何(信息 is 不 无 为 信息 在 诊断信息):
            提升 追踪检查错误(*诊断信息)


类 跟踪警告(警告):
    @staticmethod
    def _使用 Python 的跟踪器警告():
        我们忽略所有子模块(除了 JIT)的警告,因为我们需要它们,例如用于_check_trace
        警告.过滤警告(
            "忽略", 分类=跟踪警告, 模块=torch.(?!jit)
        )
        警告.过滤警告("忽略", torch::jit::fuser::cuda)


我们忽略来自库内部的跟踪器警告,因为所有我们的形状检查在 nn 中都会触发它们。
忽略库警告
跟踪警告._使用 Python 的跟踪器警告()
火炬._C._tracer_warn_use_python()


def make_tuple(示例输入):
    如果 isinstance(示例输入, (火炬.张量, 字典)):
        返回 (示例输入,)
    # 主要是为了让奇怪的迭代器在这里失败,而不是 pybind11 代码
    如果 不 isinstance(示例输入, 元组):
        返回 元组(示例输入)
    返回 示例输入


def make_module(模块, _module_class, 编译单元):
    如果 isinstance(模块, 脚本模块):
        返回 修饰
    如果...否则 火炬._jit_internal.模块有导出(模块):
        推断方法存根函数 = 火炬.算子.递归.从导出方法创建存根
        返回 火炬.算子.递归.创建脚本模块(
            模块, 推断方法存根函数, 分享类型=错误, is_tracing=真实
        )
    else:
        如果 _模块类 is 无:
            _模块类 = 顶层跟踪模块
        返回 _module_class(模块, 编译单元=编译单元)


def 输入包装检查(检查输入):
    如果 检查输入 is 无:
        返回 无

    返回 [
    - 检查输入
  ]前进: c} 为 c 在 检查输入]


def 分析导出结果与时间序列结果(导出, 跟踪):
    导入 torch.utils._pytree 是 pytree

    平坦导出 = py 树.树叶(导出)
    平坦轨迹 = py 树.树叶(跟踪)

    为 原始, 已加载 在 zip(平坦导出, flat_trace):
        如果 原始.布局 != 已加载.布局:
            返回 假
        # 不支持 mkldnn 的 torch.allclose
        如果 原始.布局 == 火炬._mkldnn:  # 类型: 忽略[attr-defined]
            返回 真实
        如果 类型(原始) != 类型(已加载):
            返回 假

        如果 isinstance(原始, 火炬.子类.假 Tensor):
            跳过 FakeTensor。
            返回 真实
        如果...否则 isinstance(原始, 火炬.张量):
            如果 原始.dtype != 已加载.数据类型:
                返回 假
            如果 不 火炬.allclose(原始, 已加载):
                返回 假
        else:
            如果 原始 != 已加载:
                返回 假
    返回 真实


def _跟踪实现(
    函数,
    示例输入=无,
    优化=无,
    检查跟踪=是,
    检查输入=无,
    检查公差=0.00001,
    严格的=是,
    _force_outplace=错误,
    _module_class=无,
    编译单元=Python 编译单元,
    示例关键字输入=无,
    _store_inputs=是,
):
    如果 isinstance(函数, 火炬.算子.脚本模块):
        因为 ScriptModule 的 forward 方法已经被定义,所以很难追踪它,这会导致错误。
        。
        警告.警告(
            输入已经是 ScriptModule,追踪它是一个空操作。直接返回对象。
        )
        返回 函数

    如果 isinstance(函数, 火炬.神经网络.模块):
        如果 示例输入 is 无:
            如果 isinstance(示例关键字输入, 字典):
                示例输入 = 示例关键字输入
            else:
                提升 运行时错误("example_kwarg_inputs 应该是一个字典")
        返回 跟踪模块(
            函数,
            {前进: 示例输入},
            无,
            检查跟踪,
            输入包装检查(检查输入),
            检查公差,
            严格的,
            _force_outplace,
            _module_class,
            example_inputs_is_kwarg 参数=isinstance(示例关键字输入, 字典),
            _store_inputs=_store_inputs,
        )
    如果 (
        有属性(函数, "__self__")
        和 isinstance(函数.__self__, 火炬.神经网络.模块)
        和 函数.__name__ == 向前
    ):
        如果 示例输入 is 无:
            如果 isinstance(示例关键字输入, 字典):
                示例输入 = 示例关键字输入
            else:
                提升 运行时错误("example_kwarg_inputs 应该是一个字典")
        返回 跟踪模块(
            函数.__self__,
            {前进: 示例输入},
            无,
            检查跟踪,
            输入包装检查(检查输入),
            检查公差,
            严格的,
            _force_outplace,
            _module_class,
            example_inputs_is_kwarg 参数=isinstance(示例关键字输入, 字典),
            _store_inputs=_store_inputs,
        )

    # 特殊情况,用于传递单个 Tensor 的常见情况
    如果 (
        isinstance(示例输入, (火炬.张量, 字典))
        和 示例关键字输入 is 无
    ):
        示例输入 = (示例输入,)
    # 主要是为了让奇怪的迭代器在这里失败,而不是 pybind11 代码
    如果...否则 示例关键字输入 is 无 和 不 isinstance(示例输入, 元组):
        示例输入 = 元组(示例输入)

    var_lookup_fn = 创建解释器名称查找函数(0)

    如果 有属性(函数, "__self__") 和 isinstance(函数.__self__, 火炬.神经网络.模块):
        提升 属性错误(
            "trace 不支持编译单个模块的函数。"输入文本翻译为简体中文为:\n"
            "请使用 trace_module"
        )

    名称 = _qualified_name(函数)
    如果 isinstance(示例关键字输入, 字典):
        示例输入 = 示例关键字输入
        追踪 = 火炬._C.根据字典从追踪中创建函数(
            名称,
            函数,
            示例关键字输入,
            var_lookup_fn,
            严格的,
            _force_outplace,
            获取可调用参数名称(函数),
        )
    else:
        追踪 = 火炬._C.从跟踪创建函数(
            名称,
            函数,
            示例输入,
            var_lookup_fn,
            严格的,
            _force_outplace,
            获取可调用参数名称(函数),
        )

    将跟踪与从用户指定输入创建的新跟踪进行比对
    如果 检查跟踪:
        如果 检查输入 is 不 无:
            _检查追踪(
                检查输入,
                函数,
                跟踪的,
                检查公差,
                严格的,
                _force_outplace,
                错误,
                _module_class,
                example_inputs_is_kwarg 参数=isinstance(示例关键字输入, 字典),
            )
        else:
            _检查追踪(
                [示例输入]
                函数,
                跟踪的,
                检查公差,
                严格的,
                _force_outplace,
                错误,
                _module_class,
                example_inputs_is_kwarg 参数=isinstance(示例关键字输入, 字典),
            )

    允许 torch.compile() 内联
    跟踪的._torchdynamo_inline = 函数  # 类型: 忽略[attr-defined]
    返回 追踪


类 导出类型(字符串, 枚举):
    直接导出 = "直接导出"
    跟踪并导出 = "跟踪并导出"
    源到源 = "源到源"

    def __str__(我) 翻译 字符串:
        返回 我.值


类 _导出结果(字符串, 枚举):
    成功 = "成功"
    导出失败 = 导出失败
    运行失败 = 运行失败
    准确性错误 = "精度错误"

    def __str__(我) 翻译 字符串:
        返回 我.值


[文档]def 跟踪( 函数, 示例输入=无, 优化=无, 检查跟踪=是, 检查输入=无, 检查公差=0.00001, 严格的=是, _force_outplace=错误, _module_class=无, 编译单元=Python 编译单元, 示例关键字输入=无, _store_inputs=是, ): r"" 跟踪一个函数并返回一个可执行的脚本或:class:`ScriptFunction`,该脚本将使用即时编译进行优化。 跟踪非常适合仅操作于 ``Tensor``\\s、列表、字典以及 元组形式的“Tensor”。 使用 `torch.jit.trace` 和 `torch.jit.trace_module`,你可以将 现有模块或 Python 函数到 TorchScript `:class:`脚本函数` 或 :class:`脚本模块`。你必须提供示例 输入,然后运行函数,记录所有操作。 记录张量。 * 独立函数的记录结果产生 `ScriptFunction`。 * `nn.Module.forward` 或 `nn.Module` 的记录结果产生 `脚本模块`. 此模块还包含原始模块的所有参数。 注意: 警告: 仅正确记录函数和模块,不记录数据 依赖(例如,不要在张量数据上使用条件语句)且不 任何未跟踪的外部依赖(例如,执行输入/输出或) 访问全局变量)。仅记录在给定 函数在给定的张量上运行。因此,返回的结果 `ScriptModule` 总是在任何输入上运行相同的跟踪图。这 有一些重要的含义,当你的模块需要根据输入和/或模块 运行不同的操作集时,取决于输入和/或模块 状态。例如, * 跟踪不会记录任何控制流,如 if 语句或循环。 当这种控制流在您的模块中是恒定时,这是可以的 并且它通常内联控制流决策。但有时, 控制流实际上是模型本身的一部分。例如,一个 循环神经网络是对输入序列(可能是动态长度)的循环。 * 在返回的 :class:`ScriptModule` 中,具有不同操作的 训练和评估模式下的行为始终会像在追踪期间所处的模式一样表现 无论`ScriptModule`处于哪种模式,都不会改变 在这种情况下,追踪是不合适的 在这些情况下,追踪是不合适的 `torch.jit.script`脚本是一个更好的选择。如果您跟踪这些模型,您可能在后续的模型调用中默默地得到错误的结果。当追踪器尝试执行可能导致错误追踪的操作时,它将尝试发出警告。 如果跟踪这样的模型,您可能在后续的模型调用中默默地得到错误的结果。 追踪器将尝试在执行可能导致错误追踪的操作时发出警告。 当执行可能导致错误追踪的操作时,追踪器将尝试发出警告。 参数: func (可调用或 torch.nn.Module):一个 Python 函数或`torch.nn.Module` 将使用 `example_inputs` 运行。`func` 参数和返回值 的值必须是张量或(可能嵌套的)元组,其中包含张量。 当传递 `torch.jit.trace` 模块时,仅运行并跟踪 `forward` 方法(参见 :func:`torch.jit.trace`) ``forward`` 方法被运行和跟踪(参见 :func:`torch.jit.trace`) `torch.jit.trace_module>`的详细信息。 关键字参数: example_inputs (可选,tuple 或 torch.Tensor 或 None):传递给函数的示例输入。 输入,在跟踪函数时使用。 默认:`None`。此参数或`example_kwarg_inputs`任选其一。 应该指定。生成的跟踪可以运行不同类型和形状的输入 假设跟踪的操作支持这些类型和形状 `example_inputs` 也可以是一个单独的 Tensor,在这种情况下,它会被自动包裹在一个元组中。当值为 None 时, 也可以是一个单独的 Tensor,在这种情况下,它会被自动包裹在一个元组中。当值为 None 时, 应指定 ``example_kwarg_inputs``。 检查跟踪(`bool`, 可选):检查是否相同的输入运行通过 跟踪代码产生相同的输出。默认:``True``。你可能想 禁用此功能,例如,如果您的网络中包含非 确定性操作或如果你确定网络是正确的尽管 检查器失败。 check_inputs(可选的元组列表):一个元组列表,包含应用于检查跟踪的输入 参数,以与实际跟踪进行比较。 预期。每个元组相当于一组输入参数, 将在 `example_inputs` 中指定。为了获得最佳结果,请传入 一组代表形状空间的检查输入 您期望网络看到的输入类型。如果未指定, 原始的 `example_inputs` 用于检查 检查容差(浮点数,可选):浮点数比较容差 用于检查程序。这可以用来放宽 事件结果数值差异时的检查严格度 由于众所周知的原因,例如操作符融合。 严格(`bool`,可选):以严格模式运行跟踪器或不。 (默认:`True`)。只有当你想关闭跟踪器时才关闭此选项。 记录你的可变容器类型(目前为 `list`/`dict`)。 你确定你使用的容器是一个“常量”结构,并且不会用作控制流(if、for)条件。 例如:example_kwarg_inputs(dict,可选):此参数是一组关键字参数。 条件。 输入示例(字典,可选):此参数是一组关键字参数的包。 示例输入的参数,这些参数将被传递给函数,用于追踪。 默认为 ``None``。此参数或 ``example_inputs`` 至少应指定一个。字典将根据追踪函数的参数名称进行解包。如果字典的键与追踪函数的键不匹配,则 应该被指定。字典将根据追踪函数的参数名称进行解包。如果字典的键与追踪函数的键不匹配,则 应该被指定。字典将根据追踪函数的参数名称进行解包。如果字典的键与追踪函数的键不匹配,则 追踪函数的参数名称,将引发运行时异常。 返回: 如果 `func` 是 `nn.Module` 或 `nn.Module` 的 `forward`,则 `trace` 返回 一个具有单个 `forward` 方法的 :class:`ScriptModule` 对象 包含追踪代码。返回的 `ScriptModule` 将 原版具有相同的子模块和参数集 ``nn.Module``。如果 ``func`` 是一个独立函数,则 ``trace`` 返回 `ScriptFunction`。 示例(跟踪一个函数): .. testcode:: 导入 torch def foo(x, y): return 2 * x + y # 运行 `foo` 并记录提供的输入和张量操作 traced_foo = torch.jit.trace(foo, (torch.rand(3), torch.rand(3))) # `traced_foo` 现在可以用 TorchScript 解释器运行或保存 # 和加载在一个无 Python 的环境中 示例(跟踪现有模块):: 导入 torch 导入 torch.nn 作为 nn class Net(nn.Module): def __init__(self) -> None: super().__init__() self.conv = nn.Conv2d(1, 1, 3) def forward(self, x): return self.conv(x) n = Net() example_weight = torch.rand(1, 1, 3, 3) example_forward_input = torch.rand(1, 1, 3, 3) # 跟踪特定方法并构建 `ScriptModule` # 一个单独的 `forward` 方法 module = torch.jit.trace(n.forward, example_forward_input) # 跟踪一个模块(隐式跟踪 `forward`)并构建一个 # 具有单个 `forward` 方法的 `ScriptModule` module = torch.jit.trace(n, example_forward_input) "文档" 如果 不 启用: 返回 函数 如果 优化 is 不 无: 警告.警告( "`优化` 已弃用且无效果。" "请使用 `with torch.jit.optimized_execution()` 代替", 未来警告, 栈级别=2, ) from torch._utils_internal 导入 ( 检查 torch 是否可导出, log_torch_jit_trace 导出可访问性, log_torchscript_usage, ) 跟踪函数 = _跟踪实现( 函数, 示例输入, 优化, 检查跟踪, 检查输入, 检查公差, 严格的, _force_outplace, _module_class, 编译单元, 示例关键字输入, _store_inputs, ) log_torchscript_usage("跟踪", 模型 ID=_获取模型 ID(跟踪函数)) 如果 检查 torch 是否可导出(): from torch._export.converter 导入 TS2EP 转换器 from torch.export._trace 导入 ( 将 ts 转换为导出实验性, _处理导出 JIT 跟踪输入, ) 导出跟踪函数 = _跟踪实现( 函数, 示例输入=示例输入, 优化=优化, 检查跟踪=错误, 检查输入=检查输入, 检查公差=检查公差, 严格的=严格的, _force_outplace=_force_outplace, _module_class=_module_class, 编译单元=编译单元, 示例关键字输入=示例关键字输入, _store_inputs=_store_inputs, ) 导出参数, _ = _处理导出 JIT 跟踪输入( 示例输入, 示例关键字输入 ) def _日志导出性(导出函数, 导出函数, 导出参数, 导出类型): 尝试: 追踪结果 = 导出函数(*导出参数) 除了 异常 是 e: _ = e log_torch_jit_trace 导出可访问性( "跟踪", 字符串(导出类型), 字符串(_导出结果.成功), 成功 ) 返回 尝试: 沉浸式模块 = 导出函数(导出函数, 导出参数) 除了 异常 是 e: log_torch_jit_trace 导出可访问性( "跟踪", 字符串(导出类型), 字符串(_导出结果.导出失败), 字符串(e), ) 返回 尝试: 导出 = 沉浸式模块(*导出参数) 除了 异常 是 e: log_torch_jit_trace 导出可访问性( "跟踪", 字符串(导出类型), 字符串(_导出结果.运行失败), 字符串(e) ) 返回 如果 不 分析导出结果与时间序列结果(导出, 跟踪结果): log_torch_jit_trace 导出可访问性( "跟踪", 字符串(导出类型), 字符串(_导出结果.准确性错误), "准确度误差", ) 返回 log_torch_jit_trace 导出可访问性( "跟踪", 字符串(导出类型), 字符串(_导出结果.成功), 成功 ) def 直接导出并转换为小写(函数, 导出参数): 返回 火炬.导出.导出(函数, 导出参数, 严格的=错误).模块() def _将时间戳转换为导出源到源(函数, 导出参数): 返回 TS2EP 转换器(函数, 导出参数).转换().模块() 当原始模块是 torch.jit.ScriptModule 时,torch.jit.trace 为空操作 如果 不 isinstance(跟踪导出函数, 火炬.算子.脚本模块): _日志导出性( 跟踪导出函数, 直接导出并转换为小写, 导出参数, 导出类型.直接导出, ) _日志导出性( 跟踪导出函数, 将 ts 转换为导出实验性, 导出参数, 导出类型.跟踪并导出, ) _日志导出性( 跟踪导出函数, _将时间戳转换为导出源到源, 导出参数, 导出类型.源到源, ) 返回 跟踪函数
_trace_module_map: 可选[字典[任何, 任何]] = 无
[文档]def 跟踪模块( 模块, 输入, 优化=无, 检查跟踪=是, 检查输入=无, 检查公差=0.00001, 严格的=是, _force_outplace=错误, _module_class=无, 编译单元=Python 编译单元, example_inputs_is_kwarg 参数=错误, _store_inputs=是, ): "" 跟踪一个模块并返回一个可执行的 :class:`ScriptModule`,该模块将使用即时编译进行优化。 当将模块传递给 :func:`torch.jit.trace ` 时, 仅运行并跟踪 ``forward`` 方法。使用 ``trace_module``,您可以指定一个字典,其中包含要跟踪的方法名称和示例输入(见下面的 ``inputs`` 参数)。 有关 ``inputs`` 参数的详细信息,请参阅文档。 查看 :func:`torch.jit.trace ` 获取更多关于追踪的信息。 参数: mod (torch.nn.Module):一个包含方法名称的 ``torch.nn.Module`` 指定在 `inputs` 中。给定的方法将被编译 作为单个 `ScriptModule` 的一个部分。 输入字典(dict):一个包含按方法名称索引的 ``mod`` 中示例输入的字典。 在跟踪过程中,将传入与输入键对应名称的方法。 的输入。 ``{ 'forward' : example_forward_input, 'method2': example_method2_input}`` 关键字参数: 检查跟踪(`bool`, 可选):检查是否相同的输入运行通过 跟踪代码产生相同的输出。默认:``True``。你可能想 禁用此功能,例如,如果您的网络中包含非 确定性操作或如果你确定网络是正确的尽管 检查器失败。 check_inputs(可选的字典列表):一个包含输入参数的字典列表,这些参数应该被使用 来检查跟踪与预期的一致性。每个元组 等价于一组输入参数,这些参数会 需要在 ``inputs`` 中指定。为了获得最佳结果,请传入一组具有代表性的检查输入,这些输入代表了你期望网络看到的形状和类型。 一组具有代表性的检查输入,这些输入代表了你期望网络看到的形状和类型。 你期望网络看到的输入的形状和类型。 如果未指定,则使用原始的 ``inputs`` 进行检查。 检查容差(float,可选):在检查程序中使用浮点数比较容差。 这可以用于在需要时放宽检查器的严格性 结果因已知原因在数值上有所差异,例如操作符融合。 example_inputs_is_kwarg(`bool`, 可选):此参数指示示例输入是否为包 关键字参数的包。默认值:``False``。 返回: 一个包含单个 ``forward`` 方法的 ``ScriptModule`` 对象,其中包含追踪的代码。 当 ``func`` 是 ``torch.nn.Module`` 时,返回的 ``ScriptModule`` 将具有与 ``func`` 相同的子模块和参数。 子模块和参数与 ``func`` 相同。 例子(追踪具有多个方法的模块):: 导入 torch 导入 torch.nn 作为 nn class Net(nn.Module): def __init__(self) -> None: super().__init__() self.conv = nn.Conv2d(1, 1, 3) def forward(self, x): return self.conv(x) def weighted_kernel_sum(self, weight): return weight * self.conv.weight n = Net() example_weight = torch.rand(1, 1, 3, 3) example_forward_input = torch.rand(1, 1, 3, 3) # 跟踪特定方法并构建 `ScriptModule` # 一个单独的 `forward` 方法 module = torch.jit.trace(n.forward, example_forward_input) # 跟踪一个模块(隐式跟踪 `forward`)并构建一个 # 具有单个 `forward` 方法的 `ScriptModule` module = torch.jit.trace(n, example_forward_input) # Trace specific methods on a module (specified in `inputs`), constructs # a `ScriptModule` with `forward` and `weighted_kernel_sum` methods inputs = {"forward": example_forward_input, "weighted_kernel_sum": example_weight} module = torch.jit.trace_module(n, inputs) "文档" 如果 不 启用: 返回 修饰 如果 优化 is 不 无: 警告.警告( "`优化` 已弃用且无效果。" "请使用 `with torch.jit.optimized_execution()` 代替", 未来警告, 栈级别=2, ) var_lookup_fn = 创建解释器名称查找函数(0) 如果 不 isinstance(模块, 火炬.神经网络.模块): 提升 属性错误(预期第一个参数为 torch.nn.Module) 如果 不 isinstance(输入, 字典): 提升 属性错误(预期一个包含 (方法名, 输入) 对的字典) 旧模块映射 = 火炬.算子.跟踪.跟踪模块映射 尝试: 跟踪模块映射: 字典[任何, 任何] = {} def 注册子模块(模块, 前缀): 为 名称, 儿童 在 模块.命名子项(): 子模块全称 = 前缀 + "." + 名称 跟踪模块映射[儿童] = 子模块全称 注册子模块(儿童, 子模块全名) 跟踪模块映射["__模块"] = 修饰 火炬.算子.跟踪.跟踪模块映射 = 跟踪模块映射 注册子模块(模块, "__模块") 模块 = make_module(模块, _module_class, 编译单元) 为 方法名称, 示例输入 在 输入.项目(): 如果 方法名 == 前进: # "forward" 是一个特殊情况,因为我们需要追踪 # `Module.__call__`,它设置了一些额外的追踪,但使用 实际 `Module.forward` 方法的参数名称。 函数 = 修饰 forward_method = getattr(模块, 方法名称) 参数名 = 获取可调用参数名称(forward_method) else: 函数 = getattr(模块, 方法名称) 参数名 = 获取可调用参数名称(函数) 如果 isinstance(示例输入, 字典) 和 example_inputs_is_kwarg 参数: 当用户提供的键名与 forward()方法参数名称不匹配时引发异常 为 key 在 示例输入: 如果 key 不 在 参数名: 合法参数 = [ + ",".连接(参数名) + `]` 提升 名字错误( f''{键}' 不在 forward() 方法的参数中, 合法参数的名称为{合法参数}"" ) 模块._c.从跟踪字典创建方法( 方法名称, 函数, 示例输入, var_lookup_fn, 严格的, _force_outplace, 参数名, _store_inputs, ) else: 示例输入 = make_tuple(示例输入) 模块._c._create_method_from_trace( 方法名称, 函数, 示例输入, var_lookup_fn, 严格的, _force_outplace, 参数名, _store_inputs, ) 检查跟踪方法 = 模块._c._获取方法(方法名称) 将跟踪与从用户指定输入创建的新跟踪进行比对 如果 检查跟踪: 如果 检查输入 is 不 无: _检查追踪( 检查输入, 函数, 检查跟踪方法, 检查公差, 严格的, _force_outplace, 是, _module_class, example_inputs_is_kwarg 参数=example_inputs_is_kwarg 参数, ) else: _检查追踪( [输入] 函数, 检查跟踪方法, 检查公差, 严格的, _force_outplace, 是, _module_class, example_inputs_is_kwarg 参数=example_inputs_is_kwarg 参数, ) 最后: 火炬.算子.跟踪.跟踪模块映射 = 旧模块映射 返回 模块
[文档]def is_tracing(): 返回一个布尔值。 返回“在跟踪中返回`True`(如果在调用函数期间)” 使用 `torch.jit.trace` 跟踪代码,否则为 `False`。 """ 如果 is_scripting()返回 True 返回 False 返回 torch._C._is_tracing()
类
跟踪模块(脚本模块): 禁用脚本元信息 = 真实 def __init__(我, 原始, id 已设置=无, 编译单元=无): # XXX:原可以是 nn.Module 或一个函数! 超级().__init__() 断言 isinstance(原始, 火炬.神经网络.模块) 将 `orig` 的子集复制到一个临时的 nn.Module。 这是一种自定义实际由 create_script_module 编译的内容的方法。 id_set = 设置() 这允许我们通过定义一个新的来保留原始模块的限定名称。 在 torch._jit_internal._qualified_name 中,使用属性_jit_override_qualname 我们有一个特殊情况,会查找此属性以覆盖从 Python 类型系统获取的任何 qualname 我们会从 Python 类型系统中获取 类 QualnameWrapper(火炬.神经网络.模块): 通过 QualnameWrapper._jit_override_qualname = 火炬._jit_internal._qualified_name( # 类型: 忽略[attr-defined] 类型(原始) ) tmp_module = QualnameWrapper() def check_unique(参数): 如果 参数 在 id 已设置: 提升 ValueError( "TracedModules 不支持模块间的参数共享" ) id 已设置.添加(参数) tmp 模块.训练 = 原始.训练 为 名称, 参数 在 原始.参数.项目(): 如果 参数 is 不 无: tmp 模块.参数[名称] = 参数 check_unique(参数) 为 名称, 缓冲区 在 原始._缓冲区.项目(): 如果 缓冲区 is 不 无: tmp 模块._缓冲区[名称] = 缓冲区 check_unique(缓冲区) 为 名称, val 在 原始.字典.项目(): 如果 ( 火炬._C._jit_is_script_object(val) 和 名称 不 在 原始.参数 和 名称 不 在 原始._缓冲区 ): setattr(tmp 模块, 名称, val) 如果 原始._backward_hooks: 提升 ValueError( "具有反向钩子分配的模块无法编译:" + 字符串(原始) ) 为 名称, 子模块 在 原始.模块.项目(): 如果 子模块 is 无: continue tmp 模块.模块[名称] = make_module( 子模块, 跟踪模块, 编译单元=无 ) 脚本模块 = 火炬.算子.递归.创建脚本模块( tmp 模块, lambda 模块: (), 分享类型=错误, is_tracing=真实 ) 我.字典[_名称] = 类型(原始).__name__ 我.字典[_实际脚本模块] = 脚本模块 为 名称 在 (_参数, _缓冲区, _模块, "训练"): delattr(我, 名称) def 前向(我, *参数, **kwargs): 提升 运行时错误("无法调用子模块的跟踪") def __getattr__(我, 属性): 如果 "_实际脚本模块" 不 在 我.字典: 返回 超级().__getattr__(属性) 返回 getattr(我._实际脚本模块, 属性) def __setattr__(我, 属性, 值): 如果 "_实际脚本模块" 不 在 我.字典: 返回 超级().__setattr__(属性, 值) setattr(我._实际脚本模块, 属性, 值) def _获取名称(我): 返回 我.名称 def 额外表示(我): 返回 foriginal_name={我.名称}" 类 顶级跟踪模块(跟踪模块): 前向: 可调用[..., 任何] = 已缓存的前向() # 类型:忽略[赋值] def 重建(我, C++模块): "" 使用一个 C++模块的实例重建 TopLevelTracedModule 的实例。 参数: cpp_module: 该 TopLevelTracedModule 将围绕其重建的 C++模块。 "文档" 我.字典[_实际脚本模块].重建(C++模块) def _script_if_tracing(函数: 可调用[P, R]) 翻译 可调用[P, R]: @functools.包装(函数) def 包装器(*参数: P.参数, **kwargs: P.kwargs) 翻译 R: 如果 不 is_tracing(): # 不追踪,不做任何事情 返回 函数(*参数, **kwargs) 编译函数: 可调用[P, R] = 脚本(包装器.__原始函数) # 类型: 忽略[attr-defined] 返回 编译函数(*参数, **kwargs) 包装器.__original_fn = fn # 类型: 忽略[attr-defined] 包装器.__脚本跟踪包装器 = 真实 # 类型: 忽略[attr-defined] 返回 包装器 def _get_trace_graph( f, 参数=(), kwargs=无, 严格的=是, _force_outplace=错误, 返回输入=错误, _return_inputs_states=错误, ): """在跟踪函数或模型时返回一个元组。 .. 警告:: 此函数为内部专用,仅应供 ONNX 使用 exporter.如果您尝试通过跟踪来获取图表,请前往 通过公共 API 而不是: trace = torch.jit.trace(nn.LSTMCell(), (输入, 隐藏状态)) trace_graph = trace.graph 跟踪一个函数或模型,返回一个元组,包含执行的 *trace* 以及原始返回值。 如果 return_inputs 为 True,则元组中还包含跟踪输入。 也返回跟踪输入作为元组的一部分。 跟踪保证不会改变被跟踪函数/模块的语义 被跟踪的。 参数: f (torch.nn.Module 或 function):要跟踪的函数或模块。 要追踪。 args(元组或张量):传递给编译的函数/模块的位置参数。 待追踪的函数/模块。假设非元组为 模型需要传递的单个位置参数。 kwargs(dict):传递给函数/模块的关键字参数 要追踪。 示例(追踪一个细胞): .. testcode:: trace = torch.jit.trace(nn.LSTMCell(), (输入, 隐藏状态)) "文档" 如果 kwargs is 无: kwargs = {} 如果 不 isinstance(参数, 元组): args = (参数,) 输出:outs = ONNX 跟踪模块( f, 严格的, _force_outplace, 返回输入, _return_inputs_states )(*参数, **kwargs) 返回 输出:outs

© 版权所有 PyTorch 贡献者。

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

文档

查看 PyTorch 的全面开发者文档

查看文档

教程

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

查看教程

资源

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

查看资源