# IMLPredictor

In NatML, predictors are lightweight primitives that make edge (on-device) predictions with one or more [`MLModel`](https://docs.natml.ai/js/api/mlmodel) instances. Predictors play a very crucial role in using ML models, because of their two primary purposes:

* Predictors provide models with the exact input data they need.
* Predictors convert model outputs to a form that is usable by developers.

{% hint style="success" %}
You will typically never have to implement `IMLPredictor` yourself. Instead, discover existing edge predictors on [NatML Hub](https://hub.natml.ai).
{% endhint %}

## Defining the Predictor

**All edge predictors must** implement this interface. The predictor has a single generic type argument, `TOutput`, which is a developer-friendly type that is returned when a prediction is made. For example, a `MobileNetv2Predictor` for the MobileNet v2 image classifier model will use a tuple for its output type:

```typescript
// The MobileNetv2 classification predictor returns a (label, score) tuple
class MobileNetv2Predictor implements IMLPredictor<[string, number]> { ... }
```

{% hint style="info" %}
Edge predictor class name should always end with `"Predictor"`.
{% endhint %}

## Writing the Constructor

**All edge predictors must** define one or more constructors that accept one or more [`MLModel`](https://docs.natml.ai/js/api/mlmodel) instances, along with any other predictor data needed to make predictions with the model(s). For example:

```typescript
/**
 * Create a predictor
 * @param model ML model used to make predictions.
 */
public constructor (model: MLModel) { ... }
```

Within the constructor, the model should store a `readonly` reference to the model(s). The type of this reference should be [`MLEdgeModel`](https://docs.natml.ai/js/api/mlmodel/mledgemodel):

```csharp
// Define the `model` member
private readonly model: MLEdgeModel;
// And in the constructor...
constructor (model: MLModel) {
    this.model = model as MLEdgeModel;
}
```

{% hint style="info" %}
The [`MLEdgeModel`](https://docs.natml.ai/js/api/mlmodel/mledgemodel) class extends [`MLModel`](https://docs.natml.ai/js/api/mlmodel), and exposes a `predict` method for making edge predictions.
{% endhint %}

## Making Predictions

**All edge predictors must** implement a public `predict` method which accepts a variadic `MLFeature[]` and returns a `TOutput`:

```typescript
/**
 * Make a prediction on one or more input features.
 * @param inputs Input features.
 * @returns Prediction output.
 */
public predict (...inputs: MLFeature[]): TOutput;
```

Within the `predict` method, the predictor should do three things:

### Input Checking

The predictor should check that the client has provided the correct number of input features, and that the features have the model's [expected types](https://docs.natml.ai/js/mlmodel#input-features).

{% hint style="warning" %}
If these checks fail, an appropriate exception should be thrown. Do this instead of returning an un-initialized output.
{% endhint %}

### Prediction

{% hint style="warning" %}
NatML for NodeJS currently does not support making predictions with edge predictors.
{% endhint %}

### Marshaling

Once you have raw output features from the model, you can then marshal the feature data into a more developer-friendly type. This is where most of the heavy-lifting happens in a predictor:

```csharp
// Marshal the output feature data into a developer-friendly type
const outputArrayFeature = new MLArrayFeature<Float32Array>(rawOutputFeatures[0]);
// Do stuff with this data...
...
```

Finally, return your predictor's output:

```csharp
// Create the prediction result from the output data
const result: TOutput = ...;
// Return it
return result;
```

## Disposing the Predictor

Edge predictors may define a `dispose` method. This method should be used to dispose any explicitly-managed resources used by the predictor, like recurrent state for recurrent models.

{% hint style="danger" %}
The predictor **must not** `dispose` any models provided to it. This is the responsibility of the client.
{% endhint %}
