前言
import torch
当一个tensor有特别多0的时候,我们可以使用稀疏矩阵来存储,大家可能都听过的库是sicpy,不过,本文要讲的是torch。
构造
有大量0元素的时候,我们可以使用坐标形式存储稀疏矩阵,例如我们有一个3*3的矩阵,但是只有0,0处有值,值为1,其他地方全为0,那么我们只需要如下做即可:
i = torch.LongTensor([[0],
[0]])
v = torch.FloatTensor([1])
a=torch.sparse.FloatTensor(i, v, torch.Size([3,3]))
a
解释:
- nnz means: number of non zero elements.即非0元素个数。
- 布局就是稀疏矩阵存储格式,我们这里是坐标形式,即coordinate,这个和scipy一样。
注意,我们的稀疏张量格式允许uncoalesced(未合并) 的稀疏张量, 什么意思?如下:
i = torch.LongTensor([[0,0],
[0,0]])
v = torch.FloatTensor([1,5])
a=torch.sparse.FloatTensor(i, v, torch.Size([3,3]))
a
可以发现,坐标0,0处值为1,又为5,非常反直觉。其实,这只是未合并而已,合并的意思就是会加起来,从而变成6,也就是说坐标0,0处的值实际上为6。
a.coalesce()
注意,默认情况上,如果按照上述方法来构造稀疏矩阵,那么就是未合并状态uncoalesced=True ,而不管你是否有重复的坐标。
属性和运算
a.indices()
a.values()
a._indices()
a.to_dense()
a *= 1000
a +=1000
tensor([[1., 0., 0.], [0., 0., 0.], [0., 0., 0.]])
两个稀疏矩阵相减,这个也比较容易实现,合并两者的坐标,然后相减即可,如下:
i = torch.LongTensor([[0,0],
[0,1]])
v = torch.FloatTensor([1,5])
a=torch.sparse.FloatTensor(i, v, torch.Size([3,3]))
i = torch.LongTensor([[0,0],
[0,2]])
v = torch.FloatTensor([1,4])
b=torch.sparse.FloatTensor(i, v, torch.Size([3,3]))
a-b
tensor(indices=tensor([[0, 0, 0], [0, 1, 2]]), values=tensor([ 0., 5., -4.]), size=(3, 3), nnz=3, layout=torch.sparse_coo)
同理,两个稀疏矩阵相加,也是比较容易实现的(因为加法和减法本质上一样),而且此时会重新排列那个indices,排列准则是坐标中的x坐标,从小到大排列。
上面说完了加减乘除,其他的还有按照某个维度求和:
torch.sparse.sum(a,dim=1)
这个也是比较容易实现的,因为只需要找到每一行的索引以及值,然后相加即可。
|