# mypy: 允许未类型化定义
""
弱脚本注解需要在这里而不是在 torch/jit/内部,这样
它就可以在 torch/的其他地方(即 torch.nn)中使用,而不会遇到
循环依赖问题
""
导入
源
导入
内置函数
导入
集合
导入 contextlib
导入
枚举
导入
检查
导入
输入/输出
导入
酸菜
导入
系统
导入
文本换行
导入
线程
导入
类型
导入
打字
导入
警告
导入
弱引用
from 打字
导入 (
# noqa: UP035, F401 # (字典,列表,元组) 由 torch.jit.annotations 导入
任何,
可调用,
字典,
最终,
ForwardRef,
获取参数,
获取源,
列表,
可选,
元组,
联合,
)
导入
火炬
# 这是必需的。在导入 `torch.distributed.__init__` 之前导入 `torch._jit_internal`。
# 明确要求首先导入 `torch.distributed.__init__`。
# 否则,会引发 "AttributeError: 模块 'torch' 没有属性 'distributed'" 错误。
导入 torch.distributed.rpc
导入 torch.package._mangling as package_mangling
from torch._awaits 导入 _Await
from torch._C 导入 _Await as CAwait,
未来 as
未来
from torch._源
导入
模拟范围,
获取源代码行和文件,
解析定义
from torch.futures 导入
未来
是 Python310 以上版本:
最终[bool] =
系统模块.version_info
≥ (3, 10)
内置联合类型:
联合[
类型,
元组[
类型, ...]]
如果
系统模块.version_info
≥ (3, 10):
# 注意:IS_PY310_PLUS 在 mypy 中不适用。
# 参考:https://mypy.readthedocs.io/en/stable/common_issues.html#python-version-and-system-platform-checks
内置联合类型 =
类型.
联合类型
否则:
内置联合类型 = ()
#技巧:这使得 isinstance 短路。
锁类型:
类型
尝试:
导入
线程
锁类型 =
线程.
锁类型
除了
导入错误:
导入
_模拟线程
# 类型:忽略[导入未找到]
锁类型 =
_模拟线程.
锁类型
# 包装函数,可以根据布尔值调用其中的两个函数之一
# 参数
boolean 分派: "weakref.WeakKeyDictionary[Callable, dict[str, Callable]]" = (
弱引用.WeakKeyDictionary()
) # noqa: T484
FAKE_FILENAME_PREFIX = "__torch_jit_dataclass"
定义
是否最终(
注解) -> bool:
返回 (
有属性(
注解, "__module__")
和 ann.__module__
在 {
打字,
打字扩展}
和 (
获取源(ann)
是
最终
或者 isinstance(ann,
类型(
最终)))
)
允许 BroadcastingList 实例可索引
类
广播列表类:
定义 __getitem__(self,
类型):
返回
# mypy 不支持在类型上使用参数,因此我们必须显式地给每个
# 列表大小
广播列表 1 =
广播列表类()
对于 i
在
范围(2, 7):
全局变量()[f
广播列表{i}"] =
广播列表 1
[文档]def is_scripting() -> bool:
r"""
函数在编译时返回 True,否则返回 False。这特别有用,尤其是在使用@unused 装饰器时,可以在模型中留下尚未与 TorchScript 兼容的代码。
这在特别与@unused 装饰器结合使用时非常有用,可以在模型中留下尚未与 TorchScript 兼容的代码。
这在特别与@unused 装饰器结合使用时非常有用,可以在模型中留下尚未与 TorchScript 兼容的代码。
.. 测试代码::
导入 torch
@torch.jit.unused
定义不支持线性操作函数 unsupported_linear_op(x):
return x
def 线性(x):
if torch.jit.is_scripting():
return torch.linear(x)
else:
返回不支持的一元操作(x)
"""
返回 False
获取给定 obj 的完全限定名称(模块层次+类名)。
定义 _qualified_name(
对象, mangle_name=True) -> str:
此特殊情况允许我们覆盖类型上的限定名称。
目前它与跟踪功能一起使用,我们创建一个
模拟模块以仅过滤支持的属性。然而,由于
新类型被定义为本地类,我们需要一个机制来
覆盖其 qualname,以便它在 TorchScript 系统中正确
我们将'_jit_override_qualname'设置为原始追踪模块的原始名称
限定名称,在这里被选中
如果
有属性(
对象, "_jit_override_qualname"):
返回
对象._jit_override_qualname
在对象已具有已知合格名称的情况下进行短路
如果 isinstance(
对象,
火炬._C.
脚本函数):
返回
对象.
合格名称
如果 getattr(
对象,
"__名称__",
无):
名称 =
对象.__name__
枚举类没有 `__name__` 属性,而是有 `name`。
如果...否则 isinstance(
对象,
枚举.
枚举):
名称 =
对象.
名称
否则:
抛出
运行时错误(
"无法获取 Python 类对象的名称")
如果
名称 == "<lambda>":
名称 = "_lambda"
# 将名称变为有效的标识符
模块名称 =
对象.__module__
如果模块实际上是 torchbind 模块,那么我们应该短路
如果
模块名称 == "torch._classes":
返回
对象.qualified_name
Python 文档非常明确指出`__module__`可以是 None,但我做不到
实际上会是什么时候
如果
模块名称
是
无:
抛出
运行时错误(
f"无法获取类的合格名称 '"{
名称}
:
"__module__ 不能为 None。"
)
# 如果 getattr(sys.modules[module_name], name) 不是 obj:
# raise RuntimeError(f"无法获取类 '{name}' 的合格名称:"
# f"模块 {module_name} 上的属性 {name} 不是类")
# torch.package 和 TorchScript 使用不同的混淆方案以避免
来自多个包的名称冲突。为了避免它们相互干扰,在此处规范化包管理。
为了避免它们相互干扰,在此处规范化包管理。
如果
包混淆.
已混淆(
模块名称):
模块名称 =
模块名称.
替换("<",
“_”)
模块名称 =
模块名称.
替换(">",
“_”)
# torch/csrc/jit/python/python_sugared_value.h 中的 PythonExceptionValue C++ 类
# 不需要对 Python 类名进行名称修饰。
如果
修改名称:
"__main__" 是内置模块,因此重写为 "__torch__"。
如果
模块名称 == "__main__":
模块名称 = "__torch__"
否则:
所有其他内容都加上 "__torch__" 前缀以避免名称冲突
# 与用户值名称。
模块名称 =
__torch__. +
模块名称
如果 "."
在
名称:
抛出
运行时错误(
f无法获取类 '的合格名称{
名称}
无效的标识符
f''{
名称}
不是有效的标识符
)
返回
模块名称 + "." +
名称
类
源加载器:
定义 __init__(self):
self.内容 = {}
定义
缓存(self, fn,
源):
self.内容[fn] =
源
定义
获取源(self, fn):
返回 self.
内容.
获取(fn)
加载器 =
源加载器()
定义
从环境创建分辨率回调(
查找基础):
""
创建一个解析回调,该回调将查找合格名称
环境,从`lookup_base`开始,作为任何合格项的基础
names,然后沿着解析对象向下查找链进行。
您不应直接使用此内容,而应仅从其他
从 createResolutionCallbackFrom*函数创建。
"""
定义
在模块中查找。(
完整名称。,
模块):
如果 "."
在
完整名称。:
基础,
剩余件数 =
合法名称.
分割(
“。”,
最大分割数=1)
模块值 = getattr(
模块,
基础)
返回
在模块中查找(
剩余件数,
模块值)
否则:
返回 getattr(
模块,
合法名称)
定义
解析嵌套表达式(
表达式,
模块) ->
元组[
任何, int
]
i = 0
当 i <
长度(
表达式)
和
表达式[i]
不
在 (",", "[", "]"):
i += 1
# 空元组作为下标的特殊情况逻辑(用于类型注解 `Tuple[()]`)
# 在
如果 expr
[i] ==
"空括号":
返回 (), i
基础 =
在模块中查找(
表达式
[i].strip(),
模块)
断言
基础
是
不
无, f
"无法解析的类型"{
表达式
[i]}"
如果 i ==
长度(
表达式)
或者
表达式[i] != "[":
返回
基础, i
断言
表达式[i] ==
[
部分 =
输入文本为空,请提供需要翻译的文本
当
表达式[i] !=
]:
部分长度 = 0
i += 1
部分,
部分长度 =
解析嵌套表达式(
表达式[i
,
模块)
parts.添加(
部分)
i += 长度
如果
长度(parts) > 1:
返回
基础[
元组(parts
)], i + 1
否则:
返回
基础[parts[0]], i + 1
定义
解析表达式(
表达式,
模块):
尝试:
value, 解析长度 =
解析嵌套表达式(
表达式,
模块)
断言
len 解析 ==
长度(
表达式), (
"整个表达式未解析,回退到 C++解析器"
)
返回
值
除了
异常:
""
Python 解析器在多个已知单元测试中失败,并旨在优雅地回退到 C++解析器。例如,在我们的单元测试中频繁出现的 Python 2 风格注释通常会因为类型(例如 int)无法从调用帧中解析而出错。
通常情况下,会优雅地回退到 C++解析器。例如,Python 2 风格的注释在我们的单元测试中经常因为类型(例如 int)无法从调用帧中解析而出错。
例如,在我们的单元测试中频繁出现的 Python 2 风格注释通常会因为类型(例如 int)无法从调用帧中解析而出错。
例如,在我们的单元测试中频繁出现的 Python 2 风格注释通常会因为类型(例如 int)无法从调用帧中解析而出错。
"""
返回
无
返回
lambda 表达式
表达式:
解析表达式(
表达式,
查找基础)
定义
从帧创建分辨率回调函数(
帧上移:
整型 = 0):
""
创建一个函数,该函数接受一个字符串变量名,
返回调用者作用域中该变量的值
调用 createResolutionCallbackFromFrame 函数的功能(默认情况下)。
这用于在 TorchScript 片段中启用对作用域内 Python 变量的访问。
TorchScript 片段。
frames_up 是向上移动栈的额外帧数。
默认值为 0,对应调用者的帧
从帧创建 createResolutionCallback。例如,如果 frames_up 被设置
到 1,然后从帧创建分辨率回调的调用者的调用者的框架
将被取走。
例如,以下程序打印 2::
def bar():
cb = createResolutionCallbackFromFrame(1)
打印(cb("foo"))
def baz():
foo = 2
bar()
baz()
"""
框架 =
检查.currentframe()
i = 0
当 i < frames_up + 1:
断言
框架
是
不
无
框架 = frame.f_back
i += 1
断言
框架
是
不
无
f_locals = frame.f_locals
f_globals = frame.全局变量
类
环境:
定义 __getattr__(self,
键):
如果
键
在
局部变量:
返回
本地变量[
键]
elif 键
在
全局变量:
返回
全局变量[
键]
elif 键
在
目录(builtins):
返回 getattr(builtins,
键)
返回
从环境变量创建分辨率回调(
环境())
定义
获取闭包(fn):
""
从函数中获取封闭变量的字典
"""
捕获 = {}
捕获.
更新(fn.
__全局变量__)
对于
索引,
捕获的名称
在
列举(fn.__code__.co_freevars):
captures[captured_name] = fn.__关闭__[
索引].
单元内容
返回
捕获
# [Python 中的局部解析]
根据变量定义的位置和使用位置,我们可能无法在递归编译脚本函数时恢复其值。记住,在一般情况下,模块或函数是先定义后脚本化的。这意味着我们无法获取
# 或者可能无法在递归编译脚本函数时恢复其值。记住,在一般情况下,模块或函数是先定义后脚本化的。这意味着我们无法获取
# 在一般情况下,模块或函数是先定义后脚本化的。这意味着我们无法获取
# 在一般情况下,模块或函数是先定义后脚本化的。这意味着我们无法获取
# 捕获函数定义时的活动帧的机会。因此,名称解析必须在创建的闭包之后进行。Python 捕获类型注解的方式限制了我们可以恢复的内容。以下示例说明了不同的情况:
# 名称解析必须在创建的闭包之后进行。Python 捕获类型注解的方式限制了我们可以恢复的内容。以下示例说明了不同的情况:
# Python 捕获类型注解的方式限制了我们可以恢复的内容。以下示例说明了不同的情况:
# 以下示例说明了不同的情况:
#
# 类 MyGlobalClass:
# ...
# def my_local_scope():
# @torch.jit.script
# class MyClass:
# ...
# @torch.jit.script
# class MyClassUsedAsVar:
# ...
# def eg(x: MyClass, y: MyGlobalClass):
# a_local_capture : Foo
# 返回使用变量 MyClassUsedAsVar(x)的 MyClassUsedAsVar()
#
# MyGlobalClass 定义在函数的__globals__字典中
# 因此它总是可恢复的。my_local_scope 在函数中引入了一个新的局部变量作用域
# 范围。在这里定义的类只能在该函数内部可见
# 本地变量。对于 MyClassUsedAsVar 的情况,它被捕获
# 因为它被用作函数体内的变量,我们可以通过`get_closure`返回的捕获来解析它。然而,
# 闭包并没有捕获类型注解。在 Python 中
# # 闭包并没有捕获类型注解。在 Python 中
# 3.0--3.9,MyClass 和 MyGlobalClass 的 _值_ 将作为
# `eg` 的注释存在,但自 Python 4.0 开始,它们将表示为
# 字符串,并且不再存在。此外,由于 `eg` 的主体不引用这些名称,
# 因此它们不会出现在封闭的名称列表中
# 变量。在 Python 2.x 中,类型注解位于注释中,导致以下
相似的情况,其中它们的定义不可用。我们预计
大多数用户不会遇到这个问题,因为他们的模块和
函数将在全局作用域中定义,例如 MyGlobalClass。在情况下
# 在它们不存在的地方,可以通过声明函数中的全局值来绕过问题。
# values global in the function.
# 在 Python 3.9 中,将类声明为全局将使其对 `inspect.getsource` 不可见,请参阅 https://bugs.python.org/issue42666 。
# `inspect.getsource` 不可见,请参阅 https://bugs.python.org/issue42666 。
这可以通过手动将其添加到 `global()` 字典中解决。
定义
从闭包中创建 createResolutionCallback(fn):
""
通过反射函数创建 resolutionCallback,而不是
在调用栈中查找封装作用域
"""
闭包 =
获取闭包(fn)
类 closure_lookup:
# 这是一个类,因为 `closure` 是一个字典,使用 `getattr` 调用会更简单
# `env_helper` 如果所有操作都通过 `getattr` 调用就能顺利完成
定义 __getattr__(self,
键):
如果
键
在 closure:
返回
闭包[
键]
elif 有属性(
输入法,
键):
返回 getattr(
输入法,
键)
elif 有属性(builtins,
键):
返回 getattr(builtins,
键)
返回
无
返回
从环境创建分辨率回调函数(
闭包查找())
定义
是否能编译类(cls) -> bool:
如果一个类型上的任何函数没有代码对象,则此类型不能
# 可能是从 C 语言编译的内置或绑定
如果 is_ignored_fn(cls):
返回
假
# 忽略以下内置类列表。
ignored_builtin_classes = (火炬.
神经网络.
模块,
元组,
列表,
异常)
如果
派生类(cls,
忽略内置类):
返回
假
名称 = cls.__dict__
函数列表 = [
getattr(cls, 名称)
对于
名称
在
名称
如果
检查.
是常规的(getattr(cls,
名称,
无))
]
有代码 = [
有属性(fn,
"__代码__")
对于 fn
在
函数]
返回
所有(
有代码)
定义
获取可调用参数名称(fn) ->
列表[str
]
""
获取可调用对象 `fn` 的所有位置参数或关键字参数的名称。
当存在其他类型的参数时,返回一个空列表。
这被 `torch.jit.trace` 用于为追踪函数和模块分配有意义的参数名称。
用于追踪函数和模块。
参数:
可调用对象。
返回值:
参数名称:字符串列表。
"""
# inspect.signature 可能会失败,在这种情况下放弃。
尝试:
可调用签名。 =
检查.
签名(fn)
除了
异常:
返回
输入文本为空,请提供需要翻译的文本
参数名 =
输入文本为空,请提供需要翻译的文本
对于
名称,
参数
在
可调用签名.
参数.
项目():
# 所有其他四种类型的参数都不映射到单独的值
# 使用关键字作为名称。
如果
不
参数.
仁慈 ==
参数.
位置或关键字:
continue
参数名.
添加(
名称)
返回
参数名
定义
获取注解字符串(
注解):
""
将包含类型注解的 AST 节点转换为源中存在的字符串
该字符串代表相同的注解。
"""
如果 isinstance(
注释,
抽象语法树.
名称):
返回
注释.
标识符
elif isinstance(注解,
抽象语法树.
属性):
返回
“。”.
连接
[
获取注解字符串(
注解.value),
注释.
属性])
elif isinstance(注释,
抽象语法树.
下标):
Python3.9+ 中,下标索引不再被 ast.Index 包装
下标切片 =
注释.
切片
返回 f"{
获取注解字符串(
注解.value)}[{
获取注解字符串(
下标切片)}]"
elif isinstance(注解,
抽象语法树.
元组):
返回 ",".
连接
[
获取注解字符串(elt)
对于 elt
在
注释.elts])
elif isinstance(注释,
抽象语法树.
常量):
返回 f"{
注释.value}"
如果 AST 节点在这里没有被处理,那么它可能是在 ScriptTypeParser 中被处理的。
返回
无
定义
获取类型提示捕获(fn):
""
获取包含必要类型解析映射的字典,以解析类型
对于 'fn' 的字面注释。这些不被认为是由 fn 封闭的。
必须单独获取(例如使用此函数)。
参数:
fn:一个可调用对象。
返回值:
一个包含从字面注释映射到它们所引用的 Python 对象的 Dict[str, Any]。
fn 到 Python 对象的映射。
"""
首先,尝试获取函数的来源。我们需要解析它以找到实际的字符串名称
用于注释类型的那些,因为 inspect.signature()只会返回类对象
注释指的是,而不是字符串名称。如果我们无法获取源代码,则简单地返回一个空字典。
这种情况可能发生在函数在运行时动态合成时。
源 =
加载器.
获取源(
函数)
如果
源
是
无:
尝试:
源 =
检查.
获取源(fn)
除了 OSError as e:
抛出 OSError(
f获取源失败{fn}
使用 inspect.getsource"
) from e
收集一个参数名称 -> 类型的字典,跳过任何带有注释的参数
类型是字符串。这些只在 TorchScript 的类型注解上下文中被理解。
# 那个类在其自己的定义中引用自身,但试图在结果中包含对此的映射
# 函数会导致无限递归,因为类目前正在编译
# 此外,ScriptTypeParser 中还有逻辑来处理这种情况
签名 =
检查.
签名(fn)
名称类型 = {
名称:
参数.
注释
对于
名称,
参数
在
签名.
参数.
项目()
如果
参数.
注释
是
不
检查.
参数.
空的
和
不 isinstance(
参数.
注释, str)
}
然后,从函数声明中获取字面类型注解
通过源代码检查。这考虑了别名使用的情况
用于注释参数(例如 device_t = torch.device,然后 d: device_t)。
frontend.py 不能在这里使用,因为它包含了 _jit_internal,所以使用 ast。
a = ast.解析(textwrap.dedent(
源))
如果
长度(a.
主体) != 1
或者
不 isinstance(a.
主体[0
]
抽象语法树.
函数定义):
抛出
运行时错误(f
预期{fn}
应该是一个函数)
f = a.函数体[0]
准备一个源注释 -> 类型的字典,这将是这个函数的最终结果
使用解析的 AST(f)将每个参数的源注释作为字符串重建
将它们通过 name_to_type 参数按名称映射到对应的类型对象。
标注到类型 = {}
for arg 在 f.
参数.
参数:
尝试获取此参数的源类型注释字符串,如果可能的话。
arg_annotation_str = (
获取注解字符串(
参数.
注解)
如果
参数.
注释
否则
无
)
# 如果参数没有注释或 get_annotation_str 无法将其转换为字符串,
# arg_annotation_str 将为 None。跳过此参数;ScriptTypeParser 可能会在后续处理。
# 这种情况下。
如果 arg_annotation_str
是
无:
continue
# 在可能的情况下,将 {arg_annotation_str: type} 插入 annotation_to_type。arg_name 可能不存在的
# 原因是注释本身是一个字符串而不是类型对象(在类的自引用注释中很常见)。再次,让 ScriptTypeParser 处理这个问题。
# 一旦再次,让 ScriptTypeParser 处理这个问题。
变量名 =
参数.
参数
如果
变量名
在
名称到类型:
标注到类型[
参数标注字符串] =
名称到类型[
参数名称]
# 如果存在有效的返回注释,请将其包含在 annotation_to_type 中。与参数注释一样,
# 文字注释必须可以通过 get_annotation_str 转换为字符串,注释的实际类型
# 不能是字符串。
literal_return_annotation = 获取注解字符串(f.
返回)
有效的字面量注解 =
字面量返回注解
是
不
无
返回注解 =
签名.
返回注解
有效的返回注解类型 = (
返回注解
是
不
检查.
参数.
空的
和
不 isinstance(
返回注解, str)
)
如果
有效的字面量注解
和
有效的返回注解类型:
注解到类型[
文字返回注解] =
返回注解
返回
标注到类型
定义
为类方法创建创建分辨率回调(cls):
""
这会查看类中定义的所有方法并提取它们的闭包
将变量放入字典中,并使用该字典解析变量。
"""
# cls 是一个类型,所以 ismethod 为 false,因为类型上的方法
# 并没有绑定到任何东西,所以 Python 将它们视为常规函数
函数 = [
getattr(cls, 名称)
为
名称
在
类.
字典
如果
检查.
是例程(getattr(cls,
名称))
]
# 跳过内置函数,因为它们没有全局作用域也没有类型提示
# 需要支持 Python-3.11 中 `enum.Enum` 派生类
添加 `_new_member_` 属性,它是 `__new__` 的别名
函数 = [fn
对于 fn
在
函数
如果
不
检查.
是否是内置函数(fn)
和
有属性(fn,
全局变量)]
捕获 = {}
对于 fn
在
函数:
captures.更新(
获取闭包(fn))
captures.更新(
获取类型提示捕获(fn))
定义
类中查找(
键):
如果
键
在 captures:
返回 captures[
键]
否则:
返回 getattr(builtins,
键,
无)
返回
类中查找
定义
布尔分发(
参数名称,
索引参数,
默认,
如果为真,
如果为假,
模块名称,
函数名,
):
""
根据布尔参数调用 2 个脚本函数之一。
在 TorchScript 中,布尔参数必须是常量,以便在编译时确定要使用的函数。
要使用的函数可以在编译时确定。
"""
定义 fn(*
参数, **
关键字参数):
分发标志 =
默认
如果
参数名称
在
关键字参数:
分发标志 =
关键字参数[
参数名称]
elif 参数索引 <
长度(
参数):
分发标志 =
参数[
索引参数]
如果
分发标志:
返回
如果为真(*
参数, **
关键字参数)
否则:
返回
如果为假(*
参数, **kwargs)
if if_true.__doc__ 是
无
和
如果为假.
__文档__
是
不
无:
文档 =
如果为假.
__文档__
如果为真.
__文档__ =
文档
elif 如果为假.
__文档__
是
无
和
如果为真.
__文档__
是
不
无:
文档 =
如果为真.
__文档__
如果为假.
__文档__ =
文档
elif 如果为假.
__文档__
是
无
和
如果为真.
__文档__
是
无:
# 两个函数都没有文档字符串
文档 =
无
否则:
抛出
运行时错误(
"只有一个函数可以有文档字符串")
fn.__文档__ =
文档
如果
模块名称
是
不
无:
fn.__module__ = 模块名称
如果
函数名
是
不
无:
fn.__name__ = 函数名
boolean 分派[fn] = {
如果为真:
如果为真,
如果为假:
如果为假,
索引:
索引参数,
默认:
默认,
参数名:
参数名称,
}
返回 fn
类
函数修饰符:
""
用于表示 TorchScript 中函数的行为。有关详情,请参阅 export()和 ignore()。
未使用
"""
UNUSED = "未使用(忽略,并用抛出异常代替)"
忽略 =
"忽略(保留为对 Python 的调用,不能使用 torch.jit.save)"
导出 =
"导出(即使没有函数调用也要编译此函数)"
默认 =
"默认(如果从导出函数/前向调用则编译)"
复制到脚本包装器 = (
"如果此方法未脚本化,则将 Python 方法复制到脚本化模型上"
)
_DROP = "_drop(函数完全忽略,声明可以是不可脚本化的)"
[文档]def 导出(fn):
"""
该装饰器表示一个 ``nn.Module`` 上的方法用作 ``ScriptModule`` 的入口点,并应进行编译。
默认情况下,``forward`` 方法被视为入口点,因此不需要此装饰器。
``forward`` 方法隐式地被认为是入口点,所以它不需要这个装饰器。
函数和方法在 `forward` 中被调用时,按其出现的方式编译
由编译器处理,因此它们也不需要这个装饰器。
示例(在方法上使用 `@torch.jit.export`):
.. 测试代码::
导入 torch 库
导入 torch.nn 模块
class MyModule(nn.Module):
def implicitly_compiled_method(self, x):
return x + 99
# `forward` 是隐式装饰的 `@torch.jit.export`,
# 所以在这里添加它不会有任何效果
def forward(self, x):
return x + 10
@torch.jit.export
def another_forward(self, x):
# 当编译器看到这个调用时,它将编译
隐式编译方法
返回 self.implicitly_compiled_method(x)
def unused_method(self, x): 无用方法
返回 x - 20
`m` 将包含编译后的方法:
# `forward`
# `another_forward`
隐式编译方法
# `unused_method` 由于未被编译方法调用且未使用 `@torch.jit.export` 装饰,将不会被编译
# 任何编译方法都没有调用,并且没有使用 `@torch.jit.export` 装饰
m = torch.jit.script(MyModule())
"""
fn._torchscript_modifier = 函数修饰符.导出
返回 fn
[文档]
定义
未使用(fn):
""
该装饰器指示编译器,一个函数或方法应该
被忽略,并用抛出异常来替换。这允许
在您的模型中留下尚未与 TorchScript 兼容的代码,并且仍然
导出您的模型。
示例(在方法上使用 ``@torch.jit.unused``)::
导入 torch
导入 torch.nn 作为 nn
class MyModule(nn.Module):
def __init__(self, use_memory_efficient):
super().__init__()
self.use_memory_efficient = use_memory_efficient
@torch.jit.unused
def memory_efficient(self, x):
import pdb
pdb.set_trace()
return x + 10
def forward(self, x):
# 使用尚未可脚本化的内存高效模式
如果 self.use_memory_efficient:
返回 self.memory_efficient(x)
否则:
return x + 10
m = torch.jit.script(MyModule(use_memory_efficient=False))
m.save("m.pt")
m = torch.jit.script(MyModule(use_memory_efficient=True))
# 异常抛出
m(torch.rand(100))
"""
如果 isinstance(fn,
属性):
属性 = fn
setattr( # 无需注意:B010
属性.
获取,
_torchscript 修改器,
函数修饰符.
未使用
)
如果
属性.fset:
setattr( # noqa: B010
属性.fset,
_torchscript 修改器,
函数修饰符.
未使用
)
返回
属性
fn._torchscript 修改器 =
函数修饰符.
未使用
返回 fn
# 从 Python 端的无操作上下文管理器
类 _IgnoreContextManager(contextlib.
抽象上下文管理器):
定义 __init__(self, **
关键字参数):
通过
定义
__退出__(self,
异常类型:
任何, exc_value:
任何,
跟踪回溯:
任何) ->
无:
通过
[文档]def
忽略(drop=False, **
关键字参数):
""
该装饰器指示编译器一个函数或方法应该
被忽略并保留为 Python 函数。这允许你保留代码
您的模型尚未与 TorchScript 兼容。如果从 TorchScript 调用,将被忽略的函数将调用 Python 解释器。无法导出具有忽略函数的模型;请使用:func:`@torch.jit.unused `代替。
忽略的函数将调用 Python 解释器。无法导出的模型;请使用:func:`@torch.jit.unused `代替。
具有忽略函数的模型无法导出;请使用:func:`@torch.jit.unused `代替。
示例(在方法上使用``@torch.jit.ignore``)::
导入 torch
导入 torch.nn 作为 nn
class MyModule(nn.Module):
@torch.jit.ignore
def debugger(self, x):
导入 pdb
pdb.set_trace()
def forward(self, x):
x += 10
# 编译器通常会尝试编译 `debugger`,
# 但由于它被 `@ignore`d,所以它将被保留为调用
Python 代码
调用 self.debugger(x)
return x
m = torch.jit.script(MyModule())
错误!无法保存调用`debugger`的调用,因为它调用 Python
m.save("m.pt")
示例(在方法上使用 `@torch.jit.ignore(drop=True)`):
.. testcode::
导入 torch
导入 torch.nn 作为 nn
class MyModule(nn.Module):
@torch.jit.ignore(drop=True)
def training_method(self, x):
import pdb
pdb.set_trace()
def forward(self, x):
如果 self.training:
self.training_method(x)
return x
m = torch.jit.script(MyModule())
# 这是可以的,因为 `training_method` 没有保存,调用被替换了
抛出异常
m 保存为"m.pt"
.. 测试清理
导入 os 模块
os.remove('m.pt')
"""
如果
可调用(
删除):
# used without any args, so drop is actually a function
# @torch.jit.ignore
# def fn(...):
fn = 删除
fn._torchscript 修饰符 =
函数修饰器.
忽略
返回 fn
如果
不 isinstance(
删除, bool):
抛出
运行时错误(
f"@torch.jit.ignore 的参数必须是 bool 或函数,但得到了"{
删除}"
)
# for backwards compat
导出时删除 =
关键字参数.
流行(
"导出时删除",
无)
如果
导出时删除:
警告.
警告(
"ignore(drop_on_export=True) 已被弃用。TorchScript 现在将在编译时丢弃该函数"
"使用 torch.jit.unused 代替。"{}",
类别=
未来警告,
)
丢弃 =
导出时丢弃
如果...否则
丢弃:
警告.
警告(
"ignore(True) 已被弃用。TorchScript 现在将在编译时删除该函数"
"使用 torch.jit.unused 代替。"{}",
分类=
未来警告,
)
定义
装饰器(fn):
如果
下降:
fn._torchscript 修饰符 =
函数修饰符.
未使用
否则:
fn._torchscript 修饰符 =
函数修饰符.
忽略
返回 fn
返回
装饰器
定义 _drop(fn):
fn._torchscript 修饰器 =
函数修饰器._DROP
返回 fn
定义 _copy_to_script_wrapper(fn):
fn._torchscript_modifier = 函数修饰器.
将内容复制到脚本包装器
返回 fn
定义
模块有导出(
模块):
对于
名称
在
目录(
模块):
如果
有属性(
模块,
名称):
项目 = getattr(
模块,
名称)
如果
可调用(
项目):
如果
获取 TorchScript 修饰符(
项目)
是
函数修饰符.EXPORT:
返回
真实
返回
假
# 警告:should_drop 目前正被我们的 JIT 代码覆盖率插件用于标记 JIT 编译的代码为已覆盖。
# 请重命名此函数,请更新 tools/coverage_plugins_package/src/coverage_plugins/jit_plugin.py 中的引用,以
# 允许 JIT 编译的代码仍然被覆盖。
定义
应该删除(fn) -> bool:
属性 =
获取 torchscript 修饰符(fn)
如果
属性
是
无:
返回
假
返回
属性
是
函数修饰符.
未使用
或者
属性
是
函数修饰符._DROP
定义 is_ignored_fn(fn) -> bool:
修饰 =
获取 torchscript 修饰符(fn)
返回 (
修饰
是
函数修饰符.
未使用
或者
模块
是
函数修饰符.
忽略
或者
模块
是
函数修饰符._DROP
)
定义 _is_drop_fn(fn) -> bool:
修饰 =
获取 torchscript 修饰符(fn)
返回
修饰
是
函数修饰符._DROP
定义 is_static_fn(cls, fn) -> bool:
返回 isinstance(
检查.getattr_static(cls, fn,
默认=
无), staticmethod)
定义 get_static_fn(cls, fn):
返回
检查.getattr_static(cls, fn).__func__
定义 get_torchscript_modifier(fn):
如果
不
可调用(fn):
返回
无
如果
有属性(fn, "__func__"):
fn = fn.__func__
返回 getattr(fn,
_torchscript 修改器,
函数修饰符.
默认)
定义
复制_torchscript 修改器(
原始,
新) ->
无:
属性 =
获取 TorchScript 修饰符(
原始)
如果
属性
是
无:
返回
新.
_torchscript 修饰符 =
属性
# 覆载注册
在此文件中注册重载,并在 torch/jit/__init__.py 中编译
以便它们可以在 nn/functional.py 中导入,而不会出现导入循环
qualified_name => 列表[overload_functions]
_overloaded_fns: 字典[str,
列表[
可调用]] = {} # noqa: T484
_OVERLOAD_EXAMPLE = ""
覆载函数的示例用法:
@torch.jit._overload
def my_function(x: type0) -> type0: # decl 1
通过
@torch.jit._overload
def my_function(x: type1) -> type1: # 声明 2
通过
def my_function(x): # 实现
如果 isinstance(x, type0):
return x
elif isinstance(x, type1):
return x
""
定义
获取无实现错误信息(
类型,
对象):
源代码行数,
文件行号,
文件名 =
获取源代码行和文件(
对象)
返回 (
f实现为:{
类型} "{
_合格名称(
对象)}
"缺失。请将'
f"毕竟在所有重载声明之后提供了定义和定义。
输入文本翻译为简体中文为:\n"
f'文件 '{
文件名}
",行 "{file_lineno}:
输入文本翻译为简体中文为:\n'
+ 输入文本翻译为简体中文为:"".
连接(
源代码行)
+ "输入文本翻译为简体中文为:\n"
+ _OVERLOAD_EXAMPLE
)
定义
_检查过载体(
函数):
尝试:
解析定义 =
解析定义(
函数)
除了 OSError:
# 解析函数定义可能会因为源不可用而引发 OSError。
# 由于这只是一个初始检查,如果出现这种情况,只需发出警告即可。
警告.
警告(
f"无法检索 @torch.jit._overload 函数的源代码:"{
函数}
。
)
返回
主体 =
解析定义.
抽象语法树.
主体[0].
身体
定义
是否通过(x):
返回 isinstance(x,
抽象语法树.
通过)
定义
是省略号(x):
返回 (
isinstance(x, 源代码.
表达式)
和 isinstance(x.value,
源代码.
常量)
和 x.value.
值
是
省略号
)
如果
长度(
正文) != 1
或者
不 (
是否通过(
正文[0])
或者
是否省略号(
正文[0])):
msg = (
"只有 `pass` 语句或 `...` 可以是重载声明的主体:"
输入文本翻译为简体中文为:\n"
)
msg += "输入文本翻译为简体中文为:\n".
连接(
解析定义.
源.
分割("
输入文本翻译为简体中文为:\n"
`):`3])
msg += " <- 预期此处为 `pass` 或 `...`!"
输入文本翻译为简体中文为:\n" + _OVERLOAD_EXAMPLE
抛出
运行时错误(
信息)
定义
超载_(
函数):
_check_overload_body(函数)
限定名称 =
_限定名称(
函数)
全局
_重载函数
函数重载列表 =
过载函数.
获取(
标准化名称)
如果
函数重载列表
是
无:
函数重载列表 =
输入文本为空,请提供需要翻译的文本
函数重载[qual_name] =
函数重载列表
函数重载列表.
添加(
函数)
返回
函数
定义
获取函数重载(qual_name):
返回 _overloaded_fns.
获取(qual_name)
定义 _clear_fn_overloads(qual_name) ->
无:
删除
_overloaded_fns
(无翻译内容)[qual_name]
定义
获取类名和行号(
方法) ->
元组[str, int
]
当前帧 =
检查.currentframe()
# 一个用于 get_class_name 调用,一个用于_overload_method 调用
对于 _
在
范围(2):
断言 (
current_frame 是
不
无
) # 断言当前帧不是 Optional[FrameType]
当前帧 =
当前帧.f_back
断言
当前帧
是
不
无
# 同样如此
类名 =
当前帧.
f 代码.
公司名称
行号 =
当前帧.
代码文件.co_firstlineno
返回
类名,
行号
在装饰器应用于类方法时
# 没有指向其所属类的引用。_qualified_name 不会包含
# 定义它的类,因此同一文件中具有相同名称的方法
# 即使它们定义在不同的类中,也会有相同 的_qualified_name。这个问题仅在 Python 2 中存在
# # 仅在 Python 2 中存在
我们通过查看堆栈帧并识别来解决这个问题
类名,并在使用重载时抛出错误
当同一文件中存在同名模块时
# qualified_name => 类名 => list[重载函数]
重载方法:
字典[str,
字典[str,
列表[
可调用]]] = {} # noqa: T484
(类名, 名称) => 类文件编号
被重载的方法类文件编号:
字典[
元组[str, str
] int] = {}
定义
重载方法(
函数):
检查过载主体(
函数)
限定名称 =
_限定名称(
函数)
全局
_重载方法
类名映射 =
方法过载.
获取(qual_name,
无)
如果
类名映射
是
无:
类名映射 = {}
方法过载[qual_name] =
类名映射
类名,
行号 =
获取类名行号(
函数)
方法重载 =
类名映射.
获取(
类名,
无)
如果
方法重载
是
无:
方法重载 =
输入文本为空,请提供需要翻译的文本
类名映射[
类名] =
方法重载
_重载方法类 fileno
[qual_name,
类名)] =
行号
否则:
已存在的行号 =
_重载方法类文件编号
[qual_name,
类名)]
如果
已存在的行号 !=
行号:
抛出
运行时错误(
"目前无法在同一个模块中重载具有相同名称的两个不同类中的相同方法名"
"在同一个模块中,不能有同名类"
)
方法重载.
添加(
函数)
返回
函数
定义
获取重载方法(
方法,
模类):
# TODO: 递归脚本中子模块未设置 __name__
如果
不
有属性(
方法,
"__名称__"):
返回
无
qual_name = _qualified_name(方法)
类名映射 =
被重载的方法.
获取(qual_name,
无)
如果
类名映射
是
无:
返回
无
重载 =
类名映射.
获取(
模块类.__name__,
无)
如果
覆载
是
无:
返回
无
方法行号 =
获取源代码行和文件(
方法
)]1]
模块类文件号 =
获取源代码行和文件(
模块类
)]1]
模块结束文件号 = mod_class_fileno +
长度(
获取源代码行和文件(mod_class
)]0])
如果
不 (
方法行号
≥
模块类文件号
和
方法行号 <=
模块结束文件号):
抛出
断言错误(
"当模块在同一个文件中重新声明时,重载不可用:"
+ str(方法)
)
返回
重载
定义
是元组(
注解) -> bool:
检查类型。元组缺少参数(但`tuple`是好的)
如果 ann
是
输入法.
元组: # noqa: UP006
抛出错误容器参数缺失(
元组)
# 由于某种原因,Python 3.7 违反了 Type[A, B].__origin__ == Type 规则
如果
不
有属性(ann, "__module__"):
返回
假
ann_origin = get_origin(ann)
返回 ann.__module__
在 (
内建函数,
打字)
和 ann_origin
是
元组
定义
列表(
安) -> bool:
# 检查输入.List 缺少参数(但`list`是好的)
如果
安
是
输入法.
列表: # noqa: UP006
抛出错误容器参数缺失(
列表)
如果
不
有属性(
安, "__module__"):
返回
假
原始标注 =
获取原始(
标注)
返回 ann.__module__
在 (
内建函数,
打字)
和 ann_origin
是
列表
定义 is_dict(ann) -> bool:
# 检查 typing.Dict 缺少参数(但`dict`是好的)
如果 ann
是
输入法.
字典: # noqa: UP006
抛出错误容器参数缺失(
字典)
如果
不
有属性(ann, "__module__"):
返回
假
原始文本 =
获取原始(
注释)
返回
注释.__module__
在 (
内建函数,
打字)
和
原注
是
字典
定义
是否为联合(
注释):
如果 ann
是
联合:
抛出错误容器参数缺失(
联合)
返回 isinstance(ann,
内置联合类型)
或者 (
有属性(ann, "__module__")
和 ann.__module__ == "typing"
和 (
获取源(
注)
是
联合)
)
定义
是可选的(
注):
如果
安
是
可选:
抛出错误容器参数缺失(
可选)
定义
作为可选的 is_optional(ann):
返回 (
有属性(ann, "__module__")
和 ann.__module__ ==
打字
和 (
获取源(ann)
是
可选)
)
定义
是联合作为可选(ann):
ann_args = get_args(ann)
返回
长度(ann_args) == 2
和 (
无
在 ann_args
或者
类型(
无)
在 ann_args)
返回
可选_as_optional(
注解)
或者 (
是联合(
注解)
和
是联合作为可选(
注解))
定义
未来(
安) -> bool:
如果
安
是
未来:
抛出
运行时错误(
尝试使用未来而没有
"包含类型。请添加一个包含类型,例如:"
"Future[int]"
)
返回
获取原始(
注解)
是
未来
定义
等待中(
安) -> bool:
如果
安
是 _Await:
返回
真实
返回
获取源(
安)
是
等待
如果
PyTorch.
分布式.rpc.
是否可用():
from torch._C._distributed_rpc 导入 PyRRef
from torch.distributed.rpc 导入 RRef
定义 is_rref(ann) -> bool:
如果 ann
是 RRef:
抛出
运行时错误(
"尝试使用 RRef 而没有"
"包含类型。请添加包含类型,例如"
"RRef[int]"
)
返回 get_origin(
安)
是 RRef
定义
是_rref_instance 实例(
对象) -> bool:
返回 isinstance(
对象, PyRRef)
否则:
定义
是_rref_instance 实例(
对象) -> bool:
如果 RPC 模块不存在,那么 RRefs 也不存在。
返回
假
定义
尝试获取已分发的函数(fn):
如果
不
可调用(fn):
返回
无
返回
boolean 分派.
获取(fn)
定义
获取命名元组属性(
对象,
loc: 可选[
PyTorch._C._jit_tree_views.
源范围] =
无,
rcb=无,
):
如果
定位
是
无:
位置 =
伪造范围()
断言
派生类(
对象,
元组)
和
有属性(
对象,
"_字段")
如果
有属性(
对象,
"_字段默认值"):
默认 = [
对象.
字段默认值[
字段]
对于
字段
在
对象.
字段列表
if 字段
在
对象.
_字段默认值
]
否则:
默认 =
输入文本为空,请提供需要翻译的文本
# 在 3.10 版本中,推荐通过调用`inspect.get_annotations`函数来获取注解
# 基类中的注解不会继承,因此需要显式查询
if 系统模块.
版本信息
[2] < (3, 10):
对象标注 = getattr(
对象, "__annotations__", {})
否则:
obj_annotations = 检查.get_annotations(
对象)
if 长度(obj_annotations) == 0
和
有属性(
对象, "__base__"):
对象标注 =
检查.
获取标注(
对象.__base__)
注释 =
输入文本为空,请提供需要翻译的文本
对于
字段
在
对象.
字段:
if 字段
在
对象标注:
字段类型 =
对象标注[
字段]
# [注意:NamedTuple 属性中的 ForwardRef 注释]
# NamedTuple 类型与普通类型略有不同。
#
# 通常,注释是这样评估的(在 jit.script 期间):
# 1. 将 Python 代码的字符串加载到 C++中并解析。
获取注释作为字符串
使用 PythonResolver 的解析回调(rcb)将字符串转换为 Python 对象
将字符串转换为 Python 对象
我们调用 annotations.py:ann_to_type 将 Python 对象转换为类型
将步骤 3 中的内容转换为 torchscript 理解的类型。
#
命名元组更复杂,因为它有子类型。
通常,一旦我们有了步骤 3 中的命名元组类型对象,
我们可以直接查看注解字面值并使用。
直接在它们上应用 # ann_to_type。
#
但有时,用户会使用字符串字面量进行标注,例如
# x: 'int'
这也发生在 PEP563(从 __forward__ 导入 annotations)中
#
这些注释在注释字典中作为 ForwardRef('int') 出现。
#
然后,我们需要将字符串转换为 Python 对象。这
需要具有本地上下文以处理自定义对象或导入的类型。
rcb() 就是提供这个的。所以,我们将 rcb 通过堆栈连接起来。
# 可以用于下面的 if 块中。
#
# 常见问题:
# - 为什么需要对 NamedTuple 进行特殊处理,而字符串
# 注释对普通类型却可以正常工作?通常,我们解析的
# 直接从 C++中调用 rcb()。
# - 为什么不使用 ForwardRef._evaluate?为了这个,我们需要 globals()
# 和 locals()来获取 NamedTuple 定义的局部上下文。
# rcb 允许我们查找这些。所以,基本上 rcb 是做这个的。
我们的努力
if isinstance(字段类型,
前向引用)
和 rcb
是
不
无:
rcb 类型 = rcb(
字段类型.
__前向参数__)
# rcb 返回 None 如果找不到任何内容。
if rcb 类型
是
无:
抛出
值错误(
f"未知类型注解:"{
字段类型}
在 NamedTuple 中{
对象.__name__}
。
f"可能是因为 NamedTuples 对 ForwardRef 参数的支持不完整,参见#95858。"
f"问题发生于"{
位置.
突出显示()}"
)
字段类型 =
rcb 类型
该类型 =
PyTorch.
算子.
标注.
标注到类型(
字段类型,
位置, rcb)
注释.
添加(
类型)
否则:
标注.
添加(
PyTorch._C.
张量类型.
获取推断())
返回
类型(
对象).__name__,
对象.
字段,
注释,
默认
定义
_创建命名元组(
t,
未指定名称: str,
字段名:
列表[str
]
默认值:
元组[
任何, ...
]
):
元组类型 =
集合.
命名元组(
未指定名称,
字段名,
默认值=
默认值) # type: ignore[call-arg, no-redef, misc]
返回
元组类型(*t)
@contextlib.contextmanager
定义
禁用发射钩子():
钩子 =
PyTorch._C._jit_get_emit_hooks()
PyTorch._C._jit_set_emit_hooks(
无,
无)
尝试:
产生
最后:
PyTorch._C._jit_set_emit_hooks(
钩子[0
]
钩子[1])
定义 _disable_emit_hooks_decorator(
装饰器上下文管理器) ->
无: # noqa: F811
# noqa: F841
定义
__进入__(self) ->
无:
self.钩子 =
PyTorch._C._jit_get_emit_hooks()
PyTorch._C._jit_set_emit_hooks(
无,
无)
定义
__退出__(self, *
参数) ->
无:
PyTorch._C._jit_set_emit_hooks(self.
钩子[0
] self.
钩子[1])
定义 _is_exception(
对象) -> bool:
if 不
检查.
是否为类(
对象):
返回
假
返回
派生类(
对象,
异常)
定义 raise_error_container_parameter_missing(
目标类型) ->
无:
if 目标类型.
以...结尾(
信息技术):
抛出
运行时错误(
f尝试使用{
目标类型}
没有引号
请添加包含类型,例如:
f"{目标类型}
[int, int]
)
抛出
运行时错误(
f尝试使用{
目标类型}
"而没有包含类型“
"请添加包含类型,例如“
f"{目标类型}
[int]
)
_原始类型名称映射 = {
字典:
"字典",
列表:
列表,
元组:
元组,
输入法.
字典:
字典,
# 无需注意:UP006
输入法.
列表:
列表,
无
输入法.
可选:
可选,
输入法.
元组:
元组,
# 无需注意:UP006
}
def 检查参数是否存在(
目标类型) ->
无:
if 名称 :=
原始类型名称映射.
获取(
目标类型):
抛出错误容器参数缺失(
名称)
def 检查空容器(
对象) ->
无:
if 对象 ==
输入文本为空,请提供需要翻译的文本
或者
对象 == {}
或者
对象 == ():
警告.
警告(
"容器内部的类型在调用 torch.jit.isinstance 时在 eager 模式下丢失。例如,List[int]会变成 list,因此对于 List[float]等会错误地返回 True。"
"example, List[int] would become list and"
"因此对于 List[float]等会错误地返回 True。"
"therefore falsely return True for List[float] or"
"List[str]."
)
支持 List/Dict/Tuple 和 Optional 类型
# TODO 支持未来
def 容器检查器(
对象,
目标类型) -> bool:
原始类型 =
获取源(
目标类型)
检查参数是否存在(
目标类型)
if 原始类型
是
无:
返回
假
如果...否则
原始类型
是
列表
或者
原始类型
是
输入法.
列表: # noqa: UP006
检查空容器(
对象)
if 不 isinstance(
对象,
列表):
返回
假
参数类型 =
获取参数(
目标类型
)]0]
参数来源 =
获取来源(
参数类型)
对于 el
在
对象:
# 检查是否为嵌套容器,例如:List[List[str]]
if arg_origin: # 处理嵌套容器,例如:List[List[str]]
if 不
容器检查器(
元素,
参数类型):
返回
假
如果...否则
不 isinstance(
元素,
参考类型):
返回
假
返回
真实
如果...否则
原始类型
是
输入法.
字典
或者
原始类型
是
字典: # noqa: UP006
检查空容器(
对象)
if 不 isinstance(
对象,
字典):
返回
假
键类型 =
获取参数(
目标类型
)]0]
值类型 =
获取参数(
目标类型
)]1]
对于
键, val
在
对象.
项目():
检查键的类型
if 不 isinstance(
键,
键类型):
返回
假
原始值 =
获取原始值(
值类型)
if 值来源:
if 不
容器检查器(val,
值类型):
返回
假
如果...否则
不 isinstance(val,
val 类型):
返回
假
返回
真实
如果...否则
原始类型
是
输入法.
元组
或者
原始类型
是
元组: # noqa: UP006
检查空容器(
对象)
if 不 isinstance(
对象,
元组):
返回
假
参数类型 =
获取参数(
目标类型)
if 长度(
对象) !=
长度(
参数类型):
返回
假
对于 el,
元素类型
在 zip(
对象,
参数类型):
元素来源 =
获取来源(
元素类型)
if 原始元素:
if 不
容器检查器(
元素,
元素类型):
返回
假
如果...否则
不 isinstance(el, el_type):
返回
假
返回
真实
如果...否则 origin_type
是
联合
或者
派生类(
origin_type, 内置联合类型
): # 也处理可选类型
if 对象
是
无:
# 检查递归前因为 None 总是可以
返回
真实
内置类型 =
获取参数(
目标类型)
对于 t
在
内置类型:
原始类型 =
获取原始(t)
if 原始类型:
返回
容器检查器(
对象, t)
如果...否则 isinstance(
对象, t):
返回
真实
返回
假
def isinstance(
对象,
目标类型) -> bool:
if isinstance(目标类型,
集合.abc.
容器):
if 不 isinstance(
目标类型,
元组):
抛出
运行时错误(
"第二个参数是 "
"必须是一个类型"
"或者一个类型元组"
)
对于 t_type
在 target_type:
if isinstance(
对象, t_type):
返回
真实
返回
假
原始类型 = get_origin(
目标类型)
if 原始类型:
返回
容器检查器(
对象,
目标类型)
# 检查以将未指定类型的可选原始返回值处理为空
3.7-3.8 中 #of 可选
检查参数是否存在(
目标类型)
处理非容器
返回 isinstance(
对象,
目标类型)
类 _TensorExtractor(pickle.
挑选器):
def __init__(self, *参数,
张量:
列表[
PyTorch.
张量
] **kwargs):
超级().__init__(*
参数, **kwargs)
self.张量 =
张量
def 持久化 ID(self,
对象):
if isinstance(对象,
PyTorch.
张量):
self.张量.
添加(
对象)
返回
请提供需要翻译的文本
# 由于我们只想提取张量,我们不在乎一个对象是否
无法序列化,如果它不包含张量,因为我们只需忽略/跳过
# 它。为了安全起见,我们只为确定是常见物体的对象这样做
不包含张量。在此处添加新类型也请随意。注意也
即使这里没有列出类型,这也不会阻止用户,因为他们
只需为他们的类添加一个 __getstate__ 或 __reduce__ 方法即可。
if isinstance(对象,
锁类型):
返回
请提供需要翻译的文本
# 期货和 RRefs 从技术上讲不包含值,它们只是提供
# 访问值的方法。
if isinstance(对象,
未来)
或者 is_rref_instance(
对象):
返回
请提供需要翻译的文本
if isinstance(对象, CAwait):
返回
请提供需要翻译的文本
if isinstance(对象,
PyTorch.cuda.
活动):
返回
请提供需要翻译的文本
if isinstance(对象,
线程.Thread):
返回
请提供需要翻译的文本
返回
无
def 提取张量(
对象):
r""
此函数仅从 C++中调用。
请参阅 `torch/csrc/jit/python/python_ivalue.h`。
通过序列化提取给定对象中的张量。
"""
张量:
列表[
PyTorch.
张量] =
输入文本为空,请提供需要翻译的文本
提取器 =
_Tensor 提取器(
输入/输出.BytesIO(),
协议=-1,
张量=
张量)
提取器.
导出(
对象)
返回
张量
def _获取模型 ID(
对象) ->
可选[str
]
if isinstance(对象,
PyTorch.
算子.
脚本模块):
返回 str(
对象._c._type())
如果...否则 isinstance(
对象,
PyTorch.
算子.
脚本函数):
返回
对象.
合法名称
否则:
返回
无
# 在 Python-3.11+ 中,类型枚举(例如 IntEnum)保留子类中先前删除的基类方法数量
# 为了保留行为,请在此处显式删除它们
if 系统模块.version_info
≥ (3, 11):
_drop(枚举.
枚举.__new__)
_drop(枚举.
枚举.
格式化)
_drop(枚举.
枚举.__repr__)
_drop(枚举.
枚举.__str__)