通过上文所述案例,我们已经选择了最优回归算法来预测学生的综合成绩,并且完成了基于训练数据集的预测模型训练。从实现上,训练好的模型被保存成一个ZIP文件,以便在其它项目中直接调用以完成机器学习的实践场景。在本文中,我将介绍如何在ASP.NET Core中使用这个ZIP文件,以提供用于学生成绩预测的RESTful API。

我们已经得到了经过ML.NET训练好的模型数据文件,也就是一个ZIP文件,在开发的RESTful API中,需要读入这个文件以便实现预测功能。于是,ZIP文件保存在何处就成为了我们首要解决的问题。在开发环境,我们可以将ZIP文件保存在ASP.NET Core的运行目录中,可是,开发好的RESTful API最终还是要部署到生产环境,这种部署有可能是单节点的,也有可能是位于负载均衡服务器后端的多节点部署,而且模型文件也会随着训练数据集的增加或变化进行增量式更新,因此,依赖于部署环境的本地文件系统并不是一个好的做法。因此,我选择将模型文件保存在Azure Blob Storage中。

注意:为了防止在开发调试阶段过多使用Azure Blob Storage的流量,我们可以在ASP.NET Core的应用程序中实现两套模型数据供应器:一套从本地文件系统读入模型,用于开发环境,另一套从Azure Blob Storage读入模型,用于生产环境,然后通过ASP.NET Core的Hosting Environment进行区分以选择不同的供应器。

我们首先登录Microsoft Azure的主页,在主页中创建一个新的Storage Account。注意:我这里使用的是Global的Azure,对于由世纪互联运营的Azure,操作过程有可能不一样。

创建过程就不一一赘述了,根据自己的需要和钱包的厚度来决定所需的配置,待创建完成后,进入Storage Account的Access keys页面,注意其中的Connection string部分的值,接下来构建RESTful API的时候,需要用到这些值。值得一提的是,Azure会同时给你提供两个不同的Key和Connection String,因为经常更换Access key将会是一个良好的习惯,为了防止Access key更新时,应用程序无法正常工作,因此会有一个备用Key来保证程序的正常运行。我们先不管Azure Key Vault的事情,目前先把其中的某个Key复制下来。

然后,进入Blobs服务,新建一个容器(Container),比如命名为mlnetmodel,这个名字也要记下来。之后,在容器中上传我们的模型文件即可,如下:

在准备好模型文件之后,我们就可以开始开发RESTful API了。

打开宇宙第一最强IDE Visual Studio,我用的是2019的版本,新建一个ASP.NET Core的应用程序,启用docker支持,因为我们接下来会将这个应用程序编译成docker镜像,以便在容器中运行。详细的项目创建过程以及RESTful API实现过程我也就不多说明了,网上相关资料实在太多了。这里只强调几个需要重点注意的地方。

首先需要添加如下NuGet包的引用,由于我们需要使用ML.NET,并且需要访问Azure Blob Storage,因此,以下依赖项不可缺少:

  • Microsoft.ML

  • Microsoft.Azure.Storage.Blob

有点小坑的地方是,当你直接引用Microsoft.Azure.Storage.Blob时,编译项目会出错,提示所依赖的Microsoft.Azure.KeyVault.Core不支持.NET Standard。解决办法就是手工添加Microsoft.Azure.KeyVault.Core的依赖,我使用的是3.0.3的版本。

接下来,通过ASP.NET Core的配置系统,从配置数据中读入访问Azure Blob Storage所需的连接字符串参数,然后初始化Storage Account以及Blob Client对象,以便将保存在Azure Blob Storage中的模型文件下载下来。代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

public void ConfigureServices(IServiceCollection services)

{

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    var defaultEndpointsProtocol = Configuration[BlobProtocolConfigName];

    var accountName = Configuration[BlobAccountNameConfigName];

    var accountKey = Configuration[BlobAccountKeyConfigName];

    var endpointSuffix = Configuration[BlobEndpointSuffixConfigName];

    var connectionString = $@"DefaultEndpointsProtocol={defaultEndpointsProtocol};

AccountName={accountName};

AccountKey={accountKey};

EndpointSuffix={endpointSuffix}";

    var storageAccount = CloudStorageAccount.Parse(connectionString);

    var blobClient = storageAccount.CreateCloudBlobClient();

    var mlnetContainer = blobClient.GetContainerReference("mlnetmodel");

    var blob = mlnetContainer.GetBlobReference("student_perf_model.zip");

    using (var ms = new MemoryStream())

    {

        blob.DownloadToStream(ms);

    }

}

上面高亮的代码,通过blob对象,将模型文件下载到MemoryStream中。问题来了,干嘛不保存在本地文件中呢?因为我们接下来需要使用的ML.NET中的PredictionEngine(预测引擎)不是线程安全的,我们只能通过services.AddScoped方法来注册PredictionEngine的实例,也就是说,每当有一个新的HTTP请求到来时,PredictionEngine实例都需要构建一次,而PredictionEngine的构建是需要访问模型文件的,频繁的访问文件系统中的文件会损耗应用程序的性能。

因此,我构建了下面的数据结构,用来保存下载的模型数据:

1

2

3

4

5

6

7

8

9

public class ModelData

{

    public ModelData(byte[] dataBytes)

    {

        this.DataBytes = dataBytes;

    }

    public byte[] DataBytes { get; }

}

于是,上面的blob.DownloadToStream这部分代码,就可以改写为:

1

2

3

4

5

using (var ms = new MemoryStream())

{

    blob.DownloadToStream(ms);

    services.AddSingleton(new ModelData(ms.ToArray()));

}

然后,通过如下方法来注册PredictionEngine实例:

1

2

3

4

5

6

7

8

9

10

11

services.AddScoped(serviceProvider =>

{

    var mlContext = serviceProvider.GetRequiredService<MLContext>();

    var dataStream = serviceProvider.GetRequiredService<ModelData>().DataBytes;

    using (var modelStream = new MemoryStream(dataStream))

    {

        var model = mlContext.Model.Load(modelStream);

        return model.CreatePredictionEngine<StudentTrainingModel, StudentPredictionModel>(mlContext);

    }

});

现在,我们已经完成了模型文件的下载,以及PredictionEngine实例的注册,接下来就非常简单了,只需要在API Controller中,使用构造器注入的PredictionEngine实例来实现我们的预测功能即可。代码非常简单:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

[Route("api/[controller]")]

[ApiController]

public class StudentsController : ControllerBase

{

    private readonly PredictionEngine<StudentTrainingModel, StudentPredictionModel> predictionEngine;

    public StudentsController(PredictionEngine<StudentTrainingModel, StudentPredictionModel> predictionEngine)

    {

        this.predictionEngine = predictionEngine;

    }

    [HttpPost("predict")]

    public IActionResult Predict([FromBody] StudentTrainingModel model)

        => Ok(predictionEngine.Predict(model));

}

至此,API编写完成,将API运行起来,并进行简单的测试:

测试成功。cURL命令从本地文件data.json中读入学生问卷调查数据,并预测他的综合成绩是12.8184786分(实际是9分,还是有点偏差)。

由于在创建ASP.NET Core应用程序时,已经选择了docker支持,因此,我们可以直接使用docker build命令来编译镜像,并使用docker run来运行容器。当然,在Windows环境下需要安装Docker for Windows,不过这里就不多说明安装步骤了,在我以前的博客中有详细介绍。为了方便编译和运行容器,我在ASP.NET Core的上层目录中建了一个docker-compose.yml文件,以使用docker compose来实现容器镜像的编译与容器的运行。在这里我强调“上层目录”,因为,docker-compose.yml文件中,已经通过相对路径指定了docker build的context路径。docker-compose.yml文件内容如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

version: '3'

services:

  mlnet_webapi:

    image: daxnet/mlnet_webapi

    build:

      context: .

      dockerfile: mlnet_webapi/Dockerfile

    environment:

      - BLOB_ACCOUNT_NAME=${BLOB_ACCOUNT_NAME}

      - BLOB_DEFAULT_ENDPOINTS_PROTOCOL=${BLOB_DEFAULT_ENDPOINTS_PROTOCOL}

      - BLOB_ENDPOINT_SUFFIX=${BLOB_ENDPOINT_SUFFIX}

      - BLOB_ACCOUNT_KEY=${BLOB_ACCOUNT_KEY}

      - Serilog__MinimumLevel=${Serilog__MinimumLevel:-Debug}

    container_name: mlnet_webapi

    ports:

      - 880:80

      - 8443:443

值得一提的是,文件中环境变量都是通过.env文件注入进来的,因此,访问Azure Blob Storage的Connection String相关信息不会签入到Github代码库中。

使用docker-compose up命令一键编译并启动容器,再次访问我们的API以确保程序能够正常工作:

本文主要介绍了如何在ASP.NET Core项目中使用ML.NET产生的训练模型,并向外界提供RESTful API,案例使用了容器技术,使得所生成的RESTful API应用能够在容器中运行,以便为下一步的持续部署做铺垫。在下文中,我将介绍基于Azure DevOps的持续集成与持续部署。

原文地址:https://sunnycoding.cn/2019/05/06/mlnet-containerize-and-azure-devops-practices-part3/

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 

ML.NET机器学习、API容器化与Azure DevOps实践(三):RESTful API相关推荐

  1. ML.NET机器学习、API容器化与Azure DevOps实践(一):简介

    打算使用几篇文章介绍一下.NET下的机器学习框架ML.NET的具体应用,包括一些常用的业务场景.算法的选择.模型的训练以及RESTful API的创建.机器学习服务容器化,以及基于Azure DevO ...

  2. ML.NET机器学习、API容器化与Azure DevOps实践(四):持续集成与k8s持续部署

    通过上文所介绍的内容,我们已经完成了RESTful API的开发,现在,就可以使用Azure DevOps来进行持续集成(CI)和k8s持续部署(CD)了.本文我会对使用Azure DevOps进行C ...

  3. ML.NET机器学习、API容器化与Azure DevOps实践(二):案例

    在上文中,我简单地介绍了机器学习以及ML.NET的相关知识,从本讲开始,我会基于一个简单的案例:学生成绩预测,来介绍使用ML.NET进行机器学习以及API部署的基本过程. 本案例的数据来源为加州大学尔 ...

  4. 腾讯云EMR基于YARN针对云原生容器化的优化与实践

    导语 | 传统HADOOP生态系统使用YARN管理/调度计算资源,该系统⼀般具有明显的资源使⽤周期.实时计算集群资源消耗主要在⽩天,而数据报表型业务则安排在离线计算集群中.离在线业务分开部署的首要问题 ...

  5. 专访智链ChainNova CTO谢文杰:区块链容器化与水平扩展实践

    [编者按]每个人的成长曲线不同,有的人在研究生之时就已有相当知名的产品和框架,从而在接下来的工作中一路顺风顺水,有的人缺需要经历一个又一个的坑才能成长,不管是前者的聪明高效,还是后者的稳扎稳打,他们都 ...

  6. CSDN专访智链ChainNova CTO谢文杰:区块链容器化与水平扩展实践

    [小编写在前面] 2017年9月23日,由全球最大中文IT社区CSDN举办的SDCC 2017之区块链技术实战线上峰会强势来袭,智链ChainNova CTO 谢文杰受邀将带来题为<区块链容器化 ...

  7. 直播 | 平安证券Kubernetes容器集群的DevOps实践

    分享时间:5月28日 20:30 分享主题:平安证券Kubernetes容器集群的DevOps实践 分享人介绍: 陈刚,平安证券运维研发工程师,负责经纪业务IT应用的持续交付平台的设计和开发. 分享摘 ...

  8. Apache Hadoop 基础设施容器化在 Uber 的实践

    大数据厂长备注:以下的我们均代表 Uber 的 Hadoop 运维团队. 介绍 随着 Uber 业务的增长,Uber 公司在 5 年内将 Apache Hadoop(本文简称为"Hadoop ...

  9. 提升60%基础资源利用率!中国联通的容器化大数据平台实践

    中国联通数据中心总经理王志军在Rancher举办的ECIC大会上的演讲实录,分享了中国联通为何开始进行平台容器化并如何运用Kubernetes对9000台的服务器数据节点进行最大化利用和合理调度,进而 ...

最新文章

  1. 馅饼还是陷阱,TMG2010升级经验谈
  2. html5怎么设置勾选,word文档怎么设置输入勾选框
  3. “make -n”和 “+command”的解释
  4. C#类型与SQLSEVER类型对比
  5. MongoDB复制集技术
  6. Android学习之动态调用碎片
  7. 100家店干翻17000家药店!刘强东最恐惧的对手来了!
  8. 记dropbox与git不和谐的一个问题
  9. VMware vSAN的相关告警处理 2021-01-04
  10. 2008年不错的图书
  11. Java实现对字符串的快速排序
  12. UVALive 3713 Astronauts(2-sat+输出任意路径)
  13. QQ等级图标排名说明_QQ等级表,QQ最高等级(皇冠) qq到一星要5天
  14. Tornado 源码分析(一)
  15. 时空复杂度(时间复杂度/空间复杂度)O(1)、O(n)、O(n^2)、O(log n)、O(n log n)是什么意思
  16. 效率神器 SCons 构建工具
  17. syslog协议发送本机日志到其他设备/服务器(winlinux)
  18. 云计算 第四章 微软云计算 Windows Azure
  19. 后端开发如何快速转前端开发
  20. 深入浅出!mysql免安装版教程

热门文章

  1. vim编辑和命令模式、实践
  2. 系统学习redis之二——redis集群搭建
  3. 3四则运算软件2016011992
  4. 网构软件-Internetware
  5. 详解用65行javascript代码做Flappy Bird
  6. hdoj-1005-Number Sequences
  7. 一个IT人的非典型职场十年 (5)
  8. 编写properties文件的Eclipse插件
  9. ITU-R BT.656 协议
  10. 让 Hangfire 使用 MongoDB 存储