分類およびコード生成用の System object
この例では、学習済み分類モデルを使用して数字のイメージを分類する MATLAB® System object™ から C コードを生成する方法を示します。また、Simulink® での分類に System object を使用する方法も示します。MATLAB 関数ではなく System object を使用する利点は、System object の方が大量のストリーミング データの処理に適しているということです。詳細は、System object とはを参照してください。
この例は、HOG 特徴を使用した数字の分類 (Computer Vision Toolbox)の代替ワークフローであるイメージ分類用のコードの生成をベースとしています。
データの読み込み
digitimages
を読み込みます。
load digitimages.mat
images
は uint16
整数の 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);
データの再スケーリング
各イメージ内で範囲が区間 [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
データの形状変更
コードを生成する場合、学習用の予測子データは数値変数の table または数値行列に格納されていなければなりません。
データの形状を行列に変更して、予測子変数を列に、イメージを行に対応させます。reshape
は列単位で要素を処理するので、結果を転置します。
X = reshape(X,[p,n])';
分類モデルの学習と最適化
学習観測値に基づいて、SVM バイナリ学習器による ECOC モデルとランダム フォレストを交差検証します。5 分割交差検証を使用します。
ECOC モデルについて、予測子の標準化を指定し、ECOC の符号化設計と SVM のボックス制約に対して分類誤差を最適化します。次の値の組み合わせをすべて探索します。
ECOC の符号化設計については、1 対 1 と 1 対他を使用します。
SVM のボックス制約については、0.1 から 100 の範囲にある対数間隔の 3 つの値を使用します。すべてのモデルについて、5 分割の交差検証済み誤分類率を格納します。
coding = {'onevsone' 'onevsall'}; boxconstraint = logspace(-1,2,3); cvLossECOC = 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}); cvLossECOC(i,j) = kfoldLoss(CVMdl); fprintf('cvLossECOC = %f for model using %s coding and box constraint=%f\n',... cvLossECOC(i,j),coding{i},boxconstraint(j)) end end
cvLossECOC = 0.058333 for model using onevsone coding and box constraint=0.100000 cvLossECOC = 0.057083 for model using onevsone coding and box constraint=3.162278 cvLossECOC = 0.050000 for model using onevsone coding and box constraint=100.000000 cvLossECOC = 0.120417 for model using onevsall coding and box constraint=0.100000 cvLossECOC = 0.121667 for model using onevsall coding and box constraint=3.162278 cvLossECOC = 0.127917 for model using onevsall coding and box constraint=100.000000
ランダム フォレストについて、 という数列の値を使用して最大分割数を変化させます。m は、 が n - 1 を超えない値です。無作為な予測子の選択を再現するため、'Reproducible',true
を指定します。
n = size(X,1); m = floor(log(n - 1)/log(3)); maxNumSplits = 3.^(2:m); cvLossRF = nan(numel(maxNumSplits)); for i = 1:numel(maxNumSplits) t = templateTree('MaxNumSplits',maxNumSplits(i),'Reproducible',true); CVMdl = fitcensemble(X(idxTrn,:),Y(idxTrn),'Method','bag','Learners',t,... 'KFold',5); cvLossRF(i) = kfoldLoss(CVMdl); fprintf('cvLossRF = %f for model using %d as the maximum number of splits\n',... cvLossRF(i),maxNumSplits(i)) end
cvLossRF = 0.319167 for model using 9 as the maximum number of splits cvLossRF = 0.192917 for model using 27 as the maximum number of splits cvLossRF = 0.066250 for model using 81 as the maximum number of splits cvLossRF = 0.015000 for model using 243 as the maximum number of splits cvLossRF = 0.013333 for model using 729 as the maximum number of splits cvLossRF = 0.009583 for model using 2187 as the maximum number of splits
各アルゴリズムについて、誤分類率が最小になるハイパーパラメーターのインデックスを決定します。
minCVLossECOC = min(cvLossECOC(:))
minCVLossECOC = 0.0500
linIdx = find(cvLossECOC == minCVLossECOC,1); [bestI,bestJ] = ind2sub(size(cvLossECOC),linIdx); bestCoding = coding{bestI}
bestCoding = 'onevsone'
bestBoxConstraint = boxconstraint(bestJ)
bestBoxConstraint = 100
minCVLossRF = min(cvLossRF(:))
minCVLossRF = 0.0096
linIdx = find(cvLossRF == minCVLossRF,1); [bestI,bestJ] = ind2sub(size(cvLossRF),linIdx); bestMNS = maxNumSplits(bestI)
bestMNS = 2187
ランダム フォレストの方が、交差検証された誤分類率が小さくなります。
学習データを使用して ECOC モデルとランダム フォレストに学習をさせます。最適なハイパーパラメーターの組み合わせを与えます。
t = templateSVM('BoxConstraint',bestBoxConstraint,'Standardize',true); MdlECOC = fitcecoc(X(idxTrn,:),Y(idxTrn),'Learners',t,'Coding',bestCoding); t = templateTree('MaxNumSplits',bestMNS); MdlRF = fitcensemble(X(idxTrn,:),Y(idxTrn),'Method','bag','Learners',t);
検定標本イメージ用の変数を作成し、学習済みモデルを使用して検定標本のラベルを予測します。
testImages = X(idxTest,:); testLabelsECOC = predict(MdlECOC,testImages); testLabelsRF = predict(MdlRF,testImages);
ディスクへの分類モデルの保存
MdlECOC
と MdlRF
は予測分類モデルですが、これらをコード生成用に準備する必要があります。saveLearnerForCoder
を使用して MdlECOC
と MdlRF
を現在の作業フォルダーに保存します。
saveLearnerForCoder(MdlECOC,'DigitImagesECOC'); saveLearnerForCoder(MdlRF,'DigitImagesRF');
予測用 System object の作成
ECOC モデル用とランダム フォレスト用に 1 つずつ、以下を行う 2 つの System object を作成します。
loadLearnerForCoder
を使用して、以前に保存された学習済みモデルを読み込む。step
メソッドにより逐次予測を行う。入力データのサイズ変更を抑止する。
倍精度のスカラー出力を強制する。
type ECOCClassifier.m % Display contents of ECOCClassifier.m file
classdef ECOCClassifier < matlab.System % ECOCCLASSIFIER Predict image labels from trained ECOC model % % ECOCCLASSIFIER loads the trained ECOC model from % |'DigitImagesECOC.mat'|, and predicts labels for new observations % based on the trained model. The ECOC model in % |'DigitImagesECOC.mat'| was cross-validated using the training data % in the sample data |digitimages.mat|. properties(Access = private) CompactMdl % The compacted, trained ECOC model end methods(Access = protected) function setupImpl(obj) % Load ECOC model from file obj.CompactMdl = loadLearnerForCoder('DigitImagesECOC'); end function y = stepImpl(obj,u) y = predict(obj.CompactMdl,u); end function flag = isInputSizeMutableImpl(obj,index) % Return false if input size is not allowed to change while % system is running flag = false; end function dataout = getOutputDataTypeImpl(~) dataout = 'double'; end function sizeout = getOutputSizeImpl(~) sizeout = [1 1]; end end end
type RFClassifier.m % Display contents of RFClassifier.m file
classdef RFClassifier < matlab.System % RFCLASSIFIER Predict image labels from trained random forest % % RFCLASSIFIER loads the trained random forest from % |'DigitImagesRF.mat'|, and predicts labels for new observations based % on the trained model. The random forest in |'DigitImagesRF.mat'| % was cross-validated using the training data in the sample data % |digitimages.mat|. properties(Access = private) CompactMdl % The compacted, trained random forest end methods(Access = protected) function setupImpl(obj) % Load random forest from file obj.CompactMdl = loadLearnerForCoder('DigitImagesRF'); end function y = stepImpl(obj,u) y = predict(obj.CompactMdl,u); end function flag = isInputSizeMutableImpl(obj,index) % Return false if input size is not allowed to change while % system is running flag = false; end function dataout = getOutputDataTypeImpl(~) dataout = 'double'; end function sizeout = getOutputSizeImpl(~) sizeout = [1 1]; end end end
メモ: このページの右上にあるボタンをクリックしてこの例を MATLAB® で開くと、MATLAB® で例のフォルダーが開きます。このフォルダーには、この例で使用しているファイルが含まれています。
System object の基本的な要件については、基本的な System object の定義を参照してください。
コード生成用の予測関数の定義
predictDigitECOCSO.m
および predictDigitRFSO.m
という名前の 2 つの MATLAB 関数を定義します。これらの関数では以下を行います。
コード生成命令
%#codegen
を含める。X
に相応するイメージ データを受け入れる。System object
ECOCClassifier
およびRFClassifier
をそれぞれ使用してラベルを予測する。予測したラベルを返す。
type predictDigitECOCSO.m % Display contents of predictDigitECOCSO.m file
function label = predictDigitECOCSO(X) %#codegen %PREDICTDIGITECOCSO Classify digit in image using ECOC Model System object % PREDICTDIGITECOCSO classifies the 28-by-28 images in the rows of X % using the compact ECOC model in the System object ECOCClassifier, and % then returns class labels in label. classifier = ECOCClassifier; label = step(classifier,X); end
type predictDigitRFSO.m % Display contents of predictDigitRFSO.m file
function label = predictDigitRFSO(X) %#codegen %PREDICTDIGITRFSO Classify digit in image using RF Model System object % PREDICTDIGITRFSO classifies the 28-by-28 images in the rows of X % using the compact random forest in the System object RFClassifier, and % then returns class labels in label. classifier = RFClassifier; label = step(classifier,X); end
MEX ファイルへの MATLAB 関数のコンパイル
codegen
を使用して、検定標本精度が優れている予測関数をコンパイルして MEX ファイルにします。引数 -args
を使用して検定セットのイメージを指定します。
if(minCVLossECOC <= minCVLossRF) codegen predictDigitECOCSO -args testImages else codegen predictDigitRFSO -args testImages end
Code generation successful.
生成された MEX ファイルが MATLAB 関数と同じ予測を行うことを確認します。
if(minCVLossECOC <= minCVLossRF) mexLabels = predictDigitECOCSO_mex(testImages); verifyMEX = sum(mexLabels == testLabelsECOC) == numel(testLabelsECOC) else mexLabels = predictDigitRFSO_mex(testImages); verifyMEX = sum(mexLabels == testLabelsRF) == numel(testLabelsRF) end
verifyMEX = logical
1
verifyMEX
は 1
です。これは、生成された MEX ファイルおよび対応する MATLAB 関数で予測が同じであることを示します。
Simulink で System object を使用したラベルの予測
検定セットのイメージをフレーム単位で表示するビデオ ファイルを作成します。
v = VideoWriter('testImages.avi','Uncompressed AVI'); v.FrameRate = 1; open(v); dim = sqrt(p)*[1 1]; for j = 1:size(testImages,1) writeVideo(v,reshape(testImages(j,:),dim)); end close(v);
RGB イメージをグレースケールに変換してから、生成されたピクセル強度を値が区間 [0,1] に収まるようにスケーリングする、scalePixelIntensities.m
という名前の関数を定義します。
type scalePixelIntensities.m % Display contents of scalePixelIntensities.m file
function x = scalePixelIntensities(imdat) %SCALEPIXELINTENSITIES Scales image pixel intensities % SCALEPIXELINTENSITIES scales the pixel intensities of the image such % that the result x is a row vector of values in the interval [0,1]. imdat = rgb2gray(imdat); minimdat = min(min(imdat)); maximdat = max(max(imdat)); x = (imdat - minimdat)/(maximdat - minimdat); end
Simulink® モデル slexClassifyAndDisplayDigitImages.slx
を読み込みます。
SimMdlName = 'slexClassifyAndDisplayDigitImages';
open_system(SimMdlName);
Simulink® モデルが Figure に表示されます。シミュレーションの最初に、From Multimedia File ブロックで検定セットのイメージのビデオ ファイルが読み込まれます。ビデオの各イメージについて以下を行います。
From Multimedia File ブロックで、イメージを変換して 28 行 28 列のピクセル強度の行列を出力します。
Process Data ブロックで、
scalePixelIntensities.m
を使用してピクセル強度をスケーリングし、1 行 784 列のスケーリングされた強度のベクトルを出力します。Classification Subsystem ブロックで、与えられた処理済みイメージ データからラベルを予測します。このブロックでは、分類誤差が最小になる System object を選択します。この場合、ランダム フォレストが選択されます。このブロックでは、倍精度スカラーのラベルを出力します。
Data Type Conversion ブロックで、ラベルを
int32
スカラーに変換します。Insert Text ブロックで、予測されたラベルを現在のフレームに埋め込みます。
To Video Display ブロックで、注釈付きのフレームを表示します。
モデルをシミュレートします。
sim(SimMdlName)
600 個の検定セットのイメージおよびその予測が素早く表示されます。最後のイメージがビデオ表示に残ります。代わりに [ステップを進める] ボタンをクリックすると、1 つずつ予測を生成して対応するイメージと共に表示できます。
Simulink® Coder™ のライセンスもある場合、Simulink® の slexClassifyAndDisplayDigitImages.slx
またはコマンド ラインから slbuild
(Simulink) を使用して C コードを生成できます。詳細は、モデル用 C コードの生成 (Simulink Coder)を参照してください。
参考
loadLearnerForCoder
| saveLearnerForCoder
| predict
| predict