Main Content

このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。

Intel ターゲットでのさまざまなバッチ サイズの深層学習コードの生成

この例では、codegen コマンドを使用して、Intel® プロセッサでの深層学習を使用するイメージ分類用途のコードを生成する方法を説明します。生成されたコードは、Intel Math Kernel Library for Deep Neural Networks (MKL-DNN) を使用します。この例は、次の 2 つの部分で構成されます。

  • 最初の部分では、イメージのバッチを入力として受け入れる MEX 関数を生成する方法を示します。

  • 2 番目の部分では、イメージのバッチを入力として受け入れる実行可能ファイルを生成する方法を示します。

必要条件

  • Intel Advanced Vector Extensions 2 (Intel AVX2) 命令をサポートする Intel プロセッサ

  • Intel Math Kernel Library for Deep Neural Networks (MKL-DNN)

  • コンパイラおよびライブラリの環境変数。サポートされているコンパイラのバージョンの詳細については、サポートされるコンパイラを参照してください。環境変数の設定は、MATLAB Coder を使用した深層学習の前提条件 (MATLAB Coder)を参照してください。

この例は、Linux®、Windows®、および Mac® プラットフォームでサポートされていますが、MATLAB Online ではサポートされていません。

入力ビデオ ファイルのダウンロード

サンプル ビデオ ファイルをダウンロードします。

   if ~exist('./object_class.avi', 'file')
       url = 'https://www.mathworks.com/supportfiles/gpucoder/media/object_class.avi.zip';
       websave('object_class.avi.zip',url);
       unzip('object_class.avi.zip');
   end

関数 resnet_predict の定義

この例では、DAG ネットワーク ResNet-50 を使用して、Intel デスクトップでイメージの分類を表示します。MATLAB 用の事前学習済み ResNet-50 モデルは、Deep Learning Toolbox Model for ResNet-50 Network サポート パッケージに含まれています。

関数 resnet_predict は、ResNet-50 ネットワークを永続ネットワーク オブジェクトに読み込んだ後、入力に対して予測を実行します。関数のそれ以降の呼び出しでは、この永続オブジェクトが再利用されます。

type resnet_predict
% Copyright 2020 The MathWorks, Inc.

function out = resnet_predict(in) 
%#codegen

% A persistent object mynet is used to load the series network object.
% At the first call to this function, the persistent object is constructed and
% setup. When the function is called subsequent times, the same object is reused 
% to call predict on inputs, avoiding reconstructing and reloading the
% network object.

persistent mynet;

if isempty(mynet)
    % Call the function resnet50 that returns a DAG network
    % for ResNet-50 model.
    mynet = coder.loadDeepLearningNetwork('resnet50','resnet');
end

% pass in input   
out = mynet.predict(in);

resnet_predict 用の MEX 生成

関数 resnet_predict 用に MEX 関数を生成するために、MKL-DNN ライブラリ用の深層学習構成オブジェクトを指定して codegen を使用します。codegen に渡す MEX コード生成構成オブジェクトに深層学習構成オブジェクトを追加します。codegen コマンドを実行し、サイズ [224,224,3,|batchSize|] の 4 次元行列を入力として指定します。この値は ResNet-50 ネットワークの入力層サイズに対応します。

    batchSize = 5;
    cfg = coder.config('mex');
    cfg.TargetLang = 'C++';
    cfg.DeepLearningConfig = coder.DeepLearningConfig('mkldnn');
    codegen -config cfg resnet_predict -args {ones(224,224,3,batchSize,'single')} -report
Code generation successful: To view the report, open('codegen\mex\resnet_predict\html\report.mldatx').

イメージのバッチでの予測の実行

Object_class.avi ビデオ ファイルが既にダウンロードされていると仮定します。videoReader 読み取り関数を使用して videoReader オブジェクトを作成し、5 フレームを読み取ります。batchSize が 5 に設定されているため、5 つのイメージが読み取られます。入力イメージのバッチのサイズを、resnet50 に必要なサイズ (ResNet50 ネットワークで期待されるサイズ) に変更します。

   videoReader = VideoReader('Object_class.avi');
   imBatch = read(videoReader,[1 5]);
   imBatch = imresize(imBatch, [224,224]);

生成された関数 resnet_predict_mex を呼び出します。この関数は、指定した入力についての分類結果を出力します。

   predict_scores = resnet_predict_mex(single(imBatch));

バッチ内の各イメージについて、上位 5 つの確率スコアおよびそのラベルを取得します。

   [val,indx] = sort(transpose(predict_scores), 'descend');
   scores = val(1:5,:)*100;
   net = resnet50;
   classnames = net.Layers(end).ClassNames;
   for i = 1:batchSize
       labels = classnames(indx(1:5,i));
       disp(['Top 5 predictions on image, ', num2str(i)]);
       for j=1:5
           disp([labels{j},' ',num2str(scores(j,i), '%2.2f'),'%'])
       end
   end

最初のイメージの予測について、上位 5 つの予測スコアを synset ディクショナリの単語にマッピングします。

   fid = fopen('synsetWords.txt');
   synsetOut = textscan(fid,'%s', 'delimiter', '\n');
   synsetOut = synsetOut{1};
   fclose(fid);
   [val,indx] = sort(transpose(predict_scores), 'descend');
   scores = val(1:5,1)*100;
   top5labels = synsetOut(indx(1:5,1));

イメージ上に上位 5 つの分類ラベルを表示します。

   outputImage = zeros(224,400,3, 'uint8');
   for k = 1:3
       outputImage(:,177:end,k) = imBatch(:,:,k,1);
   end
   scol = 1;
   srow = 1;
   outputImage = insertText(outputImage, [scol, srow], 'Classification with ResNet-50', 'TextColor', 'w','FontSize',20, 'BoxColor', 'black');
   srow = srow + 30;
   for k = 1:5
       outputImage = insertText(outputImage, [scol, srow], [top5labels{k},' ',num2str(scores(k), '%2.2f'),'%'], 'TextColor', 'w','FontSize',15, 'BoxColor', 'black');
       srow = srow + 25;
   end
   imshow(outputImage);

永続ネットワーク オブジェクトをメモリからクリアします。

clear mex;

エントリポイント関数 resnet_predict_exe の定義

MATLAB コードから実行可能ファイルを生成するには、新しいエントリポイント関数 resnet_predict_exe を定義します。この関数は、前のエントリポイント関数 resent_predict に似ていますが、加えて前処理と後処理のコードが含まれています。resnet_predict_exe で使用する API は、プラットフォームに依存しません。この関数は、ビデオとバッチ サイズを入力引数として受け入れます。これらの引数はコンパイル時の定数です。

type resnet_predict_exe
% Copyright 2020 The MathWorks, Inc.

function resnet_predict_exe(inputVideo,batchSize) 
%#codegen

    % A persistent object mynet is used to load the series network object.
    % At the first call to this function, the persistent object is constructed and
    % setup. When the function is called subsequent times, the same object is reused 
    % to call predict on inputs, avoiding reconstructing and reloading the
    % network object.
    persistent mynet;

    if isempty(mynet)
        % Call the function resnet50 that returns a DAG network
        % for ResNet-50 model.
        mynet = coder.loadDeepLearningNetwork('resnet50','resnet');
    end

    % Create video reader and video player objects %
    videoReader = VideoReader(inputVideo);
    depVideoPlayer = vision.DeployableVideoPlayer;


    % Read the classification label names %
    synsetOut = readImageClassLabels('synsetWords.txt');

    i=1;
    % Read frames until end of video file %
    while ~(i+batchSize > (videoReader.NumFrames+1))
        % Read and resize batch of frames as specified by input argument%
        reSizedImagesBatch = readImageInputBatch(videoReader,batchSize,i);

        % run predict on resized input images %
        predict_scores = mynet.predict(reSizedImagesBatch);


        % overlay the prediction scores on images and display %
        overlayResultsOnImages(predict_scores,synsetOut,reSizedImagesBatch,batchSize,depVideoPlayer)

        i = i+ batchSize; 
    end
    release(depVideoPlayer);
end

function synsetOut = readImageClassLabels(classLabelsFile)
% Read the classification label names from the file 
%
% Inputs : 
% classLabelsFile - supplied by user
%
% Outputs : 
% synsetOut       - cell array filled with 1000 image class labels

    synsetOut = cell(1000,1);
    fid = fopen(classLabelsFile);
    for i = 1:1000
        synsetOut{i} = fgetl(fid);
    end
    fclose(fid);
end

function reSizedImagesBatch = readImageInputBatch(videoReader,batchSize,i)
% Read and resize batch of frames as specified by input argument%
%
% Inputs : 
% videoReader - Object used for reading the images from video file
% batchSize   - Number of images in batch to process. Supplied by user
% i           - index to track frames read from video file
%
% Outputs : 
% reSizedImagesBatch - Batch of images resized to 224x224x3xbatchsize

    img = read(videoReader,[i (i+batchSize-1)]);
    reSizedImagesBatch = coder.nullcopy(ones(224,224,3,batchSize,'like',img));
    resizeTo  = coder.const([224,224]);
    reSizedImagesBatch(:,:,:,:) = imresize(img,resizeTo);
end


function overlayResultsOnImages(predict_scores,synsetOut,reSizedImagesBatch,batchSize,depVideoPlayer)
% Read and resize batch of frames as specified by input argument%
%
% Inputs : 
% predict_scores  - classification results for given network
% synsetOut       - cell array filled with 1000 image class labels
% reSizedImagesBatch - Batch of images resized to 224x224x3xbatchsize
% batchSize       - Number of images in batch to process. Supplied by user
% depVideoPlayer  - Object for displaying results
%
% Outputs : 
% Predicted results overlayed on input images

    % sort the predicted scores  %
    [val,indx] = sort(transpose(predict_scores), 'descend');

    for j = 1:batchSize
        scores = val(1:5,j)*100;
        outputImage = zeros(224,400,3, 'uint8');
        for k = 1:3
            outputImage(:,177:end,k) = reSizedImagesBatch(:,:,k,j);
        end

        % Overlay the results on image %
        scol = 1;
        srow = 1;
        outputImage = insertText(outputImage, [scol, srow], 'Classification with ResNet-50', 'TextColor', [255 255 255],'FontSize',20, 'BoxColor', [0 0 0]);
        srow = srow + 30;
        for k = 1:5
            scoreStr = sprintf('%2.2f',scores(k));
            outputImage = insertText(outputImage, [scol, srow], [synsetOut{indx(k,j)},' ',scoreStr,'%'], 'TextColor', [255 255 255],'FontSize',15, 'BoxColor', [0 0 0]);
            srow = srow + 25;
        end
    
        depVideoPlayer(outputImage);
    end
end


関数 resnet_predict_exe の構造

関数 resnet_predict_exe には、次のアクションを実行する 4 つのサブセクションが含まれています。

  • 指定された入力テキスト ファイルから分類ラベルを読み取る

  • イメージの入力バッチを読み取り、ネットワークの必要に応じてサイズを変更する

  • 入力イメージ バッチで推論を実行する

  • 結果をイメージに重ね合わせる

これらの各手順の詳細については、後続の節を参照してください。

関数 readImageClassLabels

この関数は、synsetWords.txt ファイルを入力引数として受け入れます。分類ラベルを読み取り、cell 配列を挿入します。

       function synsetOut = readImageClassLabels(classLabelsFile)
       % Read the classification label names from the file
       %
       % Inputs :
       % classLabelsFile - supplied by user
       %
       % Outputs :
       % synsetOut       - cell array filled with 1000 image class labels
           synsetOut = cell(1000,1);
           fid = fopen(classLabelsFile);
           for i = 1:1000
               synsetOut{i} = fgetl(fid);
           end
           fclose(fid);
       end

関数 readImageInputBatch

この関数は、入力引数として関数に渡されるビデオ入力ファイルからイメージを読み取り、サイズを変更します。指定された入力イメージを読み取り、resnet50 ネットワークのサイズである 224x224x3 にサイズを変更します。

       function reSizedImagesBatch = readImageInputBatch(videoReader,batchSize,i)
       % Read and resize batch of frames as specified by input argument%
       %
       % Inputs :
       % videoReader - Object used for reading the images from video file
       % batchSize   - Number of images in batch to process. Supplied by user
       % i           - index to track frames read from video file
       %
       % Outputs :
       % reSizedImagesBatch - Batch of images resized to 224x224x3xbatchsize
           img = read(videoReader,[i (i+batchSize-1)]);
           reSizedImagesBatch = coder.nullcopy(ones(224,224,3,batchSize,'like',img));
           resizeTo  = coder.const([224,224]);
           reSizedImagesBatch(:,:,:,:) = imresize(img,resizeTo);
       end

関数 mynet.predict

この関数は、サイズ変更されたイメージのバッチを入力として受け入れ、予測結果を返します。

      % run predict on resized input images %
      predict_scores = mynet.predict(reSizedImagesBatch);

関数 overlayResultsOnImages

この関数は、予測結果を受け入れ、降順に並べ替えます。これらの結果を入力イメージに重ねて合わせて表示します。

       function overlayResultsOnImages(predict_scores,synsetOut,reSizedImagesBatch,batchSize,depVideoPlayer)
       % Read and resize batch of frames as specified by input argument%
       %
       % Inputs :
       % predict_scores  - classification results for given network
       % synsetOut       - cell array filled with 1000 image class labels
       % reSizedImagesBatch - Batch of images resized to 224x224x3xbatchsize
       % batchSize       - Number of images in batch to process. Supplied by user
       % depVideoPlayer  - Object for displaying results
       %
       % Outputs :
       % Predicted results overlayed on input images
           % sort the predicted scores  %
           [val,indx] = sort(transpose(predict_scores), 'descend');
           for j = 1:batchSize
               scores = val(1:5,j)*100;
               outputImage = zeros(224,400,3, 'uint8');
               for k = 1:3
                   outputImage(:,177:end,k) = reSizedImagesBatch(:,:,k,j);
               end
               % Overlay the results on image %
               scol = 1;
               srow = 1;
               outputImage = insertText(outputImage, [scol, srow], 'Classification with ResNet-50', 'TextColor', [255 255 255],'FontSize',20, 'BoxColor', [0 0 0]);
               srow = srow + 30;
               for k = 1:5
                   scoreStr = sprintf('%2.2f',scores(k));
                   outputImage = insertText(outputImage, [scol, srow], [synsetOut{indx(k,j)},' ',scoreStr,'%'], 'TextColor', [255 255 255],'FontSize',15, 'BoxColor', [0 0 0]);
                   srow = srow + 25;
               end
               depVideoPlayer(outputImage);
           end
       end

実行可能ファイルのビルドと実行

実行可能ファイルを生成するために、コード構成オブジェクトを作成します。深層学習構成オブジェクトを追加します。変数 batchSize と変数 inputVideoFile を設定します。

カスタムの C++ main 関数を作成せず、代わりに、生成されたサンプルの C++ main 関数を使用する場合は、GenerateExampleMain パラメーターを 'GenerateCodeAndCompile' に設定します。また、デスクトップ ターミナルから実行可能ファイルを実行するときに、cfg.EnableOpenMP を無効にし、openmp ライブラリの依存関係がないことを確認してください。

       cfg = coder.config('exe');
       cfg.TargetLang = 'C++';
       cfg.DeepLearningConfig = coder.DeepLearningConfig('mkldnn');
       batchSize = 5;
       inputVideoFile = 'object_class.avi';
       cfg.GenerateExampleMain = 'GenerateCodeAndCompile';
       cfg.EnableOpenMP = 0;

codegen コマンドを実行し、実行可能ファイルをビルドします。生成された実行可能ファイル resnet_predict_exe を、MATLAB コマンド ラインまたはデスクトップ ターミナルで実行します。

       codegen -config cfg resnet_predict_exe -args {coder.Constant(inputVideoFile), coder.Constant(batchSize)} -report
       system('./resnet_predict_exe')

関連するトピック