Main Content

並列統計計算での再現性

並列計算の再現における問題および考察

"再現性のある" 計算とは、実行するたびに同じ結果が得られる計算のことを指します。再現性は、次のような場合に重要となります。

  • デバッグ — 異常な結果を修正するために結果を再現する必要があります。

  • 信頼度 — 結果を再現できると、その結果を検証および理解できます。

  • 既存のコードの変更 — 既存のコードを変更するとき、コードを破壊していないことを確認する必要があります。

一般的に、計算の再現性を保証する必要はありません。再現性が必要な場合にしばしば利用できる最も簡単な方法として、並列実行の代わりに逐次実行を利用することが挙げられます。逐次計算では、次のように単純に rng 関数を呼び出すことができます。

s = rng % Obtain the current state of the random stream
% run the statistical function
rng(s) % Reset the stream to the previous state
% run the statistical function again, obtain identical results

この節では、乱数を使用する場合、および並列計算での再現性が必要な場合について説明します。また、並列計算で逐次計算と同じ結果の取得が必要な場合についても説明します。

再現性のある並列計算を実行する

再現性があるように Statistics and Machine Learning Toolbox™ 関数を実行するには、次の手順を実行します。

  1. statset を使用して UseSubstreams オプションを true に設定します。

  2. Streams オプションを、次のようにサブストリームをサポートしているタイプに設定します。'mlfg6331_64' または 'mrg32k3a' に設定します。これらのストリームの詳細については、RandStream.list を参照してください。

  3. 並列実行するには、UseParallel オプションを true に設定します。

  4. fitcensemble または fitrensemble を使用してアンサンブルを並列的に当てはめるには、名前と値のペア 'Reproducible'true に設定して木テンプレートを作成します。

    t = templateTree('Reproducible',true);
    ens = fitcensemble(X,Y,'Method','bag','Learners',t,...
        'Options',options);
  5. オプション構造体を使用して関数を呼び出します

  6. 計算を再現するにはストリームをリセットし、関数をもう一度呼び出します。

この方法でなぜ再現性が確保できるかを理解するには、サブストリームが再現性のある並列計算を可能にする方法を参照してください。

たとえば、再現性のある計算に対して 'mlfg6331_64' ストリームを次のように使用します。

  1. 適当なオプション構造体を作成します。

    s = RandStream('mlfg6331_64');
    options = statset('UseParallel',true, ...
        'Streams',s,'UseSubstreams',true);
  2. 並列計算を実行します。手順については、Statistics and Machine Learning Toolbox を使用した並列計算の基本操作を参照してください。

  3. 乱数ストリームをリセットします。

    reset(s);
  4. 並列計算を再度実行します。まったく同一の結果が取得されます。

再現性のあるこの方法での並列計算の例については、再現可能な並列ブートストラップおよびアンサンブル分類の並列学習を参照してください。

乱数を使用した並列統計計算

サブストリームとは

"サブストリーム" とは、RandStream がすばやくアクセスできる乱数ストリームの一部です。任意の正の整数 k に対して RandStream がストリーム内の kM 番目の疑似乱数に移動できるような数値 M が存在します。この時点から、RandStream はストリーム内に後続のエントリを生成できます。現在、RandStream には M = 272 (約 5e21) 以上があります。

Timeline showing the first three substreams of a sequence. Each substream has length M.

別のサブストリーム内の要素には独立性があり、様々なラグにおいてk 因子相関がない、優良な統計的特性が存在します。サブストリームは、次の図に示すように、独立したストリームとして表示できるほど長くなります。

Three boxes illustrating three consecutive substreams. Inside each box is a sequence of random numbers.

サブストリームをサポートする 2 つの RandStream ストリーム タイプは、'mlfg6331_64''mrg32k3a' です。

サブストリームが再現性のある並列計算を可能にする方法

MATLAB® によって parfor を使用した並列計算が実行される場合、各ワーカーはループの反復を予期できない順番で受け取ります。したがって、どのワーカーがどの反復を取得するかを予測することはできず、各反復に関連付けられた乱数を判定することもできません。

サブストリームを使用することで、MATLAB は各反復を特定の乱数の列に結合できるようになります。parfor によって、各反復にインデックスが与えられます。反復は、インデックスをサブストリーム番号として使用します。乱数がワーカーではなく反復に関連付けられているため、全体の計算が再現可能となります。

再現性のある結果を取得するには、ストリームをリセットします。そうするとすべてのサブストリームが再呼び出しが行われた場合にまったく同一な乱数を生成するようになります。この方法は、すべてのワーカーが同じストリームを使用している場合、かつストリームがサブストリームをサポートしている場合に使用できます。以上で、再現性のある並列計算を実行する の手順がどう並列計算の結果に再現性を与えるかの説明を終わります。

クライアントまたはワーカー上の乱数

乱数を並列ワーカーに分配する前にクライアント上で乱数を生成する関数がいくつかあります。ワーカーが乱数を使用しないため、純粋に確定的な動作を行います。これらの関数では、任意の乱数ストリーム タイプを使用して再現性のある並列計算が実行できます。

このように動作する関数には、次のような関数が挙げられます。

まったく同一の結果を取得するには、クライアント上の乱数ストリームをリセットするか、クライアントに引き渡す乱数ストリームをリセットします。以下に例を示します。

s = rng % Obtain the current state of the random stream
% run the statistical function
rng(s) % Reset the stream to the previous state
% run the statistical function again, obtain identical results

この方法では、並列で再現性のある実行が行える一方、結果は逐次計算の結果とは異なる結果となります。この差異は、for ループと逆の順序で parfor ループが実行されることに起因します。したがって、逐次計算は、並列計算とは異なる順番で乱数を生成する可能性があります。絶対的な再現性が必要な場合は、再現性のある並列計算を実行するにある方法を使用してください。

ストリームを明示的に分配する

特定の乱数アルゴリズムを使用したテストまたは比較では、乱数発生器を設定しなければなりません。これらの生成器を並列に設定する方法、特定の方法で各ワーカー上でストリームを初期化するにはどうしたらよいでしょうか。また、これまでに実行した乱数の列とは異なる乱数の列を使用して計算を実行する必要がある場合があるかもしれません。統計的に独立した列が使用されることを保証する方法には、どのような方法があるでしょうか。

Statistics and Machine Learning Toolbox の並列関数を使用すると、各ワーカー上でのストリームを明示的に設定できます。複数のストリームを "作成" する方法の詳細については、コマンド ラインで「help RandStream/create」と入力してください。'mrg32k3a' 生成器を使用して独立した 4 つのストリームを作成するには、次の手順を実行します。

s = RandStream.create('mrg32k3a','NumStreams',4,...
    'CellOutput',true);

Streams オプションを使用して、これらのストリームを統計関数に引き渡します。以下に例を示します。

parpool(4) % if you have at least 4 cores
s = RandStream.create('mrg32k3a','NumStreams',4,...
    'CellOutput',true); % create 4 independent streams
paroptions = statset('UseParallel',true,...
    'Streams',s); % set the 4 different streams
x = [randn(700,1); 4 + 2*randn(300,1)];
latt = -4:0.01:12;
myfun = @(X) ksdensity(X,latt); 
pdfestimate = myfun(x);
B = bootstrp(200,myfun,x,'Options',paroptions);

ストリームを分配するこの方法によって、それぞれのワーカーに計算用の別のストリームが与えられます。ただし、ワーカーが予期できない順番で 200 のブートストラップを実行するため、再現性のある計算はできません。再現性のある計算を実行するには、再現性のある並列計算を実行するで説明されているようにサブストリームを使用してください。

UseSubstreams オプションを true に設定し、Streams オプションをサブストリームをサポートするタイプの単一の乱数ストリーム ('mlfg6331_64' または 'mrg32k3a') に設定します。この設定によって、計算は再現性がある計算となります。