web-dev-qa-db-ja.com

KerasおよびTensorflowでスパース行列を使用する

私のデータは10Bエントリ(100M x 100)のマトリックスとして見ることができ、非常にまばらです(<1/100 * 1/100のエントリはゼロではありません)。 Tensorflowバックエンドを使用して、作成したKerasニューラルネットワークモデルにデータを送りたいと思います。

私が最初に考えたのは、データを高密度に拡張することでした。つまり、すべての10Bエントリを一連のCSVに書き込み、ほとんどのエントリをゼロにすることでした。しかし、これはすぐに私のリソースを圧倒します(ETLを圧倒してもpandasであり、postgresを苦労させています)。したがって、真のスパース行列を使用する必要があります。

Keras(およびTensorflow)でこれを行うにはどうすればよいですか? numpyはスパース行列をサポートしていませんが、scipyとtensorflowは両方ともサポートしています。多くの議論があります(例 https://github.com/fchollet/keras/pull/1886https://github.com/fchollet/keras/pull/3695/fileshttps://github.com/pplonski/keras-sparse-checkhttps://groups.google.com/forum/#!topic/keras-users/odsQBcNCdZg )このアイデアについて-scipyのスパース行列を使用するか、Tensorflowのスパース行列に直接移動します。しかし、明確な結論を見つけることができず、何も機能させることができませんでした(または、どの方法を使用するかを明確に知ることすらできませんでした!)。

これどうやってするの?

私は2つの可能なアプローチがあると信じています:

  1. Scipy sparse matrixとして保持し、Kerasにミニバッチを与えるとき、それを密にします
  2. ずっとスパースに保ち、Tensorflow Sparse Tensorsを使用します

また、ずっと優れたパフォーマンスが得られるので(#2)が望ましいと思いますが、#1はおそらくもっと簡単で適切です。私はどちらかで満足しています。

どちらを実装できますか?

19
SRobertJames

申し訳ありませんが、コメントする評判はありませんが、ここの答えをご覧ください。 ケラス、スパースマトリックスの問題 。私はそれを試しましたが、正しく機能しますが、少なくとも私の場合、シャッフルは本当に悪い結果につながったので、私はこのわずかに変更されたシャッフルされていない代替を使用しました:

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

Kerasのシャッフルされた実装(設定shuffle=True in fit)。

6
Marawan Okasha

この回答は、質問で述べた2番目のアプローチに対応しています。カスタムトレーニングループを記述する場合、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]

ただし、このアプローチの有用性は、モデルでスパース行列を高密度化する必要があるかどうかによって異なります。実際、上記のモデルには、疎行列を密行列に変換する1つの層があります。これは、スパース行列がメモリに収まらない場合に問題になる可能性があります。

0
Maurice Qch