命名张量¶
命名张量允许用户为张量维度指定明确的名称。在大多数情况下,接受维度参数的操作将接受维度名称,避免按位置跟踪维度。此外,命名张量使用名称在运行时自动检查 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 访问张量的维度名称,并使用 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)
命名张量可以与未命名张量共存;命名张量是 torch.Tensor 的实例。未命名张量具有 None 命名维度。命名张量不需要所有维度都被命名。
>>> imgs = torch.randn(1, 2, 2, 3 , names=(None, 'C', 'H', 'W'))
>>> imgs.names
(None, 'C', 'H', 'W')
名称传播语义¶
命名张量使用名称在运行时自动检查 API 是否被正确调用。这发生在称为 *名称推断* 的过程中。更正式地说,名称推断包括以下两个步骤
- **检查名称**: 运算符可以在运行时执行自动检查,以检查某些维度名称是否必须匹配。 
- **传播名称**: 名称推断将名称传播到输出张量。 
所有支持命名张量的操作都会传播名称。
>>> x = torch.randn(3, 3, names=('N', 'C'))
>>> x.abs().names
('N', 'C')
匹配语义¶
如果两个名称相等(字符串相等)或至少有一个是 None,则它们 *匹配*。Nones 本质上是一个特殊的“通配符”名称。
unify(A, B) 确定要传播到输出的名称 A 和 B 中的哪一个。如果它们匹配,它将返回两个名称中更 *具体* 的一个。如果名称不匹配,则会出错。
注意
在实践中,在使用命名张量时,应避免使用未命名维度,因为它们的处理可能很复杂。建议使用 refine_names() 将所有未命名维度提升为命名维度。
基本名称推断规则¶
让我们看看在没有广播的情况下添加两个一维张量时,match 和 unify 如何在名称推断中使用。
x = torch.randn(3, names=('X',))
y = torch.randn(3)
z = torch.randn(3, names=('Z',))
检查名称:检查两个张量的名称是否匹配。
对于以下示例
>>> # 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',)
有关名称推断规则的完整列表,请参阅 命名张量运算符覆盖范围。以下列出两个可能需要了解的常见操作
按名称显式对齐¶
使用 align_as() 或 align_to() 按名称将张量维度对齐到指定的顺序。这对于执行“按名称广播”很有用。
# 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 会忽略所有张量上的名称。梯度计算仍然正确,但我们失去了名称带来的安全性。
>>> 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 和张量运算符的完整列表。我们目前不支持以下未被链接覆盖的内容
- 索引,高级索引。 
对于 torch.nn.functional 运算符,我们支持以下内容
子系统¶
支持 Autograd,请参阅 Autograd 支持。由于梯度目前未命名,优化器可能有效,但未经测试。
目前不支持 NN 模块。这会导致以下情况,当使用命名张量输入调用模块时
- NN 模块参数未命名,因此输出可能部分命名。 
- NN 模块前向传递包含不支持命名张量的代码,并将适当地报错。 
我们也不支持以下子系统,尽管有些可能开箱即用
- 分布 
- 序列化 ( - torch.load(),- torch.save())
- 多进程 
- JIT 
- 分布式 
- ONNX 
命名张量 API 参考¶
在本节中,请查找命名张量特定 API 的文档。有关名称如何在其他 PyTorch 运算符中传播的全面参考,请参阅 命名张量运算符覆盖范围。
- class torch.Tensor
- names¶
- 存储此张量每个维度的名称。 - names[idx]对应于张量维度- idx的名称。名称可以是字符串(如果维度已命名)或- None(如果维度未命名)。- 维度名称可以包含字符或下划线。此外,维度名称必须是有效的 Python 变量名称(即,不能以下划线开头)。 - 张量不能有两个同名的命名维度。 - 警告 - 命名张量 API 处于实验阶段,可能会发生变化。 
 - rename(*names, **rename_map)[source]¶
- 重命名 - self的维度名称。- 主要有两种用法 - self.rename(**rename_map)返回一个张量视图,该视图的维度已根据映射- 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 处于实验阶段,可能会发生变化。 
 - refine_names(*names)[source]¶
- 根据 - names细化- self的维度名称。- 细化是重命名的一个特例,它“提升”了未命名的维度。一个 - None维度可以被细化为任何名称;一个已命名的维度只能被细化为相同的名称。- 由于命名张量可以与未命名张量共存,因此细化名称提供了一种很好的方法来编写既能处理命名张量又能处理未命名张量的代码。 - names可以包含最多一个省略号 (- ...)。省略号将被贪婪地扩展;它将被就地扩展以填充- names到与- self.dim()相同的长度,使用来自- self.names对应索引的名称。- Python 2 不支持省略号,但可以使用字符串字面量代替 ( - '...')。- 参数
- names (iterable of str) – 输出张量的期望名称。可以包含最多一个省略号。 
 - 示例 - >>> 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张量的维度顺序匹配,为任何新名称添加大小为一的维度。- 此操作对于通过名称进行显式广播很有用(参见示例)。 - 要使用此方法,必须命名 - self的所有维度。生成的张量是原始张量的视图。- self的所有维度名称必须存在于- other.names中。- other可能包含不在- self.names中的命名维度;输出张量对于每个新名称都有一个大小为一的维度。- 要将张量对齐到特定顺序,请使用 - 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)[source]¶
- 将 - self张量的维度排列为与- names中指定的顺序匹配,并为任何新名称添加大小为一的维度。- 要使用此方法,必须命名 - self的所有维度。生成的张量是原始张量的视图。- self的所有维度名称必须存在于- names中。- names可能包含不在- self.names中的附加名称;输出张量对于每个新名称都有一个大小为一的维度。- names可以包含最多一个省略号 (- ...)。省略号被扩展为等于- self中未在- names中提到的所有维度名称,它们在- self中出现的顺序。- Python 2 不支持省略号,但可以使用字符串字面量代替 ( - '...')。- 参数
- names (可迭代 的 str) – 输出张量的所需维度排序。可以包含最多一个省略号,它将扩展到 - 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的维度。- 所有dims在 - self张量中必须按顺序连续,但不必在内存中连续。- 示例 - >>> 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 处于实验阶段,可能会发生变化。