Theano2.1.11-基础知识之稀疏
来自:http://deeplearning.net/software/theano/tutorial/sparse.html
sparse
通常来说,稀疏矩阵可以和常规矩阵一样提供相同的功能。两者不同之处在于在内存中存储矩阵和表示矩阵的方式。 在稀疏矩阵中,只有非0元素才会被存储。这种方式带来的优点有:首先,这可以很明显的减少内存的使用‘第二;通过使用指定的稀疏算法和这种稀疏存储方法可以减少计算时间。我们通常将常规的存储矩阵叫做密集矩阵(dense matrices)。
Theano的稀疏包提供高效的算法,不过却并不推荐在所有的矩阵和所有的情况下使用。正如一个显而易见的例子,当稀疏比例非常低的时候,就等于在常规矩阵上使用这些算法,而且本身带来的存储开销会比常规矩阵还大。稀疏比例指的是元素为0的值所占整个矩阵上所有元素的个数比。一个低稀疏比例会导致在内存上使用更多的空间,不只是需要存储实际的数据,而且还需要存储每个元素的位置信息。这同样需要更多的计算时间,然而一个密集矩阵是使用常规优化算法的,可能效果比这时候的稀疏表示矩阵更高效。其他例子可以在特定目的和矩阵的结构的联系上找到。更多的文档可以查看 SciPy Sparse Reference.
因为稀疏矩阵不是存储在连续数组上的,所以有几种方式来存储。这通常被设计成所谓的矩阵的格式(format)。因为 Theano的稀疏矩阵包是基于SciPy 稀疏包的,完整的有关稀疏矩阵的信息可查阅 SciPy的文档。就像SciPy一样, Theano没有对那些维度不等于2的数组实现稀疏格式。
到目前为止,Theano实现了两个稀疏矩阵的格式: csc and csr。 这些几乎是等同的,除了csc是基于矩阵的列,而csr是基于矩阵的行的。他们都是有着相同的目的:为了提供给高效的算法用来执行线性代数操作。不过缺点就是它们没法通过一个高效的方法来修改潜在矩阵的稀疏结构,例如:增加元素。这也就是说如果你在你的计算graph中会频繁的在稀疏矩阵中增加新的元素,也许一个tensor变量是更好的选择。
更多的文档可以查看 Sparse Library Reference.
在进行下一步之前,来做做准备工作:
>>> import theano >>> import numpy as np >>> import scipy.sparse as sp >>> from theano import sparse
一、稀疏压缩格式
Theano支持两种稀疏压缩格式: csc 和 csr, 分别是基于列和行的。他们都有着相同的属性: data, indices, indptr 和 shape.
- data 属性是一个一维的 ndarray ,它包含稀疏矩阵所有的非0元素。
- indices 和indptr 属性是用来存储稀疏矩阵中数据的位置的。
- shape 属性,准确的说是和密集矩阵的shape属性一样的。如果从前三个属性上没法推断,那么它可以在稀疏矩阵创建的时候显式指定 。
1.1 应该使用哪种格式 ?
最后,格式不会影响到data和indices属性的长度(length)。它们都是通过你所想存储的元素个数确定的。唯一会被格式改变的就是 indptr。在csc 格式下,该句子是按着列进行压缩的,所以列数量更少的时候,所需要的内存就更少。另一方面,csr 格式下,句子是按行压缩的,所以当一个矩阵有着更少行数的时候,csr格式是个更好的选择。下面就是规则的形式:
note:If shape[0] > shape[1], 使用 csr format. ;否则,使用 csc。(觉得这里和上面说的完全相反了,上面说当矩阵行少的时候用csr)。
有时候,因为稀疏模块到现在的时间还不长,ops还没有针对两种format的操作。所以这里也是最相关的规则:
note:使用该矩阵格式可以兼容你计算graph中的ops。
关于ops和所支持的format等文档可以查阅: Sparse
Library Reference.
二、在theano中处理稀疏
在theano中大多数的ops都是依赖于稀疏矩阵的格式(format)的。这就是为什么有两种稀疏变量的构造器: csc_matrix 和 csr_matrix。这些都能被普通的name和dtype参数所调用,不过没有 broadcastable 标识。这是被禁止的,因为稀疏包(和SciPy的稀疏模块一样)不提供任何方式来处理维度不等于2的情况的矩阵。稀疏矩阵的所有可接受的dtype值可以在 sparse.all_dtypes中找到:
>>> sparse.all_dtypes set(['int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64', 'float32', 'float64', 'complex64', 'complex128'])
2.1 转换
为了在稀疏矩阵和密集矩阵之间相互转换。Theano提供了 dense_from_sparse,csr_from_dense 和 csc_from_dense 函数。不需要任何额外的细节。这里就是从稀疏到稀疏的一个完整转换的例子:
>>> x = sparse.csc_matrix(name='x', dtype='float32') >>> y = sparse.dense_from_sparse(x) >>> z = sparse.csc_from_dense(y)
2.2 属性和构造
尽管稀疏变量不允许直接访问它们的属性,不过还是可以通过 csm_properties 来完成的。它会返回一个一维的tensor变量的元组,用来表示稀疏矩阵的内部特征。
为了从某些属性上重构一个稀疏矩阵,可以使用函数 CSC 和 CSR 。这会以合适的格式来创建稀疏矩阵。例如,下面的代码重构一个csc矩阵到csr格式:
>>> x = sparse.csc_matrix(name='x', dtype='int64') >>> data, indices, indptr, shape = sparse.csm_properties(x) >>> y = sparse.CSR(data, indices, indptr, shape) >>> f = theano.function([x], y) >>> a = sp.csc_matrix(np.asarray([[0, 1, 1], [0, 0, 0], [1, 0, 0]])) >>> print a.toarray() [[0 1 1] [0 0 0] [1 0 0]] >>> print f(a).toarray() [[0 0 1] [1 0 0] [1 0 0]]最后的例子显示,格式可以从一个转换到另一个。的确,当调用transpose函数的时候,生成的矩阵的稀疏特征就不会和输入的时候一样了
2.3 结构(structured)操作
有几个ops是用在稀疏矩阵的非常奇特的结构上的。这些ops是结构式的(structured),而且不会在稀疏矩阵的0元素上有任何的计算操作。 它们被认为是只用在后面(暂时不知道是指哪个)的数据属性上的。 注意,这些结构操作都提供一个结构梯度(structured gradient)。更多的解释如下:
>>> x = sparse.csc_matrix(name='x', dtype='float32') >>> y = sparse.structured_add(x, 2) >>> f = theano.function([x], y) >>> a = sp.csc_matrix(np.asarray([[0, 0, -1], [0, -2, 1], [3, 0, 0]], dtype='float32')) >>> print a.toarray() [[ 0. 0. -1.] [ 0. -2. 1.] [ 3. 0. 0.]] >>> print f(a).toarray() [[ 0. 0. 1.] [ 0. 0. 3.] [ 5. 0. 0.]]
2.4 梯度
在稀疏模块中ops的梯度同样可以是structured。一些ops提供一个 flag 来指定该梯度是否structured。该文档可以用来决定一个op的梯度是否是常规的还是structured还是它的实现是否能够被修改。相似于structured ops,当计算了一个structured gradient的时候,该计算只会应用在系数矩阵的非0元素上。
更多有关特定op上的梯度可以查阅: Sparse Library Reference.
参考资料:[1]官网:http://deeplearning.net/software/theano/tutorial/sparse.html