Theano:对稀疏矩阵的非零元素进行操作

Theano: Operate on nonzero elements of sparse matrix

我正在尝试获取稀疏 theano 变量中非零元素的 exp。我有当前代码:

A = T.matrix("Some matrix with many zeros")
A_sparse = theano.sparse.csc_from_dense(A)

我正在尝试做一些等同于以下 numpy 语法的事情:

mask = (A_sparse != 0)
A_sparse[mask] = np.exp(A_sparse[mask])

但是 Theano 还不支持 != 掩码。 (而且 (A_sparse > 0) | (A_sparse < 0) 似乎也不起作用。)

我怎样才能做到这一点?

这是使用 scipy.sparse 模块执行此操作的方法。我不知道theano如何实现它的稀疏。它可能基于类似的想法(因为它使用的名称类似于 csc

In [224]: A=sparse.csc_matrix([[1.,0,0,2,0],[0,0,3,0,0],[0,1,1,2,0]])

In [225]: A.A
Out[225]: 
array([[ 1.,  0.,  0.,  2.,  0.],
       [ 0.,  0.,  3.,  0.,  0.],
       [ 0.,  1.,  1.,  2.,  0.]])

In [226]: A.data
Out[226]: array([ 1.,  1.,  3.,  1.,  2.,  2.])

In [227]: A.data[:]=np.exp(A.data)

In [228]: A.A
Out[228]: 
array([[  2.71828183,   0.        ,   0.        ,   7.3890561 ,   0.        ],
       [  0.        ,   0.        ,  20.08553692,   0.        ,   0.        ],
       [  0.        ,   2.71828183,   2.71828183,   7.3890561 ,   0.        ]])

csc 格式的主要属性位于 dataindicesindptr。如果您在创建后 fiddle 使用它们,data 可能有一些 0 值,但新创建的矩阵不应该。

该矩阵还有一个以 numpy 为模型的 nonzero 方法。实际上,它将矩阵转换为 coo 格式,过滤掉任何零值,并且 returns rowcol 属性:

In [229]: A.nonzero()
Out[229]: (array([0, 0, 1, 2, 2, 2]), array([0, 3, 2, 1, 2, 3]))

并且 csc 格式允许像密集的 numpy 数组一样进行索引:

In [230]: A[A.nonzero()]
Out[230]: 
matrix([[  2.71828183,   7.3890561 ,  20.08553692,   2.71828183,
           2.71828183,   7.3890561 ]])

Theano 对稀疏矩阵的支持不完善,所以有些东西很难实现。您可以在该特定情况下使用 theano.sparse.structured_exp(A_sparse),但我会在下面尝试更笼统地回答您的问题。

比较

在 Theano 中,通常会使用此处描述的比较运算符:http://deeplearning.net/software/theano/library/tensor/basic.html

例如,可以写 T.neq(A, 0) 而不是 A != 0。对于稀疏矩阵,必须使用 theano.sparse 中的比较运算符。两个算子都必须是稀疏矩阵,结果也是稀疏矩阵:

mask = theano.sparse.neq(A_sparse, theano.sparse.sp_zeros_like(A_sparse))

修改子张量

为了修改矩阵的一部分,可以使用theano.tensor.set_subtensor。对于密集矩阵,这将起作用:

indices = mask.nonzero()
A = T.set_subtensor(A[indices], T.exp(A[indices]))

请注意 Theano 没有单独的布尔类型——掩码是零和一——所以必须先调用 nonzero() 来获取非零元素的索引。此外,这不适用于稀疏矩阵。

对非零稀疏元素进行运算

Theano 提供了据说是结构化的稀疏操作,并且只对非零元素进行操作。看: http://deeplearning.net/software/theano/tutorial/sparse.html#structured-operation

更准确地说,它们对稀疏矩阵的 data 属性进行操作,与元素的索引无关。这样的操作很容易实现。请注意,结构化操作将对 data 数组中的所有值进行操作,也包括那些明确设置为零的值。

T.where 有效。

A_sparse = T.where(A_sparse == 0, 0, T.exp(A_sparse))

@Seppo Envari 的回答似乎更快。所以我会接受他的回答。