快捷鍵

具名張量

具名張量允許使用者為張量維度指定明確的名稱。 在大多數情況下,採用維度參數的運算將接受維度名稱,從而避免了按位置追蹤維度的需要。 此外,具名張量使用名稱來自動檢查 API 是否在運行時被正確使用,從而提供額外的安全性。 名稱也可以用於重新排列維度,例如,為了支援「按名稱廣播」而不是「按位置廣播」。

警告

具名張量 API 是一個原型功能,可能會發生變更。

建立具名張量

工廠函數現在採用一個新的 names 引數,該引數將名稱與每個維度關聯。

>>> torch.zeros(2, 3, names=('N', 'C'))
tensor([[0., 0., 0.],
        [0., 0., 0.]], names=('N', 'C'))

具名維度與常規張量維度一樣是有序的。 tensor.names[i]tensor 的維度 i 的名稱。

以下工廠函數支援具名張量

具名維度

有關張量名稱的限制,請參閱 names

使用 names 來存取 tensor 的維度名稱,並使用 rename() 來重新命名具名維度。

>>> imgs = torch.randn(1, 2, 2, 3 , names=('N', 'C', 'H', 'W'))
>>> imgs.names
('N', 'C', 'H', 'W')

>>> renamed_imgs = imgs.rename(H='height', W='width')
>>> renamed_imgs.names
('N', 'C', 'height', 'width)

具名 tensors 可以與不具名 tensors 並存;具名 tensors 是 torch.Tensor 的實例。不具名 tensors 具有 None 作為維度名稱。具名 tensors 並不要求所有維度都必須具名。

>>> imgs = torch.randn(1, 2, 2, 3 , names=(None, 'C', 'H', 'W'))
>>> imgs.names
(None, 'C', 'H', 'W')

名稱傳播語意

具名 tensors 使用名稱來自動檢查 API 在執行時是否被正確調用。這個過程稱為名稱推斷。更正式地說,名稱推斷包含以下兩個步驟:

  • 檢查名稱:運算子可能會在執行時執行自動檢查,以檢查某些維度名稱是否必須匹配。

  • 傳播名稱:名稱推斷會將名稱傳播到輸出 tensors。

所有支援具名 tensors 的操作都會傳播名稱。

>>> x = torch.randn(3, 3, names=('N', 'C'))
>>> x.abs().names
('N', 'C')

匹配語意

兩個名稱,如果它們相等(字串相等)或至少其中一個為 None,則認為是匹配。Nones 本質上是一個特殊的“萬用字元”名稱。

unify(A, B) 決定將哪個名稱 AB 傳播到輸出。如果它們匹配,則它會回傳兩個名稱中更具體的那個。如果名稱不匹配,則會發生錯誤。

注意

實際上,在使用具名 tensors 時,應避免使用不具名的維度,因為它們的處理可能很複雜。建議使用 refine_names() 將所有不具名的維度提升為具名的維度。

基本名稱推斷規則

讓我們看看在沒有廣播的情況下,對於添加兩個一維 tensors,matchunify 是如何在名稱推斷中使用的。

x = torch.randn(3, names=('X',))
y = torch.randn(3)
z = torch.randn(3, names=('Z',))

檢查名稱:檢查兩個 tensors 的名稱是否匹配

對於以下範例:

>>> # x + y  # match('X', None) is True
>>> # x + z  # match('X', 'Z') is False
>>> # x + x  # match('X', 'X') is True

>>> x + z
Error when attempting to broadcast dims ['X'] and dims ['Z']: dim 'X' and dim 'Z' are at the same position from the right but do not match.

傳播名稱統一名稱以選擇要傳播的名稱。在 x + y 的情況下,unify('X', None) = 'X',因為 'X'None 更具體。

>>> (x + y).names
('X',)
>>> (x + x).names
('X',)

有關名稱推斷規則的完整列表,請參閱 具名 Tensors 運算子覆蓋範圍。以下是兩個常見的操作,可能對您有所幫助:

通過名稱顯式對齊

使用 align_as()align_to(),通過名稱將 tensor 維度對齊到指定的順序。這對於執行“通過名稱廣播”很有用。

# This function is agnostic to the dimension ordering of `input`,
# as long as it has a `C` dimension somewhere.
def scale_channels(input, scale):
    scale = scale.refine_names('C')
    return input * scale.align_as(input)

>>> num_channels = 3
>>> scale = torch.randn(num_channels, names=('C',))
>>> imgs = torch.rand(3, 3, 3, num_channels, names=('N', 'H', 'W', 'C'))
>>> more_imgs = torch.rand(3, num_channels, 3, 3, names=('N', 'C', 'H', 'W'))
>>> videos = torch.randn(3, num_channels, 3, 3, 3, names=('N', 'C', 'H', 'W', 'D')

>>> scale_channels(imgs, scale)
>>> scale_channels(more_imgs, scale)
>>> scale_channels(videos, scale)

操作維度

使用 align_to() 來置換大量維度,而無需像 permute() 所要求的那樣提及所有維度。

>>> tensor = torch.randn(2, 2, 2, 2, 2, 2)
>>> named_tensor = tensor.refine_names('A', 'B', 'C', 'D', 'E', 'F')

# Move the F (dim 5) and E dimension (dim 4) to the front while keeping
# the rest in the same order
>>> tensor.permute(5, 4, 0, 1, 2, 3)
>>> named_tensor.align_to('F', 'E', ...)

使用 flatten()unflatten() 分別展平和解除展平維度。這些方法比 view()reshape() 更冗長,但對閱讀程式碼的人來說,具有更多的語義含義。

>>> imgs = torch.randn(32, 3, 128, 128)
>>> named_imgs = imgs.refine_names('N', 'C', 'H', 'W')

>>> flat_imgs = imgs.view(32, -1)
>>> named_flat_imgs = named_imgs.flatten(['C', 'H', 'W'], 'features')
>>> named_flat_imgs.names
('N', 'features')

>>> unflattened_named_imgs = named_flat_imgs.unflatten('features', [('C', 3), ('H', 128), ('W', 128)])
>>> unflattened_named_imgs.names
('N', 'C', 'H', 'W')

Autograd 支援

Autograd 目前以有限的方式支援具名 tensors:autograd 忽略所有 tensors 上的名稱。梯度計算仍然正確,但我們失去了名稱給我們的安全性。

>>> x = torch.randn(3, names=('D',))
>>> weight = torch.randn(3, names=('D',), requires_grad=True)
>>> loss = (x - weight).abs()
>>> grad_loss = torch.randn(3)
>>> loss.backward(grad_loss)
>>> weight.grad  # Unnamed for now. Will be named in the future
tensor([-1.8107, -0.6357,  0.0783])

>>> weight.grad.zero_()
>>> grad_loss = grad_loss.refine_names('C')
>>> loss = (x - weight).abs()
# Ideally we'd check that the names of loss and grad_loss match but we don't yet.
>>> loss.backward(grad_loss)
>>> weight.grad
tensor([-1.8107, -0.6357,  0.0783])

目前支援的操作和子系統

運算子

有關支援的 torch 和 tensor 運算的完整列表,請參閱 具名 Tensors 運算子覆蓋範圍。我們目前尚不支援連結中未包含的以下內容:

  • 索引,進階索引。

對於 torch.nn.functional 運算子,我們支援以下內容:

子系統

支援 Autograd,請參閱 Autograd 支援。因為梯度目前是不具名的,所以最佳化器可能會起作用,但尚未經過測試。

目前不支援 NN 模組。當使用具名張量輸入呼叫模組時,可能會導致以下情況:

  • NN 模組參數未命名,因此輸出可能只有部分命名。

  • NN 模組的前向傳遞 (forward pass) 中有程式碼不支援具名張量,並會適當地產生錯誤。

我們也不支援以下子系統,儘管有些可能可以直接運作:

  • distributions (分佈)

  • 序列化 (torch.load()torch.save())

  • 多進程 (multiprocessing)

  • JIT (即時編譯)

  • 分散式 (distributed)

  • ONNX

如果這些功能對您的使用案例有幫助,請搜尋是否已提交 issue,如果沒有,請提交一個

具名張量 API 參考

在本節中,您可以找到具名張量特定 API 的文件。 有關名稱如何在其他 PyTorch 運算子中傳播的完整參考,請參閱具名張量運算子覆蓋範圍

class torch.Tensor
names

儲存此張量每個維度的名稱。

names[idx] 對應於張量維度 idx 的名稱。如果維度已命名,則名稱為字串;如果維度未命名,則名稱為 None

維度名稱可以包含字元或底線。 此外,維度名稱必須是有效的 Python 變數名稱 (即,不能以底線開頭)。

張量不能有兩個具有相同名稱的命名維度。

警告

具名張量 API 是實驗性的,可能會更改。

rename(*names, **rename_map)[source][source]

重新命名 self 的維度名稱。

有兩種主要用法

self.rename(**rename_map) 傳回張量上的視圖 (view),該視圖的維度已按照映射 rename_map 中指定的進行重新命名。

self.rename(*names) 傳回張量上的視圖,使用 names 按位置重新命名所有維度。 使用 self.rename(None) 來刪除張量上的名稱。

不能同時指定位置引數 names 和關鍵字引數 rename_map

範例

>>> imgs = torch.rand(2, 3, 5, 7, names=('N', 'C', 'H', 'W'))
>>> renamed_imgs = imgs.rename(N='batch', C='channels')
>>> renamed_imgs.names
('batch', 'channels', 'H', 'W')

>>> renamed_imgs = imgs.rename(None)
>>> renamed_imgs.names
(None, None, None, None)

>>> renamed_imgs = imgs.rename('batch', 'channel', 'height', 'width')
>>> renamed_imgs.names
('batch', 'channel', 'height', 'width')

警告

具名張量 API 是實驗性的,可能會更改。

rename_(*names, **rename_map)[source][source]

rename() 的原地 (in-place) 版本。

refine_names(*names)[source][source]

根據 names 優化 self 的維度名稱。

優化是重新命名的特殊情況,可以“提升”未命名的維度。 None 維度可以優化為具有任何名稱;命名的維度只能優化為具有相同的名稱。

由於具名張量可以與未命名的張量共存,因此優化名稱提供了一種很好的方式來編寫具名張量感知程式碼,該程式碼可以與具名和未命名的張量一起使用。

names 最多可以包含一個 Ellipsis (...)。 Ellipsis 會貪婪地擴展;它會就地擴展,以使用來自 self.names 對應索引的名稱,將 names 填滿到與 self.dim() 相同的長度。

Python 2 不支援 Ellipsis,但可以使用字串文字代替 ('...')。

參數

names (iterable of str) – 輸出張量所需的名稱。 最多可以包含一個 Ellipsis。

範例

>>> imgs = torch.randn(32, 3, 128, 128)
>>> named_imgs = imgs.refine_names('N', 'C', 'H', 'W')
>>> named_imgs.names
('N', 'C', 'H', 'W')

>>> tensor = torch.randn(2, 3, 5, 7, 11)
>>> tensor = tensor.refine_names('A', ..., 'B', 'C')
>>> tensor.names
('A', None, None, 'B', 'C')

警告

具名張量 API 是實驗性的,可能會更改。

align_as(other) Tensor

排列 self 張量的維度,使其符合 other 張量中的維度順序,並為任何新的名稱添加大小為 1 的維度。

此操作對於通過名稱進行顯式廣播非常有用(請參閱範例)。

必須命名 self 的所有維度才能使用此方法。結果張量是原始張量的一個視圖。

self 的所有維度名稱必須存在於 other.names 中。other 可能包含不在 self.names 中的已命名維度;輸出張量會為每個新名稱都有一個大小為 1 的維度。

要將張量對齊到特定順序,請使用 align_to()

範例

# Example 1: Applying a mask
>>> mask = torch.randint(2, [127, 128], dtype=torch.bool).refine_names('W', 'H')
>>> imgs = torch.randn(32, 128, 127, 3, names=('N', 'H', 'W', 'C'))
>>> imgs.masked_fill_(mask.align_as(imgs), 0)


# Example 2: Applying a per-channel-scale
>>> def scale_channels(input, scale):
>>>    scale = scale.refine_names('C')
>>>    return input * scale.align_as(input)

>>> num_channels = 3
>>> scale = torch.randn(num_channels, names=('C',))
>>> imgs = torch.rand(32, 128, 128, num_channels, names=('N', 'H', 'W', 'C'))
>>> more_imgs = torch.rand(32, num_channels, 128, 128, names=('N', 'C', 'H', 'W'))
>>> videos = torch.randn(3, num_channels, 128, 128, 128, names=('N', 'C', 'H', 'W', 'D'))

# scale_channels is agnostic to the dimension order of the input
>>> scale_channels(imgs, scale)
>>> scale_channels(more_imgs, scale)
>>> scale_channels(videos, scale)

警告

具名張量 API 是實驗性的,可能會更改。

align_to(*names)[原始碼][原始碼]

排列 self 張量的維度,使其符合 names 中指定的順序,並為任何新的名稱添加大小為 1 的維度。

必須命名 self 的所有維度才能使用此方法。結果張量是原始張量的一個視圖。

self 的所有維度名稱必須存在於 names 中。names 可能包含不在 self.names 中的其他名稱;輸出張量會為每個新名稱都有一個大小為 1 的維度。

names 最多可以包含一個 Ellipsis(...)。Ellipsis 會展開成等於 self 中所有未在 names 中提及的維度名稱,並按照它們在 self 中出現的順序排列。

Python 2 不支援 Ellipsis,但可以使用字串文字代替 ('...')。

參數

names (字串的 iterable) – 輸出張量所需的維度順序。最多可以包含一個 Ellipsis,該 Ellipsis 會展開為 self 的所有未提及的維度名稱。

範例

>>> tensor = torch.randn(2, 2, 2, 2, 2, 2)
>>> named_tensor = tensor.refine_names('A', 'B', 'C', 'D', 'E', 'F')

# Move the F and E dims to the front while keeping the rest in order
>>> named_tensor.align_to('F', 'E', ...)

警告

具名張量 API 是實驗性的,可能會更改。

flatten(dims, out_dim) Tensor

dims 平坦化為一個單一維度,名稱為 out_dim

self 張量中,所有 dims 必須是連續的,但不一定要在記憶體中連續。

範例

>>> imgs = torch.randn(32, 3, 128, 128, names=('N', 'C', 'H', 'W'))
>>> flat_imgs = imgs.flatten(['C', 'H', 'W'], 'features')
>>> flat_imgs.names, flat_imgs.shape
(('N', 'features'), torch.Size([32, 49152]))

警告

具名張量 API 是實驗性的,可能會更改。

文件

存取 PyTorch 的全面開發人員文件

檢視文件

教學課程

獲取初學者和高級開發人員的深入教學課程

檢視教學課程

資源

查找開發資源並獲得您的問題解答

檢視資源