torch.sparse¶
介绍¶
PyTorch 提供来表示
包含单个数据类型的元素的多维数组。由
default,数组元素连续存储在内存中,从而导致
各种数组处理算法的高效实现
中继对数组元素的快速访问。但是,存在一个
重要的多维数组类,即所谓的稀疏数组,
其中,数组元素的连续内存存储结果是
欠佳。稀疏数组具有很大一部分
元素等于 0,这意味着也会有大量内存
因为如果只有非零元素
stored 或/和 processed。各种稀疏存储格式(如 COO、
CSR/CSC、LIL 等)已开发,针对
稀疏数组中非零元素的特定结构以及
对数组进行特定操作。
注意
当谈论仅存储 sparse 的非零元素时 数组,形容词 “non-zero” 的用法并不严格:1 是 允许在稀疏数组数据中存储零 结构。因此,在下文中,我们使用 “specified elements” for 那些实际存储的数组元素。此外, 未指定的元素通常假定为零值,但 不仅如此,因此我们使用术语“填充值”来表示 元素。
注意
使用稀疏存储格式来存储稀疏数组可以是 仅当数组的大小和稀疏级别 高。否则,对于小尺寸或低稀疏度数组,使用 连续内存存储格式可能是最有效的 方法。
警告
稀疏张量的 PyTorch API 目前处于测试阶段,在不久的将来可能会发生变化。
稀疏 COO 张量¶
PyTorch 实现了所谓的坐标格式,即 COO format 作为实现 sparse 的存储格式之一 张。在 COO 格式中,指定的元素存储为 Tuples 元素索引和相应值。特别
指定元素的索引以 size 的 Tensor 和 element type , 收集
indices
(ndim, nse)
torch.int64
相应的值收集在 Tensor 的 size 和任意整数或浮点数 Number 元素类型、
values
(nse,)
其中 是张量的维数,是
指定元素的数量。ndim
nse
注意
稀疏 COO 张量的内存消耗至少为字节(加上一个常量
存储其他张量数据的开销)。(ndim *
8 + <size of element type in bytes>) * nse
跨步张量的内存消耗至少为 。product(<tensor shape>) * <size of element type in bytes>
例如,一个 10 000 x 10 000 张量的内存消耗
使用 COO 张量时,100 000 个非零 32 位浮点数至少是字节
layout 和 bytes
默认的跨步张量布局。注意 200 倍内存
使用 COO 存储格式进行保存。(2 * 8 + 4) * 100 000 = 2 000 000
10 000 * 10 000 * 4 = 400 000 000
建设¶
稀疏 COO 张量可以通过提供
indices 和 values,以及稀疏张量的大小(当它
无法从 indices 和 values 张量推断出)到函数 。
假设我们想定义一个稀疏张量,条目 3 位于 location (0, 2),位置 (1, 0) 的条目 4 和位置 (1, 2) 的条目 5。 未指定的元素假定具有相同的值、填充值、 默认情况下为零。然后我们会写:
>>> 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]])
请注意,input 不是索引 Tuples 的列表。如果需要帮助,
要以这种方式编写索引,您应该在将它们传递给
Sparse 构造函数: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 张量通过允许
tensor 设置为多维张量,以便我们
有:values
指定元素的索引以 size 的 Tensor 和 element type , 收集
indices
(sparse_dims, nse)
torch.int64
相应的 (Tensor) 值以 size 的 Tensor 和任意整数收集 或浮点数元素类型。
values
(nse, dense_dims)
注意
我们使用 (M + K) 维张量来表示 N 维混合体 sparse 张量,其中 M 和 K 是 sparse 和 density 的数量 维度,使得 M + K == N 成立。
假设我们想创建一个 (2 + 1) 维张量,其中条目为 [3, 4] 在位置 (0, 2),条目 [5, 6] 在位置 (1, 0) 和条目 [7, 8] 在位置 (1, 2)。我们会写
>>> 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]]])
一般来说,如果 是一个稀疏 COO 张量和 ,那么我们有以下内容
invariants:s
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]
- 值 的 Hybrid Tensor 是 K 维张量,
s.values().layout == torch.strided
- 值存储为 跨步张量。
注意
密集维度始终遵循稀疏维度,即混合 不支持密集和稀疏维度。
未合并的稀疏 COO 张量¶
PyTorch 稀疏 COO 张量格式允许未合并的稀疏张量,
索引中可能存在重复的坐标;在本例中,
解释是该索引处的值是所有
重复的值条目。例如,可以指定多个值,而 , 对于同一索引 ,这将导致 1-D
uncoalesced Tensor:3
4
1
>>> 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)
通常,method 的输出是一个
sparse 张量具有以下属性:
注意
在大多数情况下,您不必关心 稀疏张量是否合并,因为大多数操作都可以 以相同方式给出合并或未合并的稀疏张量。
但是,某些操作可以更有效地实现 未合并的张量,以及一些关于合并的张量。
例如,稀疏 COO 张量的添加是通过 简单地连接 indices 和 values 张量:
>>> 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)
如果您重复执行可能产生重复的操作
条目(例如,),您应该偶尔
合并稀疏张量以防止它们变得太大。
另一方面,索引的字典顺序可以是 有利于实现涉及许多元素的算法 选择操作,例如切片或矩阵产品。
使用稀疏 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 张量是一个实例,为了区别于使用
其他一些布局,on 可以使用
或 属性:
torch.Tensor.layout
>>> isinstance(s, torch.Tensor)
True
>>> s.is_sparse
True
>>> s.layout == torch.sparse_coo
True
>>> s.sparse_dim(), s.dense_dim()
(2, 1)
如果 是稀疏 COO 张量,则其 COO 格式数据可以是
使用 方法 和
获取。
s
注意
目前,只有当张量 instance 被合并:
>>> 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 张量会得到一个不是 coalesced:
>>> s.is_coalesced()
False
>>> s2 = s.coalesce()
>>> s2.indices()
tensor([[0, 1, 1],
[2, 0, 2]])
当使用未合并的稀疏 COO 张量时,必须考虑到
一个帐户 未合并数据的加法性质:的值
相同的指数是 Evaluation 给出 的值
相应的 Tensor 元素。例如,标量
未合并稀疏张量上的乘法可以通过以下方式实现
将所有未合并的值乘以标量 because 成立。但是,任何非线性运算
例如,一个平方根,不能通过将操作应用于
uncoalesced data (未合并的数据),因为
持有。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 中,不能指定稀疏张量的 fill 值
显式 ,通常假定为零。然而,存在
可能以不同方式解释 fill 值的操作。为
实例中,使用
假设 Fill 值为负无穷大。
稀疏 CSR 张量¶
CSR (Compressed Sparse Row) 稀疏张量格式实现了 CSR 格式 用于存储 2 维张量。虽然不支持 N 维 张量,与 COO 格式相比,它的主要优势是更好地利用了存储和 更快的计算操作,例如稀疏矩阵向量乘法 使用 MKL 和 MAGMA 后端。目前不存在 CUDA 支持。
CSR 稀疏张量由三个 1-D 张量组成:和 :crow_indices
col_indices
values
张量由压缩的行索引组成。这是一个 1-D 张量 的大小。最后一个元素是非零的数量。这个张量 根据给定行的位置对索引进行编码 开始。张量中的每个连续数字减去它前面的数字表示 给定行中的元素数。
crow_indices
size[0] + 1
values
col_indices
张量包含每个值的列索引。这是 1-D 大小为 的张量。
col_indices
nnz
张量包含 CSR 张量的值。这是一个 1-D 张量 的大小。
values
nnz
注意
索引张量 和 的元素类型 为 (default) 或 .如果要使用启用 MKL 的矩阵
操作中,请使用 .这是由于 pytorch 的默认链接
使用 MKL LP64,它使用 32 位整数索引。crow_indices
col_indices
torch.int64
torch.int32
torch.int32
CSR 张量的构造¶
使用该方法可以直接构建稀疏 CSR 矩阵。用户必须分别提供行和列索引以及值张量。
该参数是可选的,如果不存在,将从 the 和 中推导出来。
size
crow_indices
col_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.double)
>>> 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)
CSR Tensor 操作¶
从 stramed 或sparse COO 构建稀疏 CSR 张量的最简单方法
tensor 将使用 。(strided) 张量中的任何零都将
被解释为稀疏张量中的缺失值: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()
>>> vec = torch.randn(4, 1, dtype=torch.float64)
>>> sp.matmul(vec)
tensor([[0.9078],
[1.3180],
[0.0000]], dtype=torch.float64)
支持的线性代数运算¶
下表总结了 上支持的线性代数运算
操作数布局可能不同的稀疏矩阵。这里表示具有给定布局的张量。同样,表示矩阵(二维 PyTorch 张量),表示向量(一维 PyTorch 张量)。此外,表示
标量(浮点或 0-D PyTorch 张量)是按元素计算的
multiplication,并且是矩阵乘法。T[layout]
M[layout]
V[layout]
f
*
@
PyTorch 操作 |
稀疏的毕业生? |
布局签名 |
---|---|---|
不 |
|
|
不 |
|
|
不 |
|
|
不 |
|
|
不 |
|
|
是的 |
|
|
不 |
|
|
不 |
|
|
不 |
|
|
不 |
|
|
是的 |
|
|
不 |
|
|
不 |
|
|
是的 |
|
|
是的 |
|
其中 “Sparse grad?” 列表示 PyTorch 操作是否支持
相对于稀疏矩阵参数向后。所有 PyTorch 操作、
except ,支持相对于 stribed 向后
matrix 参数。
注意
目前,PyTorch 不支持使用
布局签名 。然而
应用程序仍然可以使用 matrix relation 来计算此函数。M[strided] @ M[sparse_coo]
D @
S == (S.t() @ D.t()).t()
张量方法和稀疏¶
以下 Tensor 方法与稀疏 Tensor 相关:
如果 Tensor 使用稀疏存储布局,否则。 |
|
返回 sparse tensor 中的密集维度数。 |
|
返回稀疏张量中的稀疏维度数。 |
|
返回一个新的稀疏张量,其中包含由 sparse 张量的索引过滤的跨步张量中的值。 |
|
返回张量的稀疏副本。 |
|
|
将张量转换为坐标格式。 |
|
将张量转换为压缩的行存储格式。 |
返回稀疏 COO 张量的 indices 张量。 |
|
返回稀疏 COO 张量的 values tensor。 |
以下 Tensor 方法特定于稀疏 COO 张量:
返回 if 是未合并张量的合并副本。 |
|
将稀疏张量的大小调整为所需的大小以及稀疏和密集维度的数量。 |
|
从稀疏张量中删除所有指定的元素,并调整为所需的大小以及稀疏和密集维度的数量。 |
|
如果是合并的稀疏 COO 张量,则返回,否则返回。 |
|
创建 的跨步副本。 |
以下方法特定于稀疏 CSR 张量:
|
当 是 layout 的稀疏 CSR 张量时,返回包含张量的压缩行索引的张量。 |
|
当 是 layout 的稀疏 CSR 张量时,返回包含张量列索引的张量。 |
以下 Tensor 方法支持稀疏 COO 张量:
特定于稀疏张量的 Torch 函数¶
以 COO(rdinate) 格式构造一个稀疏张量,并在给定的 . |
|
在 CSR(压缩稀疏行)中构造一个稀疏张量,并在给定的 和 处使用指定的值。 |
|
返回给定 dimensions 中稀疏张量的每一行的总和 。 |
|
对密集矩阵执行矩阵乘法,并在稀疏模式 指定的位置执行 。 |
|
执行稀疏矩阵和 (sparse 或 strided) 矩阵的矩阵乘法。 |
|
Matrix 将稀疏张量与密集张量相乘,然后将稀疏张量添加到结果中。 |
|
执行稀疏 COO 矩阵和跨步矩阵的矩阵乘法。 |
|
执行稀疏矩阵与密集矩阵 的矩阵乘法。 |
|
应用 softmax 函数。 |
|
应用 softmax 函数,后跟对数。 |
其他功能¶
以下函数支持稀疏张量:torch
cat()
dstack()
empty()
empty_like()
hstack()
index_select()
is_complex()
is_floating_point()
is_nonzero()
is_tensor()
lobpcg()
mm()
pca_lowrank()
select()
stack()
svd_lowrank()
unsqueeze()
vstack()
zeros()
zeros_like()
is_same_size()
is_signed()
native_norm()