百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

使用 FastAPI 和 Angular 部署机器学习模型

toyiye 2024-06-21 12:36 9 浏览 0 评论

在本文中,我们将探讨如何为生产准备机器学习模型,并将其部署在简单的 Web 应用程序中。部署机器学习模型本身就是一门艺术。事实上,将机器学习模型成功投入生产超出了数据科学知识的范围,并且涉及许多软件开发和DevOps技能。你为什么要关心这一切?目前,数据科学团队中最有价值的角色之一是机器学习工程师。这个角色聚集了两全其美的精华。

这些工程师不仅知道如何将不同的机器学习和深度学习模型应用于适当的问题,还知道如何测试它们,验证它们并最终部署它们。拥有一个能够将机器学习模型投入生产的人对任何公司来说都是一笔巨大的资产。一般来说,这是Rubik's Code提供的主要服务类型。为了成为一名成功的机器学习工程师,你需要具备各种技能,而不仅仅是关注数据。实际上,为机器学习模型编写的代码量远小于支持测试和提供该模型的代码量。

MLOps,一个围绕这种需求构建的工程术语,正在成为一种新的趋势。这就是为什么在本文中,我们将重点介绍您需要了解的几种技术,以便构建一个用户想要的成功机器学习应用程序。本教程中提供的完整解决方案由两个组件组成:服务器端和客户端。这是基本的 Web 体系结构,其中客户端与应用程序的用户交互并将其发送到服务器端。服务器端执行数据处理,或者在本例中运行预测,并将结果返回到客户端,客户端将其呈现给用户。从本质上讲,在本文中,我们构建了一个可以用下图表示的小系统:

MLOps,一个围绕这种需求构建的工程术语,正在成为一种新的趋势。这就是为什么在本文中,我们将重点介绍您需要了解的几种技术,以便构建一个用户想要的成功机器学习应用程序。本教程中提供的完整解决方案由两个组件组成:服务器端和客户端。这是基本的 Web 体系结构,其中客户端与应用程序的用户交互并将其发送到服务器端。服务器端执行数据处理,或者在本例中运行预测,并将结果返回到客户端,客户端将其呈现给用户。

为了涵盖所有内容,我们需要涵盖几个主题:

  • 安装和数据集
  • Rest API 基础知识
  • FastAPI 基础知识
  • 客户端 – 用户界面
  • 服务器端 – 使用 FastAPI 进行模型训练的解决方案
  • 服务器端 – 使用 FastAPI 加载模型的解决方案

1. 安装和数据集

要成功运行本教程中的示例,需要安装 Python 3.6 或更高版本。最简单的方法是使用Anaconda分发。它附带了本教程所需的所有其他必要库,如PandasNumPySciKit Learn等。要安装 FastAPI 及其所有依赖项,请使用以下命令:

pip install fastapi[all]

这包括 Uvicorn,一个运行代码的 ASGI 服务器。如果您对其他一些ASGI服务器(如Hypercorn)更满意,那也很好,您可以在本教程中使用它。

对于Web应用程序,我们使用Angular。为此,您需要安装 Node.jsnpm。使用Angular框架进行操作的最常见方法是使用Angular命令行界面 - Angular-CLI。这个工具的好处之一是,一旦我们用它初始化了我们的应用程序,我们就可以使用TypeScript,它将自动转换为JavaScript。安装此接口是通过 npm 完成的,当然,通过运行以下命令:

npm install -g angular-cli

当您要创建新的Angular应用程序时,您可以使用以下命令执行此操作:

ng new application_name

此命令将创建一个文件夹结构,供我们的应用程序使用。要运行此应用程序,请将 shell 放在刚刚创建的应用程序的根文件夹 (cd application_name) 中,然后调用命令:

ng serve

如果您在转到浏览器并打开localhost:4200后按照上述步骤操作,您将能够看到默认的Angular应用程序。

我们在本文中使用的数据来自PalmerPenguins Dataset。该数据集最近被引入,作为著名的Iris数据集的替代方案。它由Kristen Gorman博士和南极洲LTER的Palmer站创建。您可以在此处或通过Kaggle获取此数据集。该数据集主要由两个数据集组成,每个数据集包含344只企鹅的数据。就像在鸢尾花数据集中一样,有3种不同种类的企鹅来自帕尔默群岛的3个岛屿。此外,这些数据集还包含每个物种的 culmen 维度。Culmen是鸟喙的上脊。在简化的企鹅数据中,culmen的长度和深度被重命名为变量culmen_length_mmculmen_depth_mm。以下是数据集:

2. REST API 基础知识

在我们开始使用Python和Flask实现Web应用程序之前,让我们首先找出什么是REST API。现在,我相信你一生中已经看过这个词两次了。术语的第二部分 - API代表应用程序编程接口。从本质上讲,它 API 表示程序用于相互通信的一组规则。例如,在服务器-客户端体系结构中,应用程序的服务器端以公开可由应用程序客户端调用的方法进行编程。这意味着客户端可以在其代码中调用服务器上的方法,并从中获取特定结果。REST 代表"具象状态转移"。这表示开发人员在构建 API 时应遵循的一组规则。它定义了 API 的外观,因此 API 是标准化的。

其中一个规则定义了在链接特定 URL 时可以收集数据或资源。例如,您可以链接"api.rubikscode.com/blogs"并获取博客列表作为响应。URL api.rubikscode.com/blogs "称为"请求",返回的客户端列表称为响应。每个请求由 4 个部分组成:

  • 终结点(路由) – 这是我们之前提到的 URL。它的结构是这样的 - "根端点/?根终结点是起点,后跟路径和查询参数。该路径定义所需的特定资源。例如,GitHub 的 API 的根端点是"api.github.com",而我在 GitHub 上的存储库列表的完整端点是 https://api.github.com/users/nmzivkovic/repos。
  • 方法 – 可以发送五种类型的请求,该方法定义此类型:GET – 用于获取或读取信息。开机自检 – 用于创建新资源。PUTPATCH – 它们用于更新资源。删除 – 删除资源。
  • 标头 – 标头用于以属性值对的形式向客户端和服务器提供其他信息。MDN的HTTP头引用上的有效头列表。
  • 正文 – 此部分包含客户端发送到服务器的信息。它不用于 GET 请求。

我们要在本文中创建的是 Web 服务器,它为 Iris 预测提供模型。我们希望构建 API,应用程序客户端可以使用该 API 从模型中获取预测。这是使用Python框架Flask完成的。

2. 快速API基础知识

在本文中,我们使用 FastAPI 来构建 REST API。我们为什么要使用这个库?这有几个原因。与其他主要的Python框架(如FlaskDjango)相比,FastAPI更快。此外,此框架还支持使用 async/await Python 关键字的开箱即用异步代码。这进一步提高了其性能。使FastAPI成为最好的API库之一的最显着的功能可能是内置的交互式文档。稍后我们将更详细地探讨此功能。最后,使用 FastAPI 构建的应用程序非常易于测试和部署。由于所有这些,FastAPI成为使用Python构建Web API应用程序的标准。

2.1 首次快速API应用

好了,让我们构建第一个 FastAPI 应用程序。很酷的事情是,一个简单的HelloWorld示例与FastAPI可以用5行代码创建。我不是在开玩笑。准备好了吗?以下是您需要执行的操作:

  • 创建一个新文件夹并将其命名为"my_first_fastapi"(或者您认为:)的任何内容)
  • 创建一个名为 main.py 的新Python脚本(或者你觉得它:)的任何内容)
  • 将以下代码添加到 main.py:
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
  return {"message": "Hello World"}
  • 转到终端并放入my_first_fastapi文件夹中
  • 运行以下命令
uvicorn main:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.

太棒了,现在你有一个Web服务器在 http://127.0.0.1:8000 运行。如果您在浏览器中转到此地址,您将看到如下内容:

请注意,在上面的代码中@app.get("route") 装饰器?此修饰器确定可以在特定终结点上发出的请求类型。这意味着,例如,如果我们放置 app.get("/users"),我们将 REST API 端点定义为"users",我们可以在其上发出 GET http 请求。

2.2 快速 API 文档

FastAPI最酷的事情之一是内置的交互式文档。它以 Swagger UI 呈现。如果我们使用刚刚构建的示例并转到 http://127.0.0.1:8000/docs 我们将看到 API 的文档页面:

您可以单击任何端点,进一步浏览并了解它们。本文档的最大好处可能是,您可以通过单击"试用"按钮来执行实时浏览器内测试。

我知道,对吧?!

好了,回到我们的应用程序,让我们看看如何利用 FastAPI 进行机器学习部署

3. 客户端和用户界面

好的,为了让用户与我们的模型进行通信,我们需要某种用户界面。有许多可用的框架和技术可供您使用。在这里,您可以看到我们如何用Flask和Python做类似的事情。在本教程中,我们使用 Angular 构建用户可以与之交互的 Web 应用程序。

我们不会在这里过多地讨论实现的细节,因为重点是FastAPI和机器学习模型。从本质上讲,应用程序TrainPredict的工具栏中有两个项目,它将我们引导到两个具有相同名称的网页。完整的内容在两个组件中实现:训练组件预测组件。还有一项服务 - fastapi.service。此服务包含对服务器端实现的 REST API 的调用。

在训练选项卡中,您可以选择要训练的模型,选择要试验的数据(采用类似 PalmerPenguing 数据集的格式),以及定义测试数据集的大小。按下训练按钮后,包含此信息的 HTTP 请求将发送到服务器端,我们希望它将训练定义的机器学习模型。

在"预测"选项卡中,用户可以使用通过上一个选项卡训练的机器学习模型进行预测。在这里,用户可以输入描述企鹅的参数,用户希望对此进行预测。按下"预测"按钮后,此信息将发送到服务器,该服务器使用机器学习模型进行预测并将其发送用户。

要运行此应用程序(我们假设您已经克隆了 GitHub 存储库),请打开终端并放入 train_solution\client 并运行以下命令:

npm install
ng serve

完成此操作后,此 Web 应用将在 localhost:4200 上可用。好吧,让我们看看服务器端实现的样子。

3. 模型训练解决方案

服务器解决方案由多个组件组成,这些组件可以在train_solution\server 文件夹中的文件中找到。整体架构如下所示:

让我们来探索每个组件。

3.1 数据合同

train_parameters.py文件包含从 Web 应用程序的"训练"选项卡传递的模型。从本质上讲,此文件包含一个数据协定,当来自客户端的HTTP请求到达我们的服务器时,将使用该协定。

from pydantic import BaseModel

class TrainParameters(BaseModel):
    model: str
    path: str
    testsize: float

请注意,我们使用 Pydantic、数据验证和设置管理库进行类型注释。此库在运行时强制实施类型提示,并在数据无效时提供用户友好的错误。我们在penguin_sample.py中使用的同一库,其中我们定义了从Web应用程序的预测页面发送HTTP请求时使用的数据协定:

from pydantic import BaseModel

class PenguinSample(BaseModel):
    island: str
    culmenLength: float
    culmenDepth: float
    flipperLength: float
    bodyMass: float
    sex: str
    species: str

    def __getitem__(self, item):
        return getattr(self, item)

3.2 数据加载器

此类用于加载准备数据。这是它的样子:

import pandas as pd
import numpy as np
from scipy.stats import norm
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

from penguin_sample import PenguinSample

class DataLoader():
    def __init__(self, test_size = 0.2, scale = True):
        self.test_size = test_size
        self.scale = scale
        self.scaler = StandardScaler()
        self._island_map = {}
        self._sex_map = {}

    def load_preprocess(self, path):
        data = pd.read_csv(path)

        data = self._feature_engineering_pipeline(data)

        X = data.drop(['species', "island", "sex"], axis=1)

        if(self.scale):
            X = self.scaler.fit_transform(X) 

        y = data['species']
        spicies = {'Adelie': 0, 'Chinstrap': 1, 'Gentoo': 2}
        y = [spicies[item] for item in y]
        y = np.array(y) 

        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=self.test_size, \ 
							    random_state=33)

        return X_train, X_test, y_train, y_test

    def prepare_sample(self, raw_sample: PenguinSample):
        island = self._island_map[raw_sample.island]
        sex = self._sex_map[raw_sample.sex]

        sample = [raw_sample.culmenLength, raw_sample.culmenDepth, raw_sample.flipperLength, \ 
		  raw_sample.bodyMass, island, sex]
        sample = np.array([np.asarray(sample)]).reshape(-1, 1)

        if(self.scale):
            self.scaler.fit_transform(sample)

        return sample.reshape(1, -1)

    def _feature_engineering_pipeline(self, data):
        data['culmen_length_mm'].fillna((data['culmen_length_mm'].mean()), inplace=True)
        data['culmen_depth_mm'].fillna((data['culmen_depth_mm'].mean()), inplace=True)
        data['flipper_length_mm'].fillna((data['flipper_length_mm'].mean()), inplace=True)
        data['body_mass_g'].fillna((data['body_mass_g'].mean()), inplace=True)

        data["species"] = data["species"].astype('category')
        data["island"] = data["island"].astype('category')
        data["sex"] = data["sex"].astype('category')

        data["island_cat"] = data["island"].cat.codes
        data["sex_cat"] = data["sex"].cat.codes

        self._island_map = dict(zip(data['island'], data['island'].cat.codes))
        self._sex_map = dict(zip(data['sex'], data['sex'].cat.codes))

        return data

作为构造函数中的参数,它接收测试数据集大小和指示数据是否应缩放的标志。此类中有两个公共方法和一个私有方法:

  • _feature_engineering_pipeline – 此方法在现有集合上进行小型特征工程。也就是说,填充缺失的数据并对分类数据进行编码。如果您想了解有关功能工程的更多信息,请查看此博客文章
  • load_preprocess – 此方法执行繁重的工作,它从定义的路径加载数据,并将数据拆分为训练和测试数据集。
  • prepare_sample – 当新样本进入我们的系统时,我们需要以与处理训练数据相同的方式处理它。这就是为什么我们在进行进一步预测之前使用prepare_sample方法的原因。

3.3 模型训练器

此组件负责训练模型。通过构造函数,它接收有关用户选择的算法的信息,并从那里开始处理它。这是它的样子:

from data_loader import DataLoader
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from penguin_sample import PenguinSample

class ModelTrainer():
    def __init__(self, algoritm, test_size=0.2):
        if(algoritm == 'svm'):
            self.data_loader = DataLoader()
            self.model = SVC(kernel="rbf", gamma=0.1, C=500, verbose=True)

        if(algoritm == 'logistic regression'):
            self.data_loader = DataLoader()
            self.model = LogisticRegression(C=1e20, verbose=True)
        
        if(algoritm == 'decision tree'):
            self.data_loader = DataLoader(scale = False)
            self.model = DecisionTreeClassifier(max_depth=5)

        if(algoritm == 'random forest'):
            self.data_loader = DataLoader(scale = False)
            self.model = RandomForestClassifier(n_estimators=11, max_leaf_nodes=16, n_jobs=-1, \ 
						verbose=True)

    def train(self, path):
        X_train, X_test, y_train, y_test = self.data_loader.load_preprocess(path)
        self.model.fit(X_train, y_train)
        predictions = self.model.predict(X_test)
        return accuracy_score(predictions, y_test)

    def predict(self, data: PenguinSample):
        prepared_sample = self.data_loader.prepare_sample(data)
        return self.model.predict(prepared_sample)

在构造函数中,实例化了正确的模型。如您所见,使用了SciKit Learn中的类。除此之外,还创建了DataLoader一个实例。在训练方法中,检索数据并训练模型。完成此操作后,将计算准确性分数,并将该值返回给调用方。另一方面,预测方法接收新示例,并使用数据加载程序实例将其调整到模型。然后调用 predict 方法,并将结果返回给调用方。

3.4 REST API 模块

最重要的文件是 main.py 文件。此文件将所有其他部分放在一起,并使用 FastAPI 构建 REST API。这是看起来的样子:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from model_trainer import ModelTrainer
from train_parameters import TrainParameters
from penguin_sample import PenguinSample

origins = [
    "http://localhost:8000",
    "http://localhost:4200"
]

app = FastAPI()
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.model = ModelTrainer('svm')

@app.post("/train")
async def train(params: TrainParameters):
    print("Model Training Started")
    app.model =  ModelTrainer(params.model.lower(), params.testsize)
    accuracy = app.model.train(params.path)
    return accuracy

@app.post("/predict")
async def predict(data:PenguinSample):
    print("Predicting")
    spicies_map = {0: 'Adelie', 1: 'Chinstrap', 2: 'Gentoo'}
    species = app.model.predict(data)
    return spicies_map[species[0]]

首先,我们导入所有必要的库。由于我们的服务器在 http://localhost:8000 和客户端中以 http://localhost:4200 运行,因此我们需要处理 CORS 策略。这就是我们导入 CORSMiddleware 的原因。此类在应用初始化期间使用:

app = FastAPI()
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
app.model = ModelTrainer('svm')

请注意,我们在那里添加了一个 ModelTrainer 的实例。此实例只是一个占位符,稍后将替换。有两个终结点"/trian""/predict"都接受POST HTTP请求。这样,我们有两个函数来处理这些请求。训练方法根据从客户端收到的参数创建 ModelTrainer 的新实例。然后,它运行模型的训练并返回模型的准确性:

@app.post("/train")
async def train(params: TrainParameters):
    print("Model Training Started")
    app.model =  ModelTrainer(params.model.lower(), params.testsize)
    accuracy = app.model.train(params.path)
    return accuracy

预测方法是从 Web 应用程序的预测选项卡接收数据。它从 ModelTrainer 调用 predict 方法并返回预测值:

@app.post("/predict")
async def predict(data:PenguinSample):
    print("Predicting")
    spicies_map = {0: 'Adelie', 1: 'Chinstrap', 2: 'Gentoo'}
    species = app.model.predict(data)
    return spicies_map[species[0]]

3.5 测试服务器端

要运行此解决方案,请打开终端,然后转到train_solution\server 文件夹。运行以下命令:

uvicorn main:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.

应用程序运行后,转到浏览器中的localhost:8000 / docs。您应该看到如下内容:

首先,让我们测试一下训练终结点。展开它,然后单击"试用"按钮:

作为请求正文传递此 json 对象:

{
    "model": "svm",
    "path": "./data/penguins_size.csv",
    "testsize": 0.2
}

然后点击 执行 按钮:

以下是我们得到的回应:

以类似的方式,我们可以测试预测端点。试试吧!

3.6 一起运行

要运行服务器端,您需要转到train_solution\server文件夹并使用以下命令:

uvicorn main:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.

在另一个终端中,您需要转到train_solution\client文件夹并运行:

npm install
ng serve
√ Browser application bundle generation complete.

Initial Chunk Files   | Names         |      Size
vendor.js             | vendor        |   3.02 MB
polyfills.js          | polyfills     | 481.27 kB
styles.css, styles.js | styles        | 340.83 kB
main.js               | main          |  93.72 kB
runtime.js            | runtime       |   6.15 kB

                      | Initial Total |   3.92 MB

Build at: 2020-11-22T10:33:00.423Z - Hash: bf345d81dfd56983facb - Time: 10867ms

** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **


√ Compiled successfully.

完成此操作后,您可以转到localhost:4200并测试应用程序:

4. 模型加载解决方案

现在,以前的解决方案真的很漂亮。我真的很喜欢你可以选择不同的模型并玩转参数。然而,即使它是底层的,它也不是一个现实世界的例子,它更像是一个虚荣的项目。在实际解决方案中,一个组件负责收集数据,另一个组件负责处理该数据,第三个组件负责定期训练模型并将其存储在某个位置。然后,REST API 会利用这些存储的模型。现在,所有这些对于这个简单的教程来说都太多了,但是,我仍然需要给出一些更接近现实世界的问题和解决方案的东西。因此,服务器端的体系结构更改为:

这些更改也会影响 UI。火车选项卡变成了"加载"选项卡,它更简单一些。没有测试大小定义,也没有数据路径定义。但是,用户仍然可以选择要使用的模型。该解决方案位于load_solution/客户端路径中,如下所示:

服务器端位于load_solution/服务器文件夹中,它的变化更多一些。让我们来看看每个组件。

4.1 训练和保存模型

您可能已经注意到解决方案文件夹中的新文件夹"models"。在此文件夹中,您可以找到以下文件:

这些是已经训练过的模型。实际上,有一个脚本train_models_script.py,如果要再次重新训练以下模型,则可以运行该脚本。它利用了先前实现中的零碎部分,但有一个主要区别。模型不存储在内存中,而是存储在硬设备中。脚本如下:

from sklearn.ensemble import RandomForestClassifier

from joblib import dump

def load_data(scale = True):
    data = pd.read_csv('./data/penguins_size.csv')

    data['culmen_length_mm'].fillna((data['culmen_length_mm'].mean()), inplace=True)
    data['culmen_depth_mm'].fillna((data['culmen_depth_mm'].mean()), inplace=True)
    data['flipper_length_mm'].fillna((data['flipper_length_mm'].mean()), inplace=True)
    data['body_mass_g'].fillna((data['body_mass_g'].mean()), inplace=True)

    data["species"] = data["species"].astype('category')
    data["island"] = data["island"].astype('category')
    data["sex"] = data["sex"].astype('category')

    data["island_cat"] = data["island"].cat.codes
    data["sex_cat"] = data["sex"].cat.codes

    X = data.drop(['species', "island", "sex"], axis=1)

    if(scale):
        scaler = StandardScaler()
        X = scaler.fit_transform(X) 

    y = data['species']
    spicies = {'Adelie': 0, 'Chinstrap': 1, 'Gentoo': 2}
    y = [spicies[item] for item in y]
    y = np.array(y) 

    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=33)
    return X_train, X_test, y_train, y_test

# Train SVM
X_train, X_test, y_train, y_test = load_data(scale=True)
model = SVC(kernel="rbf", gamma=0.1, C=500, verbose=True)
model.fit(X_train, y_train)
dump(model, './models/svm.joblib') 

# Train Decision Tree
X_train, X_test, y_train, y_test = load_data(scale=False)
model = DecisionTreeClassifier(max_depth=5)
model.fit(X_train, y_train)
dump(model, './models/decision_tree.joblib') 

# Train Random Forest
X_train, X_test, y_train, y_test = load_data(scale=False)
model = RandomForestClassifier(n_estimators=11, max_leaf_nodes=16, n_jobs=-1, verbose=True)
model.fit(X_train, y_train)
dump(model, './models/random_forest.joblib') 

# Train Logistic Regression
X_train, X_test, y_train, y_test = load_data(scale=True)
model = LogisticRegression(C=1e20, verbose=True)
model.fit(X_train, y_train)
dump(model, './models/logistic_regression.joblib') 

load_data函数加载数据并执行所有必要的预处理,就像 DataLoader 在上一个解决方案中所做的那样。然后,我们使用 joblib 的转储函数训练模型并将其保存在文件中。您可以按如下方式运行此脚本:

python train_models_script.py

4.2 模型加载器

此组件看起来类似于先前实现中的 ModelTrainer,但它更简单。这是它的样子:

from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from penguin_sample import PenguinSample
from sklearn.preprocessing import StandardScaler
from joblib import load
import numpy as np

class ModelLoader():
    def __init__(self, algoritm):
        self.scaledData = True
        self._island_map = {'Torgersen': 2, 'Biscoe': 0, 'Dream': 1}
        self._sex_map = {'MALE': 2, 'FEMALE': 1}
        if(algoritm == 'svm'):
            self.model = load('./models/svm.joblib')

        if(algoritm == 'logistic regression'):
            self.model = load('./models/decision_tree.joblib')
        
        if(algoritm == 'decision tree'):
            self.scaledData = False
            self.model = load('./models/random_forest.joblib')

        if(algoritm == 'random forest'):
            self.scaledData = False
            self.model = load('./models/logistic_regression.joblib')

        self.scaler = StandardScaler()

    def prepare_sample(self, raw_sample: PenguinSample):
        island = self._island_map[raw_sample.island]
        sex = self._sex_map[raw_sample.sex]

        sample = [raw_sample.culmenLength, raw_sample.culmenDepth, raw_sample.flipperLength, \
		  raw_sample.bodyMass, island, sex]
        sample = np.array([np.asarray(sample)]).reshape(-1, 1)

        if(self.scaledData):
            self.scaler.fit_transform(sample)

        return sample.reshape(1, -1)

    def predict(self, data: PenguinSample):
        prepared_sample = self.prepare_sample(data)
        return self.model.predict(prepared_sample)

同样,根据我们从客户端接收的参数,我们使用 joblib 的 load 函数加载正确的模型。这两种方法用于执行预测。prepare_sample准备一个新样本进行模型处理,而预测方法则在模型中运行样本并检索预测。

4.3 REST API 模块

此模块与之前的实现几乎相同:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from model_loader import ModelLoader
from train_parameters import TrainParameters
from penguin_sample import PenguinSample

origins = [
    "http://localhost:8000",
    "http://127.0.0.1:8000/predict",
    "http://127.0.0.1:8000/load",
    "http://localhost:4200"
]

app = FastAPI()
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.model = ModelLoader('svm')

@app.post("/train")
async def train(params: TrainParameters):
    print("Model Loading Started")
    app.model =  ModelLoader(params.model.lower())
    return True

@app.post("/predict")
async def predict(data:PenguinSample):
    print("Predicting")
    spicies_map = {0: 'Adelie', 1: 'Chinstrap', 2: 'Gentoo'}
    species = app.model.predict(data)
    return spicies_map[species[0]]

主要区别在于使用了 ModelLoader 类,并且没有对模型进行任何训练。

要运行服务器端,您需要转到train_solution\server文件夹并使用以下命令:

4.4 一起运行

要运行服务器端,您需要转到load_solution\server文件夹并使用以下命令:

uvicorn main:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.

在另一个终端中,您需要转到load_solution\client文件夹并运行:

npm install
ng serve
√ Browser application bundle generation complete.

Initial Chunk Files   | Names         |      Size
vendor.js             | vendor        |   3.02 MB
polyfills.js          | polyfills     | 481.27 kB
styles.css, styles.js | styles        | 340.83 kB
main.js               | main          |  93.72 kB
runtime.js            | runtime       |   6.15 kB

                      | Initial Total |   3.92 MB

Build at: 2020-11-22T10:33:00.423Z - Hash: bf345d81dfd56983facb - Time: 10867ms

** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **


√ Compiled successfully.

完成此操作后,您可以转到localhost:4200并测试应用程序:

结论

在本文中,我们能够看到如何使用 FastAPI 和一些 JavaScript 框架(在此特定情况下为 Angular)部署机器学习算法。我们看到了什么是REST API以及如何使用FastAPI构建它。最后,我们在用户界面的帮助下利用了这个API,完成了整个解决方案。如果你想更进一步,你可能想把它放到Docker实例中,并使用Kubernetes

感谢您的阅读!

原文标题:Deploying Machine Learning Models with FastAPI and Angular

作者:AI, Angular, Machine Learning, Python

原文:https://rubikscode.net/2020/11/23/deploying-machine-learning-models-with-fastapi-and-angular/

编译:LCR

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码