このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。
デスクトップからクラスターへのスケール アップ
ローカル マシンで並列 MATLAB® コードを開発し、クラスターにスケール アップします。
クラスターは、計算を高速化して分散するためのより多くの計算リソースを提供します。ローカル マシンで対話的にコードを並列で実行してから、コードを変更せずにクラスターでも同様に実行できます。ローカル マシンでのコードのプロトタイプの作成完了後、バッチ ジョブを使用して計算をクラスターにオフロードできます。これにより、MATLAB を閉じて、結果を後で取得することができます。
アルゴリズムの開発
ローカル マシンでアルゴリズムのプロトタイプを作成することから始めます。この例ではサンプル問題として整数の因数分解を使用します。これは、数の絶対値と共に因数分解の複雑度が高くなる計算量の多い問題です。シンプルなアルゴリズムを使用して整数の数列を因数分解します。
64 ビットの精度で素数のベクトルを作成し、素数のペアをランダムに乗算して大きな合成数を取得します。各因数分解の結果を保存する配列を作成します。この例の以降の各節にあるコードの実行には 20 分以上かかる場合があります。高速化するには、使用する素数の数を減らして (2^19
など) 負荷を軽減します。2^21
を指定して実行し、最適な最終プロットを表示します。
primeNumbers = primes(uint64(2^21)); compositeNumbers = primeNumbers.*primeNumbers(randperm(numel(primeNumbers))); factors = zeros(numel(primeNumbers),2);
ループを使用して個々の合成数を因数分解し、計算の所要時間を測定します。
tic; for idx = 1:numel(compositeNumbers) factors(idx,:) = factor(compositeNumbers(idx)); end toc
Elapsed time is 684.464556 seconds.
ローカル並列プールでのコードの実行
Parallel Computing Toolbox™ では、並列プールの複数のワーカーで計算を実行することにより、ワークフローをスケール アップできます。前述した for
ループの反復は独立しているため、parfor
ループを使用して複数のワーカーに反復を分散することができます。単純に for
ループを parfor
ループに変換します。次に、コードを実行して全体の計算時間を測定します。コードは追加の変更なしで並列プールで実行され、ワーカーは計算結果をローカル ワークスペースに返します。作業負荷が複数のワーカーに分散されているため、計算時間は短くなります。
tic; parfor idx = 1:numel(compositeNumbers) factors(idx,:) = factor(compositeNumbers(idx)); end toc
Elapsed time is 144.550358 seconds.
parfor
を使用するときに Parallel Computing Toolbox がある場合、MATLAB は自動的にワーカーの並列プールを起動します。並列プールの起動にはある程度の時間がかかります。この例は、プールが既に起動した状態での 2 回目の実行を示します。
既定のプロファイルは 'Processes'
です。MATLAB の [ホーム] タブ、[並列]、[並列環境を選択] で、このプロファイルが既定に設定されていることを確認できます。このプロファイルが有効の場合、MATLAB は並列プール用のマシンにワーカーを作成します。'Processes'
プロファイルを使用すると、MATLAB は既定でマシンの物理コアと同じ数のワーカー ('Processes'
プロファイルで設定される上限まで) を起動します。並列基本設定を使用して並列動作を制御することができます。MATLAB の [ホーム] タブで、[並列]、[並列基本設定] を選択します。
ワーカーの数による高速化を測定するために、ワーカーの最大数を制限して、同じコードを複数回実行します。まず、各実行のワーカー数を定義し (上限はプール内のワーカー数)、各テストの結果を保存するための配列を作成します。
numWorkers = [1 2 4 6]; tLocal = zeros(size(numWorkers));
ループを使用してワーカーの最大数まで反復し、前述のコードを実行します。ワーカー数を制限するために、parfor
の 2 番目の入力引数を使用します。
for w = 1:numel(numWorkers) tic; parfor (idx = 1:numel(compositeNumbers), numWorkers(w)) factors(idx,:) = factor(compositeNumbers(idx)); end tLocal(w) = toc; end
1 つのワーカーでの計算時間と各最大ワーカー数での計算時間との比を計算して、高速化を計算します。ワーカー数と共に計算がスケール アップしている様子を可視化するために、ワーカー数に対して高速化をプロットします。ワーカー数と共に高速化も上昇していることがわかります。しかし、並列化に伴うオーバーヘッドがあるため、スケーリングは比例的ではありません。
f = figure; speedup = tLocal(1)./tLocal; plot(numWorkers, speedup); title('Speedup with the number of workers'); xlabel('Number of workers'); xticks(numWorkers); ylabel('Speedup');
計算が完了したら、現在の並列プールを削除します。これにより、クラスター用に新しい並列プールを作成できます。関数 gcp
で現在の並列プールを取得できます。
delete(gcp);
クラスターの設定
計算タスクがローカル コンピューターにとって大きすぎるまたは遅すぎる場合は、計算をオンサイトのクラスターまたはクラウドにオフロードできます。以降の節の内容を実行するには、クラスターにアクセスできなければなりません。MATLAB の [ホーム] タブで、[並列]、[クラスターの検出] に移動し、MATLAB Parallel Server™ がインストールされたクラスターにアクセスできるかどうかを確認します。詳細については、クラスターの検出を参照してください。
クラスターにアクセスできない場合は、以降の節に進む前にクラスターへのアクセスを設定しなければなりません。MATLAB では、Amazon AWS などのクラウド サービス上に MATLAB デスクトップから直接クラスターを作成することができます。[ホーム] タブの [並列] メニューで [クラスターの作成と管理] を選択します。クラスター プロファイル マネージャーで、[クラウド クラスターの作成] をクリックします。クラウドへのスケール アップの詳細については、Getting Started with Cloud Center を参照してください。ネットワーク上のクラスターにスケーリングするオプションの詳細については、インストール (MATLAB Parallel Server)を参照してください。
クラスター プロファイルを設定した後、そのプロパティを [並列]、[クラスターの作成と管理] で変更できます。詳細については、クラスターの検出とクラスター プロファイルの使用を参照してください。次のイメージはクラスター プロファイル マネージャー内のクラスター プロファイルを示します。
クラスター並列プールでのコードの実行
並列関数を既定でクラスターで実行する場合、[並列]、[並列環境を選択] で、クラスター プロファイルを既定として設定します。
また、プログラムによる方法でクラスターを指定することもできます。このためには、parpool
コマンドにクラスター プロファイルの名前を指定して、クラスターで並列プールを起動します。次のコードの MyCluster
をクラスター プロファイルの名前に置き換えます。また、2 番目の入力引数でワーカー数を指定します。
parpool('MyCluster',64);
Starting parallel pool (parpool) using the 'MyCluster' profile ... connected to 64 workers.
前と同様に、ワーカーの最大数を制限して同じコードを複数回実行することで、ワーカー数による高速化を測定します。この例のクラスターはローカル設定よりも多くのワーカーを使用できるため、numWorkers
により多くの値を指定できます。このコードを実行すると、parfor
ループがクラスターで実行されます。
numWorkers = [1 2 4 6 16 32 64]; tCluster = zeros(size(numWorkers)); for w = 1:numel(numWorkers) tic; parfor (idx = 1:numel(compositeNumbers), numWorkers(w)) factors(idx,:) = factor(compositeNumbers(idx)); end tCluster(w) = toc; end
高速化を計算してワーカー数に対してプロットし、ワーカー数と共に計算がスケール アップする様子を可視化します。この結果をローカル設定の結果と比較します。ワーカー数と共に高速化も上昇していることがわかります。しかし、並列化に伴うオーバーヘッドがあるため、スケーリングは比例的ではありません。
figure(f); hold on speedup = tCluster(1)./tCluster; plot(numWorkers, speedup); title('Speedup with the number of workers'); xlabel('Number of workers'); xticks(numWorkers(2:end)); ylabel('Speedup');
計算が完了したら、現在の並列プールを削除します。
delete(gcp);
batch
による計算のオフロードとスケーリング
プロトタイプの作成と対話的な実行の完了後、バッチ ジョブを使用して、実行時間の長い計算をオフロードしてバックグラウンドのバッチ処理で実行できます。計算はクラスターで実行されるため、MATLAB を閉じて、結果を後で取得することができます。
関数 batch
を使用してジョブをクラスターに投入します。スクリプト内にアルゴリズムの内容を配置し、関数 batch
を使用してスクリプトを投入します。たとえば、スクリプト myParallelAlgorithm は、この例で示した整数の因数分解問題に基づくシンプルなベンチマークを実行します。このスクリプトは、異なるワーカー数を使用して複数の問題の複雑度の計算時間を測定します。
batch
を使用してスクリプト ファイルを送信すると、MATLAB はスクリプトで使用しない場合でも、すべてのワークスペース変数をクラスターに転送します。ワークスペースが大きい場合、これはデータ転送時間に悪影響を及ぼします。ベスト プラクティスとして、スクリプトを関数ファイルに変換することにより、この通信オーバーヘッドを回避します。これを行うには、スクリプトの冒頭に関数の行を単純に追加します。myParallelAlgorithm を関数に変換する方法の詳細については、myParallelAlgorithmFcn を参照してください。
次のコードは myParallelAlgorithmFcn
をバッチ ジョブとして投入します。myParallelAlgorithmFcn
は 2 つの出力引数、numWorkers
と time
を返すため、出力数の入力引数として 2
を指定しなければなりません。このコードには parfor
ループ用の並列プールが必要であるため、batch
で名前と値のペア 'Pool'
を使用してワーカー数を指定します。クラスターは追加のワーカーを使用して関数自体を実行します。既定で、batch
はクラスター内のワーカーの現在のフォルダーを MATLAB クライアントの現在のフォルダーに変更します。これは現在のフォルダーの制御に便利な場合があります。たとえば、クラスターの使用しているファイルシステムが異なる場合 (Windows クライアント マシンから Linux クラスターに送信する場合など) パスが異なります。名前と値のペア 'CurrentFolder'
を任意のフォルダーに設定するか、'.'
に設定してワーカーのフォルダーの変更を回避します。
totalNumberOfWorkers = 65; cluster = parcluster('MyCluster'); job = batch(cluster,'myParallelAlgorithmFcn',2,'Pool',totalNumberOfWorkers-1,'CurrentFolder','.');
投入後のジョブの状態を監視するには、[並列]、[ジョブの監視] でジョブ モニターを開きます。計算がクラスターで開始されるときに、ジョブの状態が running
に変更されます。
ジョブが投入されたら、MATLAB を閉じることができます。MATLAB を再度開くと、ジョブ モニターがジョブを記録しており、ジョブを右クリックして操作することができます。たとえば、ジョブ オブジェクトを取得するには [詳細を表示] を選択し、バッチ ジョブの出力をワークスペースに転送するには [出力の取得] を選択します。
あるいは、ジョブが完了するまで MATLAB をブロックする場合は、ジョブ オブジェクトに対して関数 wait
を使用します。
wait(job);
関数の出力をクラスターから転送するには、関数 fetchOutputs
を使用します。
outputs = fetchOutputs(job); numWorkers = outputs{1}; time = outputs{2};
結果の取得後、ローカル マシンでの計算に結果を使用できます。高速化を計算し、ワーカー数に対してプロットします。このコードは異なる問題複雑度について因数分解を実行するため、各レベルのプロットが得られます。それぞれの問題複雑度で、追加のワーカーによるオーバーヘッドが並列化によるパフォーマンス上昇を超えるまで、ワーカーの数と共に高速化が上昇していることがわかります。問題複雑度が高くなるほど、ワーカー数が多いときにより良い高速化が得られます。これは並列化に付随するオーバーヘッドの影響が少ないためです。
figure speedup = time(1,:)./time; plot(numWorkers,speedup); legend('Problem complexity 1','Problem complexity 2','Problem complexity 3','Problem complexity 4','Location','northwest'); title('Speedup vs complexity'); xlabel('Number of workers'); xticks(numWorkers(2:end)); ylabel('Speedup');
参考
parpool
| parfor
| batch
| fetchOutputs (Job)
関連する例
詳細
- 並列 for ループ (parfor)
- インストール (MATLAB Parallel Server)