稀疏矩阵
稀疏矩阵(sparse matrix)是由于矩阵中存在大量0,从而可以采用特别的存储技巧来压缩内存。
由于在工作需要将一个150666569x9860的超大矩阵作为数据,来训练NN模型,所以采用稀疏矩阵的方式,将这个超大矩阵压缩,从而使得能够放入内存中。
python的稀疏矩阵在scipy包中,而theano同时支持的是csc_matrix,和csr_matrix。
from scipy.sparse import csc_matrix,csr_matrix
这两种稀疏矩阵的选择取决于要稀疏的矩阵的情况,如果row比column多,就用csc_matrix,反之则用csr_matrix,更具体的可以看这里。我们当然就选择scs_matrix
构建稀疏矩阵
有两种方法构建矩阵,一种方法是用3个list,分别记录非0元素的行序列, 列序列,还有该元素本身。
row = np.array([0, 2, 2, 0, 1, 2])
col = np.array([0, 0, 1, 2, 2, 2])
data = np.array([1, 2, 3, 4, 5, 6])
sparse_matrix=csc_matrix((data, (row, col)), shape=(3, 3))
sparse_matrix.toarray()
output:array([[1, 0, 4],
[0, 0, 5],
[2, 3, 6]])
另一种方法也是用3个list,看例子来详解下
indptr = np.array([0, 2, 3, 6])
indices = np.array([0, 2, 2, 0, 1, 2])
data = np.array([1, 2, 3, 4, 5, 6])
csc_matrix((data, indices, indptr), shape=(3, 3)).toarray()
output:
array([[1, 0, 4],
[0, 0, 5],
[2, 3, 6]])
在csc_matrix中indptr的差值代表每列有几个非0元素,比如2-0=2,代表第一列有2个非0元素,在哪里是看indices这个list,它记录了行的序列,元素本身则在data list中。
知道这个原理,我们可以自己写一个合并两个csc_matrix的函数:
def concatenate_csc_matrices_by_columns(matrix1, matrix2):
new_data = np.concatenate((matrix1.data, matrix2.data))
new_indices = np.concatenate((matrix1.indices, matrix2.indices))
new_ind_ptr = matrix2.indptr + len(matrix1.data)
new_ind_ptr = new_ind_ptr[1:]
new_ind_ptr = np.concatenate((matrix1.indptr, new_ind_ptr))
return csc_matrix((new_data, new_indices, new_ind_ptr))
很明显的看到,第二种存储稀疏矩阵的方式,更节省空间。但是第一种更浅显易懂。
将稀疏矩阵用于theano
以deeplearning tutorial的mlp为例,如果输入的training_x数据为稀疏矩阵,那么需要改一下几个地方:
- Symbolic declaration:
将原来的x = T.matrix('x')改成:
x = theano.sparse.csc_matrix('x')
- 将Hiddenlayer的lin_out改成:
lin_output = theano.sparse.dot(input, self.W) + self.b
其他只要跟原来的模型保持一致就可以了。
theano改起来还是很容易的,这主要是因为theano本身支持稀疏矩阵。
将稀疏矩阵用于keras
Keras is a minimalist, highly modular neural networks library, written in Python and capable of running on top of either TensorFlow or Theano.
keras是一个高度模块化的深度学习框架,用起来非常方便,只需要关注模型本身就行。
要使得稀疏矩阵能在keras中用,只需要对keras的training.py这个文件做些修改就行。
- 将所有len(ins[0])替换成ins[0].shape[0]
- 在用SGD的时候,将每批batch选出来的样本还原成正常的矩阵,这样的方式,使得内存不会被占用很多。要实现这个,只需要在每次调用slice_X这个函数之后,插入如下代码,将ins_batch变成正常矩阵就可以。
代码如下:
if sps.issparse(ins_batch[0]):
ins_batch[0] = ins_batch[0].toarray()
if sps.issparse(ins_batch[1]):
ins_batch[1] = ins_batch[1].toarray()
总结
- keras很好用
- keras是用python实现的,查看源代码很方便,修改起来也很方便
- 这次因为这个稀疏矩阵的需求,研究了下theano和keras,收获颇丰,以后有机会还是应该多看看源代码