Search code examples
ml.netasp.net-core-middleware

How to add model to PredictionEnginePool in middleware (ML.NET)?


I'm using ML.NET in an ASP.NET Core application, and I am using the following code in Startup:

var builder = services.AddPredictionEnginePool<Foo, Bar>();

if (File.Exists("model.zip"))
{
    builder.FromFile(String.Empty, "model.zip", true);
}

If model.zip doesn't exist, I create it later in the middleware. How do I add it to the PredictionEnginePool that is injected?

There are no options to load a model via PredictionEnginePool, and instantiating or injecting a PredictionEnginePoolBuilder isn't an option as it requires IServiceCollection (so must be configured during Startup.ConfigureServices).

The only option I can see at the moment is to set a flag if the file doesn't exist at startup, and then restart the service after model.zip is created in the middleware later on (using IApplicationLifetime.StopApplication), but I really don't like this as an option.


Solution

  • PredictionEnginePool is designed in such a way that you can write your own ModelLoader implementation. Out of the box, Microsoft.Extensions.ML has 2 loaders, File and Uri. When those don't meet your needs, you can drop down and write your own.

    See https://github.com/dotnet/machinelearning-samples/pull/560 which changes one of the dotnet/machine-learning samples to use an "in-memory" model loader, it doesn't get the model from a file or a Uri. You can follow the same pattern and write whatever code you need to get your model.

        public class InMemoryModelLoader : ModelLoader
        {
            private readonly ITransformer _model;
    
            public InMemoryModelLoader(ITransformer model)
            {
                _model = model;
            }
    
            public override ITransformer GetModel() => _model;
    
            public override IChangeToken GetReloadToken() =>
                // This IChangeToken will never notify a change.
                new CancellationChangeToken(CancellationToken.None);
        }
    

    And then in Startup.cs

                services.AddPredictionEnginePool<ImageInputData, ImageLabelPredictions>();
                services.AddOptions<PredictionEnginePoolOptions<ImageInputData, ImageLabelPredictions>>()
                    .Configure(options =>
                    {
                        options.ModelLoader = new InMemoryModelLoader(_mlnetModel);
                    });