在 ASP.NET Core Web API 中部署模型

了解如何使用 ASP.NET Core Web API 在 Web 上提供预先训练的 ML.NET 机器学习模型。 通过 Web API 提供模型可实现通过标准 HTTP 方法进行预测。

先决条件

创建 ASP.NET Core Web API 项目

  1. 启动 Visual Studio 2022 并选择“创建新项目”。

  2. 在“创建新项目”对话框中:

    • 在搜索框中输入 Web API
    • 选择“ASP.NET Core Web API”模板,然后选择“下一步”。
  3. 在“配置项目”对话框中:

    • 将项目命名为 SentimentAnalysisWebAPI。
    • 选择“下一页”。
  4. 在“其他信息”对话框中:

    • 取消选中“不使用顶级语句”。
    • 选择“创建”。
  5. 安装以下 NuGet 包:

    有关在 Visual Studio 中安装 NuGet 包的详细信息,请参阅在 Visual Studio 中安装和使用 NuGet 包指南。

将模型添加到 ASP.NET Core Web API 项目

  1. 将预生成的模型复制到 SentimentAnalysisWebAPI 项目目录中。

  2. 配置项目以将模型文件复制到输出目录中。 在“解决方案资源管理器”中:

    • 右键单击模型 zip 文件并选择“属性”。
    • 在“高级”下,将“复制到输出目录”的值更改为“如果较新则复制”。

创建数据模型

需要创建一些类来定义模型输入和输出的架构。

注意

输入和输出架构类的属性取决于用于训练模型的数据集列以及机器学习任务(回归、分类等)。

在 Program.cs 文件中:

  1. 添加以下 using 语句:

    using Microsoft.ML.Data;
    using Microsoft.Extensions.ML;
    
  2. 在文件底部添加下列类:

    模型输入

    对于此模型,输入包含单个属性 SentimentText,该属性是表示用户注释的字符串。

    public class ModelInput
    {
        public string SentimentText;
    }
    

    模型输出

    模型评估输入后,会输出具有以下三个属性的预测:SentimentProbabilityScore。 在这种情况下,Sentiment 是用户注释的预测情绪,ProbabilityScore 是预测的置信度度量值。

    public class ModelOutput
    {
        [ColumnName("PredictedLabel")]
        public bool Sentiment { get; set; }
    
        public float Probability { get; set; }
    
        public float Score { get; set; }
    }
    

注册 PredictionEnginePool 用于应用程序

若要进行单一预测,必须创建 PredictionEnginePredictionEngine 不是线程安全。 此外,必须在应用程序中的每一处所需位置创建它的实例。 随着应用程序的增长,此过程可能会变得难以管理。 为了提高性能和线程安全,请结合使用依赖项注入和 PredictionEnginePool 服务,这将创建一个在整个应用程序中使用的 PredictionEngine 对象的 ObjectPool

如果想要详细了解 ASP.NET Core 中的依赖项注入,以下链接提供详细信息。

将以下代码添加到 Program.cs 文件:

builder.Services.AddPredictionEnginePool<ModelInput, ModelOutput>()
    .FromFile(modelName: "SentimentAnalysisModel", filePath: "sentiment_model.zip", watchForChanges: true);

概括地讲,此代码在应用程序请求时自动初始化对象和服务供以后使用,无需手动执行初始化。

机器学习模型不是静态的。 随着新的训练数据变得可用,模型将重新训练和重新部署。 将最新版本的模型引入应用程序的一种方法是重启或重新部署应用程序。 但这会导致应用程序关闭。 PredictionEnginePool 服务提供一种机制,用于在不重启或重新部署应用程序的情况下重新加载已更新的模型。

watchForChanges 参数设置为 true,则 PredictionEnginePool 会启动 FileSystemWatcher,用于侦听文件系统更改通知并在文件发生更改时引发事件。 这会提示 PredictionEnginePool 自动重新加载模型。

模型由 modelName 参数标识,因此更改时可以重新加载每个应用程序的多个模型。

提示

或者,如果使用远程存储的模型,则可以使用 FromUri 方法。 FromUri 会轮询远程位置以获取更改,而不是监视文件更改事件。 轮询间隔默认为 5 分钟。 你可以根据应用程序的要求,增加或减少轮询间隔。 在下面的代码示例中,PredictionEnginePool 每分钟轮询存储在指定 URI 中的模型。

services.AddPredictionEnginePool<SentimentData, SentimentPrediction>()
  .FromUri(
      modelName: "SentimentAnalysisModel",
      uri:"https://github.com/dotnet/samples/raw/main/machine-learning/models/sentimentanalysis/sentiment_model.zip",
      period: TimeSpan.FromMinutes(1));

映射预测终结点

若要处理传入的 HTTP 请求,请创建终结点。

/ 终结点替换为以下内容:

var predictionHandler =
    async (PredictionEnginePool<ModelInput, ModelOutput> predictionEnginePool, ModelInput input) =>
        await Task.FromResult(predictionEnginePool.Predict(modelName: "SentimentAnalysisModel", input));

app.MapPost("/predict", predictionHandler);

/predict 终结点接受 HTTP POST 请求,并使用预测引擎池通过提供的输入返回预测。

完成后,Program.cs 应如下所示:

using Microsoft.ML.Data;
using Microsoft.Extensions.ML;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddPredictionEnginePool<ModelInput, ModelOutput>()
    .FromFile(modelName: "SentimentAnalysisModel", filePath: "sentiment_model.zip", watchForChanges: true);

var app = builder.Build();

var predictionHandler =
    async (PredictionEnginePool<ModelInput, ModelOutput> predictionEnginePool, ModelInput input) =>
        await Task.FromResult(predictionEnginePool.Predict(modelName: "SentimentAnalysisModel", input));

app.MapPost("/predict", predictionHandler);

app.Run();

public class ModelInput
{
    public string SentimentText;
}

public class ModelOutput
{
    [ColumnName("PredictedLabel")]
    public bool Sentiment { get; set; }

    public float Probability { get; set; }

    public float Score { get; set; }
}

在本地测试 Web API

完成所有设置后,是时候测试应用程序了。

  1. 运行该应用程序。

  2. 打开 PowerShell,并输入以下代码(其中,PORT 是应用程序正在侦听的端口)。

    Invoke-RestMethod "https://localhost:<PORT>/predict" -Method Post -Body (@{SentimentText="This was a very bad steak"} | ConvertTo-Json) -ContentType "application/json"
    

    如果成功,输出文本应如下所示:

    sentiment probability score
    --------- ----------- -----
    False         0.5     0
    

祝贺你! 已成功提供模型用于使用 ASP.NET Core Web API 通过 Internet 进行预测。

后续步骤