使用具有Keras和Tensorflow的稀疏矩阵

SRo*_*mes 20 sparse-matrix keras tensorflow

我的数据可以被视为10B条目(100M x 100)的矩阵,这是非常稀疏的(<1/100*1/100的条目非零).我想使用Tensorflow后端将数据输入到我制作的Keras神经网络模型中.

我的第一个想法是将数据扩展为密集,即将所有10B条目写入一系列CSV,大多数条目为零.然而,这很快就压倒了我的资源(甚至做了ETL不堪重负的大熊猫,并导致postgres挣扎).所以我需要使用真正的稀疏矩阵.

我怎么能用Keras(和Tensorflow)做到这一点?虽然numpy不支持稀疏矩阵,但scipy和tensorflow都支持稀疏矩阵.有很多讨论(例如 https://github.com/fchollet/keras/pull/1886 https://github.com/fchollet/keras/pull/3695/files https://github.com/pplonski/keras-稀疏检查 https://groups.google.com/forum/#!topic/keras-users/odsQBcNCdZg)关于这个想法 - 使用scipy的稀疏矩阵或直接转到Tensorflow的稀疏矩阵.但是我找不到一个明确的结论,我也无法得到任何工作(或者甚至清楚地知道要走哪条路!).

我怎样才能做到这一点?

我相信有两种可能的方法:

  1. 保持它作为scipy稀疏矩阵,然后,当给Keras一个小批量,使其密集
  2. 保持稀疏,并使用Tensorflow稀疏张量

我也认为#2是首选,因为你会在整个过程中获得更好的表现(我相信),但#1可能更容易并且足够了.我会很高兴.

如何实施?

Mar*_*sha 6

对不起,没有评论的声誉,但我认为你应该看看这里的答案:Keras,稀疏矩阵问题.我已经尝试了它并且它工作正常,但只有一个注意事项,至少在我的情况下,改组导致了非常糟糕的结果,所以我使用了这个稍微修改过的非改组替代方案:

def nn_batch_generator(X_data, y_data, batch_size):
    samples_per_epoch = X_data.shape[0]
    number_of_batches = samples_per_epoch/batch_size
    counter=0
    index = np.arange(np.shape(y_data)[0])
    while 1:
        index_batch = index[batch_size*counter:batch_size*(counter+1)]
        X_batch = X_data[index_batch,:].todense()
        y_batch = y_data[index_batch]
        counter += 1
        yield np.array(X_batch),y_batch
        if (counter > number_of_batches):
            counter=0
Run Code Online (Sandbox Code Playgroud)

它产生相当的精度由keras的实现者执行洗牌(设置shuffle=Truefit).


Mau*_*Qch 5

该答案解决了问题中提到的第二种方法。如果您编写自定义训练循环,则可以使用稀疏矩阵作为具有 Tensorflow 后端的 Keras 模型的输入。在下面的示例中,模型将稀疏矩阵作为输入并输出密集矩阵。

from keras.layers import Dense, Input
from keras.models import Model
import scipy
import numpy as np

trainX = scipy.sparse.random(1024, 1024)
trainY = np.random.rand(1024, 1024)

inputs = Input(shape=(trainX.shape[1],), sparse=True)
outputs = Dense(trainY.shape[1], activation='softmax')(inputs)
model = Model(inputs=inputs, outputs=outputs)
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

steps = 10
for i in range(steps):
  # For simplicity, we directly use trainX and trainY in this example
  # Usually, this is where batches are prepared
  print(model.train_on_batch(trainX, trainY))
# [3549.2546, 0.0]
# ...
# [3545.6448, 0.0009765625]
Run Code Online (Sandbox Code Playgroud)

但是,这种方法的有用性取决于您的模型是否需要对稀疏矩阵进行增密。事实上,上述模型有一层将稀疏矩阵转换为密集矩阵。如果您的稀疏矩阵不适合内存,这可能是一个问题。