ドキュメンテーション

最新のリリースでは、このページがまだ翻訳されていません。 このページの最新版は英語でご覧になれます。

イメージ分類用のコードの生成

この例では、学習済み分類モデルを使用して数字のイメージを分類する MATLAB 関数から C コードを生成する方法を示します。この例では、HOG 特徴を使用した数字の分類 (Computer Vision Toolbox)に代わるワークフローを示します。ただし、この例のコード生成手順に従えば、上記の例におけるコード生成をサポートできます。

自動化されたイメージ分類は、どこにでもあるツールです。たとえば、学習済みの分類器は、撮影した映像で地上の異常を自動的に識別するためにドローンに配備したり、手紙に書かれている手書きの郵便番号をスキャンする機械に装備できます。後者の例では、機械が郵便番号を見つけて個々の数字のイメージを格納した後で、装備された分類器は郵便番号を再構成するためにどの数字がイメージに含まれているかを判断しなければなりません。

この例では、ラスター イメージのピクセル強度に基づいて数字を分類するようにマルチクラス誤り訂正出力符号 (ECOC) 分類モデルの学習と最適化を行う方法を示します。この ECOC モデルにはバイナリ サポート ベクター マシン (SVM) 学習器が含まれています。次に、学習済みモデルを使用して新しいイメージを分類する C コードを生成する方法を示します。データは各種のフォントのゆがんだ数字による人工的なイメージで、手書きの数字をシミュレートしています。

C コンパイラの設定

C コードの生成では C コンパイラへのアクセスが必要であるため、コンパイラが適切に設定されていなければなりません。mex -setup コマンドを使用してコンパイラを設定できます。詳細については、C コンパイラの設定 (MATLAB Coder)を参照してください。

前提条件と制限

C コードを生成するため、MATLAB Coder は、

  • 適切に設定されたコンパイラを必要とします。

  • サポートされる関数を、定義する MATLAB 関数内に含める必要があります。基本的なワークフローについては、コード生成の紹介を参照してください。

  • 定義した関数の入力引数としてオブジェクトを禁止します。

最後の制限については、以下に注意してください。

  • 学習済みの分類モデルはオブジェクトです。

  • MATLAB Coder は学習済みモデルを使用して観測値を分類するための predict をサポートしますが、モデルのあてはめはサポートしません。

分類に関するコード生成の制限に対処するには、MATLAB を使用して分類モデルに学習をさせてから、生成されたモデル オブジェクトをsaveCompactModelに渡します。saveCompactModel は、必要な場合はモデルのメモリ フットプリントを縮小してから (つまり、コンパクトにしてから)、学習済みモデルを構造体配列としてディスクに格納します。コンパクトなモデルと同じように、構造体配列には新しい観測値の分類に使用される情報のみが格納されます。

モデルをディスクに保存した後で、loadCompactModelを使用して MATLAB 関数でモデルを読み込みます。loadCompactModel は、保存された構造体配列を読み込んでから、元のコンパクトなモデル オブジェクトを再構築します。MATLAB 関数では、観測値を分類するためにモデルと予測子データセット (これらは関数の入力引数として使用可能) を predict に渡すことができます。

分類用のコード生成のワークフロー

イメージ分類器をデバイスに展開する前に、以下を行います。

  1. 十分な量のラベル付けされたイメージを取得する。

  2. イメージから抽出する特徴量を決定する。

  3. 分類モデルに学習をさせ、最適化する。この手順には、適切なアルゴリズムの選択とハイパーパラメーター、つまり学習時にあてはめが行われないモデル パラメーターの調整が含まれます。

  4. saveCompactModel を使用してモデルをディスクに保存する。

  5. 新しいイメージを分類する関数を定義する。この関数は、loadCompactModel を使用してモデルを読み込む必要があり、分類スコアなどのラベルを返せるものです。

  6. C コンパイラを設定する。

  7. 生成されたコードを実行する環境を決定する。

  8. 関数の C コードを生成する。

データの読み込み

digitimages データセットを matlabroot/examples/stats ディレクトリから読み込みます。

load(fullfile(matlabroot,'examples','stats','digitimages.mat'))

imagesuint16 整数の 28 x 28 x 3000 の配列です。各ページは数字のラスター イメージです。各要素はピクセル強度です。対応するラベルは 3000 行 1 列の数値ベクトル Y に格納されています。詳細については、コマンド ラインで Description を入力してください。

観測値の数と予測子変数の数を格納します。データの 20% ホールドアウトを指定するデータ分割を作成します。学習セットとテスト セットのインデックスをデータ分割から抽出します。

rng(1); % For reproducibility
n = size(images,3);
p = numel(images(:,:,1));
cvp = cvpartition(n,'Holdout',0.20);
idxTrn = training(cvp);
idxTest = test(cvp);

データから 9 つのランダムなイメージを表示します。

figure;
for j = 1:9
    subplot(3,3,j);
    selectImage = datasample(images,1,3);
    imshow(selectImage,[]);
end

データの再スケーリング

生のピクセル強度はばらつきが大きいので、分類モデルに学習をさせる前に値を正規化する必要があります。範囲が区間 [0,1] になるようにピクセル強度を再スケーリングします。つまり、 はイメージ 内のピクセル強度 であると仮定します。イメージ について、次の式を使用してすべてのピクセル強度を再スケーリングします。

X = double(images);

for i = 1:n
    minX = min(min(X(:,:,i)));
    maxX = max(max(X(:,:,i)));
    X(:,:,i) = (X(:,:,i) - minX)/(maxX - minX);
end

または、Image Processing Toolbox™ のライセンスがある場合は、mat2gray を使用して効率的にイメージのピクセル強度を [0,1] に再スケーリングできます。詳細については、mat2grayを参照してください。

データの形状変更

コードを生成する場合、学習用の予測子データは数値変数のテーブルまたは数値行列に格納されていなければなりません。

データの形状を行列に変更して、予測子変数 (ピクセル強度) を列、イメージ (観測値) を行に対応させます。reshape は列単位で要素を処理するので、結果を転置しなければなりません。

X = reshape(X,[p,n])';

データを前処理してもイメージが変化しないことを確認するため、X の 1 番目の観測値をプロットします。

figure;
imshow(reshape(X(1,:),sqrt(p)*[1 1]),[],'InitialMagnification','fit')

特徴量の抽出

Computer Vision System Toolbox™ には、イメージの特徴量を抽出する手法がいくつか用意されています。このような手法の 1 つは、勾配方向ヒストグラム (HOG) という特徴量の抽出です。HOG 特徴量を使用して ECOC モデルに学習をさせる方法については、HOG 特徴を使用した数字の分類 (Computer Vision Toolbox)を参照してください。サポートされる他の手法の詳細については、局所特徴の検出と抽出 (Computer Vision Toolbox)を参照してください。この例では、再スケーリングしたピクセル強度を予測子変数として使用します。

分類モデルの学習と最適化

多くの場合、分類用のイメージ データセットには線形 SVM モデルが適用されます。しかし、SVM はバイナリ分類器であり、データセット内には 10 のクラスがある可能性があります。

複数のバイナリ SVM 学習器が含まれているマルチクラス モデルは、fitcecocを使用して作成できます。fitcecoc は符号化設計を使用して複数のバイナリ学習器を結合します。既定では、fitcecoc は 1 対 1 の設計を適用します。この設計では、クラスのペアの組み合わせすべての観測値に基づいてバイナリ学習器に学習をさせるよう指定します。たとえば、10 個のクラスがある問題の場合、fitcecoc は 45 個のバイナリ SVM モデルに学習をさせなければなりません。

一般に、分類モデルに学習をさせる場合は、満足できる汎化誤差が得られるまでハイパーパラメーターを調整する必要があります。つまり、特定のハイパーパラメーターのセットについてモデルを交差検証し、分割外誤分類率を比較する必要があります。

独自のハイパーパラメーターの値のセットを選択するか、ベイズ最適化を実装するよう指定できます (ベイズ最適化の全般的な詳細についてはベイズ最適化のワークフローを参照)。この例では、選択した値のグリッドに対して交差検証を行います。

学習観測値に基づいて SVM バイナリ学習器の ECOC モデルを交差検証するため、5 分割の交差検証を使用します。予測子の値は同じ範囲にありますが、学習時の数値的な問題を回避するため、予測子を標準化します。また、ECOC の符号化設計と SVM のボックス制約を最適化します。以下の値の組み合わせをすべて使用します。

  • ECOC の符号化設計については、1 対 1 と 1 対他を使用します。

  • SVM のボックス制約については、0.1 から 100 の範囲にある対数間隔の 3 つの値を使用します。

すべてのモデルについて、5 分割の交差検証済み誤分類率を格納します。

coding = {'onevsone' 'onevsall'};
boxconstraint = logspace(-1,2,3);
cvLoss = nan(numel(coding),numel(boxconstraint)); % For preallocation

for i = 1:numel(coding)
    for j = 1:numel(boxconstraint)
        t = templateSVM('BoxConstraint',boxconstraint(j),'Standardize',true);
        CVMdl = fitcecoc(X(idxTrn,:),Y(idxTrn),'Learners',t,'KFold',5,...
            'Coding',coding{i});
        cvLoss(i,j) = kfoldLoss(CVMdl);
        fprintf('cvLoss = %f for model using %s coding and box constraint=%f\n',...
            cvLoss(i,j),coding{i},boxconstraint(j))
    end
end
cvLoss = 0.052083 for model using onevsone coding and box constraint=0.100000
cvLoss = 0.055000 for model using onevsone coding and box constraint=3.162278
cvLoss = 0.050000 for model using onevsone coding and box constraint=100.000000
cvLoss = 0.116667 for model using onevsall coding and box constraint=0.100000
cvLoss = 0.123750 for model using onevsall coding and box constraint=3.162278
cvLoss = 0.125000 for model using onevsall coding and box constraint=100.000000

誤分類率が最小になるハイパーパラメーターのインデックスを決定します。学習データを使用して ECOC モデルに学習をさせます。学習データを標準化し、観測された最適なハイパーパラメーターの組み合わせを指定します。

minCVLoss = min(cvLoss(:))
linIdx = find(cvLoss == minCVLoss);
[bestI,bestJ] = ind2sub(size(cvLoss),linIdx);
bestCoding = coding{bestI}
bestBoxConstraint = boxconstraint(bestJ)

t = templateSVM('BoxConstraint',bestBoxConstraint,'Standardize',true);
Mdl = fitcecoc(X(idxTrn,:),Y(idxTrn),'Learners',t,'Coding',bestCoding);
minCVLoss =

    0.0500


bestCoding =

    'onevsone'


bestBoxConstraint =

   100

テスト セットのイメージについて混同行列を作成します。

testImages = X(idxTest,:);
testLabels = predict(Mdl,testImages);
confusionMatrix = confusionmat(Y(idxTest),testLabels,'Order',Mdl.ClassNames)
confusionMatrix =

    63     0     0     0     0     0     0     0     0     0
     0    58     0     0     0     1     0     1     0     0
     0     0    64     0     0     0     0     0     3     0
     0     1     2    58     0     5     0     0     2     0
     0     0     0     0    66     0     0     0     0     0
     0     0     0     1     0    50     0     0     0     0
     0     1     0     0     0     1    39     0     0     0
     0     0     0     0     0     0     0    66     0     0
     0     0     0     2     0     3     0     0    52     0
     0     0     0     0     0     1     0     0     1    59

confusionMatrix の行は真のラベルに、列は予測したラベルに対応します。行と列の順序は Mdl.ClassNames 内のクラスの順序に対応します。confusionMatrix(i,j) は、数字 Mdl.ClassNames(i)predict が返した数字 Mdl.ClassNames(j) が実際に含まれているテスト セット イメージの数です。したがって、対角要素は正しい分類を示します。Mdl はほとんどのイメージを正しく分類すると考えることができます。

Mdl の性能が満足できるものになった場合は、予測用のコードの生成に進むことができます。それ以外の場合は、引き続きハイパーパラメーターを調整します。たとえば、異なるカーネル関数を使用して SVM 学習器の学習を試すことができます。

ディスクへの分類モデルの保存

Mdl は予測分類モデルですが、コード生成用に準備しなければなりません。saveCompactModel を使用して Mdl を現在の作業ディレクトリに保存します。

saveCompactModel(Mdl,'DigitImagesECOC');

saveCompactModelMdl をコンパクトにし、構造体配列に変換し、MAT ファイル DigitImagesECOC.mat に保存します。

コード生成用の予測関数の定義

MATLAB 関数 predictDigitECOC.m を定義します。この関数は以下を行う必要があります。

  • コード生成命令 %#codegen を関数内に含める。

  • X に相応するイメージ データを受け入れる。

  • loadCompactModel を使用して DigitImagesECOC.mat を読み込む。

  • 予測したラベルを返す。

function label = predictDigitECOC(X) %#codegen
%PREDICTDIGITECOC Classify digit in image using ECOC Model 
%   PREDICTDIGITECOC classifies the 28-by-28 images in the rows of X using
%   the compact ECOC model in the file DigitImagesECOC.mat, and then
%   returns class labels in label.
CompactMdl = loadCompactModel('DigitImagesECOC');
label = predict(CompactMdl,X); 
end

予測関数が predict と同じテスト セットのラベルを返すことを確認します。

pfLabels = predictDigitECOC(testImages);
verifyPF = sum(pfLabels == testLabels) == numel(testLabels)
verifyPF =

  logical

   1

一致するラベルの数がテスト セットのサイズと等しいので、predictDigitECOC は期待どおりの結果を生成します。

生成されたコードを実行する環境の決定

生成されたコードは、以下のように実行できます。

  • MATLAB 環境内で C-MEX ファイルとして

  • MATLAB 環境外でスタンドアロンの実行可能ファイルとして

  • MATLAB 環境外で別のスタンドアロンの実行可能ファイルにリンクされた共有ユーティリティとして

この例では、MATLAB 環境で実行する MEX ファイルを生成します。このような MEX ファイルを生成すると、関数を MATLAB 環境外に展開する前に、MATLAB のツールを使用して MEX 関数の入力引数と出力引数を分析および検証できます。coder.extrinsicを使用してコマンドを外部コマンドとして宣言すると、コード生成用ではなく検証用のコードを MEX 関数に含めることができます。外部コマンドには、コード生成をサポートしない関数を含められます。MEX 関数内の外部コマンドはすべて MATLAB で動作しますが、codegen はそれらについてコード生成を行いません。

MATLAB 環境外にコードを展開する場合、スタンドアロンの実行可能ファイルを生成しなければなりません。コンパイラの選択を指定する方法の 1 つは、codegen-config オプションの使用です。たとえば、静的な C 実行可能ファイルを生成するには、codegen を呼び出すときに -config:exe を指定します。コード生成オプションの設定の詳細については、codegen-config オプションを参照してください。

MEX ファイルへの MATLAB 関数のコンパイル

codegen を使用して predictDigitECOC.m をコンパイルし、MEX ファイルを生成します。次のオプションを指定します。

  • '-report' — コンパイル レポートを生成します。このレポートでは、元の MATLAB コードと、コード生成時に codegen が作成した関連ファイルを識別できます。

  • '-args' — MATLAB Coder で、関数の入力引数すべてのプロパティを指定する必要があります。これを行う方法の 1 つとして、入力値の例を codegen に与えます。すると、MATLAB Coder は値の例からプロパティを推測します。X に相応するテスト セットのイメージを指定します。

codegen predictDigitECOC -report -args testImages
Code generation successful: To view the report, open('codegen\mex\predictDigitECOC\html\report.mldatx').

codegen は予測関数のコードを正常に生成しました。コマンド ラインでリンクをクリックすると、レポートを表示できます。コードの生成に失敗した場合、レポートはデバッグに役立ちます。

codegenpwd/codegen/mex/predictDigitECOC というディレクトリを作成します。pwd は現在の作業ディレクトリです。codegen は、predictDigitECOC_mex.mexw64 という MEX ファイルも子ディレクトリ内に生成します。

MEX ファイルが predict と同じラベルを返すことを確認します。

mexLabels = predictDigitECOC_mex(testImages);
verifyMEX = sum(mexLabels == testLabels) == numel(testLabels)
verifyMEX =

  logical

   1

一致するラベルの数がテスト セットのサイズと等しいので、MEX ファイルは期待どおりの結果を生成します。

参考

| | |

関連するトピック