目录

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()

提供了一个方法,该方法将返回一个 Printable 和 queryable 对象。该对象是一个简单的目录结构,可用于浏览 的当前内容。file_structure()torch.package

对象本身是可直接打印的,并将打印出文件树表示形式。要过滤返回的内容, 使用 glob-style 和 filtering 参数。includeexclude

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

您还可以使用该方法查询对象。has_file()

importer_file_structure = importer.file_structure()
found: bool = importer_file_structure.has_file("package_a/subpackage.py")

了解为什么将给定模块作为依赖项包含在内?

假设有一个给定的 module ,你想知道为什么你要作为一个依赖项拉入。foofoo

将返回所有直接依赖 的模块。foo

如果您想了解给定模块如何依赖于 ,该方法将 返回一个 DOT 格式的图形,其中显示 和 之间的所有依赖关系路径。srcfoosrcfoo

如果您只想查看 的整个依赖关系图 ,则可以使用

在我的包中包含任意资源并在以后访问它们?

公开了三种方法,这些方法允许您将 Python 对象、文本和二进制数据添加到包中。save_picklesave_textsave_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)

公开名为 的补充方法,并且允许您加载 来自包的 Python 对象、文本和二进制数据。load_pickleload_textload_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__

步骤:

  1. 在 target 类上定义方法。此方法应将类实例保存在包内,并应返回相应解包函数的元组,其中包含调用解包函数所需的参数。当遇到目标类的实例时,将调用此方法。__reduce_package__(self, exporter: PackageExporter)PackageExporter

  2. 为类定义一个解包函数。此解包函数应执行重新构造和返回类实例的工作。函数签名的第一个参数应为实例,其余参数为用户定义。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

在我的源代码中测试它是否在包内执行?

A 会将该属性添加到它初始化的每个模块中。您的代码可以检查 存在此属性来确定它是否在打包的上下文中执行。__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

警告: 一般来说,根据代码是否打包而具有不同的行为是不好的做法。这可能导致 难以调试的问题,这些问题对您导入代码的方式很敏感。如果您的软件包打算被大量使用,请考虑重组 您的代码,以便无论它如何加载,它的行为方式都相同。

将代码修补到包中?

提供了一种方法,允许将任意 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'

从打包的代码中访问包内容?

实现 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

# 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.packagetorch.package.is_from_package()externstdlibFalse

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

重新导出导入的对象?

要重新导出以前由 导入的对象,必须使 new 知道原始对象,以便它可以找到对象的依赖项的源代码。

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_pickleload_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"

解释

格式概述

文件是通常使用扩展名的 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:被视为 的模块列表。 模块将使用加载环境的 System Importer 导入。externextern

  • *.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

如何查找代码的依赖项

分析对象的依赖关系

当你发出 call 时,会正常 pickle 对象。然后,它使用 standard library 模块来解析 pickle 字节码。save_pickle(obj, ...)pickletools

在 pickle 中,一个对象与一个操作码一起保存,该操作码描述了在何处可以找到对象类型的实现,例如:GLOBAL

GLOBAL 'torchvision.models.resnet Resnet`

依赖项解析器将收集所有 op 并将它们标记为 pickled 对象的依赖项。 有关 pickling 和 pickle 格式的更多信息,请参阅 Python 文档GLOBAL

分析模块的依赖项

当 Python 模块被标识为依赖项时,遍历模块的 python AST 表示形式,并使用 完全支持标准格式:、、 等。当这些 import 语句之一为 遇到,将导入的模块注册为依赖项,然后这些依赖项本身在相同的 AST walking way 中进行解析。torch.packagefrom x import yimport zfrom w import v as utorch.package

注意:AST 解析对语法的支持有限,并且不支持调用。一般来说,您应该 不希望 检测到动态导入。__import__(...)importlib.import_moduletorch.package

依赖关系管理

torch.package自动查找您的代码和对象所依赖的 Python 模块。此过程称为依赖项解析。 对于依赖项解析程序找到的每个模块,您必须指定要执行的操作

允许的操作包括:

  • intern:将此模块放入包中。

  • extern:将此模块声明为软件包的外部依赖项。

  • mock:存根此模块。

  • deny:取决于此模块将在包导出期间引发错误。

最后,还有一个更重要的操作,从技术上讲不是 :torch.package

  • 重构:删除或更改代码中的依赖项。

请注意,操作仅在整个 Python 模块上定义。没有办法从模块中“只”打包一个函数或类,而把其余的都省略掉。 这是设计使然。Python 不在模块中定义的对象之间提供清晰的边界。唯一定义的依赖关系组织单位是 模块,所以这就是 USE。torch.package

操作使用模式应用于模块。模式可以是模块名称 () 或 globs (如 )。您关联模式 使用 on 的方法执行操作,例如"foo.bar""foo.**"

my_exporter.intern("torchvision.**")
my_exporter.extern("numpy")

如果模块与模式匹配,则会对其应用相应的操作。对于给定的模块,将按照定义模式的顺序检查模式。 ,将执行第一个操作。

intern

如果一个模块是 -ed 的,它将被放入 package 中。intern

此操作是您的模型代码,或要打包的任何相关代码。例如,如果您尝试从 打包 ResNet,则 您将需要模块 torchvision.models.resnet。torchvisionintern

在包导入时,当你的打包代码尝试导入一个 -ed 模块时,PackageImporter 将在你的包中查找该模块。 如果找不到该模块,则会引发错误。这可确保每个 Slas 与 Load Environment 隔离 — 甚至 如果您在包和加载环境中都可用,则只会使用 包。internmy_interned_module

注意:只有 Python 源模块可以被 -ed。其他类型的模块,如 C 扩展模块和字节码模块,如果 你试图去找他们。这些类型的模块需要 -ed 或 -ed。interninternmockextern

extern

如果模块是 -ed 的,则不会打包。相反,它将被添加到此包的外部依赖项列表中。你可以找到这个 上的 列表。externpackage_exporter.extern_modules

在包导入时,当打包的代码尝试导入 -ed 模块时,将使用默认的 Python 导入器来查找 该模块,就像您执行了 .如果找不到该模块,则会引发错误。externimportlib.import_module("my_externed_module")

通过这种方式,您可以依赖第三方库,例如 和 从您的包中,而不必也打包它们。numpyscipy

警告: 如果任何外部库以向后不兼容的方式更改,则您的包可能无法加载。如果您需要长期可重复性 对于您的包,请尝试限制您对 .extern

mock

如果模块是 -ed 的,则不会打包。相反,一个 stub 模块将被打包在它的位置。stub 模块将允许您检索 对象(这样不会出错),但对该对象的任何使用都会引发 .mockfrom my_mocked_module import fooNotImplementedError

mock应该用于您 “知道” 在加载的包中不需要的代码,但您仍然希望在未打包的内容中使用。 例如,初始化/配置代码,或仅用于调试/训练的代码。

警告: 一般来说,应该作为最后的手段使用。它引入了打包代码和非打包代码之间的行为差异。 这可能会导致以后的混淆。而是选择重构代码以删除不需要的依赖项。mock

重构

管理依赖项的最好方法是完全没有依赖项!通常,可以重构代码以删除不必要的依赖项。以下是一些 编写具有干净依赖项的代码的准则(这通常也是很好的做法!

仅包含您使用的内容。不要在代码中保留未使用的导入。依赖项解析器不够聪明,无法判断它们确实未使用, 并将尝试处理它们。

限定您的导入。例如,与其编写 import foo 然后使用 ,不如写 。这 精确地指定您的真实依赖关系 (),并让依赖关系解析程序知道您不需要所有 .foo.bar.bazfrom foo.bar import bazfoo.barfoo

将功能不相关的大文件拆分为较小的文件。如果您的模块包含大量不相关的功能,则任何模块 那依赖于 will 需要拉取许多不相关的依赖项,即使你只需要其中的一小部分。Prefer 改为定义 可以彼此独立打包的单一用途模块。utilsutils

模式

模式允许您使用方便的语法指定模块组。模式的语法和行为遵循 Bazel/Buck glob()。

我们尝试与模式匹配的模块称为 candidate。候选 Cookie 由一系列段组成,这些段由 分隔符字符串,例如 .foo.bar.baz

模式包含一个或多个段。细分可以是:

  • 一个 Literals 字符串(例如 ),它完全匹配。foo

  • 包含通配符的字符串(例如 、 或 )。通配符匹配任何字符串,包括空字符串。torchfoo*baz*

  • 双通配符 ()。这将与零个或多个完整区段匹配。**

例子:

  • torch.**:匹配及其所有子模块,例如 和。torchtorch.nntorch.nn.functional

  • torch.*:匹配 或 ,但不匹配 或torch.nntorch.functionaltorch.nn.functionaltorch

  • torch*.**:匹配 、 和它们的所有子模块torchtorchvision

指定 action 时,您可以传递多个模式,例如

exporter.intern(["torchvision.models.**", "torchvision.utils.**"])

如果模块与任何模式匹配,则模块将与此操作匹配。

您还可以指定要排除的模式,例如

exporter.mock("**", exclude=["torchvision.**"])

如果模块与任何排除模式匹配,则模块将不会与此操作匹配。在这个例子中,我们模拟了除 及其子模块之外的所有模块。torchvision

当一个模块可能与多个操作匹配时,将执行定义的第一个操作。

锋利的边缘

避免在模块中使用全局状态

Python 使绑定对象和在模块级范围内运行代码变得非常容易。这通常很好,毕竟,函数和类都绑定到 以这种方式命名。然而,当你在模块范围内定义一个对象并打算改变它时,事情会变得更加复杂,引入 mutable 全局状态。

可变全局状态非常有用 — 它可以减少样板文件,允许打开注册到表中,等等。但是,除非非常小心地使用,否则它可以 与 一起使用时会导致并发症。torch.package

每个 Symbol 都会为其内容创建一个独立的环境。这很好,因为这意味着我们加载多个包并确保 它们彼此隔离,但是当以假定共享可变全局状态的方式编写模块时,此行为可能会产生难以调试的情况 错误。

类型不在包和加载环境之间共享

您从 导入的任何类都将是特定于该导入器的类的版本。例如:

from foo import MyClass

my_class_instance = MyClass()

with PackageExporter(f) as exporter:
    exporter.save_module("foo")

importer = PackageImporter(f)
imported_MyClass = importer.import_module("foo").MyClass

assert isinstance(my_class_instance, MyClass)  # works
assert isinstance(my_class_instance, imported_MyClass)  # ERROR!

在此示例中,它们不是同一类型。在这个特定示例中,并且恰好具有 相同的实现,因此您可能会认为将它们视为同一类是可以的。但是考虑一下来自 older 包具有完全不同的实现 — 在这种情况下,将它们视为同一个类是不安全的。MyClassimported_MyClassMyClassimported_MyClassimported_MyClassMyClass

在后台,每个导入器都有一个前缀,允许它唯一标识类:

print(MyClass.__name__)  # prints "foo.MyClass"
print(imported_MyClass.__name__)  # prints <torch_package_0>.foo.MyClass

这意味着当其中一个参数来自包而另一个不是时,你不应该期望检查会起作用。如果您需要这个 功能,请考虑以下选项:isinstance

  • 进行鸭子类型化(仅使用类,而不是显式检查它是否属于给定类型)。

  • 使类型关系成为类协定的显式部分。例如,您可以添加属性标记并让客户端代码检查 of 的值,而不是直接检查类型。self.handler = "handle_me_this_way"handler

如何使包彼此隔离

每个实例都为其模块和对象创建一个独立的隔离环境。包中的模块只能导入 其他打包的模块或标记为 的模块 。如果您使用多个实例加载单个包,您将获得 多个不交互的独立环境。extern

这是通过使用自定义导入器扩展 Python 的导入基础设施来实现的。提供与 importer 相同的核心 API;即,它实现 AND 方法。importlibimport_module__import__

当你调用 时,将构造并返回一个新模块,就像系统导入器所做的那样。 但是,修补返回的模块以使用(即该实例)以实现将来的导入 请求。self

杂耍

为避免混淆(“此对象是我的包中的那个,还是我的 Python 环境中的对象?”),通过向所有导入的模块添加 mangle 前缀来破坏它们。foo.bar__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.mdtorch/package/

API 参考

torch.package 中。PackagingErrordependency_graphdebug=False[来源]

当导出包时出现问题时,会引发此异常。 将尝试收集所有错误并呈现 他们立刻向你。PackageExporter

torch.package 中。EmptyMatchError[来源]

当 mock 或 extern 被标记为 时,会引发一个异常,并且在打包过程中与任何模块都不匹配。allow_empty=False

torch.package 中。PackageExporterfimporter=<torch.package.importer._SysImporter object>debug=False[来源]

导出器允许您编写代码包、腌制的 Python 数据和 将任意二进制和文本资源合并到一个自包含的包中。

导入可以以封闭的方式加载此代码,以便加载代码 而不是普通的 Python 导入系统。这允许 用于打包 PyTorch 模型代码和数据,以便可以运行 在服务器上或将来用于迁移学习。

包中包含的代码是从原始 source 时创建,并且文件格式是专门组织的 zip 文件。该包的未来用户可以解压缩该包,并编辑代码 以便对其执行自定义修改。

packages 的导入器确保模块中的代码只能从 在包中,但使用 . zip 存档中的文件列出了软件包外部依赖的所有模块。 这可以防止包在本地运行的 “隐式” 依赖项,因为它正在导入 本地安装的软件包,但在将软件包复制到另一台计算机时失败。extern_modules

将源代码添加到包中时,导出器可以选择对其进行扫描 有关进一步的代码依赖项 ()。它查找 import 语句 解析对限定模块名称的相对引用,并执行用户指定的操作 (请参阅:、 和 )。dependencies=True

__init__fimporter=<torch.package.importer._SysImporter object>debug=False[来源]

创建导出器。

参数
  • fUnion[strPathBinaryIO]) – 要导出到的位置。可以是包含文件名的 / 对象 或二进制 I/O 对象。stringPath

  • importerUnion[ImporterSequence[Importer]]) – 如果传递了单个 Importer,则使用它来搜索模块。 如果传递了一系列导入器,则将从中构建一个。OrderedImporter

  • debugbool) – 如果设置为 True,则将损坏模块的路径添加到 PackagingErrors。

add_dependencymodule_namedependencies=True[来源]

给定一个模块,根据模式将其添加到依赖项图 由用户指定。

all_pathssrcdst[来源]
返回子图的点表示

,其中包含从 src 到 DST 的所有路径。

返回

包含从 src 到 dst 的所有路径的点表示形式。 (https://graphviz.org/doc/info/lang.html)

返回类型

str

close[来源]

将软件包写入文件系统。之后的任何调用现在都无效。 最好改用资源防护语法:

with PackageExporter("file.zip") as e:
    ...
denied_modules[来源]

返回当前被拒绝的所有模块。

返回

一个包含模块名称的列表,这些模块将是 在此包中被拒绝。

返回类型

列表[str]

denyinclude*exclude=()[来源]

将名称与软件包可以导入的模块列表中的给定 glob 模式匹配的模块列入黑名单。 如果找到对任何匹配包的依赖项,则会引发 a

参数
  • includeUnion[List[str]str]) – 字符串,例如 ,或字符串列表 以获取要 externed 的模块的名称。这也可以是 glob 样式模式,如 中所述"my_package.my_subpackage"

  • excludeUnion[List[str]str]) – 一种可选模式,用于排除与 include 字符串匹配的某些模式。

dependency_graph_string[来源]

返回包中依赖项的二合图字符串表示形式。

返回

package 中依赖项的字符串表示形式。

返回类型

str

externinclude*exclude=()allow_empty=True[来源]

包含在包可以导入的外部模块列表中。 这将阻止依赖项发现保存 it 在包中。导入器将直接从标准导入系统加载外部模块。 extern 模块的代码也必须存在于加载包的进程中。module

参数
  • includeUnion[List[str]str]) – 字符串,例如 ,或字符串列表 以获取要 externed 的模块的名称。这也可以是 glob 样式模式,如 中描述。"my_package.my_subpackage"

  • excludeUnion[List[str]str]) – 一个可选模式,用于排除与 include 字符串。

  • allow_emptybool) – 一个可选标志,用于指定此调用指定的 extern 模块 到方法时必须与某个模块匹配。如果 extern 模块 glob pattern 使用 , 添加并在任何模块匹配该模式之前调用(显式或通过),则会引发异常。如果 不会引发此类异常。externallow_empty=False__exit__allow_empty=True

externed_modules)[来源]

返回当前 externed 的所有模块。

返回

一个包含模块名称的列表,这些模块将是 externed 在此包中。

返回类型

列表[str]

get_rdepsmodule_name[来源]

返回依赖于 module 的所有模块的列表。module_name

返回

包含依赖于 的模块名称的列表。module_name

返回类型

列表[str]

get_unique_id[来源]

获取 ID。此 ID 保证此包仅分发一次。

返回类型

str

interninclude*exclude=()allow_empty=True[来源]

指定应打包的模块。模块必须与某种模式匹配才能 包含在包中,并递归处理其依赖项。intern

参数
  • includeUnion[List[str]str]) – 字符串,例如 “my_package.my_subpackage”,或字符串列表 以获取要 externed 的模块的名称。这也可以是 glob 样式模式,如 中所述

  • excludeUnion[List[str]str]) – 一种可选模式,用于排除与 include 字符串匹配的某些模式。

  • allow_emptybool) – 一个可选标志,用于指定此调用指定的实习生模块 到方法时必须与某个模块匹配。如果模块 glob pattern 与 一起添加,并被调用(显式或通过) 在任何模块与该模式匹配之前,将引发异常。如果 ,则不会引发此类异常。interninternallow_empty=False__exit__allow_empty=True

interned_modules[来源]

返回当前实习的所有模块。

返回

一个包含模块名称的列表,这些模块将是 在这个包中实习。

返回类型

列表[str]

mockinclude*exclude=()allow_empty=True[来源]

将一些必需的模块替换为 mock 实现。模拟模块将返回一个 fake object 来访问它的任何属性。因为我们逐个文件复制,所以依赖项解析有时会 查找由模型文件导入但其功能从未使用过的文件 (例如,自定义序列化代码或训练帮助程序)。 使用此函数可以模拟此功能,而无需修改原始代码。

参数
  • 包括Union[List[str]str]) –

    字符串(例如 )或字符串列表 以获取要模拟的模块的名称。字符串也可以是 glob 样式模式 字符串。与此模式匹配的任何必需依赖项 string 将自动模拟。"my_package.my_subpackage"

    例子:

    'torch.**'– 匹配和 torch 的所有子模块,例如 和torch'torch.nn''torch.nn.functional'

    'torch.*'– 匹配 或 ,但不匹配'torch.nn''torch.functional''torch.nn.functional'

  • excludeUnion[List[str]str]) – 一种可选模式,用于排除与 include 字符串匹配的某些模式。 例如 将模拟除 默认值:为 .include='torch.**', exclude='torch.foo''torch.foo'[]

  • allow_emptybool) – 一个可选标志,用于指定此调用指定的模拟实现是否 到方法时必须与某个模块匹配。如果 mock 是使用 , 添加的,并且被调用(显式或通过),并且 mock 具有 未与正在导出的包使用的模块匹配,则会引发异常。 如果 ,则不会引发此类异常。allow_empty=False__exit__allow_empty=True

mocked_modules[来源]

返回当前被模拟的所有模块。

返回

一个包含模块名称的列表,这些模块将是 在这个包中被模拟。

返回类型

列表[str]

register_extern_hook子)[来源]

在导出器上注册 extern 钩子。

每次模块与模式匹配时,都会调用 hook。 它应具有以下签名:

hook(exporter: PackageExporter, module_name: str) -> None

Hook 将按照注册顺序被调用。

返回

一个句柄,可用于通过调用 来删除添加的钩子。handle.remove()

返回类型

torch.utils.hooks.RemovableHandle

register_intern_hook子)[来源]

在导出器上注册 intern hook。

每次模块与模式匹配时,都会调用 hook。 它应具有以下签名:

hook(exporter: PackageExporter, module_name: str) -> None

Hook 将按照注册顺序被调用。

返回

一个句柄,可用于通过调用 来删除添加的钩子。handle.remove()

返回类型

torch.utils.hooks.RemovableHandle

register_mock_hook子)[来源]

在导出器上注册一个 mock hook。

每次模块与模式匹配时,都会调用 hook。 它应具有以下签名:

hook(exporter: PackageExporter, module_name: str) -> None

Hook 将按照注册顺序被调用。

返回

一个句柄,可用于通过调用 来删除添加的钩子。handle.remove()

返回类型

torch.utils.hooks.RemovableHandle

save_binary资源二进制文件[来源]

将原始字节保存到包中。

参数
  • packagestr) – 此资源应包含的模块 package 的名称(例如 )。"my_package.my_subpackage"

  • resourcestr) – 资源的唯一名称,用于标识要加载的资源。

  • binarystr) – 要保存的数据。

save_modulemodule_namedependencies=True[来源]

将 的代码保存到包中。模块的代码使用路径进行解析,以查找 module 对象,然后使用其属性查找源代码。moduleimporters__file__

参数
  • module_namestr) – 例如,将保存代码以提供代码 对于此软件包。my_package.my_subpackage

  • dependenciesbooloptional) – 如果 ,我们将扫描源中的依赖项。True

save_picklepackageresourceobjdependencies=Truepickle_protocol=3[来源]

使用 pickle 将 python 对象保存到存档中。等效于但保存到 存档文件,而不是独立文件。标准 pickle 不保存代码,只保存对象。 如果为 true,则此方法还将扫描需要 modules 的腌制对象 以重新构造它们并保存相关代码。dependencies

为了能够保存对象,其中 is ,必须根据顺序解析为对象的类。当保存 之前已经打包过,则导入器的方法需要出现在列表中 才能使它起作用。type(obj).__name__my_module.MyObjectmy_module.MyObjectimporterimport_moduleimporter

参数
  • packagestr) – 此资源应放入的模块 package 的名称(例如 )。"my_package.my_subpackage"

  • resourcestr) – 资源的唯一名称,用于标识要加载的资源。

  • objAny) – 要保存的对象必须是 picklable 的。

  • dependenciesbooloptional) – 如果 ,我们将扫描源中的依赖项。True

save_source_filemodule_namefile_or_directorydependencies=True[来源]

将本地文件系统添加到源码包中以提供代码 为。file_or_directorymodule_name

参数
  • module_namestr) – 例如,将保存代码以为此包提供代码。"my_package.my_subpackage"

  • file_or_directorystr) – 文件或代码目录的路径。当一个目录时,目录中的所有 python 文件 使用 递归复制。如果文件已命名,则处理代码 作为一个包。"/__init__.py"

  • dependenciesbooloptional) – 如果 ,我们将扫描源中的依赖项。True

save_source_stringmodule_namesrcis_package=Falsedependencies=True[来源]

在导出的包中添加为 的源代码。srcmodule_name

参数
  • module_namestr) – 例如,将保存代码以为此包提供代码。my_package.my_subpackage

  • srcstr) – 要为此软件包保存的 Python 源代码。

  • is_packagebooloptional) – 如果 ,则此模块被视为一个包。包可以有子模块 (例如 ),并且可以在其中保存资源。默认为 。Truemy_package.my_subpackage.my_subsubpackageFalse

  • dependenciesbooloptional) – 如果 ,我们将扫描源中的依赖项。True

save_text资源文本[来源]

将文本数据保存到包中。

参数
  • packagestr) – 此资源应包含的模块 package 的名称(例如 )。"my_package.my_subpackage"

  • resourcestr) – 资源的唯一名称,用于标识要加载的资源。

  • textstr) – 要保存的内容。

torch.package 中。PackageImporterfile_or_buffermodule_allowed=<function PackageImporter.<lambda>>[来源]

导入器允许您加载通过 . 使用包中的文件以封闭方式加载代码 而不是普通的 Python 导入系统。这允许 用于打包 PyTorch 模型代码和数据,以便可以运行 在服务器上或将来用于迁移学习。

packages 的导入器确保模块中的代码只能从 在包中,但在导出过程中明确列为 external 的模块除外。 zip 存档中的文件列出了软件包外部依赖的所有模块。 这可以防止包在本地运行的 “隐式” 依赖项,因为它正在导入 本地安装的软件包,但在将软件包复制到另一台计算机时失败。extern_modules

__init__file_or_buffermodule_allowed=<function PackageImporter.<lambda>>[来源]

打开以供导入。这将检查导入的包是否只需要模块 允许者file_or_buffermodule_allowed

参数
  • file_or_bufferUnion[strPyTorchFileReaderPathLikeBinaryIO]) – 类文件对象(必须实现、、 、 和 ), 字符串或包含文件名的对象。read()readline()tell()seek()os.PathLike

  • module_allowedCallable[[str]bool]optional) – 一种确定是否为外部提供的模块的方法 应该允许。可用于确保加载的软件包不依赖于服务器 不支持。默认允许任何内容。

提高

ImportError – 如果包将使用不允许的模块。

file_structure*include='**'exclude=())[来源]

返回包的 zipfile 的文件结构表示形式。

参数
  • includeUnion[List[str]str]) – 可选字符串,例如 ,或可选的字符串列表 以获取要包含在 Zipfile 表示中的文件名。这也可以是 glob 样式模式,如"my_package.my_subpackage"

  • excludeUnion[List[str]str]) – 一种可选模式,用于排除名称与模式匹配的文件。

返回

目录

返回类型

目录

id[来源]

返回 torch.package 用于区分实例的内部标识符。 看来:

<torch_package_0>
import_modulenamepackage=None[来源]

如果尚未加载 package,则从 package 中加载一个 module,然后返回 模块。模块在本地加载 添加到导入器中,并且将显示在 而不是 中。self.modulessys.modules

参数
  • namestr) – 要加载的模块的完全限定名称。

  • package[type]optional) – 未使用,但存在以匹配 importlib.import_module 的签名。默认为 。None

返回

(可能已经)加载的模块。

返回类型

类型。模块类型

load_binary资源[来源]

加载原始字节。

参数
  • packagestr) – 模块 package 的名称(例如 )。"my_package.my_subpackage"

  • resourcestr) – 资源的唯一名称。

返回

加载的数据。

返回类型

字节

load_pickle资源map_location=[源]

从包中解封资源,加载构造对象所需的任何模块 使用 .

参数
  • packagestr) – 模块 package 的名称(例如 )。"my_package.my_subpackage"

  • resourcestr) – 资源的唯一名称。

  • map_location – 传递给 torch.load 以确定如何将张量映射到设备。默认为 。None

返回

解封的对象。

返回类型

任何

load_text资源encoding='utf-8'errors='strict'[来源]

加载字符串。

参数
  • packagestr) – 模块 package 的名称(例如 )。"my_package.my_subpackage"

  • resourcestr) – 资源的唯一名称。

  • encodingstroptional) – 传递给 .默认为 。decode'utf-8'

  • errorsstroptional) – 传递给 .默认为 。decode'strict'

返回

加载的文本。

返回类型

str

python_version[来源]

返回用于创建此包的 python 版本。

注意:此功能是实验性的,不向前兼容。计划是将其移至 lock 中 文件。

返回

Optional[str]python 版本,例如 3.8.9 或 None,如果此包中没有存储任何版本

torch.package 中。目录名称is_dir[来源]

文件结构表示形式。组织为具有 他们的目录子项。通过调用 来创建包的目录。

has_file文件名[来源]

检查文件是否存在于 .

参数

filenamestr) – 要搜索的文件的路径。

返回

如果 a 包含指定的文件。

返回类型

布尔

文档

访问 PyTorch 的全面开发人员文档

查看文档

教程

获取面向初学者和高级开发人员的深入教程

查看教程

资源

查找开发资源并解答您的问题

查看资源