torch.package¶
torch.package
添加了对创建包含构件和任意的包的支持
PyTorch 代码。这些包可以保存、共享、用于加载和执行模型
在以后或在其他计算机上部署,甚至可以使用 .torch::deploy
本文档包含教程、作指南、说明和 API 参考,其中
将帮助您了解有关和如何使用它的更多信息。torch.package
警告
此模块依赖于不安全的模块。仅解包您信任的数据。pickle
可以构造恶意的 pickle 数据,这些数据将在解封期间执行任意代码。 切勿解压缩可能来自不受信任的来源或可能已被篡改的数据。
有关更多信息,请查看该模块的文档。pickle
教程¶
打包您的第一个模型¶
Colab 上提供了指导您打包和解包简单模型的教程。 完成本练习后,您将熟悉用于创建和使用 API 的基本 API Torch 软件包。
我该如何...¶
查看包内有什么?¶
将包视为 ZIP 存档¶
a 的容器格式为 ZIP,因此任何使用标准 ZIP 文件的工具都应该
用于探索内容。与 ZIP 文件交互的一些常见方法:torch.package
unzip my_package.pt
将压缩文件解压缩到磁盘,您可以在其中自由检查其内容。torch.package
$ unzip my_package.pt && tree my_package
my_package
├── .data
│ ├── 94304870911616.storage
│ ├── 94304900784016.storage
│ ├── extern_modules
│ └── version
├── models
│ └── model_1.pkl
└── torchvision
└── models
├── resnet.py
└── utils.py
~ cd my_package && cat torchvision/models/resnet.py
...
Python 模块提供了一种读取和写入 ZIP 存档内容的标准方法。
zipfile
from zipfile import ZipFile
with ZipFile("my_package.pt") as myzip:
file_bytes = myzip.read("torchvision/models/resnet.py")
# edit file_bytes in some way
myzip.writestr("torchvision/models/resnet.py", new_file_bytes)
vim 具有本机读取 ZIP 存档的能力。您甚至可以编辑文件并 : 将它们返回存档中!
write
# add this to your .vimrc to treat `*.pt` files as zip files
au BufReadCmd *.pt call zip#Browse(expand("<amatch>"))
~ vi my_package.pt
使用 APIfile_structure()
¶
PackageImporter
提供了一个方法,该方法将返回一个 Printable
和可查询file_structure()
Directory
对象。这Directory
object 是一个简单的目录结构,您可以使用它来浏览
的当前内容。torch.package
这Directory
Object 本身是可直接打印的,并且会打印出一个文件树表示。要过滤返回的内容,
使用 glob-style 和 filtering 参数。include
exclude
with PackageExporter('my_package.pt') as pe:
pe.save_pickle('models', 'model_1.pkl', mod)
importer = PackageImporter('my_package.pt')
# can limit printed items with include/exclude args
print(importer.file_structure(include=["**/utils.py", "**/*.pkl"], exclude="**/*.storage"))
print(importer.file_structure()) # will print out all files
输出:
# filtered with glob pattern:
# include=["**/utils.py", "**/*.pkl"], exclude="**/*.storage"
─── my_package.pt
├── models
│ └── model_1.pkl
└── torchvision
└── models
└── utils.py
# all files
─── my_package.pt
├── .data
│ ├── 94304870911616.storage
│ ├── 94304900784016.storage
│ ├── extern_modules
│ └── version
├── models
│ └── model_1.pkl
└── torchvision
└── models
├── resnet.py
└── utils.py
您还可以查询Directory
对象。has_file()
importer_file_structure = importer.file_structure()
found: bool = importer_file_structure.has_file("package_a/subpackage.py")
了解为什么将给定模块作为依赖项包含在内?¶
假设有一个给定的模块 ,并且您想知道为什么您的foo
PackageExporter
作为依赖项拉入。foo
PackageExporter.get_rdeps()
将返回所有直接依赖 的模块。foo
如果您想了解给定模块如何依赖于 ,src
foo
PackageExporter.all_paths()
方法将
返回一个 DOT 格式的图形,其中显示 和 之间的所有依赖关系路径。src
foo
如果您只想查看PackageExporter
,您可以使用PackageExporter.dependency_graph_string()
.
在我的包中包含任意资源并在以后访问它们?¶
PackageExporter
公开了三种方法,这些方法允许您将
Python 对象、文本和二进制数据添加到包中。save_pickle
save_text
save_binary
with torch.PackageExporter("package.pt") as exporter:
# Pickles the object and saves to `my_resources/tensor.pkl` in the archive.
exporter.save_pickle("my_resources", "tensor.pkl", torch.randn(4))
exporter.save_text("config_stuff", "words.txt", "a sample string")
exporter.save_binary("raw_data", "binary", my_bytes)
PackageImporter
公开名为 的补充方法,并且允许您加载
来自包的 Python 对象、文本和二进制数据。load_pickle
load_text
load_binary
importer = torch.PackageImporter("package.pt")
my_tensor = importer.load_pickle("my_resources", "tensor.pkl")
text = importer.load_text("config_stuff", "words.txt")
binary = importer.load_binary("raw_data", "binary")
自定义类的打包方式?¶
torch.package
允许自定义类的打包方式。通过在类上定义方法并定义相应的解包函数来访问此行为。这类似于为
Python 的正常 pickling 过程。__reduce_package__
__reduce__
步骤:
在 target 类上定义方法。此方法应将类实例保存在包内,并应返回相应解包函数的元组,其中包含调用解包函数所需的参数。当遇到目标类的实例时,将调用此方法。
__reduce_package__(self, exporter: PackageExporter)
PackageExporter
为类定义一个解包函数。此解包函数应执行重新构造和返回类实例的工作。函数签名的第一个参数应为实例,其余参数为用户定义。
PackageImporter
# foo.py [Example of customizing how class Foo is packaged]
from torch.package import PackageExporter, PackageImporter
import time
class Foo:
def __init__(self, my_string: str):
super().__init__()
self.my_string = my_string
self.time_imported = 0
self.time_exported = 0
def __reduce_package__(self, exporter: PackageExporter):
"""
Called by ``torch.package.PackageExporter``'s Pickler's ``persistent_id`` when
saving an instance of this object. This method should do the work to save this
object inside of the ``torch.package`` archive.
Returns function w/ arguments to load the object from a
``torch.package.PackageImporter``'s Pickler's ``persistent_load`` function.
"""
# use this pattern to ensure no naming conflicts with normal dependencies,
# anything saved under this module name shouldn't conflict with other
# items in the package
generated_module_name = f"foo-generated._{exporter.get_unique_id()}"
exporter.save_text(
generated_module_name,
"foo.txt",
self.my_string + ", with exporter modification!",
)
time_exported = time.clock_gettime(1)
# returns de-packaging function w/ arguments to invoke with
return (unpackage_foo, (generated_module_name, time_exported,))
def unpackage_foo(
importer: PackageImporter, generated_module_name: str, time_exported: float
) -> Foo:
"""
Called by ``torch.package.PackageImporter``'s Pickler's ``persistent_load`` function
when depickling a Foo object.
Performs work of loading and returning a Foo instance from a ``torch.package`` archive.
"""
time_imported = time.clock_gettime(1)
foo = Foo(importer.load_text(generated_module_name, "foo.txt"))
foo.time_imported = time_imported
foo.time_exported = time_exported
return foo
# example of saving instances of class Foo
import torch
from torch.package import PackageImporter, PackageExporter
import foo
foo_1 = foo.Foo("foo_1 initial string")
foo_2 = foo.Foo("foo_2 initial string")
with PackageExporter('foo_package.pt') as pe:
# save as normal, no extra work necessary
pe.save_pickle('foo_collection', 'foo1.pkl', foo_1)
pe.save_pickle('foo_collection', 'foo2.pkl', foo_2)
pi = PackageImporter('foo_package.pt')
print(pi.file_structure())
imported_foo = pi.load_pickle('foo_collection', 'foo1.pkl')
print(f"foo_1 string: '{imported_foo.my_string}'")
print(f"foo_1 export time: {imported_foo.time_exported}")
print(f"foo_1 import time: {imported_foo.time_imported}")
# output of running above script
─── foo_package
├── foo-generated
│ ├── _0
│ │ └── foo.txt
│ └── _1
│ └── foo.txt
├── foo_collection
│ ├── foo1.pkl
│ └── foo2.pkl
└── foo.py
foo_1 string: 'foo_1 initial string, with reduction modification!'
foo_1 export time: 9857706.650140837
foo_1 import time: 9857706.652698385
在我的源代码中测试它是否在包内执行?¶
一个PackageImporter
会将 attribute 添加到它初始化的每个模块中。您的代码可以检查
存在此属性来确定它是否在打包的上下文中执行。__torch_package__
# In foo/bar.py:
if "__torch_package__" in dir(): # true if the code is being loaded from a package
def is_in_package():
return True
UserException = Exception
else:
def is_in_package():
return False
UserException = UnpackageableException
现在,代码的行为将有所不同,具体取决于它是通过 Python 环境正常导入还是从 .torch.package
from foo.bar import is_in_package
print(is_in_package()) # False
loaded_module = PackageImporter(my_package).import_module("foo.bar")
loaded_module.is_in_package() # True
警告: 一般来说,根据代码是否打包而具有不同的行为是不好的做法。这可能导致 难以调试的问题,这些问题对您导入代码的方式很敏感。如果您的软件包打算被大量使用,请考虑重组 您的代码,以便无论它如何加载,它的行为方式都相同。
将代码修补到包中?¶
PackageExporter
提供了一种方法,允许将任意 Python 源代码保存到您选择的模块中。save_source_string()
with PackageExporter(f) as exporter:
# Save the my_module.foo available in your current Python environment.
exporter.save_module("my_module.foo")
# This saves the provided string to my_module/foo.py in the package archive.
# It will override the my_module.foo that was previously saved.
exporter.save_source_string("my_module.foo", textwrap.dedent(
"""\
def my_function():
print('hello world')
"""
))
# If you want to treat my_module.bar as a package
# (e.g. save to `my_module/bar/__init__.py` instead of `my_module/bar.py)
# pass is_package=True,
exporter.save_source_string("my_module.bar",
"def foo(): print('hello')\n",
is_package=True)
importer = PackageImporter(f)
importer.import_module("my_module.foo").my_function() # prints 'hello world'
从打包的代码中访问包内容?¶
PackageImporter
实现 importlib.resources API,以便从包内部访问资源。
with PackageExporter(f) as exporter:
# saves text to my_resource/a.txt in the archive
exporter.save_text("my_resource", "a.txt", "hello world!")
# saves the tensor to my_pickle/obj.pkl
exporter.save_pickle("my_pickle", "obj.pkl", torch.ones(2, 2))
# see below for module contents
exporter.save_module("foo")
exporter.save_module("bar")
API 允许从打包代码中访问资源。importlib.resources
# foo.py:
import importlib.resources
import my_resource
# returns "hello world!"
def get_my_resource():
return importlib.resources.read_text(my_resource, "a.txt")
使用是从打包代码中访问包内容的推荐方法,因为它符合
使用 Python 标准。但是,也可以访问父级importlib.resources
PackageImporter
实例本身
打包的代码。
# bar.py:
import torch_package_importer # this is the PackageImporter that imported this module.
# Prints "hello world!", equivalent to importlib.resources.read_text
def get_my_resource():
return torch_package_importer.load_text("my_resource", "a.txt")
# You also do things that the importlib.resources API does not support, like loading
# a pickled object from the package.
def get_my_pickle():
return torch_package_importer.load_pickle("my_pickle", "obj.pkl")
区分打包代码和非打包代码?¶
要判断对象的代码是否来自 ,请使用该函数。
注意:如果对象来自包,但其定义来自标记为 或 from 的模块,
此检查将返回 。torch.package
torch.package.is_from_package()
extern
stdlib
False
importer = PackageImporter(f)
mod = importer.import_module('foo')
obj = importer.load_pickle('model', 'model.pkl')
txt = importer.load_text('text', 'my_test.txt')
assert is_from_package(mod)
assert is_from_package(obj)
assert not is_from_package(txt) # str is from stdlib, so this will return False
重新导出导入的对象?¶
要重新导出以前由PackageImporter
,您必须将新的PackageExporter
了解原始PackageImporter
以便它可以找到对象依赖项的源代码。
importer = PackageImporter(f)
obj = importer.load_pickle("model", "model.pkl")
# re-export obj in a new package
with PackageExporter(f2, importer=(importer, sys_importer)) as exporter:
exporter.save_pickle("model", "model.pkl", obj)
打包 TorchScript 模块?¶
要打包 TorchScript 模型,请使用与任何其他对象相同的 and API。
还支持保存作为属性或子模块的 TorchScript 对象,无需额外工作。save_pickle
load_pickle
# save TorchScript just like any other object
with PackageExporter(file_name) as e:
e.save_pickle("res", "script_model.pkl", scripted_model)
e.save_pickle("res", "mixed_model.pkl", python_model_with_scripted_submodule)
# load as normal
importer = PackageImporter(file_name)
loaded_script = importer.load_pickle("res", "script_model.pkl")
loaded_mixed = importer.load_pickle("res", "mixed_model.pkl"
解释¶
torch.package
格式概述¶
文件是通常使用扩展名的 ZIP 存档。在 ZIP 存档中,有两种类型的文件:torch.package
.pt
框架文件,这些文件位于 .
.data/
User 文件,这是其他所有内容。
例如,这是完全打包的 ResNet 模型的样子:torchvision
resnet
├── .data # All framework-specific data is stored here.
│ │ # It's named to avoid conflicts with user-serialized code.
│ ├── 94286146172688.storage # tensor data
│ ├── 94286146172784.storage
│ ├── extern_modules # text file with names of extern modules (e.g. 'torch')
│ ├── version # version metadata
│ ├── ...
├── model # the pickled model
│ └── model.pkl
└── torchvision # all code dependencies are captured as source files
└── models
├── resnet.py
└── utils.py
框架文件¶
该目录由 torch.package 拥有,其内容被视为私有实现细节。
该格式不保证 的内容,但所做的任何更改都将向后兼容
(也就是说,较新版本的 PyTorch 将始终能够加载较旧版本的 )。.data/
torch.package
.data/
torch.packages
目前,该目录包含以下项:.data/
version
:序列化格式的版本号,以便导入基础设施知道如何加载此包。torch.package
extern_modules
:将被视为模块的模块列表将使用加载环境的系统导入器导入。extern:class:`PackageImporter`. ``extern
*.storage
:序列化的 Tensor 数据。
.data
├── 94286146172688.storage
├── 94286146172784.storage
├── extern_modules
├── version
├── ...
用户文件¶
存档中的所有其他文件都是由用户放在那里的。布局与 Python 常规包相同。要更深入地了解 Python 打包的工作原理, 请查阅这篇文章(它有点过时了,所以请仔细检查实现细节 替换为 Python 参考文档)。
<package root>
├── model # the pickled model
│ └── model.pkl
├── another_package
│ ├── __init__.py
│ ├── foo.txt # a resource file , see importlib.resources
│ └── ...
└── torchvision
└── models
├── resnet.py # torchvision.models.resnet
└── utils.py # torchvision.models.utils
如何查找代码的依赖项torch.package
¶
分析对象的依赖关系¶
当您发出呼叫时,save_pickle(obj, ...)
PackageExporter
将正常 pickle 对象。然后,它使用 standard library 模块来解析 pickle 字节码。pickletools
在 pickle 中,一个对象与一个作码一起保存,该作码描述了在何处可以找到对象类型的实现,例如:GLOBAL
GLOBAL 'torchvision.models.resnet Resnet`
依赖项解析器将收集所有 op 并将它们标记为 pickled 对象的依赖项。
有关 pickling 和 pickle 格式的更多信息,请参阅 Python 文档。GLOBAL
分析模块的依赖项¶
当 Python 模块被标识为依赖项时,遍历模块的 python AST 表示形式,并使用
完全支持标准格式:、、 等。当这些 import 语句之一为
遇到,将导入的模块注册为依赖项,然后这些依赖项本身在相同的 AST walking way 中进行解析。torch.package
from x import y
import z
from w import v as u
torch.package
注意:AST 解析对语法的支持有限,并且不支持调用。一般来说,您应该
不希望 检测到动态导入。__import__(...)
importlib.import_module
torch.package
依赖关系管理¶
torch.package
自动查找您的代码和对象所依赖的 Python 模块。此过程称为依赖项解析。
对于依赖项解析程序找到的每个模块,您必须指定要执行的作。
允许的作包括:
intern
:将此模块放入包中。extern
:将此模块声明为软件包的外部依赖项。mock
:存根此模块。deny
:取决于此模块将在包导出期间引发错误。
最后,还有一个更重要的作,从技术上讲不是 :torch.package
重构:删除或更改代码中的依赖项。
请注意,作仅在整个 Python 模块上定义。没有办法从模块中“只”打包一个函数或类,而把其余的都省略掉。
这是设计使然。Python 不在模块中定义的对象之间提供清晰的边界。唯一定义的依赖关系组织单位是
模块,所以这就是 USE。torch.package
作使用模式应用于模块。模式可以是模块名称 () 或 globs (如 )。您关联模式
使用 methods on 的作"foo.bar"
"foo.**"
PackageExporter
,例如
my_exporter.intern("torchvision.**")
my_exporter.extern("numpy")
如果模块与模式匹配,则会对其应用相应的作。对于给定的模块,将按照定义模式的顺序检查模式。 ,将执行第一个作。
intern
¶
如果一个模块是 -ed 的,它将被放入 package 中。intern
此作是您的模型代码,或要打包的任何相关代码。例如,如果您尝试从 打包 ResNet,则
您将需要模块 torchvision.models.resnet。torchvision
intern
在包导入时,当你的打包代码尝试导入一个 -ed 模块时,PackageImporter 将在你的包中查找该模块。
如果找不到该模块,则会引发错误。这确保了每个intern
PackageImporter
与加载环境隔离 — 甚至
如果您的 package 和 loading environment 中都可用,则my_interned_module
PackageImporter
将仅使用
包。
注意:只有 Python 源模块可以被 -ed。其他类型的模块,如 C 扩展模块和字节码模块,如果
你试图去找他们。这些类型的模块需要 -ed 或 -ed。intern
intern
mock
extern
extern
¶
如果模块是 -ed 的,则不会打包。相反,它将被添加到此包的外部依赖项列表中。你可以找到这个
上的 列表。extern
package_exporter.extern_modules
在包导入时,当打包的代码尝试导入 -ed 模块时,extern
PackageImporter
将使用默认的 Python 导入器来查找
该模块,就像您执行了 .如果找不到该模块,则会引发错误。importlib.import_module("my_externed_module")
通过这种方式,您可以依赖第三方库,例如 和 从您的包中,而不必也打包它们。numpy
scipy
警告: 如果任何外部库以向后不兼容的方式更改,则包可能无法加载。如果您需要长期可重复性
对于您的包,请尝试限制您对 .extern
mock
¶
如果模块是 -ed 的,则不会打包。相反,一个 stub 模块将被打包在它的位置。stub 模块将允许您检索
对象(这样不会出错),但对该对象的任何使用都会引发 .mock
from my_mocked_module import foo
NotImplementedError
mock
应该用于您“知道”在加载的包中不需要的代码,但您仍然希望在未打包的内容中使用。
例如,初始化/配置代码,或仅用于调试/训练的代码。
警告: 一般来说,应该作为最后的手段。它引入了打包代码和非打包代码之间的行为差异。
这可能会导致以后的混淆。相反,更喜欢重构代码以删除不需要的依赖项。mock
重构¶
管理依赖项的最好方法是完全没有依赖项!通常,可以重构代码以删除不必要的依赖项。以下是一些 编写具有干净依赖项的代码的准则(这通常也是很好的做法!
仅包含您使用的内容。不要在代码中保留未使用的导入。依赖项解析器不够聪明,无法判断它们确实未使用, 并将尝试处理它们。
限定您的导入。例如,与其编写 import foo 然后使用 ,不如写 。这
精确地指定您的真实依赖关系 (),并让依赖关系解析程序知道您不需要所有 .foo.bar.baz
from foo.bar import baz
foo.bar
foo
将功能不相关的大文件拆分为较小的文件。如果您的模块包含大量不相关的功能,则任何模块
那依赖于 will 需要拉取许多不相关的依赖项,即使你只需要其中的一小部分。Prefer 改为定义
可以彼此独立打包的单一用途模块。utils
utils
模式¶
模式允许您使用方便的语法指定模块组。模式的语法和行为遵循 Bazel/Buck glob()。
我们尝试与模式匹配的模块称为 candidate。候选 Cookie 由一系列段组成,这些段由
分隔符字符串,例如 .foo.bar.baz
模式包含一个或多个段。细分可以是:
一个 Literals 字符串(例如 ),它完全匹配。
foo
包含通配符的字符串(例如 、 或 )。通配符匹配任何字符串,包括空字符串。
torch
foo*baz*
双通配符 ()。这将与零个或多个完整区段匹配。
**
例子:
torch.**
:匹配及其所有子模块,例如 和。torch
torch.nn
torch.nn.functional
torch.*
:匹配 或 ,但不匹配 或torch.nn
torch.functional
torch.nn.functional
torch
torch*.**
:匹配 、 和它们的所有子模块torch
torchvision
指定 action 时,您可以传递多个模式,例如
exporter.intern(["torchvision.models.**", "torchvision.utils.**"])
如果模块与任何模式匹配,则模块将与此作匹配。
您还可以指定要排除的模式,例如
exporter.mock("**", exclude=["torchvision.**"])
如果模块与任何排除模式匹配,则模块将不会与此作匹配。在这个例子中,我们模拟了除 及其子模块之外的所有模块。torchvision
当一个模块可能与多个作匹配时,将执行定义的第一个作。
torch.package
锋利的边缘¶
避免在模块中使用全局状态¶
Python 使绑定对象和在模块级范围内运行代码变得非常容易。这通常很好,毕竟,函数和类都绑定到 以这种方式命名。然而,当你在模块范围内定义一个对象并打算改变它时,事情会变得更加复杂,引入 mutable 全局状态。
可变全局状态非常有用 — 它可以减少样板文件,允许打开注册到表中,等等。但是,除非非常小心地使用,否则它可以
与 一起使用时会导致并发症。torch.package
每PackageImporter
为其内容创建独立的环境。这很好,因为这意味着我们加载多个包并确保
它们彼此隔离,但是当以假定共享可变全局状态的方式编写模块时,此行为可能会产生难以调试的情况
错误。
如何使包彼此隔离torch.package
¶
每PackageImporter
实例为其模块和对象创建一个独立的隔离环境。包中的模块只能导入
其他打包的模块或标记为 的模块 。如果您使用多个extern
PackageImporter
实例来加载单个 package,您将获得
多个不交互的独立环境。
这是通过使用自定义导入器扩展 Python 的导入基础设施来实现的。PackageImporter
提供与 importer 相同的核心 API;即,它实现 AND 方法。importlib
import_module
__import__
调用PackageImporter.import_module()
,PackageImporter
将构造并返回一个新模块,就像系统导入器一样。
然而PackageImporter
修补返回的模块以使用(即self
PackageImporter
instance) 来完成将来的导入
请求。
杂耍¶
为避免混淆(“此对象是我的包中的对象,还是我的 Python 环境中的对象?foo.bar
PackageImporter
通过向所有导入的模块添加 mangle 前缀来破坏 and。__name__
__file__
对于 ,名称(如 )变为 。__name__
torchvision.models.resnet18
<torch_package_0>.torchvision.models.resnet18
对于 ,名称(如 )变为 。__file__
torchvision/models/resnet18.py
<torch_package_0>.torchvision/modules/resnet18.py
名称重整有助于避免不同包之间无意中混淆模块名称,并通过制作堆栈跟踪和打印来帮助你进行调试
语句更清楚地表明它们是否引用打包代码。有关修饰的面向开发人员的详细信息,请参阅 。mangling.md
torch/package/
API 参考¶
- 类 torch.package 中。PackagingError(dependency_graph)[来源]¶
当导出包时出现问题时,会引发此异常。 将尝试收集所有错误并呈现 他们立刻向你。
PackageExporter
- 类 torch.package 中。EmptyMatchError[来源]¶
当 mock 或 extern 被标记为 时,会引发一个异常,并且在打包过程中与任何模块都不匹配。
allow_empty=False
- 类 torch.package 中。PackageExporter(f, importer=<torch.package.importer._SysImporter object>)[来源]¶
导出器允许您编写代码包、腌制的 Python 数据和 将任意二进制和文本资源合并到一个自包含的包中。
导入可以以封闭的方式加载此代码,以便加载代码 而不是普通的 Python 导入系统。这允许 用于打包 PyTorch 模型代码和数据,以便可以运行 在服务器上或将来用于迁移学习。
包中包含的代码是从原始 source 时创建,并且文件格式是专门组织的 zip 文件。该包的未来用户可以解压缩该包,并编辑代码 以便对其执行自定义修改。
packages 的导入器确保模块中的代码只能从 在包中,但显式列为 external using 的模块
extern()
. zip 存档中的文件列出了软件包外部依赖的所有模块。 这可以防止包在本地运行的 “隐式” 依赖项,因为它正在导入 本地安装的软件包,但在将软件包复制到另一台计算机时失败。extern_modules
将源代码添加到包中时,导出器可以选择对其进行扫描 有关进一步的代码依赖项 ()。它查找 import 语句 解析对限定模块名称的相对引用,并执行用户指定的作 (请参阅:
dependencies=True
extern()
,mock()
和intern()
).- all_paths(src, dst)[来源]¶
- 返回子图的点表示
,其中包含从 src 到 DST 的所有路径。
- 结果
包含从 src 到 dst 的所有路径的点表示形式。 (https://graphviz.org/doc/info/lang.html)
- 返回类型:
- deny(include, *, exclude=())[来源]¶
将名称与软件包可以导入的模块列表中的给定 glob 模式匹配的模块列入黑名单。 如果找到对任何匹配软件包的依赖项,则
PackagingError
被提升。
- extern(include, *, exclude=(), allow_empty=True)[来源]¶
包含在包可以导入的外部模块列表中。 这将阻止依赖项发现保存 it 在包中。导入器将直接从标准导入系统加载外部模块。 extern 模块的代码也必须存在于加载包的进程中。
module
- 参数
include (Union[List[str], str]) – 字符串,例如 ,或字符串列表 以获取要 externed 的模块的名称。这也可以是 glob 样式模式,如 在
"my_package.my_subpackage"
mock()
.allow_empty (bool) – 一个可选标志,用于指定此调用指定的 extern 模块 到方法时必须与某个模块匹配。如果 extern 模块 glob pattern 添加 ,并且
extern
allow_empty=False
close()
在任何模块匹配该模式之前被调用(显式或通过),则会引发异常。如果 不会引发此类异常。__exit__
allow_empty=True
- intern(include, *, exclude=(), allow_empty=True)[来源]¶
指定应打包的模块。模块必须与某种模式匹配才能 包含在包中,并递归处理其依赖项。
intern
- 参数
include (Union[List[str], str]) – 字符串,例如 “my_package.my_subpackage”,或字符串列表 以获取要 externed 的模块的名称。这也可以是 glob 样式模式,如
mock()
.exclude (Union[List[str], str]) – 一种可选模式,用于排除与 include 字符串匹配的某些模式。
allow_empty (bool) – 一个可选标志,用于指定此调用指定的实习生模块 到方法时必须与某个模块匹配。如果模块 glob pattern 添加 ,并且
intern
intern
allow_empty=False
close()
被调用(显式或通过) 在任何模块与该模式匹配之前,将引发异常。如果 ,则不会引发此类异常。__exit__
allow_empty=True
- mock(include, *, exclude=(), allow_empty=True)[来源]¶
将一些必需的模块替换为 mock 实现。模拟模块将返回一个 fake object 来访问它的任何属性。因为我们逐个文件复制,所以依赖项解析有时会 查找由模型文件导入但其功能从未使用过的文件 (例如,自定义序列化代码或训练帮助程序)。 使用此函数可以模拟此功能,而无需修改原始代码。
- 参数
字符串(例如 )或字符串列表 以获取要模拟的模块的名称。字符串也可以是 glob 样式模式 字符串。与此模式匹配的任何必需依赖项 string 将自动模拟。
"my_package.my_subpackage"
- 例子:
'torch.**'
– 匹配和 torch 的所有子模块,例如 和torch
'torch.nn'
'torch.nn.functional'
'torch.*'
– 匹配 或 ,但不匹配'torch.nn'
'torch.functional'
'torch.nn.functional'
exclude (Union[List[str], str]) – 一种可选模式,用于排除与 include 字符串匹配的某些模式。 例如 将模拟除 默认值:为 .
include='torch.**', exclude='torch.foo'
'torch.foo'
[]
allow_empty (bool) – 一个可选标志,用于指定此调用指定的模拟实现是否 到
mock()
method 必须与某个模块匹配。如果添加了 mock ,则使用 和allow_empty=False
close()
被调用(显式或通过),并且 mock 具有 未与正在导出的包使用的模块匹配,则会引发异常。 如果 ,则不会引发此类异常。__exit__
allow_empty=True
- register_extern_hook(钩子)[来源]¶
在导出器上注册 extern 钩子。
每次模块与
extern()
模式。 它应具有以下签名:hook(exporter: PackageExporter, module_name: str) -> None
Hook 将按照注册顺序被调用。
- 结果
一个句柄,可用于通过调用 来删除添加的钩子。
handle.remove()
- 返回类型:
torch.utils.hooks.RemovableHandle
- register_intern_hook(钩子)[来源]¶
在导出器上注册 intern hook。
每次模块与
intern()
模式。 它应具有以下签名:hook(exporter: PackageExporter, module_name: str) -> None
Hook 将按照注册顺序被调用。
- 结果
一个句柄,可用于通过调用 来删除添加的钩子。
handle.remove()
- 返回类型:
torch.utils.hooks.RemovableHandle
- register_mock_hook(钩子)[来源]¶
在导出器上注册一个 mock hook。
每次模块与
mock()
模式。 它应具有以下签名:hook(exporter: PackageExporter, module_name: str) -> None
Hook 将按照注册顺序被调用。
- 结果
一个句柄,可用于通过调用 来删除添加的钩子。
handle.remove()
- 返回类型:
torch.utils.hooks.RemovableHandle
- save_module(module_name, dependencies=True)[来源]¶
将 的代码保存到包中。模块的代码使用路径进行解析,以查找 module 对象,然后使用其属性查找源代码。
module
importers
__file__
- save_pickle(package, resource, obj, dependencies=True, pickle_protocol=3)[来源]¶
使用 pickle 将 python 对象保存到存档中。相当于
torch.save()
但存到 存档文件,而不是独立文件。Stanard pickle 不保存代码,只保存对象。 如果为 true,则此方法还将扫描需要 modules 的腌制对象 以重新构造它们并保存相关代码。dependencies
为了能够保存对象,其中 is ,必须根据顺序解析为对象的类。当保存 之前已经打包过,则导入器的方法需要出现在列表中 才能使它起作用。
type(obj).__name__
my_module.MyObject
my_module.MyObject
importer
import_module
importer
- save_source_file(module_name, file_or_directory, dependencies=True)[来源]¶
将本地文件系统添加到源码包中以提供代码 为。
file_or_directory
module_name
- 参数
module_name (str) – 例如,将保存代码以为此包提供代码。
"my_package.my_subpackage"
file_or_directory (str) – 文件或代码目录的路径。当一个目录时,目录中的所有 python 文件 使用
save_source_file()
.如果文件已命名,则处理代码 作为一个包。"/__init__.py"
dependencies (bool, optional) – 如果 ,我们将扫描源中的依赖项。
True
- 类 torch.package 中。PackageImporter(file_or_buffer, module_allowed=<function PackageImporter.<lambda>>)[来源]¶
导入器允许您加载写入包的代码
PackageExporter
. 使用包中的文件以封闭方式加载代码 而不是普通的 Python 导入系统。这允许 用于打包 PyTorch 模型代码和数据,以便可以运行 在服务器上或将来用于迁移学习。packages 的导入器确保模块中的代码只能从 在包中,但在导出过程中明确列为 external 的模块除外。 zip 存档中的文件列出了软件包外部依赖的所有模块。 这可以防止包在本地运行的 “隐式” 依赖项,因为它正在导入 本地安装的软件包,但在将软件包复制到另一台计算机时失败。
extern_modules
- __init__(file_or_buffer, module_allowed=<function PackageImporter.<lambda>>)[来源]¶
打开以供导入。这将检查导入的包是否只需要模块 允许者
file_or_buffer
module_allowed
- id()[来源]¶
返回 torch.package 用于区分的内部标识符
PackageImporter
实例。 看来:<torch_package_0>
- import_module(name, package=None)[来源]¶
如果尚未加载 package,则从 package 中加载一个 module,然后返回 模块。模块在本地加载 添加到导入器中,并且将显示在 而不是 中。
self.modules
sys.modules
- load_pickle(包、资源、map_location=无)[源]¶
从包中解封资源,加载构造对象所需的任何模块 用
import_module()
.