NumPy / Scipyに関数を実装して、単一の(トレーニング)ベクトルと他の多数の(観測)ベクトルの間のイェンセンシャノンの発散を計算しようとしています。観測ベクトルは、非常に大きな(500,000x65536)Scipyスパース行列に格納されます(密行列はメモリに収まりません)。
アルゴリズムの一部として、観測ベクトルOiごとにT+ O iを計算する必要があります。ここで、Tはトレーニングベクトルです。スパース行列はそれらをサポートしていないように見えるため、NumPyの通常のブロードキャストルールを使用してこれを行う方法を見つけることができませんでした(Tが密な配列として残されている場合、Scipyは最初にスパース行列を密にしようとします。メモリ不足。Tをスパース行列にすると、形状に一貫性がないため、T + O iは失敗します)。
現在、トレーニングベクトルを500,000x65536のスパース行列にタイリングするという非常に非効率的な手順を実行しています。
training = sp.csr_matrix(training.astype(np.float32))
tindptr = np.arange(0, len(training.indices)*observations.shape[0]+1, len(training.indices), dtype=np.int32)
tindices = np.tile(training.indices, observations.shape[0])
tdata = np.tile(training.data, observations.shape[0])
mtraining = sp.csr_matrix((tdata, tindices, tindptr), shape=observations.shape)
ただし、これは、最大1500の「実際の」要素しか格納しない場合、大量のメモリ(約6GB)を消費します。構築もかなり遅いです。
stride_tricksを使用して、CSRマトリックスのindptrとデータメンバーが繰り返されるデータに余分なメモリを使用しないようにすることで、賢くしようとしました。
training = sp.csr_matrix(training)
mtraining = sp.csr_matrix(observations.shape,dtype=np.int32)
tdata = training.data
vdata = np.lib.stride_tricks.as_strided(tdata, (mtraining.shape[0], tdata.size), (0, tdata.itemsize))
indices = training.indices
vindices = np.lib.stride_tricks.as_strided(indices, (mtraining.shape[0], indices.size), (0, indices.itemsize))
mtraining.indptr = np.arange(0, len(indices)*mtraining.shape[0]+1, len(indices), dtype=np.int32)
mtraining.data = vdata
mtraining.indices = vindices
ただし、ストライドビューのmtraining.dataとmtraining.indicesは間違った形状であるため、これは機能しません(この回答によると、正しい形状にする方法はありません)。.flatイテレータを使用してそれらをフラットに見せようとすると、配列のように見えないため(たとえば、dtypeメンバーがないため)失敗し、flatten()メソッドを使用するとコピーが作成されます。
これを行う方法はありますか?