快捷键

torch.onnx.verification 的源代码

# mypy: 允许未类型化定义
ONNX 验证模块提供了一套验证 ONNX 模型正确性的工具。

from 未来 导入 注释


全部 = [
    OnnxBackend,
    VerificationOptions,
    "验证",
    "检查导出模型差异",
    "验证信息",
    "验证 ONNX 程序",
    "图信息",
    "OnnxTestCaseRepro 美化打印器",
    "Onnx 测试用例重现",
    "查找不匹配",
    verify_aten_graph,
]

导入 contextlib
导入 复制
导入 dataclasses
导入 datetime
导入 difflib
导入 枚举
导入 functools
导入 输入/输出
导入 itertools
导入 操作系统
导入 tempfile
导入 typing_extensions
导入 警告
from collections.abc 导入 收藏, 映射, 序列
from 打字 导入 任何, 可调用, 联合

导入 numpy  np
导入 numpy.typing  npt

导入 火炬
导入 torch._C._onnx  C_onnx
from 火炬 导入 _C
from torch.onnx 导入 _constants, _实验性, 工具
from torch.onnx._全局_ 导入 全局变量
from torch.onnx._internal 导入 onnx_proto_utils
from torch.onnx._internal.exporter._verification 导入 (
    验证信息,
    verify_onnx_program,
)
from torch.types 导入 


# TODO: 更新弃用信息,推荐使用新类

验证信息.__module__ = torch.onnx.verification
verify_onnx_program.__module__ = torch.onnx.verification

# 以下内容已弃用 ####################################################################

orts_提供者 = (CPU 执行提供者,)

_数值类型 = 并集[数字, 火炬.张量, numpy.纳维数组]
_模型类型 = 并集[火炬.神经网络.模块, 火炬.算子.脚本模块]
输入参数类型 = 并集[火炬.张量, 元组[任何, ...]]
输入关键字参数类型 = 映射[字符串, 任何]
输出类型 = 并集[序列[数值类型] 序列]


[docs]类 OnnxBackend(enum.Enum): """用于导出验证的 ONNX 后端使用的枚举类。""" .. 已弃用:: 2.7 考虑使用 `torch.onnx.export(..., dynamo=True)` 并使用返回的 `ONNXProgram` 来测试 ONNX 模型。 """ REFERENCE = "ONNX 参考评估器" ONNX 运行时 CPU = "CPU 执行提供者" ONNX 运行时 CUDA = "CUDA 执行提供者"
[文档]@dataclasses.dataclass 类 VerificationOptions: ONNX 导出验证的选项。 .. deprecated:: 2.7 考虑使用 ``torch.onnx.export(..., dynamo=True)`` 并使用返回的 ONNXProgram 用于测试 ONNX 模型。 属性: flatten: 如果为 True,将嵌套的列表/元组/字典输入展开成一个扁平化的列表 Tensors for ONNX。如果需要保留嵌套结构,请设置为 False 对于 ONNX,这在导出 ScriptModules 时通常是默认情况。默认为 True。 忽略 None:是否在 torch 输出中忽略 None 类型,这通常是 案例带有跟踪。如果 torch 输出应保持 None 类型,请将其设置为 False。 通常导出 ScriptModules 时是这样的情况。默认为 True。 检查形状:是否检查 PyTorch 和 ONNX Runtime 输出的形状 它们完全相同。将其设置为 False 以允许输出形状广播。 默认为 True。 检查 dtype:是否检查 PyTorch 和 ONNX Runtime 输出的数据类型 默认为 True,保持一致。 后端:ONNX 验证后端。默认为 OnnxBackend.ONNX_RUNTIME_CPU。 rtol:ONNX 与 PyTorch 输出比较中的相对容差。 atol:ONNX 与 PyTorch 输出比较中的绝对容差。 remained_onnx_input_idx: 如果提供,则仅传递指定的输入到 ONNX 模型。当模型中有未使用的输入时,请提供列表。 to the ONNX model. Supply a list when there are unused inputs in the model. 由于未使用的输入将在导出的 ONNX 模型中删除,提供所有输入将导致意外输入时出错。此参数告诉 all inputs will cause an error on unexpected inputs. This parameter tells 输入验证器,该验证器将传递到 ONNX 模型中。 可接受错误百分比:比较中元素不匹配的可接受百分比。 应该是一个介于 0.0 和 1.0 之间的浮点数。 """ flatten: 布尔类型 = True ignore_none: 布尔类型 = True check_shape: 布尔类型 = True check_dtype: 布尔类型 = True backend: OnnxBackend = OnnxBackend.ONNX_RUNTIME_CPU rtol: float = 1e-3 atol: float = 1e-7 remained_onnx_input_idx: Sequence[int] | None = None acceptable_error_percentage: 浮点数 | None = None
定义
_展平元组(元素): 扁平化 = 输入文本为空,请提供需要翻译的文本 t 元素: 如果 isinstance(t, 元组): 扁平化.扩展(_展平元组(t)) else: 扁平化.append(t) 返回 扁平化 # TODO(justinchuby): 在输入为 None 时添加类型检查,通过缩小返回类型 定义 _to_numpy(元素) 翻译 列表 | npt.NDArray: 如果 isinstance(元素, 火炬.张量): 如果 元素.需要梯度: 返回 元素.detach().cpu().numpy() else: 返回 元素.cpu().numpy() 如果...否则 isinstance(元素, (列表, 元组)): 返回 [_to_numpy(输入) 输入 元素] 如果...否则 isinstance(元素, (布尔, int, float)): 返回 numpy.数组(元素) 如果...否则 isinstance(元素, 字典): 扁平化 = 输入文本为空,请提供需要翻译的文本 k 元素: 扁平化.扩展[_to_numpy(k), _to_numpy(元素[k))]) 返回 扁平化 返回 元素 def _inline_flatten_list(输入, 资源列表) 翻译 列表: i 输入: 资源列表.append(i) 如果 isinstance( i, (列表, 元组) ) 否则 _inline_flatten_list(i, 资源列表) 返回 资源列表 def _解包为 numpy(, cast_onnx_accepted=) 翻译 列表: 解包的值 = 输入文本为空,请提供需要翻译的文本 : 解包值.扩展( 工具.解包量化张量(, cast_onnx_accepted=cast_onnx_accepted) ) 返回 [_to_numpy(v) v 解包值] def 运行 onnx(ONNX 会话, 输入) 翻译 输出类型: 关键词输入 = {} 如果 输入 isinstance(输入[-1] 字典): 关键词输入 = 输入[-1] 输入 = 输入[-1] 输入 = _解包为 numpy(_展平元组(输入)) ort 输入 = {} 输入名称, 输入 kw 输入.项目(): ort 输入[输入名称] = _to_numpy(输入) 输入 = _to_numpy(输入) 如果 有属性(ONNX 会话, 获取输入): # onnxruntime.InferenceSession 输入名称 = [i.名称 i ONNX 会话.获取输入()] 如果...否则 有属性(ONNX 会话, 输入名称): # onnx 参考参考评估器 输入名称 = ONNX 会话.输入名称 else: 提升 ValueError(f"未知 ONNX 后端类型:"{类型(ONNX 会话)}.") i, 输入 列举(输入): 如果 i == 长度(输入名称) 或者 输入名称[i] ort 输入: 提升 ValueError( f"位置输入太多。输入:"{输入}. 关键字输入:{kw 输入}. f输入名称:{输入名称} ) ort 输入[输入名称[i]] = 输入 onnx_outs = ONNX 会话.run(, ort 输入) 返回 onnx_outs def _ort 会话( 模型: 字符串 | 输入/输出.BytesIO, ort_providers: 序列[字符串] = orts_提供者 ): 尝试: 导入 onnxruntime # type: ignore[import] 除了 导入错误 e: 提升 导入错误("onnxruntime 是导出验证所必需的。") from e 如果 ort_providers is : ort_providers = orts_提供者 会话选项 = onnxruntime.SessionOptions() 抑制 ort 警告。 0:详细,1:信息,2:警告。3:错误,4:致命。默认为 2。 会话选项.日志严重级别 = 3 ort_session = onnxruntime.推理会话( 模型 如果 isinstance(模型, 字符串) 否则 模型.获取值(), 会话选项, 提供者=ort_providers, ) 返回 ort_session def _onnx 参考评估会话(模型: 字符串 | 输入/输出.BytesIO): 尝试: 导入 onnx from onnx 导入 reference onnx 参考 # 类型: 忽略[attr-defined] 除了 导入错误 异常: 提升 导入错误("onnx >= 1.13 是参考评估器所必需的。") from exc 协议 = ( onnx.加载(模型) # 类型: 忽略[attr-defined] 如果 isinstance(模型, 字符串) 否则 onnx.从字符串加载模型(模型.获取值()) # 类型: 忽略[attr-defined] ) onnx 会话 = onnx 参考.参考评估器(proto) 返回 onnx 会话 def _onnx 后端会话(模型: 字符串 | 输入/输出.BytesIO, 后端: Onnx 后端): 如果 后端 == Onnx 后端.参考: onnx 会话 = _onnx 参考评估会话(模型) 如果...否则 后端 {Onnx 后端.ONNX 运行时 CPU, Onnx 后端.ONNX 运行时 CUDA}: onnx 会话 = _ort 会话(模型, (后端.,)) else: 提升 ValueError(f不支持的后端:{后端}") 返回 onnx 会话 def 在 NumPy 中比较 ONNX 和 PyTorch 的输出( ONNX 输出: 输出类型, pt_outs: 输出类型, 选项: 验证选项, ): 断言 长度(ONNX 输出) == 长度(pt_outs), ( fONNX 运行时输出数量不同:({长度(ONNX 输出)})PyTorch:({长度(pt_outs)})" ) 可接受错误百分比 = 选项.可接受错误百分比 如果 可接受错误百分比 ( 可接受错误百分比 > 1.0 或者 可接受错误百分比 < 0.0 ): 提升 ValueError( 如果设置,可接受错误百分比应在 0.0 和 1.0 之间 ) ort_out, pt_out zip(ONNX 输出, pt_outs): 尝试: # TODO: 一旦解决所有形状不一致的问题后,请移除 `check_shape` 选项。 如果 选项.检查形状: # 允许不同的但可广播的输出形状。 ort_out, pt_out = numpy.广播数组(ort_out, pt_out) 火炬.测试.断言关闭( ort_out, pt_out, 相对误差=选项.相对误差, 精度=选项.精度, 检查数据类型=选项.检查数据类型, 等于 NaN=, ) 除了 断言错误 e: 如果 可接受错误百分比: 错误百分比 = 1 - numpy.总和( numpy.isclose(ort_out, pt_out, 相对误差=选项.相对误差, 精度=选项.精度) ) / numpy.生产(ort_out.形状) 如果 错误百分比 <= 可接受错误百分比: 警告.警告( f"抑制的断言错误:"输入文本翻译为简体中文为:\n{e}.输入文本翻译为简体中文为:\n" f"错误百分比"{error_percentage} " f"在可接受范围内"{可接受错误百分比} ) continue 如果 ort_out.dtype == numpy.uint8 或者 ort_out.dtype == numpy.int8: 警告.警告(ONNX 输出已量化) 如果 pt_out.dtype == numpy.uint8 或者 pt_out.dtype == numpy.int8: 警告.警告("PyTorch 输出已量化") 提升 def _比较 onnx 和 pytorch 输出( ONNX 输出: 输出类型, pt_outs: 任何, 选项: 验证选项, ): "" 比较 ONNX 和 PyTorch 的输出。 参数: onnx_outs: ONNX 后端输出。 pt_outs: PyTorch 输出。 选项:验证选项。 抛出异常: AssertionError:如果 ONNX 模型和 PyTorch 模型的输出在指定精度上不相等。 ValueError:如果提供的参数无效。 ValueError:如果提供的参数无效。 "文档" 如果 选项.忽略 None。: # torch.jit._flatten 过滤 None 类型。 pt_outs, _ = 火炬.算子._flatten(pt_outs) else: pt_outs = _inline_flatten_list[pt_outs] [] pt_outs_np = _解包为 numpy(pt_outs, cast_onnx_accepted=错误) onnx_outs = _inline_flatten_list(ONNX 输出, [] 在 NumPy 中比较 ONNX 和 PyTorch 的输出(onnx_outs, PyTorch 输出(NumPy 格式), 选项) def 准备输入数据供 PyTorch 使用(参数, kwargs): 准备输入以执行 PyTorch 模型。 在将输入发送到 PyTorch 模型之前,对输入的任何未来更改/格式化都应在该函数中完成。 该函数应处理发送到 PyTorch 模型之前的输入的任何更改/格式化。 参数: args:PyTorch 模型前向方法的定位参数。 kwargs:PyTorch 模型前向方法的键值参数。 返回: args:PyTorch 模型前向方法的定位参数。 kwargs:PyTorch 模型前向方法的键值参数。 "文档" 如果 isinstance(参数, (火炬.张量, 字典)): args = (参数,) # 在位操作将更新输入张量数据。 # 因此,在每次前向调用之前都会复制输入。 args = 复制.深拷贝(参数) 如果 kwargs: kwargs = 复制.深拷贝(kwargs) else: kwargs = {} 返回 参数, kwargs def _prepare_input_for_export(参数, kwargs): """准备输入以导出 ONNX 模型。 在将输入发送到处理之前,对输入进行任何未来的更改/格式化。 应在此函数中实现 :func:`torch.onnx.export` api。 参数: args:PyTorch 模型前向方法的定位参数。 kwargs:PyTorch 模型前向方法的键值参数。 返回: onnx_inputs:ONNX 模型导出的位置参数,类似于 `args`。 func:`torch.onnx.export`。 "文档" 参数, kwargs = 准备输入数据供 PyTorch 使用(参数, kwargs) 如果 kwargs 长度(参数) > 0 isinstance(参数[-1] 字典): onnx_inputs = args + ({},) 如果...否则 kwargs: onnx_inputs = args + (kwargs,) else: onnx_inputs = args 返回 onnx_inputs def 准备 ONNX 输入( 参数, kwargs, 剩余的 onnx 输入索引: 序列[int] | , 展平: 布尔值 ): 在 ONNX 后端执行 ONNX 模型之前,准备输入。 在将输入发送到 ONNX 后端之前,对输入进行任何未来的更改/格式化。 此函数中应执行运行。 参数: args:PyTorch 模型前向方法的定位参数。 kwargs:PyTorch 模型前向方法的键值参数。 remained_onnx_input_idx:用于 ONNX 模型执行的输入索引。 展平:在派发到 ONNX 模型执行之前是否展平输入。 返回: onnx_inputs:在 ONNX 后端中 ONNX 模型执行的定位参数。 "文档" onnx_inputs = _prepare_input_for_export(参数, kwargs) 如果 展平: onnx 输入, _ = 火炬.算子._flatten(onnx 输入) 如果...否则 onnx_inputs onnx 输入[-1] == {}: 处理空 kwargs(通常在 flatten 过程中被移除) onnx_inputs = onnx 输入[-1] 如果 剩余的 onnx 输入索引 is : 返回 [onnx 输入[i] i 剩余的 onnx 输入索引] else: 返回 onnx_inputs 定义 _try_clone_model(模型): 用于在模型状态前向突变的情况下保留原始模型。 尝试: 返回 复制.深拷贝(模型) 除了 异常: 警告.警告( 复制模型失败。模型状态可能在验证期间被突变。 ) 返回 模型 定义 _compare_onnx_pytorch_model( pt_model: _模型类型, onnx 模型文件: 字符串 | 输入/输出.BytesIO, 输入参数: 输入参数类型, 输入参数: 输入关键字参数类型 | , 额外测试输入: 序列[输入参数类型] | , 选项: 验证选项, ): 将 ONNX 模型运行输出与 PyTorch 模型运行输出进行比较。 参数: pt_model: PyTorch 模型。 ONNX 模型文件路径或文件对象。 PyTorch 模型前向方法的定位参数。 PyTorch 模型前向方法的键值参数。 PyTorch 模型额外的定位参数。 前进方法。 选项:验证选项。 抛出异常: AssertionError:如果 ONNX 模型和 PyTorch 模型的输出在指定精度上不相等。 ValueError:如果提供的参数无效。 "文档" onnx 会话 = _onnx 后端会话(onnx 模型文件, 选项.后端) 定义 比较 onnx 与 PyTorch 模型及输入(输入参数, 输入参数): pt 参数, pt 参数字典 = 准备输入数据供 PyTorch 使用(输入参数, 输入参数) # TODO: 移除此行并单独处理模型修改。参见 #77679 pt_model_copy = _try_clone_model(pt_model) pt_outs = pt_model_copy(*pt 参数, **pt_kwargs) onnx_inputs = 准备 ONNX 输入( 输入参数, 输入参数, 选项.剩余的 onnx 输入索引, 选项.展平 ) onnx_outs = 运行 onnx(ONNX 会话, onnx 输入) _比较 onnx 和 pytorch 输出( ONNX 输出=ONNX 输出, pt_outs=pt_outs, 选项=选项, ) 比较 onnx 与 PyTorch 模型及输入(输入参数, 输入参数) 如果 额外测试输入: 测试输入参数 额外测试输入: 比较 onnx 与 PyTorch 模型及输入(测试输入参数, {}) 图形差异: 表示两个图之间差异的类。 定义 __init__(自身, 图_a: _C., 图_b: _C.): 构建一个_GraphDiff 对象。 参数: graph_a (_C.Graph):第一个要比较的图。 图_b (_C.Graph):第二个用于比较的图。 "文档" 自身.图_a = 图_a 自身.图_b = 图_b 定义 __str__(自身): “见函数::func:`diff_report`。” 返回 自身.差异报告() 定义 _缩进(自身, : 字符串) 翻译 字符串: 返回 "输入文本翻译为简体中文为:\n".连接["制表符" + .按行分割()]) 定义 差异报告(自身) 翻译 字符串: 返回图差异的字符串表示。 报告显示了第一个发生分歧的节点对。它还显示了节点对的位置。 节点对的位置。 返回: 图差表示(字符串):图差异的字符串表示。 "文档" 图_a = 自身.图_a 图_b = 自身.图_b 图_a_str = 字符串(图_a) 图_b_str = 字符串(图_b) 如果 图_a_str == 图_b_str: 返回 请提供需要翻译的文本 graph_diff = 差分库.ndiff( 图_a_str.按行分割(), 图_b_str.按行分割() ) 图形差异报告 = [图差异:, 自身._缩进(输入文本翻译为简体中文为:"".连接(图差分))] 节点_a, 节点_b itertools.zip_longest(图_a.节点(), 图_b.节点()): 如果 字符串(节点_a) != 字符串(节点_b): 图形差异报告.append("第一个分叉操作符:") 节点差异 = 差分库.ndiff( 字符串(节点_a).按行分割(), 字符串(节点_b).按行分割() ) 源打印输出 = ["节点差异:", 自身._缩进(输入文本翻译为简体中文为:"".连接(节点差异))] 栈_a = 节点_a.源范围() 如果 node_a 否则 如果 stack_a: source_printout.扩展( ["前源位置:", 自身._缩进(字符串(stack_a))] ) stack_b = 节点_b.源范围() 如果 节点_b 否则 如果 stack_b: source_printout.扩展( ["后者源位置:", 自身._缩进(字符串(stack_b))] ) 图形差异报告.扩展(source_printout) 断开 返回 "输入文本翻译为简体中文为:\n".连接(图形差异报告) 定义 _检查图像差异( 模型: 火炬.神经网络.模块 | 火炬.算子.脚本模块, test_input_groups: 序列[元组[元组[任何, ...] 映射[字符串, 任何]], 导出选项: _实验性.导出选项, 模型转图函数: 可调用[ [ 火炬.神经网络.模块, 元组[任何, ...] 映射[字符串, 任何] _实验性.导出选项, ] _C., ] ) 翻译 字符串: 检查由 `model_to_graph_func` 产生的图在 `test_input_groups` 中是否相同。 参数: 模型:参见 :func:`check_export_model_diff`。 test_input_groups:参见 :func:`check_export_model_diff`。 导出选项:参见 :func:`check_export_model_diff`。 model_to_graph_func: 将 PyTorch 模型转换为 JIT IR 图的函数。 返回: 图差表示(字符串):图差异的字符串表示。 "文档" 如果 长度(test_input_groups) < 2: 提升 ValueError("至少需要两组测试输入进行比较。") 引用 JIT 图 = 参数, kwargs test_input_groups: JIT 图 = 模型转图函数(模型, 参数, kwargs, 导出选项) 如果 引用 JIT 图 is : 引用 JIT 图 = JIT 图 continue 图形差异报告 = 图形差异(ref_jit_graph, JIT 图).差异报告() 如果 图形差异报告: 返回 图形差异报告 返回 请提供需要翻译的文本 定义 从模型中追踪的图形( 模型: 火炬.神经网络.模块 | 火炬.算子.脚本模块, 参数: 元组[任何, ...] kwargs: 映射[字符串, 任何] 导出选项: _实验性.导出选项, ) 翻译 _C.: 作为 ONNX 导出步骤的一部分,从 PyTorch 模型创建一个追踪的 JIT 图。 参数: 模型:参见 :func:`check_export_model_diff`。 参数:参见 :func:`check_export_model_diff`。 关键字参数:参见 :func:`check_export_model_diff`。 导出选项:参见 :func:`check_export_model_diff`。 返回: jit_graph (_C.Graph): 跟踪的 JIT 图。 "文档" 训练 = 导出选项.训练 详细 = 导出选项.详细 工具.导出上下文(模型, 训练, 详细模式): 导出输入 = _prepare_input_for_export(参数, kwargs) 模型 = 工具._预追踪量化模型(模型, 导出输入) JIT 图, _, _, _ = 工具.创建 JIT 图(模型, 导出输入) 返回 JIT 图 定义 从模型生成 ONNX 图( 模型: 火炬.神经网络.模块 | 火炬.算子.脚本模块, 参数: 元组[任何, ...] kwargs: 映射[字符串, 任何] 导出选项: _实验性.导出选项, ) 翻译 _C.: 作为 ONNX 导出步骤的一部分,从 PyTorch 模型导出 ONNX JIT 图。 参数: 模型:参见 :func:`check_export_model_diff`。 参数:参见 :func:`check_export_model_diff`。 关键字参数:参见 :func:`check_export_model_diff`。 导出选项:参见 :func:`check_export_model_diff`。 返回: onnx_graph (_C.Graph):一个 ONNX 即时编译图。 "文档" # TODO:重构 utils.py 以删除上下文设置的重复代码。参见#78834 算子版本 = 导出选项.算子版本 操作导出类型 = 导出选项.操作导出类型 将模块导出为函数 = 导出选项.将模块导出为函数 训练 = 导出选项.训练 详细 = 导出选项.详细 动态轴 = 导出选项.动态轴 输入名称 = 导出选项.输入名称 输出名称 = 导出选项.输出名称 如果 算子版本 is : 算子版本 = _constants.ONNX 默认 opset 工具.设置跟踪模块映射(模型, 将模块导出为函数) 如果 操作符导出类型: 操作导出类型 = _C_onnx.运算符导出类型.ONNX 全局变量.导出 ONNX 算子版本 = 算子版本 全局变量.操作导出类型 = 操作导出类型 工具.导出上下文(模型, 训练, 详细模式): 做常量折叠 = 工具.决定常量折叠( 导出选项.执行常量折叠, 操作符导出类型, 训练 ) 如果 动态轴 is : 动态轴 = {} 工具._验证动态轴(动态轴, 模型, 输入名称, 输出名称) 导出输入 = _prepare_input_for_export(参数, kwargs) 导出输入 = 工具._决定输入格式(模型, 导出输入) onnx 图, _, _ = 工具.模型转图( 模型, 导出输入, 详细模式, 输入名称, 输出名称, 操作符导出类型, 执行常量折叠, 训练=训练, 动态轴=动态轴, ) 返回 onnx_graph 定义 _onnx_graph_from_aten_graph( graph: 火炬., 导出选项: _实验性.导出选项, params_dict: 字典[字符串, 任何] | = , ) 翻译 元组[火炬., 字典[字符串, 任何]] 如果 params_dict is : params_dict = {} 操作导出类型 = 导出选项.操作导出类型 动态轴 = 导出选项.动态轴 或者 {} 输入名称 = 导出选项.输入名称 训练 = 导出选项.训练 做常量折叠 = 导出选项.做常量折叠 算子版本 = 导出选项.算子版本 或者 _constants.ONNX 默认 opset 全局变量.导出 ONNX 算子版本 = 算子版本 全局变量.操作导出类型 = 操作导出类型 做常量折叠 = 工具.决定常量折叠( 执行常量折叠, 操作符导出类型, 训练 ) # TODO: 下面正在进行 aten 图到 onnx 的转换。应该将其抽象为 # torch/onnx/utils.py 中的函数。 = graph.复制() = 工具.优化图( graph, 操作符导出类型, params_dict=params_dict, 动态轴=动态轴, 输入名称=输入名称, ) 如果 训练 is 或者 训练 == _C_onnx.训练模式.评估: params_dict = 火炬._C._jit_pass_onnx_eval_peephole(graph, params_dict) 如果 ( 做常量折叠 算子版本 >= _constants.ONNX 常量折叠最小操作集 ): params_dict = _C._jit_pass_onnx_constant_fold(graph, params_dict, opset 版本) _C._jit_pass_dce 允许删除具有副作用节点的操作(graph) 如果 全局变量.ONNX 形状推理: _C._jit_pass_onnx_graph_shape_type_inference 操作(graph, params_dict, opset 版本) params_dict = _C._jit_pass_onnx_eliminate_unused_items(graph, params_dict) 对于 ONNX 操作集小于 9 的情况,常量只有三种数据类型:float16、float、double。 在这个过程中,将其他数据类型的常量转换为 float/double 并添加类型转换操作符。 如果 算子版本 < 9: _C._jit_pass_onnx_cast_all_constant_to_floating(graph) params_dict = _C._jit_pass_filter_non_tensor_arguments(params_dict) _C._jit_decay_packed_param_input_types(graph) _C._jit_pass_dce 允许删除具有副作用节点的操作(graph) 如果 导出选项.详细模式: 打印(ONNX 图:, graph) 返回 graph, params_dict 定义 _onnx_proto_from_onnx_graph( onnx 图: 火炬., 导出选项: _实验性.导出选项, params_dict: 字典[字符串, 任何] ) 翻译 元组[字节, 映射[字符串, 字节]] 算子版本 = 导出选项.算子版本 或者 _constants.ONNX 默认 opset 动态轴 = 导出选项.动态轴 或者 {} 操作导出类型 = 导出选项.操作导出类型 保持初始化器作为输入 = 工具.决定保留初始输入( 导出选项.将初始化器作为输入保留, 操作符导出类型, opset 版本, ) 添加节点名称的值 = 工具.决定添加节点名称(, 操作符导出类型) 自定义操作集 = 导出选项.自定义操作集 或者 {} proto, 导出映射, _, _ = onnx 图.导出 ONNX( # 类型: 忽略[attr-defined] params_dict, opset 版本, 动态轴, 错误, 操作符导出类型, 导出选项.详细模式, 将初始化值保持为 IP, 自定义算子集, 添加节点名称, 输入文本翻译为简体中文为:"", {}, ) 返回 proto, export_map
[文档]def check_export_model_diff( 模型: torch.nn.Module | torch.jit.ScriptModule, test_input_groups: Sequence[tuple[tuple[Any, ...], Mapping[str, Any]]], export_options: _experimental.ExportOptions | None = None, ) -> 字符串 验证导出模型在不同输入组之间的差异。 每个输入组导出一张图。然后比较导出的图 彼此之间,并报告第一对节点的差异。此函数 首先检查 jit 图。如果没有发现差异,然后检查 onnx 图 除非另有说明,jit/ONNX 图应保持相同 输入用于导出的输入之一。差异意味着导出的图 在运行在其他输入组时通常不准确,这通常会导致 运行时错误或输出不匹配。 Args: 模型 (torch.nn.Module 或 torch.jit.ScriptModule):要导出的模型。 测试输入组(Sequence[Tuple[Tuple[Any, ...], Mapping[str, Any]]]):一个序列 输入组用于导出模型。每个输入组是一对 (args, kwargs) export_options (_实验性的.ExportOptions, 可选): 一个 _实验性的.ExportOptions 对象,用于控制导出行为。 返回: str: 包含导出模型差异的字符串。 ```python # 假设输入文本为: input_text = '"""' # 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API) def translate_to_simplified_chinese(text): # 这里应该调用真实的翻译 API 进行翻译 # 由于示例中不使用真实的 API,以下为模拟翻译结果 return text # 输出翻译结果 translated_text = translate_to_simplified_chinese(input_text) print(translated_text) ``` export_options = ( _experimental.ExportOptions() if export_options is None else export_options ) jit_diff_report = _check_graph_diff( 模型,测试输入组,导出选项,从模型中追踪的图 ) 如果启用 jit_diff_report: 返回 jit_diff_report return _check_graph_diff( 模型, 测试输入组, 导出选项, _onnx_graph_from_model )
[文档]@typing_extensions.已弃用( "torch.onnx.verification.* 已弃用。请考虑使用 torch.onnx.export(..., dynamo=True) " 使用 ONNXProgram 测试 ONNX 模型, 分类=, ) 定义 核实( 模型: _模型类型, 输入参数: 输入参数类型, 输入参数: 输入关键字参数类型 | = , 执行常量折叠: 布尔值 = , 动态轴: 映射[字符串, 映射[int, 字符串] | 映射[字符串, 序列[int]]] | = , 输入名称: 序列[字符串] | = , 输出名称: 序列[字符串] | = , 训练: _C_onnx.训练模式 = _C_onnx.训练模式.评估, opset 版本: 整型 | = , 将初始化器作为输入保留: 布尔值 = , 详细模式: 布尔值 = 错误, 固定批次大小: 布尔值 = 错误, 使用外部数据: 布尔值 = 错误, 额外测试输入: 序列[输入参数类型] | = , 选项: 验证选项 | = , ): 验证模型导出为 ONNX 与原始 PyTorch 模型是否一致。 已弃用 考虑使用 `torch.onnx.export(..., dynamo=True)` 并使用返回的 测试 ONNX 模型的 ``ONNXProgram``。 参数: 模型:参见 :func:`torch.onnx.export`。 输入参数:参见 :func:`torch.onnx.export`。 输入关键字参数:参见 :func:`torch.onnx.export`。 做常数折叠:参见 :func:`torch.onnx.export`。 dynamic_axes: 请参阅 :func:`torch.onnx.export`。 input_names: 请参阅 :func:`torch.onnx.export`。 output_names: 请参阅 :func:`torch.onnx.export`。 training: 请参阅 :func:`torch.onnx.export`。 opset_version: 请参阅 :func:`torch.onnx.export`。 keep_initializers_as_inputs: 请参阅 :func:`torch.onnx.export`。 verbose: 请参阅 :func:`torch.onnx.export`。 fixed_batch_size: 已废弃的参数,仅由 rnn 测试用例使用。 使用外部数据:明确指定是否导出包含外部数据的模型。 附加测试输入:元组列表。每个元组是一组 输入参数以进行测试。目前仅支持 `*args`。 选项:控制验证行为的 VerificationOptions 对象。 抛出异常: AssertionError:如果 ONNX 模型和 PyTorch 模型的输出在指定精度上不相等。 ValueError:如果提供的参数无效。 ValueError:如果提供的参数无效。 "文档" 如果 选项 is : 选项 = 验证选项() 如果 训练 == 火炬.onnx.训练模式.训练: 模型.训练() 如果...否则 训练 == 火炬.onnx.训练模式.评估: 模型.评估() 火炬.不梯度(), contextlib.退出栈() : 模型_f: 字符串 | 输入/输出.BytesIO = 输入/输出.BytesIO() 如果 使用外部数据: 临时目录路径 = .进入上下文(临时文件.临时目录()) 模型_f = os.路径.连接(临时目录路径, "模型.onnx") 导出输入 = _prepare_input_for_export(输入参数, 输入参数) # TODO(#77679): 移除此条并单独处理模型修改。 模型复制 = _try_clone_model(模型) 工具._export( 模型, 导出所需输入, 模型_f, opset 版本=opset 版本, 执行常量折叠=执行常量折叠, 将初始化器作为输入保留=将初始化器作为输入保留, 动态轴=动态轴, 输入名称=输入名称, 输出名称=输出名称, 固定批次大小=固定批次大小, 训练=训练, 详细模式=详细模式, ) _compare_onnx_pytorch_model( pt_model=模型副本, onnx 模型文件=模型_f, 输入参数=输入参数, 输入参数=输入参数, 额外测试输入=额外测试输入, 选项=选项, )
[文档]@typing_extensions.已弃用( "torch.onnx.verification.* 已弃用。请考虑使用 torch.onnx.export(..., dynamo=True) " 并使用 ONNXProgram 测试 ONNX 模型 ) 定义 验证 aten 图( graph: 火炬., 输入参数: 元组[任何, ...] 导出选项: _实验性.导出选项, params_dict: 字典[字符串, 任何] | = , 验证选项: 验证选项 | = , ) 翻译 元组[断言错误 | , 火炬., 输出类型, 输出类型]: 验证将 aten 图导出为 ONNX 与原始 PyTorch 模型的一致性。 已弃用 考虑使用 `torch.onnx.export(..., dynamo=True)` 并使用返回的 测试 ONNX 模型的 ``ONNXProgram``。 "文档" 如果 验证选项 is : 验证选项 = 验证选项() 如果 params_dict is : params_dict = {} 原始的 JIT 图 = = graph.复制() 执行 aten 图并获取参考 torch jit 输出。 图输入 = 列表(graph.输入()) JIT 输入 = 元组[参数 参数 输入参数 如果 参数 is ]) 权重 = [params_dict[v.调试名称()] v 图输入[长度(JIT 输入) ]] 断言 所有(w is w 权重) # TODO: 仅在检测到 Graph 中的突变时复制参数。 JIT 输入 = 复制.深拷贝(JIT 输入) JIT 输入与参数 = JIT 输入 + 元组(权重) jit 输出 = 火炬._C._jit 解释图(graph, jit 输入和参数) # 类型: 忽略[attr-defined] 如果 isinstance(jit_outs, (列表, 元组)): jit 输出 = [jit_outs] 将 aten 图转换为 onnx 图。 graph, onnx_params_dict = _onnx_graph_from_aten_graph( graph, 导出选项, params_dict ) proto, export_map = _onnx_proto_from_onnx_graph( graph, 导出选项, onnx_params_dict ) 模型_f: 字符串 | 输入/输出.BytesIO = 输入/输出.BytesIO() onnx 协议工具._导出文件(proto, 模型_f, 导出映射) # 备注:验证不稳定。尝试捕获以输出调试信息。 尝试: # 备注:输入可能被 dce'ed,因此我们需要从输入参数中移除这些。 新输入名称 = {v.调试名称() v graph.输入()} 新输入参数 = 输入文本为空,请提供需要翻译的文本 v, 参数 zip(原始 jit 图.输入(), 输入参数): 如果 v.调试名称() 新输入名称: 新输入参数.append(arg) 输入参数 = 元组(新输入参数) onnx_inputs = 准备 ONNX 输入( 输入参数, {}, 验证选项.剩余的 onnx 输入索引, 验证选项.展平, ) onnx 会话 = _onnx 后端会话(模型_f, 验证选项.后端) onnx_outs = 运行 onnx(ONNX 会话, onnx 输入) 删除 onnx 会话 释放设备内存 尝试: _比较 onnx 和 pytorch 输出( onnx_outs=onnx_outs, pt_outs=jit_outs, 选项=验证选项, ) 除了 断言错误 e: 返回 e, graph, jit_outs, onnx_outs 返回 , graph, jit_outs, onnx_outs 除了 异常 e: 打印("验证过程中出现意外错误。") 打印("jit 图:", 原始 jit 图) 打印(onnx 图:, graph) 提升 e
[文档] 图信息美化打印器: 图信息: 图信息 | 上方打印机: 图形信息美化打印机 | 下方打印机: 图形信息美化打印机 | 图结构_lambdas: 映射[int, 字符串] 连接器_str_lambdas: 映射[int, 字符串] 子节点_str_lambdas: 映射[int, 字符串] 定义 __init__(自身, 图信息: 图信息 | ): 自身.图信息 = 图信息 如果 ( 图信息 is 图信息.上层图信息 is 图信息.下层图信息 is ): 自身.上方打印机 = 图信息美化打印器(图信息.上层图信息) 自身.下位打印机 = 图信息美化打印器(图信息.下位图信息) else: 自身.上方打印机 = 自身.下位打印机 = 定义 总行数(自身) 翻译 int: 如果 自身.图信息 is : 返回 1 如果 自身.上方打印机 自身.下方打印机: 返回 ( 自身.上方打印机.总行数() + 自身.下方打印机.总行数() + 1 ) 返回 2 # 两行:节点数 + ID。 定义 节点数量段字符串(自身) 翻译 字符串: 如果 自身.图信息 is : 返回 "..." 节点数量 = 自身.图信息.必要节点数() 存在差异 = 自身.图信息.存在差异() 错误节点类型 = ( f“(”{自身.图信息.必要节点类型().流行()})" 如果 节点数量 == 1 存在差异 否则 请提供需要翻译的文本 ) 返回 f"{节点数量} {'X' 如果 存在差异 否则 chr(10003)} {错误节点类型}" 定义 _graph_id_segment_str(自身) 翻译 字符串: 如果 自身.图信息 is : 返回 请提供需要翻译的文本 返回 f"id: "{自身.图信息.id}" 定义 最大分段列数(自身) 翻译 int: 返回 最大值( 地图(长度, (自身.节点数量段字符串(), 自身._graph_id_segment_str())) ) 定义 _graph_segment_str_at_line(自身, : int) 翻译 字符串: 获取给定行处的图段的字符串表示 如果 == 0: 结果字符串 = 自身.节点数量段字符串() 结果字符串 += 输入文本为空,请提供需要翻译的文本 * (自身.最大分段列数() - 长度(结果字符串)) 返回 结果字符串 如果 == 1: 结果字符串 = 自身._graph_id_segment_str() 结果字符串 += 输入文本为空,请提供需要翻译的文本 * (自身.最大分段列数() - 长度(结果字符串)) 返回 结果字符串 如果 0 <= < 自身.总行数(): 返回 输入文本为空,请提供需要翻译的文本 * 自身.最大分段列数() 返回 请提供需要翻译的文本 定义 行连接分段字符串(自身, : int) 翻译 字符串: 获取给定行的连接器段字符串。 如果 自身.上方打印机 is 自身.下位打印机 is : 返回 请提供需要翻译的文本 总行数 = 自身.上方打印机.总行数() 如果 自身.上方打印机 否则 1 下方总行数 = 自身.下方打印机.总行数() 如果 自身.下位打印机 否则 1 如果 == 0: 返回 " __" 如果...否则 < 总行数 + 1: 返回 " | " 如果...否则 == 总行数 + 1: 返回 " |__" 如果...否则 < 总行数 + 下方总行数 + 1: 返回 " " 返回 请提供需要翻译的文本 定义 _children_str_at_line(自身, : int) 翻译 字符串: 获取给定行下子元素的字符串表示。 递归调用 `_str_at_line` 在子节点上。 "文档" 如果 自身.上方打印机 is 自身.下位打印机 is : 返回 请提供需要翻译的文本 总行数 = 自身.上方打印机.总行数() 如果 自身.上方打印机 否则 1 下方总行数 = 自身.下方打印机.总行数() 如果 自身.下位打印机 否则 1 如果 0 <= < 上方总行数: 返回 ( 自身.上方打印机._str_at_line() 如果 自身.上方打印机 否则 "..." ) 如果...否则 总行数 < < 总行数 + 下方总行数 + 1: 返回 ( 自身.下方打印机._str_at_line( - 总行数 - 1) 如果 自身.下位打印机 否则 "..." ) 返回 请提供需要翻译的文本 定义 _str_at_line(自身, : int) 翻译 字符串: 获取给定行处的图字符串表示。 返回 ( 自身._graph_segment_str_at_line() + 自身.行连接分段字符串() + 自身._children_str_at_line() ) 定义 美化打印(自身): 如果 自身.图信息 is : 打印() 返回 # 打印树。 打印(树:.中心(80, 等于)) 总行数 = 自身.总行数() 范围(总行数): 打印(自身._str_at_line().去除字符串右侧空白字符()) 如果 自身.图信息.存在差异(): # 概括存在差异的叶子子图。 打印("差异叶子子图:".中心(80, 等于)) 打印( [ 图信息.标识符 图信息 自身.图信息.所有误匹配叶图信息() ] ) 节点类型不匹配的总结 不匹配的节点类型: 字典[字符串, int] = {} 图信息 自身.图信息.所有误匹配叶图信息(): 节点类型 = 图信息.必要节点类型() 如果 长度(节点类型) == 1: 节点种类 = 节点类型.流行() 不匹配的节点类型[节点类型] = ( 不匹配的节点类型.获取(节点类型, 0) + 1 ) 打印("不匹配节点类型:".中心(80, 等于)) 打印(不匹配的节点类型) else: 打印("未找到不匹配。".中心(80, 等于))
[文档] Onnx 测试用例复现: 定义 __init__(自身, 复现目录): 自身.复现目录 = 复现目录 自身.proto, 自身.输入, 自身.输出 = onnx 协议工具.加载测试用例( 复现目录 ) @classmethod 定义 创建测试用例复现( , proto: 字节, 输入, 输出, 目录: 字符串, 名称: 字符串 | = ): 在"{dir}/test_{name}"下创建一个 ONNX 测试用例的副本。 测试用例包含模型以及输入/输出数据。目录结构如下: 结构如下: dir └── test_ └┴┬┬ model.onnx └─┴┴ test_data_set_0 └─┬┬┬ input_0.pb ┌ └── input_1.pb ┌ └── output_0.pb ┌ └── output_1.pb 参数: proto: ONNX 模型 proto. 模型输入 模型输出 保存复现结果的目录 测试用例名称。如未指定,则根据当前时间生成名称 将被生成。 返回: 重复的路径。 "文档" 如果 名称 is : 名称 = 日期时间.日期时间.现在().strftime("%Y_%m_"%d_%H_%M_%S_格式化文件") 返回 onnx 协议工具.导出为测试用例( proto, _to_numpy(输入), _to_numpy(输出), 名称, 目录, ) 定义 验证(自身, 选项: 验证选项): 运行带有 options.backend 的 ONNX 测试用例,并与预期输出进行比较。 参数: options:验证的选项。 提升: AssertionError:如果 options.backend 的输出和预期输出不匹配 ValueError:如果提供的参数无效。 "文档" onnx 会话 = _onnx 后端会话(输入/输出.BytesIO(自身.proto), 选项.后端) 运行输出 = ONNX 会话.run(, 自身.输入) 如果 有属性(ONNX 会话, 获取输出): 输出名称 = [o.名称 o ONNX 会话.获取输出()] 如果...否则 有属性(ONNX 会话, 输出名称): 输出名称 = ONNX 会话.输出名称 else: 提升 ValueError(f"未知 ONNX 会话类型:"{类型(ONNX 会话)}") 预期输出 = [自身.输出[名称] 名称 输出名称] 在 NumPy 中比较 ONNX 和 PyTorch 的输出(运行输出, 预期输出, 选项)
[文档]@typing_extensions.已弃用( "torch.onnx.verification.* 已弃用。请考虑使用 torch.onnx.export(..., dynamo=True) " 并使用 ONNXProgram 测试 ONNX 模型 ) @dataclasses.数据类 图信息: GraphInfo 包含 TorchScript 图及其转换为 ONNX 图的验证信息。 已弃用 考虑使用 `torch.onnx.export(..., dynamo=True)` 并使用返回的 测试 ONNX 模型的 ``ONNXProgram``。 "文档" graph: 火炬. 输入参数: 元组[任何, ...] params_dict: 字典[字符串, 任何] 导出选项: _实验性.导出选项 = dataclasses.字段( 默认工厂=_实验性.导出选项 ) _错误匹配: 断言错误 | = dataclasses.字段(默认=, 初始化=错误) pt_outs: 序列[数值类型] | = dataclasses.字段(默认=, 初始化=错误) 上层图信息: 图信息 | = dataclasses.字段(默认=, 初始化=错误) 下位图信息: 图信息 | = dataclasses.字段(默认=, 初始化=错误) id: 字符串 = dataclasses.字段(默认=输入文本翻译为简体中文为:"") _onnx 图: 火炬. | = dataclasses.字段(初始化=错误, 默认=) _排除节点类型: 冻结集合[字符串] = 冻结集合( {prim::常量, prim::ListConstruct, aten::ScalarImplicit} ) 定义 清晰(自身): 清除之前验证的状态和结果。 自身.匹配错误 = 自身.pt_outs = 自身.onnx 图 = 自身.上层图信息 = 自身.下层图信息 = 定义 美化打印树(自身): 美化打印 `GraphInfo` 树。 每个节点代表一个子图,显示子图中的节点数, 以及子图在 torch 和 ONNX 之间是否存在输出不匹配的勾选标记。 子图的 ID 显示在节点下方。对于任何 通过调用 `graph_info.find_partition(id)` 可以检索子图。 示例:: ==================================== 树:===================================== 5 X __2 X __1 √ id: | id: 0 | id: 00 | | | |__1 X (激活函数) | id: 01 | |__3 X __1 √ id: 1 | id: 10 | |__2 X __1 X (aten::relu) id: 11 | id: 110 | |__1 √ id: 111 =========================== 不匹配的叶子子图:======================== ['01', '110'] ============================= 不匹配的节点类型:======================== {'aten::relu': 2} "文档" 图信息美化打印器(自身).美化打印() 定义 美化打印不匹配(自身, graph: 布尔值 = 错误): 美化显示 torch 与 ONNX 之间的不匹配细节。 参数: graph: 如果为 True,则打印 ATen JIT 图和 ONNX 图。 "文档" 打印(f图分区不匹配信息{自身.id}输入文本翻译为简体中文为:": ".中心(80, 等于)) 如果 graph: 打印("ATen JIT 图".中心(80, 等于)) # TODO: 一个更紧凑的图形打印器。 # * 删除步长、梯度、设备信息。 # * 在单独的一行上显示源位置。 打印(自身.graph) 如果 自身.onnx 图 is : 打印(ONNX 图.中心(80, 等于)) 打印(自身._onnx 图) 如果 自身.存在差异(): 打印("不匹配错误".中心(80, 等于)) 打印(自身._错误匹配) else: 打印("无不匹配".中心(80, 等于)) 定义 存在差异(自身) 翻译 布尔: "如果子图在 torch 和 ONNX 之间存在输出不匹配,则返回 True。" 返回 自身.匹配错误 is 定义 必要节点数(自身) 翻译 int: 返回子图中节点数量,不包括在 `_EXCLUDED_NODE_KINDS` 中的节点。 返回 总和( 1 n 自身..节点() 如果 n.类型() 自身._排除的节点类型 ) 定义 必要节点类型(自身) 翻译 设置[字符串]: 返回子图中节点类型的集合,排除那些在`_EXCLUDED_NODE_KINDS`中的节点类型。 返回 { n.类型() n 自身..节点() 如果 n.类型() 自身._排除的节点类型 } 定义 所有误匹配叶图信息(自身) 翻译 列表[图信息]: 返回所有不匹配的`图信息`对象的列表。 如果 自身.存在差异(): 返回 输入文本为空,请提供需要翻译的文本 无冲突子项 = ( 自身.上层图信息 is 或者 自身.上层图信息.存在差异() ) ( 自身.下层图信息 is 或者 自身.下位图信息.存在差异() ) 如果 无差异子节点: 返回 [自身] 结果 = 输入文本为空,请提供需要翻译的文本 如果 自身.上层图信息 is : 结果 += 自身.上层图信息.所有误匹配叶图信息() 如果 自身.下层图信息 is : 结果 += 自身.下位图信息.所有误匹配叶图信息() 返回 结果 定义 查找分区(自身, id: 字符串) 翻译 图信息 | : 查找具有给定 ID 的`GraphInfo`对象。 如果 标识符 == 自身.id: 返回 self 当前长度 = 长度(自身.id) 如果 长度(id) > 当前长度: 如果 id[当前长度] == "零" 自身.上层图信息 is : 返回 自身.上层图信息.查找分区(id) 如果...否则 id[当前长度] == 1 自身.下层图信息 is : 返回 自身.下位图信息.查找分区(id) 返回 定义 导出重试( 自身, 复现目录: 字符串 | = , 名称: 字符串 | = ) 翻译 字符串: 将子图及其输入/输出数据导出为 ONNX 格式,以便重现。 重现目录将包含以下文件: dir └── test_ └┴┬┬ model.onnx └─┴┴ test_data_set_0 └─┬┬┬ input_0.pb ┌ └── input_1.pb ┌ └── output_0.pb ┌ └── output_1.pb 参数: repro_dir: 导出重放文件的目录。默认为当前工作目录,如果为空则使用。 working directory if None. 测试案例文件夹的可选名称:“test_{name}”。 返回: 导出重放目录的路径。 "文档" 如果 复现目录 is : 复现目录 = os.获取当前工作目录() 复现目录 = os.路径.连接(复现目录, onnx 调试) onnx 图, onnx_params_dict = _onnx_graph_from_aten_graph( 自身., 自身.导出选项, 自身.params_dict ) proto, _ = _onnx_proto_from_onnx_graph( onnx 图, 自身.导出选项, onnx_params_dict ) 返回 Onnx 测试用例复现.创建测试用例复现( proto, 自身.输入参数, 自身.pt_outs, 复现目录, 名称 ) 定义 _图分区轴心(自身) 翻译 int: 找到分区图的中心点索引。 中心点是分割图的节点。每个部分应该 除去非必要操作后,具有相同数量的节点 `_EXCLUDED_NODE_KINDS`,例如`prim::Constant`。 如果图中的节点数为奇数,则上半部分将多一个节点。 如果图中没有可以划分的节点,则返回-1。 返回: 轴点索引。 "文档" 包含的节点索引。 = [ i i, n 列举(自身..节点()) 如果 n.类型() 自身._排除的节点类型 ] 半索引 = 长度(包含节点索引) // 2 - 1 如果 半索引 >= 0 长度(包含节点索引) > 半索引: 返回 包含节点索引[半索引] + 1 返回 -1 定义 分区上层图(自身) 翻译 火炬.: 轴心 = 自身._图分区轴心() 如果 轴心 == -1: 返回 火炬.() = 自身..复制() # 复制以不修改父图。 原始输出 = 列表(.输出()) 定义 处理桥接值为大写( 新输出: 列表[火炬.] 桥接值: 火炬.价值 ) 翻译 火炬.: 将桥接值添加为上层图输出。 新输出.append(桥接值) 返回 桥接值 新输出: 列表[火炬.] = 输入文本为空,请提供需要翻译的文本 处理桥接值上限 = functools.偏函数( 处理桥接值为大写, 新输出 ) _, 删除节点, 完整上节点集, _ = 自身.分区节点( , 轴心, 处理桥接值上限 ) _ 列举(原始输出): .删除输出(0) 输出 新输出: .注册输出(输出) 节点 反转(删除节点): 节点.摧毁() i, 输入 反转(列表(列举(列表(.输入())))): 如果 ( 节点使用(输入, 完整上节点集) 输入 新输出 ): 尝试: .删除输入(i) 除了 运行时错误 e: 打印(输入, ) 提升 e 返回 定义 _分区低阶图(自身) 翻译 火炬.: 轴心 = 自身._图分区轴心() 如果 轴心 == -1: 返回 火炬.() = 自身..复制() # 复制以不修改父图。 原始输出 = 列表(.输出()) 原始输入 = 列表(.输入()) 定义 __处理桥接值(下)( : 火炬., 桥接值: 火炬.价值 ) 翻译 火炬.: 将桥接值添加为下桥图输入。 新输入 = .添加输入() 桥接值.将所有使用替换为(新输入) 新输入.复制元数据(桥接值) 返回 新输入 处理下级桥接值 = functools.偏函数( __处理桥接值(下), ) 上层节点, 下级节点, _, 完整下级节点集 = 自身.分区节点( , 轴心, 处理下级桥接值 ) 新输出 = [ 输出 输出 原始输出 如果 由...制作(输出, 下级节点) ] _ 列举(原始输出): .删除输出(0) 输出 新输出: .注册输出(输出) 输入 原始输入: 如果 节点使用(输入, 完整下节点集): 新输入 = .添加输入() 输入.将所有使用替换为(新输入) 新输入.复制元数据(输入) 节点 反转(上层节点): 如果 节点 完整下节点集: 尝试: 节点.摧毁() 除了 运行时错误 e: 打印(节点, ) 提升 e _ 原始输入: .删除输入(0) 返回 定义 分区节点( 自身, 节点: 火炬.节点, 完整上节点集: 设置[火炬.节点] 完整下节点集: 设置[火炬.节点] 原始图输出: 设置[火炬.] 覆盖桥值: 设置[火炬.] 处理桥梁值: 可调用[[火炬.] 火炬.] ): 如果 节点 完整下节点集: 返回 如果 ( _节点有使用者_(节点, 完整下节点集) 节点.类型() 自身._排除的节点类型 ): 完整下节点集.更新(_所有节点[节点])) 输入 节点.输入(): 如果 输入 覆盖桥值: continue 自身.分区节点( 输入.节点(), 完整上节点集, 完整下节点集, 原始图输出, 覆盖桥值, 处理桥梁值, ) else: 输出 节点.输出(): 如果 输出 覆盖桥值: continue 如果 ( 节点使用(输出, 完整下节点集) 或者 输出 原始图输出 ): 覆盖桥值.添加(处理桥梁值(输出)) 定义 分区节点( 自身, : 火炬., 轴心: int, 处理桥梁值: 可调用[[火炬.] 火炬.] ) 输入文本: -> 翻译: -> 元组[列表[火炬.节点] 列表[火炬.节点] 设置[火炬.节点] 设置[火炬.节点]] 节点 = 列表(.节点()) 上层节点 = 节点[轴心] 下层节点 = 节点[轴心] `上层节点` 和 `完整的上层节点集` 的区别在于后者 # 递归包含 `upper_nodes` 的子块中的节点。 # 同样适用于 `lower_nodes` 和 `complete_lower_nodes_set`。 # 此外,`complete_lower_nodes_set` 将包括从 `upper_nodes` 确定要复制到 `lower_nodes` 的节点。 # # 确定要复制到 `lower_nodes` 的节点。 完整的节点集 = _所有节点(上层节点) 完整下级节点集 = _所有节点(下级节点) 原始图输出 = 设置(.输出()) 桥值是从上层图中产生的值,并被消耗 通过下级图。这些值需要成为上级图输出 # 和低级图输入,以建立交互。 所有图输入均标记为已覆盖。如果任何图输入 需要由下级图使用,则保留在下级图输入中。 覆盖桥值 = 设置(.输入()) 节点 上层节点: 自身.分区节点( 节点, 完整上节点集, 完整下节点集, 原始图输出, 覆盖桥值, 处理桥梁值, ) 返回 ( 上层节点, 下级节点, 完整上节点集, 完整下节点集, ) 定义 _bridge_kwargs(自身): pt_outs = 自身.pt_outs 图输出 = 列表(自身..输出()) 断言 pt_outs is 断言 长度(图输出) == 长度(pt_outs), ( f"{长度(图输出)}{长度(pt_outs)}输入文本翻译为简体中文为:\n图:{自身.}" ) 返回 {v.调试名称(): o for v, o zip(图输出, pt_outs)} 定义 分区图的参数和参数( 自身, : 火炬., 桥接参数: 映射[字符串, _数值类型 | 序列[数值类型]], 完整参数: 映射[字符串, 火炬.张量] 完整参数: 映射[字符串, 火炬.张量] ): 输入名称 = [输入.调试名称() 输入 .输入()] args = 元组(桥接参数[k] k 输入名称 如果 k 桥接参数) args += 元组(完整参数[k] k 输入名称 如果 k 完整参数) params = {k: 完整参数[k] k 输入名称 如果 k 完整参数} 断言 长度(参数) + 长度(参数) == 长度(输入名称), ( f"{长度(参数)} + {长度(参数)}{长度(输入名称)}: {输入名称}" ) 返回 参数, params 定义 验证导出( 自身, 选项: 验证选项 ) 翻译 元组[断言错误 | , 火炬., 输出类型, 输出类型]: "" 验证从 TorchScript IR 图导出到 ONNX 的导出。 将 TorchScript IR 图导出到 ONNX,包括输入、参数和导出。 记录在此对象中的选项。然后根据提供的验证选项验证导出的 ONNX 图。 与提供的验证选项下的原始 TorchScript IR 图进行验证。 参数: 验证选项:验证选项。 返回: 错误:验证过程中抛出的 AssertionError。如果没有错误,则返回 None。 错误被抛出。 onnx_graph:导出的 ONNX 图以 TorchScript IR 格式。 onnx_outs:在`options`中运行导出的 ONNX 模型后的输出。 backend:在`options`中的后端。 运行 TorchScript IR 图输出的结果。 "文档" 返回 验证 aten 图( 自身., 输入参数=自身.输入参数, params_dict=自身.params_dict, 导出选项=自身.导出选项, 验证选项=选项, ) 定义 查找不匹配( 自身, 选项: 验证选项 | = , ): "" 找到 TorchScript IR 图和导出的 ONNX 模型之间的所有不匹配。 二分搜索模型图以找到表现出不匹配的最小子图。 为每个子图创建一个`GraphInfo`对象,记录测试输入和导出选项,以及验证结果。 记录测试输入和导出选项,以及验证结果。 参数: 验证选项:验证选项。 "文档" 自身.清晰() 如果 选项 is : 选项 = 验证选项() 如果 自身.导出选项.详细模式: 打印(自身.) 如果 长度(列表(自身..输出())) == 0: 返回 断言 长度(自身.输入参数) + 长度(自身.params_dict) == 长度( 列表(自身..输入()) ), ( f"图输入数量("{长度(列表(自身..输入()))})与 f"提供的张量参数("{长度(自身.输入参数)} + {长度(自身.params_dict)}). ) 自身._错误匹配, 自身._onnx 图, 自身.pt_outs, _ = 自身.验证导出( 选项 ) 如果 自身.匹配错误 is : 图中未找到不匹配项。 返回 如果 自身.必要节点数() <= 1: 达到叶子节点,不再进行分区。 返回 全部参数 = { k.调试名称(): v k, v zip(自身..输入(), 自身.输入参数) } 完整参数集 = 自身.params_dict 上层图 = 自身.分区上层图() 上层参数, 上层参数集 = 自身.分区图的参数和参数( 上层图, {}, 完整参数, 完整参数集 ) 自身.上层图信息 = 图信息( 上层图, 上层参数, 上层参数, 自身.导出选项, id=自身.标识符 + "0", ) 自身.上层图信息.查找不匹配(选项) 桥接关键字参数 = 自身.上层图信息._bridge_kwargs() 低阶图 = 自身._分区低阶图() 低阶参数, 低阶参数集 = 自身.分区图的参数和参数( 低阶图, 桥接参数, 完整参数, 完整参数集 ) 自身.下层图信息 = 图信息( 低阶图, 低阶参数, 低阶参数值, 自身.导出选项, id=自身.标识符 + "1", ) 自身.下位图信息.查找不匹配(选项)
定义 _所有节点(节点: 收藏[火炬.节点]) 翻译 设置[火炬.节点]: 所有节点 = 设置(节点) n 节点: b n.(): 所有节点.更新(_所有节点(列表(b.节点()))) 返回 所有节点 定义 节点使用(: 火炬., 节点: 收藏[火炬.节点]) 翻译 布尔: 返回 任何(使用.用户 节点 使用 .使用者()) 定义 _节点有使用者_(节点: 火炬.节点, 节点: 收藏[火炬.节点]) 翻译 布尔: 输出 节点.输出(): 如果 节点使用(输出, 节点): 返回 真实 返回 定义 由...制作(: 火炬., 节点: 收藏[火炬.节点]) 翻译 布尔: 返回 .节点() 节点
[文档]@typing_extensions.已弃用( "torch.onnx.verification.* 已弃用。请考虑使用 torch.onnx.export(..., dynamo=True) " 并使用 ONNXProgram 测试 ONNX 模型 ) 定义 查找不匹配( 模型: 火炬.神经网络.模块 | 火炬.算子.脚本模块, 输入参数: 元组[任何, ...] 执行常量折叠: 布尔值 = , 训练: _C_onnx.训练模式 = _C_onnx.训练模式.评估, opset 版本: 整型 | = , 将初始化器作为输入保留: 布尔值 = , 详细模式: 布尔值 = 错误, 选项: 验证选项 | = , ) 翻译 图信息: r找出原始模型和导出模型之间的所有不匹配。 已弃用 考虑使用 `torch.onnx.export(..., dynamo=True)` 并使用返回的 测试 ONNX 模型的 ``ONNXProgram``。 实验。该 API 可能会更改。 这个工具帮助调试原始 PyTorch 模型与导出模型之间的不匹配 ONNX 模型。它通过二分搜索模型图来找到最小的子图 展示出不匹配。 参数: 模型:要导出的模型。 输入参数:模型输入参数。 与 :func:`torch.onnx.export` 中的 `do_constant_folding` 相同。 与 :func:`torch.onnx.export` 中的 `training` 相同。 与 :func:`torch.onnx.export` 中的 `opset_version` 相同。 与 :func:`torch.onnx.export` 中的 `keep_initializers_as_inputs` 相同。 verbose:与 :func:`torch.onnx.export` 中的 `verbose` 相同。 选项:不匹配验证的选项。 返回: 包含不匹配信息的 GraphInfo 对象。 示例:: >>> 导入 torch >>> 导入 torch.onnx.verification >>> torch.manual_seed(0) >>> 设置 opset_version 为 15 >>> # 定义 aten::relu 的自定义符号函数。 >>> # 自定义符号函数错误,这将导致不匹配。 >>> def incorrect_relu_symbolic_function(g, self): ... return self >>> torch.onnx.register_custom_op_symbolic( aten::relu incorrect_relu_symbolic_function ... opset_version=opset_version, ... ) >>> class Model(torch.nn.Module): ... def __init__(self) -> None: ... super().__init__() ... self.layers = torch.nn.Sequential( ... torch.nn.Linear(3, 4), ... torch.nn.ReLU(), ... torch.nn.Linear(4, 5), ... torch.nn.ReLU(), ... torch.nn.Linear(5, 6), ... ) ... def forward(self, x): ... 返回 self.layers(x) >>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_ONNX) >>> graph_info = torch.onnx.verification.find_mismatch( ... 模型(), ... (torch.randn(2, 3),), ... opset_version=opset_version, ... ) ===================== 图划分不匹配信息:===================== ================================ 不匹配错误 ================================ 张量相似度不接近! 不匹配的元素:12 / 12 (100.0%) 最大的绝对差异:0.2328854203224182 在索引 (1, 2) 处(允许达到 1e-07) 最大相对差异:0.699536174352349 在索引(1,3)处(允许误差高达 0.001) ==================================== 树:===================================== 5 X __2 X __1 √ id: | id: 0 | id: 00 | | | |__1 X (激活函数) | id: 01 | |__3 X __1 √ id: 1 | id: 10 | |__2 X __1 X (aten::relu) id: 11 | id: 110 | |__1 √ id: 111 =========================== 不匹配的叶子子图:======================== ['01', '110'] ============================= 不匹配的节点类型:======================== {'aten::relu': 2} "文档" 如果 选项 is : 选项 = 验证选项() 如果 算子版本 is : 算子版本 = _constants.ONNX 默认 opset 从 aten 图开始,在图分区上执行二分搜索以找到操作导出差异。 # TODO: 从 utils.py 的`export`复制到`_optimize_graph`。 如果 训练 == 火炬.onnx.训练模式.训练: 模型.训练() 如果...否则 训练 == 火炬.onnx.训练模式.评估: 模型.评估() 火炬.不梯度(): 导出输入 = _prepare_input_for_export(输入参数, {}) args = 工具._决定输入格式(模型, 导出所需输入) 模型 = 工具._预追踪量化模型(模型, 参数) , 参数, _torch 输出, _模块 = 工具.创建 JIT 图(模型, 参数) params_dict = 工具.获取命名参数字典(, 参数) 工具.应用友好的调试名称(, params_dict) 图信息 = 图信息( , 输入参数, params_dict, _实验性.导出选项( 执行常量折叠=执行常量折叠, 训练=训练, opset 版本=opset 版本, 将初始化器作为输入保留=将初始化器作为输入保留, 详细模式=详细模式, ), ) 图信息.查找不匹配(选项) 图信息.美化打印不匹配() 图信息.美化打印树() 返回 图信息

© 版权所有 PyTorch 贡献者。

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

文档

查看 PyTorch 的全面开发者文档

查看文档

教程

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

查看教程

资源

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

查看资源