このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。
インクリメンタル学習用のコード生成
この例では、バイナリ線形分類用のインクリメンタル学習を実装するコードの生成方法を示します。この目的を達するために、ウェアラブル デバイスの学習を検討します。着用者がアイドルであるか移動しているかを判別するタスクは、デバイスが読み取る感覚の特徴に基づきます。
生成されたコードで実行するタスクは次のとおりです。これらをエントリポイント関数で定義します。
コマンド ラインで作成した構成済みのインクリメンタル学習モデル テンプレートを読み込みます。
データ ストリームからのデータの入力バッチでパフォーマンス メトリクスを追跡します。この例では、誤分類率とヒンジ損失を追跡します。
インクリメンタル モデルをデータのバッチに当てはめてモデルを更新します。
データのバッチのラベルを予測します。
この例では MATLAB® コマンド ラインからコードを生成しますが、代わりに MATLAB® Coder™ アプリを使用してコードを生成することもできます。詳細については、機械学習モデルの予測を MATLAB Coder アプリを使用して行うコードの生成を参照してください。
バイナリ線形分類 (および線形回帰) 用のインクリメンタル学習のオブジェクト関数は、いずれもコード生成をサポートしています。インクリメンタル学習用にコードを生成する準備として、適切に構成されたインクリメンタル学習モデル オブジェクトがオブジェクト関数に必要ですが、codegen
(MATLAB Coder)の -args
オプションはこれらのオブジェクトを受け入れません。この制限に対処するために、関数saveLearnerForCoder
とloadLearnerForCoder
を使用します。
次のフロー チャートは、線形モデル用のインクリメンタル学習のオブジェクト関数に対するコード生成ワークフローを示しています。
フロー チャートでは、2 つの異なるワークフローがマージされる形で示されています。
Train Model > Convert Model で始まるワークフローでは、データが必要になります。この場合、インクリメンタル学習用のコードを生成する前に、必要に応じて特徴選択を実行したり、交差検証を実行してモデルを最適化したりできます。
Configure Model で始まるワークフローでは、データは必要ありません。代わりに、インクリメンタル学習モデル オブジェクトを手動で構成しなければなりません。
これらのワークフローの違いとどちらを使用すべきかの詳細については、インクリメンタル学習モデルの構成を参照してください。
選択するワークフローに関係なく、結果のインクリメンタル学習モデルは次のすべての品質を満たしていなければなりません。
インクリメンタル学習中に予測子データに含まれる予測子の数を
NumPredictors
プロパティに反映します。分類の場合、インクリメンタル学習中に予測されるすべてのクラス名を
ClassNames
プロパティに含めなければなりません。
Train Model > Convert Model のワークフローを選択した場合、すべての既知のクラスを含むデータにモデルを当てはめると、コード生成用にモデルが構成されます。
インクリメンタル学習モデルの準備ができたら、saveLearnerForCoder
を使用してモデル オブジェクトを保存します。その後、loadLearnerForCoder
を使用して保存済みモデルを読み込み、オブジェクト関数を呼び出してインクリメンタル学習を実行するエントリポイント関数を定義します。代わりに、インクリメンタル学習の段階をそれぞれ実行する複数のエントリポイント関数を定義することもできます (この例ではこのワークフローを使用します)。ただし、このワークフローでは、更新されたモデル オブジェクトが別のエントリポイント関数の入力である場合に特別な扱いが必要になります。たとえば、次の 3 つのエントリポイント関数を記述します。
現在のモデルとデータのバッチを受け入れ、
updateMetrics
を呼び出して、パフォーマンス メトリクスが更新されたモデルを返す関数。更新されたモデルとデータのバッチを受け入れ、
fit
を呼び出して、係数が更新されたモデルを返す関数。さらに更新されたモデルと予測子データのバッチを受け入れ、
predict
を呼び出して、予測されたラベルを返す関数。
最後に、codegen
を使用してエントリポイント関数のコードを生成し、生成されたコードを確認します。
データの読み込みと前処理
人の行動のデータ セットを読み込みます。データをランダムにシャッフルします。
load humanactivity rng(1); % For reproducibility n = numel(actid); p = size(feat,2); idx = randsample(n,n); X = feat(idx,:); actid = actid(idx);
データ セットの詳細については、コマンド ラインで Description
を入力してください。
応答は、次の 5 つのクラスのいずれかになります。座る、立つ、歩く、走る、または踊る。被験者がアイドルであるかどうか (actid
<= 2) を基準に、応答を二分します。一意のクラス名を格納します。categorical 配列を作成します。
classnames = categorical(["Idle" "NotIdle"]); Y = repmat(classnames(1),n,1); Y(actid > 2) = classnames(2);
インクリメンタル学習モデルの構成
インクリメンタル分類用のコードを生成するには、インクリメンタル学習用のバイナリ分類線形モデル incrementalClassificationLinear
を適切に構成しなければなりません。
インクリメンタル学習用のバイナリ分類 (SVM) モデルを作成します。予測されるすべてのクラス名と予測子変数の数を指定して、モデルをコード生成用に完全に構成します。さらに、誤分類率とヒンジ損失を追跡するように指定します。再現性を得るために、この例ではスケール不変ソルバー用の観測値のシャッフルはオフにします。
metrics = ["classiferror" "hinge"]; IncrementalMdl = incrementalClassificationLinear('ClassNames',classnames,'NumPredictors',p,... 'Shuffle',false,'Metrics',metrics)
IncrementalMdl = incrementalClassificationLinear IsWarm: 0 Metrics: [2x2 table] ClassNames: [Idle NotIdle] ScoreTransform: 'none' Beta: [60x1 double] Bias: 0 Learner: 'svm' Properties, Methods
Mdl
はコード生成用に構成された incremenalClassificationLinear
モデル オブジェクトです。Mdl
はデータを処理していないため "コールド" (Mdl.IsWarm
が 0
) であり、係数は 0
になります。
代わりに、利用できるデータがあるため、fitcsvm
または fitclinear
を使用してデータに SVM モデルを当てはめてから、結果のモデルを incrementalLearner
に渡してインクリメンタル学習モデルに変換できます。結果のモデルはデータを処理してあるため "ウォーム" であり、係数は非ゼロになる可能性が高くなります。
saveLearnerForCoder
の使用によるモデルの保存
saveLearnerForCoder
を使用して、インクリメンタル学習モデルを InitialMdl.mat
というファイルに保存します。
saveLearnerForCoder(IncrementalMdl,'InitialMdl');
saveLearnerForCoder
は、現在のフォルダーの MATLAB バイナリ ファイル SVMClassIncrLearner.mat
に構造体配列としてインクリメンタル学習モデルを保存します。
エントリポイント関数の定義
"エントリポイント" 関数は、コード生成用に定義する関数で、"最上位" 関数または "プライマリ" 関数とも呼ばれます。codegen
を使用して最上位レベルの関数を呼び出すことはできないので、コード生成に対応する関数を呼び出すエントリポイント関数を定義し、codegen
を使用してエントリポイント関数の C/C++ コードを生成しなければなりません。エントリポイント関数内のすべての関数がコード生成をサポートしなければなりません。
次のアクションを実行する 4 つの別々のエントリポイント関数を現在のフォルダーで定義します。
myInitialModelIncrLearn.m
—loadLearnerForCoder
を使用して保存済みモデルを読み込み、コード生成用に同じ形式のモデルを返します。このエントリポイント関数により、エントリポイント関数から返されるモデルを別のエントリポイント関数の入力として簡単に使用できるようになります。myUpdateMetricsIncrLearn.m
— 現在のモデルの性能をデータの入力バッチで測定し、パフォーマンス メトリクスをモデルに格納します。この関数は、現在のモデルと予測子および応答のデータを受け入れ、更新されたモデルを返します。myFitIncrLearn.m
— 現在のモデルをデータの入力バッチに当てはめ、更新された係数をモデルに格納します。この関数は、現在のモデルと予測子および応答のデータを受け入れ、更新されたモデルを返します。myPredictIncrLearn.m
— 現在のモデルを使用して、データの入力バッチのラベルを予測します。この関数は、現在のモデルと予測子のデータを受け入れ、ラベルとクラス スコアを返します。
複数のエントリポイント関数に対するコード生成の詳細については、複数のエントリポイント関数のためのコード生成 (MATLAB Coder)を参照してください。
MATLAB のアルゴリズムについてのコードを生成しようとしていることを指示するため、コンパイラ命令 %#codegen
(またはプラグマ) をエントリポイント関数のシグネチャの後に追加します。この命令を追加すると、MATLAB Code Analyzer はコード生成時にエラーになる違反の診断と修正を支援します。コード アナライザーによるコードのチェック (MATLAB Coder)を参照してください。
代わりに、mlr/examples/stats/main
の関数にアクセスすることもできます。mlr
は matlabroot
の値です。
各関数の本体を表示します。
type myInitialModelIncrLearn.m
function incrementalModel = myInitialModelIncrLearn() %#codegen % MYINITIALMODELINCRLEARN Load and return configured linear model for % binary classification InitialMdl incrementalModel = loadLearnerForCoder('InitialMdl'); end
type myUpdateMetricsIncrLearn.m
function incrementalModel = myUpdateMetricsIncrLearn(incrementalModel,X,Y) %#codegen % MYUPDATEMETRICSINCRLEARN Measure model performance metrics on new data incrementalModel = updateMetrics(incrementalModel,X,Y); end
type myFitIncrLearn.m
function incrementalModel = myFitIncrLearn(incrementalModel,X,Y) %#codegen % MYFITINCRLEARN Fit model to new data incrementalModel = fit(incrementalModel,X,Y); end
type myPredictIncrLearn.m
function [labels,scores] = myPredictIncrLearn(incrementalModel,X) %#codegen % MYPREDICTINCRLEARN Predict labels and classification scores on new data [labels,scores] = predict(incrementalModel,X); end
コードの生成
コンパイラの設定
C/C++ コードを生成するには、適切に設定されている C/C++ コンパイラにアクセスできなければなりません。MATLAB Coder は、サポートされているインストール済みのコンパイラを探して使用します。mex
-setup
を使用すると、既定のコンパイラを表示および変更できます。詳細は、既定のコンパイラの変更を参照してください。
ビルド タイプ
MATLAB Coder は、以下のビルド タイプについてコードを生成できます。
MEX (MATLAB 実行可能ファイル) 関数
スタンドアロン C/C++ コード
スタティック ライブラリにコンパイルされるスタンドアロン C/C++ コード
ダイナミック リンク ライブラリにコンパイルされるスタンドアロン C/C++ コード
実行可能ファイルにコンパイルされるスタンドアロン C/C++ コード
ビルド タイプは、codegen
(MATLAB Coder) の -config
オプションを使用して指定できます。コード生成オプションの設定の詳細については、codegen
(MATLAB Coder)の -config
オプションとビルド設定の構成 (MATLAB Coder)を参照してください。
既定では、codegen
は MEX 関数を生成します。MEX 関数は、MATLAB から実行できる C/C++ プログラムです。MEX 関数を使用すると、MATLAB のアルゴリズムを高速化し、生成されたコードの機能と実行時の問題をテストすることができます。詳細は、MATLAB アルゴリズムの高速化 (MATLAB Coder) と MATLAB で MEX 関数をテストする理由 (MATLAB Coder) を参照してください。
codegen
の使用によるコードの生成
C および C++ は静的な型の言語なので、エントリポイント関数内のすべての変数のプロパティをコンパイル時に指定しなければなりません。次を指定します。
エントリポイント関数のデータ入力のデータ型。
coder.typeof
(MATLAB Coder) を使用します。また、バッチによって観測値の数が異なる場合があるため、観測値の数 (1 番目の次元) が可変サイズであることを指定します。詳細は、コード生成用の可変サイズ引数の指定 と エントリポイント関数の入力のプロパティの指定 (MATLAB Coder) を参照してください。いくつかのエントリポイント関数でインクリメンタル モデル オブジェクトを入力として受け入れて操作を行うため、
coder.OutputType
(MATLAB Coder)を使用してコード生成用のモデル オブジェクトの表現を作成します。詳細については、入力としてのエントリポイント関数出力の受け渡し (MATLAB Coder)を参照してください。
predictorData = coder.typeof(X,[],[true false]);
responseData = coder.typeof(Y,[],true);
IncrMdlOutputType = coder.OutputType('myInitialModelIncrLearn');
codegen
(MATLAB Coder)を使用して、エントリポイント関数のコードを生成します。エントリポイント関数の各引数について、コード生成における変数の表現を -args
フラグを使用して指定します。出力の MEX 関数の名前 myIncrLearn_mex
を指定します。
codegen -o myIncrLearn_mex ... myInitialModelIncrLearn ... myUpdateMetricsIncrLearn -args {IncrMdlOutputType,predictorData,responseData} ... myFitIncrLearn -args {IncrMdlOutputType,predictorData,responseData} ... myPredictIncrLearn –args {IncrMdlOutputType,predictorData} -report
Code generation successful: To view the report, open('codegen/mex/myIncrLearn_mex/html/report.mldatx')
コード生成の問題についてデバッグするときは、[View report]
をクリックして生成された C/C++ コードを確認すると便利です (コード生成レポート (MATLAB Coder)を参照)。
生成されたコードの確認
MEX 関数をテストして、生成されたコードが元の MATLAB コードと同じ機能を提供するかどうかを確認します。このテストを実行するため、元の MATLAB コードの実行に使用したものと同じ入力を使用して MEX 関数を実行してから、結果を比較します。スタンドアロン コードを生成する前に MATLAB で MEX 関数を実行すると、実行時エラーを検出して修正することもできます。生成されたスタンドアロン コードでは、このようなエラーの診断がはるかに困難になります。詳細は、MATLAB で MEX 関数をテストする理由 (MATLAB Coder)を参照してください。
生成された MEX 関数を使用し、オブジェクト関数を直接使用して、インクリメンタル学習を実行します。バッチを指定します。
% Preallocation numObsPerChunk = 50; nchunk = floor(n/numObsPerChunk); ce = array2table(zeros(nchunk,2),'VariableNames',["Cumulative" "Window"]); hinge = ce; ceCG = ce; hingeCG = ce; IncrementalMdlCG = myIncrLearn_mex('myInitialModelIncrLearn'); scores = zeros(n,2); scoresCG = zeros(n,2); % Incremental fitting for j = 1:nchunk ibegin = min(n,numObsPerChunk*(j-1) + 1); iend = min(n,numObsPerChunk*j); idx = ibegin:iend; IncrementalMdl = updateMetrics(IncrementalMdl,X(idx,:),Y(idx)); ce{j,:} = IncrementalMdl.Metrics{"ClassificationError",:}; hinge{j,:} = IncrementalMdl.Metrics{"HingeLoss",:}; IncrementalMdlCG = myIncrLearn_mex('myUpdateMetricsIncrLearn',IncrementalMdlCG,... X(idx,:),Y(idx)); ceCG{j,:} = IncrementalMdlCG.Metrics{"ClassificationError",:}; hingeCG{j,:} = IncrementalMdlCG.Metrics{"HingeLoss",:}; IncrementalMdl = fit(IncrementalMdl,X(idx,:),Y(idx)); IncrementalMdlCG = myIncrLearn_mex('myFitIncrLearn',IncrementalMdlCG,X(idx,:),Y(idx)); [~,scores(idx,:)] = predict(IncrementalMdl,X(idx,:)); [~,scoresCG(idx,:)] = myIncrLearn_mex('myPredictIncrLearn',IncrementalMdlCG,X(idx,:)); end
オブジェクト関数および MEX 関数で返される累積メトリクスと Idle
を分類するスコアを比較します。
idx = all(~isnan(ce.Variables),2); areCEsEqual = norm(ce.Cumulative(idx) - ceCG.Cumulative(idx))
areCEsEqual = 8.9904e-18
idx = all(~isnan(hinge.Variables),2); areHingeLossesEqual = norm(hinge.Cumulative(idx) - hingeCG.Cumulative(idx))
areHingeLossesEqual = 8.4704e-17
areScoresEqual = norm(scores(:,1) - scoresCG(:,1))
areScoresEqual = 8.8356e-13
返される量には無視できるほどの差しかありません。