TowardsDataScience 博客中文翻译 2021(一百八十八)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

用 Docker 容器化你的应用程序

原文:https://towardsdatascience.com/containerize-your-application-with-docker-b0608557441f?source=collection_archive---------6-----------------------

在虚拟化操作系统上运行您的应用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

托德·克雷文在 Unsplash 上的照片

动机

假设您想将一个应用程序部署到服务器上。在您的本地系统中,应用程序运行良好,没有任何问题。但是一旦你将应用程序部署到服务器上,嘣!你的应用程序不工作。

许多因素都会导致这种情况。这可能是操作系统兼容性或不同的库版本。因此,您的应用程序永远不会被部署,您会因此而感到头疼。

怎么才能去除仅仅因为不兼容问题而头疼的问题?码头工人来救你了!

本文将向您展示如何使用 Docker 来封装您的应用程序,以便您可以在任何服务器上运行它们,而不管它们内部的操作系统是什么。没有进一步,让我们开始吧!

Docker 是什么?

在我们进入实现之前,让我向您解释一下 Docker。Docker 是一个部署应用程序的平台。它的工作原理是将应用程序隔离到一个映像中。该映像将由一个容器运行,其中包含操作系统和支持软件。

由于这种隔离,我们不必担心软件安装及其版本。您可以通过容器运行应用程序,而不管计算机中的操作系统和软件如何。因此,您可以专注于开发您的应用程序并直接部署它们。

履行

在你理解了 Docker 的概念之后,现在让我们进入实现。我们将执行几个步骤:

  1. 安装 Docker
  2. 创建名为 Dockerfile 的文件
  3. 建立形象
  4. 运行图像

安装 Docker

我们可以做的第一步是安装 docker 应用程序。你可以在这里下载 DockerT5并确保根据你的操作系统选择正确的。

安装 Docker 后,现在让我们测试 Docker 是否已经安装在您的计算机上。您可以运行命令“docker ”,如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你的电脑显示如上提示,我们可以向你保证 Docker 已经安装在你的电脑上。现在让我们进入下一步。

创建 Dockerfile 文件

安装 Docker 后,下一步是创建一个名为 Dockerfile 的文件。Dockerfile 是一个用于构建 docker 映像的脚本。它包含了从安装库到运行我们的项目的设置映像的指令。

在本例中,我创建了一个基于 Flask 库的 API。这个 API 将被用作用户和机器学习模型之间的连接器,以返回预测结果。下面是 API 的代码:

要创建 docker 文件,请确保该文件与您的应用程序和机器学习模型文件夹位于同一位置。在我的例子中,文件夹位置如下所示:

**|   app.py
|   Dockerfile
|   requirements.txt
|
+---resnet50_food_model
|   |   saved_model.pb
|   |
|   +---assets
|   +---variables
|           variables.data-00000-of-00001
|           variables.index**

在该文件夹中,我们有用于运行我的应用程序的 app.py ,包含我们将使用的包列表的 requirements.txt,包含预训练模型的模型文件夹,以及用于构建 docker 映像的 docker 文件。

请记住,在创建 docker 文件时,请确保不要在文件名后添加任何扩展名。您只能写“Dockerfile”。

现在让我们编写 Dockerfile 脚本。以下是 Dockerfile 文件中的脚本:

让我解释一下脚本的每一行:

“FROM”指令将从 docker 注册表中获取 docker 映像。该映像将包含操作系统和 Python。

“WORKDIR”指令将设置我们将用来运行应用程序的默认工作目录。

“复制”指令会将当前目录中的每个文件复制到新的工作目录中。

“运行”指令将运行一个命令。在这种情况下,是“pip install”命令。

“EXPOSE”指令会将端口 5000 作为连接器暴露给 docker 映像。

最后,“CMD”指令将运行一个命令。在这种情况下,“烧瓶运行”命令。

旁注:
‘CMD’指令和‘RUN’指令有相同的功能,但是它们的用途不同。

“CMD”指令用于在开始运行 docker 映像时运行命令。

同时,“RUN”指令用于在构建 docker 映像时运行命令。

建立 docker 形象

创建 docker 映像后,下一步是构建映像。要建立形象,真的很简单。你需要做的就是像这样运行“docker build”命令:

**docker build -t my-image .**

正如你在上面看到的,我在“docker build”命令旁边加上了“-t”标记。'-t '标记有两个参数。它们是图像名称和点字符,代表文件夹中的所有文件。

这是我们在构建 docker 映像时的预览(这将需要很长时间,所以请耐心等待) :

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们运行“docker images”命令来显示已经构建的现有图像。以下是结果预览:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

运行 docker 映像

从上面可以看到,图像已经存在。现在下一步是在我们的计算机上运行 docker 映像。要运行映像,您可以像这样使用命令“docker run ”,

**docker run -dp 5000:5000 my-image**

让我们等一会儿,等 3 到 5 分钟。要知道我们的映像是否已经在运行,我们可以使用’ docker ps -a '命令来检查所有正在运行的映像。以下是预览:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如你从上面看到的,图像已经上升了大约一分钟。这意味着映像已经在端口 5000 上运行。现在让我们使用 localhost:5000 或 127.0.0.1:5000 来访问映像。以下是预览:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如您从上面看到的,我们的容器已经在我们的计算机上成功运行了。因为设置了’-d '参数,所以不能显示容器的日志。

要检查容器上的活动,可以使用“docker 日志”来完成。另外,请在旁边设置容器 id。您可以从“docker ps -a”命令中看到容器 id。该命令如下所示:

**docker logs bff6d3c8e2da**

下面是日志预览的样子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你想停止容器,你可以使用’ docker kill '命令,并在旁边设置容器 id。以下是停止 docker 命令的命令:

**docker kill bff6d3c8e2da**

停止容器后,它看起来像这样,

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

是的,我们的集装箱已经终止了。

结束语

干得好!您已经学习了如何将您的应用程序容器化为 docker 映像。我希望这篇文章能帮助你在你的项目中建立自己的 docker 形象。

如果你对这篇文章感兴趣,你可以关注我在媒体上的文章。如果你有任何问题或者想和我打招呼,你可以在 LinkedIn 上和我联系。

谢谢你看我的文章!

参考

[1]https://docs.docker.com/
【2】https://nickjanetakis . com/blog/docker-tip-7-the-difference-between-run-and-cmd

通过 AWS 上的 Docker 和 FastAPI 实现 GPU 推理的容器化 Huggingface 转换器

原文:https://towardsdatascience.com/containerizing-huggingface-transformers-for-gpu-inference-with-docker-and-fastapi-on-aws-d4a83edede2f?source=collection_archive---------18-----------------------

为 GPU 上的总结任务创建 docker 容器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者使用来自 Canva.com 的免费图片

在 docker 容器中使用 GPU 并不简单。容器和主机上的 CUDA 和 CuDNN 驱动程序之间不应该有任何不匹配,以实现无缝通信。

理想的方法是在您的 docker 中使用NVIDIA container toolkit image,它支持自动识别您的基本机器上的 GPU 驱动程序,并在 Docker 容器运行时将这些相同的驱动程序传递到您的 Docker 容器。在 roboflow 团队的这篇精彩文章中,你可以读到更多关于在 GPU 中使用 Docker 的内容。

在本文中,我们将看到如何使用 Docker 和 FastAPI 将来自 HuggingFace transformers 的摘要算法封装成用于 GPU 推理的容器,并将其部署在一台 AWS EC2 机器上。如果您想要更多的可伸缩性,您可以使用相同的 docker 容器来部署容器编排服务,如 AWS 提供的 ECS

Youtube 视频

如果你想看视频,这里有-

https://www.youtube.com/watch?v=I3kkQVNuXyc

汇总代码

首先,我们将使用 HuggingFace transformers 为摘要器编写代码。你可以看看这个 Colab 笔记本 自己运行一下看看总结。

总结的基本代码如下所示:

上述代码的输出是我们传递给它的文本的摘要-

**Elon Musk has shown again he can influence the digital currency market with just his tweets. The SpaceX CEO has in recent months often tweeted in support of Dogecoin, but rarely for Bitcoin. In a recent tweet, Musk put out a statement from Tesla that it was concerned about the rapidly increasing use of fossil fuels. A day later he again tweeted saying, To be clear, I strongly believe in crypto but it can't drive a massive increase in fossil fuel use, especially coal. Following the two distinct statements from him, the world's largest cryptocurrency hit a two-month low.**

现在,我们将看到在 AWS EC2 机器上将它作为 API 进行封装和部署的步骤。

集装箱化代码

在这个 Github repo 中提供了为上述摘要算法创建 GPU docker 容器所需的所有代码。

启动 AWS EC2 GPU 机器来服务 API

我们将从基础 AMI 映像(深度学习基础 AMI (Ubuntu 18.04)版本 42.0)启动一台 EC2 GPU 机器(g4dn.xlarge),创建 docker 映像,并运行该映像以在同一台机器上提供用于摘要的 API。

步骤 1: 登录 AWS 控制台,进入 EC2 仪表板。

步骤 2: 进入仪表板后,点击右上角的**“启动实例”**。

第三步:现在我们被要求选择一个 AMI。在搜索栏输入“深度学习基础 AMI”。我们没有自己安装 CUDA、CuDNN 和 Docker(这很难),而是选择亚马逊机器映像(AMI ),它已经为我们预装了所有东西。

从返回的选项中选择**“深度学习基础 AMI (Ubuntu 18.04)版本 42.0”**。您可以相应地选择任何更新的映像,与我们 docker 文件中提到的基础映像中使用的 CUDA 和 CuDNN 库版本相匹配。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自作者 AWS 帐户的快照

步骤 4: 在下一个屏幕中选择实例类型。选择**“g4dn”**并从选项中选择 g4dn.xlarge 并继续。请注意,如果您以前没有使用过此 GPU,您需要在 AWS 中提出限额增加请求,以将此 GPU 分配到您的帐户所在区域。

为什么是 G4 实例类型?这是可用的 AWS 实例中最具成本效益的选项。点击阅读更多关于在 AWS 上选择合适 GPU 的信息

然后单击“配置实例详细信息”

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自作者 AWS 帐户的快照

**第 5 步:**保留所有默认设置,然后单击“添加存储”。在“添加存储”部分,记住将根卷大小更改为 120 (GiB)等。我们需要这样做,因为我们的 docker 图像和其他必要的配置需要大量的空间。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自作者 AWS 帐户的快照

**第 6 步:**接下来点击“添加标签”。这里没什么可改变的。
接下来点击“配置安全组”并点击“添加规则”来添加端口 80 的自定义 TCP,其来源可以来自任何地方。这将使我们能够在默认端口 80 上托管 API,并从任何地方访问 API。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自作者 AWS 帐户的快照

**第 7 步:**接下来点击“审核并启动”,点击“启动”。创建“新的密钥对”或使用现有的密钥对。这用于 SSH,如果您在 Windows 上或从命令行,可以通过 Putty 等工具连接到 EC2 机器。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自作者 AWS 帐户的快照

步骤 8: 一旦 EC2 机器准备就绪,您就可以通过任何 SSH 客户端连接到它。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自作者 AWS 帐户的快照

步骤 9: 一旦你通过 SSH 进入 EC2 机器,运行“git clonehttps://github . com/ramsrigouthamg/GPU _ Docker _ Deployment _ HuggingFace _ summary . git”来克隆包含 Docker 文件的存储库,以将来自 hugging face 的摘要算法容器化。

第十步: CD 到“GPU _ Docker _ Deployment _ hugging face _ summary”文件夹,依次运行以下命令。

**pip3 install transformers==4.6.1
pip3 install torch==1.9.0
python3 download_HF_Question_Generation_summarization.py**

我们从 HuggingFace 本地下载摘要模型,并将其打包在 docker 容器中,而不是每次下载时都将代码放在容器中。

步骤 11: 完成上一步后,使用以下命令构建 docker 映像

**docker build -t summarization .**

建立映像需要一些时间,所以请耐心等待。

**第 12 步:**一旦构建了映像,使用以下命令运行容器—

**docker run -p 80:80 --gpus all summarization**

一旦一切准备就绪,只需在浏览器中访问 EC2 机器的基本 URL,您应该会看到一条“hello world”消息。

ec2–18–189–32–8.us-east-2.compute.amazonaws.com

接下来,通过像 Postman 这样的工具测试摘要 API。您可以传入任何文本,并获得它的摘要版本。记住传递文本以及最小 _ 长度最大 _ 长度参数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者快照

如果您想无限期地运行 API,请使用控制台应用程序,如 Screen ,这样即使您关闭连接,API 也会继续运行。

创建 GPU Docker 的代码

将我们在开头展示的 Colab 笔记本转换成由 FastAPI 托管的 API 的主要代码如下所示

用于从基础 Nvidia 映像创建 GPU docker 的 docker 文件如下所示

**FROM nvidia/cuda:11.0-cudnn8-runtime-ubuntu18.04****#set up environment
RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y curl
RUN apt-get install unzip
RUN apt-get -y install python3
RUN apt-get -y install python3-pip****# Copy our application code
WORKDIR /var/app****# . Here means current directory.
COPY . .****RUN pip3 install --no-cache-dir -r requirements.txt****ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8****EXPOSE 80****# Start the app
CMD ["gunicorn", "-b", "0.0.0.0:80","app:app","--workers","1","-k","uvicorn.workers.UvicornWorker"]**

这是 requirements.txt 文件

**pydantic==1.8.2
uvicorn==0.14.0
gunicorn==20.0.4
fastapi==0.67.0
torch==1.9.0
sentencepiece==0.1.82
transformers==4.6.1**

点记:

如果您想要确定,请确保您创建的 docker 映像(NVIDIA container toolkit 基本映像)中的驱动程序(CUDA 和 CuDNN 版本)与运行容器映像的主机中的 GPU 驱动程序匹配(或兼容)。在 AWS 中,您可以选择一台主机作为 AMI,它与您用来创建 docker 映像的 NVIDIA container toolkit 映像兼容(请记住在您的 docker 文件中使用 NVIDIA/cuda:11.0-cud nn8-runtime-Ubuntu 18.04)。

您可以使用 GPU 兼容的 Amazon 机器映像(AMI)作为主机映像,在 ECS 等容器编排服务上可伸缩地部署 API

祝 NLP 探索愉快,如果你喜欢它的内容,请随时在 Twitter 上找到我。

如果你想学习使用变形金刚的现代自然语言处理,看看我的课程使用自然语言处理的问题生成

上下文管理器;Python 开发人员的最佳经理

原文:https://towardsdatascience.com/context-managers-the-best-managers-for-python-developers-a5809fb7e428?source=collection_archive---------10-----------------------

如何避免不关灯

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

亚历山大·奈特Unsplash 上拍照

介绍

你有没有饿着肚子去厨房,打开冰箱,拿出好吃的东西,又因为饿得忘记关冰箱?或者你有没有在晚上回到家,你的一些灯还亮着?我想我们都知道这种情况。

那么,当标题说我们要讨论 Python 时,我为什么要告诉你呢?作为一名数据科学家或机器学习从业者,你为什么会关心这个问题?原因是你会经常面临这样的情况。例如,当您连接到一个数据库以获取有价值的数据时,却忘记了关闭连接。或者假设您正在设置一个巨大的计算集群来训练您的模型,当您完成后,您让它继续运行。这些东西可能会变得非常昂贵,让你的经理或公司烦恼。

这让我想起了我们现实生活中忘记关冰箱或忘记开灯的情况。我们忘记做家务了!软件的不同之处在于,我们不会亲自回来,并有第二次机会来收拾残局。因此,后果可能会更加严重,比如系统变慢,甚至完全崩溃。最糟糕的是,这种情况可能发生在程序内部的任何地方,不一定靠近造成混乱的代码。这很难找到和调试。

那么在 Python 中我们能做些什么来避免遇到这些情况并且永远不要忘记清理资源呢?

使用上下文管理器!

在本文中,我将向您介绍上下文管理器以及如何用 Python 编写自己的上下文管理器。一旦你知道并应用它们,你将永远不会忘记做家务,因为它是自动为你做的。这当然只适用于代码,对提到的实际情况没有帮助😃你准备好了吗?我们开始吧!

上下文管理器

基本概念

管理资源是编程的一个重要部分,但我们有时容易忘记。资源是任何数量有限的可用资源。例子包括文件句柄、网络套接字,仅举几例。对于这些资源来说,确保在你获得它们之后释放它们*是至关重要的。*如果它们没有被释放,您就有一个资源泄漏,您的系统可能会变慢或崩溃。

除了管理资源之外,在其他情况下,您也应该执行最后的清理操作。例如,关闭与获取数据的数据库的连接,向 Kafka 提交偏移量,或者在扩大计算资源后缩小计算资源。后一种方法可以真正节省成本,尤其是在讨论用于模型训练的大规模计算集群时。

总的来说,有一个我们正在寻找的属于下列行动的一般模式

  • Open - Close
  • Lock - Release
  • Change - Reset
  • Enter - Exit
  • Start - Stop
  • Setup - Teardonw

每当你发现自己处于这种情况时,上下文管理器将是你最好的朋友。这有助于你的程序始终处于良好状态。如果你使用它们,你不会忘记做家务,也不会意外地在失败的情况下不做家务。最后,当您应用上下文管理器时,您的代码也处于可读性更强、重复性更低的状态。

说得够多了,让我们在下一节看看如何在代码中使用上下文管理器。

如何使用 Python 上下文管理器

在我的工作中,我做过许多与 Python 相关的采访。在那里,我几乎总是问人们:“什么是上下文管理器?”。有趣的是,大多数受访者表示他们从未听说过这个术语。然而,如果我给他们看一个例子,他们都会说

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Afif KusumaUnsplash 上拍摄

“那是上下文管理器吗?我经常用!”。我也想在这里和你做同样的事。这是一个例子

你是不是像“啊”一样走了?我想不是因为你已经知道什么是上下文管理器。如果没有,没问题,让我们快速消化我们在这里做的事情。

在本例中,open是上下文管理器。[**with**](https://www.python.org/dev/peps/pep-0343/) 语句确保上下文管理器执行其打开和关闭动作。在这里,上下文管理器打开给定的文件something.json,,并返回相应的文件处理程序。我们可以使用**as**语句将上下文管理器的返回值赋给一个变量。当我们退出**with**块时,上下文管理器确保所有东西都被清理了,即使在失败的情况下。很甜蜜,不是吗?

现在,如何编写上下文管理器呢?让我们在最后一节检查一下。

如何编写上下文管理器

在了解了如何使用上下文管理器之后,让我们更深入一层,看看如何编写上下文管理器。原则上,你要做的就是写一个类,并简单地实现两个 magic 或 dunder 函数__enter__来设置一切,以及__exit__来清理混乱。我认为最好的做法是__enter__返回 self,这样您就可以将创建的对象赋给as子句中的一个变量,并在以后使用它。

如果您正在使用现代 Python,并且希望在设置或拆除时进行一些异步调用,您必须编写一个异步上下文管理器。幸运的是,这几乎和同步调用一样简单。你只需要实现两个异步函数__aenter____aexit__。最后一点,要调用异步上下文管理器,只需调用async with YourManager() as a:。很简单,不是吗?

现在,这是编写上下文管理器的正确方式。但是如果 Python 不能提供更多的语法糖来帮助以同步和异步方式编写上下文管理器,它就不是 Python 了。你所要做的就是写一个函数并使用一个装饰器。听起来很酷,不是吗?让我们看看这在代码中是怎样的

在这里,我以同步和异步方式创建了一个名为training_cluster的上下文管理器。这个上下文管理器旋转一个假设的训练集群,并确保它在被使用后被关闭。要实现这一点,你只需要在某个时候写一个函数yield,并用来自令人敬畏的 Python 内置 contextlib 模块的contextmanageracontextmanager来修饰它。现在,您可以将它与两个训练功能中所示的withasync with关键字一起使用。完成了。就这么简单。

我喜欢这种方法的一点是,发生了什么非常清楚。在yield之前的一切都是安装部分,之后的一切都是拆卸部分。为了确保拆除总是发生,你必须把它放到一个finally块中。顺便提一下,如果您希望您的上下文管理器不返回任何内容,只需使用没有任何返回值的yield

最后,这种方法的另一个优点是,您可以轻松地为第三方类提供上下文管理器,而不必继承它们。这同样有助于编写清晰漂亮的代码。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Tim MossholderUnsplash 上拍摄

包裹

在本文中,我已经向您展示了 Python 中的上下文管理器及其用途。此外,我还为您提供了同步和异步上下文管理器的示例实现和用法。我希望你同意使用这个既超级有用,同时又非常简单。老实说,自动完成家务就像梦想成真一样😃

感谢您关注这篇文章。一如既往,如有任何问题、意见或建议,请随时联系我或关注我,无论是在这里还是通过 LinkedIn

背景很重要:为什么人工智能(仍然)不擅长做决定

原文:https://towardsdatascience.com/context-matters-why-ai-is-still-bad-at-making-decisions-975f2f797da7?source=collection_archive---------20-----------------------

意见

人工智能还不够聪明,不符合道德规范(尽管它足够聪明,可以收集你的大量数据),但这里有一个想法可能会让它朝着正确的方向发展。

这里有一个假设。

一个男人和一个女人住在一起。

那人每次说话都不耐烦,在你没听懂他的问题时大声咒骂你。他粗暴得近乎生气,只在深夜和你说话,只问关于夜总会和酒吧的事。

这位女士每次说话,要么流着泪,要么声音单调。她的问题更多地与家务相关——食谱、购物提醒、财务问题。她整天和你聊天,经常问心理健康问题。她过去的搜索查询甚至包括有关家庭暴力求助热线的信息。

一天早上,凌晨 3:00,在那个人向你问路去最近的酒吧 5 个小时后,他问你最近的枪支商店在哪里。

想象你是这些人的朋友。你会怎么说?

现在想象一下,男人和女人不是在和你说话,而是在和一个支持亚马逊 Alexa 的设备说话。你认为 Alexa 会说什么?

很有可能,你的两个答案截然不同——因为人工智能仍然没有足够的智能在这些类型的情况下做出合乎道德的行为。

伦理人工智能是难以想象的。

人工智能中的伦理如此困难的众多原因之一是,没有人能够就什么是普遍伦理或道德达成一致。(目前)我们能做的最好的事情是基于边缘案例或思想实验定义一个设计框架,就像上面展示的那样。我想说的是,Alexa 知道正在发生什么——有大量信息表明这个男人对女人来说是一个危险——但人工智能世界对 Alexa 应该做什么没有达成共识。粗略搜索一下伦理框架,你可能会找到一些术语,比如价值伦理(良好的品格定义了你的行为)道义论(你的职责定义了你的行为),或者结果主义(结果证明了你的行为),但在我看来,理想的设计要简单得多。语境意识

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

“亚历克斯——嗯?”阿比纳夫·拉古纳坦。

有上下文意识的人工智能更好。

在任何真实的人类对话中,语境就是一切。背景是你不在葬礼上讲笑话或在生日聚会上谈论死亡的原因。为什么技术不能利用环境的力量做出更明智、更道德的决定呢?

在上面的场景中,Alexa 知道的事情(语音语调、音调、搜索历史等。)都是亚马逊收集或者已经可以收集的数据片段。他们利用这些信息来判断你是谁,以便更智能地推动他们的电子商务和广告。除此之外,他们还可以推动这种情境优先的方法做出道德决策。当人工智能能够收集数据,筛选可能的场景,并潜在地防止负面后果(无论这可能需要什么)时,会有更大的力量。

自然,这说起来容易做起来难。我列出的场景没有完美的答案,但是不考虑上下文就回答这个人的问题本身就是一个错误。也许 Alexa 提供了答案,但也通知警方作为预防措施。也许 Alexa 拒绝回答。当然,这个人可以稍后再用谷歌搜索,但是迫在眉睫的暴力不应该被激活或者让 T2 变得更容易。

我的观点很简单:

人工智能永远不应该在存在可访问的上下文信息时盲目行动。

这甚至适用于像机器学习这样的人工智能子集。数据集中总是有上下文的,无视这种上下文的算法根本不能被认为是可用的。这种情况可能包括数据偏差,如种族/性别代表性不足,或与犯罪记录或教育背景等有缺陷的来源有关。

我说这种方法绝对更好,因为如果从上下文中似乎没有任何可辨别、可学习的特征,它可以被忽略,AI 可以像正常情况下一样继续进行。如果 Alexa 确信给定的问题与上下文没有相关性或联系,它可以安全地回答该问题。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Abhinav Raghunathan 的《语境盲》。

背景是价值驱动因素。

上下文优先的人工智能为价值主张增加了额外的维度。就个人而言,如果我知道我的 Alexa 会在特定的情况和背景下做出合乎道德的故意反应,我可能会更愿意自愿提供我的数据。如果我看到它在工作,我甚至会更信任亚马逊的数据(即使他们仍然在后台执行他们不太值得信任的做法)。

如果你是一家数据公司,你的算法在提取见解之前考虑了数据集中的种族或性别背景,那就是增值。

如果你是一家机器人公司,你的机器人在行动之前会考虑社会背景,这就是一种增值。

如果你是一家支持语音的人工智能公司,并且你的产品在谈论枪支或毒品之前考虑到了你家里有小孩的事实,那就是增值。

具有上下文意识的人工智能很可怕,但却是必要的。

不可否认,让人工智能更多地了解你可能看起来令人毛骨悚然。也许是因为我的建议是,人工智能在判断情况和做出反应的能力上更像人类。不幸的是,我们在日常生活中越来越依赖技术要求这项技术的行为符合道德规范,不会危及或负面影响我们。我们也有一种“与机器建立友谊甚至亲密关系”的心理倾向[1]。如果这还不可怕,那就没什么可怕的了。这正是为什么我们需要更聪明、更有道德的人工智能。

从法律责任的角度来看,公司可能会担心。如果像谷歌、苹果和亚马逊这样的公司还没有通过 不断监听 你的每一次谈话来让自己成为见证人的话,这就说得通了。上下文意识的目的是以更聪明的方式使用这个“特性”。他们已经在收集所有这些数据,为什么不明智地使用这些数据呢?

它的美妙之处在于它是一份保险:大多数时候,没有特别麻烦的上下文。然而,如果环境需要,人工智能应该准备好做出相应的响应。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Abhinav Raghunathan 的“环境意识框架”。

我们需要实现上下文相关的框架。

在一个日益互联的世界里,功能性已经不够了。仅仅能够回答“最近的枪支商店在哪里”这个问题是不够的背景很重要。道德很重要。

环境意识就是认识到所有的技术都积极地影响着人们的生活方式——而这些人不会生活在泡沫中。因为人工智能已经发展出了超越功能的力量,所以设计和工程团队有责任构建理解和尊重环境的人工智能。无论是数据集中的隐藏背景还是机器人的社会背景。

我们需要让技术做它最擅长的事情并改变生活,但要为它提供环境意识,以确保它以积极的方式这样做。

参考

[1] C. Bartneck 等人,*机器人学与人工智能中的伦理学导论,*伦理学中的 SpringerBriefs,https://doi.org/10.1007/978-3-030-51110-4_7

[2]原帖可以在这里找到

语境理论 II:语义框架

原文:https://towardsdatascience.com/context-theory-ii-semantic-frames-f96693480779?source=collection_archive---------35-----------------------

对话管理的语义框架

在语境理论系列的前几篇文章中,首先我们发现了一些与语境相关的语言学概念。接下来,我们一头扎进对话结构;是什么让谈话变得有意义和连贯。在本文中,我们将关注一种结构化的对话管理方式,称为语义框架。顾名思义,语义框架是对话的单元,它们捕捉所有必要的信息来解析上下文。语义框架概念捕获了槽填充、共指解决、上下文相关的意图分类、解决错误路径以及分类/控制域切换的概念。

语义框架的诞生是为了给对话管理带来结构。我们先快速了解一下我们的 Chris,了解一下语义框架概念。

我们的克里斯

我们的克里斯是司机助理,由德国 Autolabs 打造。

用户在开车时与克里斯在车里交谈,因此话语通常简洁而中肯。以下是克里斯话语的一些例子:

Hey Chris, navigate
Play music 
Send a message
Start the navigation
Make a call

结果,诸如导航目的地、消息的接收者姓名、要呼叫的联系人或要播放的艺术家的一些信息通常不在单个话语中提供。Chris 会跟进以填补所需的空缺。这是一个非常典型的对话片段:

User: Hey Chris make a call
Chris: OK, who do you want to call?
User: Alicia
Chris: Do you mean Alicia A?
User: Yes
Chris: Shall I call Alicia A on her mobile?
User: No, home
Chris: OK, I'm calling Alicia A on her home number.

虽然不太常见,但包含所有填充位置的话语也来自客户。我们称之为“一次性”话语。下面是上面的对话片段撞成的一句话:

Call Alicia on her home number

在语音助手中,通常有两种方式来设计和训练对话式 NLU;第一种方式是端到端对话管理,它输入话语并产生动作/响应。没有诸如 ASR(语音识别)输出或意图概率的中间步骤。这些系统很好,不需要单独处理 ASR 和 NLU 组件培训。此外,您不需要处理来自 ASR 组件的不良/噪声输出,不需要在 NLU 步骤中模拟噪声或无意义的 ASR 转录。

第二种方法显然是分别进行语音识别和 NLU。然后,人们可以明确地检查 ASR 转录,还可以看到每个步骤的输出,如意图分类和实体提取。克里斯会话 NLU 属于这一类。以下是对克里斯对话式 NLU 设计的高度描述:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

克里斯对话 NLU 设计

每个话语首先访问语音引擎,然后变成文本。接下来,话语文本被提供给对话管理器进行识别和解析。然后触发一个响应和可能的系统动作,例如,在上面的对话片段中,当用户说出“不,家”时,Chris 用“好的,我正在用 Alicia A 家的号码呼叫她。”然后开始和艾丽西娅打电话。

正如我们所说,克里斯首先转录的演讲。车内环境非常嘈杂,因此处理噪音和可能的误解对克里斯 NLU 来说是一个挑战。语义框架就是这样诞生的。

上下文建模

典型的 Chris 对话以用户请求开始,然后是填充空位的话语。下面是一个对话示例:

User: Send a message
Chris: Who do you want to message?
User: Patrick
Chris: What do you want to say?
User: Hello Patrick, I'm on my way.

看看这个一次性的话语:

Send a message to Patrick saying hello

虽然,第一个对话片段实际上是 5 个话语的对话,而第二个句子只有一个话语,但语义上它们是等价的。最后,您知道收件人姓名和邮件正文;所以这两个语义框架是等价的。

没有适当的对话管理,生活有时会很困难。想想那些简短的话语,它们是后续;一般来说,它们没有任何意图,只是对前一个问题的回答。在传统系统中,每一个话语都必须被贴上意图标签。让我们考虑下面的例子,意图写在括号中的话语旁边:

User: Send a message [messages.write]
Chris: To who?
User: Patrick        [calls.dial]
Chris: Do you mean Patrick?
User: yes            [universals.accept]

这是来自传统系统的标记,其中联系人姓名的单个实体映射到呼叫意图(单个联系人姓名最有可能映射到呼叫或消息意图)。在这一点上,NLU 设计器只是放弃了意图,因为它是一个响应话语,并试图解析一个人名实体来填充收件人姓名槽。这就把我们带回了第一点,的确,“帕特里克”的话语根本不带有意图,这种处理方式看起来令人困惑和丑陋,尽管这个系统以某种方式工作。

如果出现不愉快的情况,比如 ASR 错误发生或者用户没有填写插槽,会怎么样?让我们看下面的例子:

User: Send a message [messages.write]
Chris: To who?
User: Britney        [music.play]## oopsi do, now what ask the recipient name or play Britney Spears??

下面是上面发生的事情:

  • 用户想要发送消息
  • 克里斯接着问了收件人的名字
  • 此时麻烦开始了。用户说出“Brittany”或“Betty ”,但是 ASR 进行了错误的转录,并将话语转录为“Britney ”,这在用户的本地音乐中出现为“Britney Spears”。单个艺术家姓名映射到“music.play”话语。
  • 那怎么办呢?再次询问收件人姓名或跟随音乐。播放意图?

在设计一个语音机器人的时候,我们总是牢记会出现 ASR 错误。语音是一个物理量,在对物理世界建模时,我们始终需要记住一些事情可能(并将)变得不理想。

另一种上下文失败发生在噪音上。假设您有一个噪声(无法识别的语音)的占位符文本和相应的意图。在下面的片段中,噪音话语引起了许多“请你重复一遍好吗”来烦扰用户:

User: Make a call  [calls.dial]
Chris: Ok, who?
User: <...>        [universals.noise]
Chris: Could you repeat that?
User: <...>        [universals.noise]
Chris: Could you repeat that?
User: <...>        [universals.noise]

这里,用户未能在给定的时间框架内说出响应,或者车内噪音太大。无论如何,语音助理设计师应该在一些尝试之后结束当前的框架。此外,在这里说“你能重复一遍吗?”是没有意义的,后续应该宁愿是:“你要打电话给谁?”;当前上下文是关于填充联系人姓名槽。

什么是语义框架?

语义帧是对话片段中所有语义成分的总和,包括帧起始意图、与帧起始意图相关联的槽、到目前为止由用户填充的槽、使用的共同参照以及错误路径的当前展望。一个示例帧是:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个示例语义框架从意图消息开始

因此,语义框架为克里斯对话带来了以下语境单位:

  • 领域
  • 帧起始意图
  • 上下文相关意图
  • 时间
  • 实体
  • 共同参照
  • 槽填充
  • 插槽校正
  • 插槽确认
  • 插槽误差
  • 畴跳跃分布
  • 行动
  • 误差建模

语义框架为克里斯对话带来了结构,每个话语都承认一个上下文角色,如帧开始槽填充槽错误槽确认。这段对话解释了话语角色:

User: send a message         frameStarter
Chris: Who do you want to send a message?
User: Patrick                slotFill
Chris: Do you want to text him on mobile?
User: ergghh arghhh          slotError
Chris: Excuse me?
User: yes, mobile            slotConfirm

让我们看看动作的语义框架:

保持流动

语义框架的首要目标是保持流动。再次考虑我们现在看到的第一个例子,一个单独的实体被标记了意图,尽管它是一个响应。现在,该话语具有良好定义的会话上下文角色作为空位填充者,因此我们用当前帧的意图来标记该话语:

User: Send a message [messages.write]
Chris: To who?
User: Patrick        [messages.write]  slot-filler
Chris: Do you mean Patrick?
User: yes            [universals.accept]

布兰妮的第二个例子看起来也不同了。在这个例子中,发生了 ASR 转录错误,ASR 不理解联系人姓名和艺术家姓名,而是返回 Britney。传统系统可能会跳入音乐播放意图并进行错误的域切换,然而语义框架如下识别这种上下文:

User: Send a message [messages.write]
Chris: To who?
User: Britney        [messages.write]  slot-error
Chris: I didn't understand the recipient name, can you say again?

在这里,话语“布兰妮”是一个单一的实体,因此看起来像一个反应和一个真正的补缺;然而它的类型是艺术家,而不是联系人。我们在这里所做的是,我们将这个话语标记为时隙错误,并保留当前帧,即 messages.write。

有了双向标记——帧意图和上下文角色,NLU 的行为对于阅读对话日志的开发人员来说就一目了然了。我们还将当前话语的上下文角色(slot-filler)提供给上下文编码器(上下文编码器的细节将在另一篇文章中介绍)。它基本上是一个 LSTM 编码来自用户话语的当前上下文。

域开关

是保留当前框架还是删除当前框架并开始新的框架有时是一个复杂的交易。在会话的每一个话语中,下一个话语的语境角色分布都是不平凡的,总是有域跳转的可能性。尽管如此,从统计上来说,一些帧之间的一些跳跃更有可能发生,例如调用消息和消息调用。举例来说,《呼唤音乐》不太可能出现在上述布兰妮对话中。我们的上下文编码器在当前语义框架的帮助下生成域跳转概率。让我们看一些例子:

User: Send a message to Patrick                         frameStarter
Chris: Do you want to text Patrick on his mobile number?
User: Call him instead                                  frameStarter
Chris: Do you want to call Patrick on mobile?
User: Yes, pleaseUser: Call Patrick                                      frameStarter
Chris: Do you want to call Patrick on his mobile number?
User: No send a message                                 frameStarter
Chris: Do you want to message Patrick on mobile?
User: Yes, please

这里,在这两个例子中,第三个话语显然是一个框架开始。在第二话语之后,上下文编码器输出第一对话中第三话语的上下文角色分布(按可能到不太可能排序),如下:

affirmative/negative answer
slot-confirmation(phone_type)
slot-correction     
cancel the message sending
domain jump, calldomain jump, navigation.start
domain jump, music.play
.
.
.

第三个话语看起来很可能是 calls.dial,因此此时上下文编码器判定这是域跳转。这个例子怎么样:

User: Call Patrick
Chris: Do you want to call Patrick on his mobile number?
User: Play Moby                   ASR confidence: low

在这个对话片段中,第三个话语很可能是一个 ASR 错误。根据上面的上下文角色分布,这里的音乐播放意图是非常不可能的,并且话语置信度低。因此,上下文编码器将该话语标记为 ASR 错误。

错误校正

错误恢复是对话系统的重要组成部分。语义框架允许灵活和准确的错误跟踪。考虑下面的例子:

User: Make a call                    calls.dial
Chris: Who should I call?
User: <...>                          noise,slot-error
Chris: Who should I call?
User: <...>                          noise, slot-error
Chris: Who is it?           
User: <...>                          too much errors in a row
Chris: I aborted the call

上下文相关意图

人类的语言是复杂的,同样的话语在不同的语境中可以表达完全不同的意思。让我们看一些例子:

User: Call Patrick                          calls.dial
Chris: Do you want me to call him on **mobile**?
User: **Mobile                                 universals.accept**

在这里,用户通过确认 Chris 询问的槽值给出了肯定的答案。这不是一个槽填充或槽确认,这是一个肯定的回答。

这个例子怎么样:

User: **Anrufen**  (make a call)    **calls.dial**
Chris: Wen willst du anrufen?  (Who do you wanna call?)
User: Patrick
Chris: Meinst du Patrick?
User: **Anrufen **                 **universals.accept**

在这里,同一个字“安如芬”在第一行是框架启动符,在最后一行却是一个肯定的回答。这是一种显式的共指方式,“安如芬”是意向名“calls.dial”的同义词;因此指代画面中的动作,指代整个画面

我知道这看起来很多(确实很多),但是对话管理从来都不容易。接下来是什么?首先,我们将看到我在文章中提到的上下文编码器架构。接下来的文章将提供更多关于槽和上下文相关槽提取的内容。我很高兴在这个非常好的关于语境理论的系列中见到你,我希望你和我一样喜欢这个系列。保持关注和健康,直到下一次!

使用 Python 进行上下文化主题建模(EACL2021)

原文:https://towardsdatascience.com/contextualized-topic-modeling-with-python-eacl2021-eacf6dfa576?source=collection_archive---------6-----------------------

将 BERT 和 friends 与神经变分主题模型相结合

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片作者。

在这篇博文中,我讨论了我们最新发表的关于主题建模的论文:

比安奇、特拉尼、霍维、诺扎和弗西尼(2021)。零镜头学习的跨语言语境化主题模型。计算语言学协会(EACL)欧洲分会。https://arxiv.org/pdf/2004.07737

假设我们有一小组葡萄牙语文档,这些文档不够大,无法可靠地运行标准的主题建模算法。但是,我们在同一个域中有足够多的英文文档。使用我们的跨语言零触发主题模型( ZeroShotTM ),我们可以首先学习英语主题,然后预测葡萄牙语文档的主题(只要我们使用预先训练的表示法,既考虑英语又考虑葡萄牙语)。

我们还发布了一个 Python 包,可以用来运行主题建模!看看我们的 github 页面和我们的 c olab 教程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们的标志:)由西尔维娅用爱制成

热身:什么是话题建模?

主题模型允许我们从文本中提取有意义的模式,使浏览文本数据更容易,并更好地理解隐藏在下面的主题的潜在分布。假设您想要获得手头一组文档的鸟瞰图;一个接一个地阅读它们不是一个好主意,对吗?

主题模型可以有所帮助:它们查看您的文档集合,并提取重复出现的主题。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片作者。

一些细节

主题模型通常有两个主要假设。

首先,一个文档可以以不同的比例谈论不同的主题。例如,假设我们有三个主题,即“人类”、“进化”和“疾病”。一个文档可以讲一点人类,一点进化,剩下的讲动物。用概率的话来说,我们可以说它讲了 20%的人类,20%的进化,60%的动物。这可以很容易地用主题的多项式分布来表示。这种概率分布称为文档主题分布。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

描述人类进化的文档如何分类到不同主题的例子。图片作者。

其次,主题建模中的主题不是无序的单词列表:在像“动物、猫、狗、小狗”这样的主题中,词汇表中的每个单词都有特定的权重。换句话说,主题也可以由多项式分布来表示,其中具有最高概率的词汇是对给定主题贡献最大的词汇。这种分布称为词-主题分布。

最著名的主题模型是 LDA (Blei et al .,2003),它也假设文档中的单词是相互独立的,即被表示为单词包(BoW)。多年来已经提出了几个主题模型,解决了各种各样的问题和任务。最先进的主题模型包括基于变分自动编码器(VAE)的神经主题模型(金玛&韦林,2014)。

标准主题建模的两个问题

然而,这种模型通常必须处理两个限制:

  1. 一旦经过训练,大多数主题模型就不能处理未见过的单词,这是因为它们是基于单词包(BoW)表示的,无法解释缺失的术语。
  2. 如果不结合多种语言的词汇,很难将主题模型应用于多语言语料库(Minmo 等人,2009;Jagarlamudi 等人,2010),使得该任务在计算上非常昂贵,并且不支持零射击学习。

我们如何解决这个问题?

情境化话题模式:邀请伯特和朋友们入席

我们新的神经主题模型 ZeroShotTM ,解决了我们刚刚举例说明的两个问题。ZeroShotTM 是一个神经变分主题模型,它基于语言预训练的最新进展(例如,BERT 等上下文化单词嵌入模型)。

是的,你答对了!我们建议将基于深度学习的主题模型与最近的嵌入技术(如伯特或 XLM)相结合。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ZeroShotTM:我们的具有情境化嵌入的神经变分主题模型。图片作者。

文档的预训练表示被传递到神经架构,然后用于重建文档的原始弓形。一旦模型被训练,ZeroShotTM 可以生成测试文档的表示,从而预测它们的主题分布**,即使文档在训练期间包含看不见的单词**。

此外,如果我们在训练期间使用多语言预训练表示,我们可以在测试时获得显著优势。使用共享相同嵌入空间的表示允许模型学习不同语言文档共享的主题表示。然后,经过训练的模型可以在训练期间预测看不见的语言文档的主题

我们扩展了基于变分自动编码器的神经主题模型 ProdLDA (Srivastava & Sutton,2017)。ProdLDA 将文档的 BoW 表示作为输入,并学习高斯分布的两个参数μ和σ。从这些参数中采样连续的潜在表示,然后通过 softplus,从而获得文档的文档主题分布。然后,使用这个主题-文档表示来重构原始文档 BOW 表示。

我们不是使用文档的 BoW 表示作为模型输入,而是将预先训练的文档表示传递给神经架构,然后使用它来重建文档的原始 BoW。一旦模型被训练,ZeroShotTM 可以生成测试文档的表示,从而预测它们的主题分布,即使文档在训练期间包含看不见的单词。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们的 ZeroShotTM,由于多语言表示,可以有效地预测在训练期间没有见过的语言文档的主题。图片作者。

TL;速度三角形定位法(dead reckoning)

ZeroShotTM 有两个主要优点:1)它可以处理测试集中缺失的单词,2)继承了最近预训练的多语言模型的多语言能力。

使用标准的主题模型,您经常需要从数据中删除那些在测试集中有但在训练集中没有的单词。在这种情况下,由于我们依赖于一个上下文化的模型,我们可以使用它来构建测试文档的文档表示,表达这些嵌入的全部功能。此外,标准的多语言主题建模需要考虑多语言词汇。

ZeroShotTM 可以在英语数据(这是一种数据丰富的语言)上进行训练,并在更低资源的数据上进行测试。例如,你可以在英文维基百科文档上训练它,并在完全看不见的葡萄牙语文档上测试它,正如我们在论文中所示。

情境化主题建模:一个 Python 包

我们围绕这款车型打造了一整套套件。您可以运行主题模型并使用几行代码获得结果。在软件包主页上,我们有不同的 Colab 笔记本,可以帮助您运行实验。

你可以在这里或者直接在 colab 上看例子。

根据用例的不同,您可能想要使用特定的上下文化模型。在这种情况下,我们将使用distiluse-base-multilingual-cased模型。

当使用主题模型时,执行文本预处理总是更好,但是当我们处理上下文化的模型时,如 BERT 或通用句子编码器,最好不要做太多预处理(因为这些模型是上下文并且大量使用上下文)。

今天的任务

我们将在英语维基百科文档上训练一个主题模型,并预测意大利语文档的主题。

您需要做的第一件事是安装软件包,从命令行您可以运行:

确保为您的系统安装正确的 PyTorch 版本,另外,如果您想使用 CUDA,请安装支持 CUDA 的版本(您可能会发现使用 colab 更容易)。

数据

让我们下载一些数据,我们将从在线存储库中获取它们。这两个命令将下载英文摘要和意大利文文档。

如果您打开英文文件,您看到的第一个文档应该包含以下文本:

The Mid-Peninsula Highway is a proposed freeway across the Niagara Peninsula in the Canadian province of Ontario. Although plans for a highway connecting Hamilton to Fort Erie south of the Niagara 
Escarpment have surfaced for decades,it was not until The Niagara...

现在,让我们应用一些预处理。我们需要这一步来创建单词包,我们的模型将使用它来表示主题;尽管如此,我们仍将使用未经预处理的数据集来生成来自distiluse-base-multilingual-cased模型的表示。

让我们训练人们

我们的预处理文档将只包含 2K 个最常用的单词,这是一个优化步骤,允许我们删除可能不太有意义的单词。对象允许我们创建数据集来训练主题模型。然后使用我们的 ZeroShotTM 对象,我们可以训练这个模型。

玩模型

我们可以快速检查的一件事是我们的主题。运行下面的方法应该会在输出中得到一些主题

他们很吵,不是吗?

**[['house', 'built', 'located', 'national', 'historic'],
 ['family', 'found', 'species', 'mm', 'moth'],
 ['district', 'village', 'km', 'county', 'west'],
 ['station', 'line', 'railway', 'river', 'near'],
 ['member', 'politician', 'party', 'general', 'political'],
...
...**

如果你想有一个更好的视觉效果,你可以使用这个:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片作者。

是的,但是多语种的在哪里?

所以现在,我们需要做一些推论。尽管如此,我们还是可以从一些新的看不见的英文文档中预测主题,但我们为什么不试试意大利语呢?

这个过程类似于我们已经看到的;在这种情况下,我们将收集每个文档的主题分布,并提取每个文档最可能的主题。

该文档包含以下文本,关于一部电影:

**Bound - Torbido inganno (Bound) è un film del 1996 scritto e diretto da Lana e Lilly Wachowski. È il primo film diretto dalle sorelle Wachowski, prima del grande successo cinematografico e mediatico di Matrix, che avverrà quasi quattro anni dopo**

看预测题目:

**['film', 'produced', 'released', 'series', 'directed', 'television', 'written', 'starring', 'game', 'album']**

有道理,对吧?

这篇博文到此结束,如果你有问题或者有什么想讨论的,欢迎给我发邮件:)你也可以在 Twitter 上找到我。

参考

布莱博士,Ng,A. Y .,&乔丹,M. I. (2003 年)。潜在狄利克雷分配。 JMLR

Jagarlamudi 和 h . daumé(2010 年)。从未对齐的可比语料库中抽取多语言主题。 ECIR

金马博士和韦林博士(2014 年)。自动编码变分贝叶斯。 ICLR

米米诺博士、瓦拉赫博士、纳拉多斯基博士、史密斯博士和麦卡勒姆博士(2009 年 8 月)。多语种主题模型。 EMNLP

斯利瓦斯塔瓦和萨顿(2017 年)。主题模型的自动编码变分推理。 ICLR

学分

这篇博文的内容主要由我和西尔维娅·特拉尼撰写。非常感谢 Debora NozzaDirk Hovy 对本文之前版本的评论。

列联表、卡方检验和克拉默 V

原文:https://towardsdatascience.com/contingency-tables-chi-squared-and-cramers-v-ada4f93ec3fd?source=collection_archive---------1-----------------------

如何轻松检查类别之间的关联

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

简介

在最近的一个项目过程中,我不得不检查一个特性与多个其他特性的关联(缺乏独立性)。为了方便起见,我编写了几个函数来执行并帮助解释这些分类特征之间的关联测试。在这篇文章中,我将演示这一过程,并提供代码示例,读者可以使用自己的数据。

数据

本次演示的数据集是开放大学学习分析数据集。数据集由 7 个 csv 文件组成,包含学生人口统计、评估和注册数据;以及表格形式的课程、课程评估和学习环境数据。我们将查看来自studentInfo.csv 文件的两个分类特征, final_resulthigher _ education,。本演示假设该数据已经加载到数据帧 df 中。

测试的特性

final_result 特征是授予该课程的最终成绩(未通过、退出、通过、优秀),而 highest_education 是学生完成的最高教育水平。这些(英国)教育资格类别的排名如下(从最低到最高):无正式资格,低于 A 级,A 级,he 资格,研究生资格。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

从图表中可以看出,较低的教育水平与退缩和失败的结果正相关,而较高的教育水平与通过和优秀正相关。我们想测试和量化这些概念,如果可能的话,使用统计方法。

列联表

我们将通过使用pandas . crosstab为我们的数据创建一个列联表来开始我们的研究,并实例化一个stats models . stats . table对象来为我们提供查找和显示任何关联的便利方法。Table 类使用皮尔森卡方检验来评估任何关联。

# *creating crosstab data frame*tabs = pd.crosstab(df.highest_education, df.final_result)# creating a statsmodels table objecttable = sm.stats.Table(tabs)

table_orig 方法将返回一个原始数据的列联表。列联表中的数字单元格表示相应行和列对的观察次数。**

table.table_orig

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

fittedvalues 方法将从数据的最佳拟合独立分布中返回值的列联表。

table.fittedvalues

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

resid_pearson 方法返回残差表,该表将揭示数据中存在的任何关联。如果要素是独立的,正值表示观察值比预期值多,负值表示观察值少。

table.resid_pearson

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

从列联表中可以看出,一般来说,成绩和及格与教育水平直接相关。学生的受教育程度越高,就越有可能通过或以优异成绩通过。相反,退缩和失败与教育水平成反比。一般来说,学生的教育水平越低,越有可能失败或退学。

接下来,我们将执行假设检验来验证我们的结果。

假设检验

我们将使用scipy . stats . chi2 _ contingency测试独立性。与 Table 类类似,chi2_contingency 使用皮尔逊卡方检验来评估数据中的任何关联。

让我们首先定义测试的无效假设和替代假设,并指定显著性水平。

Ho = 最高学历最终成绩是独立的。

Ha = 最高 _ 学历最终 _ 成绩不是独立的。

显著性水平α= 0.05。

既然我们已经准备好了,我们就来进行测试。我写了一个小函数,可以很好的打印结果。

def chi_sq_test(cross_tabs):
    """
    Prints the Chi-Squared Statistic, p-value, and degress of freedom from a Chi-Squared test.

    Args:
        cross_tabs: A crosstab dataframe.
    """
    chi2, p, dof, con_table = stats.chi2_contingency(cross_tabs)
    print(f'chi-squared = {chi2}\np value= {p}\ndegrees of freedom = {dof}')

将该函数应用于交叉表数据框会返回:

chi-squared = 962.2117100356752
p value= 2.4827414817328365e-198
degrees of freedom = 12

由于返回的 p 值小于我们的 alpha,我们拒绝零假设,并得出结论最高学历最终结果不是独立的,从而证实了我们上面的发现。

最后,我们将检查我们的功能的影响大小。

效果大小

效果大小是对两个特征之间关联强度的度量。我们将使用我编写的函数来测量影响大小,以计算和显示数据的克莱姆 V 值、克莱姆 V 自由度和影响大小阈值

def cramers_v(cross_tabs):
    """
    Prints the degrees of freedom, effect size thresholds, and Cramer's V value.

    Args:
        cross_tabs: A crosstab dataframe.
    """

    # *effect size data frame for cramer's v function*
    data = np.array([[1, .1, .3, .5],
       [2, .07, .21, .35],
       [3, .06, .17, .29],
       [4, .05,.15,.25],
       [5, .04, .13, .22]])
    sizes = pd.DataFrame(data, columns=['Degrees of Freedom', 'Small Effect', 'Medium Effect', 'Large Effect']) 

    # *getting the chi sq. stat*
    chi2 = stats.chi2_contingency(cross_tabs)[0] # *calculating the total number of observations*
    n = cross_tabs.sum().sum() # *getting the degrees of freedom*
    dof = min(cross_tabs.shape)-1 # *calculating cramer's v*
    v = np.sqrt(chi2/(n*dof)) # *printing results*
    print(f'V = {v}')
    print(f'Cramer\'s V Degrees of Freedom = {dof}')
    print(f'\nEffect Size Thresholds\n{sizes}\n')

将该函数应用于交叉表数据会返回:

V = 0.10148164448653103
Cramer's V Degrees of Freedom = 3

Effect Size Thresholds
   Degrees of Freedom  Small Effect  Medium Effect  Large Effect
0                 1.0          0.10           0.30          0.50
1                 2.0          0.07           0.21          0.35
2                 3.0          0.06           0.17          0.29
3                 4.0          0.05           0.15          0.25
4                 5.0          0.04           0.13          0.22

根据自由度进行调整后,Cramer 的 V 结果表明最高教育程度最终结果有微小的、统计上显著的影响。

结论

希望这个演示能让我们了解一个简单而强大的例程来检查关联的分类特征。为了您的方便,请随意使用和修改上述功能。特别感谢 Sgr Folge 在我的原始帖子中指出了 Cramer 的 V 代码块中的一个遗漏。

来源

开放大学学习分析数据集。Sci 数据 4,170171(2017)https://doi.org/10.1038/sdata.2017.171

该数据集可以通过 CC-BY 4.0 许可在https://analyse.kmi.open.ac.uk/open_dataset免费获得。

Python 中的连续和离散均匀分布—统计

原文:https://towardsdatascience.com/continuous-and-discrete-uniform-distribution-in-python-statistics-82b5aa5c20b1?source=collection_archive---------33-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

布莱恩·麦高恩在 Unsplash 上的照片

在本教程中,我们将探索 Python 中的连续和离散均匀分布。

目录

  • 介绍
  • 什么是均匀分布
  • 连续均匀分布示例
  • Python 中的连续均匀分布示例
  • 离散均匀分布示例
  • Python 中的离散均匀分布示例
  • 结论

介绍

为了继续学习本教程,我们需要以下 Python 库:scipy、numpy 和 matplotlib。

如果您没有安装它,请打开“命令提示符”(在 Windows 上)并使用以下代码安装它:

pip install scipy
pip install numpy
pip install matplotlib

什么是均匀分布

有两种类型的均匀分布:

  1. 连续均匀分布-使用连续值
  2. 离散均匀分布-使用离散(有限)值

连续均匀分布

连续均匀概率分布是具有恒定概率的分布,这意味着测量被观察的相同概率。

连续均匀分布也称为矩形分布。这是为什么呢?让我们一起探索吧!

这种类型的分布由两个参数定义:

  • —最小值
  • b —最大值

并且写成: U(a,b)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://en .维基百科. org/wiki/Continuous _ uniform _ distribution

ba 的区别是音程长度: l=b-a 。由于这是一个累积分布,区间长度内的所有区间都是等概率的(假设这些区间具有相同的长度)。

连续均匀分布的 PDF(概率密度函数)由下式给出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

否则为 0。

连续均匀分布的 CDF(累积分布函数)由下式给出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

用 0 代表x<a用 1 代表x>b。****

离散均匀分布

离散均匀概率分布是具有恒定概率的分布,这意味着有限数量的值同样可能被观察到。

这种类型的分布由两个参数定义:

  • —最小值
  • b —最大值

并且写成: U(a,b)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://en.wikipedia.org/wiki/Discrete_uniform_distribution

ba**+1 之差为观测数: ba 之差为区间长度: n=b-a+1 。所有的观察都是同样可能的。**

对于任一×x∈【a,b】,离散均匀分布的 PMF(概率质量函数)由下式给出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

而对于任意一个【a,b】,一个离散均匀分布的 CDF(累积分布函数)由下式给出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

连续均匀分布示例

让我们考虑一个例子:你住在一栋 10 层的公寓楼里,刚刚回家。你进入大厅,准备按电梯按钮。你知道你可能需要 0 到 20 秒的时间来等待电梯,如果电梯在一楼(无等待)需要 0 秒,如果电梯在十楼(最长等待)需要 20 秒。这将是连续均匀分布的一个例子,因为等待时间可以以相同的概率取任何值,并且是连续的,因为电梯可以在建筑物中第一层和第十层之间的任何地方(例如,在第五层和第六层之间)。

这里我们有最小值 a = 0,最大值 b = 20。

连续均匀分布 PDF

知道了 ab 的值,我们就可以很容易地计算出连续均匀分布的 PDF:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

使用 f(x) 公式和给定参数我们可以创建以下连续均匀 PDF 的可视化:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

那么在连续均匀分布的情况下,这到底告诉了我们什么呢?让我们在区间[0,20]的任何地方取两个 1 秒的区间。例如从 1 到 2(i1 =【1,2】)和从 15 到 16*(I _ 2 =【15,16】*)。重要的是要注意,这两个间隔的长度相同,都等于 1。使用 PMF 结果,我们可以说这些区间以 0.05 的概率同样可能发生。换句话说,电梯在 1 到 2 秒之间到达的可能性与在 15 到 16 秒之间到达的可能性一样大(概率为 0.05)。

连续均匀分布 CDF

现在,让我们考虑在本节的示例中添加一个内容。你还在公寓楼里等电梯,但现在你想知道你按下按钮后,电梯 6 秒或更短时间到达的概率是多少。

使用本节中的连续分布 CDF 公式,我们可以求解:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

我们观察到电梯在 6 秒或更短时间内(0 到 6 之间)到达的概率是 0.3。

使用 F(x) 公式和给定参数我们可以创建以下连续均匀 CDF 的可视化:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

并且我们观察到累积概率和随机变量 X 之间的线性关系,其中函数以 f(x) 的速率单调递增(在我们的例子中 f(x)=0.05 )。

Python 中的连续均匀分布示例

在前面的一节中,我们手工计算了连续均匀分布的概率密度函数。在本节中,我们将使用 Python 再现相同的结果。

我们将从导入所需的依赖项开始:

接下来,我们将创建一个介于 0 和 20(最小和最大等待时间)之间的连续值数组。从数学上来说,有无限多的值,因此在本例中,我们将创建 4,000 个范围在 0 到 20 之间的值。我们也将打印前三个只是为了看看。

您应该得到:

**[0\. 0.00500125 0.0100025 ]**

现在我们必须使用 scipy.stats.uniform 创建一个均匀连续的随机变量:

在接下来的章节中,我们将重点介绍使用 Python 计算 PDF 和 CDF。

Python 中的连续均匀分布 PDF

为了使用 Python 计算累积均匀分布 PDF,我们将使用。scipy.stats.uniform 生成器的 pdf()** 方法:**

您应该得到:

**[0.05 0.05 0.05 ... 0.05 0.05 0.05]**

所以现在我们发现每个值的概率是相同的,等于 0.05,这和我们手工计算的完全一样。

使用 Python 绘制连续均匀分布 PDF

使用 matplotlib 库,我们可以使用 Python 轻松绘制连续均匀分布 PDF:

您应该得到:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Python 中连续均匀分布 CDF

为了用 Python 计算连续均匀分布的 CDF,我们将使用。scipy.stats.uniform 生成器的 cdf()** 方法:**

由于我们将有 4,000 个值,如果我们想要仔细检查我们手工计算的正确性,您将需要找到与等于 6 的值相关联的累积概率。确实在 0.3 左右。

使用 Python 绘制连续均匀分布 CDF

使用 matplotlib 库,我们可以很容易地用 Python 绘制出连续均匀分布的 CDF:

您应该得到:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

离散均匀分布示例

让我们考虑一个例子(这是我们大多数人自己做的):掷骰子。基本上,滚动单个 6 面骰子的可能结果遵循离散的均匀分布。

这是为什么呢?这是因为你只能从 6 个可能的结果中选择 1 个结果(你可以选择 1、2、3、4、5 或 6)。可能结果的数量如果是有限的,并且每个结果被观察到的概率是相等的,即 1/6

离散均匀分布 PMF

已知所有可能结果的数量 n ,我们可以很容易地计算出离散均匀分布的 PMF:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

使用 f(x) 公式和给定参数,我们可以创建以下离散均匀 PMF 的可视化:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在本例中,骰子的每一侧被观察到的机会相等,等于 0.16。

离散均匀分布 CDF

现在让我们考虑这个例子的补充。你正在掷出同一个 6 面骰子,现在想知道你观察到的结果等于或小于 2(意味着 1 或 2)的概率。

已知所有可能结果的数量 n ,我们可以很容易地计算出离散均匀分布的 CDF:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

这告诉我们,如果我们掷出一个 6 面骰子,观察到小于或等于 2 的值的概率是 0.33。

使用 F(x) 公式和给定的参数我们可以创建以下可视化的离散均匀 CDF:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

我们观察到一种逐步的关系,因为我们有离散的值作为可能的结果。

Python 中的离散均匀分布示例

在前面的一节中,我们手工计算了连续均匀分布的累积分布函数。在本节中,我们将使用 Python 再现相同的结果。

我们将从导入所需的依赖项开始:

接下来,我们将创建一个 1 到 6 之间的值的数组(最小和最大骰子值),并打印出来看看。

您应该得到:

**[1 2 3 4 5 6]**

现在我们必须使用 scipy.stats.randint 创建一个均匀连续的随机变量:

在以下章节中,我们将重点介绍如何使用 Python 计算 PMF 和 CDF。

Python 中的离散均匀分布 PMF

为了使用 Python 计算离散均匀分布 PMF,我们将使用。scipy.stats.randint 生成器的 pmf()** 方法:**

您应该得到:

**[0.16666667 0.16666667 0.16666667 0.16666667 0.16666667 0.16666667]**

这正是我们手工计算的 0.16。

使用 Python 绘制离散均匀分布 PMF

使用 matplotlib 库,我们可以使用 Python 轻松绘制离散均匀分布 PMF:

您应该得到:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Python 中的离散均匀分布 CDF

为了用 Python 计算离散均匀分布的 PMF,我们将使用。scipy.stats.randint 生成器的 cdf()** 方法:**

您应该得到:

**[0.16666667 0.33333333 0.5 0.66666667 0.83333333 1\. ]**

我们在这里看到,数组中的第二个值是 0.33,这与我们手工计算的值完全相同。

使用 Python 绘制离散均匀分布 CDF

使用 matplotlib 库,我们可以使用 Python 轻松绘制离散均匀分布 CDF:

您应该得到:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结论

在本文中,我们探讨了累积均匀分布和离散均匀分布,以及如何在 Python 中创建和绘制它们。

如果你有任何问题或对一些编辑有建议,请随时在下面留下评论,并查看更多我的统计文章。

原载于 2021 年 11 月 29 日 https://pyshark.comhttps://pyshark.com/continuous-and-discrete-uniform-distribution-in-python/。****

使用 Github Actions、Docker 和 AWS 的持续部署管道

原文:https://towardsdatascience.com/continuous-deployment-pipeline-using-github-actions-docker-and-aws-185bb3bf41b?source=collection_archive---------5-----------------------

将 Flask ML 应用程序自动部署到 AWS Elastic Beanstalk

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

马文·迈耶在 Unsplash 上的照片

介绍

公司越来越多地寻找机器学习工程师。但是机器学习工程师和数据科学家有什么区别呢?数据科学家纯粹关心训练机器学习模型。他们处理数据,评估数据,并更详细地探索数据。他们试图从中产生附加值。另一方面,机器学习工程师应该将这个训练好的模型转化为最终可用的应用程序。他们必须将 Jupyter notebook 等环境中的代码转换成可用的应用程序。这个应用程序可以是任何东西,从移动应用程序到复杂的网站或普通的 API。这个应用程序也应该得到维护,最好是不断扩展和改进。它还应该在新的更新后重新部署,以便最终用户始终拥有可用的最佳和最新版本。整个部署过程可以而且应该自动化。这就叫做持续集成和部署。集成部分是第一次测试新代码的部分,以确保一切正常工作。如果是,那么代码可以被交付/部署。

在本文中,我想与您分享一个连续部署管道的示例,其中我首先创建了一个 Docker 容器,该容器运行我的 Birds Classifier Flask 应用程序,然后通过使用 Github 操作将该 Docker 容器自动部署到 AWS Elastic Beanstalk。因此,每当一个新的代码状态被推送到我的主分支时,首先创建 Docker 容器以确保一切正常,然后通过 AWS Elastic Beanstalk 部署这个容器。

如果你想知道我是如何从零开始训练鸟类图像分类器的,我可以推荐这篇文章。在这篇文章中,我描述了如何用 Flask 创建 Web API。包括 Dockerfile 和 Github Actions 文件的完整代码可以在我的 Github 库这里找到。

在本文的第一部分,我将更详细地解释 Docker、Github Actions 和 AWS Elastic Beanstalk,并展示它们的优势。然后,我将向您展示如何创建 Docker 映像,以及如何在本地创建和测试容器。之后,我将向您展示如何创建一个能够运行 birds 分类器 API 的 AWS Elastic Beanstalk 应用程序。最后,我将解释如何使用 GitHub Actions 在每次新代码被推送到主分支时自动部署 Docker 容器。

码头工人

好吧,让我们从 Docker 开始。什么是 Docker,为什么要使用 Docker?我觉得下面这句话你们每个人听起来都很熟悉:你在网上发现了有趣的 Python 代码,想在本地运行。但是首先你需要一个版本正确的 Python 环境。例如,Anaconda 可以用于此目的。现在,如果你有了正确版本的 Python,首先要做的就是创建一个新的环境,希望代码的开发者已经创建了一个 requirements.txt,其中包含了运行程序的所有依赖项。如果没有,在一些错误消息告诉您缺少哪些包之后,必须逐个安装所需的 Python 包。如果一些包不能通过 Conda 或 Pip 安装,情况会变得更糟。然后,必须费很大力气手动安装它们。因此,可能需要几个小时才能最终运行 Python 程序。这就是 Docker 发挥作用的地方。Docker 希望通过为应用程序创建容器来改善这一点。然后,一个容器包含所有的依赖项和正确的 Python 版本,这样最终用户就可以运行这个容器,而不必担心所有的依赖项。如果他不想再在本地拥有这个应用程序,他可以简单地删除容器。

容器可以被看作是一个独立的环境,它自己的资源运行在主机上。图 1 显示了一个具有三个不同容器的示例设置,其中每个容器运行一个应用程序,每个应用程序在硬盘驱动器中有自己的内存区域,其他容器无法访问(除非您告诉容器共享它们的内存)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 Docker 是什么的概述,灵感来自https://www.docker.com/resources/what-container(图片由作者提供)。

Docker 可以在 Windows、Linux 和 MacOS 上使用。要在 Windows 上安装和运行 Docker,首先必须安装 Windows 子系统 Linux 2。这是一个在 Windows 上运行 Linux 的轻量级虚拟机。在本页阅读更多关于安装 Docker for Windows 的信息。要在 MacOS 上安装 Docker,可以跟着阅读这一页

Github 操作

现在让我们来看看 Github Actions。在介绍中,我说过应用程序的集成和部署应该是自动化的,这样,当执行新的主分支时,应用程序会自动进行测试,然后重新部署。这就是 Github Actions 发挥作用的地方。Github Actions 是一个直接集成到 Github 中的 CI/CD 工具。它允许在检测到 Github 存储库的变化后直接运行测试和预定义的步骤。我真的很喜欢这个直接集成到 Github!这避免了必须处理另一个工具,如 Travis CI。Github Actions 已经有很多例子和库,可以用来快速创建 CI/CD 管道。管道本身被定义为 YAML 文件中的代码。这允许对您的管道进行版本控制,这在您想要恢复到旧版本的情况下是非常重要的。

AWS 弹性豆茎

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 AWS 弹性豆茎概述(图片由作者提供)。

AWS Elastic Beanstalk 是来自 Amazon Web Services 的一项服务,允许轻松部署用 Java、PHP、Node.js、Python、Docker 等编写的应用程序。代码可以简单地上传到 AWS Elastic Beanstalk,它会自动处理诸如容量供应、负载平衡、自动伸缩和应用程序健康监控之类的事情。AWS Elastic Beanstalk 本身使用 EC2 实例来运行您的应用程序,使用 S3 存储来存储数据,但是作为用户,您不必为这些事情费心。你可以简单地上传你的 Docker 图片,AWS Elastic Beanstalk 会帮你处理剩下的事情。

关于如何创建持续部署管道的分步说明

好了,现在你知道了所用环境和工具的基本知识。现在让我们从创建最终的持续部署管道开始。我将经历所有需要的步骤,这样最终你有希望理解所有这些,并且能够将它们应用到你自己的项目中。首先,我将向您展示如何为 Flask 应用程序创建 Docker 映像,以及如何在本地构建和测试容器。然后,我将向您展示如何为 Flask 应用程序创建 AWS 环境。最后,我将指导您创建 Github 动作管道和所有必要的配置,以通过 Github 动作运行持续部署。

步骤 1:创建 Docker 映像

作为第一步,我们必须创建 Docker 图像。为此,我们需要创建一个名为“Dockerfile”的文件。该文件定义了如何使用 Docker 映像设置 Docker 容器的所有必需步骤。代码 1 显示了创建的 Dockerfile 的全部内容。

代码 1: Dockerfile,用于为鸟类分类器 Flask 应用程序定义 Docker 图像(由作者编写代码)。

来自 python:3.9

这一行定义了应该使用的基本图像。基础图像就像是容器的起点。它定义了一些应该安装的基本安装,比如 Python。

工作目录/usr/src/app

这里我们说我们想要使用指定路径上的文件夹作为工作目录。我们现在以后用“T4”时。”,我们总是把这个工作目录称为根目录。

复制。/requirements.txt。/

需求文件现在被复制到 Docker 容器的工作目录中。

运行 pip 安装—升级 pip &运行 pip 安装—no-cache-dir-r requirements . txt

这几行首先升级 pip,然后安装 requirements.txt 文件中列出的所有依赖项。这确保了 Flask ML 应用程序所需的所有包都安装在 Docker 容器上。

添加和复制步骤

在添加步骤中,目录被复制到容器的工作目录中,而 COPY 只复制单个文件,不会保留正确的文件夹结构。application.py 文件包含 Flask ML 应用程序,data 文件夹包含带有所有类名的 csv 文件,model 文件夹包含已训练 Tensorflow 模型,templates 文件夹包含前端 HTML 文件。

曝光 5000

EXPOSE 步骤告诉容器他应该监听端口 5000 上的传入连接和数据。这对于在主机上调用网页和与容器通信是很重要的。

CMD [“python “,” application.py” ]

这一行定义了 Docker 容器启动时要执行的命令。在这里,我们想执行 Flask ML 应用程序,然后启动网页。

既然已经创建了容器的映像,那么让我们也在本地创建容器,并运行它来尝试是否一切都按预期运行。为此,请遵循以下步骤:

  1. 运行docker build-t/<应用程序名称>。在包含 Dockerfile 的目录下的命令行中。使用 -t 标志,您可以标记 docker 容器,以便在以后运行该容器时方便地引用它。 < docker_id > / <应用名称> 只是 docker 的一个命名约定,但是你可以给你的容器加上任何你想要的名字。在我的例子中,我用 ga63qes/flask-ml-app 标记它。还有别忘了“”。“结束了!这告诉 Docker 在当前目录中搜索 Docker 文件。
  2. 当一切都解决了,运行docker run-p 5000:5000****/<应用程序名称> 之后。这将启动您的 Docker 容器,并将您机器上的端口 5000 映射到 Docker 容器的端口 5000。这很重要,因为 Docker 容器监听该端口上的传入连接(如 Docker 文件中所定义的)。

您应该在终端上看到如图 3 所示的输出。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3:启动 Docker 容器后的终端输出(图片由作者提供)。

现在,在浏览器中输入“ http://127.0.0.1:5000 ”即可打开网页。

好吧。现在我们必须做最后一步来完成 Docker 部分。我们必须创建一个 docker-compose 文件,因为 AWS Elastic Beanstalk 将使用这个文件来最终创建和运行 docker 容器。Docker-compose 是一个来自 Docker 的 CLI,用于将多个单个 Docker 步骤合并到一个文件中。只需创建一个“docker-compose.yml”文件,并添加代码 2 中的内容。

代码 2: Docker-compose 文件的鸟类分类器烧瓶毫升应用程序(代码由作者)。

这里,作为构建上下文,Dockerfile 被链接,并且作为根目录,当前工作目录被选择。这意味着“docker-compose.yml”文件必须放在与 docker 文件相同的目录中。此外,端口 80 被映射到容器的端口 5000。这是因为网页将被托管在 AWS Elastic Beanstalk 上,默认情况下在端口 80 上监听传入的连接,而创建的容器在端口 5000 上监听。

现在,您还可以通过在包含 docker-compose 文件的目录中运行以下步骤来检查 docker-compose 文件是否正常工作:

  1. 运行 docker-compose build 来构建 docker 容器。
  2. 运行docker-组合来运行 Docker 容器。现在,您应该能够通过在浏览器中输入“http://127 . 0 . 0 . 1:80”连接到该网页。重要提示:您现在必须使用端口 80 而不是 5000,因为我们将这个端口映射到容器的端口 5000。

呸,太多了!但这是最重要的部分!现在,应用程序可以在每台安装了 Docker 的机器上执行。因此,没有人需要首先手动安装依赖项和设置环境。

步骤 2:创建一个 AWS 弹性 Beanstalk 应用程序

第二步,您首先需要创建一个 AWS 帐户。这个账户本身是完全免费的,但是你必须给你的账户添加一张信用卡。创建账户后,你可以进入 AWS 起始页,在搜索栏中搜索“AWS Elastic Beanstalk”。然后,您可以点击“创建应用程序”。选择您想要创建一个 Web 应用程序,然后您应该会看到如图 4 所示的窗口。您可以添加所需的信息。在我的例子中,我还必须打开“配置更多选项”并选择其他实例类型,因为默认实例类型(t2.micro 和 t2.nano)对我的应用程序来说内存太少。然后我选择了实例类型 c5d.2xlarge 和 c5a.2xlarge。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 AWS 弹性豆茎应用程序的设置(图片由作者提供)。

当您添加了所有必需的信息并选择了正确的实例类型后,单击“创建应用程序”。您的应用程序应该需要几分钟才能设置好并准备好运行。当您的环境完成后,您应该会看到类似于图 5 的内容,您可以开始使用您的应用程序了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5:已经可以使用的 AWS 弹性 Beanstalk 环境(图片由作者提供)。

然后您可以点击环境,一个新的窗口将会打开(图 6)。此窗口包含到您的网站的链接。部署应用程序后,可以与最终用户共享这些信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6:在 AWS Elastic Beanstalk 中创建的应用程序的环境窗口(图片由作者提供)。

你也可以在这里直接上传申请。这有助于查看 Docker 容器是否在 AWS 上正常运行。为此,您可以选择文件夹中所有相关的文件夹和文件,并将它们放入 zip 文件夹中。重要的是,在打开文件夹后,Dockerfile 和 docker-compose 文件位于根目录下。

好了,接下来的步骤只需要在你想继续用 Github 动作自动部署应用程序的情况下完成。为此,我们首先必须在 AWS 中创建一个用户,允许他将代码部署到创建的 Elastic Beanstalk 应用程序中。为此,在 AWS 搜索栏中搜索“IAM ”,然后单击“Users”和“Add users”。然后你可以添加一个用户名(在我的例子中是 birds-classifier-api)并选择“访问键-编程访问”。点击“Next: Permissions”并选择如图 7 所示的选项。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 7:允许将应用程序部署到创建的弹性 Beanstalk 环境的 IAM 用户设置(图片由作者提供)。

然后,您可以一步一步地完成 IAM 用户的设置。创建用户后,您将看到一个“访问密钥 ID”和一个“秘密访问密钥”。您将需要这些用于您的 Github repo,稍后将在那里推送代码。将它们下载为 CSV 文件,以便您以后可以访问它们。然后进入你的 Github repo,点击“设置”,导航到“秘密”。这里您必须添加图 8 中的两个变量。作为值,您可以插入在 AWS 中创建的用户的值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 8:自动将新的应用程序代码部署到 AWS Elastic Beanstalk 需要添加的存储库秘密(图片由作者提供)。

第三步:创建 Github 动作文件

现在我们终于到了最后一步。我们现在可以创建包含代码的 YAML 文件,告诉 Github Actions 每当执行 master 上的 push 时,它应该自动构建 Docker 容器并将其部署到 AWS Elastic Beanstalk 应用程序。如果你不熟悉 Github 动作,那么我可以向你推荐这个关于如何使用 Github 动作的 Youtube 教程。代码 3 显示了创建自动部署的完整代码。该文件必须在名为“”的文件夹中创建。github/workflows”被 Github Actions 认可。

代码 3:定义 Github Actions 持续部署管道的 YAML 文件(作者代码)。

在第 16 到 18 行中,定义了 checkout。我还添加了 git lfs checkout,因为我将我的存储库配置为 git lfs repo,以便有效地存储我的大型 Tensorflow 模型。在这里阅读更多关于 git lfs 的内容

该管道的不同阶段在结帐后定义。每个新阶段以“ - ”和阶段名称开始。关键字“使用”表示加载并使用了另一个用户的库。

构建 Docker 映像

在这个阶段,Docker 映像被构建。这是为了确保在将 Docker 容器部署到 AWS Elastic Beanstalk 之前,构建 Docker 容器的一切工作正常。

生成部署包

在这个阶段,repo 的内容被压缩,因为 AWS Elastic Beanstalk 需要上传一个包含应用程序和 docker 文件的压缩文件夹。

获取时间戳

这里加载了当前时间戳。这随后用于向新部署的应用程序添加版本。

运行管柱更换

这个阶段获取时间戳,并应用一些格式将其转换成一种良好的格式。

部署到 EB

在最后一个阶段,通过使用之前创建的 AWS 用户凭证和所创建环境的一些必需信息,最终将压缩的应用程序文件夹部署到 AWS Elastic Beanstalk。关于环境的所有必需信息都可以在图 5 中找到。

现在,您可以将这个创建的 YAML 文件推送到 Github,并在浏览器中打开您的 repo。然后,您可以导航到“Actions”选项卡,您应该会看到一个正在进行的构建。构建完成后,您应该会看到类似于图 9 的内容。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9:完成的 Github 动作构建管道的示例视图(图片由作者提供)。

因此,现在无论何时在主服务器上执行推送,应用程序都会自动重新部署到 AWS Elastic Beanstalk。这太棒了!机器学习工程师现在不必再为部署而烦恼了。

现在,您可以使用 AWS Elastic Beanstalk 环境中提供的 web 链接导航到创建的网页。你可以看看我的情况:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Gif 1:如何在 AWS 部署的网页上打开的示例(图片由作者提供)。

重要提示:我建议最后删除在 AWS 上创建的应用程序,以避免产生成本。我删除了我的资源,因为我还有更大的实例类型,并且已经为我的应用程序支付了一些费用。因此,当您现在查看我的 Github 操作结果时,您可以看到我的最新构建在部署阶段失败了。

未来的工作

目前只使用默认的 Flask 服务器,它应该只在开发期间使用,而不在生产中使用(如图 3 中的命令行输出所示)。所以当你真的想把你的 Flask 应用程序投入生产时,我会推荐你阅读 Flask 的这篇文章。

结论

现在您已经看到了这样一个自动化部署管道的样子。你也知道 Docker 的优点,以及如何使用 Github 动作。现在是时候实施您自己的机器学习项目并考虑部署了!

谢谢你把我的文章看完!我希望你喜欢这篇文章和我参与的项目。如果你想在未来阅读更多类似的文章,请关注我,保持更新。

接触

LinkedIn|Github

连续科学

原文:https://towardsdatascience.com/continuous-science-6b5ed833ab23?source=collection_archive---------41-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

约翰·施诺布里奇在 Unsplash 上的照片

业内笔记

软件工程实践如何解决科学再现性

这篇文章是关于通过实施现代软件工程实践来提高计算生物学的可重复性和生产率。

我写这封信是因为很明显,科学界正变得越来越依赖公共软件解决方案——这些解决方案可以通过在软件工程中大量投资不断发展但令人兴奋的解决方案而得到更好的支持。

介绍

计算生物学家花在基准测试和评估代码上的时间比他们写基本功能的时间还多。

幸运的是,我们的软件工程师面临许多类似的问题,并且已经开发了无数的解决方案来确保软件在其生命周期内继续良好运行。

持续集成和持续交付(CI/CD) 是这些解决方案的顶峰,允许敏捷软件开发社区中的软件开发人员比以往更快、更安全地交付解决方案。

CI/CD 是一种文化和实践的集合,可以为科学界提供大量的东西。

在过去的一年里,我作为一名数据科学家,在与经验丰富的行业软件开发人员一起工作的同时,构建生物信息管道并对其进行基准测试。在此期间,我越来越清楚地认识到,在科学计算领域引入 CI/CD 或类似的系统可能有很多好处。

我称之为“持续科学”,它提供了一个机会,通过数据驱动的科学来提高再现性、减少浪费并加速我们的集体理解。

科学软件当前面临的挑战

众所周知,现代科学正面临一场再现性危机,科学软件也不例外。

虽然复制一篇已发表的论文通常很困难,但复制计算尤其难以实现。通常,科学家必须检索现有解决方案的所有开放源代码、所有数据输入和所有数据输出,然后才能与他们的新提案进行比较。

检索所有这些资源不仅是一项困难而漫长的任务,而且由于数据的不良记录、有限的代码共享或版本控制以及缺乏以不同编码语言实现的现有解决方案的专业知识,这通常是不可能的。

再现性的挑战严重地影响了个人,因为它减缓了他们的研究,并耗费了他们必须花费在验证软件完整性上的宝贵时间。

然而,公共效应更严重,因为这减缓了领域的进展,阻碍了蛋白质组学等重要科学领域的进展。

不幸的是,所有这一切意味着像我这样编写科学代码的人往往会花更多的时间来尝试实现算法和代码之间的有效比较,而不是构建新的令人兴奋的解决方案。

当我们考虑到全球实验室之间发生了多少重复工作时,这是令人难以置信的浪费。

此外,如果工具构建者很难进行比较,那么很可能几乎不可能相信像生物学家这样的用户能够被恰当地告知他们正在使用的工具。

输入 CI/CD 和连续科学的发展(双关语)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Unsplash科学高清拍摄的照片

什么是持续集成/持续交付,为什么我们需要这样的东西?

CI/CD 是一种软件工程文化,围绕着随着新解决方案的交付而自动检查代码的任务而构建。这意味着代码可以随时更新,工程师可以确信,无论代码发生多大的变化,它都会运行良好。

我将用一个类比来解释这一点——我爱我的 Fitbit。

我用它来跟踪对我的健康有意义的指标,比如我每天的步数和我的平均心率。当然,我的 Fitbit 从来不会强迫我锻炼,但当我的好习惯开始消失,我需要更多外出时,它就变得非常明显。

自动跟踪某些东西的状态,如身体的健康状况或代码的健康状况,因为它会发生变化,这使得维护它并保持在您的目标的轨道上变得更加容易。代码健康是真实的,因为随着时间的推移,算法可能会失去与常见输入格式的兼容性,或者在编辑时变得杂乱无章、错误百出。就像身体健康一样,如果没有得到适当的照顾和监控,算法和工具也会随着时间的推移而失去优势。

在 Mass Dynamics,我见过托管服务器应用 CI/CD,详细说明如何在每次更改代码时运行和测试代码。通过这样做,我们能够自动获得我们的代码在任何时候都工作的信心。如果检查不是自动的,我们不可能保持它的健康。

相比之下,在科学界,我们看到一个非常不同的场景。

虽然许多科学工具都很棒,但每年构建的新算法/工具的数量不仅通过不断的比较和评估为开发人员社区创造了工作,也为用户区分哪些工具最适合他们的需求创造了工作。

一个复杂因素是,许多工具不能自动运行,另一个复杂因素是,即使对于相同的科学问题,它们也经常采用不同的输入,产生略有不同的输出,这使得比较变得困难。

这意味着对新方法的信心是缓慢的,并且是由构建基准测试脚本的个体社区成员辛苦获得的(这些脚本本身发布的频率低于工具代码本身)。通常,这些脚本的结果是惊人的论文,讲述了一个创新解决方案的故事,但这些努力是重复的(通常它们本身很难比较)。

回到健康类比,科学软件工具可能是健康的,但我们只知道这一点,因为我们支付了偶尔复杂的医疗评估——或更糟——手术!

知道哪些科学工具起作用应该不难。不难知道哪种科学工具更适合给定的用户或问题。

那么我们如何解决这个问题呢?我们如何减少科学开发人员创建和测试新解决方案所需的时间和精力,同时确保该软件的消费者对其使用充满信心?

持续科学解决方案

为了更好地阐述我提出的解决方案,我画了一个图形,希望它能传达出持续科学概念的模块化和优雅。

图 1 显示了如何将数据集、算法和评估指标全部模块化,并在单个服务器上运行。这个服务器可以是一个公共的、透明的资源,以显示给定计算挑战的进展。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1:作者的原始数据(约瑟夫·布鲁姆)

具体来说,连续科学服务器可以通过共享基础设施和公共数据格式来工作,以允许使用公共数据集和公共基准对算法进行相互比较。数据集、算法和基准都可以独立提交,但被一个共同的问题联系在一起。应该公开列出每个算法在指标和数据集上的性能。

虽然 CI/CD 强调检查代码的健康状况,但 Continuous Science 可以在公共基准和数据集上评估算法性能,这些基准和数据集对社区是透明和可访问的。

如果社区能够走到一起,就解决个别问题(如蛋白质推理问题)的算法的通用格式和基准达成一致,那么合乎逻辑的下一步将是建立公共服务器,在所有提交的算法和数据集上执行这些基准。

结果可以实时显示在网站上,这些解决方案的用户可以浏览,就像一个科学健康的仪表板。

此外,建立包含数据、算法和评估指标模块的管道的一个好处是,我们可以使解决方案民主化。如果一个新的解决方案在一个新的、合法的、但以前没有预料到的指标或数据集类型上表现良好,那么可以将它们提交给工具,并由所有人来审查结果。

一个类似的令人敬畏的概念的例子是 Kaggle ,这是一个数据科学竞赛平台,人们可以提交数据问题,并设置基准以与提交的答案进行比较。数据科学家通过提交不同算法的结果来竞争。

虽然“Kaggle”有一种连续的味道,因为每个上传的结果集都会被自动评估以检查解决方案的质量,但连续科学在众包测试数据集和评估指标方面走得更远。

可能的挑战和希望的理由

想法往往在一开始就不切实际。考虑到我最近工作过的一些领域,一些迫在眉睫的挑战跃入脑海。

这些是:

  1. 最流行的解决方案必须是开源的,这样社区才会关心比较的结果。
  2. 要使运行状况检查自动化,解决方案必须是自动化的。
  3. 解决方案必须共享共同的输入和输出,以便进行公平的比较。

最终,为了克服这些技术挑战,我们需要在可扩展解决方案的开发上进行开放和诚实的分享和合作,这与资助系统可能强加给我们的竞争文化相反。

尽管研究人员被迫竞争资金,但科学家们共同努力创造了许多倡议,以提高科学的可及性和透明度。

尤其是,将“开放科学作为解决可复制性危机的驱动力令人振奋。创建公平数据(可发现、可访问、可互操作和可重复使用)的努力正通过像本文这样的论文进入蛋白质组学这样的高科技领域,它清楚地表明了全球共同的善意和共同的愿望,即减少研究的竞争,加强合作。

一个竞争更少、合作更多的研究社区正是那种可以通过持续的科学来分担维护我们算法健康的责任的社区。

总之:

可复制性危机是真实的,我们可以从令人敬畏的软件开发文化中获得灵感来帮助我们解决它。

通过“持续科学”服务器跟踪和比较我们算法的健康状况的公共努力,可以解决科学中软件的可再现性和可访问性,就像我们用健康设备跟踪和维护我们身体的健康,用 CI/CD 服务器跟踪和维护我们的代码一样。

这些公共资源可以加速同行的共识和标准化,就像开源更广泛地影响了技术世界一样。

将 CI/CD 文化引入科学是未来之路。它将为科学开发人员提供一个公共资源,用于维护和比较支持非计算科学家做出有益于所有人的发现的解决方案。

如果你觉得这篇文章有趣,我很乐意与你讨论。你可以在 joseph@massdynamics.com 找到我。

非常感谢我所有了不起的同事和朋友们,他们编辑了这篇文章并给了我反馈!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

国立癌症研究所Unsplash 上拍摄的照片

机器学习系统的连续测试

原文:https://towardsdatascience.com/continuous-testing-for-machine-learning-systems-a8519eede545?source=collection_archive---------21-----------------------

通过 ML 产品生命周期验证机器学习系统的正确性和性能。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

托尔加·乌尔坎在 Unsplash 上拍摄的照片

目录

机器学习系统中的测试

软件行业中的测试是一个经过充分研究的成熟领域。从不计其数的失败项目中吸取的好的实践帮助我们频繁地发布,并且有更少的机会看到产品中的缺陷。像 CI、测试覆盖和 TDD 这样的行业惯例被很好地采用,并为每个项目量身定制。

然而,当我们试图将 SWE 测试哲学借用到机器学习领域时,我们必须解决一些独特的问题。在这篇文章中,我们将讨论 ML 模型(系统)测试中的一些常见问题,并讨论潜在的解决方案。

ML 系统在这里代表一个生成可供用户使用的预测(洞察)的系统(管道)。它可能包括一些机器学习模型。例如,OCR 模型(系统)可以包括一个用于检测文本区域的 ML 模型、一个用于判断当前文本区域类别的 ML 模型(汽车牌照与路标)以及一个用于从图片中识别文本的模型。

ML 测试的范围

模型由代码(算法、预处理、后处理等)、数据和促进运行时的基础设施组成。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ML 系统测试的范围,图片由作者提供

不同类型的测试涵盖了系统不同组件的质量保证。

数据测试:确保新数据满足你的假设。在我们训练模型和进行预测之前,需要进行这种测试。在训练模型之前,X 和 y(标签)

管道测试:确保你的管道设置正确。这就像 SWE 中的集成测试。对于 ML 系统,它也可以测量一致性(再现性)。

模型评估:评估你的 ML 管道有多好。取决于您使用的指标和数据集,它可能指不同的东西。

  • 对维持/交叉验证数据集的评估。
  • 部署管线和地面实况的评估(连续评估)。
  • 基于系统用户反馈的评估(与业务相关的指标,而不是可测量的 ML 代理)

有许多技术可以应用于该过程,如基于切片的评估、MVP(数据的关键子集)组/样本分析、消融研究、基于用户分组的实验(如 Beta 测试和 A/B 测试)。

模型测试:包括对我们期望模型遵循的行为的明确检查。这种类型的测试不是为了告诉我们与准确性相关的指标,而是为了防止我们在生产中出现不良行为。常见的测试类型包括但不限于:

  • 不变性(扰动)测试:输入的扰动不影响模型的输出
  • 方向性期望测试:为了实现我们的应该对模型输出有一个可预测的效果。例如,如果手术中失血量增加,输血量也应该增加。
  • 基准回归:使用预定义的样本和精度门来确保模型版本不会引入疯狂的问题。
  • 过度拟合(记忆)测试:尝试用整个数据集的一小部分来过度拟合模型,并确认模型是否能够记忆数据。

我们什么时候进行不同类型的测试?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们什么时候进行测试?作者图片

有些人可能会问,为什么我们需要使用维持评估和持续评估来衡量 CI 和服务时间方面几乎相同的指标。

一个原因是,我们无法通过查看预定义维持数据集的指标来全面评估模型性能,因为数据泄漏有时比看起来更难检测。例如,一些预期在服务时间内存在的特征被证明具有获取的高延迟,因此我们的训练模型不能习惯于看到该特征总是为空。

有时模型评估可能非常昂贵,因此将全周期维持评估集成到 CI 中是不可行的。在这种情况下,我们可以在 CI 中定义一个子集回归评估,并且只在重要的里程碑之前进行完整的评估。

模型测试不是一次性的步骤,相反,它应该是一个与自动化设置持续集成的过程。一些测试用例可以在 CI 过程中执行,所以每次代码提交都会触发它们,我们可以保证 repo 的主要分支中的代码/模型质量。其他的可以在服务环境中进行,所以我们不会对系统的性能视而不见,当我们有问题时,我们可以有相对充足的时间来解决问题。有时,服务环境中正在进行的测试可以被视为监控组件的一部分,我们可以与警报工具集成以结束循环。

结论

机器学习系统不容易测试,不仅因为它包括更多要验证的组件(代码+数据),而且它具有动态性。虽然我们没有改变任何东西,但我们的模型可能会因为数据变化(数据漂移)或事物的本质随着时间的推移而变化(概念漂移)而变得陈旧。

自动化测试是 CI / CD 中的一个重要组成部分,用于以较小的占用空间验证管道的正确性。虽然在我们说一个新的 ML 流水线已经可以生产之前,手工测试和人在回路中的验证仍然是至关重要的步骤。管道投产后,持续的监控和评估可以确保我们不会盲目行动。最后,基于客户反馈的测试(即 A/B 测试)能够告诉我们,我们试图解决的问题是否真的有所改善。

在 ML 系统测试中没有银弹,持续地尝试覆盖边缘情况将帮助我们减少犯错误的机会。希望有一天我们能找出一个简单的度量标准,比如代码覆盖率,来判断我们的系统是否足够好。

参考:

对比对比学习方法

原文:https://towardsdatascience.com/contrasting-contrastive-learning-approaches-c3eab8a4728c?source=collection_archive---------17-----------------------

思想和理论

深入探讨哪些计算机视觉任务是很好的基准,数据集如何影响模型性能,以及哪种编码器是最好的通用主干。

链接:Github论文

近年来,我们看到了计算机视觉领域新的自我监督学习方法的爆炸式增长——研究人员已经成功训练了神经网络,这些网络在公共基准上表现非常好,如使用大部分未标记数据的 ImageNet 分类。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图文由温森韩

事实证明,理解是什么使一幅图像与其他图像不同,就足以产生该图像的抽象表示,这种表示可用于现实世界的任务,如语义分类。这种方法的早期成功引发了大量描述这一主题的变体的出版物,这些变体彼此之间都有微小的改进。

我们现在有诸如 PIRLCPCSimCLRMoCoSwAV 等方法,这些方法都使用一种称为对比学习的特定类型的自我监督学习来产生显著的结果,在对比学习中,编码器被训练来识别同一图像的稍微视觉增强版本,因为它们彼此相似,而与其他图像不同。

虽然这种爆炸性的研究速度对于推进一个新的想法很有帮助,但它也产生了许多难以比较或整合的独立线索。在这篇博客中,我想谈谈自我监督的计算机视觉研究的现状和我最近发表的一篇论文的问题,以及旨在解决其中一些问题的论文Gabriel IlharcoLudwig SchmidtKiana EshaniRoozbeh Mottaghi

在我们深入探讨之前,让我们快速回顾几个关键术语,以及我将如何在本文中使用它们:

***预训练算法:*虽然术语“预训练算法”在深度学习中的定义相当松散,但在这篇文章中,我将使用它来描述最近流行的作品(如 MoCo 和 SwAV)提出的整个预训练管道。

***预训练数据:*这是用于计算机视觉编码器自我监督预训练的数据集。大部分作品为此使用 ImageNet。

***编码器:*在计算机视觉中,我们通常将我们的网络分为两个组件:通用特征提取器,它将图像的原始像素数据编码为有用的抽象表示;以及终端任务网络,它使用该抽象表示来完成一些现实世界的任务。前者就是我在这篇博文中所说的编码器。

***终端任务网络:*如上所述,终端任务网络是我们的模型的一部分,它被定制来执行特定的现实世界任务,如图像分类,因此它必须针对每个任务分别进行调整。

***结束任务:*结束任务是我们的模型可以执行的一些有用的任务。通常,这些都是实际的事情,比如从图像中估计房间的深度或者对狗的品种进行分类。最终任务是一种将我们的抽象模型与现实世界的工作联系起来的方式,人们可以从中受益。

***终端任务数据:*这是与特定终端任务相关联的训练数据集,用于训练终端任务网络对编码器产生的抽象图像表示做一些有用的事情。

所以总而言之,像 SwAV 这样的预训练算法使用一个预训练数据集来训练一个编码器,这是一个从图像中提取抽象表示的通用工具。结束任务网络然后在结束任务数据上被训练,以使用这些抽象表示来执行一些有用的现实世界结束任务

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图表来自对比自我监督对比模型

既然我们都已经掌握了术语,让我们深入探讨一下自我监督视觉领域的快速创新带来的几个关键问题。

1。苹果、橘子和香蕉

虽然各种建议的训练算法都试图创建良好的通用图像编码器,但它们共享非常少的兼容数据点,这意味着将该算法应用于完全相同的模型架构,使用完全相同的端点使用完全相同的预训练数据。

像这样的完全匹配的数据点集合通常会减少到只有一个:使用在 ImageNet 数据上训练的 ResNet50 的 ImageNet 分类性能。虽然这是一个很好的基准,但如果它是我们唯一关心的基准,它可能会变得极其危险。除此之外,不同的论文提供了最终任务、预训练数据集和模型架构的非重叠子集的结果,因此比较不同论文之间的数字常常会导致比较苹果和橙子。

2.我们到底在追求什么?

由于 ImageNet 分类是大多数计算机视觉社区可以同步并达成一致的唯一基准,因此似乎真正追求的目标不是生产一个好的通用图像编码器,而是生产一个在 ImageNet 分类上表现良好的编码器,以及类似的最终任务。在某种程度上,任何开发新算法的研究人员都被迫追求这一基准,因为高分将给予算法更多的关注,但这无意中导致社区优化“ImageNet 性能”的代理目标,而不是“良好的视觉编码器”的真正目标。结合大多数论文使用 ImageNet 作为训练数据的事实,我们有一个强大的反馈回路的配方,该反馈回路产生擅长学习数据集(如 ImageNet)的底层分布统计的编码器,而不是擅长理解图像中的内容。

我们的工作

希望这足以让你相信,在自我监督的计算机视觉领域存在着重大的不一致。现在让我们谈谈解决这些问题的方法。具体来说,我将谈论我最近的论文对比对比自我监督表示学习模型的方法和发现。

为了获得一个标准化的参考框架来比较各种自监督算法和预训练数据集,我们必须固定许多实验变量。我们所有的测试都是使用相同的编码器架构(ResNet50)完成的。在训练终端任务网络时,我们还冻结了编码器的权重。

尽管冻结了这些变量,我们仍然使用数千小时的 GPU 时间运行了 700 多个实验。我们在 4 个不同的预训练数据集( ImageNetPlacesTaskonomyKinetics400 )和 4 个组合上测试了由 4 个不同的预训练算法( SwAVMoCo v1MoCo v2PIRL )产生的总共 30 个编码器。我们在 20 个最终任务训练集上为每个编码器训练了最终任务网络,并报告了这些编码器在最终任务测试集上产生的结果(参见下面的最终任务图)。

更多详情请参考文件

现在让我们深入研究结果…

ImageNet 是一个好的基准吗?

如上所述,在 ImageNet 分类结束任务中评估在 ImageNet 数据集上训练的模型似乎是相当循环的。为了衡量这一指标的好坏,我们对 ImageNet 上编码器的性能和其他终端任务进行了相关性分析。这意味着,对于任何给定的编码器,我们计算了 ImageNet 上的性能与其他终端任务的性能之间的关系。我们发现 ImageNet 根本不是一个很好的指标。虽然它在预测类似任务(如加州理工学院和 CIFAR-100 分类)的性能方面相当不错,但在预测不同任务(如深度预测)的性能方面确实很差。

我们根据任务类型(语义或结构)和输出形式(图像级或像素级)将任务大致分为四类。下面是我们所有最终任务及其相应分类的图示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自对比自我监督对比模型的图形

下图描绘了 ImageNet 分类准确性与其他终端任务性能的关系。它说明了 ImageNet 性能对于其他图像级语义任务是一个很好的指标,但是对于所有其他终端任务类别是一个很弱的信号。此外,我们甚至看到一些负相关的结果,表明将编码器调优为非常擅长 ImageNet 分类会导致它忽略一些对其他任务类型至关重要的信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来自对比自我监督对比模型

总而言之,这表明仅报告模型的 ImageNet 分类性能是非常有限的。

所有预训练数据集都是平等的吗?

我们想探索的另一个领域是预训练数据对最终模型的质量有多大影响。由于这个领域的绝大多数工作都是在 ImageNet 上预先训练他们的编码器,所以在这个轴上没有太多的探索。我们在 4 个数据集上训练了 MoCo v2 和 SwAV 编码器:ImageNet、Places、Taskonomy 和 Kinetics400。我们对所有数据集进行子采样,以匹配 ImageNet 的大小,并对 4 个数据集的组合进行了训练。

首先,我们发现在 ImageNet 上训练的编码器倾向于最好地解决语义终端任务,而在 Places 上训练的编码器倾向于最好地解决结构终端任务。这很有意义,因为 ImageNet 包含许多不同的图像,而 Places 包含房间和建筑物的图像。此外,Places 和 ImageNet 都对数据进行了策划、标记和组织,而 Kinetics 是从 youtube 视频中捕获的一系列帧,Taskonomy 是一系列 Matterport 3d 扫描。这表明,尽管我们没有明确使用标签,但使用一个整洁有序的数据集仍然可能有一些优势。这就对在来自互联网的随机完全无监督数据上训练视觉模型的可行性提出了质疑——这是自我监督计算机视觉的伟大承诺之一。虽然最近的一些工作显示了在从互联网上收集的大型数据集上进行训练的成功,但尚不清楚这些数据有多干净和有组织。

其次,我们测试了在类似于我们的终端任务数据的大型数据集上使用自我监督方法预训练我们的编码器是否会产生更好的编码器。对于我们的每个预训练数据集(ImageNet、Kinetics、Places 和 Taskonomy),我们找到了使用相似数据集或相同数据集的子集(分别为加州理工学院分类、Kinetics 动作预测、太阳场景分类和 Taskonomy 深度预测)的相应最终任务。我们绘制了我们在以下 4 个数据集上训练的所有编码器的最终任务性能:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自对比自我监督对比模型的图形

这个结果对于监督学习来说有些明显,但是在我们的工作中,我们也验证了它对于对比学习也是成立的。有趣的是,我们发现组合数据集平均产生的编码器在所有任务中都相当好,但在任何任务中都不是最好的。事实上,我们还发现,在 ImageNet 和 Places 上训练的编码器平均性能优于组合编码器,因此混合数据集给我们带来的好处似乎少于缺点。

数据集平衡重要吗?

除了上面提到的预训练数据集,我们还使用 ImageNet 的非平衡版本测试了预训练的效果,我们通过对每个类别中的图像数量进行对数采样来产生该非平衡版本(例如,我们从几个类别中获得许多样本,从许多类别中获得少量样本)。我们发现,如果我们在 ImageNet 的严重不平衡的子集上预训练我们的编码器,我们的最终任务性能不会比在相同大小的 ImageNet 的完全平衡的子集上预训练差。我们测试了每个数据集的 3 个不同样本,没有非常大的差异,这表明所有子采样都一样好,并且如果我们从子样本中的特定类获得许多样本,没有神奇的类会为我们提供巨大的性能提升。为了稍微破坏这一发现的兴奋,重要的是要提到我们只使用了 200 个时期训练的小数据集(250,000 个样本),因此需要进一步的工作来验证更大数据集和更长训练运行的这一趋势。

不同的预训练算法是否表现出不同的实力?

我们详细描述的两种训练算法是 MoCo v2 和 SwAV。虽然不是我们工作的主要焦点,但我们的分析提出了两种算法的一些有趣的对比特性。

MoCo v2 往往更擅长于结构性任务,而 SwAV 在图像级任务上表现出色。关于为什么会发生这种情况,我的高层次假设是,由于 SwAV 在最后一层使用聚类方法,它往往会丢失一些空间图像信息。这个理论的一些支持来自我们对编码器进行的分层 CKA 分析的结果。我们发现,平均而言,用 MoCo v2 训练的编码器在早期和晚期层表示之间具有更强的一致性,这表明在最终编码中保留了更多的空间信息。下图展示了 MoCo 和 SwAV 编码器在像素级和图像级任务中的性能差异:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来自对比自我监督对比模型

如果我们试图为需要空间信息的任务构建自定义编码器,这可能是一个有用的数据点,因为我们现在有证据表明 MoCo v2 是这项工作的更好的预训练算法。在这里,我们看到了将 ImageNet 分类性能作为我们的基准的另一个缺点。由于 SwAV 在这一特定的最终任务上优于 MoCo v2,许多人可能会认为它总体上更好,而我们的研究表明现实并不是如此清晰。

自我监督编码器对所有下游任务都有用吗?

简单来说,答案是肯定的。对于我们测试的每个任务,自我监督模型都表现得非常好,事实上,除了 3 个任务,它们都优于监督的 ImageNet 基线。受监督编码器表现较好的 3 个最终任务是 ImageNet 分类、ImageNet v2 分类和 Pets 分类(与 ImageNet 非常相似)。由于我们没有为手头的任务微调编码器,这个结果一点也不奇怪,因为在 ImageNet 上训练的监督编码器在编码器训练期间有效地微调了任务。对于其他一切,自我监督的方法表现更好,这给了我们一个强烈的迹象,他们产生更好的通用编码器。

此外,我们发现一些终端任务从使用自我监督模型中获得了比其他任务更大的提升,即结构性任务。下图显示,虽然一些自监督编码器在每个任务类别中都优于监督基准,但几乎所有的自监督编码器在结构化任务方面都优于监督基准,甚至那些预训练数据集和预训练算法与最终任务不匹配的编码器也是如此:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来自对比自我监督对比模型

那么我应该使用什么编码器呢?

在考虑了所有上述结果之后,很明显当前的标准计算机视觉编码器(在 ImageNet 上用监督学习训练的 ResNet50)通常不是最好的通用编码器。我们发现,一些经过自我监督学习训练的编码器在解决最终任务方面几乎总是更好,并且一个特定的编码器(在 ImageNet 上经过 SwAV 训练)在超过 75%的最终任务方面更好。

下图显示了自监督模型相对于监督 ImageNet 的相对改进水平。它还表明,ImageNet 和 Places 往往是实现上述最佳结果的两个数据集。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来自对比自我监督对比模型

更多未回答的问题

虽然我们在工作中进行了 700 多次实验,但我们只描绘了自我监督计算机视觉整体前景的一小部分。为了获得我们所做的详细结果,我们需要修正许多变量,这给我们留下了许多未解决的问题,例如:

  1. 模型架构如何影响不同自监督算法的性能?
  2. 微调整个编码器会显著影响性能吗?
  3. 如果我们为更多的时代训练编码器,我们观察到的趋势会消失还是变得更明显?

这些都是未来工作的良好起点,将进一步帮助我们理解自我监督计算机视觉的优点和缺点。

结论

虽然这篇博文指出了自我监督视觉领域当前工作的许多缺陷,但庆祝它的许多成就也很重要。我们的论文发现证据表明,对比学习方法在产生良好的通用编码器方面优于监督学习,进一步验证了这不仅仅是一个巧妙的技巧,而是一个真正的重要进步。然而,我们也已经表明,在单一维度(ImageNet 分类)中衡量进展可能会导致我们忽略更大画面的某些部分(比如 MoCo v2 在我们测试的近一半最终任务中优于 SwAV 的事实)。

总之,我想从这项工作中提供 4 个关键的收获,可能对计算机视觉研究人员和工程师未来的计算机视觉项目有所帮助:

  1. 自监督图像编码器是伟大的通用特征提取器,你应该考虑在你的下一个项目中使用它。我会推荐一个 ResNet50,在 ImageNet 上用 SwAV 训练 800 个历元(或者 Places,如果你的项目是结构化的)
  2. 如果您的领域中有大量的数据,考虑用它来训练一个自我监督的编码器,因为这可能会给您带来更大的性能提升。
  3. 如果你正在开发一个新的自我监督模型,确保在各种各样的任务上对它进行评估。考虑使用我们在项目中发布的 ViRB 代码库。
  4. 如果您正在开发一个新的数据集(或训练 webly 监督模式),您的数据类的平衡可能不那么重要,但拥有一些不同的样本是重要的。

对增长的贡献—分解百分比变化的 SQL 框架

原文:https://towardsdatascience.com/contribution-to-growth-a-sql-framework-for-breaking-down-percent-change-d0573e0f7d7?source=collection_archive---------14-----------------------

现在你终于可以回答:“每个资产/组件/模因对整体百分比变化的贡献是多少?”

这是一个非常基本的概念,我想知道其他人是否已经知道了,那天的数学课我一直在睡觉。但后来我想起,如果我只是想通了这一点,可能还有其他人和我处于同一浪潮中。如果他们和我在同一个波段上,那就意味着他们可能顺便来看看我,别挡我的路,傻瓜🤙🏾 🌊

话虽如此,这是一个非常简单的框架,但我觉得最简单的框架是最强大的,因为即使对那些没有强大数据背景的人来说,它们也是直观的。

我经常面临一个非常常见的分析难题——假设给定的指标有很大的百分比变化。也许你的股票投资组合上涨了 200%。为了这个例子,让我们说业务收入,因为如果有一件事每个人都关心,那就是面包。

通常情况下,第一个问题是“每只资产/组件/meme 股票对整体的百分比变化贡献多少?”

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个可能让你挠头的增长图表的例子。除非另有说明,所有图表均由作者绘制

如果你有多种收入来源,那么通常的第一步是查看不同收入来源的收入,然后查看每个收入来源与前一时期的百分比变化。

我在这里提供了一些我自己公司的例子,亲爱的(这些数字是随机的,不能以任何方式反映现实)。我们有几个附属合作伙伴(也编辑和随机化)提供了我们的大部分收入。这里的每个缩写代表一个附属合作伙伴

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按合作伙伴列出的与前 3 个工作日平均值相比的百分比变化

我们可以开始看到哪些合作伙伴增加了或减少了——百分比方面

这很好,但假设你有一些小土豆,它们波动很大,但对整体变化没有任何实际影响。以 IA 为例,在上图中👆🏾与前几周相比,12 月 12 日的百分比有大幅增长,但如果我们看一下每日总收入👇🏾内部调查甚至没有记录为一个信号。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每日收入的总值给了我们一个权重应该是多少的概念

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自的 meme know your meme

我们可以使用一些心理体操来说,哦,让我们只考虑大型网络的运动,以确定它如何影响总数,但这不是我们的分析能力。

我们如何更好地沟通?

我从这里借用的概念被称为对增长的贡献,这是一个最常用来衡量不同行业或 GDP 组成部分对前一时期整体增长或收缩的影响的指标。
有了下面的这个可视化,也许我们可以看到它对我们的难题的应用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自 OECD 的图片

每个条形图表示“对增长的贡献”,或组件带动总体增长的百分点数。因此,在 2016 年第 2 季度,我们可以看到私人消费比上一时期的总体国内生产总值增长了约 0.45 个百分点,而库存变化降低了 0.15 个百分点的增长。

所有增长贡献的总和等于总量。
GDP 增长=私人消费+政府消费+投资+ NX +库存变化
≈我在这里盯着它。. 45+. 06+. 05±. 02±. 15)∞. 39(顶部的黑线

如何计算对增长的贡献

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

仅此而已!

如果我们这样做只是为了 LS,它会看起来像

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在让我们看看这在实践中是什么样子

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以在 10 月 31 日看到,尽管 LS 较 3 周平均值变化了+24%(未显示),但对总收入百分比变化的总体影响仅为+3.7% CTG,而 CJ 对-2.1% CTG 有很大的下行吸引力。如果我们看看 10 月 31 日的 CTG 总和(3.7%+3% %-2.1%)=+1.9%
幽灵般的对吗?

SQL 时间

现在让我们看看如何将它组合成一个查询!(如果你想看整件事,就跳到最后)

这样做的主要技巧是窗口功能,如果您需要复习请在此处勾选

第一步是计算要与给定的当前值进行比较的先前值。就我们的情况而言,这是最近 3 周的平均值。我们这样做是因为它是一个稳定的指标,允许我们查看与一周中的最近几天相比,今天是好是坏。这很方便,尤其是当有两个星期的季节性时——例如,周一可能是你一周中最好的一天,而周末稍微慢一点。
这有点棘手,但大多数情况都会比这个简单——所以让我们从最难的开始吧!

AVG(Commission) OVER (PARTITION BY providerId, weekday ORDER BY date ASC ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING) AS rolling_3_week_avg

这个函数是说我们想要得到平均佣金。PARTITION 子句告诉我们,我们需要每个提供商的平均值,按工作日对其进行分区可以让我们比较一周中同一天的收入。ROWS BETWEEN 子句定义了我们希望平均为前 3 行直到前 1 行的行——但是只针对那些具有相同 providerid 和 weekday 的分区。我试着在下表中列出它👇🏾

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

窗口函数允许我们获取最近 3 个工作日的佣金,给我们一个标准化的数字进行比较

撇开这个不谈,我们实际上能够写出我们的 CTG 计算——这是最简单的部分:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

记得这个人吗?

(commission — rolling_3_week_avg) / SUM(rolling_3_week_avg) OVER(partition by date) as CTG

你做到了!这是一个金 star⭐️

额外信用:比率变化 CTG

⚠️警告:高级分析区域⚠️

几乎可以肯定的是,可能有一种比我更简单的方法,有人已经在我之前找到了,但不管怎样,我还是来了。

从算术的角度来看,这部分不太直观。有些情况下,您会有与上述相同的问题,但您不是在跟踪数字指标(如收入)的增长,而是在调查一个比率(如点击率或转换率)的变化,您希望按组件细分(如浏览器平台的点击率,或电子邮件副本的转换率)?

某些成分会增加变化,而其他成分会减少变化。除此之外,我们还有每个分量的相对权重,所以我们也需要考虑到这一点。这有点令人生畏,但我保证最终所有的逻辑都会变得有意义。

我们在这里使用的例子是跨两种浏览器(Chrome 和 Firefox)的点击率(CTR)

在第一阶段(我们称之为 P0 ),两个浏览器的点击率相当于 30%。我们将用表格而不是图表来做这件事,因为这样更容易理解。完整的床单文件可以在这里找到。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

到目前为止一切顺利 ‘

当跟踪比率变化时,需要理解的一个关键指标是加权系数。你可能熟悉加权,比如说,根据家庭作业和期末考试来计算你的期末成绩。权重因子越大,对最终结果的影响越大

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在让我们来看一个不同时期的变化——P1

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

FF 向上,CH 向下,整体向下

在我们的例子中,Chrome 有一个大得多的用户群,所以它有一个更高的权重因子,这个权重因子是用它的节目数/所有节目数的和来计算的

对于铬合金= 9000/(1100+900) = 0.89

我们对 Firefox 做了同样的事情来获得每个平台的权重。

所有加权因子的总和应该等于 1,见上文

在 P1,我们看到总体比率从 30%的 CTR 下降到 20%。然而,当按浏览器分类时,我们看到 Firefox 上升,Chrome 下降。火狐的崛起在多大程度上抵消了整体下跌?答案比你想象的要难,因为分母随着分子一起变化,导致相对权重也随之变化。🤔

为了理解 P1 权重背景下的 P0 比率,我们需要调整 delta。
原始增量只是相对于 P0-P1
的总百分比变化,对于 FF 来说是 0.55–0.3 = 0.25,这意味着 FF 的 CTR 增加了 25%的绝对百分比。
但是我们然后通过乘以新的 P1 权重来调整它,所以
0.25 * .11 = 0.03
这是权重调整后的δ(WAD?).这个重量调整的增量是一个等价的概念,我们的 CTG,你可以看到,所有 WAD 的总和给我们-10%,CTR 的综合下降。现在让 GFTO 超越自我,进入有趣的部分。

SQL 时间

通常,当我发现自己在做这种分析时,我会查看两个特定的日期范围,然后寻找它们之间差异的贡献者。这里的场景是在商店级别上跟踪点击率的急剧下降。
所以我们的 SQL 方法会记住这个方法。第一步是将两个日期范围转换成一行。

WITH step1 as (
  select
    name store_name
    -- case statements allow us to group each date range into a given label - p0 and p1
    , case
      when day between "2020-10-27"
      and "2020-10-28"
        then 'p1'
      when day between "2020-10-19"
      and "2020-10-20"
        then 'p0'
      else null
    end as week
    , sum(clicks) as shows
    , sum(shows) as sessions
  from
    base
  group by
    store_name
    , week
  having
    -- limiting to sessions > 0 will help remove divide by 0 errors down the road
    sessions > 0
)
    , period_split as (
    select
      store_name
      -- kind of a pain, but this is the best way I know to pivot
      , sum(if(week = "p1", shows, 0)) as p1_shows
      , sum(if(week = "p0", shows, 0)) as p0_shows
      , sum(if(week = "p1", sessions, null)) as p1_sessions
      , sum(if(week = "p0", sessions, null)) as p0_sessions
    from
      step1
    group by
      1
  )

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这将为我们提供一个很好的数据透视表来开始我们的原始值。下一步相当简单,唯一棘手的部分来自构建窗口函数来寻找权重。

sum(p1_shows) over (partition by store_name) / sum(p1_shows) over() as weight_p1

窗口函数将首先返回为给定商店over partition by store_name划分的节目,然后用over ()子句将其除以所有商店的所有节目的总和。布埃诺?

select
  *
-- this is the critical step where we adjust the raw ratio change and multiply it by the P1 weighting to get the adjusted delta
  , ratio_change * weight_p1 as weight_adjusted_delta
from
  (
    select
      store_name
-- get ratios from raw values
      , p0_shows / p0_sessions as p0_ratio
      , p1_shows / p1_sessions as p1_ratio
-- get the raw ratio change
      , p1_shows / p1_sessions-p0_shows / p0_sessions as ratio_change
-- use a window function to find the weighting factor of each individual store
      , sum(p1_shows) over(partition by store_name) / sum(p1_shows) over() as weight_p1
    from
      period_split
    where
-- for the sake of presentation, let's ignore the super small potatoes
      p0_shows > 10
  )

这给了我们漂亮的完整图表

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

只要打破我们所有的图表。做就是了

在这里,我们可以清楚地看到耐克导致点击率大幅上升,而 Urban Planet 由于完全崩溃导致点击率大幅下降。这里有一些古怪的数字,所以绝对有理由深入调查这两家商店。这里的一个好方法是从主要指标计算中删除这两家商店,看看行为是否正常,这样您就可以明确地将责任归咎于这两个坏蛋🥚
再见,数据牛仔……🤠

附录

Pt 1 的完整代码

#standardSQL
with
  TRANS_TRANS as (
    select
      A.affiliate_Provider_Id as providerId
      , cast(trx_time as date) as date
      , cast(sum(A.affiliate_Sale_Value) / 100 as numeric) as gmv
      , round(cast(sum(A.affiliate_Commission) / 100 as numeric), 0) as Commission
    from
      `honey-production.dbt.fct_affiliate_transactions` as A
      left join `honey-production.analytics.stores_master` as B on
      A.store_id = B.storeid
  where
    1 = 1
    and cast(trx_time as date) >= '2020-01-01'
  group by
    1
    , 2
  )
  , base as (
    (
      select
        date
        , weekday
        , providerid
        , Commission
        , avg(Commission) over(partition by providerId, weekday order by date asc rows between 3 preceding and 1 preceding) as rolling_3_week_avg
      from
        (
          select
            date
            , extract(DAYOFWEEK from date) as weekday
            #  date_trunc(A.Date, month) as month,
            , providerId
            , sum(Commission)*(rand()/2) as commission
            , sum(gmv) as gmv
          from
            TRANS_TRANS where providerId in ("CJ","IA","LS", "AW")
          and
            date >= '2020-01-01'
          group by
            1
            , 2
            , 3
        )
    )
  )
  , final as (
    select
      date
      , weekday
      , providerid, Commission as provider_commission
      ,(Commission-rolling_3_week_avg) / rolling_3_week_avg as pct_change
      , sum(commission) over(partition by date) as total_commission
      , sum(rolling_3_week_avg) over(partition by date) as total_commission_3_week_avg
      , (commission - rolling_3_week_avg) / sum(rolling_3_week_avg) over(partition by date) as CTG
    from
      base
    where
      rolling_3_week_avg > 0
    order by
      commission desc
  )
select
  *
from
  final   
where
date between "2020-12-03" and "2020-12-12"
union all-- this union is necessary in Periscope to make the "total" line show up. It's pretty annoying
(
  select
    date
    , weekday
    , "total" as providerid, null as provider_commission
    , null as pct_change
    , null as total_commission
    , null as total_commission_3_week_avg
    , sum(ctg) as  ctg
  from
    final  where
date between "2020-12-03" and "2020-12-12"
  group by
    date
    , weekday
    , providerId, provider_commission
    , pct_change
    , total_commission
    , total_commission_3_week_avg
)

Pt 2 的完整代码

#standardSQL
with
  click as (
    select
      date(timestamp, 'America/Los_Angeles') as date
      , user_id
      , store.session_id
      , store.name
    from
      `honey-production.sdata_events_partitioned.ext_apply_codes_click`
    where
      date(timestamp, 'America/Los_Angeles') between "2020-10-19"
      and "2020-10-28"
      and cta.type = 'c0_g0'
      and cta.img is not null
      and cta.img_text is not null
      and cta.btn_text is not null
  )
  , show as (
    select
      date(timestamp, 'America/Los_Angeles') as date
      , user_id
      , version
      , store.session_id
      , store.name
    from
      `honey-production.sdata_events_partitioned.ext_apply_codes_show`
    where
      date(timestamp, 'America/Los_Angeles') between "2020-10-19"
      and "2020-10-28"
      and cta.type = 'c0_g0'
      and cta.img is not null
      and cta.img_text is not null
      and cta.btn_text is not null
  )
  , base as (
    select
      date day
      , name
      , count(distinct click.session_id) as clicks
      , count(distinct show.session_id) as shows
    from
      show
      left join click using (date, name)
      group by
        day
        , name
  )
  , step1 as (
    select
      name store_name
      -- case statements allow us to group each date range into a given label - p0 and p1
      , case
        when day between "2020-10-27"
        and "2020-10-28"
          then 'p1'
        when day between "2020-10-19"
        and "2020-10-20"
          then 'p0'
        else null
      end as week
      , sum(clicks) as clicks
      , sum(shows) as shows
    from
      base
    group by
      store_name
      , week
    having
      -- limiting to sessions > 0 will help remove divide by 0 errors down the road
      shows > 0
  )
  , period_split as (
    select
      store_name
      -- kind of a pain, but this is the best way I know to pivot
      , sum(if(week = "p1", clicks, 0)) as p1_clicks
      , sum(if(week = "p0", clicks, 0)) as p0_clicks
      , sum(if(week = "p1", shows, null)) as p1_shows
      , sum(if(week = "p0", shows, null)) as p0_shows
    from
      step1
    group by
      1
  )
select
  *
  -- this is the critical step where we adjust the raw ratio change and multiply it by the P1 weighting to get the adjusted delta
  , ratio_change * weight_p1 as weight_adjusted_delta
from
  (
    select
      store_name
      -- get ratios from raw values
      , p0_clicks / p0_shows as p0_ratio
      , p1_clicks / p1_shows as p1_ratio
      -- get the raw ratio change
      , p1_clicks / p1_shows-p0_clicks / p0_shows as ratio_change
      -- use a window function to find the weighting factor of each individual store
      , sum(p1_shows) over(partition by store_name) / sum(p1_shows) over() as weight_p1
    from
      period_split
    where
      -- for the sake of presentation, let's ignore the super small potatoes
      p0_clicks > 10
  )
order by-- this way we can see the big hitters
  abs(ratio_change * weight_p1) desc

Google Sheets with the whole thang

用手势控制 DJI·泰洛无人机

原文:https://towardsdatascience.com/control-dji-tello-drone-with-hand-gestures-b76bd1d4644f?source=collection_archive---------2-----------------------

使用 MediaPipe 手关键点检测器和简单的神经网络来识别手势和控制无人机

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Unsplash剂量媒体拍照

使用手势控制无人机是一个非常常见的主题。但是大多数解决方案都集中在旧的 OpenCV 上。因此,这是快速的解决方案(如果你想直接在无人机上运行它),但很难添加自定义手势,甚至是动作。在这篇文章中,我想介绍一种基于手部关键点检测模型的解决方案,它由 MediaPipe 和简单的多层感知器(神经网络)组成。

介绍

该项目依托两个主要部分——DJI 泰洛无人机和 MediaPipe 快手关键点检测。

DJI·泰洛是任何一种编程实验的完美无人机。它有一个丰富的 Python API(也有 Swift 和 JS APIs 可用),这有助于几乎完全控制无人机,创建无人机群,并利用其相机进行计算机视觉。

MediaPipe 是一个令人惊叹的 ML 平台,拥有许多强大的解决方案,如面部网格、手关键点检测和 Objectron。此外,他们的模型可以在具有设备上加速的移动平台上使用。

这是你需要的启动包:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片作者| DJI·泰洛,笔记本电脑和人手(狗爪子正在开发中)

进场说明

该应用分为两个主要部分:手势识别无人机控制器。这些都是独立的实例,很容易修改。例如,添加新的手势或改变无人机的移动速度。

让我们仔细看看每个部分!

手势识别

当然,这个项目的主要部分是致力于手势检测器。这个项目中识别方法的想法受到了这个 GitHub repo 的启发。这里是它如何工作的一个快速概述。

MediaPipe 为他们的手关键点检测器提供了 python 实现。正在返回 20 手界标的三维坐标。像这样:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自开放媒体管道库的 GIF(链接)

在这个项目中,将只使用 2D 坐标。在这里,您可以看到所有 20 个要点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来自开放媒体管道库(链接

然后,将这些坐标展平并归一化。手势的 ID 被添加到每个点列表中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片|此类积分列表示例

当我们为每个手势收集了大约20–100 个例子时,我们就可以开始训练我们的神经网络了。

MLP 只是一个简单的 5 层 NN,有 4 个全连接层和 1 个 Softmax 层用于分类。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片作者|神经网络结构

因为这样简单的结构,我们可以用少量的例子得到极好的精度。我们不需要在不同的光照下为每个手势重新训练模型,因为 MediaPipe 接管了所有的检测工作。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

在我的实验中,我可以对 8 种不同的手势中的每一种获得超过 97%的准确率。

因为网络的结构非常简单,您可以很容易地使用网格搜索来找到最适合神经网络的超参数。

这是我在这个项目中使用的 Tensorboard 的一个例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片|网格搜索可视化示例

无人机控制器

好了,我们有了无人机的图像和基于检测到的关键点返回手势 ID 的模型。但是如何控制我们的无人机呢?

泰洛最棒的地方在于他有现成的 Python API 来帮助我们完成这项工作。我们只需要将每个手势 ID 设置为一个命令。

尽管如此,为了消除错误识别的情况,我们将创建一个手势缓冲区。当这个缓冲区主要包含一个特定的手势 ID 时,我们可以发送一个命令来移动无人机。

以下是项目代码的功能实现示例:

这里可以看到,我们只是根据每个 ID 设置不同方向的期望速度。这使得无人机能够朝着一个方向飞行而不会颠簸。

演示

这是最甜蜜的部分🔥

但是首先,运行项目需要一些准备工作:

设置

首先,克隆存储库

# Using HTTPS
git clone [https://github.com/kinivi/tello-gesture-control.git](https://github.com/kinivi/tello-gesture-control.git)
# Using SSH
git clone [git@github.com](mailto:git@github.com):kinivi/tello-gesture-control.git

1。媒体管道设置

然后,安装以下依赖项:

ConfigArgParse == 1.2.3
djitellopy == 1.5
numpy == 1.19.3
opencv_python == 4.5.1.48
tensorflow == 2.4.1
mediapipe == 0.8.2

图像处理需要 OpenCV,djitellop 是 DJI 官方 Python API 的一个非常有用的包装器

2。泰洛设置

打开无人机并将电脑连接到其 WiFi

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

接下来,运行以下代码来验证连通性

成功连接后,您将看到以下内容

1\. Connection test:
Send command: command
Response: b'ok'2\. Video stream test:
Send command: streamon
Response: b'ok'

运行应用程序

有两种控制方式:键盘手势。在飞行过程中,你可以在不同的控制类型之间转换。下面是对这两种类型的完整描述。

运行以下命令启动 tello 控件:

python3 main.py

该脚本将启动 python 窗口,显示如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

键盘控制

为了将你的无人机定位到一个完美的地方或者在紧急情况下,你可以使用键盘控制。默认情况下,起飞后,键盘的控制方式

检查以下按键和动作描述列表:

  • k - >切换键盘控制
  • g - >切换手势控制
  • Space - >起飞无人机(如果降落)或降落无人机(如果飞行中)
  • w - >向前移动
  • s - >向后移动
  • a - >向左移动
  • d - >向右移动
  • e - >顺时针旋转
  • q - >逆时针旋转
  • r - >上移
  • f - >向下移动
  • Esc - >结束程序,降落无人机

手势控制

按下g激活手势控制模式。以下是我的回购中可用手势的完整列表:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片作者|手势列表

飞行🚀

现在你已经准备好飞翔了。按下Space起飞,享受🛸

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者 GIF |演示

项目回购

https://github.com/kinivi/tello-gesture-control.git

参考

附言。这个项目也可以很容易地添加你自己的手势。只需查看自述的这一部分。

P.S.S. 在不久的将来,我将使用一个 整体模型 来检测大距离的手势,并使用 TensorFlow JS 来利用智能手机上的 WebGPU 加速(用智能手机上的摄像头控制无人机)。所以,如果你对它感兴趣,请在 GitHub 上关注我。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值