創建過程就不一一贅述了,根據自己的需要和錢包的厚度來決定所需的配置,待創建完成后,進入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.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中的模型文件下載下來。代碼如下:

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的構建是需要訪問模型文件的,頻繁的訪問文件系統中的文件會損耗應用程序的性能。

因此,我構建了下面的數據結構,用來保存下載的模型數據:

public class ModelData

{

public ModelData(byte[] dataBytes)

{

this.DataBytes = dataBytes;

}

public byte[] DataBytes { get; }

}

于是,上面的blob.DownloadToStream這部分代碼,就可以改寫為:

using (var ms = new MemoryStream())

{

blob.DownloadToStream(ms);

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

}

然后,通過如下方法來注冊PredictionEngine實例:

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實例來實現我們的預測功能即可。代碼非常簡單:

[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文件內容如下:

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的持續集成與持續部署。

文章轉自微信公眾號@dotNET跨平臺

上一篇:

.Net中如何創建RESTful API

下一篇:

.NET Core微服務之路:基于Ocelot的API網關實現--http/https協議篇
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費