PyTorch SparseTensor 稀疏张量

初始化

torch竟然没有from scipy这种方法。。。。
真的是。。

idx  , LongTensor, shape=(2,nnz)
val , FloatTensor, shape=(nnz)
shp, tuple, 
s = torch.sparse.Tensor(idx,val,shp)

也可以直接传入一个dense tensor

a=torch.FloatTensor([1,2,3])
s=torch.sparse.FloatTensor(a)

to_sparse() , to_dense() 互转

a=torch.FloatTensor([1,2,3])
s= a.to_sparse()
a_ = s.to_dense()

torch.isclose(a,a_)

indices() 与 values()


a=torch.FloatTensor([1,2,3])
s=torch.sparse.FloatTensor(a)

#这两个都是方法,不是属性。
idx = s.indices()
val = s.values()


#这个是属性
shp = s.shape

判断is_sparse

a.is_sparse , bool,每个Tensor都有的属性。

转csr

现在只有to_sparse_csr()

a=torch.FloatTensor([[1,0,3],[2,0,1],[0,1,0]])
c=a.to_sparse_csr()
print(c)
>tensor(crow_indices=tensor([0, 2, 4, 5]),
       col_indices=tensor([0, 2, 0, 2, 1]),
       values=tensor([1., 3., 2., 1., 1.]), size=(3, 3), nnz=5,
       layout=torch.sparse_csr)

转coo

暂不支持to_sparse_coo

已经有人提issue了

https://github.com/pytorch/pytorch/issues/67654

然后这个人一直在努力实现csr_to_coo,花了一年时间…

https://github.com/pytorch/pytorch/pull/66774

我今天(22.01.17)看了一眼,最近一个commit是9天前(22.01.08)…

看了一下repo已经有这个函数了。

https://github.com/pytorch/pytorch/blob/67941c8a94e1731c1f33f37915d210ec244be589/torch/_tensor.py
tensor.to_sparse_coo()

但是服务器上的torch 1.10.1,这个功能还是没有实现。

‘Tensor’ object has no attribute ‘to_sparse_coo’
module ‘torch’ has no attribute ‘to_sparse_coo’
module ‘torch’ has no attribute ‘_convert_indices_from_csr_to_coo’

四则运算

sparse只能跟scalar做四则运算。

加法支持scala或者同型矩阵。
同型矩阵仅支持Dense + Sparse。

add(sparse, dense) is not supported. Use add(dense, sparse) instead.

乘法只支持scala

mul(sparse, dense) is not supported
mul(dense, sparse) is not supported

除法只支持scala

RuntimeError: Sparse division requires a scalar or zero-dim dense tensor divisor (got shape [3, 3] for divisor)

经过个人测试,文档没写,但是支持**运算符。
而且sparse上的 幂运算,会自动将 inf 置为0。

a=torch.FloatTensor([1,0,2])
s=a.to_sparse()

s_ = s ** -1 
print(s_)
>tensor(indices=tensor([[0, 2]]),
       values=tensor([1.0000, 0.5000]),
       size=(3,), nnz=2, layout=torch.sparse_coo)
 
#sparse上的幂运算自动重置inf
print(s_.to_dense())
>tensor([1.0000, 0.0000, 0.5000])

#做dense上的幂运算会出现inf
print(a**-1)
>tensor([1.0000,    inf, 0.5000])

操作符

sparse库有自己的操作符。
直接对sparse tensor用torch operator会报错。

a=torch.FloatTensor([1,2,3])
s=a.to_sparse()

torch.sum(a) #正常
torch.sum(s) #报错

NotImplementedError: Could not run ‘aten::sum.IntList_out’ with arguments from the ‘SparseCPU’ backend. This could be because the operator doesn’t exist for this backend, or was omitted during the selective/custom build process (if using custom build).

If you are a Facebook employee using PyTorch on mobile, please visit https://fburl.com/ptmfixes for possible resolutions. ‘aten::sum.IntList_out’ is only available for these backends: [CPU, CUDA, Meta, BackendSelect, Python, Named, Conjugate, Negative, ADInplaceOrView, AutogradOther, AutogradCPU, AutogradCUDA, AutogradXLA, AutogradLazy, AutogradXPU, AutogradMLC, AutogradHPU, AutogradNestedTensor, AutogradPrivateUse1, AutogradPrivateUse2, AutogradPrivateUse3, Tracer, UNKNOWN_TENSOR_TYPE_ID, Autocast, Batched, VmapMode].

换成专用操作符就可以了

a=torch.FloatTensor([1,2,3])
s=a.to_sparse()

torch.sum(a) #正常
torch.sparse.sum(s) #正常

所以我们需要在使用的时候先判断一下

if x.is_sparse:
	out = torch.sparse.sum(x)
else:
	out  = torch.sum(x)

问题来了,torch为什么不在torch.sum()里面自己集成一下判断???
直接让torch.sum支持sparse不行吗???

支持的操作符

torch.sparse.sum
torch.sparse.mm
torch.sparse.addmm
torch.sparse.softmax
torch.sparse.log_softmax

注意,sparse不支持mean!!!
什么反人类设计。

可以自己写一个sparse_mean()
也不是很难啊。。。torch干嘛不搞。

注意CSR不支持torch.sparse.sum

只有COO支持

重复idx

coo 如果 出现重复的索引,默认累加该索引处的值

import scipy
import numpy as np
A = scipy.sparse.coo_matrix(
		[[1., 0., 3.],
       [2., 1., 1.],
       [0., 1., 1.]])
row,col = A.row,A.col
val =A.data

#在坐标(1,1)处添加9
row2 = np.hstack([row,np.array(1)])
col2 = np.hstack([col,np.array(1)])
val2 = np.hstack([vals,np.array(9)])
A2 = scipy.sparse.coo_matrix((val2,(row2,col2)))
print(A2.A)

[[ 1.  0.  3.]
 [ 2. 10.  1.]
 [ 0.  1.  1.]]

你可能感兴趣的:(pytorch,pytorch,深度学习,python)