Main Content

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

並列計算および GPU コンピューティングを使用した浅層ニューラル ネットワーク

メモ

深層学習では、並列計算および GPU が自動的にサポートされます。関数 trainnet および関数 trainNetwork を使用して、畳み込みニューラル ネットワーク (CNN、ConvNet) または長短期記憶ネットワーク (LSTM または BiLSTM ネットワーク) に学習させ、trainingOptions を使用して、実行環境 (CPU、GPU、マルチ GPU、並列) を選択できます。

並列または 1 つの GPU での学習には、Parallel Computing Toolbox™ が必要です。マルチ GPU および並列での深層学習の詳細は、CPU、GPU、並列、およびクラウドでのビッグ データを使用した深層学習を参照してください。

並列化のモード

ニューラル ネットワークは本質的に並列アルゴリズムです。マルチコア CPU、グラフィックス処理装置 (GPU)、および複数の CPU と GPU を使用したコンピューターのクラスターでは、この並列化の利点を活かすことができます。

Parallel Computing Toolbox では、Deep Learning Toolbox™ と併用することで、ニューラル ネットワークの学習とシミュレーションで並列化の各モードを活用できます。

例として、以下に標準のシングルスレッドの学習およびシミュレーション セッションを示します。

[x, t] = bodyfat_dataset;
net1 = feedforwardnet(10);
net2 = train(net1, x, t);
y = net2(x);

このセッションで並列化できる 2 つのステップは、train の呼び出しと、(ネットワーク net2 を関数として呼び出すところでの) sim の暗黙的な呼び出しです。

Deep Learning Toolbox では、前述の例のコードにある xt などの任意のデータを標本全体で分割できます。xt に標本がそれぞれ 1 つだけ含まれている場合、並列化は行われません。しかし、xt に数百または数千の標本が含まれている場合、並列化には速度と問題のサイズの両面で利点があります。

分散コンピューティング

Parallel Computing Toolbox では、MATLAB® Parallel Server™ を使用して、ニューラル ネットワークの学習とシミュレーションを 1 台の PC の複数の CPU コアにわたって、またはネットワーク上の複数のコンピューターの複数の CPU にわたって実行できます。

複数のコアを使用することで、計算を高速化できます。複数のコンピューターを使用すると、大きすぎて 1 台のコンピューターの RAM に収まらないデータセットを使用して問題を解くことができます。問題のサイズを制限するのは、すべてのコンピューターの使用可能な RAM の合計容量だけです。

クラスター構成を管理するには、MATLAB の [ホーム] タブの [環境] メニューにある [並列][クラスター プロファイルの管理] から、クラスター プロファイル マネージャーを使用します。

既定のクラスター プロファイル (通常はローカル CPU コア) を使用して MATLAB ワーカーのプールを開くには、次のコマンドを使用します。

pool = parpool
Starting parallel pool (parpool) using the 'Processes' profile ... connected to 4 workers.

parpool が実行されると、そのプールで使用可能なワーカーの数が表示されます。ワーカーの数を確認するもう 1 つの方法は、プールをクエリすることです。

pool.NumWorkers
   4

これで、すべてのワーカーにわたって標本で分割したデータを使用して、ニューラル ネットワークの学習とシミュレーションを行えるようになりました。これを行うには、trainsim のパラメーター 'useParallel''yes' に設定します。

net2 = train(net1,x,t,'useParallel','yes')
y = net2(x,'useParallel','yes')

引数 'showResources' を使用して、計算が複数のワーカーにわたって実行されたことを確認します。

net2 = train(net1,x,t,'useParallel','yes','showResources','yes');
y = net2(x,'useParallel','yes','showResources','yes');

MATLAB には使用されたリソースが示されます。次に例を示します。

Computing Resources:
Parallel Workers
  Worker 1 on MyComputer, MEX on PCWIN64
  Worker 2 on MyComputer, MEX on PCWIN64
  Worker 3 on MyComputer, MEX on PCWIN64
  Worker 4 on MyComputer, MEX on PCWIN64

trainsim が呼び出されると、学習とシミュレーションの前に、入力行列または cell 配列データが分散 Composite 値に分割されます。sim で Composite が計算されると、この出力は同じ行列または cell 配列の形式に変換されてから返されます。

ただし、以下の場合にこのデータ分割を手動で行う必要がある場合もあります。

  • 問題のサイズがホスト コンピューターに対して大きすぎる。Composite 値の要素を順に手動で定義すると、非常に大きな問題を定義できます。

  • 一部のワーカーが他のコンピューターよりも高速なコンピューターまたは大容量のメモリがあるコンピューターにあることがわかっている。ワーカーあたりの標本数を変えて、データを分散させることができます。これは、負荷分散と呼ばれます。

次のコードは、一連のランダム データセットを順に作成し、個別のファイルに保存します。

pool = gcp;
for i=1:pool.NumWorkers
  x = rand(2,1000);
  save(['inputs' num2str(i)],'x');
  t = x(1,:) .* x(2,:) + 2 * (x(1,:) + x(2,:));
  save(['targets' num2str(i)],'t');
  clear x t
end

データが順に定義されるため、ホストの PC メモリに収まるサイズよりも合計が大きなデータセットを定義できます。PC メモリには一度に 1 つのサブデータセットのみを格納しなければなりません。

これで、並列ワーカーにわたってデータセットを順に読み込み、Composite データでネットワークの学習とシミュレーションを行えるようになりました。Composite データを使用して train または sim を呼び出す場合、引数 'useParallel' が自動的に 'yes' に設定されます。Composite データを使用する場合、学習の前に、関数 configure を使用して、データセットのいずれかと一致するようにネットワークの入力と出力を手動で構成してください。

xc = Composite;
tc = Composite;
for i=1:pool.NumWorkers
  data = load(['inputs' num2str(i)],'x');
  xc{i} = data.x;
  data = load(['targets' num2str(i)],'t');
  tc{i} = data.t;
  clear data
end
net2 = configure(net1,xc{1},tc{1});
net2 = train(net2,xc,tc);
yc = net2(xc);

sim で返される Composite 出力を変換するために、メモリ制限を考慮する必要がある場合は、各要素に個別にアクセスできます。

for i=1:pool.NumWorkers
  yi = yc{i}
end

メモリ制限を考慮する必要がない場合は、Composite 値を 1 つのローカル値にまとめます。

y = {yc{:}};

負荷分散を行う場合、同じプロセスが行われますが、各データセットの標本の数 (上記の例では 1000) を同じにするのではなく、ワーカー ホスト コンピューターのメモリと速度の違いを最大限に活かせるように標本の数を調整できます。

各ワーカーに必ずしもデータを割り当てる必要はありません。Composite の要素 i が未定義の場合、ワーカー i は計算には使用されません。

単一 GPU コンピューティング

GPU カードのコアの数、メモリのサイズ、速度効率は新しい世代ごとに急速に増加しています。ビデオ ゲームは長きにわたり GPU 性能の向上による恩恵を受けていますが、現在これらのカードは、ニューラル ネットワークの学習などの一般的な数値計算を実行できるほどに柔軟になりました。

最新の GPU 要件については、Parallel Computing Toolbox の Web ページを参照してください。または、PC で GPU がサポートされているかどうかを判断するには、MATLAB にクエリしてください。次の関数はシステムに搭載されている GPU の数を返します。

count = gpuDeviceCount
count =

    1

結果が 1 つ以上ある場合、インデックスを使用して各 GPU の特性をクエリできます。これには、名前、マルチプロセッサの数、各マルチプロセッサの SIMDWidth、合計メモリが含まれます。

gpu1 = gpuDevice(1)
gpu1 = 

  CUDADevice with properties:

                      Name: 'NVIDIA RTX A5000'
                     Index: 1
         ComputeCapability: '8.6'
            SupportsDouble: 1
             DriverVersion: 11.6000
            ToolkitVersion: 11.2000
        MaxThreadsPerBlock: 1024
          MaxShmemPerBlock: 49152 (49.15 KB)
        MaxThreadBlockSize: [1024 1024 64]
               MaxGridSize: [2.1475e+09 65535 65535]
                 SIMDWidth: 32
               TotalMemory: 25553076224 (25.55 GB)
           AvailableMemory: 25153765376 (25.15 GB)
       MultiprocessorCount: 64
              ClockRateKHz: 1695000
               ComputeMode: 'Default'
      GPUOverlapsTransfers: 1
    KernelExecutionTimeout: 0
          CanMapHostMemory: 1
           DeviceSupported: 1
           DeviceAvailable: 1
            DeviceSelected: 1

GPU を活用する最も簡単な方法は、trainsim をパラメーター引数 'useGPU''yes' (既定は 'no') に設定して呼び出すことです。

net2 = train(net1,x,t,'useGPU','yes')
y = net2(x,'useGPU','yes')

net1 の学習関数が既定の trainlm である場合、GPU 計算はヤコビアンによる学習をサポートしておらず、勾配による学習のみをサポートしていることを示す警告が表示されます。そして、学習関数は勾配学習関数 trainscg に自動的に変更されます。通知を回避するには、学習の前にこの関数を指定します。

net1.trainFcn = 'trainscg';

学習とシミュレーションが GPU デバイスで行われていることを確認するには、コンピューター リソースを表示するよう要求します。

net2 = train(net1,x,t,'useGPU','yes','showResources','yes')
y = net2(x,'useGPU','yes','showResources','yes')

上記のコードの各行によって、以下のリソース概要が出力されます。

Computing Resources:
GPU device #1, GeForce GTX 470

入力引数のいずれかが gpuArray の場合、MATLAB の多くの関数は自動的に GPU で実行されます。通常は、関数 gpuArraygather を使用して、GPU との間で配列をやり取りします。ただし、ニューラル ネットワークの計算を GPU で効率的に行うためには、行列を転置して、各列の最初の要素が GPU メモリに適切に合うように列をパディングする必要があります。Deep Learning Toolbox には、配列を GPU に移動して適切に整理するために、nndata2gpu という特殊関数が用意されています。

xg = nndata2gpu(x);
tg = nndata2gpu(t);

これで、引数 'useGPU' を指定することなく、既に GPU にある変換済みデータを使用してネットワークの学習とシミュレーションを行えるようになりました。次に、相補関数 gpu2nndata を使用して、結果の GPU 配列を変換し、MATLAB に返します。

gpuArray データで学習させる前に、関数 configure を使用して、手動でネットワークの入力と出力を通常の MATLAB 行列で構成しなければなりません。

net2 = configure(net1,x,t);  % Configure with MATLAB arrays
net2 = train(net2,xg,tg);    % Execute on GPU with NNET formatted gpuArrays
yg = net2(xg);               % Execute on GPU
y = gpu2nndata(yg);          % Transfer array to local workspace

GPU や、ニューラル ネットワークを展開するその他のハードウェアでは多くの場合、指数関数 exp がハードウェアで実装されておらず、ソフトウェア ライブラリで実装されています。この場合、シグモイド伝達関数 tansig を使用するニューラル ネットワークの計算が遅くなることがあります。代替となる関数は、式に高次の関数の呼び出しが一切含まれない Elliot シグモイド関数です。

(equation)	a = n / (1 + abs(n))

学習の前に、ネットワークの tansig 層を、次のように elliotsig 層に変換できます。

for i=1:net.numLayers
  if strcmp(net.layers{i}.transferFcn,'tansig')
    net.layers{i}.transferFcn = 'elliotsig';
  end
end

これにより、GPU やシンプルな展開ハードウェアでの学習とシミュレーションが高速になる可能性があります。

分散 GPU コンピューティング

MATLAB Parallel Server を使用して、分散コンピューティングと GPU コンピューティングを組み合わせて、1 台のコンピューター上の複数の CPU や複数の GPU にわたって、またはクラスターで計算を実行できます。

これを簡単に行うには、使用するクラスター プロファイルで決定される並列プールを使用して、そうするように trainsim を指定します。この場合、想定するハードウェアが搭載されていることを確認するために、'showResources' オプションを使用することを特に推奨します。

net2 = train(net1,x,t,'useParallel','yes','useGPU','yes','showResources','yes')
y = net2(x,'useParallel','yes','useGPU','yes','showResources','yes')

これらのコード行では、並列プールで使用可能なワーカーをすべて使用します。各固有の GPU に対して 1 つのワーカーがその GPU を使用し、それ以外のワーカーは CPU として動作します。場合によっては、GPU のみを使用する方が高速になることがあります。たとえば、1 台のコンピューターに 3 つの GPU が搭載されており、全部で 4 つのワーカーがある場合、3 つの GPU で高速化されている 3 つのワーカーの速度が、CPU を使用する 4 番目のワーカーによって制限されることがあります。このような場合、trainsim で、固有の GPU を持つワーカーのみを使用するように指定できます。

net2 = train(net1,x,t,'useParallel','yes','useGPU','only','showResources','yes')
y = net2(x,'useParallel','yes','useGPU','only','showResources','yes')

シンプルな分散コンピューティングと同様に、分散 GPU コンピューティングでは手動で作成した Composite 値によるメリットが得られます。Composite 値を定義すると、使用するワーカー、各ワーカーに割り当てる標本の数、GPU を使用するワーカーを指定できます。

たとえば、4 つのワーカーがあり、GPU が 3 つしかない場合、GPU を使用するワーカーに対して、より大きなデータセットを定義できます。ここでは、Composite の要素ごとに異なる標本を読み込んでランダム データセットを作成しています。

numSamples = [1000 1000 1000 300];
xc = Composite;
tc = Composite;
for i=1:4
  xi = rand(2,numSamples(i));
  ti = xi(1,:).^2 + 3*xi(2,:);
  xc{i} = xi;
  tc{i} = ti;
end

ここで、trainsim で 3 つの使用可能な GPU を使用するように指定できます。

net2 = configure(net1,xc{1},tc{1});
net2 = train(net2,xc,tc,'useGPU','yes','showResources','yes');
yc = net2(xc,'showResources','yes');

最初の 3 つのワーカーが確実に GPU を使用するようにするため、各ワーカーの Composite 要素を gpuArray に変換します。各ワーカーはこの変換を、並列に実行される spmd ブロック内で行います。

spmd
  if spmdIndex <= 3
    xc = nndata2gpu(xc);
    tc = nndata2gpu(tc);
  end
end

ここで、データによって GPU を使用するタイミングが指定されるため、これを行うように trainsim に指定する必要はありません。

net2 = configure(net1,xc{1},tc{1});
net2 = train(net2,xc,tc,'showResources','yes');
yc = net2(xc,'showResources','yes');

各 GPU が 1 つのワーカーのみで使用されるようにしてください。そうすることで、計算が最も効率的になります。複数のワーカーが gpuArray データを同じ GPU に割り当てている場合でも計算は実行されますが、GPU は複数のワーカーのデータを順番に処理するので、計算が遅くなります。

並列時系列

時系列ネットワークの場合、単純に xt に対する cell 配列値を使用し、必要に応じて初期の入力遅延状態 xi と層遅延の初期状態 ai をオプションで含めます。

net2 = train(net1,x,t,xi,ai,'useGPU','yes')
y = net2(x,xi,ai,'useParallel','yes','useGPU','yes')

net2 = train(net1,x,t,xi,ai,'useParallel','yes')
y = net2(x,xi,ai,'useParallel','yes','useGPU','only')

net2 = train(net1,x,t,xi,ai,'useParallel','yes','useGPU','only')
y = net2(x,xi,ai,'useParallel','yes','useGPU','only')

並列化は標本全体で行われます。時系列の場合は、異なる系列をまたいで行われます。ただし、ネットワークに入力の遅延のみがあり、層の遅延がない場合は、遅延入力を事前に計算できるので、計算のためにタイム ステップを異なる標本にして並列化できます。これは、timedelaynet や、narxnetnarnet の開ループ バージョンなどのネットワークに当てはまります。ネットワークに層の遅延がある場合、時間は計算のために "フラット" にできないため、単一の時系列データを並列化することはできません。これは、layrecnet や、narxnetnarnet の閉ループ バージョンなどのネットワークに当てはまります。ただし、データが複数のシーケンスで構成されている場合は、個別のシーケンス全体で並列化できます。

並列の使用可能性、フォールバック、およびフィードバック

前述のように、使用可能な現在の並列リソースを検出するために MATLAB にクエリできます。

ホスト コンピューターで使用可能な GPU を確認するには、以下のようにします。

gpuCount = gpuDeviceCount
for i=1:gpuCount
  gpuDevice(i)
end

現在の並列プールで実行中のワーカーの数を確認するには、以下のようにします。

poolSize = pool.NumWorkers

MATLAB Parallel Server を使用した PC クラスターで実行されている並列プール全体で使用可能な GPU を確認するには、以下のようにします。

spmd
  worker.index = spmdIndex;
  worker.name = system('hostname');
  worker.gpuCount = gpuDeviceCount;
  try
    worker.gpuInfo = gpuDevice;
  catch
    worker.gpuInfo = [];
  end
  worker
end

'useParallel' または 'useGPU''yes' に設定されているのに、並列または GPU のワーカーを使用できない場合、原則ではリソースが要求されたときに使用可能であれば使用されます。使用できない場合でも、計算はエラーなく実行されます。要求したリソースから実際のリソースへのフォールバックのプロセスは、次のように行われます。

  • 'useParallel''yes' であるが Parallel Computing Toolbox を使用できない場合、または並列プールが開いていない場合、計算はシングルスレッド MATLAB に戻ります。

  • 'useGPU''yes' であるが現在の MATLAB セッションに対して gpuDevice が割り当てられていない場合、またはサポートされていない場合、計算は CPU に戻ります。

  • 'useParallel''useGPU''yes' である場合、固有の GPU を持つワーカーはそれぞれの GPU を使用し、他のワーカーは CPU に戻ります。

  • 'useParallel''yes' であり、'useGPU''only' である場合、固有の GPU を持つワーカーが使用されます。どのワーカーにも GPU がない場合を除き、他のワーカーは使用されません。GPU がない場合、すべてのワーカーが CPU を使用します。

ハードウェアが実際に使用しているものがわからない場合は、gpuDeviceCountgpuDevice、および pool.NumWorkers をチェックして、目的のハードウェアが使用できることを確認してから、trainsim を、'showResources''yes' に設定して呼び出し、実際に使用されているリソースを確認してください。