メモリオーバーフローを引き起こしたメモリに一時的な行列を作成せずに行列を「コピー」する方法は?


9

はるかに大きい割り当てられたメモリにマトリックスを割り当てることにより、MATLABはそれを 'コピー'しながら何らかの方法で複製し、コピーされるマトリックスが十分に大きい場合、メモリオーバーフローが発生します。これはサンプルコードです:

main_mat=zeros(500,500,2000);
n=500;
slice_matrix=zeros(500,500,n);
for k=1:4
    parfor i=1:n
        slice_matrix(:,:,i)=gather(gpuArray(rand(500,500)));
    end
    main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix; %This is where the memory will likely overflow
end

ただ「スマッシュ」にどのような方法slice_matrixmain_matオーバーヘッドなし?前もって感謝します。

編集:

main_matあらかじめ割り付けておくとオーバーフローが発生します。main_matmain_mat=zeros(500,500,1);(小さいサイズ)で初期化された場合、オーバーフローは発生しませんが、行列が割り当てられる前に割り当てが行われないため、オーバーフローが遅くなります。これにより、範囲がk増えるにつれてパフォーマンスが大幅に低下します。


1
ループについて:最適化のために外側のループをループに設定することをお勧めしparforます。さらに、parforデータを各ワーカーにコピーします。したがって、4つのワーカーを想定して、データをRAMに4回複製します。
Adriaan

1
Matlabが実際にメモリを複製していることをどのように示していますか?このmemory機能を使用していますか?タスクマネージャー?Matlabからのメモリエラー?どのコード行で発生していますか?
エリアフアーロン

あなたがコードにコメントした場所を見ることができるようにmain_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)、メモリオーバーフローの問題が発生する場所です。main_mat事前に割り当てたときに検証されます。オーバーフローします。オーバーフローしない場合はオーバーフローしません。Matlabは「メモリ不足エラー」を返します。
Gregor Isack

500x500x2000マトリックスはメモリに収まりますか?約4 GBです。配列への書き込み時にのみメモリ不足エラーが発生する理由については、stackoverflow.com / q / 51987892/7328782を参照してください。
クリス・ルエンゴ

問題をよりよく理解するために、 h=h+slice_matrix(end)前にmain_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix;(およびhを0で初期化して)か?この新しく追加された行がすでにメモリの問題を引き起こしていると思います。
ダニエル

回答:


4

主な問題は、数値はゼロよりも多くのスペースを取ることです。 GPUとparforのどちらを使用しているかに関係なく、main_mat=zeros(500,500,2000);RAMをほとんど使用しmain_mat = rand(500,500,2000);ません(実際には、parforを使用するとRAMの使用量が増えます)。ですから、これは不自然な記憶の腫れではありません。以下のダニエルのリンクをたどると、ゼロの割り当てはメモリへのポインタを作成するだけであり、物理メモリは「数値」の行列を使用する場合にのみ満たされます。これはオペレーティングシステムによって管理されます。そして、それは、Windows、Mac、およびLinuxで期待されており、MatlabまたはCなどの他の言語で行うことができます。


現在、MATLABは理解できません。コマンドを入力すると、zeros仮想メモリ全体が実際に割り当てられますが、メモリは使用されません。whos両方の行列で同じサイズを示していますが、私のOSでは異なるメモリ消費を示しています。あなたの答えは間違いなく間違っていなかったので、コメントを削除しました。
ダニエル

3
:私は何か、この説明見つかっstackoverflow.com/questions/51987892/...
ダニエル・

正解です。ありがとう。
JLev

@Gregor:これを確認すると思います。ではonesなくで試してくださいzeros。これにより、それぞれの関数を呼び出すときに実際にメモリが割り当てられます。
ダニエル

すべてを正しく理解すると、結論は次のようになります。一時的なコピーはありません。にmain_matはゼロ以外の値が割り当てられているため、メモリ不足の例外が発生します。以前は仮想メモリ(アドレススペース)のみが割り当てられていましたが、現在は物理メモリに割り当てられています。
ダニエル

1

削除parforすると問題が解決する可能性があります。

parforそこでは役に立ちません。MATLAB parforは共有メモリの並列処理(つまり、新しいスレッドを開始しない)を使用せず、分散メモリの並列処理(新しいプロセスを開始する)を使用します。セットまたはワーカーノードに作業を分散するように設計されています。また、1つのノード(または単一のデスクトップコンピューター)内でも機能して複数のコアに作業を分散しますが、1つのノード内で並列処理を行う最適な方法ではありません。

これは、によって開始されたプロセスのそれぞれがparfor独自のコピーを持っている必要があることを意味しますslice_matrix。これが、プログラムが大量のメモリを使用する原因になります。

詳細およびいつ使用するかについては、MATLABドキュメンテーションの使用する場合の決定」をparfor参照してくださいparfor


1
削除parfor が唯一の方法ですか?内部のすべてparforがCPUとGPUを集中的に使用するため、処理はそのように設計したときに最適に機能し、パフォーマンスが大幅に向上しました。
Gregor Isack

@GregorIsack:私はあなたのサンプルコードを使いました、あなたが実際にの中で多くの仕事をしたことを知りませんでしたparfor。もしそうなら、はい、それはおそらく便利です。-多分ない場合slice_matrixgpuarrayそれは割り当てにコピーされません。
クリスLuengo

うーんでslice_matrixなくてgpuArrayも、オーバーフロー症状が出ます。この質問を開いて、別の解決策があるかどうかを見てみましょう。でも答えてくれてありがとう!
Gregor Isack

0

あなたのコードは単なるサンプルコードであり、 rand()があなたのMVEのカスタム表すと思います。したがって、MATLABのメモリ使用量に関するヒントとコツがいくつかあります。

MathWorksトレーニングハンドブックの抜粋があります。

関数にパラメーターを渡すときのように、MATLABで変数を別の変数に割り当てるとき、MATLABはその変数への参照を透過的に作成します。コードが1つ以上の値を変更する場合にのみ、MATLABは参照を解除し、その変数のコピーを作成します。copy-on-writeまたはlazy-copyingと呼ばれるこの動作は、コードが値を変更するまで、大きなデータセットをコピーするコストを遅らせます。したがって、コードが変更を実行しない場合、変数をコピーするための追加のメモリ領域と実行時間は必要ありません。

最初に行うことは、コードの(メモリ)効率をチェックすることです。優れたプログラマーのコードでさえ、(少し)頭脳の力でさらに最適化できます。ここに、メモリ効率に関するいくつかのヒントがあります

  • MathWorks社のMATLABのnativベクトル化の使用を作る、例えばsum(X,2)mean(X,2)std(X,[],2)
  • matlabが行列を展開する必要がないことを確認してください(暗黙的な展開が最近変更されました)。使用する方が効率的かもしれませんbsxfun
  • インプレース・オペレーション、例えば使用x = 2*x+3ではなく、x = 2*x+3
  • ...

メモリ使用量に関する最適化は、計算時間を短縮したい場合と同じではないことに注意してください。したがって、ワーカーの数を減らすか、parfor-loopの使用を控えることを検討してください。(parfor共有メモリを使用できないため、Parallel Toolboxを使用したコピーオンライト機能はありません。

あなたの記憶、Matlabが利用できるもの、そして利用可能なものを詳しく見てみたい場合は、をチェックしてくださいfeature('memstats')。あなたにとって興味深いのは、仮想メモリです。

MATLABプロセス全体に関連する使用可能な合計メモリ。プロセッサアーキテクチャとオペレーティングシステムによって制限されます。または、このコマンドを使用します[user,sys] = memory

クイックサイドノード:Matlabは一貫して行列をメモリに保存します。大きな行列の場合は、RAMの大きなブロックが必要です。これは、変数を変更する理由でもあります。変数を変更すると、Matlabは現在のスポットを超えるたびに、マトリックス全体をRAM内のより大きなスポットにコピーします。

本当にメモリの問題がある場合は、データ型の技術を詳しく調べたいと思うかもしれません。たとえば、最初から直接単精度を使用することでメモリ使用量を半分に減らすことができますmain_mat=zeros(500,500,2000,'single');-ところで、これはrand(...,'single')よりネイティブな関数でも機能します-より洗練されたいくつかのMATLAB関数はdouble型の入力を必要としますが、再びアップキャスト。


0

私が正しく理解していれば、あなたの主な問題はparforメモリを共有できないことです。すべてのparforワーカーをほぼ独立したMATLABインスタンスと考えてください。

:Fileexchangeの「共有行列」で私が知っているのはこのためのひとつの回避策(私が試したことがないこと)、基本的にはありhttps://ch.mathworks.com/matlabcentral/fileexchange/28572-sharedmatrixは、

その他の解決策:他の提案どおり、parforの削除は確かに1つの解決策であり、ramを増やし、tall配列を使用します(ramがいっぱいになったときにハードドライブを使用します)、操作を小さなチャンクに分割します。 Matlab。


0

次のコードを使用できます。実際には、slice_matrixは必要ありません。

main_mat=zeros(500,500,2000);
n=500;
slice_matrix=zeros(500,500,n);
for k=1:4
   parfor i=1:n
       main_mat(:,:,1+(k-1)*n + i - 1) = gather(gpuArray(rand(500,500)));
   end
   %% now you don't need this main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix; %This is where the memory will likely overflow
end

parforループの中でそれを行うことはできません
Gregor Isack

やってみましたか?
mayank1513

それをパーフォアループから外したのには理由があります。まったく同じコードを試したわけではありませんが、索引付けが原因で機能しないことはわかっていました。
Gregor Isack
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.