Skip to content

[Microsoft.Extensions.ML] PredictionEnginePool.GetModel(string modelName) does not ensure the named model is loaded #5831

Description

@wjwilimowski

Preface

We're using a named prediction engine with the name model1 in a PredictionEnginePool.

services
    .AddPredictionEnginePool<ModelInput, ModelOutput>()
    .FromFile(modelName: "model1", filePath: "MLModel.zip", watchForChanges: false);

Example usage:

private readonly PredictionEnginePool<ModelInput, ModelOutput> _pool;

public void ThisWorks()
{
    // This will initialize the "model1" prediction engine if it hasn't been used yet
    // See source code:
    // https://github.com/dotnet/machinelearning/blob/58450d4f0709c237de95f31f8f05d46983c7a5c0/src/Microsoft.Extensions.ML/PredictionEnginePool.cs#L81
    PredictionEngine<ModelInput, ModelOutput> engine = _pool.GetPredictionEngine("model1");
    
    // We can now use the engine, then return it to the pool
}

In the above snippet, the PredictionEnginePool.GetPredictionEngine(string modelName) method ensures the engine is loaded before use.

//Here we are in the world of named models where the model hasn't been built yet.
var options = _predictionEngineOptions.Create(modelName);
var pool = new PoolLoader<TData, TPrediction>(_serviceProvider, options);
pool = _namedPools.GetOrAdd(modelName, pool);
return pool.PredictionEnginePool.Get();

The issue

If _pool.GetPredictionEngine("model1") has never been called before calling _pool.GetModel("model1"), the model1 prediction engine is not loaded and KeyNotFoundException will be thrown.

private readonly PredictionEnginePool<ModelInput, ModelOutput> _pool;

public void ThisDoesNotWork()
{
    // Throws KeyNotFoundException unless _pool.GetPredictionEngine("model1") has been called before
    // See source code:
    // https://github.com/dotnet/machinelearning/blob/58450d4f0709c237de95f31f8f05d46983c7a5c0/src/Microsoft.Extensions.ML/PredictionEnginePool.cs#L51
    ITransformer model = _pool.GetModel("model1");
}

This inconsistent behavior can easily catch someone off-guard - one expects every public method on PredictionEnginePool to have the same "ensure initialized" behavior.

public ITransformer GetModel(string modelName)
{
return _namedPools[modelName].Loader.GetModel();
}

Code example

https://github.com/wjwilimowski/UnexpectedPredictionEnginePool

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions