Main Content

In-Place Model Update of Offline Linear Model Using IncrementalClassificationLinear Predict Block

Since R2025a

This example shows how to use the incremental variants of offline Simulink® blocks to update the model parameters while running a simulation and without regeneration of deployed code. Offline models have fixed parameter values obtained from training the model on a dataset.

Applying in-place model updates reduces the effort required to regenerate, redeploy, and reverify C/C++ code when you retrain a model with new data or configurations. Specifically, this example uses the IncrementalClassificationLinear Predict block for label prediction and does the following:

  1. Train multiple linear models with different subsets of data.

  2. Extract model parameters like beta and bias values for each model.

  3. Run a simulation and while the model is running, switch between different sets of model parameters.

  4. Observe changes in model performance by observing loss values using the Update Metrics block.

  5. Generate C code from the Simulink model that can accept model parameters at runtime.

The use of the IncrementalClassificationLinear Predict block is preferred for in-place model updates as the block accepts the model parameters as a bus input. Although this example demonstrates a binary classification workflow, you can implement regression or multiclass classification by constructing the corresponding model object bus with the corresponding incremental predict block. Note that this applies to models that have incremental variants such as ECOC, Naive Bayes, Linear and Kernel.

Load and Preprocess Data

Load the human activity data set. For details on the data set, enter Description at the command line.

Responses can be one of five classes: Sitting, Standing, Walking, Running, or Dancing. Dichotomize the response by identifying whether the subject is moving (actid > 2).

load humanactivity
X = feat;
Y = actid;
Y = Y > 2;

Randomly shuffle the data into three sets.

rng(0,"twister") % For reproducibility
n = numel(Y);
idx1 = randsample(n,floor(n/300));
X1 = X(idx1,:);
Y1 = Y(idx1);

idx2 = randsample(n,floor(n/30));
X2 = X(idx2,:);
Y2 = Y(idx2);

idx3 = randsample(n,n);
X3 = X(idx3,:);
Y3 = Y(idx3);

Train Classification Models and Extract Model Parameters

Train three linear models using the three sets of data partitions.

linMdl1 = fitclinear(X1,Y1);
linMdl2 = fitclinear(X2,Y2);
linMdl3 = fitclinear(X3,Y3);

Extract the model parameters, Beta and Bias, from the trained model objects and concatenate them into a single vector.

BetaBias1 = [linMdl1.Beta;linMdl1.Bias];
BetaBias2 = [linMdl2.Beta;linMdl2.Bias];
BetaBias3 = [linMdl3.Beta;linMdl3.Bias];

Create Input Data for Simulink

Simulate streaming data by passing one observation at each timestep to the IncrementalClassficationLinear Predict Block.

Convert the training data into time series data.

t = 0:size(X,1)-1;
Xin_ts = timeseries(X,t,InterpretSingleRowDataAs3D=true); 
Yin_ts = timeseries(Y,t,InterpretSingleRowDataAs3D=true);

Configure Model for Simulink

Open the provided Simulink model slexInPlaceModelUpdate.slx. This model uses the IncrementalClassificationLinear Predict block for prediction using tunable Beta and Bias values and an Update Metrics block for computation of classification loss values, window loss and cumulative loss. The window loss values are computed over MetricsWindowSize observations, with the default window size of 200 observations.

Double-click the IncrementalClassificationLinear Predict block to open the Block Parameters dialog box. Specify the Select initial machine learning model parameter as linMdl1, the workspace variable that contains the trained linear model. Select the Add output port for predicted class scores check box to add the second output port score. Click the OK button.

SimMdlName = "slexInPlaceModelUpdate"; 
open_system(SimMdlName);

The input bus signal is created by the addModelParamsToBus subsystem shown below that adds the Beta and Bias values to a bus, along with nontunable parameters like Prior, IsWarm, CanPredict and MajorityClass. There are two manual switches to toggle the Beta and Bias values used as input to the subsystem. OutBus is the model input to the IncrementalClassificationLinear Predict and Update Metrics block.

Create three vectors by concatenating Beta, Bias and Prior values.

BetaBiasPrior1 = [BetaBias1;linMdl1.Prior'];
BetaBiasPrior2 = [BetaBias2;linMdl2.Prior'];
BetaBiasPrior3 = [BetaBias3;linMdl3.Prior'];

Set a stop time and simulate the model.

sim(SimMdlName,StopTime="n"); 

The manual switch blocks can be double-clicked to toggle the use of different Beta, Bias and Prior values at runtime.

Configure Model for Tunable Parameters in Generated Code

To configure the model for tunable model parameters in generated code, use the provided slexInPlaceModelUpdateCodeExample.slx model that includes only the IncrementalClassficationLinear Predict block.

CodeMdlName = "slexInPlaceModelUpdateCodeExample"; 
open_system(CodeMdlName)

This model uses the input BetaBias for beta and bias values. To configure the parameters for runtime tuning, use a Simulink.Parameter object with the same name.

BetaBias = Simulink.Parameter(BetaBias1);

To make BetaBias represent a global variable that the external code defines, use the built-in storage class ImportedExternPointer. To learn more about storage classes, see ImportedExtern, ImportedExternPointer (Embedded Coder). Lastly, set the GenCodeOnly="on" to only generate code without building the executable.

BetaBias.CoderInfo.StorageClass = "ImportedExternPointer";
set_param(CodeMdlName,GenCodeOnly="on")

To generate code, press Ctrl+B in the Simulink model window.

After the code generation process is complete, click the View Code button to open the Code section where you can see the generated code.

The generated C/C++ algorithmic code reads from and writes to a global variable defined by the external code.The generated code declares the variable in the generated file model_private.h so that the model entry-point functions can read and write to the variable. Navigate to the slexInPlaceModelUpdateCodeExample_private.h file in the right-hand code pane and observe how the parameter BetaBias is defined as a pointer. The generated code does not use a model_data.c file to define the BetaBias parameter internally and instead expects the value to be defined by the user.

In conclusion, this allows you to change the model parameters by updating the global variable BetaBias, without having to regenerate code for the IncrementalClassificationLinear Predict block.

See Also