Main Content

여러 배치 크기에 대한 Intel 대상 플랫폼에서의 딥러닝 코드 생성

이 예제에서는 Intel® 프로세서에서 딥러닝을 사용하는 영상 분류 응용 프로그램의 코드를 codegen 명령을 사용하여 생성하는 방법을 보여줍니다. 생성된 코드는 Intel MKL-DNN(Math Kernel Library for Deep Neural Networks)을 사용합니다. 이 예제는 두 부분으로 구성됩니다.

  • 첫 번째 부분에서는 영상 배치를 입력값으로 받는 MEX 함수를 생성하는 방법을 보여줍니다.

  • 두 번째 부분에서는 영상 배치를 입력값으로 받는 실행 파일을 생성하는 방법을 보여줍니다.

선행 조건

  • Intel AVX2(Intel Advanced Vector Extensions 2) 명령을 지원하는 Intel 프로세서

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

  • 컴파일러 및 라이브러리 환경 변수. 지원되는 컴파일러 버전에 대한 자세한 내용은 지원되는 컴파일러를 참조하십시오. 환경 변수 설정에 대한 자세한 내용은 Prerequisites for Deep Learning with 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 함수 정의하기

이 예제는 Intel 데스크탑에서의 영상 분류를 보여주기 위해 DAG 신경망 ResNet-50을 사용합니다. MATLAB에서 사용 가능한 사전 훈련된 ResNet-50 모델은 Deep Learning Toolbox Model for ResNet-50 Network 지원 패키지의 일부입니다.

resnet_predict 함수는 ResNet-50 신경망을 영속 network 객체로 불러온 다음 입력값에 대해 예측을 수행합니다. 이 함수에 대한 후속 호출에서 이 영속 network 객체를 재사용합니다.

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 read 함수를 사용하여 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);

메모리에서 영속 network 객체를 지웁니다.

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 파일을 입력 인수로 받습니다. 함수는 분류 레이블을 읽어 들여서 셀형 배열을 채웁니다.

       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 신경망에 필요한 크기인 224×224×3으로 조정합니다.

       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++ 메인 함수를 만드는 대신 생성된 예제 C++ 메인 함수를 사용하려면 GenerateExampleMain 파라미터를 'GenerateCodeAndCompile'로 설정하십시오. 또한, 데스크탑 터미널에서 실행 파일을 실행할 때 openmp 라이브러리 종속성이 없도록 cfg.EnableOpenMP를 비활성화하십시오.

       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')

관련 항목