torch.Storage†
在 PyTorch 中,常规张量是一个由以下组件定义的多维数组:
存储空间:张量的实际数据,存储为一个连续的一维字节数组。
dtype
:张量中元素的类型,例如 torch.float32 或 torch.int64。shape
:一个元组,表示张量在每个维度的大小。步长:在每个维度中从一个元素移动到下一个元素所需的步长。
偏移量:存储中数据开始的起始点。对于新创建的张量,这通常为 0。
这些组件共同定义了张量的结构和数据,存储持有实际数据,其余部分作为元数据。
未类型化存储 API ¶
torch.UntypedStorage
是一个连续的一维元素数组。其长度等于张量的字节数。存储作为张量的底层数据容器。一般来说,使用常规构造函数(如 zeros()
、 zeros_like()
或 new_zeros()
)在 PyTorch 中创建的张量,其张量存储与张量本身之间存在一对一的对应关系。
然而,存储可以被多个张量共享。例如,任何张量的视图(通过 view()
或某些索引方式如整数和切片获得,但不是所有类型的索引)都将指向与原始张量相同的底层存储。当序列化和反序列化共享公共存储的张量时,这种关系得到保留,张量继续指向相同的存储。有趣的是,反序列化指向单个存储的多个张量可能比反序列化多个独立张量更快。
张量存储可以通过 untyped_storage()
方法访问。这将返回一个类型为 torch.UntypedStorage
的对象。幸运的是,存储有一个唯一的标识符,可以通过 torch.UntypedStorage.data_ptr()
方法访问。在常规设置中,具有相同数据存储的两个张量将具有相同的存储 data_ptr
。然而,张量本身可以指向两个不同的存储,一个用于其数据属性,另一个用于其 grad 属性。每个都需要自己的 data_ptr()
。一般来说,没有保证 torch.Tensor.data_ptr()
和 torch.UntypedStorage.data_ptr()
匹配,不应假设这是真的。
未类型化的存储与构建在其上的张量相对独立。实际上,这意味着具有不同 dtype 或形状的张量可以指向相同的存储。这也意味着张量存储可以被更改,如下面的示例所示:
>>> t = torch.ones(3)
>>> s0 = t.untyped_storage()
>>> s0
0
0
128
63
0
0
128
63
0
0
128
63
[torch.storage.UntypedStorage(device=cpu) of size 12]
>>> s1 = s0.clone()
>>> s1.fill_(0)
0
0
0
0
0
0
0
0
0
0
0
0
[torch.storage.UntypedStorage(device=cpu) of size 12]
>>> # Fill the tensor with a zeroed storage
>>> t.set_(s1, storage_offset=t.storage_offset(), stride=t.stride(), size=t.size())
tensor([0., 0., 0.])
警告
请注意,如本例所示直接修改张量的存储不是推荐的做法。这种低级操作仅用于教育目的,以展示张量与其底层存储之间的关系。一般来说,使用标准的 torch.Tensor
方法,如 clone()
和 fill_()
,以实现相同的结果更高效且更安全。
除了 data_ptr
之外,未类型化的存储还有其他属性,例如 filename
(如果存储指向磁盘上的文件), device
或 is_cuda
用于设备检查。存储还可以通过 copy_
、 fill_
或 pin_memory
等方法就地或就地操作。有关更多信息,请参阅以下 API 参考。请注意,修改存储是低级 API,存在风险!大多数这些 API 也存在于张量级别:如果存在,应优先于它们的存储对应项。
特殊情况
我们提到,具有非 None grad
属性的张量实际上包含两份数据。在这种情况下, untyped_storage()
将返回 data
属性的存储,而梯度的存储可以通过 tensor.grad.untyped_storage()
获取。
>>> t = torch.zeros(3, requires_grad=True)
>>> t.sum().backward()
>>> assert list(t.untyped_storage()) == [0] * 12 # the storage of the tensor is just 0s
>>> assert list(t.grad.untyped_storage()) != [0] * 12 # the storage of the gradient isn't
- 还有一些特殊情况,张量没有典型的存储,或者根本没有存储:
张量在
"meta"
设备上:张量在"meta"
设备上用于形状推断,并不存储实际数据。模拟张量:PyTorch 编译器使用的另一个内部工具是 FakeTensor,其基于类似的概念。
张量子类或类似张量对象也可能表现出异常行为。通常,我们并不期望许多用例需要操作在存储级别!
- class torch.UntypedStorage(*args, **kwargs)[source][source]¶
- bfloat16()[来源] ¶
将此存储转换为 bfloat16 类型。
- bool()[来源] ¶
将此存储转换为布尔类型。
- byte()[源码] ¶
将此存储转换为字节类型。
- byteswap(dtype)[源码] ¶
交换底层数据中的字节。
- char()[来源]
将此存储转换为 char 类型。
- clone()[来源]
返回此存储的副本。
- complex_double()[来源] ¶
将此存储转换为复数双精度类型。
- complex_float()[来源] ¶
将此存储转换为复数单精度类型。
- copy_() 方法
- cpu()[来源] 方法
如果此存储未在 CPU 上,则返回其 CPU 副本。
- cuda(device=None, non_blocking=False)[来源] 方法
返回此对象在 CUDA 内存中的副本。
如果此对象已在 CUDA 内存中且位于正确的设备上,则不执行复制,并返回原始对象。
- 参数:
设备(int)- 目标 GPU ID。默认为当前设备。
non_blocking(bool)- 如果
True
且源数据在固定内存中,则复制相对于主机是异步的。否则,此参数无效果。
- 返回类型:
_StorageBase 和 TypedStorage 的联合
- data_ptr()函数
- devicedevice
- double()[来源]
将此存储转换为双精度类型。
- element_size()¶
- 属性 filenameOptional[str] ¶
返回与此存储关联的文件名。
如果存储在 CPU 上并且通过
from_file()
创建,则文件名将是一个字符串。否则,此属性是None
。
- fill_()¶
- static from_buffer()¶
- static from_file(filename, shared=False, size=0) Storage ¶
创建一个由内存映射文件支持的 CPU 存储。
如果
shared
是True
,则所有进程之间共享内存。所有更改都写入文件。如果shared
是False
,则存储上的更改不会影响文件。存储中的元素数量。如果
shared
是False
,则文件必须至少包含size * sizeof(Type)
字节(Type
是存储类型,在UnTypedStorage
的情况下,文件必须至少包含size
字节)。如果shared
是True
,则如果需要将创建文件。- 参数:
文件名(str)- 要映射的文件名
共享(bool)- 是否共享内存(是否将
MAP_SHARED
或MAP_PRIVATE
传递给底层的 mmap(2)调用)大小(int)- 存储中的元素数量
- get_device()[源]
- 返回类型:
- half()[源]
将此存储转换为半类型。
- hpu(device=None, non_blocking=False)[源]
返回此对象在 HPU 内存中的副本。
如果此对象已在 HPU 内存中且位于正确的设备上,则不执行复制,并返回原始对象。
- 参数:
device(int)- 目标 HPU ID。默认为当前设备。
non_blocking(bool)- 如果
True
且源数据已在固定内存中,则复制相对于主机是异步的。否则,此参数无效果。
- 返回类型:
Union[_存储基类, 类型化存储]
- int()[来源] ¶
将此存储转换为 int 类型。
- property is_cuda
- 属性是否已固定_hpu
- is_pinned(device='cuda')[source]
判断 CPU 存储是否已在设备上固定。
- 参数:
device (str 或 torch.device) – 要固定内存的设备(默认:
'cuda'
)。此参数不建议使用,并可能被弃用。- 返回:
布尔变量。
- long()[源]
将此存储转换为 long 类型。
- mps()[源]
如果此存储不在 MPS 上,则返回其 MPS 副本。
- nbytes()¶
- new()¶
- pin_memory(设备='cuda')[source] ¶
将 CPU 存储复制到固定内存中,如果它尚未固定。
- 参数:
设备(str 或 torch.device)- 用于固定内存的设备(默认:
'cuda'
)。此参数不建议使用,并可能被弃用。- 返回:
固定 CPU 存储。
- resizable()¶
- resize_()¶
将存储移动到共享内存。
对于已经位于共享内存中的存储和 CUDA 存储,这些存储不需要移动即可在进程间共享,此操作为无操作。共享内存中的存储不能调整大小。
注意,为了减轻此类问题,可以从多个线程中安全地调用此函数以操作同一对象。但是,如果没有适当的同步,则不能在 self 上调用其他函数,这是不安全的。请参阅多进程最佳实践以获取更多详细信息。
注意
当删除对共享内存中存储的所有引用时,相关的共享内存对象也将被删除。PyTorch 有一个特殊的清理过程来确保即使当前进程意外退出,也会发生这种情况。
值得注意的是,
share_memory_()
与from_file()
与shared = True
之间的区别。share_memory_
使用 shm_open(3) 创建 POSIX 共享内存对象,而from_file()
使用 open(2) 打开用户传递的文件名。两者都使用 mmap(2) 调用,将文件/对象映射到当前虚拟地址空间。
在将对象映射后调用
shm_unlink(3)
,以确保当没有进程打开对象时释放共享内存对象。torch.from_file(shared=True)
不会解除链接文件。此文件是持久的,直到用户删除它。
- 返回:
self
- 短()[来源] ¶
将此存储转换为 short 类型。
- size()[来源] ¶
- 返回类型:
- to(*, 设备, non_blocking=False)[source] ¶
- 未类型化()[来源] ¶
旧版类型化存储 ¶
警告
关于历史背景,PyTorch 之前使用过已弃用的类型化存储类,现在应避免使用。以下内容详细说明了此 API,以防万一您遇到它,尽管其使用被高度不建议。未来将移除除 torch.UntypedStorage
之外的所有存储类,并且 torch.UntypedStorage
将在所有情况下使用。
torch.Storage
是与默认数据类型( torch.get_default_dtype()
)对应的存储类的别名。例如,如果默认数据类型是 torch.float
,则 torch.Storage
解析为 torch.FloatStorage
。
torch.<type>Storage
和 torch.cuda.<type>Storage
类,如 torch.FloatStorage
、 torch.IntStorage
等,实际上从未被实例化。调用它们的构造函数会创建一个具有适当 torch.dtype
和 torch.device
的 torch.TypedStorage
。 torch.<type>Storage
类具有与 torch.TypedStorage
相同的所有类方法。
A torch.TypedStorage
是一个由特定 torch.dtype
元素组成的连续、一维数组。它可以赋予任何 torch.dtype
,内部数据将被适当地解释。 torch.TypedStorage
包含一个 torch.UntypedStorage
,它将数据作为未类型化的字节数组存储。
每个跨步 torch.Tensor
都包含一个 torch.TypedStorage
,它存储了 torch.Tensor
视图的所有数据。
- class torch.TypedStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source]¶
- byte()[来源][来源] ¶
将此存储转换为字节类型。
- char()[来源][来源] ¶
将此存储转换为字符类型。
- cuda(device=None, non_blocking=False)[source][source]¶
返回此对象在 CUDA 内存中的副本。
如果该对象已在 CUDA 内存中且位于正确的设备上,则不执行复制并返回原始对象。
- 参数:
设备(int)- 目标 GPU ID。默认为当前设备。
non_blocking(bool)- 如果
True
和源数据在固定内存中,则复制相对于主机是异步的。否则,该参数无效果。
- 返回类型:
- data_ptr()[源][源] ¶
- 属性设备
- double()[源][源] ¶
将此存储转换为 double 类型。
- 元素大小()[来源][来源] ¶
- 属性 文件名 Optional[str] ¶
返回与此存储关联的文件名,如果存储是从文件内存映射创建的。或
None
如果存储不是通过内存映射创建的。
- 填充_(值)[来源][来源] ¶
- float()[来源][来源] ¶
将此存储转换为浮点类型。
- float8_e4m3fn()[来源][来源] ¶
将此存储转换为 float8_e4m3fn 类型
- float8_e4m3fnuz()[来源][来源] ¶
将此存储转换为 float8_e4m3fnuz 类型
- float8_e5m2()[来源][来源] ¶
将此存储转换为 float8_e5m2 类型
- float8_e5m2fnuz()[来源][来源] ¶
将此存储转换为 float8_e5m2fnuz 类型
- classmethod from_buffer(*args, **kwargs)[来源][来源] ¶
- from_file(filename, shared=False, size=0) → Storage[source][source] ¶
创建一个由内存映射文件支持的 CPU 存储。
如果
shared
是True
,则所有进程之间共享内存。所有更改都写入文件。如果shared
是False
,则存储上的更改不会影响文件。size
是存储中的元素数量。如果shared
是False
,则文件必须至少包含size * sizeof(Type)
字节(Type
是存储类型)。如果shared
是True
,则如果需要将创建文件。- 参数:
文件名(str)- 映射的文件名
共享(bool)-
是否共享内存(是否将MAP_SHARED
或MAP_PRIVATE
传递给底层的 mmap(2)调用)大小(int)- 存储中元素的数量
- hpu(device=None, non_blocking=False)[source][source]¶
返回此对象在 HPU 内存中的副本。
如果此对象已在 HPU 内存中且位于正确的设备上,则不执行复制,并返回原始对象。
- 参数:
device(int)- 目标 HPU ID。默认为当前设备。
non_blocking(bool)- 如果
True
且源数据已在固定内存中,则复制相对于主机是异步的。否则,此参数无效果。
- 返回类型:
- int()[来源][来源] ¶
将此存储转换为 int 类型。
- property 是_cuda ¶
- property 是_hpu ¶
- is_pinned(device='cuda')[source][source]¶
判断 CPU TypedStorage 是否已经固定在设备上。
- 参数:
设备(str 或 torch.device)- 将内存固定在的设备(默认:
'cuda'
)。此参数不建议使用,并可能被弃用。- 返回值:
一个布尔变量。
- long()[来源][来源] ¶
将此存储转换为长整型。
- nbytes()函数[来源][来源] ¶
- pickle_storage_type()函数[来源][来源] ¶
- pin_memory(device='cuda')[来源][来源] ¶
将 CPU TypedStorage 复制到固定内存中,如果它尚未固定。
- 参数:
设备(str 或 torch.device)- 将内存固定在的设备(默认:
'cuda'
)。此参数不建议使用,并可能被弃用。- 返回:
固定 CPU 存储。
查看
torch.UntypedStorage.share_memory_()
- to(*, 设备, non_blocking=False)[source][source] ¶
返回此对象在设备内存中的副本。
如果此对象已经在正确的设备上,则不执行复制,并返回原始对象。
- 参数:
设备 (int) – 目标设备。
non_blocking(布尔值)- 如果
True
且源数据位于固定内存中,则复制操作相对于主机是异步的。否则,该参数无效果。
- 返回类型:
自身
- type(dtype=None, non_blocking=False)[source][source]¶
如果未提供 dtype,则返回类型,否则将此对象转换为指定的类型。
如果此对象已经是正确的类型,则不执行复制,并返回原始对象。
- 参数:
dtype (类型或字符串) – 所需的类型
non_blocking (bool) – 如果
True
,并且源在固定内存中,目标在 GPU 上或反之,则异步复制相对于主机执行。否则,该参数无效果。**kwargs – 为了兼容性,可能包含键
async
以代替non_blocking
参数。async
参数已弃用。
- 返回类型:
Union[_StorageBase, TypedStorage, str]
- untyped()[source][source]
返回内部
torch.UntypedStorage
。
- class torch.DoubleStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source]¶
- dtype: torch.dtype = torch.float64[source]¶
- class torch.FloatStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source]¶
- dtype: torch.dtype = torch.float32[source]¶
- 类 torch.HalfStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source] ¶
- dtype: torch.dtype = torch.float16[source]¶
- 类 torch.LongStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source] ¶
- dtype: torch.dtype = torch.int64[source]¶
- 类 torch.IntStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source] ¶
- dtype: torch.dtype = torch.int32[source]¶
- 类 torch.ShortStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source] ¶
- dtype: torch.dtype = torch.int16[source]¶
- 类 torch.CharStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source] ¶
- dtype: torch.dtype = torch.int8[source]¶
- 类 torch.ByteStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source] ¶
- dtype: torch.dtype = torch.uint8[source]¶
- class torch.BoolStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source]¶
- dtype: torch.dtype = torch.bool[source]¶
- class torch.BFloat16Storage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source]¶
- dtype: torch.dtype = torch.bfloat16[source]¶
- 类 torch.ComplexDoubleStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source] ¶
- dtype: torch.dtype = torch.complex128[source]¶
- 类 torch.ComplexFloatStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source] ¶
- dtype: torch.dtype = torch.complex64[source]¶
- 类 torch.QUInt8Storage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source] ¶
- dtype: torch.dtype = torch.quint8[source]¶
- 类 torch.QInt8Storage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source] ¶
- dtype: torch.dtype = torch.qint8[source]¶
- 类 torch.QInt32Storage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source] ¶
- dtype: torch.dtype = torch.qint32[source]¶
- 类 torch.QUInt4x2Storage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source] ¶
- dtype: torch.dtype = torch.quint4x2[source]¶
- 类 torch.QUInt2x4Storage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source] ¶
- dtype: torch.dtype = torch.quint2x4[source]¶