1

大きな用語文書行列があり、matlab が提供する非負行列因数分解関数を使用したいと考えています。問題は、最初の繰り返しの後、メモリ使用量が急速に上昇してトップに達し (私のシステムには 6GB あります)、一方で CPU 使用率レベルが非常に低く (約 1%-5%) になることです。システム全体がクラッシュしたかのように動作し、何年も待った場合にのみ、2 回目の反復が終了します。(良い結果を得るには、さらに多くの反復が必要であることに注意してください)。

質問:

誰かがこれを経験したことがある場合、または私のものよりもさらに大きな行列で nnmf() を実行したことがある場合は、言及された問題を実際にどのように克服したかを知りたいです。

また、これを小さなマトリックス (約 7000x1800) で実行しましたが、問題はありませんでした。用語とドキュメントの行列には多数のゼロ要素が含まれており、保存に必要なスペースを減らすのに役立つため、疎行列を使用します。たとえば、私の場合、Term-Document マトリックスには14608 * 18828 = 275039424要素とsum(sum(spa~=0)) = 1312582ゼロ以外の要素があります。

>> whos
Name          Size                    Bytes  Class     Attributes

full      14608x18828            2200315392  double              
spa       14608x18828              21151944  double    sparse    
4

2 に答える 2

1

最終的に機能したもの:

nnmf.mファイル(Matlabが提供するアルゴリズムの実装)を確認し、コードを理解しようとしました。'd'と呼ばれる1つの変数があり、これは次のことを行います。これは'a'とd = a - w*h; 同じ次元の完全な行列(つまり、大きな用語-ドキュメント行列)です。

Name             Size                    Bytes  Class      Attributes
a            14608x18828              21151944  double     sparse    
d            14608x18828            2200315392  double               
...
h                4x18828                602496  double               
h0               4x18828                602496  double               
...
w            14608x4                    467456  double               
w0           14608x4                    467456  double   

メモリスペースを節約するために、私はclearこのマトリックスが不要なときに削除していました。古い nnmf.mファイルの一部:

d = a - w*h;
dnorm = sqrt(sum(sum(d.^2))/nm);
dw = max(max(abs(w-w0) / (sqrteps+max(max(abs(w0))))));
dh = max(max(abs(h-h0) / (sqrteps+max(max(abs(h0))))));
delta = max(dw,dh);

この新しいものに置き換えられました:

d = a - w*h;
dnorm = sqrt(sum(sum(d.^2))/nm);
clear d;
dw = max(max(abs(w-w0) / (sqrteps+max(max(abs(w0))))));
dh = max(max(abs(h-h0) / (sqrteps+max(max(abs(h0))))));
delta = max(dw,dh);

clear dその後使用されなかったため、そこに追加されましdた。使用されていた用語ドキュメントマトリックスの場合、これはメモリの問題を引き起こすことなく機能しました。

于 2012-08-22T08:07:33.817 に答える
1

私たちは皆、スタートレックのエピソードをあまりにも多く見てきたと思います. 私たちのコンピューターは無限に高速ではなく、無限のメモリを備えています。私たちは、ほとんどすべての計算をほぼ即座に実行できるという期待に甘んじています。巨大な行列の因数分解を行いたいからといって、それができるわけではありません。このサイズの問題を処理するには、メモリを増やしてください。または、より小さな問題に取り組みます。

あなたが説明する行列はひどくまばらではなく、それらの因数分解は本質的に完全にいっぱいになります。スパース行列は、非ゼロ値の数が全体のごく一部でない限り、ほとんど価値がありません。ゼロ値が 50% しかない疎行列は、ツールの無駄です。例えば、

>> A = randi([0 1],100, 100);
>> B = sparse(A);
>> whos
  Name        Size             Bytes  Class     Attributes

  A         100x100            80000  double              
  B         100x100            81480  double    sparse    

ここで A は 50% ゼロですが、スパース フォームは実際にはフル バージョンよりも保存に多くのメモリを必要とします! ゼロ以外の要素だけでなく、その場所も保存する必要があることに注意してください。

わかりました、まばらなストレージはそれほど効率的ではありませんでした。しかし、業務の効率化に関して確実に利益を得ることができるでしょうか? その中でもそうではありません。Steve Eddins の timeit 関数を使用して比較すると、次の結果が得られます。

>> timeit(@() A*A)
ans =
   7.3604e-05

>> timeit(@() B*B)
ans =
    0.0014884

そのため、疎な乗算は完全な乗算よりもかなり遅くなりました。

基本的に、ゼロが 50% しかないスパース行列は、スパース形式の機能を無駄にしています。行列がもっとまばらだったら、結果は違っていたでしょう。

于 2012-08-21T14:16:41.257 に答える