# mypy: 允许未类型化定义
来自
未来
导入
注释
__all__ = [
"诊断选项",
"导出选项",
ONNX 运行时选项,
无效导出选项错误,
ONNX 注册表,
不满足依赖错误,
dynamo 导出,
启用模拟模式,
]
导入 abc
导入 contextlib
导入 dataclasses
导入
记录日志
导入
警告
来自
集合
导入 defaultdict
来自
打字
导入
任意,
可调用,
类型检查,
类型变量
来自 typing_extensions
导入
已弃用
导入
火炬
导入 torch._ops
导入 torch.utils._pytree
作为 pytree
来自 torch.onnx
导入
错误
来自 torch.onnx._internal
导入
离线适配器
来自 torch.onnx._internal._lazy_import
导入 onnxscript_apis, onnxscript_ir
作为 ir
来自
torch.onnx._内部诊断
导入
基础设施
来自 torch.onnx._internal.exporter
导入 _constants,
_onnx 程序
来自 torch.onnx._internal.fx
导入 (
分解表,
patcher 作为
修补器,
注册,
)
# 我们只能在类型检查的上下文中从这个模块导入 onnx,以确保
# 'import torch.onnx' 继续工作,即使没有安装 'onnx'。我们完全
在 dynamo_export(通过_assert_dependencies 方式)内部导入 onnx
如果
类型检查:
导入
输入/输出
来自 collections.abc
导入
映射,
序列
导入 onnxruntime
导入 onnxscript
来自 torch._subclasses
导入 fake_tensor
来自 torch.onnx._internal.fx
导入
诊断
_PYTORCH_GITHUB_ISSUES_URL = "https://github.com/pytorch/pytorch/issues"
"PyTorch GitHub 问题页面网址。"
_DEFAULT_FAILED_EXPORT_SARIF_LOG_PATH = "report_dynamo_export.sarif"
"如果导出失败,则写入 SARIF 日志的默认路径。"
日志 =
记录日志.
获取日志记录器(__name__)
诊断选项 =
基础设施.
诊断选项
@dataclasses.数据类
类
ONNX 伪造上下文:
一个用于存储使用 FakeTensor 导出模型上下文的 dataclass。
此数据类存储用于转换的 FakeTensorMode 实例
将真实张量和模型参数转换为假张量。此 :attr:`ONNXFakeContext.fake_mode` 是
在追踪一个 :class:`torch.nn.Module` 到 FX :class:`GraphModule` 时内部重用。
"源代码"
模拟模式:
伪造张量.
模拟 Tensor 模式
用于跟踪模型使用伪造张量和参数的模拟张量模式。
state_dict_paths: 元组[
字符串 |
输入/输出.BytesIO |
字典[
字符串,
任意]] |
无 =
无
包含模型 :meth:`state_dict` 的文件路径列表。
@deprecated(
torch.onnx.dynamo_export 自 2.7.0 版本以来已弃用。请使用 torch.onnx.export(..., dynamo=True) 代替。,
)
类
Onnx 注册表:
ONNX 函数注册表。
已弃用
请使用 ``torch.onnx.export(..., dynamo=True)`` 代替。
该注册表维护了合格名称到固定 opset 版本下符号函数的映射。
它支持注册自定义 onnx-script 函数,并为调度器提供调用适当函数的功能。
调度器用于调度调用到相应的函数。
"源代码"
def 初始化(self) ->
无:
初始化注册表
# 注意:_registry 是将 OpName 映射到 ONNXFunctions 列表的注册表。直接修改此变量是不重要的
# 应当通过公共方法:register_custom_op、get_ops 和 is_registered_op 来访问它。
# 公共方法包括:注册自定义操作、获取操作列表和检查操作是否已注册。
self._注册表:
字典[
注册.
操作名称,
列表[
注册.
ONNX 函数]] = (
defaultdict(列表)
)
self._opset 版本 = _constants.TORCHLIB_OPSET
warnings.警告(
ftorch.onnx.dynamo_export 仅实现 opset 版本{self._opset_version}
目前。如果您需要使用一个“
不同 opset 版本,请使用 register_custom_op 进行注册。
)
self.从 torchlib 初始化注册表()
@property
def opset 版本(self) -> int:
导出器应针对的 ONNX 操作集版本。
返回 self._opset_version
def 从 torchlib 初始化注册表(self) ->
无:
向注册表填充来自 torchlib 的 ATen 函数。
参数:
torchlib_registry:用于填充注册表的 torchlib 注册表。
"源代码"
为
元数据
在 onnxscript_apis.get_torchlib_ops():
内部名称实例 =
注册.
操作名称.
来自限定名称(
元数据.qualified_name
)
符号函数 =
注册.
ONNX 函数(
onnx 函数=
元数据.
函数, # type: ignore[arg-type]
全名操作=
实例内部名称.
合法名称(),
自定义=
错误,
是复杂的=
元数据.
是复杂的,
)
self.注册(
实例内部名称,
符号函数)
def 注册(
self,
内部限定名:
注册.
操作名称,
符号函数:
注册.
ONNX 函数,
) -> 无:
"""将 ONNX 函数注册到算子中。
参数:
internal_qualified_name: 要注册的算子的限定名称:OpName。
symbolic_function: 要注册的 ONNX 函数。
"源代码"
self._注册表[
内部限定名称].
追加(
符号函数)
[文档] def 注册操作(
self,
函数: onnxscript.OnnxFunction | onnxscript.TracedOnnxFunction,
命名空间: str,
操作名称: str,
覆载: str | None = None,
is_complex: 布尔 = False,
) -> None:
"""注册自定义操作:torch.ops....
Args:
函数:用于注册的 onnx-sctip 函数。
命名空间:要注册的操作员的命名空间。
op_name:要注册的操作员名称。
重载:注册运算符的重载。如果它是默认重载,
放任它为空。
is_complex:判断该函数是否处理复数值输入的函数。
抛出:
ValueError:如果名称不是 'namespace::op' 的形式。
"""
internal_name_instance = registration.OpName.from_name_parts(
namespace=namespace, op_name=op_name, overload=overload
)
symbolic_function = registration.ONNXFunction(
onnx_function=function,
op_full_name=internal_name_instance.qualified_name(),
is_custom=True,
is_complex=是复杂的,
)
self._register(内部名称实例, 符号函数)
[文档] def 获取操作函数(
self, 命名空间: str, 操作名称: str, 载荷: str | None = None
) -> list[registration.ONNXFunction] | None:
"""返回给定操作:torch.ops... 的 ONNXFunction 列表。
列表按注册时间排序。自定义操作应该为
列表的后半部分。
参数:
命名空间:获取操作符的命名空间。
op_name:获取的操作符的名称。
运算符获取的重载。如果使用默认重载,
则将其留空。
返回值:
与给定名称对应的 ONNX 函数列表,或如果没有找到则返回 None。
该名称不在注册表中。
"""
internal_name_instance = registration.OpName.from_name_parts(
namespace=namespace, op_name=op_name, overload=overload
)
return self._registry.get(internal_name_instance)
[文档] def is_registered_op(
self, 命名空间: str, 操作名称: str, 超载: str | None = None
-> bool:
返回是否已注册给定操作:torch.ops....
Args:
namespace: 要检查的操作的命名空间。
操作符名称:要检查的操作符名称。
要检查的操作符的重载。如果是默认重载,请留空。
留空为 None。
返回值:
真的如果给定的操作已注册,否则为假。
"""
functions = self.get_op_functions(
namespace=namespace, op_name=op_name, overload=overload
)
返回函数不为空
def _所有已注册的操作(self) ->
集合[
字符串
]:
返回所有已注册函数名的集合。
返回 {
op_name_class.合法名称()
为 op_name_class
在 self.
_注册表.
键()
}
@deprecated(
"torch.onnx.dynamo_export 自 2.7.0 起已弃用。请使用 torch.onnx.export(..., dynamo=True)代替。",
分类=
无,
)
类
导出选项:
TorchDynamo ONNX 导出器的选项,用于影响导出过程。
已弃用
请使用 ``torch.onnx.export(..., dynamo=True)`` 代替。
属性:
dynamic_shapes: 输入/输出张量的形状信息提示。
当为 ``None`` 时,导出器将确定最兼容的设置。
当为 ``True`` 时,所有输入形状都被视为动态。
当为 ``False`` 时,所有输入形状都被视为静态。
诊断选项:导出器的诊断选项。
伪造上下文:用于符号跟踪的伪造上下文。
onnx_registry:用于将 ATen 运算符注册到 ONNX 函数的 ONNX 注册表。
"源代码"
动态形状:
布尔类型 |
无 =
无
输入/输出张量的形状信息提示。
- ``None``:导出器确定最兼容的设置。
- ``True``:所有输入形状都被视为动态。
- ``False``:所有输入形状都被视为静态。
"源代码"
诊断选项: DiagnosticOptions
导出器的诊断选项。
模拟上下文:
ONNX 假上下文 |
无 =
无
用于符号跟踪的假上下文。
onnx 注册表: OnnxRegistry |
无 =
无
"用于将 ATen 运算符注册到 ONNX 函数的 ONNX 注册表。"
def 初始化(
self,
*,
动态形状:
布尔类型 |
无 =
无,
伪造的上下文:
ONNX 伪造上下文 |
无 =
无,
onnx 注册表: OnnxRegistry |
无 =
无,
诊断选项:
诊断选项 |
无 =
无,
):
self.dynamic_shapes = dynamic_shapes
self.模拟上下文 =
模拟上下文
self.ONNX 注册表 =
ONNX 注册表
self.诊断选项 =
诊断选项
或
诊断选项()
@deprecated(
"自 2.7.0 版本起,torch.onnx.dynamo_export 已被弃用。请使用 torch.onnx.export(..., dynamo=True)代替。",
分类=
无,
)
类
已解决的导出选项(
导出选项):
"""整合具有默认值的 :class:`ExportOptions`。
所有未指定的`:class:`ExportOptions`选项都分配了默认值。
这是一个内部类,其 API 可能会在任何时候未经通知而更改。
```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)
```
公共属性必须在下方重新定义,无需从“ExportOptions”中包含“Optional[]”
动态形状:
布尔类型
诊断选项: DiagnosticOptions
模拟上下文:
ONNX 模拟上下文
onnx 注册表:
Onnx 注册表
# 仅私有属性
分解表:
字典[
火炬.
操作符.
操作重载,
可调用]
“一个将算子映射到其分解函数的字典。”
onnxfunction_dispatcher: (
火炬.onnx.
内部.fx.onnxfunction_dispatcher.OnnxFunctionDispatcher
)
用于将 ATen 运算符调度到 ONNX 函数的 ONNX 调度器。
fx_tracer: FXGraphExtractor
用于从模型中提取 FX 图的 FXGraphExtractor 实例。
diagnostic_context: 诊断.DiagnosticContext
导出诊断上下文。负责记录诊断信息。
记录诊断信息,并生成 SARIF 日志。
def 初始化(
self,
选项:
导出选项 |
已解决导出选项,
模型:
火炬.nn.
模块 |
可调用 |
无 =
无,
忽略名称定义
):
来自 torch.onnx._internal.fx
导入 (
防止循环依赖
诊断,
dynamo_graph_extractor,
)
如果 isinstance(
选项,
已解决的导出选项):
self.dynamic_shapes = 选项.dynamic_shapes
self.诊断选项 =
选项.
诊断选项
self.模拟上下文 =
选项.
模拟上下文
self.fx_tracer = 选项.fx_tracer
self.ONNX 注册表 =
选项.
onnx 注册表
self.onnx 函数分发器 =
选项.
onnx 函数分发器
self.分解表 =
选项.
分解表
self.诊断上下文 =
选项.
诊断上下文
否则:
T = 类型变量(
T)
def 解决(
值: T |
无,
备用: T |
可调用
[] T]) -> T:
如果 value
是 not
无:
返回 value
如果
可调用(
备用):
返回
备用()
返回
回退
self.dynamic_shapes = 解决(
选项.
动态形状,
错误)
self.诊断选项 =
解决(
选项.
诊断选项,
诊断选项()
)
self.fx_tracer = Dynamo 图提取器.
动力导出()
self.模拟上下文 =
解决(
选项.
模拟上下文,
无) # type: ignore[arg-type]
self.诊断上下文 =
诊断.
诊断上下文(
torch.onnx.dynamo_export,
火炬.
__版本__,
self.诊断选项,
)
self.onnx_registry = 解决(
选项.onnx_registry,
Onnx 注册表())
self.分解表 = (
分解表.
创建 ONNX 友好分解表(
# 类型:忽略[赋值]
self.ONNX 注册表
)
)
来自 torch.onnx._internal.fx
导入 onnxfunction_dispatcher
self.onnxfunction_dispatcher = (
onnxfunction_dispatcher.OnnxFunctionDispatcher(
self.onnx_registry,
self.诊断上下文,
)
)
为 key
在
目录(
选项):
如果 not
键.
以...开头(
“_”):
# 跳过私有属性
断言
有属性(self,
键), f
"未解决的选项 '"{
键}
'"'
@contextlib.contextmanager
def 启用模拟模式():
启用模拟模式,持续整个上下文过程。
内部它实例化一个 :class:`torch._subclasses.fake_tensor.FakeTensorMode` 上下文管理器
该管理器将用户输入和模型参数转换为 :class:`torch._subclasses.fake_tensor.FakeTensor`
一个 :class:`torch._subclasses.fake_tensor.FakeTensor`
是一个具有运行 PyTorch 代码能力的 :class:`torch.Tensor`,无需通过在 ``meta`` 设备上分配张量来实际进行计算。
因为没有在设备上实际分配数据,这个 API 允许在不实际执行所需的内存占用情况下初始化和导出大型模型。
由于没有在设备上实际分配数据,这个 API 允许在不实际执行所需的内存占用情况下初始化和导出大型模型。
由于没有在设备上实际分配数据,这个 API 允许在不实际执行所需的内存占用情况下初始化和导出大型模型。
非常推荐在导出模型时,如果模型太大无法放入内存,请使用模拟模式初始化模型。
该函数不支持 torch.onnx.export(..., dynamo=True, optimize=True)。
.. 注意::
请在模型导出后,在函数外部调用 ONNXProgram.optimize()。
请在模型导出后,在函数外部调用 ONNXProgram.optimize()进行优化。
示例::
# xdoctest: +REQUIRES(env:TORCH_DOCTEST_ONNX)
>>> 导入 torch
>>> 类 MyModel(torch.nn.Module): # 带有参数的模型
... def __init__(self) -> None:
... super().__init__()
... self.weight = torch.nn.Parameter(torch.tensor(42.0))
... def forward(self, x):
... return self.weight + x
>>> with torch.onnx.enable_fake_mode():
... 当以模拟模式初始化时,模型的参数是模拟张量
... 这些张量不占用内存,因此我们可以初始化大型模型
... my_nn_module = MyModel()
... arg1 = torch.randn(2, 2, 2)
>>> onnx_program = torch.onnx.export(my_nn_module, (arg1,), dynamo=True, optimize=False)
>>> # 保存模型时不包含初始化器(仅架构)
>>> onnx_program.save()
... \"my_model_without_initializers.onnx\",
... include_initializers=False,
... keep_initializers_as_inputs=True,
... )
>>> # 保存模型后应用具体权重,包含初始化器
>>> onnx_program.apply_weights({"weight": torch.tensor(42.0)})
>>> onnx_program.save("my_model_with_initializers.onnx")
.. 警告::
该 API 是实验性的,并且**不**向下兼容。
"源代码"
来自 torch._subclasses
导入 fake_tensor
来自 torch.fx.experimental.symbolic_shapes
导入
形状环境
# 这将覆盖由 `torch._dynamo.export`[1] 创建的内部 `FakeTensorMode` 实例。
# 最好保持它们(构造函数参数)同步,以保持相同的默认行为
# [1] `torch/_dynamo/output_graph.py::InstructionTranslator::OutputGraph.__init__`
仅当在 `FakeTensorMode` 中未调用 `torch.onnx.dynamo_export` 时,才允许混合假/实张量
这是因为模型可以在 `forward(self, *args, **kwargs)` 运行期间创建新的参数
模拟模式 =
伪造张量.
假 Tensor 模式(
allow_non_fake_inputs=not 火炬.
_守卫.
检测伪造模式(),
形状环境=ShapeEnv(
允许标量输出=
错误,
允许动态输出形状操作=
假
),
)
当用户在假模式下调用 `fake_model.load_state_dict(...)` 时需要这个补丁器
补丁器上下文 =
修补器.ONNXTorchPatcher()
模拟上下文 =
ONNX 模拟上下文(
模拟模式=
模拟模式)
与
模拟模式,
修补器上下文:
产生
模拟上下文
模拟上下文.
状态字典路径 =
元组(
修补器上下文.
路径列表,
) # 类型:忽略[赋值]
@deprecated(
"torch.onnx.dynamo_export 自 2.7.0 版本开始已弃用。请使用 torch.onnx.export(..., dynamo=True)代替。",
)
类
ONNX 运行时选项:
"""通过 ONNX Runtime 影响 ONNX 模型执行选项。"""
已弃用
请使用 ``torch.onnx.export(..., dynamo=True)`` 代替。
属性:
""session_options: ONNX Runtime 会话选项。""
""execution_providers: 模型执行期间使用的 ONNX Runtime 执行提供者。""
ONNX Runtime 执行提供者选项。
"源代码"
会话选项:
序列[onnxruntime.SessionOptions] | None =
无
ONNX Runtime 会话选项。
执行提供者:
序列[
字符串 |
元组[
字符串,
字典[
任意,
任意]]] |
无 =
无
"ONNX Runtime 在模型执行期间使用的执行提供程序。"
执行提供程序选项:
序列[
字典[
任意,
任意]] |
无 = None
"ONNX Runtime 执行提供程序选项。"
def 初始化(
self,
*,
会话选项:
序列[onnxruntime.SessionOptions] |
无 =
无,
执行提供者:
序列[
字符串 |
元组[
字符串,
字典[
任意,
任意]]] |
无 =
无,
执行提供者选项:
序列[
字典[
任意,
任意]] |
无 =
无,
):
self.会话选项 =
会话选项
self.执行提供者 =
执行提供者
self.执行提供者选项 =
执行提供者选项
类
FX 图提取器(abc.ABC):
"""FX 图提取器引擎的抽象接口。
该类将 FX 提取逻辑从其他导出逻辑中隔离出来。
这使得可以复用不同 FX 图的单一 ONNX 导出器。
def 初始化(self) ->
无:
超级().
初始化()
self.输入适配器:
输入/输出适配器.
输入适配器 =
io 适配器.
输入适配器()
self.输出适配器:
离线适配器.
输出适配器 =
离线适配器.
输出适配器()
@abc.抽象方法
def 生成 FX(
self,
选项:
已解决的导出选项,
模型:
火炬.nn.
模块 |
可调用,
model_args: 序列[
任意
]
模型参数:
映射[
字符串,
任意
]
) -> 火炬.fx.
图模块:
分析用户 ``模型`` 并生成 FX 图。
参数:
选项:导出选项。
模型:用户模型。
模型参数:模型的定位输入参数。
模型关键字输入参数
返回:
生成的 FX 图。
"源代码"
...
# TODO: 设计遍历 API
@abc.抽象方法
def 预导出步骤(
self,
选项:
已解决导出选项,
原始模型:
火炬.nn.
模块 |
可调用,
效果模块:
火炬.fx.
图模块,
fx_module_args: 序列[
任意
]
):
在 FX 图上应用预导出过程。
预导出过程是 FX 到 FX 图转换,使图
更适合 FX 到 ONNX 的转换。
例如,它可以用于展平模型输入/输出,添加显式
将到图的映射,替换/分解算子,函数化图等。
"源代码"
...
类
出口商:
def 初始化(
self,
选项:
已解决导出选项,
模型:
火炬.nn.
模块 |
可调用,
model_args: 序列[
任意
]
模型参数:
映射[
字符串,
任意
]
):
self.选项 =
选项
断言 self.
选项
是 not
无
self.模型 =
模型
self.模型参数 =
模型参数
self.模型参数 =
模型参数
# TODO: https://github.com/pytorch/pytorch/issues/107714
# NOTE: FXSymbolicTracer 在这个断言中会失败,因为它没有使用 `enable_fake_mode`
来自 torch.onnx._internal.fx
导入 fx_symbolic_graph_extractor
如果 not isinstance(
self.选项.fx_tracer, fx_symbolic_graph_extractor.FXSymbolicTracer
):
self._assert_fake_tensor_mode()
def 导出(self) -> _onnx_program.
ONNX 程序:
来自 torch.export._trace
导入 (
防止循环依赖
默认导出 Dynamo 配置,
)
将`import onnxscript`从`import torch`路径中延迟导入
https://github.com/pytorch/pytorch/issues/103764
来自 torch.onnx._internal.fx
导入
分解跳过
与 (
self.选项.
诊断上下文,
分解跳过.
启用分解跳过(self.
选项),
火炬._dynamo.
配置.
补丁(
dataclasses.asdict(默认导出 Dynamo 配置)
),
):
图模块 = self.
选项.fx_tracer.
生成 FX(
self.选项, self.
模型, self.model_args, self.
模型参数
)
# TODO: 将`import onnxscript`从`import torch`路径中延迟导入
# https://github.com/pytorch/pytorch/issues/103764
来自 torch.onnx._internal.fx
导入 fx_onnx_interpreter
fx_interpreter = fx_onnx_interpreter.FxOnnxInterpreter(
诊断上下文=self.
选项.
诊断上下文
)
onnxscript_graph = fx_interpreter.run(
fx_graph_module=图模块,
onnxfunction_dispatcher=self.选项.onnxfunction_dispatcher,
)
# 注意:在 fake_mode 导出时,过滤掉具有虚假张量的初始化器。
# 否则,ONNX 导出器将失败:RuntimeError: basic_string::_M_construct null
# 无效。
# 具体数据将在 `ONNXProgram.save` 后期初始化时填充。
如果 self.
选项.
模拟上下文
是 not
无:
初始化器包含真实张量:
字典[
字符串,
火炬.
张量] = {}
为 (
初始化器名称,
初始化器,
) 在
onnxscript 图.
初始化器.
项目():
如果 not isinstance(
初始化器,
火炬.
子类.
假 Tensor):
使用真实张量的初始化器[
初始化器名称] =
初始化器
onnxscript 图.
初始化器 =
带真实张量的初始化器
# 导出 TorchScript 图到 ONNX ModelProto。
ONNX 模型 = onnxscript_graph.to_model_proto(
self.选项.onnx_registry.
opset 版本,
)
ir_model = ir.serde.deserialize_model(onnx_model)
try:
ir_model = onnxscript_apis.优化(
ir 模型)
除了
异常
作为 e:
warnings.警告(
"ONNXScript 优化器失败。跳过优化。"
"
\n\n
\n\n请在 https://github.com/microsoft/onnxscript/issues 报告一个错误
f"
\n\n
\n\n详情:
输入文本翻译为简体中文为:\n{e}"
)
返回
onnx 程序.
ONNX 程序(
索引模型,
无)
def _assert_fake_tensor_mode(self):
断言模型及其输入不包含伪造张量。
模型使用虚假输入/权重且未启用虚假模式
是否有任何虚假张量 =
py 树.
树中任何(
lambda x: isinstance(x, 火炬.
子类.
假 Tensor),
(self.model_args, self.模型参数),
)
是否有任何虚假参数或缓冲区 =
假
如果 isinstance(self.
模型,
火炬.nn.
模块):
包含任何伪造的参数或缓冲区 =
py 树.
树任何(
lambda x: isinstance(x, 火炬.
子类.
假 Tensor),
(self.模型.
参数(), self.
模型.
缓冲区()),
)
如果 (
包含任何伪造的张量
或
包含任何伪造的参数或缓冲区
) 和 not self.
选项.
模拟上下文:
提升
运行时错误(
"无法在不启用模拟模式的情况下导出具有模拟输入/权重的模型。",
)
# 案例二:具有非模拟输入/权重的模型且已启用模拟模式
是否包含任何非模拟张量 =
py 树.
树_任意(
lambda x: isinstance(x, 火炬.
张量)
和 not isinstance(x,
火炬.
子类.
假 Tensor),
(self.model_args, self.模型参数),
)
有任何非假参数或缓冲区 =
假
如果 isinstance(self.
模型,
火炬.nn.
模块):
有任何非假参数或缓冲区 =
py 树.
树_任意(
lambda x: isinstance(x, 火炬.
张量)
和 not isinstance(x,
火炬.
子类.
假 Tensor),
(self.模型.
参数(), self.
模型.
缓冲区()),
)
如果 (
包含任何非伪造张量
或
包含任何非伪造参数或缓冲区
) 和 self.
选项.
伪造上下文:
提升
运行时错误(
"无法导出具有非伪造输入/权重并启用伪造模式的模型。",
)
类
不满足依赖错误(
运行时错误):
当 ONNX 导出器依赖无法满足时引发。
def 初始化(self,
包名:
字符串,
消息:
字符串):
超级().
初始化(
消息)
self.包名 =
包名
类
无效导出选项错误(
运行时错误):
当用户为`:class:`ExportOptions`指定了无效值时引发。
def 断言依赖(
导出选项:
已解决导出选项):
算子版本 =
导出选项.onnx_registry.
算子版本
def 缺少包(
包名:
字符串, exc_info:
记录日志._ExcInfoType):
消息 = (
f"请安装以下软件包"{
包名}
f"(例如 `python -m pip install"{
包名}
。)
)
日志.
致命(
消息, exc_info=exc_info)
返回
不满足的依赖错误(
包名,
消息)
def 缺少 opset(
包名:
字符串):
消息 = (
f"已安装的 `{
包名}
不支持指定的 ONNX 操作集版本 "
f"版本"{
opset 版本}
安装一个更新的 `{
包名}
` 包或 "
f指定一个较旧的 opset 版本。
)
日志.
致命(
消息)
返回
不满足的依赖错误(
包名,
消息)
try:
导入 onnx
除了
导入错误
作为 e:
提升
缺少包(
onnx, e)
来自 e
如果 onnx.
定义.
ONNX 操作集版本() <
opset 版本:
提升
缺少 opset(
onnx)
try:
PyTorch 在 CI 中运行 lintrunner 时未安装 onnxscript
导入 onnxscript # type: ignore[import]
除了
导入错误
作为 e:
提升
缺少包(
onnxscript, e)
来自 e
如果 not isinstance(
onnxscript.onnx_opset.all_opsets["",
opset 版本
)],
onnx 脚本.
值.Opset,
):
提升
缺少 Opset(
"onnx 脚本")
def dynamo_export(
模型:
火炬.nn.
模块 |
可调用,
/,
*model_args,
导出选项:
导出选项 |
无 =
无,
**模型参数,
) -> _onnx 程序.
ONNX 程序:
将 torch.nn.Module 导出为 ONNX 图。
已弃用
请使用 ``torch.onnx.export(..., dynamo=True)`` 代替。
参数:
导出至 ONNX 的 PyTorch 模型。
model 参数:传递给`model`的位置参数。
model_kwargs:传递给`model`的关键字参数。
导出选项:影响导出到 ONNX 的选项。
返回:
导出 ONNX 模型的内存表示。
**示例 1 - 最简单的导出**
::
class MyModel(torch.nn.Module):
def __init__(self) -> None:
super().__init__()
self.linear = torch.nn.Linear(2, 2)
def forward(self, x, bias=None):
out = self.linear(x)
out = out + bias
return out
model = MyModel()
kwargs = {"bias": 3.0}
args = (torch.randn(2, 2, 2),)
onnx_program = torch.onnx.dynamo_export(model, *args, **kwargs).save(
"my_simple_model.onnx"
)
示例 2 - 使用动态形状导出
::
上一个模型可以导出为动态形状
export_options = torch.onnx.ExportOptions(dynamic_shapes=True)
onnx_program = torch.onnx.dynamo_export(
model, *args, **kwargs, export_options=export_options
)
onnx_program.save("my_dynamic_model.onnx")
通过打印输入动态维度,我们可以看到输入形状不再是 (2,2,2)
::
>>> print(onnx_program.model_proto.graph.input[0])
name: "arg0"
类型 {
张量类型 {
元素类型:1
shape {
dim {
维度参数:"arg0_dim_0"
}
dim {
dim_param: "arg0_dim_1"
}
dim {
dim_param: "arg0_dim_2"
}
}
}
}
"源代码"
如果
导出选项
是 not
无:
resolved_export_options = (
导出选项
如果 isinstance(
导出选项, ResolvedExportOptions)
否则
已解决导出选项(
导出选项,
模型=
模型)
)
否则:
已解决导出选项 =
已解决导出选项(
导出选项(),
模型=
模型)
_断言依赖(
已解决导出选项)
try:
来自 torch._dynamo
导入
配置
作为 _dynamo_config
与 _dynamo_config.
补丁(
不发出运行时断言=True):
返回
导出器(
选项=
已解析的导出选项,
模型=
模型,
model_args=model_args,
模型参数=
模型参数,
).导出()
除了
异常
作为 e:
sarif 报告路径 =
默认失败导出 SARIF 日志路径
解析的导出选项.
诊断上下文.
导出(
sarif 报告路径)
消息 = (
f"导出模型到 ONNX 失败。正在生成 SARIF 报告。"{
sarif 报告路径}
。
SARIF 是静态分析工具输出格式的标准。
"SARIF 日志可以在 VS Code SARIF 查看器扩展中加载,"
"或者 SARIF 网页查看器(https://microsoft.github.io/sarif-web-component/)。"
f"请在 PyTorch 的 GitHub 上报告一个错误:"{_PYTORCH_GITHUB_ISSUES_URL}"
)
提升
错误.
ONNX 导出器错误(
消息)
来自 e
def 常见导出前处理(
选项:
已解决的导出选项,
原始模型:
火炬.nn.
模块 |
可调用,
效果模块:
火炬.fx.
图模块,
fx 模块参数:
序列[
任意
]
):
# TODO: 在此处导入以防止循环依赖
来自 torch.onnx._internal.fx
导入
分析,
通过
诊断上下文 =
选项.
诊断上下文
将分解表应用于输入图。
模块 =
通行证.
分解(
诊断上下文,
fx 模块,
选项.
分解表,
启用动态坐标轴=
选项.
动态形状,
允许伪造常量=
选项.
伪造上下文
是 not
无,
).run(*fx_module_args)
# ONNX 不支持视图和修改。
# 函数化以获取无修改的语义等价图。
模块 =
通行证.
函数化(
诊断上下文,
模块,
启用动态坐标轴=
选项.
动态形状,
允许伪造常量=
选项.
伪造上下文
是 not
无,
).run(*fx_module_args)
# 输入变异在 `Functionalize` 阶段之后被检测和提炼。
# 由于 ONNX 推理不需要它们,因此可以移除。
模块 =
通行证.RemoveInputMutation(
诊断上下文,
模块).run(*
fx 模块参数)
# ONNX 不支持(隐式)类型提升的概念。
# 在需要的地方显式插入类型转换。
模块 =
通行证.
插入类型促销(
诊断上下文,
模块).run()
分析.
不支持的 Fx 节点分析(
诊断上下文,
模块,
选项.
ONNX 函数调度器
).分析(
基础设施.
等级.
错误)
如果 isinstance(
原始模型,
火炬.nn.
模块):
模块 =
通行证.
恢复参数和缓冲区名称(
诊断上下文,
模块,
原始模型
).run()
# 此操作应在导出前作为最后一个预导出步骤调用。
# 查看[注意:模块化步骤排序]
模块 =
通行证.
模块化(
诊断上下文,
模块).run()
# ONNX 不支持 None 输入。在图构建过程中,所有 None 输入
# 都被移除。这里我们将此步骤注册到输入适配器中。
选项.fx_tracer.
输入适配器.
添加步骤(
输入/输出适配器.
删除 None 输入步骤())
# NOTE: 临时解决方案针对 https://github.com/pytorch/pytorch/issues/99534
# Dynamo 不支持非张量输入。
选项.fx_tracer.
输入适配器.
添加步骤(
离线适配器.
删除非张量输入步骤())
# ONNX 不支持复杂数据输入。在构建图的过程中,所有复杂数据输入
# 都会被转换为实数表示的输入。这里我们注册这个步骤以
输入/输出适配器
选项.fx_tracer.
输入适配器.
添加步骤(
输入输出适配器.
将复杂类型转换为实表示法输入步骤()
)
# ONNX 无法表示集合类型(例如,字典,元组的元组等),我们将集合展平并将每个元素注册为输出。
# 张量等),我们将集合展平并将每个元素注册为输出。
选项.fx_tracer.
输出适配器.
添加步骤(
输入输出适配器.
扁平化输出步骤())
在 `FlattenOutputStep` 之后进行输出后处理步骤。
选项.fx_tracer.
输出适配器.
添加步骤(
输入/输出适配器.
将复杂数据转换为实数表示输出步骤()
)
返回
模块