Main Content

このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。

SVM の予測用の固定小数点コード生成

この例では、サポート ベクター マシン (SVM) モデルの予測用に固定小数点 C/C++ コードを生成する方法を示します。一般的な C/C++ コード生成ワークフローと比較すると、固定小数点コードの生成には予測に必要な変数の固定小数点データ型を定義する追加の手順が必要です。generateLearnerDataTypeFcnを使用して固定小数点データ型構造体を作成し、その構造体をエントリポイント関数でloadLearnerForCoderの入力引数として使用します。コードを生成する前に固定小数点データ型を最適化することもできます。

次のフローチャートは固定小数点のコード生成ワークフローを示します。

  1. SVM モデルに学習させます。

  2. saveLearnerForCoderを使用して、学習済みモデルを保存します。

  3. generateLearnerDataTypeFcnによって生成されるデータ型関数を使用して、予測に必要な変数の固定小数点データ型を定義します。

  4. loadLearnerForCoderと構造体の両方を使用してモデルを読み込み、関数predictを呼び出すエントリポイント関数を定義します。

  5. (オプション) 固定小数点データ型を最適化します。

  6. 固定小数点の C/C++ コードを生成します。

  7. 生成されたコードを検証します。

手順5は生成された固定小数点コードのパフォーマンスを高めるための任意の手順です。これを行うには、コードのパフォーマンスに満足するまで次の 2 つの手順を繰り返します。

  1. buildInstrumentedMex(Fixed-Point Designer)を使用して、予測用の変数の最小値と最大値を記録します。

  2. showInstrumentationResults(Fixed-Point Designer)を使用して計測結果を表示します。オーバーフローとアンダーフローを回避するために (必要な場合は) 固定小数点データ型を調整し、固定小数点コードの精度を向上させます。

このワークフローでは、generateLearnerDataTypeFcnによって生成されるデータ型関数を使用して固定小数点データ型を定義します。変数のデータ型をアルゴリズムから独立させると、テストが簡単になります。データ型関数の入力引数を使用して、プログラムにより浮動小数点と固定小数点の間でデータ型を切り替えることができます。また、このワークフローは手動による固定小数点の変換ワークフロー(Fixed-Point Designer)と互換性があります。

データの前処理

census1994データセットを読み込みます。このデータセットは、個人の年収が $50,000 を超えるかどうかを予測するために使用される、米国勢調査局の人口統計データから構成されています。

loadcensus1994

年齢、労働階級、教育レベル、資本利得および損失、および 1 週間の勤務時間が与えられた従業員の給与カテゴリを予測するモデルを考えます。対象とする変数を抽出し、table を使用して保存します。

tbl = adultdata(:,{'age','education_num','capital_gain','capital_loss','hours_per_week'});

table の概要を表示します。

summary(tbl)
Variables: age: 32561x1 double Values: Min 17 Median 37 Max 90 education_num: 32561x1 double Values: Min 1 Median 10 Max 16 capital_gain: 32561x1 double Values: Min 0 Median 0 Max 99999 capital_loss: 32561x1 double Values: Min 0 Median 0 Max 4356 hours_per_week: 32561x1 double Values: Min 1 Median 40 Max 99

変数のスケールは一致していません。この場合、fitcsvmの名前と値のペアの引数'Standardize'を指定することにより、標準化されたデータセットを使用してモデルに学習させることができます。ただし、標準化の演算を固定小数点コードに追加すると、精度が下がり、メモリ使用量が増える可能性があります。代わりに、この例に示すようにデータセットを手動で標準化できます。この例では、最後にメモリ使用量を確認する方法についても説明しています。

固定小数点コード生成では table または categorical 配列はサポートされていません。このため、数値行列を使用して予測子データXを定義し、logical ベクトルを使用してクラス ラベルYを定義します。logical ベクトルはバイナリ分類問題でメモリを最も効率よく使用します。

X = table2array(tbl); Y = adultdata.salary =='<=50K';

観測値の重みwを定義します。

w = adultdata.fnlwgt;

モデル内のサポート ベクターの数が増加するにつれ、学習済みモデルのメモリの使用量が増加します。サポート ベクターの数を減らすには、学習させる際に名前と値のペアの引数'BoxConstraint'を使用してボックス制約の値を大きくするか、学習用にサブサンプリングされた代表データセットを使用することができます。ボックス制約の値を大きくすると学習時間が長くなる場合があり、また、サブサンプリングされたデータセットを使用すると学習済みモデルの精度が低下する可能性があることに注意してください。この例では、データセットから 1000 の観測値を無作為に抽出し、サブサンプリングされたデータを学習に使用します。

rng('default')% For reproducibility[X_sampled,idx] = datasample(X,1000,'Replace',false); Y_sampled = Y(idx); w_sampled = w(idx);

名前と値のペアの引数'Weight'および'Standardize'を使用してモデルを学習させて、加重平均および標準偏差を求めます。

tempMdl = fitcsvm(X_sampled,Y_sampled,'Weight',w_sampled,'KernelFunction','gaussian','Standardize',true); mu = tempMdl.Mu; sigma = tempMdl.Sigma;

学習に名前と値のペアの引数'Cost''Prior',または'Weight'を使用しない場合は、関数zscoreを使用して平均と標準偏差を求めることができます。

[standardizedX_sampled,mu,sigma] = zscore(X_sampled);

muおよびsigmaを使用して予測子データを標準化します。

standardizedX = (X-mu)./sigma; standardizedX_sampled = standardizedX(idx,:);

テスト データ セットを使用して学習済みモデルを検証し、インストルメント化された MEX 関数をテストできます。muおよびsigmaを使用してテスト データ セットを指定し、テスト予測子データを標準化します。

XTest = table2array(adulttest(:,{'age','education_num','capital_gain','capital_loss','hours_per_week'})); standardizedXTest = (XTest-mu)./sigma; YTest = adulttest.salary =='<=50K';

モデルの学習

バイナリ SVM 分類モデルに学習させます。

Mdl = fitcsvm(standardizedX_sampled,Y_sampled,'Weight',w_sampled,'KernelFunction','gaussian');

MdlClassificationSVMモデルです。

学習データ セットおよびテストデータ セットについて分類エラーを計算します。

loss(Mdl,standardizedX_sampled,Y_sampled)
ans = 0.1663
loss(Mdl,standardizedXTest,YTest)
ans = 0.1905

SVM 分類器は、学習データの約 17% とテスト データの 19% を誤分類しています。

モデルの保存

saveLearnerForCoderを使用して、SVM 分類モデルをmyMdl.matというファイルに保存します。

saveLearnerForCoder(Mdl,'myMdl');

固定小数点データ型の定義

generateLearnerDataTypeFcnを使用して、SVM モデルの予測に必要な変数の固定小数点データ型を定義する関数を生成します。使用可能なすべての予測子データを使用して固定小数点データ型の現実的な範囲を取得します。

generateLearnerDataTypeFcn('myMdl',[standardizedX; standardizedXTest])

generateLearnerDataTypeFcnは関数myMdl_datatypeを生成します。関数typeを使用してmyMdl_datatype.mの内容を表示します。

typemyMdl_datatype.m
function T = myMdl_datatype(dt) %MYMDL_DATATYPE Define data types for fixed-point code generation % % T = MYMDL_DATATYPE(DT) returns the data type structure T, which defines % data types for the variables required to generate fixed-point C/C++ code % for prediction of a machine learning model. Each field of T contains a % fixed-point object returned by fi. The input argument dt specifies the % DataType property of the fixed-point object. Specify dt as 'Fixed' (default) % for fixed-point code generation or specify dt as 'Double' to simulate % floating-point behavior of the fixed-point code. % % Use the output structure T as both an input argument of an entry-point % function and the second input argument of loadLearnerForCoder within the % entry-point function. For more information, see loadLearnerForCoder. % File: myMdl_datatype.m % Statistics and Machine Learning Toolbox Version 12.4 (Release R2022b) % Generated by MATLAB, 10-Oct-2022 03:23:02 if nargin < 1 dt = 'Fixed'; end % Set fixed-point math settings fm = fimath('RoundingMethod','Floor', ... 'OverflowAction','Wrap', ... 'ProductMode','FullPrecision', ... 'MaxProductWordLength',128, ... 'SumMode','FullPrecision', ... 'MaxSumWordLength',128); % Data type for predictor data T.XDataType = fi([],true,16,11,fm,'DataType',dt); % Data type for output score T.ScoreDataType = fi([],true,16,14,fm,'DataType',dt); % Internal variables % Data type of the squared distance dist = (x-sv)^2 for the Gaussian kernel G(x,sv) = exp(-dist), % where x is the predictor data for an observation and sv is a support vector T.InnerProductDataType = fi([],true,16,6,fm,'DataType',dt); end

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

関数myMdl_datatypeは既定の語長 (16) を使用し、最大の小数部の長さを提案して、オーバーフローを回避します。これは、各変数について、既定の語長 (16) と安全余裕 (10%) に基づいています。

myMdl_datatypeを使用して、固定小数点データ型を定義する構造体Tを作成します。

T = myMdl_datatype('Fixed')
T =struct with fields:XDataType: [0x0 embedded.fi] ScoreDataType: [0x0 embedded.fi] InnerProductDataType: [0x0 embedded.fi]

構造体Tには、関数predictの実行に必要な名前付きの内部変数に対するフィールドが含まれています。各フィールドには、fi(Fixed-Point Designer)で返される固定小数点オブジェクトが含まれています。たとえば、予測子データの固定小数点データ型プロパティを表示します。

T.XDataType
ans = [] DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 16 FractionLength: 11 RoundingMethod: Floor OverflowAction: Wrap ProductMode: FullPrecision MaxProductWordLength: 128 SumMode: FullPrecision MaxSumWordLength: 128

生成された関数と構造体の詳細については、データ型関数を参照してください。

エントリポイント関数の定義

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

  • 予測子データXおよび固定小数点データ型構造体Tを受け入れる。

  • loadLearnerForCoderおよび構造体 T の両方を使用して、学習済み SVM 分類モデルの固定小数点バージョンを読み込む。

  • 読み込まれたモデルを使用してラベルとスコアを予測する。

function[label,score] = myFixedPointPredict(X,T)%#codegenMdl = loadLearnerForCoder('myMdl','DataType',T); [label,score] = predict(Mdl,X);end

(オプション) 固定小数点データ型の最適化

buildInstrumentedMexおよびshowInstrumentationResultsを使用して固定小数点データ型を最適化します。buildInstrumentedMexを使用して、予測のためにすべての名前付きの内部変数の最小値と最大値を記録します。showInstrumentationResultsを使用して計測結果を表示します。次に、その結果に基づいて、変数の固定小数点データ型のプロパティを調整します。

エントリポイント関数の入力引数の型の指定

2 行 1 列の cell 配列を使用してmyFixedPointPredictの入力引数の型を指定します。

ARGS = cell(2,1);

1 番目の入力引数は予測子データです。構造体TXDataTypeフィールドは予測子データの固定小数点データ型を指定します。関数cast(Fixed-Point Designer)を使用してXT.XDataTypeで指定された型に変換します。

X_fx = cast(standardizedX,'like',T.XDataType);

テスト データ セットは学習データ セットと同じサイズではありません。coder.typeof(MATLAB Coder)を使用してARGS{1}を指定し、MEX 関数が可変サイズの入力を取ることができるようにします。

ARGS{1} = coder.typeof(X_fx,size(standardizedX),[1,0]);

2 番目の入力引数は構造体Tであり、これはコンパイル時の定数でなければなりません。coder.Constant(MATLAB Coder)を使用して、コード生成中にTを定数として指定します。

ARGS{2} = coder.Constant(T);

インストルメント化された MEX 関数の作成

buildInstrumentedMex(Fixed-Point Designer)を使用してインストルメント化された MEX 関数を作成します。

  • -argsオプションを使用してエントリポイント関数の入力引数の型を指定します。

  • -oオプションを使用して MEX 関数の名前を指定します。

  • -histogramオプションを使用してヒストグラムを計算します。

  • -coderオプションを使用して完全なコード生成サポートを許可します。

buildInstrumentedMexmyFixedPointPredict-argsARGS-omyFixedPointPredict_instrumented-histogram-coder
Code generation successful.

インストルメント化された MEX 関数のテスト

インストルメント化された MEX 関数を実行してインストルメント化の結果を記録します。

[labels_fx1,scores_fx1] = myFixedPointPredict_instrumented(X_fx,T);

インストルメント化された MEX 関数を複数回実行して、さまざまなテスト データ セットからの結果を記録できます。standardizedXTestを使用してインストルメント化された MEX 関数を実行します。

Xtest_fx = cast(standardizedXTest,'like',T.XDataType); [labels_fx1_test,scores_fx1_test] = myFixedPointPredict_instrumented(Xtest_fx,T);

インストルメント化された MEX 関数の結果の表示

showInstrumentationResults(Fixed-Point Designer)を呼び出し、インストルメント化の結果を含むレポートを開きます。シミュレーションの最小値と最大値、推定された小数部の長さ、現在の範囲の割合、0 または正の整数ステータスを表示します。

showInstrumentationResults('myFixedPointPredict_instrumented')

Xの推定された語長と小数部の長さは、構造体TXDataTypeのものと同じです。

[変数]タブのをクリックして、変数のヒストグラムを表示します。

ウィンドウには、ヒストグラム、オーバーフローとアンダーフローの可能性についての情報、および変数のデータ型が含まれています。

clearInstrumentationResults(Fixed-Point Designer)を使用して結果をクリアします。

clearInstrumentationResults('myFixedPointPredict_instrumented')

インストルメント化された MEX 関数の検証

predictmyFixedPointPredict_instrumentedからの出力を比較します。

[labels,scores] = predict(Mdl,standardizedX); verify_labels1 = isequal(labels,labels_fx1)
verify_labels1 =logical0

isequalは、labelslabels_fx1が等しい場合、logical 1 (true) を返します。ラベルが等しくない場合、不正に分類されたラベルの割合を次のように計算できます。

diff_labels1 = sum(strcmp(string(labels_fx1),string(labels))==0)/length(labels_fx1)*100
diff_labels1 = 0.1228

スコア出力間の相対的な差分の最大値を求めます。

diff_scores1 = max (abs (scores_fx1.double(: 1)上海合作组织res(:,1))./scores(:,1)))
diff_scores1 = 75.1316

固定小数点データ型の調整

記録された結果がオーバーフローまたはアンダーフローを示す場合、または生成されたコードの精度を向上させる場合、固定小数点データ型を調整できます。関数myMdl_datatypeを更新して、新しい構造体を作成して固定小数点データ型を変更し、その新しい構造体を使用してコードを生成します。関数myMdl_datatypeを更新するには、関数ファイル (myMdl_datatype.m) の固定小数点データ型を手動で変更できます。または、この例に示すように、generateLearnerDataTypeFcnを使用し、より長い語長を指定して関数を生成できます。詳細は、ヒントを参照してください。

新しいデータ型関数を生成します。生成された関数について、語長 32 と名前myMdl_datatype2を指定します。

generateLearnerDataTypeFcn('myMdl',[standardizedX; standardizedXTest],'WordLength',32,'OutputFunctionName','myMdl_datatype2')

myMdl_datatype2.mの内容を表示します。

typemyMdl_datatype2.m
function T = myMdl_datatype2(dt) %MYMDL_DATATYPE2 Define data types for fixed-point code generation % % T = MYMDL_DATATYPE2(DT) returns the data type structure T, which defines % data types for the variables required to generate fixed-point C/C++ code % for prediction of a machine learning model. Each field of T contains a % fixed-point object returned by fi. The input argument dt specifies the % DataType property of the fixed-point object. Specify dt as 'Fixed' (default) % for fixed-point code generation or specify dt as 'Double' to simulate % floating-point behavior of the fixed-point code. % % Use the output structure T as both an input argument of an entry-point % function and the second input argument of loadLearnerForCoder within the % entry-point function. For more information, see loadLearnerForCoder. % File: myMdl_datatype2.m % Statistics and Machine Learning Toolbox Version 12.4 (Release R2022b) % Generated by MATLAB, 10-Oct-2022 03:24:02 if nargin < 1 dt = 'Fixed'; end % Set fixed-point math settings fm = fimath('RoundingMethod','Floor', ... 'OverflowAction','Wrap', ... 'ProductMode','FullPrecision', ... 'MaxProductWordLength',128, ... 'SumMode','FullPrecision', ... 'MaxSumWordLength',128); % Data type for predictor data T.XDataType = fi([],true,32,27,fm,'DataType',dt); % Data type for output score T.ScoreDataType = fi([],true,32,30,fm,'DataType',dt); % Internal variables % Data type of the squared distance dist = (x-sv)^2 for the Gaussian kernel G(x,sv) = exp(-dist), % where x is the predictor data for an observation and sv is a support vector T.InnerProductDataType = fi([],true,32,22,fm,'DataType',dt); end

関数myMdl_datatype2は語長 32 を指定し、オーバーフローを回避するための最大の小数部の長さを推定します。

myMdl_datatype2を使用して、固定小数点データ型を定義する構造体T2を作成します。

T2 = myMdl_datatype2('Fixed')
T2 =struct with fields:XDataType: [0x0 embedded.fi] ScoreDataType: [0x0 embedded.fi] InnerProductDataType: [0x0 embedded.fi]

buildInstrumentedMexおよびshowInstrumentationResultsを使用して、新しいインストルメント化された MEX 関数を作成し、結果を記録し、その結果を表示します。

X_fx2 = cast(standardizedX,'like',T2.XDataType); buildInstrumentedMexmyFixedPointPredict-args{X_fx2,coder.Constant(T2)}-omyFixedPointPredict_instrumented2-histogram-coder
Code generation successful.
[labels_fx2,scores_fx2] = myFixedPointPredict_instrumented2(X_fx2,T2); showInstrumentationResults('myFixedPointPredict_instrumented2')

インストルメント化レポートを表示し、その後結果をクリアします。

clearInstrumentationResults('myFixedPointPredict_instrumented2')

myFixedPointPredict_instrumented2を検証します。

verify_labels2 = isequal(labels,labels_fx2)
verify_labels2 =logical0
diff_labels2 = sum(strcmp(string(labels_fx2),string(labels))==0)/length(labels_fx2)*100
diff_labels2 = 0.0031
diff_scores2 = max(abs((scores_fx2.double(:,1)-scores(:,1))./scores(:,1)))
diff_scores2 = 3.4514

不正に分類されたラベルの割合diff_labels2とスコア値の相対差分diff_scores2は、既定の語長 (16) を使用して生成された以前の MEX 関数からの値よりも小さくなります。

MATLAB® コードのインストルメント化による固定小数点データ型の最適化の詳細については、buildInstrumentedMex(Fixed-Point Designer)showInstrumentationResults(Fixed-Point Designer)、およびclearInstrumentationResults(Fixed-Point Designer)のリファレンス ページと例最小/最大計測機能を使用したデータ型の設定(Fixed-Point Designer)を参照してください。

コードの生成

codegenを使用して、エントリポイント関数のコードを生成します。予測子データ セットに可変サイズの入力を指定するのではなく、coder.typeofを使用して固定サイズの入力を指定します。生成されるコードに渡す予測子データ セットのサイズがわかっている場合は、固定サイズの入力のコードを生成するほうが、コードを簡略化するには望ましいです。

codegenmyFixedPointPredict-args{coder.typeof(X_fx2,[1,5],[0,0]),coder.Constant(T2)}
Code generation successful.

codegenは、プラットフォームに依存する拡張子をもつ MEX 関数myFixedPointPredict_mexを生成します。

生成されたコードの確認

インストルメント化された MEX 関数を検証するのと同じ方法で、関数myFixedPointPredict_mexを検証できます。詳細については「インストルメント化された MEX 関数の検証」セクションを参照してください。

[labels_sampled,scores_sampled] = predict(Mdl,standardizedX_sampled); n = size(standardizedX_sampled,1); labels_fx = true(n,1); scores_fx = zeros(n,2);fori = 1:n [labels_fx(i),scores_fx(i,:)] = myFixedPointPredict_mex(X_fx2(idx(i),:),T2);endverify_labels = isequal(labels_sampled,labels_fx)
verify_labels =logical1
diff_labels = sum(strcmp(string(labels_fx),string(labels_sampled))==0)/length(labels_fx)*100
diff_labels = 0
diff_scores = max(abs((scores_fx(:,1)-scores_sampled(:,1))./scores_sampled(:,1)))
diff_scores = 0.0626

メモリの使用

モデルを学習させる前に手動で予測子データを標準化することをお勧めします。代わりに名前と値のペアの引数'Standardize'を使用する場合、生成される固定小数点コードには標準化演算が含まれます。これにより、精度の低下やメモリ使用量の増加が起こる可能性があります。

スタティック ライブラリを生成すると、コード生成レポートを使用することにより、生成されたコードのメモリ使用量がわかります。-config:libを指定してスタティック ライブラリを生成し、-reportオプションを使用してコード生成レポートを生成します。

codegenmyFixedPointPredict-args{coder.typeof(X_fx2,[1,5],[0,0]),coder.Constant(T2)}-omyFixedPointPredict_lib-config:lib-report

コード生成レポートの[概要]タブで[コード メトリクス]をクリックします。[関数情報] セクションには累積スタック サイズが表示されます。

'Standardized','true'で学習されたモデルのメモリ使用量を求めるには、次のコードを実行できます。

Mdl = fitcsvm(X_sampled,Y_sampled,'Weight',w_sampled,'KernelFunction','gaussian','Standardize',true); saveLearnerForCoder(Mdl,'myMdl'); generateLearnerDataTypeFcn('myMdl',[X; XTest],'WordLength',32,'OutputFunctionName','myMdl_standardize_datatype') T3 = myMdl_standardize_datatype('Fixed'); X_fx3 = cast(X_sampled,'like',T3.XDataType); codegenmyFixedPointPredict-args{coder.typeof(X_fx3,[1,5],[0,0]),coder.Constant(T3)}-omyFixedPointPredict_standardize_lib-config:lib-report

参考

||(Fixed-Point Designer)|(Fixed-Point Designer)|(Fixed-Point Designer)|(MATLAB Coder)|(Fixed-Point Designer)||(Fixed-Point Designer)

関連するトピック