Main Content

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

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

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

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

C コンパイラの設定

C/C++ コードを生成するには、適切に設定されている C/C++ コンパイラにアクセスできなければなりません。MATLAB Coder™ は、サポートされているインストール済みのコンパイラを探して使用します。mex -setup を使用すると、既定のコンパイラを表示および変更できます。詳細は、既定のコンパイラの変更を参照してください。

前提条件と制限

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

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

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

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

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

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

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

分類に関するコード生成の制限に対処するには、MATLAB を使用して分類モデルに学習をさせてから、生成されたモデル オブジェクトをsaveLearnerForCoderに渡します。関数 saveLearnerForCoder は、予測には必要ないプロパティを削除してから、学習済みモデルを構造体配列としてディスクに格納します。モデルと同じように、構造体配列には新しい観測値の分類に使用される情報が格納されます。

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

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

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

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

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

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

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

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

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

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

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

データの読み込み

digitimages データ セットを読み込みます。

load digitimages

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] になるようにピクセル強度を再スケーリングします。つまり、pij はイメージ i 内のピクセル強度 j であると仮定します。イメージ i について、次の式を使用してすべてのピクセル強度を再スケーリングします。

pˆij=pij-minj(pij)maxj(pij)-minj(pij).

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 (Image Processing Toolbox)を参照してください。

データの形状変更

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

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

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

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

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

特徴量の抽出

Computer Vision 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(:))
minCVLoss = 0.0500
linIdx = find(cvLoss == minCVLoss);
[bestI,bestJ] = ind2sub(size(cvLoss),linIdx);
bestCoding = coding{bestI}
bestCoding = 
'onevsone'
bestBoxConstraint = boxconstraint(bestJ)
bestBoxConstraint = 100
t = templateSVM('BoxConstraint',bestBoxConstraint,'Standardize',true);
Mdl = fitcecoc(X(idxTrn,:),Y(idxTrn),'Learners',t,'Coding',bestCoding);

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

testImages = X(idxTest,:);
testLabels = predict(Mdl,testImages);
confusionMatrix = confusionchart(Y(idxTest),testLabels);

対角線上の要素は正しく分類された観測値に、対角線外の要素は誤って分類された観測値に対応します。Mdl はほとんどのイメージを正しく分類すると考えることができます。

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

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

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

saveLearnerForCoder(Mdl,'DigitImagesECOC')

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

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

以下を行う predictDigitECOC.m という名前のエントリポイント関数を定義します。

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

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

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

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

type predictDigitECOC.m % Display contents of predictDigitECOC.m file
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 = loadLearnerForCoder('DigitImagesECOC.mat');
label = predict(CompactMdl,X); 
end

メモ: このページの右上にあるボタンをクリックしてこの例を MATLAB で開くと、MATLAB で例のフォルダーが開きます。このフォルダーには、エントリポイント関数のファイルが含まれています。

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

pfLabels = predictDigitECOC(testImages);
verifyPF = isequal(pfLabels,testLabels)
verifyPF = logical
   1

isequal は、すべての入力が等しいことを意味する logical 1 (true) を返します。predictDigitECOC は、予想された結果を生成します。

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

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

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

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

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

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

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

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: View report

codegen は予測関数のコードを正常に生成しました。コマンド ウィンドウで View report リンクをクリックするか、open('codegen/mex/predictDigitECOC/html/report.mldatx') と入力するとレポートを表示できます。コードの生成に失敗した場合、レポートはデバッグに役立ちます。

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

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

mexLabels = predictDigitECOC_mex(testImages);
verifyMEX = isequal(mexLabels,testLabels)
verifyMEX = logical
   1

関数 isequal は、MEX ファイルが期待どおりの結果になったことを示す logical 1 (true) を返します。

参考

| | | (MATLAB Coder)

関連するトピック