本文将使用ML.NET创建机器学习分类模型,通过ASP.NET Core Web API公开它,将其打包到Docker容器中,并通过Azure Container Instances将其部署到云中。
先决条件
本文假设您对Docker有一定的了解。构建和部署示例应用程序还需要以下软件/依赖项。重要的是要注意应用程序是在Ubuntu 16.04 PC上构建的,但所有软件都是跨平台的,应该适用于任何环境。
- Docker
- Azure CLI
- .NET Core 2.0
- Docker Hub Account
设置项目
我们要做的第一件事是为我们的解决方案创建一个文件夹。
mkdir mlnetacidemo
然后,我们想在新创建的文件夹中创建一个解决方案。
cd mlnetacidemodotnet new sln
建立模型
在我们的解决方案文件夹中,我们想要创建一个新的控制台应用程序,这是我们构建和测试我们的机器学习模型的地方。
设置模型项目
首先,我们要创建项目。从解决方案文件夹输入:
dotnet new console -o model
现在我们要将这个新项目添加到我们的解决方案中。
dotnet sln mlnetacidemo.sln add model/model.csproj
添加依赖项
由于我们将使用ML.NET
框架,我们需要将其添加到我们的model
项目中。
cd modeldotnet add package Microsoft.MLdotnet restore
在我们开始训练模型之前,我们需要下载我们将用于训练的数据。我们通过创建一个名为data的目录并将数据文件下载到那里来实现。
mkdir datacurl -o data/iris.txt https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data
如果我们看一下数据文件,它看起来应该是这样的:
5.1,3.5,1.4,0.2,Iris-setosa4.9,3.0,1.4,0.2,Iris-setosa4.7,3.2,1.3,0.2,Iris-setosa4.6,3.1,1.5,0.2,Iris-setosa5.0,3.6,1.4,0.2,Iris-setosa5.4,3.9,1.7,0.4,Iris-setosa4.6,3.4,1.4,0.3,Iris-setosa5.0,3.4,1.5,0.2,Iris-setosa4.4,2.9,1.4,0.2,Iris-setosa4.9,3.1,1.5,0.1,Iris-setosa
训练模型
现在我们已经设置了所有依赖项,现在是构建模型的时候了。我利用了ML.NET入门网站上使用的演示。
定义数据结构
在我们model
项目的根目录中,让我们创建两个被调用的类IrisData
,IrisPrediction
它们将分别定义我们的特性和预测属性。它们都将用于Microsoft.ML.Runtime.Api
添加属性属性。
这是我们IrisData
的样子:
using Microsoft.ML.Runtime.Api;namespace model{public class IrisData ???{ ???????[Column("0")] ???????public float SepalLength; ???????[Column("1")] ???????public float SepalWidth; ???????[Column("2")] ???????public float PetalLength; ???????????????[Column("3")] ???????public float PetalWidth; ???????[Column("4")] ???????[ColumnName("Label")] ???????public string Label; ???} ??????}
同样,这是IrisPrediction
:
using Microsoft.ML.Runtime.Api;namespace model{ ???public class IrisPrediction ???{ ???????[ColumnName("PredictedLabel")] ???????public string PredictedLabels; ???}}
构建LearningPipeLine
using Microsoft.ML.Data;using Microsoft.ML;using Microsoft.ML.Runtime.Api;using Microsoft.ML.Trainers;using Microsoft.ML.Transforms;using Microsoft.ML.Models;using System;using System.Threading.Tasks;namespace model{ ???class Model ???{ ???????????????public static async Task<PredictionModel<IrisData,IrisPrediction>> Train(LearningPipeline pipeline, string dataPath, string modelPath) ???????{ ???????????// Load Data ???????????pipeline.Add(new TextLoader(dataPath).CreateFrom<IrisData>(separator:‘,‘)); ????????????// Transform Data ???????????// Assign numeric values to text in the "Label" column, because ????????????// only numbers can be processed during model training ??????????????pipeline.Add(new Dictionarizer("Label")); ???????????// Vectorize Features ???????????pipeline.Add(new ColumnConcatenator("Features", "SepalLength", "SepalWidth", "PetalLength", "PetalWidth")); ???????????// Add Learner ???????????pipeline.Add(new StochasticDualCoordinateAscentClassifier()); ???????????// Convert Label back to text ????????????pipeline.Add(new PredictedLabelColumnOriginalValueConverter() {PredictedLabelColumn = "PredictedLabel"}); ???????????// Train Model ???????????var model = pipeline.Train<IrisData,IrisPrediction>(); ???????????// Persist Model ???????????await model.WriteAsync(modelPath); ???????????return model; ???????} ???}}
除了构建LearningPipLine并训练我们的机器学习模型之外,该模型还序列化并保存在名为model.zip的文件中以供将来使用。
测试我们的模型
现在是时候测试所有内容以确保它正常工作。
using System;using Microsoft.ML;namespace model{ ???class Program ???{ ???????static void Main(string[] args) ???????{ ???????????string dataPath = "model/data/iris.txt"; ???????????string modelPath = "model/model.zip"; ???????????var model = Model.Train(new LearningPipeline(),dataPath,modelPath).Result; ???????????// Test data for prediction ???????????var prediction = model.Predict(new IrisData() ????????????{ ???????????????SepalLength = 3.3f, ???????????????SepalWidth = 1.6f, ???????????????PetalLength = 0.2f, ???????????????PetalWidth = 5.1f ???????????}); ???????????Console.WriteLine($"Predicted flower type is: {prediction.PredictedLabels}"); ???????} ???}}
全部设定运行。我们可以通过从解决方案目录输入以下命令来完成此操作:
dotnet run -p model/model.csproj
运行应用程序后,控制台上将显示以下输出。
Automatically adding a MinMax normalization transform, use ‘norm=Warn‘ or‘norm=No‘ to turn this behavior off.Using 2 threads to train.Automatically choosing a check frequency of 2.Auto-tuning parameters: maxIterations = 9998.Auto-tuning parameters: L2 = 2.667734E-05.Auto-tuning parameters: L1Threshold (L1/L2) = 0.Using best model from iteration 882.Not training a calibrator because it is not needed.Predicted flower type is: Iris-virginica
公开模型
此外,您会注意到在我们model
项目的根目录中创建了一个名为model.zip的文件。这个持久化模型现在可以在我们的应用程序之外用于进行预测,我们接下来将通过API执行操作。
一旦构建了机器学习模型,您就希望部署它以便开始进行预测。一种方法是通过REST API。它的核心部分需要做的是接受来自客户端的数据输入并回复预测。为了帮助我们这样做,我们将使用ASP.NET Core API。
设置API项目
我们要做的第一件事是创建项目。
dotnet new webapi -o api
然后我们想将这个新项目添加到我们的解决方案中
dotnet sln mlnetacidemo.sln add api/api.csproj
添加依赖项
因为我们将加载我们的模型并通过我们的API进行预测,所以我们需要将ML.NET
包添加到我们的api
项目中。
cd apidotnet add package Microsoft.MLdotnet restore
引用模型
在我们构建机器学习模型的上一步中,它被保存到一个名为的文件中model.zip
。这是我们将在API中引用的文件,以帮助我们进行预测。要在我们的API中引用它,只需将它从模型项目目录复制到我们的api
项目目录中。
创建数据模型
我们的模型是使用数据结构构建的IrisData
,IrisPrediction
用于定义特征以及预测属性。因此,当我们的模型通过我们的API进行预测时,它也需要引用这些数据类型。因此,我们需要在项目内部定义IrisData
和IrisPrediction
类api
。类的内容几乎与model
项目中的内容相同,唯一的例外是我们的命名空间从更改model
为api
。
using Microsoft.ML.Runtime.Api;namespace api{ ???public class IrisData ???{ ???????[Column("0")] ???????public float SepalLength; ???????[Column("1")] ???????public float SepalWidth; ???????[Column("2")] ???????public float PetalLength; ???????????????[Column("3")] ???????public float PetalWidth; ???????[Column("4")] ???????[ColumnName("Label")] ???????public string Label; ???} ???}
using Microsoft.ML.Runtime.Api;namespace api{ ???public class IrisPrediction ???{ ???????[ColumnName("PredictedLabel")] ???????public string PredictedLabels; ???}}
构建控制器
现在我们的项目已经建立,是时候添加一个控制器来处理来自客户端的预测请求了。在Controllers
我们api
项目的目录中,我们可以创建一个PredictController
使用单个POST
端点调用的新类。该文件的内容应如下所示:
using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using Microsoft.AspNetCore.Mvc;using Microsoft.ML;namespace api.Controllers{ ???[Route("api/[controller]")] ???public class PredictController : Controller ???{ ???????// POST api/predict ???????[HttpPost] ???????public string Post([FromBody] IrisData instance) ???????{ ???????????var model = PredictionModel.ReadAsync<IrisData,IrisPrediction>("model.zip").Result; ???????????var prediction = model.Predict(instance); ???????????return prediction.PredictedLabels; ???????} ???}}
测试API
当我们的predict
控制器完成编码,就可以来测试它了。从我们mlnetacidemo
解决方案的根目录中,输入以下命令。
dotnet run -p api/api.csproj
我们的请求的正文应该类似于下面的代码段:在POSTMAN或Insomnia等客户端中,向端点发送HHTP POST请求http://localhost:5000/api/predict
。
{ ???"SepalLength": 3.3, ???"SepalWidth": 1.6, ???"PetalLength": 0.2, ???"PetalWidth": 5.1,}
打包应用程序
如果成功,返回的输出应该Iris-virginica
与我们的控制台应用程序相同。大!现在我们的应用程序已在本地成功运行,现在是时候将它打包到Docker容器中并将其推送到Docker Hub。
创建Dockerfile
在我们的mlnetacidemo
解决方案目录中,使用以下内容创建一个Dockerfile:
FROM microsoft/dotnet:2.0-sdk AS buildWORKDIR /app# copy csproj and restore as distinct layersCOPY *.sln .COPY api/*.csproj ./api/RUN dotnet restore# copy everything else and build appCOPY api/. ./api/WORKDIR /app/apiRUN dotnet publish -c release -o outFROM microsoft/aspnetcore:2.0 AS runtimeWORKDIR /appCOPY api/model.zip .COPY --from=build /app/api/out ./ENTRYPOINT ["dotnet", "api.dll"]
构建镜像
我们需要在命令提示符中输入以下命令。这需要一段时间,因为它需要下载.NET Core SDK和ASP.NET Core运行时Docker镜像。
docker build -t <DOCKERUSERNAME>/<IMAGENAME>:latest .
本地测试镜像
我们需要在本地测试我们的镜像,以确保它可以在云上运行。为此,我们可以使用该docker run
命令。
docker run -d -p 5000:80 <DOCKERUSERNAME>/<IMAGENAME>:latest
要停止容器,请使用Ctrl + C
。虽然API暴露了端口80,但我们将其绑定到本地端口5000只是为了保持我们先前的API请求不变。向http://localhost:5000/api/predict
适当的主体发送POST请求时,应该再次响应同样的结果Iris-virginica。
推送到Docker Hub
现在Docker镜像在本地成功运行,是时候推送到Docker Hub了。同样,我们使用Docker CLI来执行此操作。
docker logindocker push <DOCKERUSERNAME>/<IMAGENAME>:latest
部署到云
现在,最后一步是向全世界部署和展示我们的机器学习模型和API。我们的部署将通过Azure容器实例进行,因为它几乎不需要配置或管理服务器。
准备部署清单
尽管可以在命令行中执行部署,但通常最好将所有配置放在文件中以备文档,并节省时间,而不必每次都输入参数。使用Azure,我们可以通过JSON文件来实现。
{ ?"$schema": ???"https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", ?"contentVersion": "1.0.0.0", ?"parameters": { ???"containerGroupName": { ?????"type": "string", ?????"defaultValue": "mlnetacicontainergroup", ?????"metadata": { ???????"description": "Container Group name." ?????} ???} ?}, ?"variables": { ???"containername": "mlnetacidemo", ???"containerimage": "<DOCKERUSERNAME>/<IMAGENAME>:latest" ?}, ?"resources": [ ???{ ?????"name": "[parameters(‘containerGroupName‘)]", ?????"type": "Microsoft.ContainerInstance/containerGroups", ?????"apiVersion": "2018-04-01", ?????"location": "[resourceGroup().location]", ?????"properties": { ???????"containers": [ ?????????{ ???????????"name": "[variables(‘containername‘)]", ???????????"properties": { ?????????????"image": "[variables(‘containerimage‘)]", ?????????????"resources": { ???????????????"requests": { ?????????????????"cpu": 1, ?????????????????"memoryInGb": 1.5 ???????????????} ?????????????}, ?????????????"ports": [ ???????????????{ ?????????????????"port": 80 ???????????????} ?????????????] ???????????} ?????????} ???????], ???????"osType": "Linux", ???????"ipAddress": { ?????????"type": "Public", ?????????"ports": [ ???????????{ ?????????????"protocol": "tcp", ?????????????"port": "80" ???????????} ?????????] ???????} ?????} ???} ?], ?"outputs": { ???"containerIPv4Address": { ?????"type": "string", ?????"value": ???????"[reference(resourceId(‘Microsoft.ContainerInstance/containerGroups/‘, parameters(‘containerGroupName‘))).ipAddress.ip]" ???} ?}}
现在我们可以使用这个模板并将其保存到我们mlnetacidemo
解决方案根目录下的文件azuredeploy.json中。唯一需要改变的是containerimage
的配置,将其替换为您的Docker Hub用户名和刚刚推送到Docker Hub的镜像的名称。
部署
为了部署我们的应用程序,我们需要确保登录我们的Azure帐户。要通过Azure CLI执行此操作,请在命令提示符下键入:
az login
按照提示登录。登录后,是时候为容器创建资源组了。
az group create --name mlnetacidemogroup --location eastus
成功创建组后,就可以部署我们的应用程序了。
az group deployment create --resource-group mlnetacidemogroup --template-file azuredeploy.json
完成后,可以使用以下命令清理资源:
az group delete --name mlnetacidemogroup
为部署初始化需要消耗几分钟的时间。如果部署成功,您应该在命令行上看到一些输出。寻找ContainerIPv4Address主机
,这是可以访问容器的IP地址,更换URL后再次做一个POST请求到http://<ContainerIPv4Address>/api/predict,
ContainerIPv4Address
是在部署后命令行中找到的值。如果成功,响应内容应该像以前的请求一样返回Iris-virginica
。
小结
在本文中,我们构建了一个分类机器学习模型,使用ML.NET
该模型预测鸢尾花的分类,给出了四种分类的预测功能,通过ASP.NET Core REST API公开它,将其打包到容器中并使用Azure Container Instances将其部署到云中。虽然随着模型的变化,这些操作变得更加复杂,但是目前介绍的内容已经足够标准化,扩展此示例仅需要进行很少量的修改即可。
使用ML.NET + ASP.NET Core + Docker + Azure Container Instances部署.NET机器学习模型
原文地址:https://www.cnblogs.com/BeanHsiang/p/10056414.html