如何在 AWS 上部署带芹菜的阿帕奇气流
完全指南
免责声明:本帖假设基本了解 气流 、 AWS ECS、 (安全组等)和Docker*。我建议一种架构,在您的特定情况下,* 可能不完美,也可能不是最好的 。在这种情况下,从这个讲座中得到你想要的。
一点背景
在我工作的地方,我们广泛使用阿帕奇气流。我们大约有 15 个 Dag,看起来可能不多,但其中一些有许多步骤(任务),包括下载大型 SQL 备份、使用 Python 转换一些值并将其重新上传到我们的仓库。
我们的气流仪表板截图
起初,我们开始使用顺序执行器(没有并行性,一次只运行一个任务),因为设置简单,而且没有很多 Dag。随着时间的推移,dag 不断增加,其中一些提供了利用并行性的机会,因此对于一些配置,我们开始使用本地执行器。
利用并行设置的 DAG 示例
你可能会问……为什么整件事不再有用了?
这两种情况都只在 AWS ECS 中部署了一个容器来做所有的事情:服务于 web UI、调度作业和执行它们的工作进程。这不是可扩展的,我们唯一的选择是垂直扩展(你知道,添加更多 vCPU、更多 RAM 等等)。没有其他选择。
此外,如果容器中的某个东西失败了,整个东西都失败了(没有高可用性)。同样**,整个服务必须是公共的**,以便通过互联网访问网络服务器。如果你想使某些组件私有(如调度器和工人)这在这里是不可能的。
为什么要创建这个指南?
没有任何指南谈论如何在 AWS 中部署气流,或者利用他们广泛提供的服务。使用docker-compose
在本地或 EC2 中部署整个系统很容易,但是这真的是您想要的吗?在同一个 VPC 中,完全隔离的节点如何相互通信?把需要保密的事情保密,把需要公开的事情公开?
建筑
用 Lucichart 制作的建筑图
乍一看,这整个图表可能很复杂,甚至可能会让感到害怕,但是不要担心。由此你要了解的大概只是以下几点:
- 一个人只能通过入口连接到 Airflow 的 web 服务器或 Flower(我们稍后会谈到 Flower)。没有从外部到调度器、工作器、Redis 甚至元数据数据库的访问点。你不会想从外面连接那里。
- 一切都在同一个 VPC 内,让事情变得更简单。每个对象都有自己的安全组,只允许来自正确服务的连接。
- 一切都是 AWS Fargate 的任务,同样,我们稍后将讨论 Fargate。
我们将使用什么服务?为什么?
主要来说, AWS ECS 和 Fargate 是其中的明星。
Amazon Elastic Container Service(Amazon ECS)是一个完全托管的容器编排服务[…]您可以选择使用 AWS Fargate 来运行您的 ECS 集群,这是一个针对容器的无服务器计算。Fargate 消除了供应和管理服务器的需要,允许您为每个应用程序指定和支付资源,并通过设计应用程序隔离来提高安全性。
关于无服务器计算的一个很好的类比是我在这篇酷帖中读到的:
无服务器计算就像无人驾驶汽车;还有一个司机,只是你看不到。你不需要问司机是饿了、累了、喝醉了还是需要停下来上厕所。如果我们让无人驾驶汽车在我们的道路上行驶,那将是因为我们不必关心司机,只是他们会带我们去我们想去的地方这个事实——玛丽·布兰斯科姆
我喜欢说 ECS 只是一个 chill Kubernetes,不需要太多的配置,它可以使用 Docker 映像和一些额外的设置来部署您的应用程序,例如您希望您的应用程序能够使用多少 CPU 或 RAM,如果您希望自动扩展,使用开箱即用的负载平衡器等等。
我们还应该建立一个元数据数据库,为此我们将使用方便的 RDS。
指南
在做任何事情之前,我们必须设置我们将使用哪个 Docker 图像,并将其设置为基础图像以在其上构建。为此,我使用了普克尔的气流。这张 docker 图片为你提供了在 3 个主要执行器中设置气流所需的一切。下载量超过 500 万,可以肯定地说这家伙做得很棒。
Dockerfile 文件
让我们创建我们的自定义 docker 文件。我使用了以下方法:
我添加了一个个人的airflow.cfg
(包含 s3 日志和 SMTP 服务器凭证的配置)、一个自定义的entrypoint.sh
和一个包含我所有 Dag 的dags
文件夹。在这种情况下,已经使用指令WORKDIR
在基础图像中将.
定义为/usr/local/airflow
。
我的切入点如下:
我去掉了基本图像的入口点中的一些行,这些行是为不同的执行者服务的条件,并且只为芹菜做了这些行,还去掉了一个烦人的不工作的wait_for_port
函数。
这整个事情首先做的是,设置有用的环境变量,然后,根据docker run
中给出的命令,跟随一个执行代码不同部分的开关。比方说,如果您正在启动一个worker
,它将安装您的 Python 需求,然后执行 worker 进程。如果是webserver
,它也会安装需求,但也会用airflow initdb
命令初始化数据库,然后打开 air flow UI 的 web 服务器。
本地测试
如果你想测试整个事情,并确保一切正常,你可以用 Puckel 的 docker-compose 芹菜 YAML 文件来做。
过一会儿,你应该能够访问localhost:8080
并看到气流的仪表板。你还不如访问localhost:5555
和看花。从这一点出发,运行一些示例 DAGs 甚至是您的示例——并亲自看看 web 服务器中的触发器是如何处理事情的,调度程序抓取任务并将其发送到队列,最后,工作人员拾取并运行它。
上传 docker 图像
对于本教程,我们将保持简单,使用 AWS ECR。ECR 只是一个 Docker 图像库。
ECR 与 ECS 集成,开箱即用。
来源: AWS ECR
要创建存储库,请进入 ECR 控制台,点击创建存储库,选择您认为合适的名称。提示:您可以有一个用于暂存气流的存储库,一个用于生产。请记住,所有的气流过程都将使用相同的图像,以避免冗余和干燥。
我的 AWS ECR 截图
现在进入新的存储库,点击查看推送命令。这将引导您将气流图像推向回购。如果在第一步中出现错误,比如unable to locate credentials
您可能还没有设置您的awscli
凭证,请查看这个。
一旦您推送图像并在 ECR 控制台中看到它,您就为下一步做好了准备!
在 ECS 上部署服务
让我们从创建 ECS 群集开始,转到“Services ”,然后选择“ECS”。
可能因为这是你第一次,你会看到一个向你展示服务的屏幕和一个简单的第一个集群按钮。这里您需要做的只是创建一个纯网络集群。
AWS ECS 中集群创建的屏幕截图
此时,您可能会看到一个类似这样的窗口。这是您自己的选择,是使用与其余实例相同的 VPC,还是专门为该集群创建另一个——我选择了后者。如果您选择这样做,我认为一个子网就足够了。
设置数据库(如果您还没有)
我们将建立一个 PostgreSQL 9.6 微实例数据库。如果您熟悉如何做到这一点,请随意操作并跳到下一步。
转到服务-> RDS。转到数据库部分和创建数据库。选择 PostgreSQL 徽标,转到版本 9.6.X,任何次要版本都可以。现在,我仍然在考虑是否我非常便宜或者气流元数据数据库真的不需要那么健壮,所以我选择了一个自由层微实例。如果你发现这对你来说还不够,以后很容易升级,所以不要担心。
接下来的配置由您决定,无论实例名称、用户名、密码是什么,只要确保它将创建在 ECS 使用的同一个群集中。
创建任务定义
太好了,我们现在有空的星团了。让我们创建我们的任务定义。
任务定义就像蓝图一样,它们定义了您的服务将如何执行——它将使用哪个容器,分配给它多少 CPU 和 RAM,映射哪些端口,它有哪些环境变量,等等。
转到左侧面板的任务定义,点击创建新的任务定义。
AWS ECS 截图
记住,我们想要 Fargate,所以选择它并点击下一步。
AWS ECS 截图
从现在开始,我们必须为 web 服务器、调度器和工作器创建一个任务定义。
我将向您介绍您必须为每项任务正确工作提供的所有必要配置。
**任务定义名称:**标识名称。选择一些描述性的东西,如 airflow-webserver、airflow-worker 等。
**任务角色:**任务将要注入到容器中的 IAM 角色。选择一个对你的任务必须做的事情有权限的人——从秘密管理器提取秘密,用awslogs
日志驱动程序记录日志,从 S3 查询存储桶。如果你不确定,就使用基本的ecsTaskExecutionRole
,如果下拉列表中没有,请在此处检查。
网络模式: awsvpc
既然我们用的是 Fargate。
**任务执行角色:**能够从 AWS ECR 提取图像并登录 Cloudwatch 的角色。ecsTaskExecutionRole
这两种政策都有。
**任务大小:**几乎完全取决于你。你的大部分资源将花在工人身上,因此他们会做所有的脏活。只是提供一个指南,这些是我的配置:
Webserver: 1GB, 0.5vCPU
Scheduler: 2GB, 0.5vCPU
Flower: 512MB, 0,25vCPU
Worker: 3GB, 1vCPU
Redis: 2GB, 1vCPU
现在点击添加容器。右侧面板将会弹出。
**集装箱名称:**集装箱的标识名。
**图像:ECR 存储库的 URL。例:*1234567890 . dkr . ECR . us-east-1 . Amazon AWS . com/air flow-celery:最新。*对于 Redis,使用:*docker.io/redis:5.0.5
T21端口映射:*对于 webserver 写 8080。对于花,5555。对于工人,8793-访问日志。对于 Redis,6379。
在环境部分,在命令中,根据您正在创建的任务选择webserver
、flower
、worker
或scheduler
。
你也可以利用环境变量!您可以使用value
来硬编码 env,或者使用valueFrom
来使用秘密管理器或 AWS 参数存储库。**但是请不要在没有安全措施的情况下注入秘密。**更多信息这里。
对于除 flower 之外的所有服务,您必须设置POSTGRES_
变量,记得我们在entrypoint.sh
中提到的那些变量吗?如果没有这些,服务在尝试连接到一个不存在的数据库时将会悲惨地失败。
对于调度器和工作器的任务定义,需要设置REDIS_HOST
。您可以像我在这里一样设置 IP 或内部 DNS。我们没有设置用户和密码认证,我不认为这是必要的,因为服务本身是私人的。尽管如此,请随意。
我们正式完成了任务定义!坚持住,从现在开始事情会变得更容易。。
启动服务
转到您的 ECS 集群,在服务选项卡中单击创建。
- 选择相应的任务定义。
- 写服务的名字: webserver,scheduler,workers 等。
- 对于 webserver、Redis、flower 和 scheduler,我们应该总是有一个任务。对于工人,我们想要多少就有多少,还记得横向缩放吗?
- 点击下一步。选取您的群集的 VPC 以及您想要使用的任何子网。
- 对于安全组,只需确保将名称更改为更容易识别的名称。比如:气流-web server-安全-群组。我们稍后会弄乱这些。
- 公有 IP:还记得第一张架构图吗?嗯,除非你不想使用负载平衡器/入口,否则所有服务都应该是私有的。
- 对于 webserver 和 flower,我们可以添加一个应用负载均衡器,作为弹性 IPs 的替代。为什么不能用 EIPs?目前不可能。要在 AWS 中设置 LB,参考此处的。
- 确认并点击创建!
- 每隔一个服务重复一次。
过一会儿,所有的服务都应该是这样的。不要担心,如果一些服务不工作。我们将在下一节整理出它们之间的联系。
连接—安全组
我们现在应该做的是确保每个服务从相应的来源接收信息。我们要设置他们的安全组。
一个安全组充当您的实例的虚拟防火墙,控制入站和出站流量。在 VPC 中启动实例时,最多可以为该实例分配五个安全组。安全组在实例级起作用,而不是在子网级。因此,可以将 VPC 子网中的每个实例分配给不同的安全组。–AWS 文档
以下是气流芹菜架构的官方文档:
我将借用 Airflow 文档中的一些语句:
Airflow consist of several components:
**Workers** - Execute the assigned tasks
**Scheduler** - Responsible for adding the necessary tasks to the queue
**Web server** - HTTP Server provides access to DAG/task status information
**Database** - Contains information about the status of tasks, DAGs, Variables, connections, etc.
**Celery** - Queue mechanismThe components communicate with each other in many places
**[1] Web server –> Workers** - Fetches task execution logs
**[2] Web server –> DAG files** - Reveal the DAG structure
**[3] Web server –> Database** - Fetch the status of the tasks
**[4] Workers –> DAG files** - Reveal the DAG structure and execute the tasks
**[5] Workers –> Database** - Gets and stores information about connection configuration, variables and XCOM.
**[6] Workers –> Celery’s result backend** - Saves the status of tasks
**[7] Workers –> Celery’s broker** - Stores commands for execution
**[8] Scheduler –> Database** - Store a DAG run and related tasks
**[9] Scheduler –> DAG files** - Reveal the DAG structure and execute the tasks
**[10] Scheduler –> Celery’s result backend** - Gets information about the status of completed tasks
**[11] Scheduler –> Celery’s broker** - Put the commands to be executed
上述内容应在安全组中得到反映。
进入 AWS 中的 VPC 服务,选择安全组。在设置所有服务时,我要求您用一个合适的名称来标识它们,这样您可以方便地过滤它们并提供配置。
我的气流安全组的屏幕截图
从这里,选择每个组并设置正确的**入站规则。**以雷迪斯为例:
Redis 服务器运行在端口 6379 上(我们在任务定义中启用的端口)。架构图向我们展示了工作人员和调度人员应该可以访问它。我们还包括 flower 来检查经纪人状态。因此,我们为那些实例的每个源安全组包含了行。
请记住,按照图表并相应地设置所有服务的安全组。这确保了应该被允许的服务之间的每个连接。如您所见,数据库应该接受来自每个气流过程的连接。
测试整个事情
测试很容易,只需访问 web 服务器和 flower。启动一个示例 DAG,看看在执行任务时,活动计数器如何快速增加和减少。
不要担心,如果有什么不工作,去检查失败的容器任务的日志并做一些研究,解决方案应该很快出现。
如果你仍然失败,很可能是你忘记做什么了(或者是我忘记告诉你了,哈哈)。欢迎评论,我会尽力帮助你!
如果一切顺利…
恭喜你!你成功了!
就是这个!你的气流集群准备好了!我知道我知道…这很长,甚至有点混乱,但是嘿!你成功做到了!👏👏😄。
这对我来说是一次漫长的旅行,我在建立自己的集群时经历了许多问题、错误和异常。我真的希望我的这份指南能让你少一些头疼。
在那之前,谢谢你,再见!👋👋👋
如何将 Docker 容器部署到云中
Docker 和 GCP 让与世界分享你的作品变得容易
ocker 容器是很棒的小东西。它们本质上是独立的应用程序,可以在任何操作系统上运行。
假设您有一个 Python 应用程序,您将它与运行它所需的一切捆绑到 Docker 容器中——该容器现在可以在任何 Windows、Linux 或 macOS 系统上运行,无需安装任何东西!
Docker 的另一个好处是对云平台上的容器的支持,比如我们将在本文中使用的 Google Cloud (GCP)。
我们可以快速构建一个应用程序,使用 Docker 将其打包到一个容器中,然后使用 GCP 在全球范围内部署它。
这就是我们在本文中要做的。我们将采用一个简单的 Python API,用 Docker 打包,用 GCP 部署,涵盖:
**> Project Setup****> Dockerfile**
- FROM
- WORKDIR and COPY
- RUN
- CMD**> Building the Docker Image****> Deploy with Google Cloud Platform**
- GCloud SDK
- Cloud Build and Container Registry
- Cloud Run
项目设置
我们不会仅仅关注 Python 代码,因为这不是本文的目的。相反,带上你自己的代码——或者,这是我之前做的一些东西。
我们的 gcp-api 目录应该是这样的。
我们将代码存储在一个名为gcp-api
(你可以随便叫它什么)的目录中,命名为app.py
。除了我们的脚本,我们还需要:
- aDocker file——Docker 的使用说明书
- requirements.txt —一组 Python 模块,供我们的 docker 文件安装
当然,我们用的是 Docker,所以;我们也需要码头工人。可以从这里安装。
如果您在安装 Docker 时遇到任何特定于操作系统的问题,此视频中的 1:46:21 标记说明了 Windows 安装,随后是 macOS 的 1:53:22 标记。
Dockerfile 文件
docker 文件是我们的容器构建蓝图。它确切地告诉 Docker 如何以一种产生自包含应用程序的方式重新排列我们的脚本和文件。
就像盖房子一样。
兰迪·法特在 Unsplash 拍摄的照片
我们的脚本和文件是原材料(木材、砖块等)。).我们创建了一套我们希望我们的房子是什么样子的说明(Dockerfile),然后我们把它交给我们的建筑师(Docker),他然后做所有的技术工作来产生一个房子蓝图(图像)。
稍后,我们还将把蓝图交给我们的建造者(Google Build),他将为我们建造房子(容器)——但现在还不是时候。
我们的档案。看起来是这样的:
FROM python:3.6-slim-busterWORKDIR /app
COPY . .RUN pip install -r requirements.txtCMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 app:app
最初,它可能看起来令人困惑,但它非常简单。
来自 python:3.6-slim-buster
Docker 文件的第一行用另一个预构建的 Docker 映像初始化我们的容器映像。
这个预构建的映像本质上就是一个包含 Python 3.6 的轻量级 Linux 操作系统。
但为什么是*【瘦身达人】*?嗯, buster 是 Debian(一个 Linux 发行版)所有版本 10 变体的代号。
至于他们为什么选择“buster”这个词——我想有人打开字典,选择了他们看到的第一个词。
另一方面,斯利姆确实有道理。正如你可能已经猜到的,它意味着 Debian 10 . x——但是被削减了,导致一个更小的包大小。
官方 Python 图片的完整列表可从这里获得。
Firestore (NoSQL 数据库)通过谷歌的 Firebase 平台提供。图像来源。
警告: 另外值得注意的是,我们这里用的是 Python 3.6 你不需要坚持这一点,除非你将使用 Google Firebase(我们不会在这里使用,但意识到这一点是很好的)。
如果您碰巧在 Python 中使用 Google Firebase,您可能会使用 *python-firebase*
模块,其中包含一个名为 *async*
的导入。
不幸的是,Python 3.7 引入了这个词作为关键字。我们坚持使用 Python 3.6 来避免由此产生的语法错误。
工作目录和副本
接下来是WORKDIR
和COPY
。
我们使用WORKDIR
将我们的映像(我们的容器的构造站点)中的活动目录设置为/app
。从现在开始,我们映像外部的.
是指我们当前的目录(例如/gcp-api
),我们映像内部的.
是指/app
。
在WORKDIR
之后,我们COPY
从本地目录/gcp-api
到内部活动目录/app
的所有内容。
我们在图像中复制app.py
到/app
的原因是因为这是我们的谷歌云实例所期望的结构。我们可以改变这一点,但这是我们将在这里使用的。
奔跑
现在,我们有了自己的pip install
指令。我们使用RUN
告诉 Docker 运行下面的命令。下面的命令是pip install -r requirements.txt
。
通过编写pip install -r requirements.txt
,我们告诉 Docker 对包含在requirements.txt
中的每一行递归运行pip install
。
那么requirements.txt
长什么样?
pandas==1.1.1
gunicorn==20.0.4
flask==1.1.2
flask-api==2.0
当它被输入到我们的递归pip install
指令中时,它被翻译成:
pip install pandas==1.1.1
pip install gunicorn==20.0.4
pip install flask==1.1.2
pip install flask-api==2.0
我相信每个人都知道这一点。
煤矿管理局
根据我们的应用程序,我们的最终指令不是必需的。在这种情况下,它使用gunicorn
Python 包来托管我们的 API。
尽管如此,CMD
指令相当于打开我们计算机的命令行界面 CLI 并键入我们提供的任何命令,在本例中为exec gunicorn — bind :$PORT --workers 1 --threads 8 --timeout 0 app:app
。
建立码头工人形象
在本文的前面,我们描述了 Docker 容器的房屋建筑隐喻。到目前为止,我们已经获得了原材料(脚本和文件),并编写了一套说明,解释我们希望我们的房子是什么样的(Dockerfile)。
现在,是时候创建我们的蓝图了 Docker 图像。
我们可以通过执行以下命令来创建它:
docker build -t gcp-api .
- 这里,Docker 映像构建命令是
docker build
- 接下来,我们使用
-t
标志来指定我们的图像名称—gcp-api
- 最后,我们告诉 Docker 用
.
包含当前目录中的所有内容
此时,我们已经有了蓝图,现在我们需要的是我们的构建者——云——所以让我们开始设置它。
使用谷歌云平台进行部署
要将容器部署到云中,我们需要采取三个步骤。首先我们:
- 下载 Google Cloud SDK,我们将使用它来—
- 用云构建构建我们的容器。
- 将集装箱上传到 GCP 的集装箱登记处。
- 使用云运行部署它。
GCloud SDK
我们可以在这里找到 SDK 安装程序。安装完成后,我们需要通过打开 CMD 提示符(或等效的 CLI)并键入以下命令来验证我们的 GCloud SDK:
gcloud auth login
这个命令打开我们的 web 浏览器,并允许我们像往常一样登录到 Google Cloud。我们将 Docker 配置为将我们的 GCP 凭据用于:
gcloud auth configure-docker
最后,将活动项目设置为您的项目 ID(我的是medium-286319
),使用:
gcloud config set project *medium-286319*
云构建和容器注册
Google 的容器注册(GCR)服务允许我们存储 Docker 容器,我们可以将其用作部署的发射台。
我们需要一个现有的项目来部署我们的容器。图片作者。
在我们可以使用 GCR(或任何其他 GCP 服务)之前,我们需要创建一个项目。我们可以通过在 GCP 控制台中导航到项目选择器页面并点击创建项目来实现。
建立一个新项目非常简单。图片作者。
我们需要做的就是给我们的项目起一个名字。我用的是介质。
如果这是我们第一次在项目中使用 GCR,我们将需要启用 GCR API。图片作者。
现在我们有了项目设置;我们应该能够访问容器注册表。在这里,我们应该能够在顶栏中看到我们新创建的项目的名称。
要使用 GCR,我们需要点击控制台窗口中央的Enable Container Registry API。
最后,我们可以通过将容器提交到 Cloud Build——构建 Docker 容器的 GCP 服务——来将容器上传到 GCR。
为此,我们在项目目录(gcp-api
)中打开 CLI,并键入:
gcloud builds submit --tag gcr.io/[PROJECT-ID]/gcp-api
gcloud builds submit
将附加到我们当前目录的 Docker 映像提交到 Cloud Build——它将被打包到一个容器中。
我们的容器注册位置被提供给--tag
标志,其中:
*gcr.io*
就是 GCR 主机名 。*[PROJECT-ID]*
是我们的项目 ID;我们在创建我们的项目时看到了这一点——对我来说,它是*medium-286319*
。*gcp-api*
是我们的形象名称。
我们的项目 gcp-api 在容器注册表中。图片作者。
如果我们回到我们的 GCR 窗口,我们应该能够看到我们新上传的 Docker 图像。如果它还没有出现,很可能还在构建过程中——这可以在我们的云构建仪表板中找到。
云运行
现在我们已经准备好了 Docker 容器;我们可以用云运行来部署它。
使用云运行部署容器的分步过程。图片作者。
在云运行界面中,我们通过以下方式进行部署:(1)单击创建服务,(2)配置我们的部署,(3–4)选择容器,以及(5)创建我们的部署!
云运行中正在进行的部署。图片作者。
我们将在云运行控制台中看到部署状态,这应该不会超过几分钟。
完成后,我们的部署名称和区域旁边会出现一个绿色勾号和 URL。图片作者。
完成后,我们会看到部署名称旁边有一个绿色勾号,旁边有我们的部署 URL。
完成了的
就是这样,我们已经把我们的 Python 应用程序打包到 Docker 容器中,并使用 Google Cloud 将其部署到 web 上!
多亏了一些出色的工具——即 Docker 和 GCP——这个过程没有痛苦,并且(通常)一次又一次地导致完美的部署。
现在,比人类历史上任何时候都多。我们可以将脑海中的想法和概念在现实世界中有形地呈现出来——这可以产生一些真正令人惊叹的创作。
我希望这篇文章能帮助你们中的一些人——如果你有任何问题、反馈或想法,请随时通过 Twitter 或在下面的评论中联系。感谢阅读!
有兴趣了解云上的 SQL 吗?试试 Google 出色的 MySQL、PostgreSQL 和 SQL Server 数据库服务:
Google 云和 Python 上的 SQL 简明指南
towardsdatascience.com](/sql-on-the-cloud-with-python-c08a30807661)
如何在谷歌云平台上部署可解释模型
获取生产张量流模型的本地和全球解释
图片来源于 Pixabay 。
由 Chris Rawles,Michael Munn 和 Michael Abel 发布。
现代机器学习和人工智能已经证明了在解决非常复杂的问题方面令人印象深刻的结果。然而,更复杂的问题往往意味着更复杂的数据,这必然导致更复杂的模型。真正理解一个模型为什么做出某种预测,可以和原问题本身一样复杂!
这可能会有问题,因为许多这样的 ML 系统已经影响到医疗干预、自主运输、刑事司法、风险管理和许多其他社会领域的用例。在许多情况下,这些人工智能系统的有用性和公平性受到我们理解、解释和控制它们的能力的限制。因此,相当多的努力和研究已经进入了解开强大而复杂的 ML 模型的黑盒,如深度神经网络。
可解释的人工智能指的是方法和技术的集合,这些方法和技术使人类能够理解为什么一个模型会给出特定的结果。模型可解释性是我们在谷歌云的高级解决方案实验室教给客户的一个关键话题,在这篇文章中,我们将展示如何使用谷歌云的可解释人工智能来部署可解释和包容的机器学习模型。
这篇文章中使用的所有代码都可以在这里找到。
可解释方法的分类
(事后)模型可解释性方法的概述和不同技术的例子。
大多数可解释性方法可以沿着三个轴分开[ 来源 ]:
**内在与事后。**所谓内在,我们指的是内在可解释的模型。也就是说,它们在结构上足够简单,我们可以通过简单地查看模型本身来理解模型是如何进行预测的。例如,线性模型的学习权重或通过决策树学习的拆分可用于解释模型做出预测的原因。
事后方法包括使用经过训练的模型和数据来理解为什么做出某些预测。在某些情况下,事后方法也可以应用于具有内在可解释性的模型。
在这篇文章中,我们将关注后特设模型的可解释性,因为许多先进的方法,如梯度推进和神经网络,是最好的理解使用这些方法。
**模型不可知与模型特定。**模型不可知意味着可解释性方法可以应用于任何模型,而特定于模型的方法只能用于某些模型类型。例如,如果该方法只适用于神经网络,那么它将被认为是特定于模型的。相反,如果一个可解释性方法将训练好的模型视为一个黑盒,那么它将被认为是模型不可知的。
局部与全局:局部可解释性方法旨在解释单个数据点或预测,而全局方法试图提供模型整体表现的综合解释。通过使用局部结果的集合,所有局部方法都可以变成全局技术。
在谷歌云上部署可解释的模型
你可以使用可解释的人工智能在 GCP 部署可解释的模型,并使用gcloud beta ai-platform explain
命令进行预测。
使用解释进行训练和预测的步骤是
- 训练一个模型并将其部署在 GCP 上。
- 将一个包含基线特征值的 JSON 文件上传到一个云存储桶。
- 使用这个 JSON 文件创建模型的一个版本,并指定
explanation-method
。 - 致电
gcloud beta ai-platform explain
获取解释。
下面我们将更详细地展示这些步骤。
首先,你需要一个在谷歌云人工智能平台(CAIP)上训练和部署的模型。我们将查看纽约市出租车数据集。你可以看看这篇博文,看看如何在 CAIP 轻松训练一个模特。在撰写本文时,AI 解释仅支持 TensorFlow 1.x,因此无论您构建什么模型,请确保您使用 TensorFlow 1.x。一旦您将模型保存为 SavedModel 格式,我们将在 CAIP 上创建一个新模型:
gcloud ai-platform models create taxifare
在部署我们的模型之前,我们必须配置一个explanations_metadata.json
文件,并将其复制到模型目录中。在这个 JSON 文件中,我们需要告诉 AI 解释我们的模型所期望的输入和输出张量的名称。
此外,在这个文件中,我们需要设置input_baselines
,它告诉解释服务我们的模型的基线输入应该是什么。理解基线对于许多模型解释技术的有效使用是很重要的。两种支持的技术,采样 Shapley 和综合梯度,将预测与基线特征值和预测进行比较。选择合适的基线很重要,因为本质上您是在比较模型的预测与基线值的比较。要阅读更多关于基线的内容,请查看可解释的人工智能白皮书。
一般来说,对于数字数据,我们建议您选择一个简单的基线,如平均值或中值。对于本例,我们将使用每个要素的中值-这意味着此模型的基线预测将是我们的模型使用数据集中每个要素的中值预测的出租车费用。
我们可以将这个 Python 字典写出到一个 JSON 文件中:
# Write the json to a local file
with open(‘explanation_metadata.json’, ‘w’) as output_file:
json.dump(explanation_metadata, output_file)
# Copy the json to the model directory.
然后在 bash 中,我们使用gsutil.
将 JSON 文件复制到您的模型目录中
$ gsutil cp explanation_metadata.json $model_dir
现在我们已经创建了我们的explanations_metadata.json
文件,我们将部署模型的新版本。这段代码非常类似于使用gcloud
创建模型版本的通常过程,但是有一些额外的标志:
gcloud beta ai-platform versions create $VERSION_IG \
-- model $MODEL \
--origin $model_dir \
--runtime-version 1.15 \
--framework TENSORFLOW \
--python-version 3.5 \
--machine-type n1-standard-4 \
**--explanation-method ‘integrated-gradients’ \
--num-integral-steps 25**
使用**解释方法
**标志,您可以指定解释方法——目前支持[integrated-gradients](https://github.com/ankurtaly/Integrated-Gradients)
和[sampled-shapley](https://christophm.github.io/interpretable-ml-book/shapley.html)
。
注意:在综合渐变和采样 Shapley 之间做出决定时,我们引用了白皮书:
一般来说,对于神经网络和可微分模型,推荐使用积分梯度。它提供了计算优势,特别是对于大的输入特征空间(例如,具有数千个输入像素的图像)。对于不可微模型,建议使用采样 Shapley,这是由树和神经网络的集成组成的 AutoML 表模型的情况。
此外,对于那些想知道采样的 Shapley 方法与流行的【SHAP】库有何不同的人,我们还引用了白皮书:
应用 Shapley 值的方法有很多种,不同之处在于它们引用模型、定型数据和解释上下文的方式。这导致了用于解释模型预测的 Shapley 值的多样性,
考虑到 Shapley 的唯一性,这是有点不幸的。Mukund Sundararajan 和 Amir Najmi 的《模型解释的多个 Shapley 值》中对该主题进行了全面的讨论。我们的方法属于基线 Shapley 类别,并支持跨各种输入数据模态的多个同步基线。
现在我们的模型已经部署好了,我们可以从 Jupyter 笔记本中获得本地属性:
*resp_obj = !gcloud beta ai-platform explain — model $MODEL \
— version $VERSION_IG — json-instances=’taxi-data.txt’
response_IG = json.loads(resp_obj.s)# Analyze individual example.
explanations_IG = response_IG[‘explanations’][0][‘attributions_by_label’][0]*
我们可以将这些加载到 Pandas 数据框架中,并绘制各个示例的属性:
*df = pd.DataFrame(explanations_IG)
df.head()*
*row = df.iloc[0] # First example.
row.plot(kind=’barh’)*
最后,我们可以通过聚集局部属性来获得全局模型可解释性:
*df.mean(axis=0).plot(kind=’barh’, color=’orange’)*
有关使用采样 Shapley 全局属性的更多信息,请参考本文。
结论
就是这样!在这篇文章中,我们展示了如何使用可解释的人工智能在谷歌云平台上部署可解释的模型。可解释的人工智能工具允许用户从已部署的模型中获得本地解释。这些解释可以组合在一起,以提供全局可解释性。除了上述步骤,您还可以查看假设工具来检查和解释您的模型。
额外资源
如何使用 Flask + Gunicorn + Nginx + Docker 部署 ML 模型
一个配置 Flask + Gunicorn + Nginx + Docker 的模板,并附有详细的解释,这应该会让你更接近使用微服务、构建 MVP 等等。
吴伯毅 via flickr
开发一个好的机器学习模型可能很棘手,但即使有人成功做到了,在你部署它以便其他人可以访问它之前,它仍然几乎没有用处。
部署模型有很多方法,我想谈谈一个非常简单的适用于基本 MVP 的解决方案——用 Flask 为您的模型编写一个 API,用 Gunicorn 为应用服务器编写 API,用 Nginx 为 web 服务器编写 API,用 Docker 包装它,这样就可以更容易地部署在其他机器上(特别是 AWS 和 GCP)。
完整代码可以在 GitHub repo 中找到。
设置服务器
我更喜欢在我专门租用的服务器上用新配置做实验,而不是使用我的个人或工作硬件。这样,如果你把什么东西弄坏了,也没什么大不了的。我推荐使用 Linode 来实现这些目的,因为我个人在我的实验中使用它们,它们的硬件工作得很好。但是你可以随意使用任何其他服务,只要是在 LTS Ubuntu 18.04 上。
曼努埃尔·盖辛格
如果你决定使用 Linode,那么这一部分就是为你准备的。导航至 Linodes 并点击“添加 Linode”。有几件事你应该填写。在发行版中,我建议选择 Ubuntu 18.04 LTS 映像、区域—任何离你更近的地方(我使用法兰克福,DE)、Linode 计划— Nanode(每月仅花费 5 美元,但对于我们的目的来说已经足够了)、root password —你的密码,然后单击“创建”。一段时间后(大约几分钟),你可以进入“网络”,在那里你可以找到通过 SSH 访问你的服务器的信息。
我建议做的下一件事是连接到服务器并创建具有 sudo 特权的非 root 用户。该操作背后的逻辑相当简单:您不希望以 root 用户身份运行任何东西来扰乱服务器,因为这样更容易破坏东西。
adduser usernameusermod -aG sudo username
最后,切换到您的新用户:
su — username
创建应用程序容器
整个系统配置分为两部分:应用容器(Flask + Gunicorn)和 web 容器(Nginx web 服务器)。先说第一个。
步骤 0 —安装 Docker 和 Docker Compose
Docker 和 docker-compose 安装非常容易。它们分别在 4 行和 2 行中完成。因此,我建议遵循以下页面:
步骤 1 —创建 Flask 应用程序和 WSGI 入口点
在主目录中创建 flask_app 目录,并将以下文件放在那里。
这是最基本的 Flask 应用程序,几乎没有任何功能。我们不加载任何模型,不添加任何 GET/POST 请求之类的东西。那是以后的事。目前,我们只有一个在主页上显示“hello world”的应用程序。
这是一个非常简单的部分——我们只需为 Gunicorn 创建一个单独的文件,让它在端口 8000 上运行。
步骤 2 —为 Flask 创建一个 Docker 映像
现在,我们需要创建一个 Dockerfile 来使用这些文件,并创建一个稍后可以运行的映像。
对于那些不熟悉 Docker 的人来说,这个脚本的作用如下:导入 Python 3.6.7 图像,为所有文件设置工作目录,复制包含 Flask、Gunicorn 和运行 Flask 应用程序所需的所有内容的需求文件。之后,通过 RUN 命令安装来自需求的所有包,最后我们将所有文件从 flask dir 复制到容器内的 usr/scr/flask_app 。
现在你只需要把这个文件放在同一个 flask_app 目录下,并添加 requirements.txt 。在这种特殊情况下,这是非常基本的:
附言记住,如果你对目录之类的东西有点困惑,可以在文章末尾查看完整的项目结构,或者访问 GitHub repo。
步骤 3 —创建 Nginx 文件
为了运行 Nginx,您需要进行一些配置。但是在我们继续之前,在您的主目录中创建 nginx 目录(与 flask_app 在同一层)。之后,我们需要的第一个文件是 nginx.conf ,它包含了所有基本的 nginx 信息和变量。一个非常基本的 Nginx 设置示例:
第二个文件—我们特定应用程序的配置。有两种流行的方法可以做到这一点。第一种是在*/etc/nginx/sites-available/your _ project中创建一个配置文件,然后创建一个指向/etc/nginx/sites-enabled/your _ project*的符号链接。第二种方法是在主 Nginx 目录中创建一个 project.conf 。我们将采用第二种方法。
有几件事你应该注意。首先看一下听 80。这个命令指定了你的应用程序将在哪个端口运行。作为默认端口,我们选择 80。其次,服务器名。你可以指定你从 Linode 得到的 IP 地址,或者你可以只使用你的 docker 镜像名称。最后但同样重要的是,代理传递命令,将您的 Nginx 配置指向 flask 项目。由于 flask 容器名为 flask_app(我们稍后会用到它),所以我们只使用容器的名称,以及我们在 flask 项目中指定的端口。
步骤 4 —为 Nginx 创建一个 Docker 映像
这个特定的 Docker 图像相当简单。和 Flask 的情况一样,它也只包含 5 行代码,只做了两件事:导入 nginx 图像,复制我们的文件,并用默认文件替换它们。
步骤 5-用 docker-compose 组合 docker 文件
所以,现在我们有两个 docker 文件:一个用于 Flask + Gunicorn,另一个用于 Nginx。是时候让他们互相交流,运行整个系统了。为了做到这一点,我们需要 docker-compose。
我们需要做的唯一基本更改是在主目录中创建 docker-compose.yml 文件。
为了理解它是如何工作的,我们应该解决几个重要的问题。首先, docker-compose 拆分成 2 个部分(2 个服务): flask_app 和 nginx 。从下面几行可以看出,flask_app 容器执行 Gunicorn,guni corn 运行 flask 应用程序,并使用 1 个 worker 将其转换为 8000 端口。而第二个容器只是在 80 端口上运行 Nginx。另外,注意依赖于部分。它告诉 docker-compose 首先启动 flask_app 容器,然后才启动 nginx 容器,因为它们相互依赖。
实际上,我们还应该添加一个东西,这样就可以更容易地运行这个 docker 设置。那就是 run_docker.sh 文件
它只是运行 docker-compose,但首先确保此时没有旧的 docker 进程处于活动状态。
第六步——把所有东西放在一起
好的,请记住,当前的项目结构应该是这样的:
.
├── flask_app
│ ├── app.py
│ ├── wsgi.py
│ └── Dockerfile
├── nginx
│ ├── nginx.conf
│ ├── project.conf
│ └── Dockerfile
├── docker-compose.yml
└── run_docker.sh
确保一切就绪后,就该运行 docker 了:
bash run_docker.sh
通过导航到您从 Linode 获得的 IP 地址,在浏览器中查看主页:
第 7 步—我什么也没得到。我该怎么办?
嗯,首先在 Linode 租一个服务器,安装 docker 和 docker-compose,然后克隆 git 库,运行 bash run_docker.sh. 在你确定运行成功后,开始改东西。玩玩 Flask、Dockerfiles 或 docker-compose,直到你打破一些东西。之后,试着找出问题所在并修复它。
此外,如果你不精通 Flask、Gunicorn、Nginx 或 Docker,我强烈推荐这些教程:
第八步——好吧,我明白了。下一步是什么?
接下来要添加的是 Flask App 中的 POST 请求支持。这样,您可以向您的模型发送请求,并获得响应。所以,我们需要两样东西。第一个是处理请求的模型。第二— POST 请求支持本身。
为了简单起见,本例中的模型只返回颜色列表的第 I 个元素。但是运行的是哪种模型并不重要,只需在所有方法之上创建模型的实例()就可以了,这里有 server = Flask(name) 。
现在,如果您导航到您的 IP 地址,您将看到一条消息"*模型已启动并正在运行。*发送 POST 请求”,因为只是去 IP 就有资格成为 GET 请求。然而,让我们试着发送一个包含模型索引的 json 文件的 POST 请求。就我个人而言,我使用 Postman,但您可以使用任何您喜欢的名称(即 Curl)。
嘿,成功了!现在,您可以添加能够接收 GET/POST 请求的附加路由。这个想法背后的原因是,您可以加载几个模型,并根据 URL 向特定的模型发送请求。
第九步——更进一步怎么样?
实际上还有一件大事要做。为了部署这个 docker 设置,将它部署在云中可能是个好主意。例如,我建议看一看将 Docker 部署到 Amazon ECS 的。这种方法的主要优点之一是 AWS 将负责集群管理基础设施。
结论
我们已经用 Gunicorn + Nginx + Docker 在 Flask 应用程序中运行了一个模型。请注意,如果您有任何问题,请随时在评论、GitHub 问题或我的电子邮件地址 ivan.panshin@protonmail.com 联系我
如何利用人工智能平台大规模部署模型
将机器学习模型部署到云中,并将其作为 API 提供给世界其他地方。
马里乌斯·马萨拉尔在 Unsplash 上拍摄的照片由作者编辑。
通常,当我们都开始学习机器学习时,我们会发现大量关于如何建立模型的信息,这当然是主题的核心。但是在数据科学的学术世界中,ML 还有一个同样重要的方面很少被教授,那就是如何部署这些模型。我如何与世界上的其他人分享我做的这件有用的事情?因为,在一天结束的时候…这就是我们工作的目的,对吗?让人们的生活更轻松😊。
在本帖中,我们将学习如何将机器学习模型部署到云中,并将其作为 API 提供给世界其他地方。
工作流程
我们将首先将模型存储在 Firebase 存储中,以将其部署到 AI 平台,我们可以在生产中对其进行版本化和分析。最后,我们将通过具有 Firebase 云功能的 API 来提供我们的模型。
图片由作者提供。
AI 平台是什么?🧠
AI Platform 是谷歌云平台 (GCP)的一项服务,通过不必担心维护自己的基础设施,让你只为使用付费,可以轻松管理整个生产和部署过程。这将使您能够为快速增长的项目大规模扩展您的产品。
你可以利用 GCP 的 12 个月、300 美元的免费试用来免费尝试这个和更多的实验**。**
什么是 Firebase 云函数?🔥
本质上,对于本文的目的,云函数将作为一个 API 工作。我们将通过一个任何人都可以提出请求的链接来提供我们模型的预测,并实时接收我们模型的响应。
你需要什么
- 一个准备分享✔的模型
- 一个谷歌账户✔
是的,就这些
入门指南
为了简单起见,我假设这个模型是用 Python 开发的,并且存在于一个 Jupyter 笔记本中。但是当然,这些步骤可以适用于任何其他环境。
1.登录 Firebase
首先,用你的谷歌账户登录到 Firebase 控制台,创建一个新项目。现在你在 Firebase 仪表板里面,进入项目设置 > 服务账户 > Firebase 管理 SDK ,(在这种情况下)你选择 Python 选项并点击生成新私钥。这将给出您的服务帐户的 JSON 文件,您可以将其保存在笔记本的目录中。
然后,安装 Firebase Admin SDK 包:pip install firebase-admin
2.燃料库中的存储模型
一旦你训练和测试了你的模型,它就可以上传到人工智能平台了。但在此之前,我们需要先将模型导出并存储在 Firebase 存储中,这样 AI 平台才能访问它。
如果您使用笔记本,在末尾创建一个新的单元格,并添加以下脚本。这将启用您的 firebase 帐户:
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore# Use a service account
if (not len(firebase_admin._apps)):
cred = credentials.Certificate(r'service_account.json')
firebase_admin.initialize_app(cred)db = firestore.client()
现在,要运行下面的代码,您需要获取项目 ID,您可以在 Firebase 项目设置中再次找到它。
一旦我们有了我们的项目 ID,我们就通过运行下面的代码来上传模型(您应该首先用您的项目 ID 来更改它)。
from sklearn.externals import joblib
from firebase_admin import storagejoblib.dump(clf, 'model.joblib')
bucket = storage.bucket(name='[YOUR PROJECT ID HERE].appspot.com')
b = bucket.blob('model-v1/model.joblib')
b.upload_from_filename('model.joblib')
print('model uploaded!')
现在,我们可以通过检查指定目录(在我们的例子中是model-v1/
)中的 Firebase 存储来验证模型已经被正确上传。
3.在人工智能平台中部署模型
现在模型已经存储好了,可以接入 AI 平台了。
我们需要在谷歌云平台中启用几个 API。在左侧面板上,在库部分中,我们找到 API*“AI 平台训练&预测 API”和“云构建 API”*并启用它们。
现在,在左侧面板上,我们点击人工智能平台>模型,我们创建新模型并输入相应的信息。
一旦我们创建了模型,是时候创建它的一个版本了,它将指向*。我们之前存储的 joblib* 文件。我们点击型号 > 新版本并填写信息。重要的是,我们选择用于训练模型的相同 Python 版本。我们选择 scikit-learn 作为框架。当指定它的版本时,我们可以通过在笔记本中运行下面的代码来获得它。
import sklearn
print('The scikit-learn version is {}.'.format(sklearn.__version__))
在选择 ML 运行时版本时,您应该选择推荐的版本。机器类型可以暂时默认保留。
最后,我们指定我们的所在的文件夹。joblib 文件被定位。重要的是选择文件夹,而不是文件!其余字段可以保留默认并保存。那时,我们模型的一个实例将被部署在人工智能平台上。
现在,我们将能够从命令行或其他 Google APIs 进行预测,如 Cloud Function,我们将在接下来看到。此外,我们将能够获得模型的一些性能指标。
4.创建云函数
让我们看看如何实现该功能!
我们将在终端上运行一些命令,但为此,您需要确保您的计算机上安装了 Node.js 。以下命令特定于 Windows,但是您应该能够在 Unix 和 Mac OS 设备中使用它们,方法是在每个命令的开头添加sudo
。
让我们从安装 Firebase 客户端开始:$ npm install -g firebase-tools
我们进入谷歌账户:$ firebase login
初始化一个新的项目目录(确保你在你想要初始化它的目录中):$ firebase init
运行最后一个命令时,将会询问您几个问题。当询问您想要在目录中包含的 Firebase 项目时,您必须选择包含我们之前导出的 ML 模型的项目。选择 JavaScript 作为编程语言。我们不使用 ESLint,所以回答否。最后,用 npm 安装依赖项,回答是。
创建项目后,目录将具有以下结构:
在这个目录中,我们将只修改 index.js 和 package.json 文件。
我们安装 Google API 的包:$ npm i googleapis
现在,我们通过打开 package.json 文件来检查软件包是否已经正确安装。如果你想在你的代码中使用任何其他的外部包,你也应该把它和它相应的版本一起添加到这个文件中。
目前,它应该具有类似于以下的结构:
"dependencies": {
"firebase-admin": "~7.0.0",
"firebase-functions": "^2.3.0",
"googleapis": "^39.2.0"
}
我将简要说明它们的作用:
- firebase-admin :它是管理 SDK,允许从特权环境与 firebase 交互。
- firebase-functions:这是一个定义 firebase 中云函数的 SDK。
- Google APIs:是 Google API 使用的客户端库 Node.js。
现在让我们看看函数的实现(我们正在编辑 index.js 文件),你也可以在这个 GitHub 库中找到。作为一个例子,我将使用代码访问一个简单的假账户检测模型。
我们首先加载 firebase-functions 和 firebase-admin 模块。
const functions = require('firebase-functions');
const admin = require('firebase-admin');
我们加载 googleapis 模块,并添加对 ml 版本 1 的引用。
admin.initializeApp(functions.config().firebase);
const googleapis_1 = require("googleapis");
const ml = googleapis_1.google.ml('v1');
这些请求将被发送到一个 http 函数。
exports.predictSPAM = functions.https.onRequest(async(request,response)=>
{
我们指定函数的输入值。在这个例子中,我得到了一些关于社交媒体账户的数据,我的模型将使用这些数据来分类虚假与否。您应该指定您计划随后输入到模型中的字段。
const account_days_old = request.body.account_days_old;
const followers_count = request.body.followers_count;
const following_count = request.body.following_count;
const publications_count = request.body.publications_count;
之后,我们构建模型的输入,也就是我们将发送给模型以获得预测的输入参数。请注意,这些输入应遵循与模型训练时相同的结构(要素顺序)。
const instance =
[[account_days_old,followers_count,following_count,publications_count]]
现在,让我们向 Google API 发出请求,这个请求需要认证,这将把我们的 Firebase 凭证与 Google API 连接起来。
const model = "[HERE THE NAME OF YOUR MODEL]";
const { credential } = await
googleapis_1.google.auth.getApplicationDefault();
在一个变量中存储了我们的模型的名称之后(这个名称应该与您在 AI 平台控制台中给它的名称相同),我们通过发送我们的凭证、模型的名称和我们想要预测的实例来对 AI 平台进行预测调用。
const modelName = `projects/[YOUR PROJECT ID HERE]/models/${model}`;
const preds = await ml.projects.predict({
auth: credential,
name: modelName,
requestBody: {
instance
}
});
response.send(preds.data['predictions'][0]);
});
5.将云功能部署为 API
一旦我们创建了访问模型的云函数,我们只需要将它上传到 Firebase,将其作为 API 进行部署。
为了上传 Firebase 函数,我们在终端中运行以下命令:$ firebase deploy --only functions
一旦完成加载,将获得一个 URL,通过该 URL 可以访问该功能,这可以通过登录 Firestore,在功能部分,在请求下以较小的字体找到。
就这样,现在你的模型已经建立并运行了,可以开始分享了!🎉🎉🎉
你可以从一个移动应用程序、一个网站向这个 API 发出请求…它可以被集成到任何地方!
6.用失眠测试你的 API
当然,这是一个可选的步骤,如果您遵循了前面的指南,您的模型应该准备好接收请求。然而,作为一名程序员,我喜欢测试东西,以检查一切工作正常。
我最喜欢的测试 API 的方法是使用失眠。失眠症是一个 REST API 客户端,它让您可以轻松地测试您的 API。这款免费的桌面应用适用于 Windows、MacOS 和 Ubuntu。让我们检查一下我们新做的 API 是否工作正常!
安装桌面应用程序后,我们可以创建新的请求。
我们将编写请求名,并选择 POST 作为方法,JSON 作为其结构。
一旦我们创建了请求,我们就复制云函数的 URL,并将其粘贴到顶栏中。
我们现在将按照我们在函数中指定的格式编写请求,在我的例子中,它是这样的:
{
"account_days_old": 32,
"followers_count": 162,
"following_count": 152,
"publications_count": 45,
}
我们现在点击发送,我们将得到响应,以及响应时间和大小。如果有任何错误,您也应该收到错误代码,而不是200 OK
消息。
当然,您得到的响应会因您的型号而异。但是如果一切正常,那么恭喜你!您已经准备好与全世界分享您的模型了!🌍
如果你做到了这一步,感谢你的时间,我希望你能从这篇文章中得到一些价值😊
下一集再见!🚀
将张量流模型部署到 Web
如何使用基本的 JavaScript 在浏览器中运行 Python 构建的模型
Avi Richards 在 Unsplash 上拍摄的照片
用 Python 开发机器学习模型会是一种美妙的体验。Python 对 ML 和数据科学的支持和社区是任何其他语言都无法比拟的。
尽管如此,与非 Python 用户共享这些模型的方法非常少——对于我们大多数人来说,这描述了我们的大多数同事和最终用户。
另一方面,世界上几乎每个拥有电脑的人都有一个互联网浏览器。
幸运的是,我们只需要一个网络浏览器。
在本文中,我们将使用 Python 和 TensorFlow 创建一个简单的模型。我们将导出它,并将其部署到使用 JavaScript 和 TensorFlow.js 的 web 浏览器中——我们将保持它非常简单。要做到这一点,您不需要了解 JavaScript。
Python 部分
我们将使用一个基本的神经网络来告诉我们 0-10 之间的数字是奇数还是偶数。当然,我们不需要一个神经网络来做到这一点,但这意味着我们保持这个例子非常简单——没有任何错误。
这个模型需要一个数字作为输入,并产生一个数字作为输出。奇数会产生一个1
甚至一个0
。
首先,我们创建训练数据:
x = []
y = []
for _ in range(10000):
num = np.random.randint(0, 101) *# generate random integer*
x.append(num)
y.append(num % 2)
**x** =[2, 7, 4, 1, 9, ..., 0]
**y** = [0, 1, 0, 1, 1, ..., 0]
现在我们有了数据,让我们建立模型:
事实证明,模函数的表达具有惊人的挑战性。因此,神经网络确实包含合理数量的参数——训练后偶尔会告诉我们 10 是一个奇数——但它在大多数情况下是有效的。
现在我们保存它:
model.save('model_py/model.h5')
这将我们的模型保存为一个HDF5
文件——准备转换为TensorFlow.js
web 格式。
要转换模型,我们首先需要pip install tensorflowjs
。安装完成后,我们从命令行运行tensorflowjs_converter
(Command Prompt
、Terminal
、Bash
等)。).
打开命令行并导航到我们的项目文件夹(Windows 上的cd <directory_path>
)。然后通过键入以下命令运行转换器:
tensorflowjs_converter \
--input_format=keras \
model_py/model.h5 \
model_js
这里,我们告诉tensorflowjs_converter
期待keras
模型格式。然后我们指定模型路径model_py/model.h5
。最后,我们告诉转换器将转换后的模型保存在model_js
目录中。
如果我们导航到model_js we
,会发现以下内容:
那个.json
文件是我们的支持 web 的模型,可以在 JavaScript 中使用。
JavaScript 部分
服务器设置
首先,我们需要建立一个本地 web 服务器。由此,我们可以模拟一个网页的行为,它将包含我们的模型和用户前端。
最简单的方法是使用 Chrome 网络服务器应用程序。这是超级轻量级的,易于使用。
安装完成后,导航至chrome://apps/
并点击网络服务器图标:
这将启动 web 服务器,但可能不在正确的目录中。点击CHOOSE FOLDER
并导航到包含我们项目的目录:
现在,输入localhost:8887
应该会显示 chrome 中的同一个目录:
这意味着我们的服务器设置正确。如果localhost:8887
不工作,服务器很可能被托管在另一个端口上。要找到正确的地址,请查看 Chrome Web 服务器窗口中的Web Server URL(s)
列表,并单击给定的 URL。
构建页面
接下来,我们需要一个网页。首先,创建名为index.html
的文件。在其中,我们创建了一个form
来为我们的模型提供输入,如下所示:
<input type="text"></input><button>Predict</button>
当然,这还没有做任何事情。我们需要添加一些 JavaScript。
我们将编写两个函数,一个用于加载模型,另一个用于进行预测:
该代码可以通过包装在<script>
标签中嵌入到index.html
中。我们还需要导入tensorflow.js
——同样可以使用<script>
标签来完成。
将所有这些都写入代码会给我们带来:
最后一步是将我们在<input>
框中输入的内容连接到我们的模型。
我们可以通过在调用predict
时获取<input>
元素来做到这一点。为此,我们给<input>
一个惟一的标识符id="userInput"
,然后用这个标识符将元素拉进我们的带有document.getElementByID('userInput')
的函数中——这给了我们整个元素,所以我们通过在末尾添加.value
来指定值。
现在我们已经将用户给定值连接到我们的predict
函数,我们只需要触发它。我们简单的把onclick="predict(model)"
加到<button>
上。所有这些给了我们完整的代码:
这就是我们的 NN,运行在一个世界上任何人都可以使用的浏览器中。当然,除了告诉我们一个数字是奇数还是偶数之外,我们可能还需要一些东西——但是我们都是从某个地方开始的。
后续步骤
在此基础上,您还可以做更多的事情。你已经知道最难的部分——教机器学习。在这之后,你需要的只是一点点时间,足够的激情,你就能创造出一些令人惊叹的东西。
实际上,像我们在本文中所做的那样快速而直接地编写东西并不是您处理真实项目的方式。为了学习和简洁,我们跳过了许多步骤和最佳实践。
使用 Angular 或 Node 之类的框架(Python 的替代方案包括 Django 和 Flask)可以轻松构建交互式、快速、可伸缩的 web 应用程序。Bootstrap 是另一个神奇的工具,它可以让我们看起来很糟糕的网站变得漂亮,而我们几乎不需要付出任何努力。
我不能代表所有人,但是以我个人的经验,学习 Angular ,用 Bootstrap 设计 web 应用程序,会产生很好的效果——而且可以很快上手。
如果这是你想进一步探索的东西,我强烈推荐这两个。
我希望你喜欢这篇文章——如果你有任何问题或建议,请告诉我!
感谢阅读!
如何使用 Azure 部署 Web 应用
利用 Angular 和 Azure 应用服务快速轻松地部署应用
照片由卡斯帕·卡米尔·鲁宾在 Unsplash 上拍摄
azure——或任何其他云服务——让分享我们创造性劳动的成果变得前所未有的容易。
我们可以用 Angular(一个非常容易上手的框架)构建一个应用程序,并以比制作咖啡更快的速度将其部署到世界各地。
对我来说,这真的是惊人的。我们开发和部署的容易程度和速度令人难以置信。它解放了我们的创新精神,让我们可以在几分钟内与世界分享。
这篇文章将带我们经历从孤独的 Angular app 到高度可用、高度连接的 Angular app 的步骤。
我们将使用的所有服务都是免费的(感谢微软),而且——老实说——非常容易使用。简而言之,我们将涵盖:
>准备我们的 App
>设置我们的 Azure 应用服务
>使用 Azure DevOps 创建我们的部署管道
尽情享受吧!
准备我们的应用
首先,我们需要一个应用程序——如果你没有,没问题——我们可以使用自然语言生成应用程序,你可以在 GitHub 这里找到。
应用程序编译
*The* ***App Compilation*** *step is repeated in our Azure pipeline. It can be skipped now — but it is useful to be aware of, and useful to confirm that our app compiles.*
Azure 需要一个dist/
目录——这是一个 Angular 构建的分发目录——包含我们已编译并准备好用于生产的整个应用程序。
为了构建dist/
,我们打开 Angular CLI 并导航到我们的 Angular 应用程序目录。然后我们告诉 Angular 使用生产配置 和ng build --prod
进行构建——然后应用程序将编译到dist/
目录中。
显示 ng 构建过程的屏幕截图。
检查输出
我们需要确保我们的ng build --prod
命令将我们的应用程序直接输出到dist/
目录中。默认情况下,Angular 将分配给dist/<app-name>/
——我们在angular.json
中对此进行了更改:
在 angular.json 中,我们从" outputPath "中删除了我们的 app-name,留下了 “outputPath”: “dist” 。
现在,在dist/
目录中,我们应该能够看到index.html
——如果它不在那里,找到它在哪里,并相应地调整angular.json
中的"outputPath"
值。
设置我们的 Azure 应用服务
首先,我们需要前往 Azure 门户网站——Azure 云的首页。如果你需要注册,那就去吧,只需要几分钟。
[## Microsoft Azure 门户| Microsoft Azure
从微软和我们的合作伙伴提供的 3,000 多种服务中进行选择,其中许多是免费的。找到打开的…
azure.microsoft.com](https://azure.microsoft.com/en-us/features/azure-portal/)
既然我们已经登录到门户,我们应该欢迎进入门户屏幕。如果这是你第一次使用 Azure,你将需要注册一个免费试用版(我们将坚持使用免费版,因此我们不会使用任何点数!).
我们通过点击类似于**“从 Azure 免费试用开始”**的大方块来注册。
注册后,我们会创建一个应用服务实例,如下所示:
一旦我们注册了免费试用,我们就可以通过点击上面突出显示的图标来创建一个应用服务实例。
在这里,我们需要为我们的应用程序键入一些细节。这些选项中的大部分将特定于您正在构建的内容——但是对于运行时堆栈,请选择ASP.NET 4.7 版,当然还要选择离您最近的区域:
我们的 web 应用程序详细信息—注意运行时堆栈。接下来讨论我们的应用服务计划。
接下来,我们需要选择我们的 Windows 计划 —如果您还没有计划设置,我们需要创建一个。选择创建资源组,按开发/测试找到自由选项,如下图:
资源组规格。
现在我们已经创建了我们的应用服务资源!我们可以通过点击左上角的按钮(三条水平线)并点击 All Resources 来查看我们所有的资源。
资源列表应该是这样的——应用程序服务本身是中间项。
然后我们可以通过在浏览器中输入<app service name>.azurewebsites.net
来浏览我们的网页。我们将看到:
使用 Azure DevOps 创建我们的部署管道
现在我们需要设置我们的 Azure DevOps 项目。为此,请转到 Azure DevOps,使用您在 Azure 门户中使用的同一 Microsoft 帐户登录。
登录后,您应该会在屏幕的右上角看到创建一个新组织的选项,单击此处。
然后我们将看到另一个窗口,在这里我们命名我们的组织并为我们组织的项目分配一个地理位置。我常驻罗马,所以选择了西欧。
在下一个屏幕上,我们可以创建我们的项目:
现在我们有了项目设置,我们需要连接我们的 GitHub 库并建立一个生产构建管道。
连接到 GitHub
要连接到我们的 GitHub 存储库,使用右边的工具栏导航到 Pipelines 区域,并单击 Create Pipeline 。
我们将被带到一个新窗口,Azure 将询问我们的代码在哪里——我们正在拉入一个现有的 GitHub repo,因此我们单击 GitHub 。
然后,我们授权 AzurePipelines 在下一个窗口中访问我们的 GitHub 帐户。
下一步是选择我们想要使用的存储库,对我来说就是jamescalam/nlg-project
——你可以使用自己的 repo 或者简单地派生这个。
现在我们需要批准&为我们选择的存储库安装 Azure 管道。
下一步,我们配置我们的管道,使用带有 Angular 的 Node.js,这将生成以下 YAML 脚本:
在脚本中,我们可以看到管道 YAML 设置的步骤。首先,第 6 行是trigger
——设置为master
——这意味着每当我们的 GitHub repo 中的主分支被更新时,我们的 YAML 脚本就会被触发。
接下来——在第 10 行——我们可以看到这将在运行 Ubuntu 的虚拟机(VM)上运行。然后我们在第 13 行看到,该脚本将 Node.js 安装到我们的虚拟机上。
最后,我们的 YAML 脚本安装 Angular CLI,然后使用我们之前创建dist/
目录时使用的相同方法构建我们的应用程序——这执行相同的功能*(我们也可以在早期跳过这一步,但这对于确认应用程序编译无误非常有用)*。
但是我们缺少最后一步,部署到我们的 Azure 应用服务。
要添加这个,在右上角找到展示助手——点击这个。现在我们将看到可以添加到 YAML 脚本中的所有任务的列表;我们需要 Azure 应用服务部署:
点击后,会出现一个表格。我们需要做的就是添加我们的 Azure 订阅(我的是这个奇怪的俄语文本——我不知道为什么),我们的应用服务名称,最后将包或文件夹改为dist/
。
现在我们将把 Azure App Service deploy 代码添加到我们的 YAML 脚本中——确保这被添加到脚本的末尾。因此,我们的 YAML 脚本应该包括:
trigger
pool
steps
- task (install Node.js)
- script (npm install Angular CLI and build app)
**- task (deploy to Azure App Service)**
我们单击“save ”,将更改提交给我们的回购。最后点击运行。
YAML 管道将需要一分钟左右的时间来运行。如果似乎什么都没有发生,并且作业状态停留在 Queued 中,刷新页面并允许管道在提示时使用您的描述。
完成后,我们的作业状态将变为 Success ,现在我们可以使用之前使用的相同网址<app service name>.azurewebsites.net
导航到我们部署的 web 应用程序,对我来说,这是meditations-ai.azurewebsites.net
。
使用由 Azure App Services 托管的自然语言生成器 web 应用程序。
我们做到了!
仅此而已——我们现在知道如何用 Azure App Services 部署 Angular 应用了。有一些技能并不太难学,但对我们能构建的东西有着巨大的影响——这是其中之一。
能够使用我们内置的 Angular 应用程序,并以比制作咖啡更快的速度与世界分享,这是非常了不起的。
如果这还不够的话,我们不仅部署了一个应用程序,还将它直接挂在了我们的 GitHub 上。
所以现在,每次我们想把我们最新发布的网络应用推向世界,我们只需输入git push
——对我来说,这太不可思议了。
我希望这篇文章对你和对我一样有用。我很乐意听到你的想法、问题或评论——所以请随时通过 Twitter 或在下面的评论中联系我们。
感谢阅读!
对更有棱角感兴趣?请随意查看我写的这篇关于构建基于 TensorFlow 的 Angular 应用程序的基础知识的文章:
[## 如何使用 Angular 部署 TensorFlow Web 应用程序
在角度构建的 web 应用程序中使用 Python 构建的模型
towardsdatascience.com](/how-to-use-angular-to-deploy-tensorflow-web-apps-5675b5a042cc)
如何使用 Streamlit 和 Heroku 部署您的定制 ML 模型
我的互动模型!作者图片
数据科学
一步一步的指导来主持你的模型!
我一直想把我的一些数据科学项目放到网上,这样我的模型就可以是交互式的,有更大的影响力。YouTube 上的数据教授 (Chanin Nantasenamat)有一个关于 Streamlit 的很棒的教程系列,这是一个开源的交互式数据应用平台,似乎提供了我正在寻找的一切!
TLDR: 这是我的最后一页!
所以我回到了之前的项目,根据电子健康记录预测糖尿病患者的住院需求(EHR)。我的 GitHub repo 包含原始建模的所有代码,以及在 Heroku 上托管的必要附加内容。
但是!我遇到了一个问题。甚至当我把一系列简单应用的指南和教程拼凑在一起的时候,我仍然无法将最终的应用部署到 Heroku!所以这里有另一个指南,希望这个能帮助你跟随我的脚步。
步骤 0 —所有传统的 CRISP-DM 步骤!
本指南从最终模型到托管。因此,我假设您已经完成了开发模型的尽职调查,从数据和业务理解到清理和 EDA,再到建模和评估。
第一步——腌制你的模型
我使用 scikit-learn 的 LogisticRegressionCV 开发了一个多元逻辑回归模型。它被称为 logreg_nopoly ,因为它没有包含多项式或交互特性。
**import** **pickle**pickle.dump(logreg_nopoly, open('diabetes_model.pkl', 'wb'))
您的腌泡模型应该在根目录中。
步骤 2-创建 web_app.py 文件
这是链接到我的文件。我的模型有 19 个特征,混合了分类特征和连续特征,所以我需要清理我的数据,并对用户输入的数据执行相同的转换(特征工程和 get_dummies)。
Streamlit 允许简单的降价风格的标题和文本,以及嵌入图像和图表。为了将数据输入模型以获得预测,您应该创建一个函数,允许用户为您的每个要素定义一个值。
对于连续变量:
st.sidebar.slider(‘名称’,最小值,最大值,默认值)
num_medications = st.sidebar.slider('Num of Medications', 1, 79, 16)
对于分类变量:
st.sidebar.selectbox('name ‘,(’ option1 ‘,’ option2 ',…),其中包含该功能中的所有类别
gender = st.sidebar.selectbox('Gender', ('Female', 'Male'))
如何在 Streamlit 中对滑块和框进行编码的示例。作者图片
该功能的前半部分将创建用户将在应用程序上与之交互的各种滑块和框。这些可以是任何顺序。我将一些最有影响力的特性放在栈顶,以使改变预测的体验更容易。
如何创建实际输入数据帧的示例。作者图片
函数的第二部分是创建数据集特征名(键)和我们在上面为相应特征(值)创建的变量的字典。然后将它加载到熊猫数据帧中。这个字典应该按照原始数据中列的顺序排列,这样当我们连接时,我们的 input_df 和原始 df 匹配。
您会注意到,为了确保所有分类变量都以相同的方式编码(以便我们的 get_dummies 编码特性中所有可能的条目),我们需要在这个文件中执行相同的数据清理和特性工程步骤,并且我们需要将这个用户输入连接到数据集。
以一些特征工程步骤为例——这里是要检查的完整文件。在这里,我创建了一些二元特征来确定患者是否接受了 HbA1c 测试,以及他们的药物治疗是否有所改变。
# Feature Engineering
df['A1C_test'] = np.where(df.A1Cresult == 'None', 0, 1)df.change = np.where(df.change == 'No', 0, 1)df['A1C_test_and_changed'] = np.where((df.change == 1) & (df.A1C_test == 1), 1, 0)
然后,我们删除目标特征(“重新接收”),并在编码前连接用户输入。
X = df.drop('readmitted', axis = 1) # drop target feature
df = pd.concat([input_df, X], axis=0) # add user input to dfencode = [categorical_variables]
for col in encode: # encode all categorical
dummy = pd.get_dummies(df[col], prefix=col)
df = pd.concat([df, dummy], axis=1)
del df[col]
df = df[:1] # first row is user input
现在我们将读入我们的 pickled 模型,以便对用户输入进行预测!st.write 方法接受要显示的字符串,但它也将以本机方式显示 pandas 数据帧和系列。
load_clf = pickle.load(open('diabetes_model.pkl', 'rb'))
prediction = load_clf.predict(df)
prediction_proba = load_clf.predict_proba(df)readmitted = np.array(['NO','<30','>30'])
st.write(readmitted[prediction]) # writes value from array
st.write(prediction_proba) # writes probability of each value
第三步——在本地改进 Steamlit 应用程序
一旦处理好建模,您就可以在本地托管 Streamlit,并添加必要的降价来构建应用程序。
在您的终端/CLI 中
这将安装 Streamlit(如果尚未安装)并打开演示页面。
$ pip install streamlit
$ streamlit hello
现在您已经准备好了一个 web_app.py 文件(或者足够接近),可以在本地打开它进行实时查看和编辑。你应该在应用程序的根目录。
$ streamlit run web_app.py
一旦打开,任何时候你更新和保存。py 文件,Streamlit 应用程序将检测到这些更改,并可以设置为自动更新应用程序。
步骤 4-创建 Heroku 依赖项
因此,您的应用程序已经准备就绪,正在本地运行!太棒了。所以现在我们需要在这个根目录下创建一些文件来馈送给 Heroku。本节大量参考了本之前的指南,但是我已经更改了 setup.sh 文件的内容,因为最初的指南对我不适用。
Procfile
在 Jupyter 中,创建一个名为 Procfile 的文件。将此作为唯一内容粘贴。这告诉 Heroku 运行我们将要创建的 setup.sh 文件,并运行我们之前运行的 Streamlit 命令来运行我们的应用程序。
web: sh setup.sh && streamlit run app.py
requirements.txt
在 Jupyter 中,创建一个名为 requirements.txt 的文件。在这里,您可以指定必要的包及其版本,以确保您的应用程序不会因进一步的更新而中断。这是我的版本(因为我正在使用的模型,所以我需要 sklearn)。
streamlit==0.71.0
scikit-learn==0.23.2
setup.sh
在 Jupyter 中,创建一个名为 setup.sh 的文件,这个文件创建一个目录,设置 Heroku 在托管你的 app 时使用的一些变量,并存储在 config.toml 文件中(一种开源的配置文件格式)。
mkdir -p ~/.streamlit echo "[server]
headless = true
port = $PORT
enableCORS = false
" > ~/.streamlit/config.toml
第五步——Heroku!
从这里你可以跟随[汉密尔顿·张的原版导游](http://streamlit0.71.0 scikit-learn0.23.2)!他可以指导您加载文件、运行应用程序和部署应用程序。我只补充一个方面…
如何更新 Git 远程路径
Heroku 给你一个随机生成的应用程序名称。重命名应用程序部署后,您必须更新 Git 远程路径,以便您可以继续更新应用程序并推送更改。
首先,删除原来的 heroku 路径。然后,添加新的远程路径。我将我的应用程序命名为糖尿病住院(也就是我对我部署的应用程序的命名)。
$ git remote rm heroku
$ heroku git:remote -a diabetes-hospitalization
然后,您可以更新应用程序,并将更改推送到您的回购中!
$ git push heroku master
结论
希望这个指南是有帮助的,是最新的(!).这些步骤使我能够将模型的交互式版本发布到 web 上,供用户进行交互!你可以在这里参观和游玩。拥有一个你的项目的工作演示是将你的项目扩展到雇主的一个很好的方法,它表明你可以部署一个工作/健壮的模型。虽然 Streamlit 不是最强大的工具,但它的易用性和开源特性使它非常适合初学者项目。
连接
我一直在寻找连接和探索其他项目!或者让我知道本指南中的某些内容是否可以扩展/不适用!
如何在 Heroku 上部署 Dash 应用程序
与世界分享您的应用程序的分步说明
来源:https://unsplash.com/photos/xrVDYZRGdw4
你刚刚花了几周时间开发你的 Dash 应用。它现在看起来很棒,你想让全世界都看到它?本教程将向您展示如何使用 Heroku 做到这一点。
Heroku 是一个云应用平台,允许你运行你的应用程序,完全免费。
你需要什么
对于本教程,您需要安装一些东西:
- Heroku 账号:https://id.heroku.com/login
- 饭桶痛击:https://git-scm.com/download/win
- Virtualenv ,可以安装 pip:
pip install virtualenv
。
你还应该下载 4 个文件,都在这里:https://github.com/francoisstamant/dash_heroku_deployment。
App.py
是包含 Dash 应用程序的文件。如果你想更新/改进应用程序,你应该更改这个文件。
requirements.txt
包含运行应用程序本身所需的 Python 依赖项。
循序渐进教程
好了,现在你已经得到了所有需要的东西,下面是一步一步的教程,它会让你部署你的 Dash 应用程序给其他人看!
- 打开 Git。在那里,键入以下代码为项目创建一个文件夹,并将该文件夹作为当前目录。
$mkdir dash_app_deployment
$cd dash_app_deployment
2.用一个空的 Git 存储库和$ git init
初始化文件夹。
3.用$ virtualenv venv
创建一个名为 venv 的虚拟环境。
4.如果您使用 Git Bash 来激活环境,那么首先需要将 Scripts 文件夹作为当前目录。然后,就可以激活环境了。以下是命令:
5.然后,在虚拟环境中安装 Dash 和 Gunicorn:
$ pip install dash
$ pip install gunicorn
只是提醒一下,安装 dash 可能需要一段时间(对我来说大约需要 4 分钟)。
5.然后,确保将目录改回存储库,在本例中使用$ cd ~/dash_app_deployment
。
6.现在,确保前面的 4 个文件确实被复制到当前位置,一旦它们被复制,通过逐个添加它们来初始化文件夹,就像这样:
$ git add app.py
$ git add Procfile
$ git add requirements.txt
$ git add .gitignore
7.现在你可以用你想要的名字创建 heroku 应用程序。该名称需要唯一。如果名字不可用,它会让你知道。然后,您可以将代码部署到 heroku。
$ heroku create francois-st-amant-app
$ git add .
$ git commit -m 'Initial app template'
$ git push heroku master
8.最后,通过做$ heroku ps:scale web=1
在一个 dyno 上运行应用程序。Dynos 是运行应用/代码的“容器”。假设你想保持所有东西都是免费的,你可以运行 2 个 dynos,每个都有 512MB 的内存。
在步骤 7 之后,您的应用程序的 URL 应该是可见的。基本上会是 https:// 你的应用名 .herokuapp.com 。
这是我的应用:https://francois-st-amant-app.herokuapp.com/
你会注意到,如果你现在登录 Heroku 账户,你会看到你的应用页面。在那里,您可以管理应用程序设置、添加合作者等。
更新应用程序
要更改应用程序,只需修改 app.py 文件。然后,以下 4 个命令将允许您将更改推送到 Heroku 应用程序。
我希望这有所帮助。如果您有任何问题,请随时联系我们。感谢阅读!
如何部署你的第一个机器学习模型——第二部分
使用带有较少命令的 CircleCI 管道将机器学习 API 部署到 Heroku
在之前的文章中,我给出了根据行业最佳实践开发机器学习管道所需步骤的高度概述。在这一部分中,我将继续构建可访问的 REST-API 端点,并使用 CI/CD 管道将其部署到 Heroku 平台。
这篇文章中的大部分代码已经在第一部分解释过了。
Github 的项目回购如果你想跟进的话。
目录
- 开发 REST-api 包
- 定义所需的 circleci 配置
- 部署到 Heroku 平台
- 测试一个端点。
我们一个一个的分解一下,了解一下结构。
什么是 REST API?
REST 代表表述性状态转移(REST ),这意味着服务器将向客户机传送所请求的资源状态的表示。API 代表应用编程接口;在本教程中,我们不会构建一个完整的 REST-API;我们将开发一种预测服务。这是因为本教程的范围是为 ML 模型开发一个 REST-API。
为了理解 API 结构,这里有一个很好的资源,可以从头开始学习 API 和的创建,本指南和在这里。
作为一个软件架构的思维模式,你会专注于做出设计决策,使其易于更改、可扩展性,当然还有更少的错误。这就是使用 MVC(模型、视图、控制器)架构的好处,它在应用程序中模块化不同的功能,提供三个组件的抽象。让我们简要总结一下这三个组成部分:
- 视图:终端用户在与应用程序交互时的体验——界面。
- 模型:数据驻留和更改的位置
- 控制器:模型和视图组件之间的通信器。
MVC 模式的好处是:
- 模块化:每个部分都是独特的、封装的,并且可以在不破坏应用程序其余部分的情况下进行替换。
- 语言不可知——可用于多种语言,不仅仅是 python。
- 简单快速的开发过程。
- 可伸缩和可扩展。
如果你想了解更多关于 MVC 模式和软件工程中的其他模式,查看本指南和本指南。
第 1 部分是通过在 Gemfury 上以私人包的形式发布回归模型而完成的。在这一部分中,我们将使用这个包来处理数据并部署到 Heroku 平台。
我们首先在包主目录下创建一个名为 ml_api 的新包。包框架将包括以下内容:
包目录结构
ml_package 有三个主目录和其他 python 脚本文件。
requirements.txt :包含运行包的所有需求。
ml_api 包的 requirements.txt
这里没有什么新的,我只是包括了我希望使用的 flask 版本。此外,包括我在 gemfury 上发布的 regression_model 包——我提供了 index-url 变量,因为它是私有包,还没有公开。如果您希望在本地使用这个包,只需添加您的路径而不是我的路径,然后取消注释即可。我包含了用于模式验证的 marshmallow,以及用于部署的 gunicorn。
重要的是每个单独的包都有自己的需求文件。
如果您克隆了 Github repo 并遵循以下步骤,请确保在 ml_api 包目录中安装所需的依赖项。
-
app.py :这个文件就像 flask 应用程序的工厂,它通过一系列命令来创建 flask 应用程序和蓝图。这个蓝图负责创建位于控制器中的端点。
-
controller.py :该文件作为浏览器后端代码和前端的接口。所以,这个控制器有三个端点,健康、版本、v1/预测/回归。保持 API 版本化是一个很好的实践。
controller.py
- run.py :这将是启动应用程序的入口点。负责调用 create_app() 方法来启动应用程序。
run.py
在这个阶段,您可以尝试检查浏览器上的 API 端点。我们可以通过告诉 flask 启动 API 的入口点来做到这一点。在终端中,运行以下命令
FLASK_APP=run.py
然后从终端运行python run.py
执行 run.py 文件;现在您可以看到服务器已经启动并运行在 /health 端点的端口 5000 上。
在端口 5000 成功运行服务器,端点健康
更好地了解 Flask 微框架的资源:
-
链接 Python 装饰初级读本:https://realpython.com/primer-on-python-decorators/
-
Flask Mega 教程:https://blog . miguelgrinberg . com/post/the-flask-Mega-tutorial-part-I-hello-world
-
烧瓶源代码:https://github.com/pallets/flask(可读性很强!)
-
Flask Web 开发:用 Python 开发 Web 应用程序
-
config.py :如果你是从 part#1 跟进的话,跟regression _ model包的逻辑是一样的。我只添加了一些配置对象来设置特定的 flask 属性。除了微框架使用的其他几个不同的标志之外,还将 development 设置为 true。
配置. py
-
版本文件:将版本添加到
__init__.py
文件中,以便能够调用版本。 -
validation.py :这将负责验证模式;模式是数据的一种表示。在这里,它表示我们将接收到 API 的输入。关于模式优先 API 设计方法的争论越来越多。虽然有一种观点认为模式应该存在于模型包中,但是我们在这里使用它来定义 API 契约,这在这里是有意义的。
验证. py
我们实例化了模式,然后将输入数据转换成正确的格式。之后,加载输入数据并对模式进行检查,以确保没有错误。如果在验证检查过程中出现问题,它只会引发一个验证错误。
使用容器 Docker 映像进行部署
这些步骤如下:
- 安装 docker。
- 通过 Circleci 配置 Docker
- 通过 Circleci 将 docker 映像部署到 Heroku。
这看起来有点吓人,但是一旦你有了这个想法,这将是一个简单的任务。所以,让我们开始吧!
什么是容器?
容器是软件的标准单元,它将代码及其所有依赖项打包,以便应用程序能够从一个计算环境快速可靠地运行到另一个计算环境。
Docker 是什么?
Docker 是一个让创建、部署和运行容器变得简单的工具。Docker 容器是软件开发的标准化单元,包含软件应用程序运行所需的一切。这包括代码、运行时、系统工具、库、依赖等。
以上所有这些看起来都很好,很新奇,我为什么要使用它们呢?
容器自 2013 年发现以来变得如此受欢迎,因为它们提供了可再现性。这是一个巨大的好处,因为你确切地知道创建一个给定容器的步骤,容易跟踪错误。此外,它比虚拟机更快、更轻量级。易于与 CI/CD 管道一起使用。
1.安装 Docker
你可以导航到 docker 并按照步骤将其下载到你的本地机器上。
2.Dockerfile 文件设置
因此,我们想要创建的是一个基于 linux 的容器映像,这就是为什么大多数命令都是 linux 命令。
- Dockerfile:它拉下所需的 python 版本镜像,指定工作目录,安装需求,设置服务器端口。
Dockerfile 文件
- run.sh :这个 shell 脚本负责运行 guicorn 来启动 flask 应用程序。
run.sh
- dockerignore: 在构建映像后告诉 docker 忽略哪些文件。
。dockerignore
建立码头工人形象
现在我们已经准备好构建图像了;为此,如果您在 OSX/莱纳斯,我们需要在终端中运行以下命令:
prediction_app $ docker build --build-arg PIP_EXTRA_INDEX_URL=${PIP_EXTRA_INDEX_URL} -t YOUR_APP_NAME:latest .
重要提示:如果您希望首先在本地机器上构建映像作为测试,您可以使用
.env
文件在本地定义 PIP_EXTRA_INDEX_URL。否则,下面的命令将抛出一个错误,即它无法获取所需的包,回归模型。
In the above command, just replace ${PIP_EXTRA_INDEX_URL} with yours if you wish to build locally before doing so through the circleci pipeline.
构建映像的快照
您可以通过在终端中使用docker images
来检查图像是否已成功构建。它将列出在您的本地机器上构建的所有 docker 映像。
一些有用的 docker 命令:
- 建造一个集装箱— 参考
docker build --build-arg PIP_EXTRA_INDEX_URL=${PIP_EXTRA_INDEX_URL} -t YOUR_APP_NAME:latest .
2.运行 docker 镜像— 参考
docker run --name YOUR_APP_NAME -d -p 8000:5000 --rm YOUR_APP_NAME:latest
3.查看正在运行的容器:
docker ps
4.查看容器日志(通过运行docker ps
获得容器 ID)—引用
docker logs CONTAINER_ID — tail
和 docker 一起部署到 Heroku
Heroku 是一个基于云的平台即服务,允许开发人员完全在云中构建、运行和操作应用程序。
实现应用程序所需的步骤有:
- 如果您没有帐户,请浏览 heroku 网站并创建帐户。
- 导航至
New
菜单并创建新应用,填写应用名称并选择地区,然后点击创建应用。 - 安装 heroku-cli 工具,确保保留默认设置,以便 heroku 被添加到您的系统路径中。
- 安装后重新启动命令行工具。
- 通过
heroku login
使用 cli 工具登录 heroku 账户,输入你的邮箱和密码,你就可以登录 heroku 平台了。
Heroku 构型
为了能够部署,您需要将 PIP_EXTRA_INDEX_URL 变量添加到 heroku 项目设置中的 config vars 列表中。
为此,导航至应用程序设置→显示配置变量→
关键字:PIP_EXTRA_INDEX_URL
值:your_token@pypi.fury.io/user_name/→添加。
现在是时候配置部署管道了,以便在每次提交到远程时自动执行部署。
为此,我们将从以下方面着手:
- 根据 heroku 指令创建过程文件。这个文件负责运行应用程序和访问错误日志文件。
web: gunicorn --pythonpath packages/ml_api --access-logfile - --error-logfile - run:application
2.确保regression-model = = 1 . 0 . 0和 gunicorn==19.9.0 都被导入到 ml_api 目录下的需求文件中。
3.创建负责捕获主分支上最新变更的提交 id 的 Makefile,然后创建一个 remote,最后将工作推入 heroku。
生成文件
- config.py 将所需步骤添加到 circleci 配置文件——第 10 节和第 11 节。它基本上设置了部署所需的步骤,从重新安装需求到捕获新的依赖项,再到设置 heroku remote 并进行部署。最后,指定管道的工作流,在训练模型之后应该在哪里进行部署——逻辑步骤。
页(page 的缩写)n:在第 114 行,我设置了
docker_layer_caching: false
,因为在运行 circleci 时将它设置为 true 会出错。您需要升级您的飞机才能将此设置为真。
完整配置文件
现在,当您将更改提交到 github 时,应用程序应该会自动部署到 heroku 平台。
测试 API
你可以导航到 heroku dashboard 并从那里打开应用程序,或者使用像 postman 这样的工具来确保 API 正在工作。
使用 postman 测试 API,为 GET 动词返回 200 状态代码
工作应用 JSON
circleci 仪表板工作流程
注意,我们只有两个端点,健康和版本。一旦确认一切正常,就可以添加额外的端点。这种方法非常有用,从简单开始会更容易捕捉错误和 bug,从而在调试会话中花费更少的时间。
总结和结论
在这一部分中,我们探讨了许多关于 API 设计的概念,以及如何自动化这个过程以节省时间。这个项目为您提供了一些构建产品级应用程序的最佳实践。此外,它还让您领略了 SLCD 的实际工作流程——机器学习模型的软件生命周期开发。有问题就问吧;我很乐意帮忙!快乐学习!
如何在 Kubernetes 上部署你的机器学习模型
使用 GCP 的 Kubernetes 和 Terraform 部署、扩展和管理您的机器学习服务。
Guillaume Bolduc 在 Unsplash 上拍摄的照片
Kubernetes 是一个生产级的容器编排系统,它自动化了容器化应用的部署、扩展和管理。该项目是开源的,并通过谷歌运行的关键任务应用程序进行了测试。
机器学习解决方案通常被分解成许多步骤,这些步骤可能与操作系统和框架无关。此外,数据科学项目通常遵循数据流编程范式,其中程序被设计为一个有向图,数据从一个操作移动到下一个操作。这些方法和抽象很容易用 Kubernetes 实现,将基础设施管理的负担留给了系统。
在这个故事中,我们将在 Kubernetes 上部署一个简单的图像分类器 web 服务。我们将在谷歌云平台(GCP)上工作,并利用他们的安全和管理的 Kubernetes 服务产品:GKE。我们将首先使用 Terraform 来供应和管理所需的基础设施,然后创建一个预训练 PyTorch 模型的简单部署。我们开始吧。
学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!
基础设施作为代码
为了建造所需的基础设施,我们将使用 Terraform。Terraform 将基础设施视为代码,以供应和管理任何云、基础设施或服务。Terraform 将使我们很容易创造我们需要的资源,并在我们完成后进行清理,以避免积累成本。要安装 Terraform,请遵循您的平台的说明。
预赛
要处理 GCP,我们首先需要创建一个项目资源。项目资源是一个逻辑组织实体,它是创建、启用和使用其他 Google 云服务的基础。有必要开始对 GCP 和容易建设一个或使用任何新的 GCP 帐户初始化默认项目的工作。
要创建一个新的,从侧面板转到IAM & Admin
并选择底部的Manage Resources
。按下Create Project
按钮,给出一个名字,你就可以开始了。
下一步是创建一个服务帐户,terraform 将使用它来创建我们需要的资源。服务帐户是一种特殊的帐户,由应用程序使用,而不是由个人使用。确保您正在使用您创建的项目,返回到IAM & Admin
选项并选择Service Accounts
。按下按钮Create Service Account
创建一个新的,将其命名为terraform
并按下 Create。下一步,授予服务帐户Project Editor
的角色,然后按 continue。最后,通过按下Create Key
按钮生成一个 JSON 密钥。该密钥将成为 Terraform 的身份验证方法。
地形结构
首先,我们需要配置 Terraform 使用 Google 存储桶来存储它需要的元数据。这是保持 Terraform 在自动化环境中运行的一个很好的方法。首先,让我们创建桶;创建一个名为main.tf
的新文件:
然后,我们需要为它使用的变量创建一个新文件。创建该文件并将其命名为variables.tf
:
这个文件告诉 Terraform 应该使用哪些变量,并提供了一些默认值。例如,我们第一个脚本中的location
变量现在有了一个默认值US
。还有其他变量,比如project_id
,我们需要自己提供值。为此,我们创建一个新的terraform.tfvars
文件:
确保用必要的信息填充terraform.tfvars
文件,然后运行terraform init
和terraform apply
。最后,转到 GCP 控制台,验证铲斗是否在那里。
改造您的 GKE 集群
我们现在准备剥离我们的 Kubernetes 集群。我们将在一个新目录中创建三个单独的文件:一个用于定义 Terraform 后端,一个用于云提供商,一个用于实际的集群。当然,我们需要两个额外的变量文件。让我们设置后端。创建一个terraform.tf
文件,并将以下内容复制到其中:
确保提供您之前创建的存储桶的名称。然后为云提供商创建一个provider.tf
文件:
最后,创建一个main.tf
文件来配置我们想要的 GKE 集群。对于这个例子,我们将把它保持在最低限度。
我们将改变的一件事是删除默认的节点池并创建一个我们自己的节点池,其中我们使用n1-standard-1
可抢占的机器。最后,创建variables.tf
和terraform.tfvars
文件,提供必要的变量。
和terraform.tfvars
文件:
将位置设置为区域格式将创建一个区域簇。谷歌为每个付费账户提供一个免费的区域集群,因此我们将利用这个折扣。像以前一样,运行terraform init
和terraform apply
,等待几分钟,您的集群将准备就绪。
图像分类器
对于这个例子,我们使用一个预先训练的 PyTorch 模型和 Flask ,来创建一个简单的机器学习 web 服务。接下来,我们将创建一个简单的 Kubernetes 部署来部署、管理和扩展 web 服务。
PyTorch +烧瓶
为了设计一个简单的图像分类器服务,我们使用了一个用于图像分类的 CNN 模型 AlexNet 的 PyTorch 实现。我们使用烧瓶微型框架来提供它。
首先,我们定义一个Predict
Flask 资源,它初始化模型并接受一个HTTP POST
请求。我们使用any-host
标识符(0.0.0.0
)将它与烧瓶一起提供。
Flask 的内置服务器不适合生产,因为它的伸缩性不好。对于我们的目的是好的,但是如果你想知道如何正确地部署 Flask 应用程序,请看这里的。
集装箱化
要在 Kubernetes 上部署它,我们首先需要将服务容器化。为此,我们定义如下Dockerfile
:
要从这个Dockerfile
构建一个映像,在同一个文件夹中创建一个requirements.txt
文件,包含以下内容:
flask
flask-restful
在同一个文件夹中下载包含 Imagenet 标签的 JSON 文件这里。我们现在准备建立我们的 docker 形象;运行以下命令:
docker build -t <your-dockerhub-username>/image-classifier:latest .
最后,您需要将映像推送到容器注册中心。例如,要在 docker hub 上推送它,创建一个帐户,配置 docker 并运行以下命令:
docker login --username usernamedocker push <your-dockerhub-username>/image-classifier:latest
为了简单起见,你可以用我为你准备的图像。可以从 docker hub 拉出来。
部署
最后一步是部署。为此,我们使用一个简单的YAML
配置文件。但是首先,我们需要安装kubectl
并获得连接到我们的集群的凭证。
要安装kubectl
,请遵循平台的说明。接下来,安装 gcloud
,GCP 的 CLI 工具。要获取 GKE 群集的凭据,请运行以下命令:
cloud container clusters get-credentials <the-name-of-your-cluster> --zone <the-zone-that-it-is-in>
例如:
cloud container clusters get-credentials my-gke-cluster --zone us-central1-a
该命令将创建一个配置文件,并指示kubectl
如何连接您的 GKE 集群。最后,定义图像分类器YAML
部署文件。
这个配置分为三部分:首先,我们定义一个名称空间,它为我们的资源名称提供了一个范围。然后,我们定义实际的部署,其中我们只使用服务的一个副本。你可以根据自己的需要调整这个数字。最后,我们用一个LoadBalancer
来公开我们的 web 服务。这将使我们的服务可以从互联网上访问。通过运行以下命令创建部署:
kubectl apply -f image-classifier.yaml
您现在已经准备好测试您的图像分类器 web 服务了。对于这个例子,我们使用curl
。
curl -X POST -d '{"url": "[https://i.imgur.com/jD2hDMc.jpg](https://l.messenger.com/l.php?u=https%3A%2F%2Fi.imgur.com%2FjD2hDMc.jpg&h=AT3BE3ChNWH0HYFPvWjWK_Aqtq08m0_DGLZpxfwEu_219IP625hqKCAjWzfap2ucsTFqtwk224-0Djl3nFCbpbxixNC4XgclqUkdsR9kOzTEkVVjazQJx395DGlzq3offB8i10LHlveiqg)"}' -H 'Content-Type: application/json' [http://<your-cluster's-ip>/predict](http://35.239.113.2/predict)
这个命令将使用一个小猫图片查询您的服务。你得到的是与某种自信相关的预测。您现在已经在 Kubernetes 上成功部署了一个机器学习模型!
清理
为了清理我们自己,我们将按相反的顺序进行:
- 删除命名空间、部署和负载平衡器:
kubectl delete -f image-classifier.yaml
2.销毁集群:
terraform destroy
从您在“改造您的 GKE 集群”步骤中创建的文件夹中运行此命令。
3.删除 Google 存储桶:
terraform destroy
从您在“地形配置”步骤中创建的文件夹中运行此命令。
结论
在这个故事中,我们看到了如何在 GKE 用地形创造资源。具体来说,我们创建了一个 GKE 集群,以利用 Google 云平台提供的托管 Kubernetes 解决方案。然后,我们创建了一个简单的图像分类 web 服务,用它构建了一个 docker 图像,并将其部署在 Kubernetes 上。最后,我们自己清理,销毁我们不再需要的资源,以避免额外的成本。
Kubernetes 是一个为生产部署机器学习模型的伟大平台。在后面的文章中,我们将探索 KubeflowKubernetes 的机器学习工具包。
我叫 Dimitris Poulopoulos,是希腊比雷埃夫斯大学BigDataStack和博士©的机器学习研究员。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲中央银行、经合组织和宜家等主要客户设计和实施人工智能和软件解决方案。如果你有兴趣阅读更多关于机器学习、深度学习和数据科学的帖子,请关注我关于 中 、LinkedIn或@ james2pl上
如何将您的 ML 模型部署到浏览器中
来自 TensorFlow 的 jS 哥哥的嗨
以及如何有效地做到这一点。
当我刚开始学习 AI 和 ML 时,我经常会有这样的问题:我为什么要学习这个?在找到工作之前,我能有所作为吗?
这些问题出现是因为我知道如何训练模型,但不知道 如何部署 。因此,如果你正处于这个阶段,并且想学习如何使用模型,那么你来对地方了!
我是谁
我是 Dweep,一个充满热情的高中生,从各种课程和项目中获得了许多深度学习知识。
认识一下 TensorFlow 的哥哥 TensorFlow.jS
我们都知道 TensorFlow,以及如何在 TensorFlow 中制作模型(如果你不知道,那么我会推荐你阅读这篇博客,然后回到这里。)然而,它的 javaScript 兄弟却是相当的鲜为人知。但这并不意味着 TensorFlow.jS(也称为 tfjs)就没那么有用。大部分 TensorFlow 模型可以直接转向 tfjs 模型,tfjs 本身也有能力训练模型!
关于你下一步要做的事情
我深信代码是学习代码的最佳方式。因此,在本文的最后,您将在浏览器上实现一个 tfjs 系统。顺便说一下,我从 Coursera 上的数据和部署专业化的第一门课程中学到了大部分内容,我在这里回顾了一下。因为 tfjs 最常见的用例是迁移学习,所以您将实现它。
为了使尽可能与 tensor flow相关,我将首先解释 TensorFlow Keras 库和 tfjs 层库之间的关系。
代码风格的显著差异
就像 Keras 构建在 TensorFlow 库之上以提供高级功能一样,Layers 库也为 tfjs 做了同样的事情。
忘记下划线
所有的 jS 代码都在lower case中,这意味着所有的一切都应该有小写的第一个单词的第一个字母(像 l ),以及大写的第一个单词(像 C )。所有的函数和语法都遵循这个规则。因此,我们应该使用 inputShape 而不是 input_shape 。此外,所有语法都以分号结尾。
数据到张量
由于 javaScript 没有 NumPy,所有数据都需要转化为张量,供 tfjs 进行推理或训练模型。
使用{ }进行配置
另一个显著的区别是,与 Python 不同,所有的函数输入都在花括号内配置。一个例外是当你输入数据时,比如训练集。
还有一些差异,但我认为这些就足够了。
基本语法
下面列出了最常用的函数。要了解其中任何一个函数的更多信息,只需单击该函数的名称。我建议你对每一个都这样做,以便更好地理解。
- TF . tensor(data,shape)创建一个张量,tfjs 稍后可以使用它进行训练或推理,并将其保存在分配给该函数的变量中
- TF . sequential()创建由一系列层组成的模型。该模型保存到一个 const 或常量变量中。**
- TF . layers . dense({单位:_ _ _ _,激活:’ _ _ _ _ _ _ '})创建一个 tfjs 图层,可以使用 model.add() 添加到模型中。注意,像 TensorFlow 一样,第一层有一个可选的附加输入,称为 inputShape ,它将进入模型第一层的配置内部。
- model . add()获取一个 tf.layers 图层,并将其添加到模型中现有的图层列表中。也可以使用 tf.layers.flatten 或 tf.layers.conv2d 。
- model . compile({优化器:’ ___ ‘,损耗:’ _ _ _ '})编译模型。优化器在 tf.train ,比如 tf.train.adam 和 tf.train.rmsprop 。
- model . fit(xs,ys,{epochs:_ _ _,回调:{_ _ _ _ _ _})拟合模型上 xs,ys 的数据集。
- . predict(【xs】)使用训练好的模型来预测标签。
语法已经过时了,我们现在可以开始编程了。
请注意,该程序是数据&部署专业化中 tfjs 课程中基于浏览器的模型的第 4 周示例的定制。
人脸识别
我们用 tfjs 中的迁移学习做一个人脸识别模型。该模型首先将三个人的图像作为输入,并将输出模型从网络摄像头中看到的人。如果你只是想看看演示,那么我在下面的一个网站上有。看看吧!
**[## 人脸识别 TFjS 演示
展示浏览器训练和推理能力的演示
djthegr8.github.io](https://djthegr8.github.io/)**
安装
- 从这里下载 Chrome 的 200 OK 网络服务器。它需要消除多个 HTTP 请求,并确保我们得到良好的上传。
- 可选地,如果你想编辑我的代码来玩 tfjs(我真的推荐这么做),你可以下载一个编辑器,比如括号,让你的工作更容易。
- 最后,所有的代码都可以在这个 GitHub 库中找到。请下载它,并将 Chrome Web 服务器的目标设置到该文件夹中。要运行,请打开服务器应用程序中的链接,然后打开 facerecgn.html 文件。
实际模型
让我们首先看一下 TensorFlow.jS 库的导入。这一行位于 HTML 页面的 head 部分。
**<script src="[https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest](https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest)"> </script>**
现在,我们将跳过 HTML 代码,在 index.jS 页面中查看 Tensorflow.jS 代码。
下面是加载 MobileNet 的代码,MobileNet 是一个经过预先训练的 tfjs 网络,它本身可以将图像分类到大约 1000 个类别。该函数通过声明一个新的模型来移除它的推理层,该模型采用倒数第二层的输出。
下面是代码中最重要的函数。我们正在展平 MobileNet 编码的三维输出(在 loadMobilenet() 函数中声明的模型的输出),然后通过一个小的 NN。损失是分类交叉熵,优化器是 adam。
我将展示的另一个函数是处理最终导致数据集创建的按钮按压的函数。这是不言自明的。
最后一个主要功能是 predict() ,它根据模型预测人。该函数查找预测概率并输出最高的概率。
完成后,rps-dataset.jS 就剩下了……与其描述代码,我将快速描述它的功能。它所做的只是创建一个可追加的数据集,并具有(一次性)标签。当然,代码在存储库中。
完成所有这些函数后,您可以查看最终的 index.jS 代码。
谢谢并评论
非常感谢你阅读这篇文章,如果你发现任何错误,请评论!
免费的任何疑问,项目帮助或任何合作机会!
给我发邮件到我的 Gmail 获取任何关于 TF、Keras、TFjS 或 Python 的帮助或合作!或者查看我的 Linkedin
如何服务您的 PyTorch 模型
TorchServe 的最新版本离 GA 又近了一步。
由 BENCE BOROS 在 Unsplash 上拍摄的照片
你已经收集了你的数据,处理了它们,训练了你的模型,微调了它,结果是有希望的。接下来去哪里?你如何让公众获得它?
嗯,如果你是一个 TensorFlow 用户,你可能想摆弄一下 TFX 。TFX 是一个优秀的工具集,帮助数据科学家创建和管理机器学习生产管道。但是如果你是 PyTorch 用户呢?嗯,你很幸运;截至 2020 年 4 月,你获得了torch serve。
学习率是我每周给那些对 AI 和 MLOps 世界好奇的人发的简讯。你会在每周五收到我关于最新人工智能新闻、研究、回购和书籍的更新和想法。在这里订阅!
火炬服务是什么
TorchServe 是一个灵活易用的工具,用于服务 PyTorch 模型。它没有 TFX 的复杂性,因此也没有提供那么多的功能。然而,这是完成工作的直接方法!
TorchServe 提供了一组必要的特性,比如服务器、模型归档工具、API 端点规范、日志记录、度量、批量推断和模型快照等等。它还提供了一系列高级特性,例如,支持定制推理服务、单元测试和通过 JMeter 收集基准数据的简单方法。目前,它还处于试验阶段,但它在大多数情况下都很有效。事实上,在本文的后面部分,我们将对它进行测试。
最新版本
TorchServe 在两天前(2020 年 6 月 10 日)发布了最新版本(0.1.1)。这是向 GA(全面上市)迈出的一步,包括一系列有希望的新功能。除其他外,TorchServe 的最新版本包括:
- 支持 HuggingFace ,这是一个深度学习库,其任务是为每个人推进和民主化 NLP,提供文档和示例
- 支持 Nvidia Waveglow ,一个基于流的语音合成生成网络,有文档和例子
- 与 Model Zoo 紧密集成,Model Zoo 是一个深度学习注册表,具有从流行的预训练模型创建的模型档案
- 支持 AWS 云形成,它提供了在 EC2 实例上运行服务器的能力,并提供了一个简单的配置文件(YAML 或 JSON)
- 支持通过 snakevize 分析器分析 TorchServe Python 执行,以获得详细的执行时间报告
- 具有清晰说明的重构文档
有关可用功能的详细列表,请阅读发行说明。
装置
安装 TorchServe 很简单。您可以使用文档中提供的说明,但是让我们使用 conda 在 Ubuntu 上安装它:
- 为您的 TorchServe 安装创建一个新环境(可选但推荐)。
conda create -n torch python=3.8
2.激活新环境。
conda activate torch
3.运行以下脚本来安装 TorchServe 及其依赖项。这个脚本在您的机器上安装 CPU 专用的 PyTorch、torchvision 和 torchtext 模块。如果你不需要的话,可以跳过这些。
conda install pytorch torchvision torchtext torchserve torch-model-archiver psutil future cpuonly -c pytorch -c powerai
您现在已经准备好开始使用 TorchServe,并通过 REST 端点使您的模型可用。
简单的例子
在这个例子中,我们部署了一个 MNIST 分类器。我们通过 TorchServe 文档中的代码示例来完成所需的步骤。
-
首先,我们需要定义一个 PyTorch 模型来解决 MNIST 挑战。下面的代码只是一种方法;将其复制并粘贴到一个名为
model.py
的文件中: -
然后,我们需要创建一个训练模型的脚本。将以下代码复制到一个名为
main.py
的文件中。你可以运行python main.py -h
来查看可用选项列表。训练新模型并保存(python main.py --save-model True
)或在此下载可用的预训练模型。不管怎样,把保存的模型移到一个名为artefacts
的新文件夹中。 -
接下来,我们需要编写一个定制的处理程序来在您的模型上运行推理。将以下代码复制并粘贴到一个名为 handler.py 的新文件中。该代码对灰度图像进行推理,就像 MNIST 图像一样:
-
接下来,我们需要使用 torch-model-archiver 实用程序创建 torch 模型归档。该命令将提供的模型(
artefacts/model.pt
)归档到一个.mar
文件中:
torch-model-archiver --model-name mnist --version 1.0 --model-file model.py --serialized-file artefacts/model.pt --handler handler.py
- 创建一个
model_store
文件夹,并将存档的模型移入其中:
mkdir model_store
mv mnist.mar model_store/
- 最后,启动服务器并向其查询答案。你可以在这里下载一些的测试数据。要使用它们,只需将它们放在一个名为
test_data
的新文件夹中:
torchserve --start --model-store model_store --models mnist=mnist.marcurl http://127.0.0.1:8080/predictions/mnist -T test_data/0.png
- 完成后,停止服务器:
torchserve --stop
结论
在这个故事中,我们介绍了 TorchServe,这是一个灵活易用的工具,用于服务 PyTorch 模型。我们看到了它是什么,它提供了什么,以及我们如何通过 REST 端点利用它的工具来服务 PyTorch 模型。最后,我们检查了它的最新版本(版本 0.1.1)和最新支持的特性,并用一个 MNIST 例子对它进行了测试。为了让您的手变脏,请阅读文档和官方示例。
学习率是我每周给那些对 AI 和 MLOps 世界好奇的人发的简讯。你会在每周五收到我关于最新人工智能新闻、研究、回购和书籍的更新和想法。在这里订阅!
我叫 Dimitris Poulopoulos,是希腊比雷埃夫斯大学BigDataStack和博士©的机器学习研究员。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲中央银行、经合组织和宜家等主要客户设计和实施人工智能和软件解决方案。如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和 DataOps 的帖子关注我上 中 、LinkedIn或@ James 2pl
如何设计一款流行的视频游戏:使用 NLP 和随机森林进行评分预测
诚然,电子游戏行业现在是热点,其收入是电影的 4 倍,音乐的 7 倍。尤其是现在面对新冠肺炎,越来越多的人在虚拟的电子游戏世界中寻求社交联系和自我娱乐。毫无疑问,视频游戏行业前景广阔。
然而,在电子游戏行业成功容易吗?答案是否定的!尽管前景看好,但这仍是一项风险很大的业务。首先,有超过 100 万的视频游戏在行业内引发了激烈的竞争。第二,利润空间超级紧张。例如,playstation4 的利润率接近 5%。你猜怎么着,大部分成本来自研发。因此,在游戏设计上的准确投资可以产生巨大的差异。本文旨在使用随机森林和 NLP 技术来寻找能够极大地影响游戏评级的关键游戏设计特征。
作者来源
资料组
现有的亚马逊数据集包含元数据(包括视频游戏的基本产品信息)和评论数据(包括视频游戏的评论和评级)。这些表通过唯一的产品 ID (asin)链接在一起。下面是数据集的快照。虽然列出了许多特性,但没有一个与游戏设计特性直接相关。我们可能在哪里产生游戏设计特征?评论!接下来,我们将深入评论以提取特征。
元数据快照,按作者排序
作者来源的综述数据快照
特征工程
在这个项目中,我们将使用 IBM 自然语言理解包来实现特征工程。这个包中的一个嵌入功能是“keywords ”,它可以返回整个文本的关键字。此外,可以返回情感信息或情绪信息。我们从提取整个评论数据集中的关键词(合并所有评论)开始。然而,返回的不是一个词,而是一个阶段。正如在文本挖掘中经常出现的情况一样,关键字也因为不同形式的单词而变得非常混乱。
关键词示例,按作者来源
因此,我们应用了 PorterStemmer、word_tokenize、stopwords 来精简我们的关键字列表。最后,我们得到了如下所示的关键字列表。提到最多的关键词是“character”,是“character”的缩写。您可能已经注意到,如果我们将“character”输入到情感提取函数中,该函数无法检测到文本中相应的形式。下一步,我们检查了最常用的关键字形式,并给它们添加了内容。例如,打架可以是打架、打架和打架。
关键字列表的快照 1,按作者排序的来源
关键字列表快照 2,按作者排序的来源
现在我们已经有了最终的关键字列表。将所有功能放在一个篮子里可能会很混乱,也不太直观。让我们将它们归类到不同的篮子中,以进一步研究我们的关键字。关键词可以进一步分为 4 个篮子——游戏类型、系列、游戏元素和特征。
不同关键字组的 Wordcloud,按作者排序
最后,我们提取了每个产品在这些关键词上的情感得分。最终的特征矩阵是稀疏的,具有许多缺失值。考虑到许多关键词指向同一个游戏设计特征,如故事、情节和故事线,我们通过平均它们的情感分数来聚合相似的特征。
描述性分析
- 评分:平均评分约为 4.15,排名前 25%的产品评分超过 4.46。
评级分布,来源按作者
- 游戏类型:就平均收视率和波动性而言,rpg(角色扮演游戏)在所有游戏类型中脱颖而出,其次是冒险游戏和多人游戏。体育游戏和动作游戏在收视率上表现不佳。
不同游戏类型的分级,由作者提供
- 游戏系列:数码宝贝、口袋妖怪、金太阳平均评分最高,在 4.25 以上,而马登平均评分仅 3.88。
不同游戏系列的评分,由作者提供
- 游戏元素&特点:标尺是情绪得分。不同元素&特征之间的平均情感分数是一条乏味的直线,但情感分数的标准差确实形成了一些见解。在图形、新、易等方面,情感得分差异很大。与怪物相比。
游戏元素情感得分的标准差,来源于作者
机器学习和解释
现在我们为机器学习做好了准备。根据描述性分析中的发现,我们将评分降低到 4.4 分,形成一个高绩效组(30%)和一个低绩效组。功能是我们从评论中提取的,价格也是。游戏类型和游戏系列被编码为二进制变量,而其他的是连续的。
从个人经验来看,逻辑回归和随机森林在解释和预测准确性方面确实很突出。我们应用了这两种技术,并最终选择随机森林作为主要的解释器模型,因为它的性能稍好一些。采用的性能矩阵是 AUC 和准确性。
- 重采样:由于我们将产品分成不同组的方式,数据集有点倾斜。我们尝试了欠采样、过采样和 smote。为了更好的解释和准确性,我们最终利用欠采样。
- 特征选择:尝试了特征重要性技术和递归特征消除技术,但改进不大。
- 超参数调整:使用网格搜索调整 n_estimators、max_depth 和 min_sample_split。
最后,我们能够在验证集上实现 70%的准确性和 72%的 AUC。为了解释,我们使用排列重要性分数,因为我们有一些二元变量。我们也删除了游戏系列在解说剧情中的特征,因为它们对游戏设计贡献很少。
排列重要性分数,来源于作者
- 游戏类型(深蓝) : 体育游戏对区分高性能产品有很大影响。结合描述性分析中体育游戏对收视率产生负面影响的发现,我们通过进行逻辑回归进一步支持这一观点,逻辑回归也表明体育游戏对收视率产生显著的负面影响。
- 游戏元素(橙色) : **图形、关卡、控制对评分贡献最大。**在描述性分析中,我们还发现图形在行业内具有最大的可变性。下面是评论中与“图形”或“级别”一起出现的词,它们可以为游戏设计提供很好的见解。产品设计的其他焦点可以是外观、声音和个性。
评论中的“图形”,来源于作者
评论中的“级别”,来源于作者
- 特征(浅蓝色) : 创新当然应该受到鼓励,因为“新”在重要性分数中排名第三。最常谈论的创新是“新功能”、“新武器”和“新风格”。
评论中的“新”,来源按作者
对于进一步的调查,可以做更多的工作。例如:
- 对于不同类型的电子游戏,不同功能的重要性分数会有很大差异吗?
- 图形是成本结构的一大部分。哪种类型/风格的图形对市场更有吸引力?
- 哪些创新会带来更高的回报?
- 难度等级设计如何选择合适的方法?
如何设计 Rust 中的恐慌恢复能力
错误处理
不要慌!学会构建对错误有弹性的高质量软件。
照片:安德烈斯·达利蒙提 /Unsplash
试着想象使用一些软件和 WHAM,一堆文本,以及大脑无法忽略的视觉垃圾。或者更好的是,当你的用户同时按下两个按钮,飞机关闭时,他们正在驾驶一架商业客机。我们需要的是明确的反馈,并防止暂停执行。在这个故事中,我们讨论 Rust 应用程序中的恐慌恢复方法,以使高质量的软件用户可以依赖。
如果你认为你的软件是一辆时速 60 英里的汽车,恐慌就像撞上了一堵砖墙。
1990 年,一次软件更新导致美国电话电报公司全国 114 个电子交换系统全部瘫痪。当一座塔发生故障时,它会向邻近的塔发送一条信息,告知它正在停止交通。其他塔收到的信息导致它们进入类似的故障状态,通过整个美国电话电报公司长途网络使信息永久存在。
糟糕的逻辑是大多数有害软件错误的原因。C #中的错误可能更谨慎,因为被忽略的错误不会产生警告。Rust 本可以防止过去发生的一些讨厌的软件错误,但前提是软件开发人员利用了 Rust 语言提供的重要错误处理逻辑。
在 C 语言中,数值是表达“发生了错误”的惯用方法。函数调用返回一个表示错误代码的整数。如果代码为零,则没有错误发生。否则,可以将代码与值进行比较,以确定发生了什么故障。
C 中错误处理方法的问题是,忽略函数调用的返回值既不是错误,也不是警告。失败可能会被忽视和处理。
错误处理的首要目标是防止崩溃。
一些在 C 之后设计的新语言使用异常进行错误处理,这是对错误代码的高级抽象。调用一个可能失败并导致异常的函数需要一个try
和catch
块来执行可能导致异常的代码,并处理异常发出的错误信号。异常仍然不总是被显式处理,因此一些懒惰的程序员处理异常的方式与.unwrap()
在 Rust 中处理错误的方式相同——打印错误并失败。
在 Rust 中,错误显而易见。根据习语的说法,铁锈中的错误有Result
和Option
三种类型。因为错误是显而易见的,程序员厌倦了处理它们,最终更喜欢.unwrap()
每一个错误,这在恐慌恢复的名义下毫无用处。Unwrap 鼓励“最好的希望”,盲目地钻研可能存在的任何数据,如果在任何情况下都失败了,那就是严重的崩溃——恐慌。
错误处理的首要目标是防止崩溃。
让我们看看 Rust 中处理错误的三个关键部分:
- 什么时候恐慌,
- 处理错误,
- 和附加部分:库中的错误处理。
何时恐慌
带着错误代码退出总比惊慌失措好。在最好的情况下,你写的任何软件都不会死机。死机是一种可控制的崩溃,为了构建可靠的软件,必须避免死机。
崩溃从来都不是“恰当”的行为,但这总比让你的系统造成物理损坏要好。如果在任何时候,人们认为该软件可能会导致一些致命的、昂贵的或破坏性的事情发生,那么最好是将其关闭。
如果你认为你的软件是一辆时速 60 英里的汽车,恐慌就像撞上了一堵砖墙。
死机会解开调用堆栈,跳出每个函数调用并从程序执行中返回,在此过程中破坏对象。这不被认为是安全或干净的关闭。避免恐慌。
结束程序执行的最好方法是让它运行到最后一个大括号。以某种方式,为那种行为编程。它允许所有物体安全地自我毁灭。参见掉落特性。
处理错误
恐慌是最后的手段,而不是一个很好的内置工具,可以很容易地通过一个消息退出!
*Result*
、*Option*
、std::io::*Result*
等其他一些类型可以代表一次手术的成功。在惯用的 Rust 中,如果某个东西可能失败,它会返回一个*Result*
,该值编码了两个可能的值:要么是成功值(**Ok**
),要么是错误值(Err
)。*Result*<**T**, **E**>
其中T
是成功值类型,E
是错误值类型。
我们将我们的*Result*
与成功和错误值相匹配。如果这是一个成功,那么我们只是把我们的价值和进展,在我们的软件。但是,如果该值产生错误,我们必须基于以下问题制定有效的备份计划:
- 我们能再试一次吗?
- 数据是绝对强制进行的,还是可以生成、调整或假设的?
如果需要数据来继续,那么我们需要向调用者报告错误。除了 main 以外,我们绝对不能对任何功能感到恐慌。否则,你会得到自认为是上帝的东西的函数。适当的错误处理会尽其所能,当有疑问时,让调用者来处理问题。
下面的例子适用于第一个问题:我们可以再试一次吗?
**fn** open_config() -> *Result*<std::fs::File, std::io::Error> {
**use** std::fs::File;
**match** File::**open**("config.toml") {
**Ok**(f) => **Ok**(f),
// If not found, search in second location:
**Err**(e) => **match** File::**open**("data/config.toml") {
**Ok**(f) => **Ok**(f),
// Otherwise, bubble first error up to caller
_ => **Err**(e),
}
}
}**fn** main() {
**let mut** result = **open_config**();
**if** result.**is_err**() { // If failed the first time
// Try again in about 5 seconds ...
std::thread::**sleep**(std::time::Duration::**from_secs**(5));
// Reattempt
result = **open_config**();
} **match** result {
// Proceed as usual ...
**Ok**(cfg) => *println!*(**"Opened the config file"**),
// Print the cause to stderr, and DONT PANIC
**Err**(e) => *{
eprintln!*(**"File could not be opened: {:?}"**, e.**kind**());
std::process::**exit**(1); // Exit with code 1 (fail)
}
}
这段代码试图在“config.toml”中找到一个配置文件。如果失败,它会尝试在特定的子文件夹中查找相同的配置文件。只有当第二次尝试失败时,它才会将错误冒泡到调用者。调用者是 main,它愿意在暂停 5 秒钟后第一次重试失败。请注意,即使 main 也不会死机,因为虽然这是一个致命的错误,但是可以恢复正常的退出进程。带着错误代码退出总比惊慌失措好。
但是和恐慌一样,std::process:exit
可以防止物品的毁坏,所以只能在没有需要掉落的物品时使用。因此,恐慌是最后的手段,而不是一个漂亮的内置功能,可以很容易地通过一个消息退出!
最后一个例子适用于第二个问题:数据是否绝对必须继续?
/// Get the username from the config if it is present.
**fn** read_username_from_config() -> *Option*<*String*> {
// Implementation hidden
}/// Get the username if present. Otherwise returns the
/// default username "unnamed".
**fn** get_username() -> *String* {
**read_username_from_config**()
.**unwrap_or**(*String*::**from**(**"unnamed"**))
}**fn** main() {
**let** username = **get_username**();
*println!*(**"Username is: {}"**, username);
}
在上面的例子中,main 只请求一个用户名。get_username
返回String
,这意味着它没有失败的能力。它试图使用read_username_from_config
从配置文件中读取一个用户名,但是如果无法检索到,它将使用默认字符串“未命名”。
权衡你可能得不到的数据的价值是很重要的。考虑是否有可能返回到输入循环,或者带着警告继续。关注你的软件的可用性,以及它如何克服缺乏数据的问题。⁴
库中的错误处理
将错误值表示为代码时,可以使用枚举。
#[derive(Debug, PartialEq)] // Use derives
**enum** *SafeDivideError* { // Define a custom error type
**DivideByZero**,
}**fn** safe_divide(dividend: **i32**, divisor: **i32**) -> *Result*<**i32**, *SafeDivideError*> {
**if** divisor == 0 { // If the dividend is zero …
**Err**(*SafeDivideError*::***Divi*deByZero**) // Return the error value
} **else** { // Otherwise …
**Ok**(dividend / divisor) // Return the success value
}
}*assert_eq!*(safe_divide(4, 2), **Ok**(4/2));
*assert_eq!*(safe_divide(4, 0), **Err**(*SafeDivideError*::**DivideByZero**));
在上面的例子中,我们使用自定义枚举作为错误返回类型。这很容易看出我们产生错误的原因,但是在这种情况下,被零除是我们需要报告错误的唯一原因。因此,更好的型号可能是*Option*<**i32**>
。
创建自定义错误类型很有价值。当您使用空枚举作为错误类型时,数据足迹可能很小。这很重要,因为不管使用*Result*<**i32**, *String*>
的成功或错误值,例如,它消耗的内存和它的最大成员一样多。在这种情况下,是一个字符串,比堆栈上的一个**i32**
大 16 个字节。相反,SafeDivideError
枚举消耗“零”字节的内存。
*println!*(**"String: {}B"**, std::mem::size_of::<*String*>());
*println!*(**"SafeDivideError: {}B"**, std::mem::size_of::<*SafeDivideError*>());// String: 24B
// SafeDivideError: 0B
当使用两个或更多值时,它就变成了一个u8
的大小,在获得另一个字节之前,可以表示多达 256 个不同的错误值。将错误值表示为代码时,可以使用枚举。
利用文档注释来解释函数为什么会返回错误,尤其是不同的错误值意味着什么,这一点很重要。如果一个函数返回*Result*<**i32**, *String*>
,那么使用你的库的人肯定会想知道函数失败会返回什么不同的字符串。
旧的规则仍然适用于创建库:永远不要惊慌,只允许函数的调用者在您不能处理错误时处理错误——必要时冒泡错误。设计一个好的错误恢复库需要强调健壮的错误类型和它们的文档。从[std::io::Error](https://doc.rust-lang.org/std/io/struct.Error.html)
中汲取一些天才。
Rust 使任何人都能够构建高度健壮、可靠和高效的软件。所以不要慌!使用正确的方法编写可靠的 Rust 软件。
脚注
- 来源:http://www.phworld.org/history/attcrash.htm
- 这里有一个很好的列表:https://en.wikipedia.org/wiki/List_of_software_bugs
- 错误冒泡是指代码向上游传递错误,因为它肯定不会处理它。又名错误传播。
- 但是不要执行静默数据操作。