# 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 额外表示(
我):
返回 f
original_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