torch.Storage¶
在 PyTorch 中,常規張量是一個多維陣列,由以下元件定義
儲存空間 (Storage):張量的實際資料,儲存為連續的、一維的位元組陣列。
dtype
:張量中元素的資料類型,例如 torch.float32 或 torch.int64。shape
:一個元組,指示張量在每個維度上的大小。步幅 (Stride):在每個維度中從一個元素移動到下一個元素所需的步長。
偏移量 (Offset):張量資料開始的儲存空間中的起始點。對於新建立的張量,這通常為 0。
這些元件共同定義了張量的結構和資料,其中儲存空間保存實際資料,其餘則充當元資料。
未類型儲存空間 API¶
torch.UntypedStorage
是一個連續的、一維的元素陣列。它的長度等於張量的位元組數。儲存空間用作張量的底層資料容器。通常,在 PyTorch 中使用常規建構子(例如 zeros()
、zeros_like()
或 new_zeros()
)建立的張量,將產生張量儲存空間和張量本身之間存在一對一對應關係的張量。
但是,一個儲存空間可以被多個張量共享。例如,張量的任何視圖(通過 view()
或某些(但不是全部)種類的索引(例如整數和切片)獲得)將指向與原始張量相同的底層儲存空間。在序列化和反序列化共享相同儲存空間的張量時,這種關係會被保留,並且張量會繼續指向相同的儲存空間。有趣的是,反序列化指向單個儲存空間的多個張量可能比反序列化多個獨立張量更快。
可以通過 untyped_storage()
方法訪問張量儲存空間。這將返回一個 torch.UntypedStorage
類型的對象。幸運的是,儲存空間具有一個唯一的識別碼,可以通過 torch.UntypedStorage.data_ptr()
方法進行訪問。在常規設定中,具有相同資料儲存空間的兩個張量將具有相同的儲存空間 data_ptr
。但是,張量本身可以指向兩個單獨的儲存空間,一個用於其 data 屬性,另一個用於其 grad 屬性。每個都需要自己的 data_ptr()
。通常,無法保證 torch.Tensor.data_ptr()
和 torch.UntypedStorage.data_ptr()
匹配,不應假設這是真的。
未類型儲存空間在某種程度上獨立於建立在其上的張量。實際上,這意味著具有不同 dtypes 或 shape 的張量可以指向相同的儲存空間。這也意味著可以更改張量儲存空間,如下例所示
>>> 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)[原始碼][原始碼]¶
-
- copy_()¶
- cuda(device=None, non_blocking=False)[原始碼]¶
傳回此物件在 CUDA 記憶體中的副本。
如果此物件已在 CUDA 記憶體中且位於正確的裝置上,則不執行複製,並傳回原始物件。
- 參數
- 傳回類型
Union[_StorageBase, TypedStorage]
- data_ptr()¶
- element_size()¶
- property filename: Optional[str]¶
傳回與此 storage 相關聯的檔案名稱。
如果 storage 在 CPU 上且是透過
from_file()
建立且shared
為True
,則檔案名稱將為字串。 否則,此屬性為None
。
- fill_()¶
- static from_buffer()¶
- static from_file(filename, shared=False, size=0) Storage ¶
建立一個由記憶體映射檔案支援的 CPU 儲存體。
如果
shared
為True
,則記憶體會在所有進程之間共享。所有變更都會寫入檔案。如果shared
為False
,則儲存體上的變更不會影響檔案。size
是儲存體中的元素數量。如果shared
為False
,則該檔案必須至少包含size * sizeof(Type)
個位元組(Type
是儲存體的類型,在UnTypedStorage
的情況下,該檔案必須至少包含size
個位元組)。如果shared
為True
,則會在需要時建立檔案。- 參數
filename (str) – 要映射的檔案名稱
shared (bool) – 是否共享記憶體(是否將
MAP_SHARED
或MAP_PRIVATE
傳遞到基礎的 mmap(2) 呼叫)size (int) – 儲存體中的元素數量
- hpu(device=None, non_blocking=False)[原始碼]¶
傳回此物件在 HPU 記憶體中的複本。
如果此物件已經在 HPU 記憶體中,並且位於正確的裝置上,則不會執行複製,並且會傳回原始物件。
- 參數
- 傳回類型
Union[_StorageBase, TypedStorage]
- property is_cuda¶
- property is_hpu¶
- is_pinned(device='cuda')[原始碼]¶
確定 CPU 儲存體是否已釘選在裝置上。
- 參數
device (str 或 torch.device) – 要將記憶體釘選到的裝置。預設值:
'cuda'
。- 傳回
一個布林變數。
- nbytes()¶
- new()¶
- pin_memory(device='cuda')[原始碼]¶
如果 CPU storage 尚未釘選,則將其複製到釘選記憶體。
- 參數
device (str 或 torch.device) – 要將記憶體釘選到的裝置。預設值:
'cuda'
。- 傳回
一個釘選的 CPU storage。
- resizable()¶
- resize_()¶
將 storage 移動到共享記憶體。
對於已經在共享記憶體中的 storage 以及 CUDA storage 來說,這是一個空操作 (no-op),因為 CUDA storage 不需要移動即可跨進程共享。 共享記憶體中的 Storages 無法調整大小。
請注意,為了緩解諸如此類的問題 this 從多個線程在同一個物件上呼叫此函數是執行緒安全的。 但是,在沒有適當同步的情況下,呼叫 self 上的任何其他函數 *並非* 執行緒安全。 請參閱 Multiprocessing best practices 以取得更多詳細資訊。
注意
當刪除共享記憶體中 storage 的所有引用時,關聯的共享記憶體物件也將被刪除。 PyTorch 有一個特殊的清理程序,以確保即使當前進程意外退出,也會發生這種情況。
值得注意的是
share_memory_()
和from_file()
使用shared = True
之間的差異share_memory_
使用 shm_open(3) 來建立 POSIX 共享記憶體物件,而from_file()
使用 open(2) 開啟使用者傳遞的檔案名稱。兩者都使用带有
MAP_SHARED
的 mmap(2) 呼叫,將檔案/物件對應到目前的虛擬位址空間中share_memory_
將在對應物件後呼叫shm_unlink(3)
,以確保當沒有進程開啟該物件時,共享記憶體物件會被釋放。torch.from_file(shared=True)
不會取消連結檔案。 該檔案是持久性的,並且會一直存在,直到使用者刪除它。
- 傳回
self
- type(dtype=None, non_blocking=False)[原始碼]¶
- 傳回類型
Union[_StorageBase, TypedStorage]
舊版具型別 Storage¶
警告
就歷史背景而言,PyTorch 以前使用具型別的 storage 類別,這些類別現在已被棄用,應避免使用。以下詳細說明了此 API,以防您遇到它,儘管非常不建議使用它。 除了 torch.UntypedStorage
之外的所有 storage 類別都將在未來移除,並且 torch.UntypedStorage
將在所有情況下使用。
torch.Storage
是儲存類別的別名,該類別對應於預設的資料類型 (torch.get_default_dtype()
)。例如,如果預設資料類型是 torch.float
,則 torch.Storage
會解析為 torch.FloatStorage
。
像 torch.FloatStorage
、torch.IntStorage
等 torch.<type>Storage
和 torch.cuda.<type>Storage
類別實際上從未被實例化。呼叫它們的建構函式會建立一個具有適當 torch.dtype
和 torch.device
的 torch.TypedStorage
。torch.<type>Storage
類別具有與 torch.TypedStorage
相同的所有類別方法。
torch.TypedStorage
是特定 torch.dtype
的元素的連續一維陣列。它可以給定任何 torch.dtype
,並且內部資料將被適當地解釋。torch.TypedStorage
包含一個 torch.UntypedStorage
,它將資料保存為未指定類型的位元組陣列。
每個跨步 (strided) 的 torch.Tensor
都包含一個 torch.TypedStorage
,它儲存了 torch.Tensor
檢視的所有資料。
- class torch.TypedStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[原始碼][原始碼]¶
- cuda(device=None, non_blocking=False)[原始碼][原始碼]¶
傳回此物件在 CUDA 記憶體中的副本。
如果此物件已在 CUDA 記憶體中且位於正確的裝置上,則不執行複製,並傳回原始物件。
- property device¶
- classmethod from_file(filename, shared=False, size=0) Storage [原始碼][原始碼]¶
建立一個由記憶體映射檔案支援的 CPU 儲存體。
如果
shared
為True
,則記憶體會在所有進程之間共享。所有變更都會寫入檔案。如果shared
為False
,則儲存體上的變更不會影響檔案。size
是儲存空間中的元素數量。如果shared
為False
,則檔案必須至少包含size * sizeof(Type)
位元組(Type
是儲存空間的類型)。如果shared
為True
,則會視需要建立該檔案。- 參數
filename (str) – 要映射的檔案名稱
shared (bool) –
是否共享記憶體(是否將
MAP_SHARED
或MAP_PRIVATE
傳遞給底層的 mmap(2) 呼叫)size (int) – 儲存體中的元素數量
- hpu(device=None, non_blocking=False)[source][source]¶
傳回此物件在 HPU 記憶體中的複本。
如果此物件已經在 HPU 記憶體中,並且位於正確的裝置上,則不會執行複製,並且會傳回原始物件。
- property is_cuda¶
- property is_hpu¶
- is_pinned(device='cuda')[source][source]¶
判斷 CPU TypedStorage 是否已釘選在裝置上。
- 參數
device (str 或 torch.device) – 要釘選記憶體的裝置。預設值:
'cuda'
- 傳回
一個布林變數。
- pin_memory(device='cuda')[source][source]¶
將 CPU TypedStorage 複製到釘選記憶體,如果尚未釘選。
- 參數
device (str 或 torch.device) – 要將記憶體釘選到的裝置。預設值:
'cuda'
。- 傳回
一個釘選的 CPU storage。
- to(*, device, non_blocking=False)[原始碼][原始碼]¶
傳回此物件在裝置記憶體中的副本。
如果此物件已經在正確的裝置上,則不會執行複製,並且傳回原始物件。
- 參數
device (int) – 目標裝置。
non_blocking (bool) – 如果
True
且來源在 pinned memory 中,則複製將相對於主機是非同步的。 否則,此引數無效。
- 傳回類型
Self
- type(dtype=None, non_blocking=False)[原始碼][原始碼]¶
如果未提供 dtype,則傳回類型,否則將此物件轉換為指定的類型。
如果這已經是正確的類型,則不會執行複製,並且傳回原始物件。
- 參數
dtype (type 或 string) – 所需的類型
non_blocking (bool) – 如果
True
,且來源在釘選記憶體中,而目的地在 GPU 上或反之,則複製會相對於主機非同步執行。 否則,此引數無效。**kwargs – 為了相容性,可能包含鍵
async
來代替non_blocking
引數。async
引數已被棄用。
- 傳回類型
Union[_StorageBase, TypedStorage, str]
- untyped()[原始碼][原始碼]¶
傳回內部的
torch.UntypedStorage
。
- class torch.DoubleStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[原始碼][原始碼]¶
- dtype: torch.dtype = torch.float64[原始碼]¶
- class torch.FloatStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[原始碼][原始碼]¶
- dtype: torch.dtype = torch.float32[原始碼]¶
- class torch.HalfStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source]¶
- dtype: torch.dtype = torch.float16[source]¶
- class torch.LongStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source]¶
- dtype: torch.dtype = torch.int64[source]¶
- class torch.IntStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source]¶
- dtype: torch.dtype = torch.int32[source]¶
- class torch.ShortStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source]¶
- dtype: torch.dtype = torch.int16[source]¶
- class torch.CharStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source]¶
- dtype: torch.dtype = torch.int8[source]¶
- class 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]¶
- class torch.ComplexDoubleStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[source][source]¶
- dtype: torch.dtype = torch.complex128[原始碼]¶
- class torch.ComplexFloatStorage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[原始碼][原始碼]¶
- dtype: torch.dtype = torch.complex64[原始碼]¶
- class torch.QUInt8Storage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[原始碼][原始碼]¶
- dtype: torch.dtype = torch.quint8[原始碼]¶
- class torch.QInt8Storage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[原始碼][原始碼]¶
- dtype: torch.dtype = torch.qint8[原始碼]¶
- class torch.QInt32Storage(*args, wrap_storage=None, dtype=None, device=None, _internal=False)[原始碼][原始碼]¶
- dtype: torch.dtype = torch.qint32[原始碼]¶