Main Content

GPU でのデータの解析とモデル化

この例では、グラフィックス処理装置 (GPU) でコードを実行することでパフォーマンスを改善する方法を示します。GPU で実行することによってパフォーマンスを改善できるのは次の場合です。

  • 計算量が多いコードで、計算時間が GPU メモリとの間でデータを転送する時間よりも大幅に長い。

  • ワークフローでgpuArray (Parallel Computing Toolbox)をサポートする関数と大規模な配列の入力を使用している。

GPU 用のコードを記述する際は、CPU で既に良好に動作するコードから始めます。GPU で高いパフォーマンスを実現するには、通常はベクトル化が重要になります。GPU 配列の引数をサポートする関数を使用して入力データを GPU に転送するようにコードを変換します。GPU 配列の入力を取る MATLAB 関数の詳細については、GPU での MATLAB 関数の実行 (Parallel Computing Toolbox)を参照してください。

Statistics and Machine Learning Toolbox™ の多くの関数は、GPU 配列の入力データを使用すると自動的に GPU で実行されます。たとえば、出力が GPU 配列である確率分布オブジェクトを GPU で作成できます。

pd = fitdist(gpuArray(x),"Normal")

GPU の使用には、Parallel Computing Toolbox™ およびサポートされている GPU デバイスが必要です。サポートされているデバイスの詳細については、GPU 計算の要件 (Parallel Computing Toolbox)を参照してください。GPU 配列を受け入れる Statistics and Machine Learning Toolbox™ の関数の完全な一覧については、関数を参照し、左側のナビゲーション バーで「拡張機能」のセクションまでスクロールして「GPU 配列」を選択してください。

GPU のプロパティの調査

関数 gpuDevice を使用して GPU デバイスのクエリと選択が可能です。GPU が複数ある場合は、関数 gpuDeviceTable を使用して、システムで検出されたすべての GPU のプロパティを調べることができます。その後、単一の GPU 実行に対する特定の GPU をインデックス (gpuDevice(index)) を使用して選択できます。

D = gpuDevice
D = 
  CUDADevice with properties:

                      Name: 'TITAN V'
                     Index: 1
         ComputeCapability: '7.0'
            SupportsDouble: 1
             DriverVersion: 11.2000
            ToolkitVersion: 11.2000
        MaxThreadsPerBlock: 1024
          MaxShmemPerBlock: 49152 (49.15 KB)
        MaxThreadBlockSize: [1024 1024 64]
               MaxGridSize: [2.1475e+09 65535 65535]
                 SIMDWidth: 32
               TotalMemory: 12652838912 (12.65 GB)
           AvailableMemory: 12096045056 (12.10 GB)
       MultiprocessorCount: 80
              ClockRateKHz: 1455000
               ComputeMode: 'Default'
      GPUOverlapsTransfers: 1
    KernelExecutionTimeout: 0
          CanMapHostMemory: 1
           DeviceSupported: 1
           DeviceAvailable: 1
            DeviceSelected: 1

GPU での関数の実行

記述統計を使用して GPU でのデータの分布を調べます。

GPU で正規分布の乱数のデータ セットを生成します。

dist = randn(6e4,6e3,"gpuArray");

dist が GPU 配列であるかどうかを判定します。

TF = isgpuarray(dist)
TF = logical
   1

GPU 配列の入力引数を使用して関数を実行します。たとえば、dist の各列の標本歪度を計算します。dist が GPU 配列であるため、関数 skewness は GPU で実行され、結果を GPU 配列として返します。

skew = skewness(dist);

出力 skew が GPU 配列であることを確認します。

TF = isgpuarray(skew)
TF = logical
   1

GPU 実行による高速化の評価

GPU での関数の実行時間を評価し、CPU で実行した場合とパフォーマンスを比較します。

CPU と GPU でコードの実行にかかる時間を比較すると、適切な実行環境を判断するのに役立つことがあります。たとえば、標本データから記述統計を計算する場合は、実行時間とデータ転送時間を検討することが全体的なパフォーマンスを評価する上で重要になります。GPU 配列をサポートする関数の場合、観測値の数が増えるほど、一般に CPU に比べて GPU の方が計算が向上します。

関数gputimeit (Parallel Computing Toolbox)を使用して関数の実行時間 (秒数) を測定します。GPU を使用する関数の場合、timeit よりも gputimeit の方が演算が確実に補完されてオーバーヘッドが補正されるため適しています。

skew = @() skewness(dist);
t = gputimeit(skew)
t = 0.2458

CPU での実行時間を別に測定し、GPU と CPU のパフォーマンスの違いを評価します。このケースでは、GPU の方が CPU よりもコードが高速になります。

GPU でのコードのパフォーマンスは、使用する GPU に大きく依存します。GPU のパフォーマンスの測定と改善の詳細については、GPU パフォーマンスの測定と向上 (Parallel Computing Toolbox)を参照してください。

GPU での単精度

倍精度ではなく単精度で計算することで、コードのパフォーマンスを改善できます。

単精度の dist データ セットの入力引数を使用して関数 skewness の実行時間を調べます。

dist_single = single(dist);
skew_single = @() skewness(dist_single);
t_single = gputimeit(skew_single)
t_single = 0.0503

このケースでは、単精度のデータでコードを実行した方が倍精度のデータで実行した場合よりも高速になります。

パフォーマンスの改善は GPU カードとコアの合計数に依存します。GPU での単精度の使用の詳細については、GPU パフォーマンスの測定と向上 (Parallel Computing Toolbox)を参照してください。

GPU での次元削減とモデルの当てはめ

GPU で次元削減と分類のワークフローを実装します。

pcafitcensembleなどの関数を一緒に使用して、機械学習モデルに学習させることができます。

  • 関数 pca (主成分分析) は、相関関係がある複数の変数を元の変数の線形結合である新しい一連の変数に置き換えることにより、データの次元を削減します。

  • 関数 fitcensemble は、複数の分類学習器を当てはめて、単一の学習器よりも優れた予測を可能にするアンサンブル モデルを形成します。

どちらの関数も計算量が多く、GPU を使用することで大幅に高速化できます。

たとえば、humanactivity データ セットについて考えてみます。データ セットには、人間の 5 種類の身体動作 (座る、立つ、歩く、走る、踊る) についての 24,075 個の観測値が含まれています。各観測値には、スマートフォンの加速度センサーによって測定された加速度データから抽出した 60 個の特徴量が含まれています。このデータ セットには、以下の変数が含まれています。

  • actid — 整数による行動 ID が格納されている応答ベクトル。1 ~ 5 はそれぞれ、座る、立つ、歩く、走る、踊る、を表します。

  • actnames — 整数の行動 ID に対応する行動名。

  • feat — 24,075 個の観測値に対する 60 個の特徴量が格納されている特徴量行列。

  • featlabels — 60 個の特徴量のラベル。

load humanactivity

5 種類の行動を分類するモデルの学習に観測値の 90% を使用し、学習済みモデルの検証に観測値の 10% を使用します。cvpartition を使用して、テスト セット用に 10% のホールドアウトを指定します。

Partition = cvpartition(actid,"Holdout",0.10);
trainingInds = training(Partition); % Indices for the training set
testInds = test(Partition); % Indices for the test set

学習データとテスト データを GPU に転送します。

XTrain = gpuArray(feat(trainingInds,:));
YTrain = gpuArray(actid(trainingInds));
XTest = gpuArray(feat(testInds,:));
YTest = gpuArray(actid(testInds));

学習データ セット XTrain の主成分を求めます。

[coeff,score,~,~,explained,mu] = pca(XTrain);

変動性の 99% 以上を説明するために必要な成分の個数を求めます。

idx = find(cumsum(explained)>99,1);

主成分空間における X を表す主成分スコアを判定します。

XTrainPCA = score(:,1:idx);

分類用に学習器のアンサンブルを当てはめます。

template = templateTree("MaxNumSplits",20,"Reproducible",true);
classificationEnsemble = fitcensemble(XTrainPCA,YTrain, ...
    "Method","AdaBoostM2", ...
    "NumLearningCycles",30, ...
    "Learners",template, ...
    "LearnRate",0.1, ...
    "ClassNames",[1; 2; 3; 4; 5]);

テスト セットに対して学習済みモデルを使用するには、学習データ セットから取得した PCA を使用して、テスト データ セットを変換する必要があります。

XTestPCA = (XTest-mu)*coeff(:,1:idx);

テスト データを使用して学習済み分類器の精度を評価します。

classificationError = loss(classificationEnsemble,XTestPCA,YTest);

ローカル ワークスペースへの転送

GPU 配列をサポートしない関数で使用するために、データやモデルのプロパティを GPU からローカル ワークスペースに転送します。

GPU 配列の転送にはコストがかかる場合があり、GPU 配列をサポートしない関数で結果を使用したり、GPU を利用できない別のワークスペースで結果を使用したりする必要がない限り、通常は必要ありません。

関数gather (Parallel Computing Toolbox)は、データを GPU からローカル ワークスペースに転送します。dist データを収集し、データが GPU 配列でなくなったことを確認します。

dist = gather(dist);
TF = isgpuarray(dist)
TF = logical
   0

関数gatherは、機械学習モデルのプロパティを GPU からローカル ワークスペースに転送します。classificationEnsemble モデルを収集し、前は GPU 配列だった X などのモデル プロパティが GPU 配列でなくなったことを確認します。

classificationEnsemble = gather(classificationEnsemble);
TF = isgpuarray(classificationEnsemble.X)
TF = logical
   0

参考

(Parallel Computing Toolbox) | (Parallel Computing Toolbox) | (Parallel Computing Toolbox)

関連するトピック