並列計算および GPU コンピューティングを使用した浅層ニューラル ネットワーク
メモ
深層学習では、並列計算および GPU が自動的にサポートされます。関数 trainnet を使用して、畳み込みニューラル ネットワーク (CNN、ConvNet) または長短期記憶ネットワーク (LSTM または BiLSTM ネットワーク) に学習させ、trainingOptions を使用して、実行環境 (CPU、GPU、マルチ GPU、並列) を選択できます。
並列または 1 つの GPU での学習には、Parallel Computing Toolbox™ が必要です。GPU および並列での深層学習の詳細については、Scale Up Deep Learning in Parallel, on GPUs, and in the Cloudを参照してください。
並列化のモード
ニューラル ネットワークは本質的に並列アルゴリズムです。マルチコア 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 では、前述の例のコードにある x や t などの任意のデータをサンプル全体で分割できます。x と t にサンプルがそれぞれ 1 つだけ含まれている場合、並列化は行われません。しかし、x と t に数百または数千のサンプルが含まれている場合、並列化には速度と問題のサイズの両面で利点があります。
分散コンピューティング
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 parallel pool with 6 workers.
parpool が実行されると、そのプールで使用可能なワーカーの数が表示されます。ワーカーの数を確認するもう 1 つの方法は、プールをクエリすることです。
pool.NumWorkers
4
これで、すべてのワーカーにわたってサンプルで分割したデータを使用して、ニューラル ネットワークの学習とシミュレーションを行えるようになりました。これを行うには、train と sim のパラメーター '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
train と sim が呼び出されると、学習とシミュレーションの前に、入力行列または 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 要件については、GPU 計算の要件 (Parallel Computing Toolbox)を参照してください。または、PC で GPU がサポートされているかどうかを判断するには、MATLAB にクエリしてください。次の関数はシステムに搭載されている GPU の数を返します。
count = gpuDeviceCount
count =
1結果が 1 つ以上ある場合、インデックスを使用して各 GPU の特性をクエリできます。これには、名前、コンピューティング能力、合計メモリ、使用可能なメモリなどが含まれます。
gpu1 = gpuDevice(1)
gpu1 =
CUDADevice with properties:
Name: 'NVIDIA RTX A5000'
Index: 1 (of 2)
ComputeCapability: '8.6'
DriverModel: 'TCC'
TotalMemory: 25544294400 (25.54 GB)
AvailableMemory: 25120866304 (25.12 GB)
DeviceAvailable: true
DeviceSelected: true
Show all properties.GPU を活用する最も簡単な方法は、train と sim をパラメーター引数 '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 上で実行されます。通常は、関数 gpuArray と gather を使用して、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 にわたって、またはクラスターで計算を実行できます。
これを簡単に行うには、使用するクラスター プロファイルで決定される並列プールを使用して、そうするように train と sim を指定します。この場合、想定するハードウェアが搭載されていることを確認するために、'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 番目のワーカーによって制限されることがあります。このような場合、train と sim で、固有の 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
ここで、train と sim で 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 を使用するタイミングが指定されるため、これを行うように train と sim に指定する必要はありません。
net2 = configure(net1,xc{1},tc{1});
net2 = train(net2,xc,tc,'showResources','yes');
yc = net2(xc,'showResources','yes');各 GPU が 1 つのワーカーのみで使用されるようにしてください。そうすることで、計算が最も効率的になります。複数のワーカーが gpuArray データを同じ GPU に割り当てている場合でも計算は実行されますが、GPU が複数のワーカーのデータを順番に処理するので、計算は遅くなります。
並列時系列
時系列ネットワークの場合、単純に x と t に対する 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 や、narxnet と narnet の開ループ バージョンなどのネットワークに当てはまります。ネットワークに層の遅延がある場合、時間は計算のために "フラット" にできないため、単一の時系列データを並列化することはできません。これは、layrecnet や、narxnet と narnet の閉ループ バージョンなどのネットワークに当てはまります。ただし、データが複数のシーケンスで構成されている場合は、個別のシーケンス全体で並列化できます。
並列の使用可能性、フォールバック、およびフィードバック
前述のように、使用可能な現在の並列リソースを検出するために 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 を使用します。
ハードウェアが実際に使用しているものがわからない場合は、gpuDeviceCount、gpuDevice、および pool.NumWorkers をチェックして、目的のハードウェアが使用できることを確認してから、train と sim を、'showResources' を 'yes' に設定して呼び出し、実際に使用されているリソースを確認してください。