Embedded Coder for C - can loadLearnerForCoder generate global constants?

5 views (last 30 days)
Hi all,
I'm working on a project that involves generating C code for a Cortex-M micro.
We have trained a model in Matlab using ClassificationSVM and saved it with saveLearnerForCoder. We then used the Matlab embedded coder to generate the C code for our prediction function.
Everything is working fine, except I'm a little frustated by the code generated for loadLearnerForCoder (located inside the prediction function). Indeed, the Matlab code:
trainedModelBase = loadLearnerForCoder('model/embeddedModelBase.mat', 'DataType','single');
Generates the following C function:
float c_CompactClassificationSVM_Comp(
float obj_Alpha[1106],
float obj_SupportVectorsT[35392],
float *obj_Scale,
float *obj_Order,
float obj_Mu[32],
float obj_Sigma[32],
d_classreg_learning_coderutils_ *obj_KernelFunction,
int obj_ClassNamesLength[2], c_classreg_learning_coderutils_
*obj_ScoreTransform,
float obj_Prior[2],
bool obj_ClassLogicalIndices[2],
float obj_Cost[4]
)
Which all it does is using memcpy to pass the model and hyperparameters:
...
memcpy(&obj_SupportVectorsT[0], &fv[0], 35392U * sizeof(float));
...
This is not optimal for us, as memory is limited on our target.
What I'm doing now is manually moving the model variables to globals, but I would love to find a better way.
Thus, I was wondering if there was any way of making the Embedded coder generating global constants instead?
I've tried to load the model before invoking the coder and specify it as a global constant (inspired by coder.Constant) with:
%% Load the model as a global const
trainedModelBase = loadLearnerForCoder('model/embeddedModelBase.mat', 'DataType','single');
globals = {'trainedModelBase', coder.Constant(trainedModelBase)};
%% Invoke MATLAB Coder.
codegen -config cfg -globals globals -singleC Predicto -args ARGS{1}
But it gives me the following error:
Error using coder.Constant
'coder.typeof' and 'coder.Constant' not supported for the input object. Use
'saveLearnerForCoder' and 'loadLearnerForCoder' for generating code instead.
Error in GeneratedCode (line 32)
globals = {'trainedModelBase', coder.Constant(trainedModelBase)};
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This problem might not have a good answer, and I'm affraid it's just not possible to do so.
Feel free to ask me more details if that doesn't make enough sense.

Answers (1)

Harsh
Harsh on 30 May 2025
Hi @Hugo,
I understand that “loadLearnerForCodergenerated code uses runtime memcpy to load your SVM model, eating up RAM on Cortex-M targets. You can avoid this in two ways -
1) Use a single MATLAB Coder entry point function to load the SVM Struct and then use predict function. Consider the following dataset (for demonstration purpose only) -
X = [randn(50,2)+1.5; randn(50,2)-1.5];
Y = [ones(50,1); -ones(50,1)];
% Fit an SVM with a Gaussian kernel, single precision
svmModel = fitcsvm(X, Y, ...
'KernelFunction','rbf', ...
'Standardize',true, ...
'BoxConstraint',1, ...
'ClassNames',[-1,1]);
svmModel = compact(svmModel); % reduce size for codegen
saveLearnerForCoder(svmModel, 'svmModelForCoder.mat');
In MATLAB create a “svmPredictEntry” function -
function labels = svmPredictEntry(data)
%#codegen
svmStruct = loadLearnerForCoder('svmModelForCoder.mat', 'DataType','single');
labels = predict(svmStruct, data);
end
From command line, generate code :
codegen -c svmPredictEntry -args {zeros(1,2,'single')}
In the generated Code, the supportVectors appear as constants within the function scope, hence eliminating the need to copy data using “memcpy”.
2) Consider wrapping each array in a Simulink.Parameter object and set its “customStorageClass” if you can write the predict function using the trained parameters.
Let’s use the same data as above for demonstration,
- Create “Simulink.Parameter” with “Custom” storage class and set to “Const”
alpha = Simulink.Parameter(single(svmModel.Alpha));
alpha.CoderInfo.StorageClass = 'Custom';
alpha.CoderInfo.CustomStorageClass = 'Const';
svT = Simulink.Parameter(single(svmModel.SupportVectors'));
svT.CoderInfo.StorageClass = 'Custom';
svT.CoderInfo.CustomStorageClass = 'Const';
mu = Simulink.Parameter(single(svmModel.Mu));
mu.CoderInfo.StorageClass = 'Custom';
mu.CoderInfo.CustomStorageClass = 'Const';
sigma= Simulink.Parameter(single(svmModel.Sigma));
sigma.CoderInfo.StorageClass = 'Custom';
sigma.CoderInfo.CustomStorageClass = 'Const';
Create a Simulink model with a MATLAB Function block with the following code -
function y = fcn(u, alpha, mu, sigma)
%#codegen
arguments (Input)
u (1,1) single
alpha
mu
sigma
end
arguments (Output)
y (1,1) single
end
% Simple predict: here we just do a linear combination for demo
y = alpha(1)*u + mu(1) - sigma(1);
end
Note that you must set the Scope as Parameter” for all the inputs in MATLAB Function block. After opening the MATLAB function block, click on “Edit Data”. Then click on “create Data” from “Symbols” window. Also set the correct “size” and “type” for each input.
Finally set the system target file to “ert.tlc” and generate the code for your model. Here’s a snapshot of the generated code with global constants:
Hope this resolves your query!

Categories

Find more on MATLAB Coder in Help Center and File Exchange

Products


Release

R2024b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!