Main Content

Model Implementation for Modelscape Deploy

This example shows you how to use and implement the Modelscape™ Deploy™.

Modelscape Deploy supports a generic interface for specifying model inputs, model outputs, and a single method to execute models. This example explains the interface and shows you how a model developer must implement it.

This example uses a toy model that takes inputs x and y and calculates the weighted sum z = A*x + B*y, where A and B are scalar weights. If x and y are vectors, the evaluation of the model is a batch evaluation for each pair of elements in x and y. The scalars A and B are configurable, but constant across a batch of evaluations – and are therefore regarded as parameters.

Realistic examples of inputs varying within a batch are the contract details for a book of derivative transactions, and the data corresponding to a group of credit card applicants. Examples of parameters corresponding to these inputs are the number of Monte Carlo paths used for pricing the derivatives, and certain macro-economic data used for credit-scoring the loan applicants. Note that the batch parameters are fixed for all inputs within a batch.

Work with Modelscape Deploy

Models to be executed in Modelscape Deploy must be implemented as subclasses of mrm.execution.Model.

classdef WeightedSum < mrm.execution.Model

Both the inputs and the outputs of the model execution must be tables. Each model class defines how to interroage the input table and populate the output table.

Methods for Inputs and Outputs

Each model must implement three methods for specifying the inputs and the outputs of the model.

  • getInputs: returns the definition of the variables required for each evaluation in a batch - for example, the names and types of x and y above.

  • getParameters: returns the definition of the variables that are fixed within a batch of evaluations - that is the names and types of A and B above.

  • getOutputs: returns the definition of the output variables - variable z above.

The output, in each case, should be a struct with the following fields:

  • name: a cell array of strings containing the names of the input/output variables.

  • type: a cell array of structs defining the type of each input/output variable - each struct should have a field called name with any of the values listed in mwtype.

  • sizes: a cell array of two-element arrays [a b] defining the size of each input/output variable - use NaN to indicate unrestricted size, e.g. [1 NaN] for a single column of an arbitrary height.

Define the toy model as follows.

function parameters = getInputs(~)
    doubleDatatype = struct( ...
        "name", "double");
    parameters = struct( ...
        "name", {"X", "Y"}, ...
        "dataType", {doubleDatatype, doubleDatatype});
end

function parameters = getParameters(~)
    doubleDatatype = struct( ...
        "name", "double");
    parameters = struct( ...
        "name", {"A", "B"}, ...
        "dataType", {doubleDatatype, doubleDatatype});
end

function parameters = getOutputs(~)
    doubleDatatype = struct( ...
        "name", "double");
    parameters = struct( ...
        "name", {"Z"}, ...
        "dataType", {doubleDatatype});
end

Evaluation Method

Define the evaluate method as follows.

[outputs, diagnostics, batchDiagnostics] = evaluate(this, inputs, parameters)

Here inputs should be a table, with a row for each evaluation within the batch, and parameters should be struct, that contains the variables that apply to all evaluations within the batch.

The outputs variable must be a table and contain a row for each row of the inputs table. The diagnostics output must be an array of structs, one for each row of the input table. The batchDiagnostic output is a single diagnostic for the whole batch and must be a scalar struct.

The toy model also has the following definition.

function [outputs, diagnostics, batchDiagnostics] = evaluate(~, inputs, parameters)
    outputs = table( ...
        parameters.A * inputs.X + parameters.B * inputs.Y, ...
        'VariableNames', {'Z'}, ...
        'RowNames', inputs.Properties.RowNames);
    rawDiagnostics = [inputs.Properties.RowNames, repmat({struct()}, numel(inputs.Properties.RowNames), 1)]';
    diagnostics = struct(rawDiagnostics{:});
    batchDiagnostics = struct();
end

In this case the diagnostics structs are empty. In the more complicated examples listed above, they could carry, for instance, information about the Monte Carlo noise present in the valuation.

Create an image for Deployment

To deploy a model that implements the mrm.execution.Model interface, firstly, package the executable model code into a Docker® image suitable for deployment using MATLAB® Compiler SDK. Use the helper function mrm.execution.packageModel to do this.

modelInstance = WeightedSum();
outputFolder = tempname();
imageName = mrm.execution.compiler.packageModel(modelInstance, ...
    OutputFolder=outputFolder, ...
    Name="weighted-sum", ...
    Tag="v1")
Runtime Image Already Exists
Sending build context to Docker daemon    278kB

Step 1/6 : FROM matlabruntime/r2023a/prerelease/update0/308000000000000000
 ---> 9578d4e15248
Step 2/6 : COPY ./applicationFilesForMATLABCompiler /usr/bin/mlrtapp
 ---> ff0709fcec70
Step 3/6 : RUN chmod -R a+rX /usr/bin/mlrtapp/*
 ---> Running in c83375557f83
Removing intermediate container c83375557f83
 ---> da1d6f8978b3
Step 4/6 : RUN useradd -ms /bin/bash appuser
 ---> Running in aab934c26070
Removing intermediate container aab934c26070
 ---> 5e5490e6e58e
Step 5/6 : USER appuser
 ---> Running in fd6d76d6d108
Removing intermediate container fd6d76d6d108
 ---> 54efdb411a1b
Step 6/6 : ENTRYPOINT ["/opt/matlabruntime/R2023a/bin/glnxa64/muserve", "-a", "/usr/bin/mlrtapp/weightedsum.ctf"]
 ---> Running in 4c6771bc9751
Removing intermediate container 4c6771bc9751
 ---> 0da443f8e974
Successfully built 0da443f8e974
Successfully tagged weighted-sum:v1

DOCKER CONTEXT LOCATION:

/tmp/tp984f0556_95f6_46b1_a428_473bcc9e54dc/docker


FOR HELP GETTING STARTED WITH MICROSERVICE IMAGES, PLEASE READ:

/tmp/tp984f0556_95f6_46b1_a428_473bcc9e54dc/docker/GettingStarted.txt

Sending build context to Docker daemon  4.608kB

Step 1/7 : FROM weighted-sum:v1
 ---> 0da443f8e974
Step 2/7 : COPY ./routes.json /usr/bin/mlrtapp/routes.json
 ---> e97e7b05ec7e
Step 3/7 : USER root
 ---> Running in 01c65af653f1
Removing intermediate container 01c65af653f1
 ---> 276549f8c441
Step 4/7 : RUN useradd -u 2000 -ms /bin/bash modeluser
 ---> Running in e5d62f47d4fa
Removing intermediate container e5d62f47d4fa
 ---> 206c7ad88b83
Step 5/7 : USER 2000
 ---> Running in 98307802e3cb
Removing intermediate container 98307802e3cb
 ---> 0ac44031eb4a
Step 6/7 : EXPOSE 8080
 ---> Running in 75b018a3bd8d
Removing intermediate container 75b018a3bd8d
 ---> 314e6255d91e
Step 7/7 : CMD ["--http", "8080","--routes-file", "/usr/bin/mlrtapp/routes.json"]
 ---> Running in 1549e1f467cc
Removing intermediate container 1549e1f467cc
 ---> f703f5e9bd1b
Successfully built f703f5e9bd1b
Successfully tagged weighted-sum:v1
imageName = 
"weighted-sum:v1"

Deploy to Modelscape Deploy

The image must be pushed to a Docker registry visible to the Modelscape API. For the next steps, choose the model version for which you want to create a model version build. Create the build, a deployment environment, and deploy your build.