【问题标题】:How to add model to PredictionEnginePool in middleware (ML.NET)?如何在中间件(ML.NET)中将模型添加到 PredictionEnginePool?
【发布时间】:2020-01-01 02:10:12
【问题描述】:

我在 ASP.NET Core 应用程序中使用 ML.NET,我在 Startup 中使用以下代码:

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

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

如果 model.zip 不存在,我稍后会在中间件中创建它。如何将其添加到注入的PredictionEnginePool

没有通过PredictionEnginePool 加载模型的选项,实例化或注入PredictionEnginePoolBuilder 不是一个选项,因为它需要IServiceCollection(因此必须在Startup.ConfigureServices 期间配置)。

目前我能看到的唯一选项是如果文件在启动时不存在,则设置一个标志,然后稍后在中间件中创建 model.zip 后重新启动服务(使用IApplicationLifetime.StopApplication),但我真的不喜欢这个选项。

【问题讨论】:

  • 我也注意到PredictionEnginePool 的这个限制。我能想到的唯一解决方法是,如果您不能始终保证文件存在,可能是运行 Azure 函数或计划任务来检查它是否不存在,然后从 Azure 存储或其他地方获取它。跨度>
  • @Jon 是的,但它在Startup.ConfigureServices 期间不存在的原因是它尚未创建。然后,我的应用稍后将在中间件中创建它,这当然是在 Startup.ConfigureServices 运行之后。此时,我需要通过PredictionEnginePool 访问模型,这意味着我需要以编程方式重新启动应用程序,以便在启动期间可以读取 model.zip。我想还有另一种方法可以做到这一点,那就是将我的 API 分成两部分——一个负责创建模型,一个负责使用它(有 PredictionEnginePool)。

标签: ml.net asp.net-core-middleware


【解决方案1】:

PredictionEnginePool 的设计方式使您可以编写自己的ModelLoader 实现。开箱即用,Microsoft.Extensions.ML 有 2 个加载程序,文件和 Uri。当这些不能满足您的需求时,您可以下拉并自己编写。

请参阅 https://github.com/dotnet/machinelearning-samples/pull/560,它将 dotnet/机器学习示例之一更改为使用“内存中”模型加载器,它不会从文件或 Uri 中获取模型。您可以遵循相同的模式并编写获取模型所需的任何代码。

    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);
    }

然后在 Startup.cs 中

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

【讨论】:

  • 感谢您的回答,并为延迟回复表示歉意。您提到的 PR 中的更改依赖于 TensorFlowModelConfigurator.ModelStartup 期间从文件路径设置。因此,在 Startup 已经过去之后,这本身并不能解决我稍后在中间件中创建模型的问题。那么,您是否建议我通过将我的中间件服务(例如通过ConfigureServices 中的services.BuildServiceProvider().GetService 获得)传递给自定义ModelLoader,然后在调用GetModel 时从中获取模型来实现这一点?
  • 我是说你可以按照这个模式编写一个继承自ModelLoader 的类,并在该类中做任何你需要的事情来访问模型。因此,如果您需要引用某个中间件服务来获取模型,那么您可以编写一个知道该中间件服务的MyMiddlewareServiceLoader : ModelLoader
  • 我尝试使用自定义ModelBuilder,但发现在Startup.ConfigureServices 期间我无法访问中间件服务,并且AddPredictionEnginePool 不提供接受我通常会的实现工厂的重载能够访问IServiceProvider,就像我使用AddAddSingletonAddScopedAddTransient 一样。使用我之前提到的方法 (ServiceProvider.BuildServiceProvider) 会导致警告说将创建一个额外的单例服务副本。我已经解决了这个问题并提出了 PR here
猜你喜欢
  • 1970-01-01
  • 2021-05-12
  • 1970-01-01
  • 2017-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多