目录

命名张量

命名张量允许用户为张量维度赋予明确的名称。 在大多数情况下,接受维度参数的操作将支持 使用维度名称,从而避免通过位置来跟踪维度的需要。 此外,命名张量会在运行时利用名称自动检查 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,则它们匹配。 None 实质上是一个特殊的“通配符”名称。

unify(A, B) 决定将名称 AB 中的哪一个传播到输出中. 如果这两个名称匹配,它会返回更 具体 的那个名称。如果名称不匹配, 则会报错。

注意

在实际操作中,当使用命名张量时,应避免出现未命名的维度,因为它们的处理可能较为复杂。建议通过使用 refine_names() 将所有未命名的维度提升为命名维度。

基本名称推断规则

让我们看看在将两个一维张量相加且不进行广播的情况下,matchunify 如何用于名称推断。

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和tensor操作的完整列表。链接未涵盖的以下内容我们尚未支持:

  • 索引,高级索引。

对于 torch.nn.functional 运算符,我们支持以下内容:

子系统

自动求导是支持的,参见 自动求导支持。 由于梯度目前未命名,优化器可能工作但未经测试。

当前不支持 NN 模块。在调用具有命名张量输入的模块时,可能会导致以下情况:

  • NN模块的参数是未命名的,因此输出可能部分命名。

  • NN模块的前向传播包含不支持命名张量的代码,并会适当报错。

我们也不支持以下子系统,尽管其中一些可能开箱即用:

如果这些中有任何一项对您的用例有帮助,请 搜索是否已经提交了问题 并且如果没有,提交一个

命名张量 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

Examples:

>>> 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]

就地版本的rename()

refine_names(*names)[source]

根据names精炼self的维度名称。

Refining 是 renaming 的一种特殊情况,它为未命名的维度“提升”名称。一个 None 维度可以被细化为具有任何名称;已命名的维度只能被细化为具有相同的名称。

由于命名张量可以与未命名张量共存,因此细化名称提供了一种编写适用于命名和未命名张量的、具有命名张量意识的代码的好方法。

names 可能包含最多一个省略号 (...)。 省略号是贪婪扩展的;它会在原地扩展以填充 names,使其长度与 self.dim() 相同,并使用来自 self.names 对应索引的名称。

Python 2 不支持 Ellipsis,但可以使用字符串字面量代替 ('...')。

Parameters

名称 (可迭代对象 of str) – 输出张量的期望名称。最多可以包含一个省略号。

Examples:

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

Examples:

# 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 不支持 Ellipsis,但可以使用字符串字面量代替 ('...')。

Parameters

names (iterable of str) – 输出张量所需的维度顺序。可以包含最多一个省略号,该省略号将扩展为 self 中所有未提及的维度名称。

Examples:

>>> 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 必须按顺序连续出现, 但不一定要在内存中是连续的。

Examples:

>>> 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 的全面开发人员文档

查看文档

教程

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

查看教程

资源

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

查看资源