评价此页

torch.sparse#

创建于: 2017年4月26日 | 最后更新于: 2025年6月18日

警告

PyTorch 的稀疏张量 API 处于 beta 阶段,未来可能会有所更改。我们非常欢迎在 GitHub 上提交功能请求、错误报告和一般性建议。

为什么以及何时使用稀疏性#

默认情况下,PyTorch 将 torch.Tensor 的元素连续地存储在物理内存中。这使得各种需要快速访问元素的数组处理算法能够高效实现。

现在,一些用户可能会选择用“大部分元素值为零”的张量来表示数据,例如图的邻接矩阵、剪枝后的权重或点云。我们认识到这些都是重要的应用场景,并致力于通过稀疏存储格式为这些用例提供性能优化。

多年来,已经开发了各种稀疏存储格式,如 COO、CSR/CSC、半结构化、LIL 等。虽然它们在确切布局上有所不同,但它们都通过高效表示零值元素来压缩数据。我们称压缩值之外的指定元素为指定元素,相对于未指定、压缩的元素。

通过压缩重复的零,稀疏存储格式旨在节省各种 CPU 和 GPU 上的内存和计算资源。特别是对于高度稀疏或高度结构化的稀疏性,这可能会带来显著的性能影响。因此,稀疏存储格式可以被视为一种性能优化。

与许多其他性能优化一样,稀疏存储格式并非总是占优。当尝试将稀疏格式用于您的用例时,您可能会发现执行时间反而增加而不是减少。

如果您在分析上预期性能会大幅提升,但实际测量结果却出现退化,请随时在 GitHub 上打开一个 issue。这有助于我们优先实现高效的内核和更广泛的性能优化。

我们使尝试不同的稀疏布局和它们之间的转换变得容易,而不会对您的特定应用程序的最佳选择持偏见。

功能概览#

我们希望通过为每种布局提供转换例程,使从给定的密集张量构建稀疏张量变得直接。

在以下示例中,我们将一个默认密集(跨步)布局的二维张量转换为一个由 COO 内存布局支持的二维张量。在这种情况下,只存储非零元素的 the values 和 indices。

>>> a = torch.tensor([[0, 2.], [3, 0]])
>>> a.to_sparse()
tensor(indices=tensor([[0, 1],
                       [1, 0]]),
       values=tensor([2., 3.]),
       size=(2, 2), nnz=2, layout=torch.sparse_coo)

PyTorch 目前支持 COOCSRCSCBSRBSC

我们还有一个原型实现来支持 :ref: 半结构化稀疏性<sparse-semi-structured-docs>。有关更多详细信息,请参阅参考文献。

请注意,我们提供了这些格式的轻微泛化。

批量:GPU 等设备需要批量处理才能获得最佳性能,因此我们支持批量维度。

我们目前提供了一种非常简单的批量处理方式,即稀疏格式的每个组件本身都是批量处理的。这也要求每个批量条目具有相同数量的指定元素。在此示例中,我们从一个三维密集张量构建一个三维(批量)CSR 张量。

>>> t = torch.tensor([[[1., 0], [2., 3.]], [[4., 0], [5., 6.]]])
>>> t.dim()
3
>>> t.to_sparse_csr()
tensor(crow_indices=tensor([[0, 1, 3],
                            [0, 1, 3]]),
       col_indices=tensor([[0, 0, 1],
                           [0, 0, 1]]),
       values=tensor([[1., 2., 3.],
                      [4., 5., 6.]]), size=(2, 2, 2), nnz=3,
       layout=torch.sparse_csr)

密集维度:另一方面,一些数据(如图嵌入)可能最好被视为稀疏向量的集合,而不是标量。

在此示例中,我们从一个三维跨步张量创建一个具有 2 个稀疏维度和 1 个密集维度的三维混合 COO 张量。如果三维跨步张量中的整行均为零,则不存储。但是,如果行中的任何值为非零,则会完全存储它们。这减少了索引的数量,因为我们只需要为每行一个索引,而不是每个元素一个索引。但这也增加了存储值的大小。由于只能发出“整行”为零的行,任何非零值的存在都会导致整行被存储。

>>> t = torch.tensor([[[0., 0], [1., 2.]], [[0., 0], [3., 4.]]])
>>> t.to_sparse(sparse_dim=2)
tensor(indices=tensor([[0, 1],
                       [1, 1]]),
       values=tensor([[1., 2.],
                      [3., 4.]]),
       size=(2, 2, 2), nnz=2, layout=torch.sparse_coo)

运算符概览#

从根本上说,对具有稀疏存储格式的张量的操作与对具有跨步(或其他)存储格式的张量的操作行为相同。存储的特殊性,即数据的物理布局,会影响操作的性能,但不应影响其语义。

我们正在积极增加稀疏张量的运算符覆盖范围。用户目前不应期望获得与密集张量同等的支持级别。有关列表,请参阅我们的 运算符 文档。

>>> b = torch.tensor([[0, 0, 1, 2, 3, 0], [4, 5, 0, 6, 0, 0]])
>>> b_s = b.to_sparse_csr()
>>> b_s.cos()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: unsupported tensor layout: SparseCsr
>>> b_s.sin()
tensor(crow_indices=tensor([0, 3, 6]),
       col_indices=tensor([2, 3, 4, 0, 1, 3]),
       values=tensor([ 0.8415,  0.9093,  0.1411, -0.7568, -0.9589, -0.2794]),
       size=(2, 6), nnz=6, layout=torch.sparse_csr)

如上例所示,我们不支持 cos 等非零保留的一元运算符。非零保留的一元运算的输出可能无法与输入一样充分利用稀疏存储格式,并可能导致内存急剧增加。我们转而依赖用户先显式转换为密集张量,然后运行该运算。

>>> b_s.to_dense().cos()
tensor([[ 1.0000, -0.4161],
        [-0.9900,  1.0000]])

我们知道有些用户希望忽略 cos 等运算的压缩零值,而不是保留运算的精确语义。为此,我们可以指向 torch.masked 及其 MaskedTensor,后者本身也由稀疏存储格式和内核支持。

另外请注意,目前用户无法选择输出布局。例如,将稀疏张量添加到常规跨步张量会得到一个跨步张量。一些用户可能希望保留稀疏布局,因为他们知道结果仍然足够稀疏。

>>> a + b.to_sparse()
tensor([[0., 3.],
        [3., 0.]])

我们承认,能够高效生成不同输出布局的内核的访问权限可能非常有用。后续操作可能从接收特定布局中受益匪浅。我们正在开发一种控制结果布局的 API,并认识到它是一个重要的功能,可以为任何给定的模型规划更优化的执行路径。

稀疏半结构化张量#

警告

稀疏半结构化张量目前是一项原型功能,可能会发生更改。如果您发现错误或想提供反馈,请随时在 GitHub 上打开一个 issue。

半结构化稀疏性是一种稀疏数据布局,最初在 NVIDIA 的 Ampere 架构中引入。它也被称为**细粒度结构化稀疏性**或**2:4 结构化稀疏性**。

这种稀疏布局存储每 2n 个元素中的 n 个元素,其中 n 由张量数据类型(dtype)的宽度决定。最常用的 dtype 是 float16,其中 n=2,因此得名“2:4 结构化稀疏性”。

半结构化稀疏性在 这篇 NVIDIA 博客文章 中有更详细的介绍。

在 PyTorch 中,半结构化稀疏性是通过张量子类实现的。通过子类化,我们可以重写 __torch_dispatch__,这使得我们在执行矩阵乘法时可以使用更快的稀疏内核。我们还可以将张量存储在其压缩形式中,以减少内存开销。

在这种压缩形式下,稀疏张量通过仅保留指定元素和一些元数据来存储,这些元数据编码了掩码。

注意

半结构化稀疏张量的指定元素和元数据掩码存储在单个扁平压缩张量中。它们相互追加,形成一个连续的内存块。

压缩张量 = [ 原始张量的指定元素 | 元数据掩码 ]

对于大小为 (r, c) 的原始张量,我们预期前 m * k // 2 个元素是保留的元素,其余部分是元数据。

为了让用户更容易查看指定元素和掩码,可以使用 .indices().values() 分别访问掩码和指定元素。

  • .values() 返回指定元素,其张量大小为 (r, c//2),且 dtype 与密集矩阵相同。

  • .indices() 返回元数据掩码,其张量大小为 (r, c//2),且元素类型为 torch.int16(如果 dtype 为 torch.float16 或 torch.bfloat16),元素类型为 torch.int32(如果 dtype 为 torch.int8)。

对于 2:4 稀疏张量,元数据开销很小——每个指定元素仅 2 位。

注意

需要注意的是,torch.float32 仅支持 1:2 稀疏性。因此,它不遵循上述公式。

在这里,我们详细介绍如何计算 2:4 稀疏张量的压缩比(密集大小/稀疏大小)。

(r, c) = tensor.shapee = bitwidth(tensor.dtype),所以对于 torch.float16torch.bfloat16e = 16;对于 torch.int8e = 8

Mdense=r×c×eMsparse=Mspecified+Mmetadata=r×c2×e+r×c2×2=rce2+rc=rce(12+1e)M_{dense} = r \times c \times e \\ M_{sparse} = M_{specified} + M_{metadata} = r \times \frac{c}{2} \times e + r \times \frac{c}{2} \times 2 = \frac{rce}{2} + rc =rce(\frac{1}{2} +\frac{1}{e})

使用这些计算,我们可以确定原始密集表示和新稀疏表示的总内存占用。

这为我们提供了一个简单的压缩比公式,该公式仅取决于张量数据类型的位宽。

C=MsparseMdense=12+1eC = \frac{M_{sparse}}{M_{dense}} = \frac{1}{2} + \frac{1}{e}

使用该公式,我们发现 torch.float16torch.bfloat16 的压缩比为 56.25%,torch.int8 的压缩比为 62.5%。

构建稀疏半结构化张量#

您可以通过使用 torch.to_sparse_semi_structured 函数,将密集张量转换为稀疏半结构化张量。

请注意,我们仅支持 CUDA 张量,因为半结构化稀疏性的硬件兼容性仅限于 NVIDIA GPU。

以下数据类型支持半结构化稀疏性。请注意,每种数据类型都有其自身的形状约束和压缩因子。

PyTorch 数据类型

形状约束

压缩因子

稀疏模式

torch.float16

张量必须是二维的,并且 (r, c) 都必须是 64 的正整数倍

9/16

2:4

torch.bfloat16

张量必须是二维的,并且 (r, c) 都必须是 64 的正整数倍

9/16

2:4

torch.int8

张量必须是二维的,并且 (r, c) 都必须是 128 的正整数倍

10/16

2:4

要构建半结构化稀疏张量,首先创建一个符合 2:4(或半结构化)稀疏格式的常规密集张量。为此,我们通过平铺一个小型的 1x4 条带来创建一个 16x16 的密集 float16 张量。之后,我们可以调用 to_sparse_semi_structured 函数对其进行压缩,以加速推理。

>>> from torch.sparse import to_sparse_semi_structured
>>> A = torch.Tensor([0, 0, 1, 1]).tile((128, 32)).half().cuda()
tensor([[0., 0., 1.,  ..., 0., 1., 1.],
        [0., 0., 1.,  ..., 0., 1., 1.],
        [0., 0., 1.,  ..., 0., 1., 1.],
        ...,
        [0., 0., 1.,  ..., 0., 1., 1.],
        [0., 0., 1.,  ..., 0., 1., 1.],
        [0., 0., 1.,  ..., 0., 1., 1.]], device='cuda:0', dtype=torch.float16)
>>> A_sparse = to_sparse_semi_structured(A)
SparseSemiStructuredTensor(shape=torch.Size([128, 128]), transposed=False, values=tensor([[1., 1., 1.,  ..., 1., 1., 1.],
        [1., 1., 1.,  ..., 1., 1., 1.],
        [1., 1., 1.,  ..., 1., 1., 1.],
        ...,
        [1., 1., 1.,  ..., 1., 1., 1.],
        [1., 1., 1.,  ..., 1., 1., 1.],
        [1., 1., 1.,  ..., 1., 1., 1.]], device='cuda:0', dtype=torch.float16), metadata=tensor([[-4370, -4370, -4370,  ..., -4370, -4370, -4370],
        [-4370, -4370, -4370,  ..., -4370, -4370, -4370],
        [-4370, -4370, -4370,  ..., -4370, -4370, -4370],
        ...,
        [-4370, -4370, -4370,  ..., -4370, -4370, -4370],
        [-4370, -4370, -4370,  ..., -4370, -4370, -4370],
        [-4370, -4370, -4370,  ..., -4370, -4370, -4370]], device='cuda:0',
dtype=torch.int16))

稀疏半结构化张量运算#

目前,以下运算支持半结构化稀疏张量

  • torch.addmm(bias, dense, sparse.t())

  • torch.mm(dense, sparse)

  • torch.mm(sparse, dense)

  • aten.linear.default(dense, sparse, bias)

  • aten.t.default(sparse)

  • aten.t.detach(sparse)

要使用这些操作,只需将 to_sparse_semi_structured(tensor) 的输出传递给它们,而不是使用 tensor,一旦您的张量在半结构化稀疏格式中包含 0,如下所示

>>> a = torch.Tensor([0, 0, 1, 1]).tile((64, 16)).half().cuda()
>>> b = torch.rand(64, 64).half().cuda()
>>> c = torch.mm(a, b)
>>> a_sparse = to_sparse_semi_structured(a)
>>> torch.allclose(c, torch.mm(a_sparse, b))
True

使用半结构化稀疏性加速 nn.Linear#

如果权重已经是半结构化稀疏的,您只需几行代码即可加速模型中的线性层

>>> input = torch.rand(64, 64).half().cuda()
>>> mask = torch.Tensor([0, 0, 1, 1]).tile((64, 16)).cuda().bool()
>>> linear = nn.Linear(64, 64).half().cuda()
>>> linear.weight = nn.Parameter(to_sparse_semi_structured(linear.weight.masked_fill(~mask, 0)))

稀疏 COO 张量#

PyTorch 实现了一种称为坐标格式(Coordinate format,简称 COO 格式)的存储格式,用于实现稀疏张量。在 COO 格式中,指定元素存储为元素索引和相应值的元组。具体来说,

  • 指定元素的索引收集在大小为 (ndim, nse) 且元素类型为 torch.int64indices 张量中,

  • 相应的 the values 收集在大小为 (nse,) 且元素类型为任意整数或浮点数的 values 张量中,

其中 ndim 是张量的维度,nse 是指定元素的数量。

注意

稀疏 COO 张量的内存消耗至少为 (ndim * 8 + <元素类型的大小(字节)>) * nse 字节(加上存储其他张量数据的常量开销)。

跨步张量的内存消耗至少为 product(<张量形状>) * <元素类型的大小(字节)>

例如,一个 10000 x 10000 的张量,包含 100000 个非零的 32 位浮点数,当使用 COO 张量布局时,内存消耗至少为 (2 * 8 + 4) * 100 000 = 2 000 000 字节,而使用默认的跨步张量布局时,内存消耗为 10 000 * 10 000 * 4 = 400 000 000 字节。注意,使用 COO 存储格式可以节省 200 倍的内存。

构造#

可以通过向函数 torch.sparse_coo_tensor() 提供索引和 the values 的两个张量,以及稀疏张量的大小(当无法从索引和 the values 张量推断时)来构建稀疏 COO 张量。

假设我们要定义一个稀疏张量,在位置 (0, 2) 处有条目 3,在位置 (1, 0) 处有条目 4,在位置 (1, 2) 处有条目 5。未指定的元素假定具有相同的 the value,即填充值,默认情况下为零。然后我们这样写:

>>> i = [[0, 1, 1], [2, 0, 2]]
>>> v =  [3, 4, 5]
>>> s = torch.sparse_coo_tensor(i, v, (2, 3))
>>> s
tensor(indices=tensor([[0, 1, 1],
                       [2, 0, 2]]),
       values=tensor([3, 4, 5]),
       size=(2, 3), nnz=3, layout=torch.sparse_coo)
>>> s.to_dense()
tensor([[0, 0, 3],
        [4, 0, 5]])

请注意,输入 i **不是** 索引元组的列表。如果您想以这种方式编写索引,应该在将其传递给稀疏构造函数之前进行转置。

>>> i = [[0, 2], [1, 0], [1, 2]]
>>> v =  [3,      4,      5    ]
>>> s = torch.sparse_coo_tensor(list(zip(*i)), v, (2, 3))
>>> # Or another equivalent formulation to get s
>>> s = torch.sparse_coo_tensor(torch.tensor(i).t(), v, (2, 3))
>>> torch.sparse_coo_tensor(i.t(), v, torch.Size([2,3])).to_dense()
tensor([[0, 0, 3],
        [4, 0, 5]])

可以通过仅指定大小来构造一个空的稀疏 COO 张量。

>>> torch.sparse_coo_tensor(size=(2, 3))
tensor(indices=tensor([], size=(2, 0)),
       values=tensor([], size=(0,)),
       size=(2, 3), nnz=0, layout=torch.sparse_coo)

稀疏混合 COO 张量#

PyTorch 实现了一个从带有标量值的稀疏张量到带有(连续)张量值的稀疏张量的扩展。这些张量称为混合张量。

PyTorch 混合 COO 张量通过允许 values 张量成为多维张量来扩展稀疏 COO 张量,从而使我们有:

  • 指定元素的索引收集在大小为 (sparse_dims, nse) 且元素类型为 torch.int64indices 张量中,

  • 相应的(张量)the values 收集在大小为 (nse, dense_dims) 且元素类型为任意整数或浮点数的 values 张量中。

注意

我们将 (M + K) 维张量表示 N 维稀疏混合张量,其中 M 和 K 分别是稀疏维度和密集维度的数量,使得 M + K == N 成立。

假设我们要创建一个 (2 + 1) 维张量,在位置 (0, 2) 处有条目 [3, 4],在位置 (1, 0) 处有条目 [5, 6],在位置 (1, 2) 处有条目 [7, 8]。我们会这样写:

>>> i = [[0, 1, 1],
         [2, 0, 2]]
>>> v =  [[3, 4], [5, 6], [7, 8]]
>>> s = torch.sparse_coo_tensor(i, v, (2, 3, 2))
>>> s
tensor(indices=tensor([[0, 1, 1],
                       [2, 0, 2]]),
       values=tensor([[3, 4],
                      [5, 6],
                      [7, 8]]),
       size=(2, 3, 2), nnz=3, layout=torch.sparse_coo)
>>> s.to_dense()
tensor([[[0, 0],
         [0, 0],
         [3, 4]],
        [[5, 6],
         [0, 0],
         [7, 8]]])

通常,如果 s 是一个稀疏 COO 张量,并且 M = s.sparse_dim()K = s.dense_dim(),那么我们有以下不变式:

  • M + K == len(s.shape) == s.ndim — 张量的维度是稀疏维度和密集维度的数量之和,

  • s.indices().shape == (M, nse) — 稀疏索引被显式存储,

  • s.values().shape == (nse,) + s.shape[M : M + K] — 混合张量的 the values 是 K 维张量,

  • s.values().layout == torch.strided — the values 以跨步张量形式存储。

注意

密集维度总是跟随稀疏维度,也就是说,不支持密集和稀疏维度的混合。

注意

为了确保构造的稀疏张量具有一致的索引、值和大小,可以通过 check_invariants=True 关键字参数在每个张量创建时启用不变性检查,或者通过 torch.sparse.check_sparse_tensor_invariants 上下文管理器实例进行全局启用。默认情况下,稀疏张量不变性检查是禁用的。

未合并的稀疏 COO 张量#

PyTorch 稀疏 COO 张量格式允许稀疏的*未合并*张量,其中索引可能存在重复坐标;在这种情况下,解释为该索引处的值是所有重复值条目的总和。例如,可以为同一个索引 1 指定多个值,例如 34,这会导致一个一维未合并张量。

>>> i = [[1, 1]]
>>> v =  [3, 4]
>>> s=torch.sparse_coo_tensor(i, v, (3,))
>>> s
tensor(indices=tensor([[1, 1]]),
       values=tensor(  [3, 4]),
       size=(3,), nnz=2, layout=torch.sparse_coo)

而合并过程将使用求和来累积多值元素为一个值。

>>> s.coalesce()
tensor(indices=tensor([[1]]),
       values=tensor([7]),
       size=(3,), nnz=1, layout=torch.sparse_coo)

通常,torch.Tensor.coalesce() 方法的输出是一个稀疏张量,具有以下属性:

注意

对于大多数情况,您不必关心稀疏张量是否已合并,因为大多数操作在给定合并或未合并的稀疏张量时行为相同。

然而,一些操作可以在未合并张量上更高效地实现,而另一些操作则可以在合并张量上更高效地实现。

例如,稀疏 COO 张量的加法是通过简单地连接索引和值张量来实现的。

>>> a = torch.sparse_coo_tensor([[1, 1]], [5, 6], (2,))
>>> b = torch.sparse_coo_tensor([[0, 0]], [7, 8], (2,))
>>> a + b
tensor(indices=tensor([[0, 0, 1, 1]]),
       values=tensor([7, 8, 5, 6]),
       size=(2,), nnz=4, layout=torch.sparse_coo)

如果您重复执行可能产生重复条目的操作(例如 torch.Tensor.add()),您应该偶尔合并您的稀疏张量,以防止它们变得过大。

另一方面,索引的字典序对于实现涉及许多元素选择操作(如切片或矩阵乘法)的算法可能很有优势。

使用稀疏 COO 张量#

让我们考虑以下示例。

>>> i = [[0, 1, 1],
         [2, 0, 2]]
>>> v =  [[3, 4], [5, 6], [7, 8]]
>>> s = torch.sparse_coo_tensor(i, v, (2, 3, 2))

如上所述,稀疏 COO 张量是 torch.Tensor 的一个实例,为了将其与使用其他布局的“Tensor”实例区分开来,可以使用 torch.Tensor.is_sparsetorch.Tensor.layout 属性。

>>> isinstance(s, torch.Tensor)
True
>>> s.is_sparse
True
>>> s.layout == torch.sparse_coo
True

稀疏和密集维度的数量可以使用方法 torch.Tensor.sparse_dim()torch.Tensor.dense_dim() 分别获取。例如:

>>> s.sparse_dim(), s.dense_dim()
(2, 1)

如果 s 是一个稀疏 COO 张量,那么它的 COO 格式数据可以使用方法 torch.Tensor.indices()torch.Tensor.values() 获取。

注意

目前,只有当张量实例已合并时,才能获取 COO 格式数据。

>>> s.indices()
RuntimeError: Cannot get indices on an uncoalesced tensor, please call .coalesce() first

要获取未合并张量的 COO 格式数据,请使用 torch.Tensor._values()torch.Tensor._indices()

>>> s._indices()
tensor([[0, 1, 1],
        [2, 0, 2]])

警告

调用 torch.Tensor._values() 将返回一个*分离*的张量。要跟踪梯度,必须改用 torch.Tensor.coalesce().values()

构造一个新的稀疏 COO 张量会得到一个未合并的张量。

>>> s.is_coalesced()
False

但是,可以使用 torch.Tensor.coalesce() 方法来构造稀疏 COO 张量的合并副本。

>>> s2 = s.coalesce()
>>> s2.indices()
tensor([[0, 1, 1],
       [2, 0, 2]])

在使用未合并的稀疏 COO 张量时,必须考虑到未合并数据的加性性质:相同索引的值是求和的项,这些求和的计算结果是相应张量元素的值。例如,稀疏未合并张量上的标量乘法可以通过将所有未合并值与标量相乘来实现,因为 c * (a + b) == c * a + c * b 成立。然而,任何非线性操作,例如平方根,都不能通过对未合并数据应用该操作来实现,因为 sqrt(a + b) == sqrt(a) + sqrt(b) 通常不成立。

稀疏 COO 张量的切片(正步长)仅支持密集维度。索引支持稀疏维度和密集维度。

>>> s[1]
tensor(indices=tensor([[0, 2]]),
       values=tensor([[5, 6],
                      [7, 8]]),
       size=(3, 2), nnz=2, layout=torch.sparse_coo)
>>> s[1, 0, 1]
tensor(6)
>>> s[1, 0, 1:]
tensor([6])

在 PyTorch 中,稀疏张量的填充值无法显式指定,通常假定为零。然而,存在一些操作可能以不同的方式解释填充值。例如,torch.sparse.softmax() 在假定填充值为负无穷的情况下计算 softmax。

稀疏压缩张量#

稀疏压缩张量是一类稀疏张量,它们具有一个共同特征,即使用一种编码来压缩特定维度的索引,这种编码能够对稀疏压缩张量的线性代数内核进行某些优化。这种编码基于压缩稀疏行 (CSR)格式,PyTorch 稀疏压缩张量在此基础上扩展,支持稀疏张量批处理、多维张量值以及将稀疏张量值存储在密集块中。

注意

我们使用 (B + M + K) 维张量来表示 N 维稀疏压缩混合张量,其中 B、M 和 K 分别是批处理、稀疏和密集维度的数量,使得 B + M + K == N 成立。稀疏压缩张量的稀疏维度始终为两个,即 M == 2

注意

我们说索引张量 compressed_indices 使用 CSR 编码,如果满足以下不变性:

  • compressed_indices 是一个连续的、步长为 32 或 64 位的整数张量。

  • compressed_indices 的形状为 (*batchsize, compressed_dim_size + 1),其中 compressed_dim_size 是压缩维度的数量(例如,行或列)。

  • compressed_indices[..., 0] == 0,其中 ... 表示批处理索引。

  • compressed_indices[..., compressed_dim_size] == nse,其中 nse 是指定元素的数量。

  • 0 <= compressed_indices[..., i] - compressed_indices[..., i - 1] <= plain_dim_size 对于 i=1, ..., compressed_dim_size,其中 plain_dim_size 是普通维度的数量(与压缩维度正交,例如列或行)。

为了确保构造的稀疏张量具有一致的索引、值和大小,可以通过 check_invariants=True 关键字参数在每个张量创建时启用不变性检查,或者通过 torch.sparse.check_sparse_tensor_invariants 上下文管理器实例进行全局启用。默认情况下,稀疏张量不变性检查是禁用的。

注意

稀疏压缩布局到 N 维张量的泛化可能会导致在指定元素计数方面产生一些混淆。当稀疏压缩张量包含批处理维度时,指定元素的数量将对应于每个批处理的此类元素的数量。当稀疏压缩张量具有密集维度时,被考虑的元素现在是 K 维数组。对于块稀疏压缩布局,2D 块被视为被指定的元素。以一个 3 维块稀疏张量为例,它有一个长度为 b 的批处理维度,以及一个 p, q 的块形状。如果这个张量有 n 个指定的元素,那么实际上我们每个批处理有 n 个指定的块。这个指定元素的数量的解释来自于所有稀疏压缩布局都源自对二维矩阵的压缩。批处理维度被视为稀疏矩阵的堆叠,密集维度将元素的概念从简单的标量值变为一个具有自身维度的数组。

稀疏 CSR 张量#

CSR 格式相较于 COO 格式的主要优势在于存储效率更高,以及使用 MKL 和 MAGMA 后端进行稀疏矩阵向量乘法等计算操作的速度更快。

在最简单的情况下,一个 (0 + 2 + 0) 维的稀疏 CSR 张量由三个一维张量组成:crow_indicescol_indicesvalues

  • crow_indices 张量包含压缩的行索引。这是一个大小为 nrows + 1(行数加 1)的一维张量。 crow_indices 的最后一个元素是指定元素的数量 nse。这个张量编码了 valuescol_indices 中给定行的起始索引。张量中每个连续的数字与其前一个数字之差表示给定行中的元素数量。

  • col_indices 张量包含每个元素的列索引。这是一个大小为 nse 的一维张量。

  • values 张量包含 CSR 张量元素的值。这是一个大小为 nse 的一维张量。

注意

索引张量 crow_indicescol_indices 的元素类型应为 torch.int64(默认)或 torch.int32。如果要使用启用 MKL 的矩阵运算,请使用 torch.int32。这是因为 PyTorch 的默认链接是 MKL LP64,它使用 32 位整数索引。

在一般情况下,(B + 2 + K) 维稀疏 CSR 张量由两个 (B + 1) 维的索引张量 crow_indicescol_indices,以及一个 (1 + K) 维的 values 张量组成,如下所示:

  • crow_indices.shape == (*batchsize, nrows + 1)

  • col_indices.shape == (*batchsize, nse)

  • values.shape == (nse, *densesize)

而稀疏 CSR 张量的形状为 (*batchsize, nrows, ncols, *densesize),其中 len(batchsize) == Blen(densesize) == K

注意

稀疏 CSR 张量的批处理是相关的:所有批处理中的指定元素数量必须相同。这个有些人为的约束允许高效地存储不同 CSR 批处理的索引。

注意

稀疏和密集维度的数量可以使用 torch.Tensor.sparse_dim()torch.Tensor.dense_dim() 方法获取。批处理维度可以从张量形状计算得出:batchsize = tensor.shape[:-tensor.sparse_dim() - tensor.dense_dim()]

注意

稀疏 CSR 张量的内存消耗至少为 (nrows * 8 + (8 + <元素类型的大小 (字节)> * prod(densesize)) * nse) * prod(batchsize) 字节(加上存储其他张量数据的恒定开销)。

使用稀疏 COO 格式介绍中的笔记中的相同示例数据,一个 10000 x 10000 的张量,包含 100,000 个非零的 32 位浮点数,当使用 CSR 张量布局时,其内存消耗至少为 (10000 * 8 + (8 + 4 * 1) * 100 000) * 1 = 1 280 000 字节。与使用 COO 和跨步格式相比,使用 CSR 存储格式的节省分别为 1.6 倍和 310 倍。

CSR 张量构造#

可以通过使用 torch.sparse_csr_tensor() 函数直接构造稀疏 CSR 张量。用户必须单独提供行和列索引以及值张量,其中行索引必须使用 CSR 压缩编码指定。如果 size 参数未提供,则将从 crow_indicescol_indices 推导得出。

>>> crow_indices = torch.tensor([0, 2, 4])
>>> col_indices = torch.tensor([0, 1, 0, 1])
>>> values = torch.tensor([1, 2, 3, 4])
>>> csr = torch.sparse_csr_tensor(crow_indices, col_indices, values, dtype=torch.float64)
>>> csr
tensor(crow_indices=tensor([0, 2, 4]),
       col_indices=tensor([0, 1, 0, 1]),
       values=tensor([1., 2., 3., 4.]), size=(2, 2), nnz=4,
       dtype=torch.float64)
>>> csr.to_dense()
tensor([[1., 2.],
        [3., 4.]], dtype=torch.float64)

注意

推导出的 size 中稀疏维度的值是根据 crow_indices 的大小以及 col_indices 中的最大索引值计算得出的。如果需要的列数大于推导出的 size,则必须显式指定 size 参数。

从跨步张量或稀疏 COO 张量构造二维稀疏 CSR 张量的最简单方法是使用 torch.Tensor.to_sparse_csr() 方法。跨步张量中的任何零将被解释为稀疏张量中的缺失值。

>>> a = torch.tensor([[0, 0, 1, 0], [1, 2, 0, 0], [0, 0, 0, 0]], dtype=torch.float64)
>>> sp = a.to_sparse_csr()
>>> sp
tensor(crow_indices=tensor([0, 1, 3, 3]),
      col_indices=tensor([2, 0, 1]),
      values=tensor([1., 1., 2.]), size=(3, 4), nnz=3, dtype=torch.float64)

CSR 张量运算#

稀疏矩阵向量乘法可以通过 tensor.matmul() 方法执行。这目前是 CSR 张量支持的唯一数学运算。

>>> vec = torch.randn(4, 1, dtype=torch.float64)
>>> sp.matmul(vec)
tensor([[0.9078],
        [1.3180],
        [0.0000]], dtype=torch.float64)

稀疏 CSC 张量#

稀疏 CSC(压缩稀疏列)张量格式实现了 CSC 格式来存储二维张量,并扩展支持批处理的稀疏 CSC 张量以及多维张量值。

注意

稀疏 CSC 张量本质上是稀疏 CSR 张量的转置,其中转置是关于交换稀疏维度。

稀疏 CSR 张量类似,稀疏 CSC 张量由三个张量组成:ccol_indicesrow_indicesvalues

  • ccol_indices 张量包含压缩的列索引。这是一个 (B + 1) 维张量,形状为 (*batchsize, ncols + 1)。最后一个元素是指定元素的数量 nse。这个张量编码了 valuesrow_indices 中给定列的起始索引。张量中每个连续的数字与其前一个数字之差表示给定列中的元素数量。

  • row_indices 张量包含每个元素的行索引。这是一个 (B + 1) 维张量,形状为 (*batchsize, nse)

  • values 张量包含 CSC 张量元素的(未压缩)值。这是一个 (1 + K) 维张量,形状为 (nse, *densesize)

CSC 张量构造#

可以通过使用 torch.sparse_csc_tensor() 函数直接构造稀疏 CSC 张量。用户必须单独提供行和列索引以及值张量,其中列索引必须使用 CSR 压缩编码指定。如果 size 参数未提供,则将从 row_indicesccol_indices 张量推导得出。

>>> ccol_indices = torch.tensor([0, 2, 4])
>>> row_indices = torch.tensor([0, 1, 0, 1])
>>> values = torch.tensor([1, 2, 3, 4])
>>> csc = torch.sparse_csc_tensor(ccol_indices, row_indices, values, dtype=torch.float64)
>>> csc
tensor(ccol_indices=tensor([0, 2, 4]),
       row_indices=tensor([0, 1, 0, 1]),
       values=tensor([1., 2., 3., 4.]), size=(2, 2), nnz=4,
       dtype=torch.float64, layout=torch.sparse_csc)
>>> csc.to_dense()
tensor([[1., 3.],
        [2., 4.]], dtype=torch.float64)

注意

稀疏 CSC 张量构造函数在行索引参数之前有压缩列索引参数。

可以使用 torch.Tensor.to_sparse_csc() 方法从任何二维张量构造 (0 + 2 + 0) 维稀疏 CSC 张量。张量中的任何零将被解释为稀疏张量中的缺失值。

>>> a = torch.tensor([[0, 0, 1, 0], [1, 2, 0, 0], [0, 0, 0, 0]], dtype=torch.float64)
>>> sp = a.to_sparse_csc()
>>> sp
tensor(ccol_indices=tensor([0, 1, 2, 3, 3]),
       row_indices=tensor([1, 1, 0]),
       values=tensor([1., 2., 1.]), size=(3, 4), nnz=3, dtype=torch.float64,
       layout=torch.sparse_csc)

稀疏 BSR 张量#

稀疏 BSR(块压缩稀疏行)张量格式实现了 BSR 格式来存储二维张量,并扩展支持批处理的稀疏 BSR 张量以及多维张量块。

稀疏 BSR 张量由三个张量组成:crow_indicescol_indicesvalues

  • crow_indices 张量包含压缩的行索引。这是一个 (B + 1) 维张量,形状为 (*batchsize, nrowblocks + 1)。最后一个元素是指定块的数量 nse。这个张量编码了 valuescol_indices 中给定列块的起始索引。张量中每个连续的数字与其前一个数字之差表示给定行中的块数量。

  • col_indices 张量包含每个元素的列块索引。这是一个 (B + 1) 维张量,形状为 (*batchsize, nse)

  • values 张量包含稀疏 BSR 张量元素的值,这些值被收集到二维块中。这是一个 (1 + 2 + K) 维张量,形状为 (nse, nrowblocks, ncolblocks, *densesize)

BSR 张量构造#

可以通过使用 torch.sparse_bsr_tensor() 函数直接构造稀疏 BSR 张量。用户必须单独提供行和列块索引以及值张量,其中行块索引必须使用 CSR 压缩编码指定。如果 size 参数未提供,则将从 crow_indicescol_indices 张量推导得出。

>>> crow_indices = torch.tensor([0, 2, 4])
>>> col_indices = torch.tensor([0, 1, 0, 1])
>>> values = torch.tensor([[[0, 1, 2], [6, 7, 8]],
...                        [[3, 4, 5], [9, 10, 11]],
...                        [[12, 13, 14], [18, 19, 20]],
...                        [[15, 16, 17], [21, 22, 23]]])
>>> bsr = torch.sparse_bsr_tensor(crow_indices, col_indices, values, dtype=torch.float64)
>>> bsr
tensor(crow_indices=tensor([0, 2, 4]),
       col_indices=tensor([0, 1, 0, 1]),
       values=tensor([[[ 0.,  1.,  2.],
                       [ 6.,  7.,  8.]],
                      [[ 3.,  4.,  5.],
                       [ 9., 10., 11.]],
                      [[12., 13., 14.],
                       [18., 19., 20.]],
                      [[15., 16., 17.],
                       [21., 22., 23.]]]),
       size=(4, 6), nnz=4, dtype=torch.float64, layout=torch.sparse_bsr)
>>> bsr.to_dense()
tensor([[ 0.,  1.,  2.,  3.,  4.,  5.],
        [ 6.,  7.,  8.,  9., 10., 11.],
        [12., 13., 14., 15., 16., 17.],
        [18., 19., 20., 21., 22., 23.]], dtype=torch.float64)

可以使用 torch.Tensor.to_sparse_bsr() 方法从任何二维张量构造 (0 + 2 + 0) 维稀疏 BSR 张量,该方法还需要指定值块大小。

>>> dense = torch.tensor([[0, 1, 2, 3, 4, 5],
...                       [6, 7, 8, 9, 10, 11],
...                       [12, 13, 14, 15, 16, 17],
...                       [18, 19, 20, 21, 22, 23]])
>>> bsr = dense.to_sparse_bsr(blocksize=(2, 3))
>>> bsr
tensor(crow_indices=tensor([0, 2, 4]),
       col_indices=tensor([0, 1, 0, 1]),
       values=tensor([[[ 0,  1,  2],
                       [ 6,  7,  8]],
                      [[ 3,  4,  5],
                       [ 9, 10, 11]],
                      [[12, 13, 14],
                       [18, 19, 20]],
                      [[15, 16, 17],
                       [21, 22, 23]]]), size=(4, 6), nnz=4,
       layout=torch.sparse_bsr)

稀疏 BSC 张量#

稀疏 BSC(块压缩稀疏列)张量格式实现了 BSC 格式来存储二维张量,并扩展支持批处理的稀疏 BSC 张量以及多维张量块。

稀疏 BSC 张量由三个张量组成:ccol_indicesrow_indicesvalues

  • ccol_indices 张量包含压缩的列索引。这是一个 (B + 1) 维张量,形状为 (*batchsize, ncolblocks + 1)。最后一个元素是指定块的数量 nse。这个张量编码了 valuesrow_indices 中给定行块的起始索引。张量中每个连续的数字与其前一个数字之差表示给定列中的块数量。

  • row_indices 张量包含每个元素的行块索引。这是一个 (B + 1) 维张量,形状为 (*batchsize, nse)

  • values 张量包含稀疏 BSC 张量元素的值,这些值被收集到二维块中。这是一个 (1 + 2 + K) 维张量,形状为 (nse, nrowblocks, ncolblocks, *densesize)

BSC 张量构造#

可以通过使用 torch.sparse_bsc_tensor() 函数直接构造稀疏 BSC 张量。用户必须单独提供行和列块索引以及值张量,其中列块索引必须使用 CSR 压缩编码指定。如果 size 参数未提供,则将从 ccol_indicesrow_indices 张量推导得出。

>>> ccol_indices = torch.tensor([0, 2, 4])
>>> row_indices = torch.tensor([0, 1, 0, 1])
>>> values = torch.tensor([[[0, 1, 2], [6, 7, 8]],
...                        [[3, 4, 5], [9, 10, 11]],
...                        [[12, 13, 14], [18, 19, 20]],
...                        [[15, 16, 17], [21, 22, 23]]])
>>> bsc = torch.sparse_bsc_tensor(ccol_indices, row_indices, values, dtype=torch.float64)
>>> bsc
tensor(ccol_indices=tensor([0, 2, 4]),
       row_indices=tensor([0, 1, 0, 1]),
       values=tensor([[[ 0.,  1.,  2.],
                       [ 6.,  7.,  8.]],
                      [[ 3.,  4.,  5.],
                       [ 9., 10., 11.]],
                      [[12., 13., 14.],
                       [18., 19., 20.]],
                      [[15., 16., 17.],
                       [21., 22., 23.]]]), size=(4, 6), nnz=4,
       dtype=torch.float64, layout=torch.sparse_bsc)

处理稀疏压缩张量的工具#

所有稀疏压缩张量——CSR、CSC、BSR 和 BSC 张量——在概念上都非常相似,因为它们的索引数据被分成两部分:所谓的压缩索引使用 CSR 编码,以及所谓的普通索引,它们与压缩索引正交。这允许对这些张量的各种工具共享相同的实现,这些实现由张量布局参数化。

稀疏压缩张量构造#

可以使用 torch.sparse_compressed_tensor() 函数构造稀疏 CSR、CSC、BSR 和 CSC 张量。该函数与前面讨论的构造函数 torch.sparse_csr_tensor()torch.sparse_csc_tensor()torch.sparse_bsr_tensor()torch.sparse_bsc_tensor() 具有相同的接口,但需要一个额外的 layout 参数。以下示例说明了使用相同的输入数据,通过向 torch.sparse_compressed_tensor() 函数指定相应的布局参数来构造 CSR 和 CSC 张量的方法。

>>> compressed_indices = torch.tensor([0, 2, 4])
>>> plain_indices = torch.tensor([0, 1, 0, 1])
>>> values = torch.tensor([1, 2, 3, 4])
>>> csr = torch.sparse_compressed_tensor(compressed_indices, plain_indices, values, layout=torch.sparse_csr)
>>> csr
tensor(crow_indices=tensor([0, 2, 4]),
       col_indices=tensor([0, 1, 0, 1]),
       values=tensor([1, 2, 3, 4]), size=(2, 2), nnz=4,
       layout=torch.sparse_csr)
>>> csc = torch.sparse_compressed_tensor(compressed_indices, plain_indices, values, layout=torch.sparse_csc)
>>> csc
tensor(ccol_indices=tensor([0, 2, 4]),
       row_indices=tensor([0, 1, 0, 1]),
       values=tensor([1, 2, 3, 4]), size=(2, 2), nnz=4,
       layout=torch.sparse_csc)
>>> (csr.transpose(0, 1).to_dense() == csc.to_dense()).all()
tensor(True)

支持的操作#

线性代数运算#

下表总结了稀疏矩阵支持的线性代数运算,其中操作数的布局可能不同。这里 T[layout] 表示具有给定布局的张量。类似地,M[layout] 表示矩阵(2D PyTorch 张量),V[layout] 表示向量(1D PyTorch 张量)。此外,f 表示标量(浮点数或 0D PyTorch 张量),* 是元素级乘法,@ 是矩阵乘法。

PyTorch 操作

稀疏梯度?

布局签名

torch.mv()

M[sparse_coo] @ V[strided] -> V[strided]

torch.mv()

M[sparse_csr] @ V[strided] -> V[strided]

torch.matmul()

M[sparse_coo] @ M[strided] -> M[strided]

torch.matmul()

M[sparse_csr] @ M[strided] -> M[strided]

torch.matmul()

M[SparseSemiStructured] @ M[strided] -> M[strided]

torch.matmul()

M[strided] @ M[SparseSemiStructured] -> M[strided]

torch.mm()

M[sparse_coo] @ M[strided] -> M[strided]

torch.mm()

M[SparseSemiStructured] @ M[strided] -> M[strided]

torch.mm()

M[strided] @ M[SparseSemiStructured] -> M[strided]

torch.sparse.mm()

M[sparse_coo] @ M[strided] -> M[strided]

torch.smm()

M[sparse_coo] @ M[strided] -> M[sparse_coo]

torch.hspmm()

M[sparse_coo] @ M[strided] -> M[hybrid sparse_coo]

torch.bmm()

T[sparse_coo] @ T[strided] -> T[strided]

torch.addmm()

f * M[strided] + f * (M[sparse_coo] @ M[strided]) -> M[strided]

torch.addmm()

f * M[strided] + f * (M[SparseSemiStructured] @ M[strided]) -> M[strided]

torch.addmm()

f * M[strided] + f * (M[strided] @ M[SparseSemiStructured]) -> M[strided]

torch.sparse.addmm()

f * M[strided] + f * (M[sparse_coo] @ M[strided]) -> M[strided]

torch.sparse.spsolve()

SOLVE(M[sparse_csr], V[strided]) -> V[strided]

torch.sspaddmm()

f * M[sparse_coo] + f * (M[sparse_coo] @ M[strided]) -> M[sparse_coo]

torch.lobpcg()

GENEIG(M[sparse_coo]) -> M[strided], M[strided]

torch.pca_lowrank()

PCA(M[sparse_coo]) -> M[strided], M[strided], M[strided]

torch.svd_lowrank()

SVD(M[sparse_coo]) -> M[strided], M[strided], M[strided]

其中“Sparse grad?”列指示 PyTorch 操作是否支持对稀疏矩阵参数进行反向传播。除 torch.smm() 外,所有 PyTorch 操作都支持对 strided 矩阵参数进行反向传播。

注意

目前,PyTorch 不支持签名格式为 M[strided] @ M[sparse_coo] 的矩阵乘法。但是,应用程序仍可以通过矩阵关系 D @ S == (S.t() @ D.t()).t() 来计算它。

Tensor 方法和稀疏#

以下 Tensor 方法与稀疏张量相关

Tensor.is_sparse

如果张量使用稀疏 COO 存储布局,则为 True,否则为 False

如果张量使用稀疏 CSR 存储布局,则为 True,否则为 False

如果 Tensor 使用稀疏 CSR 存储布局,则为 True,否则为 False

Tensor.dense_dim

返回 稀疏张量 self 中的密集维度数量。

Tensor.sparse_dim

返回 稀疏张量 self 中的稀疏维度数量。

Tensor.sparse_mask

返回一个新 稀疏张量,其中 strided 张量 self 的值由稀疏张量 mask 的索引进行过滤。

Tensor.to_sparse

返回张量的稀疏副本。

Tensor.to_sparse_coo

将张量转换为 坐标格式

Tensor.to_sparse_csr

将张量转换为压缩行存储格式 (CSR)。

Tensor.to_sparse_csc

将张量转换为压缩列存储 (CSC) 格式。

Tensor.to_sparse_bsr

将张量转换为给定块大小的块稀疏行 (BSR) 存储格式。

Tensor.to_sparse_bsc

将张量转换为给定块大小的块稀疏列 (BSC) 存储格式。

Tensor.to_dense

如果 self 不是跨步张量,则创建一个 self 的跨步副本,否则返回 self

Tensor.values

返回 稀疏 COO 张量 的值张量。

以下 Tensor 方法特定于稀疏 COO 张量

Tensor.coalesce

如果 self 是一个 未合并张量,则返回 self 的合并副本。

Tensor.sparse_resize_

self 稀疏张量 调整为所需的大小和稀疏/密集维度数量。

Tensor.sparse_resize_and_clear_

稀疏张量 self 中移除所有指定的元素,并将 self 调整为所需的大小和稀疏/密集维度数量。

Tensor.is_coalesced

如果 self 是一个合并的 稀疏 COO 张量,则返回 True,否则返回 False

Tensor.indices

返回 稀疏 COO 张量 的索引张量。

以下方法特定于 稀疏 CSR 张量稀疏 BSR 张量

Tensor.crow_indices

selfsparse_csr 布局的稀疏 CSR 张量时,返回包含 self 张量压缩行索引的张量。

Tensor.col_indices

selfsparse_csr 布局的稀疏 CSR 张量时,返回包含 self 张量列索引的张量。

以下方法特定于 稀疏 CSC 张量稀疏 BSC 张量

以下 Tensor 方法支持稀疏 COO 张量

add() add_() addmm() addmm_() any() asin() asin_() arcsin() arcsin_() bmm() clone() deg2rad() deg2rad_() detach() detach_() dim() div() div_() floor_divide() floor_divide_() get_device() index_select() isnan() log1p() log1p_() mm() mul() mul_() mv() narrow_copy() neg() neg_() negative() negative_() numel() rad2deg() rad2deg_() resize_as_() size() pow() sqrt() square() smm() sspaddmm() sub() sub_() t() t_() transpose() transpose_() zero_()

Torch 针对稀疏张量的特定函数#

sparse_coo_tensor

在给定的 indices 处,使用指定的值构建 COO(坐标)格式的稀疏张量

sparse_csr_tensor

使用给定的 crow_indicescol_indices,在指定值处构建 CSR(压缩行存储)格式的稀疏张量

sparse_csc_tensor

使用给定的 ccol_indicesrow_indices,在指定值处构建 CSC(压缩列存储)格式的稀疏张量

sparse_bsr_tensor

使用给定的 crow_indicescol_indices,在指定 2D 块处构建 BSR(块压缩行存储)格式的稀疏张量

sparse_bsc_tensor

使用给定的 ccol_indicesrow_indices,在指定 2D 块处构建 BSC(块压缩列存储)格式的稀疏张量

sparse_compressed_tensor

使用给定的 compressed_indicesplain_indices,构建 压缩稀疏格式(CSR、CSC、BSR 或 BSC)的稀疏张量

sparse.sum

返回给定稀疏张量每行的总和。

sparse.addmm

此函数在向前传播时与 torch.addmm() 的功能完全相同,不同之处在于它支持稀疏 COO 矩阵 mat1 的反向传播。

sparse.sampled_addmm

input 的稀疏性模式指定的*位置*执行密集矩阵 mat1mat2 的矩阵乘法。

sparse.mm

执行稀疏矩阵 mat1 的矩阵乘法

sspaddmm

矩阵乘以稀疏张量 mat1 和密集张量 mat2,然后将稀疏张量 input 添加到结果中。

hspmm

执行 稀疏 COO 矩阵 mat1 和 strided 矩阵 mat2 的矩阵乘法。

smm

执行稀疏矩阵 input 与密集矩阵 mat 的矩阵乘法。

sparse.softmax

应用 softmax 函数。

sparse.spsolve

计算具有唯一解的方线性方程组的解。

sparse.log_softmax

应用 softmax 函数后接对数。

sparse.spdiags

通过将 diagonals 行的值放置在输出的指定对角线上来创建稀疏 2D 张量

其他函数#

以下 torch 函数支持稀疏张量

cat() dstack() empty() empty_like() hstack() index_select() is_complex() is_floating_point() is_nonzero() is_same_size() is_signed() is_tensor() lobpcg() mm() native_norm() pca_lowrank() select() stack() svd_lowrank() unsqueeze() vstack() zeros() zeros_like()

要管理稀疏张量不变量的检查,请参阅

sparse.check_sparse_tensor_invariants

用于控制检查稀疏张量不变量的工具。

要将稀疏张量与 gradcheck() 函数一起使用,请参阅

sparse.as_sparse_gradcheck

装饰器函数,用于扩展稀疏张量的 gradcheck。

零保持一元函数#

我们的目标是支持所有“零保持一元函数”:映射零到零的单参数函数。

如果您发现我们缺少您需要的功能性零保持一元函数,请随时开设一个 issue 来请求该功能。当然,在开设 issue 之前,请先尝试使用搜索功能。

以下运算符当前支持稀疏 COO/CSR/CSC/BSR/CSR 张量输入。

abs() asin() asinh() atan() atanh() ceil() conj_physical() floor() log1p() neg() round() sin() sinh() sign() sgn() signbit() tan() tanh() trunc() expm1() sqrt() angle() isinf() isposinf() isneginf() isnan() erf() erfinv()