NeptuneAI-博客中文翻译-三-

NeptuneAI 博客中文翻译(三)

原文:NeptuneAI Blog

协议:CC BY-NC-SA 4.0

分布式培训:数据科学家指南

原文:https://web.archive.org/web/https://neptune.ai/blog/distributed-training

你有没有想过,拥有数百万到数十亿参数的复杂模型是如何在万亿字节的数据上训练出来的?事实上,这种模型的大小可以变得如此之大,以至于它们甚至不适合单个处理器的存储器。因此,通过传统方式训练这样的模型变得不可能,我们需要其他东西来支持这样的内存密集型任务。分布式培训是这个问题的解决方案之一,让我们来看看它到底是什么,以及如何用它来解决这些问题。

什么是分布式培训?

通常,当面对任何领域的巨大任务时,我们会尝试将它分成子任务并并行运行。这节省了我们的时间,并使这样一个复杂的任务成为可能。当我们在深度学习中做同样的事情时,我们称之为分布式训练

准确地说,在分布式训练中,我们在训练一个巨大的深度学习模型的同时,将训练工作量划分到多个处理器上。这些处理器被称为工作者节点或简称为工作者。这些工人同时接受培训,以加快培训过程。原则上,有两种实现并行的方法——数据并行和模型并行。

数据并行性

顾名思义,在这种方法中:

  1. 我们将数据分成 n 个分区,其中 n 是计算集群中可用工作线程的总数。
  2. 我们在每个工作者节点中都有一个模型的副本,并且每个工作者节点都在自己的数据子集上执行训练。
  3. 训练循环同步或异步进行。

Data parallelism

Distributed training explanation: data parallelism | Source

让我们看看执行分布式训练循环的两种方式以及它们之间的区别。

同步训练

正如我们已经知道的,在数据并行中,我们将数据划分为多个分区,并将每个部分发送给一个工作器。每个工人都有一个完整的模型副本,并且只对部分数据进行训练。

  1. 在同步训练中,所有工人同时开始向前传球,他们计算不同的输出和梯度。在这里,每个工人等待所有其他工人完成他们的训练循环,并计算他们各自的梯度。

  2. 现在,在所有工作人员完成梯度计算后,他们开始相互通信,并使用 all-reduce 算法聚合梯度,我们将在前面讨论。

  3. 在所有梯度被组合之后,这些更新的梯度的副本被发送给所有工人。

  4. 现在,在使用 all-reduce 算法获得更新的梯度后,每个工人继续向后传递,并正常更新权重的本地副本。除非所有工人都不更新他们的重量,否则下一次向前传球不会开始,这就是为什么它被称为同步。

值得注意的是,所有工人都产生不同的梯度,因为他们在不同的数据子集上接受训练,然而在任何时间点,所有工人都具有完全相同的权重。

全归约算法

使用所有的 reduce 算法,所有的工人都必须分担存储和维护全局参数的负载。在该算法中,每个工作者与所有其他工作者共享其梯度,并应用归约操作。简而言之,all reduce 算法将所有工作线程中的目标数组缩减为一个数组,并将结果数组返回给所有工作线程。

all-reduce 算法有不同的实现,这些实现规定了如何计算和共享这些参数。

  1. 在一个实施方式中,所有工作者将其梯度发送给被称为驱动工作者的单个工作者,该驱动工作者负责梯度的减少并将更新的梯度发送给所有工作者。但是这种方法的问题是,驱动程序成为瓶颈,因为它的通信和归约操作的应用随着进程数量的增加而增加,因此它不能很好地伸缩。

  2. 因此,我们可以使用一种不太简单的方法,称为 ring-all reduce ,其中工人被设置在一个环中。每个工作者负责某个参数子集,该子集只与环中的下一个工作者共享。该算法是一个有价值的工具,可以显著减少同步开销。

异步训练

正如您可能已经猜到的,在同步方法中,我们不能够有效地使用所有资源,因为一个工人必须等待其他工人才能前进。当所有工作机之间的计算能力存在显著差异时,这尤其是一个问题,在这种情况下,整个进程的速度仅与集群中最慢的工作机一样快。

因此,在异步培训中,我们希望工人以这样的方式独立工作,即工人不需要等待集群中的任何其他工人。实现这一点的一种方法是使用参数服务器。

参数服务器

在分布式培训中,我们有一群工作人员,到目前为止,我们已经看到所有工作人员只执行一项任务,即培训。但是我们可以为每个工作者分配不同的角色,这样一些工作者充当参数服务器,其余的充当培训工作者。

参数服务器负责保存模型的参数,并负责更新模型的全局状态。而训练工人运行实际的训练循环,并从分配给他们的数据中产生梯度和损失。

我们可以将该过程总结为:

  • 在我们所有的工人身上复制这个模型,每个工人使用一个子集的数据进行训练。
  • 每个培训工作者从参数服务器获取参数。
  • 每个训练工作者执行训练循环,并将梯度发送回所有参数服务器,然后这些服务器更新模型参数。

这允许我们独立地运行训练,但是仍然有一些缺点。

  1. 一个缺点是,在任何特定的时间,只有一个工人在使用模型的更新版本,而其他人都在使用模型的旧版本。

  2. 如果我们只是使用一个工作器作为参数服务器,这可能会成为大型集群的瓶颈,可能会成为单点故障。但是当然,通过引入多个并行服务器可以在一定程度上减少瓶颈问题。

模型并行性

到目前为止,我们已经了解了如何在具有不同数据块的多个设备中分发数据和训练模型,这种方法在大多数情况下都有效,并且易于实现。但是如前所述,在一些罕见的情况下,模型的大小对于任何单个工作者来说都可能太大,这就是为什么我们需要模型并行性。

Model parallelism

Distributed training explanation: model parallelism | Source

在模型并行性(也称为网络并行性)中,模型被水平或垂直划分为不同的部分,这些部分可以在不同的工作器中并发运行,每个工作器运行相同的数据。在这里,工作人员只需要同步共享参数,通常每个向前或向后传播步骤同步一次。

Distributed training explained: model parallelism is (network parallelism) is divided either horizontally or vertically into different parts

Distributed training explained: model parallelism is (network parallelism) is divided either horizontally or
vertically into different parts | Source

在垂直划分中,层不受影响,因此,它可以应用于任何深度学习模型。因此,我们通常使用垂直分区方法,而水平分区只是在没有其他方法将一个层放入任何单个机器的内存中时才被认为是最后的手段。

可能有更简单的情况,我们可以使用模型并行,例如在编码器-解码器架构中,我们可以在不同的工人中训练编码器和解码器。模型并行最常见的用例可以在 N LP(自然语言处理)模型中找到,如变形金刚、【GPT-3】、伯特等。

集中和分散培训

在模型并行性和数据并行性方面,我们发现工作节点之间的通信非常重要,这样它们就可以共享模型参数。有两种交流方式,即集中培训和分散培训。在前面的章节中,我们实际上已经使用了这两种方法,但是现在让我们正式地了解它们。

在集中训练中,存在负责更新和存储模型参数的节点或节点组;这个节点称为参数服务器。我们已经看到了这种方法是如何在异步训练中使用的。我们也可以将这种方法用于同步培训,如集中式同步系统。在这些系统中,参数服务器依赖于来自所有工人的梯度输入来更新模型,并且训练不能进行,除非所有工人将梯度传递给参数服务器。此外,工人依赖参数服务器来获得更新的权重。如前所述,这种方法的缺点是参数服务器本身会成为大型集群的瓶颈。

在分散式通信模式中,每个节点与所有其他节点通信以更新参数。我们已经看到了这种方法如何适用于同步系统。这种方法的优点是没有单点故障,对等更新更快,并且可以通过仅交换已更改的内容来进行稀疏更新。我们也可以将这种方法用于被称为分散异步系统的异步训练。

Centralized synchronous systems

Distributed training explained: centralized synchronous systems | Source: Author

为什么我们需要分布式培训?

当谈到深度学习时,它主要是关于优化线性代数,我们都知道它在计算上是昂贵的。当我们拥有大量训练数据时,问题就出现了,这些数据在深度学习中非常常见,在这种情况下,即使是在一台拥有强大加速器的机器上,训练也可能需要数月甚至数年的时间。

当我们试图解决涉及图像、音频或文本的复杂问题时,我们使用具有复杂架构的模型来获得更好的结果。在训练期间,这些模型可能会计算和存储数百万或数十亿个更新的体重参数,这可能会导致存储问题。此外,有时你的机器可能会在训练中崩溃,这将导致失去所有的进展,这是一个相当常见的问题,当训练期非常长,如前所述。

但是当我们转移到多台机器上时,我们可以利用线性代数是可并行化的这一事实,这使我们能够在多台机器上分割大型模型。我们还可以引入容错,这样即使我们的一台机器崩溃,训练过程也不会完全丢失,我们可以继续训练而不会有任何重大损失。

但是分布式训练在每种情况下都更好吗,即使我们有更简单的模型和更小的训练数据?不,由于并行化的开销,在分布式系统上训练它实际上可能比在单台机器上训练它花费更多的时间。

分布式培训的优势

基本上,在分布式训练中,我们在分布式系统上训练我们的模型,并且在分布式系统上训练模型具有如下所列的几个好处:

  1. 容错和可靠性

从本质上讲,分布式系统比单机更能容忍故障。如果一家公司有一个跨两个数据中心的 8 机集群,即使其中一个数据中心出现故障,它也可以继续工作,不会出现任何问题。这相当于增加了可靠性,因为当一台计算机出现故障时,其他所有计算机都会随之出现故障。但是,即使一个或多个节点或数据中心出现故障,分布式系统也能保持运行。

  1. 效率

分布式系统允许将复杂的问题分解成较小的块,并在许多计算机上并行处理,从而减少了解决这些问题所需的时间。

  1. 可扩展性

分布式系统自然是可伸缩的,因为它们运行在几台机器上。因此,用户可以安装另一台机器来处理不断增加的负载,而不是重复更新单个系统。当一个系统承受很大的压力时,每台机器都能以最大能力运行,当负担较轻时,可以关闭一些机器。我们可以说用户的扩展能力实际上是无限的。

  1. 成本效益

与一些大型的集中式系统相比,分布式系统更具成本效益。它们的初始成本高于独立系统,但是在某个点之后,它们变得更经济。

分布式培训框架

这里有一些 Python 框架,允许我们分发和并行化深度学习模型。

1.霍罗沃德

Horovod 是一个面向 TensorFlow、Keras、PyTorch 的分布式深度学习训练框架。它是由优步开发的,Horovod 的目标是让分布式深度学习变得快速而简单。使用 Horovod 为 scale 开发的训练脚本可以在单个 GPU 或多个 GPU 上运行,而无需进一步更改代码。

您可以使用 Azure ML 轻松地为 Horovod 设置环境,Azure ML 为使用各种框架设置培训提供了精选的培训环境。

2.他们是

Elephas 是一个 Keras 插件,允许你使用 Spark 大规模执行分布式深度学习模型。Elephas 的目标是保持 Keras 的简单性和易用性,实现可以在大型数据集上操作的分布式模型的快速原型制作。

3.亚马逊 Sagemaker

数据并行和模型并行都得到亚马逊 SageMaker 的分布式训练库的支持。这些库是为 SageMaker 培训环境量身定制的,帮助您将分布式培训作业适应 SageMaker,并提高培训速度和吞吐量。

SageMaker 中有 18 个流行的机器学习算法库。它们中的许多都是从底层完全重写的,以便可扩展和开箱即用。

4. Tensorflow

TensorFlow 为分布式培训提供内置支持。通过TF . distribute . strategyAPI,只需很少的代码修改,就可以将训练分散到许多 GPU 上。这个 API 还能够通过 Azure ML 启动分布式作业。它易于使用,开箱即可提供良好的性能。因为它易于使用,所以吸引了各种各样的用户群,包括研究人员、机器学习工程师等等。

5. PyTorch

Azure ML 支持使用 PyTorch 的原生分布式训练功能运行分布式作业。PyTorch 中的 torch.distributed 包提供了分布式培训功能。该软件包中的功能分为三个主要部分:

  • 分布式数据并行训练 : DDP 是单程序多数据训练范式。通过 DDP 在每个流程上复制模型,每个模型副本接收一组新的输入数据样本。为了保持模型副本同步,DDP 处理梯度通信,并将其与梯度计算重叠,以加速训练。
  • 基于 RPC 的分布式训练 : RPC 允许不适合数据并行训练的通用训练拓扑,如分布式管道并行、参数服务器范式、基于 DDP 的混合训练等。它有助于管理远程对象的生命周期,并将自动签名引擎扩展到机器范围之外。
  • 集体通信 :支持集团内跨进程发送张量,提供集体通信 API 和 P2P 通信 API。DDP 和 RPC APIs 可以处理许多分散的训练场景,所以开发人员不需要直接使用这个原始的通信 API。但是,在某些情况下,这个 API 仍然有用。一个例子是分布参数平均,应用程序不使用 DDP 来传输梯度,而是在反向传递后计算所有模型参数的平均值。

从本文中了解更多关于分布式培训的工具:分布式培训:框架和工具

在 Neptune 中,你可以跟踪来自许多进程的数据,特别是在不同机器上运行的数据。

结论

在本文中,我们讨论了什么是分布式训练,以及它如何解决我们在大型数据集上训练复杂机器学习模型的问题。我确信现在您能够区分模型并行和数据并行,并且能够决定哪种方法可能更适合您的用例。要进一步阅读,你可以参考以下材料:

使用 TensorFlow 对象检测 API 深入足球分析

原文:https://web.archive.org/web/https://neptune.ai/blog/dive-into-football-analytics-with-tensorflow-object-detection-api

说到足球,看到一个球队如何能够战胜一个更强大的对手赢得比赛是令人惊讶的。有时,观众可以通过观察队员(他们的能力和实力)来预测比赛的比分。建立一个能够跟踪球场上团队球员的自动化机器学习模型,这样我们就可以预测球员的下一步行动,这难道不是很有趣吗?

为了进一步证明这一点,让我们来看看如何直观地应用对象检测/跟踪等计算机视觉技术来监控足球场上的团队球员。

这部作品的笔记本可以在这里找到。这项工作中实现的所有代码都是在 colab 上完成的。

下面是我们将要研究的内容的概要:

  1. 数据来源
  2. 标签
  3. 数据准备(导出为张量流记录)
  4. 模型管道
  5. 建模、培训(和记录)
  6. 模型评估
  7. 结果和结论

数据来源

为了进行足球分析,需要有算法将从中学习的源数据。在这个项目中,源数据是从这里的得到的。这里有一些你需要从比赛中了解的信息。这是一场切尔西(2)对曼城(1)的比赛。这个视频包含了真实足球比赛的精彩部分。切尔西能够在这场比赛中击败曼城,靠的是球员们一些独特的战术。

从视频中提取了 152 幅图像,并使用下面的代码进行了处理。

vidcap = cv2.VideoCapture(ChelseaManCity)
count = 0
def getFrame(sec):
   vidcap.set(cv2.CAP_PROP_POS_MSEC,sec*1000)
   hasFrames,image = vidcap.read()
   if hasFrames:
       cv2.imwrite("images/frame"+str(count)+".jpg", image)     
   return hasFrames
sec = 2
frameRate = 2 
count=88
success = getFrame(sec)
while success:
   count = count + 1
   sec = sec + frameRate
   sec = round(sec, 2)
   success = getFrame(sec)

生成的图像保存在一个文件夹中。由于目标是能够跟踪足球场上的各种队友(对象),因此对数据进行标记非常重要,以便算法可以将正确的图像映射到实际目标。

机器学习标记是使算法直观地捕捉数据中呈现的信息的重要步骤。我们总是想把我们的问题作为监督学习问题(让机器从输入数据和目标标签中学习)呈现给一个算法;而不是无监督学习(让机器在输入数据中找出模式,没有目标标签)。

这样做的一个好处是,它减少了太多的计算,增强了学习,也使评估变得容易得多。因为我们正在处理图像数据或视频帧,所以需要利用好的注释工具箱来有效地检测足球场上存在的各种对象。在这个项目中,labelImg 被用作标签工具包。

标签

Labellmg 是一个用于图像处理和注释的开源图形标签工具。本地使用它的源代码可以在这里找到。在足球场上,我们确实有以下这些:

  1. 来自两个对手球队的球员(在这种情况下,切尔西和曼城),
  2. 裁判们,
  3. 守门员们,

从上面可以看出,从视频中提取的 152 个图像中,我们有 4 个不同的类别要标记。我们可以训练并使算法跟踪所有 4 个类别并进行分类。为了简单起见,我决定分成 3 个类,这样我就有了:

  1. 切尔西—0 级
  2. 曼城—1 级
  3. 裁判和守门员——2 级

所以我最后上了 3 节课。这是因为 0 级和 1 级的标签比裁判和守门员的标签多。由于在 152 帧中,裁判和守门员的标签都没有得到充分的代表,我们可以将他们作为一个单独的类别,称为‘未知’

既然已经正确标记了帧中的所有类,我们可以继续使用名为 efficientDet 的对象检测架构进行建模。请注意,在我们建模之前,我们需要将这些带标签的数据以及生成的 xml 文件(为每一帧生成的文件,包含图像中每个标签的边界框)转换为 TensorFlow 记录。

数据准备(导出为张量流记录)

既然我们已经能够方便地标记数据,我们可以继续将数据导出为 TensorFlow 记录。为此,我们将使用 roboflow.com 平台。你需要做的就是遵循这些步骤:

  1. 创建 roboflow.com 帐户后,继续点击创建数据集。
  2. 填写您的数据集详细信息,上传数据(图像和。xml 文件)。确保在为计算机视觉建模选择数据类型时选择对象检测。
  3. 如果需要,您可以继续添加预处理步骤和增强步骤,最后,
  4. 上传后,点击右上角的生成张量流记录。继续选择“生成为代码”,这将为您提供一个链接,供您下载列车数据的张量流记录数据。

模型管道

既然我们已经为训练和测试数据导出了张量流记录;下一步是使用 EfficientDet 建模。在使用 EfficientDet 建模之前,需要满足模型管道的某些先决条件,包括以下内容:

  1. 安装 TensorFlow 对象检测 API。
  2. 设置对象检测架构
  3. 设置配置文件。

TensorFlow 对象检测 API 的安装

以下信息和步骤演示了如何在 Colab 上进行培训时安装 TensorFlow 2 对象检测 API。首先,使用下面的代码在 GitHub 上克隆 TensorFlow 模型库:

import os
import pathlib

if "models" in pathlib.Path.cwd().parts:
 while "models" in pathlib.Path.cwd().parts:
   os.chdir('..')
elif not pathlib.Path('models').exists():
 !git clone --depth 1 https://github.com/tensorflow/models

接下来是使用以下命令安装 TensorFlow 对象检测 API。

%%bash
cd models/research/
protoc object_detection/protos/*.proto --python_out=.
cp object_detection/packages/tf2/setup.py .
python -m pip install .

安装了 TensorFlow 对象检测 API 后,下面的代码帮助我们确认已经安装了该 API。

import matplotlib
import matplotlib.pyplot as plt
import os
import random
import io
import imageio
import glob
import scipy.misc
import numpy as np
from six import BytesIO
from PIL import Image, ImageDraw, ImageFont
from IPython.display import display, Javascript
from IPython.display import Image as IPyImage

import tensorflow as tf

from object_detection.utils import label_map_util
from object_detection.utils import config_util
from object_detection.utils import visualization_utils as viz_utils
from object_detection.utils import colab_utils
from object_detection.builders import model_builder

%matplotlib inline

既然 API 已经正确安装,我们可以继续训练数据,但是在此之前,让我们使用下面的代码构建模型测试器。model tester 文件有助于确认任何对象检测问题的正确建模所需的库的安装和导入。为此,请尝试实现下面的代码。

!python /content/models/research/object_detection/builders/model_builder_tf2_test.py

继续建模流程,在导入提议的架构之前,我们可以使用下面的代码从 roboflow.com 下载 tfrecords 格式的导出数据。

务必注意,在使用roboflow.com平台生成 tfrecords 格式的数据时;数据可以导出为链接,下载到 Colab 中。将导出的链接插入下面的程序并运行,以便将数据下载到 Colab 中。


%cd /content
!curl -L "[insert Link]" > roboflow.zip; unzip roboflow.zip; rm roboflow.zip

如果你能走到这一步,这是迄今为止完成的伟大工作。在设置配置文件之前,还有一件事,我们需要指定训练和测试数据的目录(这在设置配置文件时是需要的)。

刚刚从 roboflow.com 下载的训练和测试数据的目录可以在当前目录中找到。您的目录应该如下所示:

train_record_fname = '/content/train/foot.tfrecord'
test_record_fname = '/content/test/foot.tfrecord'
label_map_pbtxt_fname = '/content/train/foot_label_map.pbtxt'

恭喜你已经走了这么远,为顺利的训练做好了准备。现在,让我们继续在培训前设置配置文件。

设置对象检测架构

对于这个问题,期望的对象检测架构是 EfficientDet。该架构有 4 个变体(D0、D1、D2 和 D3)。以下代码显示了 D0-D3 的模型配置,以及它们各自的模型名称和 base_pipeline_file(配置文件)。

MODELS_CONFIG = {
   'efficientdet-d0': {
       'model_name': 'efficientdet_d0_coco17_tpu-32',
       'base_pipeline_file': 'ssd_efficientdet_d0_512x512_coco17_tpu-8.config',
       'pretrained_checkpoint': 'efficientdet_d0_coco17_tpu-32.tar.gz',
       'batch_size': 16
   },
   'efficientdet-d1': {
       'model_name': 'efficientdet_d1_coco17_tpu-32',
       'base_pipeline_file': 'ssd_efficientdet_d1_640x640_coco17_tpu-8.config',
       'pretrained_checkpoint': 'efficientdet_d1_coco17_tpu-32.tar.gz',
       'batch_size': 16
   },
   'efficientdet-d2': {
       'model_name': 'efficientdet_d2_coco17_tpu-32',
       'base_pipeline_file': 'ssd_efficientdet_d2_768x768_coco17_tpu-8.config',
       'pretrained_checkpoint': 'efficientdet_d2_coco17_tpu-32.tar.gz',
       'batch_size': 16
   },
       'efficientdet-d3': {
       'model_name': 'efficientdet_d3_coco17_tpu-32',
       'base_pipeline_file': 'ssd_efficientdet_d3_896x896_coco17_tpu-32.config',
       'pretrained_checkpoint': 'efficientdet_d3_coco17_tpu-32.tar.gz',
       'batch_size': 16
   }
}

在本教程中,我们实现了轻量级、最小的艺术级 EfficientDet 模型(D0)。扩大到更高效的模型;你将需要更强的计算能力。对于训练,你可以从 5000 步开始(如果损失函数仍在下降,你可能想增加)。每步的评估次数也设置为 500。这意味着,在 500 步之后执行评估。

下面的代码演示了上面的模型设置。

chosen_model = 'efficientdet-d0'
num_steps = 5000 
num_eval_steps = 500 
model_name = MODELS_CONFIG[chosen_model]['model_name']
pretrained_checkpoint = MODELS_CONFIG[chosen_model]['pretrained_checkpoint']
base_pipeline_file = MODELS_CONFIG[chosen_model]['base_pipeline_file']
batch_size = MODELS_CONFIG[chosen_model]['batch_size'] 

完成这些后,让我们继续下载指定架构的预训练权重,如上面的代码所示(D0、D1、D2 和 D3)。下面的代码帮助我们做到这一点:

%mkdir /content/models/research/deploy/
%cd /content/models/research/deploy/
import tarfile
download_tar = 'http://download.tensorflow.org/models/object_detection/tf2/20200711/' + pretrained_checkpoint
!wget {download_tar}
tar = tarfile.open(pretrained_checkpoint)
tar.extractall()
tar.close()

让我们继续编写我们的自定义配置文件。

设置配置文件

配置文件是表示为. config 的文件扩展名。该文件包含成功训练对象检测模型/架构所需的所有信息。这包括以下参数:

  1. 训练的步数。
  2. 训练和 label_maps 数据集的目录。
  3. 微调检查点。
  4. SSD 模型参数,如锚点 _ 生成器、图像 _ 大小调整器、框 _ 预测器、特征 _ 提取器等。

默认情况下,培训所需的每个期望的体系结构都有一个配置文件。那些配置文件中需要更新的是文件检查点、label_map、列车数据(在 tfrecords 中)和测试数据的目录。

为了实现上述目标,让我们采取以下步骤。首先,让我们使用下面的代码下载定制配置文件。

%cd /content/models/research/deploy
download_config = 'https://raw.githubusercontent.com/tensorflow/models/master/research/object_detection/configs/tf2/' + base_pipeline_file
!wget {download_config}

完成以上工作后,我们可以继续设置管道文件名和模型检查点目录。下面的代码说明了这一点。此外,您可以使用函数 get_num_classes 确认从 label_map_pbtxt 文件中提取的类的数量,如下所示。

pipeline_fname = '/content/models/research/deploy/' + base_pipeline_file
fine_tune_checkpoint = '/content/models/research/deploy/' + model_name + '/checkpoint/ckpt-0'

def get_num_classes(pbtxt_fname):
   from object_detection.utils import label_map_util
   label_map = label_map_util.load_labelmap(pbtxt_fname)
   categories = label_map_util.convert_label_map_to_categories(
       label_map, max_num_classes=90, use_display_name=True)
   category_index = label_map_util.create_category_index(categories)
   return len(category_index.keys())
num_classes = get_num_classes(label_map_pbtxt_fname)

对于这个问题,类的数量是 3,即:

  1. 切尔西-0 级
  2. 人-城市-1 级
  3. 未知(裁判、守门员和其他)-2 级

现在,让我们将以下信息写入自定义配置文件:

  1. 列车方向,
  2. 测试方向。
  3. 标签图。
  4. 检查点文件目录。

下面的代码帮助我们读取配置文件并将文件目录写入文件。

import re
%cd /content/models/research/deploy
print('writing custom configuration file')
with open(pipeline_fname) as f:
   s = f.read()
with open('pipeline_file.config', 'w') as f:

   s = re.sub('fine_tune_checkpoint: ".*?"',
              'fine_tune_checkpoint: "{}"'.format(fine_tune_checkpoint), s)

   s = re.sub(
       '(input_path: ".*?)(PATH_TO_BE_CONFIGURED/train)(.*?")', 'input_path: "{}"'.format(train_record_fname), s)
   s = re.sub(
       '(input_path: ".*?)(PATH_TO_BE_CONFIGURED/val)(.*?")', 'input_path: "{}"'.format(test_record_fname), s)

   s = re.sub(
       'label_map_path: ".*?"', 'label_map_path: "{}"'.format(label_map_pbtxt_fname), s)

   s = re.sub('batch_size: [0-9]+',
              'batch_size: {}'.format(batch_size), s)

   s = re.sub('num_steps: [0-9]+',
              'num_steps: {}'.format(num_steps), s)

   s = re.sub('num_classes: [0-9]+',
              'num_classes: {}'.format(num_classes), s)

   s = re.sub(
       'fine_tune_checkpoint_type: "classification"', 'fine_tune_checkpoint_type: "{}"'.format('detection'), s)

   f.write(s)

您可以通过运行下面的代码来确认 dir 已被写入文件:

%cat /content/models/research/deploy/pipeline_file.config

现在我们有了一个配置文件,让我们开始训练吧。但是在训练之前,让我们记下配置文件的目录以及保存所有训练参数的目录。它们应该是这样的:

pipeline_file = '/content/models/research/deploy/pipeline_file.config'
model_dir = '/content/training/'

建模和培训

在所有条件都相同的情况下,我们可以通过运行 model_main_tf2.py 文件来训练数据。此文件用于运行与 TensorFlow 2 相关的任何对象检测问题。要成功运行,您只需指定以下内容:

  1. 管道配置路径。
  2. 型号目录。
  3. 训练步骤数。
  4. 评估步骤数。

下面的代码帮助我们做到这一点。

!python /content/models/research/object_detection/model_main_tf2.py
   --pipeline_config_path={pipeline_file}
   --model_dir={model_dir}
   --alsologtostderr
   --num_train_steps={num_steps}
   --sample_1_of_n_eval_examples=1
   --num_eval_steps={num_eval_steps}

这样做了之后,我不得不通过改变训练步数来不断地跑,直到我得到想要的结果。在完成 20000 步训练后,当我确信我的训练不再减少时,我不得不停止。这需要大约 5-6 个小时的培训。

经过这么长时间的训练,这里有一个张量板来说明学习速度。

football tensorboard training

让我们通过运行这段代码来导出模型的训练推理图。

%ls '/content/training/'

下一步是运行一个转换脚本,导出模型参数作为推理,以便在实时预测需要时重新加载。

import re
import numpy as np
output_directory = '/content/fine_tuned_model'

last_model_path = '/content/training/'
print(last_model_path)
!python /content/models/research/object_detection/exporter_main_v2.py
   --trained_checkpoint_dir {last_model_path}
   --output_directory {output_directory}
   --pipeline_config_path {pipeline_file}

模型评估

要评估该模型,需要实施以下步骤:

  1. 训练后加载最后一个模型检查点。
  2. 读入视频帧。
  3. 识别每个帧中的对象(边界框和精确度)。
  4. 将视频帧转换为视频。

若要在训练后加载最后一个模型检查点,请运行以下代码:

pipeline_config = pipeline_file

model_dir = '/content/training/ckpt-6'
configs = config_util.get_configs_from_pipeline_file(pipeline_config)
model_config = configs['model']
detection_model = model_builder.build(
     model_config=model_config, is_training=False)

ckpt = tf.compat.v2.train.Checkpoint(
     model=detection_model)
ckpt.restore(os.path.join('/content/training/ckpt-6'))

def get_model_detection_function(model):
 """Get a tf.function for detection."""

 @tf.function
 def detect_fn(image):
   """Detect objects in image."""

   image, shapes = model.preprocess(image)
   prediction_dict = model.predict(image, shapes)
   detections = model.postprocess(prediction_dict, shapes)

   return detections, prediction_dict, tf.reshape(shapes, [-1])

 return detect_fn

detect_fn = get_model_detection_function(detection_model)

下一步是读入视频帧,并将其通过对象检测模型进行边界框识别和正确类别的预测。下面的代码帮助我们方便地做到这一点:

label_map_path = configs['eval_input_config'].label_map_path
label_map = label_map_util.load_labelmap(label_map_path)
categories = label_map_util.convert_label_map_to_categories(
   label_map,
   max_num_classes=label_map_util.get_max_label_map_index(label_map),
   use_display_name=True)
category_index = label_map_util.create_category_index(categories)
label_map_dict = label_map_util.get_label_map_dict(label_map, use_display_name=True)

import random

TEST_IMAGE_PATHS = glob.glob('/content/test/*.jpg')
image_path = random.choice(TEST_IMAGE_PATHS)
image_np = load_image_into_numpy_array(image_path)

input_tensor = tf.convert_to_tensor(
   np.expand_dims(image_np, 0), dtype=tf.float32)
detections, predictions_dict, shapes = detect_fn(input_tensor)

label_id_offset = 1
image_np_with_detections = image_np.copy()

viz_utils.visualize_boxes_and_labels_on_image_array(
     image_np_with_detections,
     detections['detection_boxes'][0].numpy(),
     (detections['detection_classes'][0].numpy() + label_id_offset).astype(int),
     detections['detection_scores'][0].numpy(),
     category_index,
     use_normalized_coordinates=True,
     max_boxes_to_draw=200,
     min_score_thresh=.5,
     agnostic_mode=False,
)

结果和结论

成功完成上述所有过程后,该模型能够识别来自同一支球队的球员,并将球场上的人归类为另一个称为“未知”的类别,即裁判或中场休息时来自支持队的人。下面是一个完整的视频演示对象检测架构的行动视频帧。

https://web.archive.org/web/20221201165104if_/https://www.youtube.com/embed/NiBL6K3jiJM?feature=oembed

视频

总之,计算机视觉作为一个深度学习领域,在足球分析中有着可行的应用。可以做的更多事情包括:

  1. 球跟踪,
  2. 用计算机视觉分析场上球员的情绪,
  3. 预测下一个接球的球员的强化学习,等等。

如果这篇文章有助于你详细了解计算机视觉,请与朋友分享。感谢阅读!

参考

  1. roboflow.com
  2. heart beat . fritz . ai/end-to-end-object-detection-using-efficient det-on-raspberry-pi-3-part-2-bb 5133646630
  3. github.com/tzutalin/labelImg
  4. medium . com/@ iKhushPatel/convert-video-to-images-images-to-video-using-opencv-python-db27a 128 a 481
  5. github.com/microsoft/VoTT
  6. cvat.org

文档分类:小数据集的 7 种实用方法

原文:https://web.archive.org/web/https://neptune.ai/blog/document-classification-small-datasets

文档或文本分类是自然语言处理的主要任务之一。它有许多应用,包括新闻类型分类、垃圾邮件过滤、有毒评论识别等。

在大型组织中,数据集很大,从头开始训练深度学习文本分类模型是一个可行的解决方案,但对于大多数现实生活中的问题来说,你的数据集很小,如果你想建立你的机器学习模型,你需要变得聪明。

在本文中,我将讨论面向文本表示的实用方法,这些方法使小数据集上的文档分类成为可能。

文本分类 101

文本分类工作流程从清理和准备数据集中的语料库开始。然后,通过任何不同的文本表示方法来表示该语料库,随后进行建模。

在本文中,我们将关注这个管道的“文本表示”步骤。

示例文本分类数据集

我们将使用来自的数据真实与否?NLP 与灾难推文 kaggle 比赛。在这里,的任务是预测哪些推文是关于真实灾难的,哪些不是。

如果您想一步一步地学习这篇文章,您可能需要安装我用于分析的所有库。

让我们看看我们的数据,

import pandas as pd

tweet= pd.read_csv('../input/nlp-getting-started/train.csv')
test=pd.read_csv('../input/nlp-getting-started/test.csv')

tweet.head(3)

数据包含 id、关键字、位置、文本和二进制目标。我们只会考虑推文来预测目标。

print('There are {} rows and {} columns in train'.format(tweet.shape[0],tweet.shape[1]))
print('There are {} rows and {} columns in test'.format(test.shape[0],test.shape[1]))

训练数据集只有不到 8000 条推文。再加上 tweets 最多 280 个字符的事实,使得它成为一个棘手的小数据集。

文本数据准备

在开始任何 NLP 任务之前,我们需要做一些数据预处理和基本的清理工作。这不是本文的重点,但是如果你想阅读更多关于这一步的内容,请查看这篇文章。

简而言之,我们将:

  • 记号化:将句子转换成记号或单词列表的过程。
  • 删除停用词:删除单词“a”或“the”
  • :将每个单词的屈折形式化为一个共同的基或根(“学”,“学”——>“学”))。
def preprocess_news(df):
	'''Function to preprocess and create corpus'''
	new_corpus=[]

	lem=WordNetLemmatizer()
	for text in df["question_text"]:
    	words=[w for w in word_tokenize(text) if (w not in stop)]

    	words=[lem.lemmatize(w) for w in words]

    	new_corpus.append(words)
	return new_corpus

corpus=preprocess_news(df)

现在,让我们看看如何表示这个语料库,以便我们可以将它输入任何机器学习算法。

文本表示

文本不能直接用作机器学习模型的输入,而是需要首先以数字格式表示。这就是所谓的文本表示。

计价器

Countvectorizer 提供了一种简单的方法来矢量化并表示一组文本文档。它对输入文本进行标记,构建一个已知单词的词汇表,然后用这个词汇表表示文档。

让我们用一个例子来理解它,

text = ["She sells seashells in the seashore"]

vectorizer = CountVectorizer()

vectorizer.fit(text)

print(vectorizer.vocabulary_)

vector = vectorizer.transform(text)

print(vector.shape)
print(type(vector))
print(vector.toarray())

您可以看到,Coutvectorizer 已经从给定的文本中构建了一个词汇表,然后使用一个 numpy 稀疏矩阵来表示单词。我们可以试着用这个词汇翻译另一篇文章,并观察输出结果以获得更好的理解。

vector=vectorizer.transform(["I sell seashells in the seashore"])
vector.toarray()

你可以看到:

  • 索引位置 3 和 4 具有零,意味着这两个单词不存在于我们的词汇表中,而所有其他位置具有 1,意味着这些单词存在于我们的词汇表中。词汇表中缺少的相应单词是“sells”和“she”。

现在您已经了解了 Coutvectorizer 的工作原理,我们可以使用它来调整和转换我们的语料库。

vec=CountVectorizer(max_df=10,max_features=10000)
vec.fit(df.question_text.values)
vector=vec.transform(df.question_text.values)

您应该知道 Countvectorizer 有几个重要的参数,您应该针对您的问题进行调整:

  • max_features :构建一个词汇表,该词汇表只考虑在整个语料库中按词频排序的前 n 个标记。
  • min_df :在构建词汇表时,忽略那些标记频率严格低于给定阈值的术语
  • max_df :在构建词汇表时,忽略令牌频率严格高于给定阈值的术语。

通常有助于选择合理值(或超参数优化方法的范围)的是良好的探索性数据分析。看看我的另一篇文章。

tfidf 矢量器

Countvectorizer 的一个问题是,像“the”这样的常见单词会出现很多次(除非在预处理阶段将其删除),而这些单词实际上并不重要。一个流行的选择是 Tfidfvectorizer。是词频的首字母缩写——逆文档频率。

  • 词频:总结给定单词在文档中出现的频率。
  • 逆文档频率:这将缩小文档中大量出现的单词。

让我们看一个例子:

from sklearn.feature_extraction.text import TfidfVectorizer

text = ["She sells seashells by the seashore","The sea.","The seashore"]

vectorizer = TfidfVectorizer()

vectorizer.fit(text)

print(vectorizer.vocabulary_)
print(vectorizer.idf_)

vector = vectorizer.transform([text[0]])

print(vector.shape)
print(vector.toarray())

词汇表再次由 6 个单词组成,并且为每个单词计算逆文档频率,将最低分数分配给出现 4 次的“The”。

然后,分数在 0 和 1 之间被归一化,并且该文本表示可以用作任何机器学习模型的输入。

Word2vec

上述方法的一个大问题是,在表示单词时,会丢失单词的上下文。单词嵌入通过编码一些上下文信息来提供 NLP 中单词的更好的表示。它提供了从单词到相应的 n 维向量的映射。

word2vec

Blog “Dynamic Meta-Embedding: An approach to select the correct embedding” | Source

Word2Vec 是由 Tomas Mikolov 等人在谷歌开发的,它使用一个浅层神经网络来学习单词嵌入。通过理解单词出现的上下文来学习向量。具体来说,它着眼于共现词。

下面给出的是句子“猫坐在垫子上”的共现矩阵。

co occurrence matrix

Thushan Ganegedara Blog “Intuitive Guide to Understanding GloVe Embeddings” | Source

Word2vec 由两种不同的模型组成:

  • 连续单词包 (CBOW)模型可以被认为是通过训练一个模型来学习单词嵌入,以预测给定上下文的单词。
  • Skip-Gram 模型则相反,通过训练模型来学习单词嵌入,以预测给定单词的上下文。

单词嵌入的基本思想是在相似上下文中出现的单词在向量空间中倾向于彼此更接近。我们来看看如何用 python 实现 word2vec。

import gensim
from gensim.models import Word2Vec

model = gensim.models.Word2Vec(corpus,
                               min_count = 1, size = 100, window = 5)

现在您已经创建了您的 word2vec 模型,您可以实际更改并观察差异的一些重要参数是,

  • size :表示每个单词的结果向量的嵌入大小。
  • min_count :在构建词汇表时,忽略文档频率严格低于给定阈值的术语
  • window :构建表示时考虑单词周围的单词数。也称为窗口大小。

在本文中,我们将重点放在小数据集的实用方法上,我们将使用预训练的词向量,而不是来自我们语料库的训练向量。这种方法保证会产生更好的性能。

首先,你必须从这里下载训练好的向量。然后,您可以使用 gensim 加载向量。

from  gensim.models.KeyedVectors import load_word2vec_format

def load_word2vec():
    word2vecDict = load_word2vec_format(
        '../input/word2vec-google/GoogleNews-vectors-negative300.bin',
        binary=True, unicode_errors='ignore')
    embeddings_index = dict()
    for word in word2vecDict.wv.vocab:
        embeddings_index[word] = word2vecDict.word_vec(word)

    return embeddings_index

让我们检查一下嵌入,

w2v_model=load_word2vec()
w2v_model['London'].shape

你可以看到这个单词是用一个 300 维的向量来表示的。因此,你的语料库中的每个单词都可以这样表示,这个嵌入矩阵用于训练你的模型。

FastText

现在,让我们了解一下 fastText,这是 gensim 中一个非常有用的模块。FastText 是由脸书开发的,在文本分类任务中具有很高的性能和速度。

它支持连续的单词包和跳格模型。以前的模型和 FastText 的主要区别在于,它将单词分解成几个 n-gram。

让我们以橙色这个词为例。

单词 orange 的三元组是,org,ran,ang,nge(忽略单词的起始和结束边界)。

orange 的单词嵌入向量(文本表示)将是这些 n 元文法的总和。罕见单词或错别字现在可以正确表示,因为它们的一些 n-grams 很可能也出现在其他单词中。

例如,对于像 stupedofantabulouslyfantastic 这样的词,它可能从未出现在任何语料库中,gensim 可能会返回以下任意两种解决方案:零向量或低幅度的随机向量。

然而,可以通过将单词分成组块并使用这些组块的向量来创建单词的最终向量,从而产生更好的向量。在这种特殊的情况下,最终的向量可能更接近于奇妙的向量。

同样,我们将使用预先训练的模型,而不是训练我们自己的单词嵌入。

为此,你可以从这里下载预先训练好的向量。

这个文件的每一行都包含一个单词,它是一个对应的 n 维向量。我们将使用这个文件创建一个字典,将每个单词映射到它的向量表示。

from gensim.models import FastText

def load_fasttext():

	print('loading word embeddings...')
	embeddings_index = {}
	f = open('../input/fasttext/wiki.simple.vec',encoding='utf-8')
	for line in tqdm(f):
    	values = line.strip().rsplit(' ')
    	word = values[0]
    	coefs = np.asarray(values[1:], dtype='float32')
    	embeddings_index[word] = coefs
	f.close()
	print('found %s word vectors' % len(embeddings_index))

	return embeddings_index

embeddings_index=load_fastext()

让我们检查一个单词的嵌入,

embeddings_index['london'].shape

GloVe(单词表示的全局向量)

GloVe 代表单词表示的全局向量。它是由斯坦福大学开发的无监督学习算法。GloVe 的基本思想是使用共现矩阵导出单词之间的语义关系。这个想法与 word2vec 非常相似,但是有细微的区别。去这里阅读更多。

为此,我们将使用在大型语料库上训练的预训练手套向量。这保证在几乎任何情况下都有更好的表现。你可以从这里下载。

下载后,我们可以加载我们预先训练的单词模型。在此之前,您应该了解它可用的格式。每行包含一个单词及其对应的 n 维向量表示。像这样,

因此,要使用它,你应该首先准备一个包含单词和相应向量之间映射的字典。这可以称为嵌入字典。

让我们为我们的目的创建一个。

def load_glove():
    embedding_dict = {}
    path = '../input/glove-global-vectors-for-word-representation/glove.6B.100d.txt'
    with open(path, 'r') as f:
        for line in f:
            values = line.split()
            word = values[0]
            vectors = np.asarray(values[1:], 'float32')
            embedding_dict[word] = vectors
    f.close()

    return embedding_dict
embeddings_index = load_glove()

现在,我们有一个字典,其中包含手套中的每个单词、预训练向量以及它们在字典中的对应向量。让我们检查一个单词的嵌入。

embeddings_index['london'].shape

通用语句编码

到目前为止,我们一直在处理单词的表示,这些技术对于单词级的操作非常有用。有时候我们需要探索句级运算。这些编码器被称为句子编码器。

一个好的句子编码器应该以这样一种方式对句子进行编码,使得个相似句子的向量在向量空间中具有最小的距离。

举个例子,

  • 今天天气晴朗
  • 今天下雨了
  • 今天多云。

这些句子将被编码和表示,使得它们在向量空间中彼此接近。

让我们继续检查如何实现通用句子编码器,并使用它找到相似的句子。

你可以从这里下载相关向量。

我们将使用 TensorFlow hub 加载模块。

module_url = "../input/universalsentenceencoderlarge4"

embed = hub.load(module_url)

接下来,我们将为列表中的每个句子创建嵌入。

sentence_list=df.question_text.values.tolist()
sentence_emb=embed(sentence_list)['outputs'].numpy()

这里有一篇关于通用句子编码器的文章。

埃尔莫、伯特和其他人

当使用上述任何一种嵌入方法时,我们忘记的一件事是单词的上下文。这是这种单词表示模型的主要缺点之一。

例如,单词“stick”将使用与上下文无关的相同向量来表示,这没有多大意义。随着 NLP 领域和 BERT(变压器的双向编码器表示)等模型的最新发展,这已经成为可能。这里有一篇文章可以多看。

文本分类

在本节中,我们将准备嵌入矩阵,该矩阵被传递到 Keras 嵌入层以学习文本表示。您可以使用相同的步骤为任何单词级嵌入方法准备语料库。

让我们创建一个单词索引并确定一个最大句子长度,使用 Keras Tokenizerpad_sequences 填充我们语料库中的每个句子。

MAX_LEN=50
tokenizer_obj=Tokenizer()
tokenizer_obj.fit_on_texts(corpus)
sequences=tokenizer_obj.texts_to_sequences(corpus)

tweet_pad=pad_sequences(sequences,
                        maxlen=MAX_LEN,
                        truncating='post',
                        padding='post')

让我们检查一下语料库中独特单词的数量,

word_index=tokenizer_obj.word_index
print('Number of unique words:',len(word_index))

使用这个单词索引字典和嵌入字典,您可以为我们的语料库创建一个嵌入矩阵。这个嵌入矩阵被传递到神经网络的嵌入层以学习单词表示。

def prepare_matrix(embedding_dict, emb_size=300):
    num_words = len(word_index)
    embedding_matrix = np.zeros((num_words, emb_size))

    for word, i in tqdm(word_index.items()):
        if i > num_words:
            continue

    emb_vec = embedding_dict.get(word)
    if emb_vec is not None:
        embedding_matrix[i] = emb_vec

    return embedding_matrix

我们可以定义我们的神经网络,并将这个嵌入索引传递给网络的嵌入层。我们将向量传递到嵌入层,并设置trainible = False以防止权重被更新。

def new_model(embedding_matrix):
    inp = Input(shape=(MAX_LEN,))

    x = Embedding(num_words, embedding_matrix.shape[1], weights=[embedding_matrix],
                  trainable=False)(inp)

    x = Bidirectional(
        LSTM(60, return_sequences=True, name='lstm_layer',
             dropout=0.1, recurrent_dropout=0.1))(x)

    x = GlobalAveragePool1D()(x)
    x = Dense(1, activation="sigmoid")(x)
    model = Model(inputs=inp, outputs=x)

    model.compile(loss='binary_crossentropy',
                  optimizer='adam',
                  metrics=['accuracy'])

    return model

例如,要使用 word2vec 嵌入来运行模型,

embeddings_index=load_word2vec()
embedding_matrix=prepare_matrix(embeddings_index)
model=new_model(embedding_matrix)

history=model.fit(X_train,y_train,
                  batch_size=8,
                  epochs=5,
                  validation_data=(X_test,y_test),
                  verbose=2)

您可以调用您想要的嵌入类型,并遵循相同的步骤来实现它们中的任何一个。

比较

那么,在我们的示例问题中,哪种文本分类方法效果最好呢?

您可以使用 Neptune 通过简单地设置一个实验来比较使用不同嵌入的模型的性能。

与其他两种嵌入相比,手套嵌入在测试集中表现稍好。通过对数据进行大规模清理并调整模型,您可能会获得更好的结果。

如果你愿意,你可以在这里探索实验。

最后的想法

在本文中,我们讨论并实现了不同的文本分类特征表示方法,您可以将这些方法用于较小的数据集。

希望你会发现它们对你的项目有用。**

实验跟踪的 DVC 替代方案

原文:https://web.archive.org/web/https://neptune.ai/blog/dvc-alternatives-for-experiment-tracking

实验跟踪是一种将变量与这些变量引起的数据变化联系起来的技术。您可以测试许多不同的变量组合——使用分配给每个变量的权重运行多个实验,并查看哪些组合在一起时最有效。

实验跟踪的挑战之一是为这项任务选择正确的工具。你需要考虑很多因素:整合、培训进度、项目管理能力、定价等等。

在这篇文章中,我们将探索一种有助于实验跟踪的工具——数据版本控制(DVC)。但是,我们还会:

  • 审查数据版本控制的最佳替代方案(DVC),
  • 比较不同的实验跟踪工具。

数据版本控制(DVC)

DVC 是一个机器学习项目的开源平台。DVC 帮助数据科学家和开发人员进行数据版本控制、工作流管理和实验管理。DVC 很容易适应,用户可以利用新的功能,同时重用现有的功能。

DVC 摘要

  • 多语言和多框架支持。

  • 您可以对大量数据进行版本控制。

  • DVC 是一个兼容 Git 的工具,它将代码库连接在一起形成一个无缝的网络,并允许跨多个项目的轻松协作。

  • 有时候事情不会按计划进行。DVC 让你以一种可重复且易于管理的方式跟踪一切,因此你可以节省大量的时间和资源。DVC 通过维护输入数据、环境变量、代码等来保证可再现性。

  • DVC 是一个轻量级的开源工具,很容易适应多种语言和框架,但同时你可能会发现很难定制

  • DVC 可以处理大量数据,但提供的功能有限。

  • 在某些情况下,对于大量实验,可能会有可扩展性问题。

DVC 并不适合所有人。所以,让我们来看看 DVC 的一些好的替代品:

Neptune 是为研究和生产团队开发的 MLOps 的元数据存储。它为您提供了一个记录、存储、显示、组织、比较和查询机器学习生命周期中生成的所有元数据的中心。研究人员和工程师使用海王星进行实验跟踪和模型注册,以控制他们的实验和模型开发。

海王星摘要

Neptune 让团队更容易组织和管理机器学习项目。其直观的用户界面可让您分组组织跑步,保存自定义仪表板视图,并与您的团队快速共享。

  • 记录和显示所有元数据类型,包括参数、模型权重、媒体文件等。
  • 轻松协作和监督项目。
  • 直观的用户界面,有很多功能来分组组织跑步。
  • 比较见识和参数。
  • 自动记录代码、环境、参数、模型二进制文件等等。
  • 跟踪在脚本、笔记本和任何基础设施上执行的实验。
  • 广泛的实验跟踪和可视化功能。
  • 您可以使用托管应用程序来避免维护另一个工具的所有麻烦,或者将它部署在您的基础架构上以实现最大控制。
  • 您可以监控硬件,让您的实验自动运行。检查模型训练运行消耗的 GPU/CPU 和内存量。
  • Neptune 提供了一个 Python 客户端库,可以让你记录并跟踪他们的 ML 实验中的任何元数据类型,无论这些实验是在 Python 脚本、Jupyter 笔记本、Amazon SageMaker 笔记本还是 Google Colab 中运行。

定价

  • 个人:免费(超出免费配额的使用量)
  • 学术界:免费
  • 团队:付费
  • 了解更多: 海王定价

比较工具

检查海王星和 DVC 之间的差异——哪个工具更适合实验追踪?

weights & bias(WandB)是一个为研究人员和深度学习团队提供机器学习工具的平台。WandB 帮助您进行实验跟踪、数据集版本控制和模型管理。WandB 可以让你轻松地跟踪、比较、版本化和可视化你的机器学习和深度学习实验。

WandB 最棒的地方在于,你可以在桌面和手机上访问你的训练模型和结果。轻量级协作系统让您可以轻松地共享和管理您的项目,并提供良好的文档。

WandB 摘要

  • 它易于使用,有一个很好的用户界面,让用户可以可视化,比较和组织他们的实验到交互式的图形和表格中。
  • 您可以可视化 CPU 和 GPU 的使用情况。
  • 您可以将文件和数据集存储在 WandB 或本地存储器上。
  • 与团队协作、轻松共享和创建项目社区。
  • 轻松调试音频、视频、图像和 3D 对象。
  • 自动版本化记录的数据集。
  • 开源集成。

定价

  • 个人:免费(超出免费配额的使用量)
  • 学术界:免费
  • 团队:付费
  • 了解更多: WandB 定价

Comet 是一个基于云的元机器学习平台,开发者可以在其中跟踪、比较、分析和优化实验。Comet 提供了关于您的实验的实时统计数据和图表。

彗星摘要

  • 集成很快,只需几行代码,您就可以开始跟踪您的 ML 实验,而无需任何库。
  • 轻松比较您的实验,包括代码、指标、预测、见解等等。
  • 调试和监控您的模型,当您的实验出现问题时会收到警报。
  • 面向数据科学家和业务利益相关者的简单高效的协作平台。
  • 为您的实验和数据定制可视化。
  • 自动适用于笔记本和脚本。

定价

  • 个人:免费(超出免费配额的使用量)
  • 学术界:免费
  • 团队:付费
  • 了解更多:彗星定价

比较工具

参见彗星和海王星的区别

MLFlow 是一个用于管理机器学习生命周期的开源工具。它帮助数据科学家和开发人员进行实验、部署和模型注册。它可以与多个 ML 库和工具一起工作。

MLFlow 摘要

  • 它可以与多种机器学习库、语言或任何现有代码一起工作。
  • MLflow 有四个主要特性——跟踪、项目、模型和注册。
  • 您可以使用 MLflow 跟踪来记录和查询您的代码和数据实验。
  • MLflow 项目包括可重用和可复制的代码。它还带有一个 API 和一个命令行工具,用于 ML 和数据科学任务。
  • 使用 MLFlow 可以部署不同类型的 ML 模型。模型存储为包含任意数量文件的目录。

Verta AI 提供了一个平台来跟踪、协作、部署和监控您的机器学习实验。Verta AI 让您可以版本化、管理、分析、共享、治理、部署等等。它确保了高质量的运营以及一致的性能和可扩展性。

vertu ai 摘要

  • 支持顶级开源框架和平台。
  • 用不同的属性组织工作。
  • 直观的用户界面。
  • 使用代码、变量、数据和配置的模型再现性。
  • 与团队轻松分享和协作您的实验。
  • 实时监控和日志记录。

定价

  • 有限计划-免费
  • SaaS–提供试用
  • 企业–联系支持
  • 参见Verta AI了解更多

**Kubeflow 是 Kubernetes 的开源机器学习工具。Kubeflow 提供了详细而强大的跟踪。Kubeflow 并不是 100%专注于实验跟踪,但是它确实有一些特性,比如数据版本控制、模型版本控制、资源监控等等。

Kubeflow 摘要

  • 在不同的基础设施上进行可重复、可移植的部署。
  • 开源,集成了许多框架和平台。
  • Kubeflow 非常适合 Kubernetes 用户。
  • 它是可扩展的,在超参数调整方面具有很大的灵活性。
  • 访问kube flow了解更多信息。

**Polyaxon 是一个专门用于管理机器学习生命周期以及促进 ML 团队合作的应用程序。Polyaxon 面向数据科学家、架构师、团队领导和高管。它提供了广泛的产品(如跟踪、编排、优化、洞察、模型管理、协作等)。

多轴特征

  • Polyaxon 允许您自动跟踪基本的模型度量、超参数、可视化、人工制品、资源以及版本控制代码和数据。
  • 比较、过滤和搜索,以便更好地了解您的实验。
  • 轻量级集成,几行代码入门。
  • 支持大多数流行的框架和工具。
  • 在不改变你的工作流程的情况下,代码和模型之间的链接是非常容易的。
  • 轻松的团队协作。
  • 您可以将它部署在云上或本地机器上。
  • 以并行和分布式的方式运行实验。

定价

  • 起步计划-每月 300 美元
  • 平台计划——每月 450 美元
  • 商业计划——每月 1200 美元
  • 企业–联系支持
  • 参见了解详情。

****### 比较工具

参见多轴子和海王星的区别

有了 Amazon SageMaker,你可以准备、构建、训练、调优、部署和管理你所有的机器学习实验。它提供了一个易于使用的界面,使得开发人员和数据科学家的工作更加容易。如果您已经在使用 AWS,那么 Sagemaker Studio 将是最适合您的,因为它为所有 AWS 产品提供了良好的集成支持。

pagemaker studio 摘要

  • 它可以与其他 AWS 工具无缝协作。
  • 易于使用的界面。
  • 你可以追踪数以千计的实验。
  • 从头到尾管理您的实验。
  • 它提供了用于训练和运行实验的内置算法。
  • SageMaker 提供了一个内置的调试器,因此您可以识别并减少错误。

定价

  • 前两个月免费试用。
  • 免费试用结束后,就是现收现付了。
  • 访问 Sagemaker 了解更多信息。

比较工具

参见 SageMaker Studio 与海王星的深度对比。

Guild AI 是一个开源的 ML 实验跟踪平台。它是轻量级的,并提供了广泛的功能,使运行、分析和优化机器学习实验变得更加容易。

公会人工智能总结

  • Guild 会自动存储你实验的每一个过程。
  • 比较和分析,获得实验的详细结果。
  • 入门容易,可以集成任何语言和库。
  • 既可以在 GPU 加速的云系统上运行,也可以在本地机器上运行。
  • 远程培训和备份的可能性。
  • 访问 公会 AI 了解更多。

为你的团队选择正确的 ML 实验跟踪工具可能很难。你必须考虑许多事情:

  • 集成,
  • 培训进展,
  • 项目管理能力,
  • 定价等等。

因此,我们将比较开源、商业和特定于平台的工具,看看哪一个可能最适合您的机器学习或深度学习工作流。首先,让我们看看在选择实验跟踪工具时需要考虑的事情。

要考虑哪些因素?

跟踪:你将会跟踪很多东西,包括超参数、模型、代码、资源、洞察力等等。确保你选择的工具提供了你的机器/深度学习项目所需的所有东西。

存储:保存你的数据和实验很重要。一些工具提供基于云的存储,而一些工具更喜欢本地存储。

视觉化:一个好的视觉表现将帮助你轻松地分析结果。它使复杂的事情变得容易理解,除此之外,你还可以向你的利益相关者展示可视化的结果。因此,请确保您选择的工具具有一些良好的可视化功能。

稳定性和可伸缩性:在企业层面,你需要一个稳定的工具,提供简单的团队协作。

有许多工具可以帮助使用各种功能和技术跟踪实验。一般来说,这些工具可以分为三类:

  • 开源的,
  • 商业,和
  • 特定于平台。

我们将看看这些部分的优点和缺点,并评估一些实验跟踪工具。

优点

  • 自由的
  • 可以根据您的需求定制
  • 可以处理大量数据
  • 良好的社区支持

缺点

  • 缺乏专家支持
  • 可扩展性问题
  • 有限的功能
  • 长期分享和管理问题

优点

  • 易于使用和直观的用户界面
  • 专家支持
  • 有利于长期使用和稳定性
  • 为您的 ML 实验提供更多功能

缺点

  • 在某些情况下,价格可能是一个问题
  • 并不是每个工具和框架都受支持
  • 有限定制

优点

  • 与平台无缝集成
  • 专家支持

缺点

  • 可能需要一些特殊的基础设施并依赖于 API
  • 只有与平台集成才能正常工作
  • 定价可能高于其他商业工具

结论

实验跟踪在你的机器学习或深度学习之旅中起着重要的作用,所以为你的实验选择合适的平台是至关重要的一部分。有许多工具,但只有少数适合您的工作流程。有些公司提供免费试用,你可以试试,看看你是否喜欢他们的平台。希望这篇文章对你有所帮助,祝你实验顺利!

参考资料和推荐读物

哈希尔·帕特尔

Android 开发者和机器学习爱好者。我热衷于开发移动应用程序、制造创新产品和帮助用户。

接下来的步骤

如何在 5 分钟内上手海王星


1.创建一个免费帐户

2.安装 Neptune 客户端库

3.将日志记录添加到脚本中

Sign up

2. Install Neptune client library
pip install neptune-client

3. Add logging to your script
import neptune.new as neptune

run = neptune.init_run("Me/MyProject")
run["parameters"] = {"lr":0.1, "dropout":0.4}
run["test_accuracy"] = 0.84

Try live notebook


海王星提前停止

原文:https://web.archive.org/web/https://neptune.ai/blog/early-stopping-with-neptune

最近对 20,036 名担任数据科学家的 Kaggle 成员进行的调查(发表在 2020 年机器学习和数据科学报告中)显示,大多数现实世界的问题都可以使用流行的机器学习算法轻松解决,如线性或逻辑回归,决策树或随机森林。但是,数据科学界发展最快的研究领域是深度学习——主要是神经网络[1]。

深度学习是机器学习的一个新兴领域。最近,它在研究人员和工程师中很受欢迎。深度学习在许多工业应用中表现出了一流的性能——自动驾驶、航空航天和国防、医学研究、工业自动化和电子。

深度学习实际上是人工智能子集的子集。

AI, machine learning, and deep learning

Figure 1: AI, machine learning, and deep learning

在过去的几年里,深度神经网络已经在计算机视觉、语音识别、自然语言处理、图像分类和对象检测等广泛的领域中显示出巨大的成功。

研究表明,在 2006 年之前,深度神经网络没有被成功训练。从那以后,已经实现了几种算法来提高神经网络的性能。

与浅层网络相比,深层神经网络更难训练。在本文中,我们的主要目标是强调训练神经网络中一个价值百万美元的问题:训练一个神经网络需要多长时间

神经网络训练时间会导致训练和测试数据的欠拟合(过短)或过拟合(过长)。过度拟合是监督机器学习中的一个非常基本的问题,它阻止我们概括模型的性能,因为模型在训练集的观察数据上拟合得很好,但在测试集上表现很差。

欠拟合与过拟合

一般来说,欠拟合和过拟合只不过是方差和偏差之间的权衡。

在统计学和机器学习中,偏差-方差权衡是模型的一个非常重要的性质。偏差是模型的平均预测值和我们试图预测的真实值之间的误差。高偏差会导致模型错过数据中的重要信息,并使模型过于简化(拟合不足)。

方差是对训练集的小波动的敏感性的误差。在具有高方差的模型中,训练集中的微小变化会导致精确度发生非常大的变化。该模型可以在观察到的数据上表现良好,而在以前没有观察到的数据上表现不佳(过拟合)。

bias variance tradeoff

Figure 2: Bias – Variance Tradeoff [2]

欠拟合

无法捕捉数据潜在趋势的机器学习模型通常被定义为拟合不足。当模型拟合不足时,它不能很好地拟合数据,因此它可能会错过数据中的重要信息。

当模型与可用数据相比非常简单时,通常会出现拟合不足。可用数据较少,数据中有噪声,或者当我们试图用非线性数据建立线性模型时[3]。在欠拟合期间,模型不仅在测试数据上表现不佳,甚至在对训练数据集进行训练期间也表现不佳。

underfitting

Figure 3: Underfitting [3]

欠拟合数据的模型往往具有:

  1. 低方差和高偏差,
  2. 更少的特征(例如 x)。

减少欠拟合的技术:

  1. 使模型更加复杂,
  2. 执行特征工程,
  3. 增加训练时间或历元数。

过度拟合

当 ML 模型被允许训练更长的时间时,它将不仅从可用数据开始学习,而且从数据中的噪声开始学习,那么机器学习模型是过度拟合的。因此,由于存在噪声、训练集的有限大小以及分类器的复杂性,会发生过拟合[2]。

overfitting

Figure 4: Overfitting [3]

过度拟合的模型往往具有:

  1. 高方差和低偏差。
  2. 高特征(例如 x,x ² ,x ³ ,x ⁴ ,…)

减少过度拟合的技术:

  1. 增加训练集上的观察数据,
  2. 让模型更简单,
  3. 提前停车,
  4. 使用“网络缩减”策略减少训练集中的噪声,
  5. 数据增强,
  6. 正规化-L1,L2,辍学。

捕捉数据总体趋势的模型不会趋向于欠拟合或过拟合。

perfect fit

Figure 5: Perfect fit [3]

非常符合数据的模型往往具有:

  1. 低方差和低偏差,
  2. 合理数量的特征,
  3. 即使在未观察到的数据上也表现很好。

神经网络中的早期停止

训练神经网络的主要挑战之一是训练神经网络的时间长度。为有限数量的时期训练模型会导致拟合不足,而为大量时期训练模型会导致拟合过度。监控训练过程,在适当的时候停止训练是非常重要的。

在本文中,我们将发现在神经网络过度拟合之前尽早停止神经网络的训练,实际上可以减少过度拟合,并导致更好的模型性能——在训练和测试数据集上都是如此。

在训练神经网络时,在某个点上,模型将停止归纳并开始学习数据中的噪声,这使得模型在未观察到的数据上表现不佳。为了克服这个问题,我们将使用历元数作为超参数之一,并监控训练和测试损失。

训练神经网络时,我们将在每个时期后输入测试数据集,并监控测试损失。如果模型性能下降(测试损失开始增加),或者测试精度降低,训练过程将停止。

early stopping

Figure 6: Early stopping [4]

用海王星来监控实验

使用 Neptune 可以轻松地监控训练过程和其他实验。这是一个非常棒的工具,可以帮助研究人员和机器学习工程师监控和组织他们的项目,与队友分享结果,并通过使用单一平台来改善团队合作。


请注意,由于最近的 API 更新,这篇文章也需要一些改变——我们正在努力!与此同时,请检查海王星文档,那里的一切都是最新的!


在海王星设置实验的过程非常简单。第一步是注册一个帐户,这将为您的实验创建一个唯一的 id 和一个仪表板。

您将使用唯一的令牌 ID 将任何深度学习框架(如 TensorFlow 或 PyTorch)链接到 Neptune。在我们的实验中,我们将使用 PyTorch 。注册并按照以下步骤创建一个唯一的 id。

Neptune unique-id

Figure 7: Neptune unique id [5]

为了使用 Python 直接从 Pytorch 访问 Neptune 仪表板,Neptune.ai 的开发人员开发了一个易于访问的工具箱,可以使用 pip 安装:

pip install neptune-client

安装完成后,可以通过将 Neptune 导入到主 Python 脚本来轻松完成实验初始化:

import neptune

NEPTUNE_API_TOKEN="<api-token-here>"
neptune.init('<username>/sandbox',api_token=NEPTUNE_API_TOKEN)
neptune.create_experiment('Pytorch-Neptune-Example')

海王星与 PyTorch 的融合

实验装置

在我们的实验中,我们将使用 CIFAR10 影像分类数据集。CIFAR-10 数据集由 10 类 60000 幅 32×32 彩色图像组成,每类 6000 幅图像。有 50,000 个训练图像和 10,000 个测试图像。

以下是数据集中的类,以及每个类中的 10 幅随机图像:

Experimental setup

Figure 8: CIFAR10 Dataset [6]

数据集可以在 PyTorch 中轻松下载。导入 Torchvision 并使用以下命令:

import torchvision.datasets as datasets

cifar_trainset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)

cifar_testset = datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)

为了解释早期停止的重要性,我们将使用一个简单复杂的(例如,没有 BatchNorm,或任何正则化技术,如 dropout)卷积神经网络(CNN)架构来训练训练数据集上的模型,并故意过度拟合数据。

本实验使用的 CNN 架构如下:

class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=(1, 1))
        self.conv2 = nn.Conv2d(32, 32, kernel_size=3, padding=(1, 1))
        self.conv3 = nn.Conv2d(32, 64, kernel_size=3, padding=(1, 1))
        self.conv4 = nn.Conv2d(64, 64, kernel_size=3, padding=(1, 1))
        self.conv5 = nn.Conv2d(64, 128, kernel_size=3, padding=(1, 1))
        self.conv6 = nn.Conv2d(128, 128, kernel_size=3, padding=(1, 1))
        self.maxpool = nn.MaxPool2d(2, stride=2)
        self.fc1 = nn.Linear(128 * 4 * 4, 1024)
        self.fc2 = nn.Linear(1024, 512)
        self.fc3 = nn.Linear(512, 10)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = self.maxpool(F.relu(self.conv2(x)))
        x = F.relu(self.conv3(x))
        x = self.maxpool(F.relu(self.conv4(x)))
        x = F.relu(self.conv5(x))
        x = self.maxpool(F.relu(self.conv6(x)))
        x = x.view(-1, 128 * 4 * 4)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.log_softmax(self.fc3(x), dim=1)
        return x

将 Python 脚本集成到 Neptune

在训练过程中,将监控训练/测试损失和训练/测试准确度,可以使用 Neptune.log_metric() 函数轻松调用。

PyTorch python 脚本与 Neptune 的集成在 fit()函数中类似如下:

def fit(model, train_loader, test_loader, epochs, optimizer, loss):
    model.train()
    import neptune
    neptune.init(project_qualified_name='sanghvirajit/sandbox',    api_token='eyJhcGlfYWRkcmVzcyI6Imh0dHBzOi8vdWkubmVwdHVuZS5haSIsImFwaV91cmwiOiJodHRwczovL3VpLm5lcHR1bmUuYWkiLCJhcGlfa2V5IjoiN2Y4MzU5YTctZmJjZS00MmU5LTg4YmYtNDUwZWI5ZTQ3ZmJmIn0=',)

    PARAMS = {'train_batch_size': 5000,
    'test_batch_size': 1000,
    'optimizer': 'Adam'}

    neptune.create_experiment('Pytorch-Neptune-CIFAR10-Early     Stopping',params=PARAMS,tags=['classification','pytorch','neptune'])

    if optimizer == 'Adam':

    optimizer = torch.optim.Adam(model.parameters())

    if loss == 'CrossEntropy':

    error = nn.CrossEntropyLoss()

    for epoch in range(epochs):

        correct = 0
        for batch_idx, (X_batch, y_batch) in enumerate(train_loader):

        var_X_batch = Variable(X_batch).float()
        var_y_batch = Variable(y_batch)

        optimizer.zero_grad()

        output = model.forward(var_X_batch)

        loss = error(output, var_y_batch)
        train_cost = loss.data

        loss.backward()

        optimizer.step()

        predicted = torch.max(output.data, 1)[1]
        correct += (predicted == var_y_batch).sum()
        Train_accuracy = float(correct*100) / float(train_batch_size*(batch_idx+1))

        test_accuracy, test_cost = evaluate(model, test_loader)

    print('Epoch : {} [{}/{} ({:.0f}%)]tLoss: {:.6f}t Accuracy:{:.3f}%'.format(
    epoch+1,
    (batch_idx+1)*(len(X_batch)),
    len(train_loader.dataset),
    100.*(batch_idx+1) / len(train_loader),
    train_cost,
    train_accuracy))

    neptune.log_metric('training loss', train_cost)
    neptune.log_metric('training accuracy', train_accuracy)

    neptune.log_metric('testing loss', test_cost)
    neptune.log_metric('testing accuracy', test_accuracy)

neptune.stop()

可以很容易地调用 fit()函数,这将生成一个链接,该链接将我们重定向到 Neptune 仪表板:

fit(cnn, train_loader, test_loader, epochs=100, optimizer='Adam', loss='CrossEntropy')

Early stopping fit function

现在可以使用 Neptune 中的图表轻松监控测试损失:

Neptune monitoring loss

Figure 9: Monitoring testing loss in Neptune

日志指标可在日志下访问,通道数据可轻松下载。csv 文件格式,用于结果的进一步后处理。

Neptune log metrics

Figure 10: Log metric in Neptune

让我们看看我们得到的结果:

Early stopping results

Figure 11: Results

图 11 显示了训练和测试数据集的分类结果。训练准确率达到 98.84%,而测试准确率只能达到 74.26%。

正如我们所看到的,测试损失在第 55 纪元左右开始分散。该模型已经学会对训练集进行很好的分类,以至于它失去了有效概括的能力,即正确分类测试集上未观察到的数据的能力。因此,该模型开始在测试数据集上表现不佳——它过度拟合

在这种情况下,最好在第 55 世左右停止训练。

现在,让我们在代码中引入提前停止:

valid_loss_array = np.array(valid_losses)
min_valid_loss = np.min(valid_loss_array)

if(test_cost > min_valid_loss):
patience_counter += 1
else:

patience_counter = 0

if(patience_counter > patience):
        print("Early stopping called at {} epochs".format(epoch+1))
        break

我们将使用耐心作为超参数之一来触发训练期间的提前停止。耐心是测试损失没有改善的次数,在此之后训练过程将停止。

让我们调用耐心值为 10 的 fit()函数,并监控训练过程:

Neptune monitoring patience

Figure 12: Monitoring testing loss in Neptune

让我们再来看看我们得到的结果:

Early stopping results

Figure 13: Results

从结果中我们可以注意到,在第 44 个时期之后,测试损失没有进一步的改善,因此在第 54 个时期触发了早期停止,并且训练过程如我们所预期的那样停止了。

这消除了训练过程中过拟合的可能性,也有助于节省我们的计算资源和时间。

摘要

在本文中,我们发现了早期停止在深度神经网络模型中的重要性。

具体来说,我们已经看到:

  • 早期停止减少了训练过程中的过度配合,
  • 我们可以使用 Neptune 监控机器学习项目,以及如何将 PyTorch python 脚本集成到 Neptune。

如果你对实验的详细代码感兴趣,可以在 my Github 上找到。

参考

[1] 数据科学与机器学习 2020 年状态

[2]了解偏差-方差权衡-https://towards data science . com/Understanding-the-Bias-Variance-trade-165 e 6942 b229

[3]解决欠拟合和过拟合-https://morioh.com/p/ebe9597eae3a

[4]使用 PyTorch 提前停止以防止模型过度拟合–https://medium . com/analytics-vid hya/Early-Stopping-with-py torch-to-inhibit-your-Model-from-over fitting-dce6de 4081 C5

[5] Neptune.ai 文档—设置 Neptune API 令牌

[6]CIFS ar 10 和 CIFAR100 数据集—https://www.cs.toronto.edu/~kriz/cifar.html

[7]薛瑛。CISAT 2018。过度拟合及其解决方案概述-https://IOP science . IOP . org/article/10.1088/1742-6596/1168/2/022022/pdf

[8]Lutz pre helt。“早停——但是什么时候?."《神经网络:交易的诀窍》,第 55-69 页。施普林格,柏林,海德堡,1998—https://docs.google.com/viewer?URL = https % 3A % 2F % 2f page . mi . fu-Berlin . de % 2f pre chelt % 2f iblio % 2f stop _ tricks 1997 . pdf

来自 ECML-PKDD 2020 会议的顶级“应用数据科学”论文

原文:https://web.archive.org/web/https://neptune.ai/blog/ecml-pkdd-2020-applied-data-science

上周,我参加了 ECML-PKDD 2020 会议。欧洲机器学习和数据库中知识发现的原理和实践会议是欧洲最受认可的关于 ML 的学术会议之一

本着传播 ML 发展的精神,我想分享我从会议中挑选的最好的“应用数据科学”论文。这是这个系列的第二篇文章。上一篇关于顶级研究的论文,可以在这里找到。一定要检查它。

应用数据科学论文和演示对纯研究论文是一个很好的补充。由于这一点,会议在研究和行业主题之间取得了平衡。

在本帖中,论文按照会议计划进行分类:

尽情享受吧!

运动

1.停止时钟:超时效应是真实的吗?

论文 | 简报

论文摘要:暂停是游戏过程中的短暂中断,用于传达策略的变化,让玩家休息或停止游戏中的负面流。(…)但是,这些超时在这方面的效果如何呢?暂停前后得分差异的简单平均值被用作存在影响且影响显著的证据。我们声称这些统计平均值不是适当的证据,需要一个更合理的方法。我们应用了一个正式的因果框架,使用了一个大型的 NBA 官方比赛列表数据集,并在因果图中绘制了我们对数据生成过程的假设。(…)


2.基于目标检测和 LSTM 的足球视频流自动传球标注

论文 | 简报

论文摘要:由于可以获得描述每场比赛中发生的所有时空事件的数据,足球分析正在吸引学术界和工业界越来越多的兴趣。(…)在本文中,我们描述了 PassNet,这是一种从视频流中识别足球中最常见事件(即传球)的方法。我们的模型结合了一组人工神经网络,这些网络从视频流中执行特征提取,对象检测以识别球和球员的位置,并将帧序列分类为传球或不传球。(…)


3.SoccerMix:用混合模型表示足球动作

论文 | 简报

论文摘要:分析比赛风格是足球分析中的一项重复任务,在俱乐部活动中起着至关重要的作用,如球员球探和比赛准备。(…)当前用于分析比赛风格的技术经常受到足球事件流数据的稀疏性的阻碍(即,同一球员很少在同一位置多次执行相同的动作)。本文提出了 SoccerMix,一种基于混合模型的软聚类技术,实现了一种新的足球动作概率表示。(…)

主要作者:


4.SoccerMap:一个用于足球可视化分析的深度学习架构

论文 | 简报

论文摘要:我们提出了一种全卷积神经网络架构,它能够从高频时空数据中估计足球中潜在传球的全概率表面。该网络接收多层低级输入,并学习在不同采样级别生成预测的要素等级,从而捕捉粗略和精细的空间细节。通过合并这些预测,我们可以为任何比赛情况生成视觉上丰富的概率表面,使教练能够对球员的定位和决策进行精细分析,这是体育领域中迄今为止很少探索的领域。(…)

硬件和制造

1.学习 I/O 访问模式以提高固态硬盘的预取性能

论文 | 简报

论文摘要:基于闪存的固态硬盘已经成为云计算和移动环境中硬盘的高性能替代产品。然而,固态硬盘仍然是计算机系统的性能瓶颈,因为它们的 I/O 访问延迟很高。(…)在本文中,我们讨论了固态硬盘中预取的挑战,解释了先前方法无法实现高精度的原因,并提出了一种基于神经网络的预取方法,该方法明显优于现有技术。为了实现高性能,我们解决了在非常大的稀疏地址空间中预取的挑战,以及通过提前预测及时预取的挑战。(…)


2.FlowFrontNet:用 CNN 改进碳复合材料制造

论文 | 简报

论文摘要:碳纤维增强聚合物(CFRP)是一种轻质而坚固的复合材料,旨在减轻航空航天或汽车部件的重量,从而减少温室气体排放。树脂传递模塑(RTM)是 CFRP 的一种制造工艺,可以放大到工业规模生产。(…)我们提出了一种深度学习方法 FlowFrontNet,通过学习从传感器到流动前沿“图像”的映射(使用向上扩展层)来增强原位过程视角,以捕捉流动前沿的空间不规则性来预测干点(使用卷积层)。(…)


3.基于 FPGAs 的深度学习现场伽马-强子分离

论文 | 简报

论文摘要:现代高能天体粒子实验每天在连续的大容量流中产生大量数据。(……)从背景噪音中分离出伽马射线是不可避免地要被记录下来的,这被称为伽马-强子分离问题。当前的解决方案严重依赖手工制作的功能。(…)事件发生后,整个机器学习管道在商用计算机硬件上执行。在本文中,我们提出了一种替代方法,将卷积神经网络(CNN)和二进制神经网络(BNNs)直接应用于望远镜相机的原始特征流。(…)

第一作者:

塞巴斯蒂安

网站


4.从电网络传感器提取可解释的尺寸一致特征

论文 | 简报

论文摘要:电力网络是高度监控的系统,需要操作员在了解底层网络状态之前执行复杂的信息合成。我们的研究旨在通过从传感器数据自动创建特征来帮助这一合成步骤。我们提出了一种使用语法引导进化的监督特征提取方法,它输出可解释的和维度一致的特征。(…)

运输

1.用于推荐具有提前预约的出租车路线的多标准系统

论文 | 简报

论文摘要:随着出租车预约服务需求的增加,如何通过高级服务增加出租车司机收入的策略备受关注。然而,由于利润的不平衡,需求通常得不到满足。本文提出了一个考虑实时时空预测和交通网络信息的多准则路径推荐框架,旨在优化出租车司机提前预约时的利润。(…)

第一作者:

范德尔林


2.基于模型字典聚类的自动驾驶验证

论文 | 简报

论文摘要:自动驾驶系统的验证仍然是汽车制造商为了提供安全的无人驾驶汽车而必须解决的最大挑战之一。(…)在本文中,我们提出了一种应用于自动驾驶数值模拟产生的时间序列的新方法。这是一种基于字典的方法,由三个步骤组成:每个时间序列的自动分段、状态字典的构建和产生的分类序列的聚类。我们提出了时间序列的具体结构和建议的方法优势,处理这样的数据,与国家的最先进的参考方法。


3.使用深度学习模型实现租赁车辆回报评估的自动化

论文 | 简报

论文摘要:损害评估包括对损害进行分类和估计其修理费用,是车辆租赁和保险行业的一个基本流程。特别是车辆租赁,租赁结束评估对客户必须支付的实际成本有很大影响。(…)在本文中,我们提出了一种基于机器学习(ML)的租赁车辆回报评估自动化解决方案。此外,我们强调了在处理没有标准过程收集的数据集时,标准的 ML 模型及其训练协议是如何失败的。(…)


4.具有协调强化学习的实时车道配置

论文 | 简报

论文摘要:根据交通模式改变道路的车道配置,是提高交通流量的一种行之有效的解决方案。传统的车道方向配置解决方案假设预先知道交通模式,因此不适合现实世界的应用,因为它们不能适应变化的交通条件。我们提出了一个动态车道配置解决方案来改善交通流使用两层,多代理架构,命名为协调学习为基础的车道分配(CLLA)。(…)


5.学习用于按需交付应用的感兴趣区域的上下文和拓扑表示

论文 | 简报

论文摘要:城市区域的良好表现对于按需交付服务(如 ETA 预测)非常重要。然而,现有的表示方法要么从稀疏的签到历史中学习,要么从拓扑几何中学习,因此要么缺乏覆盖并且违反了地理规律,要么忽略了来自数据的上下文信息。在本文中,我们提出了一种新的表示学习框架,用于从上下文数据(轨迹)和拓扑数据(图形)中获得感兴趣区域的统一表示。(…)

异常检测

1.使用上下文特征解释端到端 ECG 自动诊断

P a | 演示

论文摘要:我们提出了一种新的方法来生成对端到端分类模型的解释。解释包括对用户有意义的特征,即上下文特征。我们在自动心电图(ECG)诊断的场景中实例化我们的方法,并分析在可解释性和鲁棒性方面产生的解释。所提出的方法使用噪声插入策略来量化 ECG 信号的间隔和分段对自动分类结果的影响。(…)


2.自我监督的日志解析

论文 | 简报

论文摘要:日志在软件系统的开发和维护过程中被广泛使用。(…)然而,大规模软件系统会产生大量的半结构化日志记录,这给自动化分析带来了重大挑战。将带有自由格式文本日志消息的半结构化记录解析成结构化模板是实现进一步分析的第一步,也是关键的一步。现有的方法依赖于特定于日志的试探法或手动规则提取。(…)我们提出了一种称为 NuLog 的新解析技术,该技术利用自我监督学习模型,并将解析任务公式化为掩蔽语言建模(MLM)。(…)


3.环境智能系统中基于上下文的异常行为检测方法

论文 | 简报

论文摘要:异常的人类行为可能是健康问题或危险事件发生的征兆。检测这种行为在环境智能(AmI)系统中是必不可少的,以增强人们的安全性。(…)在本文中,提出了一种利用人类行为的上下文信息来检测这种行为的新方法。(…)


4.基于预测误差模式的多元时间序列异常检测

论文 | 简报

论文摘要:以信息物理系统(CPSs)的发展为部分特征的工业 4.0 的到来,自然需要可靠的安全方案。(…)在这项工作中,我们的目标是对异常检测技术在 CPSs 中的应用文献做出贡献。我们提出了新的功能数据分析(FDA)和基于自动编码器的方法,用于安全水处理(SWaT)数据集中的异常检测,该数据集真实地代表了按比例缩小的工业水处理厂。(…)


5.基于时间因果网络模型的复杂活动识别

论文 | 简报

论文摘要:复杂活动识别具有挑战性,这是由于执行复杂活动的固有多样性和因果性,其每个实例具有其自己的原始事件配置及其时间因果依赖性。(…)我们的方法引入了从优化的网络骨架生成的时间因果网络,以明确地将特定复杂活动的这些独特的时间因果配置表征为可变数量的节点和链接。(…)

第一作者:

廖俊

广告

1.包装之外的思考:推荐电子商务运输的包装类型

论文 | 简报

论文摘要:多种产品属性,如尺寸、重量、易碎性、液体含量等。确定电子商务公司运送产品时使用的包装类型。(…)在这项工作中,我们提出了一种多阶段方法,在每种产品的运输和损坏成本之间进行权衡,并使用一种可扩展的、计算高效的线性时间算法来准确分配最佳包装类型。提出了一种简单的二分搜索法算法来寻找在运输成本和损坏成本之间取得平衡的超参数。(…)


2.为工作推荐 MOOCs 课程:一种自动弱监督方法

论文 | 简报

论文摘要:大规模开放在线课程(mooc)的激增需要一种有效的课程推荐方式来推荐招聘网站上发布的职位,尤其是那些参加 mooc 寻找新工作的人。(…)本文提出了一个通用的自动化弱监督框架 AutoWeakS 通过强化学习来解决这个问题。一方面,该框架使得能够在由多个非监督排序模型产生的伪标签上训练多个监督排序模型。另一方面,该框架能够自动搜索这些监督和非监督模型的最佳组合。(…)


3.反馈引导的属性图嵌入相关视频推荐

论文 | 简报

论文摘要:图的表示学习作为传统特征工程的替代方法,已经在从电子商务到计算生物学的许多应用领域得到了开发。(…)在本文中,我们提出了一种名为 Equuleus 的视频嵌入方法,该方法从用户交互行为中学习视频嵌入。在 Equuleus 中,我们仔细地将用户行为特征结合到视频图的构造和节点序列的生成中。(…)

第一作者:


4.用于好友增强推荐的社会影响力注意力神经网络

论文 | 简报

论文摘要:随着在线社交网络的蓬勃发展,在许多社交应用中出现了一种新的推荐场景,称为好友增强推荐(FER)。在 FER,用户被推荐他们的朋友喜欢/分享的项目(称为朋友推荐圈)。(…)在本文中,我们首先阐述了 FER 问题,并提出了一种新颖的社会影响注意神经网络(SIAN)解决方案。为了融合丰富的异构信息,SIAN 中的 attentive 特征聚集器被设计为在节点和类型级别学习用户和项目表示。(…)

Web 挖掘

1.校准在线广告中的用户响应预测

论文 | 简报

论文摘要:准确预测点击率(CTR)和转化率(CVR)等用户响应概率对在线广告系统至关重要。(…)由于点击和转换等用户响应行为的稀疏性和延迟性,传统的校准方法在现实世界的在线广告系统中可能不太适用。在本文中,我们提出了一个全面的在线广告校准解决方案。更具体地说,我们提出了一个校准算法来利用预测概率的隐含属性,以减少数据稀疏问题的负面影响。(…)


2.6 ve clm:IPv6 目标生成的向量空间语言建模

论文 | 简报

论文摘要:快速 IPv6 扫描在网络测量领域具有挑战性,因为它需要探索整个 IPv6 地址空间,但受到当前计算能力的限制。(…)在本文中,我们介绍了我们的方法 6VecLM 来探索实现这样的目标生成算法。该体系结构可以将地址映射到向量空间以解释语义关系,并使用转换器网络来构建 IPv6 语言模型以预测地址序列。(…)

第一作者:

天宇崔


3.有限样本下多分类器的精度估计

论文 | Pres e 论文

论文摘要:机器学习分类器通常需要定期跟踪其性能指标,如精度、召回率等。,用于模型改进和诊断。(…)我们提出了一种采样方法来估计多个二元分类器的精度,该方法利用了它们的预测集之间的重叠。我们从理论上保证我们的估计量是无偏的,并从经验上证明从我们的抽样技术估计的精度度量与从均匀随机样本获得的精度度量一样好(就方差和置信区间而言)。(…)


4.从浏览事件中嵌入神经用户

论文 | 简报

论文摘要:基于在线用户行为数据的深度理解对于向他们提供个性化服务至关重要。然而,现有的学习用户表示的方法通常基于监督框架,例如人口预测和产品推荐。(…).受预训练词嵌入在许多自然语言处理任务中的成功启发,我们提出了一种简单而有效的神经用户嵌入方法,通过使用在线用户的未标记行为数据来学习他们的深层表征。一旦用户被编码成低维密集嵌入向量,这些隐藏的用户向量可以在各种用户参与的任务(例如人口统计预测)中用作附加的用户特征,以丰富用户表示。(…)

计算社会科学

1.用于需求预测的空间社区信息演化图

论文 | 简报

论文摘要:数量迅速增加的共享自行车极大地方便了人们的日常通勤。然而,由于用户的免费入住和退房,不同车站的可用自行车数量可能会不平衡。(…)为了应对这些挑战,我们提出了一种新的空间社区信息演化图(SCEG)框架来预测站级需求,该框架考虑了两种不同粒度的交互。具体来说,我们使用 EvolveGCN 从进化站网络中的细粒度交互中学习时间进化表示。(…)

第一作者:

**Qianru Wang **

网站


2.深入探究多语言仇恨言论分类

论文 | 简报

论文摘要:仇恨言论是目前困扰社会的一个严重问题,并已造成缅甸罗辛亚社区种族灭绝等严重事件。社交媒体让人们可以更快地传播这种仇恨内容。对于缺乏仇恨言论检测系统的国家来说,这尤其令人担忧。在本文中,我们使用来自 16 个不同来源的 9 种语言的仇恨言论数据集,首次对多语言仇恨言论检测进行了广泛的评估。我们分析了不同深度学习模型在各种场景下的性能。(…)


3.基于分层联合分解的半监督多方面误报检测

论文 | 简报

论文摘要:区分误传信息和真实信息是当今互联世界最具挑战性的问题之一。绝大多数检测错误信息的最新技术都是完全监督的,需要大量高质量的人工注释。(…)在这项工作中,我们感兴趣的是探索注释数量有限的情况。在这种情况下,我们研究了如何挖掘表征一篇新闻文章的不同数量的资源,以下称为“方面”,可以弥补标签的缺乏。(…)


4.模型桥接:仿真模型与神经网络的连接

论文 | 简报

论文摘要:机器学习,尤其是深度神经网络的可解释性,对于现实世界应用中的决策至关重要。一种方法是用具有简单解释结构的代理模型代替不可解释的机器学习模型。另一种方法是通过使用由人类知识建模的具有可解释的模拟参数的模拟来理解目标系统。(…)我们的想法是使用模拟模型作为可解释的代理模型。然而,由于仿真模型的复杂性,模拟器校准的计算成本很高。因此,我们提出了一个“模型桥接”框架,通过一系列内核均值嵌入来桥接机器学习模型和仿真模型,以解决这些困难。(…)

电子商务和金融

1.面向电子商务的时尚服装代

论文 | 简报

将赠送的衣服组合成一套服装的任务对大多数人来说都很熟悉,但迄今为止证明很难实现自动化。我们提出了一个基于图像和文本描述的服装多模态嵌入模型。在一种新颖的深度神经网络结构中,嵌入和共享风格空间被端到端地训练。该网络是在迄今为止最大最丰富的标签服装数据集上训练的,我们开源了这个数据集。(…)


2.用机器学习测量移民对本地人购物消费的采纳

论文 | 简报

论文摘要:“告诉我你吃什么,我就告诉你你是什么”。Jean Anthelme Brillat-Savarin 是最早认识到身份与食物消费之间关系的人之一。与其他个体行为相比,食物选择受外部判断和社会压力的影响要小得多,而且可以长期观察。这使得它们成为从食物消费角度研究移民融合的有趣基础。事实上,在这项工作中,我们从购物零售数据中分析了移民的食品消费,以了解它是否以及如何向本地人靠拢。(…)


3.我的消费者为什么购物?学习零售商交易数据的有效距离度量

论文 | 简报

论文摘要:交易分析是旨在了解消费者行为的研究中的一个重要部分。(…)在本文中,我们提出了一种新的距离度量,这种度量在设计上独立于零售商,允许跨零售商和跨国分析。该指标带有一种寻找产品类别重要性的新方法,在无监督学习技术和重要性校准之间交替使用。(…)


4.用于植入式广告的 3D 广告创作系统

论文 | 简报

论文摘要:在过去的十年里,视频分享平台的发展吸引了大量对情境广告的投资。常见的上下文广告平台利用用户提供的信息将 2D 视觉广告整合到视频中。(…)本文提出了一个视频广告植入&集成(Adverts)框架,它能够感知场景的三维几何形状和摄像机运动,以融合视频中的三维虚拟对象,并创建现实的幻觉。(…)


5.发现和预测巴西市场内幕交易的证据

论文 | 简报

论文摘要:众所周知,内幕交易会对市场风险产生负面影响,在许多国家被视为犯罪。然而,执行率差别很大。在巴西,特别是很少的法律案件得到追究,而且据我们所知,以前的案件的数据集是不存在的。在这项工作中,我们考虑巴西市场,并处理两个问题。首先,我们提出了一种建立内幕交易证据数据集的方法。(……)其次,我们使用我们的数据集,试图在相关事件披露之前识别可疑的谈判。(…)

作者:

社会公益

1.使用堆叠非参数贝叶斯方法的能源消耗预测

论文 | 简报

论文摘要:利用多个短时间序列数据,在非参数高斯过程(GP)的框架内研究家庭能源消费的预测过程。随着我们开始使用智能电表数据来描绘澳大利亚住宅用电的更清晰的画面,越来越明显的是,我们还必须构建一个详细的画面,并理解澳大利亚与天然气消费的复杂关系。(…)考虑到这些事实,我们构建了一个堆叠 GP 模型,其中应用于每个任务的每个 GP 的预测后验概率用于下一级 GP 的先验和似然。我们将我们的模型应用于真实世界的数据集,以预测澳大利亚几个州的家庭能源消耗。(…)


2.基于非参数生存分析的管道长期失效预测

论文 | 简报

论文摘要:澳大利亚的水利基础设施已经有一百多年的历史,因此已经开始通过水管故障来显示其老化。我们的工作涉及横跨澳大利亚主要城市的大约 50 万条管道,这些管道向家庭和企业供水,服务于 500 多万客户。(…)我们应用了机器学习技术,为这些澳大利亚城市的管道故障问题找到了一种经济高效的解决方案,这些城市每年平均发生 1500 起主水管故障。为了实现这一目标,我们构建了一个详细的图像并理解了水管网的行为(…)。


3.约束深度学习的拉格朗日对偶

论文|Presenstation

论文摘要:本文探讨了拉格朗日对偶对于具有复杂约束的学习应用的潜力。这种约束出现在许多科学和工程应用中,在这些应用中,任务相当于学习优化问题,这些问题必须重复求解,并且包括硬的物理和操作约束。本文还考虑了学习任务必须对预测器本身施加约束的应用,因为它们是要学习的函数的自然属性,或者因为从社会角度来看施加这些约束是可取的。(…)


4.犯罪预测:通过利用邻居的时空依赖性进行犯罪预测

论文 | 简报

论文摘要:城市地区的犯罪预测可以改善资源分配(例如,警察巡逻)以实现更安全的社会。最近,研究人员一直在使用深度学习框架进行城市犯罪预测,与以前的工作相比,精确度更高。(…)在本文中,我们设计并实现了一个端到端的时空深度学习框架,称为犯罪预测器,它可以同时捕获区域内和跨区域的时间重现和空间依赖性。(…)

摘要

我个人建议您也访问活动网站,更深入地探索您最感兴趣的话题。

请注意,我们还发布了来自会议的顶级研究论文的帖子。看看这里的。

我很乐意扩展这个列表,因为这是我的主观选择。欢迎提出更多的论文。如果你觉得少了什么很酷的东西,简单地告诉我,我会延长这个帖子。

来自 ECML-PKDD 2020 会议的顶级研究论文

原文:https://web.archive.org/web/https://neptune.ai/blog/ecml-pkdd-2020-research

上周,我有幸参加了 ECML-PKDD 2020 会议。欧洲机器学习和数据库中知识发现的原理和实践会议是欧洲最受认可的关于 ML 的学术会议之一

完全在线的活动,24 小时不间断运行——让所有时区都可以参加的好主意。会议时间表被整齐地分成许多不同风格的部分,这使得我可以很容易地进入强化学习、对抗学习和元主题中我最喜欢的主题。

ECML-PKDD 在 ML 领域带来了大量新的想法和鼓舞人心的发展,所以我想挑选顶级论文并在这里分享

在这篇文章中,我主要关注研究论文,这些论文分为以下几类:

尽情享受吧!

强化学习

1.自我映射:深层强化学习的投射映射和结构化自我中心记忆

论文 | 简报

论文摘要:在部分可观测的 3D 环境中涉及定位、记忆和规划的任务是深度强化学习中的一个持续挑战。我们提出了 EgoMap,一种空间结构化的神经记忆体系结构。EgoMap 增强了深度强化学习代理在 3D 环境中执行具有多步目标的挑战性任务的性能。(…)


2.选项编码器:强化学习中发现策略基础的框架

论文 | 简报

论文摘要:选项发现和技能获取框架对于分层组织的强化学习代理的功能是不可或缺的。然而,这样的技术通常会产生大量的选项或技能,可以通过过滤掉任何冗余信息来简洁地表示出来。这种减少可以减少所需的计算,同时还可以提高目标任务的性能。为了压缩一系列选项策略,我们试图找到一个策略基础,准确地捕捉所有选项的集合。在这项工作中,我们提出了 Option Encoder,这是一个基于自动编码器的框架,具有智能约束的权重,有助于发现基本策略的集合。(…)

主要作者:


3.ELSIM:通过内在动机进行可重用技能的端到端学习

论文 | 简报

论文摘要:受发展学习的启发,我们提出了一种新的强化学习架构,它以端到端的方式分层学习和表示自我生成的技能。在这种架构下,智能体只关注任务奖励技能,同时保持技能的学习过程自下而上。这种自下而上的方法允许学习这样的技能:1-可以跨任务转移,2-当回报很少时可以提高探索能力。为此,我们将先前定义的交互信息目标与新颖的课程学习算法相结合,创建了一个无限的、可探索的技能树。(…)

第一作者:

亚瑟奥伯莱特

GitHub


4.基于图的运动规划网络

论文 | 简报

论文摘要:可微分规划网络体系结构已经显示出在解决转移规划任务方面的强大功能,同时它具有简单的端到端训练特征。(…)然而,现有的框架只能在具有网格结构的域上进行有效的学习和规划,即嵌入在特定欧几里得空间中的正则图。在本文中,我们提出了一个通用的规划网络称为基于图的运动规划网络(GrMPN)。GrMPN 将能够 I)学习和规划一般的不规则图形,因此 ii)呈现现有规划网络架构的特殊情况。(…)

第一作者:

泰皇

使聚集

1.利用结构丰富的特征来改进聚类

论文 | 简报

论文摘要:为了成功的聚类,算法需要找到聚类之间的边界。虽然如果聚类是紧凑的和非重叠的并且因此边界被清楚地定义,这是相对容易的,但是聚类相互融合的特征阻碍了聚类方法正确地估计这些边界。因此,我们的目标是提取显示清晰聚类边界的特征,从而增强数据中的聚类结构。我们的新技术创建了包含对聚类重要的结构的数据集的压缩版本,但是没有噪声信息。我们证明了数据集的这种转换对于 k-means 以及各种其他算法来说更容易聚类。此外,基于这些结构丰富的特征,我们引入了 k-means 的确定性初始化策略。(…)

第一作者:

本杰明·谢林

LinkedIn


2.在线二元不完全多视图聚类

论文 | 简报

论文摘要:在过去的几十年中,多视图聚类因其在多模态或来自不同来源的数据上的良好表现而吸引了相当多的关注。在现实应用中,多视图数据经常遭遇实例不完整的问题。在这样的多视图数据上进行聚类被称为不完全多视图聚类(IMC)。大多数现有的 IMC 解决方案是离线的,并且具有高的计算和存储成本,尤其是对于大规模数据集。为了应对这些挑战,本文提出了一个在线二元不完全多视图聚类框架。OBIMC 鲁棒地学习不完全多视图特征的公共紧凑二进制码。(…)

第一作者:


3.简单、可扩展且稳定的可变深度聚类

论文 | 简报

论文摘要:深度聚类(DC)已经成为无监督聚类的最新发展。原则上,DC 代表了各种无监督的方法,这些方法联合学习底层聚类和直接来自非结构化数据集的潜在表示。然而,由于高运营成本、低可扩展性和不稳定的结果,DC 方法通常应用不佳。在本文中,我们首先使用八个经验标准在工业适用性的背景下评估几个流行的 DC 变量。然后,我们选择关注变分深度聚类(VDC)方法,因为除了简单性、可伸缩性和稳定性之外,它们大多满足这些标准。(…)


4.高斯偏移:密度吸引子聚类比均值偏移更快

论文 | 简报

论文摘要:均值漂移是一种流行而强大的聚类方法。虽然存在改进其绝对运行时间的技术,但是没有方法能够有效地改进其关于数据集大小的二次时间复杂度。为了能够开发一种可替代的、更快的方法来得到相同的结果,我们首先贡献了正式的聚类定义,这意味着隐式地跟随了 shift。基于这一定义,我们推导并贡献了高斯移位——一种具有线性时间复杂度的方法。我们使用具有已知拓扑的合成数据集来量化高斯偏移的特征。我们使用来自活跃神经科学研究的真实生活数据进一步限定高斯偏移,这是迄今为止对任何亚细胞器最全面的描述。

神经网络体系结构

1.在分类任务中寻找最佳网络深度

论文 | 简报

论文摘要:我们开发了一种使用多个分类器头训练轻量级神经网络的快速端到端方法。通过允许模型确定每个头部的重要性并奖励单个浅层分类器的选择,我们能够检测并移除网络中不需要的组件。该操作可以被视为找到模型的最佳深度,显著地减少了参数的数量并加速了跨不同硬件处理单元的推断,这对于许多标准剪枝方法来说并不是这样。(…)

主要作者:

你把缰绳解开

子宫肌瘤


2.XferNAS:转移神经结构搜索

论文 | 简报

论文摘要:术语神经架构搜索(NAS)是指为一个新的、以前未知的任务自动优化网络架构。由于测试一个架构在计算上是非常昂贵的,许多优化者需要几天甚至几周的时间来找到合适的架构。但是,如果重用以前对不同任务进行搜索的知识,则可以大大减少搜索时间。在这项工作中,我们提出了一个普遍适用的框架,只需对现有的优化器进行微小的修改,就可以利用这一特性。(…)此外,我们在 CIFAR 基准测试中观察到 NAS 优化器分别获得了 1.99 和 14.06 的新纪录。在另一项研究中,我们分析了源数据和目标数据量的影响。(…)


3.稀疏神经网络的拓扑洞察

论文|Presenstation

论文摘要:稀疏神经网络是降低深度神经网络部署资源需求的有效途径。最近,出现了自适应稀疏连接的概念,以允许通过在训练期间优化稀疏结构来从头开始训练稀疏神经网络。(…)在这项工作中,我们从图论的角度介绍了一种理解和比较稀疏神经网络拓扑的方法。我们首先提出神经网络稀疏拓扑距离(NNSTD)来度量不同稀疏神经网络之间的距离。此外,我们证明了稀疏神经网络在性能方面可以胜过过参数化模型,即使没有任何进一步的结构优化。(…)

主要作者:

迁移和多任务学习

1.图形扩散 Wasserstein 距离

论文 | 简报 t 离子

论文摘要:结构化数据的最优传输(OT)在机器学习社区中受到了很多关注,尤其是在解决图分类或图转移学习任务方面。在本文中,我们提出了扩散 Wasserstein (DW)距离,作为对无向图和连通图的标准 Wasserstein 距离的推广,其中节点由特征向量描述。DW 基于拉普拉斯指数核,并受益于热扩散来从图中捕捉结构和特征信息。(…)

第一作者:

改善胡子


2.使用双层规划实现可解释的多任务学习

论文 | 简报

论文摘要:全局可解释多任务学习可以表示为基于学习模型的预测性能来学习任务关系的稀疏图。我们提出了学习稀疏图的回归多任务问题的双层模型。我们表明,这种稀疏图提高了学习模型的可解释性。

第一作者:

弗朗切斯科·阿莱西亚尼

领英


3.领域转移下基于多样性的无监督文本分类泛化

论文 | 简报

论文摘要:领域适应方法寻求从源领域学习并将其推广到未知的目标领域。(…)在本文中,我们提出了一种用于单任务文本分类问题的领域适应的新方法,该方法基于基于多样性的泛化的简单而有效的思想,该思想不需要未标记的目标数据。多样性通过迫使模型不依赖于相同的特征来进行预测,起到了促进模型更好地概括和不加选择地进行域转换的作用。我们将这一概念应用于神经网络中最容易解释的部分,即注意力层。(…)


4.深度学习、语法迁移和迁移理论

论文 | 简报

论文摘要:尽管基于深度学习的人工智能技术被广泛采用并取得了成功,但在提供可理解的决策过程方面存在局限性。这使得“智能”部分受到质疑,因为我们希望真正的人工智能不仅能完成给定的任务,还能以人类可以理解的方式执行。为了实现这一点,我们需要在人工智能和人类智能之间建立联系。在这里,我们用语法迁移来展示连接这两种智力的范例。(…)

第一作者:

张凯旋


5.具有联合领域对抗重构网络的无监督领域适应

论文 | 简报

论文摘要:无监督领域自适应(UDA)试图将知识从已标记的源领域转移到未标记的目标领域。(…)我们在本文中提出了一种称为联合领域对抗重构网络(JDARN)的新模型,它将领域对抗学习与数据重构相结合,以学习领域不变和领域特定的表示。同时,我们提出了两种新的鉴别器来实现联合比对,并采用了一种新的联合对抗损失来训练它们。(…)

第一作者:

钱晨

联合学习和聚类

1.分散矩阵分解的算法框架

论文 | 简报

论文摘要:我们提出了一个完全去中心化机器学习的框架,并将其应用于 top-N 推荐的潜在因素模型。分散学习环境中的训练数据分布在多个代理上,这些代理共同优化一个共同的全局目标函数(损失函数)。这里,与联合学习的客户机-服务器体系结构相反,代理直接通信,维护和更新它们自己的模型参数,没有中央集合,也没有共享它们自己的数据。(…)

主要作者:

艾丽卡·杜利亚科娃

黄伟鹏


2.用于个性化推荐的联合多视图矩阵分解

Paper|演示文稿

论文摘要:我们介绍了联邦多视图矩阵分解方法,该方法将联邦学习框架扩展到具有多个数据源的矩阵分解。我们的方法能够学习多视图模型,而无需将用户的个人数据传输到中央服务器。据我们所知,这是第一个使用多视图矩阵分解提供推荐的联邦模型。该模型在生产环境的三个数据集上进行了严格评估。(…)


3.FedMAX:减少激活分歧,实现精确和高效的联合学习

论文 | 简报

论文摘要:在本文中,我们发现了一种称为激活-发散的新现象,这种现象在联邦学习中由于数据异构而发生。具体来说,我们认为,当使用联合学习时,激活向量可能会出现分歧,即使一个用户子集与驻留在不同设备上的数据共享一些公共类。为了解决这个问题,我们引入了基于最大熵原理的先验知识;该先验假设关于每个设备的激活向量的信息最少,并且旨在使相同类别的激活向量在多个设备上相似。(…)

第一作者:

陈为


4.使用 HDBSCAN*进行基于模型的聚类

论文 | 简报

论文摘要:我们提出了一种有效的基于模型的聚类方法,用于从有限数据集创建高斯混合模型。使用分类可能性和期望最大化算法从 HDBSCAN层次结构中提取模型。对应于聚类数量的模型组件数量的先验知识不是必需的,并且可以动态确定。由于与以前的方法相比,HDBSCAN创建的层次相对较小,因此可以高效地完成这项工作。(…)

第一作者:

迈克尔施特罗布尔

GitHub

网络建模

1.节点分类的渐进监督

论文 | 简报

论文摘要:图卷积网络(GCNs)是一种用于节点分类任务的强大方法,其中通过最小化最终层预测的损失来训练 GCNs。然而,这种训练方案的局限性在于,它强制每个节点从感受野的固定和统一大小中被分类,这可能不是最佳的。我们提出了 ProSup(渐进式监督),通过以不同的方式培训 gcn 来提高其有效性。ProSup 逐步监督所有层,引导它们的表现向我们期望的特征发展。(…)

第一作者:

王义桅


2.基于时间 RNN 的分层注意动态异构网络链路预测模型

论文 | 简报

论文摘要:网络嵌入旨在学习节点的低维表示,同时捕捉网络的结构信息。(…)在本文中,我们提出了一种新的动态异构网络嵌入方法,称为 DyHATR,它使用分层注意来学习异构信息,并将递归神经网络与时间注意相结合来捕获进化模式。(…)


3.GIKT:基于图的知识追踪交互模型

论文 | 简报

论文摘要:随着在线教育的快速发展,知识追踪(KT)已经成为追踪学生知识状态和预测他们在新问题上表现的基本问题。在线教育系统中的问题通常很多,并且总是与很少的技能相关联。(…)在本文中,我们提出了一个基于图的知识追踪交互模型(GIKT)来解决上述问题。更具体地说,GIKT 利用图卷积网络(GCN)通过嵌入传播来充分结合问题-技能相关性。(…)

第一作者:

杨洋

图形神经网络

1.格拉姆-SMOT:基于图关注机制和子模块优化的 Top-N 个性化捆绑推荐

论文 | 简报

论文摘要:捆绑推荐——向客户推荐一组产品来代替单个产品,日益受到关注。它提出了两个有趣的挑战——(1)如何有效地向用户推荐现有的捆绑包,以及(2)如何生成针对特定用户的个性化小说捆绑包。(……)在这项工作中,我们提出了 GRAM-SMOT——一种基于图形注意力的框架,以解决上述挑战。此外,我们定义了一个基于度量学习方法的损失函数来有效地学习实体的嵌入。(…)

第一作者:

维杰库玛米


2.用于下一个项目推荐的时间异构交互图嵌入

论文 | 简报

论文摘要:在下一个项目推荐的场景中,以前的方法试图通过捕捉顺序交互的演变来建模用户偏好。然而,它们的顺序表达往往是有限的,没有对短期需求往往会受到长期习惯影响的复杂动态进行建模。此外,它们很少考虑用户和项目之间的异构类型的交互。在本文中,我们将这种复杂数据建模为时间异构交互图(THIG ),并学习 THIGs 上的用户和项目嵌入,以解决下一个项目推荐。主要的挑战包括两个方面:复杂的动力学和丰富的交互异构性。(…)


3.一种基于自关注网络的节点嵌入模型

论文 | 简报

论文摘要:尽管最近取得了一些进展,但对归纳设置进行的研究有限,在归纳设置中,新出现的未知节点需要嵌入——这是图网络深度学习的实际应用中常见的设置。(…)为此,我们提出了 SANNE——一种新的无监督嵌入模型——其中心思想是采用一种自我注意机制,后跟一个前馈网络,以便迭代地聚合采样随机行走中节点的矢量表示。(…)


4.图形修正卷积网络

论文 | 简报

论文摘要:图卷积网络(GCNs)在机器学习社区中受到越来越多的关注,因为它在各种应用中有效地利用了节点的内容特征和跨图的链接模式。(…)本文提出了一个称为图修正卷积网络(GRCN)的新框架,它避免了这两个极端。具体而言,引入了基于 GCN 的图修正模块,用于通过联合优化来预测缺失边和修正下游任务的边权重。(…)


5.基于潜在扰动的图卷积网络鲁棒训练

论文 | 简报

论文摘要:尽管最近图卷积网络(GCNs)在对图结构数据建模方面取得了成功,但其对敌对攻击的脆弱性已经暴露出来,针对节点特征和图结构的攻击已经被设计出来。(…)我们建议通过扰动 GCNs 中的潜在表示来解决这个问题,这不仅免除了生成敌对网络,而且通过尊重数据的潜在流形来实现改进的鲁棒性和准确性。这种在图上进行潜在对抗训练的新框架被应用于节点分类、链接预测和推荐系统。(…)

自然语言处理

1.多源弱社会监督下的假新闻早期发现

论文 | 简报

论文摘要:社交媒体极大地让人们以前所未有的速度参与到网络活动中。然而,这种无限制的访问也加剧了错误信息和虚假新闻在网上的传播,除非及早发现并加以缓解,否则可能会造成混乱和混乱。(…)在这项工作中,我们利用来自用户和内容约定的不同来源的多个弱信号及其互补效用来检测假新闻。我们共同利用有限数量的干净数据以及来自社交活动的弱信号,在元学习框架中训练深度神经网络,以估计不同弱实例的质量。(…)


2.通过多重编辑神经网络从宏观新闻中生成财务报告

帕佩 r | 演讲

论文摘要:给定一条突发的宏观新闻,自动生成财务报告是相当具有挑战性的任务。本质上,该任务是文本到文本的生成问题,但是要从一条短新闻中学习长文本,即大于 40 个单词。(…)为了解决这个问题,我们提出了新的多重编辑神经网络方法,该方法首先学习给定新闻的大纲,然后根据学习的大纲生成财务报告。具体来说,输入新闻首先通过跳格模型嵌入,然后输入双 LSTM 组件训练上下文表示向量。(…)

第一作者:


3.面向短文本聚类的归纳文档表示学习

论文 | 简报

论文摘要:短文本聚类(STC)是一项重要的任务,可以在快速增长的社交网络中发现主题或群组,例如 Tweets 和 Google News。(…)受 GNNs 中图结构引导的顶点信息传播机制的启发,我们提出了一个称为 IDRL 的归纳文档表示学习模型,该模型可以将短文本结构映射到图网络中,并递归地聚合看不见的文档中单词的邻居信息。然后,我们可以用以前学习的有限数量的单词嵌入来重建以前看不见的短文本的表示。(…)

第一作者:


4.用于文档级情感分析的具有反思机制的分层交互网络

论文 | 简报

论文摘要:由于模糊的语义链接和复杂的情感信息,文档级情感分析(DSA)更具挑战性。最近的工作致力于利用文本摘要,并取得了可喜的成果。然而,这些基于摘要的方法没有充分利用摘要,包括忽略摘要和文档之间的内在交互。(…)在本文中,我们研究了如何有效地为 DSA 生成具有显式主题模式和情感上下文的区别性表示。提出了一种层次交互网络(HIN)来探索摘要和文档在多个粒度上的双向交互,并学习面向主题的文档表示用于情感分类。(…)

第一作者:


5.学习一系列情感分类任务

论文 | 简报

论文摘要:研究终身学习环境下的情感分类,以提高情感分类的准确性。在 LL 设置中,系统在神经网络中递增地学习一系列 SC 任务。这种情况在情感分析应用程序中很常见,因为情感分析公司需要为不同的客户处理大量的任务。(…)本文提出了一种称为 KAN 的新技术来实现这些目标。KAN 通过前向和后向知识转移,可以显著提高新旧任务的 SC 准确性。(…)

第一作者:

Zixuan Ke

时间序列和递归神经网络

1.用于时间序列分类的时间字典集成(TDE)分类器

论文 | 简报

论文摘要:用词袋表示时间序列是一种流行的时间序列分类方法。这些算法包括在一系列上近似和离散化窗口以形成单词,然后在给定的字典上形成单词计数。在得到的单词计数直方图上构建分类器。2017 年对一系列时间序列分类器的评估发现,符号-傅立叶近似符号包(BOSS)集成是基于字典的分类器中最好的。(…)我们提出了这些基于字典的分类器的进一步扩展,它将其他分类器的最佳元素与一种基于参数空间的自适应高斯过程模型构建集成成员的新方法相结合。(…)


2.利用多尺度动态记忆的递归神经网络的增量训练

论文 | 简报

论文摘要:递归神经网络的有效性很大程度上受到其将从不同频率和时间尺度的输入序列中提取的信息存储到其动态记忆中的能力的影响。(…)在本文中,我们提出了一种新的增量训练递归体系结构,明确针对多尺度学习。首先,我们展示了如何通过将简单 RNN 的隐藏状态分成不同的模块来扩展其架构,每个模块以不同的频率对网络隐藏激活进行子采样。然后,我们讨论一种训练算法,其中新模块被迭代地添加到模型中,以学习逐渐变长的依赖性。(…)


3.柔性递归神经网络

论文 | 简报

论文摘要:我们介绍了两种方法,使得递归神经网络(RNNs)能够在序列分析过程中以计算成本来权衡准确性。(…)第一种方法对模型的改动很小。因此,它避免了从慢速存储器加载新参数。在第二种方法中,不同的模型可以在序列分析中相互替换。后者适用于更多数据集。(…)

主要作者:


4.z 嵌入:用于有效聚类和分类的事件区间的谱表示

论文 | 简报

论文摘要:事件区间序列出现在多个应用领域,而其固有的复杂性阻碍了聚类和分类等任务的可扩展解决方案。本文提出了一种新的依赖于二部图的事件区间序列的谱嵌入表示。更具体地,每个事件区间序列通过以下三个主要步骤由二分图表示:(1)创建可以将事件区间序列的集合快速转换成二分图表示的哈希表,(2)创建并正则化对应于二分图的双邻接矩阵,(3)定义双邻接矩阵上的谱嵌入映射。(…)

维数缩减和自动编码器

1.具有一跳线性模型的简单有效的图形自动编码器

论文 | 简报

论文摘要:在过去的几年里,图自动编码器(AE)和变分自动编码器(VAE)作为强大的节点嵌入方法出现,(…)。图形 AE、VAE 及其大多数扩展依赖于多层图形卷积网络(GCN)编码器来学习节点的向量空间表示。在本文中,我们表明,GCN 编码器实际上是不必要的复杂的许多应用。我们建议用图的直接邻域(一跳)邻接矩阵的更简单和更易解释的线性模型来代替它们,包括更少的操作、更少的参数和没有激活函数。(…)


2.稀疏可分非负矩阵分解

论文 | 简报

论文摘要:我们提出了一种新的非负矩阵分解(NMF)变体,结合了可分性和稀疏性假设。可分离性要求第一 NMF 因子的列等于输入矩阵的列,而稀疏性要求第二 NMF 因子的列是稀疏的。我们称这种变体为稀疏可分 NMF (SSNMF),我们证明它是 NP 难的,而不是可以在多项式时间内求解的可分 NMF。(…)

大规模优化和差分隐私

1.L1-正则化优化的正交近似随机梯度方法

论文 | 简报

论文摘要:稀疏诱导正则化问题在机器学习应用中普遍存在,范围从特征选择到模型压缩。在本文中,我们提出了一种新的随机方法——基于蚂蚁的近似随机梯度方法(OBProx-SG)——来解决可能是最流行的实例,即 l1 正则化问题。OBProx-SG 方法包含两个步骤:(I)预测解的支撑覆盖的近似随机梯度步骤;以及(ii)另一个步骤,通过另一个面部投影积极地增强清晰度水平。(…)


2.结构化非凸优化的坐标下降法的效率

论文 | 简报

论文摘要:提出了新的坐标下降(CD)方法,用于最小化由三项组成的非凸函数:(I)连续 differentiable 项,(ii)简单凸项,以及(iii)凹连续项。首先,通过将随机 CD 扩展到非光滑非凸环境,我们发展了一种坐标次梯度方法,该方法通过使用块复合次梯度映射来随机更新块坐标变量。(…)第二,我们开发了一个随机置换 CD 方法,它有两个交替的步骤:线性化凹形部分和循环变量。(…)第三,我们将加速坐标下降法(ACD)推广到非光滑和非凸优化中,发展了一种新的随机近似 DC 算法,从而用 ACD 不精确地求解子问题。(…)

第一作者:

齐登


3.基于 DP-信赖域方法的经验风险鞍点的私密可伸缩规避

论文 | 简报

论文摘要:最近有研究表明,机器学习和深度学习中的许多非凸目标/损失函数已知是严格鞍点。这意味着找到二阶驻点({em 即,}近似局部最小值)并因此避开鞍点对于这样的函数来说足以获得具有良好推广性能的分类器。然而,现有的鞍点逃逸算法都没有考虑到设计中的一个关键问题,即训练集中敏感信息的保护。(…)本文研究了非凸损失函数的经验风险的私逃鞍点和寻找二阶驻点问题。(…)

对抗性学习

1.对抗性学习分子图的推理和生成

论文 | 简报

论文摘要:最近用于产生新分子的方法使用分子的图形表示,并采用各种形式的图形卷积神经网络进行推理。然而,训练需要解决一个昂贵的图同构问题,以前的方法没有解决或只是近似地解决。在这项工作中,我们提出了 ALMGIG,一个用于推理和从头分子生成的无似然对抗性学习框架,它避免了显式计算重建损失。我们的方法扩展了生成对抗网络,通过包含对抗循环一致性损失来隐含地执行重建属性。(…)


2.可解释人工智能的通用模型不可知样本合成框架

论文 | 简报

论文摘要:随着深度学习方法在实际应用中的日益复杂,解释和诠释这种方法的决策的需求越来越迫切。在这项工作中,我们专注于可解释的人工智能,并提出一种新的通用和模型不可知的框架,用于合成输入样本,最大化机器学习模型的期望响应。为此,我们使用一个生成模型,该模型作为生成数据的先验,并使用一种新的具有动量更新的进化策略遍历其潜在空间。(…)


3.通过无监督对抗攻击的自动编码器的质量保证

论文 | 简报

论文摘要:自动编码器是无监督学习中的一个基本概念。目前,自动编码器的质量要么在内部评估(例如,基于均方误差),要么在外部评估(例如,通过分类性能)。然而,无法证明自动编码器的泛化能力超过了有限的训练数据,因此,对于要求对看不见的数据也有正式保证的安全关键应用来说,它们是不可靠的。为了解决这个问题,我们提出了第一个框架,将自动编码器的最坏情况错误限制在无限值域的安全关键区域内,以及导致这种最坏情况错误的无监督对抗示例的定义。(…)


4.显著图与对抗鲁棒性

论文 | 简报

论文摘要:最近出现了一种趋势,即将可解释性和对抗稳健性的概念结合起来,而不是像早期那样只关注良好的解释或对抗对手的稳健性。(…)在这项工作中,我们提供了一个不同的角度来看待这种耦合,并提供了一种方法,即基于显著性的对抗训练(SAT),以使用显著性图来提高模型的对抗鲁棒性。特别地,我们表明,使用已经与数据集一起提供的注释(如边界框和分割掩模)作为弱显著图,足以提高对抗鲁棒性,而无需额外的努力来生成扰动本身。(…)


5.神经网络中的可扩展后门检测

论文 | 简报

论文摘要:最近有研究表明,深度学习模型容易受到木马攻击。在特洛伊木马攻击中,攻击者可以在训练期间安装后门,使模型错误识别被小触发补丁污染的样本。当前的后门检测方法不能实现良好的检测性能,并且计算量大。在本文中,我们提出了一种新的基于触发逆向工程的方法,其计算复杂度不随标签数量的增加而增加,并且基于跨不同网络和补丁类型的可解释和通用的度量。(…)

深度学习理论

1.答:激活异常分析

论文 | 简报

论文摘要:受最近神经网络覆盖引导分析进展的启发,我们提出了一种新的异常检测方法。我们表明,隐藏的激活值包含有助于区分正常和异常样本的信息。我们的方法在一个纯数据驱动的端到端模型中结合了三个神经网络。基于目标网络中的激活值,警报网络决定给定样本是否正常。多亏了异常网络,我们的方法甚至可以在严格的半监督环境下工作。(…)

主要作者:

2.卷积神经网络的有效版本空间缩减

论文 | 简报

论文摘要:在主动学习中,采样偏差会造成严重的不一致性问题,阻碍算法找到最优假设。然而,许多方法是假设空间不可知的,没有解决这个问题。我们通过版本空间缩减的原则镜头检查深度神经网络的主动学习,并检查可实现性假设。基于他们的目标,我们确定了以前的质量减少和直径减少方法之间的核心差异,并提出了一种新的基于直径的查询方法-吉布斯投票分歧。(…)

主要作者:


3.通过记忆驱动的通信提高小规模多智能体深度强化学习的协调性

论文 | 简报

论文摘要:深度强化学习算法最近被用于以集中的方式训练多个相互作用的代理,同时保持它们的执行是分散的。当智能体只能获得部分观察值,并且面临需要协调和同步技能的任务时,智能体间的通信起着重要的作用。在这项工作中,我们提出了一个使用深度确定性策略梯度的多代理训练框架,该框架允许通过存储设备对显式通信协议进行并行的端到端学习。在训练期间,代理学习执行读和写操作,使他们能够推断世界的共享表示。(…)

主要作者:


4.神经网络训练的最小作用原理

论文 | 简报

论文摘要:尽管高度过度参数化,但神经网络已经在许多任务上实现了高泛化性能。由于经典的统计学习理论难以解释这种行为,最近许多努力都集中在揭示其背后的机制上,希望开发一个更合适的理论框架,并对训练好的模型进行更好的控制。在这项工作中,我们采用了另一种观点,将神经网络视为一个动态系统,随着时间的推移取代输入粒子。我们进行了一系列的实验,并通过分析网络的位移行为,我们表明在网络的传输图中存在低动能偏差,并将这种偏差与泛化性能联系起来。(…)

计算机视觉/图像处理

1.用于人脸识别的同伴引导的软边界

论文 | 简报

论文摘要:人脸识别在基于角度裕度的 softmax 损失的帮助下取得了显著的进步。然而,在训练过程中,间隔通常是手动设置并保持不变的,这忽略了优化难度和不同实例之间的信息相似性结构。(…)在本文中,我们从超球流形结构的角度提出了一种新的样本自适应边缘损失函数,我们称之为同伴引导软边缘(CGSM)。CGSM 在特征空间中引入分布信息,并在每个小批内进行师生优化。(…)


2.用于无监督领域适应的具有区别表示学习的软标签转移

论文 | 简报

论文摘要:领域自适应旨在解决将从标签信息丰富的源领域获得的知识转移到标签信息较少甚至没有标签信息的目标领域的挑战。最近的方法开始通过结合目标样本的硬伪标签来解决这个问题,以更好地减少跨域分布偏移。然而,这些方法易受误差累积的影响,因此无法保持跨领域类别的一致性。(…)为了解决这个问题,我们提出了一个具有判别表示学习的软标签转移(SLDR)框架,以联合优化具有软目标标签的类别式适应,并在一个统一的模型中学习判别域不变特征。(…)

第一作者:

曹曼良


3.显著区域发现的信息瓶颈方法

论文 | 简报

论文摘要:基于信息瓶颈原理,我们提出了一种在半监督环境下学习图像注意力掩模的新方法。在提供了一组标记图像的情况下,屏蔽生成模型最小化输入和屏蔽图像之间的互信息,同时最大化同一屏蔽图像和图像标签之间的互信息。与其他方法相比,我们的注意力模型产生一个布尔型而不是连续的掩蔽,完全隐藏了被掩蔽的像素中的信息。(…)


4.FAWA:对光学字符识别(OCR)系统的快速对抗性水印攻击

论文 | 简报

论文摘要:光学字符识别(OCR)作为一种关键的预处理工具,广泛应用于信息抽取和情感分析等实际应用中。在 OCR 中采用深度神经网络(DNN)会导致针对恶意示例的漏洞,恶意示例是为了误导威胁模型的输出而精心制作的。针对白盒 OCR 模型提出了快速水印对抗攻击(FAWA ),在水印的伪装下产生自然失真,逃避人眼的检测。本文首次尝试将普通的对抗性扰动和水印一起应用于对抗性攻击,生成对抗性水印。(…)

第一作者:

陈箓

深度学习的优化

1.ADMMiRNN:通过有效的 ADMM 方法训练稳定收敛的 RNN

论文 | 简报

论文摘要:由于递归单元中的权值在迭代之间是重复的,因此很难训练出稳定收敛的递归神经网络(RNN)并避免梯度消失和爆炸。此外,RNN 对权重和偏差的初始化很敏感,这给训练阶段带来了困难。与传统的随机梯度算法相比,交替方向乘子法(ADMM)具有无梯度特性和对恶劣条件的免疫能力,是一种很有前途的神经网络训练算法。然而,ADMM 不能直接用于训练 RNN,因为循环单元中的状态在时间步长上重复更新。因此,本文在 RNN 展开形式的基础上构建了一个新的框架 ADMMiRNN,以同时解决上述挑战,并提供了新的更新规则和理论收敛性分析。(…)

第一作者:

玉堂


2.网络零和凹对策中梯度方法的指数收敛性

论文 | 论文 论文

论文摘要:本文以生成型竞争网络为研究对象,研究了凹型网络零和博弈(NZGSs)中纳什均衡的计算..推广了蔡等人的结果,我们证明了凹凸两人零和对策的各种博弈论性质在这一推广中是保持的。然后我们推广了以前在两人零和博弈中得到的最后迭代收敛结果。(…)


3.神经网络优化的自适应动量系数

论文 | 简报

论文摘要:我们提出了一种新颖有效的基于动量项的一阶神经网络优化算法。我们的算法称为{it 自适应动量系数} (AMoC),它利用梯度的内积和参数的先前更新,根据优化路径中方向的变化,有效地控制动量项的权重。该算法易于实现,并且其计算开销比动量法小得多。(…)


4.用于资源高效深度神经网络的压缩相关神经元

论文 | 简报

论文摘要:由于 dnn 在挑战性问题上的准确性,它们在现实生活中有大量的应用,然而它们对内存和计算成本的要求挑战了它们在资源受限环境中的适用性。迄今为止,驯服计算成本一直集中在一阶技术上,例如通过数值贡献度量优先化来消除数值上无关紧要的神经元/滤波器,从而产生可接受的改进。然而,DNNs 中的冗余远远超出了数值无关紧要的界限。(…)为此,我们采用了实用的数据分析技术,并结合了一种新颖的特征消除算法,以确定一个最小的计算单元集,从而捕获图层的信息内容并压缩其余内容。(…)

摘要

就是这样!

我个人建议您也访问活动网站,更深入地探索您最感兴趣的话题。

请注意,还有另一篇文章提供了最好的应用数据科学论文,敬请关注!

如果你觉得少了什么很酷的东西,简单地告诉我,我会延长这个帖子。

最佳端到端 MLOps 平台:每个数据科学家都需要了解的领先机器学习平台

原文:https://web.archive.org/web/https://neptune.ai/blog/end-to-end-mlops-platforms

每个机器学习模型在幕后总是有一个模型生命周期——它从数据版本化开始,然后是数据验证,通常是一些预处理(将现实世界的数据映射到我们的模型理解的东西),模型训练,架构,一些调整,分析验证,最后是部署。

如果你是一名数据科学家,你将会一遍又一遍地重复这个循环,所以让这个过程自动化是有意义的。另外,对于数据科学家来说,另一个大问题是大多数 ML 项目从未超出实验阶段。

所以,作为这些问题的解决方案,出现了一个新的趋势: MLOps

在本文中,我们将探索 MLOps,并比较流行的 MLOps 平台,包括托管平台和开源平台。

什么是 MLOps?

MLOps 这个名字是“机器学习”和“操作”的融合。MLOps 是机器学习、DevOps 和数据工程的交集。

这是一套在生产中自动化 ML 算法生命周期的方法。通过这种方式,您可以在 ML 系统构建的所有步骤中实现自动化和监控,从最初的模型训练到针对新数据的部署和再训练。

借助 MLOps,数据科学家和 IT 团队可以协作并结合数据工程、机器学习和 DevOps 中使用的技能、技术和工具。它通过强大的机器学习生命周期管理来促进快速创新。

最大的问题是:有工具管理机器学习生命周期的所有部分吗?嗯,是也不是。

事实上,在本文中,我们将关注端到端 MLOps 平台。这些平台中的大多数都提供了强大的工具来管理从模型训练到部署等各种 ML 管道,但重要的是要提到,数据收集和标记是留给专门为这些任务构建的其他工具的。

介绍够了。让我们看看一些非常棒的端到端系统来管理机器学习管道。



MLOps 平台概述

有几个 MLOps 框架用于管理机器学习的生命周期。以下是 11 大端到端 MLOps 平台:

名字 简短描述

通过健康的 ML 生命周期安全地管理您的机器学习操作。

|
| |

端到端的企业级平台,供数据科学家、数据工程师、开发人员和管理人员管理整个机器学习&深度学习产品生命周期。

|
| |

一个端到端的机器学习平台,用于大规模构建和部署 AI 模型。

|
| |

平台使数据访问民主化,使企业能够构建自己的人工智能之路。

|
| |

AI 平台,使数据科学民主化,并大规模自动化端到端 ML。

|
| | 人工智能领域的开源领导者,其使命是为每个人实现人工智能的民主化。 |
| |

利用端到端的机器学习管道自动化 MLOps,将 AI 项目转化为现实世界的商业成果。

|
| |

致力于让 Kubernetes 上的机器学习(ML)工作流部署变得简单、可移植、可扩展。

|
| |

将数据谱系与 Kubernetes 上的端到端管道相结合,专为企业而设计。

|
| |

Kubernetes 上可复制、可扩展的机器学习和深度学习的平台。

|
| |

带你从 POC 到生产,同时管理整个模型生命周期。

|

基于 MLOps 任务的比较

为了比较我们列表中的平台,我们将它们分为以下四类:

  • 数据和管道版本化:通过对数据集、特征及其转换的版本控制进行数据管理
  • 模型和实验版本化:管理模型生命周期(跟踪实验、参数、度量和模型训练运行的性能)
  • 超参数调整:对给定模型的超参数值进行系统优化
  • 模型部署和监控:管理生产中部署的模型并跟踪性能

我们的平台负责哪些任务?

某些平台如 KubeflowAllegro.ai 覆盖了大范围的任务,其他如 H2O厚皮动物专注于特定的任务。

这种比较提出了一个棘手的问题:是选择一个完成所有任务的平台好,还是将多个专门的平台缝合在一起好?

每个平台处理不同深度的任务并不会变得更容易。

基于受支持库的比较

每个数据科学家都使用不同的编程语言、库和框架来开发 ML 模型。因此,我们需要一个 MLOps 平台来支持您项目中的库。让我们基于一系列流行的库和框架来比较我们的平台。

在我看来,数据科学工程师最关心的是他们的编程语言的支持水平,在这种情况下,尤其是 Python 和/或 r。

该表告诉我们,与其他平台相比,Pachyderm 和 Algorithmia 涵盖了更多的库。TensorFlow 显然是最受支持的库。

基于 CLI 和 GUI 的 MLOps 平台比较

在这一部分,我们比较的重点将转移到数据科学家的专业知识上。

一些 MLOps 平台侧重于具有较少工程专业知识的能力来构建和部署 ML 模型。他们关注 GUI(图形用户界面),一个允许通过 web 客户端访问的可视化工具。

其他平台面向具有工程专业知识的专家数据科学家。当将平台与现有工具集成时,这些平台倾向于使用命令行界面(CLI)或 API,而 web UI 对于专业用户来说可能并不重要。

下表包含了每个平台的使用基本上是围绕 CLI 还是 GUI 设计的近似和个人比较。

cnvrg.ioVolahai 这样的一系列平台都有更多的 CLI 焦点和进一步的 GUI 支持。其他平台,也就是 Datarobot 带有 GUI 焦点。然而,大多数托管平台介于两者之间,例如 Allegro.aiIguazio

MLOps 平台列表

Algorithmia 管理现有运营流程中 ML 生命周期的所有阶段。它将模型快速、安全且经济高效地投入生产。该平台自动化了 ML 部署,提供了最大的工具灵活性,优化了运营和开发之间的协作,利用了现有的 SDLC 和 CI/CD 实践,并包括高级安全和治理功能。

赞成的意见

  • 轻松部署,无忧无虑
  • 版本管理:对测试任何版本都有用。
  • GPU 支持

骗局

  • 目前,Algorithmia 不支持 SAS。
  • 创业成本高

Allegro 是一个开创性的端到端企业级平台,供数据科学家、数据工程师、开发人员和管理人员管理实验、编排工作负载和管理数据,所有这些都在一个简单的工具中完成,该工具集成了团队正在使用的任何工具链。该公司的平台支持本地、私有云、多云租户和定制配置。针对无限数量设备的持续学习和模型个性化。

优点:

  • 基于对象存储的完全差异化的数据管理和版本控制解决方案(S3/GS/Azure/NAS)
  • 自动实验跟踪、环境和结果
  • ML/DL 作业的自动化、管道和流程编排解决方案

缺点:

  • 在可定制性方面稍有欠缺
  • 不支持 R 语言

Cnrvg.io 是一个端到端的平台,管理、构建和自动化从研究到生产的整个 ML 生命周期。实际上,它是由数据科学家设计的,旨在组织数据科学项目的每个阶段,包括研究、信息收集、代码编写和模型优化。

优点:

  • 允许用户只需点击几下鼠标就能构建紧凑的人工智能模型的平台
  • 适用于大多数库和框架

缺点:

  • 有一些缺失的功能,如可定制的模板,预测分析和问题管理等。

Dataiku 使数据访问民主化,并使企业能够以人为中心的方式建立自己的人工智能之路。它允许您创建、共享和重用利用数据和机器学习来扩展和自动化决策的应用程序。该平台为数据专家和探索者提供了一个共同的基础,一个最佳实践的存储库,机器学习和人工智能部署/管理的捷径,以及一个集中的受控环境。

优点:

  • 根据不同的业务需求进行数据清理和转换的最佳工具。
  • 用户界面非常直观,只需点击几下鼠标,即可将数据上传到项目中。

缺点:

  • 无法很好地适应更多用户
  • 可以在平台安装和维护方面获得更好的支持

DataRobot 是领先的端到端企业人工智能平台,可以自动化并加速您从数据到价值的每一步。它是在生产中部署、监控、管理和治理机器学习模型的中心枢纽,以最大限度地增加对数据科学团队的投资,并管理风险和法规合规性。

优点:

–易于 IT 组织使用,有良好的公司支持

–能够轻松构建从简单回归到复杂梯度提升树的机器学习模型算法

缺点:

–输入大数据可能需要很长时间

–缺少到 RDBMS 类型数据库(如 mysql 或 postgres)的数据源连接器

H2O.ai 是人工智能和自动机器学习领域的开源领导者,其使命是为每个人实现人工智能的民主化。它提供了一个平台,包括数据操作、各种算法、交叉验证、超参数调整的网格搜索、特性排序和模型序列化。此外,它还能帮助全球各行各业的数据科学家提高工作效率,并以更快、更简单、更经济的方式部署模型。

优点:

  • 顶级的开源工具,包括 H2O-3 和 AutoML 系列。
  • R 和 Python 的接口支持将现有的工作流平稳过渡到 H2O 框架。
  • 专有和开源工具的结合,无人驾驶人工智能和 H2O,提供了各种用例的工具。

缺点:

  • 与 python pandas 或 pyspark 数据框架相比,H2O 框架的数据处理选项非常有限。
  • H20 错误不会返回人类可读的调试语句。

Iguazio 是一个自动化机器学习管道的数据科学平台。它通过 MLOps 和机器学习管道的端到端自动化,加速人工智能应用的大规模开发、部署和管理。这使得数据科学家能够专注于提供更好、更强大的解决方案,而不是将时间花在基础架构上。我们应该提到,它使用 Kubeflow 进行工作流编排。

优点:

  • 能够在几秒钟内从笔记本电脑或 IDE 进行部署
  • 与大多数流行的框架和 ML 库集成

缺点:

  • 怀念 CI/CD 管道的场景

Kubeflow 是一个为想要构建和试验 ML 管道的数据科学家提供的平台。它也适用于希望将 ML 系统部署到各种开发、测试和生产级服务环境中的 ML 工程师和运营团队。Kubeflow 是一个开源的 Kubernetes-native 平台,用于促进 ML 模型的扩展。另外,它是一个基于谷歌内部 ML 管道的云原生平台。该项目致力于使在 Kubernetes 上部署 ML 工作流变得简单、可移植和可扩展。它可以作为补充工具与其他 MLOps 平台一起使用。

优点:

  • 多框架集成
  • 非常适合 Kubernetes 用户

缺点:

  • 难以手动设置和配置。
  • 高可用性不是自动的,需要手动配置。

参见海王星和库伯流的对比。

Pachyderm 是一个强大的 MLOps 工具,允许用户控制端到端的机器学习周期。从数据沿袭,通过构建和跟踪实验,到可伸缩性选项。事实上,对于数据科学家和团队来说,这是一个简单的选择,因为它可以快速准确地跟踪知识和再现技能。它有助于开发可扩展的 ML/AI 管道,正如我们在基于受支持库的比较中看到的那样,它对大多数语言、框架和库都非常灵活。

赞成

  • 与大多数流行的框架和 ML 库集成
  • 当您测试新的转换管道时,它可以保留您的数据集的分支
  • 基于容器,这使得您的数据环境可移植,并易于迁移到不同的云提供商。

缺点:

  • 由于有如此多的移动部件,比如管理 Pachyderm 的免费版本所需的 Kubernetes 服务器,所以需要更多的学习曲线。

海王星和厚皮兽的对比。

Polyaxon 是一个在 Kubernetes 上自动化和复制深度学习和机器学习应用的平台。它让用户更快地迭代他们的研究和模型创建。该平台包括广泛的功能,从实验的跟踪和优化到模型管理和法规遵从性。它允许通过智能容器和节点管理进行工作负载调度,并将 GPU 服务器转变为团队或组织的共享自助服务资源。

优点:

  • 可以根据自己的需求调整软件版本
  • 端到端流程支持
  • 使在 Kubernetes 集群上安排培训变得容易

缺点:

参见海王星和多轴子的对比。

Valohai 是一个深度学习管理平台,帮助企业自动化深度学习基础设施。该平台使数据科学家能够管理机器编排、版本控制和数据管道。它使 DL 开发可审计,降低合规风险并削减劳动力和基础设施成本。

Valohai 提供了许多功能,包括并行 hypermeter 扫描、自定义脚本、培训课程可视化、数据探索、Jupyter 笔记本扩展、部署和生产监控。该平台允许用户在云或内部环境中使用多个中央处理单元(CPU)或图形处理单元(GPU)构建模型。此外,它兼容任何语言或框架,以及许多不同的工具和应用程序。Valohai 也是一款面向团队合作的软件,可以帮助团队领导管理协作、共享项目、分配成员、跟踪实验进度以及查看实时数据模型。

优点:

  • 允许轻松管理深度学习
  • 模型的全自动版本控制
  • 有益的客户服务和每月检查

缺点:

结论

有几个 MLOps 平台用于管理机器学习的生命周期。确保在选择平台时考虑相关因素。

在整篇文章中,我探讨了在决策过程中要考虑的最符合您给定需求的不同因素。我希望这能帮助你做决定。

现在您已经有了最佳端到端平台的列表,这一切都归结到您的特定用例。

快乐学习!

资源

集成学习综合指南:你到底需要知道什么

原文:https://web.archive.org/web/https://neptune.ai/blog/ensemble-learning-guide

集成学习技术已经被证明可以在机器学习问题上产生更好的性能。我们可以将这些技术用于回归和分类问题。

这些集合技术的最终预测是通过组合几个基本模型的结果获得的。平均、投票和堆叠是组合结果以获得最终预测的一些方式。

在本文中,我们将探索如何使用集成学习来提出最佳的机器学习模型。

什么是集成学习?

集成学习是一个问题中几个机器学习模型的组合。这些模型被称为弱学习者。直觉是,当你把几个弱学习者结合起来,他们就能成为强学习者。

每个弱学习器适合训练集,并提供获得的预测。通过组合来自所有弱学习器的结果来计算最终预测结果。

基本集成学习技术

让我们花点时间看看简单的集成学习技术。

最大投票

在分类中,来自每个模型的预测是一个投票。在 max 投票中,最终的预测来自票数最多的预测。

让我们举一个例子,其中有三个分类器,它们具有以下预测:

  • 分类器 1–A 类
  • 分类器 2–B 类
  • 分类器 3–B 类

最后的预测是 B 类,因为它拥有最多的票数。

求平均值

在平均中,最终输出是所有预测的平均值。这适用于回归问题。例如,在随机森林回归中,最终结果是各个决策树预测的平均值。

让我们以预测商品价格的三个回归模型为例,如下所示:

  • 回归变量 1–200
  • 回归变量 2–300
  • 回归变量 3–400

最终预测将是 200、300 和 400 的平均值。

加权平均值

在加权平均中,具有更高预测能力的基础模型更重要。在价格预测示例中,将为每个回归变量分配一个权重。

权重之和等于 1。假设回归变量的权重分别为 0.35、0.45 和 0.2。最终模型预测可以计算如下:

0.35 * 200 + 0.45300 + 0.2400 = 285

高级集成学习技术

以上是简单的技术,现在让我们来看看集成学习的高级技术。

堆垛

叠加是组合各种估计量以减少其偏差的过程。来自每个估计器的预测被堆叠在一起,并被用作计算最终预测的最终估计器(通常称为元模型)的输入。最终评估者的训练通过交叉验证进行。

回归和分类问题都可以进行叠加。

可以认为堆叠发生在以下步骤中:

  1. 将数据分成训练集和验证集,
  2. 将训练集分成 K 个折叠,例如 10 个,
  3. 在 9 个折叠上训练一个基础模型(比如说 SVM)并且在第 10 个折叠上进行预测,
  4. 重复直到你对每个折叠都有一个预测,
  5. 在整个训练集上拟合基础模型,
  6. 使用该模型对测试集进行预测,
  7. 对其他基础模型(例如决策树)重复步骤 3–6,
  8. 使用来自测试集的预测作为新模型的特征—元模型,
  9. 使用元模型对测试集进行最终预测。

对于回归问题,传递给元模型的值是数字的。对于分类问题,它们是概率或类别标签。

混合

混合类似于堆叠,但是使用定型集中的维持集来进行预测。因此,只对维持集进行预测。预测和维持集用于构建最终模型,该模型对测试集进行预测。

您可以将混合视为一种堆叠,其中元模型是根据基础模型对拒绝验证集所做的预测来训练的。

您可以将混合过程视为:

  • 将数据分成测试和验证集,
  • 根据验证集拟合基础模型,
  • 对验证和测试集进行预测,
  • 使用验证集及其预测来构建最终模型,
  • 使用该模型进行最终预测。

混合的概念因 T2 Netflix 有奖竞赛而变得流行起来。获胜团队使用混合解决方案将网飞电影推荐算法的性能提高了 10 倍。

根据本 Kaggle 组装指南:

“混合是由网飞获奖者引入的一个词。这非常接近于堆叠概括,但是更简单,信息泄露的风险更小。一些研究人员交替使用“堆叠组合”和“混合”。

使用混合,不是为训练集创建超出折叠的预测,而是创建一个小的维持集,比如说训练集的 10%。然后,堆叠器模型仅在此维持集上训练。"

混合与堆叠

混合比堆叠简单,可以防止模型中的信息泄漏。概化器和堆栈器使用不同的数据集。但是,混合使用的数据较少,可能会导致过度拟合。

交叉验证在堆叠上比混合更可靠。与在混合中使用小的保留数据集相比,它是在更多的折叠上计算的。

制袋材料

Bagging 随机抽取数据样本,构建学习算法,并使用平均值来计算 bagging 概率。它也被称为引导聚合。Bagging 汇总了几个模型的结果,以获得一个概括的结果。

该方法包括:

  • 用替换从原始数据集创建多个子集,
  • 为每个子集建立基础模型,
  • 并行运行所有的模型,
  • 组合所有模型的预测以获得最终预测。

助推

Boosting 是一种机器学习集成技术,通过将弱学习者转换为强学习者来减少偏差和方差。弱学习器以连续的方式应用于数据集。第一步是建立一个初始模型,并使其适合训练集。

然后拟合试图修正由第一模型产生的误差的第二模型。整个过程如下所示:

  • 从原始数据创建一个子集,
  • 用这些数据建立一个初始模型,
  • 对整个数据集进行预测,
  • 使用预测值和实际值计算误差,
  • 给不正确的预测分配更多的权重,
  • 创建另一个模型,尝试修复上一个模型的错误,
  • 使用新模型对整个数据集运行预测,
  • 创建多个模型,每个模型旨在纠正前一个模型产生的错误,
  • 通过加权所有模型的平均值获得最终模型。

集成学习图书馆

介绍完之后,让我们来讨论一下可以用于集成的库。概括地说,有两类:

  • 打包算法,
  • 推进算法。

打包算法

装袋算法基于上述装袋技术。让我们来看看其中的几个。

Bagging 元估计量

Scikit-learn 让我们实现一个[打包分类器](https://web.archive.org/web/20221115204110/https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.BaggingClassifier.html)和一个打包分类器`。bagging 元估计器根据原始数据集的随机子集拟合每个基本模型。然后,它通过聚合各个基础模型预测来计算最终预测。聚合是通过投票或平均来完成的。该方法通过在构造过程中引入随机化来减少估计量的方差。

有几种装袋方式:

  • 将数据的随机子集绘制为样本的随机子集被称为粘贴。**
  • 当用替换抽取样本时,该算法被称为装袋
  • 如果随机数据子集被视为特征的随机子集,则该算法被称为随机子空间
  • 当您从样本和特征的子集创建基本估计量时,它是随机补丁

让我们看看如何使用 Scikit-learn 创建 bagging 估计器。

这需要几个步骤:

  • 导入“打包分类器”,
  • 导入一个基础评估器——决策树分类器,
  • 创建“BaggingClassifier”的实例。
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
bagging = BaggingClassifier(base_estimator=DecisionTreeClassifier(),n_estimators=10, max_samples=0.5, max_features=0.5)

bagging 分类器有几个参数:

  • 基础估计器——这里是一个决策树分类器,
  • 集合中你想要的估计数,
  • “max_samples”定义将从每个基本估计量的训练集中抽取的样本数,
  • “max_features ”,以指示将用于训练每个基本估计量的特征的数量。

接下来,您可以在训练集上拟合这个分类器,并对其进行评分。

bagging.fit(X_train, y_train)
bagging.score(X_test,y_test)

回归问题的过程是一样的,唯一的不同是你将使用回归估计器。

from sklearn.ensemble import BaggingRegressor
bagging = BaggingRegressor(DecisionTreeRegressor())
bagging.fit(X_train, y_train)
model.score(X_test,y_test)

随机树木的森林

随机森林是随机决策树的集合。每个决策树都是从数据集的不同样本中创建的。样品是替换抽取的。每棵树都有自己的预测。

在回归中,这些结果被平均以获得最终结果。

在分类中,最终结果可以作为得票最多的类别。

平均和表决通过防止过拟合来提高模型的准确性。

在 Scikit-learn 中,可以通过“RandomForestClassifier”和“ExtraTreesClassifier”实现随机树的森林。回归问题也有类似的估计。

from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import ExtraTreesClassifier
clf = RandomForestClassifier(n_estimators=10, max_depth=None,  min_samples_split=2, random_state=0)
clf.fit(X_train, y_train)
clf.score(X_test,y_test)

clf = ExtraTreesClassifier(n_estimators=10, max_depth=None, min_samples_split=2, random_state=0)
clf.fit(X_train, y_train)
clf.score(X_test,y_test)

助推算法

这些算法基于前面描述的 boosting 框架。让我们来看看其中的几个。

adaboost 算法

AdaBoost 通过拟合一系列弱学习者来工作。它在随后的迭代中给不正确的预测更多的权重,给正确的预测更少的权重。这迫使算法关注更难预测的观察结果。最终的预测来自于对多数票或总数的权衡。

AdaBoost 可用于回归和分类问题。让我们花点时间看看如何使用 Scikit-learn 将该算法应用于分类问题。

我们使用“AdaBoostClassifier”。‘n _ estimators’表示集合中弱学习者的数量。每个弱学习者对最终组合的贡献由“learning_rate”控制。

默认情况下,决策树被用作基本估计器。为了获得更好的结果,可以调整决策树的参数。您还可以调整基本估计量的数量。

from sklearn.ensemble import AdaBoostClassifier
model = AdaBoostClassifier(n_estimators=100)
model.fit(X_train, y_train)
model.score(X_test,y_test)

梯度树提升

梯度树提升还结合了一组弱学习器来形成强学习器。就梯度推进树而言,有三个主要事项需要注意:

  • 必须使用微分损失函数,
  • 决策树被用作弱学习器,
  • 这是一个添加模型,所以树是一个接一个添加的。梯度下降用于在添加后续树时最小化损失。

可以使用 Scikit-learn 建立一个基于梯度树提升的模型。

from sklearn.ensemble import GradientBoostingClassifier
model = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0, max_depth=1, random_state=0)
model.fit(X_train, y_train)
model.score(X_test,y_test)

极端梯度推进

极限梯度提升(eXtreme Gradient Boosting),俗称 XGBoost ,是一个顶级的梯度提升框架。它基于弱决策树的集合。它可以在单台计算机上进行并行计算。

该算法对基础学习者使用回归树。它还内置了交叉验证。开发人员喜欢它的准确性、效率和可行性。

import xgboost as xgb
params = {"objective":"binary:logistic",'colsample_bytree': 0.3,'learning_rate': 0.1,
                'max_depth': 5, 'alpha': 10}
model = xgb.XGBClassifier(**params)
model.fit(X_train, y_train)
model.fit(X_train, y_train)
model.score(X_test,y_test)

LightGBM

LightGBM 是一种基于树学习的梯度推进算法。与其他使用深度生长的基于树的算法不同,LightGBM 使用叶子生长。逐叶增长算法往往比基于 dep 的算法收敛得更快。

通过设置适当的目标,LightGBM 可以用于回归和分类问题。

以下是如何将 LightGBM 应用于二进制分类问题。

import lightgbm as lgb
lgb_train = lgb.Dataset(X_train, y_train)
lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train)
params = {'boosting_type': 'gbdt',
              'objective': 'binary',
              'num_leaves': 40,
              'learning_rate': 0.1,
              'feature_fraction': 0.9
              }
gbm = lgb.train(params,
    lgb_train,
    num_boost_round=200,
    valid_sets=[lgb_train, lgb_eval],
    valid_names=['train','valid'],
   )

CatBoost

CatBoost 是由 Yandex 开发的深度梯度增强库。它使用遗忘决策树生成一棵平衡树。正如您在下图中看到的,在每个级别进行左右分割时使用了相同的功能。

研究人员需要 Catboost 的原因如下:

  • 本机处理分类特征的能力,
  • 模型可以在几个 GPU 上训练,
  • 它通过使用默认参数提供很好的结果来减少参数调整时间,
  • 可以将模型导出到 Core ML 用于设备上推理(iOS),
  • 它在内部处理丢失的值,
  • 它可用于回归和分类问题。

以下是如何将 CatBoost 应用于分类问题的方法。

from catboost import CatBoostClassifier
cat = CatBoostClassifier()
cat.fit(X_train,y_train,verbose=False, plot=True

帮助您在基础模型上进行堆叠的库

当叠加时,单个模型的输出被叠加,并且最终估计器被用于计算最终预测。估计量适用于整个训练集。最终估计量是根据基本估计量的交叉验证预测训练的。

Scikit-learn 可用于堆叠估计量。让我们来看看如何对分类问题的估计量进行叠加。

首先,您需要设置您想要使用的基本估计量。

estimators = [
  ('knn', KNeighborsClassifier()),
   ('rf', RandomForestClassifier(n_estimators=10, random_state=42)),
   ('svr', LinearSVC(random_state=42))
]

接下来,实例化堆叠分类器。其参数包括:

  • 上面定义的估计量,
  • 你想用的最后一个估计量。默认情况下使用逻辑回归估计量,
  • ` cv '交叉验证生成器。默认情况下使用 5 k 倍交叉验证,
  • “stack_method ”,规定应用于每个估算器的方法。如果为“auto ”,它将依次尝试“predict_proba”、“decision_function”或“predict”。
from sklearn.ensemble import StackingClassifier
clf = StackingClassifier(
 estimators=estimators, final_estimator=LogisticRegression()
 )

之后,您可以将数据拟合到训练集,并在测试集上对其进行评分。

clf.fit(X_train, y_train)
clf.score(X_test,y_test)

Scikit-learn 还允许您实现投票估计器。它使用多数投票或基本估计值的概率平均值来进行最终预测。

这可以使用分类问题的“VotingClassifier”和回归问题的“VotingRegressor”来实现。就像堆叠一样,你首先必须定义一组基本估计量。

让我们看看如何实现它来解决分类问题。“投票分类器”允许您选择投票类型:

  • ‘软’意味着概率的平均值将被用于计算最终结果,
  • ` hard '通知分类器使用预测类别进行多数表决。
from sklearn.ensemble import VotingClassifier
voting = VotingClassifier(
    estimators=estimators,
    voting='soft')

投票回归器使用几个估计量,并将最终结果作为预测值的平均值返回。

使用 Mlxtend 堆叠

您还可以使用 Mlxtend 的`StackingCVClassifier进行堆叠。第一步是定义一个基本估计量列表,然后将估计量传递给分类器。

您还必须定义将用于汇总预测的最终模型。在这种情况下,它是逻辑回归模型。

knn = KNeighborsClassifier(n_neighbors=1)
rf = RandomForestClassifier(random_state=1)
gnb = GaussianNB()
lr = LogisticRegression()
estimators = [knn,gnb,rf,lr]
stack = StackingCVClassifier(classifiers = estimators,
                            shuffle = False,
use_probas = True,
cv = 5, 
meta_classifier = LogisticRegression())

何时使用集成学习

当您想要提高机器学习模型的性能时,可以采用集成学习技术。例如增加分类模型的准确性或减少回归模型的平均绝对误差。集合也导致更稳定的模型。

当您的模型过度适应训练集时,您还可以采用集成学习方法来创建更复杂的模型。然后,集合中的模型将通过组合它们的预测来提高数据集的性能。

当集成学习效果最好时

当基本模型不相关时,集成学习效果最好。例如,您可以在不同的数据集或要素上训练不同的模型,如线性模型、决策树和神经网络。基础模型越不相关越好。

使用不相关模型背后的想法是,每一个都可能解决另一个的弱点。它们还具有不同的强度,当组合时,将产生性能良好的估计器。例如,创建仅基于树的模型的集合可能不如将树型算法与其他类型的算法相结合有效。

最后的想法

在本文中,我们探索了如何使用集成学习来提高机器学习模型的性能。我们还学习了各种工具和技术,您可以使用它们进行组装。你的机器学习技能有望增长。

组装愉快!

资源

德里克·姆维蒂

Derrick Mwiti 是一名数据科学家,他对分享知识充满热情。他是数据科学社区的热心贡献者,例如 Heartbeat、Towards Data Science、Datacamp、Neptune AI、KDnuggets 等博客。他的内容在网上被浏览了超过一百万次。德里克也是一名作家和在线教师。他还培训各种机构并与之合作,以实施数据科学解决方案并提升其员工的技能。你可能想看看他在 Python 课程中完整的数据科学和机器学习训练营。


阅读下一篇

机器学习中模型评估和选择的最终指南

10 分钟阅读|作者 Samadrita Ghosh |年 7 月 16 日更新

在高层次上,机器学习是统计和计算的结合。机器学习的关键围绕着算法或模型的概念,这些概念实际上是类固醇的统计估计。

然而,根据数据分布的不同,任何给定的模型都有一些限制。它们中没有一个是完全准确的,因为它们只是 (即使使用类固醇) 。这些限制俗称 偏差方差

具有高偏差的模型会因为不太注意训练点而过于简化(例如:在线性回归中,不管数据分布如何,模型将总是假设线性关系)。

具有高方差的模型将通过不对其之前未见过的测试点进行概括来将其自身限制于训练数据(例如:max_depth = None 的随机森林)。

当限制很微妙时,问题就出现了,比如当我们必须在随机森林算法和梯度推进算法之间进行选择,或者在同一决策树算法的两个变体之间进行选择。两者都趋向于具有高方差和低偏差。

这就是模型选择和模型评估发挥作用的地方!

在本文中,我们将讨论:

  • 什么是模型选择和模型评估?
  • 有效的模型选择方法(重采样和概率方法)
  • 流行的模型评估方法
  • 重要的机器学习模型权衡

Continue reading ->


机器学习教程中的深度 ETL——Neptune 案例研究

原文:https://web.archive.org/web/https://neptune.ai/blog/etl-in-machine-learning

大多数时候,作为数据科学家,我们认为我们的核心价值是我们找出解决任务的机器学习算法的能力。事实上,模型训练只是大量工作的最后一部分,主要是数据,这是开始构建模型所需要的。

在 ML 解决方案或高度复杂的神经网络出现之前,一个完整的数据基础设施应该已经就位、经过测试并准备就绪。不幸的是,我们常常认为整个数据管道上游部分所需的大量工作是理所当然的。

数据应该是我们的主要关注点,同时找到将其转化为可操作见解的方法。如今,对于任何寻求在快速发展的世界中领先的公司来说,数据都被视为高价值资源。

在本文中,我将介绍一组构建数据基础设施的概念和过程,以及成功的数据管道的不同构件。我将重点介绍:

  • 解释通用数据管道
  • 涉及 ML 实践的 ETL(提取、转换、加载)过程
  • 使用 Apache Airflow 实现数据工作流程自动化
  • 在 Neptune 培训和管理不同的 ML 模型解决方案

为了让这篇文章更加实用和有指导意义,我将使用一个信用评分数据集来运行所有的实验。我坚信边做边学,所以让我们马上开始吧!

: 完整的代码可以在我的 Github repo 中找到。不要犹豫,克隆它,自己尝试。

数据管道和工作流

通常在商业中,我们经常为了各种各样的目的处理大量的数据。构建健壮的管道可能会变得相当复杂,尤其是在数据稀缺、转换过程涉及大量技术细节的时候。

高效的数据传输依赖于三个重要的模块:

  1. 数据生产者

数据源指向原始数据准备好被获取的地方。

  1. 转换和运输工作流程

ETL 子流程,涉及一堆提取、转换和数据加载层,将数据路由到相应的端点。

  1. 数据消费者

利用干净和预处理信息执行高端 taks 的最终端点。

管道是非常通用的,根据商业计划有不同的用途。它们通常共享一般的概念,但是具体的实现会有所不同。

在我们的例子中,数据集已经准备好了。我们需要的是设计一个 ETL 过程,根据我们假装要做的事情来转换我们的数据。

探索信用评分数据集

在这一部分,我们将彻底分析信用评分数据集。数据集将帮助我们实现和测试我们的 ETL 工作流。

银行使用信用评分模型为客户分配信用评分。这些分数代表了客户的总体信用度。信用评分起源于 20 世纪 50 年代初的美国,供债权人评估有信用历史的客户的财务实力。今天,这项技术已经成为一个真正的金融机构。这一评级适用于所有拥有社会保障号码的美国人。

我们将使用的数据集“给我一些信任”,来自 Kaggle 。我将简要概述数据结构,解释每个特性的本质,并展示一组通用统计数据。

数据特征

  • 无担保额度的循环使用:信用卡和个人信用额度的总余额,除了房地产,没有分期付款债务,如汽车贷款,除以信用额度的总和
  • 年龄:借款人的年龄,以年为单位
  • 逾期 30-59 天未恶化的次数:在过去 2 年中,借款人逾期 30-59 天未恶化的次数
  • 债务比率:每月的债务支付、赡养费、生活费用除以每月总收入
  • 月收入:人均月收入
  • 未结清的信用额度和贷款数量:未结清的贷款(汽车贷款或抵押贷款等分期付款)和信用额度(如信用卡)数量
  • 逾期 90 天的次数:借款人逾期 90 天或以上的次数
  • 房地产贷款数量或额度:包括房屋净值信用额度在内的抵押和房地产贷款数量
  • 逾期 60-89 天的次数没有恶化:在过去 2 年中,借款人逾期 60-89 天的次数没有恶化
  • 被赡养人数:家庭中除自己以外的被赡养人数(配偶、子女等)。)

目标

  • 两年内严重拖欠:逾期拖欠 90 天或更长时间的人

该目标表明在两年的时间窗内衡量的债务人的拖欠情况。值为 1 表示借款人拖欠贷款,并且在过去 2 年中一直拖欠贷款。值为 0 表示借款人是一个好客户,并且在最近两年中按时偿还了债务。

通常,大多数金融行业数据包含缺失值,或者对于特定特征没有意义的值。这个特殊的数据集也不例外,在债务和信贷余额比率方面存在不一致,价值远远超出了应该承认的范围。

因此,我们将应用数据转换来消除所有会改变建模和训练阶段结果的差异。

现在,让我们专注于描述性分析:

不出所料,目标特性高度不平衡,会导致模型训练出现严重问题。将 86.3 %的债务人归类为不良付款人将导致模型过度适合这一特定类别,而完全忽略其他类别。

通过查看年龄分布,我们清楚地观察到,40 岁到 50 岁之间的年龄组包含大多数样本,其他剩余的组或多或少是平衡的。

Age distribution

Age distribution regarding Frequency and Cumulative Frequency

年龄分析表明,人口中负债最多的部分是 35 至 70 岁的人。最重要的是,月收入最低的人群的债务总是更高。

Debt ratio

Debt ratio distribution regarding Age and Monthly Income

积累金融资源最多的人口段在 45 岁到 60 岁之间,这是相当符合逻辑和似是而非的。

Monthly Income distribution by Age

Monthly Income distribution by Age

循环债务的趋势与长期债务非常相似,人口非常年轻,负债总是越来越多。数据中最明显的相关性是短期和长期债务、年龄组和工资之间的相关性。

Revolving credits ratio by Age and Monthly Income

现在我们对数据集有了更多的了解和理解,我们可以继续进行数据提取和转换的 ETL 过程。

构建并自动化您的 ETL 过程

在这一节中,我们将实现一个 ETL 工作流,该工作流将数据从 csv 文件提取到一个可用的 pandas 数据框架中,我们将应用所有需要的转换来为 ML 模型准备一个干净的数据集。为了提高效率,我们将尝试模拟一个自动化循环来运行该流程。

本节将介绍一些概念,如用于过程自动化的气流定向非循环图,以及实现数据转换的因素分析程序。

数据析取

我们希望从 csv 文件中提取数据,并将其用于我们的实验目的。为此,首先我们创建一个小的 Python 数据管理器类,它将负责解析 csv、提取和格式化任何相关数据以供我们分析。

class DataETLManager:
    def __init__(self, root_dir: str, csv_file: str):
        if os.path.exists(root_dir):
            if csv_file.endswith('.csv'):
                self.csv_file = os.path.join(root_dir, csv_file)
            else:
                logging.error('The file is not in csv format')
                exit(1)
        else:
            logging.error('The root dir path does not exist')
            exit(1)

        self.credit_scoring_df = pd.read_csv(self.csv_file, sep=',', encoding='ISO-8859-1')
    def extract_data(self):
        return self.credit_scoring_df

    def fetch_columns(self):
        return self.credit_scoring_df.columns.tolist()

    def data_description(self):
        return self.credit_scoring_df.describe()

    def fetch_categorical(self, categorical=False):
        if categorical:
            categorical_columns = list(set(self.credit_scoring_df.columns) - set(self.credit_scoring_df._get_numerical_data().columns))
            categorical_df = self.credit_scoring_df[categorical_columns]
            return categorical_df
        else:
            non_categorical = list(set(self.credit_scoring_df._get_numerical_data().columns))
            return self.credit_scoring_df[non_categorical]

需要仔细研究的三种重要方法:

  • extract_data():返回我们刚刚创建的信用评分数据框架
  • fetch_columns():返回数据中的所有列
  • data_description():如果我们想快速浏览一下数据的结构,这很有用
  • fetch _ categorical():返回数据框中的分类值

我们将把列名改得更短:

credit_df=credit_df.drop('Unnamed: 0', axis=1)
credit_df.columns = ['Target', 'Revolving', 'Age', '30-59PastDue', 'DbtRatio', 'Income', 'NumOpenLines', 'Num90DayLate', 'NumRealEstLines', '60-89PastDueNoW', 'FamMemb']

结果看起来像这样:

Credit Scoring datatset

Credit Scoring datatset

数据转换

我们将关注两个转型阶段:

  • 预处理转换
  • 分析转换

这个想法是,我们绝对需要预处理传入的原始数据,消除重复,丢弃空值和缺失值。此外,进行单变量分析时,我们很快会发现许多样本的比率变量超出了范围。通常,我们需要检测和删除异常值。

有了可用的数据,我们将开始实施因子分析,以提取最能解释方差和相关性的深刻特征。

预处理转换

删除重复值和缺失值:

def transform_data(self):

        self.credit_scoring_df.drop_duplicates(keep='last', inplace=True)

        self.credit_scoring_df.dropna(how='all', inplace=True)

去除异常值:

  • 年龄特征是从 0 到最大值 100 的连续变量。有某些记录,价值为零,没有意义,不能作为借款人的资格,该人必须是 18 岁的成年人。
  • 检查值大于 1 的债务和周转比率的上限和顶部编码方法,这意味着所有高于上限的值都将被删除。
  • 从模型中排除具有显著(超过 50%)缺失值的特征或记录,尤其是当缺失的程度对于数据不平衡率(相当高)来说足够重要时。
clean_credit = self.credit_scoring_df.loc[self.credit_scoring_df['Revolving'] <= 1]
clean_credit = clean_credit.loc[clean_credit['DbtRatio'] <= 1]
clean_credit = clean_credit.loc[clean_credit['Age'] <= 100]
clean_credit = clean_credit.loc[clean_credit['Age'] >= 18]
clean_credit = clean_credit.loc[clean_credit['FamMemb'] < 20]

分析转换

清理完数据后,我们将用均值=0标准差=1 对数据进行标准化,除了作为目标的二元因变量。

def normalize(dataset):
    dataNorm=((dataset-dataset.min())/(dataset.max()-dataset.min()))
    dataNorm["Target"]=dataset["Target"]
    return dataNorm

clean_scaled_df = normalize(clean_credit)

数据值范围从 0 到 1:

Normalized data values

Normalized data values

从因子分析开始

在分离训练阶段的数据之前,我们希望检查所有变量之间的相关性,以了解变量将如何组合。

因子分析是一种线性统计模型。它用来解释观察变量之间的方差,将一组观察变量浓缩成未观察变量,称为因子。观察变量被建模为因子和误差项的线性组合。

首先,让我们运行一个充分性测试来检查数据集是否适合于因子分析。我们将进行巴莱特球形度测试

from scipy.stats import chi2, pearsonr
import numpy as np

def barlett_test(frame: pd.DataFrame):

    frame.info()

    col, row = frame.shape
    x_corr = frame.corr()

    corr_det = np.linalg.det(x_corr)
    chi_measure = -np.log(corr_det) * (col - 1 - (2 * row + 5) / 6)
    degrees_of_freedom = row * (row - 1) / 2
    p_value = chi2.sf(statistic, degrees_of_freedom)
    return chi_measure, p_value
chi_square, p_value = barlett_test(clean_scaled_df)
(1003666.113272278, 0.0)

高度适合 : 观察到的相关性不同于单位矩阵,H0 和 H1 假设得到验证。

我们将使用 factor_analyzer python 包,通过以下命令安装它:

pip install factor_analyzer

将数据拟合到 FactorAnalyzer 类,我们将运行 Kaiser criterion 内部统计以得出数据中的特征值。

from factor_analyzer import FactorAnalyzer

fa = FactorAnalyzer()
fa.fit(clean_scaled_df)

ev, v = fa.get_eigenvalues()
eigen_values = pd.DataFrame(ev)
eigen_values

原始特征值:

有四个特征值大于 1 的主分量:

Eigen Values

Eigen Values after Running Factor Analysis

绘制碎石图我们可以很容易地想象出我们需要的四个相关因素:

import matplotlib.pyplot as plt

plt.scatter(range(1,clean_scaled_df.shape[1]+1),ev)
plt.plot(range(1,clean_scaled_df.shape[1]+1),ev)
plt.title('Scree Plot')
plt.xlabel('Factors')
plt.ylabel('Eigenvalue')
plt.grid()
plt.show()

Scree plot for the 4 factors

Scree plot for the 4 factors

检查如何将在 matplotlib 中生成的图表记录到 Neptune。

让我们对这 4 个因素进行因素分析轮换,以获得更好的解释。旋转可以是正交的或倾斜的。它有助于在观察到的变量之间重新分配公度,具有清晰的载荷模式。

fac_rotation = FactorAnalyzer(n_factors=4, rotation='varimax')
fac_rotation.fit(clean_scaled_df)

fac_rotation.get_factor_variance()
特征 因素 1 因素 2 因素 3 因素 4

我们得出这四个分量解释的方差为 51.4% ,是令人满意的。基于此,我们决定用四个因素进行进一步分析。

显示 4 个因素及其各自的可观察特征,我们看到:

Factors and Observable Features

Factors and Observable Features side by side

我的观察

  • 变量30-59 过期60-89 过期现在num 90 延迟工厂 1 上加载高。这意味着这一因素导致借款人越来越拖欠。因此我们可以把这个因素命名为 财务斗争

二观察

  • 变量 DbtRatioNumOpenLinesNumRealEstLinesFactor2 上加载高。这意味着这一因素导致借款人承担更多的债务和更多的信贷额度。我们可以将其命名为 财务要求

三观察

  • 变量年龄家庭成员旋转因子 3 上负载高,年龄与因子 3 成间接比例。这个因素被命名为 消耗性收入 ,因为随着年龄的增长,消耗性收入也会增加。

四观察

  • 变量收入家庭成员加载到工厂 4 上。所以我们可以很容易地将其命名为 行为生活方式 因为随着收入的增加,我们的生活方式和我们家庭成员的生活方式也会增加。

现在我们有了 ML 分析的四个因素:

  • 财务斗争
  • 财务要求
  • 消耗性收入
  • 行为生活方式

使用 Dag 自动化 ETL 流程

一旦提取和转换管道形成并准备好进行部署,我们就可以开始考虑将以前的数据存储在数据库中的方法。

为了简化和便于说明,我们将使用 Sql_Alchemy python 包将之前转换的数据框加载到本地 MySQL 数据库中。

pip install SQLAlchemy
from sqlalchemy.engine import create_engine

def load_data(self):
        database_config = {
            'username': 'your_username',
            'password': 'your_pass',
            'host': '127.0.0.1',
            'port':'3306',
            'database':'db_name'
        }

        engine = create_engine('mysql+mysqlconnector://{}:{}@{}:{}/{}'.format(
            database_config['username'],
            database_config['password'],
            database_config['host'],
            database_config['port'],
            database_config['database']
        ))

        data_to_load = type(pd.DataFrame())(self.credit_scoring_df)
        try:
            data_to_load.to_sql('Credit Scoring', con=engine, if_exists='append', index=False)
        except Exception as err:
            print(err)

气流有向图:有向无环图

Airflow 计划自动化的数据工作流,包括共享特定依赖关系的多个任务或流程。气流文件对 Dag 的定义如下:

在 Airflow 中,DAG(或有向无环图)是您想要运行的所有任务的集合,以反映它们的关系和依赖性的方式组织。在 Python 脚本中定义了一个 DAG,它将 DAG 结构(任务及其依赖项)表示为代码

要安装并开始使用 Airflow,可以查看网站,网站对每一步都解释的很透彻: AirFlow Doc

在我们的例子中,我们将编写一个小的 DAG 文件来模拟 ETL 的自动化。我们将安排 DAG 从 2021 年 3 月 25 日开始每天运行。DAG 将有三个 python 运算符,分别代表提取、转换和加载功能。

from datetime import timedelta, datetime
from airflow import DAG
from airflow.operators.python import PythonOperator

from etl_process import DataETLManager, DATA_PATH

default_dag_args = {
    'owner': 'airflow',
    'depends_on_past': False,
    'start_date': datetime(2021, 3, 9),
    'email': ['airflow@example.com'],
    'email_on_failure': False,
    'email_on_retry': False,
    'retries': 2,
    'retry_delay': timedelta(minutes=1),
}

etl_dag = DAG(
    'etl_retail',
    default_args=default_dag_args,
    description='DAG for ETL retail process',
    schedule_interval=timedelta(days=1),
    tags=['retail']
)

负责运行每个 ETL 过程的 PyhtonOperators:

etl_manager = DataETLManager(DATA_PATH, 'OnlineRetail.csv')

extract = PythonOperator(
    task_id='extract_data',
    python_callable=etl_manager.extract_data,
    dag=etl_dag
)

transform = PythonOperator(
    task_id='transform_data',
    python_callable=etl_manager.transform_data,
    dag=etl_dag
)

load = PythonOperator(
    task_id='load_data',
    python_callable=etl_manager.load_data,
    dag=etl_dag
)

最后,我们定义任务相关性:提取,然后转换,然后加载到数据库中。

extract >> transform >gt; load

运行预测和基准测试结果

在这一部分中,我们将把我们获得的经过转换和简化的数据分成训练集和测试集,并使用三种集成算法,使用我们之前提取的 4 个因素来预测严重的拖欠行为。

我们将把我们所有的 ML 开发与 Neptune 集成在一起,以跟踪和比较我们一路上得到的所有指标。


请注意,由于最近的 API 更新,这篇文章也需要一些改变——我们正在努力!与此同时,请检查海王星文档,那里的一切都是最新的!


使用三个 ML 模型,我们将能够比较结果,并看到每种方法在哪里可以表现得更好。我们将为此特定任务测试三个 ML 模型:

  • 逻辑回归
  • 决策树
  • 极端梯度推进

为发展设定海王星

安装所需的 neptune 客户端库,开始将您的代码与 Neptune 集成:

安装 neptune 库:

pip  install neptune-client

安装 Neptune 笔记本,这样可以将我们所有的工作保存到 Neptune 网站

pip install -U neptune-notebooks

通过安装以下扩展来启用 jupiter 集成

jupyter nbextension enable --py neptune-notebooks

获取您的 api 密钥,将您的笔记本与您的 Neptune 会话连接起来:

ML-development-API

*Set up your Neptune Token from the website *

要完成设置,请在笔记本中导入 neptune 客户端库,并调用 neptune.init()方法初始化连接:

import neptune
neptune.init(project_qualified_name='aymane.hachcham/CreditScoring')

逻辑回归

回归模型的主要目标是根据特定的数学标准找到最适合一组数据的预测值组合。

在分类反应数据问题中最常用的回归模型是逻辑回归。通常,逻辑回归使用逻辑函数的基本形式,根据各种预测值对二元因变量进行建模。

该模型的训练非常简单。我们使用著名的机器学习库 SciKit-Learn 来实现逻辑模型。之前在数据处理方面所做的努力将在这一部分对我们有很大帮助。

包含先前定义的因子的表格如下所示:

ETL final_table

Table that aggregates the values for the 4 factors

credit_scoring_final = pd.DataFrame(new_data_frame, columns=['Financial_Struggle', 'Finance_Requirements', 'Expendable_Income', 'Behavioral_LifeStyle'])
credit_scoring_final

分离训练集和测试集中的数据:

X = credit_scoring_final
x_train, x_test, y_train, y_test = train_test_split(X, target, test_size=0.25, random_state=56)

用逻辑回归训练:

from sklearn.linear_model import LogisticRegression

model = LogisticRegression(C=0.00026366508987303583, class_weight=None, dual=False, max_iter=100, multi_class='auto', n_jobs=None, penalty='l1',
random_state=None, solver='saga')
model.fit(x_train, y_train)

测试结果:

from sklearn.metrics import accuracy_score, classification_report

predictions = model.predict(x_test)
test_accuracy = accuracy_score(y_test, predictions)
准确(性) 回忆 精确 f1-分数 因素 4

ROC 曲线和混淆矩阵:

ROC Curve and Confusion Matrix

ROC Curve and Confusion Matrix for the Logistic Regression

由于坏账在数据中所占的比例,该模型总是能预测出比好债务人更好的坏账。这是不可避免的,回归模型无法超越这一限制,无论涉及的工程水平如何。

XGBoost

EXtreme Gradient Boosting(XGBoost)是华盛顿大学博士生陈天琦(Tianqi Chen)创建的梯度增强的优化和并行化开源实现。

XGBoost 使用决策树(像 random forest)来解决分类(二进制和多类)、排序和回归问题。所以,我们在这里的监督学习算法领域。

从初始化海王星实验开始:

import neptune
from neptunecontrib.monitoring.xgboost import neptune_callback

params_attempt3 = {
    'max_depth':10,
    'learning_rate':0.001,
    'colsample_bytree': 0.7,
    'subsample':0.8,
    'gamma': 0.3,
    'alpha':0.35,
    'n_estimator': 100,
    'objective': 'binary:logistic',
    'eval_metric': 'error'
}

neptune.create_experiment(
    name='CreditScoring XGB',
    tags=['XGBoost', 'Credit Scoring'],
    params=params
)

拆分数据并实例化 DMatrix 数据加载器:

x_train, x_test, y_train, y_test = train_test_split(X, target, test_size=0.25, random_state=56)

dtrain = xgb.DMatrix(x_train, label=y_train)
dtest = xgb.DMatrix(x_test, label=y_test)

让我们开始训练模型,并使用Neptune XGBoost integration跟踪每个指标。

import xgboost as xgb
import neptune
from neptunecontrib.monitoring.xgboost import neptune_callback

xgb_classifer = xgb.XGBClassifier(**params_attempt3)
xgb_classifer.fit(
    x_train,
    y_train,
    eval_set=[(x_test, y_test)],
    callbacks=[neptune_callback(log_tree=[0, 1])])

neptune.stop()

回到 Neptune 查看损失指标和特性重要性图:

Charts of train and eval loss

Charts of train and eval loss: Neptune web UI

Feature importance graph

Feature importance graph for the 4 factors

我们甚至可以看看模型的内部估计器:XGBoost 内部使用的树的图形。

Internal XGBoost estimators

Internal XGBoost estimators (click to enlarge)

XGBoost 结果:

准确(性)

回忆 精确 f1-分数
决策图表

决策树的优点是解释简单、训练快速、非参数化,并且只需要很少的数据预处理。它们可以通过监督学习算法自动计算,该算法能够在非结构化和潜在的大数据中自动选择区别变量。

我们将为这个准备好的数据集测试决策树的一个轻量级实现,然后对三个模型进行基准测试,看看哪个性能更好。

ROC Curve and Confusion Matrix for the XGBoost performer

训练模型

结果:

准确(性)

回忆

from sklearn.tree import DecisionTreeClassifier

classifier = DecisionTreeClassifier()
classifier.fit(x_train, y_train)

精确

preds = classifier.predict(x_test)
print('Accuracy Score: ', metrics.accuracy_score(y_test, preds))

f1-分数

三个模型的基准 在多次训练逻辑回归(LR)、决策树(DT)和极端梯度推进(XGBoost)以避免单一结果偏差之后,将使用每个模型的最佳执行迭代来进行比较。

我们看到所有的模型在准确性方面都非常接近,尽管总的来说 XGBoost 做得更好。最有趣的度量是 F1 分数,它更好地评估了模型在识别正确类别方面的混乱程度。 XGBoost 在预测正确的类别和区分“”和“”债务人方面做得更好。

结论

ROC Curve and Confusion Matrix for the Decision Tree model

在本教程中,我们对数据科学工作中涉及的不同方面进行了全面考察,例如:

数据预处理和转换,

数据管道自动化,

统计分析和降维,

ML 开发和培训,

对多个模型变量进行基准测试并选择正确的一个,

使用 Neptune 的 ML 工作流。

  • 我希望这篇教程对你有用,因为我已经把它设计成完全覆盖真实数据科学用例的不同方面。如果你觉得你对知识的渴望仍然需要冷却,请查看下面的参考资料。玩得开心!
  • 参考
  • Statistical Analysis and Dimensionality reduction,
  • ML development and training,
  • Benchmarking multiple model variants and picking the right one,
  • ML workflow using Neptune.

I hope this tutorial was useful to you, as I’ve designed it to fully cover different aspects of real data science use-cases.  If you feel that your thirst for knowledge still needs quenching go ahead check the references below. Have fun!

References

二元分类的 24 个评估指标(以及何时使用它们)

原文:https://web.archive.org/web/https://neptune.ai/blog/evaluation-metrics-binary-classification

分类指标让你评估机器学习模型的性能但是它们数量太多,每一个都有自己的优点和缺点,选择一个适合你的问题的评估指标有时真的很棘手。

在本文中,您将了解一些常见的和鲜为人知的评估指标和图表,以理解如何为您的问题选择模型性能指标。

具体来说,我将谈论:

  • 大多数主要分类指标背后的定义直觉是什么,
  • 非技术性解释您可以向业务利益相关者传达二进制分类的指标,
  • 如何绘制性能图表和计算二元分类的通用指标,
  • 什么时候应该用他们。

有了这些,你就会明白权衡取舍,从而更容易做出与指标相关的决策。

分类指标到底是什么?

简单地说,分类指标是一个衡量机器学习模型在将观察值分配给特定类别时的性能的数字。

二元分类是一种特殊的情况,你只需要分类:积极的和消极的。

典型地,性能表现在从 0 到 1 的范围内(尽管不总是如此),其中 1 分是为完美模型保留的。

不要用枯燥的定义来烦你,让我们基于最近的 Kaggle 竞赛来讨论一个欺诈检测问题示例的各种分类指标。

我选择了 43 个特征,并从原始数据集中采样了 66000 个观察值,将正类的分数调整为 0.09

然后我用不同的超参数训练了一堆 lightGBM 分类器。我只使用了 learning_raten_estimators 参数,因为我想对哪些模型“真正”更好有一个直觉。具体来说,我怀疑只有 10 棵树的模型比有 100 棵树的模型更差。当然,随着使用更多的树和更小的学习率,这变得棘手,但我认为这是一个不错的代理。

因此,对于学习率n 估计量的组合,我做了以下工作:

  • 定义的超参数值:
MODEL_PARAMS = {'random_state': 1234,
                'learning_rate': 0.1,
                'n_estimators': 10}
model = lightgbm.LGBMClassifier(**MODEL_PARAMS)
model.fit(X_train, y_train)
y_test_pred = model.predict_proba(X_test)

  • 每次跑步的记录分数:
run["logs/score"] = score

要了解更多关于记录分数和指标的信息,请访问 Neptune docs。

  • 每次运行的记录 matplolib 数字:
run["images/figure"].upload(neptune.types.File.as_image(fig))

要了解更多关于记录 matplotlib 数字的信息,请访问 Neptune docs。

在这里,您可以通过以下方式探索实验运行:

  • 评估指标
  • 性能图表
  • 阈值图度量

好了,现在我们可以开始讨论那些分类指标了!

了解以下评估指标

我知道一下子要检查的东西很多。这就是为什么你可以跳到你感兴趣的部分去读。

1.混淆矩阵

如何计算:

这是呈现真阳性(tp)、真阴性(tn)、假阳性(fp)和假阴性(fn)预测的常见方式。这些值以矩阵的形式显示,其中 Y 轴显示真实的类,而 X 轴显示预测的类。

它是基于类预测计算的,这意味着您的模型的输出需要首先进行阈值处理。

from sklearn.metrics import confusion_matrix

y_pred_class = y_pred_pos > threshold
cm = confusion_matrix(y_true, y_pred_class)
tn, fp, fn, tp = cm.ravel()

看起来怎么样:

在这个例子中,我们可以看到:

  • 11918 个预言被真否定
  • 872真阳性
  • 82误报
  • 333 个预测被误判

此外,正如我们已经知道的,这是一个不平衡的问题。顺便说一句,如果你想阅读更多关于不平衡问题的文章,我推荐你看看这篇由汤姆·福西特写的文章。

何时使用:

  • 差不多一直都是。我喜欢看到名义值,而不是标准化的值,以了解模型在不同的、通常不平衡的类上的表现。

2.假阳性率| I 型错误

当我们预测到某件事,而它并没有发生时,我们就增加了假阳性率。你可以把它看作是基于你的模型预测而产生的假警报的一小部分

如何计算:

from sklearn.metrics import confusion_matrix

y_pred_class = y_pred_pos > threshold
tn, fp, fn, tp = confusion_matrix(y_true, y_pred_class).ravel()
false_positive_rate = fp / (fp + tn)

run[“logs/false_positive_rate”] = false_positive_rate

模型在此指标中的得分情况(阈值=0.5):

对于所有模型,类型 1 错误警报非常低,但是通过调整阈值,我们可以获得更低的比率。因为我们在分母中有真正的负数,我们的误差会很低,只是因为数据集不平衡。

它如何取决于阈值:

显然,如果我们提高阈值,只有得分较高的观察结果才会被归类为阳性。在我们的例子中,我们可以看到,为了达到 0 的完美 FPR,我们需要将阈值增加到 0.83。然而,这可能意味着只有很少的预测被分类。

何时使用:

  • 你很少会单独使用这个指标。通常作为其他度量的辅助指标,
  • 如果处理警报的成本很高,您应该考虑提高阈值以获得更少的警报。

3.假阴性率|第二类错误

当我们没有预测到某件事情的发生时,我们就造成了假阴性率。你可以把它想成是你的模型允许错过的欺诈交易的部分。

如何计算:

from sklearn.metrics import confusion_matrix

y_pred_class = y_pred_pos > threshold
tn, fp, fn, tp = confusion_matrix(y_true, y_pred_class).ravel()
false_negative_rate = fn / (tp + fn)

run[“logs/false_negative_rate”] = false_negative_rate

模型在此指标中的得分情况(阈值=0.5):

我们可以看到,在我们的例子中,第二类错误比第一类错误高得多。有趣的是,我们的 BIN-98 实验中第一类错误最低的第二类错误最高。有一个简单的解释,基于这样一个事实,即我们的数据集是不平衡的,并且对于类型 2 错误,我们在分母中没有真正的负数。

它如何取决于阈值:

如果我们降低阈值,更多的观察结果将被归类为阳性。在特定阈值,我们会将所有内容标记为肯定的(例如欺诈)。通过将阈值降至 0.01,我们实际上可以获得 0.083 的 FNR。

何时使用:

  • 通常,它不单独使用,而是与其他度量一起使用,
  • 如果让欺诈交易通过的成本很高,而你从用户那里获得的价值不高,你可以考虑关注这个数字。

4.真阴性率|特异性

它测量所有负面观察中有多少被我们归类为负面。在我们的欺诈检测示例中,它告诉我们在所有非欺诈交易中有多少交易被标记为干净的。

如何计算:

from sklearn.metrics import confusion_matrix

y_pred_class = y_pred_pos > threshold
tn, fp, fn, tp = confusion_matrix(y_true, y_pred_class).ravel()
true_negative_rate = tn / (tn + fp)

run[”logs/true_negative_rate”] = true_negative_rate

模型在此指标中的得分情况(阈值=0.5):

所有模型的特异性都非常高。如果你想一想,在我们的不平衡问题中,你会想到这一点。将阴性病例归类为阴性比将阳性病例归类容易得多,因此得分高。

它如何取决于阈值:

阈值越高,我们能回忆起的真正负面的观察就越多。我们可以看到,从阈值=0.4 开始,我们的模型在将负面情况分类为负面方面做得非常好。

何时使用:

  • 通常,您不会单独使用它,而是将其作为一个辅助指标,
  • 当你说某样东西是安全的时候,你真的想确定你是对的。一个典型的例子是医生告诉病人“你很健康”。在这里犯一个错误,告诉一个病人他们是安全的,可以回家了,这可能是你想要避免的。

5.阴性预测值

它衡量所有负面预测中有多少是正确的。你可以认为它是负类的精度。在我们的例子中,它告诉我们在所有非欺诈性预测中,正确预测的干净交易的比例是多少。

如何计算:

from sklearn.metrics import confusion_matrix

y_pred_class = y_pred_pos > threshold
tn, fp, fn, tp = confusion_matrix(y_true, y_pred_class).ravel()
negative_predictive_value = tn/ (tn + fn)

run[”logs/negative_predictive_value”] = negative_predictive_value

模型在此指标中的得分情况(阈值=0.5):

所有的模型得分都很高,这并不奇怪,因为对于一个不平衡的问题,预测负类是很容易的。

它如何取决于阈值:

阈值越高,被归类为阴性的病例越多,分数就越低。然而,在我们不平衡的例子中,即使在非常高的阈值下,阴性预测值仍然是好的。

何时使用:

  • 当我们关心负面预测的高精度时。例如,假设我们真的不想有任何额外的过程来筛选预测为干净的事务。在这种情况下,我们可能要确保我们的阴性预测值很高。

6.错误发现率

它衡量所有积极预测中有多少预测是不正确的。你可以简单地认为它是 1-精度。在我们的示例中,它告诉我们在所有欺诈预测中,错误预测的欺诈交易所占的比例。

如何计算:

from sklearn.metrics import confusion_matrix

y_pred_class = y_pred_pos > threshold
tn, fp, fn, tp = confusion_matrix(y_true, y_pred_class).ravel()
false_discovery_rate = fp/ (tp + fp)

run[“logs/false_discovery_rate”] = false_discovery_rate

模型在此指标中的得分情况(阈值=0.5):

“最佳模型”是令人难以置信的浅层 lightGBM,我们预计这是不正确的(更深的模型应该工作得更好)。

这是很重要的一点,单看精度(或召回率)会导致你选择一个次优的模型。

它如何取决于阈值:

阈值越高,正面预测越少。不太正面的预测,被分类为正面的预测具有较高的确定性分数。因此,错误发现率下降。

何时使用它

  • 同样,单独使用它通常是没有意义的,而是要与其他指标结合使用,如召回率。
  • 当发出错误警报的成本很高时,当您希望所有积极的预测都值得一看时,您应该优化精确度。

7.真实阳性率|回忆|灵敏度

它衡量在所有积极的观察中,我们将多少观察归类为积极的。它告诉我们我们从所有欺诈交易中收回了多少欺诈交易。

当你优化回忆时,你想把所有有罪的人关进监狱。

如何计算:

from sklearn.metrics import confusion_matrix, recall_score

y_pred_class = y_pred_pos > threshold
tn, fp, fn, tp = confusion_matrix(y_true, y_pred_class).ravel()
recall = recall_score(y_true, y_pred_class) 

run[“logs/recall_score”] = recall

模型在此指标中的得分情况(阈值=0.5):

我们的最佳模型可以在阈值为 0.5 时召回 0.72 笔欺诈交易。我们的模型在召回率上的差异非常显著,我们可以清楚地看到更好和更差的模型。当然,对于每个模型,我们可以调整阈值来召回所有欺诈交易。

它如何取决于阈值:

对于阈值 0.1,我们将绝大多数交易归类为欺诈性交易,因此召回率非常高,为 0.917。随着阈值的增加,回忆下降。

何时使用:

  • 通常,您不会单独使用它,而是将它与精度等其他指标结合使用。
  • 也就是说,当你真的关心捕捉所有欺诈性交易时,即使以虚假警报为代价,召回也是一个必不可少的指标。对你来说,处理这些警报的成本可能很低,但当交易不为人知时,成本会非常高。

8.阳性预测值|精确度

它测量有多少预测为阳性的观察结果实际上是阳性的。以我们的欺诈检测为例,它告诉我们被正确归类为欺诈的交易的比例是多少。

当你优化精度时,你想确保你投入监狱的人是有罪的。

如何计算:

from sklearn.metrics import confusion_matrix, precision_score

y_pred_class = y_pred_pos > threshold
tn, fp, fn, tp = confusion_matrix(y_true, y_pred_class).ravel()
precision = precision_score(y_true, y_pred_class) 

run[“logs/precision_score”] = precison

模型在此指标中的得分情况(阈值=0.5):

似乎所有的模型在这个阈值上都有相当高的精度。“最佳模式”是令人难以置信的浅光 GBM,这显然有鱼腥味。这是很重要的一点,单看精度(或召回率)会导致你选择一个次优的模型。当然,对于每个模型,我们可以调整阈值来提高精度。这是因为,如果我们采用一小部分高分预测,这些预测的精确度可能会很高。

它如何取决于阈值:

阈值越高,精度越好,阈值为 0.68 时,我们实际上可以获得非常精确的模型。超过这个阈值,模型不会将任何东西归类为积极的,所以我们不会绘制它。

何时使用:

  • 同样,单独使用它通常是没有意义的,而是要与其他指标结合使用,如召回率。
  • 当发出错误警报代价高昂时,当你希望所有积极的预测都值得一看时,你应该优化精确度。

9.准确(性)

它衡量有多少正面和负面的观察结果被正确分类。

不应该在不平衡的问题上使用准确性。那么,简单地把所有的观测值归为多数类,就很容易得到高精度的分数。例如,在我们的案例中,通过将所有交易分类为非欺诈交易,我们可以获得超过 0.9 的准确度。

如何计算:

from sklearn.metrics import confusion_matrix, accuracy_score

y_pred_class = y_pred_pos > threshold
tn, fp, fn, tp = confusion_matrix(y_true, y_pred_class).ravel()
accuracy = accuracy_score(y_true, y_pred_class) 

run[“logs/accuracy”] = accuracy

模型在此指标中的得分情况(阈值=0.5):

我们可以看到,对于所有模型,我们都以很大的优势击败了虚拟模型(所有干净的交易)。此外,我们预期会更好的模型实际上位于顶部。

它如何取决于阈值:

准确地说,你真的可以使用上面的图表来确定最佳阈值。在这种情况下,选择稍微高于标准 0.5 的值可能会使分数提高一点点 0.9686->0.9688。

何时使用:

  • 当你的问题得到平衡时,使用准确性通常是一个好的开始。一个额外的好处是,向项目中的非技术涉众解释它非常容易,
  • 当每门课对你来说都同样重要的时候。

10.fβ分数

简而言之,它将精确度和召回率结合成一个指标。分数越高,我们的模型越好。你可以用下面的方法计算它:

当在 F-beta 分数中选择 beta 时,你越关心回忆而不是精度,你就应该选择更高的 beta 。例如,对于 F1 分数,我们同样关心召回率和精确度;对于 F2 分数,召回率对我们来说是两倍重要。

在 0 1 的情况下,我们的最佳阈值向更低的阈值移动,而在β= 1 的情况下,它在中间的某个位置。

如何计算:

from sklearn.metrics import fbeta_score

y_pred_class = y_pred_pos > threshold
fbeta = fbeta_score(y_true, y_pred_class, beta)

run["logs/fbeta_score"] = fbeta

11.F1 分数(β= 1)

这是精确度和召回率之间的调和平均值。

如何计算:

from sklearn.metrics import f1_score
y_pred_class = y_pred_pos > threshold
f1= f1_score(y_true, y_pred_class)

run[“logs/f1_score”] = f1

模型在此指标中的得分情况(阈值=0.5):

正如我们所看到的,精确度和召回率的结合给了我们一个更真实的模型视图。我们得到 0.808 的最佳成绩,还有很大的提升空间。

好的一点是,它似乎正确地对我们的模型进行了排序,那些较大的 lightGBMs 在顶部。

它如何取决于阈值:

我们可以调整阈值来优化 F1 得分。请注意,无论是精确度还是召回率,您都可以通过提高或降低阈值来获得满分。好消息是,你可以为 F1metric 找到一个甜蜜点。正如你所看到的,获得合适的阈值实际上可以提高你的分数 0.8077- > 0.8121。

何时使用:

  • 几乎在所有的二元分类问题中。这是我解决这些问题时的首要标准。这可以很容易地向商业利益相关者解释。

12.F2 分数(β= 2)

这是一个结合了精确度和召回率的指标,将的召回率提高了两倍。

如何计算:

from sklearn.metrics import fbeta_score

y_pred_class = y_pred_pos > threshold
f2 = fbeta_score(y_true, y_pred_class, beta = 2)

run[“logs/f2_score”] = f2

模型在此指标中的得分情况(阈值=0.5):

所有车型的得分甚至低于 F1,但可以通过大幅调整阈值来提高。同样,它似乎对我们的模型进行了正确的排序,至少在这个简单的例子中是这样。

它如何取决于阈值:

我们可以看到,阈值越低,回忆起的真阳性越多,分数就越高。你通常可以找到一个最佳切入点。从 0.755 - > 0.803 的可能增益显示了阈值调整在这里是多么重要。

何时使用:

  • 当回忆正面的观察(欺诈交易)比精确更重要时,我会考虑使用它

13.科恩卡帕度量

简而言之,Cohen Kappa 告诉你你的模型比基于类别频率预测的随机分类器好多少。

要计算它,需要计算两件事:“观察一致”(po)“预期一致”(pe) 。观察一致(po)就是我们的分类器预测如何与地面事实一致,这意味着它只是准确性。预期一致性(pe)是根据类别频率进行采样的随机分类器的预测如何与基本事实或随机分类器的准确性相一致。

从解释的角度来看,我喜欢它通过合并基线(虚拟)分类器,将一些很容易解释的东西(准确性)扩展到数据集不平衡的情况。

如何计算:

from sklearn.metrics import cohen_kappa_score

cohen_kappa = cohen_kappa_score(y_true, y_pred_class)

run[“logs/cohen_kappa_score”] = cohen_kappa

模型在此指标中的得分情况(阈值=0.5):

基于这个指标,我们可以很容易地区分最差/最好的模型。还有,我们可以看到,我们最好的模型还有很大的改进空间。

它如何取决于阈值:

使用如上图所示的图表,我们可以找到优化 cohen kappa 的阈值。在这种情况下,它为 0.31,比标准的 0.5 提高了 0.7909 -> 0.7947。

何时使用:

  • 这一指标在分类环境中并不常用。然而,它可以很好地解决不平衡的问题,似乎是准确性的一个伟大的伴侣/替代品。

14.马修斯相关系数

这是预测类和地面真相之间的关联。它可以基于混淆矩阵的值来计算:

或者,您也可以计算 y_true 和 y_pred 之间的相关性。

如何计算:

from sklearn.metrics import matthews_corrcoef

y_pred_class = y_pred_pos > threshold
matthews_corr = matthews_corrcoef(y_true, y_pred_class)
run[“logs/matthews_corrcoef”] = matthews_corr

模型在此指标中的得分情况(阈值=0.5):

我们可以清楚地看到我们的模型质量有所提高,还有很大的发展空间,这是我非常喜欢的。此外,它对我们的模型进行合理的排名,并将您认为更好的模型放在最上面。当然,MCC 取决于我们选择的阈值。

它如何取决于阈值:

我们可以调整阈值来优化 MCC。在我们的例子中,最好的分数是 0.53,但我真正喜欢的是它对阈值变化不是超级敏感。

何时使用:

  • 当处理不平衡的问题时,
  • 当你想要一些容易理解的东西时。

15.受试者工作特征曲线

这是一个图表,它可视化了真阳性率(TPR)和假阳性率(FPR)之间的权衡。基本上,对于每个阈值,我们计算 TPR 和 FPR,并绘制在一个图表上。

当然,对于每个阈值,TPR 越高,FPR 越低越好,因此曲线越靠左上侧的分类器越好。

Tom Fawcett 的这篇文章对 ROC 曲线和 ROC AUC 评分进行了广泛讨论。

如何计算:

from scikitplot.metrics import plot_roc

fig, ax = plt.subplots()
plot_roc(y_true, y_pred, ax=ax)

run[“images/ROC”].upload(neptune.types.File.as_image(fig))

看起来怎么样:

我们可以看到一条健康的 ROC 曲线,无论是正类还是负类都被推向左上侧。不清楚哪一个在所有方面表现更好,因为 FPR < ~0.15,正类更高,从 FPR 开始~0.15,负类更高。

16.ROC AUC 得分

为了得到一个告诉我们曲线有多好的数字,我们可以计算 ROC 曲线下的面积,或 ROC AUC 得分。曲线越靠左上方,面积越大,ROC AUC 得分也越高。

或者,可以显示【ROC AUC 分数等同于计算预测和目标之间的等级相关性。从解释的角度来看,它更有用,因为它告诉我们这个度量向展示了你的模型在预测排名方面有多好。它告诉你随机选择的正面实例比随机选择的负面实例排名更高的概率是多少。

如何计算:

from sklearn.metrics import roc_auc_score

roc_auc = roc_auc_score(y_true, y_pred_pos)

run[“logs/roc_auc_score”] = roc_auc

模型在此指标中的得分情况:

我们可以看到改进,人们认为更好的模型确实得分更高。此外,分数独立于阈值,这很方便。

何时使用:

17.精确回忆曲线

这是一条在单一可视化中结合了精确度(PPV)和召回率(TPR)的曲线。对于每个阈值,你计算 PPV 和 TPR 并绘制它。y 轴上的曲线越高,模型性能越好。

当遇到经典的精确/召回难题时,你可以利用这个图做出明智的决定。显然,召回率越高,精确度越低。知道在哪个回忆上你的精度开始快速下降可以帮助你选择阈值并提供更好的模型。

如何计算:

from scikitplot.metrics import plot_precision_recall

fig, ax = plt.subplots()
plot_precision_recall(y_true, y_pred, ax=ax)

run[“images/precision_recall”].upload(neptune.types.File.as_image(fig))

看起来怎么样:

我们可以看到,对于负类,我们几乎在整个阈值范围内保持高精度和高召回率。因为当我们回忆起 0.2 的真阳性时,阳性分类的精确度就开始下降,当我们达到 0.8 时,精确度下降到 0.7 左右。

18.PR AUC 分数|平均精确度

与 ROC AUC 得分类似,您可以计算精确度-召回曲线下的面积,以获得描述模型性能的一个数字。

你也可以把 PR AUC 想成每个回忆阈值[0.0,1.0]计算出来的精度分数的平均值。如果需要,您还可以通过选择/剪裁召回阈值来调整此定义,以满足您的业务需求。

如何计算:

from sklearn.metrics import average_precision_score

avg_precision = average_precision_score(y_true, y_pred_pos)

run[“logs/average_precision_score”] = avg_precision

模型在此指标中的得分情况:

我们怀疑“真正”更好的模型实际上在这个指标上更好,这绝对是一件好事。总的来说,我们可以看到高分,但远不如 ROC AUC 分数乐观(0.96+)。

何时使用:

19.原木损失

Log loss 经常被用作在机器学习模型的罩下被优化的目标函数。然而,它也可以用作性能指标。

基本上,我们计算每个观察值的真实值和预测值之间的差异,并对所有观察值的误差进行平均。对于一次观测,误差公式为:

我们的模型越确定一个观察结果是肯定的,当它实际上是肯定的时候,误差就越小。但这不是线性关系。看一下误差如何随着差异的增加而变化是有好处的:

所以当我们确定某事不真实时,我们的模型会受到很大的惩罚。例如,当我们给一个负面的观察值打 0.9999 分时,我们的损失就会大增。这就是为什么有时候为了降低发生这种情况的风险,删减你的预测是有意义的。

如果你想了解更多关于日志损失的知识,请阅读丹尼尔·戈多伊的文章。

如何计算:

from sklearn.metrics import log_loss

loss = log_loss(y_true, y_pred)

run[“logs/log_loss”] = loss

模型在此指标中的得分情况:

很难真正看到强大的改进,也很难对模型的强大程度有一个直观的感受。还有,之前被选为最好的那款(BIN-101)在群里是中游。这表明使用日志损失作为性能指标可能是一个有风险的提议。

何时使用:

  • 几乎总有一个性能指标能更好地匹配你的业务问题。因此,我会将对数损失作为您模型的一个目标,并结合一些其他指标来评估性能。

20.布赖尔乐谱

这是一个衡量你的预测与真实值相差有多远的指标。有一个观察结果是这样的:

基本上,它是概率空间中的均方误差,因此,它通常用于校准机器学习模型的概率。如果你想阅读更多关于概率校准的内容,我推荐你阅读 Jason Brownlee 的这篇文章。

它可以很好地补充您的 ROC AUC 得分和其他关注其他事情的指标。

如何计算:

from sklearn.metrics import brier_score_loss

brier_loss = brier_score_loss(y_true, y_pred_pos)

run[“logs/brier_score_loss”] = brier_loss

模型在此指标中的得分情况:

来自实验 BIN-101 的模型具有最佳校准,对于该模型,我们的预测平均误差为 0.16 (√0.0263309)。

何时使用:

  • 当你关心校准概率时。

21.累积收益图

简而言之,对于给定分数的最高得分预测,它可以帮助您衡量通过使用您的模型而不是随机模型获得了多少收益。

简单来说:

  • 你把你的预测从最高到最低排序
  • 对于每一个百分位数,你都要计算直到那个百分位数的真正正面观察的分数。

使用你的模型来定位给定的用户/账户/交易组的好处是显而易见的,尤其是如果你真的关心对它们进行排序的话。

如何计算:

from scikitplot.metrics import plot_cumulative_gain

fig, ax = plt.subplots()
plot_cumulative_gain(y_true, y_pred, ax=ax)

run[“images/cumulative_gains”].upload(neptune.types.File.as_image(fig))

看起来怎么样:

我们可以看到,随着得分最高的预测样本的增加,我们的累积收益图表迅速上升。当我们到达第 20 个百分位数时,超过 90%的阳性病例被覆盖。您可以使用此图表来区分优先级,并筛选出可能的欺诈交易进行处理。

假设我们要使用我们的模型来分配可能的欺诈交易进行处理,并且我们需要进行优先级排序。我们可以用这个图表来告诉我们在哪里选择一个截止点最有意义。

何时使用:

  • 每当您希望选择最有希望的客户或交易作为目标,并且希望使用您的模型进行排序时。
  • 它可以很好地补充 ROC AUC 分数,ROC AUC 分数衡量模型的排名/排序性能。

22.升力曲线|升力图

它只是累积收益图的一种不同表现形式:

  • 我们将预测从最高到最低排序
  • 对于每个百分位数,我们计算我们的模型和随机模型在该百分位数上的真实正观察的分数,
  • 我们计算这些分数的比率,然后画出来。

它会告诉您,对于给定百分比的最高得分预测,您的模型比随机模型好多少。

如何计算:

from scikitplot.metrics import plot_lift_curve

fig, ax = plt.subplots()
plot_lift_curve(y_true, y_pred, ax=ax)

run[“images/lift_curve”].upload(neptune.types.File.as_image(fig))

看起来怎么样:

因此,对于前 10%的预测,我们的模型比随机模型好 10 倍以上,对于 20%的预测,比随机模型好 4 倍以上,以此类推。

何时使用:

  • 每当您希望选择最有希望的客户或交易作为目标,并且希望使用您的模型进行排序时。
  • 它可以很好地补充 ROC AUC 分数,ROC AUC 分数衡量模型的排名/排序性能。

23. Kolmogorov-Smirnov plot

KS 图有助于评估正类和负类预测分布之间的分离。

为了创建它,您需要:

  • 根据预测得分对您的观察结果进行排序,
  • 对于排序数据集(深度)的每个截止点[0.0,1.0],计算该深度中真阳性和真阴性的比例,
  • 在 Y 轴上绘制这些分数,正(深度)/正(所有)、负(深度)/负(所有),在 X 轴上绘制数据集深度。

因此,它的工作原理类似于累积收益图,但它不是只看正类,而是看正类和负类之间的分离。

Riaz Khan 的这篇文章对 KS 图和 KS 统计数据进行了很好的解释。

如何计算:

from scikitplot.metrics import plot_ks_statistic

fig, ax = plt.subplots()
plot_ks_statistic(y_true, y_pred, ax=ax)

run[“images/kolmogorov-smirnov”].upload(neptune.types.File.as_image(fig))

看起来怎么样:

因此,我们可以看到,最大的差异是在顶部预测的 0.034 的分界点。在这个阈值之后,随着我们增加顶部预测的百分比,它会以适中的速度下降。在 0.8 左右,情况变得非常糟糕。因此,即使最佳间隔是 0.034,我们也可以将它推得更高一点,以获得更积极的分类观察。

24.科尔莫戈罗夫-斯米尔诺夫统计量

如果我们想要绘制 KS 图并获得一个可以用作度量的数字,我们可以查看 KS 图中的所有阈值(数据集临界值),并找到真阳性和真阴性观察值的分布之间的距离(间隔)最大的阈值。

如果存在一个阈值,对于该阈值,上面的所有观察值都是真的正,下面的所有观察值都是真的负,则我们得到完美的 KS 统计值 1.0。

如何计算:

from scikitplot.helpers import binary_ks_curve

res = binary_ks_curve(y_true, y_pred_pos)
ks_stat = res[3]

run[“logs/ks_statistic”] = ks_stat

模型在此指标中的得分情况:

通过使用 KS 统计数据作为衡量标准,我们能够将 BIN-101 列为最佳模型,我们确实希望它是“真正”最佳模型。

何时使用:

  • 当你的问题是对最相关的观察进行排序/优先排序,并且你同样关心积极和消极的类别时。
  • 它可以很好地补充 ROC AUC 分数,ROC AUC 分数衡量模型的排名/排序性能。

最后的想法

在这篇博文中,您了解了各种分类指标和性能图表。

我们复习了度量的定义和解释,学习了如何计算它们,并讨论了何时使用它们。

希望有了这些知识,您将完全有能力在未来的项目中处理与度量相关的问题。

为了帮助您最大限度地利用这篇博文中的信息,我准备了://r//n//r//n

看看下面这些吧!//r//n//r//n

记录功能

您可以记录我们为您的机器学习项目覆盖的所有指标** 性能图表,并使用我们的 Python 客户端在 Neptune 中探索它们。**

pip install neptune-client
Import neptune.new as neptune

run = neptune.init(...)

run[“logs/score”] = score

  • 探索应用中的一切:

访问 Neptune docs 查看您可以在应用程序中记录和显示的内容。

二进制分类指标清单

我们已经为您创建了一个不错的备忘单,它将我在这篇博文中浏览的所有内容都放在一个几页长、易于理解的文档中,您可以在需要任何二进制分类指标相关的内容时打印和使用它。

获取您的二元分类指标清单

机器学习实验管理:如何组织你的模型开发过程

原文:https://web.archive.org/web/https://neptune.ai/blog/experiment-management

机器学习或深度学习实验跟踪是交付成功结果的关键因素。没有它,你不可能成功。

我来分享一个听了太多次的故事。

“所以我和我的团队开发了一个机器学习模型,经过几周的大量实验,我们得到了有希望的结果……

…不幸的是,我们无法确切地说出什么表现最好,因为我们没有跟踪功能版本,没有记录参数,并且使用不同的环境来运行我们的模型……

…几周后,我们甚至不确定我们实际尝试了什么,所以我们需要重新运行几乎所有的东西"

听起来很熟悉?

在这篇文章中,我将向您展示如何跟踪您的机器学习实验,并组织您的模型开发工作,以便这样的故事永远不会发生在您身上。

您将了解到:

什么是机器学习实验管理?

机器学习环境中的实验管理是一个跟踪实验元数据的过程,例如:

  • 代码版本,
  • 数据版本,
  • 超参数,
  • 环境,
  • 度量标准,

以有意义的方式组织它们,并使它们可用于在您的组织内访问和协作

在接下来的部分中,您将通过示例和实现看到这到底意味着什么。

如何跟踪机器学习实验

我所说的跟踪是指收集所有关于你的机器学习实验的元信息,这是为了:

  • 与团队(以及未来的你)分享你的成果和见解,
  • 重现机器学习实验的结果,
  • 保持你的结果,这需要很长时间才能产生,安全。

让我们一个接一个地检查我认为应该被记录下来的所有实验片段。

数据科学的代码版本控制

好的,在 2022 年,我认为几乎每个从事代码工作的人都知道版本控制。未能跟踪您的代码是一个很大的(但明显且容易修复的)疏忽。

我们应该继续下一部分吗?没那么快。

问题 1: Jupyter 笔记本版本控制

很大一部分数据科学发展发生在 Jupyter 笔记本中,它不仅仅是代码。幸运的是,有一些工具可以帮助笔记本版本控制和区分。我知道的一些工具:

一旦你有了你的笔记本版本,我会建议你再多做一点,确保它从上到下运行。为此,您可以使用 jupytext 或 nbconvert:

jupyter nbconvert --to script train_model.ipynb;
python train_model.py

问题 2:脏提交实验

数据科学人员倾向于不遵循软件开发的最佳实践。你总能发现有人(包括我)会问:

但是如何跟踪提交之间的代码呢?如果有人在没有提交代码的情况下运行一个实验会怎么样?”

一种选择是明确禁止在脏提交(包含修改或未跟踪文件的提交)上运行代码。另一个选择是每当用户进行实验时,给他们一个额外的安全网和快照代码。

注意:

Neptune 记录你的 git 信息 同时跟踪一个 运行 ,并提醒你 运行 是否在脏回购中启动。

跟踪超参数

大多数像样的机器学习模型和管道都调整了非默认超参数。这些可能是学习率、树的数量或缺失值插补方法。未能跟踪超参数会导致浪费数周时间寻找它们或重新训练模型。

好的一面是,跟踪超参数非常简单。让我们从人们倾向于定义它们的方式开始,然后我们将继续进行超参数跟踪:

配置文件

通常是一个。yaml 文件,包含脚本运行所需的所有信息。例如:

data:
    train_path: '/path/to/my/train.csv'
    valid_path: '/path/to/my/valid.csv'

model:
    objective: 'binary' 
    metric: 'auc'
    learning_rate: 0.1
    num_boost_round: 200
    num_leaves: 60
    feature_fraction: 0.2

命令行+ argparse

您只需将参数作为参数传递给脚本:

python train_evaluate.py \
    --train_path '/path/to/my/train.csv' \
    --valid_path '/path/to/my/valid.csv' \
    -- objective 'binary' \
    -- metric 'auc' \
    -- learning_rate 0.1 \
    -- num_boost_round 200 \
    -- num_leaves 60 \
    -- feature_fraction 0.2

main.py 中的参数字典

您将所有参数放在脚本中的字典中:

TRAIN_PATH = '/path/to/my/train.csv' 
VALID_PATH = '/path/to/my/valid.csv'

PARAMS = {'objective': 'binary',
          'metric': 'auc',
          'learning_rate': 0.1,
          'num_boost_round': 200,
          'num_leaves': 60,
          'feature_fraction': 0.2}

水螅

Hydra 是脸书开源开发的一个配置管理框架。

其背后的关键理念是:

  • 动态地创建一个一个层次化的 配置 组成
  • 需要时通过命令行覆盖它,
  • 通过 CLI 传递新参数(配置中没有)——它们将被自动处理

Hydra 使您能够准备和覆盖复杂的配置设置(包括配置组和层次结构),同时跟踪任何被覆盖的值。

为了理解它是如何工作的,让我们举一个 config.yaml 文件的简单例子:

project: ORGANIZATION/home-credit
name: home-credit-default-risk
parameters:

	n_cv_splits: 5
	validation_size: 0.2
	stratified_cv: True
	shuffle: 1

	rf__n_estimators: 2000
	rf__criterion: gini
	rf__max_depth: 40
	rf__class_weight: balanced

只需调用 hydra decorator,就可以在应用程序中使用这种配置:

import hydra
from omegaconf import DictConfig
@hydra.main(config_path='config.yaml')
def train(cfg):
	print(cfg.pretty())  
	print(cfg.parameters.rf__n_estimators)  
if __name__ == "__main__":
	train()

运行上述脚本将产生以下输出:

name: home-credit-default-risk
parameters:
	n_cv_splits: 5
	rf__class_weight: balanced
	rf__criterion: gini
	rf__max_depth: 40
	rf__n_estimators: 2000
	shuffle: 1
	stratified_cv: true
	validation_size: 0.2
project: ORGANIZATION/home-credit
2000

要覆盖现有参数或添加新参数,只需将它们作为 CLI 参数传递即可:

python hydra-main.py parameters.rf__n_estimators=1500 parameters.rf__max_features=0.2

注意:添加新参数必须关闭严格模式:

@hydra.main(config_path='config.yaml', strict=False)

Hydra 的一个缺点是,要共享配置或跨实验跟踪它,您必须手动保存 config.yaml 文件。

Hydra 正在积极开发中,请务必查看他们的最新文档。

到处都是神奇的数字

每当你需要传递一个参数时,你只需传递该参数的一个值。

...
train = pd.read_csv('/path/to/my/train.csv')

model = Model(objective='binary',
              metric='auc',
              learning_rate=0.1,
              num_boost_round=200,
              num_leaves=60,
              feature_fraction=0.2)
model.fit(train)

valid = pd.read_csv('/path/to/my/valid.csv')
model.evaluate(valid)

我们有时都会这样做,但这不是一个好主意,尤其是当有人需要接管你的工作时。

好吧,所以我确实喜欢。yaml 从命令行配置和传递参数(选项 1 和 2),但是除了幻数之外的任何东西都可以。重要的是你记录每个实验的参数

如果您决定将所有参数作为脚本参数传递,请确保将它们记录在某个地方。这很容易忘记,所以使用一个实验管理工具可以自动做到这一点,可以节省你的时间。

parser = argparse.ArgumentParser()
parser.add_argument('--number_trees')
parser.add_argument('--learning_rate')
args = parser.parse_args()

experiment_manager.create_experiment(params=vars(args))
...

...

没有什么比在一个完美的数据版本上拥有一个完美的脚本来产生完美的指标更痛苦的了,只是发现你不记得作为参数传递的超参数是什么了。

**#### 海王星

Neptune 通过提供各种选项,使得在运行中跟踪超参数变得非常容易:

  • 单独记录超参数:
run["parameters/epoch_nr"] = 5
run["parameters/batch_size"] = 32
run["parameters/dense"] = 512
run["parameters/optimizer"] = "sgd"
run["parameters/metrics"] = ["accuracy", "mae"]
run["parameters/activation"] = "relu"  
  • 将它们作为字典记录在一起:
params = {
	"epoch_nr": 5,
	"batch_size": 32,
	"dense": 512,
	"optimizer": "sgd",
	"metrics": ["accuracy", "binary_accuracy"],
	"activation": "relu",
}

run["parameters"] = params

在上述两种情况下,参数都记录在运行 UI 的所有元数据部分下:

run["config_file"].upload("config.yaml")

该文件将被记录在运行界面的所有元数据部分下:

数据版本化

在实际项目中,数据会随着时间而变化。一些典型的情况包括:

  • 添加新的图像,
  • 标签得到了改进,
  • 标签错误/错误的数据被移除,
  • 发现了新的数据表,
  • 新的特征被设计和处理,
  • 验证和测试数据集会发生变化,以反映生产环境。

每当你的数据改变,你的分析、报告或者实验结果的输出将可能改变,即使代码和环境没有改变。这就是为什么要确保你在比较苹果和苹果,你需要跟踪你的数据版本

拥有几乎所有的版本并得到不同的结果是非常令人沮丧的,可能意味着浪费大量的时间(和金钱)。可悲的是,事后你对此无能为力。所以,再一次,保持你的实验数据版本化。

对于绝大多数用例,每当有新数据进来时,您可以将它保存在一个新位置,并记录这个位置和数据的散列。即使数据非常大,例如在处理图像时,您也可以创建一个包含图像路径和标签的较小的元数据文件,并跟踪该文件的更改。

一位智者曾经告诉我:

“存储很便宜,但在一个 8 GPU 的节点上训练一个模型两周就不便宜了。”

如果你仔细想想,记录这些信息并不一定是火箭科学。

exp.set_property('data_path', 'DATASET_PATH')
exp.set_property('data_version', md5_hash('DATASET_PATH'))

你可以自己计算散列,使用一个简单的数据版本扩展(T1)或者将散列外包给一个成熟的数据版本工具,比如 T2 DVC T3。

您可以自己计算和记录散列,或者使用成熟的数据版本化工具,该工具为您提供了更强大的版本化功能。阅读以下市场上一些最佳工具的更多信息。

无论您决定哪个选项最适合您的项目,请将您的数据版本化。

跟踪模型性能指标

我从来没有发现自己在这种情况下认为我为我的实验记录了太多的指标,你呢?

在现实世界的项目中,由于新的发现或不断变化的规范,您关心的指标可能会发生变化,因此记录更多的指标实际上可以在将来为您节省一些时间和麻烦。

不管怎样,我的建议是:

“记录指标,全部记录”

通常,指标就像一个简单的数字

exp.send_metric('train_auc', train_auc)
exp.send_metric('valid_auc', valid_auc)

但我喜欢把它想得更宽泛一些。为了了解你的模型是否有所改进,你可能想看看图表、混淆矩阵或预测分布。在我看来,这些仍然是度量标准,因为它们帮助你衡量实验的表现。

exp.send_image('diagnostics', 'confusion_matrix.png')
exp.send_image('diagnostics', 'roc_auc.png')
exp.send_image('diagnostics', 'prediction_dist.png')

注意:

在训练和验证数据集上跟踪指标可以帮助您评估模型在生产中表现不佳的风险。差距越小,风险越低。Jean-Fran ois Puget 的 kaggle days 演讲是一个很好的资源。

https://web.archive.org/web/20220928194919if_/https://www.youtube.com/embed/VC8Jc9_lNoY?feature=oembed

视频

此外,如果您正在处理在不同时间戳收集的数据,您可以评估模型性能衰减并建议一个合适的模型再训练方案。只需跟踪验证数据不同时间段的指标,并查看性能如何下降。

版本化实验环境

环境版本控制的大部分问题可以用一句臭名昭著的话来概括:

“我不明白,它在我的机器上工作。”

有助于解决这个问题的一种方法可以称为 “环境作为代码” ,其中环境可以通过逐步执行指令( bash/yaml/docker )来创建。通过采用这种方法,您可以从版本化环境切换到版本化环境设置代码,我们知道如何做。

据我所知,在实践中有几个选项可以使用(这绝不是一个完整的方法列表)。

Docker 图像

这是首选方案,关于这个主题有很多资源。我特别喜欢的一个是杰夫·黑尔的“学足够多的 Docker 有用”系列。简而言之,您用一些指令定义 docker 文件。

FROM continuumio/miniconda3

RUN pip install jupyterlab==0.35.6 && \
pip install jupyterlab-server==0.2.0 && \
conda install -c conda-forge nodejs

RUN pip install neptune-client && \
pip install neptune-notebooks && \
jupyter labextension install neptune-notebooks

ARG NEPTUNE_API_TOKEN
ENV NEPTUNE_API_TOKEN=$NEPTUNE_API_TOKEN

ADD . /mnt/workdir
WORKDIR /mnt/workdir

您可以根据这些说明构建您的环境:

docker build -t jupyterlab \
    --build-arg NEPTUNE_API_TOKEN=$NEPTUNE_API_TOKEN .

您可以通过以下方式在环境中运行脚本:

docker run \
    -p 8888:8888 \
    jupyterlab:latest \
    /opt/conda/bin/jupyter lab \
    --allow-root \
    --ip=0.0.0.0 \
    --port=8888

康达环境

这是一个更简单的选择,在许多情况下,它足以管理您的环境,不会出现任何问题。它不像 docker 那样给你很多选择或保证,但对你的用例来说已经足够了。环境可以定义为一个。yaml 配置文件如下:

name: salt

dependencies:
   - pip=19.1.1
   - python=3.6.8
   - psutil
   - matplotlib
   - scikit-image

- pip:
   - neptune-client==0.3.0
   - neptune-contrib==0.9.2
   - imgaug==0.2.5
   - opencv_python==3.4.0.12
   - torch==0.3.1
   - torchvision==0.2.0
   - pretrainedmodels==0.7.0
   - pandas==0.24.2
   - numpy==1.16.4
   - cython==0.28.2
   - pycocotools==2.0.0

您可以通过运行以下命令来创建 conda 环境:

conda env create -f environment.yaml

非常酷的是,您总是可以通过运行以下命令将环境状态转储到这样的配置中:

conda env export > environment.yaml

简单,完成工作。

生成文件

您总是可以在 Makefile 中显式定义所有 bash 指令。例如:

git clone git@github.com:neptune-ml/open-solution-mapping-challenge.git
cd open-solution-mapping-challenge

pip install -r requirements.txt

mkdir data
cd data
curl -0 https://www.kaggle.com/c/imagenet-object-localization-challenge/data/LOC_synset_mapping.txt

并通过运行以下命令进行设置:

source Makefile

阅读这些文件通常很困难,你放弃了 conda 和/或 docker 的大量附加功能,但没有比这更简单的了。

现在,您已经将您的环境定义为代码,确保为每个实验记录环境文件。

同样,如果您使用的是实验管理器,您可以在创建新实验时对代码进行快照,即使您忘记了 git commit:

experiment_manager.create_experiment(upload_source_files=['environment.yml')
...

...

并将它安全地存储在应用程序中:

版本化机器学习模型

现在,您已经使用模型的最佳超参数对模型进行了训练,并对数据、超参数和环境进行了记录和版本化。但是模型本身呢?在大多数情况下,训练和推理发生在不同的地方(脚本/笔记本),您需要能够将您训练的模型用于其他地方的推理。

有两种基本方法可以做到这一点:

1.将模型保存为二进制文件

您可以将模型导出为二进制文件,并在需要进行推理的地方从二进制文件中加载它。

有多种方法可以做到这一点——像 PyTorchKeras 这样的库有自己的保存和加载方法,而深度学习之外的 Pickle 仍然是从文件中保存和加载模型的最流行的方法:

import pickle

with open(“saved_model.pkl”, “wb”) as f:
	pickle.dumps(trained_model, f)

with open(“saved_model.pkl”, “rb”) as f:
	model = pickle.load(f)

由于模型被保存为文件,您可以使用文件版本控制工具,如 git,或者将文件上传到实验跟踪器,如 Neptune:

run[“trained_model”].upload(“saved_model.pkl”)

2.使用模型注册表

模型注册中心是发布和访问模型的中央存储库。在这里,ML 开发人员可以将他们的模型推给其他利益相关者或他们自己在以后使用。

目前可用的一些流行的模型注册中心有:

a)海王星:

Neptune 是 MLOps 的元数据存储库,为运行大量实验的研究和生产团队而构建。

它为您提供了一个中心位置来记录、存储、显示、组织、比较和查询机器学习生命周期中生成的所有元数据。

个人和组织使用 Neptune 进行实验跟踪和模型注册,以控制他们的实验和模型开发。

海王星提供:

b) MLflow:

MLflow 模型注册中心是当今市场上为数不多的开源模型注册中心之一。你可以决定在你的基础设施上管理这个 T1,或者在像 T4 数据块 T5 这样的平台上使用 T2 完全管理的实现 T3。

MLflow 提供:

  • 注释和描述工具用于标记模型,提供文档和模型信息,例如模型的注册日期、注册模型的修改历史、模型所有者、阶段、版本等;
  • ,odel versioning 更新时自动跟踪注册模型的版本;
  • 一个 API 集成,将机器学习模型作为 RESTful APIs,用于在线测试、仪表板更新等;
  • CI/CD 工作流程集成记录阶段转换、请求、审查和批准变更,作为 CI/CD 管道的一部分,以实现更好的控制和治理;
  • 一个模型阶段特性,为每个模型版本分配预设或定制的阶段,如“阶段”和“生产”来代表模型的生命周期;
  • 促销方案配置方便在不同阶段之间移动模型。

c)亚马逊 Sagemaker 模型注册中心

亚马逊 SageMaker 是一个完全托管的服务,开发者可以在 ML 开发的每一步使用它,包括模型注册。模型注册中心是 SageMaker 中MLOps 套件的一部分,该套件通过在整个组织中自动化标准化 MLOps 实践来帮助用户构建和操作机器学习解决方案。

使用 SageMaker 模型注册表,您可以执行以下操作:

  • 生产用目录型号
  • 管理型号版本
  • 将元数据,例如训练度量,与模型相关联;
  • 管理模型的审批状态;
  • 将模型部署到生产中;
  • 使用 CI/CD 自动进行模型部署。

如何组织你的模型开发过程?

尽管我认为跟踪实验和确保工作的可重复性很重要,但这只是难题的一部分。一旦你跟踪了数百次实验,你将很快面临新的问题:

  • 如何搜索和可视化所有这些实验,
  • 如何将它们组织成你和你的同事可以消化的东西,
  • 如何在您的团队/组织内部共享和访问这些数据?

这就是实验管理工具真正派上用场的地方。他们让你:

  • 过滤/分类/标记/分组实验,
  • 可视化/比较实验运行,
  • 共享(应用程序和编程查询 API)实验结果和元数据。

例如,通过发送链接,我可以分享机器学习实验的比较以及所有可用的附加信息。

有了这些,您和您团队中的所有人就能确切地知道在模型开发中会发生什么。它使跟踪进度、讨论问题和发现新的改进想法变得容易。

在创造性迭代中工作

像这样的工具非常有用,是对电子表格和笔记的巨大改进。然而,我认为可以让你的机器学习项目更上一层楼的是一种专注的实验方法,我称之为创造性迭代。

我想从一些伪代码开始,稍后再解释:

time, budget, business_goal = business_specification()

creative_idea = initial_research(business_goal)

while time and budget and not business_goal:
   solution = develop(creative_idea)
   metrics = evaluate(solution, validation_data)
   if metrics > best_metrics:
      best_metrics = metrics
      best_solution = solution
   creative_idea = explore_results(best_solution)

   time.update()
   budget.update()

在每个项目中,都有一个创建业务规范的阶段,通常需要机器学习项目的时间框架、预算和目标。当我说目标时,我指的是一组 KPI,业务指标,或者如果你超级幸运的话,机器学习指标。在这个阶段,管理业务预期非常重要,但这是以后的事了。如果你对这些东西感兴趣,我建议你看看凯西·科济尔科夫的一些文章,比如,这篇

假设你和你的团队知道商业目标是什么,你就可以做初始研究并制定一个基线方法,一个第一创意想法。然后你开发它并提出解决方案,你需要评估并得到你的第一套指标。如前所述,这些数据不一定是简单的数字(通常不是),也可以是图表、报告或用户研究结果。现在,您应该研究您的解决方案、指标和 explore_results

您的项目可能会在这里结束,因为:

  • 您的第一个解决方案足够好来满足业务需求,
  • 你可以合理地预期没有办法在先前假定的时间和预算内达到业务目标
  • 你发现在附近的某个地方有一个低挂水果的问题,你的团队应该把精力集中在那里。

如果以上都不适用,你列出你的解决方案中所有表现不佳的部分,找出哪些可以改进,哪些创意可以帮你实现。一旦你有了这个清单,你需要根据预期的目标改进和预算对它们进行优先排序。如果您想知道如何评估这些改进,答案很简单:结果探索

你可能已经注意到结果探索出现了很多。这是因为它非常重要,值得拥有自己的一部分。

模型结果探索

这是这个过程中极其重要的一部分。您需要彻底了解当前方法的失败之处,您距离目标的时间/预算还有多远,在生产中使用您的方法会有什么风险。实际上,这一部分并不容易,但掌握它非常有价值,因为:

  • 它导致对业务问题的理解,
  • 它导致关注重要的问题,并为团队和组织节省大量时间和精力,
  • 它导致发现新的商业见解和项目想法。

目前使用的一些流行的模型解释工具有:

SHAP(SHapley Additive explaints)是一种解释任何机器学习模型输出的博弈论方法。它将最优信用分配与使用博弈论及其相关扩展的经典 Shapley 值的本地解释联系起来。

阅读如何在他们的文档中使用 SHAP。

局部可解释模型不可知解释(LIME)是一篇论文,作者在其中提出了局部代理模型的具体实现。代理模型被训练来近似底层黑盒模型的预测。LIME 不是训练一个全局代理模型,而是专注于训练局部代理模型来解释个体预测。当前的 Python 实现支持表格、文本和图像分类器。

这是一个用于解释 scikit-learn 的决策树和随机森林预测的包。允许将每个预测分解成偏差和特征贡献分量。在这里学习用法

我找到的一些关于这个主题的好资源有:

  • Gael Varoquaux 的 PyData 演讲“理解和诊断你的机器学习模型”

https://web.archive.org/web/20220928194919if_/https://www.youtube.com/embed/kbj3llSbaVA?version=3&rel=1&showsearch=0&showinfo=1&iv_load_policy=1&fs=1&hl=en-US&autohide=2&wmode=transparent

视频

  • 伊恩·奥斯瓦尔德的《创造正确而有能力的分类器》

https://web.archive.org/web/20220928194919if_/https://www.youtube.com/embed/DkLPYccEJ8Y?version=3&rel=1&showsearch=0&showinfo=1&iv_load_policy=1&fs=1&hl=en-US&autohide=2&wmode=transparent

视频

深入探索结果是另一个故事,也是另一篇博文,但关键的一点是,投入时间了解您当前的解决方案对您的业务极其有益

最后的想法

在这篇文章中,我解释道:

  • 什么是实验管理,
  • 组织您的模型开发过程如何改进您的工作流程。

对我来说,将实验管理工具添加到我的“标准”软件开发最佳实践中是一个顿悟时刻,这使得我的机器学习项目更有可能成功。我想,如果你试一试,你会有同样的感觉。

雅各布·查肯

大部分是 ML 的人。构建 MLOps 工具,编写技术资料,在 Neptune 进行想法实验。

西达丹·萨达特

我目前是 Neptune.ai 的一名开发人员,我坚信最好的学习方式是边做边教。


阅读下一篇

真实世界的 MLOps 示例:超因子中的模型开发

6 分钟阅读|作者斯蒂芬·奥拉德勒| 2022 年 6 月 28 日更新

在“真实世界的 MLOps 示例”系列的第一部分中,MLOps 工程师 Jules Belveze 将带您了解 Hypefactors 的模型开发流程,包括他们构建的模型类型、他们如何设计培训渠道,以及您可能会发现的其他有价值的细节。享受聊天!

公司简介

Hypefactors 提供一体化媒体智能解决方案,用于管理公关和沟通、跟踪信任度、产品发布以及市场和金融情报。他们运营着大型数据管道,实时传输世界各地的媒体数据。人工智能用于许多以前手动执行的自动化操作。

嘉宾介绍

你能向我们的读者介绍一下你自己吗?

嘿,斯蒂芬,谢谢你邀请我!我叫朱尔斯。我 26 岁。我在巴黎出生和长大,目前住在哥本哈根。

嘿朱尔斯!谢谢你的介绍。告诉我你的背景以及你是如何成为催眠师的。

我拥有法国大学的统计学和概率学士学位以及普通工程学硕士学位。除此之外,我还毕业于丹麦的丹麦技术大学,主修深度学习的数据科学。我对多语言自然语言处理非常着迷(并因此专攻它)。在微软的研究生学习期间,我还研究了高维时间序列的异常检测。

今天,我在一家名为 Hypefactors 的媒体智能技术公司工作,在那里我开发 NLP 模型,帮助我们的用户从媒体领域获得洞察力。对我来说,目前的工作是有机会从原型一直到产品进行建模。我想你可以叫我书呆子,至少我的朋友是这么形容我的,因为我大部分空闲时间不是编码就是听迪斯科黑胶。

超因子模型开发

你能详细说明你在 Hypefactors 建立的模型类型吗?

尽管我们也有计算机视觉模型在生产中运行,但我们主要为各种用例构建 NLP(自然语言处理)模型。我们需要覆盖多个国家和处理多种语言。多语言方面使得用“经典机器学习”方法开发变得困难。我们在变形金刚库的基础上打造深度学习模型。

我们在生产中运行各种模型,从跨度提取或序列分类到文本生成。这些模型旨在服务于不同的用例,如主题分类、情感分析或总结。

Continue reading ->


如何让实验跟踪工具适合你的项目管理设置

原文:https://web.archive.org/web/https://neptune.ai/blog/experiment-tracking-tools-in-project-management-setup

在机器学习中,工程师倾向于做大量的实验(至少可以这么说)。正因为如此,实验跟踪是每个 ML 项目必不可少的一部分。我们需要一个工具,它不仅可以为我们做跟踪,还可以轻松地集成到我们现有的项目管理设置中,这样其他团队成员就可以跟踪工作流。

海王星已经提出了一个实验跟踪的解决方案,我们的团队已经对其进行了相当广泛的开发。我们最近决定将 Neptune 更多地整合到我们的工作流程中,并将其扩展到日常活动,如日常会议和每周冲刺。

这使得我们的整个项目流程对整个团队来说更加透明和易于理解,而我们,ML 工程师,继续享受 Neptune 的跟踪能力。

双赢的解决方案?对我来说,绝对是!我会告诉你我们到底做了什么,有什么好处。

每个冲刺都有一个目标。我们的团队每两周召开一次会议,会上我们设定了 sprint 时间段要实现的目标。

这些目标在吉拉中成为高级任务——我们管理软件开发的工具。每个任务都有一个唯一的 ID 与之相关联,所以我们可以使用这个 ID 来引用一个特定的任务。

让我们考虑一个我最近参与的真实 ML 项目的例子。下面是在吉拉新建任务的页面外观:

ML PM Jira

Unique task ID is shown for a newly created sprint task

当我们决定一个任务并在吉拉创建它时,我们接着在 Neptune 中设置一个新项目,并通过 ID 将它链接到最初的吉拉任务。我在 Neptune 中创建的项目是这样的:

ML PM Jira

Project created in Neptune and linked to Jira via the unique project ID

现在,吉拉和海王星是连在一起的。我们在海王星分配了一个特定的项目,旨在解决吉拉的任务中描述的一个发展问题。

项目的开发阶段

对于开发环境,我们的 ML 团队倾向于在 Jupyter 笔记本上工作。为了跟踪整个项目工作流程,在这些笔记本中跟踪进度是非常重要的。

当 Neptune 链接到 Jupyter 时,它让我们对笔记本进行检查点操作。这些检查点被上传到 Neptune 中的项目页面,在 Neptune 的 UI 中如下所示:

Checkpoints in Jupyter

Checkpoints logged and listed for a jupyter notebook. 
Screenshot from Neptune’s UI.

在每天的会议上,我们看着这些检查站。它使开发过程变得可理解和透明。查看上面的截图,了解我的模型开发工作流程是如何进行的,从针对输入数据的探索性数据分析 (EDA)开始,继续创建数据生成器,以日志包含结束。

另外,请注意日期和时间信息是如何显示在检查点旁边的。这使得时间线清晰可循。必要时,如果需要详细的进度信息,我们可以比较两个检查点(两个笔记本)。使用 Neptune 的跟踪能力使项目易于管理和预测。

如果您喜欢在 IDE 中开发,也可以完成相同的跟踪过程。您的脚本可以像我们在 Jupyter 笔记本上看到的那样进行存储和比较。

项目的假设测试阶段

当 ML 项目的开发阶段完成时,我们通常会得到一个基线模型,它显示了一些性能,但很少是最好的性能。现在是时候测试假设,并检查是否有任何其他模型配置可能会导致我们更好的性能,或更优的解决方案。

假设检验是每个 ML 项目必不可少的一部分,Neptune 以一种简单方便的方式追踪实验结果。跟踪记录可以用作日志来建立对 ML 项目的管理。让我向您展示我们如何将 Neptune 整合到我们的整体管理工作流程中。

吉拉让我们做子任务,所以每个假设检验都从为它创建的子任务开始。子任务位于原来的高级任务之下,并属于它。我的项目看起来是这样的:

Hypothesis testing subtask

Subtask creation for a hypothesis testing.
Example from Jira.

如果子任务作为一个单独的页面打开,它在吉拉的样子如下:

Subtask page within Jira

Subtask page within Jira

请注意,一个假设(上面显示为吉拉的一个子任务)通过一个链接与海王星所创建的一个独特的实验相联系。我们这样做是为了方便,因为它可以帮助我们在吉拉和海王星之间导航。

另一方面,如果我们去海王星,看看实验页面,这是我们会看到的:

Experiments page in Neptune

Experiments page in Neptune

看一下红色矩形中的记录。这是我们之前看到的子任务的实验。注意,这个实验有一些与之相关的标签。如果我们阅读这些,我们会注意到一些有趣的信息:

  • 吉拉的子任务标识号
  • 冲刺数

子任务 ID 帮助我们保持特定实验和吉拉任务之间的联系,而 sprint 数字提醒我们处理这个特定假设时的 sprint 是什么。

您可能会想到对您的特定情况有用的任何其他标记。关键的一点是你可以把它放在海王星的实验旁边,它真的简化了整个跟踪过程。

顺便说一句,如果你想知道如何给实验添加标签,这是我的 jupyter 笔记本中的一个单元格,我在这里添加标签:

create_experiment = True
log_aug_script = False

launch_name = 'hypothesis_test' 
tags = ['sprint 49', 'DOC-2698']

params = {
    'backbone': backbone.name,
    'loss': loss_name,
    'pooling': pooling_name,
    'dense_layer': dense_count,
    'input_shape': input_shape,
    'batch_norm_usage_in_top_part': batch_norm_usage_in_top_part
}

if create_experiment:
    neptune.create_experiment(name=launch_name,
                              params=params,
                              upload_source_files=['aug.py'] if log_aug_script else [])
    if tags:
        neptune.append_tags(tags)

CI/CD 和再现能力

CI/CD 应用于机器学习越来越受到关注。我们需要一套实践和工具,可以用来增强项目开发和简化未来的部署。

由于它的记录能力,海王星也覆盖了我们感兴趣的这个区域。Neptune 可以记录和存储一些最重要的工件,这些工件不仅是部署阶段所需要的,也是复制我们所做的事情所需要的。此外,所有这些工件和日志都可以附加到一个特定的实验中,为它提供所需的核心信息。

让我们看一个我们团队广泛使用这些能力的例子。首先,由 Neptune 跟踪并显示为图表的损失和指标值。

Metrics and loss plots Neptune

Metrics and loss plots displayed in Neptune for a particular experiment.
Can be tracked for both training and validation sets
.

接下来,我们可以随时提醒自己,我们使用了哪些模型参数和架构来获得这样的模型性能。Neptune 在 parameters 选项卡下为我们存储了这些信息。

Model architecture and parameters Neptune

Model architecture and parameters stored in Neptune for a particular experiment

每个机器学习工程师可能遇到的问题就是数据集版本控制。Neptune 允许我们上传特定实验的数据集信息。

Dataset information Neptune

Dataset information stored in Neptune

我个人主要处理图像数据,更喜欢记录的不是图像本身,而是包含我需要的所有必要信息的数据框(比如图像的路径和标签)。这些数据帧可以通过编程方式从 Neptune 获取,供以后使用。

作为一名计算机视觉工程师,我也喜欢尝试图像增强。我尝试了多种增强方法,并且需要跟踪我当前的增强设置。Neptune 允许我将增强信息(作为代码脚本)附加到特定的实验中,因此它不会丢失,并且可以恢复。

Augmentation information

Augmentation information attached to the experiment

模型检查点也可以上传和存储。我通常会上传某个特定实验的最佳检查点,这样我就可以在以后需要的时候获取它。

Best checkpoint Neptune

Best checkpoint for an experiment is stored

如果我们想提醒自己模型性能能力,我们不仅可以查看损失和度量值,还可以查看我通常构建的性能图,这些图也附在实验运行中。Neptune 允许我上传这些图,并将它们保存在实验页面中。

Model performance Neptune

Model performance information stored for a particular experiment.
Loss value, metrics value and performance plots are included
.

在上面截图的最底部,你可能会注意到我附上的两张图:roc-auc 曲线和混淆矩阵图。图表、指标和损失值将为我提供关于特定实验运行所实现的模型的全面信息。

最后但同样重要的是,我倾向于包含完整推理调用的代码,并将其附加到最佳实验运行中。稍后,当模型部署的时候,我的队友可以获取最佳的检查点和推理代码,并使用它来设计可以部署的服务。很漂亮,对吧?

结论

如果您的项目中有机器学习部分,您已经看到了您的项目管理设置如何受益于 Neptune 集成。

它提供了跟踪功能,不仅可以帮助您的 ML 团队进行开发,还可以帮助您进行整体项目管理,让您可以看到每天或冲刺阶段的进度。

您还看到了一个广为接受的软件开发工具吉拉是如何以一种简单方便的方式与 Nepune 连接起来的。

最后,海王星可以为你储存大量的艺术品。所有这些结合起来将使你的项目具备 CI/CD 能力,并使你的项目具有完全的可复制性。

可以帮助您进行项目管理的其他工具:

1.https://www.ganttproject.biz/

我们这里有什么:

  • 甘特图
  • 里程碑跟踪
  • 完成百分比跟踪
  • 计划图编制
  • 资源管理
  • 任务管理

2.https://www.meisterlabs.com/

我们这里有什么:

  • 任务跟踪
  • 任务规划
  • 任务调度
  • 思维导图
  • 计划图编制
  • 项目时间跟踪
  • 按项目跟踪时间
  • 工作流程管理
  • 实时报告
  • 活动仪表板
  • 标签和关键词
  • 状态跟踪
  • 项目跟踪
  • 项目工作流程
  • 协作工作空间
  • 实时通知

3.https://www.wrike.com/vj/

我们这里有什么:

  • 文件共享
  • 子任务
  • 进度报告
  • 品牌工作空间
  • 电子邮件到任务同步
  • 为假期、病假等定制日历。
  • 工作负载视图和调度
  • 日历与 Google 和 iCalendar 的集成
  • android 和 iphone 应用程序 api
  • 用户组
  • 共享工作区
  • 任务规划
  • 任务调度
  • 任务管理
  • 活动仪表板
  • 文件管理
  • 文件传输
  • 实时活动流
  • 报告和统计
  • 与任务相关的讨论
  • 自动化周期性任务和项目
  • 第三方集成
  • 时间线管理
  • 日历管理
  • 项目时间跟踪
  • 按项目跟踪时间
  • 到期日跟踪
  • 资源管理
  • 预算跟踪
  • 活动跟踪
  • 活动管理
  • 电子邮件和日历同步
  • 同步管理
  • 项目跟踪
  • 可配置工作流
  • 工作流程管理
  • 仪表板创建
  • 用户访问控制
  • 权限管理
  • 数据备份
  • 基于角色的权限
  • 密码管理
  • 数据加密
  • 安全数据存储
  • 自动备份
  • 实时报告
  • 4.https://www.orangescrum.com/

我们这里有什么:

包括托管

  • 基于网络
  • 仪表盘
  • 每日追赶
  • 任务模板
  • 电子邮件和实时支持
  • Google Drive 和 Dropbox
  • 免费试用
  • 开源版本
  • 多用户
  • 通过电子邮件回复
  • 桌面通知
  • 无限项目
  • 日历
  • 看板视图
  • 对话线索
  • 票务/工作流程
  • 时间跟踪
  • 活动
  • 电子邮件通知
  • 5.https://freedcamp.com/

我们这里有什么:

错误跟踪

  • 合作
  • 文件共享
  • 问题管理
  • 里程碑跟踪
  • 计划图编制
  • 状态跟踪
  • 任务管理
  • 时间和费用跟踪
  • Time & Expense Tracking

实验跟踪 vs 机器学习模型管理 vs MLOps

原文:https://web.archive.org/web/https://neptune.ai/blog/experiment-tracking-vs-ml-model-management-vs-mlops

机器学习模型从想法到生产需要相当多的步骤。这些步骤可能会变得太复杂、太快。

在本文中,我们将重点剖析模型部署的三个主要方面。

这些是:

  • 实验跟踪
  • 机器学习模型管理
  • 机器学习操作

在文章的最后,你会知道三者之间的区别,以及各自的各个部分。

让我们开始吧。

什么是 MLOps

部署机器学习模型涉及一系列工具、原则和实践。它类似于 DevOps,只是它的目标是优化软件开发项目的启动方式。

在机器学习领域,这些工具和实践被称为 MLOps。一般来说,MLOps 是 DevOps 原理在机器学习中的应用。

MLOps 的组成部分

各个 MLOps 实践可能有所不同,但在该过程中需要完成几个基本部分:

  • 开发和管理模型,
  • 部署模型,
  • 监控。

现在,我们将探讨 MLOps 的不同部分如何协同工作,以确保所有这些方面的成功。本节将重点介绍它们。

专题报道

这是一个中央存储库,提供对培训和服务功能的访问。它很重要,因为它:

  • 支持重复使用功能,而不是创建新功能,
  • 防止使用具有不同定义的相似特征,
  • 允许您提供最新的特征值,
  • 确保用于培训的功能也在模型服务期间使用。

数据版本化

当新数据可用时,机器学习模型总是可以被重新训练。当有新的培训方法时,他们也可以重新接受培训。

根据新数据重新训练模型可能会导致性能下降。在这种情况下,版本控制允许您恢复到以前的模型,并且您将知道哪个版本的数据导致了令人沮丧的性能。版本控制对于法规遵从性以及数据审计也至关重要。

ML 元数据存储

在这里,所有关于模型执行的信息都被记录下来,以帮助再现和比较。这也有助于检测异常和调试。记录的一些信息包括:

  • 用于运行管道的参数,
  • 流程的开始和结束时间,
  • 链接到管道中使用的各种工件,
  • 指向最后一个训练模型的指针,
  • 用于训练和测试集的模型评估度量,以便能够与以前的模型进行比较,
  • 谁创造了这个模型,
  • 当模型被创建时,
  • 应用的特征变换,
  • 用于创建模型的数据集。

存储模型元数据为您提供了模型搜索能力。例如,您可以根据功能、模型类型和培训日期来搜索模型。这种可搜索性支持管理、分析、实验和跟踪许多模型。

模型元数据允许您比较不同的模型,并决定将哪个模型投入生产。这对于确定团队的进展也是至关重要的,以便确定可能需要更多努力的领域。手动跟踪所有元数据会很快变成一场噩梦。幸运的是,您可以使用 ML 工具从 ML 管道中自动提取元数据,并记录下来。

什么是 ML 模型管理

这些实践和方法可以让你更快地试验和开发机器学习模型。在这一节中,我们来看看这是如何工作的。

模型服务

活动模型版本可以通过 REST API 提供给目标应用程序。其他 MLOps 系统允许您将模型下载到目标设备上。这样做的好处是,只要有新版本,模型就会在目标设备上自动更新。因此,无论何时您的模型发生变化,您都不需要发布新版本的应用程序。

你也可以为你的模型提供不同的版本,监控它们并选出最好的执行者。

模型版本控制

能够及时回到模型的某个状态是至关重要的。要做到这一点,您需要能够对模型开发的各个方面进行版本化。例如:

  • 笔记本,
  • 使用的数据集,
  • 超参数集,
  • 代码,
  • 神器。

要恢复到以前的模型,您需要能够唯一地识别每个模型实例。在生产过程中,您不能更改模型。每个模型都应该是不可变的。

在生产过程中改变模型可能会导致意想不到的行为,所以很少这样做。版本模型更常见,因为它使您能够根据需要在各种模型版本之间切换。

您可能需要新的型号版本,原因如下:

  • 模型架构变化,例如从神经网络到 Scikit-learn 线性回归的变化,
  • 超参数变化,
  • 特征添加/移除,
  • 重新训练模型。

模型监控

一旦使用了机器学习模型,就必须对其进行监控。需要监控的主要项目有两个:模型漂移生产偏斜

模型漂移是一种情况,其中被预测的项目的统计属性以无法预测的方式改变。因此,如果训练数据和预测数据的统计属性变得不可预测,模型的性能将会下降。如果你在监控,你将能够捕捉到这个问题并迅速解决它。

当离线模型的性能明显不同于服务模型的性能时,就会发生生产偏斜。这可能是由以下原因造成的:

  • 训练中的 bug,
  • 服务实现中的错误,
  • 训练数据和传递给模型的数据之间不一致。

检测模型漂移和生产偏差将确保您的模型在生产环境中按预期执行。

模型再训练

根据模型评估的信息,在需要时总是重新训练模型是很重要的。当新数据可用时,还可以重新训练该模型。

正如在最后一部分中提到的,生产模型容易产生模型漂移和生产偏差。当您在应用程序中注意到这一点时,可以用新数据重新训练模型。因此,您的生产系统应该自动检测模型漂移,并发送触发模型再训练的警报。

也就是说,一些模型可能不会改进,应该被丢弃而不是重新训练,以节省计算资源,这些资源将用于无法改进的模型。

同样,您的系统应该能够自动检测这样的场景,弃用模型,并根据新数据训练新模型。在使用这些模型的所有系统迁移到新系统之前,不推荐使用的模型应该保留在服务器上。

当重新训练模型时,应该使用规则系统。例如,只有当新模型的平均绝对误差低于前一个模型的平均绝对误差时,才应该使用新模型。在这种情况下,应该自动获取并部署新模型。还可以设置规则,以便它们检查误差和/或准确性的某个阈值。

在生产环境中实现规则之前,需要对它们进行审查。您可以在基于 Git 的系统中通过同行评审来做到这一点。这一点至关重要,因为产生错误的规则可能会导致系统停机。

什么是实验跟踪

开发高性能的机器学习通常需要重复几次实验。需要对这些实验进行跟踪,以确保可比性和可重复性。

为了实现这一点,需要记录实验元数据。例如代码版本、数据版本等等。正如我们之前提到的,模型管理是当模型进入生产时发生的事情。然而,并不是所有的模型都可以生产,也不是所有的模型都应该生产。

为了获得将被转移到生产中的最佳模型,跟踪所有实验是至关重要的。如果不能再现最佳性能的实验,那将是非常不幸的。记住这一点,让我们看看实验跟踪的各个部分。

模特培训

在这一阶段,你要建立一个培训渠道。管道负责:

  • 摄取数据,
  • 设计新功能,
  • 监控培训过程。

在此阶段,功能将被验证为与功能库中的功能相同。当管道用于真实世界的数据时,使用不同的特征可能会导致问题。管道还确保数据以正确的质量和格式传递给它。

训练可以通过几次实验来完成。你的实验工具会详细记录每个实验。一旦该过程完成,您就可以重现产生最佳性能的实验。此外,通过记录模型本身,您可以立即选择产生最佳性能的模型。

模型评估

在这一阶段,模型用以前从未见过的数据进行测试,为部署做好准备。测试数据特征应该类似于培训中使用的特征。否则评估将失败。如果性能很差,那么可以在调整特征和/或数据之后重新训练模型。

模型注册表

使用实验工具时,您可以将最佳模型保存到模型注册表中。一旦你得到了最好的模型,这就为服务做好了准备。这取决于您使用的实验工具,但是这种功能应该是现成的。

还需要注意的是,模型注册中心可以在模型管理的再培训阶段使用。一旦有了新模型,就需要更新模型注册中心。

模型注册中心很重要,因为它包含模型元数据。这种元数据很重要,原因有几个:

  • 管理模型,
  • 遵守您所在地区的监管框架,
  • 知道模型是否在生产中运行以及在哪个端点运行。

到目前为止,我们已经走过了很多地方。我们先花点时间,通过技术对比简单总结一下。

MLOps 与实验跟踪

开发任何机器学习模型,都需要尝试大量的特征、参数和数据集。这可能会产生许多模型。

尽管大多数模型会被丢弃,但跟踪每一个实验是很重要的。因为你不知道为什么一个模型表现得好,而不能复制一个表现得好的模型,这将是非常不幸的。这个过程——运行几个实验并比较它们——就是实验跟踪的全部内容。一旦您有了想要投入生产的最佳模型,MLOps 就会介入。

MLOps 与 ML 模型管理

MLOPs 是关于你的机器学习模型的成功部署和服务。简单地说,所有的 MLOps 步骤确保您的模型总是可用的。当您确定模型本身总是可用时,您就需要管理模型本身。

ML 模型管理与实验跟踪

模型管理的目标是跟踪注册中心中的各种模型,并为它们服务。需要对模型进行监控,以便在性能下降时,可以采取必要的措施。

现在,模型进入模型注册的第一步是通过实验阶段。在这里,您可以对各种模型进行实验,并将表现最好的模型发送到模型注册中心。一旦它出现了,当情况需要时,你总是可以触发再训练和重塑。有鉴于此,实验跟踪和模型管理是两个相互依赖的过程。

在本文中,您已经看到 MLOps 是与将您的机器学习模型投入生产相关的整个生态系统。你也看到了 MLOps 各个方面的区别,比如模型管理和实验跟踪。具体来说,我们涵盖了:

  • 什么是 MLOps,
  • 部分 MLOps,
  • 什么是模型管理,
  • 模型管理的各个部分,
  • 什么是实验跟踪,
  • 部分实验跟踪。

我希望这些信息对你的下一个模型有所帮助。

快乐大厦!

ML 中的可解释性和可审计性:定义、技术和工具

原文:https://web.archive.org/web/https://neptune.ai/blog/explainability-auditability-ml-definitions-techniques-tools

想象一下,你必须向 SaaS 产品的技术负责人展示你新开发的面部识别功能。演示进行得相对顺利,直到首席技术官问你“那么里面到底发生了什么?”而你只能说“没人知道,是黑匣子”。

很快,其他利益相关者就会开始担心。"如果我们不知道某样东西的作用,我们怎么能相信它呢?"。

这是一个合理的担忧。很长一段时间,ML 模型被普遍视为黑箱,因为我们无法解释输入和输出之间的数据发生了什么。但是现在,我们有了解释能力。

在这篇文章中,我们将解释可解释性,探索它的必要性,并讨论简化可解释性的技术和工具。

Explainability Black Box

ML Black Box | Source: Author

在 ML 中什么是可解释的,什么是可解释的 AI (XAI)?

机器学习中的可解释性意味着你可以从输入到输出解释你的模型中发生的事情。它使模型透明,解决了黑箱问题。

可解释的人工智能(XAI)是描述这一点的更正式的方式,适用于所有人工智能。XAI 意味着帮助人类专家理解人工智能开发的解决方案的方法。

“可解释性”和“可解释性”经常互换使用。虽然他们目标一致(‘理解模型。

Christoph Molnar 在他的著作《可解释的机器学习》中,将可解释性定义为人类能够理解决策原因的程度,或者人类能够持续预测 ML 模型结果的程度。

举个例子:你正在构建一个预测时尚行业价格趋势的模型。这个模型可能是可解释的——你可以看到你在做什么。但这还无法解释。一旦你深入挖掘生成结果背后的数据和特征,这就可以解释了。理解哪些特征有助于模型的预测,以及为什么它们会这样,这就是可解释性的全部内容。

一辆汽车需要燃料来驱动,也就是说,是燃料让引擎驱动的——可解释性。理解发动机如何和为什么消耗和使用燃料——可解释性。

本文中提到的大多数工具和技术都可以用于可解释性和可解释性,因为正如我前面提到的,这两个概念都提供了理解模型的视角。

可解释的人工智能是关于更好地理解 ML 模型。他们如何做决定,为什么。模型可解释性的三个最重要的方面是:

  1. 透明度
  2. 质疑的能力
  3. 易于理解

可解释性的方法

你可以用两种方式来解释:

  1. 全局—这是对模型行为的整体解释。它向我们展示了模型的整体视图,以及数据中的要素如何共同影响结果。
  2. Locally—这分别告诉我们数据中的每个实例和特征(有点像解释在模型中的某些点上看到的观察结果),以及各个特征如何影响结果。

为什么可解释性很重要?

当机器学习对商业利润产生负面影响时,它会获得坏名声。由于数据科学团队和业务团队之间的脱节,这种情况经常发生。

XAI 将数据科学团队和非技术高管联系起来,改善知识交流,并让所有利益相关者更好地了解产品要求和限制。所有这些都促进了更好的治理。

但是至少还有五个原因说明 ML 可解释性的重要性:

1。责任:当一个模型做出错误或流氓决策时,了解导致该决策的因素,或者谁应对该失败负责,对于避免将来出现类似问题是必要的。有了 XAI,数据科学团队可以让组织对他们的人工智能工具有更多的控制权。

2。信任:在高风险领域(如医疗保健或金融),信任至关重要。在 ML 解决方案可以被使用和信任之前,所有的利益相关者必须完全理解这个模型的作用。如果你声称你的模型做出了更好的决策,并注意到了人类看不到的模式,你需要能够用证据来支持它。领域专家自然会对任何声称比他们看得更多的技术持怀疑态度。

3。合规性:模型可解释性对于数据科学家、审计员和业务决策者等来说至关重要,以确保符合公司政策、行业标准和政府法规。根据欧洲数据保护法(GDPR)第 14 条,当公司使用自动化决策工具时,它必须提供有关所涉及的逻辑的有意义的信息,以及此类处理对数据主体的重要性和预期后果。世界各地都在实施类似的规定。

4。性能:可解释性也可以提高性能。如果你理解了你的模型为什么和如何工作,你就知道该微调和优化什么。

5。增强的控制:理解你的模型的决策过程向你展示未知的漏洞和缺陷。有了这些见解,控制就容易了。在低风险情况下快速识别和纠正错误的能力越来越强,特别是当应用于生产中的所有模型时。

可解释的模型

ML 中的一些模型具有可解释的特性,即透明性、易理解性和质疑能力。让我们来看看其中的几个。

1。线性模型:线性模型如线性回归、带线性核的支持向量机等遵循两个或两个以上变量可以相加使得它们的和也是解的线性原理。例如 y = mx + c。

因此其中一个特性的变化会影响输出。这很好理解和解释。

2。决策树算法:使用决策树的模型是通过学习从先验数据中得到的简单决策规则来训练的。因为它们遵循一套特定的规则,理解结果仅仅依赖于学习和理解导致结果的规则。使用 scikit-learn 中的 plot_tree 函数,您可以看到算法如何获得其输出的可视化。使用虹膜数据集:

fig = plt.figure(figsize=(25,20))
_ = tree.plot_tree(clf,
                   feature_names=iris.feature_names,
                   class_names=iris.target_names,
                   filled=True)

我们得到:

3。广义可加模型(GAM):GAM 是这样的模型,其中预测变量和因变量(响应)之间的通常关系被线性和非线性平滑函数取代,以模拟和捕捉数据中的非线性。gam 是具有平滑功能的广义线性模型,由于它们的可加性,每个变量都对输出有贡献。因此,我们可以通过简单地理解预测变量来解释 GAM 的输出。

大多数可解释模型的问题在于,它们大多数时候没有捕捉到一些现实世界问题的复杂性,可能是不充分的。此外,因为模型是简单的或线性的,不能保证可解释性。

神经网络或集成模型等是复杂的模型。

因此,对于复杂的模型,我们使用技术和工具使它们变得可以解释。有两种主要方法:

  1. 模型不可知方法
  2. 特定模型方法

模型不可知

模型不可知的技术/工具可以用在任何机器学习模型上,不管有多复杂。这些不可知的方法通常通过分析特征输入和输出对来工作。石灰就是一个很好的例子。

特定型号

特定于模型的技术/工具特定于单一类型的模型或一组模型。它们取决于特定模型的性质和功能,例如,树解释器。

ML 中的可解释性技术

让我们从 PDP 开始,对一些有趣的可解释性技术做一个广泛的概述。

部分相关图

在其他要素保持不变的情况下,获得一个或两个要素如何影响模型预测结果的全局可视化表示。PDP 告诉您目标和所选特征之间的关系是线性的还是复杂的。PDP 是模型不可知的。

Scikit 学习检查模块提供了一个名为 plot _ partial _ dependence 的部分相关图函数,可创建单向和双向部分相关图:

from sklearn.datasets import make_hastie_10_2
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.inspection import plot_partial_dependence

X, y = make_hastie_10_2(random_state=0)
clf = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1,
    max_depth=1, random_state=0).fit(X, y)
features = [0, 1, (0, 1)]
plot_partial_dependence(clf, X, features)
plt.gcf()

Explainability Partial Dependence Plots

The figure shows two one-way and one two-way partial dependence plots for the California housing dataset | Source: scikit-learn.org

个体条件期望图(ICE)

这为您提供了模型中某个特征相对于目标特征的效果的局部可视化表示。与 PDP 不同,ICE 以每个样本一行的方式显示对特征的依赖性的单独预测。它也是模型不可知的。您可以使用 PythonR 用 PyCEbox 包创建一个冰图。使用 scikit-learn,您可以在您的模型上实现 ICE 绘图,它也使用 plot _ partial _ dependece 函数,并且您必须设置 kind='individual '。

X, y = make_hasplot_partial_dependence(clf, X, features,
    			kind='individual')

注:查看 scikit-learn 文档了解更多细节

遗漏一列(LOCO)

这是一种非常简单的方法。它留下一列,重新训练模型,然后计算每个 LOCO 模型与原始模型预测得分的差异。如果分数变化很大,被遗漏的变量一定很重要。根据模型宽度(特征的数量),这种方法可能很耗时。

PDP、ICE 和 LOCO 都有一些缺点:

  • 它们不直接捕捉特征交互,
  • 它们可能过于近似,这对于自然语言处理中经常使用的分类数据和一次性编码来说可能是个问题。

累积局部效应

ALE 图最初是由 D. Apley(等人)在论文“可视化黑盒监督学习模型中预测变量的效果”中提出的。它与 PDP 的不同之处在于,它在特征上使用一个小窗口,并在预测之间产生差异而不是平均值。由于它不是基于比较平均值,ALE 的偏差更小,性能更好。ALE 的 python 版本可以通过以下方式安装:

 pip install PyALE

给定一个具有某些特征的已处理数据集,ALE 图将如下实现:

X[features]
from PyALE import ALE
ale_eff = ale(
    X=X[features], model=model, feature=["carat"], grid_size=50, include_CI=False
)

注:点击此处了解更多 ALE 剧情

局部可解释的模型不可知解释(LIME)

LIME 由华盛顿大学的研究人员开发,旨在通过捕捉特征交互来了解算法内部发生了什么。LIME 围绕特定预测执行各种多特征扰动,并测量结果。它还处理不规则输入。

当维数很高时,保持这种模型的局部保真度变得越来越困难。LIME 解决了一个更可行的任务——找到一个与原始模型局部近似的模型。

LIME 试图通过一系列实验来复制模型的输出。创造者还引入了 SP-LIME,这是一种选择代表性和非冗余预测的方法,为用户提供了模型的全局视图。

注:你可以在这里了解更多关于石灰的知识。

这是由相同的创作者建造的石灰。锚点方法通过使用易于理解的 IF-THEN 规则来解释模型的单个预测,这些规则称为“锚点”,可以很好地支持(锚点)预测。

为了找到锚点,作者使用强化技术结合图搜索算法来探索数据周围的扰动集及其对预测的影响。这是另一种与模型无关的方法。

在最初的论文中,作者比较了石灰和锚,并可视化了它们如何处理复杂的二元分类器模型( +)以得出结果。如下所示,LIME 解释通过学习最接近模型的线性决策边界来工作,具有一些局部权重,而锚点使其覆盖范围适应模型行为并使其边界清晰。

Explainability Anchors

LIME vs. Anchors — A Toy Visualization. Figure from Ribeiro, Singh, and Guestrin (2018) | Source

主播还接受了各种机器学习任务的测试,如分类、文本生成、结构化预测。

沙普利附加解释(SHAP)

SHAP 使用沙普利值的博弈论概念来优化分配功能的重要性。

Shapley 值 SHAP(Shapley Additive exPlanations)是一个特征值对所有可能组合的平均边际贡献。

联合是用于估计特定特征的 Shapley 值的特征组合。这是一种统一的方法来解释机器学习模型的输出,如线性和逻辑回归、 NLP提升树模型和上瘾模型。可以通过 PyPIconda-forge 安装;

pip install shap

或者:

conda install -c conda-forge shap

Explainability SHAP

This shows how each feature is contributing to the model’s output. | Source

深度 SHAP 是深度学习的 SHAP 的变体,是一种高速近似算法,它使用背景样本而不是单个参考值,并使用 Shapely 方程来线性化 softmax,max,products 等操作。深度 SHAP 由 Tensorflow、Keras 和 Pytorch 支持。

深度学习的重要特性(DeepLIFT)

DeepLIFT 是一种深度学习的可解释方法,它使用反向传播将每个神经元的激活与“参考激活”进行比较,然后根据神经元差异记录并分配那个贡献分数。

本质上,DeepLIFT 只是深入挖掘神经网络的特征选择,并找到对输出形成有主要影响的神经元和权重。DeepLIFT 分别考虑了正面和负面的贡献。它还可以揭示其他方法所忽略的依赖性。分数可以在一次反向传递中有效地计算出来。

DeepLIFT 位于 pypi 上,因此可以使用 pip 进行安装:

pip install deeplift

逐层相关性传播(LRP)

逐层相关性传播类似于 DeepLIFT,它使用一组来自输出的特意设计的传播规则进行反向传播,识别神经网络中最相关的神经元,直到您返回输入。所以,你得到了所有的神经元(例如,真正对输出有贡献的像素。LRP 在 CNN 上表现很好,它可以用来解释 LSTMs

看看这个互动演示,看看 LRP 是如何工作的。

Explainability LRP

Visual representation of how LRP does backpropagation from output node through the hidden layer neurons to input, identifying the neurons that had an impact on the model’s output. | Source

对比解释法(CEM)

对比解释是关于一个事件的事实,如果发现是真的,将构成一个具体事件的真实情况。CEM 方法提供了由模型而不是另一个决策或结果做出的决策和结果的对比解释。

CEM 基于论文《基于缺失的解释:走向带有相关否定的对比解释》。这里的开源代码实现是这里的。对于分类模型,CEM 根据相关正面(PP)和相关负面(PN)生成基于实例的解释。

PP 寻找对最初预测的结果影响最小但足够大的特征(例如,图像中的重要像素),而 PN 识别对最初预测的结果影响最小且必然不影响的特征。PN 提供了一个最小集合,使其区别于最接近的不同类。CEM 可以在 TensorFlow 中实现。要了解更多关于 CEM 的信息,请点击这里。

重量

2018 年,Amit (et al)做了一篇论文“用置信剖面改进简单模型”。提出了模型可解释性的深度加权方法。ProfWeight 将预先训练的深度神经网络的高测试精度转移到低测试精度的浅层网络。

就像老师向学生传递知识一样,ProfWeight 使用探针(根据网络的难度在样本中进行加权)来传递知识。

ProfWeight 可以总结为四个主要步骤:

  1. 在高性能神经网络的中间表示上附加和训练探针,
  2. 在原始数据集上训练一个简单模型,
  3. 学习作为简单模型和探针的函数的数据集中的例子的权重,
  4. 在最终加权数据集上重新训练简单模型。

置换特征重要性

置换特征重要性显示了当单个特征被随机打乱时,模型得分(准确度、F1、R2)的降低。它显示了一个特性对于一个特定的模型有多重要。它是一种模型检验技术,显示特征和目标之间的关系,对于非线性和不透明的估计器很有用。

它可以在 sci-kit 学习库中实现。查看这里看看是怎么做的。

我们知道一些用于 ML 可解释性的方法,那么有什么工具可以让我们的工作变得更容易呢?

人工智能可解释性 360 (AIX360)

AI Explainability 360 toolkit是 IBM 的开源库,支持数据集和机器学习模型的可解释性和可解释性。AIX360 包括一组算法,涵盖了解释的不同维度以及代理可解释性度量。它也有关于不同用例中可解释性的教程,比如信用审批。

滑冰者

Skater 是一个开源的、与模型无关的统一 Python 框架,具有模型可解释性和可解释性。数据科学家可以将可解释性构建到现实世界用例的机器学习系统中。

Skater 从全局(基于完整数据集的推理)和局部(推理单个预测)两个方面研究可解释性。它支持深度神经网络、树算法和可伸缩贝叶斯。

注:点击了解更多关于滑手的信息。

像我五岁一样解释(ELI5)

ELI5 是一个 python 包,用于理解和解释 sklearn 回归器和分类器、XGBoost、CatBoost、LightGBM Keras 等分类器的预测。它通过其统一的 API 为这些算法的这些过程提供可视化和调试。ELI5 理解文本处理,可以高亮显示文本数据。它还可以实现诸如 LIME 和排列重要性之类的技术。

ELI5 在 python 2.7 和 3.4+中工作,它需要 scikit-learn 0.18+。然后,您可以使用以下命令安装它:

pip install eli5

或者:

Conda install -c conda-forge eli5

注:点击了解更多信息

解释性语言

InterpretML 是微软开发的开源工具包,旨在为数据科学家、审计员和商业领袖提高模型的可解释性。解释器是灵活和可定制的。在撰写本文时,InterpretML 支持石灰、SHAP、线性模型和决策树。它为模型提供了全局和局部的解释。主要特点:

  • 了解不同数据子集的模型性能如何变化,并比较多个模型,
  • 探索模型误差,
  • 分析数据集统计和分布,
  • 探索全球和本地的解释,
  • 过滤数据以观察全局和局部特征重要性,
  • 运行假设分析,查看编辑数据点要素时模型解释会如何变化。

激活地图集

激活图谱可视化了神经网络如何相互作用,以及它们如何随着信息和层的深度而成熟。谷歌与 OpenAI 合作推出了激活地图集。

开发这种方法是为了查看卷积视觉网络的内部工作方式,并获得隐藏网络层中的概念的人类可解释的概述。它从单个神经元的特征可视化开始,但后来发展到神经元的联合可视化。

Activation Atlases - explainability tools

An activation atlas of the InceptionV1 vision classification network reveals many fully realized features, such as electronics, buildings, food, animal ears, plants, and watery backgrounds. | Source: openai.com

不在场证明解释

Alibi 是一个用于模型检查和解释的开源 Python 库。它提供了解释黑盒算法所需的代码。

Alibi 解释有助于:

  • 为可解释的 ML 模型定义 restful APIs,
  • 模型监控,
  • 黑盒 ML 模型解释算法的高质量参考实现,
  • 多用途案例(表格、文本和图像数据分类、回归),
  • 实现最新的模型解释,
  • 概念漂移算法偏差检测,
  • 模型决策的模型置信度得分。

注:点击了解更多关于 Alibi 的信息。

假设工具(WIT)

WIT 由 TensorFlow 团队开发,是一个交互式、可视化、无代码的界面,用于在 TensorFlow 中可视化数据集和模型,以便更好地理解模型结果。除了 TensorFlow 模型之外,您还可以使用 XGBoost 和 Scikit-Learn 模型的假设分析工具。

一旦部署了模型,就可以在假设分析工具中的数据集上查看其性能。

此外,您可以按要素对数据集进行切片,并跨这些切片比较性能。然后,您可以确定模型表现最好或最差的数据子集。这对 ML 公平性调查非常有帮助。

该工具可通过 Tensorboard 或 collab notebook 访问。查看 WIT 网站了解更多信息。

微软 Azure

我们都知道 Azure,不需要解释它是什么。Azure 的 SDK 包中有可解释性类。

蔚蓝色。解释包含像 SHAP 树解释器,SHAP 深度解释器,SHAP 线性解释器等功能。

将“pip install azureml-interpret”用于一般用途。

Rulex 可解释人工智能

Rulex 是一家以一阶条件逻辑规则的形式创建预测模型的公司,每个人都可以立即理解和使用这些模型。

Rulex 的核心机器学习算法逻辑学习机(LLM)的工作方式与传统人工智能完全不同。该产品旨在产生预测最佳决策选择的条件逻辑规则,以便流程专业人员可以立即清楚地了解这些规则。Rulex 规则使每个预测完全不言自明。

与决策树和其他产生规则的算法不同,Rulex 规则是无状态和重叠的。

探索和解释的模型不可知语言(DALEX)

Dalex 是一套工具,它检查任何给定的模型,简单的或复杂的,并解释模型的行为。Dalex 围绕每个模型创建了一个抽象层次,使得探索和解释更加容易。它使用 Explain()方法(Python)或 Dalex::explain 函数在模型上创建一个包装器。一旦使用解释函数包装了模型,所有的功能都可以从该函数中获得

Dalex 可与 xgboost、TensorFlow、h2o 配合使用。可以通过 Python 和 r 安装。

r:

install.packages("DALEX")
Dalex::explain

Python:

pip install dalex -U
import dalex as dx
exp = dx.Explainer(model, X, y)

注:点击了解更多关于 Dalex 的信息。

结论

为了安全、可靠地包含人工智能,需要人类和人工智能的无缝融合。对于允许从业者容易地评估正在使用的决策规则的质量并减少假阳性的技术,也应该考虑人为干预。

让 XAI 成为一种核心能力,成为你人工智能设计和质量保证方法的一部分。它将在未来支付股息,而且是大量的股息。

理解你的模型不仅仅是一个科学问题。这不是好奇的问题。它是关于知道你的模型在哪里失败,如何修复它们,以及如何向关键的项目涉众解释它们,以便每个人都确切地知道你的模型如何产生价值。

参考文献:

  1. https://www . PwC . co . uk/audit-assurance/assets/explable-ai . pdf
  2. https://christophm . github . io/interpretable-ml-book/
  3. https://link . springer . com/chapter/10.1007% 2f 978-3-030-28954-6 _ 10
  4. https://arxiv.org/abs/1802.07623
  5. https://towards data science . com/understanding-model-predictions-with-lime-a 582 fdff 3a 3b
  6. https://sci kit-learn . org/stable/auto _ examples/inspection/plot _ partial _ dependency . html
  7. https://www . kdnugges . com/2018/12/four-approach-ai-machine-learning . html
  8. https://link . springer . com/chapter/10.1007% 2f 978-3-030-28954-6 _ 10
  9. https://sci kit-learn . org/stable/modules/partial _ dependency . html
  10. http://www . fields . utoronto . ca/talks/Boolean-decision-rules-column-generation
  11. https://pair-code.github.io/what-if-tool
  12. http://aix360.mybluemix.net/
  13. https://github.com/slundberg/shap
  14. https://dalex.drwhy.ai/

用 DALEX 和 Neptune 开发可解释和可再现的机器学习模型

原文:https://web.archive.org/web/https://neptune.ai/blog/explainable-and-reproducible-machine-learning-with-dalex-and-neptune

机器学习模型开发很难,尤其是在现实世界中。

通常,您需要:

  • 了解业务问题,
  • 收集数据,
  • 探索它,
  • 建立适当的验证方案,
  • 实现模型和调整参数,
  • 以对业务有意义的方式部署它们,
  • 检查模型结果只是为了找出你必须处理的新问题。

这还不是全部。

你应该有你运行的实验和你训练的模型版本版本,以防你或其他任何人将来需要检查它们或重现结果。从我的经验来看,这一时刻会在你最意想不到的时候到来,“我希望我以前就想到了”的感觉是如此的真实(和痛苦)。

但是还有更多。

随着 ML 模型服务于真实的人,错误分类的案例(这是使用 ML 的自然结果)正在影响人们的生活,有时会非常不公平地对待他们。这使得解释你的模型预测的能力成为一种需求,而不仅仅是一种美好。

那么你能做些什么呢?

幸运的是,今天有工具可以解决这两个问题。

最好的部分是你可以把它们结合起来让你的模型版本化,可复制,可解释

继续阅读了解:

  • DALEX 讲解器讲解机器学习模型
  • 使用 Neptune 让您的模型版本化,实验可重复
  • 使用 Neptune + DALEX 集成自动保存每次训练运行的模型讲解器和交互式讲解图表
  • 版本化解释器比较、调试和审计你构建的每一个模型

让我们开始吧。


请注意,由于最近的 API 更新,这篇文章也需要一些改变——我们正在努力!与此同时,请检查海王星文档,那里的一切都是最新的!🥳


用 DALEX 进行可解释的机器学习

亚当·赖德莱克 军情二处数据实验室的研究工程师,华沙理工大学数据科学专业的学生

przemysaw bie cekmi2 datalab 创始人,三星研发中心首席数据科学家&波兰

如今,在测试集上获得高分的模型通常是不够的。这就是为什么人们对可解释的人工智能( XAI )越来越感兴趣,这是一套让你理解模型行为的方法和技术。

在多种编程语言中有许多可用的 XAI 方法。机器学习中最常用的一些是石灰SHAP、PDP ,但还有更多。

人们很容易迷失在大量的技术中,这就是可解释的人工智能金字塔派上用场的地方。它将与模型探索相关的需求收集到一个可扩展的下钻图中。左边是与单个实例相关的需求,右边是与整个模型相关的需求。连续层挖掘关于模型行为(局部或全局)的越来越多的细节问题。

DALEX(在 R 和 Python 中可用)是一个工具,帮助你理解复杂模型是如何工作的。它目前只适用于表格数据(但将来会有文本和图像)。

它与大多数用于构建机器学习模型的流行框架相集成,如 keras、sklearn、xgboost、lightgbm、H2O 等等!

DALEX 中的核心对象是一个讲解者。它将训练或评估数据与已训练的模型联系起来,并提取解释这些数据所需的所有信息。

一旦有了它,您就可以创建可视化,显示模型参数,并深入了解其他与模型相关的信息。您可以与您的团队共享它,或者保存它供以后使用。

为任何模型创建一个解释器真的很容易,正如你在这个例子中看到的使用 sklearn

import dalex as dx
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import LabelEncoder

data = dx.datasets.load_titanic()
le = preprocessing.LabelEncoder()
for feature in ['gender', 'class', 'embarked']:
	data[feature] = le.fit_transform(data[feature])

X = data.drop(columns='survived')
y = data.survived

classifier = RandomForestClassifier()
classifier.fit(X, y)

exp = dx.Explainer(classifier, X, y, label = "Titanic Random Forest")

观测值的模型解释(局部解释)

当你想理解为什么你的模型做出了一个特定的预测时,本地解释是你最好的朋友。

这一切都从预测开始,沿着金字塔的左半部分往下,你可以探索和了解发生了什么。

DALEX 为您提供了一系列方法来显示每个变量的局部影响:

  • SHAP :使用经典的 Shapley 值计算特征对模型预测的贡献
  • 分解:用所谓的“贪婪解释”将预测分解成可归因于每个变量的部分
  • 分解交互:扩展“贪婪解释”来解释功能交互

沿着金字塔往下走,局部解释的下一个关键部分是理解模型对特征值变化的敏感性。

在 DALEX 中有一种简单的方法来绘制这些信息:

  • 其他条件不变:显示模型预测的变化,仅允许单个变量存在差异,同时保持所有其他变量不变

按照我们在 Titanic 数据集上创建的示例随机森林模型,我们可以很容易地创建上面提到的图。

observation = pd.DataFrame({'gender': ['male'],
                   	    'age': [25],
                   	    'class': ['1st'],
                   	    'embarked': ['Southampton'],
                       	    'fare': [72],
                   	    'sibsp': [0],
                   	    'parch': 0},
                  	    index = ['John'])

bd = exp.predict_parts(observation , type='break_down')
bd_inter = exp.predict_parts(observation, type='break_down_interactions')
bd.plot(bd_inter)

shap = exp.predict_parts(observation, type = 'shap', B = 10)
shap.plot(max_vars=5)

cp = exp.predict_profile(observation)
cp.plot(variable_type = "numerical")
cp.plot(variable_type = "categorical")

模型理解(全局解释)

当你想了解哪些特性对你的模型通常是重要的,当它做决定时,你应该寻找全局的解释。

为了在全球层面上理解该模型,DALEX 为您提供了变量重要性图。变量重要性图,特别是排列特征重要性,使用户能够从整体上理解每个变量对模型的影响,并区分最重要的变量。

这种可视化可以被视为 SHAP 的全球等价物,并分解描绘单次观察的相似信息的图。

沿着金字塔向下移动,在数据集层面上,有一些技术,如部分相关性分布图和累积局部相关性,使您能够将模型的反应方式可视化为所选变量的函数。

现在让我们为我们的例子创建一些全局解释。


vi = exp.model_parts()
vi.plot(max_vars=5)

pdp_num = exp.model_profile(type = 'partial')
ale_num = exp.model_profile(type = 'accumulated')

pdp_num.plot(ale_num)

pdp_cat = exp.model_profile(type = 'partial', 
variable_type='categorical',
variables = ["gender","class"])
ale_cat = exp.model_profile(type = 'accumulated',
          variable_type='categorical',
          variables = ["gender","class"])

ale_cat.plot(pdp_cat)

可重用和有组织的解释对象

一个干净的,结构化的,易于使用的 XAI 可视化集合是伟大的,但有更多的 DALEX。

DALEX explainers 中打包你的模型给你一个可重用的和有组织的方式来存储和版本化你用机器学习模型做的任何工作。

使用 DALEX 创建的 explainer 对象包含:

  • 要解释的模型,
  • 型号名称和类别,
  • 任务类型,
  • 将用于计算解释的数据,
  • 对这些数据进行模型预测,
  • 预测功能,
  • 模型残差,
  • 观察值的抽样权重,
  • 其他型号信息(包、版本等。)

将所有这些信息存储在一个对象中使得创建局部和全局解释变得容易(正如我们之前看到的)。

它还使得在模型开发的每个阶段审查、共享和比较模型和解释成为可能。

使用 Neptune 进行实验和模型版本控制

雅各布·查孔 资深数据科学家

在完美的世界里,你所有的机器学习模型和实验都是以和你给软件项目版本化一样的方式来版本化的。

不幸的是,要跟踪您的 ML 项目,您需要做的不仅仅是将代码提交给 Github。

简而言之,为了正确地版本化机器学习模型你应该跟踪:

  • 代码、笔记本和配置文件
  • 环境
  • 因素
  • 数据集
  • 模型文件
  • 评估指标、性能图表或预测等结果

其中一些东西可以很好地配合。git(代码、环境配置),但其他的就没那么多了。

海王星通过让你记录你觉得重要的每件事和任何事情,让你很容易跟踪所有这些。

您只需在脚本中添加几行代码:

import neptune
from neptunecontrib.api import *
from neptunecontrib.versioning.data import *

neptune.init('YOU/YOUR_PROJECT')

neptune.create_experiment(
          params={'lr': 0.01, 'depth': 30, 'epoch_nr': 10}, 
          upload_source_files=['**/*.py', 
                               'requirements.yaml']) 
log_data_version('/path/to/dataset') 

neptune.log_metric('test_auc', 0.82) 
log_chart('ROC curve', fig) 
log_pickle('model.pkl', clf) 

您运行的每个实验或模型训练都有版本,并在 Neptune 应用程序(和数据库)中等待您🙂 ).

见海王星

您的团队可以访问所有的实验和模型,比较结果,并快速找到信息。

您可能会想:“好极了,所以我有我的模型版本,但是”:

  • 如果我想在模型被训练后几周或几个月调试模型,该怎么办?
  • 如果我想看到每次实验运行的预测解释或变量重要性,该怎么办?
  • 如果有人让我检查这个模型是否有不公平的偏见,而我没有训练它的代码或数据,该怎么办?

我听到了,这就是 DALEX 集成的用武之地!

DALEX + Neptune =版本化和可解释的模型

为什么不让你的 DALEX 解释器为每个实验进行记录和版本化,并在一个漂亮的用户界面中呈现交互式解释图表,易于与你想要的任何人分享。

没错,为什么不呢!

通过 Neptune-DALEX 集成,您可以获得所有这些,只需增加 3 条线路。

此外,这也带来了一些实实在在的好处:

  • 你可以查看其他人创建的模型并轻松分享你的模型
  • 您可以比较任何已创建模型的行为
  • 你可以追踪和审计每个模型不必要的偏差和其他问题
  • 您可以调试并比较缺少训练数据、代码或参数的模型

好吧,这听起来很酷,但它实际上是如何工作的呢?

我们现在开始吧。

版本本地说明

要记录本地模型说明,您只需:

  • 创建一个观察向量
  • 创建您的 DALEX 解释器对象
  • 将它们从neptunecontrib传递给log_local_explanations函数
from neptunecontrib.api import log_local_explanations

observation = pd.DataFrame({'gender': ['male'],
                   	    'age': [25],
                   	    'class': ['1st'],
                   	    'embarked': ['Southampton'],
                       	    'fare': [72],
                   	    'sibsp': [0],
                   	    'parch': 0},
                  	    index = ['John'])

log_local_explanations(expl, observation)

互动解释图表将在海王星应用程序的“文物”部分等着你:

见海王星

将创建以下地块:

  • 可变重要性
  • 部分相关(如果指定了数字特征)
  • 累积相关性(如果指定了分类特征)

版本全球解说

有了全球模型解释,就更简单了:

  • 创建您的 DALEX 解释器对象
  • neptunecontrib传递给log_global_explanations函数
  • (可选)指定要绘制的分类特征
from neptunecontrib.api import log_global_explanations

log_global_explanations(expl, categorical_features=["gender", "class"])

就是这样。现在,您可以转到“工件”部分,找到您当地的解释图表:

见海王星

将创建以下地块:

  • 崩溃,
  • 在互动中崩溃,
  • shap,
  • 对于数值变量,其他条件不变,
  • 分类变量的其他条件不变

版本讲解器对象

但是如果你真的想要版本化你的解释,你应该版本化解释对象本身。

保存它的好处?:

  • 您可以在以后创建它的可视化表示
  • 您可以用表格的形式深入了解细节
  • 你可以随心所欲地使用它(即使你现在不知道如何使用)🙂)

这非常简单:

from neptunecontrib.api import log_explainer

log_explainer('explainer.pkl', expl)

你可能会想:“我还能怎么使用解释器对象呢?”

让我在接下来的部分向您展示。

获取并分析训练模型的解释

首先,如果你把你的解释器登录到 Neptune,你可以直接把它提取到你的脚本或者笔记本中:

import neptune
from neptunecontrib.api import get_pickle

project = neptune.init(api_token='ANONYMOUS',
                       project_qualified_name='shared/dalex-integration')
experiment = project.get_experiments(id='DAL-68')[0]
explainer = get_pickle(filename='explainer.pkl', experiment=experiment)

现在您已经有了模型解释,您可以调试您的模型了。

一种可能的情况是,你有一个观察结果,而你的模型悲惨地失败了。

你想找出原因。

如果保存了 DALEX 解释器对象,您可以:

  • 创建本地解释,看看发生了什么。
  • 检查更改要素对结果的影响。

见海王星

当然,你可以做得更多,特别是如果你想比较模型和解释。

让我们现在就开始吧!

比较模型和解释

如果您想:

  • 将当前的模型想法与生产中运行的模型进行比较?
  • 看看去年的实验想法是否能在新收集的数据上发挥更好的作用?

实验和模型有一个清晰的结构,并且有一个存放它们的地方,这真的很容易做到。

您可以在 Neptune UI 中基于参数、数据版本或指标来比较实验:

见海王星

可以通过两次点击看到不同之处,并可以通过一两次点击深入查看您需要的任何信息。

好吧,当涉及到比较超参数和度量时,这确实很有用,但是解释者呢?

你可以进入每个实验,并查看交互式解释图表,看看你的模型是否有可疑之处。

更好的是,Neptune 允许您访问您以编程方式记录的所有信息,包括模型解释器。
你可以获取每个实验的讲解对象并进行比较。只需使用neptunecontrib中的get_pickle函数,然后用 DALEX .plot可视化多个解释器:

experiments =project.get_experiments(id=['DAL-68','DAL-69','DAL-70','DAL-71'])

shaps = []
for exp in experiments:
	auc_score = exp.get_numeric_channels_values('auc')['auc'].tolist()[0]
	label = f'{exp.id} | AUC: {auc_score:.3f}'

	explainer_ = get_pickle(filename='explainer.pkl', experiment=exp)

	sh = explainer_.predict_parts(new_observation, type='shap', B = 10)
	sh.result.label = label
	shaps.append(sh)

shaps[0].plot(shaps[1:])

见海王星

这就是 DALEX 情节的美妙之处。你可以通过多个解释者,他们会变魔术。

当然,您可以将之前训练过的模型与您当前正在研究的模型进行比较,以确定您的方向是否正确。只需将它添加到解释器列表中,并传递给.plot方法。

最终想法

好了,总结一下。

在本文中,您了解了:

  • 各种模型解释技术以及如何用 DALEX 解释器打包这些解释
  • 如何用 Neptune 对机器学习模型和实验进行版本化
  • 如何通过 Neptune + DALEX 集成为您运行的每个培训版本化模型解释器和交互式解释图表
  • 如何比较和调试你用解释器训练的模型

有了这些信息,我希望您的模型开发过程现在会更有组织性、可再现性和可解释性。

快乐训练!

雅各布·查孔

大部分是 ML 的人。构建 MLOps 工具,编写技术资料,在 Neptune 进行想法实验。


接下来的步骤

如何在 5 分钟内上手海王星

1.创建一个免费帐户

2.安装 Neptune 客户端库

Sign up

3.将日志记录添加到脚本中

2. Install Neptune client library
pip install neptune-client

3. Add logging to your script
import neptune.new as neptune

run = neptune.init_run("Me/MyProject")
run["parameters"] = {"lr":0.1, "dropout":0.4}
run["test_accuracy"] = 0.84

Try live notebook


表格数据的探索性数据分析

原文:https://web.archive.org/web/https://neptune.ai/blog/exploratory-data-analysis-for-tabular-data

通常,在查看任何数据集时,我们会看到一堆充满数字甚至一些字母、单词或缩写的行和列。理解这些数据并试图获得尽可能多的洞察力是开始模型开发过程的明智策略。在本文中,我们将了解 EDA、其类型、技术、基础假设和工具,同时,我们将对一个样本数据集进行探索性数据分析,以了解它为什么如此重要和有用。

让我们从一个简短的介绍开始。

什么是探索性数据分析?

根据 NIST (美国国家标准与技术研究院)的说法,EDA 是一个非形式化的过程,没有确定的规则和技术;相反,这更像是一种关于如何进行数据分析的哲学或态度。再者,著名数学家和统计学家约翰·w·图基(John W. Tukey)在他的著作《探索性数据分析》中,将 EDA 描述为侦探的工作。分析师或数据科学家使用它来建立模型拟合和假设检验所需的假设,并在必要时处理缺失值和转换变量。

为了进一步简化,我们可以将 EDA 描述为一个迭代循环,其中您可以:

  • 1 对你的数据产生疑问。

  • 2 通过对数据进行可视化、转换和建模来寻找答案。

  • 3 利用你所学到的知识提炼你的问题和/或提出新的问题。

这些问题可以是:

  • 最能描述数据的典型值或中心值是什么?
  • 典型值的数据分布如何?
  • 什么是适合数据的分布?
  • 某个特征会影响目标变量吗?
  • 统计上最重要的特征/变量是什么?
  • 将目标变量与一组其他变量/特征相关联的最佳函数是什么?
  • 数据是否有异常值?

探索性数据分析与经典数据分析

除了 EDA,还有其他数据分析方法,经典数据分析是最流行的方法之一。探索性数据分析和经典数据分析都是从一个问题开始,然后收集可以用来理解问题的相关数据。它们都以产生关于数据的一些推论而结束。这就是它们的相似之处,现在让我们看看它们的不同之处:

因素 探索性数据分析 经典数据分析

不对数据强加确定性或概率性模型。相反,它允许数据建议最适合数据的可接受模型。

|

对数据施加确定性和概率性模型。

|
| |

数据的结构,离群值,以及数据所暗示的模型。

|

模型的参数,并从模型中生成预测值。

|
| |

一般为图形,例如散点图、特征图、箱线图、直方图、双直方图、概率图、残差图和均值图。

|

一般为定量,例如,方差分析、t 检验、卡方检验和 f 检验。

|
| |

本质上具有暗示性、洞察力和主观性。

|

本质上严谨、正式、客观。

|
| |

使用所有可用的数据,从这个意义上说,没有相应的信息损失。

|

将数据浓缩成位置、变化等重要特征。同时过滤其他一些重要因素,如偏斜度、尾长、自相关等。,导致信息丢失。

|
| |

很少或不做假设,因为这些技术使用所有的数据。

|

依赖于常态等基本假设。

|

探索性数据分析和经典数据分析的参数差异

应该注意的是,在现实世界中,我们可能会在数据分析过程中同时使用这两种方法和其他方法中的元素。例如,在进行 EDA 时,使用 ANOVA 和卡方检验来理解数据集不同特征之间的关系是很常见的。

单变量分析与多变量分析

通常我们的数据集包含不止一个变量,在这种情况下,我们可以进行单变量和多变量分析来更好地理解我们的数据。

术语单变量分析是指对一个变量的分析,基本上是分析数据的最简单形式。单变量分析的目的是了解单个变量的值的分布,而不是处理整个数据集中变量之间的关系。直方图、条形图和核密度图等汇总统计数据和频率分布图是进行单变量分析的一些常用方法。

另一方面,与单变量分析相比,多变量分析可以考虑数据集中的所有变量,这使其变得复杂。这种分析的主要目的是找到变量之间的关系,以便更好地理解整体数据。通常情况下,现实世界中的任何现象都受到多重因素的影响,这使得多元分析更加现实。多变量分析中常用的一些方法有回归分析、主成分分析、聚类、相关和散点图等图表。

探索性数据分析(EDA)工具

用于探索性数据分析的一些最常用的工具有:

探索性数据分析(EDA)假设

每一个测量过程都包括一些潜在的假设,这些假设在统计上是正确的。特别是,有四个假设共同构成了所有测量程序的基础。

  • 1 数据随机抽取。

  • 2 数据属于固定分布。

  • 3 分布有固定位置。

  • 分布有固定的变化。

简而言之,我们希望数据有一些我们可以发现的底层结构。否则,试图从数据中找出任何意义完全是浪费时间,这些数据给人的感觉是随机的噪音。

如果这四个基本假设为真,我们将获得概率可预测性,这允许我们对过程的过去和未来做出概率声明。它们被称为“统计控制”过程。此外,如果这四个假设是真的,该方法可以产生可靠的结论是可重复的。

但是对于不同的问题类型,对这些假设的解释可能不同。因此,这里我们将描述最简单问题类型的这些假设,即单变量问题。在单变量系统中,响应包括确定性(常数)和随机(误差)部分,因此我们可以将上述假设改写为:

  • 1 数据点彼此不相关。

  • 2 随机分量有固定分布。

  • 确定性分量仅由一个常数组成。

  • 4 随机分量有固定的变化量。

单变量模型的普遍性和重要性在于,当确定性成分不仅是一个常数,而且是几个变量的函数时,它能够很容易地推断出更一般的问题。

在本文中,我们还将看到如何使用一些简单的 EDA 技术来测试这些假设,即直方图、滞后图、概率图和运行序列图。

使用样本表格数据集进行探索性数据分析

现在,在阅读本文的其余部分之前,我将举一个数据集的例子——“120 年奥运历史:运动员和成绩”,这是一个包含从 1896 年雅典到 2016 年里约奥运会运动员和奖牌成绩的基本数据的数据集。

该数据集中的主要变量或属性是:

  • ID——每个运动员的唯一号码;
  • 姓名——运动员的姓名;
  • 性别——男或女;
  • 年龄–整数;
  • 高度——以厘米为单位;
  • 重量——以千克为单位;
  • 团队——团队名称;
  • NOC 国家奥林匹克委员会 3 个字母的代码;
  • 运动会——年份和季节;
  • 年份–整数;
  • 季节——夏天或冬天;
  • 城市——主办城市;
  • 运动——运动;
  • 事件–事件;
  • 奖牌——金、银、铜或钠。

将这些数据存储在 pandas 数据帧中后,我们可以看到前 5 行,如下所示:

Data in pandas dataframe

Sorted data in pandas dataframe

如前所述,在 EDA 中,生成关于数据集的问题以理解数据是一种很好的做法。例如,关于这些数据,我想找出以下问题的答案:

  • 哪些国家培养出更多的金牌运动员?
  • 运动员的任何身体特征,比如身高,会让他比其他人更有优势吗?
  • 有没有一些高度相关的特性可以被删除?
  • 数据中是否存在某种偏差?

当然,您可以对该数据提出一组完全不同的问题,这可能与您的数据集用例更相关。在接下来的章节中,除了回顾这些概念,我们还将尝试找到上述问题的答案。

描述统计学

描述性统计对数据进行总结,使其更容易理解和分析。请记住,EDA 的目的之一是了解变量属性,如中心值、方差、偏斜度,并提出可能的建模策略。描述性统计分为两大类:

集中趋势的度量

它们被计算以给出一个“中心”,数据中的测量值围绕该中心分布。我们可以使用均值、中值或众数来寻找数据的中心值。

平均

平均值是最广泛使用的确定中心值的方法。计算方法是将所有数据值相加,然后用总数除以数据点数。

中位数

数据集正中间的值被定义为中值。按升序排列值后,找到数据中间的数字。如果中间有两个数字,则中值计算为它们的平均值。

方式

模式可能是计算数据集中中心值的最简单的方法。它等于最频繁的数字,即在数据中出现次数最多的数字。

需要注意的是,平均值最适用于没有异常值的对称分布,而中值适用于偏态分布或有异常值的数据。该模式是最少使用的集中趋势指标,仅在处理名义数据时使用。

离差的度量

离差的度量描述了“数据扩散”,即测量值离中心有多远。一些常见的措施是:

范围

特定数据集的范围是其最大值和最小值之间的差值。范围值越大,数据的分布范围就越大。

百分位数或四分位数

将数据分成四份的数字称为四分位数。通常,他们根据数字在数字线上的位置将数据分成四个部分。数据收集分为四个四分位数:

  • 第一个四分位数:最低的 25%的数字。
  • 第二个四分位数:下一个最低的 25%的数字(直到中位数)。
  • 第三个四分位数:第二高的 25%的数字(高于中位数)。
  • 第四个四分位数:最高的 25%的数字。

基于上述四分位数,我们还可以在此定义一些附加术语,例如:

  • 第 25 个百分位数是第一个四分位数末尾的值。
  • 第 50 个百分位数是第二个四分位数(或中位数)的末端值
  • 第 75 个百分位数是第三个四分位数的末尾。
  • IQR,也称为四分位距,是一种衡量数据如何围绕平均值分布的方法。

我们可以使用箱线图绘制百分位数,我们将在本文后面看到

差异

方差衡量每个点与平均值的平均差异程度。可以使用以下公式计算:

Formula for the varaince

Formula for calculating the variance

其中 x [i] 是数据点,μ是对所有数据点计算的平均值。

在前面提到的例子中,以下数据点的方差为 3.95:6,8,7,10,8,4,9

标准偏差

标准偏差值告诉我们所有数据点偏离平均值的程度,但它会受到异常值的影响,因为它使用平均值进行计算。它等于方差的平方根。

歪斜

数据集中与对称钟形曲线或正态分布的偏差称为偏斜度。大于 1 或小于-1 的偏斜值表示高度偏斜的分布。介于 0.5 和 1 之间或-0.5 和-1 之间的值是适度倾斜的。介于-0.5 和 0.5 之间的值表示分布相当对称。我们可以使用 pandas 函数 skew 来找出所有数值变量的偏斜度:

Pandas functions skew

Finding skewness using the pandas skew function

我们可以使用简单的 pandas 方法来查找这些统计数据中的大部分,例如数据中所有数值变量的最小值、最大值、平均值、百分位值和标准偏差:

Using a simple pandas method

Using a simple pandas method to find statistics

谈到探索性数据分析中使用的技术,它们可以大致分为图形和非图形技术,其中大部分是图形技术。虽然非图形方法是定量和客观的,但它们不能提供数据的完整图像。因此,图解法,这是更多的定性和涉及一些主观分析,也是必要的。

图形技术

柱状图

直方图是一种图表,它将具有连续值的数值变量(单变量)的值分布显示为一系列条形。每个条形通常跨越一个称为柱或类的数值范围,其中条形的高度显示数据点在相应柱中出现的值内的频率。

使用直方图,我们可以了解数据的中心、数据的分布、数据的偏斜度以及异常值的存在。

例如,我们可以为数据集中的数值变量(如高度)绘制直方图。

Example of histogram for the numerical variable

Histogram for the numerical variable – height

从这个直方图中,我们可以确认运动员的平均身高在 175 cm 左右,这从最后一节中的“数据的输出中也可以明显看出。

正态概率图

通常,概率图是一种可视化工具,用于确定数据集中的变量是否具有近似的理论分布,如正态分布或伽玛分布。此图生成样本数据相对于指定理论分布(在本例中为正态分布)分位数的概率图。

例如,我们可以绘制数据集中数值变量高度的正态概率图。

Example of  Normal Probability Plot

Normal Probability Plot for the numerical variable – height

正如我们所看到的,直方图有点倾斜,因此在正态概率图中有一条轻微的曲线。我们可以执行诸如幂变换之类的技术,这将使这个变量的概率分布更加高斯或正态。

使用直方图和概率图,我们可以测试 EDA 假设之一,即数据的固定分布。例如,如果正态概率图是线性的,则基础分布是固定的和正态的。此外,由于直方图用于表示数据的分布,钟形直方图意味着基本分布是对称的,并且可能是正态分布。

核分布估计或 KDE 图

核分布估计图描绘了连续数值变量的概率密度函数,可视为类似于直方图。我们可以将该图用于单变量和多变量数据。

例如,我们可以为数据集中的数值变量(如高度)绘制 KDE 图。因此,我们在这里为篮球和游泳项目的金牌得主绘制了 KDE 图。

Example of KDE Plot

KDE Plot for a numerical variable – height

y 值是对 x 轴上相应值的概率密度的估计,x 轴是身高变量,因此曲线下 175 cm 和 180 cm 之间的面积给出了奥运会运动员身高在 175 cm 和 180 cm 之间的概率。

我们可以在 KDE 图上清楚地看到,如果一个篮球运动员个子高,他/她赢得金牌的概率就更高,而在游泳比赛中,身高是一个相对较小的因素。

圆形分格统计图表

饼图是一种圆形统计图形,用于说明分类变量的分布。饼图被分成多个切片,每个切片代表数据中的每个类别。对于上述数据集,我们可以使用饼图描述前 10 个国家的金牌份额,如下所示:

Example of pie chart

A pie chart with gold medals among the top 10 countries

通过这个饼图,我们可以看到美国、俄罗斯和德国是奥运会上领先的国家。

条形图

条形图,有时也称为条形图,是一种使用矩形条显示分类变量的图表或图形,矩形条的高度与它们所代表的值成比例。条形图可以水平或垂直绘制。

对于这个数据集,我们可以将前 20 名国家获得的金牌数绘制如下。

Example of a bar chart

A bar chart with the number of gold medals won by the top 20 countries

很明显,我们需要一个相当大的饼图来显示这些信息。相反,我们可以使用条形图,因为它看起来更直观,更容易理解。

堆积条形图

堆积条形图是简单条形图的扩展,我们可以用它来表示多个变量。每个条形被进一步划分为多个段,每个段代表一个类别。堆积条形图中条形图的高度由变量的组合高度决定。

我们现在可以显示前 20 个国家获得的金牌、银牌和铜牌数量如下:

Example of stacked bar chat

Stacked bar chart with the number of gold, silver, and bronze won by the leading 20 countries

因此,正如我们在上面的堆叠图中看到的,美国在金牌数和奖牌总数上仍然领先。当我们比较意大利和法国时,虽然法国的奖牌总数比意大利多,但意大利的金牌数却略多。因此,这个图允许我们获得更精细的信息,否则我们很容易错过。

折线图

折线图或曲线图类似于条形图,但它不是以条形显示信息,而是以数据点的集合的形式显示信息,这些数据点以特定的模式由线条连接起来。折线图有一个优势——在折线图上比在条形图上更容易看到小的变化,并且线条非常清晰地代表了整体趋势。

如前所述,折线图是描述某些趋势的绝佳选择,例如过去几年女运动员参赛人数的增加。

Example of line chart

Line chart with the number of women participating in the Olympics

从上面的线状图中,我们可以看到 1980 年后女性参加奥运会的人数急剧上升。

运行顺序图

如果我们在变量值和虚拟指数之间绘制一个线形图,我们会得到一个运行序列图。这很重要,因为我们可以在进行探索性数据分析时测试固定位置和固定变化假设。

如果运行序列图平坦且无漂移,则固定位置假设成立,而如果运行序列图的垂直分布在整个图上大致相同,则固定变化假设成立。

Example of Run Sequence plot

Run Sequence plot

因此,我们使用该图来检查数据集中的可变高度是否具有固定位置和固定变化,正如我们所看到的,该图看起来没有漂移且平坦,在整个图中具有均匀的垂直分布,因此这两个假设对该变量都成立。

面积图

面积图类似于折线图,只是 x 轴和线条之间的区域用颜色或阴影填充。折线图和面积图的用例几乎是相似的。

对于我们的数据集,我们可以使用面积图来比较男女运动员历年获得的金牌数。

Example of area plot

Area plot used to compare the gold medals won by men and women over the years

由于自 1980 年以来有了更多的女运动员,我们也可以看到女性赢得的金牌数量激增。这是一个重要的观察,因为基于 1980 年以前的数据,我们可以错误地得出结论,男性运动员比女性运动员有更高的夺金机会。因此,我们可以说,在这个数据集中存在一种被称为偏见的偏见

箱形图

箱线图,也称为盒须图,显示连续变量的数据分布。它通常显示五个数字的摘要,即数据集的最小值、第一个四分位数、中值、第三个四分位数和最大值。从第一个四分位数到第三个四分位数画一个方框,数据的中位数用画过方框的垂直线表示。此外,箱线图可用作检验正态性或识别可能异常值的可视化工具。

盒状图还包含触须,触须是从盒中延伸出来的线。对于更一般的情况,如上所述,下须的边界是数据的最小值,而上须的边界是其最大值。

在我们还想发现异常值的情况下,我们使用箱线图的变体,其中晶须从箱线图的顶部和底部延伸到四分位数范围(IQR)的 1.5 倍。四分位数间距(IQR)是上四分位数(第三季度)和下四分位数(Q1)之间的距离,通过从第三季度减去 Q1 来计算。落在胡须末端之外的数据点称为异常值,用点表示。

在我们的数据集中,我们可以为数字变量(如身高、年龄和体重)绘制箱线图。

Example of box plot

Box plots for the numeric variables – height, weight, age

因此,从上面的箱线图中,我们可以很好地了解身高、体重和年龄变量的分布情况。我们还可以看到体重和年龄特征有很多异常值,主要是在较高的 en 值。

散点图

在大多数情况下,散点图用于检查数据集中两个连续变量之间的相关性。这两个变量的值由水平轴和垂直轴表示,它们的笛卡尔坐标对应于单个数据点的值。

在我们的数据集中,我们可以尝试找出身高和体重变量之间的关系,如下所示:

Example of scatter plot

Scatter plot used to find the relation between height and weight

为了更进一步,我们可以增加一个分类变量,如运动员的性别,如下所示:

Another example of scatter plot

Scatter plot expanded to include the sex of an athlete

从上面的散点图中,我们可以得出结论,大多数男运动员在身高和体重方面比女运动员有优势。此外,我们不能忽视这样一个事实,即随着体重的增加,运动员的身高也会增加,这可能是运动员整体健康状况的一个指标。

Lag plot

滞后图是一种特殊的散点图,其中 X 轴和 Y 轴代表相同的数据点,但在指数或时间单位上有所不同。这些时间单位之间的差异称为滞后。

设 Y(i)为变量/特征在索引 I 或时间步长 I(对于时间序列数据)的假设值,则滞后图包含以下轴:

纵轴:Y(i)表示所有 I,从 0 到 n。

横轴:Y(i-k)表示所有 I,其中 k 是滞后值,默认为 1。

随机性假设是最关键的,但也是最少测试的,我们可以使用滞后图来检查它。如果数据是随机的,图表上的点将在水平和垂直方向上相当均匀地分布,表明没有模式。另一方面,具有某种形式或趋势(如线性模式)的图表显示数据并非完全随机。

我们可以绘制数据集高度变量的滞后图,如下所示:

Example of a lag plot

Lag plot for a numerical variable – height

这里的数据似乎是完全随机的,似乎没有模式存在。因此,数据也满足随机性假设。

配对图

配对图是一种数据可视化,它在网格中显示数据集的各种变量之间的成对关联,以便我们可以更容易地看到它们之间的关系。网格的对角线可以表示直方图或 KDE,如下例所示,在该例中,我们比较了数据集的身高、体重和年龄变量。

Example of a pair plot

Pair plot for the dataset

在此图中,我们可以尝试找出任何两个特征是否相关。正如我们所看到的,年龄和身高或年龄和体重之间似乎没有明确的关系。如前所述,体重和身高之间似乎存在相关性,这一点也不奇怪。一件有趣的事情是,我们是否可以在不丢失太多信息的情况下删除这些特性。

热图

热图是数据的二维矩阵表示,其中每个单元格用一种颜色表示。通常,在 EDA 过程中,我们使用这种可视化来绘制数据集中所有数值变量之间的相关性。

让我们试着在数据集的几个变量中找到这样的关系。

Example of a heatmap

Heatmap for the dataset

相关性是一个统计术语,用来衡量两个变量相互协调的程度。如果两个变量同向移动,那么这两个变量就是正相关,反之亦然。此外,如果两个变量没有关系,那么相关值接近于零,就像在我们的例子中身高和年龄之间一样。

现在我有了问题的答案,但其中一些答案会引出一系列新的问题——

  1. 我们现在知道美国在奥运会上获得了最多的奖牌,但是知道其他国家落后于美国以及为什么落后会很有趣。
  2. 我们发现,运动员的身高等一些因素在篮球比赛中可能是有利的,所以在篮球队中增加更多高个子运动员是有意义的。
  3. 我们现在还知道,我们有可能删除体重或身高特征,而不会丢失太多数据信息。
  4. 还有,很明显数据是有偏差的,如果我们用这个数据去训练任何一个模型,都可能产生一个对女运动员有偏见的模型。

要回答后续的问题,你可以用更细粒度、更细致的方式做 EDA,找到一些关于这些数据更有趣的东西。

定量技术

尽管 EDA 主要以图形技术为中心,但它也包括某些定量方法。大多数定量技术分为两大类:

  • 1 区间估计

  • 2 假设检验

在本节中,我们将简要介绍它们。如果你想深入了解这些技术,我可以指向这个资源。

区间概算

区间估计的概念是用来建立一个变量预期落入的值的范围。置信区间就是一个很好的例子。

  • 置信区间代表实际值和观察到的估计值之间的预期距离的统计显著性。
  • 某个参数 p 的 N%置信区间是具有下界(LB)和上界(UB)的区间,该区间以概率 N%包含 p,使得 LB<=p<=UB。
  • 置信区间是显示某一统计量的不确定性的一种方式。

假设检验

统计假设是一种陈述,它被认为是正确的,直到有实质性的证据证明是相反的。假设检验广泛应用于许多学科,以确定一个命题是真还是假。

拒绝一个假设意味着它是不真实的。然而,接受一个假设并不意味着它是真实的;这只能说明我们缺乏证据来证明事实并非如此。因此,假设检验是根据可接受的(零)和不可接受的(非零)结果(备选项)来定义的。

假设检验是一个多步骤的过程,包括以下内容:

  1. 零假设:这是假设为真的陈述。
  2. 替代假设:这是如果无效假设被拒绝,将被接受的陈述。
  3. 检验统计:检验确定观察到的数据是否落在零假设的期望值范围之外。数据的类型将决定使用哪种统计检验。
  4. 显著性水平:显著性水平是研究者事先指定的一个数字,作为统计显著性的阈值。得到你准备容忍的假阳性结论的风险最高。
  5. 临界值:临界区域包括那些导致拒绝零假设的检验统计值
  6. 决策:根据检验统计量和临界值之间的关系,接受或拒绝零假设。

结论

我希望这篇文章能让您对探索性数据分析背后的一些核心概念有一个很好的了解。虽然有许多 EDA 技术,尤其是本文中描述的图形技术,但还有更多,使用哪种取决于数据集和您的个人需求。正如本文前面提到的,EDA 就像一个侦探的工作,主要是主观的,所以您可以自由地提出尽可能多的关于您的数据的问题,并使用 EDA 找到它们的答案。

参考

  1. EDA——信息技术实验室
  2. R 为数据科学
  3. 描述性统计和探索性数据分析

自然语言处理的探索性数据分析:Python 工具完全指南

原文:https://web.archive.org/web/https://neptune.ai/blog/exploratory-data-analysis-natural-language-processing-tools

探索性数据分析是任何机器学习工作流中最重要的部分之一,自然语言处理也不例外。但是你应该选择哪些工具来高效地探索和可视化文本数据呢?

在这篇文章中,我们将讨论和实现几乎所有的主要技术,你可以用它们来理解你的文本数据,并给你一个完成工作的 Python 工具的完整之旅。

开始之前:数据集和依赖项

在本文中,我们将使用来自 Kaggle 的百万新闻标题数据集。如果您想一步一步地进行分析,您可能需要安装以下库:

pip install \
   pandas matplotlib numpy \
   nltk seaborn sklearn gensim pyldavis \
   wordcloud textblob spacy textstat

现在,我们可以看看数据。

news= pd.read_csv('data/abcnews-date-text.csv',nrows=10000)
news.head(3)

jupyter output

数据集只包含两列,发布日期和新闻标题。

为了简单起见,我将探索这个数据集中的前 10000 行。因为标题是按发布日期排序的,所以实际上从 2003 年 2 月 19 日到 2003 年 4 月 7 日两个月。

好了,我想我们已经准备好开始我们的数据探索了!

分析文本统计

文本统计可视化是简单但非常有洞察力的技术。

它们包括:

  • 词频分析,
  • 句子长度分析,
  • 平均字长分析,
  • 等等。

这些确实有助于探索文本数据的基本特征

为此,我们将主要使用直方图(连续数据)和条形图(分类数据)。

首先,我将看看每个句子中出现的字符数。这可以让我们大致了解新闻标题的长度。

news['headline_text'].str.len().hist()

Code snippet that generates this chart

直方图显示,新闻标题的长度在 10 到 70 个字符之间,通常在 25 到 55 个字符之间。

现在,我们将转到单词级别的数据探索。让我们画出每个新闻标题中出现的字数。

text.str.split().\
    map(lambda x: len(x)).\
    hist()

Code snippet that generates this chart

很明显,新闻标题的字数在 2 到 12 之间,大部分在 5 到 7 之间。

接下来,让我们检查一下每个句子的平均单词长度。

news['headline_text'].str.split().\
   apply(lambda x : [len(i) for i in x]). \
   map(lambda x: np.mean(x)).hist()

Code snippet that generates this chart

平均单词长度在 3 到 9 之间,5 是最常见的长度。这是否意味着人们在新闻标题中使用了非常短的单词?让我们找出答案。

这可能不正确的一个原因是停用词。停用词是在任何语言中最常用的词,如、【the】、【a】、等。由于这些单词的长度可能很小,这些单词可能会导致上图向左倾斜。

分析停用词的数量和类型可以让我们更好地了解数据。

要获得包含停用词的语料库,您可以使用 nltk 库。Nltk 包含许多语言的停用词。因为我们只处理英语新闻,所以我将从语料库中过滤掉英语停用词。

import nltk
nltk.download('stopwords')
stop=set(stopwords.words('english'))

现在,我们将创建语料库。

corpus=[]
new= news['headline_text'].str.split()
new=new.values.tolist()
corpus=[word for i in new for word in i]

from collections import defaultdict
dic=defaultdict(int)
for word in corpus:
    if word in stop:
        dic[word]+=1

并绘制顶部停用词。

Code snippet that generates this chart

我们可以清楚地看到,像“to”、“in”和“for”这样的停用词在新闻标题中占主导地位。

现在我们知道了哪些停用词在我们的文章中频繁出现,让我们检查一下除了这些停用词之外还有哪些词频繁出现。

我们将使用集合库中的计数器函数来计数并存储元组列表中每个单词的出现次数。这是一个非常有用的函数,当我们在自然语言处理中处理单词级分析时。

We will use the counter function from the collections library to count and store the occurrences of each word in a list of tuples. This is a very useful function when we deal with word-level analysis in natural language processing.

counter=Counter(corpus)
most=counter.most_common()

x, y= [], []
for word,count in most[:40]:
    if (word not in stop):
        x.append(word)
        y.append(count)

sns.barplot(x=y,y=x)

Code snippet that generates this chart

哇!“美国”、“伊拉克”和“战争”占据了过去 15 年的头条新闻。

这里的“我们”可以指美国或我们(你和我)。us 不是一个停用词,但是当我们观察图表中的其他单词时,它们都与美国有关——伊拉克战争,这里的“US”可能指的是美国。

Ngram 探索

n 元语法就是 n 个单词的连续序列。例如《河岸》、《三个火枪手》等。如果字数为二,则称之为 bigram。对于 3 个单词,它被称为三元模型等等。

查看最常见的 n 元语法可以让你更好地理解使用该单词的上下文。

为了实现 n 元语法,我们将使用来自 nltk.utiln 元语法函数。例如:

现在我们知道了如何创建 n 元语法,让我们把它们可视化。

from nltk.util import ngrams
list(ngrams(['I' ,'went','to','the','river','bank'],2))

bigrams

为了构建我们的词汇表,我们将使用 Countvectorizer。 Countvectorizer 是一种简单的方法,用于对语料库进行记号化、矢量化,并以适当的形式表示出来。在sk learn . feature _ engineering . text中有

有了这些,我们将分析新闻标题中的重要人物。

top _ n _ bigrams = get _ top _ ngram(news[' headline _ text '],2)[:10] x,y=map(list,zip(* top _ n _ bigrams))SNS . bar plot(x = y,y=x)

def get_top_ngram(corpus, n=None):
    vec = CountVectorizer(ngram_range=(n, n)).fit(corpus)
    bag_of_words = vec.transform(corpus)
    sum_words = bag_of_words.sum(axis=0) 
    words_freq = [(word, sum_words[0, idx]) 
                  for word, idx in vec.vocabulary_.items()]
    words_freq =sorted(words_freq, key = lambda x: x[1], reverse=True)
    return words_freq[:10]

top_n_bigrams=get_top_ngram(news[‘headline_text’],2)[:10] x,y=map(list,zip(*top_n_bigrams)) sns.barplot(x=y,y=x)

Code snippet that generates this chart

我们可以观察到,与战争有关的“反战”、“阵亡”等连词占据了新闻标题。

三元模型怎么样?

我们可以看到,这些三元组中有许多是由、【反战抗议】组合而成的。 这意味着我们应该努力清理数据,看看我们能否将这些同义词合并成一个干净的令牌。

top_tri_grams=get_top_ngram(news['headline_text'],n=3)
x,y=map(list,zip(*top_tri_grams))
sns.barplot(x=y,y=x)

Code snippet that generates this chart

pyLDAvis 主题建模探索

主题建模是使用无监督学习技术提取文档集合中出现的主要主题的过程。

潜在狄利克雷分配(LDA)是一种易于使用且高效的主题建模模型。每个文档由主题的分布来表示,每个主题由词的分布来表示。

一旦我们按主题对文档进行分类,我们就可以对每个主题或主题组进行进一步的数据探索。

但是在进入主题建模之前,我们必须对数据进行一些预处理。我们将:

:将句子转换成一列标记或单词的过程。

*删除停用词

  • :将每个单词的屈折形式缩减为一个共同的基或根。
  • 转换为单词包 :单词包是一个字典,其中的键是单词(或 ngrams/tokens),值是每个单词在语料库中出现的次数。
  • 使用 NLTK,您可以轻松地进行标记化和词条化:
  • 现在,让我们使用 gensim 创建单词袋模型

**我们最终可以创建 LDA 模型:

import nltk
nltk.download('punkt')
nltk.download('wordnet')

def preprocess_news(df):
    corpus=[]
    stem=PorterStemmer()
    lem=WordNetLemmatizer()
    for news in df['headline_text']:
        words=[w for w in word_tokenize(news) if (w not in stop)]

        words=[lem.lemmatize(w) for w in words if len(w)>2]

        corpus.append(words)
    return corpus

corpus=preprocess_news(news)

题目 0 表示与伊拉克战争和警察有关的东西。主题 3 显示澳大利亚卷入伊拉克战争。

dic=gensim.corpora.Dictionary(corpus)
bow_corpus = [dic.doc2bow(doc) for doc in corpus]

您可以打印所有的主题并尝试理解它们,但是有一些工具可以帮助您更有效地进行数据探索。一个这样的工具是 pyLDAvis ,它交互地可视化 LDA 的结果。

lda_model = gensim.models.LdaMulticore(bow_corpus, 
                                   num_topics = 4, 
                                   id2word = dic,                                    
                                   passes = 10,
                                   workers = 2)
lda_model.show_topics()

lda topics results

The topic 0 indicates something related to the Iraq war and police. Topic 3 shows the involvement of Australia in the Iraq war.

在左侧,每个圆圈的区域代表主题相对于语料库的重要性。因为有四个主题,所以我们有四个圈。

pyLDAvis.enable_notebook()
vis = pyLDAvis.gensim.prepare(lda_model, bow_corpus, dic)
vis

Code snippet that generates this chart

圆心之间的距离表示主题之间的相似度。在这里,您可以看到主题 3 和主题 4 重叠,这表明主题更加相似。

  • 在右侧,每个话题的直方图显示了前 30 个相关词。例如,在主题 1 中,最相关的单词是警察、新闻、五月、战争等
  • 所以在我们的案例中,我们可以在新闻标题中看到大量与战争相关的词汇和话题。
  • Wordcloud

Wordcloud 是一种表现文本数据的好方法。出现在单词云中的每个单词的大小和颜色表明了它的频率或重要性。

用 python 创建 wordcloud 很容易,但是我们需要语料库形式的数据。幸运的是,我在上一节中准备了它。

Wordcloud is a great way to represent text data. The size and color of each word that appears in the wordcloud indicate it’s frequency or importance.

同样,您可以看到与战争相关的术语被突出显示,这表明这些词在新闻标题中频繁出现。

from wordcloud import WordCloud, STOPWORDS
stopwords = set(STOPWORDS)

def show_wordcloud(data):
    wordcloud = WordCloud(
        background_color='white',
        stopwords=stopwords,
        max_words=100,
        max_font_size=30,
        scale=3,
        random_state=1)

    wordcloud=wordcloud.generate(str(data))

    fig = plt.figure(1, figsize=(12, 12))
    plt.axis('off')

    plt.imshow(wordcloud)
    plt.show()

show_wordcloud(corpus)

Code snippet that generates this chart

许多参数可以调整。一些最突出的例子是:

:被阻止在图像中出现的一组单词。

*max_words :显示最大字数。

  • max_font_size :最大字体大小。
  • 有更多的选择来创建美丽的单词云。更多详情可以参考这里。
  • 情感分析

情感分析是一项非常常见的自然语言处理任务,我们在其中确定文本是正面、负面还是中性的。这对于发现与评论相关的情感非常有用,评论可以让我们从文本数据中获得一些有价值的见解。

有很多项目会帮助你用 python 做情感分析。我个人喜欢 TextBlob维德的情调。

文本 blob

Textblob 是构建在 nltk 之上的 python 库。它已经存在了一段时间,使用起来非常简单方便。

TextBlob 的情感函数返回两个属性:

极性: 是位于 [-1,1] 范围内的浮点数,其中 1 表示正语句, -1 表示负语句。

主观性:某人的判断是如何被个人观点和感受所塑造的。主观性表示为位于[0,1]范围内的浮点值。

  • 我将在我们的新闻标题上运行这个功能。
  • TextBlob 声称文本“100 人在伊拉克丧生”是负面的,不是一种观点或感觉,而是一种事实陈述。我想我们可以同意 TextBlob 的观点。

既然我们知道了如何计算这些情感分数,我们就可以使用直方图来可视化它们,并进一步探索数据。

from textblob import TextBlob
TextBlob('100 people killed in Iraq').sentiment

textblob sentiment

TextBlob claims that the text “100 people killed in Iraq” is negative and is not an opinion or feeling but rather a factual statement. I think we can agree with TextBlob here.

可以看到极性主要在 0.00 到 0.20 之间。这表明大多数新闻标题是中性的。

def polarity(text):
    return TextBlob(text).sentiment.polarity

news['polarity_score']=news['headline_text'].\
   apply(lambda x : polarity(x))
news['polarity_score'].hist()

Code snippet that generates this chart

让我们再深入一点,根据分数将新闻分为负面、正面和中性。

You can see that the polarity mainly ranges between 0.00 and 0.20. This indicates that the majority of the news headlines are neutral.

是的,70 %的新闻是中性的,只有 18%是正面的,11%是负面的。

def sentiment(x):
    if x<0:
        return 'neg'
    elif x==0:
        return 'neu'
    else:
        return 'pos'

news['polarity']=news['polarity_score'].\
   map(lambda x: sentiment(x))

plt.bar(news.polarity.value_counts().index,
        news.polarity.value_counts())

Code snippet that generates this chart

让我们来看看一些正面和负面的标题。

积极的新闻标题大多是关于体育运动中的一些胜利。

是的,非常负面的新闻标题。

news[news['polarity']=='pos']['headline_text'].head()

维德情感分析

news[news['polarity']=='neg']['headline_text'].head()

我们要讨论的下一个图书馆是 VADER。维德在探测负面情绪方面表现更好。在社交媒体文本情感分析的情况下非常有用。

VADER 或价感知词典和情感推理机是一个基于规则/词典的开源情感分析器预建库,受麻省理工学院许可证保护。

VADER 情感分析类返回一个字典,该字典包含文本正面、负面和中性的概率。然后我们就可以筛选选择概率最大的情感。

我们将使用 VADER 做同样的分析,并检查是否有很大的差异。

VADER sentiment analysis class returns a dictionary that contains the probabilities of the text for being positive, negative and neutral. Then we can filter and choose the sentiment with most probability.

是的,在分布上有一点点不同。甚至更多的标题被归类为中性 85 %,负面新闻标题的数量有所增加(至 13 %)。

from nltk.sentiment.vader import SentimentIntensityAnalyzer

nltk.download('vader_lexicon')
sid = SentimentIntensityAnalyzer()

def get_vader_score(sent):

    ss = sid.polarity_scores(sent)

    return np.argmax(list(ss.values())[:-1])

news['polarity']=news['headline_text'].\
    map(lambda x: get_vader_score(x))
polarity=news['polarity'].replace({0:'neg',1:'neu',2:'pos'})

plt.bar(polarity.value_counts().index,
        polarity.value_counts())

Code snippet that generates this chart

命名实体识别

命名实体识别是一种信息提取方法,其中文本中存在的实体被分类为预定义的实体类型,如“人”、“地点”、“组织”等。通过使用 NER,我们可以获得关于给定文本数据集中存在的实体类型的深刻见解。

让我们考虑一篇新闻报道的例子。

在上面的新闻中,命名实体识别模型应该能够识别诸如 RBI 作为一个组织,Mumbai 和 India 作为地点等实体。

有三个标准库可以进行命名实体识别:

news headline example

The Economic Times – Indian Times 2019

在本教程中,我将使用 spaCy ,这是一个用于高级自然语言处理任务的开源库。它是用 Cython 编写的,以其工业应用而闻名。除了 NER, spaCy 还提供了许多其他功能,如词性标注、词到向量转换等。

SpaCy 的命名实体识别已经在 OntoNotes 5 语料库上进行训练,它支持以下实体类型:

spaCy 的英语有三种预训练模式。我将使用 en_core_web_sm 来完成我们的任务,但您可以尝试其他模型。

要使用它,我们必须先下载它:

现在我们可以初始化语言模型了:

Spacy 的一个好处是我们只需要应用 nlp 函数一次,整个后台管道就会返回我们需要的对象。

python -m spacy download en_core_web_sm

我们可以看到,印度和伊朗被认为是地理位置(GPE),Chabahar 是人,星期四是日期。

import spacy

nlp = spacy.load("en_core_web_sm")

我们也可以使用 spaCy 中的 displacy 模块来可视化输出。

doc=nlp('India and Iran have agreed to boost the economic viability \
of the strategic Chabahar port through various measures, \
including larger subsidies to merchant shipping firms using the facility, \
people familiar with the development said on Thursday.')

[(x.text,x.label_) for x in doc.ents]

spacy ner

这创建了一个非常简洁的句子的可视化,其中每个实体类型用不同的颜色标记。

现在我们知道了如何执行 NER,我们可以通过对从数据集中提取的命名实体进行各种可视化来进一步探索数据。

from spacy import displacy

displacy.render(doc, style='ent')

首先,我们将在新闻标题上运行命名实体识别并存储实体类型。

现在,我们可以可视化实体频率:

First, we will run the named entity recognition on our news headlines and store the entity types.

def ner(text):
    doc=nlp(text)
    return [X.label_ for X in doc.ents]

ent=news['headline_text'].\
    apply(lambda x : ner(x))
ent=[x for sub in ent for x in sub]

counter=Counter(ent)
count=counter.most_common()

现在我们可以看到,GPE 和 ORG 占据了新闻标题,其次是 PERSON 实体。

x,y=map(list,zip(*count))
sns.barplot(x=y,y=x)

Code snippet that generates this chart

我们还可以可视化每个实体最常见的令牌。我们来看看哪些地方在新闻标题中出现的次数最多。

Now we can see that the GPE and ORG dominate the news headlines followed by the PERSON entity.

我想我们可以确认这样一个事实,即新闻标题中的“美国”指的是美国。让我们也找出新闻标题中最常见的名字。

def ner(text,ent="GPE"):
    doc=nlp(text)
    return [X.text for X in doc.ents if X.label_ == ent]

gpe=news['headline_text'].apply(lambda x: ner(x))
gpe=[i for x in gpe for i in x]
counter=Counter(gpe)

x,y=map(list,zip(*counter.most_common(10)))
sns.barplot(y,x)

Code snippet that generates this chart

萨达姆·侯赛因和乔治·布什是战时伊拉克和美国的总统。此外,我们可以看到,该模型在将“维克政府”“新南威尔士州政府”归类为个人而非政府机构方面远非完美。

per=news['headline_text'].apply(lambda x: ner(x,"PERSON"))
per=[i for x in per for i in x]
counter=Counter(per)

x,y=map(list,zip(*counter.most_common(10)))
sns.barplot(y,x)

Code snippet that generates this chart

探索 Python 中的词性标注

词性(POS)标注是一种方法,将词性标签分配给句子中的单词。有八种主要的词类:

名词(NN)-约瑟夫,伦敦,桌子,猫,老师,钢笔,城市

动词(VB)-读,说,跑,吃,玩,住,走,有,喜欢,是,是

  • 形容词(JJ)-美丽,快乐,悲伤,年轻,有趣,三
  • 副词(RB)-慢慢地,悄悄地,非常,总是,从来没有,太,嗯,明天
  • 介词(在)-在,在,在,从,与,近,之间,大约,在
  • 连词(CC)- and,or,but,因为,所以,然而,除非,既然,如果
  • 代词(PRP)-我,你,我们,他们,他,她,它,我,我们,他们,他,她,这个
  • 感叹词(INT)-哎哟!哇!太好了!救命啊!哦!嘿!嗨!
  • 这不是一项简单的任务,因为同一个词可能在不同的上下文中用在不同的句子中。然而,一旦你这样做了,你就可以创建许多有用的可视化工具,让你对数据集有更多的了解。
  • 我将使用 nltk 来做词性标注,但是也有其他做得很好的库(spacy,textblob)。

让我们看一个例子。

注意:

我们可以在这里观察到各种依赖标签。例如, DET 标签表示限定词“the”和名词“stories”之间的关系。

import nltk
sentence="The greatest comeback stories in 2019"
tokens=word_tokenize(sentence)
nltk.pos_tag(tokens)

nltk pos tagging

doc = nlp('The greatest comeback stories in 2019')
displacy.render(doc, style='dep', jupyter=True, options={'distance': 90})

你可以在这里查看依赖标签列表及其含义

好了,现在我们知道了什么是词性标注,让我们用它来研究我们的标题数据集。

You can check the list of dependency tags and their meanings here.

我们可以清楚地看到,名词(NN)在新闻标题中占主导地位,其次是形容词(JJ)。这对于新闻文章来说是典型的,而对于艺术形式来说,更高的形容词(ADJ)频率可能发生得相当多。

def pos(text):
    pos=nltk.pos_tag(word_tokenize(text))
    pos=list(map(list,zip(*pos)))[1]
    return pos

tags=news['headline_text'].apply(lambda x : pos(x))
tags=[x for l in tags for x in l]
counter=Counter(tags)

x,y=list(map(list,zip(*counter.most_common(7))))
sns.barplot(x=y,y=x)

Code snippet that generates this chart

你可以通过调查哪一个单数名词在新闻标题中最常见来深入了解这个问题。让我们来了解一下。

We can clearly see that the noun (NN) dominates in news headlines followed by the adjective (JJ). This is typical for news articles while for artistic forms higher adjective(ADJ) frequency could happen quite a lot.

“战争”、“伊拉克”、“人”等名词在新闻标题中占据主导地位。您可以使用上面的函数可视化和检查其他词类。

def get_adjs(text):
    adj=[]
    pos=nltk.pos_tag(word_tokenize(text))
    for word,tag in pos:
        if tag=='NN':
            adj.append(word)
    return adj

words=news['headline_text'].apply(lambda x : get_adjs(x))
words=[x for l in words for x in l]
counter=Counter(words)

x,y=list(map(list,zip(*counter.most_common(7))))
sns.barplot(x=y,y=x)

Code snippet that generates this chart

探索文本的复杂性

了解文本的可读性(难读性)以及什么类型的读者能够完全理解它是非常有益的。我们需要大学学历才能理解这个信息吗?还是一个一年级的学生就能清楚地明白重点是什么?

实际上,你可以在文档或文本上标注一个叫做可读性指数的数字。可读性指数是一个数值,表示阅读和理解文本的难易程度。

有许多可读性分数公式可用于英语。一些最突出的例子是:

You can actually put a number called readability index on a document or text. Readability index is a numeric value that indicates how difficult (or easy) it is to read and understand a text.

可读性测试

解释

公式

自动化可读性索引

输出是理解一篇文章所需的美国等级水平的近似表示。

ARI = 4.71 *(字符/单词)+
0.5 *(单词/句子)-21.43

Interpretation:

轻松阅读(FRE)

Formula:

更高的分数表示材料更容易阅读,
更低的数字表示更难阅读的段落:
–0-30 岁大学
–50-60 岁高中
–60 岁+四年级

FRE = 206.8351.015 *(总字数/总句子数)
-84.6 *(总音节数/总字数)

Interpretation:

FleschKincaid 等级级别(FKGL)

Formula:

结果是一个与美国年级水平相对应的数字。

FKGL = 0.39 *(总字数/总句子数)

  • 11.8(总音节数/总字数)-15.59

Interpretation:

结果是一个与美国年级水平相对应的数字。

Formula:

GFI = 0.4 *(单词/句子)+
100 *(复合词/单词))

Interpretation:

The result is a number that corresponds with a U.S grade level.

Formula:

Textstat 是一个很酷的 Python 库,它提供了所有这些文本统计计算方法的实现。让我们用 Textstat 来实现 Flesch 阅读容易指数。

现在,您可以绘制分数的直方图并可视化输出。

Textstat is a cool Python library that provides an implementation of all these text statistics calculation methods. Let’s use Textstat to implement Flesch Reading Ease index.

几乎所有的可读性分数都在 60 分以上。这意味着一个普通的 11 岁学生可以阅读和理解新闻标题。让我们检查可读性分数低于 5 分的所有新闻标题。

from textstat import flesch_reading_ease

news['headline_text'].\
   apply(lambda x : flesch_reading_ease(x)).hist()

Code snippet that generates this chart

你可以在新闻标题中看到一些复杂的词汇,如“投降”、“过渡”、“诱捕”等。这些话可能导致分数降到了 5 分以下。

最后的想法

x=[i for i in range(len(reading)) if reading[i]<5]
news.iloc[x]['headline_text'].head()

text complexity

在本文中,我们讨论并实现了针对文本数据的各种探索性数据分析方法。有些很常见,有些不太为人所知,但所有这些都是对您的数据探索工具包的巨大补充。

希望您会发现其中一些对您当前和未来的项目有用。

为了使数据探索更加容易,我创建了一个“自然语言处理探索性数据分析模板”,您可以在工作中使用它。

Hopefully, you will find some of them useful in your current and future projects.

To make data exploration even easier, I have created a  “Exploratory Data Analysis for Natural Language Processing Template” that you can use for your work.

Get exploratory data analysis for Natural Language Processing template

此外,正如您可能已经看到的,对于本文中的每个图表,都有一个代码片段来创建它。只需点击图表下方的按钮。

探索愉快!

沙胡尔 ES

数据科学家,非常熟悉机器学习、NLP 和音频处理领域。他是 Kaggle 大师,也喜欢做开源。

阅读下一篇

如何构建和管理自然语言处理(NLP)项目


Dhruvil Karani |发布于 2020 年 10 月 12 日

How to Structure and Manage Natural Language Processing (NLP) Projects

如果说我在 ML 行业工作中学到了什么的话,那就是:机器学习项目很乱。

这并不是说人们不想把事情组织起来,只是在项目过程中有很多事情很难组织和管理。

你可以从头开始,但有些事情会阻碍你。

一些典型的原因是:

笔记本中的快速数据探索,

取自 github 上的研究报告的模型代码,

  • 当一切都已设置好时,添加新的数据集,
  • 发现了数据质量问题并且需要重新标记数据,
  • 团队中的某个人“只是快速地尝试了一些东西”,并且在没有告诉任何人的情况下改变了训练参数(通过 argparse 传递),
  • 从高层推动将原型转化为产品“仅此一次”。
  • 多年来,作为一名机器学习工程师,我学到了一堆东西,它们可以帮助你保持在事物的顶端,并检查你的 NLP 项目(就像你真的可以检查 ML 项目一样:)。
  • 在这篇文章中,我将分享我在从事各种数据科学项目时学到的关键指针、指南、技巧和诀窍。许多东西在任何 ML 项目中都是有价值的,但有些是 NLP 特有的。

Over the years working as a machine learning engineer I’ve learned a bunch of things that can help you stay on top of things and keep your NLP projects in check (as much as you can really have ML projects in check:)).

In this post I will share key pointers, guidelines, tips and tricks that I learned while working on various data science projects. Many things can be valuable in any ML project but some are specific to NLP.

Continue reading ->


TensorFlow 的最佳 ML 框架和扩展

原文:https://web.archive.org/web/https://neptune.ai/blog/extensions-for-tensorflow

TensorFlow 有一个庞大的库和扩展生态系统。如果您是开发人员,您可以轻松地将它们添加到您的 ML 工作中,而不必构建新的函数。

在本文中,我们将探索一些可以立即开始使用的 TensorFlow 扩展。

首先,让我们从 TensorFlow Hub 查看特定领域的预训练模型。

我们开始吧!

TensorFlow Hub 是一个存储库,包含数百个经过训练的现成模型。您可以找到以下型号:

  • 自然语言处理
  • 目标检测
  • 图像分类
  • 风格转移
  • 视频动作检测
  • 声音分类
  • 音高识别

要使用一个模型,首先需要在 tfhub.dev 中识别它。你需要检查它的文档。例如,下面是加载这个 ImageNet 分类模型的说明。

model = tf.keras.Sequential([
    hub.KerasLayer("https://tfhub.dev/google/imagenet/inception_v1/classification/4")
])

模型可以按原样使用,也可以进行微调。该模型的文档提供了如何做到这一点的说明。

例如,我们可以通过将' trainable = True '传递给' hub.kerasLayer '来微调上面的模型。

hub.KerasLayer("https://tfhub.dev/google/imagenet/inception_v1/classification/4",
               trainable=True, arguments=dict(batch_norm_momentum=0.997))

这是一组工具,您可以使用它们来优化模型的执行和部署。

为什么这很重要?

  • 它减少了模型在移动设备上的延迟,
  • 它降低了云的成本,因为模型变得足够小,可以部署边缘设备。

优化模型可能会导致精确度降低。根据问题的不同,您需要决定一个稍微不太精确的模型是否值得利用模型优化的优势。

优化可以应用于来自 tfhub.dev 的预训练模型,以及您自己训练的模型。也可以从 tfhub.dev 下载优化的模型。

模型优化的技术之一是修剪。在这种技术中,权重张量中不必要的值被消除。这会产生更小的模型,精度非常接近基线模型。

修剪模型的第一步是定义修剪参数。

设置 50%的稀疏度意味着 50%的权重将被置零。“修剪时间表”负责在训练期间控制修剪

from tensorflow_model_optimization.sparsity.keras import ConstantSparsity
pruning_params = {
    'pruning_schedule': ConstantSparsity(0.5, 0),
    'block_size': (1, 1),
    'block_pooling_type': 'AVG'
}

之后,您可以使用上述参数修剪整个模型。

from tensorflow_model_optimization.sparsity.keras import prune_low_magnitude
model_to_prune = prune_low_magnitude(
    keras.Sequential([
        tf.keras.layers.Dense(128, activation='relu', input_shape=(X_train.shape[1],)),
        tf.keras.layers.Dense(1, activation='relu')
    ]), **pruning_params)

一种替代方案是使用量化感知训练,该训练使用较低精度,例如 8 位而不是 32 位浮点。

import tensorflow_model_optimization as tfmot
quantize_model = tfmot.quantization.keras.quantize_model
q_aware_model = quantize_model(model)

在这一点上,你将有一个可以感知量化的模型,但是还没有量化。

编译和定型模型后,可以使用 TFLite 转换器创建量化模型。

converter = tf.lite.TFLiteConverter.from_keras_model(q_aware_model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]

quantized_tflite_model = converter.convert()

你也可以量化模型的某些层。

另一种模型优化策略是权重聚类。在这种技术中,减少了唯一权重值的数量。

TensorFlow 推荐器(TFRS)是一个用于构建推荐系统模型的库。

您可以使用它来准备数据、制定模型、培训、评估和部署。这本笔记本包含了如何使用 TFRS 的完整示例。

TensorFlow Federated (TFF)是一个基于分散数据的机器学习开源库。在联合学习中,设备可以从共享模型中协作学习。

该模型将在服务器上使用代理数据进行训练。然后,每个设备将下载该模型,并使用该设备上的数据对其进行改进。

这种方法的好处是敏感的用户数据永远不会上传到服务器。一种已经被使用的方法是在电话键盘中。

TensorFlow Federated 由两层组成:

  • 联邦学习(FL) API
  • 联邦核心(FC) API

使用联邦学习(FL) API,开发人员可以在现有的 TensorFlow 模型上应用联邦训练和评估。

联邦核心(FC) API 是一个用于编写联邦算法的低级接口系统。

如果你感兴趣,请查看官方 TensorFlow 联合教程以了解更多信息。

要构建更有效的神经网络架构,您可以插入可区分的图形层。

对神经网络的几何先验和约束进行建模导致可以更鲁棒和有效地训练的架构。

计算机图形学和计算机视觉的结合让我们可以在机器学习问题中使用未标记的数据。Tensorflow Graphics 提供了一套可区分的图形、几何图层和 3D 查看器功能。

这里有一个来自官方文档的代码片段产生的输出的例子。

import numpy as np
import tensorflow as tf
import trimesh

import tensorflow_graphics.geometry.transformation as tfg_transformation
from tensorflow_graphics.notebooks import threejs_visualization

!wget https://storage.googleapis.com/tensorflow-graphics/notebooks/index/cow.obj

mesh = trimesh.load("cow.obj")
mesh = {"vertices": mesh.vertices, "faces": mesh.faces}

threejs_visualization.triangular_mesh_renderer(mesh, width=400, height=400)

axis = np.array((0., 1., 0.))  
angle = np.array((np.pi / 4.,))  

mesh["vertices"] = tfg_transformation.axis_angle.rotate(mesh["vertices"], axis,
                                                        angle).numpy()

threejs_visualization.triangular_mesh_renderer(mesh, width=400, height=400)

该库用于训练具有训练数据隐私的机器学习模型。为此提供的一些教程包括:

  • 训练具有不同隐私的语言模型
  • 具有差分隐私的 MNIST 卷积神经网络

差分隐私使用ε和δ表示。

这是一个模型和数据集的图书馆,旨在使深度学习更容易获得,并加速机器学习的研究。

根据官方文件:

" TensorFlow Probability 是一个用于 TensorFlow 中概率推理和统计分析的库"

您可以使用该库对领域知识进行编码,但是它还具有:

  • 支持多种概率分布
  • 构建深度概率模型的工具
  • 变分推理和马尔可夫链蒙特卡罗
  • 优化者,如内尔德-米德、BFGS 和 SGLD

这是一个基于伯努利分布的示例模型:

model = tfp.glm.Bernoulli()
coeffs, linear_response, is_converged, num_iter = tfp.glm.fit(
    model_matrix=features[:, tf.newaxis],
    response=tf.cast(labels, dtype=tf.float32),
    model=model)

TensorFlow Extended (TFX)是一个平台,您可以使用它将您的机器学习管道投入生产。

另外,使用 TensorFlow 的 ModelServer 可以让您使用 RESTful API 来访问您的模型。

假设您已经安装并配置了该服务器,则可以通过运行以下命令来启动它:

$ tensorflow_model_server -- rest_api_port=8000 --   model_config_file=models.config -- model_config_file_poll_wait_seconds=300

该 API 将在本地主机的端口 8000 上可用。设置此服务器需要一些服务器管理知识。

TensorBoard 是 TensorFlow 的开源可视化工具包。您可以在您的模型培训中使用它作为回调,以便跟踪该过程。它可用于跟踪各种指标,如日志丢失和准确性。TensorBoard 还提供了几个可用于实验的工具。您可以使用它来:

  • 可视化图像
  • 检查模型权重和偏差
  • 可视化模型的架构
  • 通过性能分析查看应用程序的性能

仅举几个例子。


注意:作为替代,你也可以跟踪和可视化模型训练运行,并在 Neptune 中对你的模型进行版本化。

例如,这里是你如何使用 Neptune 记录你的 Keras 实验。

PARAMS = {'lr': 0.01, 'epochs': 10}
neptune.create_experiment('model-training-run', params=PARAMS)

model.fit(x_train, y_train,
          epochs=PARAMS['epochs'],
          callbacks=[NeptuneMonitor()])

neptune.log_artifact('model.h5')

跟踪 TensorFlow 模型训练的替代选项 Neptune + TensorFlow/Keras 集成

这个库可以用于设计、实现和测试强化学习算法。它提供经过广泛测试的模块化组件。组件可以修改和扩展。

这个笔记本展示了如何在 Cartpole 环境下训练一个 DQN(深度 Q 网络)代理。初始化代码如下所示:

import tensorflow as tf
from tf_agents.networks import q_network
from tf_agents.agents.dqn import dqn_agent

q_net = q_network.QNetwork(
  train_env.observation_spec(),
  train_env.action_spec(),
  fc_layer_params=(100,))

agent = dqn_agent.DqnAgent(
  train_env.time_step_spec(),
  train_env.action_spec(),
  q_network=q_net,
  optimizer=optimizer,
  td_errors_loss_fn=common.element_wise_squared_loss,
  train_step_counter=tf.Variable(0))

agent.initialize()

最后的想法

在本文中,我们探索了几个可用于扩展 TensorFlow 功能的库。尝试使用我提供的代码片段来熟悉这些工具。

我们讨论了:

  • 使用 TensorFlow Hub 的预训练模型,
  • 使用 TensorFlow 模型优化工具包优化您的模型,
  • 使用 TensorFlow 推荐器构建推荐器,
  • 使用 TensorFlow Federated 的分散数据训练模型,
  • 使用 TensorFlow Privacy 在私人模式下训练。

这是相当多的,所以选择其中的一个开始,并浏览列表,看看是否有任何工具适合你的机器学习工作流程。

F1 评分 vs ROC AUC vs 准确性 vs PR AUC:应该选择哪种评价指标?

原文:https://web.archive.org/web/https://neptune.ai/blog/f1-score-accuracy-roc-auc-pr-auc

PR AUC 和 F1 分数是非常稳健的评估指标,对于许多分类问题非常有效,但根据我的经验,更常用的指标是准确性和 ROC AUC。他们更好吗?不完全是。正如著名的“AUC 与准确性”的讨论一样:两者并用确实有好处。最大的问题是什么时候

你现在可能有很多问题:

  • 当准确性是比 ROC AUC 更好的评价指标时。
  • F1 成绩有什么用?
  • 什么是 PR 曲线,实际如何使用?
  • 如果我的问题高度不平衡,我应该使用 ROC AUC 还是 PR AUC?

一如既往地视情况而定,但在做出正确决策时,理解不同指标之间的权衡是至关重要的。

在这篇博文中,我将:

  • 谈论一些最常见的二元分类T2 指标,如 F1 得分、ROC AUC、PR AUC 和准确性
  • 使用一个示例二进制分类问题来比较它们
  • 告诉你在决定选择一个指标而不是另一个指标时,你应该考虑什么(F1 得分与 ROC AUC)。

好,我们开始吧!

您将了解到:

评估指标摘要

我将从介绍这些分类标准开始。具体来说:

  • 背后的定义直觉是什么
  • 非技术性解释,
  • 如何计算或绘制
  • 什么时候应该用它

^(提示)
如果你读过我之前的博文“二进制分类的 24 个评估指标(以及何时使用),你可能想跳过这一节,向下滚动到评估指标对比


1.准确(性)

它衡量有多少正面和负面的观察结果被正确分类。

不应该在不平衡的问题上使用准确性。那么,简单地把所有的观测值归为多数类,就很容易得到高精度的分数。

在 Python 中,您可以通过以下方式计算它:

from sklearn.metrics import confusion_matrix, accuracy_score

y_pred_class = y_pred_pos > threshold
tn, fp, fn, tp = confusion_matrix(y_true, y_pred_class).ravel()
accuracy = (tp + tn) / (tp + fp + fn + tn)

accuracy_score(y_true, y_pred_class)

由于准确性分数是根据预测的类别(而不是预测分数)计算的,因此我们需要在计算之前应用某个阈值。显而易见的选择是阈值 0.5,但这可能是次优的。

让我们看一个精度如何取决于阈值选择的例子:

accuracy by threshold

Accuracy by threshold

您可以使用类似上面的图表来确定最佳阈值。在这种情况下,选择稍微高于标准 0.5 的值可能会使分数提高一点点 0.9686->0.9688,但在其他情况下,提高可能会更大。

那么,什么时候使用它有意义吗?

  • 当你的问题得到平衡时,使用准确度通常是一个好的开始。一个额外的好处是,向项目中的非技术涉众解释它非常容易,
  • 每门课对你来说都同样重要

2.F1 分数

简而言之,它通过计算精确度和召回率之间的调和平均值,将精确度和召回率结合成一个指标。它实际上是更一般的函数的一个特例:

当在 F-beta 分数中选择 beta 时,你越关心回忆而不是精度,你就应该选择更高的 beta 。例如,对于 F1 分数,我们同样关心召回率和精确度;对于 F2 分数,召回率对我们来说是两倍重要。

F beta by beta

F beta threshold by beta

在 0 1 的情况下,我们的最佳阈值向更低的阈值移动,而在β= 1 的情况下,它处于中间位置。

可以通过运行以下命令轻松计算:

from sklearn.metrics import f1_score

y_pred_class = y_pred_pos > threshold
f1_score(y_true, y_pred_class)

重要的是要记住,F1 分数是根据精确度和召回率计算的,而精确度和召回率又是根据预测类(而不是预测分数)计算的。

应该如何选择一个最优阈值?让我们在所有可能的阈值上绘制 F1 分数:

f1 score by threshold

F1 score by threshold

我们可以调整阈值来优化 F1 分数。请注意,无论是精确度还是召回率,您都可以通过提高或降低阈值来获得满分。好的一面是,你可以为 F1 的分数找到一个甜蜜点。正如你所看到的,获得合适的阈值实际上可以提高你的分数,从 0.8077- > 0.8121。

你应该什么时候使用它?

  • 几乎在每一个二元分类问题中,你更关心的是正类。在解决这些问题时,这是我的首要标准。
  • It 可以很容易地向业务利益相关者解释,这在许多情况下可能是一个决定性因素。永远记住,机器学习只是解决商业问题的工具。

3.ROC AUC

AUC 是指曲线下的面积,因此要讨论 ROC AUC 得分,我们需要首先定义 ROC 曲线。

这是一个图表,它可视化了真阳性率(TPR)和假阳性率(FPR)之间的权衡。基本上,对于每个阈值,我们计算 TPR 和 FPR,并绘制在一个图表上。

当然,对于每个阈值,TPR 越高,FPR 越低越好,因此曲线越靠左上侧的分类器越好。

Tom Fawcett 的这篇文章对 ROC 曲线和 ROC AUC 评分进行了广泛讨论。

roc curve

ROC curves

我们可以看到一条健康的 ROC 曲线,无论是对积极类还是消极类,都被推向左上侧。不清楚哪一个在所有方面表现更好,因为 FPR < ~0.15,正类更高,从 FPR 开始~0.15,负类更高。

为了得到一个告诉我们曲线有多好的数字,我们可以计算 ROC 曲线下的面积,或 ROC AUC 得分。曲线越靠左上方,面积越大,ROC AUC 得分也越高。

或者,可以显示【ROC AUC 分数等同于计算预测和目标之间的等级相关性。从解释的角度来看,它更有用,因为它告诉我们这个度量向展示了你的模型在预测排名方面有多好。它告诉你随机选择的正面实例比随机选择的负面实例排名更高的概率是多少。

from sklearn.metrics import roc_auc_score

roc_auc = roc_auc_score(y_true, y_pred_pos)

4.平均精确度

类似于 ROC AUC,为了定义 PR AUC,我们需要定义精确回忆曲线。

这是一条在单一可视化中结合了精确度(PPV)和召回率(TPR)的曲线。对于每个阈值,你计算 PPV 和 TPR 并绘制它。y 轴上的曲线越高,模型性能越好。

当遇到经典的精确/召回难题时,你可以利用这个图做出明智的决定。显然,召回率越高,精确度越低。知道在哪个回忆上你的精度开始快速下降可以帮助你选择阈值并提供更好的模型。

precision recall curve

Precision-Recall curve

我们可以看到,对于负类,我们几乎在整个阈值范围内保持高精度和高召回率。对于阳性类别,一旦我们回忆起 0.2 的真阳性,精确度就开始下降,当我们达到 0.8 时,精确度下降到 0.7 左右。

与 ROC AUC 得分类似,您可以计算精确度-召回曲线下的面积,以获得描述模型性能的一个数字。

您也可以将 PR AUC 视为针对每个回忆阈值计算的精确度分数的平均值。如果需要,您还可以通过选择/剪裁召回阈值来调整此定义,以满足您的业务需求。

from sklearn.metrics import average_precision_score

average_precision_score(y_true, y_pred_pos)

评估指标比较

我们将在真实用例中比较这些指标。基于最近的一次 kaggle 竞赛,我创建了一个欺诈检测问题示例:

  • 我只选择了 43 个特性
  • 我从原始数据集中取样了 66000 个观察值
  • 我把正类的分数调整为 0.09
  • 我用不同的超参数训练了一堆 lightGBM 分类器。

我想凭直觉判断哪些模型“真正”更好。具体来说,我怀疑只有 10 棵树的模型比有 100 棵树的模型更差。当然,随着更多的树和更小的学习率,这变得棘手,但我认为这是一个不错的代理。

因此,对于学习率n 估计量的组合,我做了以下工作:

  • 定义的超参数值:
MODEL_PARAMS = {'random_state': 1234,
                'learning_rate': 0.1,
                'n_estimators': 10}
model = lightgbm.LGBMClassifier(**MODEL_PARAMS)
model.fit(X_train, y_train)
y_test_pred = model.predict_proba(X_test)

  • 记录每次运行的所有指标:
y_test_pred = model.predict_proba(X_test)

要获得完整的代码库,请访问这个库

您也可以到这里探索实验运行与:

  • 评估指标
  • 性能图表
  • 阈值图度量

让我们看看我们的模型如何在不同的指标上得分。

在这个问题上,所有这些指标都是从最好到最差的排序模型,非常相似,但略有不同。此外,分数本身也可能有很大差异。

在接下来的部分中,我们将更详细地讨论它。

5.准确性与 ROC AUC

第一个大的区别是,你计算预测类别的准确性,而你计算预测分数的 ROC AUC。这意味着您必须为您的问题找到最佳阈值。

此外,准确性着眼于正确分配的正类和负类的分数。这意味着,如果我们的问题是高度不平衡的,我们通过简单地预测所有的观察值都属于多数类,就可以得到一个真正的高精度分数

另一方面,如果你的问题是平衡的并且你既关心正面预测又关心负面预测准确性是一个很好的选择,因为它真的简单且容易解释。

另一件要记住的事情是 ROC AUC 特别擅长对预测进行排名。正因为如此,如果你有一个问题,即排序你的观察是你关心的 ROC AUC 可能是你正在寻找的。

现在,让我们看看我们的实验结果:

第一个观察结果是,模型在 ROC AUC 和准确性上的排名几乎完全相同。

其次,精确度分数从最差模型的 0.93 开始,到最佳模型的 0.97。请记住,将所有观察值预测为多数类 0 将会给出 0.9 的准确度,因此我们最差的实验 BIN-98 仅比这稍微好一点。然而,这个分数本身就很高,这表明在考虑准确性时,你应该始终考虑到不平衡。

有一个有趣的指标叫做 Cohen Kappa,它通过计算相对于“根据阶级不平衡抽样”模型的精确度改进,将不平衡考虑在内。

点击阅读更多关于科恩卡帕的信息。

6.F1 分数与准确性

这两个指标都将类别预测作为输入,因此无论选择哪一个,您都必须调整阈值。

记住 F1 分数正类上平衡精度和召回,而精度查看正确分类的观测值正类和负类。这使得差别很大,特别是对于不平衡问题而言,在默认情况下,我们的模型将擅长预测真正的负值,因此准确性将很高。然而,如果你同样关心真阴性和真阳性,那么准确性是你应该选择的标准。

如果我们看看下面的实验:

在我们的示例中,这两个指标同样能够帮助我们对模型进行排序并选择最佳模型。1-10 级不平衡让我们的准确率真的默认。正因为如此,即使是最差的模型也有非常高的准确性,当我们登上积分榜前列时,准确性方面的改进并不像 F1 分数那样明显。

7.ROC AUC 与 PR AUC

ROC AUC 和 PR AUC 之间的共同点是,它们都查看分类模型的预测分数,而不是阈值类别分配。然而不同的是 ROC AUC 看的是真阳性率TPR和假阳性率 FPRPR AUC 看的是阳性预测值 PPV 和真阳性率 TPR

因此如果你更关心正类,那么使用 PR AUC 是一个更好的选择,它对正类的改进更敏感。一个常见的场景是高度不平衡的数据集,其中我们想要找到的肯定类的比例很小(就像在欺诈检测中一样)。我强烈推荐看一下这个 kaggle 内核,以便对不平衡数据集的 ROC AUC 与 PR AUC 进行更长时间的讨论。

如果你同样关心正负类或者你的数据集相当平衡,那么使用 ROC AUC 是个好主意。

让我们比较这两个指标的实验:

他们对模型的排名相似,但如果你看看实验 BIN-100BIN 102 ,就会发现略有不同。

然而,以平均精确度(PR AUC)计算的改善更大且更清晰。我们从 0.69 到 0.87,同时 ROC AUC 从 0.92 到 0.97。因为摇摆不定 AUC 可能会给人一种非常高性能的错误感觉,而实际上你的模型可能做得不太好。

8.F1 得分与 ROC AUC

F1 分数和 ROC AUC 之间的一个很大的区别是,第一个以预测的类为输入,第二个以预测的分数为输入。因此,对于 F1 分数,您需要选择一个阈值,将您的观察结果分配给这些类别。通常,如果选择得当,您可以提高模型性能很多。

因此,如果你关心排名预测,不需要它们是正确校准的概率,并且你的数据集不是严重不平衡的,那么我会选择 ROC AUC

如果你的数据集严重不平衡和/或你主要关心正面类,我会考虑使用 F1 分数,或精确召回曲线和 PR AUC 。使用 F1(或 Fbeta)的另一个原因是这些指标更容易解释并与业务利益相关者沟通。

让我们来看看实验结果,以获得更多的见解:

实验在 F1 分数(阈值=0.5 )和 ROC AUC 上排名相同。但是,F1 值较低,最差和最佳模型之间的差异较大。对于 ROC AUC 评分,值越大,差异越小。特别有意思的是实验 BIN-98 ,F1 分 0.45,ROC AUC 0.92。其原因是 0.5 的阈值对于一个尚未训练的模型(只有 10 棵树)来说是一个非常糟糕的选择。如果将 F1 值设置为 0.24,则 F1 值为 0.63,如下所示:

如果你想很容易地为每个实验记录这些图,我在这篇文章的结尾附上一个记录助手。

f1 score by threshold

F1 score by threshold

最后的想法

在这篇博文中,你已经了解了用于评估二元分类模型的几种常见的 指标

**我们已经讨论了它们是如何定义的,如何解释和计算它们,以及何时应该考虑使用它们。

最后,我们 在一个实际问题上比较了那些评估指标,并讨论了一些你可能面临的典型决策。

有了这些知识,你就有了为下一个二元分类问题选择一个好的评估指标的设备!

奖金:

为了让事情变得简单一点,我准备了:

看看下面这些吧!

记录功能

您可以记录我们为您的机器学习项目覆盖的所有度量和性能图表,并使用我们的 Python 客户端集成在 Neptune 中探索它们(在下面的示例中,我使用 Neptune-LightGBM 集成)。

pip install neptune-client neptune-lightgbm
Import neptune.new as neptune

run = neptune.init(...)
neptune_callback = NeptuneCallback(run=run)

gbm = lgb.train(
       params,
       lgb_train,
       callbacks=[neptune_callback],
)

custom_score = ...

run["logs/custom_score"] = custom_score

您可以将不同种类的元数据记录到 Neptune,包括指标、图表、参数、图像等等。查看文档了解更多信息。

二进制分类指标清单

我们已经为您创建了一个不错的备忘单,它将我在这篇博文中浏览的所有内容都放在一个几页长、易于理解的文档中,您可以在需要任何二进制分类指标相关的内容时打印和使用它。

获取您的二元分类指标清单

Get your binary classification metrics cheatsheet**

最佳功能工程工具

原文:https://web.archive.org/web/https://neptune.ai/blog/feature-engineering-tools

说到预测模型,数据集总是需要一个好的描述。在现实世界中,数据集是原始的,需要大量的工作。如果模型要理解监督或无监督学习的数据集,您需要执行几项操作,这就是特征工程的用武之地。

在本文中,我们将讨论:

  • 什么是特征工程
  • 特征工程中的问题类型
  • 用于特征工程的开源工具
  • 特征工程工具的比较

特征工程示例

让我们从几个例子开始。在这里,我们有一个带有某些水果的分类特征列:“香蕉”、“菠萝”和“未知”。我们可以对它进行标签编码:

但是,如果我们将线性预测模型(如决策树)分解为三个不同的特征,并对它们进行一次性编码,那么它们会更好地理解这一特征:

水果 香蕉 菠萝 f _ 未知
0 0
0 0
0 0
0 0

在最后一个例子中,我们使用了一个对机器学习算法没有意义的特征,并将其转换为数字。现在,在第二个例子中,我们将执行一个更复杂的操作。就拿著名的泰坦尼克号数据集来说吧。在泰坦尼克号数据集中,基于某些属性,我们定义泰坦尼克号乘客是否幸存。

我们有一个名为“姓名”的专栏。名字有像“先生”、“夫人”、“老爷”或“主人”这样的头衔,这可能会影响一个人的生存。我们可以利用这些信息,根据乘客姓名中的头衔设计一个新功能。

让我们看看如何用一小段代码实现这一点:

import pandas as pd
import re

df = pd.read_csv('./train.csv')

names = list()
_ = [names.extend(i.split()) for i in df['Name']]

names = [' '.join(re.findall(r"[a-zA-Z]+", name)).lower() for name in names]

seen_titles = set()
titles = [x for x in names if x not in seen_titles and not seen_titles.add(x)]

counts = dict()
for title in titles:
    counts[title] = names.count(title)

print({i: counts[i] for i in counts if counts[i]>50})

输出:

{'miss': 182, 'mr': 521, 'mrs': 129, 'william': 64}

我们可以看到“小姐”、“先生”和“夫人”的出现频率很高,我们可以利用这一信息,使用这三个头衔和未知(或者如果你想做更多的工作,找到像主人、勋爵等头衔。)并从中得出一个分类特征。这些标题出现的次数越多,意味着越多的数据点具有这些值,这意味着这些标题和目标列之间可能存在某种关系。我们还可以推断,女性有更高的存活率,或者有“领主”头衔的人更有可能存活。因此,这个原本只是一堆名字的属性,现在变成了一个重要的特性。

既然您已经在实践中看到了它,让我们继续了解特性工程背后的一些理论。

什么是特征工程?

特征工程是从原始数据创建特征的艺术,因此预测模型可以深入理解数据集,并在看不见的数据上表现良好。要素工程不是一种可以以相同方式应用于所有数据集的通用方法。不同的数据集需要不同的方法。

机器学习算法的数据集表示在每种情况下都是不同的。在图像的情况下,重要的特征可以是形状、线条和边缘。对于音频来说,某些单词可能会产生影响。

图像中工程特征的一个很好的例子可以是自动编码器,其中它们实际上自动学习模型最能理解哪种特征。自动编码器输入图像,输出的是相同的图像,因此中间的层学习这些图像的潜在表示。神经网络可以更好地理解这些潜在的表示,并可以用来训练更好的模型。

特征工程中的问题类型

在讨论特征工程工具之前,我们先来看看我们可以执行的一些操作。请记住,最佳方法取决于问题陈述。

特征提取:

特征提取是制造新特征的过程,这些新特征是现有特征的组合。特征提取的一个很好的例子是降维。

一个数据集中可能有数百万个包含音频、图像甚至表格的要素。虽然它们中的许多可能是多余的,但也存在模型复杂性的问题。

对于一些机器学习算法,随着特征数量的增长,训练时间复杂度呈指数增长。在这种情况下,我们使用特征提取或降维。

有像主成分分析、TSNE 和其他算法可以用来降低特征维数。他们通过数学运算聚集不同的特征,同时试图保持信息的完整性。

让我们来看一个在 Scikit-learn 中使用 PCA 时的特征提取示例:

import pandas as pd
from sklearn.decomposition import PCA

df = pd.DataFrame([[2,4,6,8], [4,8,12,16]])
print(df)

 dr = PCA(n_components=2)
reduced_df = dr.fit_transform(df)
print(reduced_df)

array([[ 5.47722558e+00,  6.66133815e-16],
       [-5.47722558e+00,  6.66133815e-16]])

在上面的代码中,我们使用 PCA 将上述数据帧的维数从 4 减少到 2。

功能选择:

有些特性更重要,有些则是多余的,根本不影响模型。我们可以根据选定的标准对它们进行评分,并按照重要性进行排序。然后,剔除不重要的。

这也可以是一个递归过程,在特征选择之后,我们训练模型,计算准确度分数,然后再次进行特征选择。我们可以迭代,直到找到要保留在数据集中的要素的最终数量。这个过程称为递归特征选择。

一些常用的特征评分函数有:

  • f 分,
  • 互信息得分,
  • 卡方评分。

F-score 可以找到特征和目标列之间的线性关系,并相应地创建分数。使用每个特征的分数,我们可以排除 F 值较低的特征。类似地,互信息分数可以捕获特征和目标列之间的线性和非线性关系,但是需要更多的样本。

卡方检验是统计学中用来检验两个事件独立性的检验。较低的卡方值表明两个变量(特征和目标)是独立的。两个变量的较高值意味着相关的重要特征。

以上是单变量特征选择算法。还有基于树或 lasso 回归的算法,可用于计算基于杂质的特征重要性。

还可以基于特征之间的相关性来删除特征。如果两个特征高度相关,则丢弃其中一个是有意义的,因为我们将降低数据集的维度。

现在,让我们来看一个非常简单的 F 分数示例:

import pandas as pd
df = pd.DataFrame([[1,12,2], [2, 34, 4], [3,87,6] ])
print(df)
from sklearn.feature_selection import f_regression
scores, _ = f_regression(df.iloc[:,0:2], df.iloc[:,-1])
print(scores)
[4.50359963e+15 1.75598335e+01]

我们可以看到列“0”和“1”相对于目标列“2”的 F 值之间的巨大差异。您可以看到我是如何创建数据帧的,列“0”中的每个值都是列“2”中每个值的一半。然而,列“1”包含一些随机值。f 值在列“0”和目标列“2”之间较高,但在列“1”和列“2”之间较低。我们可以说列“0”更好地定义了目标列“2 ”,因此得分更高。

特征构造:

一些特征在一些工作之后对预测模型有意义,就像我们在第一个和第二个例子中看到的。这叫做特征构造。它包括从数据集中的现有要素构建更强大的要素。

例如,我们可能知道某个特性的领域知识,如果值足够高,那么它就属于一个不同的类别,而如果值较低。

假设我们有一个地区的树木数量,最多有 300 棵树。我们可以分类为:

  • 0-100 棵树为 1,
  • 101-200 棵树作为 2,
  • 201-300 棵树作为 3。

这样分类可以消除噪音。

我们可以聚集特性或者分解它们(就像我们对一键编码所做的那样)。不管怎样,我们正在现有的基础上创造新的、更好的功能。

如果你正在处理一个非常特殊的问题集,一个专门项目的数据集,那么我建议你手动处理数据。但是对于一般的问题,不是每个人都有时间坐下来设计特性。因此,在这一节中,我们将看看一些自动化特征工程的工具。

功能工具

自动化特征工程最流行的库之一。它支持许多功能,包括:

  • 特征选择,
  • 特征构造,
  • 使用关系数据库创建新功能,
  • 等等。

除此之外,它还提供了大量的原语,这些原语是使用 max、sum、mode 等的基本转换。这些是有用的操作。假设您必须从日志文件中找到事件之间的平均时间,您可以使用原语来完成此任务。

但 featuretools 最重要的一个方面是,它使用深度特征合成(DFS)来构造特征。

我们先来了解一下什么是 DFS。这个算法需要实体。将实体想象成多个相互连接的数据表。然后它堆叠原语,并对列执行转换。

这些操作可以模仿人类所做的转换。图元堆栈的长度被认为是深度,因此命名为深度特征合成。让我们用一个例子来理解:

Example of DFS

Fig. 1 – An example of DFS in action | Source

在此图中,您可以看到我们从为“ProductID”定义价格的列开始。第一个操作将现有表连接到带有“OrderID”的表。现在,所有“OrderID”在下一个转换中都是唯一的,同时使用“sum”原语,并从另一个表中为每个“OrderID”选取“CustomerID”。在第三个转换中,“OrderID”被删除,“CustomerID”变得唯一,使用 average 运算给出每个客户的平均价格。这里,DFEAT 是直接特征,RFEAT 是关系特征。

这是一个很棒的创建基线模型的库,它可以模仿人类手工做的事情。一旦达到基线,你就会知道你想要前进的方向。

让我们解决一个使用 DFS 来理解 Featuretools API 的例子:

import featuretools as ft
es = ft.demo.load_retail()
print(es)

Entityset: demo_retail_data
  Entities:
    order_products [Rows: 1000, Columns: 7]
    products [Rows: 606, Columns: 3]
    orders [Rows: 67, Columns: 5]
    customers [Rows: 50, Columns: 2]
  Relationships:
    order_products.product_id -> products.product_id
    order_products.order_id -> orders.order_id
    orders.customer_name -> customers.customer_name

我从 Featuretools 加载了 load_retail 数据。现在我们有了实体集,让我们应用 DFS 并获得一些新特性:

feature_matrix, feature_defs = ft.dfs(entityset=es,
                                      target_entity="orders",
                                      agg_primitives=["sum", "mean"],
                                      max_depth=3)
print(feature_matrix)

target_entity 参数定义了我们将为哪个实体创建新特征。和 agg_primitives 是将要应用的转换。更多的深度意味着更多的功能。在此之后,您可以使用特征选择来查找最佳特征。

Featuretools 是迄今为止我遇到的最好的特征工程工具。有许多关于各种不同方法的论文,但是其中大多数还没有实现开放源代码。

自动调整

Autofeat 是另一个很好的特性工程开源库。它自动进行特征合成、特征选择和拟合线性机器学习模型。

Autofeat 背后的算法非常简单。它生成非线性特征,例如 log(x),x ² ,或 x ³ 。在创建特征空间时,使用不同的操作数,如负数、正数和小数。这导致了特征空间的指数增长。分类特征被转换成独热编码特征。

既然我们有这么多的特性,就有必要选择重要的特性。首先 Autofeat 移除高度相关的特征,因此现在它依赖于 L1 正则化,并移除低系数的特征(在用 L1 正则化训练线性/逻辑回归之后具有低权重的特征)。这个选择相关特征和用 L1 正则化移除特征的过程重复几次,直到只留下几个特征。这些特征是通过这个实际描述数据集的迭代过程来选择的。

请参考此链接中的笔记本,获取自动吃饭的示例。

TSFresh

我们名单上的下一个是 TSFresh,一个专注于时间序列数据的库。它包括特征合成和特征选择。该库包含 60 多个特征提取器。这些操作包括全局最大值、标准差、快速傅立叶变换等。这些转换可以将 6 个原始特征变成 1200 个特征。这就是为什么在库中也给出了一个特性选择器,它删除了多余的特性。该库对于时间序列数据非常有用。

您可以在文档中找到一个很好的快速入门。

特征选择器

要素选择器是一个用于要素选择的 Python 库。这是一个小图书馆,有非常基本的选项。它根据缺失值、单个唯一值、共线要素、零重要性和低重要性要素来确定要素的重要性。它使用来自“lightgbm”的基于树的学习算法来计算特征重要性。该库还包括许多可视化方法,可以帮助您获得关于数据集的更多见解。

这里有一个到库的示例代码的链接。

OneBM

OneBM,或一键机器,处理关系数据。它从递增地连接不同的表开始,并识别特征的类型,例如时间序列、分类或数字。然后,它应用一组预定义的特征工程操作。

缺点是 OneBM 没有开源实现。

和你在一起

理论上很有希望,但不幸的是没有可用的开源代码。这里的概念与 TSFresh 非常相似,它在特性上递归地应用一系列转换。当这以指数方式增加数据的维度时,使用特征选择。

比较

最后,让我们比较一下这些库,这样您就可以知道哪个库适合您的工作:

工具/措施 对数据库类型的支持 特征工程 特征选择 开源实现 支持时间序列

Featuretools 可以满足您的大部分需求。TSFresh 专门处理时间序列数据,所以我更喜欢在处理这类数据集时使用它。

结论

我希望现在您已经理解了特性工程,并且知道接下来您想尝试哪些工具。

特征工程仍然是难以自动化的问题之一。即使有库,手动设计功能也能获得最佳效果。特征工程通常是讨论最少的问题,但它是一个非常重要的问题。

很难理解预测模型所理解的功能的底层描述。自动编码器和受限玻尔兹曼机器是理解模型所理解的特征的一步。未来肯定会给这个领域带来有趣的发展。

这里有一些额外的资源供您参考:

报纸

密码

特征选择方法以及如何选择它们

原文:https://web.archive.org/web/https://neptune.ai/blog/feature-selection-methods

你有没有发现自己坐在屏幕前想知道什么样的功能将帮助你的机器学习模型最好地学习它的任务?我打赌你有。数据准备往往会消耗大量数据科学家和机器学习工程师的时间和精力,准备好数据以供学习算法使用是一项不小的壮举。

数据准备流程中的关键步骤之一是特征选择。你可能知道一句流行的谚语:垃圾进,垃圾出。你用什么来喂养你的模型至少和模型本身一样重要,如果不是更重要的话。

在本文中,我们将:

  • 在数据准备流程中,查看功能选择在其他功能相关任务中的位置
  • 并讨论它对任何机器学习项目的成功如此重要的多种原因。
  • 接下来,我们将回顾不同的特性选择方法,并讨论一些技巧和提示来改善它们的结果。
  • 然后,我们将一瞥 Boruta(最先进的特征选择算法)的幕后,看看一种结合不同特征选择方法的巧妙方法
  • 我们还将了解特性选择在行业中是如何被利用的。

让我们开始吧!

什么是特征选择,什么不是?

让我们从定义感兴趣的对象开始。

什么是特征选择?简而言之,它是选择用于训练机器学习模型的特征子集的过程。

这就是特征选择,但同样重要的是理解特征选择不是什么——它既不是特征提取/特征工程,也不是降维。

特征提取和特征工程是描述基于领域知识从现有特征创建新特征的相同过程的两个术语。这会产生比原来更多的特性,应该在特性选择之前执行。首先,我们可以进行特征提取,以得出许多潜在有用的特征,然后我们可以执行特征选择,以挑选出确实会提高模型性能的最佳子集。

降维又是一个概念。它有点类似于特征选择,因为两者都旨在减少特征的数量。然而,它们在实现这一目标的方式上有很大的不同。虽然特征选择选择原始特征的子集来保留并丢弃其他特征,但是维度减少技术将原始特征投影到更少维度的空间上,从而创建全新的特征集。如果需要的话,降维应该在特征选择之后运行,但是在实践中,它不是这个就是那个。

现在我们知道了什么是特征选择,以及它如何对应于其他与特征相关的数据准备任务。但是我们为什么需要它呢?

我们需要特性选择的 7 个原因

一个流行的说法是,现代机器学习技术在没有特征选择的情况下做得很好。毕竟,一个模型应该能够知道特定的特性是无用的,并且应该关注其他的特性,对吗?

嗯,这个推理在某种程度上是有道理的。理论上,线性模型可以给无用的特征分配零权重,而基于树的模型应该很快学会不要对它们进行分割。然而,在实践中,当输入不相关或多余时,许多事情可能会在培训中出错——这两个术语将在后面详述。除此之外,还有许多其他原因可以解释为什么简单地将所有可用的特性都转储到模型中可能不是一个好主意。我们来看看最突出的七个。

1。无关和多余的特征

有些功能可能与手头的问题无关。这意味着它们与目标变量没有关系,与模型设计要解决的任务完全无关。丢弃不相关的特征将防止模型拾取它可能携带的虚假相关性,从而避免过度拟合。

不过,冗余功能是另一种动物。冗余意味着两个或更多特征共享相同的信息,并且除了一个之外,所有特征都可以被安全地丢弃而不会丢失信息。请注意,在存在另一个相关特征的情况下,一个重要特征也可能是多余的。应丢弃冗余要素,因为它们可能会在训练过程中造成许多问题,例如线性模型中的多重共线性。

2。维度的诅咒

特征选择技术在特征很多但训练样本很少的场景中尤其不可或缺。这种情况存在所谓的维数灾难:在一个非常高维的空间中,每个训练样本与所有其他样本相距如此之远,以至于模型无法学习任何有用的模式。解决方案是降低特征空间的维数,例如,通过特征选择。

3。训练时间

功能越多,训练时间越多。这种权衡的细节取决于所使用的特定学习算法,但是在需要实时进行再训练的情况下,人们可能需要将自己限制在几个最佳特性上。

4。部署工作

功能越多,机器学习系统在生产中就变得越复杂。这带来了多种风险,包括但不限于高维护成本、纠缠、未申报的消费者或修正级联

5。可解释性

有了太多的特性,我们就失去了模型的可解释性。虽然并不总是主要的建模目标,但是解释和说明模型的结果通常是重要的,并且在一些受管制的领域中,甚至可能构成法律要求。

6。奥卡姆剃刀

根据这个所谓的节俭定律,只要性能相同,简单的模型应该比复杂的模型更受青睐。这也和机器学习工程师的克星,过度拟合有关。不太复杂的模型不太可能过度拟合数据。

7。数据模型兼容性

最后,还有数据模型兼容性的问题。虽然原则上,这种方法应该是数据优先,这意味着收集和准备高质量的数据,然后选择一个适合这些数据的模型,但现实生活可能正好相反。

你可能试图复制一篇特定的研究论文,或者你的老板可能建议使用特定的模型。在这种模型优先的方法中,您可能被迫选择与您开始训练的模型兼容的特性。例如,许多模型无法处理数据中的缺失值。除非您非常了解您的插补方法,否则您可能需要删除不完整的特征。

不同的特征选择方法

所有不同的特征选择方法可以分为四类,每一类都有其优点和缺点。有无监督和有监督的方法。后者可以进一步分为包装器、过滤器和嵌入式方法。让我们逐一讨论。

Different approaches to feature selection

Feature selection methods | Source: author

无监督特征选择方法

就像无监督学习是在无标签数据中寻找模式的学习类型一样,无监督特征选择方法也是不利用任何标签的方法。换句话说,他们不需要访问机器学习模型的目标变量。

你可能会问,如果不分析一个特性与模型目标的关系,我们怎么能说它对模型不重要呢?嗯,在某些情况下,这是可能的。我们可能希望放弃以下功能:

  • 零或接近零的方差。(几乎)不变的特征提供的学习信息很少,因此是不相关的。
  • 许多缺失值。虽然删除不完整的特征不是处理缺失数据的首选 red 方式,但这通常是一个好的开始,如果缺失太多条目,这可能是唯一明智的做法,因为这些特征可能无关紧要。
  • 高度多重共线性;多重共线性意味着不同要素之间的相关性很强,这可能表示存在冗余问题。

实践中的无监督方法

现在让我们讨论无监督特征选择方法的实际实现。就像大多数其他机器学习任务一样,scikit-learn 包,特别是其“sklearn.feature_selection”模块,可以很好地服务于特征选择。然而,在某些情况下,一个人需要接触到其他地方。在这里,以及在本文的其余部分,让我们用“x”表示一个数组或数据帧,所有潜在的特征为列,观察值为行,目标向量为“y”。

  • the sk learn . feature _ selection。VarianceThreshold transformer 将默认删除所有零方差特征。我们还可以传递一个阈值作为参数,让它移除方差低于阈值的特征。
from sklearn.feature_selection import VarianceThreshold

sel = VarianceThreshold(threshold=0.05)
X_selection = sel.fit_transform(X)

  • 为了删除缺少值的列,可以在数据框上使用 pandas . dropna(axis = 1)方法。
X_selection = X.dropna(axis=1)
  • 要移除具有高度多重共线性的要素,我们首先需要测量它。一种流行的多重共线性测量方法是方差膨胀因子或 VIF。它是在 statsmodels 包中实现的。
from statsmodels.stats.outliers_influence import variance_inflation_factor

vif_scores = [variance_inflation_factor(X.values, feature)for feature in range(len(X.columns))]

按照惯例,VIF 大于 10 的列被视为存在多重共线性,但如果另一个阈值看起来更合理,则可以选择该阈值。

包装特征选择方法

包装器方法是指一系列受监督的特征选择方法,这些方法使用模型来对不同的特征子集进行评分,以最终选择最佳的一个。每个新的子集用于训练一个模型,然后在保留集上评估该模型的性能。选择产生最佳模型性能的特征子集。包装方法的一个主要优点是,它们倾向于为特定的模型类型提供性能最佳的特性集。

然而,与此同时,它也有局限性。包装器方法很可能会过度适应模型类型,如果想在不同的模型中尝试它们,它们产生的特性子集可能不会通用化。

包装器方法的另一个显著缺点是它们需要大量的计算。它们需要训练大量的模型,这可能需要一些时间和计算能力。

流行的包装方法包括:

  • 反向选择,我们从包含所有可用功能的完整模型开始。在随后的迭代中,我们一次删除一个特征,总是在模型性能度量中产生最大增益的那个,直到我们达到期望的特征数量。
  • 正向选择,反向工作:我们从一个零特征的空模型开始,一次贪婪地添加一个特征,以最大化模型的性能。
  • 递归特征消除,或 RFE,精神上类似于逆向选择。它也从一个完整的模型开始,一个接一个地迭代消除特征。区别在于选择要丢弃的特征的方式。RFE 并不依赖于拒不接受的模型性能指标,而是基于从模型中提取的特征重要性来做出决策。这可以是线性模型中的特征权重、基于树的模型中的杂质减少或排列重要性(适用于任何模型类型)。

实践中的包装方法

谈到包装器方法,scikit-learn 为我们提供了:

  • 向后和向前特征选择可以通过 SequentialFeatureSelector 转换器实现。例如,为了使用 k-最近邻分类器作为正向选择中的评分模型,我们可以使用以下代码片段:
from sklearn.feature_selection import SequentialFeatureSelector

knn = KNeighborsClassifier(n_neighbors=3)
sfs = SequentialFeatureSelector(knn, n_features_to_select=3, direction=”forward”)
sfs.fit(X, y)
X_selection = sfs.transform(X)

  • 递归特征消除以非常相似的方式实现。下面是一个基于支持向量分类器的特征重要性实现 RFE 的片段。
from sklearn.feature_selection import RFE

svc = SVC(kernel="linear")
rfe = RFE(svc, n_features_to_select=3)
rfe.fit(X, y)
X_selection = rfe.transform(X)

过滤特征选择方法

受监督家族的另一个成员是过滤方法。它们可以被认为是包装器的更简单、更快速的替代品。为了评估每个特征的有用性,他们简单地分析其与模型目标的统计关系,使用诸如相关性或互信息之类的度量作为模型性能度量的代理。

不仅过滤方法比包装器快,而且它们更通用,因为它们是模型不可知的;他们不会过度适应任何特定的算法。它们也很容易解释:如果一个特征与目标没有统计关系,它就会被丢弃。

然而,另一方面,过滤方法有一个主要缺点。他们孤立地看待每个特征,评估它与目标的关系。这使得他们倾向于丢弃有用的特征,这些特征本身是目标的弱预测器,但是当与其他特征结合时,为模型增加了很多价值。

实践中的过滤方法

现在让我们来看看如何实现各种过滤方法。这些将需要更多的粘合代码来实现。首先,我们需要计算每个特征和目标之间的期望相关性度量。然后,我们将根据结果对所有特征进行排序,并保留所需数量(前 K 个或前 30%)的相关性最强的特征。幸运的是,scikit-learn 提供了一些实用程序来帮助这一努力。

  • 为了保留与目标具有最强 Pearson 相关性的前 2 个特征,我们可以运行:
from sklearn.feature_selection import r_regression, SelectKBest

X_selection = SelectKBest(r_regression, k=2).fit_transform(X, y)
  • 类似地,为了保留前 30%的特性,我们将运行:
	from sklearn.feature_selection import r_regression, SelectPercentile

	X_selection = SelectPercentile(r_regression, percentile=30).fit_transform(X, y)

“SelectKBest”和“SelectPercentile”方法也适用于自定义或非 scikit-learn 相关性测量,只要它们返回长度等于特征数量的向量,每个特征的数量表示其与目标的关联强度。现在让我们看看如何计算所有不同的相关性度量(我们稍后将讨论它们的含义以及何时选择它们)。

  • Spearman 的 Rho、Kendall Tau 和点-双列相关都可以在 scipy 包中获得。这就是如何获得 x 中每个特征的值。
from scipy import stats

rho_corr = [stats.spearmanr(X[:, f], y).correlation for f in range(X.shape[1])]

tau_corr = [stats.kendalltau(X[:, f], y).correlation for f in range(X.shape[1])]

pbs_corr = [stats.pointbiserialr(X[:, f], y).correlation for f in range(X.shape[1])]

  • 卡方、互信息和 ANOVA F-score 都在 scikit-learn 中。请注意,互信息有一个单独的实现,这取决于目标是否是名义上的。
from sklearn.feature_selection import chi2
from sklearn.feature_selection import mutual_info_regression
from sklearn.feature_selection import mutual_info_classif
from sklearn.feature_selection import f_classif

chi2_corr = chi2(X, y)[0]
f_corr = f_classif(X, y)[0]
mi_reg_corr = mutual_info_regression(X, y)
mi_class_corr = mutual_info_classif(X, y)

  • Cramer 的 V 可以从最近的 scipy 版本(1.7.0 或更高版本)获得。
from scipy.stats.contingency import association

v_corr = [association(np.hstack([X[:, f].reshape(-1, 1), y.reshape(-1, 1)]), method="cramer") for f in range(X.shape[1])]

嵌入式特征选择方法

我们将讨论的最后一种特征选择方法是将其嵌入学习算法本身。这个想法是结合两个世界的优点:过滤器的速度,同时获得特定模型的最佳子集,就像从包装器中一样。

实践中的嵌入式方法

最典型的例子是套索回归。它基本上只是正则化的线性回归,其中特征权重在损失函数中向零收缩。因此,许多要素的权重最终为零,这意味着它们将从模型中被丢弃,而权重非零的其余要素将被包括在内。

嵌入式方法的问题在于,没有多少算法内置了特征选择。LASSO 旁边的另一个例子来自计算机视觉:带有瓶颈层的自动编码器迫使网络忽略图像中一些最无用的特征,而专注于最重要的特征。除此之外,没有多少有用的例子。

过滤器特征选择方法:有用的技巧和提示

正如我们所看到的,包装方法速度慢,计算量大,并且是特定于模型的,并且没有多少嵌入式方法。因此,过滤器通常是特征选择方法的首选。

同时,他们需要最专业的知识和对细节的关注。虽然嵌入式方法开箱即用,包装器实现起来也相当简单(尤其是当人们只调用 scikit-learn 函数时),但过滤器需要一点统计复杂性。现在让我们把注意力转向滤波方法,并更详细地讨论它们。

过滤方法需要评估每个特征和目标之间的统计关系。虽然听起来很简单,但事情远比看起来简单。有许多统计方法来衡量两个变量之间的关系。为了知道在特定情况下选择哪一个,我们需要回想一下我们的第一个 STATS101 类,并复习一下数据测量级别

数据测量级别

简而言之,变量的测量水平描述了数据的真实含义以及对这些数据有意义的数学运算的类型。有四种测量级别:标称、顺序、间隔和比率。

Tabel with data measurement levels

Data measurement levels | Source

  • 标称特征,例如颜色(“红”、“绿”或“蓝”)在值之间没有排序;他们只是根据这些观察结果对进行分组。

  • 序数特征,如教育水平(“初级”、“中级”、“高级”)表示顺序,但不是特定水平之间的差异(我们不能说“初级”和“中级”之间的差异与“中级”和“高级”之间的差异相同)。

  • 间隔要素(如以摄氏度为单位的温度)保持间隔相等(25 度和 20 度之间的差异与 30 度和 25 度之间的差异相同)。

  • 最后,比率特征,如以美元表示的价格,以有意义的零为特征,这允许我们计算两个数据点之间的比率:我们可以说 4 美元是 2 美元的两倍。

为了选择正确的统计工具来度量两个变量之间的关系,我们需要考虑它们的度量水平。

测量各种数据类型的相关性

当我们比较的两个变量,即特征和目标,都是区间或比率时,我们可以使用最流行的相关性度量:皮尔逊相关性,也称为皮尔逊相关性

这很好,但是皮尔逊相关性有两个缺点:它假设两个变量都是正态分布的,并且它只测量它们之间的线性相关性。当相关性是非线性时,皮尔逊的 r 不会检测到它,即使它真的很强。

你可能听说过由 Alberto Cairo 编译的 Datasaurus 数据集。它由 13 对变量组成,每个变量都具有相同的非常弱的皮尔逊相关性-0.06。一旦我们把它们标绘出来,就很快变得显而易见,这些对实际上有很强的相关性,尽管是以非线性的方式。

The Datasaurus dataset

The Datasaurus dataset by Alberto Cairo | Source

当预期非线性关系时,应考虑皮尔逊相关性的替代方法之一。最受欢迎的两个是:

  1. 斯皮尔曼秩相关(斯皮尔曼ρ),

对于比率/区间变量,Spearman 秩相关是 Pearson 相关的替代方法。顾名思义,它只查看等级值,即它根据变量中特定数据点的相对位置来比较两个变量。它能够捕捉非线性关系,但没有免费的午餐:由于只考虑排名而不是确切的数据点,我们丢失了一些信息。

  1. 肯德尔秩相关(Kendall Tau)。

另一种基于等级的相关性度量是肯德尔等级相关性。它在精神上类似于 Spearman 的相关性,但表述方式略有不同(Kendall 的计算基于一致和不一致的值对,与 Spearman 基于偏差的计算相反)。肯德尔通常被认为对数据中的异常值更稳健。

如果至少有一个被比较的变量是有序类型,Spearman 或 Kendall 等级相关是可行的。由于序数数据只包含关于等级的信息,所以它们都是完美的匹配,而皮尔逊的线性相关性用处不大。

另一种情况是两个变量都是名义变量。在这种情况下,我们可以从几个不同的相关性度量中进行选择:

  • Cramer 的 V ,它将两个变量之间的关联捕捉到一个从零(无关联)到一(一个变量完全由另一个变量决定)的数字中。
  • 卡方统计通常用于检验两个变量之间的相关性。缺乏依赖性意味着特定的特性没有用。
  • 互信息衡量两个变量之间相互依赖程度的指标,旨在量化从一个变量中提取的关于另一个变量的信息量。

选哪个?没有放之四海而皆准的答案。通常,每种方法都有一些优点和缺点。众所周知,克拉默的 V 字高估了该协会的实力。互信息作为一种非参数方法,需要更大的数据样本来产生可靠的结果。最后,卡方检验不能提供关系强度的信息,而只能提供关系是否存在的信息。

我们已经讨论了这样的场景,其中我们比较的两个变量都是区间或比率,当它们中至少有一个是序数时,以及当我们比较两个名义变量时。最后可能遇到的是比较一个名义变量和一个非名义变量。

在这种情况下,两种最广泛使用的相关性度量是:

  • ANOVA F-score ,当一个变量是连续的而另一个是名义变量时的卡方当量,
  • 点-双列相关一种专门用于评估二进制变量和连续变量之间关系的相关性度量。

再说一次,没有灵丹妙药。F 分数只捕捉线性关系,而点-双列相关作出一些强正态性假设,在实践中可能不成立,破坏了它的结果。

说了这么多,在特定情况下应该选择哪种方法呢?下表有望在这个问题上提供一些指导。

变量 1

变量 2

方法

评论

Comments:

| 仅捕捉线性关系,假设正态性 |

变量 2:

Comments:

| 当预期非线性关系时 |

变量 2:

Comments:

当预期非线性关系时

Comments:

| 仅基于等级,捕捉非线性 |

变量 2:

Comments:

类似于 Rho,但对异常值更稳健

Comments:

| 可能高估相关强度 |

变量 2:

Comments:

| 没有相关强度的信息 |

变量 2:

Method:

相互信息

Comments:

| 需要许多数据样本。 |

Variable 2:

区间/比率 /序数

Comments:

| 仅捕捉线性关系 |

变量 2:

Comments:

| 做出强正态假设 |

不同方法的比较

不要俘虏:博鲁塔不需要人类的参与

说到特性选择,不能不提到 Boruta。回到 2010 年,当第一次以 R 包的形式发布时,它作为一种革命性的特征选择算法迅速成名。

为什么博鲁塔是游戏规则的改变者?

到目前为止,我们讨论的所有其他方法都需要人类做出任意的决定。无监督方法需要我们为特征移除设置方差或 VIF 阈值。包装器要求我们决定想要保留的特性的数量。过滤器需要我们选择相关度和要保留的特征数量。嵌入式方法让我们选择正则化强度。博鲁塔不需要这些。

Boruta 是一个简单但统计优雅的算法。它使用来自随机森林模型的特征重要性度量来选择特征的最佳子集,并且它通过引入两个聪明的想法来做到这一点。

  1. 首先,特性的重要性分数不能相互比较。相反,每个特征的重要性与其随机化版本的重要性相竞争。为了实现这一点,Boruta 随机排列每个特征来构建它的“影子”版本。

然后,在整个特征集上训练随机森林,包括新的阴影特征。阴影特征中的最大特征重要性用作阈值。在最初的特征中,只有那些重要性高于这个阈值的特征得分。换句话说,只有比随机向量更重要的特征才会被加分。

这个过程反复重复多次。由于每次随机排列不同,阈值也不同,因此不同的特征可能得分。经过多次迭代后,每个原始特征都有一些指向其名称的点。

  1. 最后一步是根据每个特性的得分来决定是保留还是丢弃它。博鲁塔的两个聪明想法中的另一个出现了:我们可以使用二项式分布来模拟分数。

每一次迭代都被认为是一次独立的试验。如果该特性在给定的迭代中得了分,它就是一个保留它的投票;如果没有,那就投票决定放弃它。先验地,我们不知道某个特征是否重要,所以该特征得分的预期试验百分比是 50%。因此,我们可以用 p=0.5 的二项式分布来模拟分数。如果我们的特征得分明显高于这个次数,它就被认为是重要的并被保留。如果得分次数少得多,它就被认为不重要并被丢弃。如果它在大约 50%的试验中得分,它的状态是未解决的,但是为了保守起见,我们可以保留它。

例如,如果我们让 Boruta 运行 100 次试验,那么每个特性的预期得分将是 50。如果它接近零,我们丢弃它,如果它接近 100,我们保留它。

Graph with example of Boruta

*Boruta example | Source: author *

Boruta 在许多 Kaggle 比赛中已经证明非常成功,总是值得尝试。它还被成功地用于预测建筑供暖的能耗预测空气污染

有一个非常直观的 Python 包来实现 Boruta,名为 BorutaPy (现在是 scikit-learn-contrib 的一部分)。这个包的 GitHub readme 演示了用 Boruta 运行特性选择是多么容易。

选择哪种特征选择方法?为自己构建一个投票选择器

我们已经讨论了许多不同的特征选择方法。他们每个人都有自己的优点和缺点,做出自己的假设,并以不同的方式得出结论。选哪个?还是我们必须选择?在许多情况下,将所有这些不同的方法组合在一起会使最终的特性选择器比它的每个子部分都更强大。

灵感

一种方法是受集合决策树的启发。在这类模型中,包括随机森林和许多流行的梯度提升算法,人们训练多个不同的模型,并让它们对最终预测进行投票。本着类似的精神,我们可以为自己构建一个投票选择器。

想法很简单:实现我们已经讨论过的几个特性选择方法。您的选择可能会受到您的时间、计算资源和数据测量水平的影响。只要你能负担得起,就尽可能多的运行不同的方法。然后,对于每个特征,写下建议将该特征保留在数据集中的选择方法的百分比。如果超过 50%的方法投票支持保留该特性,那么就保留它——否则,就放弃它。

这种方法背后的思想是,虽然一些方法可能由于其固有的偏见而对一些特征做出错误的判断,但是方法的集合应该正确地得到有用的特征集。让我们看看在实践中如何实现!

实施

让我们构建一个简单的投票选择器,它集成了三种不同的特性选择方法:

  • 1 一种基于皮尔逊相关的滤波方法。

  • 2 一种基于多重共线性的无监督方法。

  • 3 一个包装器,递归特征消除。

让我们看看这样一个投票选择器可能是什么样子。

进行进口。

from itertools import compress

import pandas as pd
from sklearn.feature_selection import RFE, r_regression, SelectKBest
from sklearn.svm import SVR
from statsmodels.stats.outliers_influence import variance_inflation_factor

接下来,我们的 VotingSelector 类在 init 构造函数之上包含四个方法。其中三个实现了我们想要集成的三种特征选择技术:

  • 1 _select_pearson()进行皮尔逊相关滤波

  • 2 _select_vif()用于基于方差膨胀因子的无监督方法

  • 用于 rbf 包装器的 3 _select_rbf()

这些方法中的每一种都将特征矩阵 X 和目标 y 作为输入。基于 VIF 的方法不会使用目标,但是我们仍然使用这个参数来保持所有方法的接口一致,这样我们可以方便地在以后的循环中调用它们。除此之外,每个方法都接受一个关键字参数字典,我们将使用它来传递依赖于方法的参数。解析完输入后,每个方法调用我们之前讨论过的适当的 sklearn 或 statsmodels 函数,返回要保留的特性名称列表。

投票魔术发生在 select()方法中。在这里,我们简单地迭代三个选择方法,对于每个特征,我们记录它是否应该根据这个方法被保留(1)或丢弃(0)。最后,我们对这些投票取平均值。对于每个特性,如果这个平均值大于投票阈值 0.5(这意味着三个方法中至少有两个投票保留了一个特性),我们就保留它。

这是整个类的代码。

class VotingSelector():
   def __init__(self):
       self.selectors = {
           "pearson": self._select_pearson,
           "vif": self._select_vif,
           "rfe": self._select_rfe,
       }
       self.votes = None

 @staticmethod
   def _select_pearson(X, y, **kwargs):
       selector = SelectKBest(r_regression, k=kwargs.get("n_features_to_select", 5)).fit(X, y)
       return selector.get_feature_names_out()

 @staticmethod
   def _select_vif(X, y, **kwargs):
       return [
           X.columns[feature_index]
           for feature_index in range(len(X.columns))
           if variance_inflation_factor(X.values, feature_index) <= kwargs.get("vif_threshold", 10)
       ]

 @staticmethod
   def _select_rfe(X, y, **kwargs):
       svr = SVR(kernel="linear")
       rfe = RFE(svr, n_features_to_select=kwargs.get("n_features_to_select", 5))
       rfe.fit(X, y)
       return rfe.get_feature_names_out()

   def select(self, X, y, voting_threshold=0.5, **kwargs):
       votes = []
       for selector_name, selector_method in self.selectors.items():
           features_to_keep = selector_method(X, y, **kwargs)
           votes.append(
               pd.DataFrame([int(feature in features_to_keep) for feature in X.columns]).T
           )
       self.votes = pd.concat(votes)
       self.votes.columns = X.columns
       self.votes.index = self.selectors.keys()
       features_to_keep = list(compress(X.columns, self.votes.mean(axis=0) > voting_threshold))
       return X[features_to_keep]

让我们看看它在实践中的效果。我们将加载 scikit-learn 内置的臭名昭著的波士顿住房数据。

from sklearn.datasets import load_boston
boston = load_boston()
X = pd.DataFrame(boston["data"], columns=boston["feature_names"])
y = boston["target"]

现在,运行特征选择就像这样简单:

vs = VotingSelector()
X_selection = vs.select(X, y)

结果,我们得到的特征矩阵只剩下三个特征。

      ZN  CHAS     RM
0    18.0   0.0  6.575
1     0.0   0.0  6.421
2     0.0   0.0  7.185
3     0.0   0.0  6.998
4     0.0   0.0  7.147
..    ...   ...    ...
501   0.0   0.0  6.593
502   0.0   0.0  6.120
503   0.0   0.0  6.976
504   0.0   0.0  6.794
505   0.0   0.0  6.030
[506 rows x 3 columns]

我们还可以通过打印的投票来一瞥我们的每个方法是如何投票的

        CRIM  ZN  INDUS  CHAS  NOX  RM  AGE  DIS  RAD  TAX  PTRATIO  B  LSTAT
pearson     0   1      0     1    0   1    0    1    0    0        0  1      0
vif         1   1      0     1    0   0    0    0    0    0        0  0      0
rfe         0   0      0     1    1   1    0    0    0    0        1  0      1

最初的 13 个专栏只剩下 3 个,我们可能会不高兴。幸运的是,我们可以很容易地通过修改特定方法的参数来减少选择的限制。这可以通过简单地向 select 调用添加适当的参数来实现,这要感谢我们如何传递 kwargs。

皮尔逊和 RFE 方法需要保留预定数量的特征。默认值为 5,但我们可能希望将其增加到 8。我们还可以修改 VIF 阈值,该阈值是方差膨胀因子的值,高于该值时,由于多重共线性,我们会丢弃某个要素。按照惯例,这个阈值被设置为 10,但是增加到 15 会导致更多的特性被保留。

vs = VotingSelector()
X_selection = vs.select(X, y, n_features_to_select=8, vif_threshold=15)

这样,我们还剩下七个特征。

        CRIM  ZN  INDUS  CHAS  NOX  RM  AGE  DIS  RAD  TAX  PTRATIO  B  LSTAT
pearson     1   1      0     1    0   1    1    1    1    0        0  1      0
vif         1   1      1     1    0   0    0    1    0    0        0  0      1
rfe         1   0      1     1    1   1    0    1    0    0        1  0      1

我们的 VotingSelector 类是一个简单但通用的模板,您可以将其扩展到任意数量的特征选择方法。作为一种可能的扩展,您还可以将传递给 select()的所有参数视为建模管道的超参数,并对它们进行优化,以便最大化下游模型的性能。

Big Tech 的功能选择

GAFAM 等大型科技公司拥有数以千计的生产中的机器学习模型,是如何在野外操作特征选择的主要例子。让我们看看这些科技巨头对此有什么看法!

谷歌

ML 的规则是谷歌机器学习最佳实践的便利汇编。在其中,谷歌的工程师指出,该模型可以学习的参数数量大致为

与它可以访问的数据量成比例。因此,我们拥有的数据越少,需要丢弃的特征就越多。他们的粗略指导方针(来源于基于文本的模型)是用 1000 个训练样本使用十几个特征,或者用 1000 万个训练样本使用 100,000 个特征。

文档中的另一个关键点涉及模型部署问题,这也会影响特性选择。

  • 首先,可供选择的特性集可能会受到推理时产品中可用特性的限制。如果模型上线时没有一个很好的特性,你可能会被迫放弃它。

  • 第二,一些特性可能容易出现数据漂移。虽然解决漂移是一个复杂的话题,但有时最好的解决方案可能是从模型中完全删除有问题的特性。

脸谱网

几年前,在 2019 年,脸书提出了自己的神经网络合适的特征选择算法,以便在训练大规模模型的同时节省计算资源。他们在自己的脸书新闻数据集上进一步测试了这种算法,以便在使用更少维度的输入的同时尽可能高效地对相关项目进行排序。你可以在这里阅读全部内容

离别赠言

感谢阅读到最后!我希望这篇文章能让您相信特性选择是数据准备流程中的一个关键步骤,并为您提供一些如何实现它的指导。

不要犹豫,在社交媒体上联系我,讨论这里涵盖的主题或任何其他机器学习主题。快乐精选!

参考资料

迈克尔·奥莱塞克

有统计学背景的机器学习工程师。我身兼数职,曾在一家咨询公司、一家人工智能初创公司和一家软件公司工作过。旅行者、通晓多种语言者、数据科学博客作者和讲师,以及终身学习者。查看他的网站,了解更多信息。


阅读下一篇

真实世界的 MLOps 示例:超因子中的模型开发

6 分钟阅读|作者斯蒂芬·奥拉德勒| 2022 年 6 月 28 日更新

在“真实世界的 MLOps 示例”系列的第一部分中,MLOps 工程师 Jules Belveze 将带您了解 Hypefactors 的模型开发流程,包括他们构建的模型类型、他们如何设计培训渠道,以及您可能会发现的其他有价值的细节。享受聊天!

公司简介

Hypefactors 提供一体化媒体智能解决方案,用于管理公关和沟通、跟踪信任度、产品发布以及市场和金融情报。他们运营着大型数据管道,实时传输世界各地的媒体数据。人工智能用于许多以前手动执行的自动化操作。

嘉宾介绍

你能向我们的读者介绍一下你自己吗?

嘿,斯蒂芬,谢谢你邀请我!我叫朱尔斯。我 26 岁。我在巴黎出生和长大,目前住在哥本哈根。

嘿茱尔斯!谢谢你的介绍。告诉我你的背景以及你是如何成为催眠师的。

我拥有法国大学的统计学和概率学士学位以及普通工程学硕士学位。除此之外,我还毕业于丹麦的丹麦技术大学,主修深度学习的数据科学。我对多语言自然语言处理非常着迷(并因此专攻它)。在微软的研究生学习期间,我还研究了高维时间序列的异常检测。

今天,我在一家名为 Hypefactors 的媒体智能技术公司工作,在那里我开发 NLP 模型,帮助我们的用户从媒体领域获得洞察力。对我来说,目前的工作是有机会从原型一直到产品进行建模。我想你可以叫我书呆子,至少我的朋友是这么形容我的,因为我大部分空闲时间不是编码就是听迪斯科黑胶。

超因子模型开发

你能详细说明你在 Hypefactors 建立的模型类型吗?

尽管我们也有计算机视觉模型在生产中运行,但我们主要为各种用例构建 NLP(自然语言处理)模型。我们需要覆盖多个国家和处理多种语言。多语言方面使得用“经典机器学习”方法开发变得困难。我们在变形金刚库的基础上打造深度学习模型。

我们在生产中运行各种模型,从跨度提取或序列分类到文本生成。这些模型旨在服务于不同的用例,如主题分类、情感分析或总结。

Continue reading ->


功能存储:数据科学工厂的组件[指南]

原文:https://web.archive.org/web/https://neptune.ai/blog/feature-stores-components-of-a-data-science-factory-guide

低效而昂贵的特性工程实践经常困扰着处理大量数据的公司。这使得他们无法组织复杂的机器学习操作。为 ML 目的获取数据花费了大量时间,但是不清楚模型的摄取和服务之间是否有任何不一致。

由于这种缓慢的过程和无法再现的结果,项目利益相关者可能会对积极的 ML 结果失去信任。怎么才能避免这种情况呢?

功能商店是答案的一部分。这是数据科学基础设施的重要组成部分,旨在为最终用户建立稳定的渠道。

什么是功能商店?

要素存储是一种接收大量数据、计算要素并存储它们的服务。有了功能商店,机器学习管道和在线应用程序可以轻松访问数据。

作为双数据库实施,要素存储旨在提供实时数据和批处理数据:

  • 在线要素商店以低延迟为在线应用程序提供数据。例子有 MySQL Cluster,Redis,Cassandra DB 等。
  • 离线特征存储是向外扩展的 SQL 数据库,为开发人工智能模型提供数据,并使特征治理在可解释性和透明度方面成为可能。例子包括 Hive、BigQuery、Parquet。

功能存储与数据湖和数据仓库

在抽象层次上,特征存储提供了数据湖功能的子集。特征存储专门用于存储机器学习应用的特征,而数据湖是特征之外的数据的集中存储库,也用于分析目的。另一方面,数据仓库为关系数据库提供了一个模式,业务分析师可以使用该模式通过编写 SQL 查询来生成报告、仪表板等。

与特征工程相关的问题

  • 特性定义的动态性: 一个特定的特性可能在组织内的多个团队中有不同的定义。如果没有适当的文档,维护特性背后的逻辑和它所传达的信息会变得越来越困难。特征存储通过维护与特征相关联的事实定义来帮助解决这个问题。这使得数据的最终用户更容易使用,并保持从该数据得出的结果的一致性。
  • 特征冗余: 当数据必须以原始形式获取时,数据科学家花费大量时间重新提取可能已经被团队中的其他人或当前使用数据的管道提取的特征。由于要素存储提供了单一的事实来源,数据科学家可以在要素工程上花费更少的时间,而在实验和构建上花费更多的时间。
  • 实验和生产环境之间的差距: 产品通常使用少量的编程语言和框架,这些语言和框架可能与用于实验机器学习模型的工具不同。这种差距会导致可能被忽略的不一致,并最终恶化客户端的模型/产品。换句话说,开发中模型的预期行为/性能在产品中部署时应该或多或少是可再现的。对于功能存储,这种转换是不必要的,因为它们保持了实验和生产之间的一致性。

ML 管线中特征存储的优势

来自特性库的输出是与实现无关的。无论我们使用哪种算法或框架,应用程序/模型都将以一致的格式获取数据。使用特征库的另一个主要好处是节省了原本要花费在计算特征上的时间

功能存储的组件

  • 功能注册: 功能注册提供了一个中央界面,数据消费者(例如数据科学家)可以使用该界面来维护功能列表及其定义和元数据。这个中央存储库可以根据您的需要进行更新。
  • 运营监控: 机器学习模型在初始阶段可能表现良好,但你仍然必须监控它们的正确性和随着时间推移的可靠结果。在机器学习模型中,自变量和因变量之间总有可能存在退化关系。这主要是由于输入数据的复杂性,因此随着时间的推移,预测变得更加不稳定和不准确。这种现象称为模型漂移,可以分为两种类型:
    • 概念漂移:目标变量的统计性质随时间变化。
    • 数据漂移:预测器变量的统计特性随时间变化。

要素存储维护数据质量和正确性。它为内部和外部应用程序/工具提供了一个接口,以确保生产中的正确模型性能。

  • 转换: 在机器学习应用中,数据转换管道吸收原始数据,并将其转换为可用的特征。功能存储负责管理和编排它们。有三种主要的转换类型:
    • 为有速度的数据(例如实时日志),
    • 批次为平稳数据,
    • 按需对于无法预先计算的数据。
  • 存储: 非即时需求的特性是离线的,通常存储在雪花、蜂巢、红移等仓库中。另一方面,在线功能是实时要求的,并存储在 MongoDB、CassandraDB 或 Elasticsearch 等数据库中,具有低延迟能力。
  • 上菜: 特征提取和处理背后的逻辑是抽象的,这使得特征商店非常吸引人。当数据科学家出于实验目的访问数据快照(时间点)时,功能存储确保这些功能不断实时更新,并随时可供需要它们的应用程序使用。

功能存储和 MLOps

什么是 MLOps?

MLOps 是关于将 DevOps 原则应用于构建、测试和部署机器学习管道。通过 MLOps 实践,团队可以更频繁地部署更好的模型。MLOps 面临的挑战包括:

  • 数据版本化,
  • 管理专用硬件(GPU 等。),
  • 管理模型的数据治理和合规性。

MLOps 与 DevOps

传统上,开发人员使用 Git 对代码进行版本控制,这是自动化和持续集成(CI)所必需的。这使得自动再现环境变得容易。

每次提交 Git 都会触发包的自动创建,这些包可以使用版本控制中的信息进行部署。Jenkins 与版本控制软件一起用于构建、测试和部署代码,因此它以一种受控和可预测的方式运行。Jenkins 涉及的步骤有:

  1. 虚拟机(VMs 容器的供应。
  2. 在这些机器上读取代码。
  3. 编译代码。
  4. 运行测试。
  5. 打包二进制文件。
  6. 部署二进制文件。

MLOps 最重要的部分是版本化数据。你不能用 Git 做到这一点,因为它不能扩展到大量的数据。一个简单的机器学习管道包括以下内容:

  • 已验证的传入数据。
  • 特征计算。
  • 生成培训和测试数据。
  • 模型的训练。
  • 模型的验证。
  • 模型部署。
  • 在生产中监控模型。

当您将超参数调整、模型可解释性和分布式训练添加到图片中时,这可能会变得更加复杂。

编排框架有助于自动工作流执行、模型再训练、组件之间的数据传递以及基于事件的工作流触发。这些框架包括:

  • tensor flow Extended(TFX)–支持气流、波束、库伯流管道
  • hopworks–支持气流
  • ml flow–支持 Spark
  • 库伯流–支持库伯流管道

TFX、MLFlow 和 Hopsworks 支持使用 Beam 和 Spark 的分布式处理,支持在使用大量数据的集群上横向扩展执行。

机器学习管道

DevOps CI/CD 大多由源代码更新触发。MLOps 和 DataOps CI/CD 管道不仅可以由源代码更新触发,还可以由数据更新和数据处理触发:

  • DataOps 主要自动化数据管道的测试和部署,
  • MLOps 自动化了培训、验证和部署模型的过程。

对于端到端的机器学习管道,你需要非常谨慎的特征工程。这会占用你大部分的带宽。功能存储有两种帮助方式:

  • 接收数据,验证数据,并将其转化为可消费的功能。
  • 消耗这些数据的机器学习算法得到训练、验证并被推向生产。

机器学习管道的问题是它们有状态的本质。一个好的数据管道应该是无状态和幂等的。换句话说,在部署一个新模型(在验证阶段)之前,我们需要大量的信息,包括它的性能如何,我们做了什么假设,模型的影响,等等。通常,开发人员最终会一遍又一遍地重新编写代码,以正确定义输入和输出。

Hopsworks 提供了一种无干扰元数据模型,其中管道通过 Hopsworks API 读写 HDFS 并与要素存储进行交互。通过这种方式,我们可以存储元数据、工件、模型出处等,而无需像 TensorFlow Extended (TFX)或 MLFlow 所要求的那样重新编写代码。

一些行业最佳实践以及帮助我们实现这些实践的相关工具如下

  • 单元测试和与 Jenkins 的持续集成。
  • 使用 TFX 或 Deequ 进行数据验证,以便特性具有预期值。
  • 使用 Deequ 测试唯一性、缺失性和独特性。
  • 使用 TFX 或 Deequ 检查数据分布验证。
  • 使用 Deequ 的特征和与目标变量之间的成对关系。
  • 测量每个特性成本的自定义测试。
  • 个人身份信息(PII)泄漏测试。

功能存储架构

优步的米开朗基罗机器学习平台

2017 年,优步推出了米开朗基罗作为人工智能即服务平台,以简化人工智能的扩展。随着不断增长的客户群和大量丰富数据的涌入,优步在其多个数据中心部署了米开朗基罗来运行他们的在线应用程序。这个平台是出于一种需要而诞生的。在米开朗基罗之前,数据科学家和工程师必须创建单独的预测模型和定制系统,这在扩大规模方面是不可持续的。

米开朗基罗建立在优步的基础设施之上,内部构建的组件是 HDFS、Spark、XGBoost 或 TensorFlow 等成熟开源框架的自举。它为所有事务性数据提供了一个数据湖。Kafka 经纪人被部署来聚合来自优步所有服务的数据,并通过 Samza 计算引擎与 Cassandra 集群进行流式传输。

该平台使用 Hive/HDFS 来存储优步的交易和日志数据。在线模型所需的特征被预先计算并存储在 CassandraDB 中,在预测时可以以低延迟读取这些特征。

为了进行特性选择、转换,并确保输入数据被检查格式是否正确以及是否遗漏,优步的开发人员构建了他们自己的领域特定语言(DSL)作为 Scala 的子集。有了它,最终用户可以添加他们自己的用户定义的功能。为了保证再现性,在训练和预测期间应用相同的 DSL 表达式。

米开朗基罗支持多种机器学习算法和深度学习网络的离线、大规模分布式训练,这使得它非常具有可扩展性。模型类型、超参数、数据源、DSL 表达式和计算资源要求作为模型配置提及。它还提供超参数搜索。

已配置的训练作业在 YARN 或 Mesos 集群上运行,之后会计算性能指标并编译成报告。运行分区模型时,训练数据会根据模型配置自动分区,并在相同的模型上进行训练。需要时使用父模型。关于最终模型的信息被存储在模型库中用于部署,并且报告被保存用于将来的分析。

培训工作可以通过米开朗基罗的 UI、API,甚至通过 Jupyter 笔记本来管理。

训练完成后,包含以下信息的版本化对象将存储在 CassandraDB 中:

  1. 模型的作者,
  2. 培训工作的开始和结束时间,
  3. 车型配置,
  4. 参考培训和测试数据,
  5. 特征级统计,
  6. 模拟性能指标,
  7. 模型的学习参数,
  8. 汇总统计数据。

谷歌的盛宴:开源功能商店

Feast 是一个用于机器学习的开源功能库,旨在简化创建、管理、共享和提供功能的过程。2019 年,Gojek 与谷歌云合作推出。

它使用 BigQuery + GCS + S3 实现离线特性,使用 BigTable + Redis 和 Apache Beam 实现在线特性。

组件:

  1. 盛宴核心:这是所有特性及其各自定义共存的地方。
  2. Feast Job Service: 该组件管理将数据从数据源加载到存储中的数据处理作业,以及导出用于训练的数据的作业。
  3. 盛宴在线服务:在线功能要求对它们的低延迟访问,这由该组件实现。
  4. 盛宴 Python SDK: 这是用来管理特征定义,启动作业,检索训练数据集和在线特征。
  5. 在线商店:它存储每个实体的最新功能。它可以由流源的批处理摄取或流摄取作业填充。
  6. 离线存储:存储用于训练 AI 模型的批量数据。

它是如何工作的?

  1. 日志流数据是从应用程序获取的。
  2. Kafka 和 Spark 等流处理系统用于将这些数据转换为流特征。
  3. 然后,原始要素和流要素都被记录到数据湖中。
  4. 批处理存储中的 ETL/ELT 转换数据。
  5. 然后在特征核心上建立特征及其定义。
  6. Feast Job 服务轮询新的和更新的功能。
  7. 批处理摄取作业是短暂的,它们将数据提取到离线和在线存储中。
  8. 流接收作业是长期存在的,它们从流源获取并提供给在线应用程序。
  9. 启动机器学习管道,使用数据,所有这些都由 SDK 控制。
  10. 根据模型配置,feast 提供时间点培训数据和功能。
  11. 然后,服务经训练的模型,并且后端请求来自模型服务系统的预测。
  12. 模型服务系统从盛宴在线服务请求在线特征。
  13. 模型服务系统对在线特征进行预测并返回结果。

霍普斯沃克的特色商店

数据工程师主要负责添加/更新功能,这些功能可以使用笔记本、Python、Java 或 Scala 编写的程序,甚至是 Hopsworks 的 UI,通过 SQL 查询甚至复杂的图形嵌入来计算。程序以熊猫或火花数据帧的形式接收数据。

在摄取之前,使用数据验证 API 对要素数据进行验证。Hopsworks 提供了一个 UI 平台,用于建立数据验证规则,通过这些规则还可以查看特性统计数据。Hopsworks 还支持创建多个特性存储,因为一个特性存储不一定能被企业的所有部分访问。

数据科学家使用特征存储将数据分为训练集和测试集,以构建机器学习模型。在线应用程序使用它来创建一个特征向量,稍后用于推理。除此之外,用户还可以查询时间点数据。

特征是可测量的属性,其中每个特征属于具有用于计算的相关键的特征组。数据科学家可以通过提供/选择一组特征、特征输出的目标文件格式(CSV、TFRecords、Numpy 等)来生成训练和测试数据。),以及目标存储系统(GCS、AWS S3 等。).

有两种方法可以计算特征组:

  • 按需:有对外部数据库的内置支持,允许您在外部数据源上定义特性。
  • 缓存:Hopsworks 功能存储可以扩展到 1pb 的功能数据。

Hopsworks 提供了很棒的关于如何使用他们的 API 和开始使用其特性库的文档。

泰克顿的特征商店

虽然大多数组织已经开始构建供内部使用的功能商店,但 Tecton 一直在构建他们的平台,以服务的形式提供给各种企业。他们的创始成员最初在优步,在那里他们建造了米开朗基罗。受优步产品的启发,泰克顿也建立并开始提供服务。他们还为谷歌的开源功能商店 Feast 做出了贡献。

摘要

  • 特征存储加快并稳定了提取、转换数据、工程特征并存储它们的过程,以便于离线和在线访问。
  • 功能商店如果不是无处不在的话,应该是每个组织的下一个必须采取的步骤,这些组织旨在建立最好的人工智能产品,而不必在运营目的上损失带宽。
  • 传统的 CI/CD 流水线不适合处理数据和机器学习模型,这就引入了 MLOps 和 DataOps 的需求。
  • 特色商店的一些例子是优步的米开朗基罗,谷歌的盛宴,霍普斯沃斯的特色商店和泰克顿的特色商店。

参考资料:

与 L1 或 L2 正则化的过度拟合作斗争:哪一个更好?

原文:https://web.archive.org/web/https://neptune.ai/blog/fighting-overfitting-with-l1-or-l2-regularization

机器学习模型中的糟糕性能来自于过拟合或欠拟合,我们将仔细研究第一种情况。当学习的假设与训练数据拟合得如此之好,以至于损害了模型在看不见的数据上的性能时,就会发生过度拟合。该模型对不属于训练数据的新实例的概括能力很差。

复杂的模型,如随机森林、神经网络和 XGBoost 更容易过度拟合。更简单的模型,如线性回归,也可能过度拟合-这通常发生在特征多于训练数据中的实例数量时。

因此,考虑过度拟合的最佳方式是想象一个具有简单解决方案的数据问题,但我们决定将一个非常复杂的模型拟合到我们的数据,为模型提供足够的自由度来跟踪训练数据和随机噪声。

我们如何检测过度拟合?

为了检测我们的 ML 模型中的过度拟合,我们需要一种在看不见的数据上测试它的方法。每当我们想要在看不见的实例上评估模型的性能时,我们经常利用一种叫做“交叉验证”的技术。交叉验证是各种模型验证技术,用于评估预测模型对模型未见过的独立数据集的泛化能力的质量。

交叉验证实现的最基本类型是基于保留的交叉验证。这种实现将可用数据分成训练集和测试集。为了使用基于排除的交叉验证来评估我们的模型,我们将首先在排除集的训练分割上构建和训练模型,然后使用该模型通过测试集进行预测,这样我们就可以评估它的表现如何。

我们知道什么是过度拟合,以及如何使用基于保留的交叉验证技术来检测模型中的过度拟合。让我们获取一些数据,并在我们的数据上实现这些技术,以检测我们的模型是否过度拟合。

注意 : 在本例中,我们将使用 Scikit-learn datasets 模块中的 Iris 数据集。

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from mlxtend.plotting import plot_learning_curves
from sklearn.model_selection import train_test_split

dataset = load_iris()
df = pd.DataFrame(data= dataset.data)

df["target"] = dataset.target

X = df.iloc[:, :-1]
y = df["target"].values

X_train, X_test, y_train, y_test = train_test_split(X, y,
                                                    train_size=0.60,
                                                    shuffle=True,
                                                    random_state=24)

clf = RandomForestClassifier(random_state=24)

plot_learning_curves(X_train=X_train,
                     y_train=y_train,
                     X_test=X_test,
                     y_test=y_test,
                     clf=clf,
                     scoring="misclassification error",
                     print_model=False)
plt.ylim(top=0.1, bottom=-0.025)
plt.show()

Overfitting

在上面的图像中,我们可以清楚地看到,我们的随机森林模型过度适应训练数据。我们的随机森林模型在训练集上有完美的误分类误差,但是在测试集上有 0.05 的误分类误差。散点图上两条线之间的间隙说明了这一点。

有各种方法来对抗过度拟合。一些技术包括改进数据,例如通过特征选择减少输入到模型中的特征数量,或者通过收集更多数据使实例多于特征。

或者,我们可以通过改进我们的模型来对抗过度拟合。我们可以通过减少估计器的数量(在随机森林或 XGBoost 中)或减少神经网络中的参数数量来简化我们的模型。我们还可以引入一种被称为提前停止的技术,其中训练过程被提前停止,而不是运行设定数量的时期。

另一种简化模型的方法是通过正则化将偏差添加到模型中。这非常有趣,所以在本文的剩余部分,我们将重点关注这种方法。

什么是正规化,我们为什么需要正规化?

正则化技术在机器学习模型的开发中起着至关重要的作用。特别是复杂的模型,如神经网络,容易过度拟合训练数据。分解来看,“规则化”这个词表示我们正在使一些事情变得有规律。在数学或 ML 上下文中,我们通过添加信息来创建防止过度拟合的解决方案,从而使事情变得有规律。我们在 ML 上下文中使之规则的“东西”是“目标函数”,在优化问题中我们试图最小化它。

简单来说,在正则化中,信息被添加到一个目标函数中。我们使用正则化,因为我们希望在模型中添加一些偏差,以防止它过度适应我们的训练数据。在添加正则化之后,我们最终得到了一个在训练数据上表现良好的机器学习模型,并且具有很好的能力来概括训练期间没有见过的新示例。

最优化问题

为了获得我们模型的“最佳”实现,我们可以使用优化算法来确定最大化或最小化目标函数的输入集。通常,在机器学习中,我们希望最小化目标函数,以降低模型的误差。这就是为什么目标函数在从业者中被称为损失函数,但它也可以被称为成本函数。

有大量流行的优化算法:

  • 斐波那契搜索,
  • 二分法,
  • 线搜索,
  • 梯度下降,
  • …还有更多。

大多数人在他们的机器学习之旅的早期都会接触到梯度下降优化算法,因此我们将使用这种优化算法来演示当我们有正则化时我们的模型中会发生什么,以及当我们没有正则化时会发生什么。

无正则化的梯度下降

梯度下降是一种一阶优化算法。它包括在梯度的相反方向上采取步骤,以便找到目标函数的全局最小值(或非凸函数中的局部最小值)。下图很好地展示了梯度下降是如何逐步达到凸函数的全局最小值的。

为了表达梯度下降在数学上是如何工作的,将 N 视为观察值的数量, Y_hat 为实例的预测值, Y 为实例的实际值。

对于我们的优化算法来确定采取多大的步长(幅度)以及在什么方向上,我们计算:

其中 η 是学习率—学习率是优化算法中的一个调整参数,该算法确定每次迭代的步长,同时向损失函数的最小值移动[ 来源 : 维基百科 ]。然后,在每次迭代之后,通过以下更新规则更新模型的权重:

其中δw 是包含每个权重系数的权重更新的向量 w. 下面的函数演示了如何在没有任何正则化的情况下在 Python 中实现梯度下降优化算法。

def param_init(X):
    """
    Initialize parameters for linear regression model
    __________________
    Input(s)
    X: Training data
    __________________
    Output(s)
    params: Dictionary containing coefficients
    """
    params = {} 
    _, n_features = X.shape 

    params["W"] = np.zeros(n_features)
    params["b"] = 0
    return params

def gradient_descent(X, y, params, alpha, n_iter):
    """
    Gradient descent to minimize cost function
    __________________
    Input(s)
    X: Training data
    y: Labels
    params: Dictionary containing random coefficients
    alpha: Model learning rate
    n_iter: The number of iterations of Gradient descent
    __________________
    Output(s)
    params: Dictionary containing optimized coefficients
    """
    W = params["W"]
    b = params["b"]
    m = X.shape[0] 

    for _ in range(n_iter):

        y_pred = np.dot(X, W) + b

        dW = (2/m) * np.dot(X.T, (y_pred - y))
        db = (2/m) * np.sum(y_pred -  y)

        W -= alpha * dW
        b -= alpha * db

    params["W"] = W
    params["b"] = b
    return params

注意 : 只要迭代次数(n_iters)足以使梯度下降达到全局最小值,算法将继续向凸函数的全局最小值和局部最小值前进。

此外,请注意梯度下降有各种不同的实现方式,如随机梯度下降和小批量梯度下降,但梯度下降(也称为批量梯度下降)示例背后的逻辑超出了本文的范围。

梯度下降的这种实现没有正则化。因此,我们的模型可能会过度拟合训练数据。这个任务很简单,但是我们使用的是一个复杂的模型。L1 正则化和 L2 正则化是两种流行的正则化技术,我们可以用它们来对抗模型中的过拟合。

可能由于相似的名字,很容易认为 L1 和 L2 正则化是相同的,特别是因为它们都防止过拟合。然而,尽管目标(和名称)相似,但是这些正则化技术在防止过度拟合方面有很大的不同。

为了更好地理解这一点,让我们建立一个人工数据集,以及一个没有正则化的线性回归模型来预测训练数据。Scikit-learn 有现成的线性回归实现,内置了梯度下降优化的优化实现。让我们来看看它的实际应用:

import warnings
warnings.filterwarnings("ignore")

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

URL = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv"

df = pd.read_csv(URL, header=None)

X = df.loc[:100, 5]
y = df.loc[:100, 13] 

X_reshaped = X[:, np.newaxis]
y_reshaped = y[:, np.newaxis]

linear_regression = LinearRegression()

linear_regression.fit(X_reshaped, y_reshaped)

y_pred = linear_regression.predict(X_reshaped)

mse = mean_squared_error(y_reshaped, y_pred)
print(f"Mean Squared Error: {mse}n")

sns.scatterplot(X,y)
plt.plot(X_reshaped, y_pred, color="red")
plt.title("Linear Regression Model without Regularization")
plt.show()

>>>> Mean Squared Error: 9.762853674412973

在下一节中,我们将深入 L1 和 L2 正则化背后的直觉。

L1 正则化

L1 正则化,也称为 L1 范数或套索(在回归问题中),通过将参数收缩到 0 来防止过度拟合。这使得一些功能过时。

这是一种特征选择的形式,因为当我们为一个特征赋予 0 权重时,我们将特征值乘以 0,得到 0,从而消除了该特征的重要性。如果我们模型的输入特征的权重接近于 0,我们的 L1 范数将是稀疏的。输入要素的选择将具有等于零的权重,其余的将是非零的。

例如,想象我们想要使用机器学习来预测房价。考虑以下特性:

  • 街道–道路入口,
  • 小区–物业位置,
  • 可达性–交通通道,
  • 建造年份–房屋建造的年份,
  • 房间–房间数量,
  • 厨房–厨房数量,
  • 壁炉–房子里壁炉的数量。

在预测房子的价值时,直觉告诉我们,不同的输入特征不会对价格产生相同的影响。例如,与壁炉数量相比,邻居或房间数量对房产价格的影响更大。

因此,我们的 L1 正则化技术将赋予壁炉功能零权重,因为它对价格没有显著影响。我们可以预期邻域和房间号被赋予非零权重,因为这些特征会显著影响房产的价格。

数学上,我们通过如下扩展损失函数来表达 L1 正则化:

本质上,当我们使用 L1 正则化时,我们是在惩罚权重的绝对值。

在现实世界环境中,我们经常有高度相关的特征。比如我们家建造的年份和家里的房间数可能有很高的相关性。使用 L1 正则化时要考虑的一点是,当我们具有高度相关的特征时,L1 范数将从任意性质的相关特征组中仅选择 1 个特征,这可能是我们不想要的。

尽管如此,对于我们的示例回归问题,Lasso 回归(带 L1 正则化的线性回归)将生成一个高度可解释的模型,并且仅使用输入要素的子集,从而降低了模型的复杂性。

Python 中的套索回归示例:

import warnings
warnings.filterwarnings("ignore")

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression, Lasso, Ridge
from sklearn.metrics import mean_squared_error

URL = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv"
df = pd.read_csv(URL, header=None)

X = df.loc[:100, 5]
y = df.loc[:100, 13] 

X_reshaped = X[:, np.newaxis]
y_reshaped = y[:, np.newaxis]

lasso = Lasso(alpha=10)

lasso.fit(X_reshaped, y_reshaped)

y_pred = lasso.predict(X_reshaped)

mse = mean_squared_error(y_reshaped, y_pred)
print(f"Mean Squared Error: {mse}")
print(f"Model Coefficients: {lasso.coef_}n")

sns.scatterplot(X,y)
plt.plot(X_reshaped, y_pred, color="red")
plt.title("Linear Regression Model with L1 Regularization (Lasso)")
plt.show()

>>>> Mean Squared Error: 34.709124595627884
Model Coefficients: [0.]

Linear regression model

注意 : 由于我们之前的 Python 例子只使用了一个特性,所以我夸大了 lasso 回归模型中的 alpha 项,使得模型系数等于 0 只是为了演示的目的。

L2 正则化

L2 正则化,或 L2 范数,或岭(在回归问题中),通过迫使权重较小,但不使它们正好为 0 来对抗过度拟合。

因此,如果我们再次预测房价,这意味着预测房价的不太重要的特征仍会对最终预测产生一些影响,但这种影响很小。

当执行 L2 正则化时,我们添加到损失函数中的正则化项是所有特征权重的平方和:

因此,L2 正则化返回非稀疏解,因为权重将非零(尽管一些可能接近 0)。

使用 L2 正则化时要考虑的一个主要问题是,它对异常值不够稳健。平方项将放大异常值的误差差异。正则化将试图通过惩罚权重来解决这个问题。

L1 正则化和 L2 正则化的区别:

  • L1 正则化惩罚权重的绝对值之和,而 L2 正则化惩罚权重的平方和。
  • L1 正则化解是稀疏的。L2 正则化解是非稀疏的。
  • L2 正则化不执行要素选择,因为权重仅减少到接近 0 而不是 0 的值。L1 正则化具有内置的特征选择。
  • L1 正则化对异常值是鲁棒的,L2 正则化不是。

Python 中的岭回归示例:

import warnings
warnings.filterwarnings("ignore")

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression, Lasso, Ridge
from sklearn.metrics import mean_squared_error

URL = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv"
df = pd.read_csv(URL, header=None)

X = df.loc[:100, 5]
y = df.loc[:100, 13] 

X_reshaped = X[:, np.newaxis]
y_reshaped = y[:, np.newaxis]

ridge = Ridge(alpha=100)
ridge.fit(X_reshaped, y_reshaped)
y_pred = ridge.predict(X_reshaped)

mse = mean_squared_error(y_reshaped, y_pred)
print(f"Mean Squared Error: {mse}")
print(f"Model Coefficients: {ridge.coef_}n")

sns.scatterplot(X,y)
plt.plot(X_reshaped, y_pred, color="red")
plt.title("Linear Regression Model with L2 Regularization (Ridge)")
plt.show()

>>>> Mean Squared Error: 25.96309109305436
Model Coefficients: [[1.98542524]]

Linear regression model

看看岭回归模型的 alpha 值——是 100。超参数值α越大,这些值就越接近 0,而不会变成 0。

L1 和 L2 正规化哪个更好?

一种正则化方法是否比另一种更好,这是学术界争论的问题。然而,作为一名从业者,当你需要在 L1 和 L2 正规化之间做出选择时,有一些重要的因素需要考虑。我将它们分为 6 类,并将向您展示哪种解决方案更适合每一类。

哪种解决方案更可靠?L1

根据 Investopedia 提供的定义,如果一个模型的输出和预测始终准确,即使一个或多个输入变量或假设由于不可预见的情况而发生巨大变化,该模型也被认为是稳健的。[ 来源 : 投资媒体

由于一个相当明显的原因,L1 正则化比 L2 正则化更健壮。L2 正则化取权重的平方,因此数据中异常值的成本呈指数增长。L1 正则化采用权重的绝对值,因此成本仅线性增加。

什么方案可能性更大?L1

我指的是在某一点上达到的解的数量。L1 正则化使用曼哈顿距离来到达单个点,因此到达一个点可以采用多条路线。L2 正则化使用欧几里得距离,这将告诉你到达一个点的最快方法。这意味着 L2 范数只有一个可能的解。

哪种解决方案的计算成本更低?L2

因为 L2 正则化取权重的平方,所以它被归类为封闭解。L1 涉及采用权重的绝对值,这意味着解决方案是一个不可微的分段函数,或者简单地说,它没有封闭形式的解决方案。L1 正则化在计算上更昂贵,因为它不能用矩阵数学来求解。

哪种解决方案可以产生稀疏输出?L1

稀疏性是指正则化产生的解有许多值为零。然而,我们知道它们是 0,不像丢失数据,我们不知道一些或许多值实际上是什么。

如前所述,L2 正则化只是将权重缩小到接近 0 的值,而不是实际上为 0。另一方面,L1 正则化将值缩小到 0。这实际上是特征选择的一种形式,因为某些特征是完全从模型中提取的。也就是说,在您决定继续使用的模型拟合之前,特征选择可能是一个额外的步骤,但是对于 L1 正则化,您可以跳过这一步,因为它内置于技术中。

包裹

在本文中,我们探讨了什么是过拟合,如何检测过拟合,什么是损失函数,什么是正则化,为什么我们需要正则化,L1 和 L2 正则化如何工作,以及它们之间的差异。

决定使用哪个正则化器完全取决于你试图解决的问题,以及哪个解决方案最符合你的项目的结果。

你的第一个 MLOps 系统:好看起来像什么?和安迪·麦克马洪一起

原文:https://web.archive.org/web/https://neptune.ai/blog/first-mlops-system-with-andy-mcmahon

这篇文章最初是 MLOps Live(T1)的一集,这是一个互动的 Q(T2)环节,在这里,ML 从业者回答来自其他 ML 从业者的问题。

每集都专注于一个特定的 ML 主题,在这一集里,我们和 Andy McMahon 谈论了你的第一个 MLOps 系统。

你可以在 YouTube 上观看:

https://web.archive.org/web/20230106143950if_/https://www.youtube.com/embed/fge5I_SZu5Y?feature=oembed

视频

或者作为播客在以下位置收听:

但如果你更喜欢书面版本,这里有!

您将了解到:

1 什么是 MLOps 系统?

  • 好的 MLOps 系统是什么样的?

  • 3 如何实现?

  • 4 如何扩展 MLOps 系统?

  • 5 还有更多!

  • Sabine: 今天,我们尊贵的客人 Andy McMahon 加入了我们,我们的主题是“您的第一个 MLOps 系统”。好是什么样子的?”安迪,欢迎来到节目。

安迪·麦克马洪:非常感谢你邀请我。

安迪,你有一些有趣的教育背景。材料模拟科学硕士和物理学博士,然后你更多地进入了机器学习领域。你在数据科学和 ML 工程方面有很多经验。目前,你是银行和保险控股公司 NatWest Group 的机器学习工程主管。你还出版了一本名为《用 Python 实现机器学习工程》的书,你正在做一个名为“AI Right”的播客。在机器学习领域,你还有什么没有做的吗?

安迪:谢谢。睡觉是主要的。

什么是 MLOps 系统?

萨宾:很公平。我们真的希望你时不时能休息一下。好吧,让你先暖和一下,安迪,你能在一分钟内向我们解释一下 MLOps 系统吗?我们会给你计时。

Andy: 对我来说,MLOps 系统是一种软件解决方案,基本上可以让你对机器学习产品进行良好的操作实践。从某种意义上说,这意味着构建 ML 解决方案:

Andy: To me, MLOps Systems are software solutions that basically allow you to do good operational practices for machine learning products. What that means, in a sense, is building ML solutions that are:

1 可重复使用,

  • 2 可扩展,

  • 3 且可重现。

  • 其中包含几个不同的子实践,其中一些非常重要,特别是对于机器学习软件解决方案,例如:

模型监控,

  • 你如何知道你的机器学习模型在适当的性能标准下运行?
  • 你是如何重新训练的?
  • 你如何触发再训练?
  • 你多久再培训一次?
  • 你安排了吗?
  • 等等。
  • 然后你还有模型管理实践。您需要跟踪和管理与您的模型工件相关联的元数据,并确保它们被清楚地标记和表达。然后,所有这些都必须汇集在一套可持续的实践和流程中,这些实践和流程有一条非常清晰的生活路线,这样你就可以将机器学习模型从构思到生产。对我来说,这就是 T2 的 MLOps T3 系统。

萨宾:优秀。这仅仅是一分钟的几秒钟,它被很好地封装了。干得好。

好的 MLOps 系统是什么样子的?

斯蒂芬:我也喜欢以试图理解什么是好看作为开场白,因为我认为这是我们在标题中强调的关键内容之一。什么是好的 MLOps 系统?尤其是当你第一次尝试构建它的时候。让我们从那里开始。

安迪:我认为最重要的是确保它能让你的生活变得更轻松。

作为一个社区,我们能做的最糟糕的事情就是构建 MLOps 系统和解决方案,因为我们觉得我们必须这样做。仅仅因为它是最新的时尚或最新的趋势,我就应该整合 MLOps 工具或构建我自己的 MLOps 流程。不是这样的。你需要明白,我们正在从根本上解决一系列特定的问题。

我认为,当你觉得你的 MLOps 系统和解决方案让你作为一名数据科学家或 ML 工程师的生活变得更加轻松时,才是好的。我想,通过聊天,我们将经历我可以经历的迭代,以及如何从小规模开始并扩大规模。

从根本上来说,对我来说,如果这能让你的生活变得更轻松,你就做得很好。这可以以多种方式表现出来,你可以深入其中,但这可能只是开发者体验更容易,但你也可以看到像 DevOps 世界的 DORA metrics 这样的东西的上升。

Fundamentally for me, you’re doing this well if it’s making your life easier. That can manifest in multiple ways, which you can dive into, but it could just be a developer experience is easier, but also you see an uptick in things like the DORA metrics from the DevOps world.

你的生存时间在减少吗?

  • 2 现场部署的数量是否在减少?

  • 3 总体性能是否在提升?

  • 这些东西不仅让你的生活更轻松,也让你的顾客生活更轻松。对我来说,好看起来像是帮助你更可重复和可扩展地做 ML 的东西,但也最终以积极的方式影响你的客户。

如何建立一个好的 MLOps 系统?

斯蒂芬:太好了。建立一个好的系统需要什么?至少在高层次上。

安迪:我认为你需要把问题分解成各个组成部分。我之前提到过一些,但是我认为你的第一个系统应该总是相对初级的我非常相信自我提升你的能力,正如我所说。我过去曾谈到过这一点,所以你不应该带着这样的想法来考虑这个问题,我想解决我在电话会议开始时提到的所有问题,因为你会这样做五年,到那时,你的业务问题就消失了,你的客户群也消失了。作为一个团队、一个团队、一名数据科学家和一个组织,你必须选择对我来说最紧迫的痛点,并首先抓住它,这一点非常重要。

在我看来,你最初的 MLOps 系统应该总是做最基本的事情,首先是和 实验跟踪 。当你建立模型的时候,你需要有某种方式来理解你已经运行的实验。有大量的工具可以做到这一点,我们可以稍后再讨论具体的工具,但你需要真正有一种方法来跟踪你得到的不同实验。

然后你需要有一种方法来跟踪,正如我之前提到的,你通过那些过程生成的模型工件。你不只是想运行一千个实验,尝试不同的超参数。你还需要说,这是最好的模型,我如何将它存储在目标中的某个地方,以便以后可以使用它?

然后,您需要有一种方法来监控您的 ML 解决方案。你需要开始思考,我怎么知道什么时候性能在漂移?对我来说,性能漂移是什么样的?这可以是非常基本的,也可以是非常基本的,您定义一个您认为最重要的性能指标,然后定义一些预定的东西,获取相关数据,对其进行简单的查询,然后输出到某个文件。那就是你还在做 MLOps,这不是世界上最复杂的方法,但是对于零版本已经足够好了。

然后,我认为你需要从根本上思考,你需要发展什么样的实践来继续在此基础上发展。你的团队中有合适的软件工程能力吗?你对集成点等等有正确的理解吗?我认为你应该从小处着手,然后不断迭代。同样,您应该看到在您的旅程开始时您希望代表的那些不同指标的上升。

ML 系统和 MLOps 系统的区别

Stephen: 我所说的 ML 系统和 MLOps 系统有什么明显的区别吗?因为我认为我只是想在那里部署一些东西。我没有想到任何实验跟踪之类的东西,我只是想在那里放一个模型。也许你可以给它一个清晰的区分。

安迪:当然,实际上,我认为这是一个很好的问题。

你可以将机器学习模型投入生产或构建一个解决方案,并认为你没有做 MLOps,但实际上,你只是做得很差。

我的意思是,你建立你的模型,你在一个管道中加速,你以某种方式运行管道,如果你没有对你的实验进行任何跟踪,没有对模型工件进行任何跟踪,如果你没有监控最终结果,你几乎没有进行 MLOps,但你正在进行的 MLOps 只是最基本的可能,这是我假设一切操作都正常的地方。就像是 MLOps 版。

我认为这是非常重要的,任何解决我主要任务的 ML 解决方案都必须包含一些 MLOps 的元素。现在你是否把它分解成一个不同的系统是一个有趣的问题。

对我来说,MLOps 比我所知道的更宽泛,因为我们今晚关注的是系统,但它也是一套整体实践和正确看待世界的方式。这就像 DevOps 是软件工程,它只是关于理解你正在构建的解决方案不会只是被构建,然后你可以忘记它。这是一个活生生的东西。

这在 ML 和机器学习中非常特别,显然,我们有再培训的要求,等等。你可以将它分成不同的系统,并在你的 ML 解决方案中的多个地方进行挂钩,但对我来说,MLOps 实践应该嵌入到你作为 ML 从业者所做的事情中。那么这只是一个针对特定组织、团队等的问题,无论它是独立的系统,还是嵌入到您正在使用的工具中。

如何扩展 MLOps 系统

斯蒂芬:我认为我们现在已经有了明确的区分。你谈到了非常基础的 0.00 版本。你如何区分非常基本的 V0 和 V1?我们如何开始认为我们处于 V0,这与搬到 V2 V1 有什么不同,然后开始迭代前进?

安迪:你正在解决的任何问题都会在某些方面优于其他方面。你只有有限的时间、精力和努力去消耗。

在我看来,零版本在某种意义上可能会降低可重复性和可伸缩性,只是为了理解基本原则和真正从头到尾经历整个过程而进行优化。

我经常想,在我建立或工作过的任何团队中,我们遇到的第一个问题,你们所有人可能都会有同感。当我回头看的时候,这并不好,但重点是第一次经历了那个过程。在 MLOps 中,这意味着只是在某个地方做一些基本的模型导出,并以任何方式解决问题。同样,它可能非常简单,但它仅仅是告诉您模型版本的 pickle 或 joblibfile 的名称吗?这很可能是零版本,因为您第一次优化的是整个端到端流程的样子。

对我来说,版本 1、2、3 等等就是开始向另一个方向发展,提升质量、可重复性和可伸缩性。这取决于您和您的特定用例,您首先优化哪个。我认为,只要你能尽可能地使它简单,在所有这些方面都会有帮助。如果您正在构建的代码是模块化的,如果您正在构建的系统引用了良好的架构模式,如果一切都非常独特,并且体现了关注点的分离,这通常是一个好的迹象。一旦你到了最复杂的版本 N,这里 N 是相当大的,我会说你很容易从一个用例扩展到 1000 个用例。

可能有些问题需要解决。也许您必须为与您相关的基础架构买单,但是您知道您已经实施的流程和工具集是可以这样扩展的。这就是我在 NatWest 所处的阶段,因为我们已经以这种方式建立了我们的 MLOps 能力..我想说的是,零版本是关于优化的,只是理解过程,建立最初的原则,并学习很多。版本 1、2 和 3 就是在此基础上进行迭代,构建更具可重复性的东西。

小型团队在构建 MLOps 系统时应该优先考虑什么?

我认为这个播客非常关注的一件事是合理规模的团队。在《T4》第二集中,我们与雅格布进行了通话,我认为这是类似的,我们讨论的很多事情都是在构建,只是从小处着手,推出一些解决问题的东西,然后不断迭代。

在你看来,如果我们正在寻找一个有六个人的团队,可能有两个数据科学家,三个数据科学家,一个运营工程师,然后他们只有,比如说,三个、四个或几个生产模型。他们正在建造起动器。

你对这样的团队有什么建议?首先考虑这个问题,然后考虑他们需要首先设置哪些组件,以确保他们在开始考虑“哦,我想建立一个更大的平台,容纳大量模型并扩大规模”之类的事情之前,能够立即获得投资回报。

安迪:几年前,我实际上也遇到过类似的情况。当我开始的时候,我在一个 12 人的规模上。我是数据科学和机器学习的负责人,这意味着我只负责自己,因为我是唯一的数据科学家。非常相似的场景,资源非常有限,有几个软件工程师可以帮忙。我认为,在这种情况下,你必须认真考虑如何不重新发明轮子。我提到用非常基本的方式做事。令人欣慰的是,现在有这么多的工具和软件包,你可以用最基本的方式做事情,因为你可能没有解决所有你知道会遇到的扩展问题,但你至少可以利用现有的东西。

Python 中有很多很棒的包,有很多很棒的工具,它们都有开源或免费增值模式,至少你可以从那里开始。我建议您进行研究,了解哪些可以利用,哪些可以使用,这意味着您可以建立一个最小的工作区集,尽可能地利用它。回到我们已经提到的一些东西,也要保持简单。我相信这也适用于 ML 模型开发,总是从最简单的情况开始。如果能用线性回归解决,就不要去找神经网络。

同样的事情也适用于 MLOps 系统。如果您可以通过 cron 作业和 Python 脚本来解决它,那么首先执行 cron 作业和 Python 脚本,然后开始探测它,在后面的迭代中理解它。"为什么会倒下,或者克朗不是很稳定?"“它有一些问题,我应该走这条路。”也许转向更复杂的编排部分,或者你想解决的问题的特定部分。

这里没有提到的一点是,我认为任何这种规模的 ML 团队都必须提前真正关注数据质量,因为这与 MLOps 挑战密切相关。如果你的数据质量很差,无论你的 ML 工程师和 AI 工程师有多好,你的表现都会很差。你会引发一些事件。你要一直重新训练和调试这个模型。

当你那么小的时候,那不是你能做的事情。你不能把所有的时间都花在这些即时管理问题上。

我认为确保前期的数据质量是非常重要的,我认为这适用于任何技能,尤其是当你很小并且资源非常有限的时候。

Stephen: 我很想放大一下你在 NatWest 之前的早期经历。您典型的基线工具堆栈是什么?你是在第一手思考这个问题,然后你只是想把几件事联系起来。一般来说,你真正优先考虑的组件是什么?当团队考虑他们需要为他们的第一个 MLOps 系统组装的组件时,是否存在隐藏的盲点?

安迪:问得好。我认为在这个领域,我们经常会被最闪亮的工具所吸引,这些工具似乎有最漂亮的视频或非常酷的演示和酷的用户界面。这有时掩盖了你提到的更基本的事情的重要性。对我来说,我经常遇到的一个大问题是。如果你有一个非常干净的编排层,一个非常简化的编排层,并且 Apache Airflow 特别适合这个。在我的书中,我谈到了 Apache Airflow 的管理工作流,这是 AWS 管理的服务。

如果您有了流程编排层,并且您可以安排您的管道并创建将触发其他流程的流程,那么您就可以非常快速地开始构建非常复杂的东西。即使你没有一个具有惊人的偏好或可解释工具集或惊人的模型监控能力的工具,你也可以做我之前提到的事情,运行基本的 Python 脚本。像气流,一个非常好的编排层,意味着你仍然在一个非常坚实的基础上做这件事。

最终,您可以用一个非常漂亮的 ML 工具替换一个简单的 Python 脚本。我认为我的基线工具堆栈是为了解决您的编排问题,然后为我解决我提到的几乎其他两个问题,模型管理和模型监控问题真的很重要。还是那句话,从小处着手,先从简单的 Python 脚本开始。我认为,一个非常重要的盲点是,做模型管理有多复杂。像 MLflow、 彗星这样的东西,以及许多其他工具,正在解决一个非常尖锐的问题。你越快使用这样的东西,我想你会发现它让你的生活变得容易多了。

深入探究海王星和彗星以及海王星和 MLflow 的区别。

在我开始监控之前,我几乎要去追模特经理了。对我来说,想象如何编写一些监控逻辑和普通 Python 要比构建一个模型管理软件容易得多。那是一个非常复杂的问题。在我之前工作过的团队中,这对我们来说总是一个挑战,因为我们没有现成的工具。我们花了很多时间来构建这些可怕的 JSONs,它们跟踪我们的模型工件在哪里,以及我们使用了哪些数据。我的感觉是,如果我们可以进行编排,然后对模型管理进行排序,那么你可以在第一个实例中用一个普通的 Python 来做所有其他的事情。然后你可以在此基础上尽你所能。

解决购买与建造的困境

Stephen: 我认为大多数团队的现实是,他们可能会雇佣一名数据科学家或一名 ML 工程师来击败整个系统。我们在社区中有这样的观点,平台是不够的。你有声称能够解决端到端问题的平台,等等,然后你发现它缺乏灵活性。你反对购买平台作为一个系统或什么的吗,特别是对于早期阶段的团队?

安迪:我喜欢这个问题,因为这是一个永恒的争论。我想这与我所说的关于闪亮的新工具和我们有时的固恋有关。

我认为工具、平台、SaaS、平台即服务,所有这些解决方案只有在你首先知道自己在做什么的情况下才会有所帮助。如果你订阅了一个银弹方法,你认为,“你知道吗,我买这个东西,我花了一百万美元,”或者我是一个小得多的公司,几千美元或什么,“我会买这个工具来解决问题。”你会发现你正面临着同样的挑战,但现在在一个闪亮的用户界面前,你正在烧钱。

回到我们之前提到的那一点,我更愿意团队自己去构建他们所能构建的东西,除了编排部分和模型管理部分。有很多开源工具可以做到这一点。有很多开源工具可以帮助你做这些事情。所以,我会说,看看你能从开源工具中得到什么。还有很棒的开源工具,用于构建 ML 和 MLOps 管道。

如果你能达到这样一个阶段,你会说,“实际上,我们迫切需要别的东西”,那么就投资这些钱。如果你本末倒置的话,你只会浪费很多钱,并且非常失望,因为你没有解决根本问题。基本问题通常更多地是特定于过程和特定于架构设计的,而不是什么是最好的工具。你总是可以在工具上多花些钱,但是如果你没有把它们很好地组合在一起,我想你会遇到麻烦的。

如何在做前期团队的同时,做好一个 MLOps 系统?

Stephen: 是的,说到流程,你认为有哪些实践可以让这些早期团队正确地考虑这些系统,并正确地实施它们?

我在 MLOps 社区观看了你的一个播客,在那里,你谈到了想法和生产之间的鸿沟,在这中间,你有这个桥梁,这个需要填补的鸿沟。我认为除了你所说的工具之外,还有一些实践可以让事情运转起来。有些,比如文化,你可以把它看作一个团队,试着正确地思考更多的系统。当考虑系统时,你认为团队应该在早期阶段开始考虑哪些实践?

安迪:我很高兴有人看了那个播客。我经常提到的是我所说的四个 P:

Andy: I’m glad someone watched that podcast. The thing that I often come back to is what I call the four P’s:

1 人,

  • 2 流程,

  • 3 图样,

  • 4 产品。

  • 只是很快地覆盖它们。我认为你永远不能太早考虑这个问题。

方面,我们之前提到过,我们应该避免认为有一个独角兽可以做我们需要的一切。我们需要混合团队,拥有互补能力的混合团队。你可以用任何技巧做到这一点。只要你有两个人,甚至三个人,你仍然可以得到软件、工程知识、ML 知识的混合,然后可能是中间的东西,或者是面向业务的翻译层,等等。人是其中非常重要的一部分。你手下的人都是些什么人,他们是否互补,配合默契?

产品实际上是整个播客的内容,确保你明白你正在构建最终会影响客户的密集系统,你将如何看待这一点,而不仅仅是一段普通的原型代码?嗯,你了解产品,人们希望它们有用。这意味着你应该做大量的测试。你有合适的测试流程吗?你已经在考虑单元测试、集成测试或者回归测试了吗?如果你不是,那就开始考虑它们,因为这是构建可伸缩和可用产品的唯一方法。

然后还要考虑用户体验。在这种情况下,用户可能不是一个真实的人,而是另一个系统。在那里,他们有一个清晰的界面和清晰的消费契约。可能很简单,其他系统可以访问同一个 S3 桶吗,或者是通过结果完成的?这是你有时在产品领域必须考虑的事情,但接下来是你关于过程和模式的特殊问题,我认为这是真正相关的。

模式,对我来说,是关于你是否使用真正众所周知的架构模式,或至少有意义的模式,使用微服务架构,或使用已经存在并被一些最好的公司使用的架构?

那么在流程方面,有没有更清晰的开发护栏?你知道如何开发高质量的代码吗?你至少知道如何提高代码的质量吧?你能做任何能自动化的事情吗?越早嵌入 CI/CD 实践。我认为任何事情, GitHub actions 都是一个很好的例子, Jen kins,以及所有这些其他工具都可以让 CI/CD 服务器就位,这意味着这个过程可以越来越快。

我认为你越早考虑所有这些事情,你就会开始做正确的事情,然后为未来做好准备。当你在诸如账户安全、网络等大规模结构的问题上面临更多挑战时,这可能会晚一点。

对我来说,这四个 P 是任何团队都应该考虑的基本要素,但我认为它与 ML 和 MLOps 团队尤其相关,即人员、模式、流程和产品观点。

构建 MLOps 系统所需的技能

Stephen: 我认为如果你和团队讨论这个问题,大多数团队都会同意这真的很难,只是将这四个 P 联系在一起,只是试图围绕人、过程、产品和模式本身进行协调。你认为团队如何恰当地实现这一点?一个很好的后续问题是,我应该雇用谁来建立这个系统,我的第一个 MLOps 系统?我应该雇佣一个数据科学家或者 MLOps 工程师或者 ML 工程师之类的人吗?

安迪:很好。就你应该先雇佣谁、挑战有多大而言,这是个棘手的问题。如果你要雇佣一个人,你已经有了独角兽思维,我认为我们应该避免这种思维。如果你雇佣两个人,这是我一直推荐的,一个最小可行的团队,至少,我认为你需要一个有良好数据工程思维的人。我提到过,数据超级重要。

然后可能是数据科学家、ML 工程师、MLOps 工程师,他们如何称呼自己并不重要,但我认为是用流水线的知识来补充数据知识的人。如何构建 ML 管道?如何构建 MLOps 管道?我们指的是我们之前提到的所有事情,一些运行到一些监控中的事情,一些检查要构建什么模型版本的事情,但是这将需要一些基本的事情。

他们需要理解模型,甚至可能构建这些模型或使用现成的模型。即使是一名 ML 工程师,但他们正在重用拥抱脸模型,这也绝对没问题,但需要有人理解模型,因为你如何才能建立背后的监控逻辑,并了解你正在做什么与模型工件管理。

他们还需要有足够的软件工程能力,这样他们就可以开始构建这些健壮可靠的系统。这就是 Ops 和 MLOps 的全部意义所在,你不只是在做昙花一现的事情,你是在构建一些必须一次又一次工作的东西。你真的需要软件工程能力。我想,他们怎么协调呢?也就是说,这总是一个挑战,但我认为把它分成这四个 P 帮助我经常合理化它,并且总是分解问题。

从人的角度来看,我们刚刚讨论了我们已经得到了补充能力、掩护、关键事物和模式。再次强调,利用现有资源,不要重新发明轮子。AWS 有他们的架构透镜框架,我想它叫做 AWS 透镜,在那里他们发布了许多非常详细的架构。即使您不在 AWS 上,您至少可以看到它们,看到不同的组件以及它们如何相互作用。这与模式不符。

产品实际上是最终目标,不断地朝着业务目标迭代,但总是考虑可靠性和健壮性,而不仅仅是违反测试。然后,就过程而言,又回到了从小处开始迭代的那一点。经历第一个周期,不断迭代工作,你就进步了。许多这些问题不会是新的问题,在软件工程中会有解决的问题。也利用软件开发和软件工程生态系统。

简单操作是正确的第一步吗?

Stephen: 这是 MLOps 社区中非常流行的东西,事情是保持第一个模型简单,或者您应该尝试获得正确的基础架构,特别是当您尝试部署您的第一个模型或只是部署您的第一个迭代时。你能详细解释一下这个特别的陈述吗?

安迪:是的,当然。我 100%同意这一点,我们应该总是开始简单的行动。我之前可能提到过,仅仅做一些基于研究的数据科学和机器学习与构建一个以 MLOps 为核心的产品之间的关键区别在于,你认为它必须一次又一次地工作。

你的简单 sklearn 模型做一些回归,你可以拿其中一个,波士顿住房数据集,这是一件非常简单的事情,有很多关于它的教程。构建 ML 模型非常简单。困难的是,如果你开始说这样的事情可能是特定于业务用例的,但我如何满足跨 5 万或 10 万用户的评分请求?我该如何运行它,也许是作为一个批处理,也许是作为一个 API 可以请求的实时微服务?

我认为所有这些都可能会受到你所经营的企业的影响。

如果您知道您正在支持一个面向客户的 web 应用程序,您可能会自然而然地选择 REST API 微服务路线。

  1. 如果您正在为一个非常大的组织提供服务,就像我们经常做的那样,有许多通宵流程,您可能会更多地以批处理方式思考,并考虑使用更具可扩展性的技术,如 PySpark 等。
  2. 只需规划出您的业务挑战,然后自动开始帮助您做出架构和设计决策。

然后模型部分又变成了你可以不断重复的东西,但是从根本上说,与你必须做出的其他选择相比,它可能相对简单。然后你开始思考,“对,我如何以最小可行的产品方式设置它?我如何将所有这些信息反馈给管弦乐队,并确保它们在正确的时间运行,等等?”当然,我同意这一点,而且我认为总是要回到你试图解决的业务问题上来。

这也推动了您的运营考虑以及 MLOps 对您的影响。

同样,如果您每天晚上都在运行一个大的批处理过程,您真的需要为您的模型提供某种复杂的实时度量流吗?不,那太过分了。你可能只需要一份在批量生产后运行的夜间报告。

  1. 如果你正在做一个非常可扩展的、面向客户的应用,如果你确实需要更多的实时指标,你可能还需要恢复并了解一些指标,或者只是 DevOps 的经典指标,内存、CPU 利用率,所有这些东西,而不仅仅是我的模型的回忆。
  2. 然后,我想到了另一个挑战,我认为这也很重要,它来自业务问题,即您还能够以不同的方式对这些流程进行约束。我经常遇到的一件事是,一旦企业明白了你想用 MLOps 做什么,他们通常会说,“对。我想知道模特每天过得怎么样。”我会说,“对。我多久能得到这个模型的真实数据,”他们会说每个月。自动地,在业务、技术以及如何一起实现它们之间存在脱节。只是总是回到业务问题真的有助于磨练这一点,并了解你需要做出什么选择。

打破关于 MLOps 系统的神话

Stephen: 很好奇,MLOps 社区中有没有你不认同的关于 MLOps 系统的误解?让我们把它扔出去。

安迪:哦,那我不同意?我认为对工具的痴迷让我有点恼火。我认为,作为一个团体,我们确实忘记了好的设计、好的过程以及好的软件开发技术的重要性。我们经常沉迷于最新的演示和最新的重大公告,我也是如此。我将报名参加大约 10 场网络研讨会,我将永远不会参加所有这些不同的技术,因为有一个新的发布或新的版本,但我认为我们经常忘记我们试图在 MLOps 中解决的问题是多么简单。

在我看来,你在建的管道只有几种,

To my mind, there are only a few different pipelines you’re building,

1 你正在建立你的培训渠道,以便进入模型。

  • 你正在构建推理管道来得出结果。

  • 3 然后你构建一个 MLOps 类型的链接来完成其他部分。

  • 根本上就是这样。我想我有时不喜欢我们过分夸大特定工具选择的重要性。

随着旅程的进行,您应该非常乐意交换工具,因为它们解决问题的方式略有不同。

您的模型管理软件从开源版本开始,然后您说,“实际上,我希望获得企业级支持的好处,所以我将切换到这个提供商的付费模型,”但它不应该从根本上改变您的设计。如果您的设计与您的工具选择紧密结合,我认为您犯了一个巨大的错误,因为它实际上应该是一个交换。你只是做了一个不同的 API 调用,或者你只是写了一个不同的位置。

你不应该如此依赖一个产品,以至于遭受锁定,这也是你可能遇到的其他危险之一。无论是云提供商还是特定的工具,你都可以变得如此执着于它,以至于当你因为公司破产或工具因为重大升级而不再可用而不得不改变时,你必须修复如此多的技术深度。

我认为对我来说最大的困扰是对工具的痴迷。我可能太苛刻了,我认识的社区中有很多人都在使用非常棒的工具,也有很多非常棒的工具,尤其是在开源社区。

我只是认为,作为试图为组织构建这些解决方案的实践者,我们不应该只是认为有一个银弹就在那里。我们真的需要让它回到基础,而我们需要开发的流程,我们如何确保它们是强健的和受监控的,然后我们有良好的衡量它们性能的指标,然后只是针对这些指标工作。

MLOps 在扩展系统中的作用

Stephen: 我们有一个来自 MLOps 社区的问题。这个人说,“我正致力于建立一个餐厅推荐系统,它提供两个人口味之间的餐厅业务相似性。我计划将其部署为一个 web 应用程序。知道我将把它扩展到 50 个或更多的用户,我该如何着手呢?那么 MLOps 是如何进入这一特定场景的呢?”

Andy: 这听起来像是这个人在思考一个非常特别的用例,这个用例非常适合将它变成现实。如果你正在构建一个拥有 50 或 50,000 用户的 web 应用,你必须在后台运行这个 ML 过程,这个推荐引擎。对我来说,开始时最重要的是不要把所有这些都放在脑子里,因为你会有点不知所措,你可能会试图一次性解决所有问题,并创建一些意大利面条式的代码或一些不是很模块化的东西。

如果你把所有这些碎片分离出来,你就可以开始分解问题并理解如何解决每一个。前端,对,你如何将前端扩展到 50,000 个用户?这是一直在做的事情,所以上网看看一般的 web 应用程序是怎么做的,这不是什么新鲜事。您有前端系统,您有存储运行实际 web 界面所需的正确数据的应用程序数据库。考虑用户体验,如果可能的话,在适当的地方进行好的 UX 设计。这是一个已经解决的问题,但这只是第一部分,这只是解决方案其余部分的切入点。

然后你必须运行你的推荐引擎更新,你的再培训,你的重新运行,我根本不是一个推荐引擎专家。我就假设这是某种意义上的黑盒。从根本上说,你需要运行一个非常大规模的过程,这个过程通常计算量非常大。把那个放在一边。

您如何解决这个问题,您多久运行一次这些更新?

  • 您是否拥有所需的基础设施?
  • 您是否需要考虑自动缩放以获得特别大的数据或计算更新等等?
  • 为了回答这些问题,您需要考虑迁移到云吗?
  • 我认为你认为推荐引擎更新是一个独立的过程,并把它分开。

然后你就有了两者之间的互动。这是我喜欢谈论的接口和契约。

你的前端和你的推荐引擎之间的合同是什么?

  • 是对一些基本 Flask 应用程序的直接 API 调用,还是只是呈现推荐引擎的结果?
  • 会不会更复杂一点?
  • 推荐引擎真的可以在批量离线模式下工作,而 web 应用程序只需要从某个 S3 桶或其他位置获取结果吗?
  • 那么,MLOps 真正要做的是确保从 ML 的角度来看,所有的东西都结合在一起。推荐引擎,

你怎么知道那是表演?

  • 你将如何检查它的状态?
  • 然后你会根据它采取什么行动——这就是你的模型监控过程?
  • 如果这是一个夜间批处理过程,那么多久运行一次呢?
  • 您是否每天晚上都运行 MLOps 管道来检查监控性能,或者您是否减少了运行频率?
  • 您如何管理推荐引擎的实际版本,因为如果出现问题,您可能希望进行回滚?你也开始思考这个问题。
  • 最后,我认为在这种情况下,编排再次进入,关于它的决定是一个触发 ML 过程的动态请求。在这种情况下,你会想到事件驱动架构,如卡夫卡酒馆/订阅架构。这真的是关于检索用户请求的结果吗?这是一个批处理调度,在这种情况下,您可以执行 cron 作业或其他调度程序,或者回到 Apache Airflow,我前面提到过。

我认为关键的事情是把它分解成那些组成部分,然后想出如何单独解决这些问题。那么哪些是你不确定如何解决的最紧迫的问题,去获得结果,并帮助你理解它。

对我来说,最让我不舒服的是前端。我没有 UX 技能,也不知道如何建立一个好的前端,所以我需要帮助。其他部分,我可能知道。MLOps 实际上是管理后端,并确保对其进行监控、管理,然后在必要时进行适当的再培训。

为未来的可扩展性打下坚实的基础

Stephen: 是的,接着这个特别的问题,我认为当你构建第一个 ML 系统时,例如,一个挑战是当你想要扩展时,它真的会崩溃。尤其是如果你不考虑这个规模,你的系统就会崩溃。也许你正在运行一个 cron 作业和一个 Python 脚本,然后你不知道如何处理 50k、100k 请求,因为突然之间,业务增长了。当构建一个良好的第一个 MLOps 系统时,您如何开始考虑可伸缩性?

安迪:你可以早点做出一些选择来帮助解决这些事情。如果您的问题适合您,比方说批处理类型架构,或者至少批处理的某些元素,例如,围绕 PySpark 构建一切,这意味着可伸缩性实际上是您愿意为基础架构支付多少费用的问题。

我将回到 AWS,因为它是我最熟悉的,但它也适用于其他云提供商。如果我使用他们自己的云智能集群, Elastic Map 减少了集群,您可以开始加入自动扩展策略等内容,并在需要时扩展基础架构,并且您的代码的基础不需要更改。我认为这是您可以尽早做出的决定,因为我可以在我的笔记本电脑上运行 PySpark,它可能没有多大用处,它是一个非常小的集群,但如果我有能力支付费用,我也可以在一个 10,000 节点的集群上运行它,所以即使这样的选择。

如果你更多地考虑我们之前讨论过的微服务架构,你会开始考虑负载平衡器之类的东西。

您开始引入负载平衡器了吗?

  • 你有这方面的专业知识吗?
  • 你知道如何恰当地写这种流量,网络,以及由此产生的问题吗?
  • 那么,您是否能够生成运行您的 ML 模型所需的流程?
  • 然后,我会开始利用像云函数或 Lambda 这样的东西,因为它在 AWS 中,所以非常轻量级的代码片段,您可以以非常可扩展的方式运行,而您不必考虑底层基础架构。

我认为总的来说,云只是有助于提高可扩展性,你需要为每单位支付一点额外费用,但你晚上会睡得更好,因为你知道在那里扩展要容易得多。我总是建议您至少探索和理解云中可用的选项。然后,如果您正在以一种更本地的方式进行构建,您至少知道您是否知道您可以移植到云。

PySpark 就是一个很好的例子。即使我在我的笔记本电脑上运行,但是在 PySpark 中构建所有东西,然后移植到一个非常可扩展的云服务,这并不是一件大事。然而,如果我用普通 Python 和串行 Python 写了所有的东西,然后我不得不为了可伸缩性而进行重构,这将是一件大事。我认为,在这个过程的早期,你可以做出一些选择和思考,这会有所帮助。

整个项目的时间表和管理期望

Sabine: 我们有一个来自佩妮·约翰逊的聊天问题。Penny 问道:“您能就该领域中从模型构思到解决方案交付、监控周期和改进的实际时间表给出见解吗?此外,您如何管理这些方面的业务预期?”

安迪:哦,好问题。这就是我的工作。我担心这个。实际上,我刚刚结束了一场网络研讨会,内容是我们在以这种方式缩短价值实现时间方面所做的工作,所以我现在可以提到一些数字和事情,因为它们属于公共领域。

通常对我们来说,在我们采用一些关于工具的基本实践之前,我们有一个发现,一个是关于云的。我们花了大约一年的时间将一个模型从构思到生产。现在,这是很长的时间,对我们来说,最大的因素是在金融服务领域,有很多治理和所有我们必须经历的事情。

在我以前的工作中,我们大概每个季度都要交付一个模型,我认为这更可行,因为每隔几个月就要将一些东西从构思阶段转化为生产阶段。Penny,如果你谈论的是模型的迭代改进,而不是全面的改进,我认为你是在问白板到解决方案,我认为,如果你有良好的 CI/CD 实践,迭代改进可以是冲刺或次冲刺水平。

我们现在已经能够在 NatWest 将任何特定团队的时间缩短到大约三个月,即每季度一次,因为我们投入了时间、精力和精力来构建一个使用 SageMaker 和周围生态系统的 MLOps 平台。那是回到我以前提到的事情的一个例子。我们首先了解如何做好流程,然后我们了解基本原理以及好的设计是什么样的。我们升级了所有的东西,并且能够重构所有的内部流程。

我想说,对我来说,一季度一次对于大多数规模的组织来说是合理的。规模因素适用于较大的组织,因为他们可以并行执行许多任务,因此,对于较小的公司来说,一个季度一次对于公司来说就意味着一个 ML 模型,对于像 NatWest 这样的大型组织来说,这可能意味着每个季度数百个 ML 模型。MLOps 建筑等等,应该只是这个过程的一部分,所以只要你已经理解、设计、架构到位,你就应该能够把它也纳入到每季度一次的周期中。这只是我的看法。我认为在这个作品中会有一百万种不同的观点。

管理期望是有趣的部分,所以我认为你需要克服一些挑战。

一个是确保你的利益相关者,你的客户,你的同事首先理解机器学习的好处,但他们也理解为什么 MLOps 很重要。使用机器学习算法解决问题是一回事。

  1. 接下来的事情是确保你可以在剩下的时间里每天都解决它,这就是 MLOps 部分的作用。
  2. 您需要赢得人心,以便他们理解您为什么要投入时间、精力、精力和金钱来开发这些额外的解决方案、监控功能、模型管理部分等等。我觉得你真的需要这么做。然后,他们会明白你为什么要在这些额外的部分上投资,但同样,这归结为简化,确保他们理解你正在做的事情的基础,你不断更新他们,并确保他们理解你何时遇到问题以及瓶颈在哪里。这意味着您可以在下一组项目中重复使用它。

我不得不这样做很多次,我们认为我们可以在三个月内交付,但实际上要花更长的时间。只要你清楚地与你的利益相关者沟通,他们就会明白那些期望正在改变,我想他们会接受的。这是一个非常好的问题。我认为最重要的挑战之一是利益相关者管理。

在 MLOps 系统中拟合再训练方案

萨宾:是的,肯定的。这不仅仅是技术层面的问题,有时候,这也是人和沟通等方面的问题。纳比勒·贝尔加斯米还有一个问题。“如果我们希望我们的 ML 模型根据新数据自动重新训练,这一要求对简单的 MLOps 工作流有什么影响?”

安迪:

如果您希望它每次都根据新数据进行训练,首先,您可以挑战这一假设,“我真的需要它每次都根据新数据进行训练,还是只需要它在数据分布发生变化或性能下降时进行训练”。

假设我们已经解决了你的问题,当新的数据进来时,我们想训练模型。对您的 MLOps 流程和系统的下游影响将是,好吧,重新训练模型,但我该怎么做?你用什么流程来确定它是否是进入生产的实际模型?

你不想做的只是自动将其推向生产。这是第一次,因为它可能会被重新训练,这真的很糟糕,很可怕。基本上是绝对的垃圾。你把它推向生产,一切都在下降,所以你需要一些机制来查看新训练的模型的性能,而不仅仅是已经在生产中的模型。这也是模型管理和其他工具发挥作用的地方。您能为培训运行尝试合适的元数据和指标吗?

我认为同样重要的是,如果你正在考虑将一个特定的模型投入生产,“你真的模拟过类似生产的条件吗?您是否有一个测试环境设置,其运行方式与您的生产模型相同?”

实际上,我之前在你的问题中忽略了这一点,Stephen,但是我已经看到了许多带有一组特定假设的开发人员模型。例如,他们有五年的数据。他们已经完成了培训、测试和验证工作。然后他们认为这将在生产中发挥作用,但实际上,在生产中,你每天都会得到一千个新记录,他们不知道行为的波动会是什么样的。我认为你需要确保,如果去 Nabil,重新培训,然后将一个模型推向生产,你有一些可用的测试,显示它将如何对以节奏和频率出现的类似生产的数据起作用。

然后,支持所有这一切,回到之前的流程点,您需要一个良好的 MLOps 流程来说,“这实际上没问题。这符合我们的运营风险状况。这取决于治理控制。”不管机制是什么?你基本上需要一种方式来说,“按下按钮。将其推向生产。”我要说的是,所有这些都必须考虑到你的 MLOps 系统的外观和功能。

这是一个很好的问题。很多人很快就会遇到这种情况,我认为最重要的是在某种类似生产的环境中操作或测试,然后有一个良好的过程来说,“一切正常。我现在可以将它投入生产。”像蓝绿色部署这样的事情,你可能有时会听说,如果你给它一个谷歌,它会告诉你如何基本上并行运行两个解决方案,但其中一个是在一个空气间隙的环境中。然后,一旦你高兴了,就无缝地交换它们。构建这样的流程通常也是非常好的 MLOps 实践。

其他问题

Stephen: 我们还有一个来自 MLOps 社区的问题。这次是杰里米发来的。

杰里米说,他正与一家非常早期的初创公司合作,只有一个模型和相当低的推理量。最好的培训工作是什么?在过去,他将模型包装在 Flask API 中,制作映像,作为 CI/CD 流程的一部分将其推送到 K-cluster。现在,他还有一个气流脚本,每天用生产中的新数据重新训练模型。他会做回归测试,然后触发部署过程。他会有一个数据仓库,在那里保存推理数据,以便能够运行性能查询之类的东西。这对他来说似乎太多了。

他在想,“今天最简单的方法是什么?”有什么东西可以巩固这整个-他非常非常模块化的路径吗?你有什么看法?

安迪:我首先想到的是杰里米似乎知道自己在说什么,这很好。我认为这完美地体现了我之前提到的先学习基础和基本原则。Jeremy 在那里绘制的是所有正确的流程和正确的移交,所以你已经有了模型。这种托管方式如何,在哪些基础设施上运行?这些都是怎么更新的?这就是所有的烧瓶T5、K、 AS,以及 CI/CD。然后,开始考虑气流,他提到了所有关于回归测试的正确词汇,等等。

这个问题是关于你如何简化和改进这个过程。我想说的一件事是看看现有的工具,看看有什么可以帮你解决这些棘手的问题。如果你的推理量特别低,你能把它作为一个容易安排的匹配过程吗?你是否也过度复杂化了现有的工具,这些管道是如何连接在一起的?我不认为他提到了太多,但一个很好的例子是 SageMaker。

AWS SageMaker 是他们的 MLOps 工具,但它也为编写好的管道提供了非常好的、强有力的、固执己见的指导。做类似事情的开源软件是 ZenML 。有很多工具可以简化他正在进行的一些开发活动。

然后,就真正与托管相关的 KAS 集群而言,你可以再次考虑是否你在 SageMaker 上,例如,它会为你处理托管和底层基础设施。您可以制定缩放策略。

有一些解决方案可以为您消除一些痛苦,但听起来他已经准备好了所有正确的部分,现在可能只是转移到我应该投入时间和精力进行优化的特定部分的问题上。

我不确定杰里米可能不在状态,但我不确定具体的痛点在哪里。如果真的要扩展 Flask API,那么放弃 Flask API、SageMaker endpoint 或其他提供类似方法来托管模型的工具可能是个好主意。你能在云函数或 AWS Lambda 中完成这一切吗?实际上,它保留了所有其他部分,但实际上,你已经获得了巨大的可伸缩性,因为它是一个非常简单的 sklearnmodel。你可以很容易地在 AWS Lambda 中托管它。

我认为他必须对他所解决的问题有战略眼光,但是有很多工具和能力会有所帮助。现在他已经有了基本的设计。现在我可以使用工具了,我知道在我使用它之前,但是我认为他已经有了基本的设计。您现在可以迭代并找到将解决其中一些问题的开源和付费工具。

Stephen: 好的,我们还有一个来自 MLOps 社区的问题。这次是 Fatima,她问道:“如果他们想将中小型企业从 0 级 MLOps(这是他们典型的 Google 参考资料)转变为 1 或 2 级 MLOps(例如端到端自动化)等,他们将面临哪些挑战?他们有一个非常基本的手动工作系统,但他们希望移动东西来实现端到端管道的自动化。”

Andy: 我喜欢这个,因为我在工作中引用了相同的成熟度模型,这很好。其中很大一部分是固有的,正如你所说,问题是自动化还是手动,斯蒂芬。对我来说,这是一个编排和 CI/CD 实践的问题。你如何协调你需要的不同过程?我假设你已经通过了零级,并且已经完成了我们之前提到的工作。你第一次从头到尾经历了这些过程,这可能与 Jeremy 的问题相似。原则上,你知道如何解决所有这些问题,现在你要做的是以一种真正可扩展的方式去做。

为了实现自动化,需要以一种非常安全的方式进行协调,即使某个组件出现故障,也可以非常成功地进行监控。所有这些都需要结合起来。然后我很好地回想起 Nabil 之前的问题,你是否开始思考是什么触发了自动化过程,你是如何触发的?这是偏离了卡夫卡的主题,还是偏离了你的监测指标?现在还是手工流程吗?因为你可以自动化很多东西,但仍然有一个手动的人扣动扳机,按下按钮。

有时,如果您对风险和控制治理行为有特定的要求,就像我们在金融服务中做的那样,这是很好的。有时候在这个过程中有个人参与是很重要的。不是完全自动化,但是差不多,我很高兴,目标,然后一切都自动化了。

Fatima,我认为对你来说,关键的事情是那些编排问题、触发问题,以及 CI/CD 问题,它们将帮助你走向一种更连续和自动化的迭代解决方案的方式。

Stephen: 很好,我们还有来自社区的最后一个问题,这个人问道:“在早期构建我的 MLOps 系统时,我应该担心它的可靠性吗?因为我的用例是任务关键型的,所以我目前正在为医疗保健行业构建一个 ML 产品。”

安迪:是的,所以你应该关心你的 MLOps 系统的可靠性吗?绝对是因为如果你没有一个可靠的 MLOps 系统,你怎么知道你有一个可靠的 ML 系统句号?

我认为在这样的任务关键型场景中,我没有在医疗保健行业工作过,但我以前为一家分布式能源提供商工作过,我们在那里建立模型,检测发电机是否着火,所以我也称之为任务关键型。我们发现,再一次,将它拉回到我们想要跟踪的最简单、最基本、最健壮的东西真的很有帮助,因为然后你可以做的是与具有领域知识的人和你的业务同事密切合作,以真正理解我们绝对必须跟踪的一两个指标是什么。

我认为这有助于可靠性,因为你不会建立一个超级复杂的 MLOps 系统,对不对?你不会用 1000 万行代码做 100,000 个不同的度量来构建一个东西。您只需关注一两个对于了解系统是否正常运行以及是否以正确的方式做事至关重要的方面。

那么我认为你需要确保你也在检查那个 MLOps 系统。MLOps 系统是用来监控您的 ML 系统的,但是您如何查看所有东西是如何执行的呢?对我来说,这是拥有 MLOps 系统的自然结果,因为如果您要在仪表板或其他一些查询数据库中查看 MLOps 流程的结果,那么这样做的行为就是检查您的 MLOps 系统是否正常工作。

我认为你应该担心它的可靠性,但帮助你减少担心的主要事情是将它简化为关键指标,KPI 只是构建最基本的可行产品,然后测试它。确保你测试它,直到你用一百万种不同的方法打破它,你很高兴这个最小的可行产品不会打破。我想你可以走了。

萨宾:该收工了。我敢肯定会有更多,我们会喜欢挑选安迪的大脑。非常感谢你,安迪,你真的揭开了 MLOps 的神秘面纱,至少对我来说是这样,非常感谢。

在我们结束之前,安迪,人们怎样才能关注你在网上做的事情,并可能与你联系呢?

安迪:是的,所以你可以在 LinkedIn 上找到我。只要搜索安迪·麦克马洪,你就有希望找出是哪一个。在推特上,我是 @ElectricWeegie 。我也有一个网站,一个博客,我有一段时间没有更新了,这是 electricweegie.com。然后最后可以关注订阅“AI 对吗?”播客,它在 Spotify、Acast 或任何你可以获得播客的地方。

然后你会听到我, Megan Stamper ,他是 BBC 机器学习的负责人之一, Kris McFadyen,他是我非常熟悉的人,他做了很多招聘工作。如果你感兴趣的话,你会听到我们谈论苏格兰技术团队,但是我们也在那里谈论 ML 和 MLOps 中的许多非常酷的东西。那些是找到我的主要地方。

萨宾:对,有很多渠道可以碰到你。我们将在两周后的 8 月 3 日回来,下一次我们的嘉宾将是亚当·斯罗卡,我们将讨论在你的团队中建立一种 MLOps 文化

Sabine: Right, so plenty of channels to run into you. We’ll be back in two weeks on August 3rd, and next time our guest will be Adam Sroka, we’ll be talking about building an MLOps culture on your team.

天然气水合物抑制剂失效模式:如何识别和监控

原文:https://web.archive.org/web/https://neptune.ai/blog/gan-failure-modes

一个生成对抗网络是两个子网络的组合,它们在训练时相互竞争,以便生成真实的数据。发生器网络产生看起来真实的人造数据,而鉴别器网络识别数据是人造的还是真实的。

虽然甘是强大的模型,但他们可能很难训练。我们同时训练发生器和鉴别器,彼此牺牲。这是一个动态系统,只要一个模型的参数被更新,优化问题的性质就会改变,因此,达到收敛可能是困难的。

训练还会导致 GANs 的失败,无法模拟完整的分布,这也被称为模式崩溃

在本文中:

  • 我们将看到如何训练一个稳定的 GAN 模型
  • 然后将试验训练过程以理解模式失败的可能原因。

过去几年我一直在训练 GANs,我观察到,GANs 中常见的故障模式是模式崩溃收敛故障,我们将在本文中讨论。

训练稳定的 GAN 网络

为了理解失败(在训练 GAN 中)是如何发生的,让我们首先训练一个稳定的 GAN 网络。我们将使用 MNIST 数据集,我们的目标是使用生成器网络从随机噪声中生成人工手写数字。

生成器将随机噪声作为输入,输出为 28×28 大小的假手写数字。鉴别器将从生成器和地面实况中获取输入的 28×28 图像,并尝试对它们进行正确分类。

我把学习率 0.0002,adam optimizer,和 0.5 作为 adam optimizer 的动量。

先来看看我们稳定的 GAN 网络的代码。首先,让我们进行所需的导入。

注意,在这个练习中,我们将使用 PyTorch 来训练我们的模型,使用 neptune.ai 的仪表板来进行实验跟踪。这里是我所有实验的链接。我在 colab 和 Neptune 中运行脚本,使得跟踪所有实验变得非常容易。

import torch
import torch.nn as nn
import torchvision.transforms as transforms
import torch.optim as optim
import torchvision.datasets as datasets
import numpy as np
from torchvision.utils import make_grid
from torch.utils.data import DataLoader
from tqdm import tqdm

import neptune.new as neptune
from neptune.new.types import File

在这种情况下,适当的实验跟踪非常重要,因为损失图和中间图像可以很好地帮助识别是否存在故障模式。或者可以使用 matplotlib、神圣TensorBoard 等。也取决于您的使用情况和舒适度。

我们首先初始化 Neptune 的运行,一旦您在 Neptune 仪表板上创建了一个项目,您就可以获得项目路径和 API 令牌

我们将批次大小保持为 1024,我们将运行 100 个时期。潜在维度被初始化以生成用于生成器输入的随机数据。和样本大小将用于推断每个时期的 64 个图像,因此我们可以在每个时期之后可视化图像的质量。k 是我们打算运行 discriminator 的步骤数。

run = neptune.init(
   project="project name",
   api_token="You API token",
)

现在,我们下载 MNIST 数据并创建 Dataloader 对象。

batch_size = 1024
epochs = 100
sample_size = 64
latent_dim = 128
k = 1
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

transform = transforms.Compose([
                               transforms.ToTensor(),
                               transforms.Normalize((0.5,), (0.5,)),
           ])

最后,我们定义了一些用于训练的超参数,并使用 run object 将它们传递给 Neptune 仪表板。

train_data = datasets.MNIST(
   root='../input/data',
   train=True,
   download=True,
   transform=transform
)
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True)

这是我们定义发生器和鉴别器网络的地方。

params = {"learning_rate": 0.0002,
         "optimizer": "Adam",
         "optimizer_betas": (0.5, 0.999),
         "latent_dim": latent_dim}

run["parameters"] = params

发电机网络

发电机模型以潜在空间作为输入,这是一个随机噪声。

  • 在第一层中,我们将潜在空间(维数为 128)转换为 128 个通道的特征空间,每个通道的高度和宽度为 7×7。
  • 在两个反卷积层之后,增加特征空间的高度和宽度。
  • 随后是具有 tanh 激活的卷积层,以生成具有一个通道和 28×28 高度和宽度的图像。
  • 鉴别器网络
class Generator(nn.Module):
   def __init__(self, latent_space):
       super(Generator, self).__init__()
       self.latent_space = latent_space
       self.fcn = nn.Sequential(
           nn.Linear(in_features=self.latent_space, out_features=128*7*7),
           nn.LeakyReLU(0.2),
       )

       self.deconv = nn.Sequential(
           nn.ConvTranspose2d(in_channels=128, out_channels=128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1)),
           nn.LeakyReLU(0.2),

           nn.ConvTranspose2d(in_channels=128, out_channels=128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1)),
           nn.LeakyReLU(0.2),

           nn.Conv2d(in_channels=128, out_channels=1, kernel_size=(3, 3), padding=(1, 1)),
           nn.Tanh()
       )

   def forward(self, x):
       x = self.fcn(x)
       x = x.view(-1, 128, 7, 7)
       x = self.deconv(x)
       return x

我们的鉴别器网络由两个卷积层组成,用于从来自生成器的图像和真实图像中生成特征。

  • 后面是分类器层,通过鉴别器对图像预测是真的还是假的进行分类。
  • 现在我们初始化发生器和鉴别器网络,以及优化器和损失函数。
class Discriminator(nn.Module):
   def __init__(self):
       super(Discriminator, self).__init__()
       self.conv = nn.Sequential(
           nn.Conv2d(in_channels=1, out_channels=64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1)),
           nn.LeakyReLU(0.2),

           nn.Conv2d(in_channels=64, out_channels=64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1)),
           nn.LeakyReLU(0.2)
       )
       self.classifier = nn.Sequential(
           nn.Linear(in_features=3136, out_features=1),
           nn.Sigmoid()
       )

   def forward(self, x):
       x = self.conv(x)
       x = x.view(x.size(0), -1)
       x = self.classifier(x)
       return x

我们有一些辅助函数,为假图像和真图像创建标签(其中 size 是批量大小),还有 create_noise 函数用于生成器输入。

发电机培训功能

generator = Generator(latent_dim).to(device)
discriminator = Discriminator().to(device)

optim_g = optim.Adam(generator.parameters(), lr=0.0002, betas=(0.5, 0.999))
optim_d = optim.Adam(discriminator.parameters(), lr=0.0002, betas=(0.5, 0.999))

criterion = nn.BCELoss()
def label_real(size):
   labels = torch.ones(size, 1)
   return labels.to(device)

def label_fake(size):
   labels = torch.zeros(size, 1)
   return labels.to(device)

def create_noise(sample_size, latent_dim):
   return torch.randn(sample_size, latent_dim).to(device)

现在我们将训练发电机:

生成器接收随机噪声并给出假图像。

  • 这些伪图像然后被发送到鉴别器,现在我们最小化真实标签和鉴别器预测的伪图像之间的损失。
  • 从这个函数中,我们将观察发电机损耗。
  • 鉴别器训练功能
def train_generator(optimizer, data_fake):
   b_size = data_fake.size(0)
   real_label = label_real(b_size)
   optimizer.zero_grad()
   output = discriminator(data_fake)
   loss = criterion(output, real_label)
   loss.backward()
   optimizer.step()
   return loss

我们创建一个函数 train_discriminator:

我们知道,这个网络在训练时从地面真实图像(即真实图像)和生成器网络(即虚假图像)获取输入。

  • 一个接一个,我们通过假的和真的图像,计算损失和反馈。我们将观察到两个鉴别器损耗;实像损失(loss_real)和伪像损失(loss_fake)。
  • 甘模特培训
def train_discriminator(optimizer, data_real, data_fake):
   b_size = data_real.size(0)
   real_label = label_real(b_size)
   fake_label = label_fake(b_size)
   optimizer.zero_grad()
   output_real = discriminator(data_real)
   loss_real = criterion(output_real, real_label)
   output_fake = discriminator(data_fake)
   loss_fake = criterion(output_fake, fake_label)
   loss_real.backward()
   loss_fake.backward()
   optimizer.step()
   return loss_real, loss_fake

现在我们有了所有的函数,让我们来训练我们的模型,并查看观察结果,以确定训练是否稳定。

第一行中的噪声将用于推断每个时期之后的中间图像。我们保持噪声不变,这样我们就可以比较不同时期的图像。

  • 现在,对于每个时期,我们训练鉴别器 k 次(在这种情况下一次为 k=1),每次训练发生器。
  • 所有的损失都被记录下来并发送到 Neptune dashboard 进行绘图。我们不需要将它们添加到列表中,使用 Neptune dashboard 我们可以即时绘制损失图。它还将在. csv 文件中记录每一步的损失。
  • 我已经使用[点]上传功能在 Neptune 元数据中保存了每个纪元后生成的图像。
  • 让我们看看中间的图像。
noise = create_noise(sample_size, latent_dim)
generator.train()
discriminator.train()

for epoch in range(epochs):
   loss_g = 0.0
   loss_d_real = 0.0
   loss_d_fake = 0.0

   for bi, data in tqdm(enumerate(train_loader), total=int(len(train_data) / train_loader.batch_size)):
       image, _ = data
       image = image.to(device)
       b_size = len(image)
       for step in range(k):
           data_fake = generator(create_noise(b_size, latent_dim)).detach()
           data_real = image
           loss_d_fake_real = train_discriminator(optim_d, data_real, data_fake)
           loss_d_real += loss_d_fake_real[0]
           loss_d_fake += loss_d_fake_real[1]
       data_fake = generator(create_noise(b_size, latent_dim))
       loss_g += train_generator(optim_g, data_fake)

   generated_img = generator(noise).cpu().detach()
   generated_img = make_grid(generated_img)
   generated_img = np.moveaxis(generated_img.numpy(), 0, -1)
   run[f'generated_img/{epoch}'].upload(File.as_image(generated_img))
   epoch_loss_g = loss_g / bi
   epoch_loss_d_real = loss_d_real/bi
   epoch_loss_d_fake = loss_d_fake/bi
   run["train/loss_generator"].log(epoch_loss_g)
   run["train/loss_discriminator_real"].log(epoch_loss_d_real)
   run["train/loss_discriminator_fake"].log(epoch_loss_d_fake)

   print(f"Epoch {epoch} of {epochs}")
   print(f"Generator loss: {epoch_loss_g:.8f}, Discriminator loss fake: {epoch_loss_d_fake:.8f}, Discriminator loss real: {epoch_loss_d_real:.8f}")

时代 10

这些是在时期 10 产生的 64 位数字。

Digits generated from a Stable GAN at 10th Epoch

Fig. 1 – Digits generated from a stable GAN at 10th epoch | Source: Author

纪元 100 年

这些是在时段 100 使用相同的噪声生成的。这些看起来比 epoch 10 的图像好得多,在这里我们实际上可以识别不同的数字。我们可以训练更多的时期或调整超参数以获得更好的图像质量。

Digits generated from a stable GAN at the 100th epoch

Fig. 2 – Digits generated from a stable GAN at the 100th epoch | Source: Author

损失图

你可以很容易地进入 Neptune dashboard 中的“Add New Dashboard ”,将不同的亏损图表合并成一个图表。

在图 3 中,您可以观察到在 40 时段后损失趋于稳定。真实和虚假图像的鉴别器损耗保持在 0.6 左右,而发生器的鉴别器损耗在 0.8 左右。上图是稳定训练的预期图。我们可以将此视为基线,并尝试改变 k(鉴别器的训练步骤)、增加历元数等。

loss_stable_gans

Fig. 3 – Loss graph, the three lines indicate a loss for generator, fake images on discriminator, and real images on discriminator | Source

现在我们已经建立了一个稳定的 GAN 模型,让我们看看故障模式。

GAN 故障模式

在过去的几年中,我们已经看到 GAN 应用的快速增长,无论是提高图像分辨率、条件生成还是生成真实的合成数据。

训练失败是这类应用的一个难题。

如何识别 GAN 失效模式?我们如何知道是否有故障模式:

生成器应该理想地产生各种数据。如果它产生一种或一组相似的输出,就会有一个模式崩溃

  • 当生成一组视觉上很差的数据时,这可能是收敛失败的情况。
  • GAN 中模式崩塌的原因是什么?故障模式原因:

无法找到网络的收敛。

  • 生成器可以找到某种类型的数据,很容易骗过鉴别器。在假设目标已经实现的情况下,它会一次又一次地生成相同的数据。整个系统可能对单一类型输出进行过度优化。
  • 识别模式崩溃和其他故障模式的问题是,我们不能依赖定性分析(如手动查看数据)。如果有大量数据或者问题非常复杂(我们不会总是生成数字),这种方法可能会失败。

评估故障模式

在本节中,我们将尝试理解如何识别是否存在模式崩溃或收敛失败。我们会看到三种评估方法。其中一个我们已经在前一节讨论过了。

看中间的图像

让我们看一些例子,在那里,从中间图像可以评估模式崩溃和收敛。在图 4 中,我们看到质量非常差的图像,而在图 5 中,我们可以看到生成了相同的一组图像。

虽然图 4 是收敛失败的例子,但是图 5 显示了模式崩溃。通过手动查看图像,您可以了解模型的运行情况。但是,当问题的复杂性很高或者训练数据太大时,您可能无法识别模式崩溃。

Output from one of the unstable training

Fig. 4 – These are the output from one of the unstable training. This is on the same training code as above and slightly tweaked hyperparameters, but even after 300 epochs, you can see how bad our images are – an example of convergence failure | Source: Author

This is another example, you can see the same kind of images generated indicating Mode Collapse

Fig. 5 – This is another example, you can see the same kind of images generated indicating Mode Collapse | Source

我们来看看一些更好的方法。

通过观察损失图

通过查看损失图,我们可以了解更多情况。例如,在图 3 中,您可以注意到在某个点之后损耗饱和,显示了预期的行为。现在让我们看看图 6 中的损失图,我已经减少了潜在维度,所以行为是不稳定的。

我们可以在图 6 中看到,发电机损耗在 1 和 1.2 附近振荡。虽然伪图像和真实图像的鉴别器损失也在 0.6 左右,但损失比我们在稳定版本中注意到的要多一些。

gan_loss_latentSpace2

Fig. 6 – Loss graph when the latent dimension is reduced | Source

我建议,即使图表有很高的方差,也没关系。您可以增加历元的数量,并等待更多的时间让它变得稳定,最重要的是继续检查生成的中间图像。

如果发生器和鉴别器的损耗图在初始时期都下降到零,那么这也是一个问题。这意味着生成器发现了一组很容易被鉴别者识别的假图像。

统计上不同的箱数(NDB 分数)

与上述两种定性方法不同,NDB 评分是一种定量方法。因此,NDB 分数可以识别是否有模式崩溃,而不是查看图像和损失图,遗漏一些东西或没有做出正确的解释。

让我们了解一下 NDB 评分的工作原理:

我们有两个集合,一个训练集(在其上训练模型)和一个测试集(训练完成后由生成器在随机噪声上生成的假图像)。

  • 现在使用 K 均值聚类将训练集分成 K 个聚类。这将是我们的 K 个不同的箱子。
  • 现在,基于测试数据点和 K 个簇的质心之间的欧几里德距离,将测试数据分配到这 K 个箱中。
  • 现在,在每个箱的训练样本和测试样本之间进行双样本测试,并计算 Z 值。如果 Z 分数小于阈值(本文中使用 0.05),则将该条柱标记为统计差异。
  • 计算统计上不同的箱数,并除以 k。
  • 收到的值将介于 0 和 1 之间。
  • 高数量的统计上不同的箱意味着,即,值更接近 1,意味着高模式崩溃,意味着坏的模型。然而,NDB 分数接近 0 意味着较少或没有模式崩溃。

NDB 评估方法来自关于 GANs 和 GMMs 的论文

计算 NDB 的一个非常好实现的代码可以在沈世爱的这个 colab 笔记本中找到。

(a)Top Left - Image from Training dataset (b)Bottom Left - Image from Test dataset and the overlap is shown (c)Bar Graph showing bins for train and test set

Fig. 7 – (a) Top Left – Image from Training dataset (b) Bottom Left – Image from Test dataset and the overlap is shown (c) Bar Graph showing bins for train and test set | Source

解决故障模式

现在我们已经了解了如何识别 GANs 培训中的问题,我们将研究一些解决方案和经验法则来解决这些问题。其中一些将是基本的超参数调整。如果你想更进一步稳定你的 GANs,我们将讨论一些算法。

成本函数

有论文说无损失函数优越。我建议你从更简单的损失函数开始,就像我们使用的二进制交叉熵,然后从那里开始。

现在,在某些 GAN 架构中使用某些损失函数并不是一种强制要求。但是很多研究投入到这些论文的写作中,很多研究仍然在进行中。因此,使用图 8 中的这些损失函数将是一个很好的做法,这可能有助于防止模式崩溃和收敛。

对不同的损失函数进行实验,注意您的损失函数可能会因为超参数的错误调整而失败,比如使优化器过于激进,或者学习率过大。这些问题我们以后再讲。

Architecture of GANs and corresponding loss functions used in papers

Fig. 8 – Architecture of GANs and corresponding loss functions used in papers | Source

潜在空间

潜在空间是对发生器的输入(随机噪声)进行采样的地方。现在,如果你限制潜在空间,它将产生更多相同类型的输出,如图 9 所示。您也可以查看图 6 中相应的损耗图。

在图 9 中,你能看到这么多相似的 8 和 7 吗?因此模式崩溃。

Subplot at 100th epoch, when latent space is 2

Fig. 9 – Subplot at 100th epoch, when latent space is 2 | Source: Author

请注意,在训练 GAN 网络时,提供足够的潜在空间是至关重要的,因此生成器可以创建各种功能。

gan_loss_latentSpace1

Fig. 10 – Here I gave the latent space as 1, ran for 200 epochs.
We can see the generator loss constantly increasing and oscillation in all the losses | Source

Subplot corresponding Fig. 10, where the latent space is 1. These digits are generated on the 200th epoch.

Fig. 11 – Subplot corresponding fig. 10, where the latent space is 1.
These digits are generated on the 200th epoch | Source: Author

学习率

我在训练 gan 时观察到的一个最常见的问题是高学习率。它会导致模式崩溃或不收敛。你保持低学习率真的很重要,低到 0.0002 甚至更低。

我们可以从图 12 中的损失图清楚地看到,鉴别器将所有图像识别为真实的。这就是为什么假图像的损失很高,而真实图像的损失为零。现在,生成器假设它生成的所有图像都在欺骗鉴别器。这里的问题是,由于如此高的学习率,鉴别者甚至没有得到一点培训。

gan_loss_lr_0.2

Fig. 12 – Loss values when the learning rate is 0.2 | Source

Generated Images on 100th epoch, with a learning rate of 0.2

Fig. 13 – Generated Images on 100th epoch, with a learning rate of 0.2 | Source: Author

批量越大,学习率的值就越高,但是要尽量安全。

【计算机】优化程序

一个侵略性的修改器对训练 GANs 来说是个坏消息。它导致无法找到发电机损耗和鉴别器损耗之间的平衡,从而导致收敛失败。

在 Adam Optimizer 中,betas 是用于计算梯度及其平方的移动平均值的超参数。我们最初(在稳定训练中)对β1 使用值 0.5。将其更改为 0.9(默认值)会增加优化器的积极性。

gan_loss_adam_betas_0.9_0.999

Fig. 14 – Loss graph with default values of Adam Optimizer (betas are 0.9 and 0.999) | Source

在图 14 中,鉴别器表现良好。由于发电机损耗不断增加,我们可以看出它正在产生如此糟糕的图像,以至于鉴别器很容易将其归类为假图像。损失图没有达到平衡。

特征匹配

特征匹配提出了一种新的目标函数,其中我们不直接使用鉴别器输出。训练发生器,使得发生器输出预期与鉴别器中间特征上的实像值相匹配。

对于真实图像和虚假图像,在中间层上以小批量计算特征向量(图 15 中的 f(x )),并且测量这些特征向量的平均 L2 距离。

f(x) is the feature vector extracted at the intermediate layer of the discriminator

Fig. 15 – f(x) is the feature vector extracted at the intermediate layer of the discriminator | Source

将生成的数据与真实数据的统计数据进行匹配更有意义。如果优化器在搜索最佳数据生成时变得过于贪婪,并且从未达到收敛,那么特征匹配可能会有所帮助。

历史平均

我们保持前 t 个模型的参数(θ)的移动平均值。现在,我们惩罚模型,使用先前的参数将 L2 成本添加到成本函数中。

这里,θ[i]是第 I 次^(运行时的参数值。)

在处理非凸目标函数时,历史平均可以帮助收敛模型。

结论

我们现在明白了在训练 GANs 时实验跟踪的重要性。

  • 理解损耗图并仔细观察生成的中间数据非常重要。
  • 超参数,如学习率、优化器参数、潜在空间等。如果调整不当,可能会破坏您的模型。
  • 随着过去几年 GAN 模型的增加,越来越多的研究进入到稳定 GAN 的训练中。对于特定的用例,有更多的技术是有益的。
  • 进一步阅读

塔奈·阿格拉瓦尔

Curl Analytics 的深度学习工程师

阅读下一篇


机器学习中模型评估和选择的最终指南

10 分钟阅读|作者 Samadrita Ghosh |年 7 月 16 日更新

10 mins read | Author Samadrita Ghosh | Updated July 16th, 2021

在高层次上,机器学习是统计和计算的结合。机器学习的关键围绕着算法或模型的概念,这些概念实际上是类固醇的统计估计。

然而,根据数据分布的不同,任何给定的模型都有一些限制。它们中没有一个是完全准确的,因为它们只是 (即使使用类固醇) 。这些限制俗称 偏差方差

具有高偏差的模型会因为不太注意训练点而过于简化(例如:在线性回归中,不管数据分布如何,模型将总是假设线性关系)。

具有高方差的模型将通过不对其之前未见过的测试点进行概括来将其自身限制于训练数据(例如:max_depth = None 的随机森林)。

当限制很微妙时,问题就出现了,比如当我们必须在随机森林算法和梯度推进算法之间进行选择,或者在同一决策树算法的两个变体之间进行选择。两者都趋向于具有高方差和低偏差。

这就是模型选择和模型评估发挥作用的地方!

在本文中,我们将讨论:

什么是模型选择和模型评估?

  • 有效的模型选择方法(重采样和概率方法)
  • 流行的模型评估方法
  • 重要的机器学习模型权衡
  • Important Machine Learning model trade-offs

Continue reading ->


理解 GAN 损耗函数

原文:https://web.archive.org/web/https://neptune.ai/blog/gan-loss-functions

Ian Goodfellow 在 2014 年引入了生成对抗网络(GAN)。这是神经网络最漂亮、最简单的实现之一,它包括两个相互竞争的神经网络。 Yann LeCun,卷积神经网络(CNN)的创始人,将 GANs 描述为“过去十年机器学习中最有趣的想法”。

用简单的话来说,GANs 背后的想法可以概括如下:

  • 涉及到两个神经网络。
  • 其中一个网络,即生成器,从随机数据分布开始,并试图复制特定类型的分布。
  • 另一个网络,鉴别器,通过随后的训练,可以更好地将伪造的分布从真实的分布中区分出来。
  • 这两个网络都在玩一个最小-最大游戏,其中一个试图智胜另一个。

很简单……但是当你真正尝试去实现它们的时候,它们通常不会以你期望的方式学习。一个常见的原因是过于简单的损失函数。

在这篇博客文章中,我们将仔细研究 GAN 及其损失函数的不同变体,以便我们可以更好地了解 GAN 在解决意外性能问题时是如何工作的。

标准 GAN 损耗函数(最小-最大 GAN 损耗)

标准的 GAN 损失函数,也被称为最小-最大损失,最早是由 Ian Goodfellow 等人在 2014 年发表的题为“生成对抗网络”的论文中描述的。

生成器试图最小化该函数,而鉴别器试图最大化该函数。把它看做一个最小-最大游戏,这种损失的表述似乎是有效的。

实际上,它对于发生器来说是饱和的,这意味着如果发生器没有赶上鉴别器,它就会频繁地停止训练。

标准 GAN 损耗函数可进一步分为两部分:鉴频器损耗发生器损耗

鉴频器损耗

当鉴别器被训练时,它对来自生成器的真实数据和虚假数据进行分类。

通过最大化下面的函数,它惩罚自己将一个真实的实例误分类为假的,或者将一个假的实例(由生成器创建)误分类为真实的。

  • log(D(x)) 是指生成器正确分类真实图像的概率,
  • 最大化 log(1-D(G(z))) 将帮助它正确地标记来自生成器的假图像。

发电机损耗

当生成器被训练时,它对随机噪声进行采样,并从该噪声中产生输出。然后,输出通过鉴别器,并根据鉴别器的辨别能力被分类为“真”或“假”。

然后,根据鉴别器的分类计算发电机损耗——如果成功骗过鉴别器,将获得奖励,否则将受到惩罚。

下面的等式被最小化以训练发生器:

非饱和 GAN 损耗

在生成器最大化鉴别器概率的对数时,使用了标准损失函数的一个细微变化—log(D(G(z))。

这种变化的灵感来自于从不同的角度构建问题,其中生成器寻求最大化图像真实的概率,而不是最小化图像虚假的概率。

这通过更稳定的权重更新机制避免了发电机饱和。在他的博客中,Daniel Takeshi 比较了非饱和 GAN 损耗和其他一些变化。

GAN 损耗函数面临的挑战

通常情况下,GANs 在性能上往往表现出一些不一致性。

这些问题中的大多数都与他们的训练有关,并且是一个活跃的研究领域。

让我们详细看看其中的一些:

模式崩溃

这个问题是事情不可预测的一面。直到有人注意到发电机模型只能产生不同结果或模式中的一个或一个小的子集,人们才预见到这一点。

通常,我们希望 GAN 产生一系列输出。例如,我们希望我们设计的人脸生成器的每个随机输入都有另一个人脸。

相反,通过随后的训练,网络学习对特定的数据分布进行建模,这给了我们一个单调的输出,如下图所示。

在训练过程中,发生器总是试图找到一个对鉴别器来说似乎最合理的输出

因此,鉴别器的最佳策略总是拒绝发生器的输出

但是,如果下一代鉴别器陷入局部最小值,并且没有通过进一步优化其权重来找到出路,那么下一次生成器迭代将很容易找到当前鉴别器的最合理输出。

这样,它将不断重复相同的输出,避免任何进一步的训练。

消失渐变

当鉴别器的性能明显优于生成器时,就会出现这种现象。鉴别器的更新要么不准确,要么消失。

对此提出的原因之一是发生器受到严重惩罚,这导致激活后函数值饱和,最终梯度消失。

趋同;聚集

由于有两个网络同时被训练,GAN 收敛的问题是最早的问题之一,并且很可能是自其产生以来最具挑战性的问题之一。

在大多数情况下,两个网络都稳定并产生一致结果的乌托邦式的情况是很难实现的。对这个问题的一种解释是,随着下一个时期发生器变得更好,鉴别器的性能会变得更差,因为鉴别器无法轻易区分真假。

如果发生器一直成功,鉴别器有 50%的准确率,类似于抛硬币。这对整个 GAN 的融合构成了威胁。

下图特别显示了这个问题:

由于鉴别器的反馈通过以相等的概率给出输出而在随后的时期中失去其意义,所以如果发生器继续利用这些垃圾训练信号进行训练,它可能会恶化其自身的质量。

Jonathan Hui 的这篇文章从数学的角度全面地审视了上述所有问题。

交替 GAN 损失函数

从最初开始,人们就提出了几种不同的 GAN 损耗变化。在一定程度上,它们解决了我们之前讨论的挑战。

我们将讨论一些最受欢迎的缓解问题的方法,或用于特定问题陈述的方法:

沃瑟斯坦生成对抗网络

这是原始 GAN 损耗的最有力替代方案之一。它解决了 模式崩溃 消失渐变 的问题。

在该实现中,鉴频器输出层的激活从 sigmoid 变为线性。这个简单的变化影响鉴别器给出分数而不是与数据分布相关的概率,因此输出不必在 0 到 1 的范围内。

在这里,鉴别器被称为批判,因为它实际上并不严格地将数据分类为真实或虚假,它只是给它们一个评级。

以下损失函数分别用于训练批判和鉴别器

评论和生成器的输出不是概率项(在 0 和 1 之间),因此在训练评论网络时,评论和生成器输出之间的绝对差被最大化。

类似地,在训练发生器网络时,发生器函数的绝对值最大化。

原始论文使用 RMSprop,然后进行剪裁,以防止权重值爆炸:

条件生成对抗网络

这个版本的 GAN 用于学习多模态模型。它基本上生成描述性标签,这些标签是与不属于原始训练数据的特定图像相关联的属性。

CGANs 主要用于图像标记,其中生成器和鉴别器都被馈送一些额外的信息 y 作为辅助信息,例如来自不同模态的类别标签或与不同模态相关联的数据。

通常通过将信息 y 输入鉴别器和发生器来完成调节,作为其附加输入层。

以下修改的损失函数进行与标准 GAN 损失函数相同的最小-最大博弈。它们之间唯一的区别是,条件概率用于生成器和鉴别器,而不是常规的条件概率。

为什么是条件概率?因为我们正在输入一些辅助信息(绿点),这有助于使其成为多模态模型,如下图所示:

Figure 1: Conditional adversarial net

Jonathan Hui 的这篇文章深入探讨了 CGANs 并讨论了其背后的数学原理。

摘要

在这篇博客中,我们讨论了:

  • 原始的生成性对抗网络随着修改后的网络而失去功能。
  • 在现实生活中使用它们的不同挑战。
  • 替代损失函数,如 WGAN 和 C-GAN。

这篇文章的主要目的是提供一个生成性对抗网络发展背后的整体直觉。希望它能让你对 GANs 有更好的感觉,以及一些有用的见解。感谢阅读!

哈什特·德维韦迪

AfterShoot 的创始人兼首席执行官,AfterShoot 是一家初创公司,致力于开发人工智能工具,通过自动化工作流程中枯燥乏味的部分,帮助摄影师更好地利用时间。


阅读下一篇

机器学习中模型评估和选择的最终指南

10 分钟阅读|作者 Samadrita Ghosh |年 7 月 16 日更新

在高层次上,机器学习是统计和计算的结合。机器学习的关键围绕着算法或模型的概念,这些概念实际上是类固醇的统计估计。

然而,根据数据分布的不同,任何给定的模型都有一些限制。它们中没有一个是完全准确的,因为它们只是 (即使使用类固醇) 。这些限制俗称 偏差方差

具有高偏差的模型会由于不太注意训练点而过于简化(例如:在线性回归中,不管数据分布如何,模型将总是假设线性关系)。

具有高方差的模型将通过不对其之前未见过的测试点进行概括来将其自身限制于训练数据(例如:max_depth = None 的随机森林)。

当限制很微妙时,问题就出现了,比如当我们必须在随机森林算法和梯度推进算法之间进行选择,或者在同一决策树算法的两个变体之间进行选择。两者都趋向于具有高方差和低偏差。

这就是模型选择和模型评估发挥作用的地方!

在本文中,我们将讨论:

  • 什么是模型选择和模型评估?
  • 有效的模型选择方法(重采样和概率方法)
  • 流行的模型评估方法
  • 重要的机器学习模型权衡

Continue reading ->


生成对抗网络和一些 GAN 应用:你需要知道的一切

原文:https://web.archive.org/web/https://neptune.ai/blog/generative-adversarial-networks-gan-applications

生成模型方法是一种无监督学习。

在监督学习中,深度学习模型学习将输入映射到输出。在每次迭代中,都要计算损耗,并使用反向传播优化模型。

在无监督学习中,我们不会像在监督学习中那样将目标变量输入到深度学习模型中。为什么?

嗯,监督学习算法是为了在图像分类的情况下识别对象而构建的,或者在回归的情况下用于预测下一个值。

无监督学习算法用于学习数据的潜在模式,或者数据的表示。

无监督学习用于以下任务:

  • 主成分分析
  • 使聚集
  • 异常检测

本质上,生成模型,或深度生成模型,是一类从样本中学习底层数据分布的深度学习模型。这些模型可用于将数据简化为其基本属性,或生成具有新的不同属性的新数据样本。

生成模型有两种类型:

  1. 显式似然模型
  2. 隐式似然模型

显式似然模型:显式模型从样本分布中学习数据分布,生成新类型的数据。这些类型的模型可以访问概率分布,并使用最大似然法对它们进行训练。在最大似然法中,假设的模型被训练以最大化该模型下数据的概率分布。

显式似然模型:

  • 最大概似法
    • PPCA,因子分析,混合模型
    • 像素 CNN/像素 RNN
    • Wavenet
    • 自回归语言模型
  • 近似最大似然
    • 玻尔兹曼机器
    • 可变自动编码器

隐式似然模型:隐式模型不学习数据的分布,而是学习数据的统计性质,因此它可以概括并生成新的数据样本,而不依赖于概率分布。

什么是生成性对抗网络?

生成式对抗网络是隐式似然模型,它从数据的统计分布中生成数据样本。它们用于复制数据集中的变化。他们使用两个网络的组合:生成器和鉴别器。

发电机

生成器网络采用随机正态分布(z ),并输出接近原始分布的生成样本。

鉴别器

鉴别器尝试用原始样本评估生成器生成的输出,并输出 0 到 1 之间的值。如果值接近 0,则生成的样本是假的,如果值接近 1,则生成的样本是真的。

Discriminator

简而言之,鉴别器的工作就是通过与原始样本的比较来鉴别生成的样本是真是假。生成器的工作是通过生成接近原始样本的样本来欺骗鉴别器。

生成性对抗网络是如何工作的?

所以,甘有两个网络。这两个网络都应该独立训练。当两个模型都是多层感知器时,GAN 框架非常简单。让我们看看甘是如何工作的。

随机正态分布被输入到发生器中。然后,发生器输出随机分布,因为它没有参考点。

与此同时,一个实际的样本,或地面真相,被送入鉴别器。鉴别器学习实际样本的分布。当发生器产生的样本输入鉴别器时,它会评估分布。如果生成样本的分布接近原始样本,则鉴别器输出接近“1”=实数的值。如果两个分布不匹配,或者它们甚至彼此都不接近,那么鉴别器输出一个接近“0”的值=假。

那么生成器如何进化以生成类似实际数据的样本呢?

为了理解生成器的进化,我们需要了解鉴别器是如何评估生成的样本是真的还是假的。

答案在于损失函数或者价值函数;它测量生成数据的分布和真实数据的分布之间的距离。发生器和鉴别器都有自己的损失函数。发生器试图最小化损失函数,而鉴别器试图最大化。

发电机不直接连接到损耗,而是通过鉴别器。鉴别器产生假的或真的输出。如果输出为 0 =假,那么发生器损耗惩罚发生器产生被鉴别器分类为假的样本。

一旦计算出损耗,通过鉴别器网络到发电机的反向传播来更新发电机权重。这一点很重要,因为发生器参数的影响在很大程度上取决于鉴别器的影响,因此发生器接收反馈并使用反馈产生更“真实”的图像。

GANs equation

培养

对于每个训练步骤,我们从鉴别器循环开始。在进入发电机回路之前,我们要重复这一步。

鉴别器回路:

设置一个循环 k,其中 k>1。我们这样做是因为我们想确保鉴别器收敛到原始数据 pd 的良好估计量。

从正态分布{z1,z2,z3,…zn}中采样 m 个噪声数据,并通过发生器对其进行变换。

  1. 从正态分布{x1,x2,x3,…xn}中抽取 m 个实际数据样本。
  2. 重要的是要记住,假样本标记为 0,真样本标记为 1。
  3. 然后我们使用损失函数来计算使用标签的损失。
  4. 我们采用损失函数相对于鉴别器参数的梯度,并更新鉴别器中的权重。为了更新鉴别器中的梯度,我们使用梯度上升,因为我们想最大化它。
  5. 这就完成了鉴别器环路。
  6. 发电机回路:

GANs equation

发电机回路类似。我们从以下几点开始:

从正态分布{z1,z2,z3,…zn}中采样 m 个噪声数据,并通过生成器对其进行变换,以获得我们的伪样本。

因为我们只对更新发电机的环路感兴趣,所以我们考虑损失函数相对于发电机的梯度,最终使导数为零。

  1. 此外,在发生器循环中,我们不会使用真实样本,因此成本函数简化为:
  2. 使用相同的等式,我们现在可以使用梯度下降来更新生成器的权重。
  3. 非常有趣的是,生成器通过保持鉴别器为常数来进化。鉴别器作为向导,帮助生成器学习和进化!

GANs equation

损失函数

gans 中有两个主要损失函数:

最小-最大损失

瓦瑟斯坦损失

  1. 最小最大损失
  2. Minimax 就是最大化误差和最小化误差。最小-最大损失最初是由 Ian Goodfellow 等人在 2014 年发表的一篇题为“生成性对抗网络”的论文中描述的。

极大极小损失来自博弈论。它基本上围绕着玩家之间的竞争。这个想法是,为了获胜,玩家必须最大化自己获胜的概率,并通过找到对手可以做出的最佳移动来最小化对手获胜的概率。

在这里,我们需要明白,鉴别者是希望通过正确分类生成器生成的假图像来最大化获胜概率的玩家。它先让自己熟悉真实图像,即 D(x) = 1 ,再熟悉虚假图像,即 D(G(x)) = 0

GANs equation

(1–D(G(x)))之间的差应该增加。较大的差异表明鉴别器运行良好;它能够区分真假图像。

另一方面,当涉及到生成器时,它会试图通过最小化(1–D(G(x))来最小化鉴别器的获胜概率。

生成器想要做的只是产生样本,当通过鉴别器(D(G(x))时,该样本更接近于 1。然后,当计算损耗(1–D(G(x)))时,输出将更接近于零。

这个过程持续下去,直到一个玩家帮助另一个玩家进化,或者训练迭代终止。

瓦瑟斯坦损失

Wasserstein 损失函数是为一种称为 WGAN 的新型 GAN 开发的,其中鉴别器不会将输出分类为假或真,但对于每个生成的样本,它会输出一个介于 0 和 1 之间的数字。尽管想法是相同的,其中真实样本由较大的数字表示,而假样本由较小的数字表示。

所以,它不能真正区分真假样本。WGAN 鉴别器实际上被称为“批评家”。

评论家损失:C(x)–C(G(z))

鉴别器试图最大化这个函数,它和我们之前看到的 minimax 函数是一样的。它试图最大化真实实例和虚假实例之间的差异。

发电机损耗 : C(G(z))

生成器试图最大化该功能。换句话说,它试图最大化伪实例的鉴别器输出。

甘的问题

消失梯度下降

当在训练的每次迭代中损失函数相对于当前权重的导数非常小,以至于对原始权重的更新几乎可以忽略时,出现消失梯度下降。

为了克服这个问题,建议使用 WGANs。

模式崩溃

当发生器能够用较少种类的数据样本欺骗鉴别器时,发生模式崩溃。

例如,如果输入数据有 10 个不同的手动数字,而发生器能够通过仅产生 10 个手动数字中的 4 个来欺骗鉴别器,则 GAN 遭受模式崩溃。

GAN 变体

深度卷积 GAN

DCGANs 是对使用卷积神经网络的 gan 的改进。CNN 有利于从数据中提取重要的特征和表示,使它们更加稳定,并使它们能够生成更高质量的图像。

条件 gan

GANs 可以通过添加一些额外的信息变得更好,比如标签 y。

从上图中可以看出,生成器和鉴别器都受标签 y 的约束。这可能是任何类型的附加信息,比如类标签或数据。

在发生器中,先前的输入噪声 p(z)和 label (y)被合并。在鉴别器中,输入(x)和标签(y)作为鉴别函数的输入。

cGANs 通过利用输入模型的额外信息来学习生成更好的图像。

为什么是 cGAN?

通过提供附加信息,GANs:

倾向于收敛得更快;事实证明,即使是随机分布也会有一些模式。

您可以在推断时控制生成器的输出,方法是给出您希望它生成的图像的标签。

  1. 应用:
  2. 图像到图像的翻译

文本到图像的合成

  1. 视频生成
  2. 图像到图像的翻译
  3. 图像到图像的转换是一种应用,其中用 a 的属性来转换某个图像 B。

像素 2 像素 GAN

前面我们看到了正态分布中的随机样本是如何被输入到生成器中的,并且是未知的,或者是一个新的样本是如何生成的。Pix2Pix GAN 使用条件 GAN 将一种类型的图像转换为另一种类型的图像。

Pix2Pix GAN 使用一对图像 x 和 y。这些图像对必须是相关的。输入 x 被馈送到发生器,它是一个 U 形网。发生器的输出然后被馈送到鉴别器,鉴别器也被馈送以标签 y。直觉是一个图像可以被完全转换成另一个图像。

之前我们看到生成器学习将随机分布转换为图像。在 pix2pix 中,我们看到一个图像被转换或翻译成不同类型的图像。

Pix2Pix 可用于:

白天到晚上或晚上到白天的翻译

低分辨率到高分辨率

  1. 草图到图纸
  2. CycleGAN
  3. CycleGAN 是 Pix2Pix GAN 的更新版本。CycleGAN 使用不成对的图像转换,而不是成对的图像转换。这种技术基本上给了你很多机会去拍摄任意两个图像对,然后将两个图像的属性互相传递。

从上图中可以看出,这些技术非常有用。艺术家可以用它将照片转化为绘画。

CycleGAN 通常使用两个生成器和鉴别器。其背后的思想是,图像 A 被馈入生成器,它生成某个图像 G(A)。相同的图像 G(A)被馈送到另一个生成器中以重建原始图像 F(A)。cycleGAN 这个名字的灵感来源于这样一个事实,即 cycleGAN 不是以传统的方式计算损失,而是计算原始图像和重建图像的损失。

文本到图像的合成

斯塔克根

堆叠生成对抗网络(StackGAN)可以根据文本描述生成图像。

该架构包括一系列堆叠的文本和图像 GAN 模型。这又是一类条件句。它有两种 GAN,也称为第一阶段 GAN 和第二阶段 GAN。StackGAN 使用草图细化过程,其中第一级生成器 Stage-I GAN 以文本为条件,生成低分辨率图像,即描述性文本的原始形状和颜色。

第二级发生器,第二阶段 GAN,以文本和低分辨率图像为条件,采用第一阶段的结果并添加引人注目的细节。

低分辨率图像首先由我们的第一阶段 GAN 生成。在第一阶段 GAN 的顶部,我们堆叠了第二阶段 GAN,以根据第一阶段结果和文本描述生成逼真的高分辨率(例如 256×256)图像。通过再次调节第一阶段的结果和文本,第二阶段的甘学会捕捉第一阶段甘遗漏的文本信息,并为对象绘制更多细节……“摘自斯塔克甘:利用堆叠式生成对抗网络将文本转换为照片般逼真的图像合成(张寒等人)

达尔-埃

最近 openai 创建了一个名为 DALL-E 的深度学习网络,它也可以进行文本到图像的合成。

虽然架构没有用 GANs,而是 GPT-3 的一个版本。

人脸修复

面部修复,也称为面部修复,是为面部图像中缺失的像素生成可信的面部特征的任务。

这种技术的目的是从具有遮蔽区域的图像或具有缺失内容的图像中产生更合适和更真实的人脸图像。

GAN 的实现

香草甘

出局:

氮化镓的应用

from tensorflow.keras.layers import Input
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras.layers.core import Dense, Dropout
from tensorflow.keras.layers.advanced_activations import LeakyReLU
from tensorflow.keras.datasets import mnist
from tensorflow.keras.optimizers import Adam
from tensorflow.keras import initializers
from tensorflow.keras.layers import Activation, Dense
(X_train, y_train), (X_test, y_test) = mnist.load_data()

X_train = (X_train.astype(np.float32) - 127.5)/127.5

X_train = X_train.reshape(60000, 784)

for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(X_train.reshape(X_train.shape[0], 28, 28)[i], interpolation='nearest', cmap='gray_r')

gan 有许多实际应用,其中一些是:

Vanilla GAN output

def get_optimizer():
    return Adam(lr=0.0002, beta_1=0.5)

def get_generator(optimizer, random_dim):
    generator = Sequential()
    generator.add(Dense(256, input_dim=random_dim, kernel_initializer = 'uniform', bias_initializer = 'zeros'))
    generator.add(LeakyReLU(alpha=0.2))

    generator.add(Dense(512))
    generator.add(LeakyReLU(alpha=0.2))

    generator.add(Dense(1024))
    generator.add(LeakyReLU(alpha=0.2))

    generator.add(Dense(784, activation='tanh'))
    generator.compile(loss='binary_crossentropy', optimizer=optimizer)
    generator.summary()
    return generator

def get_discriminator(optimizer):
    discriminator = Sequential()
    discriminator.add(Dense(1024, input_dim=784, kernel_initializer = 'uniform', bias_initializer = 'zeros'))
    discriminator.add(LeakyReLU(alpha=0.3))
    discriminator.add(Dropout(0.2))

    discriminator.add(Dense(512))
    discriminator.add(LeakyReLU(alpha=0.3))
    discriminator.add(Dropout(0.2))

    discriminator.add(Dense(256))
    discriminator.add(LeakyReLU(alpha=0.3))
    discriminator.add(Dropout(0.2))

    discriminator.add(Dense(1, activation='sigmoid'))
    discriminator.compile(loss='binary_crossentropy', optimizer=optimizer)

    discriminator.summary()
    return discriminator

def get_gan_network(discriminator, random_dim, generator, optimizer):

    discriminator.trainable = False

    gan_input = Input(shape=(random_dim,))

    x = generator(gan_input)

    gan_output = discriminator(x)

    gan = Model(inputs=gan_input, outputs=gan_output) 
    gan.compile(loss='binary_crossentropy', optimizer=optimizer)

    gan.summary()
    return gan

def plot_generated_images(epoch, generator, random_dim, examples=100, dim=(10, 10), figsize=(10, 10)):
    noise = np.random.normal(0, 1, size=[examples, random_dim])
    generated_images = generator.predict(noise)
    generated_images = generated_images.reshape(examples, 28, 28)

    plt.figure(figsize=figsize)
    for i in range(generated_images.shape[0]):
        plt.subplot(dim[0], dim[1], i+1)
        plt.imshow(generated_images[i], interpolation='nearest', cmap='gray_r')
        plt.axis('off')
    plt.tight_layout()
    plt.savefig('gan_generated_image_epoch_%d.png' % epoch)

def train(X_train, y_train, x_test, y_test, epochs=100, minibatch_size=128, random_dim = 100):

    adam = get_optimizer()
    G = get_generator(adam, random_dim)
    D = get_discriminator(adam)
    gan = get_gan_network(D, random_dim, G, adam)

    D_loss = []
    G_loss = []

    for e in range(1, epochs+1):
        print('-'*15, 'Epoch %d' % e, '-'*15)

        epoch_cost = 0.                       

        num_minibatches = int(X_train.shape[0] / minibatch_size) 

        X_train, y_train = shuffle(X_train, y_train)

        for i in range(0, X_train.shape[0], minibatch_size):

            X_train_mini = X_train[i:i + minibatch_size]
            y_train_mini = y_train[i:i + minibatch_size]

            legit_images = X_train_mini[np.random.randint(0, X_train_mini.shape[0], size=int(minibatch_size/2))]

            noise = np.random.normal(0, 1, size=[int(minibatch_size/2), random_dim]) 
            syntetic_images = G.predict(noise)

            x_combined_batch = np.concatenate((legit_images, syntetic_images))
            y_combined_batch = np.concatenate((np.ones((int(minibatch_size/2), 1)), np.zeros((int(minibatch_size/2), 1))))
            y_combined_batch[:int(minibatch_size/2)] = 0.9 

            D.trainable = True
            d_loss = D.train_on_batch(x_combined_batch, y_combined_batch)
            D_loss.append(d_loss)

            noise = np.random.normal(0, 1, size=[minibatch_size, random_dim])
            y_gen = np.ones(minibatch_size)
            D.trainable = False
            g_loss = gan.train_on_batch(noise, y_gen)
            G_loss.append(g_loss)

        print ("Cost of D after epoch %i: %f" % (e, d_loss))
        print ("Cost of G after epoch %i: %f" % (e, g_loss))

        if e == 1 or e % 20 == 0:
             plot_generated_images(e, G, random_dim)

    G.save_weights('Generator.h5') 
    D.save_weights('Discriminator.h5')

    return [D_loss, G_loss]

if __name__ == '__main__':
    [D_loss, G_loss] = train(X_train, y_train, X_test, y_test, epochs = 100, minibatch_size=128, random_dim = 100)

生成图像数据集的示例

在医学或材料科学中,生成示例非常方便,因为这些领域中很少有数据可处理。

  • 生成人脸照片
    • 视频游戏设计者可以用它来生成逼真的人脸。
  • 生成逼真的照片
    • 对摄影师和摄像师非常有用。
  • 生成卡通人物
    • 艺术家可以用它来创造一个新的角色设计,或者卡通中的场景,甚至是视频游戏。
  • 图像到图像的翻译
    • 摄影师可以使用这些算法将白天转换成夜晚,将夏天转换成冬天,等等。
  • GANs 可用于模拟最坏的情况,以优化企业的风险管理。
    • GAN 的其他使用案例包括:
  • 文本到图像的翻译

人脸正面视图生成

  • 生成新的人体姿态
  • 照片到表情符号
  • 面部老化
  • 超分辨率
  • 照片修复
  • 服装翻译
  • 视频预测
  • 3D 对象生成
  • 结论
  • 在本文中,我们了解了:

生成建模和生成模型

显式似然模型

  1. 隐式似然模型
    1. 生成对抗网络
    2. 它属于隐含似然模型。
  2. 当我们设计 GANs 时,我们不关心真实数据的概率分布,而是试图模拟或生成具有相同分布和变化特征的真实数据。
    1. 它有两个网络:生成器和鉴别器,它们试图相互竞争,同时帮助彼此学习更好的表示和分布。
    2. 损失函数及其工作原理。
    3. 甘斯的问题。
  3. GANs 的不同变体
  4. 最后,我们使用 keras 实现了 vanilla GANs。
  5. 这是一个迷人的话题,如果你坚持到了最后——感谢你的阅读!
  6. 尼尔什·巴拉

我是最近一家初创公司 perceptronai.net 的创始人,该公司旨在通过我们的深度学习算法提供医疗和材料科学方面的解决方案。我也阅读和思考了很多。有时我把它们以绘画或音乐的形式表现出来。当我需要喘口气时,我会去跑步。

阅读下一篇

如何组织深度学习项目——最佳实践范例


13 分钟阅读|作者 Nilesh Barla |年 5 月 31 日更新

How to Organize Deep Learning Projects – Examples of Best Practices

一个成功的深度学习项目,你需要很多迭代,很多时间,很多努力。为了让这个过程不那么痛苦,你应该尽量利用你的资源。

一个好的循序渐进的工作流程将帮助你做到这一点。有了它,你的项目变得高效、可复制、可理解

在本文中,您将看到如何构建深度学习项目的工作——从开始到部署,监控部署的模型,以及中间的一切。

在这个过程中,我们将使用 Neptune 来运行、监控和分析您的实验。Neptune 是提高 ML 项目生产率的一个很酷的工具。

在本文中,您将了解到:

关于项目的生命周期。

定义项目目标的重要性。

  1. 根据项目需求收集数据。
  2. 模型训练和结果探索,包括:
  3. 为更好的结果建立基线。
  4. 采用现有的开源最新模型研究论文和代码库中的技术和方法。
    1. 实验跟踪和管理
    2. 避免欠拟合和过拟合的模型优化技术,例如:
    3. 控制超参数
  5. 规范化
    1. 修剪
    2. 在部署之前测试和评估您的项目。
    3. 模型部署
  6. 项目维护
  7. Model deployment
  8. Project maintenance

Continue reading ->


地理空间数据科学:使用 Plotly 在 Neptune 中记录交互式图表[指南]

原文:https://web.archive.org/web/https://neptune.ai/blog/geospatial-data-science-logging-interactive-charts-in-neptune-with-plotly

地理空间数据科学正在成为数据科学领域的重要组成部分。几乎每个事件都可以映射到地球表面。因此,外业人员倾向于回答详细的位置问题,并了解其位置的特征和基本原理。像一般数据科学一样,地理空间提供了计算技能、统计概念以及数据争论和可视化的类似基线。本文是地理空间数据科学分析和可视化的简要指南。我们将揭开术语的神秘面纱,突出这一领域最好的部分,解释使用了什么技能和技术,并检查一个 Python 用例。

什么是地理空间数据科学?

数据科学中有大量的术语,过多的术语会导致误解。因此,让我们澄清一些地理空间数据科学术语:

  • 空间来源于拉丁语“spatium”,意为空间。“空间”是指空间,因为它涵盖了分布在一个空间连续体中的特征和现象。
  • 地理学是研究地球的物理特征、现象、大气以及人类活动对地球的影响。
  • 地理空间是一个混合起源的词,希腊语“gaya”和拉丁语“Spatium”,意思是地球空间。地理空间意味着地理实体的位置是以坐标系统为参考的。
  • 地理信息系统(GIS) 是用于收集、管理、操作、分析、存储和可视化地理空间数据(具有地理成分的数据)的系统。

地理空间数据科学是关于使用位置来寻找模式和解决复杂问题。范围超越了局部性,包括发现隐藏的模式、理解现象、发现复杂的关系和推动决策。该领域研究跨时间和空间的数据,以了解关于位置、距离和空间交互的地理事件。

为什么地理空间数据科学很重要?

地理空间数据科学使空间决策更容易。您可以使用一套分析方法和算法,包括机器学习和深度学习技术,从地理空间数据中提取深刻的见解。地理空间数据科学的前景包括:

  • 数据工程:帮助读取、转换、格式化、清理和丰富地理空间数据。
  • 可视化探索:用地图和动态图表直观地引导调查。
  • 地理空间分析:使用各种方法和技术帮助学习和研究地理空间实体。
  • 机器学习和深度学习:利用多种机器学习和深度学习算法建立预测模型,解决复杂的地理空间问题。
  • 大数据分析:将大量地理空间数据转换成可管理的大小,以便进行更容易访问和更好的分析。
  • 建模和脚本:地理空间系统的自动化过程和扩展功能。

在业务方面,根据“2020 年企业地理空间数据科学状况 ”,许多行业的地理空间分析投资增长了 68%。这是一个非常有前景的领域,因为仍然很少有地理空间数据科学家— 只有三分之一的数据科学家声称自己是地理空间分析专家

地理空间数据科学可以用在哪里?

地理空间数据科学是革命性的,因为几乎所有东西都可以进行地理参考。这意味着地理空间数据科学可以用于几乎任何行业,包括:

  • 卫生保健
  • 电信
  • 城市规划/发展
  • 营销
  • 社会服务
  • 军队
  • 自然资源勘探和开发
  • 运输
  • 教育
  • 天气
  • 农业

让我们讨论一下对地理空间数据科学有用的编程语言、数据库和工具。

r 和 Python 是流行的编程语言,因为它们为数据科学操作提供了大量的库:

地理空间数据通过数据库存储和管理;这里的一些例子有 PostGISGrassGISPostgresSQLPgAdmin

一些工具被设计用于捕获、存储、操作、分析、管理和呈现地理空间数据,例如, Esri、【QGIS、 MapboxCARTO、 Google EarthSpatialKey、 、Geospark、 Alteryx、 FME弹性搜索、 Oracle

地理空间数据的类型

正如卡莉·弗洛里纳所说,“目标是将数据转化为信息,将信息转化为见解”,因此了解和理解不同的数据类型非常重要。

地理空间数据可以分为两种类型:

  1. 地理空间参考数据:用矢量和栅格格式表示。
  2. 属性数据:由表格格式定义。

矢量数据:在经纬度对(坐标)上成对存储的数据集。这种数据形式的基本单位是点(0 维)、线(1 维)和多边形(2 维)。其中每一个都是一系列一个或多个坐标点-点的集合形成线单元,连接的闭合线环形成面。

  • 点:用于描述不同的数据和不相邻的特征。0 维,所以它们没有长度或面积的属性。点数据的示例有兴趣点(POI),即学校、购物中心、火山或医院等要素。

Geospatial data - points

New York Hospital point data map made by Aboze Brain | Kepler.gl

  • 线/弧:用于描述一组表示线性特征的有序坐标。一维,可以测长度(有起点和终点),但不能测面积。线数据的例子有河流、道路、等高线、边界线。

Geospatial data - lines

New York Centerline map made by Aboze Brain | Kepler.gl

  • 多边形:用于描述区域,本质上是二维的。多边形由构成边界的线和内部用于识别和概览的点来定义。多边形的例子有行政区、城市或森林的边界。

Geospatial data - polygon

New York Airport Polygons map made by Aboze Brain | Kepler.gl

栅格数据:该数据类型代表表面;它也被称为网格数据。“网格”由按行和列组织的代表信息的单元(像素)矩阵组成。基于数据,栅格数据以两种形式存在:离散栅格数据(如人口密度分布)和连续栅格数据(如温度或高程)。还有三种类型的栅格数据集:专题数据、光谱数据和影像。

  1. 专题地图显示了人类或自然特征的分布,主要以离散数据为主。
  2. 光谱图显示电磁波谱的特定波长,大多基于连续数据。
  3. 图像仅仅是卫星或航空照片。

Geospatial data - raster

New York Elevation data analysis made by Aboze Brain | Kepler.gl

以上示例中使用的所有数据集均来自纽约市开放数据门户

*属性数据:这些是用于描述地理空间特征的表格数据。表字段可以包含以下字段数据类型:

  • 整数值
  • 浮点值(十进制数)
  • 字符值(字符串/文本)
  • 日期值
  • 二进制大对象(BLOB ),用于存储图像、多媒体或代码位等信息

地理空间数据的格式

矢量数据和栅格数据都有各种文件格式,可通过文件扩展名进行区分。要跨多个平台处理地理空间分析和数据分析,您需要知道这些平台接受哪种文件格式。

以下是矢量和栅格数据文件格式的概述:

矢量数据格式:

栅格数据格式:

地理空间数据源

我们知道地理空间数据的类型,但是我们可以从哪里获得它呢?有很多网站,维基百科公布了获取地理空间数据的可靠来源 这里

用例:Python 作为地理空间数据科学的工具

让我们使用一些 Python 库进行地理空间分析。我们将使用 GeopandasPlotly 进行数据争论和可视化,并使用 Neptune AI 记录交互式地图,以实现以下目标:

  1. 地图上的散点图
  2. 等值区域图
  3. 密度热图
  4. 地图上的线条
  5. 地图上的研究区域

先决条件:

  • Python 3.7
  • Python 库——使用 PyPI 包管理器:

–地质公园

pip install geopandas

–Plotly express

pip install plotly-express

–海王星客户端

pip install --upgrade --quiet neptune-client
  • 此外,这些库可以安装有 Conda :

–地质公园

conda install geopandas

–Plotly express

conda install -c plotly plotly_express 

–海王星客户端

 conda install -c conda-forge neptune-client

数据来源:我从 Grid3 获取数据(地理参考基础设施和人口发展数据)。该计划提供高分辨率的人口、基础设施和其他参考数据,支持尼日利亚的国家部门发展重点、人道主义工作和联合国可持续发展目标。

本出版物的分析范围集中在尼日利亚的拉各斯。拉各斯是全球发展最快的城市之一,也是整个非洲的主要金融中心。

本文使用的代码、数据集等资源的链接可以在 这里 找到。

要在 Neptune AI 中记录交互式情节,您需要注册并创建一个新项目。创建一个帐户将为你提供自定义 API 证书,以正确集成 Neptune AI 的各种功能

随着您的 Neptune AI 帐户完全设置好并访问您的自定义 API,我们导入并初始化 Neptune。

在代码编辑器中,打开一个名为。env(注意前导点)并添加以下凭证:

API_KEY=<Your API key>

出于安全目的,这一点很重要,因为你不应该将你的秘密硬编码到你的应用程序中。创建一个 gitignore 文件并添加一个. env 文件。

import neptune.new as neptune
import os
from dotenv import load_dotenv
load_dotenv()

API_token = os.getenv("API_token")

run = neptune.init(project='codebrain/Geospatial-article',
                   api_token=API_token) 

注意: Dotenv 是一个将环境变量从. env 文件加载到进程中的模块。

执行这个代码块将为您提供一个将您的项目连接到 Neptune 的自定义链接,如下所示:https://app . Neptune . ai/code brain/Geospatial-analysis/e/GEOS-2

接下来,我们导入基本库并读取文件。要读入的文件格式都是 JSON 格式。数据框对应于卫生设施、行政边界和人口数据集。

接下来,我们导入基本库并读取文件。要读入的文件格式都是 JSON。读取的数据框对应于卫生设施、行政边界和人口数据集。

import pandas as pd
pd.set_option('display.max_columns', None)
import geopandas as gpd
import plotly.express as px

health_df = gpd.read_file('../Datasets/health-care.geojson')
adminstrative_df = gpd.read_file('../Datasets/lga.geojson')
pop_df = gpd.read_file('../Datasets/NGA_population.json')

了解每个数据集功能的概况是非常重要的。通过这种方式,您可以了解各种变量及其上下文含义和数据类型。

health_df.columns

Geospatial data - dataset features

Adminstrative_df.columns

Geospatial data - dataset features

pop_df.columns

Geospatial data - dataset features

让我们用与我们的分析相关的特征来清理各种数据框:

health_df = health_df[['latitude', 'longitude','functional_status','type', 'lga_name','state_name', 'geometry']]
adminstrative_df = adminstrative_df[['lga_name','state_name','geometry']]
pop_df = pop_df[['lganame','mean', 'statename','geometry']]
pop_df = pop_df.replace(to_replace=['Ajeromi Ifelodun', 'Ifako Ijaye','Oshodi Isolo' ], value=['Ajeromi/Ifelodun','Ifako/Ijaye', 'Oshodi/Isolo']).reset_index()
pop_df = pop_df.rename(columns={'lganame':'lga_name'})
pop_df.drop('index', axis=1, inplace=True)

就本指南而言,我们希望根据功能状态、每 100000 人口的医疗机构数量和医疗机构类型分布(一级、二级和三级)对医疗机构分布进行分析。因此,让我们从基础数据中创建这些特征:

health_pop = health_df.merge(pop_df, how='left', on='lga_name')
health_pop.drop(columns=['statename','geometry_x'],axis=1, inplace=True)
health_pop.rename(columns={'geometry_y':'geometry'}, inplace=True)
total_hospital_count=health_pop.groupby('lga_name')['geometry'].count().reset_index()
hosp_per_x = total_hospital_count.merge(pop_df, how='left', on='lga_name')
hosp_per_x.rename(columns={'geometry_x':'count', 'mean':'mean_pop', 'geometry_y':'geometry'}, inplace=True)
hosp_per_x['Health_facilities_per_100000'] = (hosp_per_x['count']/hosp_per_x['mean_pop'])*100000
hosp_per_x.drop(columns=['count','mean_pop', 'statename'], axis=1, inplace=True)
hosp_per_100000 = hosp_per_x[['lga_name','Health_facilities_per_100000']]

hosp_type_df = health_df.replace(to_replace=['Primary', 'Secondary','Tertiary' ],
                      value=[1,2,3]).reset_index()
hosp_type_df.drop('index', axis=1, inplace=True)

我们将使用 Mapbox maps 和 Plotly 进行分析。Mapbox 是一个面向开发者的地图和位置云平台,它为不同的应用提供端点。地图框自定义地图基础层将被用来提高我们的地图和访问定制功能的美感。来自地图框图库的弗兰克风格被用于各种地图

要连接这两个平台以获得 epic 结果,您需要一个 Mapbox 帐户和一个公共的 Mapbox 访问令牌。您可以在此 注册 ,获得您的公共访问令牌,如下所示:

构建交互式地图

散点图

该图显示了基于坐标的点数据分布。这里的主要目标是根据卫生保健设施的功能状况绘制其分布图。

fig1 = px.scatter_mapbox(health_df, lat="latitude", lon="longitude", color="functional_status", hover_data=["type", "lga_name"],
                       zoom=8, height=300,
                      labels={'functional_status':'Functional status of Health Facilities'},
                      center={'lat': 6.5355, 'lon': 3.3087}
)
fig1.update_layout(mapbox_style=style_url, mapbox_accesstoken=access_token)
fig1.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
run['interactive__scatter_plot_img'] = neptune.types.File.as_html(fig1)

注意:不同的运行时间和剧情将会保存在你的 Neptune AI 档案中。

每个运行时跟踪结果并模拟计算资源,如 CPU 和内存使用。

交互式散点图:

等值区域图

这是一张由彩色多边形组成的地图。它用来表示一个量的空间变化。此处,目标是显示案例研究区域(在拉各斯被称为地方政府区域(LGAs ))的各个分区中每 100000 人口的医疗保健机构数量的分布。

import json

f = open('/content/drive/MyDrive/Geospatial-article/Datasets/lga.geojson',)

geo_json_file = json.load(f)
fig2 = px.choropleth_mapbox(hosp_per_100000,
                    geojson=geo_json_file,
                    locations='lga_name',
                    color='Health_facilities_per_100000',
                    featureidkey="properties.lga_name",
                    range_color=(0, 100),
                    labels={'Health_facilities_per_100000':'Health Facilities_per_100000'},
                    zoom=8.5,
                    center={'lat': 6.5355, 'lon': 3.3087}
                         )
fig2.update_layout(mapbox_style=style_url, mapbox_accesstoken=access_token)

fig2.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
run['interactive__chloropleth_map_img'] = neptune.types.File.as_html(fig2)

氯普图的交互图:

密度热图

这张地图用颜色显示了一种现象的数量级,并带有明显的视觉线索,说明这种现象是如何聚集或随空间变化的。在这里,我们可以尝试在案例研究中可视化医疗保健设施类型的集群。

按键:

  • 1:初级保健设施
  • 2:二级保健设施
  • 3:三级保健设施
fig3 = px.density_mapbox(hosp_type_df, lat='latitude', lon='longitude', z='type', radius=10,
                       center={'lat': 6.5355, 'lon': 3.3087}, zoom=8.5,
                       labels={'type':'Health Facilities type'},
                       )
fig3.update_layout(mapbox_style=style_url, mapbox_accesstoken=access_token)
fig3.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
run['interactive__heatmap_map_img'] = neptune.types.File.as_html(fig3)

密度热图交互图:

地图上的线

有时为了在地图上进行分析,你可能需要在地图上画线,例如,解释距离或路线。这很容易做到,如下所示:

import plotly.graph_objects as go
fig4 = go.Figure(go.Scattermapbox(
   mode = "markers+lines",
   lat = [6.5095,6.6018, 6.4698],
   lon = [3.3711,3.3515, 3.5852],
   marker = {'size': 10}))
fig4.update_layout(mapbox_style=style_url, mapbox_accesstoken=access_token)
fig4.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig4.update_layout(mapbox= dict(
   center={'lat': 6.5355, 'lon': 3.3087},zoom=8.5 ))
run['interactive__line_on_map_img'] = neptune.types.File.as_html(fig4)

地图上线的交互绘制:

地图上的研究区域

就像地图上的线条一样,有时我们希望隔离某些区域来进一步研究它们。根据所需隔离区域的坐标,这些隔离在形状(多边形)上可以有所不同。这种隔离可以按如下方式进行:

fig5 = go.Figure(go.Scattermapbox(
   fill = "toself",
   lon = [3.297806, 3.295470, 3.349685, 3.346413], lat = [6.539536,6.488922, 6.488922, 6.542322],
   marker = { 'size': 10, 'color': "red" }))
fig5.update_layout(mapbox_style=style_url, mapbox_accesstoken=access_token)
fig5.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig5.update_layout(mapbox= dict(
   center={'lat': 6.5355, 'lon': 3.3087},zoom=10))
run['interactive__line_on_map_img'] = neptune.types.File.as_html(fig5)

研究区域交互图:

结论

就是这样!如果你做到了这一步,感谢你的阅读。我希望这篇文章对如何开始地理空间数据科学的新兴领域有一个全面的概述。感谢阅读!*

为什么 Git 不是 ML 模型版本控制的最佳选择

原文:https://web.archive.org/web/https://neptune.ai/blog/git-for-ml-model-version-control

如今,企业坐在一个数据池上,越来越多地使用机器学习和深度学习算法来预测销售、预测客户流失和欺诈检测等。,跨行业、跨领域。

数据科学从业者用算法、数据和超参数进行实验,以开发一个产生业务洞察力的模型。然而,实验和项目规模的增加,尤其是在大中型企业中,需要有效的模型管理。数据科学团队目前难以管理多个实验和模型,需要一种高效的方法来存储、检索和利用模型版本、超参数和性能指标等细节。

在本文中,您将了解到:

  • 困扰 ML 领域的挑战
  • 以及为什么传统工具不是解决这些问题的正确答案。

它将进一步建立在需要比较实验的基础上,这些实验要求数据科学团队的可重复性、可见性和全面协作。您将了解 Git 在维护不同模型版本方面的不足之处,并将看到提供所需功能的工具。

ML 模型版本化:我们在哪里?

简而言之,我们正处于一场数据革命之中。所有关键数据产品,如文本文档或图像的模型训练,都利用了高级语言和基于视觉的算法。有趣的是,神经网络的数学概念存在了很长时间,但直到现在,训练一个具有数十亿参数的模型才成为可能。让我们通过几个例子来理解这些突破性的发展。

最新的算法进步要求增加参数搜索空间

ImageNet ,流行的图像数据集,在深度神经网络的发展中起到了举足轻重的作用。从 2012 年 8 层的 AlexNet 开始,到 2015 年 152 层的 ResNet 深度神经网络随着时间的推移越来越深。更深的网络意味着更多的超参数、更多的实验,反过来也意味着更多的模型信息要以一种需要时可以很容易检索的形式保存。

ILSVRC winners

Winners of the ILSVRC | Source

与 MT-NLG(5300 亿个参数)和开关变压器(超过一万亿个参数)相比,GPT 3(1750 亿个参数)和 DALL-E(120 亿个参数)相形见绌。这些大型模型需要广泛的超参数搜索,包括隐藏层、神经元、退出、激活、优化器、退出、时期等的数量。

大型组织中的代码库扩展

让我们从谷歌提供的广泛产品和服务中了解人工智能倡议的规模。它的大多数产品都使用机器学习或深度学习模型来实现部分或全部功能。下面的图表展示了 2000-2015 年间提交到 Google 中央存储库的数量。

The chart with the number of commits to Google’s central repository

The number of commits to Google’s central repository during 2000-15 | Source

鉴于像谷歌这样的组织正在致力于人工智能的前沿创新,他们的知识库正在呈指数级增长。这意味着在给定实验规模的情况下,很难找到项目 Z 中模型 A 的性能指标。不仅性能指标,而且导致这些指标的超参数都很难找到,更不用说重现结果了。

管理不断膨胀的模型实验世界

  • 构建任何算法的前提都是产生商业价值,即企业努力将实验投入生产。从数据收集到生产环境中的模型输出的完整管道是这项工作成功的关键。
  • 在这个管道的不同阶段,可能会出现多种情况,从而减少这项工作的潜在收益。即使在模型训练阶段,超参数和性能指标的存储、检索和解释也会对最佳模型的选择产生不利影响。
  • 不仅为开发中的模型选择最佳的性能指标很重要,而且存储这些值也很重要。评估指标的简单修改,例如从“F1 分数”到“ROC”,要求重新运行管道并存储结果。
  • 现成算法的可用性并不意味着它们可以按原样使用。它需要在数据准备、探索、处理和实验方面付出巨大努力,包括尝试算法和超参数。这是因为这些算法已经在基准数据集上证明了很好的结果,而您的业务问题以及您的数据是不同的。其中一种算法可能比其他算法更好,但是您需要找到最佳配置。从寻找合适的架构和超参数的角度来看,最佳配置来自大量的实验。

需要正确的工具和流程来实现业务价值

正确的工具和流程对于促进团队中的知识传播至关重要。此外,维护模型版本将避免丢失模型细节的风险,以防最初的模型开发人员不再为项目工作。您还需要存储模型元数据和文档细节,如配置、流程和执行实验的意图。

这种工具的三个最重要的特征是可见性、可再现性和协作性。

能见度

理解可见性含义的一个简单方法是问以下问题。这些问题还将帮助您评估适合您项目的工具。

  • 1 项目经理可以查看正在培训的模型吗?
  • 2 哪个型号版本正在生产中运行?
  • 3 该车型在开发和生产中的表现如何?
  • 4 哪个指标用于优化模型参数?
  • 5 用了哪个数据版本来训练模型?
  • 哪些超参数产生了最佳指标?

既然我们了解了可视性共享模型的重要细节,那么让我们了解一下可视性的障碍是什么:

  • 分离的部分:数据、代码、配置和结果在项目的不同阶段生成。
  • 不同的工具:你的存储库由多个工具、库和基础设施提供商组成,比如 Azure、AWS 和 GCP。
  • 过时和稀疏的文档:通常,文档与模型工件分离,并存储在不同的地方。团队必须努力维护它,因此它很快就会过时。
  • 生产中的模型中断:通常,当模型从开发环境过渡到生产环境时,它们的表现不如在模型培训期间。在其他时候,他们只是打破。可能有多种原因,但主要是因为两个环境之间缺少模型和数据踪迹。

再现性

你需要能够重复实验的步骤并产生相同的结果。

以下因素会影响实验的再现性商数:

  • 传入数据的变化:培训、验证或测试数据的任何变化都可能导致不熟悉的结果,从而延迟组织的部署和价值实现。可能发生变化的一些情况是:
    • 根路径中缺少附加训练数据
    • 数据集改组会影响小批量或随机梯度下降优化结果的结果。
    • 训练和测试时随机选择不同的种子
  • 不一致的超参数:超参数值可以改变模型架构(树和网络),需要存储才能重现结果。
  • ML 框架的变化:ML 框架的不同版本或版本更新的使用会产生不一致的结果。像 Keras 这样的包在与不同的后端(PyTorch 或 Tensorflow)一起使用时会产生不同的结果。

合作

随着团队规模的不断扩大,协作也超越了电子邮件、信使和共享驱动器。通常,组织通过松散的渠道或团队来管理沟通。但是很有可能开发人员要么没有记住他们头脑中的所有信息,要么错过了一般的交流。这种通过聊天来共享最新代码版本的依赖会带来错误信息的风险,这会在质量或时间延迟方面对项目造成损失。

合作可能会面临多重障碍,如下文所述。

  • 当团队成员处理不同版本的代码时——最新版本的代码要么没有提交,要么共同开发人员忘记从服务器获取最新的代码。
  • 模型开发和部署团队可能没有使用最新的模型
  • 一个经常被忽视的因素是数据。数据在整个模型开发过程中不断生成。模型开发团队发现很难记录哪个数据集用于哪个模型版本

Git 是 ML 模型版本化的解决方案吗?

Git 是一个很棒的工具,它支持跨传统软件开发的代码版本控制和协作。但它不是在头脑中建立机器学习模型的。它是支持软件开发的极好工具,但不是为涉及数据、模型、工件等的机器学习工作流而设计的。

Git 的局限性列举如下:

  • Git 不保存模型细节,如模型版本、超参数、性能指标、数据版本等。您可能会在每次实验运行后推送模型结果和元数据,但是随着实验数量的增加,检索、比较和分析这些数据和元数据将很快成为一件痛苦的事情。
  • Git 也不能自动记录每个实验。你的每一个实验都自动将所有相关信息记录到一个存储库中,这难道不理想吗?
  • 选择 Git 来记录必要的细节会带来手工开销,需要为实验的意图和目的、算法的选择、超参数以及结果维护单独的文档。理想情况下,实验应该构成文档,即解释实验的内容、原因和方式。

我们为什么要超越 Git?

重要的是要注意软件开发和机器学习解决方案开发和部署之间的差异,因为它们构成了 Git for ML 局限性的症结。

software development life cycle vs. ML project life cycle

Differentiation between software development life cycle and ML project life cycle | Source

  1. 传统的软件开发遵循一种更简单的方法,在这种方法中,开发人员构建一种算法来解决一个业务问题,在这种方法中,它处理输入以产生期望的输出。另一方面,机器学习开发者利用数据来训练模型,然后部署所学习的模型来进行推断。

  2. 软件开发和机器学习开发之间的一个明显区别是,前者的输出是确定性的,而后者产生的是概率性的输出。因此,当发现与先前学习的偏差时,机器/模型必须通过结合新信息来不断学习。

  3. 回到机器学习模型的学习和再学习要求,任何涉及训练和推理的解决方案也需要严格的实验,主要是因为规则不是手工制作的。

  4. Git 旨在处理任何软件开发项目中通常使用的瀑布开发模型。代码中的任何迭代都会被系统很好地捕获。但是,当迭代不限于代码,并且您需要在一个包中一次对代码、数据、模型、性能指标以及超参数进行版本控制时,会发生什么呢?这是 Git 看起来令人乏味的时候,你需要超越它。

所有这些因素都有助于为机器学习工作流定制工具的需求。

  • 跟踪:每个数据从业者最起码的要求是记录每个实验的结果。但是你为什么要就此打住呢?当您更进一步,可视化不同实验的性能时,跟踪不同模型的性能会变得容易得多。这些有助于为所有利益相关者生成报告和仪表板,以进行监控、提供反馈并将结果呈现给企业。

  • 版本化:考虑一个案例,一个开发人员成功地构建了模型,并记录了指标来证明它的价值。现在,这个性能最佳的模型被部署到生产环境中。但是和其他任何代码一样,它肯定会崩溃。即使代码按预期运行,输出也可能不是这样。由于机器学习算法的黑盒性质,无声故障是常见的现象。

降级的模型性能要求原始作者查看潜在的原因,并将其重新提出来。开发人员在开发环境中运行模型以重现结果,但未能找到相应的代码库。这突出了记录整个元数据集的需要,这可以帮助开发人员在开发环境中追溯生产复制模型。理想的工具是跟踪和维护不同的模型版本以及整个元数据。

  • 文档:代码的原作者可能并不总是能够分享部署模型(或者任何其他存档模型,如果需要的话)的血淋淋的细节。因此,一个理想的工具提供了一个维护每次模型运行的所有相关细节的日志的平台。它节省了手动文档,并促进了 ML 项目的迭代性质,即从数据中学习并比较结果。

  • 平台无关:它应该无缝集成并与任何基础设施、工具或库一起工作。

ML 模型版本控制的 Git 替代方案

Alternative tools for Git

Alternative tools for Git | Source

虽然 Git 不是机器学习管道和解决方案的完美工具,但有一些工具可以解决机器学习团队面临的一些或所有挑战。下面将对它们进行讨论。

Neptune 支持研究和生产环境,是支持所有机器学习工作流的首选元数据存储。它建立在所有机器学习实验本质上都是迭代的特权之上。实验的规模要求数据科学家比较无数的模型,这有助于海王星通过促进监测和可视化它们的性能。

  • 提供跟踪这些实验的平台,以防止重复实施并促进再现性。
  • 促进交叉协作,并允许不同的团队成员通过共享 UI 链接在不同的项目上一起工作。
  • 支持内部版本和云版本。
  • 提供多种优势,如记录和显示所有元数据,如模型权重、超参数等。–最棒的是其用户友好的用户界面,提供无缝体验来比较和分析多个实验。

MLflow 是一个开源框架,它简化了端到端的机器学习流程,包括但不限于模型训练运行、在生产中存储和加载模型、复制结果等。它带有轻量级 API,支持任何机器学习库和编程语言,可以轻松地与任何代码集成。

MLflow 的优势在于其广泛的社区影响力和支持,这对任何开源平台都是至关重要的。它有四个关键组成部分

  • MLflow Tracking :记录并比较代码版本、模型参数和输出
  • MLflow Models :打包代码供下游使用——实时服务或用于推理目的的批处理结果
  • MLflow 项目:组织代码以重现结果,将模型部署到产品中,或者在团队中共享
  • MLflow Registry :是一个模型库,提供模型血统、模型版本、元数据、各模型开发阶段的标签等。

DVC 通过对模型、数据集和中间文件进行版本控制来支持机器学习项目的版本控制。

DVC's UI

DVC’s UI | Source: DVC

  • 支持广泛的存储系统,包括但不限于亚马逊 S3、Azure Blob 存储、Google Drive、Google 云存储等。
  • 保持对中间工件的缓存,这使得迭代多个实验和利用存档的代码、数据或模型变得容易。
  • 它不是将大文件存储在 Git 中,而是通过存储元数据、模型工件等来高效地工作。用吉特。
  • 最突出的是它的 GitOps 支持,即它工作在 Git 存储库之上,并将机器学习项目与 Git 工作流连接起来。

Weight & Biases 通过实现简单的模型管理、实验跟踪和数据集版本控制,加快了模型开发过程。

  • 提供与机器学习代码的无缝集成,并在仪表板上显示关键指标和统计数据。
  • 允许您跨不同的模型版本可视化模型结果,并通过协作报告创作这些结果。
  • 支持 PyTorch LightningKerasTensorflowHuggingFace 等等。与 Neptune 不同,Weights&bias 不提供超出免费学术和开源项目的免费版本。

权重和偏差的一个显著特征是,它会自动复制记录的数据集并对其进行版本化。

Comet 通过提供实验管理、模型管理和监控部署的模型,帮助组织加速和优化模型构建过程。

Comet's UI

Comet’s UI | Source: Comet

  • 与当前的技术体系相集成,并端到端地简化繁琐的模型构建流程,即从模型培训周期到生产运行。
  • 支持使用 Plotlymatplotlib 的自定义可视化,以及 30 多种可视化。
  • 在模型或数据漂移的情况下识别并警告系统,并在模型训练期间呈现关于基线模型性能的偏差。

它是一个开源的 web 仪表板,用于配置、组织、记录和复制机器学习实验。它旨在减轻模型开发人员维护不同实验的参数和设置的开销,从而使他们能够专注于模型开发的关键方面。

  • 虽然它可以部署在云中或内部,但不是作为托管服务提供的。
  • 鉴于它是免费提供的,它没有提供聊天或电子邮件帮助来满足企业需求。
  • 您可以通过一个名为 Omniboard 的 web 仪表板可视化来自多个实验的模型度量和日志。公会 AI 是圣斗士+全能的的有用替代品之一。

虽然这篇文章列出并分享了支持模型监控和维护的多个平台,但是没有标准的方法来选择一个。下面列出了一些可以帮助你做出决定的因素,这些因素应该是你的清单的一部分:

  • 1 易用性
  • 未来的版本
  • 3 产品愿景和增强功能
  • 4 管理员权限和访问
  • 5 易于设置和开始使用
  • 6 客户支持
  • 7 框架和编程语言不可知与否?
  • 8 势成规模

结束了!

在这篇文章中,我们从机器学习项目的角度讨论了 Git 的局限性。通过理解 Git 的不足之处和理想工具的样子,我们探索了市场上当前的选择以及它们之间的比较。我希望这篇文章已经让您清楚地了解了 Git 替代品的需求,以及在选择正确的替代品时您应该记住什么。

konrad 穿孔 ml 应用中的良好设计

原文:https://web.archive.org/web/https://neptune.ai/blog/good-design-machine-learning

不久前,Delivery Hero 的首席产品设计师 Konrad Piercey 是柏林 MLOps 社区会议的发言人之一。他谈到了 ML 应用中的良好设计——为什么它是一个日益增长的话题,它实际上意味着什么,以及如何开始实施它。

我们认为这是一个非常有趣的话题,我们肯定想了解更多。所以我们和康拉德坐在一起,问了他几个问题。下面是我们对话的效果!

顺便说一下,MLOps Meetups 在世界各地的不同城市越来越多。如果你感兴趣,你应该点击这里查看 MLOps 社区时间表。也许你的城市很快会有一个会议!你也可以组织一个——如果你有兴趣,加入 MLOps 社区 slack 频道

好了,现在,我们真的可以讨论 ML 中的设计了。

对于 ML 来说,什么是(好的)设计/UX?

Patrycja :从基础开始吧。ML 的设计/UX 是什么?对于 ML 有什么特别的吗,还是只是通常的设计?为什么你认为在 ML 的背景下谈论它很重要?

Konrad: 这里的想法是,机器学习的设计实际上不是一个现有的领域。没有机器学习设计师,只有机器学习和数据科学工程师。然后是产品设计师和 UX/UI 设计师,然后可能以某种方式对机器学习的一些元素做出贡献。但如果他们这样做了,这只是如何将机器学习集成到产品中的更大计划的一小部分。

机器学习设计的主要目标是帮助创造更好的体验以及机器和用户之间更好的关系。

我们怎么做呢?通过揭示幕后真相和系统运作方式。

因为机器学习,从它早期的原理来看,是在后台发生的事情。你看不到它在做一些计算,建立一些模型,产生一些输出时发生了什么。

  • 你不知道这是怎么回事。
  • 你也看不到你是如何影响模型的。

机器学习设计正在采用 UX/用户界面的一些基本原理,并将其应用于公司或产品如何集成机器学习背后的更大的产品战略。

所以你把 UX/用户界面和机器学习结合起来。

我认为,如果你问一个普通的技术人员什么是机器学习设计,他们可能不会提到许多与用户界面相关的东西,这就是我希望改变当前行业前景的地方。

为什么优秀的 ML 应用程序设计很重要?

Patrycja :你为什么认为这很重要?为什么你认为用户必须对 ML 应用有这种良好的体验,而不仅仅是获得模型的结果?

Konrad :首先,我认为我们应该陈述一个显而易见的事实,机器学习是令人着迷和惊奇的。一些最伟大的机器学习集成人们甚至没有意识到。忘记机器学习将成为我们大多数数字产品的未来吧。

  • 以无人驾驶汽车为例。没有机器学习,无人驾驶汽车永远不会存在。
  • 但在消费者层面,更基本的机器学习是手机上的自动纠错。它使用 ML 来确保建议正确的修正或正确的下一个单词。
  • 不过,我最喜欢的例子是垃圾邮件过滤器。没有机器学习,你的垃圾邮件过滤器就永远不会存在。所有那些可爱的说你中了彩票的电子邮件会直接出现在你的电子邮件收件箱的顶部,而不需要机器学习。

所以这些有不同程度的整合。为什么它令人兴奋,为什么我们现在需要关注它,是因为机器学习开始整合到更个性化的体验中,这些体验真正定义了与产品或服务的合作。你可以拿大多数大型消费应用来说,它们在某种程度上使用了机器学习。

无论是亚马逊、脸书、YouTube 还是网飞,所有这些公司都使用机器学习来推动参与度或销售额。因此,对于用户来说,理解他们与系统的交互如何影响他们的产品体验是很重要的。

“好的 ML 设计”是一个新事物吗?

Patrycja :你认为这需要引起企业的注意吗?它是全新的东西,还是人们已经认为,“好吧,我们需要以一种人们有这种良好体验的方式来设计它”?

Konrad :我认为,数据科学家和产品设计师试图对他们如何将 ML 属性集成到他们的产品或应用程序中保持谨慎并不完全是新鲜事。但它肯定没有想到需要考虑的深度,因为机器学习的含义现在可以在很大程度上影响事情,比如选举投票系统的关键基础设施或全国范围内的肥胖流行病。

这是现在机器学习影响的东西。我们不再只是谈论你的电子邮件收件箱垃圾邮件过滤器。我们谈论的是从根本上改变社会或人性的事情。而这只 随着时间增长。

思考它前进的速度也很重要。当它已经产生影响时,往往已经太晚了。所以你不能在事后才开始考虑机器学习的设计,因为一旦你建立了一个模型,它所产生的影响已经是广泛的了。

这可能是好的也可能是坏的。一个模式的广泛成功会有积极和消极的结果。

设计 ML 产品的最大挑战

Patrycja :你认为在设计 ML 应用程序时,以一种能给人们提供良好体验的方式,最大的挑战是什么?

Konrad :第一步是让团队了解模型是如何工作的。你用来驱动模型的数据点是什么,这些数据点是如何用来推动产品前进的?

通常,从我的经验来看,数据科学和机器学习并不经常有设计师(以用户为中心的人)进来代表用户,代表他们的价值观说话。所以我要说,这是日益严重的问题的一部分,但也是日益增长的机会。

Patrycja :谈一谈你的经历,能否提及你在交付英雄所做项目的一些具体挑战?

康拉德:当然。因此,在 Delivery Hero 中,我们运营着超过 12 种不同的食品配送应用程序。这 12 款送餐应用遍布 70 多个国家。我们影响了很多人。

例如,仅在一天之内,就有超过 50 万人在我们的平台上订购。说到产品的规模和影响,当我们的产品发挥作用时,我们已经影响了很多用户:

  • 他们摄入和吃了什么,
  • 潜在的习惯改变,
  • 他们如何思考和感知食物和饮食,
  • 和他们一天的其余时间(如果你吃了一顿非常丰盛的饭,你可能以后不想锻炼了,对吗?)

所以吃确实是我们人性、新陈代谢功能和情绪中错综复杂的一部分。

因此,在 Delivery Hero,我们希望越来越多地集成机器学习,因为组织的规模越来越大,我们影响了多少人。

在 Delivery Hero,我们正在研究机器学习,通过这种方式,我们可以引导用户找到更好的产品、更好的食物或他们想要订购的其他商品。它类似于任何其他电子商务平台。显然,我们正在努力销售,但希望不要带着任何负面的意图或系统固有的偏见去做。这是主要目标。

在 Delivery Hero,我们不会让人们变得更不健康。我们希望人们健康,但我们也希望人们找到他们渴望的东西,找到好吃的东西…喂野兽哈哈。

所以,现在送货英雄面临的挑战是找到用机器学习前进的最佳方式:

  1. 助力业务增长,
  2. 帮助人们找到他们想要的关于产品和食物的信息,
  3. 此外,还要创建一个系统,在用户使用我们的平台时,不会破坏他们的道德和价值观。

如何将良好的用户体验与业务目标结合起来?

王子:这个真有意思。你会看到 Delivery Hero 将其目标与用户目标结合起来。但是那里的商业动机是什么呢?

例如,如果用户有合适的食物,不会让他们暴饮暴食,他们就不会买那么多。这可能意味着更少的销售。

那么你们是如何将这两件事与你们的设计结合起来的呢?

Konrad :很多好问题。我想我们可以把它分成几个部分。我想你提到了一个部分——用户对品牌的感知,忠诚的品牌感知。

在这些不同的平衡领域中,我称之为:最大的平衡。这是在股东盈利能力和大型科技公司与道德上正确的事情之间取得平衡。

因为在任何大规模的业务中,你都是为了发展业务,让业务盈利。这仍在进行中。即使在《投送英雄》里,我也是股东,大部分员工也是,这就是难的地方。

要在股东盈利能力和用户最佳产品体验之间取得平衡,没有简单的答案。这就是为什么这是一个对话,一个我们一直在进行的对话。

但我认为大多数企业和组织并没有完全意识到他们的技术不断移动和变形的规模(对于我们 Delivery Hero 来说,这是围绕着我们不断增长的物流和食品行业)。用户越来越意识到他们与这些大规模企业的互动,无论是脸书、优步、拼车还是送餐。随着技术的发展,用户理解他们正在使用的产品(可能比制造产品的人慢一点)。但是用户明白:

  • “好吧,这些东西越来越聪明了”,
  • “这种体验,我的饲料,是为我量身定做的。”

用户,包括你和我,我们不傻,但我们并不总是知道技术是如何工作的。一旦用户意识到这项服务可能会滥用他们,这可能会对品牌忠诚度和品牌认知度产生巨大的负面影响。

所以如果我意识到:

1 无论结果如何,一项服务确实推动了销售,

  • 另一个建议购买物品,但它也说,“嘿,你可以设定你的预算,以确保你每个月都不会超支。我们知道不是每个人都有钱,所以让我们帮你谨慎消费。”
  • 我认为这种类型的产品设计价值正在快速增长,因为用户正在看到他们的数字服务发生了什么,以及他们如何经常被滥用。

例如,你现在可以看到反对脸书的骚动。它有许多竞争者,所以这不是脸书失去大量年轻观众的主要原因。但在很大程度上,这是因为品牌认知和产品体验。

谈到有大量应用程序,脸书并不是最新的一个。但是有了这个脚印,产品背后就有了一个挥之不去的阴影:

这意味着什么,

  • 它对人的影响,
  • 如何使用它。
  • 企业通过对用户更加诚实和开放来超越这一点,说:“看,我们在这里是为了盈利,但我们也想为你提供最好的价值和最好的体验”。

他们是怎么做到的?他们是如何通过应用程序体验、用户界面和 UX 来表达这种产品设计方法的?现在正在制作中。这是一个新的领域。如何以诚实和开放的方式吸引观众,同时不破坏以下核心商业价值:

How are they doing that? How are they voicing this approach to product design through the app experience, through the UI, through the UX? That is being crafted now. That is a new field. How to engage the audience in an honest and open way while not undermining the core business values of:

1 发展业务,

  • 2 销售增长,

  • 3 不断增长的参与度。

  • 王子:我想了解一下你们的目标是什么。您是否使用了任何指标,或者您是否看到了您开始时和现在之间的任何差异?

Konrad :我无法深挖那些关于 Delivery Hero 今天如何使用机器学习的错综复杂的小细节。其中很多仍然是知识产权,我们正在构建或测试的东西,我们希望暂时保持私有。

我能说的是大致的前景。我们今天希望构建和测试的一些东西是基于您如何使用系统和您周围的元素(地区,您所在的城市)的建议内容。)

所有这些因素都考虑在内,其中一些我们可以更准确地使用,一些则不太准确。但是这些数据点是基于你以前的购买或者你以前的搜索历史的建议。

我们接受这些,我们看这些,然后我们根据这些标准推荐材料。这与你现在使用的其他数码产品非常相似。

最基本的原则是,这就是谷歌搜索的工作方式。基于在你相似的国家,在一天中相似的时间,其他人如何搜索相似的单词。这些是以后产生搜索结果的数据点。而且你的搜索结果是非常精炼的。

当你着眼于消费者驱动的产品体验时(网飞或 YouTube)。这些功能都是专为您量身定制的。我们都会有不同的提要和内容。这是件好事,很有帮助。这正是机器学习应该做的。

不幸的是,机器学习也可以向你展示压倒性的内容或引导你进入回音室的内容。从食物方面来说,我们想推荐你正在寻找的内容。但是如果你经常在我们的平台上吃汉堡,我们向你推荐的只有汉堡。那不是一种健康的生活方式,我们不想那样做。

这就是这种平衡的来源。我们采用有助于打造个性化体验的数据点,但我们也平衡和了解有助于整体身体健康和福祉的其他方面。

Patrycja :也许回到你的具体项目。在理解 ML 的背景下或者这种需求下知道什么是引擎盖。世界不同地区的人们对这一点的要求有什么不同吗?

Examples of good design in ML - Delivery Hero

Examples of good design in ML – Delivery Hero | Copyright Konrad Piercey

Konrad :嗯,我不会说我们与 ML 的整合会从一个地区到另一个地区发生巨大的变化。我只能代表我的 ML 团队说一点,因为我不是直接的数据科学家或机器学习工程师。我是做设计的。我可以谈谈我们的合作和我们的目标愿景设定。关于我们在每个地区测试的具体型号,我不能具体说明。

但是,我想说,为每个国家建立某种完全不同的模式并不是更大的目标。你可以从用户体验的角度来考虑,新加坡市中心的一些人的饮食习惯将会与瑞典斯德哥尔摩的一些人的饮食习惯不同。

But, I would say it is not the larger goal to have some sort of radically different model for each country. You can think about it from a user experience side, the eating habits of somebody in the city center of Singapore are going to be different eating habits of somebody in Stockholm, Sweden.

1 该吃的东西

  • 一天中的时间
  • 3 吃的量
  • 他们和谁一起吃饭,
  • 他们多久一起吃一次饭。
  • 从设计的角度来看,这类事情更有趣。它们可能对机器学习模型(我们会用到)有一些影响。

ML 应用中好的和坏的 UX 实践的例子

所以你谈了一些关于 UX 中 ML 应用的不好的模式,比如建议太多不健康的食物或者试图让你永远看下去。

我想知道你认为可以做些什么来使它成为人们更积极的体验。ML 应用有哪些良好的 UX 实践?

Konrad :好的例子有点难找到,因为老实说,我们没有太多好的例子。但是我可以分享一些例子,你的观众可能已经看到了,并且已经参与了,但是他们没有意识到这是机器学习设计。T3

一些糟糕的例子是,你的参与程度不健康。如果你关注内容驱动的服务(无论是社交媒体还是新闻),你通常不会对自己的消费路径有所了解。

但现在,在你的手机上,你可以看到并设置单个应用程序的限制(“我只想用这个应用程序这么长时间”)。这是智能手机的新功能。这种情况并没有持续很长时间。你必须问自己——为什么现在会有这种情况?这是因为越来越需要它的存在。这是用户因为我们不健康的技术习惯而想要的。

你也可以在 YouTube 上看到这种情况。YT 有一个定时器,你可以设置它来提醒你,“你已经看了一个小时了。您是否仍想使用该服务?”。

抖音实际上有一些你不能打开或关闭的东西。对于一些用户来说,抖音直接在 feed 中测试视频。当你在不同内容之间转换时,一个人走过来说,“嘿,你看了很多内容。你为什么不休息一下,到外面去呼吸一些新鲜空气”。这很好,但是这也违背了促使用户更多参与的商业原则。非常有趣的是,看到行业如何推动这些健康习惯的概念。

因此,在这一点上,你会看到如果模型变得如此有效以至于现在对用户有害会发生什么。在某种程度上,机器学习模型几乎太好了。

这不是人们经常谈论的事情,但这就是正在发生的事情。这是非常进步的机器学习建模的概念。AI 和 ML 正处于模型几乎变得过于高效的时候。现在,人们(而不是机器)必须设置这些休息时间,比如“嘿,该休息一下了”,以及“嘿,你可能消费太多了”。

但正如普林斯所说,购买更多的东西,花费更多的时间,这违背了商业模式。是的,确实如此。但这是道德价值的判断,必须发生在设计、产品和体验方面。

Examples of good design in ML - Facebook | Copyright Konrad Piercey

Examples of good design in ML – Facebook | Copyright Konrad Piercey

设计和构建 ML 应用程序的过程

Patrycja :我明白了。所以现在,我想知道当设计师是团队中的额外人员时,你这边的流程是什么样的。工作流程是什么样的?你什么时候开始与 ML 团队和其他人合作?

Konrad :这是一个有趣的话题,因为在我的 Delivery Hero 团队中,我们有一个菜单,在这里你可以浏览特定供应商的产品,你想把东西添加到你的购物车中。

我们也在那个屏幕上提出建议。这里的想法是,随着菜单的增长,我们会提出越来越多类型的建议。呈现的菜单将更加个性化。为了重新组织呈现给你的东西,将会有更多来自模型的输入。

这实际上是任何送餐 app 的必经之路。即使在 Delivery Hero 之外,应用程序也将开始建议和个性化越来越多的内容。他们已经在这么做了。但这将成为产品体验中更大的一部分。

重要的是,在我的团队里,我们开始问问题:

What’s important is that on my team, we started asking questions:

机器学习究竟会在哪里出现并对用户产生影响?

  • 他们会因此受到怎样的影响,正面的还是负面的?
  • 你不只是看着机器学习说,好吧,我能为用户做什么,以便帮助他们找到他们正在寻找的价格点的产品。你必须问,只是在篮子里增加更多的产品有什么坏处吗?

在我们集成这项服务时,我们必须同时问这些问题。

整合机器学习并不都是正面影响。你必须权衡结果。就我们而言,我认为我们正在努力做的是在公司内部和外部教育其他设计师。

如果你知道你的团队正在使用机器学习,第一件事就是让自己了解:

这个模式是如何运作的,

  • 它使用了哪些数据点,
  • 然后它产生了什么。
  • 那么,什么是输入,什么是输出。机器学习就是这样,输入输出。因此,让你自己和你的产品团队了解这些标准。

从那里,您可以更好地理解模型如何集成,以及它能做什么或不能做什么。我并不是说让所有的设计师都成为机器学习专家,或者参加机器学习课程,而是要了解你的模型如何工作以及如何应用的基本原则。

从那里开始,实际上有三个步骤。机器学习中优秀设计的三个超级重要的步骤(我喜欢这么称呼它)GDML:

From there, there are actually three steps. Three super important steps to Good Design in Machine Learning (as I like to call it) GDML:

1 教育

  • 2 简单的

  • 3 好玩

  • 有了这三个原则或支柱,这就是我们如何定义和处理与机器学习的集成。因此,如果我们想在菜单上集成机器学习,我们会考虑如何通过告诉用户机器在建议什么或者为什么我们会这样建议来给用户带来一些有教育意义的东西。更详细地谈谈我们如何改变他们的饮食,或者我们给他们的建议对他们的习惯有什么影响。因为,这是机器和用户之间的双向关系。

我与系统的互动改变了系统。此外,系统向我展示的东西,它给我的东西,改变了我。作为回报,根据我交互和订购的内容,这将改变系统。这就是机器学习开始在用户和产品之间建立的共生关系。

但是同样,教育,简单,有趣:

教育——尝试向用户展示他们以前不知道的东西。试着教他们一些新的有价值的东西,这些东西不是自然理解的。那很有教育意义。

  1. 保持简单——如果我们想让用户了解与 ML 或后台模型相关的东西,我们不会教他们事物如何进入或如何出来的数据属性。我们并不是要写一本书或者让他们读一本关于这些复杂数学的书。

  2. 给他们看一个简单的图形。这通常是我们想要采取的方法。我们知道那句话:图片胜于千言万语。UX 副本在这里非常重要。我们不想对用户说教,我们想保持语言简单。

最后一个很有趣——我们需要增加这个,因为归根结底,机器学习、人工智能和深度学习可能是非常复杂的话题。而且我觉得对于很多人来说,如果不容易消化的话,可能天生就没什么意思。

  1. 所以试着找到一种方法来创造一些视觉语言或图形,使用有趣的颜色或有趣的动画来更人性化一点。我们想让一些用户脸上露出笑容(我认为这个世界通常需要更多的笑容)。因此,努力创造一个有趣的、引人入胜的体验也是其中的一部分。

王子:怎么让人想学?

康拉德:再次回到我们的价值观。这三种价值观或原则可以概括为两个词。

Konrad: Again, back to our values. Those three values or principles can be generally summarized in two words.

1 透明度

  • 2 交底
  • 每当我们接近 ML 集成时,透明和公开是我们的主要目标。我认为设计界也在以这种方式对待 ML/AI/DL。当有一台机器代表人们做决定时,我们希望变得透明和公开。

透明度和公开性实际上往往是各国法律中具有法律约束力的规则。这是许多大型组织没有意识到的 UX 原则的一个重要方面,这可能会使他们面临法律风险。如果我们看看联合国教科文组织(其中有 200 多个国家是成员国),他们实际上采用了有史以来第一个人工智能道德准则,该准则规定,“当一个决定是由人工智能算法告知或基于人工智能算法做出时,人们应该被充分告知”。

所以我们不是在抽象地谈论机器学习和设计。就像“我们也许可以在这里抄近路,在那里做一些事情”,这对用户来说可能不是最好的,但会对业务有所帮助。或者根本不考虑用户——这是一个可怕的想法。让我们只考虑增加参与度,并把它作为第一要务,这种策略不会让你走得很远,事实上,它可能会危及你的业务。

嗯,我想你会发现很快在许多国家,甚至企业(有时他们有自己的人工智能和人工智能内部指南)发布新更新的道德和指南规则。

因此,正如我所说,当基于人工智能算法做出决定时,人们应该被充分告知。

我们今天已经讨论过的大多数产品都是这样做的。他们建议内容或向你展示内容,并不是因为你一定想看这些内容,而是因为它假设你想看这些内容。这个假设是代表机器完成的。

当你不喜欢内容的时候,你有一些选择。有这个小汉堡菜单,或者三点菜单,你可以选择“嘿,我对这个不感兴趣”或者“别再给我看这个了”。

但是一般来说,这些算法隐藏在一个更深的菜单,一个更深的层后面,并且通常是基于每个内容的。这意味着我可以决定我是否想看这个视频或帖子,但它并没有给我任何整体的分析数据。我不知道我是如何在那里消费内容的,也不知道我会走哪条路。

在食品配送领域,实际上要容易得多。与社交媒体、新闻、音乐或电影相比,我们有更容易的指路明灯。嗯,人体有很简单的指导方针,告诉我们什么对我们好,什么对我们不好。当然,这因人而异。

但作为一个例子,世卫组织有一个公共卫生标准。其中一个数字是针对普通成年人的,他们每天应该摄入至少 400 克水果和蔬菜(这不是每个人的确切数字。这取决于你的体重、身高、所在地区以及其他因素。。因此必须采用当地标准)。

因此,无论是这些人工智能和人工智能道德准则,还是世卫组织的明确健康标准,用户都需要意识到他们的产品如何影响他们,以及机器如何代表他们做出决定。正如我们所说,即使是代表他们提出建议,这也很重要,因为他们在消费,他们在参与。

正如普林斯所说,这有时会很难,因为你必须在业务增长之间取得平衡。你不希望通过潜在的限制人们的选择来打消他们的兴趣。这不是送货英雄想做的。我们不想限制人们的选择。网飞或 Instagram 也不想阻止人们看电影或阅读帖子。

那不是限制内容的想法,要划清界限。只是通知用户而已。机器学习设计,或 GDML,就是关于这个的。不是说什么是对的或错的,而是引导用户获得更多的信息,以便他们可以更好地了解。我们只想通知。

ML 中好的设计下一步是什么?

Prince: 你谈到了基于机器学习的服务的局限性。我想知道,就好的 ML 设计而言,或者可能在接下来的几个步骤中,你是否看到对 ML 中的应用施加或添加限制或汇总统计成为一种标准?

Konrad :如果问题是我们是否想给用户关闭算法的能力,我认为这不会很快发生。我也不认为这是最好的选择。我认为给用户选择重置他们的算法,或者完全关闭它,可能不是那么有益。

例如,如果你拿你的 YouTube 账户来说,我不知道用户关掉他们的算法会有多大帮助。那会很奇怪。当然,如果他们真的想这么做,我可以建一个新账户,然后从头开始。但是 YouTube 上没有显示“重置我的算法”的按钮。它总是不断地反馈到你的消费中,无论是你的谷歌搜索历史还是你在 YouTube 上实际观看的内容。

我想说,可能这种增长趋势更多地是着眼于我们将向用户提供什么的更广泛的意识,例如,你提到的统计数据。让人们更广泛地了解机器对他们的了解,并让用户对此有所了解。再一次,回到 GDML 的第一原则。教育,显示了一些统计数据,将会是其中很重要的一部分。

我最喜欢的一个例子是,如果你使用 Spotify,也许你已经看过你的年终总结,他们称之为“总结”。你们看到了吗?那是 GDML。然而,这只是我们迄今为止讨论的好的设计机器学习的表面实现。你在 Spotify 上包装的年终总结向你展示了你对系统的影响,以及系统对你的影响。它显示你消费了多少首歌,听了多少小时。他们甚至可以把时间分成早上、下午和晚上。他们向您展示了您的数据在系统中的独特性。此外,根据它对你的建议,它会告诉你,“嘿,你已经发现了 x 位艺术家,对于那些听和你相似音乐的人来说,你属于这种类型的第 x 百分位。?"。这就是 GDML 的开始。

然而,我想强调一点,即使这是现代 GDML 的一个很好的例子,Spotify summary wrap 实际上并没有向用户显示任何更深层次的价值。它显示的是非常肤浅的数字,对用户没有任何帮助。只是有点意思。机器学习中良好设计的一个关键因素是教育用户一些真正有用的东西,而不仅仅是无意义的数据。

我与你分享的模拟视觉示例(食品交付应用程序,脸书,亚马逊)展示了我们如何通过向用户显示统计数据和相关数据,使用 GDML 带来更深层次的意义。在这些示例草案中,用户学到了一些对他们的生活、习惯、消费或购买有更深层次意义或价值的东西。

Spotify 是一个很好的例子,因为它表明了窥视算法背后意味着什么。这些统计数据显示了你和其他人相比一年中听了多少首歌等等。默认情况下,你永远不会知道。他们给你看这些是因为这很有趣,是关于你个人的。这就是人们喜欢它的原因。是关于我的。这说明了为什么我是特别的。但是它并没有超越信息的真正表层投射。

Examples of good design in ML – Amazon metrics

Examples of good design in ML – Amazon | Copyright Konrad Piercey

如何衡量设计改进是否影响用户?

在 ML 中实现了一些好的设计实践之后,你是否以某种方式测试或检查用户是否开始以不同的方式使用应用程序,或者他们限制了应用程序的使用?或者相反,也许他们在了解情况后会更多地使用它。有这个数据吗?

Konrad:Inside Delivery Hero 和我们的食品应用程序家族,我们在一段时间内不会知道真正的结果,但我们知道:

用户要求什么,

  • 我们正在构建的解决方案,
  • 以及我今天向你们展示的过程(教育,保持简单,尽量让它有趣)。
  • 以及那些试图变得透明和公开模型如何工作的原则。这些都是我们为客户提供正确产品的最大努力。

但是在影响和验证方面,我们如何知道我们所建立的是有意义的呢?嗯,有一些方法可以发现,有一些流程和标准是有帮助的。

你需要对比软的定性指标和硬的定量指标。

我们在这里讨论的是用户访谈与实时数据分析。比如人们在看了显示该系统使用情况的条形图后是否会更多地使用该产品,或者与下午相比,他们是否会在晚上吃更多的面条和披萨。

因此,在用户参与/看到与他们的机器学习算法相关的内容后,检查他们将如何继续参与产品。你可以通过数据分析了解一些情况。但是你也必须将它与用户访谈进行对比,因为其中一些不能仅仅通过基数来判断。你需要做采访和研究。所以花点时间在研究和用户研究上,从来都不是浪费时间。

So checking, after a user has engaged/seen content related to their machine learning algorithm, how they’re going to continue engaging with the product. You can tell some of that by data analytics. But you also have to contrast that against user interviews because some of that won’t be able to be told by just the base numbers. You need to do interviews and studies. So spending some time on research and user research is never a waste of time.

1 眼球追踪,

  • 2 停留时间,

  • 3 点击率、

  • 所有这些东西都非常有用。所有这些都可以帮助你验证你的 GDML 的影响。

关于点击率的使用,我会做一个具体的说明。假设你有一些 GDML 组件,帮助用户了解算法和产品体验:它是如何改变的,他们是如何改变的,以及它是如何改变他们的。如果您确实有一些特定组件,人们可以单击这些组件来了解更多关于他们的数据的信息,那么您应该让 CTA 是非侵入性的。所以它真的不应该在视觉上对用户尖叫,但如果他们想点击它并了解更多,它应该在那里。但它不应该对他们大喊大叫,“你现在需要看看这个!你应该调查你的数据,这听起来很可怕。

又来了。我们不想吓唬用户,也不想让这成为用户流或用户体验的重要部分。但最重要的是,如果他们想了解更多,我们会给他们机会去了解更多。我们没有隐藏这些东西。我们不想让人觉得我们隐瞒了任何可能影响他们身心健康的事情。

此外,值得一提的是,在许多情况下,公司不会故意隐藏这些信息。他们甚至不一定知道系统在做什么,或者对用户有什么影响。

让我们以美国的脸书为例——假新闻传播。他们不知道假新闻是一个问题,直到它已经是一个问题,并破坏了一场关键的美国大选。这表明,一旦大规模应用机器学习,效果会比你想象的快得多,因为这是机器学习和用户产品消费的本质。

如果是宣传信息、宣传销售或提出建议,我们应该知道:

这对用户有什么影响?

  • 作为一种产品,在我们知道对他们来说什么是好什么是坏之前,我们如何通知他们?
  • 这就是 GDML 如此强大的原因,它让用户了解信息,这样他们就可以决定他们认为什么对他们健康。

Patrycja :你之前说的在对用户进行产品教育之前,人也要对自己进行教育,这一点也很感人。在与他人分享这些信息之前,他们需要了解工具和算法在做什么。

是的,这是一些新的东西,设计师和产品人员必须开始在他们自己的内部流程中实施。就在五年前,我不必担心 ML 或深度学习或任何这种算法学习。这不是我作为设计师的过程或方法的一部分。

但现在,当机器学习被整合到几乎任何数字消费者体验中时,设计师真的必须向前迈出一步,开始参与这些对话。两人都学习 ML,一般来说(它是如何工作的),但也特别是在他们的团队内部(他们计划如何使用它,他们想要如何应用它)。这将是产品和设计领域新人不断增长的需求组合的一部分。

数据科学家和 ML 工程师如何帮助 UX 设计师?

Patrycja :根据你所说的,让我们来看看这个过程的另一面。机器学习的人,比如数据科学家和 ML 工程师,有什么可以做的,让你更容易以更好的方式设计这个产品?

Konrad :我想说,如果你是一名机器学习工程师或数据科学家,可以和你的产品或设计同事随便聊聊。在那里结交新朋友。

机器和用户之间、数据科学和 UX 之间的交互现在变得如此错综复杂,以至于我们很难理解如何最好地前进。这些东西现在才刚刚被定义。设计机器学习不是一个目前存在的行业。这是一个新兴领域。

所以,任何对此非常感兴趣的人,如果你想在这条曲线上领先,你必须知道如何以一种个人的,人性化的方式谈论信息,只有当你知道你在谈论什么的时候,你才能谈论它。这并不是号召每个设计师都成为机器学习工程师,或者每个机器学习工程师都去 UX 参加新兵训练营。

这是一种手挽手,共同前进,创造我们引以为豪的产品体验的方式。为我们之后的人,为我们的孩子,为你的祖父母,为那些很久以后的人创造产品,我们已经死了。

我们必须为正确的东西设立一个行业标准,因为我们不再创造静态的产品体验,这些产品在某种程度上是一种不断成长的有机体。

我们现在创造的产品体验本质上是移动的、灵活的和邪恶的。机器,我们最新的朋友,是其中的一部分。所以我们必须学会如何恰当地整合。

最重要的设计原则

王子:对,有道理!在我们结束之前,我想问你,在发布任何机器学习应用程序或你的第一个产品迭代之前,在设计 UX/UI 设计时,你最重要的三件事、原则或必备条件是什么?

康拉德:哇,我会说:

了解你的受众,成为你的受众。因为只有当你了解并能与你的用户和顾客产生共鸣时,你才能创造出美好的体验。所以这是最重要的。

这就是产品设计师的工作。

And that’s what being a product designer is.

1 试破产品,

  • 2 和你影响的人谈谈,

  • 如果可能的话,使用你正在建造的东西。那是一个超级重要的部分。

  • 我认为即使是今天的大企业也做得不够。有时很难确保每个从事产品工作的人都真正参与到产品中,使用它,并努力成为体验的一部分,而不是仅仅设计或构建一些你对最终体验没有什么看法的东西。

好的,最后一个问题是关于 GDML 社区或运动…

Konrad :运动…哈,听起来我正在组建一支军队,“如果你想加入 GDML 的行列,我会贴一张报名表”。

Patrycja :还没有,但是谁知道呢?

Konrad:GDML,我们发现这个短语最好地概括了我们对创造更好的用户体验的态度,其中涉及了人工智能、深度学习和人工智能,它代表了良好的设计机器学习。了解更多关于 GDML 的信息

我们想变好。我们想做好事。我们想设计好。对于 GDML,我们只是想找到其他对这个话题感兴趣的人。这是最主要的。有兴趣了解更多,有兴趣在这个领域进步的人。

目前,我在这个小组和我自己的特定领域担任伪版主,但我们急切地寻找工程师、数据科学家、设计师和其他任何希望在自己的公司帮助交流 GDML 或可能在自己的社区开始会面的人。

作为一份兼职,我也正在完成我的第一本书,关于 GDML 的,你可能已经猜到了。我们很有希望在不久的某个时候看到它的问世,但在它上架之前,我不会对此做过多评论。

Patrycja :好的,完美。谢谢分享经验!

Patrycja: Okay, perfect. Thank you for sharing your experience!

如何在 Google Colab 中处理文件:你需要知道的一切

原文:https://web.archive.org/web/https://neptune.ai/blog/google-colab-dealing-with-files

谷歌合作实验室是一个免费的 Jupyter 笔记本环境,运行在谷歌的云服务器上,让用户利用后端硬件,如 GPU 和 TPU。这使您可以在本地机器上托管的 Jupyter 笔记本中做任何事情,而不需要在本地机器上托管笔记本的安装和设置。

Colab 提供了(几乎)开始编码所需的所有设置,但是它没有开箱即用的数据集!你如何从 Colab 中访问你的数据?

在本文中,我们将讨论:

  • 如何从大量数据源向 Colab 加载数据
  • 如何从 Colab 内部写回那些数据源
  • Google Colab 在处理外部文件时的局限性

Google Colab 中的目录和文件操作

由于 Colab 允许您在本地托管的 Jupyter 笔记本中做您能做的任何事情,您还可以使用 shell 命令,如ls, dir, pwd, cd, cat, echo等等,使用 line-magic (%)或 bash(!).

要浏览目录结构,您可以使用左侧的文件浏览器窗格。

如何在 Google Colab 上上传和下载文件

由于 Colab 笔记本托管在谷歌的云服务器上,因此默认情况下,无法直接访问本地驱动器上的文件(不像笔记本托管在你的机器上)或任何其他环境。

然而,Colab 提供了各种选项来连接到几乎任何您能想到的数据源。让我们看看如何。

从 Google Colab 访问 GitHub

您可以将整个 GitHub 存储库克隆到您的 Colab 环境中,也可以通过原始链接访问单个文件。

克隆一个 GitHub 库

使用 git clone,您可以像在本地机器上一样将 GitHub 存储库克隆到您的 Colab 环境中。一旦存储库被克隆,刷新文件浏览器浏览其内容。

然后,您可以像在本地机器上一样简单地读取这些文件。

colab github repository

直接从 GitHub 加载单个文件

如果您只需要处理几个文件而不是整个存储库,您可以直接从 GitHub 加载它们,而不需要将存储库克隆到 Colab。

为此:

  1. 点击存储库中的文件,
  2. 点击查看原始数据
  3. 复制原始文件的 URL,
  4. 使用此 URL 作为文件的位置。

访问 Google Colab 的本地文件系统

您可以使用文件资源管理器或 Python 代码读取或写入本地文件系统:

通过文件浏览器访问本地文件

通过文件浏览器从本地文件系统上传文件

您可以使用 file-explorer 窗格顶部的 upload 选项将本地文件系统中的任何文件上传到当前工作目录中的 Colab。

要将文件直接上传到子目录,您需要:

1.当您将鼠标悬停在目录上方时,单击可见的三个点

2.选择“上传”选项。

colab upload

3.从“文件上传”对话框中选择您希望上传的文件。

4.等待上传完成。上传进度显示在文件浏览器窗格的底部。

colab upload progress

上传完成后,您可以像平常一样读取文件。

colab upload complete

通过文件浏览器将文件下载到本地文件系统

当鼠标悬停在文件名上方时,点击可见的三个点,然后选择“下载”选项。

colab download

使用 Python 代码访问本地文件系统

这一步要求您首先从google.colab library导入files模块:

from google.colab import files

使用 Python 代码从本地文件系统上传文件

您使用了files对象的上传方法:

uploaded = files.upload()

运行此命令将打开文件上传对话框窗口:

colab file upload

选择您希望上传的文件,然后等待上传完成。将显示上传进度:

colab file upload progress

uploaded对象是一个以文件名和内容作为键值对的字典:

colab file uploaded

上传完成后,您可以像阅读 colab 中的任何其他文件一样阅读它:

df4 = pd.read_json("News_Category_Dataset_v2.json", lines=True)

或者使用io库直接从uploaded字典中读取:

import io
df5 = pd.read_json(io.BytesIO(uploaded['News_Category_Dataset_v2.json']), lines=True)

确保文件名与您希望加载的文件的名称相匹配。

使用 Python 代码将文件从 Colab 下载到本地文件系统:

files 对象的download方法可用于将任何文件从 colab 下载到您的本地驱动器。将显示下载进度,下载完成后,您可以选择将其保存在本地计算机中的什么位置。

colab downloading

从 Google Colab 访问 Google Drive

您可以使用google.colab中的drive模块将整个 Google Drive 安装到 Colab,方法是:

1.执行下面的代码,它将为您提供一个身份验证链接

from google.colab import drive
drive.mount('/content/gdrive')

2.打开链接

3.选择您想要安装其驱动器的 Google 帐户

4.允许 Google Drive Stream 访问您的 Google 帐户

5.复制显示的代码,粘贴到如下所示的文本框中,然后按 Enter 键

colab import drive

一旦安装了驱动器,您将得到消息“Mounted at /content/gdrive”,并且您将能够从文件浏览器窗格浏览驱动器的内容。

colab drive

现在你可以和你的 Google Drive 进行交互,就好像它是你的 Colab 环境中的一个文件夹一样。对此文件夹的任何更改都将直接反映在您的 Google Drive 中。你可以像阅读其他文件一样阅读谷歌硬盘中的文件。

你甚至可以使用通常的文件/目录操作从 Colab 直接写入 Google Drive。

!touch "/content/gdrive/My Drive/sample_file.txt"

这将在您的 Google Drive 中创建一个文件,并且在您刷新它后,该文件将出现在文件浏览器窗格中:

从 Google Colab 访问 Google 工作表

要访问 Google Sheets:

1.您需要首先通过运行以下代码来验证要与 Colab 链接的 Google 帐户:

from google.colab import auth
auth.authenticate_user()

2.执行上述代码将为您提供一个身份验证链接。打开链接,

3.选择您想要链接的 Google 帐户,

4.允许 Google Cloud SDK 访问您的 Google 帐户,

5.最后,复制显示的代码并将其粘贴到显示的文本框中,然后按 Enter 键。

colab code

要与 Google Sheets 交互,需要导入预装的gspread库。为了授权gspread访问您的谷歌账户,您需要预装oauth2client.client库中的GoogleCredentials方法:

import gspread
from oauth2client.client import GoogleCredentials

gc = gspread.authorize(GoogleCredentials.get_application_default())

运行上述代码后,将在当前工作目录中创建一个应用程序默认凭证(ADC) JSON 文件。这包含了gspread用来访问您的 Google 帐户的凭证。

colab adc json

一旦完成,您现在可以直接从您的 Colab 环境中创建或加载 Google sheets。

在 Colab 中创建/更新 Google 工作表

1.使用gc对象的 create 方法来create工作簿:

wb = gc.create('demo')

2.工作簿创建后,您可以在sheets.google.com中查看它。

colab google sheets

3.若要将值写入工作簿,请先打开一个工作表:

ws = gc.open('demo').sheet1

4.然后选择要写入的单元格:

colab cells

5.这将创建一个包含索引(R1C1)和值(当前为空)的单元格列表。您可以通过更新单个单元格的值属性来修改它们:

colab cells values

6.若要更新工作表中的这些单元格,请使用 update_cells 方法:

colab cells values updated

7.这些变化现在将反映在您的 Google 表单中。

colab sheet

从谷歌工作表下载数据

1.使用gc对象的open方法打开工作簿:

wb = gc.open('demo')

2.然后使用get_all_values方法读取特定工作表的所有行:

colab rows

3.要将这些加载到 dataframe 中,可以使用 DataFrame 对象的from_record方法:

colab dataframe

从 Google Colab 访问 Google 云存储(GCS)

你需要有一个谷歌云项目(GCP)来使用 GCS。您可以通过预先安装的gsutil命令行实用程序在 Colab 中创建和访问您的 GCS buckets。

1.首先指定您的项目 ID:

project_id = '<project_ID>'

2.要访问 GCS,您必须验证您的 Google 帐户:

from google.colab import auth
auth.authenticate_user()

3.执行上述代码将为您提供一个身份验证链接。打开链接,

4.选择您想要链接的 Google 帐户,

5.允许 Google Cloud SDK 访问您的 Google 帐户,

6.最后,复制显示的代码并将其粘贴到显示的文本框中,然后按 Enter 键。

colab code

7.然后您配置gsutil来使用您的项目:

!gcloud config set project {project_id}

8.您可以使用 make bucket ( mb)命令创建一个存储桶。GCP 存储桶必须有一个全球唯一的名称,所以使用预安装的uuid库来生成一个全球唯一的 ID:

import uuid
bucket_name = f'sample-bucket-{uuid.uuid1()}'
!gsutil mb gs://{bucket_name}

9.一旦创建了 bucket,您就可以从您的 colab 环境向它上传一个文件:

!gsutil cp /tmp/to_upload.txt gs://{bucket_name}/

10.上传完成后,该文件将出现在您项目的 GCS 浏览器中:https://console.cloud.google.com/storage/browser?project=T4【project _ id>

!gsutil cp gs://{bucket_name}/{filename} {download_location}

下载完成后,该文件将出现在指定下载位置的 Colab 文件浏览器窗格中。

从 Google Colab 访问 S3 自动气象站

您需要有一个 AWS 帐户,配置 IAM,并生成您的访问密钥和秘密访问密钥,以便能够从 Colab 访问 S3。您还需要在您的 colab 环境中安装awscli库:

1.安装awscli

!pip install awscli

2.安装后,通过运行aws configure来配置 AWS:

colab access

  1. 在文本框中输入您的access_keysecret_access_key,然后按回车键。

然后你可以从 S3 下载任何文件:

!aws s3 cp s3://{bucket_name} ./{download_location} --recursive --exclude "*" --include {filepath_on_s3}

filepath_on_s3可以指向单个文件,或者使用一个模式匹配多个文件。

下载完成后将会通知您,并且下载的文件将会在您指定的位置提供,以供您随意使用。

要上传文件,只需颠倒源和目标参数:

!aws s3 cp ./{upload_from} s3://{bucket_name} --recursive --exclude "*" --include {file_to_upload}

file_to_upload可以指向单个文件,或者使用一个模式匹配多个文件。

上传完成后,您将会收到通知,上传的文件将会出现在您的 S3 存储桶的指定文件夹中:https://s3.console.aws.amazon.com/s3/buckets/{存储桶名称}/{文件夹} /?区域={区域}

从 Google Colab 访问 Kaggle 数据集

要从 Kaggle 下载数据集,首先需要一个 Kaggle 帐户和一个 API 令牌。

1.要生成您的 API 令牌,请转到“我的帐户”,然后“创建新的 API 令牌”。

2.打开 kaggle.json 文件,并复制其内容。应该是{ "username":"########", "key":"################################" }的形式。

3.然后在 Colab 中运行以下命令:

!mkdir ~/.kaggle 
!echo '<PASTE_CONTENTS_OF_KAGGLE_API_JSON>' > ~/.kaggle/kaggle.json 
!chmod 600 ~/.kaggle/kaggle.json  
!pip install kaggle 

4.一旦在 Colab 中创建了 kaggle.json 文件,并且安装了 kaggle 库,就可以使用

!kaggle datasets list -s {KEYWORD}

5.然后使用下载数据集

!kaggle datasets download -d {DATASET NAME} -p /content/kaggle/

数据集将被下载,并在指定的路径中可用(在本例中为/content/kaggle/)。

从 Google Colab 访问 MySQL 数据库

1.您需要导入预先安装的sqlalchemy库来使用关系数据库:

import sqlalchemy

2.输入连接详细信息并创建引擎:

HOSTNAME = 'ENTER_HOSTNAME'
USER = 'ENTER_USERNAME'
PASSWORD = 'ENTER_PASSWORD'
DATABASE = 'ENTER_DATABASE_NAME'

connection_string = f'mysql+pymysql://{MYSQL_USER}:{MYSQL_PASSWORD}@{MYSQL_HOSTNAME}/{MYSQL_DATABASE}'

engine = sqlalchemy.create_engine(connection_string)

3.最后,只需创建 SQL 查询,并使用pd.read_sql_query():将查询结果加载到 dataframe 中

query = f"SELECT * FROM {DATABASE}.{TABLE}"

import pandas as pd
df = pd.read_sql_query(query, engine)

Google Colab 在处理文件时的局限性

使用 Colab 时要记住的一个重要警告是,你上传到它的文件不会永远可用。Colab 是一个临时环境,空闲超时为 90 分钟,绝对超时为 12 小时。这意味着,如果运行时已经空闲了 90 分钟,或者已经使用了 12 个小时,它将断开连接。断开连接时,您会丢失所有的变量、状态、已安装的软件包和文件,并在重新连接时连接到一个全新的干净的环境。

此外,Colab 的磁盘空间限制为 108 GB,其中只有 77 GB 可供用户使用。虽然这对于大多数任务来说应该足够了,但是在处理像图像或视频数据这样的大型数据集时,请记住这一点。

结论

对于那些想要利用 GPU 等高端计算资源的能力,而不受价格限制的个人来说,Google Colab 是一个很好的工具。

在本文中,我们已经介绍了通过在 Google Colab 中读取外部文件或数据以及从 Google Colab 向这些外部数据源写入数据来增强 Google Colab 体验的大多数方法。

根据您的用例,或者您的数据架构是如何建立的,您可以很容易地应用上述方法将您的数据源直接连接到 Colab,并开始编码!

其他资源

如何管理和组织你在 Google Colab 中运行的 ML 实验

原文:https://web.archive.org/web/https://neptune.ai/blog/google-colab-version-organize-ml-experiments

自从 Google Colab 问世以来,进行 ML 实验从未如此简单。借助按需共享 GPU 实例的优势,它已经能够提供无缝体验来运行实验。然而,ML 实验带有跟踪和组织的自然要求,而 Colab 本身并没有提供这种要求。在这篇博客中,我们将涉及以下几个方面:

  • 1 为什么 Google Colab 中的版本实验很重要?
  • 2Google Colab 中版本实验的不同方式。
  • 3Neptune . ai 如何在 Google Colab 中帮助追踪实验?

为什么要对在 Colab 中运行的 ML 实验进行版本化?

构建 ML 模型本质上是实验性的,通常会运行大量实验来寻找算法、参数和数据预处理步骤的组合,从而为手头的任务产生最佳模型。一旦问题变得复杂,这就需要某种形式的组织。

在 Colab 中运行实验时,您会感觉到需要以与其他方式相同的方式进行版本控制。以下是一些要点,说明为什么您应该采用最佳实践,为您在 Colab 中的 ML 实验设置某种形式的版本控制:

Colab-versioning

Source

  1. 协作:在团队中工作需要决策过程中的协作努力,如果没有集中记录的实验细节,如模型元数据、度量等,这将是很麻烦的。这可以很好地适应 Google Colab 的共享功能,在那里你也可以协作编写代码。

  2. 再现性:如果您在某个地方记录模型配置,可以节省大量的重新训练和测试时间。通过拍摄整个机器学习管道的快照,可以再次重现相同的输出。

  3. 依赖跟踪:通过使用版本控制,您可以跟踪数据集的不同版本(训练、验证和测试),在不同的分支或存储库上测试多个模型,调整模型参数和超参数,并监控每个更改的准确性。

  4. 模型更新:模型开发不是一步到位的,它是循环往复的。在版本控制的帮助下,您可以控制发布哪个版本,同时继续开发下一个版本。

如何对运行在 Google Colab 中的 ML 实验进行版本化?

在 Colab 中有许多方法可以对实验进行版本控制,从简单的日志文件到提供大量功能的全面实验跟踪工具。让我们来谈谈每个类别中的一些,并了解什么是适合你的选择。

1.电子表格

Colab-version-spreadsheets

Source

在 Excel 或 Google 电子表格中跟踪 ML 实验是一种快速而强力的解决方案。电子表格提供了一种舒适、易用的体验,可以直接粘贴元数据并为多次运行创建多个工作表。但是它有很多警告,让我们看看它哪里有亮点,哪里没有:

赞成的意见

  1. 熟悉的界面易于使用。
  2. 可以在工具中直接为利益相关者创建报告。
  3. 对于团队中的非技术人员来说,做出贡献是一件好事。

骗局

  1. 在电子表格中跟踪实验是一件乏味的事情,您要么需要将模型元数据和指标复制并粘贴到电子表格中,要么使用 pandas 这样的模块来记录信息,然后保存到电子表格中。
  2. 一旦实验数量增加,在单独的表格中记录每次运行将变得难以管理。
  3. 在一个简单的电子表格中跟踪和管理无数的变量和工件并不是解决问题的最佳方式。

2.饭桶

Colab-version-git

Source

Git 预装在 Colab 会话中,您可以直接使用它来克隆或提交到存储库。这将使您能够推送与模型相关的元数据,如训练权重、评估报告(如混淆矩阵)等。到一个中央存储库,您的数据科学团队可以使用它来做出明智的决策。让我们来看看使用 Git 进行实验跟踪的优缺点:

赞成的意见

  1. Git 在 Colab 上的本机可用性意味着没有额外的依赖性或安装。
  2. 在数据科学家和 ML 实践者中流行和已知的工具。
  3. 允许访问数百万个其他存储库,这可以作为一个起点。

骗局

  1. 很难让非程序员和其他利益相关者参与进来。
  2. 不直观的界面可能会给协作工作带来摩擦。
  3. 需要技术专家来执行和维护与实验相关的知识库。

3.ML 实验跟踪工具

Colab-version-experiment-tracking-tools

Source

实验跟踪工具是为此用例定制的。它们几乎涵盖了你对工具的所有需求,从实验跟踪到模型注册。在过去的几年里,这个领域出现了很多工具,其中比较突出的有 neptune.ai、Weights and Biases 或 MLflow。让我们看看它们的一些优点/缺点:

赞成的意见

  1. 涵盖了您在管理和组织 ML 运行时需要的几乎所有功能。
  2. 所有这些工具都带有专用的交互式用户界面,可用于比较、调试或生成报告。
  3. 每个工具都为团队协作提供了过多的功能。

骗局

  1. 与 Git 或电子表格相反,实验跟踪工具通常需要付费。虽然几乎所有的都有一个针对单个用户的免费层,但它有其局限性。但另一方面,为工具付费意味着您不必担心安装、维护或开发功能。

让我们更深入地了解版本控制 Colab 笔记本在这些工具中是如何工作的。我们将重点关注 neptune.ai。

用 Neptune 跟踪 Google Colab 实验

Metadata-dashboard-artifacts

Example dashboard in Neptune with different metadata logged

neptune.ai 是一个 ML 元数据存储库,它是为运行许多实验的研究和生产团队而构建的。它有一个灵活的元数据结构,允许您以自己喜欢的方式组织培训和生产元数据。

它为您提供了一个中心位置来记录、存储、显示、组织、比较和查询机器学习生命周期中生成的所有元数据。个人和组织使用 Neptune 进行实验跟踪和模型注册,以控制他们的实验和模型开发。

该 web 应用程序专为管理 ML 模型元数据而构建,允许您:

  • 用高级查询语言过滤实验和模型。
  • 使用灵活的表格视图和仪表板定制您看到的元数据。
  • 监控、可视化和比较实验和模型。

Neptune 支持多种 ide 和笔记本,包括 Google Colab 。您可以直接使用实验跟踪的能力,而不必使用许多工具。

以下是您可以在 Colab 中使用 Neptune 跟踪的内容:

模型构建元数据

  1. 参数和模型配置–单值和字典结构(使用字典或 YAML 文件作为超参数的良好实践)。
  2. 指标–如准确性、精确召回率等。
  3. 模型检查点–Neptune 支持所有形式的检查点扩展,如. h5、.ckpt 等。

工件和数据版本

Neptune 的 track_files()方法可以用来记录任何文件的元数据。这种方法可以用来跟踪和版本化工件,比如您将存储在其他地方的中间数据样本和模型文件。

如果您希望从实验开始就上传所有以特定扩展名结尾的文件,您可以在启动 Neptune 实例时指定,它将在后台自动上传所有文件。

文件

Neptune 允许您无缝地记录中间实验文件,如图像和音频。以下是 Neptune 目前支持的一些文件格式(在撰写本文时):

  • 图片–png、jpg 等格式。
  • 交互式可视化——如 Matplotlib 图形。
  • HTML–从 HTML 字符串对象登录,或者直接上传文件。
  • 数组和张量–记录并显示为图像。
  • 表格数据–记录和预览 CSV 或 pandas 数据帧。
  • 影音——在海王星登录观看或收听。
  • 文本–以各种方式记录文本条目。

Git 信息

如果您已经按照上一节中讨论的方式在 Google Colab 会话中初始化了 Git,那么 Neptune 会从。git 目录,并将其记录在 source_code/git 名称空间下。

你可以以最简单的方式开始,前往Neptune&Google Colab docs了解更多信息。

为什么要用 Neptune 搭配 Google Colab?

对于许多用户来说,前述功能使 Neptune 成为 Google Colab 中实验跟踪器的默认选择。除了我们在上一节中讨论的技术特性之外,以下是使它成为该角色最佳竞争者的原因:

  1. 无缝集成:使用 Neptune python 模块,您可以将您的 Colab 会话与 Neptune 仪表板无缝集成。与其他方法相比,这减少了摩擦。

  2. 丰富的特性:海王星提供的特性让你可以自由地监控/记录/存储/比较任何你想让你的实验成功的东西。

  3. 免费层的可用性:免费层面向单个用户,免费提供重要功能。查看可用计划

  4. 社区支持:借助 Neptune 的积极社区支持,您可以更快地解决问题,并专注于构建模型。

前往 Google Colab 中的这个示例项目,查看 Colab 笔记本的实际支持。

你已经到达终点了!

恭喜你!你现在已经完全了解你需要什么样的理想方法来组织你的 ML 实验。在本文中,我们探索了简单的特别方法,如电子表格和 Git,以及更微妙的方法,如实验跟踪工具。以下是一些额外的提示,帮助您轻松选择下一个工具:

  1. 坚持自己需要的!很容易迷失在工具和方法的海洋中,但是坚持你的需求会帮助你做出更好的决定。
  2. 我建议在锁定任何一个解决方案之前,使用每个工具中的“免费试用”功能。

感谢阅读!敬请关注更多内容!再见!

GPT-3 或伯特能理解语言吗?深度学习语言模型的⁠—The 极限

原文:https://web.archive.org/web/https://neptune.ai/blog/gpt-3-bert-limits-of-deep-learning-language-models

当一个话题成为《卫报》观点文章的基础时,可以有把握地认为它是主流。不寻常的是,当这个主题是一个相当小众的领域,涉及应用深度学习技术来开发自然语言模型。更不寻常的是其中一个模特(GPT-3)自己写了这篇文章!

可以理解的是,这引起了一系列末日终结者式的社交媒体热议(以及一些对《卫报》的批评,指责其误导了 GPT 3 号的能力)。

对于像 NLP 这样的领域来说,这是一个罕见和意想不到的时间,成为"人工智能(AI)与人类辩论的前沿和中心。这个负担通常落在机器人身上(最近的自动驾驶汽车),因为更容易想象被人工智能驱动的机械怪物碾过或攻击。最初,可以生成文本的 NLP 模型似乎没有红眼终结者那么可怕。

然而,近年来在这一领域取得的快速进展已经产生了像 GPT-3 这样的语言模型。许多人声称,这些 LMs 理解语言是因为他们有能力撰写《卫报》评论文章、生成 React 代码,或者执行一系列其他令人印象深刻的任务

但是这些模型在简单的自然语言处理任务中表现得有多好呢?

真的有证据表明他们“明白”自己在说什么吗?

撰写《卫报》文章的 GPT-3 模型“理解”它所说的吗?

它能像人一样保护这块棋子吗?

学习新任务的能力有多强?

即使从纯粹实用的商业角度来看,理解这些模型的潜在限制也是很重要的。

  • 如果它们真的像宣传的那样好,那么你的企业立即开始采用这些技术是至关重要的,因为它们将比电报、电力或铁路等技术产生更大的变革影响。
  • 相反,如果它们被过度宣传,那么它可能会改变你在未来计划中如何看待和使用这些模型。

为了理解 NLP,我们需要看一下这些语言模型的三个方面:

  • 1 概念上的限制:阅读大量大量的文本是否有可能理解语言?如果我们试图理解人类是如何学习和使用语言的,那么机器仅从文本中学习的能力似乎会受到隐性限制。
  • 技术限制:即使这些模型有可能在语言任务中发展出类似人类的技能,但目前的模型适合这项工作吗?这些模型的底层架构是否使它们无法实现其全部潜力?
  • 评估限制:也许问题仅仅在于我们没有能力正确评估这些模型?目前的炒作是否与我们用来测试这些模型的 NLP 任务已经过时并且过于简单有关,因为该领域最近取得了快速的进步?

语言模型概念限制:我们能从文本中学到什么?

训练任何 DL 模型的大问题是数据。你通常需要很多。多少钱?越多越好,这也是最近大多数 LMs 追随的趋势。

不需要过多地研究每个模型的设计细节(我们将在下一节中讨论),我们可以认为一般的方法是通过阅读越来越多的文本来理解语言。

关键是文本不需要贴标签。相反,这些模型可以阅读一本书或一篇博客文章,并试图理解单词在上下文中的含义。例如,“深度学习”一词将主要用于与“机器学习”、“神经网络”或“人工智能”相关的事物。因此,模型将开始把这些术语视为具有某种相关的上下文。随着越来越多的数据,他们将开始了解更多术语的细微差别,或者这些相关术语之间的不同用法和含义。至少理论上是这样。

作为所需数据量的例子,让我们以 BERT 为例。发布于 2018 年,是近年来最具影响力的模型之一,结合了 28 亿字的维基百科数据和 8 亿字的图书语料库数据,使用了 3.4 亿个参数。

GPT-2 (该模型是太危险而无法发布)在 2019 年初跟随伯特,在 800 万个网页(~40 GB 文本数据)上进行训练,包含 15 亿个参数。相比之下,OpenAIs GPT(卫报写作模型)的最新版本 GPT-3 包含高达 1750 亿个参数,并在来自各种不同文本来源的 45TB 总数据集上进行训练。

像 GPT-3 这样的模型表明,某些任务的性能随着参数的增加而提高(在这个例子中,随着任务演示或指令的增加;图中的零个、一个或几个镜头)。但这是否意味着这些模型开始“理解”语言了呢? | 来源:【GPT-3】论文

从高层次来看,很容易看出这里的趋势:创建具有更多参数的模型,让它们消费越来越多的文本数据,模型将开始在人类层面上“理解”语言。

证据表明,这种方法似乎正在发挥作用。GPT-3 似乎是最先进的模型之一,它可以很好地执行各种不同的语言任务,而不需要更多的培训。

然而,最近的一篇论文对这种方法的可行性提出了一些有趣的担忧。

像 GPT-3 或伯特这样的语言模型能通过章鱼测试吗?

在他们的论文“攀登 NLU:论数据时代的意义、形式和理解”中,艾米丽·本德和亚历山大·柯勒考虑了像 GPT-3 或伯特这样的 LMs 是否能学会“理解”语言——不管他们能接触到多少文本或有多少参数来处理这些信息。他们提出的关键问题是形式和意义之间的关系。

根据他们的论文,形式是语言的可识别的物理部分。代表语言的标记和符号,如页面上的符号或网页上的像素和字节。

的意思是这些元素如何与外部世界的事物联系起来。这里需要注意的是,作者假设所讨论的模型只使用文本进行训练,而没有使用文本和图像的任何组合或其他表示外部世界的元素进行训练。从这个意义上说,就像 GPT-3 和伯特一样,这些模型试图只从形式中学习意义。

把它想象成塞尔中文教室实验(作者在论文中提到),仅仅从形式上学习就像试图用一种你一无所知的语言交流,因为教科书和字典都是用这种奇怪的语言编写的。这类似于当前的 LMs 试图通过查看大量文本数据来做的事情。

NLP limitations

Could a machine learn the intent of the Napolean pose from form alone? Locked in a room, reading only text could the machine identify that the statement referred to a particular type of pose?

你可能会问,这和章鱼有什么关系?

章鱼测试是一个有趣的思维实验,在论文中用来展示当前的 LMs 如何永远无法真正“理解”语言。你应该去看看这篇论文,它对实验有更详细的描述,这是思维实验力量的一个很好的例子,也是对充满疯狂方程式的 DL 论文的一个很好的改变。但它的要点是:

想象一下,一只章鱼 O 被放在两个人 A 和 B 之间,他们都被困在遥远的荒岛上,只能通过水下类似电报的系统进行通信。像 LMs 一样,章鱼可以监听 A 和 B 之间的对话。想象一下,它们这样做的时间足够长,可以说出 A 和 B 能够使用的几乎每个可能的单词、短语或句子。O 能以一种显示 O“理解”他们正在谈论的方式与 A 或 B 交流吗?

我们可以很容易地想象这样的场景,O 和 A 或 B 之间的琐碎对话看起来完全有效和合理。A 和 B 都不知道他们在和一只章鱼说话。GPT 3 号似乎能够做到这一点——以类似人类的方式与人交流。

然而,这只在一定程度上有效。想象一个不同的任务,其中 A 或 B 要求 O 建造一个重要的项目(如椰子弹射器),报告它如何工作,并提供潜在的改进建议。我们在这里可以开始看到,O 没有办法“理解”如何构建它,或者所需的项目看起来像什么。形式和意义之间没有联系。

同样,随着任务性质的改变,意义和形式之间的联系变得越来越重要,这也正是 O 开始显示语言局限性的地方。

当我们想象这些场景时,不难想到像伯特或 GPT-3 这样的 LMs 很难“理解”他们在说什么,因为他们缺乏形式和意义之间的联系。他们像拼图一样把东西连在一起,识别他们在过去看到的模式。但是他们并不真正明白他们在做什么,或者为什么。

人们可能会声称这对于许多 NLP 任务并不重要,或者我们并不真正需要关心这些模型是否“理解”事物,而是它们是否能够执行类似人类的任务。也许这是一个纯粹的学术讨论,与这些模型在商业意义上是否有用无关?

即使我们假设这些模型可以仅从形态中学习足够多的知识,以接近人类的水平执行,这可能仍然不够。如果这些模型的核心架构限制了它们学习的能力,甚至是单独学习的能力,那么它们是否“理解”它们在说什么就没有意义了。这就是我们接下来要看的。

语言模型技术极限:LMs 是“作弊”吗?

他们没有服用提高成绩的药物,但像伯特和 GPT-3 这样的 LM 模型可能会获得“不公平”的优势。为了理解这是如何可能的,我们需要深入像 BERT 这样的模型的底层架构的细节;变压器架构。

正是这种架构声称可以帮助 LMs 从他们接受训练的大量文本数据集中学习“上下文”。但如果看起来根本不是真的在学习“语境”呢?如果 LMs 发现隐藏在文本数据中的线索怎么办?

使用这些线索,学习模型可以在特定任务上表现良好,如问答、实体识别或情感分析,但它实际上只有非常有限的语言洞察力。

当我们对底层文本数据进行微妙的更改时,问题就出现了——这些更改不会影响人类的表现,但会使像 BERT 这样的 LMs 几乎“无言以对”。如果是这种情况,那么这些模型可能甚至难以学习形式或语言语义的关键部分,而它们需要在许多重要的语言任务中表现出色。

2012 年发表的一篇论文中的表格,该论文创建了一个基于规则的结构,使用否定等线索来更好地执行 NLP 任务。这是一个 LMs 可以用来在 NLP 任务中“作弊”的“线索”的例子。但是,如果变形金刚使用这些简单的机制,那么它可能会对其“理解”人类语言更复杂方面的潜力提出质疑。

语境科学

5 月 6 日,美国总统唐纳德·特朗普在椭圆形办公室的一次活动中发表了如下声明:

“这真是我们遇到的最严重的袭击。这比珍珠港事件还糟糕。这比世贸中心还糟糕。从来没有过这样的袭击。而且应该从来没有发生过。

他在说什么?新的战争?新的恐怖袭击?也许他的下一句话有助于澄清这一点:

“它本可以在源头上被阻止。在中国本来是可以制止的。它应该在源头就被阻止,但它没有。

还不清楚?好吧,总统在前面一段的话应该提供了所需的明确性:

“…这种病毒将会消失。这是一个何时的问题。会不会小范围卷土重来?会不会以一种相当大的方式卷土重来?但我们现在知道如何更好地应对它。”

这里的关键要点是背景很重要。如果你不记得前面的段落,那么你可能不知道总统说的是冠状病毒疫情。语言是棘手的,它可能是混乱的,在任何语言环境中,我们都需要不断更新我们的上下文“缓存”,以便我们可以从我们正在处理的单词中推断出意思。

从语言和实用的角度来看,溢出的咖啡都是“脏兮兮”的!动词“spill”根据上下文可能有不同的含义,因此我们需要不断更新上下文“cache ”,以了解在每个场景中“spill”指的是什么。例子来自丹尼尔·t·威灵汉姆的书《阅读思维:理解思维如何阅读的认知方法》

2017 年发表了一篇新论文,“注意力是你所需要的全部”,这永远改变了 DL NLP 的格局。它仍然是你读到的任何标题的前沿,关于一个新的模型在 NLP 任务中打破性能基准。

其中一个主要原因是神经网络设计,被称为转换器,允许模型在解析文本时更容易地捕捉上下文。这在过去是一项困难的任务,因为底层架构以顺序的方式解析文本。

这意味着它必须一个单词一个单词,一个句子一个句子,所以在一个大的文本语料库上训练是非常慢的。其次,这意味着维护任何形式的长期上下文在计算上都是非常昂贵的。参考上面总统的评论,这些模型很难存储早期的上下文,即“攻击”指的是冠状病毒。

在不涉及太多细节的情况下,Transformer 架构使用键、查询和值参数,这些参数使它能够知道文本的哪一部分与这个特定的上下文最相关。想想经典的“河岸”对“钱庄”的场景。在早期的模型中,单词的意思是静态的,它不会根据上下文而改变。所以“银行”这个词在“我把鱼竿放在河边了”和“我今天把钱存到银行了”这两个词中的意思是一样的。同样,如果没有背景,特朗普总统的评论可能会有很大不同。

《变形金刚》美不胜收。如果这个图让你害怕,不要担心,现在确切地知道它是如何工作的并不重要。从这张图中可以看出,有趣的是,变压器实际上由两部分组成:编码器和解码器。不同的模型将使用该架构的不同部分。例如,伯特使用编码器部分,而 GPT 模型使用解码器部分。来源:关注是你所需要的

这都是关于注意力

Transformer 架构利用一种称为“注意”的机制来解决 NLP 中的上下文问题。注意力之前已经被其他神经网络使用过多次,但 Transformer 的独特之处在于它只使用注意力从文本中学习(因此论文标题为“注意力是你所需要的”)。

以前的模型使用注意力作为他们方法的一部分,通常是以次要的方式。 Transformer 确实在注意力的理念上加倍努力,将单个注意力元素打包在一起,称为“注意力头”,形成多头注意力模块。然后,它将这些多头模块堆叠在一起,形成注意力层。

简而言之,将注意力头想象为能够“聚焦”在一个单词(或单词的一部分)上,它可以告诉模型该单词对于理解当前被解析的单词有多相关或重要。

更多的注意力意味着你的模型可以回顾(或展望)一个句子或段落中的更多单词。更多层次的关注意味着你的模型可以学习更高层次的句法结构和语义。

粗线表示被注意力集中器识别为与当前正在处理的单词的意思更相关的单词。所以“抹布”和“咖啡”比“和”或“得到”更影响“溢出”的意思。

任何神经网络基本上都是大量的矩阵乘法,注意机制在这里也没什么不同。下表显示了一个玩具示例,展示了单词“从关注层溢出的”的输出。

它通过将不同的权重矩阵相乘来实现这一点,每个权重矩阵“学习”一个权重,以尝试并识别句子中的哪些单词网络应该“注意”,因为它们对特定单词的上下文很重要。

Trisha 溢出 咖啡 向上 得到 a 破布

代表单词“溢出”的最终向量由表格中所示的所有其他单词的权重组成。注意,原始结果是通过 softmax 函数得到的,所以它们加起来都是 1。因此,表示“溢出”的最终向量将由它自己的大部分含义组成,但也包含表示“Trisha”和“coffee”等向量的一些含义或权重。如果这是像“Word2Vec”这样的静态单词嵌入模式,那么“溢出”的单词将 100%来自它自己的单一含义,即它根本不使用任何上下文。

我知道,这是对 Transformer 架构的一个旋风般的概述(更详细地理解它的一个很好的资源是 Jay Alammar 关于主题的优秀的博客文章)。但它留给我们两个关键的假设,我们可以做,这将支持 LMs 可以“理解”语言的说法:

  1. 像伯特和 GPT-3 这样的模型使用 Transformer 架构的注意力机制从基于文本的数据集中学习上下文
  2. 通过学习语境,这些模型发展了某种程度的语言“技能”,这使它们能够更好地完成一系列语言任务。

但是如果我们能证明这两个假设都存在疑问,那么就很难宣称这些模型能够发展出任何“理解”语言的能力。

伯特学——伯特学到了什么?

在他们 2019 年的论文“揭示伯特的黑暗秘密”中,作者深入研究了伯特的内部工作原理。他们的一个重要发现是 BERT 被过度参数化了。

作者通过禁用一个或多个注意力头,然后比较结果,对此进行了研究。他们的发现令人惊讶——移除注意力不仅不会影响结果,而且在某些情况下还会提高表现。

应该注意的是,并不是所有的 NLP 任务都是这样,去除一些注意力确实会对表现产生负面影响。但是这种情况发生的次数足够多,以至于作者们对 BERT 中如此多的注意力中心的相关性提出了质疑。

实验表明,你可以从 BERT 中的注意力层移除单个头部,它将在某些任务上执行相同或更好的任务。更令人惊讶的是,它们表明你可以移除整个层,即所有的注意力头,并且不会严重影响性能。

这提出了一些重要的问题。这些模型如何通过少量的注意力来学习语言的复杂性和细微差别?其他的大脑只是简单地储存他们以后使用的信息,而不是通过上下文学习规则和结构吗?

你可以说这意味着注意力是如此强大,BERT 只需要利用它的一小部分潜能就能在 NLP 任务中表现出色。

在下一节中,我们将更详细地研究这一说法,因为这也与评估数据集的结构有关。至少,这些发现让我们质疑简单地装载越来越多的注意力头是否会导致“理解”语言的模型。

相反,如果我们想开发真正理解语言的模型,我们可能需要修剪和重新设计这些网络。作为证据,参数巨头 GPT-3 背后的 OpenAI 团队在他们自己的论文中指出,我们可能会触及语言模型从更多参数和更多训练中学习的极限。

" 本文描述的一般方法的一个更基本的限制——扩大任何 LM 类模型,无论是自回归模型还是双向模型——是它可能最终会遇到(或可能已经遇到)预训练目标的限制

语言模型是作弊吗?

作弊呢?这与我们的主张有关,即这些模型能够通过上下文学习一些关于语言的东西,这有助于它们在 NLP 任务中表现得更好。

通过能够解析不同的句子,查看所有的单词,并以特定于上下文的方式识别出重要的单词,这些模型应该能够识别出特朗普谈论的是冠状病毒,而不是我们之前例子中的恐怖袭击。这将有助于他们在一系列 NLP 任务中表现出色,而这些任务以前超出了 NLP 模型的能力。

最近的一系列论文声称像 BERT 这样的模型并没有真正以任何有意义的方式理解语言。他们以一种创造性的方式展示了这一点,通过改变一些评估数据集,然后查看结果。首先,他们分析数据集,在这些数据集上,像 BERT 这样的模型表现得非常好,以至于它们在这项任务中超过了人类。然后他们以一种对结果解释没有影响的方式改变这些数据集。

例如,他们发现数据集中的许多短语含有否定成分,如“不”、“不会”或“不能”。使用简单的规则来“切断”这些标识符将导致高的总得分。论文作者随后改变了这些数据集,以便他们在保持数据集整体结构的同时移除这些“线索”。

对一个人来说,或者任何一个最初“恰当地”对任务进行推理的人来说,他们的分数不应该有很大的差异。这相当于说:

“没有下雨,所以我可以去跑步了”,

“下雨了,所以我不能去跑步了”,

也就是说,我们改变了最初的前提,但这不应该使推断正确答案的任务变得更加困难。

如果我们没有“作弊”,并且我们明白我们不能在雨中奔跑,那么我们应该在两种情况下都做出正确的推断。一个被否定的事实不应该导致我们做出错误的推断,但这正是伯特所做的。它没有表现出人类的水平,而是立即下降到比随机表现好不了多少。

现在我们知道伯特:

  • 不会用所有的注意力从上下文中学习,
  • 似乎不能用它所学到的来“推理”或“理解”语言
  • 它似乎使用统计“线索”,像否定术语“不”和“不能”,作为一种粗糙的启发式方法来获得更好的结果。

我们能责怪模型本身吗,还是测试人员有错?

语言模型评估限制:像伯特或 GPT-3 这样的模型有多好?

到目前为止,我们已经考虑了一个广泛的哲学问题:当前的深度学习 NLP 模型可以仅通过文本学习理解语言吗?

即使我们假设这些模型可以仅从文本中学习高水平的语言知识,我们也要看看支撑新 Transformer 架构的内部结构——这是最新进展的关键。我们表明,这些模型是否能够扩展到能够开发类似人类的语言知识的水平,还存在一些问题。

所有这些都基于这样一个假设,即我们可以通过某种方式测试这些模型,看看它们的表现如何。我们假设有数据集和基准可以告诉我们这些模型是否真的学会了可转移的、类似人类的语言技能。

我们已经看到,像 BERT 这样的模型可以在一些测试中“作弊”,但这是一个异常值还是现代 NLP 数据集很容易被当前的 DL LMs 套件选中?如果这些模型可以使用一些简单的技巧来获得高分,那么我们将很难知道这些模型是否真的在提高他们的语言能力。

问正确的问题

有许多 NLP 任务可以用来评估模型。一些,如命名实体识别(NER)和词类(POS),着眼于模型理解语言的句法和层次结构的能力。

它们代表了语言的核心部分,是高级语义发展的基础。如果我们想声称新的语言模型理解语言,那么我们想看看它们在更复杂、更高级的任务(如问答)中的表现。

在这里,模型需要理解上下文、推理和语义相似性。正如我们前面提到的,像 BERT 这样的模型已经在一些更高层次的复杂任务中表现出了类似人类的水平。

但是我们也看到了这些模型可以作弊。那么,这些模型仅仅是以比基准能跟上的更快的速度改进,还是显示出语言知识的真正迹象?

Google 发布的新数据集是一个很好的例子,说明我们需要如何开发新的基准并避免以前方法的缺陷。自然问题(NQs)数据集是一个 Q &数据集,旨在评估 LM 理解问题和解析一页文本(如维基百科页面)以找到潜在答案的能力。

关于这个数据集有趣的是作者采取的使 LMs 难以作弊的措施。这些措施表明,早期的基准和数据集可能使像 BERT 这样的模型很容易作弊。

作者采取的第一步是确保他们选择的问题是“真正的”问题。“真实”是指这些问题是人们在谷歌搜索中问的。我们对它们进行了审查,以确保它们格式良好、长度合理且连贯。

以前,像 SQuAD 这样的问答数据集会要求贡献者为给定的答案创建问题。因此,给定一段文字,创造一个问题,这一段代表答案。这可能导致“启动”,即参与者首先看到答案,然后提出与答案非常相似的问题。这使得模型很容易使用“线索”找到答案。

选择问题后,NQs 参与者会得到一页文字,并被要求指出:

  • 很长的回答,
  • 简短的回答,
  • 或者根本不可能在给定的文本中找到答案。

在某些情况下,一个答案可能既有涵盖相关问题各个方面的长答案,也有简洁地回答问题的短答案。

简短回答是包括一个或多个命名实体的简短文本。不包括答案的选项是 NQ 数据集的另一个关键区别步骤。早期的问答数据集,包括 SQuAD 的第一个版本,只包含有相应答案的问题。

一旦模型开始知道总有一个答案,那么它就可以利用这种信息找到答案,而无需真正测试其更高层次的语言技能。

更好的基准,更好的模型

幸运的是,NLP 社区似乎接受了我们需要像创建语言模型本身一样努力创建数据集和基准。

最近有许多论文关注于识别像 BERT 这样的模型如何利用一些经典 NLP 数据集中的弱点。

例如,在“因错误原因而正确”中,作者指出了 LMs 在没有真正理解语言基本规则的情况下,在 NLP 任务中获得高分的三种方式。他们确定了这些模型使用的三种试探法,这些试探法显示了它们缺乏理解(但由于构建较差的数据集,仍然可能导致高分):

  1. 词汇重叠:假设“医生由演员支付报酬”与“医生向演员支付报酬”相同,
  2. 子序列:假设“演员身边的医生跳舞了”和“演员跳舞了”一样,
  3. 成分:假设“如果艺术家睡了,演员跑了”和“艺术家睡了”是一样的

作为这项研究的结果,我们看到了更好的基准,如强力胶极限,在这些基准上,像伯特这样的模型很难实现类似人类的结果。这些进步与模型技术的进步一样重要,并将迫使这些模型“更加努力”以获得高分。

那么这些模型有多好呢?

这可能看起来很奇怪——我们研究了 LMs 的理论、技术和评估限制,现在我们将赞扬他们的成就。

问题是,通过提问,我们在推测这些模型的最终潜力。这是一个很高的标准,因为我们正在考虑这些模型是否会获得一种通用的人工智能形式,在这种形式中,它们可以在没有进一步训练的情况下学习新的任务,建立在它们当前的语言技能上,并以一种显示它们理解自己在说什么的方式与人类交流。这是令人兴奋的东西,提示终结者一样的 gif。

需要澄清的关键问题是虽然我们可能会质疑它们像人类一样理解语言的能力,但毫无疑问,当前的变形金刚模型,如 BERT,已经比任何人在四五年前预测的更远更快地推进了 DL NLP 的前沿。事实上,这些模型可以“作弊”,并且似乎只使用了他们注意力的一小部分来很好地完成 NLP 任务,这表明他们已经走了多远。

但这也增加了过度宣传这些模型的危险。也许他们永远也不会达到和你我一样的语言理解水平。也许他们不需要。

也许这些模型只需要开发更多的统计线索,它们将足以通过一系列聊天机器人和自动化 NLP 应用程序来改变商业格局,这些应用程序改变了我们搜索和使用信息的方式。他们可能不足以在短期内赢得普利策奖,但我们仍然只是触及了他们未开发潜力的皮毛。

梯度推进决策树[指南]:一个概念性的解释

原文:https://web.archive.org/web/https://neptune.ai/blog/gradient-boosted-decision-trees-guide

梯度推进决策树已被证明优于其他模型。这是因为 boosting 涉及实现几个模型并聚合它们的结果。

由于在 Kaggle 上的机器学习比赛中的表现,梯度增强模型最近变得很受欢迎。

在这篇文章中,我们将看到梯度提升决策树是怎么回事。

梯度推进

梯度提升中,弱学习器的集合用于提高机器学习模型的性能。弱学习者通常是决策树。结合起来,它们的输出会产生更好的模型。

在回归的情况下,从所有弱学习者的平均值产生最终结果。通过分类,最终结果可以被计算为来自弱学习者的大多数投票的类。

在梯度推进中,弱学习者顺序工作。每个模型都试图改进前一个模型的误差。这不同于 bagging 技术,在 bagging 技术中,几个模型以并行方式拟合数据子集。这些子集通常随机抽取并替换。装袋的一个很好的例子是在随机森林中。

升压过程看起来是这样的:

  • 用数据建立一个初始模型,
  • 对整个数据集进行预测,
  • 使用预测值和实际值计算误差,
  • 给不正确的预测分配更多的权重,
  • 创建另一个模型,尝试修复上一个模型的错误,
  • 使用新模型对整个数据集运行预测,
  • 创建多个模型,每个模型旨在纠正前一个模型产生的错误,
  • 通过加权所有模型的平均值获得最终模型。

机器学习中的助推算法

我们来看看机器学习中的 boosting 算法。

adaboost 算法

AdaBoost 将一系列弱学习者与数据进行拟合。然后,它给不正确的预测分配更多的权重,给正确的预测分配更少的权重。通过这种方式,算法更加关注难以预测的观察结果。最终结果是从分类中的多数票,或回归中的平均值获得的。

您可以使用 Scikit-learn 实现这个算法。“n_estimators”参数可以传递给它,以指示所需弱学习器的数量。您可以使用“learning_rate”参数来控制每个弱学习者的贡献。

默认情况下,该算法使用决策树作为基本估计器。可以调整基本估计器和决策树的参数来提高模型的性能。默认情况下,AdaBoost 中的决策树只有一次拆分。

使用 AdaBoost 分类

您可以使用 Scikit-learn 中的“AdaBoostClassifier”来实现 AdaBoost 模型以解决分类问题。正如您在下面看到的,基本估计器的参数可以根据您的喜好进行调整。分类器也接受您想要的估计数。这是模型所需的决策树数量。

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier
base_estimator=DecisionTreeClassifier(max_depth=1,criterion='gini', splitter='best', min_samples_split=2)
model = AdaBoostClassifier(base_estimator=base_estimator,n_estimators=100)
model.fit(X_train, y_train)

使用 AdaBoost 进行回归

将 AdaBoost 应用于回归问题类似于分类过程,只是做了一些表面上的改变。首先,您必须导入“AdaBoostRegressor”。然后,对于基本估计量,您可以使用“DecisionTreeRegressor”。就像上一个一样,你可以调整决策树回归器的参数。

from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import AdaBoostRegressor
base_estimator = DecisionTreeRegressor(max_depth=1, splitter='best', min_samples_split=2)
model = AdaBoostRegressor(base_estimator=base_estimator,n_estimators=100)
model.fit(X_train, y_train)

Scikit-learn 梯度增强估计器

梯度提升不同于 AdaBoost,因为损失函数优化是通过梯度下降完成的。和 AdaBoost 一样,它也使用决策树作为弱学习器。它也依次适合这些树。添加后续树时,使用梯度下降将损失降至最低。

在 Scikit-learn 实现中,您可以指定树的数量。这是一个应该密切关注的参数,因为指定太多的树会导致过度拟合。另一方面,指定很少数量的树会导致拟合不足。

该算法允许您指定学习率。这决定了模型学习的速度。低学习率通常需要模型中有更多的树。这意味着更多的训练时间。

现在让我们看看 Scikit-learn 中梯度增强树的实现。

使用 Scikit-learn 梯度增强估计器进行分类

这是使用“GradientBoostingClassifier”实现的。该算法预期的一些参数包括:

  • 定义要优化的损失函数的“损失”
  • 确定每棵树贡献的“学习率”
  • ` n_estimatorst '表示决策树的数量
  • “最大深度”是每个估计器的最大深度
from sklearn.ensemble import GradientBoostingClassifier
gbc = GradientBoostingClassifier(loss='deviance', learning_rate=0.1, n_estimators=100, subsample=1.0, criterion='friedman_mse', min_samples_split=2, min_samples_leaf=1)
gbc.fit(X_train,y_train)

拟合分类器后,您可以使用“feauture _ importances _”属性获得特征的重要性。这通常被称为基尼系数。

gbc.feature_importances_

Gradient boosted decision tree feature import

值越高,特性越重要。获得的数组中的值总和将为 1。

注意:基于杂质的重要性并不总是准确的,尤其是当有太多的特征时。在这种情况下,您应该考虑使用基于排列的重要性

使用 Scikit-learn 梯度增强估计器进行回归

Scikit-learn 梯度增强估计器可使用“GradientBoostingRegressor”实现回归。它采用类似于分类的参数:

  • 损失,
  • 估计数,
  • 树木的最大深度,
  • 学习率…

…仅举几个例子。

from sklearn.ensemble import GradientBoostingRegressor
params = {'n_estimators': 500,
          'max_depth': 4,
          'min_samples_split': 5,
          'learning_rate': 0.01,
          'loss': 'ls'}
gbc = GradientBoostingRegressor(**params)
gbc.fit(X_train,y_train)

像分类模型一样,您也可以获得回归算法的特征重要性。

gbc.feature_importances_

海王与斯克利亚
T2 的融合

XGBoost

XGBoost 是一个支持 Java、Python、Java 和 C++、R、Julia 的渐变增强库。它还使用弱决策树的集合。

这是一个通过并行计算进行树学习的线性模型。该算法还附带了用于执行交叉验证和显示特性重要性的特性。这种模式的主要特点是:

  • 接受树增强器和线性增强器的稀疏输入,
  • 支持自定义评估和目标函数,
  • “Dmatrix ”,其优化的数据结构提高了性能。

让我们看看如何在 Python 中应用 XGBoost。该算法接受的参数包括:

  • “目标”定义任务的类型,比如回归或分类;
  • colsample_bytree构造每个树时列的子采样比率。子采样在每次迭代中发生一次。这个数字通常是 0 到 1 之间的一个值;
  • “learning_rate ”,确定模型学习的快慢;
  • ` max_depth '表示每棵树的最大深度。树越多,模型越复杂,过度拟合的机会就越大;
  • ` alpha '是权重上的 L1 正则化;
  • “n_estimators”是要拟合的决策树的数量。

使用 XGBoost 分类

导入算法后,您可以定义想要使用的参数。因为这是一个分类问题,所以使用“二元:逻辑”目标函数。下一步是使用“XGBClassifier”并解包定义的参数。您可以调整这些参数,直到获得最适合您的问题的参数。

import xgboost as xgb
params = {"objective":"binary:logistic",'colsample_bytree': 0.3,'learning_rate': 0.1,
                'max_depth': 5, 'alpha': 10}
classification = xgb.XGBClassifier(**params)
classification.fit(X_train, y_train)

使用 XGBoost 进行回归

在回归中,使用“XGBRegressor”。在这种情况下,目标函数将是“reg:squarederror”。

import xgboost as xgb
params = {"objective":"reg:squarederror",'colsample_bytree': 0.3,'learning_rate': 0.1,
                'max_depth': 5, 'alpha': 10}
regressor = xgb.XGBRegressor(**params)
regressor.fit(X_train, y_train)

XGBoost 模型还允许您通过“feature_importances_”属性获得特性的重要性。

regressor.feature_importances_

Regressor feature import

您可以使用 Matplotlib 轻松地将它们可视化。这是使用 XGBoost 中的“plot_importance”函数完成的。

import matplotlib.pyplot as plt
xgb.plot_importance(regressor)
plt.rcParams['figure.figsize'] = [5, 5]
plt.show()

“保存模型”功能可用于保存您的模型。然后,您可以将这个模型发送到您的模型注册中心。

regressor.save_model("model.pkl")

查看 Neptune 文档,了解与 XGBoost 和 T2 matplotlib 的集成

LightGBM

LightGBM 与其他梯度推进框架不同,因为它使用逐叶树生长算法。已知逐叶树生长算法比逐深度生长算法收敛得更快。然而,他们更容易过度适应。

该算法是基于直方图的,因此它将连续值放入离散的箱中。这导致更快的训练和有效的存储器利用。

该算法的其他显著特征包括:

  • 支持 GPU 训练,
  • 对分类特性的本机支持,
  • 处理大规模数据的能力,
  • 默认情况下处理缺失值。

让我们来看看这个算法的一些主要参数:

  • max_depth每棵树的最大深度;
  • 默认为回归的“目标”;
  • learning_rate提高学习率;
  • ` n_estimators '要拟合的决策树的数量;
  • device_type无论你是在 CPU 上工作还是在 GPU 上工作。

LightGBM 分类

训练二元分类模型可以通过将“二元”设置为目标来完成。如果是多分类问题,则使用“多类”目标。

数据集也被转换成 LightGBM 的“数据集”格式。然后使用“训练”功能完成模型训练。您还可以使用“valid_sets”参数传递验证数据集。

import lightgbm as lgb
lgb_train = lgb.Dataset(X_train, y_train)
lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train)
params = {'boosting_type': 'gbdt',
              'objective': 'binary',
              'num_leaves': 40,
              'learning_rate': 0.1,
              'feature_fraction': 0.9
              }
gbm = lgb.train(params,
    lgb_train,
    num_boost_round=200,
    valid_sets=[lgb_train, lgb_eval],
    valid_names=['train','valid'],
   )

用 LightGBM 回归

对于使用 LightGBM 的回归,您只需要将目标改为“回归”。提升类型默认为梯度提升决策树。

如果您愿意,您可以将其更改为随机森林,“dart ”-漏失符合多重加法回归树,或“Goss ”-基于梯度的单侧采样。

import lightgbm as lgb
lgb_train = lgb.Dataset(X_train, y_train)
lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train)
params = {'boosting_type': 'gbdt',
              'objective': 'regression',
              'num_leaves': 40,
              'learning_rate': 0.1,
              'feature_fraction': 0.9
              }
gbm = lgb.train(params,
    lgb_train,
    num_boost_round=200,
    valid_sets=[lgb_train, lgb_eval],
    valid_names=['train','valid'],
   )

您还可以使用 LightGBM 来绘制模型的特征重要性。

lgb.plot_importance(gbm)

LightGBM 还有一个用于保存模型的内置函数。该功能是“保存模型”。

gbm.save_model('mode.pkl')

海王星与 LightGBM 的融合

CatBoost

CatBoost 是 Yandex 开发的深度梯度推进库。该算法使用不经意决策树生成一棵平衡树。

它使用相同的特征在树的每一层进行左右分割。

例如,在下图中,您可以看到“297,值> 0.5”被用于该级别。

Gradient-boosting-catboost

CatBoost 的其他显著特性包括:

  • 对分类特性的本机支持,
  • 支持在多个 GPU 上训练,
  • 使用默认参数会产生良好的性能,
  • 通过 CatBoost 的模型应用程序进行快速预测,
  • 本机处理丢失的值,
  • 支持回归和分类问题。

现在让我们来看看 CatBoost 的几个训练参数:

  • loss_function用于分类或回归的损失;
  • eval_metric模型的评估度量;
  • ` n_estimators '决策树的最大数量;
  • ` learning_rate '决定模型学习的快慢;
  • “深度”,每棵树的最大深度;
  • ` ignored_features '确定在训练期间应该忽略的特征;
  • ` nan_mode '将用于处理缺失值的方法;
  • cat_features分类列的数组;
  • 用于声明基于文本的列的“text_features”。

使用 CatBoost 分类

对于分类问题,使用“CatBoostClassifier”。在训练过程中设置“plot=True”将使模型可视化。

from catboost import CatBoostClassifier
model = CatBoostClassifier()
model.fit(X_train,y_train,verbose=False, plot=True)

使用 CatBoost 进行回归

在回归的情况下,使用“CatBoostRegressor”。

from catboost import CatBoostRegressor
model = CatBoostRegressor()
model.fit(X_train,y_train,verbose=False, plot=True)

您还可以使用“feature_importances_”来获得特性的重要性排名。

model.feature_importances_

model.feature_importances_

该算法还支持执行交叉验证。这是通过传递所需参数时使用“cv”函数来完成的。

通过“plot="True "”将使交叉验证过程可视化。“cv”函数要求数据集采用 CatBoost 的“Pool”格式。

from catboost import Pool, cv
params = {"iterations": 100,
          "depth": 2,
          "loss_function": "RMSE",
          "verbose": False}
cv_dataset = Pool(data=X_train,
                  label=y_train)
scores = cv(cv_dataset,
            params,
            fold_count=2,
            plot=True)

您还可以使用 CatBoost 来执行网格搜索。这是使用“grid_search”功能完成的。搜索后,CatBoost 在最佳参数上进行训练。

在此过程之前,您不应该拟合模型。传递“plot=True”参数将可视化网格搜索过程。

grid = {'learning_rate': [0.03, 0.1],
        'depth': [4, 6, 10],
        'l2_leaf_reg': [1, 3, 5, 7, 9]}

grid_search_result = model.grid_search(grid, X=X_train, y=y_train, plot=True)

CatBoost 还使您能够可视化模型中的单棵树。这是通过使用“plot_tree”函数并传递您想要可视化的树的索引来完成的。

model.plot_tree(tree_idx=0)

Regression with catboost

梯度推进树的优势

有几个原因可以解释为什么您会考虑使用梯度推进树算法:

  • 通常比其他模式更精确,
  • 训练速度更快,尤其是在大型数据集上,
  • 它们中的大多数都支持处理分类特征,
  • 它们中的一些本身就处理缺失值。

梯度增强树的缺点

现在,让我们来解决使用梯度增强树时面临的一些挑战:

  • 易于过度拟合:这可以通过应用 L1 和 L2 正则化惩罚来解决。你也可以尝试低学习率;
  • 模型可能计算量很大,需要很长时间来训练,尤其是在 CPU 上;
  • 很难解释最终的模型。

最后的想法

在本文中,我们探讨了如何在机器学习问题中实现梯度推进决策树。我们还介绍了各种基于 boosting 的算法,您可以立即开始使用。

具体来说,我们涵盖了:

  • 什么是梯度推进,
  • 梯度推进是如何工作的,
  • 各种类型的梯度增强算法,
  • 如何对回归和分类问题使用梯度推进算法,
  • 梯度推进树的优点,
  • 梯度增强树的缺点,

…还有更多。

你已经准备好开始提升你的机器学习模型了。

资源

图形神经网络和一些 GNN 应用:你需要知道的一切

原文:https://web.archive.org/web/https://neptune.ai/blog/graph-neural-network-and-some-of-gnn-applications

最近神经网络的成功推动了模式识别和数据挖掘的研究。

像物体检测、机器翻译和语音识别这样的机器学习任务,已经被像 CNN、RNN 或自动编码器这样的端到端深度学习范式赋予了新的生命。

深度学习擅长捕捉欧几里德数据(图像、文本、视频)的隐藏模式。

但是,如果应用程序中的数据是从非欧几里得域中生成的,用对象间复杂的关系和相互依赖的图来表示,该怎么办呢?

这就是图形神经网络(GNN)出现的地方,我们将在本文中探讨。我们将从图论和基本定义开始,继续学习 GNN 形式和原理,并以 GNN 的一些应用结束。

什么是图?

GNN 最基本的部分是图形。

在计算机科学中,图是由两部分组成的数据结构:节点(顶点)和边

一个图 G 可以定义为 G = (V,E) ,其中 V 是节点的集合, E 是它们之间的边。

如果节点之间存在方向依赖性,则边是有向的。否则,边是无向的。

图表可以表示社交媒体网络或分子之类的东西。把节点想象成用户,把边想象成连接。社交媒体图表可能是这样的:

一个图往往用来表示,一个邻接矩阵。

**如果一个图有 n 个 节点, 一个 有一个 (n × n) 的维数。

有时,节点具有一组特性(例如,用户配置文件)。如果节点有 f 个特征,那么节点特征矩阵 X 的维数为 (n × f)

读一些关于 GNN 的论文

为什么分析一个图形很难?

图形数据非常复杂,给现有的机器学习算法带来了很多挑战。

原因是常规的机器学习和深度学习工具专门研究简单的数据类型。就像具有相同结构和大小的图像,我们可以将其视为固定大小的网格图。文本和语音是序列,所以我们可以把它们想象成线图。

但是还有更复杂的图形,没有固定的形式,具有可变大小的无序节点,其中节点可以有不同数量的邻居。

现有的机器学习算法有一个核心假设,即实例相互独立,这也没有帮助。对于图形数据来说,这是错误的,因为每个节点都通过各种类型的链接与其他节点相关联。

图形神经网络

图形神经网络(GNNs)是一类深度学习方法,旨在对图形描述的数据进行推理。

gnn 是可以直接应用于图的神经网络,并提供了一种简单的方法来完成节点级、边级和图级预测任务。

GNNs 可以做卷积神经网络(CNN)未能做到的事情。

为什么卷积神经网络(CNN)在图上会失败?

CNN 可以用来让机器可视化事物,并执行图像分类、图像识别或对象检测等任务。这是 CNN 最受欢迎的地方。

CNN 背后的核心概念引入了隐藏卷积和池层,以通过核形式的一组感受野来识别空间定位的特征。

卷积如何对规则网格的图像进行操作?我们在二维图像上滑动卷积算子窗口,并在该滑动窗口上计算一些函数。然后,我们通过许多层。

我们的目标是将卷积的概念推广到这些简单的二维晶格之外。

让我们达到目标的见解是卷积提取图像的一小部分(图像的一个小矩形部分),对其应用一个函数,并产生一个新部分(一个新像素)。

发生的情况是,该中心像素的中心节点聚集来自其邻居以及自身的信息,以产生新的值。

由于图形的任意大小和复杂的拓扑结构,在图形上执行 CNN 非常困难,这意味着没有空间局部性。

还有不固定的节点排序。如果我们第一次标记节点 A、B、C、D、E,第二次标记它们 B、D、A、E、C,那么网络中矩阵的输入将改变。图对于节点排序是不变的,所以无论我们如何排序节点,我们都希望得到相同的结果。

图形深度学习基础

图论中,我们实现了节点嵌入的概念。它意味着将节点映射到一个 d 维嵌入空间(低维空间,而不是图的实际维度),以便图中的相似节点彼此紧密嵌入。

我们的目标是映射节点,使得嵌入空间中的相似性近似于网络中的相似性。

我们把v 定义为一个图中的两个节点。

x[u]T5x[v]*是两个特征向量。

现在我们将定义编码器函数 Enc(u)Enc(v) ,它们将特征向量转换为 z [u]z [v]

注意:相似性函数可以是欧几里德距离。

所以现在的挑战是如何实现编码器功能?

编码器功能应能够执行:

  • 位置(本地网络邻居)
  • 汇总信息
  • 堆叠多层(计算)

位置信息可以通过使用计算图来获得。如下图所示, i 我们会看到所有可能的联系,并形成一个计算图。

通过这样做,我们捕获了结构,同时也借用了特征信息。

Neighborhood exploration

Neighborhood exploration and information sharing | Source

一旦位置信息保存了计算图,我们就开始聚合。这基本上是用神经网络完成的。

神经网络用灰色方框表示。它们要求聚合是顺序不变的,如 sum、average、maximum,因为它们是排列不变的函数。此属性允许执行聚合。

让我们继续看 GNNs 中的正向传播规则。它决定了来自输入端的信息如何到达神经网络的输出端。

Many Layers

Deep Model: Many Layers | Source

每个节点都有一个特征向量。

例如,( X [A] )是节点 A 的特征向量。

输入就是那些特征向量,盒子会取这两个特征向量(X[A]X [c] ),聚合它们,然后传递给下一层。

注意,例如,在节点 C 的输入是节点 C 的特征,但是在层 1 中节点 C 的表示将是该节点的隐藏的、潜在的表示,而在层 2 中它将是另一个潜在的表示。

因此,为了在这个计算图中执行前向传播,我们需要 3 个步骤:

1。初始化激活单元:

2。网络中的每一层:

我们可以注意到这个等式有两个部分:

  • 第一部分基本上是对节点的所有邻居进行平均。

** 第二部分是节点 v 乘以偏差 B [k] 的前一层嵌入,这是一个可训练的权重矩阵,基本上是对节点 v 的自循环激活。

  • σ :对两个零件进行的非线性激活。

3。最后一个等式(在最后一层):

它是嵌入在【K】层邻域聚合之后的。

现在,为了训练模型,我们需要定义嵌入的损失函数。

我们可以将嵌入内容输入到任何损失函数中,并运行随机梯度下降来训练权重参数。

培训可以是无人监督的,也可以是有人监督的:

  • 无监督训练:
    仅使用图结构:相似节点有相似嵌入。无监督损失函数可以是基于图中节点邻近度或随机行走的损失。
  • 监督训练:
    节点分类、正常或异常节点等监督任务的训练模型。

概括地说,在本节中,我们描述了通过聚集邻域信息来生成节点嵌入的基本思想。

接下来,我将讨论图形卷积网络(GCNs)。

图形卷积网络

gcn 首先在“图上的谱网络和深度局部连接网络”(布鲁纳等人,2014)中引入,作为将神经网络应用于图结构数据的方法。

最简单的 GCN 只有三种不同的运算符:

  • 图形卷积
  • 线性层
  • 非线性激活

这些操作通常按此顺序进行。它们共同构成了一个网络层。我们可以将一层或多层组合起来,形成一个完整的 GCN。

在 Python 中,我们可以使用 PyTorch 轻松构建 GCN:

import torch
from torch import nn

class GCN(nn.Module):
    def __init__(self, *sizes):
        super().__init__()
        self.layers = nn.ModuleList([
            nn.Linear(x, y) for x, y in zip(sizes[:-1], sizes[1:])
        ])
    def forward(self, vertices, edges):

        adj = torch.eye(len(vertices))

        adj[edges[:, 0], edges[:, 1]] = 1 
        adj[edges[:, 1], edges[:, 0]] = 1

        for layer in self.layers:
            vertices = torch.sigmoid(layer(adj @ vertices))

        return vertices

GraphSAGE idea

GraphSAGE (Hamilton 等人,NIPS 2017)是一种动态图的表示学习技术。

它可以预测新节点的嵌入,而不需要重新训练过程。

为此,GraphSAGE 使用归纳学习。它学习聚合器函数,该函数可以基于节点的特征和邻域来诱导新节点嵌入。

我们可以注意到两个大的不同。我们使用一个通用的聚合函数,通过将两个事物连接在一起来保持它们的分离,而不是将两个事物加在一起并失去它们的踪迹。

之前,我们使用的是平均聚合函数——我们只是简单地从邻居那里获取信息,然后将它们相加,然后根据邻居的数量进行归一化。现在,我们也可以采用池式方法,或者我们也可以使用深度神经网络,如 LSTM。

Neighbor Aggregation

Neighbor Aggregation: Variants | Source

GNNs 的应用

正如在介绍中所承诺的,我想以 GNNs 的一些应用来结束。

图形结构的数据无处不在。GNNs 解决的问题可以分为以下几类:

  1. 节点分类:这里的任务是通过查看样本(表示为节点)邻居的标签来确定样本的标签。通常,这种类型的问题以半监督的方式训练,只有一部分图被标记。
  2. 图分类:这里的任务是将整个图分成不同的类别。就像图像分类一样,只是目标变成了图域。图分类的应用很多,从在生物信息学中确定蛋白质是否是酶,到在 NLP 或社会网络分析中对文档进行分类。
  3. 图形可视化:是数学和计算机科学的一个领域,处于几何图论和信息可视化的交汇点。它关注图形的可视化表示,揭示数据中可能存在的结构和异常,并帮助用户理解图形。
  4. 链接预测:在这里,算法必须理解图形中实体之间的关系,并且它还试图预测两个实体之间是否存在连接。在社交网络中,推断社交互动或向用户推荐可能的朋友是至关重要的。它也被用于推荐系统问题和预测犯罪协会。
  5. 图形聚类:是指将数据以图形的形式进行聚类。对图形数据执行的聚类有两种不同的形式。顶点聚类寻求基于边权重或边距离将图的节点聚类成密集连接的区域组。第二种形式的图聚类将图视为要聚类的对象,并基于相似性来聚类这些对象。

让我们看看 GNN 可以解决各种挑战的跨领域应用。

计算机视觉中的神经网络

使用常规 CNN,机器可以区分和识别图像和视频中的对象。尽管要让机器具有人类的视觉直觉还需要很大的发展。然而,GNN 架构可以应用于图像分类问题。

其中一个问题是场景图生成,该模型旨在将图像解析为由对象及其语义关系组成的语义图。给定图像,场景图生成模型检测和识别对象,并预测对象对之间的语义关系。

然而,GNNs 在计算机视觉中的应用数量仍在增长。它包括人与物体的互动,少数镜头图像分类,等等。

自然语言处理中的 GNNs

在自然语言处理中,我们知道文本是一种序列数据,可以用 RNN 或 LSTM 来描述。然而,由于图形的自然性和易于表示,它在各种 NLP 任务中被大量使用。

最近,人们对将 GNNs 应用于大量的自然语言处理问题产生了浓厚的兴趣,如文本分类、利用机器翻译中的语义、用户地理定位、关系提取或问题回答。

我们知道每个节点都是一个实体,边描述了它们之间的关系。在 NLP 研究中,问答问题并不是最近才出现的。但它受到现有数据库的限制。虽然,使用像 GraphSage (Hamilton 等人)这样的技术,这些方法可以推广到以前看不见的节点。

交通中的 GNNs

预测交通网络中的交通速度、交通量或道路密度在智能交通系统中至关重要。我们可以通过使用 STGNNs 来解决流量预测问题。

将交通网络视为一个时空图,其中节点是安装在道路上的传感器,边由节点对之间的距离来度量,每个节点都有一个窗口内的平均交通速度作为动态输入特征。

化学中的 GNNs

化学家可以使用 GNNs 来研究分子或化合物的图形结构。在这些图中,节点是原子,边是化学键。

其他域中的 GNNs】

GNNs 的应用不限于上述领域和任务。已经尝试将 GNNs 应用于各种问题,例如程序验证、程序推理、社会影响预测、推荐系统、电子健康记录建模、大脑网络和对抗攻击预防。

GNNs 应用概述

应用

深度学习

描述

Deep Learning:

图形卷积网络/图形注意力网络

Description:

GNNs 在自然语言处理中的一个经典应用是文本分类。GNNs 利用文档或单词的相互关系来推断文档标签。GCN 和盖特模型被用来解决这个问题。它们将文本转换成单词图,然后使用图卷积运算来卷积单词图。他们通过实验表明,文本的词图表示具有捕捉非连续和长距离语义的优势

神经机器翻译

Deep Learning:

图形卷积网络/门控图形神经网络

Description:

神经机器翻译(NMT)被认为是序列到序列的任务。GNN 的一个常见应用是将语义信息整合到 NMT 任务中。为此,我们在句法感知 NMT 任务中利用了句法 GCN。我们也可以在 NMT 使用 GGNN。它通过将边转化为额外的节点,将句法依赖图转化为一种新的结构,因此边标签可以表示为嵌入

Deep Learning:

图形 LSTM/图形卷积网络

Description:

关系抽取是从文本中抽取语义关系的任务,这通常发生在两个或多个实体之间。传统系统将该任务视为两个独立任务的流水线,即命名实体识别(NER)和关系提取,但是新的研究表明,实体和关系的端到端建模对于高性能是重要的,因为关系与实体信息密切交互

Deep Learning:

图形卷积网络/门控图形神经网络

Description:

图像分类是一项基本的计算机视觉任务。当给定一个巨大的标记类的训练集时,大多数模型提供有吸引力的结果。现在的重点是让这些模型在零镜头和少镜头学习任务中表现良好。因此,GNN 看起来很有吸引力。知识图可以提供必要的信息来指导 ZSL(零射击学习)任务

目标检测

交互检测

区域分类

语义分割

Deep Learning:

图形注意网络

图形神经网络

图表 CNN

图形 LSTM/门控图形神经网络/图形 CNN/图形神经网络

Description:

计算机视觉任务还有其他应用,如对象检测、交互检测和区域分类。在目标检测中,GNNs 用于计算 RoI 特征;在交互检测中,GNN 是人和物体之间的消息传递工具;在区域分类中,GNNs 在连接区域和类的图上执行推理

Deep Learning:

图形神经网络/图形网络

Description:

模拟真实世界的物理系统是理解人类智能的最基本的方面之一。通过将对象表示为节点,将关系表示为边,我们可以有效地对对象、关系和物理进行基于 GNN 的推理。交互网络可以被训练来推理复杂物理系统中对象的交互。它可以对碰撞动力学等领域的各种系统属性进行预测和推断

Deep Learning:

图形卷积网络

Description:

分子指纹是代表分子的特征向量。ML 模型通过从使用固定长度指纹作为输入的示例分子中学习来预测新分子的属性。GNNs 可以取代给出分子固定编码的传统方法,以允许生成适合于需要它们的任务的可区分指纹

蛋白质界面预测

Deep Learning:

图形卷积网络

Description:

这是一个具有挑战性的问题,在药物发现中有重要的应用。所提出的基于 GCN 的方法分别学习配体和受体蛋白质残基表示,并将它们合并用于成对分类。在分子水平上,边缘可以是分子中原子之间的键或蛋白质中氨基酸残基之间的相互作用。在很大程度上,图表可以表示更复杂结构之间的相互作用,如蛋白质、mRNA 或代谢物

组合最优化

Deep Learning:

图形卷积网络/图形神经网络/图形注意力网络

Description:

组合优化(CO)是一个由从有限的对象集合中寻找最优对象组成的主题。它是金融、物流、能源、科学和硬件设计中许多重要应用的基础。大多数 CO 问题都用图来表示。在 DeepMind 和 Google 最近的一项工作中,图网被用于 MILP 求解器中涉及的两个关键子任务:联合变量赋值和限制目标值。他们的神经网络方法在大数据集上比现有的求解器更快

Deep Learning:

图形卷积网络/图形神经网络/ LSTM /RNN/关系-GCN

Description:

现实世界图的生成模型因其重要的应用引起了人们的极大关注,这些应用包括建模社会互动、发现新的化学结构和构建知识图。基于 GNN 的模型独立地学习每个图的节点嵌入,并使用注意机制来匹配它们。与标准的基于松弛的技术相比,这种方法提供了良好的性能

结论

在过去的几年里,图形神经网络已经成为解决任何可以用图形建模的问题的强大而实用的工具。

在本文中,我们对图神经网络做了全面的概述,并介绍了 GNN 的广泛应用。

如果你陪我到最后——谢谢你的阅读!

资源

阿迈勒·门兹利

创新、足智多谋、自我激励的数据科学家。我热衷于用数据解决难题,我相信它是我们今天最强大的工具,来回答宇宙中最模糊的问题。此外,我喜欢教学、指导和写技术博客。


阅读下一篇

在 AILS 实验室建立可扩展的医学 ML 研究工作流程[案例研究]

8 分钟阅读| Ahmed Gad |发布于 2021 年 6 月 22 日

AILS Labs 是一个生物医学信息学研究小组,致力于使人类更加健康。这个任务就是建造模型,也许有一天可以拯救你的心脏病。它归结为应用机器学习来基于临床、成像和遗传学数据预测心血管疾病的发展。

四名全职和五名以上兼职团队成员。生物信息学家、内科医生、计算机科学家,许多人都有望获得博士学位。正经事。

虽然业务可能是一个错误的术语,因为面向用户的应用程序还没有在路线图上,但研究是主要的焦点。研究如此激烈,以至于需要一个定制的基础设施(花了大约一年时间建造)来从不同类型的数据中提取特征:

  • 电子健康记录(EHR),
  • 诊断和治疗信息(时间-事件回归方法),
  • 图像(卷积神经网络),
  • 结构化数据和心电图。

通过融合这些特征,精确的机器学习模型可以解决复杂的问题。在这种情况下,这是心血管一级预防的风险分层。本质上,它是关于预测哪些患者最有可能患心血管疾病

AILS 实验室有一套完整的研究流程。每个目标都有七个阶段:

  1. 定义要解决的任务(例如,建立心血管疾病的风险模型)。
  2. 定义任务目标(例如,定义预期的实验结果)。
  3. 准备数据集。
  4. 使用 Jupyter 笔记本以交互模式处理数据集;快速试验,找出任务和数据集的最佳特性,用 R 或 Python 编码。
  5. 一旦项目规模扩大,使用像 Snakemake 或 Prefect 这样的工作流管理系统将工作转化为可管理的管道,并使其可重复。否则,复制工作流程或比较不同模型的成本会很高。
  6. 使用 Pytorch Lightning 与 Neptune 集成创建机器学习模型,其中应用了一些初始评估。记录实验数据。
  7. 最后,评估模型性能并检查使用不同特征和超参数集的效果。

扩大机器学习研究的 5 个问题

AILS Labs 最初是由一小群开发人员和研究人员组成的。一个人编写代码,另一个人审查代码。没有太多的实验。但是协作变得更具挑战性,随着新团队成员的到来,新问题开始出现:

  1. 数据隐私,
  2. 工作流程标准化,
  3. 特征和模型选择,
  4. 实验管理,
  5. 信息记录。

Continue reading ->


图形神经网络:库、工具和学习资源

原文:https://web.archive.org/web/https://neptune.ai/blog/graph-neural-networks-libraries-tools-learning-resources

图是一种数据结构,它对一组对象(节点)及其关系(边)进行建模。许多学习任务都要处理对象间具有丰富关系和相互依赖的图形数据。图有很多实际用途——在社会网络、自然科学(物理系统)、化学、医学和许多其他研究领域。这激发了深度学习研究人员对图形数据结构越来越大的兴趣。

我们将描述图形神经网络 (GNNs),涵盖流行的 GNN 图书馆,并且我们将结束伟大的学习资源让你在这个领域开始。

先决条件:本文假设对机器学习(ML)、深度学习(DL)和 GNNs 有基本的了解。要更深入地了解 GNN 的基础和应用,请随意查看我以前的文章

图形神经网络(GNN)概述

图形神经网络(GNNs)是最近才出现的。它们是一类深度学习模型,用于在图结构数据上学习。

GNNs 是一种神经网络,设计用于在节点、边或整个图形的级别进行预测。例如,节点级别的预测可以解决垃圾邮件检测之类的任务。基于边缘的预测任务可以是链接预测,这是推荐系统中常见的情况。基于图的预测任务可以是预测分子图的化学性质。

Graph Neural Networks

Photo by Alina Grubnyak on Unsplash

GNN Python 库列表

让我们探索一些高质量的图形神经网络开源库,它们将在您的 GNN 之旅中为您提供帮助。

1) PyTorch 几何

PyTorch Geometric (PyG)是一个 Python 库,用于在图形这样的不规则结构上进行深度学习。该项目由来自多特蒙德大学的两名博士生 Matthias Fey 和 Jan E. Lenssen 开发并发布。

除了一般的图形数据结构和处理方法,它还有各种最近发布的来自关系学习和 3D 数据处理领域的方法。PyTorch Geometric 通过利用稀疏 GPU 加速、提供专用 CUDA 内核以及为不同大小的输入示例引入高效的小批量处理来实现高数据吞吐量。

2)深度图库(DGL)

深度图形库(DGL) 是另一个易于使用、高性能、可扩展的 Python 库,用于图形的深度学习。这是一群深度学习爱好者的产品,他们被称为分布式深度机器学习社区。它有一个非常干净简洁的 API。DGL 引入了一个有用的高级抽象,允许自动批处理。

3)图网

Graph Nets 是 DeepMind 的库,用于在 Tensorflow 和 Sonnet 中构建图形网络。该库适用于 TensorFlow 的 CPU 和 GPU 版本。它提供了灵活性,几乎任何现有的 GNN 都可以使用 6 个核心函数来实现,并且它可以扩展到时态图。图网需要 TensorFlow 1,所以虽然只有 3 年左右的历史,但感觉已经过时了。

4)光谱

Spektral 是一个开源的 Python 图形深度学习库,基于 Keras API 和 TensorFlow 2。这个库的主要目标是为创建 gnn 提供一个简单、灵活的框架。您可以使用 Spektral 对社交网络的用户进行分类、预测分子属性、生成带有 gan 的新图表、聚类节点、预测链接以及任何其他用图表描述数据的任务。它实现了图形深度学习的一些最流行的层。这个库是根据 Keras 的指导原则设计的,目的是在保持专家灵活性的同时,使初学者的事情变得极其简单。不幸的是,使用 Spektral 的简单性是有代价的,与 DGL 和 PyG 等其他库相比,大多数任务的训练速度都很慢。

GNN 图书馆概述

库名 执照 星星 编程语言 主要贡献者
Pytorch 几何 麻省理工学院 11.2k Python,PyTorch 马蒂亚斯·费伊
深度图库 阿帕奇 2.0 7.4k Python,PyTorch,TF,MxNet 分布式 MLC
图网 阿帕奇 2.0 4.9k Python,PyTorch 深度思维
光谱 麻省理工学院 1.8k Python, TF2/Keras Daniele Grattarola

你应该选择哪个 GNN 图书馆?

而是选择满足你需求的库,而这个选择通常会受到你或你的经理/队友之前对深度学习库的一个选择的影响。

例如,如果您以前工作过,或者您习惯于使用 Keras 和 Tensorflow,那么 Spektral 可能是一个很好的库。对于 Graph Nets DeepMind 库,由于 TensorFlow 1,我不建议用它启动新的 GNN 项目。同时,如果你正在从事遗留项目,这是一个合理的选择。

如果您想要一个快速、功能强大的库,处于相对成熟的开发状态,并且易于将通用基准数据集集成到其他论文的实现中,那么 PyTorch Geometric 是一个不错的选择。

可能有用

👉如果您使用 TensorFlow/Keras 进行模型训练,请在这里查看如何跟踪这个过程
👉另一方面,如果你使用 PyTorch,你可以在这里学习如何追踪你的跑步记录。

图形神经网络的最佳学习资源

在我的第一篇 GNN 文章之后,我收到了很多信息,询问理解这个主题的最佳资源。由于 GNN 油田发展非常迅速,最新的知识并不总是容易获得。

如果你想在这个领域获得实际操作的经验,这里列出了你需要收藏的最好的资源。

我认为如果你想增长关于图形神经网络的知识,这门课是必须的。它有公开的演讲幻灯片,以及推荐的阅读材料。本课程由 GraphSage 作者 Jurij Leskovec 亲自教授。我强烈建议从这门课开始。

这本书是一个大合作的结果,它塑造了一切,从内容到可视化和交互式工具。虽然这本书不是关于 GNNs 的,但它是获得坚实的图形基础的极好资源。

这本书在网上可以买到。它对图形表示学习提供了一个简单而全面的介绍,包括嵌入图形数据的方法、图形神经网络和图形的深度生成模型。它几乎拥有图形神经网络所需的所有理论。

该库包含最近的 GNN 论文,按主题如 GNN 的模型和应用(化学、NLP、交通网络和敌对攻击等)细分。).如果您对专注于 GNNs 特定应用的新论文感兴趣,这是值得一查的。

如果你想找到可以使用的带代码实现的图形神经网络模型,带代码的纸(PwC) 是最好的搜索地点。

这是一个组织访问技术论文的网站。在过去的几年里,它发展迅速。随着可公开获得的数据集的增加,现代研究已经开始向完全透明和可信的方向靠拢。普华永道也一直在改进自己的网站。您可以通过任务或方法(例如,注意,变形金刚)浏览,轻松浏览最新技术。

结论

在过去的几年中,gnn 已经成为图形领域中机器学习任务的强大而实用的工具。本文只是对图形神经网络的简单概述。我们总结了受欢迎的 GNN 图书馆,并列出了最好的学习资源,帮助你轻松进入这个广阔的领域。

我希望你喜欢这篇文章!如果您有任何问题或需要任何帮助,请随时联系我。

阿迈勒·门兹利

创新、足智多谋、自我激励的数据科学家。我热衷于用数据解决难题,我相信它是我们今天最强大的工具,来回答宇宙中最模糊的问题。此外,我喜欢教学、指导和写技术博客。


阅读下一篇

从哪里可以了解 MLOps?学习 MLOps 最好的书籍、文章或播客有哪些?ML 实验跟踪:它是什么,为什么重要,以及如何实施

4 分钟阅读| pawekijko | 2021 年 5 月 31 日更新

MLOps 不是小菜一碟。尤其是在当今不断变化的环境中。有许多挑战—构建、集成、测试、发布、部署和基础设施管理。你需要遵循良好的实践,并知道如何适应挑战。

如果你不学习和发展你的知识,你就会落伍。合适的资源可以帮助您遵循最佳实践,发现有用的提示,并了解最新趋势。

你不用看很远,我们会掩护你的!以下是您关于 MLOps 的最佳资源列表,包括书籍、文章、播客等。让我们开始吧!

1.介绍 O'Reilly 的 MLOps

介绍 MLOps:如何在企业中规模化机器学习是 Mark Treveil 和 Dataiku 团队(集体作者)写的一本书。它介绍了 mlop 的关键概念,展示了如何随着时间的推移维护和改进 ML 模型,并解决了 mlop 的挑战。

这本书是专门为分析和 IT 运营团队经理编写的,他们直接面对在生产中扩展机器学习(ML)的任务。这是创建成功的 MLOps 环境的指南,从组织到所涉及的技术挑战。

全书分为三个部分:

  1. 对 MLOps 主题的介绍,它如何以及为什么发展成为一门学科,谁需要参与成功地执行 MLOps,以及需要什么组件。
  2. 第二部分遵循机器学习模型生命周期,其中有关于开发模型、准备生产、部署到生产、监控和治理的章节。
  3. 提供了当今公司中 MLOps 的实际例子,因此读者可以理解实际中的设置和含义。

Continue reading ->


Gumbel Softmax 损失函数指南+如何在 PyTorch 中实现

原文:https://web.archive.org/web/https://neptune.ai/blog/gumbel-softmax-loss-function-guide-how-to-implement-it-in-pytorch

训练深度学习模型从未如此简单。你只需要定义架构和损失函数,坐下来,监视,至少在简单的情况下。一些架构带有固有的随机组件。这使得正向传递具有随机性,而你的模型不再具有确定性。

在确定性模型中,模型的输出完全由参数值和初始条件决定。

随机模型具有内在的随机性。同一组参数值和初始条件将导致不同输出的集合。

这意味着你不能像以前那样采样,因为从确定性函数采样会得到相同的结果,但随机函数及其附加的随机性则不能实现这一点,整个采样会变得不确定。

你看,反向传播算法依赖于在神经网络的每一层都有连续函数链。很多神经网络从根本上利用了离散运算。由于从离散空间采样不同于从连续空间采样,这就是 Gumbel-Softmax 技巧的用处。它不仅有助于从离散空间采样像连续操作,但它保持节点的随机性质完整,同时也保持反向传播步骤可行

让我们通过例子来探究这些操作,以便更好地理解。

深度学习中的离散操作

我们在许多涉及深度学习的领域使用离散采样。例如,在语言模型中,我们有被采样的单词或字符标记序列,其中每个离散的标记对应于一个单词或一个字符。这样我们就可以从离散空间采样。

Discrete Operations

A sequence of word tokenizations demonstrating sampling from discrete space | Source

另一个流行的例子是 LSTM 循环神经网络结构。它具有用于学习长期依赖性的内部门控机制。虽然这些选通单元是连续的,但整个 LSTM 单元的操作具有某种离散的性质。

在深度学习中使用离散采样的一个更受欢迎的例子是 seq2seq DNC 架构。Seq2Seq-DNC 使用外部存储器上的读/写(离散)操作来存储编码器-解码器状态,以支持长距离依赖性。

Operation structure of DNC memory area

Operation structure of DNC memory area | Source

使用另一种神经网络架构对这些读/写操作进行采样。在某种程度上,这个神经网络是从一个离散的空间采样。

现在我们来看看 Gumbel-Softmax 背后的动机和目的。

了解 Gumbel-Softmax

Gumbel-Softmax 解决的问题是处理从分类分布中生成的离散数据。让我们看看背后的内在机制。

甘贝尔最大技巧

Gumbel Max trick 是一种允许在神经网络正向传递期间从分类分布中采样的技术。这基本上是通过结合重新参数化技巧和平滑松弛来完成的。让我们看看这是如何工作的。

Gumbel softmax 2

Sampling from a categorical distribution by taking argmax of a combination class probabilities and Gumbel noise | Source

在这种技术中,如果我们获取类别概率并对每个类别概率应用对数函数,并且对这些对数中的每一个添加 Gumbel 噪声,可以通过获取某种均匀分布的两个对数来对该噪声进行采样。这一步类似于上面重新参数化技巧中使用的步骤,我们将正态分布噪声添加到平均值中。

在结合了采样过程的确定性和随机性部分之后,我们使用 argmax 函数来查找每个样本中具有最大值的类。该类或样本被编码为独热向量,供神经网络的其余部分使用。

现在我们有了一种从分类分布中抽样的方法,与连续分布相反。然而,我们仍然不能通过 argmax 反向传播,因为从它得到的梯度是 0,即它是不可微的。

论文[ 3 提出了用 softmax 代替 argmax 的技术。让我们来看看这个。

Gumbel Softmax

Gumbel Softmax

Replacing argmax with softmax because softmax is differentiable(required by backpropagation) | Source: Author

在这种方法中,我们仍然将对数概率与 Gumbel 噪声相结合,但现在我们对样本采用 softmax 而不是 argmax。

λ(λ)是 softmax 温度参数,它允许我们控制 Gumbel-softmax 分布接近分类分布的程度。如果λ非常小,那么我们非常接近量化的分类样本,相反,随着λ的增加,Gumbel-softmax 分布变得更加均匀。

Gumbel Softmax 的实现

在这一节中,我们将在 MNIST 数据集上训练一个变分自动编码器来重建图像。我们将在编码器状态的采样中应用 Gumbel-softmax。我们来编码吧!

注意:我们将使用 Pytorch 作为这个实现的框架选择

首先,让我们导入所需的依赖项。

import numpy as np
from typing import Union, Optional, List, Tuple, Text, BinaryIO
import io
import pathlib
import math
irange = range

import torch
import torch.nn.functional as F
from torch import nn, optim
from torch.nn import functional as F
from torchvision import datasets, transforms
from torchvision.utils import save_image

import neptune.new as neptune
from neptune.new.types import File
run = neptune.init(project='common/pytorch-integration',
                   api_token='ANONYMOUS')

尽早定义一些超参数总是很方便的。

batch_size = 100
epochs = 10
temperature = 1.0
no_cuda = False
seed = 2020
log_interval = 10
hard = False 

如前所述,我们将利用 MNIST 来实施。还是导入吧。

is_cuda = not no_cuda and torch.cuda.is_available()
torch.manual_seed(seed)
if is_cuda:
torch.cuda.manual_seed(seed)

kwargs = {'num_workers': 1, 'pin_memory': True} if is_cuda else {}

train_loader = torch.utils.data.DataLoader(
datasets.MNIST('./data/MNIST', train=True, download=True,
transform=transforms.ToTensor()),
batch_size=batch_size, shuffle=True, **kwargs)
test_loader = torch.utils.data.DataLoader(
datasets.MNIST('./data/MNIST', train=False, transform=transforms.ToTensor()),
batch_size=batch_size, shuffle=True, **kwargs)

现在,我们将定义 Gumbel-softmax 采样辅助函数。

def sample_gumbel(shape, eps=1e-20):
    U = torch.rand(shape)
    if is_cuda:
        U = U.cuda()
    return -torch.log(-torch.log(U + eps) + eps)
def gumbel_softmax_sample(logits, temperature):
    y = logits + sample_gumbel(logits.size())
    return F.softmax(y / temperature, dim=-1)
def gumbel_softmax(logits, temperature, hard=False):
    """
    ST-gumple-softmax
    input: [*, n_class]
    return: flatten --> [*, n_class] an one-hot vector
    """
    y = gumbel_softmax_sample(logits, temperature)

    if not hard:
        return y.view(-1, latent_dim * categorical_dim)

    shape = y.size()
    _, ind = y.max(dim=-1)
    y_hard = torch.zeros_like(y).view(-1, shape[-1])
    y_hard.scatter_(1, ind.view(-1, 1), 1)
    y_hard = y_hard.view(*shape)

    y_hard = (y_hard - y).detach() + y
    return y_hard.view(-1, latent_dim * categorical_dim)

接下来,让我们定义 VAE 结构和损失函数。

def loss_function(recon_x, x, qy):
    BCE = F.binary_cross_entropy(recon_x, x.view(-1, 784), size_average=False) / x.shape[0]

    log_ratio = torch.log(qy * categorical_dim + 1e-20)
    KLD = torch.sum(qy * log_ratio, dim=-1).mean()

    return BCE + KLD

class VAE_gumbel(nn.Module):
    def __init__(self, temp):
        super(VAE_gumbel, self).__init__()

        self.fc1 = nn.Linear(784, 512)
        self.fc2 = nn.Linear(512, 256)
        self.fc3 = nn.Linear(256, latent_dim * categorical_dim)

        self.fc4 = nn.Linear(latent_dim * categorical_dim, 256)
        self.fc5 = nn.Linear(256, 512)
        self.fc6 = nn.Linear(512, 784)

        self.relu = nn.ReLU()
        self.sigmoid = nn.Sigmoid()

    def encode(self, x):
        h1 = self.relu(self.fc1(x))
        h2 = self.relu(self.fc2(h1))
        return self.relu(self.fc3(h2))

    def decode(self, z):
        h4 = self.relu(self.fc4(z))
        h5 = self.relu(self.fc5(h4))
        return self.sigmoid(self.fc6(h5))

    def forward(self, x, temp, hard):
        q = self.encode(x.view(-1, 784))
        q_y = q.view(q.size(0), latent_dim, categorical_dim)
        z = gumbel_softmax(q_y, temp, hard)
        return self.decode(z), F.softmax(q_y, dim=-1).reshape(*q.size())

更多超参数的时间到了。

latent_dim = 30
categorical_dim = 10  

temp_min = 0.5

ANNEAL_RATE = 0.00003

model = VAE_gumbel(temperature)

if is_cuda:
model.cuda()
optimizer = optim.Adam(model.parameters(), lr=1e-3)

我们将以两种不同的方式进行训练和测试。

在测试函数中,我们将应用图像的重建,基本上是为了测试一个看不见的数据样本的采样和建模效率。

def train(epoch):
    model.train()
    train_loss = 0
    temp = temperature
    for batch_idx, (data, _) in enumerate(train_loader):
        if is_cuda:
            data = data.cuda()
        optimizer.zero_grad()
        recon_batch, qy = model(data, temp, hard)
        loss = loss_function(recon_batch, data, qy)
        loss.backward()
        train_loss += loss.item() * len(data)
        optimizer.step()
        if batch_idx % 100 == 1:
            temp = np.maximum(temp * np.exp(-ANNEAL_RATE * batch_idx), temp_min)

        if batch_idx==0:
            reconstructed_image = recon_batch.view(batch_size, 1, 28, 28)
            grid_array = get_grid(reconstructed_image)

            run["train_reconstructed_images/{}".format('training_reconstruction_' + str(epoch))].upload(File.as_image(grid_array))
        if batch_idx % log_interval == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                       100. * batch_idx / len(train_loader),
                       loss.item()))

    print('====> Epoch: {} Average loss: {:.4f}'.format(
        epoch, train_loss / len(train_loader.dataset)))
    run['metrics/avg_train_loss'].log(train_loss / len(train_loader.dataset))
def test(epoch):
    model.eval()
    test_loss = 0
    temp = temperature
    for i, (data, _) in enumerate(test_loader):
        if is_cuda:
            data = data.cuda()
        recon_batch, qy = model(data, temp, hard)
        test_loss += loss_function(recon_batch, data, qy).item() * len(data)
        if i % 100 == 1:
            temp = np.maximum(temp * np.exp(-ANNEAL_RATE * i), temp_min)
        if i == 0:
            n = min(data.size(0), 8)
            comparison = torch.cat([data[:n],
                                    recon_batch.view(batch_size, 1, 28, 28)[:n]])
            grid_array = get_grid(comparison)

            run["test_reconstructed_images/{}".format('test_reconstruction_' + str(epoch))].upload(File.as_image(grid_array))

    test_loss /= len(test_loader.dataset)
    print('====> Test set loss: {:.4f}'.format(test_loss))
    run['metrics/avg_test_loss'].log(test_loss)

:请在笔记本这里 找到上面代码摘录中用到的实用函数。

最后,我们将定义事件循环来联合运行所有的单个函数。

for epoch in range(1, epochs + 1):
    train(epoch)
    test(epoch)

在成功执行结束时,您将获得 MNIST 样本的重建图像,如下所示:

MNIST samples

只要看到重建部分和原始部分之间的对比,就可以知道 Gumbel-softmax 的采样效果如何。我们可以在下图中看到训练和测试损失收敛:

你可以在这里访问捆绑了重建图像的完整实验,在这里访问上面的代码。

你已经到达终点了!

Gumbel-Softmax 技巧可以证明在离散采样任务中非常有用,这在过去是以其他方式处理的。例如,NLP 任务几乎必然是离散的——比如单词、字符或音素的采样。

未来前景

Gumbel-softmax 的论文也提到了它在可变自动编码器中的有用性,但它肯定不限于此。

您可以将相同的技术应用于二进制自动编码器和其他复杂的神经网络,如生成对抗网络(GAN 的)。它似乎是无限的。

目前就这些,敬请关注更多!再见!

参考

  1. https://www.youtube.com/watch?v=JFgXEbgcT7g
  2. https://sassafras13.github.io/GumbelSoftmax/
  3. https://arxiv.org/pdf/1611.01144.pdf
  4. https://towards data science . com/what-is-gum bel-soft max-7f 6d 9 cdcb 90 e
  5. https://blog . ev jang . com/2016/11/tutorial-categorial-variable . html
  6. https://arxiv.org/abs/1611.00712

人工智能和人工智能如何解决旅游业中的商业问题——聊天机器人、推荐系统和情感分析

原文:https://web.archive.org/web/https://neptune.ai/blog/how-ai-and-ml-can-solve-business-problems-in-tourism-organization-chatbots-recommendation-systems-and-sentiment-analysis

随着人们离家寻求娱乐、放松和快乐,旅游业近年来有了长足的发展。至少在 COVID 时代之前,旅游业一直是一个快速增长的行业,在全球经济中发挥着重要作用。

根据联合国世界旅游组织的数据,1950 年估计有 2500 万国际游客。68 年后,国际游客增加到约 14 亿,增长了约 56 倍。

根据 Statista 的数据,旅行和旅游业在 2019 年直接为全球经济贡献了约 2.9 万亿美元。

像所有其他行业一样,旅游业不断改进服务客户的方法,让客户满意,以吸引他们再次光临。

在本文中,我们将探索:

  • 机器学习提高客户满意度和解决业务问题的方式,
  • 公司如何利用机器学习来改善游客体验。

我们还将经历为一个旅游相关问题建立机器学习模型的过程(数据收集、数据清理和模型建立)。

机器学习和旅游业

现代技术使旅行变得容易。你可以在手机应用程序中预订航班和酒店,轻松找到餐馆和娱乐场所,并在线支付一切费用。

这也意味着移动设备一直在产生大量数据。各行业通过大数据解决方案利用这一点来改善服务,让消费者的生活变得更轻松。

除了分析这些数据以发现消费者模式之外,机器学习和人工智能还用于预测未来的结果,这有助于在问题发生之前解决问题。

数据已经成为世界上最有价值的资产,也是增长的关键驱动力。机器学习在旅游业中的影响主要是针对客户满意度和参与度。

机器学习如何解决旅游中的问题?

1。聊天机器人

如今,客户希望从为他们服务的公司获得最新信息,并需要能够快速提问和获得答案。

旅游公司过去只能雇佣前台服务员和客户服务代表。这限制了他们帮助客户的能力,有时还会因为客服人员的不良行为而导致客户流失。

随着聊天机器人的诞生,公司开始通过现有的平台,如网络浏览器和信使应用程序(WhatsApp 或脸书),将它们用作客户的个人助理。

聊天机器人可以回答常见的问题,推荐游览城市时要去的地方或要做的事情,所有这些都非常快,没有浏览网站或等待与客户服务代理交谈的麻烦。

聊天机器人的优势:

  • 节省时间,
  • 个性化服务,
  • 公司的财务成本非常低,
  • 可以对聊天进行分析,以了解客户谈论的内容,并计划未来的改进。

2。推荐系统

推荐系统无处不在。他们根据不同的因素和数据向用户推荐相关的项目。包括网飞、Linkedin 和亚马逊在内的顶级公司利用推荐系统的力量向用户推荐个性化商品。

旅游业也不例外。在这里,这些系统减少了客户流失和交易成本,为客户和服务提供商节省了时间。

公司使用客户数据和机器学习算法来建立一个推荐模型,该模型可以准确地建议最佳游览地点,而不必手动检查目录、网站或联系客户服务代理。

这些模型建立在过去的花费、旅游目的地、评分和之前选择的优惠等数据基础上。

推荐系统的好处:

  • 快速提供个性化建议,
  • 支持精准营销,
  • 为游客提供更智能的旅行。

3。社交媒体情绪分析

社交媒体已经成为从人们那里获得评论的重要方式,这可能会影响新用户对你公司的看法。

分析情绪,定位问题点,并在旅游公司中解决这些问题有助于推动增长。一些客户可能对服务不满意,而另一些客户可能很高兴,公司可以利用这些信息为自己谋利。

我们如何以自动化的方式分析这些评论来检查它们是好是坏?

通过情感分析。它使用自然语言处理,这是人工智能和人工智能的一个子领域,可以自动检查客户评论中的关系和意义。

社交媒体情绪分析的好处:

  • 提供了有效的性能指标,
  • 有助于了解客户,
  • 帮助衡量营销活动的结果。

4。瞄准合适的受众

事实证明,了解客户并知道向哪个客户推销什么是非常有效的营销策略。

客户有不同的特点,住在不同的地方,做不同的工作,挣不同的薪水。在旅游业,有些顾客可能负担得起豪华的圣托里尼度假,而有些人可能负担不起,向错误的客户群营销只能增加营销支出,而不会产生任何结果。

手动预测客户行为和细分可能是一项负担。每天都有成千上万的数据点产生,只有机器才能有效地做到这一点。

机器学习如何帮助旅游业的目标营销?

机器学习可以帮助使用聚类算法识别客户群,其中具有相似特征的客户根据旅行频率、停留时间、花费金额等特征进行分组。

机器学习还可以帮助预测客户行为,并避免不参与旅游报价的高概率客户。

锁定正确受众的好处:

  • 更好的推荐,
  • 转化率提高,
  • 更好更有成效的广告活动。

既然我们已经讨论了机器学习和人工智能如何改善旅游业的服务和营销,让我们想象一个使用机器学习和人工智能的示例公司,以及他们将如何做。

快速演示

业务问题

旅游公司 Humtourist 因对纽约曼哈顿的娱乐场所、餐馆和休闲中心的糟糕建议而受到顾客的差评。

这增加了客户流失率,大幅降低了收入。管理层听说了数据科学和机器学习,以及它可以提高客户满意度和增加收入。

应用机器学习解决方案

我们可以为 Humtourist 客户建立一个推荐和细分系统,以确保他们在纽约曼哈顿逗留期间获得最佳体验。

这项工作的一部分包括推荐不同活动的最佳地点/社区,包括休闲区、繁忙区、餐厅、公园等。所有这些都是为了提高客户满意度,并在曼哈顿提供有趣的体验。

注意:本教程的目的不是建立一个 100%精确的模型。在这里,我们将建立一个简单的模型。

为了构建此模型,我们将:

连接到外部数据源以获取数据,

  • 使用 JSON 数据格式,
  • 以准备建模的形式清理数据,
  • 建立一个简单的加权平均推荐系统以及一个细分系统。
  • 先决条件

Python 3.0+编程知识,

  • 数据预处理知识,
  • 基本的机器学习知识,
  • Foursquare 账户。
  • 我们将连接到外部数据源,使用应用程序编程接口(API)提取数据。

Foursquare 是一个定位技术平台,致力于改善人们在世界各地的移动方式。优步、脸书、苹果和三星等公司利用 Foursquare 的开发者工具来帮助了解手机位置。

我们将使用 Foursquare 的 API 来获取必要的数据,但首先您需要:

在 foursquare 开发者页面创建一个账户。

  1. 将客户端 ID 和客户端密钥复制到便笺中。
  2. 编码步骤

首先,我们将添加来自https://cocl.us/new_york_dataset的纽约州区数据。在预处理过程中,我们将提取区,邻居,纬度和经度数据。

因为我们将只关注曼哈顿区,所以我们将只提取曼哈顿的数据。

接下来,我们将使用 Foursquare API 来提取地点,并以一种准备建模的形式预处理这些数据。

import numpy as np 
import pandas as pd 
Import requests
from sklearn.cluster import KMeans 
import json 

!wget -q -O 'newyork_data.json' https://cocl.us/new_york_dataset

with open('newyork_data.json') as json_data:
    newyork_data = json.load(json_data)

neighborhoods_data = newyork_data['features']

column_names = ['Borough', 'Neighbourhood', 'Latitude', 'Longitude']
neighbourhoods = pd.DataFrame(columns=column_names)

for data in neighborhoods_data:
    borough = neighborhoods_name = data['properties']['borough']
    neighborhoods_name = data['properties']['name']

    neighborhoods_latlon = data['geometry']['coordinates']
    neighborhoods_lat = neighborhoods_latlon[1]
    neighborhoods_lon = neighborhoods_latlon[0]
    neighborhoods = neighborhoods.append({
        'Borough': borough,
        'Neighbourhood': neighborhoods_name,
        'Latitude': neighborhoods_lat,
        'Longitude': neighborhoods_lon,
    }, ignore_index=True)

manhattan = neighborhoods[neighborhoods['Borough'] == 'Manhattan'].reset_index(drop=True)

我们需要客户机 ID 和客户机密钥来首先构建细分系统,然后构建推荐系统。查看场馆的 Foursquare 文档

上面的代码块产生下面的输出:

CLIENT_ID = '*****************'
CLIENT_SECRET = '************************'
VERSION = '20200202'
LIMIT = 100
radius=500

def getNearbyVenues(names, latitudes, longitudes, radius=500):

    venues_list=[]
    for name, lat, lng in zip(names, latitudes, longitudes):

        url = 'https://api.foursquare.com/v2/venues/explore?&client_id={}&client_secret={}&v={}&ll={},{}&radius={}&limit={}'.format(
            CLIENT_ID, CLIENT_SECRET, VERSION, lat,
            lng, radius, LIMIT)

        results = requests.get(url).json()["response"]['groups'][0]['items']

        venues_list.append([(
            name, lat, lng, v['venue']['name'], v['venue']['id'],
           v['venue']['location']['lat'], v['venue']['location']['lng'],
           v['venue']['categories'][0]['name']) for v in results])

     nearby_venues = pd.DataFrame([item for venue_list in venues_list for item in venue_list])
     nearby_venues.columns = ['Neighbourhood', 'Neighbourhood Latitude', 'Neighbourhood      Longitude',  'Venue', 'id', 'Venue Latitude', 'Venue Longitude','Venue Category']

    return(nearby_venues)

manhattan_venues = getNearbyVenues(names=manhattan['Neighbourhood'],
                                   latitudes=manhattan['Latitude'],
                                   longitudes=manhattan['Longitude']
                                  )

现在我们已经准备好了我们的场馆和场馆类别,我们将只提取必要的数据,一个热编码,找到前 10 个最常见的场馆,并建立我们的细分系统。

上面的代码块产生下面的结果:

manhattan_seg_onehot = pd.get_dummies(manhattan_venues[['Venue Category']], prefix="", prefix_sep="")

manhattan_seg_onehot['Neighbourhood'] = manhattan_venues['Neighbourhood']
fixed_columns = [manhattan_seg_onehot.columns[-1]] + list(manhattan_seg_onehot.columns[:-1])
manhattan_seg_onehot = manhattan_seg_onehot[fixed_columns]

manhattan_seg_group = manhattan_seg_onehot.groupby('Neighbourhood').mean().reset_index()

def return_most_common_values(row, num_top_venues):
    row_categories = row.iloc[1:]
    row_categories_sorted = row_categories.sort_values(ascending=False)

    return row_categories_sorted.index.values[0: num_top_venues]

columns = ['Neighbourhood']
num_top_venues = 10
indicators = ['st', 'nd', 'rd']
for ind in np.arange(num_top_venues):
    try:
        columns.append('{}{} Most Common Venue'.format(ind+1, indicators[ind]))
    except:
        columns.append('{}th Most Common Venue'.format(ind+1))

manhattan_venues_seg = pd.DataFrame(columns=columns)
manhattan_venues_seg['Neighbourhood'] = manhattan_seg_group['Neighbourhood']

for ind in np.arange(manhattan_seg_group.shape[0]):
    manhattan_venues_seg.iloc[ind, 1:] = return_most_common_values(manhattan_seg_group.iloc[ind, :], num_top_venues)

这些是曼哈顿不同街区最常见的场所。

接下来,我们将使用 KMeans 算法,这是一种用于我们的分段系统的聚类算法。

我们将 K 参数设置为 5。您可以尝试不同的数字,或者更好的是,使用肘方法来确定最佳 K 值。

模型构建完成,现在让我们看看来自集群 0、1 和 2 的一些结果:

From sklearn.cluster import KMeans
man_cluster = manhattan_seg_group.drop('Neighbourhood', 1)
km = KMeans(n_clusters=5, random_state=0).fit(man_cluster)

manhattan_venues_seg.insert(0, 'Cluster', km.labels_)
manhattan_merge = manhattan
manhattan_merge = manhattan_merge.join(manhattan_venues_seg.set_index('Neighbourhood'), on='Neighbourhood')

集群 0:

集群 1:

集群 2:

从我们的细分系统中,我们可以看到聚类 0 由活跃区域(餐馆、剧院、健身房、咖啡馆、商店)组成,聚类 1 主要由餐馆组成,聚类 2 由娱乐和放松场所组成。

现在我们已经完成了我们的细分系统的构建,是时候构建我们的简单加权平均推荐系统了。

Foursquare 每天只允许 50 个高级 API 调用,用于场地评级等类别。既然我们已经有了收视率的数据,我们就把它们读进去。在下一阶段,我们将预处理收视率数据,并加入场馆数据。

下面的结果显示了每个社区整体评分的平均值:


manhattan_rec_data = pd.concat([manhattan_venues[0:298],manhattan_venues[2579:2679]],  axis=0).reset_index(drop=True)
manhattan_rec_data['ratings'] = rating['rating']
manhattan_rec_data.tail()

manhattan_rec_data = manhattan_data[manhattan_data['ratings'] != 'not rated']
manhattan_rec_data.reset_index(drop=True,inplace=True)

from sklearn.preprocessing import LabelEncoder

recommender_onehot = pd.get_dummies(manhattan_data[['Venue Category']], prefix="", prefix_sep="")

recommender_onehot['Neighbourhood'] = manhattan_data['Neighbourhood']

fixed_columns = [recommender_onehot.columns[-1]] + list(recommender_onehot.columns[:-1])
recommender_onehot=recommender_onehot.groupby(['Neighbourhood'], sort=False).sum()

matrix = recommender_onehot.reset_index(drop=True)

rec_rating=manhattan_data[['Neighbourhood','ratings']]

rec_rating['ratings'] = rec_rating['ratings'].astype('float')

rec_rating_grouped=rec_rating.groupby('Neighbourhood', sort=False)['ratings'].mean()
rec_rating_grouped

现在,让我们通过在评分和矩阵之间执行点积来确定用户评分权重。我们还将通过将邻域乘以权重并取加权平均值来创建最终评级表。

tourism_results

现在推荐表做好了。让我们来看看最受推荐的 4 个街区:

final_rating=pd.DataFrame(rec_rating_grouped)
final_rating=final_rating.reset_index()

user_rate = matrix.transpose().dot(final_rating['ratings'])

user_rate.sort_values(ascending=False)

tourism_results

rec_df= ((recommender_onehot*user_rate).sum(axis=1))/(user_rate.sum())
rec_df = rec_df.sort_values(ascending=False)

top4=pd.DataFrame(rec_df)
top4=top4.reset_index()
top4.columns=['Neighbourhood','recommendation']

因为市民中心是我们最推荐参观的街区,所以让我们来看看最热门的活动:

tourism_recommendation

因此,无论何时用户发现自己在曼哈顿,他/她都应该访问市民中心,去水疗中心,一定要去咖啡店,并在那家法国餐厅点一些法国菜。

结果和讨论

当 Humtourist 的客户在曼哈顿时,我们的系统会推荐最好的社区,并在我们的细分系统的帮助下,向他们显示不同活动的最佳社区。

我们的分析显示,曼哈顿的大多数场所都是餐馆。此外,我们发现咖啡店和中国餐馆是最值得推荐的场所,我们还发现唐人街对中国餐馆的总体评分有很大影响,而市民中心对咖啡店的总体评分也有很大影响。

我们的模型还向我们展示了用户在曼哈顿时可以参与的不同顶级活动。

这个系统可以通过获得更多的数据来进一步改进,但目前这只是一个简单的演示。

结论

对于这篇文章,我们探索了:

机器学习如何帮助旅游业,

现代旅游业如何使用机器学习,

如何构建简单的推荐和细分系统?

  • 旅游业目前处于混乱状态,但一旦 COVID 的情况得到解决,它很可能会跳回到它的高数字。机器学习和人工智能就在那里,帮助公司维持运营并实现增长。
  • 感谢您的阅读!
  • How to build simple recommendation and segmentation systems.

The tourism industry is in shambles at the moment, but once the COVID situation is resolved, it will most likely jump back to its high numbers. Machine learning and AI will be right there, helping companies stay afloat and generate growth.

Thank you for reading!

这 8 家公司如何实施 MLOps:深度指南

原文:https://web.archive.org/web/https://neptune.ai/blog/how-these-8-companies-implement-mlops

你可能已经看到了(不是最近的,但仍然是真实的)新闻:

没错。不幸的是,有很多公司试图以一种对他们的业务有意义的方式运作他们的 ML 项目,但从未真正实现成功的实施。

人工智能项目成功的最后一英里是生产中模型的部署和管理。这是决定任何人工智能或机器学习项目**完全* *成功的因素——在生产环境中部署和管理解决方案的能力。

但是,与其关注坏消息,我们不如聚焦 8 家公司如何以商业上有意义的方式实施MLOps,以及你可以从他们的方法中学到什么。

这篇文章的主要目的是让你深入了解这些公司如何运用 ML 解决方案来改善他们业务的某些方面。在一些例子中,我将解释技术解决方案,而在其他例子中,我将提供更广泛的概述。

根据Mike Gualtieri(Forrester Research 首席分析师)在网络研讨会上的观点,任何公司成功部署 MLOps 都有 8 个关键要求。任何公司的 ML 平台都必须能够:

  1. 支持不同工具及其依赖关系创建的多种机器学习模型格式。
  2. 提供 ML 生命周期所需的基础设施资源。
  3. 提供内部、云和边缘的部署自由度。
  4. 确保模型治理来解释和审计模型的使用。
  5. 确保模型的安全性和完整性。
  6. 使用用于创建原始数据的数据管道、算法和代码,在较新的数据上重新训练生产模型
  7. 为 DevOps、Ops 和 MLOps 专业人员提供可视化工具。
  8. 监控模型,以确保模型正在执行,持久,没有伤害。

在本文中,我们将了解成功满足上述所有关键要求的公司。我们还将根据平台将公司分为 3 种不同类型的 MLOps 实施:

  • 基于云/无服务器的实施:使用全套云解决方案和托管服务实施 MLOps 的公司。
  • 使用托管平台的端到端实施:使用托管平台(如 DataRobot)和/或其他 AutoML 工具实施端到端 MLOps 的公司。
  • 内部 ML 平台实施:管理其 MLOps 流程实施的公司。

希望实施 MLOps?这可能有助于…

成功实施 MLOps 还需要跟踪工作流程中每个相关组件的活动。这包括你的数据,模型,以及你的机器学习管道的其他方面!

很多时候,MLOps 项目失败或不可持续,因为团队不知道:

  • 他们的数据从哪里来,将会在哪里结束,
  • 模型在实验过程中使用的数据版本;这使得实践的再现性差,
  • 如何跟踪实验并节省他们用于诊断问题的时间,
  • 如何确保他们的数据和模型能够被监管机构和用户审计以符合要求,
  • 他们的模型的哪个版本最终投入生产,以及他们如何监控和跟踪其配置,
  • 以及由于没有记录他们的 MLOps 过程而产生的许多问题。

令人欣慰的是,当我们可以使用一个元数据存储库来自动记录来自我们的数据、模型和实验过程的活动时,我们不必担心这种乏味的记录——这可以将团队的生产率提高 10 倍!

MLOps 最好的元数据存储之一是 Neptune——一个为运行大量实验的研究和生产团队构建的工具。您可能有一个开发和部署模型的困难任务;通过使用“第二大脑”来记录来自 MLOps 实施的元数据,提高您的工作效率。

Neptune.ai 对一个用户免费,对一个团队付费。最棒的是,在看到它能让你的工作效率提高 10 倍之前,你不必注册。你可以在你的浏览器 中直接查看一个范例项目,没有任何附加条件

TL;8 家完全实施了 MLOps 的公司的灾难恢复摘要

公司名称 商业目标 工业 MLOps 实施流程 ML 用例(对于本文)

向顾客提供旅游安排套餐。

| | |

个性化和推荐

|
| |

优化顾客的杂货购物体验和零售商的服务体验。

| 零售和消费品 | |

订单管理中的欺诈检测

|
| |

为顾客提供新鲜的手工化妆品。

| |

->操作-设备- >部署-

  • | |
    | |

帮助客户最大限度地利用他们的资金。

| | | |
| |

为个人提供信贷、简单的支付解决方案、高收益的投资机会和易于使用的个人理财工具。

| |

全托管端到端 AI 平台- > DataRobot

|

贷款审批及信用评分

|
| |

以快速高效的方式,将驾车和送货与乘车者、用餐者和餐馆联系起来。

| |

内部(开源)机器学习平台- >米开朗基罗

|

通用 ML 用例

|
| |

为自己的用户提供一个最优的、个性化的电影流媒体服务。

| |

内部(开源)机器学习平台- >元流

|

通用 ML 用例

|
| |

成为每个城市最后一公里的物流层。

|

网上订餐和物流

|

内部机器学习平台

|

门口通用 ML 用例

|

免责声明:

虽然这篇文章是对这些公司如何实施 MLOps 的深入指导,但它并没有提供这些公司流程的详尽细节。可以在底部的参考资料部分找到了解这些领域的更多信息的资源。

  • 我通过联系和使用直接和间接来源,尽最大努力提供有关这些公司的 MLOps 实施流程的最新和最准确的信息。如果您觉得任何信息有错误或需要更新,请不要犹豫,通过 LinkedInTwitter 联系我。
  • 采用无服务器解决方案实施 MLOps 的公司

1.假日临时演员

Holiday extras 是一家旅游和物流公司,提供机场停车、酒店、剧院、主题公园、家庭度假、汽车租赁和其他服务的安排和套餐。

Holiday Extras 如何实现机器学习操作(MLOps)

机器学习在 Holiday Extras 的核心用途是优化客户决策以及其他用途,如定向广告、个性化推荐客户体验、自动化服务价格、自动化电话处理等等。它们的实现架构可以在下面找到。

将模型部署到生产中

MLOps holiday extras

Holiday Extras implementation architecture

虽然我无法在网上找到很多关于他们的 ML 工程流程的细节,但我确实找到了 Rebecca Vickery 关于他们如何在 Holiday Extras 部署和扩展 ML 模型的演讲(所有链接都在参考资料中)。

在 Holiday Extras,开发机器学习模型的代码是用 Cookie Cutter 结构化和模板化的,并被推送到该公司的 GitHub 存储库中。Scikit-learn 用作建模库。数据转换被配置为 sci-kit 学习管道,在模型代码中带有自定义转换器。团队内置了定制的评分和预测例程(用于尝试非标准预测)。

模型代码从 GitHub 克隆到 Google 云存储(GCS)。他们使用人工智能平台来训练他们的模型。模型文件和元数据(模型配置)被返回到 GCS。评估一个模型,AI 平台将预测服务公开为一个端点,客户端可以使用正确的数据模式调用该端点。

ML 代理是预测服务,它与客户端请求和查询 AI 平台的预测进行交互。ML 代理为 AI 平台期望的数据定义模式,以便其他服务可以使用期望的数据模式查询 AI 平台端点。

监控生产中的模型性能

为了监控数据漂移,Holiday Extras 使用 Google BigQuery 来记录预测事件,以便可以使用 Data Studio 或 Looker 等工具来可视化性能和漂移。

他们还使用 Grafana(与他们的运营生态系统集成)来可视化从 AI 平台记录的事件,这些事件表现为预测评分指标、警报和错误、系统指标以及到达端点的请求数量的延迟。

迭代和模型生命周期管理

数据科学团队相互密切合作,管理生产中 ML 解决方案的整个生命周期,他们还与作为部署流程关键部分的其他团队合作,以确保生命周期管理的批准流程得到妥善处理。

解释和审计模型使用的模型治理

对于治理,Google Cloud AI 平台中启用了模型版本控制,提供了所有的培训和性能细节,以便可以跟踪模型的血统。

2.奥卡多

Ocado 是世界上最大的网上超市之一,当顾客浏览他们的网站和应用程序、将商品添加到手推车、选择送货位置和检查订单时,他们的系统每分钟处理数百万起事件。

这当然会让你想到一个成功实现的机器学习解决方案可以利用的数据量。

Ocado 零售部门的业务目标是:

确保购物体验直观且有益于顾客(准时交货、安全交易、食品的保质期长;

  • 仓单管理系统必须高效,以便大规模运营,从而改善客户或零售商的体验;
  • 员工和供应链员工的体验都很方便。
  • Ocado 如何实现机器学习操作(MLOps)

基于上述业务目标,Ocado 的机器学习的一些核心用途包括:

个性化并向客户推荐产品

  • 在欺诈交易发生之前检测它们
  • 预测产品需求,以保持产品新鲜,减少食物浪费(由于库存过多)和库存不足
  • 管理提取和包装订单的仓库机器人
  • 扩大客户联络中心
  • 优化供应链路线,保持交付新鲜,减少燃料排放
  • 在这份实施报告中,我们将重点关注 Ocado 实施其欺诈检测机器学习解决方案的方式。该解决方案的业务目标是,当通过订单管理系统下订单时,自动有效地确保交易合法。您可以在下面找到实现架构。

Ocado 使用 Google Colaboratory 进行内部笔记本评论。你可以在谷歌数据实验室等托管笔记本上使用谷歌大查询的数据。

训练管道由通过云数据流流入 BigQuery 的数据组成,训练由 Cloud Composer 安排和协调。对于在训练管道中进行的操作,来自被摄取到数据流中的数据的特性通过使用 Apache Beam 编写的一组转换进行转换,并作为一组特性库加载到 BigQuery 中。云数据流上的 Apache Beam 转换也被再次编写,用于进一步的功能工程和数据准备方法,并加载到 Google 云存储(GCS)和 Google Datastore(用作功能存储)。

为了进行训练,AI 平台在 GCS 中对转换后的特征进行训练,并存储该模型的实例(版本化),该实例包括训练元数据和模型文件。Python 用于建模,深度神经网络算法用于构建模型。

将模型部署到生产中

将模型部署到生产由 AI 平台管理,该平台将模型公开为任何其他服务都可以调用或发送请求的预测服务。Google Cloud Datastore 充当服务的特性存储,用于获取客户详细信息和过去的交易,以便来自客户端请求的特性能够通过 BigQuery 中转换后的特性存储库的特性得到丰富。

监控模型在生产中的性能

在进行研究时,我找不到任何直接或间接的来源来证实 Ocado 用于监控其欺诈检测服务的技术堆栈。但是,在他们 3 年前的一次谈话中,他们确实提到他们将使用 Google Cloud Data Studio 来可视化预测日志和模型指标。

人们还可以假设他们可能使用 Stackdriver(这是 Google Cloud 的默认云监控服务)来监控服务的运行性能。

生命周期管理和模型治理

培训管道计划每天运行,因此每天都有新的模型版本可用。

Ocado 的数据治理团队参与数据管理流程和云中数据基础设施的设置。

在责任和审计方面,由于 Ocado 的微服务文化,发生的事件可以根据血统进行追溯。这确保了数据接收、数据转换和一般数据沿袭的触发可以在整个系统中及时追溯。

对于治理和可解释性,欺诈代理被用作人在回路中的主题专家来分析系统评分阈值(精确度、召回率、真阳性率和假阳性率)有问题的订单,以便他们可以查看该订单并提供关于交易是否合法的解释。

3.丰富的

LUSH 是一家总部位于英国的全球化妆品零售商,为顾客提供新鲜的手工化妆品。以新鲜和可持续的方式提供手工化妆品是他们的核心商业目标之一。

LUSH 如何实现机器学习操作(MLOps)

我们将要研究的机器学习用例是由 Datatonic 为 LUSH 部署的。在作为商业目标的可持续发展方面,LUSH 采用了机器学习来识别货架上没有包装的产品,以便当客户走进商店购买产品时,他们启动应用程序,将相机对准他们想要购买的产品,系统会实时识别它(没有包装),并将其添加到客户的购物车中。部署是在设备上进行的,操作只发生在谷歌云上。

产品上的图像被收集并上传到谷歌云存储(GCS)。图像通过转换为 TensorFlow 固有的 TFRecords 格式进行预处理,从而实现高效的模型训练。来自的图像转换。jpeg。tfrecords 是用 Apache Beam 写的,运行在云数据流上。在将数据加载回 GCS 之前,转换还会将数据分成训练集和评估集。

数据增强发生在使用 TensorFlow 的图像预处理功能的 AI 平台内。由于产品之间非常相似,并且化妆品总是会改变形状,所以增加的步骤非常关键。训练和评估发生在 AI 平台上,使用存储在 Google BigQuery 中的迁移学习和评估指标来监控实验(存储像实验的 run_id、实验运行的时间、模型指标、类的数量等信息)。如果基于给定的性能阈值,该模型适合生产,则使用 TFLite 模型转换器 API 将该模型转换为,将其转换为设备上的模型。tflite 格式,可以跨平台工作(iOS 和 Android 设备都可以)。生产就绪模型存储在 Google 云存储中并进行版本控制。您可以通过查看参考资料一节中的参考资料找到关于该模型的更多信息。

将模型部署到生产中

部署的模型是 mobilenetv2 模型,非常适合于设备上的视觉任务,大小约为 3.5 MB,模型评分采用 F1-score。

监控模型在生产中的性能

没有关于如何在设备上监控模型性能的信息,也没有关于应用程序是否记录回(到云)各种性能指标的信息。

迭代和模型生命周期管理

为了管理生产中的模型,Cloud Composer(一个在 Apache Airflow 上运行的托管服务)被用来自动化(通过触发器)模型的重新训练和部署。无论何时发布新产品,将这些产品的足够多的图像添加到 GCS 中,或者已经训练出更好的模型,该应用程序都可以持续更新。

解释和审计模型使用的模型治理

在治理的情况下,AI 平台将关于训练模型的有用元数据记录到 GCS,以便可以跟踪模型血统。将数据存储在 Google Cloud 上可能也有助于 LUSH 在团队想要审计事件时进行数据沿袭追踪。

4.革命报

Revolut 是一家总部位于英国的金融科技公司,为其客户提供银行服务。它的核心业务是帮助客户最大限度地利用他们的资金。

Revolut 如何实现机器学习操作(MLOps)

用“金融超级应用”帮助客户最大限度地利用他们的资金,听起来像是机器学习可以派上用场的事情——特别是在应用程序上几乎所有东西的交易数据方面。作为一项金融服务,Revolut 使用机器学习来自主冲刷数百万笔交易,并打击欺诈性的卡交易,以避免因欺诈造成的损失,并确保客户交易的安全。Revolut 构建的卡欺诈预防系统被标记为夏洛克,完全无服务器的实现架构可以在下面找到。

在数据/特征管理的情况下,很像 Ocado 的实现,夏洛克在数据流上使用 Apache Beam 转换来转换提取后的数据。CatBoost 被用作使用 boosting 算法构建模型的建模库。Python 被用作模型开发和模型部署的主要语言。

将模型部署到生产中

使用 Google Cloud Composer(在 Apache Airflow 上运行)完成生产流程编排的培训。该模型作为 Flask 应用程序部署在 AppEngine 上。为了降低延迟,模型被缓存在内存中。还有 Couchbase(他们存储客户和用户资料的内存数据库)。

引用这个消息来源:“通过 HTTP POST 请求收到交易后,夏洛克应用程序从 Couchbase 获取相应用户和商家的资料。然后,它生成一个特征向量(使用与生成训练数据的 Apache Beam 作业中创建的特征相同的特征)并进行预测。然后,该预测在 JSON 响应中被发送到处理后端,在那里采取相应的行动——所有这些都在 50 ms 内完成

监控模型在生产中的性能

为了监控他们的生产系统,Revolt 使用了:

Google Cloud Stackdriver 监控操作性能,如延迟(系统响应速度)、每秒处理的事务数量等。一切都是实时的!

  • Kibana 用于功能性能监控,如监控商户、警报和欺诈数量、真阳性率(TPR)和假阳性率(FPR)。
  • 对于警报,Google Cloud Stackdriver 会向团队发送电子邮件和短信,以便欺诈检测团队对问题进行分类。你可以在下面找到一个基巴纳可视化的例子。

迭代和模型生命周期管理

确认交易是否欺诈的责任委托给了用户,因此团队在构建直观的用户界面以获得优质用户体验方面付出了更多努力。下面是一个用户在夏洛克将交易归类为欺诈的场景中看到的示例。

虽然没有提到模型再训练是如何发生的,但它被认为很像 Ocado 的情况,来自用户的反馈作为基本事实(标签)被返回到数据库中,并且模型被安排在频繁和定期之间进行再训练。

解释和审计模型使用的模型治理

也没有提到模型在生产中是如何被治理的,特别是对于像这样的用例,必须有一个人在回路中的 SME(主题专家)来审查。基于该实现,假设用户将发送关于用他们的帐户处理的交易是否是欺诈的准确信息。

对于审计模型,在 Google Cloud AI Platform(Cloud ML Engine)中启用了模型版本控制,提供了所有的训练和性能细节,以便可以跟踪模型血统。

利用端到端托管人工智能平台实施 MLOps 的公司

5.碳

Carbon 是一家总部位于拉各斯(尼日利亚)的金融科技公司,为个人提供信贷、简单的支付解决方案、高收益的投资机会和易于使用的个人财务管理工具。

Carbon 如何实现机器学习操作(MLOps)

Carbon 的核心业务是以比传统银行贷款更快的简单、便捷的流程提供消费者贷款。为了以简单、方便和快速的流程向信用良好的客户提供贷款,Carbon 采用了机器学习。

为了有效地为其业务运营机器学习解决方案,Carbon 使用 DataRobot 来建立稳健的信用风险模型,为他们节省了整个端到端的流程,并让公司有时间获取正确的数据,并做出其他有助于推动业务发展的决策。

它使用 DataRobot 的信用风险算法引擎来支持其移动应用程序。这不仅大大减少了公司实施机器学习解决方案所需的时间,还帮助企业实现了快速批准(或拒绝)贷款的目标,扩展到大量用户,并且足够准确,以确保一定程度的自治。

系统的工作方式(引用参考资料部分的来源):

当消费者在移动应用程序上提交申请时,Carbon 的模型利用来自第一、第二和第三方来源的各种数据来建立信用评级。在五分钟内,用户将获得信用评级,“好”客户将获得更好的利率和更高的限额,而高风险客户将获得更高的利率。

Carbon 每月通过 DataRobot 的预测 API 处理 15 万份贷款申请,并在 DataRobot MLOps 中跟踪这些部署。四个独立的记分卡提供了对每个客户贷款违约可能性的洞察。该应用程序随后会相应调整其贷款条款。碳算法还考虑了欺诈和反洗钱行为。

随着他们以同样的目标扩展到其他国家,DataRobot 平台允许他们在建立客户数据库时重新培训和重新部署他们的模型。

使用内部端到端机器学习平台实施 MLOps 的公司

6.优步

优步是世界上最受欢迎的拼车公司。通过优步应用程序,那些开车和送货的人可以与骑手、食客和餐馆联系。

优步的许多服务作为机器学习解决方案具有商业意义。从智能地估计司机的到达时间或骑手的位置,到根据用户的需求和司机的供应确定最佳的行程费用,这些都是优步业务的核心。

优步如何实现机器学习操作

根据他们的工程博客,机器学习帮助优步做出数据驱动的决策。它不仅支持拼车(目的地预测、司机-乘客配对、预计到达时间等)等服务,还支持财务规划和其他核心业务需求。机器学习解决方案也在优步的其他一些业务中实施,如 UberEATSuberPool ,以及优步的自动驾驶汽车部门

他们通过一个名为米开朗基罗的内部 ML 即服务平台来操作他们的机器学习模型。它使他们的团队能够无缝地大规模构建、部署和操作机器学习解决方案。它旨在涵盖端到端的 ML 工作流:管理数据、训练、评估、部署模型、做出预测和监控预测。你可以在下面找到平台的架构;

将模型部署到生产中

优步通过米开朗基罗平台,以三种模式成功地将其模型从开发过渡到生产:

在线预测:优步为需要提供实时预测服务的模型实施这种模式。经过训练的模型被打包到多个容器中,并作为预测服务在群集内在线运行。预测服务接受来自客户端的单个或批量预测请求,以进行实时推断。它非常适合他们的服务(如动态定价、司机-乘客配对等),这些服务涉及持续的数据流和高度可变的输入。

  1. 离线预测:已经离线训练好的模型被打包到一个容器中,在 Spark 作业中运行。只要有客户请求或重复的时间表,部署的模型就可以生成离线/批量预测。以这种方式部署的模型对于不需要实时结果的内部业务需求非常有用。
  2. 嵌入式模型部署:虽然在本文(从 2017 年开始)中提到优步正计划包括库部署,但杰瑞米·赫尔曼(优步机器学习平台的负责人)确实提到模型现在正通过其应用程序部署在手机上,用于边缘推理。
  3. 著名工具:

PyML 不仅在开发方面,而且在将一个训练好的模型部署到生产方面都具有灵活性,因为您可以通过 API 或米开朗基罗用户界面部署到生产中进行批量/实时预测。

  • 在平台的后端, Cassandra 数据库被用作模型商店。
  • 监控模型在生产中的性能

通过米开朗基罗,优步通过以下方式监控成千上万的模型:

随着时间的推移发布度量特征和预测分布,以便团队或系统可以发现异常。

  • 记录模型预测并加入由数据管道生成的观察结果(或地面实况),以观察模型的预测是否正确。此处的一个示例是记录客户用餐配送的预计到达时间,并将其与实际配送时间相结合,以便可以在仪表板上监控模型产生的估计误差(用于真实世界的测量)。
  • 基于用于度量模型性能的指标来度量模型的准确性。
  • 他们还使用数据质量监控器(DQM) 大规模监控其数据质量,这是他们的内部数据监控系统,可自动发现数据集之间的异常,并进行自动测试以触发数据质量平台上的警报。收到警报后,数据表所有者知道检查潜在问题表的质量测试,如果许多测试和指标失败,他们可以继续进行根本原因分析,并采取措施来减轻停机。

它们还使用 DQM 系统来自动检测失败的作业和调度程序。

迭代和模型生命周期管理

优步使用 API 层来管理生产中模型的生命周期,并将它们的性能指标集成到运营团队的警报和监控工具中。

根据这篇博文中的,API 层还包含工作流系统,用于编排批处理数据管道、培训作业、批处理预测作业以及将模型部署到批处理和在线容器。

著名工具:

优步 ML 团队使用Manifold——一种用于机器学习的与模型无关的可视化调试工具——来调试模型在开发期间和部署到生产环境时的性能。

  • 解释和审计模型使用的模型治理

米开朗基罗包括用于审计和管理数据和模型血统可追溯性的特性。这包括了解一个模型从实验中获得的途径,它在什么数据集上被训练,以及哪个模型已经被部署到特定业务用例的生产中。该平台还包括参与特定模型生命周期或管理数据集的各种人员。

7.网飞

你知道网飞,但我还是要介绍他们:网飞可能是世界上最受欢迎的电视节目和电影流媒体平台,毫无疑问,它彻底改变了我们在线观看节目和电影的方式。

就像优步一样,网飞在他们的产品中的许多领域使用机器学习,并部署了数以千计的机器学习模型。就业务需求而言,机器学习主要帮助网飞个性化他们客户的体验,以及优化(他们客户的)体验所需的内容。

网飞如何实现机器学习操作

在网飞,机器学习的用例随处可见。从目录构成到优化内容的流媒体质量,再到推荐要制作的节目,再到检测用户注册过程中的异常情况,所有这些都围绕着通过个性化优化用户体验的业务需求。

让我们以他们的推荐用例为例。这种使用情形包括:

这个用例的业务目标是在用户观看之前预测他们想看什么。他们的机器学习解决方案的成功实施将取决于这一业务目标。

将模型部署到生产中

与优步类似,网飞大学的机器学习团队部署在线和离线模式的模型。除了这两种模式,它们还执行近线部署(其中模型被部署到在线预测服务,但不需要执行实时推理)。这种模式提高了系统对客户请求以及在线预测服务的响应能力。

模型由团队离线训练、验证和部署。离线模型通过内部发布和订阅(或发布/订阅)系统作为预测服务在线部署。我将在下面详细介绍。

以网飞的个性化系统(推荐)为例,在开发阶段,各种模型根据历史观看数据进行训练和验证,并进行离线测试,以查看它们是否满足所需的性能。如果是这样,经过训练的模型将被部署到现场 A/B 测试中,以查看它们在生产中是否表现良好。根据需要,结果也可以由模型离线计算,作为批量推断。你可以在这里了解更多关于网飞推荐系统的架构。

在工具方面,网飞团队构建并使用了 Metaflow,这是一个开源的机器学习框架不可知库,它通过训练机器学习模型和有效管理数据来帮助数据科学家快速实验。它提供了一个 API,将 ML 管道组装成一个 DAG(有向无环图)工作流,图中的每个节点作为一个处理步骤。

使用 Metaflow API,他们的 ML 工作负载通过一系列称为“流”的步骤,与 AWS 云基础设施服务无缝交互,如存储和计算、网飞的开发笔记本( Polynote )和其他用户界面。

对于调度模型训练作业,Meson 是网飞团队在将模型从开发转移到生产以调度模型训练作业时用于工作流编排的内部编排引擎。它还能确保模型在生产中不会过时,并针对动态工作负载持续进行在线学习。

Meson 引擎与 Mesos(用于集群管理的基础架构引擎)集成,执行作业调度,提交培训 ETL(提取、转换和加载)作业以触发集群,并提供这些工作流和工作流指标的主动监控和日志记录。

Meson 与内部的模型生命周期管理系统(称为跑道)集成,以将培训管道部署到生产、快速原型制作和测试新模型。

从上面的架构中可以看出,培训作业/管道元数据和笔记本元数据(如培训运行、实验信息、超参数组合、笔记本版本和贡献者)存储在亚马逊简单存储服务(S3) 中,其余数据存储在这里。

监控模型在生产中的性能

网飞使用内部自动化监控和警报工具来监控通过客户端在线功能聚合产生的不良数据质量,然后将其提供给他们的推荐服务,以便检测数据漂移。

网飞使用一个名为 Runway 的内部工具来监控和提醒 ML 团队生产中过时的模型。为了在推荐的情况下监控模型性能,收集基本事实数据(即用户是否播放推荐的视频)并将其与模型的结果进行比较,以跟踪其性能。

Runway 还保持模型的监控时间线,包括模型发布历史、警报历史(包括解决时间)和模型指标。这有助于团队发现模型陈旧性(如上所述)以及分类和故障排除的潜在问题。用户可以通过设置阈值来轻松配置陈旧性警报,该阈值基于模型预测与实际情况和模型指标的比较来检查模型陈旧性。

使用 Runway 工具,网飞团队还可以可视化应用程序集群,这些集群使用模型的预测,直到模型实例(包括模型信息),以便有效地监控系统指标和模型加载故障。

逻辑:他们使用仪表板来监控通过将数据属性与历史数据属性(这是此度量的基线属性)进行比较而生成的数据的质量,以便监控工具可以轻松发现偏差或不匹配。

除了发现不匹配,该工具还通过将输入数据属性与基线数据属性(或要素,如您所知)进行比较来检查输入数据属性中的基础分布(分布是为每个属性单独计算的),基线数据属性可能是几天或几周前的数据,也可能是实际的训练数据。你可以在这里了解更多关于分布检验背后的算法和统计检验。

迭代和模型生命周期管理

数以千计的机器学习模型正在驱动网飞的用例,如他们的个性化系统, Runway 用于管理生产中的所有这些模型

runway——网飞的模型生命周期管理系统——提供了一个存储来跟踪模型相关的信息,包括工件和模型血统。据个性化基础设施团队的高级软件工程师 Liping Peng 介绍,Runway 还为 ML 团队提供了一个用户界面,用于搜索和可视化模型结构和元数据,以轻松理解生产中的模型或即将部署到生产中的模型。

由于跑道页面内的无缝导航以及与其他网飞系统的集成,管理也变得更加容易,因为您可以调试和排除模型故障。该工具还提供了基于角色的生产模型和未使用模型的视图——这也使得模型管理更加容易。

网飞也有执行事实记录的系统。他们的 ML 团队可以用新数据离线保持训练和测试模型。

网飞团队使用内部的 A/B 测试框架(收集测试的元数据,以便团队可以轻松地搜索和比较测试)。它用于测试和跟踪由真实人员部署和使用的模型是否解决了预期的实际业务问题。(来源)

解释和审计模型使用的模型治理

Runway 使 ML 团队能够通过跟踪模型元数据(如 Dag、超参数和模型文件)和配置实例(可视为版本),如管道运行细节,来跟踪模型谱系。通过一个中央仪表板,团队可以看到模型的训练数据(和功能)、发布信息、警报和验证配置以及预测结果。

网飞团队还使用 SparkSQL 和内部审计库审计从客户端生成的数据的质量,这些审计库审计数据集的各个属性,让团队设置警报和分类的阈值。例如,当在内容播放的平均持续时间中检测到异常时,开发团队应该收到审计警报。

8.门饰

为了理解 DoorDash 如何实现机器学习操作,你需要了解一下这家公司是做什么的。转述Raghav Ramesh(door dash 的工程经理) : DoorDash 是一家专注于成为每个城市最后一英里物流层的科技公司。它通过授权当地企业提供送货,将他们与寻找送货的消费者和送货人员联系起来。

DoorDash 如何实现机器学习操作(MLOps)

DoorDash 在几个案例中使用机器学习,旨在优化 dashers、商家和消费者的体验。

DoorDash 采用的一个主要机器学习解决方案是在他们的内部物流引擎中。在 DoorDash,机器学习对权力进行建模:

在任何给定的时间内预测和平衡(搅拌器的)供给和(消费者的)需求

DoorDash 的团队使用集中式机器学习平台进行训练、服务预测、监控、记录、评估等。他们的平台主要基于微服务架构。

将模型部署到生产中

DoorDash 的机器学习模型是出于探索(研究)原因或生产需要而开发的。生产模型通常被安排为培训管道中的一项工作。该团队采用外部(开源)机器学习框架,例如:

机器学习包装器用于包装训练管道,使其与模型无关。该团队使用 Apache Airflow 来安排和执行培训工作。文件(模型和模型配置的原生格式)和元数据(使用的训练数据、训练时间、使用的超参数)被写入模型商店(存储在亚马逊 S3),在那里它们准备好被与整个 DoorDash 微服务架构集成的服务加载。

Sibyl 是 DoorDash 的预测服务,用于向各种用例提供输出。它是使用 Kotlin 开发的,并使用 Kubernetes 容器部署。该团队使用一个模型服务从模型存储中加载模型,并将它们缓存在内存中,以避免向 Sibyl 提供模型时的延迟。模型服务还有助于处理阴影预测和可选的 A/B 测试实验。

当收到预测请求时,平台会检查缺失的要素,如果有,它会联系一个要素服务,该服务会尝试从要素存储库(这是一个 Redis 要素值的内存缓存)中获取这些要素,这也适用于服务需要额外要素进行预测的请求。要素服务支持多种要素类型(包括聚合要素、嵌入等)。DoorDash 团队对要素存储中的要素进行标准化,以使数据(预测服务将使用这些数据进行预测)更加可靠。

根据使用情况,预测可以是实时的、异步的(批量预测),也可以是“影子模式”。团队使用“阴影模式”预测类型来测试生产中的多个模型,同时只确保模型的一个版本的结果是作为对预测请求的响应而返回的。

预测响应通过 gRPC 作为 protobuf 对象返回给客户机,而不是流行的 XML 或 JSON 序列化格式。预测还会记录到雪花数据存储中,其中包含元数据,如用于审计和调试预测的预测时间和模型 id。

监控模型在生产中的性能

DoorDash 使用监控服务来监控其生产的模型。该服务跟踪以下内容:

Sibyl 为监控模型指标而做出的预测,

  • 特征的分布被可视化,并且设置警报以监控数据漂移
  • 由预测服务生成的所有预测和来自预测请求的预测的日志。
  • DoorDash 团队使用 Prometheus 监控框架收集和汇总监控统计数据,同时生成要监控的指标。他们使用 Grafana (它有一个直观的 UI 和仪表板)通过在图形和图表上可视化它们来可视化地监控这些指标。对于警报,他们使用 Prometheus 的警报管理器及其内部 Terraform 存储库,在超过某个指标(如数据漂移)的阈值时向相关服务所有者发送警报。

服务所有者和/或团队通过连接的 Slack 应用程序或page duty在其渠道中接收警报。对于日志,他们利用内部阿帕奇卡夫卡流媒体解决方案来记录不同的事件和预测。

你可以从他们的详细文章这里了解更多关于 DoorDash 的监控/可观察性平台。

迭代和模型生命周期管理

生产中模型的再培训是通过培训管道安排和执行的。模型文件和元数据被写入模型存储。这些模型被用作影子模型(在生产数据上测试新模型,而不将结果返回给客户端),并且它们的预测被记录下来,以便可以监控新模型的度量,并且可以在新模型被完全部署为生产中的事实模型之前对其进行改进。

解释和审计模型使用的模型治理

模型存储为审计追踪的每个模型存储元数据(使用的训练数据、训练时间、使用的超参数),并使模型血统可追踪。这有助于在生产中对模型进行故障排除和调试。关于该系统是否基于角色并包括 ACL(访问控制级别)的细节没有具体说明。

我们可以从顶级 MLOps 实施流程中学到什么

我明白,光是学习这些组织如何在生产中实施他们的机器学习解决方案就需要做很多工作。但是对你有什么好处呢?你可能没有优步规模的运营,甚至可能没有假日临时演员的规模,并且可能不期望很快扩大你的解决方案。

然而,万一你计划大规模扩展,我认为你可以从实现过程中学到一些东西。无论你是一个工程师团队还是一组工程师团队,或是一个快速成长的团队,或是一个大型的成熟团队,这些想法和原则基本上都是你应该挑选出来的:

围绕您的业务目标规划您的实施,以便优化所需的结果;而不仅仅是复制其他人如何实现他们的解决方案。

  • 早期考虑数据质量,而不仅仅是收集和存储数据。如何评估您的数据质量?输入数据多久更改一次?这些应该有助于指导您如何考虑您的实现。
  • 从您的试点解决方案的简单且管理良好的实施开始。想法是尽可能快地建立一个端到端的管道,但是要确保它是简单的和可管理的(可能使用托管服务)。这是因为 MLOps 从根本上说是一个基础设施问题。使用托管服务可以节省您大量的时间、精力和成本,因此您的团队可以专注于提高工作效率,而不仅仅是处理系统。
  • 找到模板化的最佳实践,用那些容易实施且成本效益高的实践来进行试验——那些容易实现的成果
  • 思考上面的指南,然后开始规划您的工具/技术堆栈。确保您正在使用的工具或平台能够帮助您:

集中并跟踪您的整个工作流程/过程,

  • 重现你的结果,
  • 跟踪你的过程,
  • 简化与他人的协作,
  • 快速部署,以便您可以快速测试哪些模型有效,以及它们是否解决了所需的问题。
  • 模型不解决笔记本或纸上的问题——它们在生产时解决问题(或不解决)。试着遵循上面列出的建议,让你的整个工作流程有条不紊,很快你就会知道什么有效,什么无效。

当然,你的工具将在很大程度上取决于你——或你的团队——的背景、实地预算(计算、存储等)、它与现有组织工程系统的集成——以及其他事情。确保选择足够灵活的工具进行内部和外部(第三方)集成;从长远来看,这将为你省去很多头疼的事情

结论

这是一篇很长的文章,所以谢谢你能坚持到现在。我希望你已经能够深入了解这些公司是如何用 ML 解决许多问题,而其他公司是如何在生产中用一些 ML 模型解决一些问题的。

基于这些见解,我敦促你开始计划如何将这些机器学习模型部署到生产和操作中。但是你可能想先看看下面的参考资料。感谢阅读!

参考资料和其他资源

假日临时演员 ocado 郁郁葱葱的反抗

优步

网飞

门饰

其他人

Uber

Netflix

DoorDash

Others

如何在 TensorFlow / Keras 中构建轻量级图像分类器

原文:https://web.archive.org/web/https://neptune.ai/blog/how-to-build-a-light-weight-image-classifier-in-tensorflow-keras

计算机视觉是一个快速发展的领域,正在取得巨大的进步,但仍然有许多挑战需要计算机视觉工程师来解决。

首先,他们的终端模型需要健壮和准确。

其次,最终的解决方案应该足够快,并且在理想情况下,达到接近实时的性能。

最后,模型应该占用尽可能少的计算和内存资源。

幸运的是,有许多最先进的算法可供选择。有些在精确度方面是最好的,有些是最快的,有些是难以置信的紧凑。军火库确实很丰富,计算机视觉工程师有很多选项可以考虑。

计算机视觉解决的任务

图像分类

Image Classifier

Source: 9 Applications of Deep Learning for Computer Vision by Jason Brownlee

在本文中,我们将着重于创建图像分类器。图像分类是一项基本任务,但仍然是计算机视觉工程师能够处理的最重要的任务之一。

对图像进行分类意味着确定类别。类别的数量受限于您想要区分的图像类型的数量。例如,您可能希望根据车辆类型对图像进行分类。类别的可能选项有:自行车、汽车、公共汽车和卡车。

或者,您可能想要一个更详细的集合,并将高级类分解成低级子类。用这种方法,你的类列表可能包括运动自行车,直升机,踏板车,和全地形自行车。汽车类别将进一步分为掀背车,皮卡,紧凑型车,运动跑车,跨界车和面包车。对于公共汽车和卡车也可以进行类似的分解。

最终的类别集由计算机视觉工程师确定,该工程师非常了解问题领域,并且熟悉数据集和可用的注释。

目标检测

如果您处理的图像有多个关联的类,该怎么办?继续我们之前的例子,一张图片可能包含一辆公共汽车和一辆摩托车。你肯定不想错过任何一个对象,想两个都抓住。这里,对象检测开始发挥作用。

在计算机视觉中,检测一个对象意味着定位它并给它分配一个类别。简单来说,我们希望在图像上找到一个对象并识别它。如您所见,对象检测包含图像分类部分,因为我们在对象被定位后进行分类。它强调了一个事实,即图像分类是计算机视觉的核心,因此需要认真学习。

语义分割

Semantic segmentation

Source: Computer Vision Tutorial: A Step-by-Step Introduction to Image Segmentation Techniques (Part 1) by PULKIT SHARMA

最后,让我们简单讨论一下语义分割,对图像的每个像素进行分类。如果一个像素属于一个特定的对象,那么这个像素对于这个对象被分类为阳性。通过将该对象的每个像素分类为阳性来分割该对象。这再次强调了分类的重要性。

当然,计算机视觉中还有很多其他的任务我们今天不会去碰,但是相信我,图像分类是最核心的一个。

什么使得图像分类成为可能

在我们继续学习如何创建轻量级分类器的实用指南之前,我决定暂时停下来,回到问题的理论部分。

这个决定是经过深思熟虑的,来自我的日常观察,越来越多的计算机视觉工程师倾向于在非常高的水平上处理问题。通常,这意味着一个简单的预训练模型导入,将准确性设置为一个度量,并启动训练作业。由于在创建最常见的机器学习框架(scikit-learn、PyTorch 或 Tensorflow)方面所做的大量工作,如今这已经成为可能。

这些框架中的这些进步是否意味着没有必要深究算法背后的数学?绝对不行!了解使图像分类成为可能的基础知识是一种超能力,你可以,而且肯定应该得到。

当一切顺利时,您可能会觉得没有必要超越基本的模型导入。但是,每当你面临困难的时候,理解算法就会很好地为你服务。

也不需要成为策划人。对于深度学习,你需要掌握的只是卷积神经网络的概念。一旦你学会了这一点,你就可以解决在训练机器学习模型时可能遇到的任何问题。相信我,如果你在机器学习的职业道路上,会有很多这样的情况。

:在这篇文章里我就不细说 CNN 了,我想说明一下其他的事情。但是,我会分享一些我在网上找到的资源,我认为它们对理解 CNN 非常有用。您可以在参考资料部分找到它们。

最佳卷积神经网络综述

Convolutional Neural Network

Source: Convolutional Neural Network | Deep Learning by Swapna K E

当 CNN 的概念清晰时,你可能会想知道现在哪种 CNN 表现最好。这就是我们在这一节要讨论的内容。

尽管第一个 CNN 是在 20 世纪 80 年代推出的,但真正的突破发生在 21 世纪初,图形处理单元(GPU)的出现。

为了了解进展有多快,有必要看一下在一年一度的名为 ImageNet 大规模视觉识别挑战赛(ILSVRC)的比赛中取得的错误率统计数据。以下是错误率的历史变化情况:

Error rate history

Error rate history on ImageNet (showing best results per team and up to 10 entries per year) | Source

从 2016 年到现在,关于 CNN 已经有了很多进展。

今天值得我们关注的一个架构是由谷歌人工智能的研究人员在 2019 年 5 月推出的。谷歌人工智能博客上发布了一篇名为“ EfficientNet:通过 AutoML 和模型缩放提高准确性和效率”的文章。研究小组发明了一种全新的 CNN 架构,称为 EfficientNet,这让每个计算机视觉工程师都大吃一惊。

结果证明它非常好,在所有方面都超过了以前所有最先进的架构:准确性、速度和净尺寸。相当令人印象深刻!

今天,我想向您展示利用 Google 的最新发明是多么简单,并以一种简单的方式将其应用于您的分类问题,只要您在 Tensorflow / Keras 框架中工作。

机器学习中的 TensorFlow 和 Keras 框架

框架在每个信息技术领域都是必不可少的。机器学习也不例外。在 ML 市场上有几个成熟的玩家帮助我们简化整体的编程体验。PyTorch、scikit-learn、TensorFlow/Keras、MXNet 和 Caffe 只是值得一提的几个。

今天,我想重点谈谈 TensorFlow/Keras。毫不奇怪,这两个是机器学习领域中最受欢迎的框架。这主要是因为 TensorFlow 和 Keras 都提供了丰富的开发能力。两个框架非常相似。无需深究细节,您应该知道的关键要点是,前者(Keras)只是 TensorFlow 框架的包装器。

关于卷积神经网络,Keras 让我们使用机器学习世界中最新的 CNN 架构来导入和构建我们的模型。查看官方文档页面,在这里你可以找到 Keras 中完整的预训练模型库,以便进行微调。

图像分类器创建:真实项目示例

项目描述

好了,让我们利用 Keras 中可用的预训练模型,解决一个现实生活中的计算机视觉问题。我们将要进行的项目旨在解决一个图像方向问题。我们需要创建一个可以对输入图像的方向进行分类的模型。输入图像有四种方向选项:

  • 正常,
  • 逆时针旋转 90 度,
  • 逆时针旋转 180 度,
  • 逆时针旋转 270 度。

给定输入图像的四个方向,我们可以得出结论,模型应该能够区分四个类别。

Input image orientation

Input image orientation options displayed

该模型不应该检测任何图像的方向。如上所述,模型将处理的图像集仅限于一种类型。

该数据集包含大约 11,000 幅图像,所有图像都经过检查并确认处于正常方向。

数据生成器创建

Data generator creation

Source: Keras data generators and how to use them by Ilya Michlin

因为数据集中的所有图像都处于正常方向,所以我们需要在将它们输入到神经网络之前对它们进行旋转,以确保每个类都被表示出来。为此,我们使用一个定制的图像生成器。

自定义生成器的工作方式如下:

  • 在给定路径的情况下,从数据集中读取单个图像;
  • 图像旋转到四个方向之一。旋转方向是随机选择的。以相等的概率对每个方向进行采样,得到四个输入类的平衡;
  • 使用一组预定义的增强方法来增强旋转的图像;
  • 使用传递的预处理函数对旋转和增强的图像进行预处理;
  • 堆叠旋转和增强的图像以创建一批给定大小的图像;
  • 当这一批形成时,它被输出并输入神经网络。

以下是项目中使用的自定义数据生成器的完整代码:

class DataGenerator(Sequence):

    """
    Generates rotated images for the net that detects orientation
    """

    def __init__(self,
                 data_folder,
                 target_samples,
                 preprocessing_f,
                 input_size,
                 batch_size,
                 shuffle,
                 aug):
        """
        Initialization

        :data_folder: path to folder with images (all images: both train and valid)
        :target_samples: an array of basenames for images to use within generator (e.g.: only those for train)
        :preprocessing_f: input preprocessing function
        :input_size: (typle, (width, height) format) image size to be fed into the neural net
        :batch_size: (int) batch size at each iteration
        :shuffle: True to shuffle indices after each epoch
        :aug: True to augment input images
        """

        self.data_folder = data_folder
        self.target_samples = target_samples
        self.preprocessing_f = preprocessing_f
        self.input_size = input_size
        self.batch_size = batch_size
        self.shuffle = shuffle
        self.aug = aug
        self.on_epoch_end()
    def __len__(self):
        """
        Denotes the number of batches per epoch

        :return: nuber of batches per epoch
        """
        return math.ceil(len(self.target_samples) / self.batch_size)
    def __getitem__(self, index):
        """
        Generates a batch of data (X and Y)
        """

        indices = self.indices[index * self.batch_size : (index + 1) * self.batch_size]

        images_bn4batch = [self.target_samples[i] for i in indices]
        path2images4batch = [os.path.join(self.data_folder, im_bn) for im_bn in images_bn4batch]

        images4batch_bgr = [cv2.imread(path2image) for path2image in path2images4batch]
        images4batch_rgb = [cv2.cvtColor(bgr_im, cv2.COLOR_BGR2RGB) for bgr_im in images4batch_bgr]

        if self.aug:
            angle4rotation = 2
            images4batch_aug = [self.__data_augmentation(im, angle4rotation) for im in images4batch_rgb]
        else:
            images4batch_aug = images4batch_rgb

        rotated_images, labels = self.__data_generation(images4batch_aug)
        images4batch_resized = [cv2.resize(rotated_im, self.input_size) for rotated_im in rotated_images]

        if self.preprocessing_f:
            prep_images4batch = [self.preprocessing_f(resized_im) for resized_im in images4batch_resized]
        else:
            prep_images4batch = images4batch_resized

        images4yielding = np.array(prep_images4batch)

        return images4yielding, labels
    def on_epoch_end(self):
        """
        Updates indices after each epoch
        """

        self.indices = np.arange(len(self.target_samples))
        if self.shuffle:
            np.random.shuffle(self.indices) 
    def __data_generation(self, images):
        """
        Applies random image rotation and geterates labels.
        Labels map: counter clockwise direction! 0 = 0, 90 = 1, 180 = 2, 270 = 3

        :return: rotated_images, labels
        """

        labels = np.random.choice([0,1,2,3], size=len(images), p=[0.25] * 4)
        rotated_images = [np.rot90(im, angle) for im, angle in zip(images, labels)]

        return rotated_images, labels
    def __data_augmentation(self, image, max_rot_angle = 2):
        """
        Applies data augmentation

        :max_rot_angle: maximum angle that can be selected for image rotation
        :return: augmented_images
        """

        rotation_options = np.arange(-1 * max_rot_angle, max_rot_angle + 1, 1)
        angle4rotation = np.random.choice(rotation_options, 1)

        sometimes = lambda aug: iaa.Sometimes(0.5)

        seq = iaa.Sequential(
            [
            iaa.OneOf(
                [iaa.Add((-15,15), per_channel=False),
                 iaa.Multiply((0.8, 1.2)),
                 iaa.MultiplyHueAndSaturation((0.8,1.1))
            ]),

            iaa.OneOf(
                [iaa.AdditiveGaussianNoise(loc=0, scale=(0.02, 0.05*255), per_channel=0.5),
                 iaa.AdditiveLaplaceNoise(loc=0,scale=(0.02, 0.05*255), per_channel=0.5),
                 iaa.AdditivePoissonNoise(lam=(8,16), per_channel=0.5),
            ]),

            iaa.OneOf(
                [iaa.Dropout(p=0.005,per_channel=False),
                 iaa.Pepper(p=0.005),
                 iaa.Salt(p=0.01)
            ]),

            sometimes(
                iaa.FrequencyNoiseAlpha(
                    exponent=(-1,2),
                    first=iaa.Multiply((0.9, 1.1), per_channel=False),
                    second=iaa.ContrastNormalization((0.8,1.2)))
            ),

            iaa.OneOf([
                iaa.GaussianBlur((0.5, 1)), 
                iaa.AverageBlur(k=(3, 5)), 
                iaa.MotionBlur(k=(5, 7), angle=(0, 359)), 
                iaa.MedianBlur(k=(5, 7)), 
            ]),

            sometimes(iaa.JpegCompression((60,80))),

            iaa.OneOf(
                [iaa.GammaContrast((0.7,1.3)),
                 iaa.GammaContrast((0.7,1.3),per_channel=True),
                 iaa.SigmoidContrast(gain=(5,8)),
                 iaa.LogContrast((0.6,1)),
                 iaa.LinearContrast((0.6,1.4))
            ]),

            sometimes(
                iaa.Affine(rotate = angle4rotation, mode = 'edge')
            )
        ])

        img_aug = seq(images = [image])[0]

        return img_aug

应该仔细考虑图像增强。例如,我们的项目假设没有几何变换。由于两个原因,作物、翻耕和翻地应排除在可能的选项之外:

  • 这种增强会影响输入图像的方向,结果,我们可能会得到无效的模型预测。
  • 这种变换并不反映模型将来要处理的图像。情况并非总是如此,但对于这个特殊的项目,模型将接收没有几何变化的图像。这就是为什么在训练模型时不需要综合应用这些变化。

应该应用主要在像素级工作的其他增强类型。它意味着细微的变化,例如,颜色和对比度。模糊,混合和汇集也适用。要了解更多关于各种增强技术的信息,请看一下 imgaug GitHub 页面。

值得一提的是,该项目将初始化两个数据生成器:

  • 第一个用于生成训练数据,
  • 第二个将用于产生验证数据。

定型集和验证集之间的数据拆分比例为 8:2。所有数据的 80 %将专用于训练模型,20 %将用于模型评估。

神经网络架构设计

我们将通过引入一个主干来开始设计我们未来的图像分类器。Keras 让我们可以访问它的模型动物园,有多个 CNN 可供输入。我们的目标是创建一个轻量级的分类器,所以我们肯定应该考虑 EfficientNet,它非常高效和准确。

要导入 EfficientNet,首先你必须决定使用哪种深度。EfficientNet 有 8 个深度级别,从 B0(基线)开始,到最深的 B7 结束。EfficientNet-B7 在 ImageNet 数据集上达到了 84.4%的前 1 名/ 97.1%的前 5 名准确率。

EfficientNet comparison

EfficientNet compared to other popular CNN architectures.
Performance metrics shown on ImageNet dataset.

要选择合适的深度级别,您应该始终考虑问题的复杂性。从我的个人经验来看,选择 B1 或 B2 是一个很好的起点,因为它们足以解决大多数现实生活中的计算机视觉问题。如果你想了解更多关于 EfficientNet 的架构设计,可以考虑阅读由 Armughan Shahid 撰写的这篇文章

我们的项目并不复杂。这就是为什么 B1 是高效网络主干的理想深度。让我们导入 EfficientNet B1 并初始化这个类的一个对象。

from tensorflow.keras.applications.efficientnet import EfficientNetB1, preprocess_input

backbone = EfficientNetB1(include_top = False,
                          input_shape = (128, 128, 3),
                          pooling = 'avg')

查看用于初始化的参数集。有很多这样的例子,但我只想重点介绍其中的几个:

  • include_top 是一个布尔值,它指定是否在网络顶部包括完全连接的层。对于一个自定义的图像分类器,我们需要创建我们自己的网络的顶部来反映我们拥有的类的数量;
  • input_shape 是一个指示输入图像尺寸的元组:(图像高度、图像宽度、通道数量)。对于 B1,我决定使用相当小的输入图像大小—(128,128,3),但请记住,您的卷积神经网络越深,图像大小就越高。你肯定不希望从 B1 移到 B3,并保持输入图像大小不变;
  • 池化指定用于特征提取的池化模式。池有助于我们对要素地图中的要素进行下采样。选择的“平均”用于平均池模式。

因为我们没有包括顶部,所以我们必须明确地定义它。特别是,我们应该确定:

  • 顶部完全连接的层数;
  • 每个全连接层中的神经元数量;
  • 每层之后使用的激活函数;
  • 用于使人工神经网络更快、更稳定且不容易过度拟合的方法(例如:正则化、规范化等);
  • 反映我们试图解决的分类问题的最后一层设计。

这是我为这个项目选择的顶部架构:

from tensorflow.keras.layers import Dense, BatchNormalization, LeakyReLU, Softmax
from tensorflow.keras.models import Sequential

n_classes = 4
dense_count = 256

model = Sequential()
model.add(backbone)

model.add(Dense(dense_count))
model.add(LeakyReLU())
model.add(BatchNormalization())

model.add(Dense(n_classes))
model.add(Softmax())

如您所见,该模型是使用 Sequence 类实例设计的。第一步,添加模型主干。主干仍然是我们导入并初始化的 EfficientNet CNN 实例。

模型的顶部有两个完全连接的(密集)层。第一个有 256 个神经元和一个 LeakyReLU 激活功能。批量标准化通过图层输入的标准化来确保速度和稳定性。

第二层的神经元数量等于类的数量。Softmax 激活用于进行预测。

这是顶部的基本设计,我用在我开始的大多数基线模型上。作为一个生活黑客,我建议用没有中间全连接层的顶部来训练你的模型,只有用于预测的最终全连接层。

起初,这似乎是一个坏主意,因为它可能会由于模型容量减少而导致模型性能下降。令人惊讶的是,我的个人经验证明 EfficientNet 并非如此。在顶部删除中间层不会导致性能下降。此外,在 10 个案例中有 7 个案例中,它在减小最终模型尺寸的同时带来了更好的性能。很鼓舞人心,不是吗?试一试,你会发现 EfficientNet 有多酷。

模特培训

到目前为止,您应该已经有了一个生成器和一个模型设计来继续进行。现在,让我们训练模型并得到结果。

查看如何使用Neptune+tensor flow/Keras integration跟踪模型训练元数据。

我通常使用两阶段方法进行模型训练。当我不想因为迁移学习而引入新的数据集而大幅改变原始权重时,这对于微调尤其方便。随着高学习率的建立,它将导致第一模型层的权重发生显著变化,第一模型层负责简单的低级特征提取,并且已经在 ImageNet 数据集上进行了良好的训练。

在两阶段方法中,我们冻结了几乎整个主干,只留下最后几层可以训练。通过这样的冻结,模型被训练几个时期(如果我的训练数据集足够大,我通常不超过 5-10 个时期)。当这些最后层的权重被训练并且进一步的训练没有提高模型性能时,我们然后解冻整个主干,给模型一个机会对先前冻结的层中的权重进行轻微的改变,因此,在保持训练过程稳定的同时获得更好的结果。

下面是两阶段方法的代码:

1。模型被冻结

我们模型的主干有 7 个模块。对于第一阶段,前四个块是冻结的,因此这些块中的所有层都是不可训练的。第五,第六和第七块,以及模型的顶部没有被冻结,将在第一阶段进行训练。下面是在代码中如何执行模型冻结:

block_to_unfreeze_from = 5
trainable_flag = False

for layer in model.layers[0].layers:
    if layer.name.find('bn') != -1:
        layer.trainable = True
    else:
        layer.trainable = trainable_flag

    if layer.name.find(f'block{block_to_unfreeze_from}') != -1:
        trainable_flag = True
        layer.trainable = trainable_flag

for layer in model.layers[0].layers:
    print (layer.name, layer.trainable) 

为了检查冻结的结果,使用一个简单的打印语句来检查每一层的可训练性。

2。模型已编译

from tensorflow.keras.optimizers import Adam

model.compile(optimizer=Adam(learning_rate=0.001), loss='sparse_categorical_crossentropy',
              metrics=['sparse_categorical_accuracy'])

第一阶段,我建议编一个学习率稍微高一点的模型。例如,1e-3 是一个很好的选择。当在最后一层使用 Softmax 激活函数时,模型产生稀疏输出。这就是为什么稀疏度量和损失函数用于编译:它们可以正确地处理我们的模型产生的稀疏输出。

单词“稀疏”仅仅意味着模型输出一组概率:每个类一个概率。总而言之,所有这些概率总是等于 1。为了得出关于预测类别的结论,应该选择具有最高概率的索引。索引号是模型预测的类别。

如果您想知道稀疏和非稀疏指标有何不同,这里有一个准确性示例:

  • categorical _ accuracy 检查最大真值的索引是否等于最大预测值的索引
  • sparse _ categorical _ accuracy 检查最大真值是否等于最大预测值的索引。

3。使用标准启动培训作业。Tensorflow / Keras 中的拟合方法:

logdir = os.path.join(dir4saving, 'logs')
os.makedirs(logdir, exist_ok=True)

tbCallBack = keras.callbacks.TensorBoard(log_dir = logdir,
                                         histogram_freq = 0,
                                         write_graph = False,
                                         write_images = False)

first_stage_n = 15

model.fit_generator(generator = train_generator,
                    steps_per_epoch = training_steps_per_epoch,
                    epochs = first_stage_n,
                    validation_data = validation_generator,
                    validation_steps = validation_steps_per_epoch,
                    callbacks=[tbCallBack],
                    use_multiprocessing = True,
                    workers = 16
                   )
  • training_steps_per_epoch 和 validation_steps_per_epoch 只是两个整数,计算如下:

–training _ steps _ per _ epoch = int(len(train _ set)/batch _ train)
–validation _ steps _ per _ epoch = int(len(validation _ set)/batch _ validation

  • tbCallBack 是 Tensorboard 的回调
  • first_stage_n 是第一阶段训练的时期数
  • use_multiprocessing 和 workers 是设置多处理和要使用的 CPU 内核数量的两个参数

到第一阶段结束时,模型性能已经达到了一个良好的水平:主要度量(稀疏分类准确率)达到了 80%。现在,让我们解冻之前冻结的块,重新编译模型,并启动第二阶段的培训工作。

4。解冻模型,为第二个训练阶段做准备:

以下是解冻是如何完成的:

for layer in model.layers:
    layer.trainable = True

for layer in model.layers[0].layers:
    layer.trainable = True

5。模型被重新编译以应用块冻结中的变化

编译类似于我们在第一阶段所做的。唯一的区别是学习率值的设置。第二阶段,应该减少。对于这个项目,我将其从 1e-3 降低到 1e-4。

6。使用标准启动第二阶段培训。Tensorflow / Keras 中的拟合方法

同样,除了使用的回调次数之外,培训工作启动与我们在第一阶段的情况没有太大的不同。我们有很多这样的机会。我强烈推荐阅读这篇文章来熟悉 TensorFlow / Keras 中可用的选项。

在第二阶段结束时,模型性能很可能达到了 99.97 %左右——还不错!整个培训使用单个 GeForce RTX 2080 GPU,耗时约 4-5 小时。最终的模型检查点确实非常轻量级,只占用 85 mb 内存。

结论

我们已经完成了一个真实的计算机视觉项目,在 TensorFlow / Keras 中创建了一个图像分类器。我们作为主干网使用的 CNN 是来自谷歌的尖端高效网络架构。我们最终得到的模型非常轻。

为了比较,我用其他 CNN 做了很多骨干的实验。我得到的最好结果是 ResNet 50。使用这种架构,最终的模型大小约为 550 mb,达到的最高精度为 95.1 %。即使我们决定更深入地使用 EfficientNet,从 B-0 迁移到 B1、B2 甚至 B3,与 ResNet 相比,它们都要轻得多。

请记住,您可以考虑去掉模型的顶部,得到一个更轻的架构,它的性能也相当不错。在没有顶部部件和 ResNet B-0 的情况下,我能够实现 99.12 %的准确性,并且最终的模型大小非常小:只有 39 mb。为效率网热烈鼓掌!

参考

  1. 斯坦福大学 CS231n 课程,讲解视觉识别的卷积神经网络;
  2. 卷积神经网络课程由吴恩达教授,他是一位著名的机器学习讲师,知道如何用简单的术语解释复杂的概念;
  3. 来自谷歌的关于图像分类的 ML 实习,这是一个单页的网站,提供了你开始与 CNN 合作时需要知道的最基本的事情。对于那些没有时间,但仍然需要深入主题的人来说,这是一个很好的信息来源。

如何建立机器学习团队

原文:https://web.archive.org/web/https://neptune.ai/blog/how-to-build-machine-learning-teams-that-deliver

在这篇文章中,我记录了建立高效机器学习团队的最佳实践和方法,这种团队可以在公司实体中创造积极的业务影响和经济价值,无论是初创公司还是企业。

如果你做机器学习,无论是作为个人贡献者还是团队经理,我都会帮助你了解你目前的团队结构,以及如何改善内部流程、系统和文化。我们将探索如何建立真正颠覆性的 ML 团队来推动成功的结果。

为什么要建立一个 ML 团队?

人工智能(AI)预计到 2030 年将创造近 13 万亿美元的全球经济价值[1]。不同行业和部门的大多数公司都已经意识到人工智能的潜在价值,并正在成为人工智能优先的实体。从制造自动驾驶汽车或智能扬声器等尖端人工智能产品的科技公司,到利用人工智能进行欺诈检测或客户服务自动化等非迷人用例的传统企业,人工智能产生商业影响的潜力毋庸置疑。

许多趋势加速了人工智能在工业中的应用:

  • 来自支持互联网的设备、传感器、网络平台等的数据量呈指数级增长,同时存储、访问和共享数据的成本下降。
  • 随着 GPU 和云的出现,训练 AI 模型的计算成本更低。
  • 建立在数据和计算基础上的算法研究和深度学习模型的创新。

鉴于过去十年的这种范式转变,构建人工智能产品和服务的成本已经大幅下降。大门现在向各种各样的参与者敞开,如企业、初创公司、企业家、学生或爱好者,以创新和创造转型的人工智能。

在接下来的部分,我将分别描述创业公司和企业在建立机器学习团队方面的挑战。

初创公司面临的挑战

初创公司在运营的早期阶段通常是自举式的,并且用于建立机器学习团队的预算有限。

如果你的创业公司有一个基于人工智能的核心产品或服务,那么就必须尽早雇佣机器学习人才来建立 MVP,并筹集资金来雇佣更多人才和扩大产品规模。

另一方面,对于核心产品或服务专注于金融、医疗保健或教育等其他领域的初创公司来说,人工智能要么是核心业务的附带产品,要么在产品市场适应之前不是必不可少的。

在创业公司中建立 ML 团队的主要挑战是:

  • 人工智能的资金或预算有限。
  • 缺乏建立机器学习模型的训练数据。
  • 缺乏标签数据或资金将标签外包给第三方供应商。
  • 没有结构化数据仓库、数据管道或机器学习部署基础设施。
  • 需要更多能够在整个机器学习生命周期中操作的实践机器学习人才——从数据工程、算法和模型开发到在生产中部署和监控机器学习模型,而不是专门人才来单独关注机器学习生命周期的各个方面。
  • 无法雇佣市场上最好的机器学习人才,也无法与领先科技公司提供的薪资相匹配。
  • 为了与老牌企业竞争,更快的机器学习开发周期是必不可少的。然而,在缺乏结构化的内部流程和管理的情况下,这往往会导致摩擦和效率低下。

面对机器学习工作的这种令人生畏的挑战以及创业公司的一般组织挑战[2],创业公司从一开始就雇佣和建立正确的机器学习团队变得更加重要。

企业面临的挑战

与创业公司不同,大组织和企业不会因为缺乏资金或预算而缺乏机器学习团队。企业中的挑战因实体而异,但通常是由于组织的规模、内部官僚主义和缓慢的决策过程而产生的——这些往往有利于初创公司,并帮助他们更快地交付产品。

虽然今天,科技公司似乎无处不在,但与专注于金融、快速消费品、零售、医疗保健、教育等不同领域的大量传统企业相比,它们仍然是少数。在机器学习和人工智能方面,科技公司拥有领先优势,与传统同行相比,它们对人工智能 R&D 的早期关注和投资将确保它们的主导地位。

然而,传统企业在整个组织内采用和实施人工智能时面临着众多挑战[3],这往往会导致人工智能项目失败,并降低对人工智能能力和潜力的信任[4]:

  • 无法制定使用人工智能解决业务挑战的路线图和愿景。
  • 在促进跨职能和跨学科合作以定义具有良好定义的 KPI 的有效人工智能用例方面的障碍。
  • 缓慢的决策过程不是基于数据,而是基于本能和直觉。
  • 规避风险的文化心态不利于建立数字优先的组织。
  • 典型的人工智能用例是与领域无关的,会影响组织的每个方面,例如客户服务自动化,这不会激发或吸引大多数数据科学家。
  • 从节约成本的角度而不是潜在的创收流的角度来看待人工智能。
  • 无法快速动员内部团队来建立一个新的人工智能产品或进入一个已经被快速发展的初创公司验证的新市场。

在详细介绍了初创公司和企业面临的核心挑战之后,在下一节中,我将描述典型的机器学习团队的组成,以及在机器学习生命周期中工作的各种配置文件所使用的技能和工具。对于招聘经理和团队来说,更好地了解不同机器学习团队的技能和能力,对于建立一个完整而高效的机器学习团队至关重要。

机器学习团队中的配置文件

现代机器学习团队确实是多样化的。然而,从核心上来说,他们要求候选人具备强大的分析技能,能够理解来自不同领域的数据,训练和部署预测模型,并从中获得业务或产品见解。

Machine Learning Lifecycle

Figure 1. The Machine Learning Lifecycle

如图 1 所示,机器学习的生命周期有四个阶段,这四个阶段依次相互补充。每个阶段都是一个专业领域,基于特定的知识和技能来很好地执行相关的任务。

范围界定

界定人工智能用例的第一阶段需要人工智能专家以及业务或领域专家。许多成功的人工智能项目都始于对可以用人工智能解决的潜在商业问题的深刻理解,并需要经验丰富的技术和商业专家的直觉和理解。在这个阶段,通常的合作者包括业务负责人、产品经理、人工智能团队经理,可能还有一名或多名对底层数据有深入实践经验的高级数据科学家。

数据

第二阶段侧重于获取数据、清理、从原始格式处理为结构化格式,并将其存储在特定的内部数据库或云存储库中。在这一阶段,数据工程师和数据科学家的作用非常突出。业务和产品经理在提供对数据、元数据和任何基于基本分析的初步业务见解的访问方面起着有益的作用。

建模

第三阶段涉及核心数据科学和使用前一阶段准备的数据集的机器学习建模。在这一阶段,数据科学家、应用科学家或研究科学家在训练初始模型、基于测试集性能和来自跨职能利益相关方的反馈对其进行改进、开发新算法(如果需要)以及最终生成一个或多个满足将模型投入生产所需的准确性和延迟基准的候选模型方面发挥着主导作用。

部署

机器学习生命周期的最后阶段专注于将训练好的模型部署到生产中,在生产中,它们根据从最终用户接收到的输入进行预测。在这个阶段,机器学习工程师将数据/应用/研究科学家开发的模型用于生产。如果模型满足预定义的准确性和延迟基准,则模型可以投入使用。另外,ML 工程师致力于优化模型大小、性能、延迟和吞吐量。在决定哪个(些)版本的模型最适合部署之前,模型要经过系统的 A/B 测试过程。

接下来,我为您的 ML 团队可能需要的不同类型的专家准备了详细的资料。

数据工程师

技能

  • 数据库ˌ资料库
  • 编程;编排
  • 查询语言
  • 数据管道
  • 体系结构
  • 分析学
  • 数据操作、转换和预处理
  • 云服务
  • 工作流程管理

责任

  • 构建数据管道、架构和基础设施
  • 为数据科学建模清理和处理数据集
  • 构建内部工具来优化数据工程工作流程
  • 为定义的使用情形聚合不同的数据集
  • 支持数据科学家的数据相关需求

技术堆栈

  • SQL,MySQL
  • Java 语言(一种计算机语言,尤用于创建网站)
  • 计算机编程语言
  • C++
  • 斯卡拉
  • 火花
  • Hadoop
  • 卡夫卡
  • 数据库:邮政、蒙戈布、卡珊德拉、里兹、希夫、风暴
  • 云:AWS/Azure/GCP、EC2、EMR、RDS、红移

数据科学家

技能

  • 问题解决
  • 编程;编排
  • 统计数字
  • 数据分析
  • 数据可视化
  • 数据科学
    • 监督机器学习
    • 无监督机器学习
  • 与跨职能团队进行书面和口头沟通
  • 向领导层展示结果和见解的演示技巧
  • 从数据科学模型中获得统计上有效的见解,以改进产品开发、营销或业务战略

责任

  • 识别和验证可以用人工智能解决的业务用例
  • 在建模管道的不同阶段分析和可视化数据
  • 开发定制算法和数据科学模型
  • 识别附加数据集或生成合成数据
  • 开发数据注释策略并对其进行验证
  • 与跨职能团队协调,寻求对模型的反馈,共享结果并实施模型
  • 开发定制工具或库,以优化整个数据科学建模工作流程

技术堆栈

  • 计算机编程语言
  • 稀有
  • Java 语言(一种计算机语言,尤用于创建网站)
  • jupyter 笔记本
  • 可视化:Matplotlib,Seaborn,Bokeh,Plotly 等。
  • 结构化查询语言
  • 火花
  • Git,Github/Bitbucket
  • 云:AWS/Azure/GCP;萨格马克,S3,博托
  • 机器学习:Scikit-learn,Fast.ai,AllenNLP,OpenCV,HuggingFace
  • 深度学习:TensorFlow,PyTorch,MXNet,JAX,Chainer 等。
  • 超参数调整:海王星,彗星,重量和偏差

Data Science toolkit

Figure 2. Data Science toolkit | Source

机器学习工程师

技能

  • 数据结构
  • 数据建模
  • 编程;编排
  • 软件工程
  • ML 框架,如 TensorFlow,PyTorch,Scikit-learn 等。
  • 统计数字
  • ML 的概念知识,以理解用例并与数据科学家和其他利益相关者互动

责任

  • 将模型部署到生产中
  • 优化模型以获得更好的延迟和吞吐量
  • 候选模型的 A/B 测试
  • 在各种硬件上进行推理测试:edge、CPU、GPU
  • 监控模型性能、维护、调试
  • 维护模型版本、实验和元数据

技术堆栈

  • Linux 操作系统
  • 云:AWS/Azure/GCP;萨格马克、S3、EC2、博托
  • 机器学习:Scikit-learn,Fast.ai,AllenNLP,OpenCV,HuggingFace
  • 深度学习:TensorFlow,PyTorch,MXNet,JAX,Chainer 等。
  • 服务:TensorFlow 服务、TensorRT、TorchServe、MXNet 模型服务器
  • 计算机编程语言
  • C++
  • 斯卡拉
  • 尝试
  • 去吧,Github/Bitbucket

研究科学家

技能

  • 计算机科学、人工智能、物理学、生物学、经济学等定量学科的博士学位。
  • 科学思维和第一性原理思维
  • 科学中最先进方法的深度和广度
  • 有从事学术或行业研究的经验
  • 创造性解决问题
  • 机器学习
  • 深度学习
  • 设计和开发 ML 原型和模型
  • 与跨职能团队进行书面和口头沟通
  • 向领导层展示结果和见解的演示技巧
  • 从数据科学模型中获得统计上有效的见解,以改进产品开发、营销或业务战略

责任

  • 对新的 ML 用例及应用进行研究
  • 构建最初的 ML 原型和模型
  • 跨多个模型和超参数组合进行系统实验
  • 创建或扩充数据集
  • 清理、处理、分析和可视化数据并模拟性能
  • 了解最新的研究文献和最新的机器学习和深度学习方法
  • 传播新的 ML 方法和思想
  • 指导软件、数据和 ML 工程师

技术堆栈

  • 计算机编程语言
  • jupyter 笔记本
  • 机器学习:Scikit-learn,Fast.ai,AllenNLP,OpenCV,HuggingFace
  • 深度学习:TensorFlow,PyTorch,MXNet,JAX,Chainer 等。
  • Linux 操作系统
  • 云:AWS/Azure/GCP;萨格马克、S3、EC2、博托
  • 超参数调整:海王星,彗星,重量和偏差
  • 去吧,Github/Bitbucket

产品经理+业务负责人

技能

  • 产品设计、营销
  • 数据分析
  • 一个或多个领域的专业知识
  • 程序管理
  • 业务发展
  • 了解产品路线图和端到端项目交付
  • 了解软件、架构、数据和机器学习最佳实践
  • 基本机器学习概念、流程、指标和部署的基本知识
  • 出色的书面和口头沟通技巧,能够与客户、业务和技术团队合作
  • 人际交往技能,包括说服和完成利益相关方团队的工作
  • 意识到管理和构建机器学习与软件产品之间的区别

责任

  • 创建详细的产品、功能路线图,包括里程碑、交付成果、指标和业务影响
  • 对建议产品的客户进行调查,以简化设计、UX 并减少摩擦
  • 平衡利益相关者、客户的多个优先事项,以定义和交付产品
  • 与软件工程和机器学习团队合作,按照路线图迭代和改进模型
  • 获得产品的所有权,并确保在紧迫的期限内交付特性和整个产品

技术堆栈

  • SQL 提取和分析数据,为产品建立直觉
  • 擅长
  • 工作管理工具
  • 生产力工具
  • 调度工具

数据科学/机器学习管理师

技能

  • 完全理解机器学习从概念到生产的生命周期
  • 书面和口头沟通技巧
  • 人际交往和说服技巧,以获得领导的认同,与跨职能团队合作
  • 愿景:与产品和业务经理一起创建产品功能和路线图,并就此进行协作
  • 对机器学习和深度学习概念的实践和理论理解,ML 产品的部署和持续改进
  • 对个人机器学习贡献者的指导
  • 项目管理与产品和项目经理

责任

  • 拥有机器学习产品和路线图
  • 为新颖的机器学习产品创造愿景
  • 使利益相关者与提议的产品愿景保持一致
  • 理解机器学习指标与业务指标
  • 在公司内部以及更广泛的生态系统中宣传机器学习团队的能力和成功
  • 雇佣专门研究机器学习生命周期的机器学习人才
  • 与产品和业务团队合作并深入研究,以确定可以通过机器学习解决的潜在用例
  • 从客户的角度理解企业及其产品和服务是如何运作的
  • 了解业务收入流,并为机器学习项目提出原创想法,以改进产品或服务,降低成本,并自动化手动流程

技术堆栈

  • 计算机编程语言
  • 结构化查询语言
  • 擅长
  • 生产力、协作和沟通工具

MLOps lifecycle

Figure 3. MLOps lifecycle | Source

建立高效的机器学习团队

我们探索了机器学习团队的典型组成,其中包括各种不同的配置文件,专门用于构建机器学习项目的特定方面。然而,现实是,拥有一个可靠的机器学习团队并不能保证这个团队将创造和交付巨大的商业影响。实际情况是,绝大多数企业人工智能项目都失败了,尽管有一个很棒的机器学习团队,但很多项目还是失败了。

在这一部分,我将从基本原则出发,深入探讨构建有影响力的机器学习团队的文化、程序和协作方面。机器学习团队的成功建立在与系统、流程和文化相关的几个因素之上。当以错误的方式构建时,这将不可避免地导致失败的项目和对团队的信任和信心的侵蚀,以及作为业务能力和竞争优势的机器学习。

List of AI use cases

Figure 4. A list of AI use cases

1.致力于正确的人工智能用例

对于一个全新的机器学习团队来说,要在一个组织中产生影响,最重要的是团队一开始就要有好的开端。早期牵引对于在组织中建立信任、在业务垂直领域传播人工智能的潜力以及利用早期成功交付具有更大影响的风险更高或登月项目至关重要。

以下是头脑风暴和定义正确的人工智能用例集的注意事项。

Do's and don'ts for identifying right AI use cases

Figure 5. Do’s and don’ts for identifying right AI use cases

2.成功规划-衡量影响

作为选择和定义正确的人工智能用例的过程的一部分,批判性地评估和评价特定机器学习项目的商业影响和投资回报是非常重要的。评估的最佳方法是定义一组度量标准,这些标准涉及项目的几个方面及其潜在影响。

技术指标

对于分类模型:
  • 准确(性)
  • 精确
  • 回忆
  • F1 分数
  • 罗马纪元
对于回归模型:
  • 均方根误差
  • 调整后的 R ²
  • 绝对平均误差
对于深度学习模型(取决于特定应用):
  • 困惑,余弦相似性,雅克卡相似性,BLEU (NLP)
  • 单词错误率(语音识别)
  • 并集上的交集、平均精度、平均精度(计算机视觉)

业务指标

业务指标由基本原则定义,通常是受机器学习模型影响的下游指标。为了衡量结果,至关重要的是先验地确定相关的业务指标,并在 A/B 测试、部署和持续监控实时模型期间跟踪机器学习模型对这些指标的影响。

标准业务度量旨在获取信任、满意度、错误和 SLA 等级别。

一旦机器学习项目的候选集从概念到生产用相关联的一组度量进行了范围界定、定义和制定,每个项目都需要由领导团队从要在定义的时间段内实现的高层组织目标的角度进行评估。领导者需要平衡业务影响(在运营线或底线上)、预算、团队带宽、时间节约、效率节约以及短期和长期交付项目的紧迫性。高管需要整合多种因素,以达成一个经过仔细考虑的决定,为一个或多个机器学习项目开绿灯。

3.结构化流程——敏捷、冲刺

一旦项目被定义并得到领导团队的批准,确保系统和结构化流程到位以确保机器学习团队可以不受阻碍地工作并按照商定的计划及时执行项目是很重要的。

关键运营基础设施,如数据仓库、数据库管理系统、数据 ETL 管道、元数据存储和管理平台、数据注释框架和标记数据的可用性、对本地或云中计算的访问、简化模型培训流程的许可和开源工具和软件、机器学习实验、结果和元数据管理工具、A/B 测试平台、模型部署基础设施和解决方案、持续模型监控和仪表板,对于平稳的数据处理、模型构建和部署工作流是不可或缺的。然而,这种用于机器学习的关键骨架基础设施的存在因组织而异,取决于机器学习组织或公司的成熟程度。

除了基础设施之外,与使用 sprints 和敏捷框架的项目个体参与者的计划任务相关的过程需要被硬连线,并且可以被项目的所有涉众访问。虽然敏捷过程在软件项目中运行良好,但是机器学习项目是不同的,可能不太适合相同的框架。尽管存在类似迭代模型构建和基于反馈的提炼的相似性,但机器学习项目更加复杂,因为基本块除了代码之外还包括数据和模型。

虽然像代码审查和版本控制这样的软件工程最佳实践已经非常成熟,但同样的严谨性和结构并不总是适用于数据和机器学习模型。文档是另一个方面,它对于跟踪多种假设、实验、结果以及与机器学习项目相关的所有活动部分甚至更为关键。

在缺乏根深蒂固的工具和最佳实践的情况下,大多数数据科学工作往往非常低效,数据科学家最终会在可以自动化的日常琐事上花费大量时间。经理们必须努力减少这些障碍,以提高工作效率和生产率,这样机器学习团队才能专注于他们的工作。

Framework for applying AI

Figure 6. A framework for applying AI in the enterprise. | Source

4.团队内部和团队之间的清晰沟通

沟通是数据科学家的一项基本技能。机器学习是一门更复杂的学科,最终结果可能过于晦涩,数据科学、产品或业务团队的通才和非技术经理很难理解。然而,沟通只是冰山一角,在跨职能团队中工作时,更多的人际交往技能,如说服、同理心、协作等都需要定期锻炼。

向利益相关者和领导层发送结果或更新的电子邮件或幻灯片演示,现场演示,为产品评审文档阐述项目,为面向非专业受众的博客或面向技术受众的期刊或会议撰写整个项目,都需要很强的写作技能。典型的数据科学家可能更擅长编写代码而不是文字,因此组织应该投资于数据科学家的企业培训计划,包括书面和口头沟通技能的培训。

口头沟通能力也不可小觑,在远程优先的组织中越来越重要。有效的利益相关者管理包括建立融洽的关系和信任,以及建立清晰的沟通渠道,如果数据科学家不能以引人入胜、令人愉快的方式清晰地说话和沟通,这将变得更加困难。虽然许多工作场所生产力应用程序创建了减少面对面交流的数字渠道,但与同事、利益相关者和领导者进行实时面对面交流的力量通常可以更快地完成工作。

清晰的沟通消除了信息孤岛,因此每个利益相关者都知道、更新并与各种机器学习项目的进展保持一致。除了在工具中记录进展以确保项目朝着正确的方向前进之外,定期会议对于制衡也很重要。

5.与企业的有效协作

机器学习团队通常是公司工程或技术组织的一部分。虽然这对于来自数据、分析、工程职能部门的同事之间的有效协作来说很自然,但与业务团队的定期互动是必须的。鉴于大多数机器学习模型建立在历史“业务”数据的基础上,这些数据可能会因新产品或功能发布或季节性模式而以可预测的方式发生变化,也可能会以不可预测的方式发生变化,例如,在新冠肺炎封锁期间,机器学习团队必须实时了解业务数据正在发生的变化。

重要的不仅是在面对客户行为或新产品发布的巨大变化时调整基础假设,而且如果初始假设被违反或数据变化太大,机器学习模型变得不相关或具有与以前相同的影响,则纠正计划的行动过程也很重要。

业务团队最适合根据他们的领域专业知识对早期原型提供反馈,通过进行客户研究和调查来验证新的假设或想法,并评估部署的机器学习模型的影响。出于这些原因,机器学习和业务团队之间的伙伴关系需要是互利共生的。

机器学习团队的领导者需要与业务团队建立密切的联系,并鼓励团队成员也这样做。

6.创造创新文化

为了机器学习团队的长期成功,除了致力于正确的用例并促进整个组织的协作工作,还必须建立一种拥抱和奖励创新的文化。在这里,领导应该以身作则,鼓励不同业务垂直领域的创新和 R&D。

对于一个机器学习团队来说,通过专利申请、期刊或会议出版物、通过聚会、研讨会、领先专家的研讨会进行外联和传播、根据需要与初创公司和学术组织合作等等,在生态系统中留下印记至关重要。大多数组织并不注重建立这样一种蓬勃发展的文化,这种文化促进新思想和新技术的交流和相互渗透,而这种交流和相互渗透往往会以一种实质性的方式影响当前的组织流程和思维。

领导者还需要建立强大的多元化团队,雇佣新的人才,从入门级毕业生到经验丰富的工程师和科学家。新人才的流入带来了新的想法,可以对工作文化产生积极影响。否则停滞不前,团队会变得心胸狭窄,创新和推出有影响力的产品的能力下降。任人唯贤的行政决策对企业文化有着强烈的影响,既包括提拔表现出一贯出色业绩的人才,也包括解雇表现不佳的个人或经理。团队中适当的平衡和文化是一个持续的过程,但对于领导者来说,重要的是要确保在任何时候,机器学习团队的成员都不会因组织内的系统、流程和文化而失去动力和灵感。

7.庆祝和分享人工智能的成功故事

最后,鉴于目前人工智能项目的成功几率很低,确保任何人工智能成功故事在组织内得到广泛分享以吸引可能与机器学习团队合作的其他业务团队的注意很重要。此外,鉴于人工智能作为一门学科的巨大人气,成功的故事也可能吸引公司内部潜在的新团队成员,他们有动力提高机器学习技能,成为数据科学家。

在公司内部以公开的方式而不是关起门来认可核心贡献者对人工智能项目成功的努力是很重要的。这有助于建立士气和信心,并在团队中培养精英文化,这将有助于他们的职业发展。此外,只要有可能,领导层应该采取措施,在公司运营的更广泛的生态系统中广泛分享这种人工智能的成功故事,例如,通过公司博客、社交媒体帖子、播客或在聚会、研讨会或会议上的演讲。

对于一个机器学习团队来说,要继续提供强大的性能和结果,关键是要建立一个成功项目的组合,从简单的项目开始,逐渐变得更加复杂,范围和商业影响不断增加。机器学习团队的成功起到了触发器的作用,加速了公司的数字化和人工智能转型。在竞争激烈的数字经济中,早期投资并大量投资人工智能的公司已经成为早期赢家,例如,大型科技公司。因此,有影响力的机器学习团队在拥抱和采用人工智能并将公司转变为前瞻性、数据驱动、人工智能优先的公司的旅程中发挥了杠杆作用。

参考

Sundeep Teki

人工智能和神经科学领域的领导者,在 4 个国家(美国、英国、法国、印度)拥有跨大科技(亚马逊 Alexa AI 的对话式人工智能)、独角兽初创公司(Swiggy 的应用人工智能)和 R&D(牛津大学和伦敦大学学院的神经科学)的专业经验。发表了 40+篇关于神经科学和 AI 的论文(h-index: 23,2000+引文);为消费技术产品构建和部署人工智能;为科技初创公司提供人工智能/人工智能方面的咨询,并为有志于数据科学的学生、专业人士和公司提供辅导和技能提升服务。


阅读下一篇

管理机器学习项目的最佳工具

6 分钟阅读|作者 Jakub Czakon |年 7 月 14 日更新

管理机器学习项目并不完全是小菜一碟,但每个数据科学家都已经知道这一点。

它触及了很多东西:

  • 数据探索,
  • 数据准备和设置机器学习管道
  • 实验和模型调整
  • 数据、管道和模型版本控制
  • 管理基础设施和运行流程编排
  • 模型服务化和生产化
  • 模型维护(生产中的再培训和监控模型)
  • 不同角色(数据科学家、数据工程师、软件开发人员、开发人员、团队经理、业务利益相关者)之间的有效协作

那么如何保证一切顺利进行呢?如何管理所有的部分来创建一个连贯的工作流程?

…通过使用正确的工具来帮助您管理机器学习项目。但是你已经知道了🙂有许多应用程序可以帮助你改善部分甚至整个工作流程。当然,自己做每件事真的很酷,但是如果工具能帮你省去很多麻烦,为什么不使用呢

让我们开始吧,看看盘子里有什么!以下是涉及上述各点的工具列表。有些更倾向于端到端,有些专注于机器学习生命周期的特定阶段,但所有这些都将帮助您管理您的机器学习项目。查看我们的列表,选择你最喜欢的。

Continue reading ->


如何选择神经网络的学习速率调度器

原文:https://web.archive.org/web/https://neptune.ai/blog/how-to-choose-a-learning-rate-scheduler

研究人员普遍认为神经网络模型很难训练。最大的问题之一是需要指定和优化大量的超参数。隐藏层的数量、激活函数、优化器、学习率、正则化——不胜枚举。

调整这些超参数可以极大地改善神经网络模型。对于作为数据科学家的我们来说,构建神经网络模型是为了解决一个优化问题。我们希望通过基于梯度的方法,例如梯度下降,找到目标函数的最小值(全局的,或者有时是局部的)。

在所有梯度下降超参数中,学习率(进度)是获得良好模型性能的最关键参数之一。在本文中,我们将探讨学习率,并解释为什么在模型训练中安排学习率至关重要。

从这里开始,我们将看到如何通过在 Keras 中实现和利用各种调度器来选择学习率调度。然后,我们将在 Neptune 中创建实验来比较这些调度程序的性能。

神经网络中的学习率是多少?

什么是学习率,它对神经网络有什么影响?学习率(或步长)被解释为在反向传播训练过程中模型权重的变化/更新幅度。作为一个可配置的超参数,学习率通常被指定为小于 1.0 的正值。

在反向传播中,模型权重被更新以减少损失函数的误差估计。我们不是使用全部数量来改变权重,而是将其乘以某个学习率值。例如,将学习率设置为 0.5 将意味着用 0.5 *估计权重误差(即,梯度或总误差相对于权重的变化)来更新(通常减去)权重。

学习速度的影响

学习率控制优化器达到损失函数最小值的步长。这对我们的优化算法有什么影响?看看这些图表:

  • 学习率大(右边),算法学习快,但也可能导致算法在极小值附近振荡,甚至跳过极小值。更糟糕的是,高学习率等于大的权重更新,这可能导致权重溢出;
  • 相反,在学习率很小的情况下(左侧),对权重的更新很小,这将引导优化器逐渐接近最小值。然而,优化器可能需要太长时间来收敛或陷入平稳状态或不期望的局部最小值;
  • 好的学习率是覆盖率和超调(中间)之间的权衡。它不会太小以至于我们的算法可以快速收敛,也不会太大以至于我们的算法不会在没有达到最小值的情况下来回跳跃。

虽然找到一个合适的学习率的理论原理很简单(不要太大,也不要太小),但是说起来容易做起来难!为了解决这个问题,引入了学习率表。

学习费率表

学习率时间表是一个预定义的框架,随着训练的进行,它在各时期或迭代之间调整学习率。学习速率计划的两种最常见的技术是,

  • 学习率不变:顾名思义,我们初始化一个学习率,训练时不改变;
  • 学习率衰减:我们选择一个初始的学习率,然后按照一个时间表逐渐降低它。

知道了什么是学习率计划,你一定想知道为什么我们首先需要降低学习率?在神经网络中,我们的模型权重更新为:

其中 eta 是学习率,偏导数是梯度。

对于训练过程来说,这是好的。在训练的早期,为了达到足够好的一组重量,学习率被设置得很大。随着时间的推移,通过利用小的学习率,这些权重被微调以达到更高的准确度。

注意:你可能会读到一些文章,其中学习率时间表仅被定义为(学习率)衰减。尽管这两个术语(学习率计划和衰减)有时可以互换使用,但在本文中,我们将实现恒定学习率的场景作为性能基准测试的基线模型。

Neptune 中的分析数据集和实验配置

出于演示的目的,我们将使用 Keras 中流行的 Fashion-MINIST 数据。该数据集由 70,000 幅图像组成(训练集和测试集分别为 60,000 幅和 10,000 幅)。这些图像为 28×28 像素,与 10 个类别相关联。

为了跟踪和比较不同学习率调度器的模型性能,我们将在 Neptune 中进行实验。海王星监控所有与模型相关的东西。关于如何用 Python 设置和配置 Neptune 项目的详细分步说明,请参考本文档。

在本练习中,我们将创建一个 Neptune 项目,并将其标记为"learningrateschedule?。在获得您的 Neptune API 令牌后,您可以使用下面的代码将 Python 连接到我们的项目:

project = neptune.init(api_token=os.getenv('NEPTUNE_API_TOKEN'),
                       project='YourUserName/YourProjectName')
project.stop()

接下来,我们将使用 Keras 中可用的一些实用函数加载数据集。

为了减少本地机器上的运行时间,我们的模型将针对 20,000 张图像而不是整个 60,000 张图像进行训练。因此,我们将使用下面的代码随机选择 20,000 条数据记录。

除此之外,我们还将定义几个辅助函数来保存和绘制训练过程中的学习率:

def reset_random_seeds(CUR_SEED=9125):
   os.environ['PYTHONHASHSEED']=str(CUR_SEED)
   tf.random.set_seed(CUR_SEED)
   np.random.seed(CUR_SEED)
   random.seed(CUR_SEED)

reset_random_seeds()

fashion_mnist = keras.datasets.fashion_mnist
(X_train_full, y_train_full), (X_test_full, y_test_full) = fashion_mnist.load_data()

reset_random_seeds()
trainIdx = random.sample(range(60000), 20000)

x_train, y_train = X_train_full[trainIdx]/255.0, y_train_full[trainIdx]
x_test, y_test = X_test_full/255.0, y_test_full

def get_lr_metric(optimizer):
    def lr(y_true, y_pred):
        curLR = optimizer._decayed_lr(tf.float32)
        return curLR
    return lr

def plotLR(history):
    learning_rate = history.history['lr']
    epochs = range(1, len(learning_rate) + 1)
    fig = plt.figure()
    plt.plot(epochs, learning_rate)
    plt.title('Learning rate')
    plt.xlabel('Epochs')
    plt.ylabel('Learning rate')
    return(fig)

def plotPerformance(history, CURRENT_LR_SCHEDULER=CURRENT_LR_SCHEDULER):

    fig = plt.figure(figsize=(10, 4))
    fig = plt.subplot(1, 2, 1) 

    plt.plot(history.history['loss'])
    plt.plot(history.history['val_loss'])
    plt.legend(['Train Loss', 'Test Loss'])
    plt.title(f'Loss Curves ({CURRENT_LR_SCHEDULER})')
    plt.xlabel('Epoch')
    plt.ylabel('Loss on the Validation Set')

    fig = plt.subplot(1, 2, 2) 

    plt.plot(history.history['accuracy'])
    plt.plot(history.history['val_accuracy'])
    plt.legend(['Train Accuracy', 'Test Accuracy'])
    plt.title(f'Accuracy Curves ({CURRENT_LR_SCHEDULER})')
    plt.xlabel('Epoch')
    plt.ylabel('Accuracy on the Validation Set')
    return fig

这里有几个注意事项:

  • 当前数据集通过除以 255 进行规范化;因此,它被重新调整到 0-1 的范围内;
  • 我们定义了一个函数 get_lr_metric()来保存和打印学习率,作为 Keras verbose 的一部分。

此外,让我们还创建一个帮助器函数,在整个实验过程中,将学习率和模型性能图表记录到 Neptune:

def plot_Neptune(history, decayTitle, npt_exp):

        npt_exp[f'Learning Rate Change ({decayTitle})'].upload(neptune.types.File.as_image(plotLR(history)))

        npt_exp[f'Training Performance Curves ({decayTitle})'].upload(neptune.types.File.as_image(plotPerformance(history).get_figure()))

神经网络模型

有了数据集和辅助函数,我们现在可以构建一个神经网络模型作为图像分类器。为简单起见,我们当前的模型包含两个隐藏层和一个输出层,输出层具有用于多类分类的‘soft max’激活功能:

def runModel():
    model = Sequential()
    model.add(Flatten(input_shape=[28, 28]))
    model.add(Dense(512, activation='relu'))
    model.add(Dense(200, activation='relu'))
    model.add(Dense(10, activation='softmax'))
    return model

model = runModel()
model.summary()

这是模型结构,这是一个相当简单的网络。

学习率不变的基线模型

如上所述,恒定调度是所有学习率调度器中最简单的方案。为了设置性能基线,我们将在所有时期使用一致的学习率 0.01 来训练模型:

npt_exp = neptune.init(
        api_token=os.getenv('NEPTUNE_API_TOKEN'),
        project='YourUserName/YourProjectName',
        name='ConstantLR',
        description='constant-lr',
        tags=['LearingRate', 'constant', 'baseline', 'neptune'])

neptune_cbk = NeptuneCallback(run=npt_exp, base_namespace="metrics")

initial_learning_rate = 0.01
epochs = 100
sgd = keras.optimizers.SGD(learning_rate=initial_learning_rate)
lr_metric = get_lr_metric(sgd)

model.compile(optimizer = sgd,
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy', lr_metric])

reset_random_seeds()

trainHistory_constantLR = model.fit(
    x_train, y_train,
    epochs=epochs,
    validation_data=(x_test, y_test),
    batch_size=64,
    callbacks = [neptune_cbk]
)

npt_exp['Learning Rate Change (Constant)'].upload(neptune.types.File.as_image(plotLR(trainHistory_constantLR)))

npt_exp['Training Performance Curves (Constant)'].upload(neptune.types.File.as_image(plotPerformance(trainHistory_constantLR).get_figure()))

npt_exp.stop()  

在此,我们:

  • 在我们的项目下创建了一个 Neptune 实验来跟踪基本模型的性能;
  • 使用*learning_rate*参数指定学习率。在 Keras 的标准 SGD 优化器中;
  • 增加了 lr_metric 作为用户定义的指标进行监控,使学习率信息能够在培训中逐字显示;
  • 在 Neptune 中记录学习率和性能图表(损失和准确性曲线)。

查看训练进度,我们可以确认当前学习率被固定为 0.01 而没有改变,

在我们的海王星实验中,我们会发现下面的性能图表,

随着学习的展开,训练损失在减少,准确率在增加;尽管如此,当涉及到验证集时,模型性能不会有太大的变化。这将是我们稍后与衰减调度程序进行基准测试的基线模型。

Keras 中内置衰变时间表的问题

Keras 提供了一个内置的标准衰减策略,它可以在优化器的“衰减”参数中指定,如下所示:

initial_learning_rate = 0.1
epochs = 100

sgd = keras.optimizers.SGD(learning_rate=initial_learning_rate, decay=0.01)

model.compile(optimizer = sgd,
                  loss='sparse_categorical_crossentropy',
                  metrics=['accuracy'])

trainHistory_constantLR = model.fit(
        x_train, y_train,
        epochs=epochs,
        validation_split=0.2,
        batch_size=64
    )

这个衰减策略遵循一个基于时间的衰减,我们将在下一节讨论它,但是现在,让我们熟悉一下基本公式,

假设我们的初始学习率= 0.01,衰减= 0.001,我们会期望学习率变成,

  • 0.1 * (1/(1+0.01*1)) =第一个时期后的 0.099
  • 0.1 * (1/(1+0.01*20)) = 0.083 并且在第 20 个时期之后

然而,查看 Keras 训练进度,我们注意到不同的值,其中在第一个时期之后,学习率已经从 0.1 降低到 0.0286,

迷惑?

嗯,这是一个误解,Keras 更新的学习率在每个时代结束;相反,学习率更新是分批进行的,这意味着它是在 Keras 中的每批之后的执行的。公式是,

,其中参数步长也称为迭代。

如果我们回到前面的例子,因为我们有总的训练数据= 20000 幅图像,并且验证率= 0.2,所以训练集= 20000 * 0.2 = 16000。那么将批量大小设置为 64 意味着:

  • 16000/64 =需要 250 步或迭代来完成一个时期;
  • 在每个时期之后,学习率被更新 250 次,这等于,

*0.1 (1/(1+0.01 * 250))= 0.0286!

因此,当在 Keras 中使用标准衰减实现时,请记住这是一个批处理而不是纪元更新。为了避免这个潜在的问题,Keras 还允许数据科学家定义定制的学习率调度器。

在本文的其余部分,我们将遵循这条路线,使用 Keras 中的 Callback() 功能实现我们自己的调度程序。

带 Keras 回调的学习率计划程序

学习率衰减的基本机制是随着时期的增加而降低学习率。所以,我们基本上想把我们的学习率指定为一些纪元的递减函数。

在所有潜在的候选者中,线性函数是最直接的一个,因此学习率随着时期线性降低。由于其简单性,线性衰减通常被认为是第一个尝试。

线性衰减方案

利用这种方案,学习率将在训练时期结束时衰减到零。要实现线性衰减:

initial_learning_rate = 0.5
epochs = 100
decay = initial_learning_rate/epochs

class lr_polynomial_decay:
	def __init__(self, epochs=100, initial_learning_rate=0.01, power=1.0):

		self.epochs = epochs
		self.initial_learning_rate = initial_learning_rate
		self.power = power

	def __call__(self, epoch):

		decay = (1 - (epoch / float(self.epochs))) ** self.power
		updated_eta = self.initial_learning_rate * decay

		return float(updated_eta)

这里,我们定义了一个类 lr_polynomial_decay ,其中 arg。*力量*控制衰变的速度;也就是说,较小的功率使学习率衰减得更慢,而较大的功率使学习率衰减得更快。

将“功率”设置为 1 会产生线性衰减,其曲线如下所示。

Linear learning rate decay

为了用这个定制的线性衰减来训练我们的模型,我们所需要的就是在leargatescheduler函数中指定它:

npt_exp_4 = neptune.init(
        api_token=os.getenv('NEPTUNE_API_TOKEN'),
        project='YourUserName/YourProjectName',
        name=f'{POLY_POWER}LRDecay',
        description=f'{POLY_POWER}-lr-decay',
        tags=['LearningRate', POLY_POWER, 'decay', 'neptune'])

POLY_POWER == 'linear'
if POLY_POWER == 'linear':
    curPower = 1.0

curScheduler = lr_polynomial_decay(epochs=epochs, initial_learning_rate=initial_learning_rate, power=curPower)

model = runModel()

sgd = keras.optimizers.SGD(learning_rate=initial_learning_rate)
model.compile(
              optimizer = sgd,
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

neptune_cbk = NeptuneCallback(run=npt_exp_4, base_namespace="metrics")

reset_random_seeds()

trainHistory_polyDecay = model.fit(
    x_train, y_train,
    epochs=epochs,
    batch_size=64,
    validation_split=0.2,
    callbacks=[neptune_cbk, LearningRateScheduler(curScheduler, verbose=1)])

if POLY_POWER == 'linear':
    trainHistory_linearDecay = trainHistory_polyDecay
    plot_Neptune(history=trainHistory_linearDecay, decayTitle='Linear Decay', npt_exp=npt_exp_4)
npt_exp_4.stop()

运行这个模型,我们可以在 Neptune 项目中看到下面的性能图表,

根据验证集上的损失和准确性曲线,我们观察到,

  • 这两个指标在整个培训过程中都是波动的;
  • 在大约 40 个时期之后,模型过度拟合发生,其中训练损失继续减少,而验证损失开始增加(并且准确度几乎是平坦的)。

这种模式表明,随着训练的进行,我们的模型正在偏离,这很可能是因为学习率太高。

我们应该将学习率降低为纪元的线性函数吗?也许不是。如果有一个策略,学习率在训练开始时下降得更快,然后在训练结束时逐渐变平到一个小值,效果会更好。

这是非线性衰减的基本概念,其中最常用的有时基衰减和指数衰减。

基于时间的衰减和指数衰减

基于时间的衰减公式定义为:

def lr_time_based_decay(epoch, lr):
        return lr * 1 / (1 + decay * epoch)

其中“衰变”是一个参数,通常计算如下:

decay = initial_learning_rate/epochs

让我们指定以下参数:

initial_learning_rate = 0.5
epochs = 100
decay = initial_learning_rate/epochs

这个图表显示了生成的学习率曲线,

Time-based learning rate decay

与线性函数相比,基于时间的衰减导致学习率在训练开始时下降得更快,而在之后下降得更慢。和以前一样,让我们将这个调度器传递给 LearningRateScheduler 回调,并将性能图表记录到 Neptune:

npt_exp_1 = neptune.init(
        api_token=os.getenv('NEPTUNE_API_TOKEN'),
        project='YourUserName/YourProjectName',
        name='TimeBasedLRDecay',
        description='time-based-lr-decay',
        tags=['LearningRate', 'timebased', 'decay', 'neptune'])

neptune_cbk = NeptuneCallback(run=npt_exp_1, base_namespace="metrics")

trainHistory_timeBasedDecay = model.fit(...                callbacks=[neptune_cbk, LearningRateScheduler(lr_time_based_decay, verbose=1)])

npt_exp_1['Learning Rate Change (Time-Based Decay)'].upload(neptune.types.File.as_image(plotLR(trainHistory_timeBasedDecay)))

npt_exp_1['Training Performance Curves (Time-Based Decay)'].upload(neptune.types.File.as_image(plotPerformance(trainHistory_timeBasedDecay).get_figure()))

npt_exp_1.stop()

这是这个模型的性能,

正如我们所看到的,这个模型比线性衰减模型更适合验证集。一些观察,

  • 学习几乎在 38 个时期左右停止,因为我们的学习率降低到接近于零的值;
  • 与线性场景类似,训练开始时会有一些较大的波动。

现在,有办法消除这些波动吗?让我们转向指数衰减,它被定义为历元数的指数函数:

def lr_exp_decay(epoch):
    k = 0.1
    return initial_learning_rate * math.exp(-k*epoch)

同样,指定 initial_learning_rate = 0.5 和 epochs = 100 将产生以下衰减曲线(相对于线性和基于时间的衰减),

Learning rate decay comparison

指数方案在开始时提供了更平滑的衰减路径,这将导致更平滑的训练曲线。让我们运行这个模型,看看是否是这样:

npt_exp_3 = neptune.init(
        api_token=os.getenv('NEPTUNE_API_TOKEN'),
        project='YourUserName/YourProjectName',
        name='ExponentialLRDecay',
        description='exponential-lr-decay',
        tags=['LearningRate', 'exponential', 'decay', 'neptune'])

neptune_cbk = NeptuneCallback(run=npt_exp_3, base_namespace="metrics")

trainHistory_expDecay = model.fit(...                callbacks=[neptune_cbk, LearningRateScheduler(lr_exp_decay, verbose=1)])

npt_exp_3['Learning Rate Change (Exponential Decay)'].upload(neptune.types.File.as_image(plotLR(trainHistory_expDecay)))

npt_exp_3['Training Performance Curves (Exponential Decay)'].upload(neptune.types.File.as_image(plotPerformance(trainHistory_expDecay).get_figure()))

npt_exp_3.stop()

下面是与验证集的比较,

很容易看出,指数衰减的训练曲线(橙色线)比基于时间的衰减(蓝色线)平滑得多。总体而言,指数衰减略胜一筹。

到目前为止,我们只研究了连续衰减策略,那么离散衰减策略呢?接下来,我们将继续讨论一个流行的离散阶梯衰变,也就是基于阶梯的衰变。

基于阶跃的衰减

在该策略下,我们的学习率被安排为每 N 个时期减少一定量:

def lr_step_based_decay(epoch):
    drop_rate = 0.8
    epochs_drop = 10.0
    return initial_learning_rate * math.pow(drop_rate, math.floor(epoch/epochs_drop))

其中‘丢弃率’指定学习率被修改的量,而‘时期丢弃’指定修改的频率。

同上,设置我们的 initial_learning_rate = 0.5 和 epochs = 100 生成这个看起来像步骤的学习曲线,

*Step-based learning rate decay *

将它传递给我们的模型:

npt_exp_2 = neptune.init(
        api_token=os.getenv('NEPTUNE_API_TOKEN'),
        project='YourUserName/YourProjectName',
        name='StepBasedLRDecay',
        description='step-based-lr-decay',
        tags=['LearningRate', 'stepbased', 'decay', 'neptune'])

neptune_cbk = NeptuneCallback(run=npt_exp_2, base_namespace="metrics")

trainHistory_stepBasedDecay = model.fit(...,         callbacks=[neptune_cbk, LearningRateScheduler(lr_step_based_decay, verbose=1)])

npt_exp_2['Learning Rate Change (Step-Based Decay)'].upload(neptune.types.File.as_image(plotLR(trainHistory_stepBasedDecay)))

npt_exp_2['Training Performance Curves (Step-Based Decay)'].upload(neptune.types.File.as_image(plotPerformance(trainHistory_stepBasedDecay).get_figure()))

npt_exp_2.stop() 

我们会有与线性衰减非常相似的性能图表,其中我们的模型过度拟合。

StepBasedLRDecay-loss

Step-based learning rate schedule performance chart | See in Neptune

StepBasedLRDecay-accuracy

Step-based learning rate schedule performance chart | See in Neptune

模型性能基准

随着各种衰变方案的实施,我们现在可以把东西放在一起比较模型的表现。

*Learning rate schedulers *

基于我们的实验,总体来看,学习在大约 60 个时期停止;因此,为了便于可视化,我们将放大以关注前 60 个时期。和以前一样,我们将在 Neptune 中记录跟踪图:

npt_exp_master = neptune.init(
        api_token=os.getenv('NEPTUNE_API_TOKEN'),
        project='YourUserName/YourProjectName',
        name='ModelComparison',
        description='compare-lr-schedulers',
        tags=['LearningRate', 'schedulers', 'comparison', 'neptune'])

masterComparePlot('val_loss', ylab='Loss on the Validation Set', plotTitle='Compare Validation Loss',                  NeptuneImageTitle='Compare Model Performance -- Loss', includeAdaptive=False)

masterComparePlot('val_accuracy', ylab='Accuracy on the Validation Set', plotTitle='Compare Validation Accuracy',                   NeptuneImageTitle='Compare Model Performance -- Accuracy', includeAdaptive=False)

masterComparePlot('lr', ylab='Learning Rate', plotTitle='Compare Learning Rate Curves Generated from Different Schedulers',                  NeptuneImageTitle='Compare Learning Rate Curves', includeAdaptive=False, subset=False)

npt_exp_master.stop()

LearningRateShedule-loss

Loss curves on the validation set with different schedulers | See in Neptune

LearningRateShedule accuracy

Accuracy curves on the validation set with different schedulers | See in Neptune

上述当前练习的性能图表表明,指数衰减的性能最好,其次是基于时间的衰减;线性和基于步进的衰减方案导致模型过拟合。

自适应优化器

除了带学习率调度器的 SGD,第二个最有影响力的优化技术是自适应优化器,比如 AdaGrad,RMSprop,Adam 等等。这些优化器使用模型内部反馈来近似梯度;这意味着它们几乎是无参数的,并且与我们前面提到的与 SGD 相反的学习率调度器不兼容。

在所有自适应优化器中, Adam 一直是机器学习实践者的最爱。虽然关于这个优化器的细节超出了本文的范围,但是值得一提的是,Adam 为每个模型参数/权重分别更新了学习率。这意味着使用 Adam,学习率可能首先在早期层增加,从而有助于提高深度神经网络的效率。

现在,为了更好地衡量,让我们用 Keras 默认的“Adam”优化器来训练我们的模型,作为最后一个实验:

npt_exp_5 = neptune.init(
        api_token=os.getenv('NEPTUNE_API_TOKEN'),
        project='YourUserName/YourProjectName',
        name='Adaptive',
        description='adaptive-lr',
        tags=['LearningRate', 'adam', 'neptune'])

neptune_cbk = NeptuneCallback(run=npt_exp_5, base_namespace="metrics")
model = runModel()

adam = keras.optimizers.Adam()
lr_metric = get_lr_metric(adam)

model.compile(optimizer=adam,                     loss='sparse_categorical_crossentropy',                   metrics=['accuracy', lr_metric])

reset_random_seeds()

trainHistory_adaptive = model.fit(
        x_train, y_train,
        epochs=100,
        batch_size=64,
        validation_split=0.2,
        callbacks=[neptune_cbk])

plot_Neptune(history=trainHistory_adaptive, decayTitle='Adam Optimizer', npt_exp=npt_exp_5)

npt_exp_5.stop()

毫无疑问,这个“亚当”学习者让我们的模型很快发散,

尽管“Adam”是一个高效的学习者,但如果不进行超参数调整,“Adam”并不总是最佳选择。另一方面,SGD 可以通过调整学习率或衰减调度程序显著提高性能。

最后的想法

通过我们所有的实验,我们应该更好地理解学习进度有多重要;过度积极的衰减会导致优化器永远不会达到最小值,而缓慢的衰减会导致混乱的更新而没有显著的改善。

一些提示和要点包括:

  • 为了选择学习率时间表,通常的做法是从一个不太小的值开始,例如 0.5,然后指数地降低它以获得更小的值,例如 0.01、0.001、0.0001;
  • 虽然经常是深度学习应用程序中的默认优化器,但幕后的*亚当* **** 并不一定总是表现出色;它会导致模型发散
  • 为了建立有效的模型,我们还应该考虑其他超参数,如动量、正则化参数(丢失、提前停止等)。).

最后,值得一提的是,目前的结果是基于一个神经网络和数据集。当涉及到使用其他数据集的其他模型时,最佳学习率计划可能会有所不同。尽管如此,本文应该为您提供一个指南,告诉您如何系统地选择一个最适合您的特定模型和数据集的学习率调度器。

希望这篇文章对您有所帮助。我们的 Neptune 项目可以在这里访问,完整的脚本可以在我的 Github repo 这里获得。

人脸识别如何选择损失函数

原文:https://web.archive.org/web/https://neptune.ai/blog/how-to-choose-loss-function-for-face-recognition

人脸识别 (FR)是深度学习最有趣的任务之一。从表面上看,这就像是另一个多类分类问题。当你试着去实现它时,你会意识到它有更多的含义。损失函数的选择可能是决定模型性能的最关键因素。

为了让 FR 模型表现良好,它必须学会以这样一种方式从图像中提取这样的特征,即将属于同一张脸的所有图像紧密地放置在一起(在特征空间中),并将不同脸的图像远离放置。换句话说,我们需要模型来减少特征空间中数据点的类内距离,增加类间距离。本文的前半部分描述了对这两个子任务提供细粒度控制的损失函数。

与一般的分类任务不同,预先收集所有可能人脸的样本图像是不切实际的。因此,使用依赖于固定数量的类的损失函数可能不是一个好主意。在本文的后半部分,我们将探索损失函数,其目的是学习图像的良好的**表示,而不是图像分类到一组预定的类别中。这些表示然后被馈送到任何合适的最近邻分类器,例如 k-NN。

*## 基于分类的损失函数

损失函数将任何图像分类到已知类别。我的理解是,如果你有一个小的固定数量的类和更少的可用数据,它们会工作得更好。可以使用不同的度量来测量数据点之间的距离。欧几里德距离和余弦相似性(及其修改)是最流行的。

用欧几里得距离来衡量

软最大损失

背景/动机

Softmax 损失只不过是最后一层中 softmax 激活的分类交叉熵损失。这是 FR 最基本的损失函数,也可能是最差的。为了完整起见,我将它包含在这里,因为在此之后出现的损失是对 softmax 损失的一些修改。

定义

softmax 损耗定义如下:

X[I]是第 i ^幅幅图像的特征向量。 W [j] 是权重的第 j^(列, b [j] 是偏置项。类别数和图像数分别为 nm ,而*y[I]是第*I^(th)幅图像的类别。)**

***##### 优势

  • 这种损失在文献中有很好的探讨,并且在信息理论中有很强的概念基础
  • 大多数标准的机器学习框架已经提供了这种损失的内置实现。
不足之处
  • 每个类都需要在训练集中表示
  • 无法对类内/类间距离进行精细控制
代码示例
import tensorflow as tf

def softmax_loss(y_true, W, b, x):

    y_pred = tf.matmul(x, W) + b
    numerators = tf.reduce_sum(y_true * tf.exp(y_pred), axis=1)
    denominators = tf.reduce_sum(tf.exp(y_pred), axis=1)
    loss = - tf.reduce_sum(tf.log(numerators / denominators))

    return loss

中心损失

背景/动机
  • 为了解决 Softmax 损失的局限性,这篇论文的作者提出了中心损失的概念。

  • 首先,他们注意到数据在特征空间中的分布存在显著的类内差异。

  • 他们用一个玩具模型来证明这一点,这个玩具模型的最后一层只有两个完全连接的节点。

  • 训练后最终层激活的图如下图所示(摘自论文)

  • 为了缓解这种情况,他们在 softmax loss 中引入了一个额外的项,如果数据点远离其类的质心,则该项会惩罚模型。

定义

中心损耗定义为:

  • 第一项(灰色)与 softmax 损失相同。
  • 在第二项中,c[yi]是属于特征空间中第 i ^个数据点的类yI 的所有点的质心。**
  • 第二项实质上是所有点距其各自类质心的平方距离之和。实际上,这个质心是一次为一个批次而不是整个数据集计算的。
  • 是控制第二项效果的超参数。

**##### 优势

  • 圆形损失明确地惩罚了类内变化。
  • 与对比损失或三重损失(稍后讨论)不同,它不需要将训练样本复杂地重新组合成对或三重。
不足之处
  • 如果类的数量非常大,那么质心的计算就变得非常昂贵[ Source
  • 它没有明确地惩罚类间的变化。
代码示例
import tensorflow as tf

def circle_loss(W, b, lamda_center):

    def inner(y_true, x):
        y_pred = tf.matmul(x, W) + b
        numerators = tf.reduce_sum(y_true * tf.exp(y_pred), axis=1)
        denominators = tf.reduce_sum(tf.exp(y_pred), axis=1)
        loss_softmax = - tf.reduce_sum(tf.log(numerators / denominators))

        class_freqs = tf.reduce_sum(y_true, axis=0, keepdims=True)
        class_freqs = tf.transpose(class_freqs)

        centres = tf.matmul(tf.transpose(y_true), x)
        centres = tf.divide(centres, class_freqs)
        repeated_centres = tf.matmul(y_true, centres)

        sq_distances = tf.square(tf.norm(x - repeated_centres, axis=1))
        loss_centre = tf.reduce_sum(sq_distances)

        loss = loss_softmax + (lambda_center/2) * loss_centre

        return loss
    return inner

通过角距离测量

A-Softmax(又名 SphereFace)

背景/动机
  • 从 softmax 损耗中学习的特征本质上具有角度分布(参见中心损耗部分的图)。
  • 这篇论文的作者明确利用了这个事实。
定义
  • 作者根据特征向量和与其在权重矩阵中的类别相对应的列向量之间的角度来改写 softmax 损失的表达式(参考 softmax 损失以了解除θ之外的术语的解释):

  • 然后,他们通过 L [2] 归一化每个 W [j] 并忽略偏差项来简化表达式。这仍然是一个很好的近似值(我的理解是,这只是为了计算损耗,而不是在实际架构中)。

  • 然后他们添加一个超参数 m 来控制这个表达式对角度的敏感度

  • 这是球面损失。为了完整起见,本文描述了进一步的修改,但是这种表达对于概念性的理解是足够的。

  • 余弦函数被修改的余量如下(绿色为未修改)。

SphereFace

Source: Author

优势

该损失函数直接与角度变量一起工作,这更符合如前所述的数据的内在分布。
  • 它不需要将训练样本复杂地重组成对或三元组。
  • 这种损失有助于减少类内距离,同时增加类间距离(在分母中可以清楚地看到,因为类内角度比类间角度受到更大的惩罚)
  • 不足之处
原论文做了几个近似和假设(如 m 被约束为整数)。
  • 随着 m 的增加,余弦函数的局部极小值也来到可能的θ的范围内,在此之后该函数是非单调的(即在θ = /m 之后)。
  • 作者需要对原始损失函数进行分段修正来解决这个问题。
  • 代码示例
大幅度余弦损失(又名余弦损失)
import tensorflow as tf

def SphereFaceLoss(W, x, m):
    def inner(y_true, x):

        M = (m-1) * y_true + 1

        normalized_W, norms = tf.linalg.normalize(W, axis=0)

        y_pred = x * normalized_W

        cos_theta, norm_x = tf.linalg.normalize(y_pred, axis=1)
        theta = tf.acos(cos_theta)

        new_theta = theta * M
        new_cos_theta = tf.cos(new_theta)
        new_y_pred = norm_x * new_cos_theta

        numerators = tf.reduce_sum(y_true * tf.exp(new_y_pred), axis=1)
        denominators = tf.reduce_sum(tf.exp(new_y_pred), axis=1)
        loss = - tf.reduce_sum(tf.log(numerators / denominators))

        return loss
    return inner

背景/动机

这种损失是由与 SphereFace 相同的推理引起的,但是论文的作者声称它更容易理解和执行。
  • 定义
在这种损失中,特征向量也被归一化(类似于 W [j] )并通过常数因子 s 进行缩放
  • 余量 m 被加到角度的余弦上。公式是:

  • 余弦函数修改如下(绿色未修改):

  • 优势

Cosine loss function

Source: Author

与 SphereFace 不同,余弦函数的非单调性不会产生问题。
  • 因为特征向量也被归一化,所以模型必须学习更好的角度分离,因为它没有通过学习不同的范数来减少损失的自由。
  • 代码示例
附加角裕度损失(又名弧面)
import tensorflow as tf

def CosFaceLoss(W, m, s):
    def inner(y_true, x):

        y_true = tf.cast(y_true, dtype=tf.float32)
        M = m * y_true

        dot_product = tf.matmul(x, W)
        cos_theta, cos_theta_norm = tf.linalg.normalize(dot_product,axis=0)

        y_pred = s * cos_theta - M

        numerators = tf.reduce_sum(y_true * tf.exp(y_pred), axis=1)
        denominators = tf.reduce_sum(tf.exp(y_pred), axis=1)
        loss = - tf.reduce_sum(tf.math.log(numerators/denominators))
        return loss
    return inner

背景/动机

这是 angular softmax 损失系列中的又一损失。论文的作者声称它比它的前辈有更好的性能和更清晰的几何解释。
  • 定义
这里,cos 函数内部的余量被添加到角度本身。
  • 优势
这里的余量 m 可以解释为半径 s 的超球面上的附加弧长
  • (从实验来看)在具有大致相同的类内相似性的同时,类间差异似乎比三重丢失更好。
  • 该论文中的模型优于前面提到的论文中的所有模型。
  • 余弦函数修改如下(绿色未修改):
  • 不足之处

Additive angular margin loss

Source: Author

余弦函数的非单调性会在θ值大于–**m时产生问题,但作者似乎没有具体解决这个问题。
  • 代码示例
基于表征学习的损失函数
import tensorflow as tf

def ArcFaceLoss(W, m):
    def inner(y_true, x):

        M = (m-1) * y_true + 1

        normalized_W, norms_w = tf.linalg.normalize(W, axis=0)
        normalized_x, norms_x = tf.linalg.normalize(x, axis=0)

        cos_theta = normalized_x * normalized_W

        theta = tf.acos(cos_theta)

        new_theta = theta + M
        new_cos_theta = tf.cos(new_theta)

        y_pred = s * new_cos_theta

        numerators = tf.reduce_sum(y_true * tf.exp(y_pred), axis=1)
        denominators = tf.reduce_sum(tf.exp(y_pred), axis=1)
        loss = - tf.reduce_sum(tf.log(numerators / denominators))

        return loss

    return inner

明确的反面例子

对比损失

背景/动机

这是人脸识别中最著名的损失函数之一。
  • 这种损失背后的动机是开发一种模型,该模型将学习在特征空间中表示图像,使得该空间中的距离将对应于原始空间中的语义距离。
  • 这种损失是基于神经网络的连体结构
  • 定义
数据集由属于相同类别(y [i] = 1)或不同类别(y [i] = 0)的图像对组成。
  • 每幅图像(x [i,1] ,x [i,2] )通过基神经网络,得到其特征向量(f(x [i,1] ),f(x [i,2] )。则 d [i] 为嵌入之间的距离,即 d [i] = || f(x [i,1])–f(x[I,2] ) ||
  • 如果这一对属于同一类,那么如果嵌入的距离很近,损失就比较小。否则,模型会尝试让配对之间至少相隔的距离。
  • 优势
损失很简单理解。
  • Margin m 作为一种控制,控制着模型将不同的嵌入分开的努力程度。
  • 非常容易为新的/看不见的类别扩展训练的模型,因为模型学习创建图像的语义表示,而不是简单地在预定的类别集合中对其进行分类。
  • 不足之处
对于 n 个图像,有 O(n ² 个图像对。因此,覆盖所有可能的对在计算上是昂贵的。
  • 裕量 m 对于所有不相似的对都是相同的常数,这隐含地告诉模型在所有不相似的对之间具有相同的距离是可以的,即使一些对比其他对更不相似。【ce
  • 这里使用了相似和不相似对的绝对概念,它不能从一个上下文转移到另一个上下文。例如,在随机对象的图像对上训练的模型在仅在人的图像数据集上测试时将很难表现良好。[ 来源
  • 代码示例
三重损失
import tensorflow as tf

def contrastive_loss(m):
    def inner(y_true, d):
        loss = tf.reduce_mean(y_true*d+(1-y_true)*tf.maximum(m-d, 0))
        return loss
    return inner 

背景/动机

三重损失可能是人脸识别中最著名的损失函数。
  • 数据被排列成三个一组的图像:锚、正例、反例。
  • 图像通过一个共同的网络,目的是减少锚正距离,同时增加锚负距离。
  • 损失基础的架构如下所示:
  • 定义

Triplet loss

Source: Original image from this paper with modifications by author

这里,A [i] ,P [i] ,N [i] ,分别是主播,正面例子,反面例子形象。
  • f(A [i] ),f(P [i] ),f(N [i] )是这些图像在特征空间中的嵌入。
  • 余量为
  • 优势
意象的相似和相异的概念只是在相对意义上使用,而不是像对比损失那样在绝对意义上定义。
  • 尽管对于所有的三连音来说余量 m 是相同的,但是在每种情况下锚负距离(d^–)可以是不同的,因为锚正距离(d ^+ )是不同的。
  • 最初的论文声称胜过基于损失的对比模型。
  • 不足之处
对 d ^+ 和 d–的惩罚被约束为相同。损失是无视(d+–d^–)值的根本原因:高 d ^+ vs 低 d^–。这是低效的。[ 来源
  • 代码示例
圆形损失
import tensorflow as tf

def triplet_loss(m):
    def inner(d_pos, d_neg):
        loss = tf.square(tf.maximum(d_pos - d_neg + m, 0))
        loss = tf.reduce_mean(loss)
        return loss
    return inner

背景/动机

受上面提到的三重态损失的不利影响,本文的作者提出了一个损失函数来解决这个问题。
  • 该论文还提出了一个框架,该框架将基于分类的损失和基于表示学习的损失统一在一个保护伞下。
  • 定义
损失使用的是两幅图像之间的相似性概念,而不是距离。比方说,这种相似性可以是点积。
  • 该文件还提供了一个类似 softmax 的损失公式,以固定类别数表示。这里,我们将只考虑相似和不相似对的公式。

  • 设有 K 个具有相似度 s^Ip= { 1,2,3,…,K}和 M 个具有相似度 s[n]j= { 1,2,3,…,L}的负相关像对

  • 那么损失定义为:

  • 这里,是超参数,是系数,可以更好地控制各项对损耗的影响。

  • 它们被定义为:

  • 这里,O [p] 和 O [n] 是分别表示正图像对和负图像对中相似度的最佳值的超参数。

  • 这导致了一个循环决策边界,如图所示:

  • 优势

Cirle loss

(a) Decision boundary with Triplet loss (b) Decision Boundary with Circle Loss [source]

圆损耗比三重损耗具有更明确的收敛目标,因为在(S [n] ,S [p] 空间中有一个单点,优化被驱动向该单点(O [n] ,O [p]
  • 不足之处
这里,O [p] 和 O [n] 的选择有些随意
  • 需要显式的反例挖掘(或者在替换公式中,类的数量是固定的)
  • 代码示例
该代码使用了纸张损耗的简化表达式
  • 没有明确的反面例子
import tensorflow as tf

def circle_loss(s_pos, O_pos, s_neg, O_neg, gamma):
    alpha_pos = tf.maximum(O_pos - s_pos, 0)
    alpha_neg = tf.maximum(O_neg - s_neg, 0)

    sum_neg = tf.reduce_sum(tf.exp(gamma * alpha_neg * s_neg))
    sum_pos = tf.reduce_sum(tf.exp(-1 * gamma * alpha_pos * s_pos))

    loss = tf.log(1 + sum_neg * sum_pos)

    return loss

巴洛双胞胎

背景/动机

这是一个自我监督学习(SSL) 的例子。SSL 中的一种常见方法是学习对输入图像的失真不变的图像表示。
  • 这种方法中的一个常见问题是崩溃到平凡解,即所有图像的相同常数表示。
  • 本文提出了一种损失函数,该函数抑制同一图像的两种不同表示之间的互相关。
  • 定义
图像受到 2 种不同的(随机选择的)失真,并通过共享权重的连体结构:
  • 损失函数定义为:

  • 其中每一项 C [ij] 计算如下:

  • z 是学习的表示向量。下标 I,j 分别表示矢量表示的第 i ^个和第 j ^个分量。上标 A、B 表示同一输入图像的不同失真版本。下标 b 表示批次中的索引。

  • 优势

这种方法不需要固定数量的类
  • 它也不会受到数据膨胀的影响,因为它不需要明确的反面例子
  • 不足之处
该论文中的模型需要最终表示的大维数以获得良好的性能。
  • 对于消除输入的某些失真,性能并不稳定。
  • simsimi 代码示例
背景/动机
import tensorflow as tf
import tensorflow_probability as tfp

def barlow_twins_loss(lamda_bt):
    def inner(z_a, z_b,):
        correlation_matrix = tfp.stats.correlation(z_a, z_b)
        identity_matrix = tf.eye(correlation_matrix.shape[0])
        loss = tf.reduce_sum(tf.abs(identity_matrix - correlation_matrix))
        return loss
    return inner

这个损失是在这篇论文中提出的。

本文试图构建一个最简单的连体建筑,它可以很好地表达图像。
  • 定义
  • 损失基于以下架构:
这里,stop-grad 意味着 z [2] 被视为常数,并且编码器网络的权重不从其接收任何梯度更新。
  • 在最终损失表达式中,添加了另一个对称项,预测器网络位于右分支而不是左分支。

  • 单个图像的损失为:

  • 其中每一项定义如下:(|| || [2] 是 L[2]-范数)

  • 这是整个批次的总和或平均值。

  • 优势

  • 这种损失不需要明确的反面例子挖掘

它不需要固定数量的类
  • 与 SimCLR 或 BYOL(本文未讨论)不同,它也不需要大批量
  • 不足之处
  • 这篇论文不能从理论上解释为什么这个模型不能塌缩成一个平凡的解(常数表示),而只能从经验上证明它。
代码示例
  • 运行中的示例代码
本文探讨的每种损失都有利弊。对于一个给定的问题,很难预测哪种损失效果最好。你需要在训练中进行大量的实验,以找到最适合你的情况的解决方案。
import tensorflow as tf

def SimSiamLoss(p_1, p_2, z_1, z_2):

    cosine_loss = tf.keras.losses.CosineSimilarity(axis=1)
    D_1 = cosine_loss(p_1, tf.stop_gradient(z_2))
    D_2 = cosine_loss(p_2, tf.stop_gradient(z_1))
    loss = 0.5 * (D_1 + D_2)

    return loss

Neptune 提供了一个很好的工具来监控模型的损失(和其他指标)。它还能与您可能正在使用的其他工具/框架无缝协作。以下代码显示了如何将 MNIST 数字分类器模型的陪面损失与 TensorFlow 中的简单 Neptune 回调合并。

您可以使用 CosFace 和 ArcFace loss 分别运行一次以下脚本。只需注释/取消注释所需损失函数的函数调用(第 83 行)。

借助 Neptune 上的“比较运行”选项,我能够比较两者的性能:

由于两种损失的函数形式不同,直接比较两种损失的绝对值意义不大(但它们的总体趋势可能会提供信息)。为了更好地比较性能,我们来看看结果的准确性。

import tensorflow as tf
import neptune.new as neptune
from neptune.new.integrations.tensorflow_keras import NeptuneCallback

run = neptune.init(project='common/tf-keras-integration',
api_token='ANONYMOUS')

mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

y_train = tf.one_hot(y_train, 10)
y_test = tf.one_hot(y_test, 10)

model_input = tf.keras.Input((28, 28))
flat = tf.keras.layers.Flatten()(model_input)
dense_1 = tf.keras.layers.Dense(32, activation=tf.keras.activations.relu)(flat)
dense_2 = tf.keras.layers.Dense(10, activation='sigmoid')(dense_1)
dense_2.trainable = False

model = tf.keras.models.Model(inputs=model_input, outputs=[dense_1, dense_2])
model.build(input_shape=(28, 28))
model.summary()

def CosFaceLoss(W, m, s):
    def inner(y_true, x):

        y_true = tf.cast(y_true, dtype=tf.float32)
        M = m * y_true

        dot_product = tf.matmul(x, W)
        cos_theta, cos_theta_norm = tf.linalg.normalize(dot_product,axis=0)

        y_pred = s * cos_theta - M

        numerators = tf.reduce_sum(y_true * tf.exp(y_pred), axis=1)
        denominators = tf.reduce_sum(tf.exp(y_pred), axis=1)
        loss = - tf.reduce_sum(tf.math.log(numerators/denominators))
        return loss
    return inner

def ArcFaceLoss(W, m, s):
    def inner(y_true, x):

        M = (m-1) * y_true + 1

        dot_product = tf.matmul(x, W)
        cos_theta,cos_theta_norms = tf.linalg.normalize(dot_product,axis=0)

        theta = tf.acos(cos_theta)

        new_theta = theta + M
        new_cos_theta = tf.cos(new_theta)

        y_pred = s * new_cos_theta

        numerators = tf.reduce_sum(y_true * tf.exp(y_pred), axis=1)
        denominators = tf.reduce_sum(tf.exp(y_pred), axis=1)
        loss = - tf.reduce_sum(tf.log(numerators / denominators))

        return loss

    return inner
def dummy_loss(ytrue, ypred):
    return tf.constant([0])

loss_func = CosFaceLoss(W=model.layers[-1].weights[0], m=10.0, s=10.0)

model.compile(optimizer='adam', metrics=['accuracy'],
              loss=[loss_func, dummy_loss])

neptune_cbk = NeptuneCallback(run=run, base_namespace='metrics')

model.fit(x_train,y_train,epochs=5,batch_size=64,callbacks=[neptune_cbk])

从这个图来看,ArcFace loss 在这里的表现似乎更好。请记住,这只是一个玩具示例,在真实世界的数据集中,结果可能会有所不同,并且可能需要对边缘值和其他超参数进行更广泛的实验。

Loss in Neptune

The blue curve represents CosFace loss and the purple represents ArcFace. X-axis is the batch number and Y-axis is the loss value. | Source: Author’s Neptune project

检查如何跟踪和监控您的 TensorFlow 模型训练(包括损失、指标、超参数、硬件消耗等)。

Accuracy in Neptune

The blue curve represents CosFace loss and the purple represents ArcFace. X-axis is the epoch number and Y-axis is the accuracy. | Source: Author’s Neptune project

结论

损失函数可能是人脸识别模型中最重要的组成部分。本文中讨论的每个损失函数都有一组独特的特征。有些提供了对类分离的强大控制,有些提供了更好的可伸缩性和可扩展性。我希望这篇文章能帮助您更好地理解可用的选项以及它们对您的特定问题的适用性。我很想听听你对我提到的和我遗漏的问题的看法。感谢阅读!

Conclusion

Loss Function is possibly the most important component of a Face Recognition model. Each loss function discussed in this article comes with a unique set of characteristics. Some provide great control over class separations, others provide better scalability and extensibility.  I hope this article helps you develop a better understanding of the available options and their suitability for your particular problem. I would love to hear your thoughts on the ones I mentioned and also the ones I left out. Thanks for reading!******

如何使用 PyTorch 编写 BERT 代码

原文:https://web.archive.org/web/https://neptune.ai/blog/how-to-code-bert-using-pytorch-tutorial

如果你是一个 NLP 爱好者,那么你可能听说过伯特。在本文中,我们将探讨 BERT:它是什么?以及它是如何工作的?,并学习如何使用 PyTorch 对其进行编码。

2018 年,Google 发表了一篇名为“深度双向变压器语言理解预训练”的论文。在这篇论文中,他们引入了一个名为 BERT(使用变压器的双向编码器表示)的语言模型,该模型在类似问答自然语言推理、分类和一般语言理解评估(GLUE) 等任务中实现了最先进的性能。

BERT 版本是在三个架构发布之后发布的,这三个架构也实现了最先进的性能。这些模型是:

  • 乌尔姆-菲特(1 月)
  • 埃尔莫(二月),
  • GPT 公开赛(6 月)
  • 伯特(十月)。

OpenAI GPT 和 BERT 使用不使用递归神经网络的 变压器 架构;这使得该架构能够通过自我关注机制考虑长期依赖性,这种机制从本质上改变了我们对顺序数据建模的方式。它引入了一种编码器-解码器架构,这种架构出现在计算机视觉应用中,例如通过可变自动编码器编码器生成图像。

那么 BERT 与 2018 年发布的所有车型有什么不同呢?

要回答这个问题,我们需要了解什么是 BERT,以及它是如何工作的。

那么,我们开始吧。

伯特是什么?

BERT 代表“使用变压器的双向编码器表示”。简而言之,BERT 通过编码器从数据或单词嵌入中提取模式或表示。编码器本身是一个堆叠在一起的转换器架构。它是一个双向转换器,这意味着在训练过程中,它会考虑词汇左侧和右侧的上下文来提取模式或表示。

BERT 使用两种训练范式:预训练微调

预训练期间,在大数据集上训练模型以提取模式。这通常是一个无监督学习任务,其中模型在一个未标记的数据集上训练,如来自维基百科等大型语料库的数据。

微调期间,模型被训练用于下游任务,如分类、文本生成、语言翻译、问答等等。本质上,你可以下载一个预先训练好的模型,然后根据你的数据转换学习这个模型。

BERT 的核心组件

伯特借用了以前发布的 SOTA 模型的想法。让我们详细阐述一下那句话。

变形金刚

BERT 的主要组件是变压器架构。变压器由两部分组成:编码器解码器。编码器本身包含两个组件:T4 自关注层 T5 和 T6 前馈神经网络 T7。

自我注意层接受输入,将每个单词编码成中间编码表示,然后通过前馈神经网络。前馈网络将这些表示传递给解码器,解码器本身由三个组件组成:自关注层、编码器-解码器关注、前馈神经网络

transformer 架构的好处在于,它有助于模型保留无限长的序列,这在传统的 RNNs、LSTMs 和 GRU 中是不可能的。但即使从它可以实现长期依赖的事实来看,它仍然缺乏上下文理解

Jay Alammar 在他的文章 中深入解释了变形金刚,图文并茂的变形金刚 ,值得一探究竟。

工程与后勤管理局

BERT 借用了 ELMo 的另一个概念,即语言模型嵌入。埃尔莫是由彼得斯等人介绍的。艾尔。2017 年,涉及语境理解的思想。ELMo 的工作方式是使用双向 LSTM 来理解上下文。由于它从两个方向考虑单词,它可以为拼写相似但含义不同的单词分配不同的单词嵌入。

例如,“你们这些孩子应该在黑暗中把粘在一起”和“把那根棍子递给我”是完全不同的。尽管两个句子中使用了同一个词,但根据上下文的不同,意思是不同的。

因此,ELMo 通过考虑来自右和左两个方向的单词来分配嵌入,而之前开发的模型只考虑来自左的单词。这些模型是单向的,如 RNNs、LSTMs 等。

这使得 ELMo 能够从序列中捕获上下文信息,但是因为 ELMo 使用 LTSM,所以与变形金刚相比,它不具有长期依赖性。

到目前为止,我们已经看到,由于 transformers 中存在的注意机制,BERT 可以访问文档中的序列,即使它比序列中的当前单词落后“n”个单词,即,它可以保持长期依赖性,并且由于 ELMo 中存在的双向机制,它还可以实现对句子的上下文理解。

乌尔姆拟合

2018 年,杰瑞米·霍华德和塞巴斯蒂安·鲁德发布了一篇名为通用语言模型微调或 ULM-FiT 的论文,他们在论文中指出,迁移学习可以用于自然语言处理,就像它用于计算机视觉一样。

以前,我们使用预训练的单词嵌入模型,该模型仅针对整个模型的第一层,即嵌入层,并且整个模型是从头开始训练的,这很耗时,并且在该领域没有发现很多成功。然而,Howard 和 Ruder 提出了 3 种文本分类方法:

  • 第一步包括在更大的数据集上训练模型,以便模型学习表示。
  • 第二步包括用特定于任务的数据集对模型进行微调以进行分类,在此期间,他们引入了另外两种方法:判别微调和倾斜三角学习率(STLR)。前一种方法试图在网络的传输层期间微调或优化每个参数,而后一种方法控制每个优化步骤中的学习速率。
  • 第三步是在特定于任务的数据集上微调分类器以进行分类。

随着 ULM-FiT 的发布,NLP 实践者现在可以在他们的 NLP 问题中实践迁移学习方法。但是,ULM-FiT 迁移学习方法的唯一问题是,它包括微调网络中的所有层,这是一项繁重的工作。

GPT 开放大学

生成式预训练变压器或 GPT 是由 OpenAI 的团队引入的:拉德福德、纳拉辛汉、萨利曼斯和苏茨基弗。他们提出了一个模型,该模型在单向方法中仅使用来自转换器的解码器而不是编码器。因此,它在各种任务中的表现优于所有以前的型号,例如:

  • 分类
  • 自然语言推理
  • 语义相似度
  • 问题回答
  • 多项选择。

即使 GPT 只使用解码器,它仍然可以保持长期的依赖性。此外,与我们在 ULM-FiT 中看到的相比,它将微调减少到了最低限度。

下表根据预培训、下游任务以及最重要的微调对不同模型进行了比较。

GPT 论文的一段摘录写道“与循环网络等替代方案相比,这种模型选择为我们提供了一种更结构化的记忆,用于处理文本中的长期依赖性,从而在不同任务之间实现稳健的传输性能。在转换过程中,我们利用来自遍历式方法的特定于任务的输入适应,这种方法将结构化文本输入作为单个连续的标记序列来处理。正如我们在实验中所展示的,这些适应使我们能够有效地进行微调,对预训练模型的架构进行最小的改变。

让我们将所有模型与 BERT 进行比较,看它们能够执行的任务:

变压器 工程与后勤管理局 乌尔姆拟合 GPT 开放大学 伯特

自然语言推理

| | | | | |
| | | | | | |
|

分类或者
情绪分析

| | | | | |
| | | | | | |
| | | | | | |

你可以检查拥抱脸模型来检查模型在每个任务上的表现。

为什么是伯特?

伯特陷入了自我监督模式。这意味着,它可以从原始语料库中生成输入和标签,而无需人类显式编程。请记住,它所训练的数据是非结构化的。

伯特接受了两项特定任务的预训练:掩蔽语言模型和下一句预测。前者使用类似“该男子[面具]到商店”的屏蔽输入,而不是“该男子去了商店”。这限制了 BERT 看到它旁边的单词,这允许它尽可能多地学习双向表示,使它对几个下游任务更加灵活和可靠。后者预测这两个句子是否在上下文中相互分配。

例如,如果句子 A 是“[CLS]那个人[面具]去商店”,句子 B 是“企鹅[面具]是不会飞的鸟[SEP]”,那么 BERT 将能够区分这两个句子是否是连续的。

在训练过程中,BERT 使用特殊类型的标记,如[CLS]、[屏蔽]、[分离]等,这些标记允许 BERT 区分一个句子何时开始,哪个单词被屏蔽,以及两个句子何时分开。我已经在预处理部分以表格的形式解释了这些令牌。

由于我们之前讨论过的特性,BERT 也可用于特征提取,并将这些提取提供给现有模型。

在最初的 BERT 论文中,它与 GPT 在通用语言理解评估基准上进行了比较,下面是结果。

正如你所看到的,伯特在所有的任务中都超过了 GPT,平均比 GPT 高出 7%。

BERT tasks

The image above shows the different tasks that BERT can be used for. | Source

用 Pytorch 编写 BERT 代码

让我们用代码来理解如何用 PyTorch 构建 BERT。

我们将整个计划分为 4 个部分:

  1. 预处理
  2. 建筑模型
  3. 损失和优化
  4. 培养

预处理

在预处理中,我们将结构化数据,以便神经网络可以处理它。我们首先指定一个原始文本进行训练。

text = (
       'Hello, how are you? I am Romeo.n'
       'Hello, Romeo My name is Juliet. Nice to meet you.n'
       'Nice meet you too. How are you today?n'
       'Great. My baseball team won the competition.n'
       'Oh Congratulations, Julietn'
       'Thanks you Romeo'
   )

然后,我们将通过以下方式清理数据:

  • 把句子变成小写。
  • 创造词汇。词汇表是文档中唯一单词的列表。
  sentences = re.sub("[.,!?-]", '', text.lower()).split('n')  
   word_list = list(set(" ".join(sentences).split()))

现在,在接下来的步骤中,重要的是要记住伯特在训练中使用特殊的代币。下表解释了各种令牌的用途:

代币 目的

第一个令牌总是分类

|
| | |
| | |
| |

用等长截断句子。

|
| |

用于通过替换原来的单词来创建一个遮罩。

|

这些标记应该包含在单词字典中,其中词汇表中的每个标记和单词都分配有一个索引号。

word_dict = {'[PAD]': 0, '[CLS]': 1, '[SEP]': 2, '[MASK]': 3}
for i, w in enumerate(word_list):
   word_dict[w] = i + 4
   number_dict = {i: w for i, w in enumerate(word_dict)}
   vocab_size = len(word_dict)

考虑到这一点,我们需要创建一个函数,为三种类型的嵌入格式化输入序列:标记嵌入片段嵌入、位置嵌入

什么是令牌嵌入?

例如,如果句子是“猫在走路”。狗在叫”,那么该函数应该以如下方式创建一个序列:“[CLS]猫在走[SEP]狗在叫”。

之后,我们将所有内容转换为单词字典中的索引。所以前面的句子看起来就像“[1,5,7,9,10,2,5,6,9,11]”。请记住,1 和 2 分别是[CLS]和[九月]。

什么是片段嵌入?

片段嵌入将两个句子彼此分开,并且它们通常被定义为 0 和 1。

什么是位置嵌入?

位置嵌入给出了序列中每个嵌入的位置。

稍后我们将创建一个位置嵌入函数。

现在下一步将是创建屏蔽

正如在原始论文中提到的,BERT 随机地将掩码分配给序列的 15%。但是请记住,不要给特殊标记分配掩码。为此,我们将使用条件语句。

一旦我们将 15%的单词替换为[MASK]标记,我们将添加填充。填充通常是为了确保所有的句子长度相等。例如,如果我们拿这个句子来说:

“猫在走路。狗对着树叫

然后加上填充,看起来会是这样的:

【CLS】猫在走[PAD] [PAD] [PAD]。[CLS]狗在对着树叫。”

第一句话的长度等于第二句话的长度。

def make_batch():
   batch = []
   positive = negative = 0
   while positive != batch_size/2 or negative != batch_size/2:
       tokens_a_index, tokens_b_index= randrange(len(sentences)), randrange(len(sentences))

       tokens_a, tokens_b= token_list[tokens_a_index], token_list[tokens_b_index]

       input_ids = [word_dict['[CLS]']] + tokens_a + [word_dict['[SEP]']] + tokens_b + [word_dict['[SEP]']]
       segment_ids = [0] * (1 + len(tokens_a) + 1) + [1] * (len(tokens_b) + 1)

       n_pred =  min(max_pred, max(1, int(round(len(input_ids) * 0.15)))) 
       cand_maked_pos = [i for i, token in enumerate(input_ids)
                         if token != word_dict['[CLS]'] and token != word_dict['[SEP]']]
       shuffle(cand_maked_pos)
       masked_tokens, masked_pos = [], []
       for pos in cand_maked_pos[:n_pred]:
           masked_pos.append(pos)
           masked_tokens.append(input_ids[pos])
           if random() < 0.8:  
               input_ids[pos] = word_dict['[MASK]'] 
           elif random() < 0.5:  
               index = randint(0, vocab_size - 1) 
               input_ids[pos] = word_dict[number_dict[index]] 

       n_pad = maxlen - len(input_ids)
       input_ids.extend([0] * n_pad)
       segment_ids.extend([0] * n_pad)

       if max_pred > n_pred:
           n_pad = max_pred - n_pred
           masked_tokens.extend([0] * n_pad)
           masked_pos.extend([0] * n_pad)

       if tokens_a_index + 1 == tokens_b_index and positive < batch_size/2:
           batch.append([input_ids, segment_ids, masked_tokens, masked_pos, True]) 
           positive += 1
       elif tokens_a_index + 1 != tokens_b_index and negative < batch_size/2:
           batch.append([input_ids, segment_ids, masked_tokens, masked_pos, False]) 
           negative += 1
   return batch

由于我们正在处理下一个单词预测,我们必须创建一个标签来预测该句子是否有连续的句子,即 IsNext 或 NotNext。所以我们为下一句之前的每一句赋值 True,我们用一个条件语句来实现。

例如,如果在上下文中,文档中的两个句子通常是前后相接的。假设第一句是 A,那么下一句应该是+1。直观地,我们编写代码,使得如果第一个句子位置,即 tokens _ a _ index+1 = = tokens _ b _ index,即相同上下文中的第二个句子,那么我们可以将该输入的标签设置为 True。

如果不满足上述条件,即如果 token _ a _ index+1!= tokens_b_index 然后我们将这个输入的标签设置为 False。

建筑模型

BERT 是一个复杂的模型,如果你慢慢理解它,你就会失去逻辑。所以解释它的组件和它们的功能是有意义的。

BERT 具有以下组件:

  1. 嵌入层
  2. 注意力屏蔽
  3. 编码器层
    1. 多头注意力
      1. 比例点产品关注度
    2. 位置式前馈网络
  4. 伯特(组装所有部件)

为了便于学习,你可以随时参考这个图表。

BERT building model

Source: Author

嵌入层

嵌入是 BERT 中的第一层,它接受输入并创建一个查找表。嵌入层的参数是可学习的,这意味着当学习过程结束时,嵌入层会将相似的单词聚集在一起。

嵌入层还保留单词之间的不同关系,例如:语义、句法、线性,并且由于 BERT 是双向的,它还将保留上下文关系。

在 BERT 的例子中,它为

  • 令牌,
  • 分段和
  • 位置。

如果您还记得,我们还没有创建一个函数来接收输入并对其进行格式化以进行位置嵌入,但是标记和段的格式化已经完成。因此,我们将接受输入,并为序列中的每个单词创建一个位置。它看起来像这样:

print(torch.arange(30, dtype=torch.long).expand_as(input_ids))
Output:

tensor([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
         18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
        [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
         18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
        [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
         18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
        [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
         18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
        [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
         18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
        [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
         18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]])

在前向函数中,我们总结了所有的嵌入,并对它们进行归一化。

class Embedding(nn.Module):
   def __init__(self):
       super(Embedding, self).__init__()
       self.tok_embed = nn.Embedding(vocab_size, d_model)  
       self.pos_embed = nn.Embedding(maxlen, d_model)  
       self.seg_embed = nn.Embedding(n_segments, d_model)  
       self.norm = nn.LayerNorm(d_model)

   def forward(self, x, seg):
       seq_len = x.size(1)
       pos = torch.arange(seq_len, dtype=torch.long)
       pos = pos.unsqueeze(0).expand_as(x)  
       embedding = self.tok_embed(x) + self.pos_embed(pos) + self.seg_embed(seg)
       return self.norm(embedding)

创建注意力屏蔽

伯特需要注意力面具。并且这些应该是适当的格式。以下代码将帮助您创建遮罩。

它会将[PAD]转换为 1,其他地方为 0。

def get_attn_pad_mask(seq_q, seq_k):
   batch_size, len_q = seq_q.size()
   batch_size, len_k = seq_k.size()

   pad_attn_mask = seq_k.data.eq(0).unsqueeze(1)  
   return pad_attn_mask.expand(batch_size, len_q, len_k)  
print(get_attn_pad_mask(input_ids, input_ids)[0][0], input_ids[0])
Output:
(tensor([False, False, False, False, False, False, False, False, False, False,
         False, False, False,  True,  True,  True,  True,  True,  True,  True,
          True,  True,  True,  True,  True,  True,  True,  True,  True,  True]),
 tensor([ 1,  3, 26, 21, 14, 16, 12,  4,  2, 27,  3, 22,  2,  0,  0,  0,  0,  0,
          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0]))

编码器

编码器有两个主要组件:

  • 多头注意力
  • 位置式前馈网络。

编码器的工作是从输入和注意屏蔽中找到表示和模式。

class EncoderLayer(nn.Module):
   def __init__(self):
       super(EncoderLayer, self).__init__()
       self.enc_self_attn = MultiHeadAttention()
       self.pos_ffn = PoswiseFeedForwardNet()

   def forward(self, enc_inputs, enc_self_attn_mask):
       enc_outputs, attn = self.enc_self_attn(enc_inputs, enc_inputs, enc_inputs, enc_self_attn_mask) 
       enc_outputs = self.pos_ffn(enc_outputs) 
       return enc_outputs, attn

多头关注

这是编码器的第一个主要组件。

注意力模型有三个输入:查询键、

我强烈推荐你阅读杰伊·阿拉姆马的《变形金刚》,它深入地解释了注意力模型。

*多头注意力需要四个输入:查询值、注意力屏蔽。嵌入作为输入提供给查询、键和值参数,而注意掩码作为输入提供给注意掩码参数。
这三个输入和注意屏蔽用点积运算操作,产生两个输出:上下文向量注意。然后上下文向量通过一个线性层,最后产生输出。

class MultiHeadAttention(nn.Module):
   def __init__(self):
       super(MultiHeadAttention, self).__init__()
       self.W_Q = nn.Linear(d_model, d_k * n_heads)
       self.W_K = nn.Linear(d_model, d_k * n_heads)
       self.W_V = nn.Linear(d_model, d_v * n_heads)

   def forward(self, Q, K, V, attn_mask):

       residual, batch_size = Q, Q.size(0)

       q_s = self.W_Q(Q).view(batch_size, -1, n_heads, d_k).transpose(1,2)  
       k_s = self.W_K(K).view(batch_size, -1, n_heads, d_k).transpose(1,2)  
       v_s = self.W_V(V).view(batch_size, -1, n_heads, d_v).transpose(1,2)  

       attn_mask = attn_mask.unsqueeze(1).repeat(1, n_heads, 1, 1) 

       context, attn = ScaledDotProductAttention()(q_s, k_s, v_s, attn_mask)
       context = context.transpose(1, 2).contiguous().view(batch_size, -1, n_heads * d_v) 
       output = nn.Linear(n_heads * d_v, d_model)(context)

return nn.LayerNorm(d_model)(output + residual), attn 

现在,让我们来探索这种成比例的点积注意力:

  • 缩放的点积注意类有四个参数:查询、键、值和注意掩码。本质上,前三个参数由单词嵌入提供,而注意力屏蔽参数由注意力屏蔽嵌入提供。
  • 然后,它在查询之间进行矩阵乘法,以获得分数。

接下来我们使用 scores.masked_fill_(attn_mask,-1e9)。该属性用-1e9 填充 scores 的元素,其中注意力掩码为,而其余元素得到一个注意力分数,该分数然后通过 softmax 函数传递,该函数给出 0 到 1 之间的分数。最后,我们执行注意力和值之间的矩阵乘法,这给出了上下文向量。

class ScaledDotProductAttention(nn.Module):
   def __init__(self):
       super(ScaledDotProductAttention, self).__init__()

   def forward(self, Q, K, V, attn_mask):
       scores = torch.matmul(Q, K.transpose(-1, -2)) / np.sqrt(d_k) 
       scores.masked_fill_(attn_mask, -1e9) 
       attn = nn.Softmax(dim=-1)(scores)
       context = torch.matmul(attn, V)
       return score, context, attn
emb = Embedding()
embeds = emb(input_ids, segment_ids)

attenM = get_attn_pad_mask(input_ids, input_ids)

SDPA= ScaledDotProductAttention()(embeds, embeds, embeds, attenM)

S, C, A = SDPA

print('Masks',masks[0][0])
print()
print('Scores: ', S[0][0],'nnAttention Scores after softmax: ', A[0][0])
Output:

Masks tensor([False, False, False, False, False, False, False, False, False, False,
        False, False, False,  True,  True,  True,  True,  True,  True,  True,
         True,  True,  True,  True,  True,  True,  True,  True,  True,  True])

Scores:  tensor([ 9.6000e+01,  3.1570e+01,  2.9415e+01,  3.3990e+01,  3.7752e+01,
         3.7363e+01,  3.1683e+01,  3.2156e+01,  3.5942e+01, -2.4670e+00,
        -2.2461e+00, -8.1908e+00, -2.1571e+00, -1.0000e+09, -1.0000e+09,
        -1.0000e+09, -1.0000e+09, -1.0000e+09, -1.0000e+09, -1.0000e+09,
        -1.0000e+09, -1.0000e+09, -1.0000e+09, -1.0000e+09, -1.0000e+09,
        -1.0000e+09, -1.0000e+09, -1.0000e+09, -1.0000e+09, -1.0000e+09],
       grad_fn=<SelectBackward>)

Attention Scores after softmax::  tensor([1.0000e+00, 1.0440e-28, 1.2090e-29, 1.1732e-27, 5.0495e-26, 3.4218e-26,
        1.1689e-28, 1.8746e-28, 8.2677e-27, 1.7236e-43, 2.1440e-43, 0.0000e+00,
        2.3542e-43, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,
        0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,
        0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00],
       grad_fn=<SelectBackward>)

位置式前馈网络

multihead 的输出进入前馈网络,构成编码器部分。

让我们喘口气,复习一下到目前为止我们所学的内容:

  • 输入进入嵌入和注意功能。两者都被馈送到具有多头功能和前馈网络的编码器中。
  • 多头功能本身具有使用点积操作来操作嵌入和注意力屏蔽的功能。

BERT building model

Source: Author

组装所有组件

让我们从我们离开的地方继续,即编码器的输出。

编码器产生两个输出:

  • 一个来自前馈层,并且
  • 注意力面具。

请记住,BERT 并没有明确使用解码器。相反,它使用输出和注意力屏蔽来获得想要的结果。

虽然变压器中的解码器部分被替换为浅网络,该浅网络可用于分类,如下面的代码所示。
同样,BERT 输出两个结果:一个是针对分类器的,另一个是针对屏蔽的。

class BERT(nn.Module):
   def __init__(self):
       super(BERT, self).__init__()
       self.embedding = Embedding()
       self.layers = nn.ModuleList([EncoderLayer() for _ in range(n_layers)])
       self.fc = nn.Linear(d_model, d_model)
       self.activ1 = nn.Tanh()
       self.linear = nn.Linear(d_model, d_model)
       self.activ2 = gelu
       self.norm = nn.LayerNorm(d_model)
       self.classifier = nn.Linear(d_model, 2)

       embed_weight = self.embedding.tok_embed.weight
       n_vocab, n_dim = embed_weight.size()
       self.decoder = nn.Linear(n_dim, n_vocab, bias=False)
       self.decoder.weight = embed_weight
       self.decoder_bias = nn.Parameter(torch.zeros(n_vocab))

   def forward(self, input_ids, segment_ids, masked_pos):
       output = self.embedding(input_ids, segment_ids)
       enc_self_attn_mask = get_attn_pad_mask(input_ids, input_ids)
       for layer in self.layers:
           output, enc_self_attn = layer(output, enc_self_attn_mask)

       h_pooled = self.activ1(self.fc(output[:, 0])) 
       logits_clsf = self.classifier(h_pooled) 

       masked_pos = masked_pos[:, :, None].expand(-1, -1, output.size(-1)) 

       h_masked = torch.gather(output, 1, masked_pos) 
       h_masked = self.norm(self.activ2(self.linear(h_masked)))
       logits_lm = self.decoder(h_masked) + self.decoder_bias 

       return logits_lm, logits_clsf

需要记住的几件事:

  1. 您可以指定编码器的数量。在原始论文中,基本模型有 12 个。
  2. 有两个激活函数:Tanh 和 GELU(GaussianErrorLlinearUnit)。
def gelu(x):
   return x * 0.5 * (1.0 + torch.erf(x / math.sqrt(2.0)))

损失和优化

虽然原始论文计算了所有词汇的概率分布,但我们可以使用 softmax 近似值。但是一个简单的方法是使用 交叉熵损失 。它是 softmax负对数似然的组合。

因此,在构建模型时,您不必包括 softmax,而是从没有 softmax 归一化的前馈神经网络获得清晰的输出。

说到优化,我们将使用 Adam 优化器。

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

培养

最后,我们将开始训练。

model = BERT()
batch = make_batch()
input_ids, segment_ids, masked_tokens, masked_pos, isNext = map(torch.LongTensor, zip(*batch))

   for epoch in range(100):
       optimizer.zero_grad()
       logits_lm, logits_clsf = model(input_ids, segment_ids, masked_pos)
       loss_lm = criterion(logits_lm.transpose(1, 2), masked_tokens) 
       loss_lm = (loss_lm.float()).mean()
       loss_clsf = criterion(logits_clsf, isNext) 
       loss = loss_lm + loss_clsf
       if (epoch + 1) % 10 == 0:
           print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.6f}'.format(loss))
       loss.backward()
       optimizer.step()

   input_ids, segment_ids, masked_tokens, masked_pos, isNext = map(torch.LongTensor, zip(batch[0]))
   print(text)
   print([number_dict[w.item()] for w in input_ids[0] if number_dict[w.item()] != '[PAD]'])

   logits_lm, logits_clsf = model(input_ids, segment_ids, masked_pos)
   logits_lm = logits_lm.data.max(2)[1][0].data.numpy()
   print('masked tokens list : ',[pos.item() for pos in masked_tokens[0] if pos.item() != 0])
   print('predict masked tokens list : ',[pos for pos in logits_lm if pos != 0])

   logits_clsf = logits_clsf.data.max(1)[1].data.numpy()[0]
   print('isNext : ', True if isNext else False)
   print('predict isNext : ',True if logits_clsf else False)
Output:

Hello, how are you? I am Romeo.
Hello, Romeo My name is Juliet. Nice to meet you.
Nice meet you too. How are you today?
Great. My baseball team won the competition.
Oh Congratulations, Juliet
Thanks you Romeo
['[CLS]', 'nice', 'meet', 'you', 'too', 'how', 'are', 'you', 'today', '[SEP]', '[MASK]', 'congratulations', '[MASK]', '[SEP]']
masked tokens list :  [27, 22]
predict masked tokens list :  []
isNext :  False
predict isNext :  True

这就是伯特从头开始的编码。如果你在一个大的语料库上训练它,那么你可以使用相同的模型:

  1. 预训练:使用任何语料库,但要使用前面提到的输入表示的精确格式。
  2. 微调:确保你使用监督学习数据。
  3. 不同任务的特征提取器,甚至主题建模。

你可以在这里找到完整的笔记本

有办法得到预训练的模型吗?

在最初的论文中,发布了两个模型:BERT-base 和 BERT-large。在本文中,我展示了如何从头开始编写 BERT 代码。

一般可以下载预训练好的模型,这样就不用经历这些步骤了。Huggingface 库提供了这个特性,你可以使用 Huggingface for PyTorch 的 transformer 库。过程保持不变。

我有一个笔记本,我用了一个来自 Huggingface 的预先训练过的 BERT,你可以在这里查看一下。

当你使用一个预先训练好的模型时,你需要做的就是下载这个模型,然后在一个类中调用它,并使用一个向前的方法来提供你的输入和掩码。

例如:

import transformers

class BERTClassification(nn.Module):
    def __init__ (self):
        super(BERTClassification, self).__init__()
        self.bert = transformers.BertModel.from_pretrained('bert-base-cased')
        self.bert_drop = nn.Dropout(0.4)
        self.out = nn.Linear(768, 1)

    def forward(self, ids, mask, token_type_ids):
        _, pooledOut = self.bert(ids, attention_mask = mask,
                                token_type_ids=token_type_ids)
        bertOut = self.bert_drop(pooledOut)
        output = self.out(bertOut)

        return output

最后的想法

BERT 是一个非常强大的最先进的 NLP 模型。预训练模型是在大型语料库上训练的,您可以根据自己的需要并基于较小数据集上的任务对其进行微调。关于微调的最好的事情是,你不要做 1000 个时期,它甚至可以在 3 到 10 个时期内模仿 SOTA 性能,这取决于参数和数据集处理的好坏。

我希望这个教程是有趣的和有益的。我希望你能从中得到些什么。

资源*

如何比较机器学习模型和算法

原文:https://web.archive.org/web/https://neptune.ai/blog/how-to-compare-machine-learning-models-and-algorithms

机器学习在过去几年里迅速发展。今天,数据科学家和开发人员不再使用简单的、单向的或线性的 ML 管道,而是运行多个并行实验,即使对于大型团队来说,这些实验也可能变得不堪重负。每个实验都应该以一种不变的、可重复的格式记录下来,这就产生了无穷无尽的日志,其中包含了无价的细节。

我们需要通过将机器学习模型与平行实验进行彻底比较来缩小技术范围。使用计划周密的方法对于理解如何选择算法和手头数据的正确组合是必要的。

因此,在本文中,我们将探讨如何比较 ML 模型和算法。

模型选择的挑战

每个模型或任何机器学习算法都有几个以不同方式处理数据的特征。通常,根据之前的实验阶段,输入这些算法的数据也是不同的。但是,由于机器学习团队和开发人员通常会记录他们的实验,因此有足够的数据可供比较。

挑战在于理解哪些参数、数据和元数据必须被考虑以达到最终的选择。这是一个经典的悖论,有大量的细节却不清晰。

更具挑战性的是,我们需要了解一个具有高值的参数,比如说一个较高的度量分数,是否实际上意味着该模型比一个具有较低分数的模型更好,或者它是否只是由统计偏差或错误的度量设计引起的。

比较机器学习算法的目的

比较机器学习算法本身很重要,但有效地比较各种实验也有一些不那么明显的好处。让我们来看看比较的目标:

模型比较和选择的主要目标肯定是机器学习软件/解决方案的更好性能。目标是缩小适合数据和业务需求的最佳算法的范围。

如果选择的模型与训练数据紧密耦合,并且无法解释看不见的数据,则高性能可能是短暂的。因此,找到理解底层数据模式的模型也很重要,这样预测才能持久,并且重新训练的需要最小。

当模型被评估并为比较做准备时,微小的细节和元数据被记录下来,这在再训练时会派上用场。例如,如果开发人员可以清楚地追溯选择模型背后的原因,那么模型失败的原因将会立即显现出来,重新训练可以以相同的速度开始。

有了可用的模型细节,就很容易缩小模型的范围,使其能够提供高处理速度和最佳利用内存资源。同样在生产过程中,需要几个参数来配置机器学习解决方案。拥有生产级别的数据有助于轻松与生产工程师保持一致。此外,了解不同算法的资源需求,也将更容易检查它们相对于组织分配的资产的合规性和可行性。

机器学习算法的参数以及如何比较

让我们深入分析和理解如何比较可用于分类和选择最佳机器学习模型的算法的不同特征。可比参数分为两个高级类别:

  • 基于发展,以及
  • 基于生产的参数。

基于发展的参数

统计测试

在基本层面上,机器学习模型是在多个数据点上高速运行以得出结论的统计方程。因此,对算法进行统计测试对于正确设置算法至关重要,对于了解模型方程是否适合手头的数据集也至关重要。这里有一些流行的统计测试,可以用来为比较奠定基础:

  • 零假设检验:零假设检验用于确定两个数据样本或指标性能的差异是否具有统计显著性或大致相等,以及是否仅由噪声或巧合引起。
  • ANOVA: 方差分析,它类似于线性判别分析,只是它使用一个或多个分类特征和一个连续目标,提供不同组的均值是否相似的统计检验。
  • 卡方:这是一种统计工具或测试,可用于分类特征组,在频率分布的帮助下评估关联或相关的可能性。
  • 学生 t 检验:在标准差未知的情况下,比较正态分布不同样本的平均值或均值,以确定差异是否具有统计显著性。
  • 十重交叉验证:十重交叉验证在不同的数据集上比较每个算法的性能,这些数据集已经配置了相同的随机种子,以保持测试中的一致性。接下来,应该进行假设检验,如学生的配对 t 检验,以验证两个模型之间的指标差异是否具有统计学意义。

下面是如何利用 Neptune 来跟踪假设测试,甚至将它们与吉拉等项目管理工具集成:

模型特征和目标

要为给定的数据集选择最佳的机器学习模型,必须考虑模型的特征或参数。参数和模型目标有助于衡量模型的灵活性、假设和学习风格。

例如,如果比较两个线性回归模型,一个模型可能旨在减少均方误差,而另一个模型可能旨在通过目标函数减少平均绝对误差。为了了解第二个模型是否更适合,我们需要了解数据中的异常值是否会影响结果,或者它们是否不应该影响数据。如果必须考虑异常值或异常值,使用目标函数为平均绝对误差的第二个模型将是正确的选择。

类似地,对于分类,如果考虑两个模型(例如,决策树和随机森林),那么比较的主要基础将是模型能够达到的概括程度。只有一棵树的决策树模型通过 max_depth 参数减少方差的能力有限,而随机森林将具有通过 max_depth 和 n_estimators 参数进行泛化的扩展能力。

可以考虑模型的其他几个行为特征,如模型做出的假设类型、参数化、速度、学习风格(基于树还是基于非树)等等。

平行坐标可用于查看不同的模型参数如何影响指标:

Parallel coordinates comparison plot

Parallel coordinates comparison plot | Source

检查如何使用平行坐标比较来查看模型参数如何影响度量。

学习曲线

学习曲线有助于确定模型是否处于实现偏差-方差权衡的正确学习轨道上。它还为比较不同的机器学习模型提供了基础——在训练集和验证集上都具有稳定学习曲线的模型可能会在更长的时间内在看不见的数据上表现良好。

Bias 是机器学习模型用来使学习过程更容易的假设。方差是估计的目标变量将随着训练数据的变化而变化多少的度量。最终目标是将偏差和方差降低到最小——一种很少假设的高稳定性状态。

偏差和方差是间接成正比的,两者达到最小值的唯一途径是在交点处。了解模型是否实现了显著的权衡的一种方法是,查看它在训练和测试数据集之间的性能是否几乎相似。

跟踪模型训练进度的最好方法是使用学习曲线。这些曲线有助于确定超参数的最佳组合,并在模型选择和模型评估中提供大量帮助。通常,学习曲线是一种在 y 轴上跟踪模型性能的学习或改进,在 x 轴上跟踪时间或经验的方法。

两个最受欢迎的学习曲线是:

  • 培训学习曲线–它有效地绘制了培训过程中随时间变化的评估指标分数,从而有助于跟踪模型在培训过程中的学习或进度。
  • 验证学习曲线–在该曲线中,评估指标分数相对于验证集的时间绘制。

有时可能会发生这样的情况,训练曲线显示出改进,但是验证曲线显示出不良的性能。这表明模型过度拟合,需要恢复到之前的迭代。换句话说,验证学习曲线确定了模型 概括 的程度。

因此,在训练学习曲线和验证学习曲线之间有一个折衷,模型选择技术必须依赖于两条曲线的交叉点和最低点。

你可以在这里看到一个学习曲线的例子:

Training and validation learning curves | Source

查看如何使用图表比较来比较度量或损失的学习曲线。

损失函数和度量

损失函数和度量函数经常混淆。损失函数用于模型优化或模型调整,而度量函数用于模型评估和选择。然而,由于回归精度无法计算,相同的指标用于评估性能以及优化的模型误差。

损失函数作为参数传递给模型,使得模型可以被调整以最小化损失函数。当模型解决了不正确的判断时,损失函数提供了高的惩罚。

回归的损失函数和度量:

  • 均方误差:测量误差或偏差的平方平均值,即估计值和真实值之间的差异。它有助于对异常值施加更高的权重,从而减少过度拟合的问题。
  • 平均绝对误差:估计值与真实值的绝对差值。与均方误差相比,它降低了离群误差的权重。
  • 平滑绝对误差:接近真实值的预测的估计值与真实值的绝对差值,异常值(或远离预测值的点)的估计值与真实值差值的平方。本质上是 MSE 和 MAE 的结合。

Regression loss functions/metrics recorded experiment-wise on neptune.ai | Source

分类损失函数:

  • 0-1 损失函数:这就像统计误分类样本的个数。没什么更多的了。它可以很容易地从混淆矩阵中确定,该矩阵显示了错误分类和正确分类的数量。它旨在惩罚错误分类,并将最小损失分配给正确分类数量最多的解决方案。
  • 铰链损失函数(L2 正则化):铰链损失用于最大间隔分类,最显著的是用于支持向量机 (SVMs)。基本上,它测量两个不同类之间的边距的平方距离,以及平行穿过边距两侧的类中最近点的直线。
  • 逻辑损失:该函数显示出与铰链损失函数相似的收敛速度,由于它是连续的(不同于铰链损失),可以使用梯度下降方法。然而,逻辑损失函数不会对任何点分配零惩罚。相反,对具有高置信度的点进行正确分类的函数受到的惩罚较少。这种结构导致逻辑损失函数对数据中的异常值敏感。
  • 交叉熵/对数损失:衡量分类模型的性能,其输出是 0 到 1 之间的概率值。交叉熵损失随着预测概率偏离实际标签而增加。

还有其他几个损失函数可以用来优化机器学习模型。上面提到的是基本的,为模型设计的发展建立了基础。

分类标准:

对于每个分类模型预测,可以构建一个称为混淆矩阵的矩阵,该矩阵展示了正确和错误分类的测试用例的数量。大概是这样的(考虑到 1–正和 0–负是目标类):

| 实际 0 | 实际 1 | 预测 0 |
| 真阴性(TN) | 假阴性(FN) | 预测 1 |
| 假阳性(FP) | 真阳性(TP) | TN:正确分类的阴性病例数 |

  • TP:正确分类的阳性病例数
  • FN:被错误归类为阴性的阳性病例数
  • FP:正确归类为阳性的阴性病例数
  • 精度

准确性是最简单的度量,可以定义为正确分类的测试用例的数量除以测试用例的总数。

它可以应用于大多数一般问题,但在涉及不平衡数据集时不是很有用。例如,如果我们在银行数据中检测欺诈,欺诈与非欺诈案例的比例可能是 1:99。在这种情况下,如果使用准确性,通过预测所有测试案例为非欺诈,该模型将证明是 99%准确的。

这就是为什么准确性是模型健康的错误指标,对于这种情况,需要一个可以关注欺诈数据点的指标。

精度

精度是用于识别分类正确性的度量。

直观上,这个等式是正确的肯定分类与预测的肯定分类总数的比率。分数越大,精度越高,这意味着模型正确分类正类的能力越强。

回忆

回忆告诉我们在阳性病例总数中正确识别的阳性病例数。

F1 得分

F1 分数是召回率和准确率的调和平均值,因此它平衡了两者的优势。这在召回率和精确度都很重要的情况下很有用——比如识别可能需要修理的飞机部件。在这种情况下,需要精确以节省公司成本(因为飞机零件极其昂贵),需要召回以确保机器稳定且不会对人类生命构成威胁。

AUC-ROC

ROC 曲线是真阳性率(回忆)对假阳性率(TN / (TN+FP))的图。AUC-ROC 代表受试者操作特征下的面积,面积越大,模型性能越好。如果曲线在 50%对角线附近,则表明模型随机预测了输出变量。

基于生产的参数

Metrics and loss plots displayed in Neptune for a particular experiment. Can be tracked for both training and validation sets | Source

到目前为止,我们观察到了在开发阶段优先考虑的可比较的模型特性。让我们深入了解一些以生产为中心的特性,它们可以加快生产和处理时间。

时间复杂度

根据用例的不同,选择模型的决策可以主要集中在时间复杂度上。例如,对于实时解决方案,最好避免 K-NN 分类器,因为它在预测时计算新数据点与训练点的距离,这使它成为一种缓慢的算法。然而,对于需要批处理的解决方案来说,预测速度慢并不是一个大问题。

请注意,在给定所选模型的情况下,训练和测试阶段的时间复杂性可能不同。例如,决策树必须在训练期间估计决策点,而在预测期间,模型必须简单地应用在预先决定的决策点已经可用的条件。因此,如果解决方案需要频繁的重新训练,就像在时序解决方案中一样,选择一个在训练和测试期间都有速度的模型将是正确的选择。

空间复杂性

引用上面的 K-NN 的例子,每次模型需要预测时,它都要将整个训练数据加载到内存中来比较距离。如果训练数据相当大,这可能成为公司资源的昂贵消耗,例如为特定解决方案分配的 RAM 或存储空间。RAM 应该始终有足够的空间用于处理和计算功能。加载大量数据会对解决方案的速度和处理能力产生不利影响。

通过 Neptune 的用户友好的仪表板,可以很容易地跟踪不同实验的资源使用情况,这有助于组织 ML 实验:

线上和线下学习

Details of memory displayed for all recorded experiments | Source

在线学习是指机器学习解决方案可以即时实时更新新数据,而离线学习需要更多时间,并在更新模型参数的同时从头开始重新学习整个训练集。对于实时解决方案,在线学习是最合适的选择。

并行处理能力

并行处理的能力对 K-NN 等耗时算法来说是一个福音,在 K-NN 中,距离计算可以分布在几台机器上。此外,通过分布估计器/树,随机森林模型可以受益于并行处理。然而,对于某些设计为顺序的机器学习模型,如梯度推进,并行处理是不可能的,因为一棵树的结果需要馈送到下一棵树。

最后一个音符

不缺乏可比较的技术来衡量不同机器学习模型的有效性。然而,最重要但经常被忽略的要求是跟踪不同的可比参数,以便可以放心地使用结果,并且可以轻松地再现所选管道。

在本文中,我们探索了一些比较机器学习模型的流行方法,但是这些方法的列表要大得多,所以如果您没有为您的项目找到一个好的方法,请继续寻找!

来源:

【2】【3】——自我引用

[1] [2] [3] – Self citations

如何处理不平衡的分类和回归数据

原文:https://web.archive.org/web/https://neptune.ai/blog/how-to-deal-with-imbalanced-classification-and-regression-data

数据不平衡是现实世界中普遍存在的固有现象。数据通常表现为带有长尾的偏态分布。然而,目前使用的大多数机器学习算法是围绕每个目标类别(分类)均匀分布的假设设计的。

另一方面,我们不能忘记,许多任务涉及连续的目标,甚至无限的值(回归),其中不存在类之间的硬边界(即年龄预测,深度估计,等等)。

Data imbalance

Data imbalance | Source: Author

在本文中,我将向您介绍如何处理分类和回归任务中的不平衡数据,并讨论在这种情况下您可以对每个任务使用的性能度量。

从不平衡数据中学习有 3 种主要方法:

1 数据方法

  • 2 算法方法
  • 3 混合(系综)方法
  • 不平衡分类数据

SMOTE 不平衡分类是一个被充分探索和理解的主题。

在实际应用中,我们面临许多挑战,我们只有不均匀的数据表示,其中少数类通常是更重要的一个,因此我们需要一些方法来提高其识别率。这个问题对预测建模提出了严峻的挑战,因为学习算法将偏向于多数阶级

我们生活中的重要日常任务,如防止恶意攻击、检测威胁生命的疾病或处理监控系统中的罕见情况,都面临着从 1:1000 到 1:5000 的极端类别不平衡,人们必须设计能够调整和克服这种极端偏差的智能系统。

如何处理不平衡的数据集-数据方法

它专注于修改训练集,使其适合标准的学习算法。这可以通过平衡数据集的分布来实现,数据集可以两种方式分类:

How would you handle an imbalanced dataset?

How would you handle an imbalanced dataset? | Source

过采样

  • 欠采样
  • 1.过采样

在这种方法中,我们综合了来自少数民族的新例子。

有几种方法可用于对典型分类问题中使用的数据集进行过采样。但最常见的数据扩充技术被称为合成少数过采样技术或简称为 SMOTE

顾名思义,SMOTE 创建的是“合成”的例子,而不是带有替换的过采样。具体来说,SMOTE 的工作方式如下。它从随机选择一个少数类实例开始,并随机找到它的 k 个最近的少数类邻居。然后,在连接特征空间中的两个示例的线上随机选择的点处创建合成示例。

Scatter plot of the class distribution before and after SMOTE

Scatter plot of the class distribution before and after SMOTE | Source

当被添加到训练集时,为少数类创建的来自 SMOTE 的合成示例平衡了类分布,并使分类器创建更大和更不具体的决策区域,帮助分类器更好地概括并减轻过拟合,而不是创建更小和更具体的区域,这将使模型过拟合多数类。

这种方法受数据扩充技术的启发,该技术在手写字符识别中证明是成功的,其中旋转和倾斜等操作是干扰训练数据的自然方式。

现在,我们来看看 SMOTE 的表现。

从混淆矩阵中,我们可以注意到一些事情:

Confusion matrix of classifiers trained on data synthetic examples and tested on the imbalanced test set

Confusion matrix of classifiers trained on data synthetic examples and tested on the imbalanced test set | Source

在合成例子上训练的分类器概括得很好。

  • 分类器很好地识别少数类(真正的否定)。
  • 与欠采样相比,它们的假阳性更少。
  • 优势
它改善了由随机过采样引起的过拟合,因为生成的是合成样本,而不是现有样本的副本。
  • 没有信息丢失。
  • 很简单。
  • 不足之处
在生成合成示例时,SMOTE 不考虑可能来自其他类的相邻示例。这可能会增加类别的重叠,并会引入额外的噪声。
  • SMOTE 对于高维数据不是很实用。
  • 2.欠采样

在这种方法中,我们减少了来自多数类的样本数量,以匹配少数类的样本数量。

这可以通过几种方式实现:

Scatter plot of the class distribution before and after applying NearMiss-2

Scatter plot of the class distribution before and after applying NearMiss-2 | Source

随机抽样器:从多数类中随机选取几个样本,是平衡数据最简单快捷的方法。

  1. NearMiss :通过实现 3 种不同的试探法,给选中的样本添加一些常识性的规则,但在本文中,我们将只关注其中一种。
  2. NearMiss-2 与三个最远的少数类实例具有最小平均距离的多数类实例。
    • 从混淆矩阵中,我们可以注意到一些事情:

Confusion matrix of classifiers trained on undersampled examples and tested on the imbalanced test set

Confusion matrix of classifiers trained on undersampled examples and tested on the imbalanced test set | Source

在识别多数类(真正值)时,欠采样与过采样相比表现不佳。但除此之外,它比过采样更好地识别少数类,并且具有更少的假阴性。

  • 优势
数据科学家可以平衡数据集,并降低他们的分析或机器学习算法偏向大多数的风险。因为如果不进行重采样,科学家可能会得出所谓的准确性悖论,即他们运行的分类模型具有 90%的准确性。然而,仔细观察,他们会发现结果在很大程度上属于多数阶级。
  • 更少的存储需求和更好的分析运行时间。更少的数据意味着您或您的企业需要更少的存储和时间来获得有价值的见解。
  • 不足之处
移除足够多的多数样本以使多数类的大小与少数类的大小相同或相似会导致大量数据丢失。
  • 所选的多数类样本可能会有偏差,这意味着它可能无法准确代表真实世界,并且分析结果可能不准确。因此,它会导致分类器在真实的看不见的数据上表现不佳。
  • 由于这些缺点,一些科学家可能更喜欢过采样。它不会导致任何信息丢失,并且在某些情况下,可能比欠采样执行得更好。但是过采样也不是完美的。因为过采样通常涉及复制少数事件,所以会导致过拟合。

“SMOTE 和欠采样的组合比普通欠采样的性能更好。”

“The combination of SMOTE and under-sampling performs better than plain under-sampling.”

SMOTE:合成少数过采样技术,2011

为了平衡这些问题,某些情况下可能需要将过采样和欠采样结合起来,以获得最逼真的数据集和准确的结果。

如何处理不平衡数据——算法方法

这种方法集中于修改现有的模型,以减轻它们对多数群体的偏见。这需要对修改的学习算法有很好的洞察力,并精确识别其在学习偏斜分布的表示时失败的原因。

Algorithm approach – best models for imbalanced classification

Algorithm approach – best models for imbalanced classification | Source

最流行的技术是成本敏感方法(加权学习者)。在这里,给定的模型被修改,以纳入不同的惩罚为每一组考虑的例子。换句话说,我们使用焦点损失,在我们的成本函数中,我们将较高的权重分配给少数类,这将惩罚模型对少数类的错误分类,同时减少多数类的权重,使模型更加关注代表性不足的类。从而提高了它在学习过程中的重要性。

另一个有趣的算法级解决方案是应用单类学习或单类分类(简称 OCC),专注于目标群体,创建数据描述。通过这种方式,我们消除了对任何群体的偏见,因为我们只关注一组对象。

OCC 在不平衡分类问题中是有用的,因为它提供了异常值和异常检测的技术。它通过对多数类数据(也称为正例)拟合模型,并预测新数据是属于多数类还是属于少数类(也称为负例),这意味着它是异常值/异常值。

OCC 问题通常是实际的分类任务,其中多数类数据很容易获得,但少数类数据很难、很昂贵,甚至不可能收集,即引擎工作、欺诈交易、计算机系统的入侵检测等等。

如何处理不平衡数据——混合方法

杂交是一种利用单个组件优势的方法。在处理不平衡分类数据时,一些工作提出了混合采样和代价敏感学习。换句话说,结合数据算法的水平接近。这种两阶段训练的想法,即将数据级解决方案与算法级解决方案(即分类器集成)合并,从而产生健壮和高效的学习器,非常受欢迎。

它首先通过应用数据级方法来工作。如您所知,数据级方法通过使用过采样或欠采样来修改训练集,以平衡多数类和少数类之间的类分布。

Example scheme of the hybrid approach

Example scheme of the hybrid approach | Source

然后,使用具有平衡类别分布的预处理数据来训练分类器集成,换句话说,训练多个分类器的集合,从该集合中导出新的分类器,该新的分类器比任何组成分类器执行得更好。因此,创建一个健壮而有效的学习器,它继承了数据级和算法级方法的优点,同时减少了它们的缺点。

从混淆矩阵中,我们可以注意到一些事情:

Confusion matrix of hybrid classifiers trained and tested on the imbalanced test set

Confusion matrix of hybrid classifiers trained and tested on the imbalanced test set | Source

当涉及到识别多数类时,混合分类器比欠采样执行得更好

  • 并且,在识别少数类时,几乎与欠采样和过采样一样好。
  • 基本上是两全其美!

不平衡分类的性能度量

在这一节中,我们回顾了在处理不平衡分类数据时常用的性能指标及其有效性。

混淆矩阵

  • ROC 和 AUC
  • 精确召回
  • f 分数
  • 1.混淆矩阵

对于二进制分类问题,混淆矩阵定义了性能测量的基础。大多数性能指标都来自混淆矩阵,即准确度、误分类率、精确度和召回率。

然而,当数据不平衡时,精度是不合适的。因为该模型可以通过准确预测多数类而对少数类表现不佳来实现更高的准确性,在大多数情况下,少数类是我们最关心的类。

2.ROC 和 AUC 不平衡数据

为了适应少数类别,提出了接收机工作特性(ROC)曲线作为真阳性(TP)率和假阳性(FP)率之间权衡范围的度量。另一个重要的性能指标是曲线下面积(AUC ),这是一个常用的性能指标,用于在单个得分中总结 ROC 曲线。此外,AUC 不偏向于模型在多数或少数类上的表现,这使得这种方法在处理不平衡数据时更合适。

ROC and AUC imbalanced data

*ROC and AUC imbalanced data | Source *

3.精确度和召回率

从混淆矩阵中,我们还可以推导出精度和召回性能指标。

精度对于类不平衡是很重要的,它不受类不平衡的影响,因为它的计算中不包括真负数的数量。

精度和召回率的一个缺点是,与精度一样,在这两者之间可能会有一些不平衡,我们希望提高少数类的 TP,然而,FP 的数量也可以增加。

4.f 分数

为了平衡查全率和查准率,即提高查全率,同时保持较低的查准率,建议将 F 值作为查准率和查全率的调和平均值。

由于 F-score 同等地加权、精确和回忆,并且平衡了这两个问题,它不太可能偏向多数或少数类。【2】

在我为您准备的 Colab 笔记本中,用 3 个不平衡分类方法代码示例检查这个实验。

不平衡回归数据

不平衡数据的回归没有得到很好的探索。此外,许多重要的现实生活应用程序,如经济、危机管理、故障诊断或气象学,要求我们对不平衡数据应用回归,这意味着从输入数据中预测罕见和极端的连续目标值。

**Imbalanced regression data

Imbalanced regression data | Source

因为处理不平衡数据是主要在分类任务的上下文中研究的相关问题,所以在回归的上下文中很少有成熟或合适的策略来处理它。

让我们先来看看不平衡分类中采用的典型方法,然后我们来看看目前使用的一些最好的不平衡回归技术。

不平衡分类采用的方法

数据方法

当谈到不平衡回归的数据方法时,我们有两种受不平衡分类启发很大的技术:

1. SMOTER

SMOTE 是对众所周知的 SMOTE 算法的回归的改编。

它的工作原理是使用原始标签密度定义频繁(多数)和罕见(少数)区域,然后对多数区域应用随机欠采样,对少数区域应用过采样,其中用户必须预先确定 SMOTER 算法要执行的过采样和欠采样的百分比。

当对少数区域进行过采样时,它不仅会生成新的合成样本,还会应用一种组合不同样本的输入和目标的插值策略。准确地说,这种插值使用两种罕见的情况来执行,其中一种情况是种子情况,另一种情况是从种子的 k 个最近邻居中随机选择的。对两种情况的特征进行插值,并将新的目标变量确定为所使用的两种罕见情况的目标变量的加权平均值。

你可能会问,为什么我们必须平均目标变量?请记住,在最初的 SMOTE 算法中,这是一个微不足道的问题,因为所有罕见的情况都具有相同的区域(目标少数区域),但在回归的情况下,答案并不那么微不足道,因为当一对示例用于生成新的合成情况时,它们将不会具有相同的目标变量值。

2.斯穆恩

SMOGN 采用 SMOTER,但它会在 SMOTER 已有的过采样相位之外进一步增加高斯噪声。

SMOGN 算法的关键思想是组合 smote 和高斯噪声策略来生成合成样本,以通过使用引入高斯噪声的更保守的策略来同时限制 smote 可能招致的风险,例如缺乏多样的样本,因为 smote 在插值过程中不会使用最远的样本。其工作方式是,仅当种子样本和所选的 k-最近邻足够接近时,使用 SMOTER 生成新的合成样本,而当两个样本距离较远时,使用高斯噪声。

算法方法

与不平衡分类一样,这种方法也包括调整损失函数以补偿区域不平衡(重新加权)和其他相关的学习范例,如迁移学习、度量学习、两阶段训练和元学习【4】。但我们将重点关注前两个范例:

Algorithm approach

Algorithm approach | Source: Author

错误感知损失

  • 对成本敏感的重新加权
  • 1.错误感知损失
它是用于分类的焦点损失的回归版本,称为 Focal-R。焦点损失是一种动态加权的交叉熵损失,其中随着正确类别的置信度增加,加权因子(alpha)衰减到零。

Focal-R 用一个连续函数来代替加权因子,该函数将绝对误差(L1 距离)映射为 0 到 1 范围内的值。

The focal loss down weights easy examples with a weighting factor of  - (1-  pt)^γ

The focal loss down weights easy examples with a weighting factor of  – (1-  pt)^γ | Source

准确地说,基于 L1 距离的焦 R 损失可以写成:

其中,ei 是第 I 个样本的 L1 误差,σ()是 Sigmoid 函数,β、γ是超参数。

Focal-R loss based on L1 distance

Focal-R loss based on L1 distance | Source

2.对成本敏感的重新加权

由于可以将目标空间划分为有限的仓,所以可以直接插入经典的重新加权方案,例如逆频率加权(INV)及其平方根加权变体(SQINV ),这两种方案都是基于标签分布的。

混合工艺

它遵循不平衡分类的混合方法。

像用于不平衡分类的混合方法一样,不平衡回归混合方法也结合了数据级和算法级方法,以便产生健壮和高效的学习器。

这种方法的一个例子是基于 Bagging 的集合。

基于 Bagging 的集成

该算法结合了数据预处理策略,以解决回归任务中的不平衡域。

确切地说,一篇题为“REBAGG:不平衡回归的重采样 BAGGing”的论文提出了一种算法,该算法在生成的模型上获得多样性,同时使它们偏向最少表示和更重要的情况。

它有两个主要步骤:

使用训练集的预处理样本建立多个模型。

  1. 通过应用平均策略(基本上是平均模型的预测以获得最终预测),使用训练好的模型来获得对看不见的数据的预测。
  2. 关于第一步,作者开发了四种主要类型的重采样方法来应用于原始训练集:平衡平衡。贴片变异T7、变异。SMT** 。这些方法的主要区别在于:**

I)在新样本中使用的少数和多数样本之间的比率;而且,

ii)如何获得新的少数样本。

在标有前缀“balance”的重采样方法中,新的修改后的训练集将具有相同数量的少数和多数样本。另一方面,对于带有前缀“变化”的重采样方法,新训练集中少数样本与多数样本的比率将会变化。

当重采样方法没有附加后缀时,则通过使用随机选择的少数样本的精确副本来获得少数区域的新合成样本。并且当添加后缀“SMT”时,使用 SMOTER 算法获得少数区域的新合成示例。

深度不平衡回归

不平衡分类工作采用的方法;然而,单独使用它们有几个缺点。

请允许我打个比方!

上述数据集具有本质上不同的标签空间:( a) CIFAR-100 展示分类标签空间,其中目标是类别索引,而(b) IMDB-WIKI 展示连续标签空间,其中目标是年龄。

Figure 1. Comparison on the test error distribution (bottom) using the same training label distribution (top) on two different datasets

Figure 1. Comparison on the test error distribution (bottom) using the same training label distribution (top) on two different datasets | Source

如您所见,两者的标签密度分布相同,但误差分布却大不相同。IMDB-WIKI 的误差分布更加平滑,并且与标签密度分布没有很好的相关性,这影响了不平衡学习方法的工作方式,因为它们直接或间接地通过补偿经验标签密度分布中的不平衡来工作。这种方法适用于不平衡分类,但不适用于连续标签。相反,你必须找到一种平滑标签分布的方法。

不平衡数据密度估计的标签分布平滑法

从上面的图 2 中我们可以看到,在连续空间中,经验标签分布与真实的标签密度分布不匹配。这是为什么呢?由于邻近标签处的数据样本之间的相关性,在这种情况下,我们讨论的是相近年龄的图像。

Figure 2. Label distribution smoothing(LDS) convolves a symmetric kernel with the empirical label density to estimate the effective label density distribution that accounts for the continuity of labels

Figure 2. Label distribution smoothing (LDS) convolves a symmetric kernel with the empirical label density to estimate the effective label density distribution that accounts for the continuity of labels | Source

LDS 使用核密度估计来学习对应于连续目标的数据集中的有效不平衡。准确地说,LDS 将对称核与经验密度分布进行卷积,以提取核平滑版本,该版本考虑了附近标签的数据样本信息中的重叠。

注意:高斯或拉普拉斯核是对称核。

对称核表征了目标值 y’和 y’之间的相似性,以及它们在目标空间中的距离。

本节开头的图 2 显示了 LDS 捕获了影响回归的实际不平衡。通过应用 LDS,我们得到了与误差分布(-0.83)很好相关的标签密度分布。

一旦获得了有效的标签密度,就可以使用我们之前讨论过的用于解决不平衡分类的技术(即成本敏感的重新加权方法)。

特征分布平滑(FDS)

上图显示了 30 岁(主播)的特征统计相似度。你可以马上注意到锚周围的箱子与锚高度相似,尤其是最近的那些。但是进一步研究该图,您会注意到数据样本非常少的地区(即 0-6 岁)存在一个问题。由于数据不平衡,平均值和方差显示了与 30 岁的不合理的高度相似性。

Feature distribution smoothing (FDS)

Top: Cosine similarity of the feature means at a particular age w.r.t its value at the anchor age. Bottom: Cosine similarity of the feature variance at a particular age w.r.t its value at the anchor age. The color of the background refers to data density in a particular target range | Source

特征分布平滑(FDS)算法的创造者受到这些观察的启发,提出了这种算法,该算法在特征空间上执行分布平滑,或者换句话说,在附近的目标箱之间传输特征统计。从而校准特征分布的潜在有偏估计,特别是对于训练数据中未充分表示的目标值。

FDS 的一个伟大之处在于,您可以通过在最终特征地图后插入特征校准层,将其集成到深度神经网络中。

Feature distribution smoothing (FDS)

Feature distribution smoothing (FDS) | Source

标杆管理

使用各种算法在语义文本相似性基准(STS-B-DIR)数据集上报告了结果。

Benchmarking results on STS-B-DIR

Benchmarking results on STS-B-DIR | Source

作者表明,当 LDS 和 FDS 与其他现有方法相结合来处理不平衡数据的回归时,可以显著提高性能【4】

不平衡回归的性能度量

当谈到这类问题的评估指标时,您可以使用常见的回归指标,如 MAE、MSE、Pearson、几何平均(GM)以及我们在本节中探讨的技术。

开发不平衡回归的新方法时需要解决的关键问题

开发对成本敏感的回归解决方案,使成本适应稀有观测的重要程度。为了在预测不同重要性的罕见事件时有更大的灵活性,调查使成本不仅适用于少数群体而且适用于每个个体观察的可能性将是相当有趣的。

  • 必须提出能够区分少数样本和噪声样本的方法。
  • 开发更好的集成学习方法,如在分类中,可以在对偏斜分布的鲁棒性和预测能力方面提供显著的改进。
  • 结论

规范的 ML 算法假设所考虑的类中的对象数量大致相似。然而,在我们可以应用 ML 的许多现实生活问题中,实例的分布是偏斜的,因为我们最关心并想要预测的事件很少发生,并且在大多数情况下,我们收集代表正常状态和多数群体的正常事件的数据点。这对学习算法造成了困难,因为它们会偏向多数群体。

但是在本文中,您了解了从不平衡分类和回归数据中学习的不同方法。

感谢您的阅读!和往常一样,我有一个经过充分研究的参考部分,你可以用它来更深入地阅读下面的内容,还有一个 colab 笔记本

参考

卡努马王子

Neptune . ai

ML/DL 开发者倡导者我想通过技术帮助人们。因为这个目的,我喜欢运用我的技术和分析能力来解决具有挑战性的问题,并与你,我的读者,分享我的一点知识和经验。

阅读下一篇


利用机器学习项目改善工作流程的最佳 7 种数据版本控制工具

5 分钟阅读| Jakub Czakon |年 10 月 20 日更新

5 mins read | Jakub Czakon | Updated October 20th, 2021

跟踪所有用于模型和实验的数据并不容易。这需要很多时间,而且不仅仅是管理和跟踪文件。你需要确保每个人都在同一个页面上,并同时跟踪最新版本的变化。

使用正确的软件,你可以毫不费力地做到这一点!一个好的数据版本控制工具可以让你拥有一个统一的数据集和一个强大的实验库。

它还将实现所有团队成员之间的顺畅协作,因此每个人都可以实时跟踪变化,并始终知道发生了什么。

这是系统化数据版本控制、改进工作流程和最小化出错风险的好方法。

因此,请查看这些用于数据版本控制的顶级工具,它们可以帮助您实现工作自动化并优化流程。

如果您关心可再现性、可追溯性和 ML 模型血统,那么数据版本化工具对您的工作流程至关重要。

它们帮助您获得一个工件的版本,一个数据集或模型的散列,您可以在以后使用它来识别和比较。通常,您会将此数据版本记录到您的元数据管理解决方案中,以确保您的模型训练是版本化的和可重复的。

如何选择数据版本化工具?

要为您的工作流选择合适的数据版本化工具,您应该检查:

支持您的数据形态:它是如何支持视频/音频的?它是否为表格数据提供了一些预览?

  • 易用性:在你的工作流程中使用起来有多容易?它给你的执行增加了多少开销?
  • Diff and compare :可以比较数据集吗?你能看到你的图像目录的不同吗?
  • 它与您的堆栈配合得如何:您能否轻松连接到您的基础设施、平台或模型培训工作流?
  • 你能让你的团队参与进来吗:如果你的团队不采用它,工具再好也没用。所以,记住你的队友的技能和偏好。
  • 这里有一些值得探索的工具。

Here’re are a few tools worth exploring.

Continue reading ->


如何实现客户流失预测【程序员机器学习指南】

原文:https://web.archive.org/web/https://neptune.ai/blog/how-to-implement-customer-churn-prediction

当谈到机器学习的有用商业应用时,没有比客户流失预测更好的了。这是一个你通常有大量高质量、新鲜的数据要处理的问题,它相对简单,解决它可以是增加利润的一个很好的方法。

流失率是衡量客户满意度的关键指标。低流失率意味着快乐的顾客;高流失率意味着客户会离开你。随着时间的推移,每月/每季度的客户流失率会有所下降。1%的月流失率很快就转化为近 12%的年流失率。

据福布斯报道,获得新客户比保持现有客户需要更多的钱(最多五倍)。客户流失告诉你有多少现有客户正在离开你的企业,因此降低客户流失对你的收入流有很大的积极影响。

客户流失是增长潜力的一个很好的指标。流失率跟踪失去的客户,增长率跟踪新客户—比较和分析这两个指标可以准确地告诉您随着时间的推移,您的业务增长了多少。如果增长率高于流失率,你可以说你的业务在增长。如果流失率高于增长率,你的企业就越来越小。

在本文中,我们将深入探讨客户流失率,并实现一个机器学习客户流失率预测系统的示例。

流失率是多少?

维基百科称,“流失率”(也称为损耗率)衡量的是在特定时期内从一个集体群体中移出的个人或物品的数量。它适用于许多情况,但对流失率的主流理解与停止从你这里购买的客户的业务案例有关。

软件即服务(SaaS)凭借其基于订阅的业务模式和基于会员制的业务,处于创新型客户维系战略的前沿。分析这一领域的增长可能涉及跟踪指标(如收入、新客户比率等。),进行客户细分分析,预测终身价值。流失率是客户终身价值建模的一个输入,指导对与客户的整个未来关系贡献的净利润的估计。独立地,它计算在给定的时间框架内客户对服务或产品的订阅的不连续性的百分比。

这转化为因客户取消而造成的收入损失。市场饱和在 SaaS 市场相当明显,任何 SaaS 产品总是有大量的替代品。研究流失率有助于了解你的客户(KYC)和订阅驱动型企业的有效保留和营销策略。

杰夫·贝索斯曾经说过:“我们把顾客视为聚会的客人,而我们是主人。我们每天的工作就是让客户体验的每个重要方面都变得更好。提高客户保持率是一个持续的过程,了解流失率是朝着正确方向迈出的第一步。

您可以将客户流失分为:

  1. 客户和收入流失
  2. 自愿和非自愿流失

客户和收入流失:客户流失就是客户取消订阅的比率。也称为用户流失或徽标流失,其价值以百分比表示。另一方面,收入流失是月初你每月经常性收入(MRR)的损失。客户流失和收入流失并不总是一样的。你可能没有客户流失,但如果客户降级订阅,仍然有收入流失。负流失率是一种理想情况,仅适用于收入流失率。来自现有客户的新收入(通过交叉销售、追加销售和新注册)比你因取消和降级而损失的收入要多。

自愿和非自愿流失:自愿流失是指客户决定取消并采取必要措施退出服务。这可能是因为不满意,或者没有得到他们期望的价值。非自愿流失的发生是由于诸如付款细节过期、服务器错误、资金不足和其他不可预测的困境等情况。

客户满意度、幸福感和忠诚度可以在一定程度上实现,但客户流失将永远是业务的一部分。客户流失可能是因为:

  • 糟糕的客户服务(服务质量、回复率或整体客户体验差),
  • 财务问题(费用和费率),
  • 客户需求变化,
  • 不满意(你的服务没有达到预期),
  • 顾客看不到价值,
  • 客户转向竞争对手,
  • 长期客户不会感到被欣赏。

0%的流失率是不可能的。诀窍是始终保持尽可能低的流失率。

客户流失预测的重要性

流失率的影响显而易见,因此我们需要降低流失率的策略。预测客户流失是针对即将流失的客户开展主动营销活动的好方法。

多亏了大数据,在机器学习的帮助下预测客户流失成为可能。机器学习和数据分析是识别和预测客户流失的强大方法。在客户流失预测过程中,您还会:

  • 识别有风险的客户,
  • 识别客户的棘手问题,
  • 确定降低客户流失率和增加客户保持率的策略/方法。

构建有效客户流失模型的挑战

以下是可能使您难以建立有效客户流失模型的主要挑战:

  • 不准确或混乱的客户数据,
  • 弱摩擦探索性分析,
  • 缺乏信息和领域知识,
  • 缺乏对合适的流失建模方法的一致选择,
  • 选择验证流失模型性能的指标,
  • 服务或产品的业务线(LoB ),
  • 搅动事件审查,
  • 基于驱动客户流失的客户行为模式变化的概念漂移,
  • 不平衡数据(阶级不平衡问题)。

流失预测用例

基于公司的业务线(LoB)、运营工作流程和数据架构,客户流失预测是不同的。预测模型和应用程序必须适合公司的需求、目标和期望。流失预测的一些使用案例包括:

  • 电信(有线或无线网段),
  • 软件即服务提供商(SaaS),
  • 零售市场,
  • 基于订阅的业务(媒体、音乐和视频流服务等。),
  • 金融机构(银行、保险公司、抵押公司等。),
  • 营销,
  • 人力资源管理(员工流动)。

设计流失预测工作流程

构建 ML 驱动的应用程序以预测客户流失的总体范围是标准化 ML 项目结构的一般范围,包括以下步骤:

  1. 定义问题和目标:了解你需要从分析和预测中获得什么样的洞察力是至关重要的。理解问题并收集需求、涉众的痛点和期望。
  2. 建立数据源:接下来,指定建模阶段所需的数据源。一些流行的客户流失数据来源是 CRM 系统、分析服务和客户反馈。
  3. 数据准备、探索和预处理:用于解决问题和建立预测模型的原始历史数据需要转换成适合机器学习算法的格式。这一步骤还可以通过提高数据质量来改善总体结果。
  4. 建模和测试:这涵盖了使用各种机器学习算法的客户流失预测模型的开发和性能验证。
  5. 部署和监控:这是应用机器学习进行流失率预测的最后阶段。在这里,最合适的模型被投入生产。它既可以集成到现有软件中,也可以成为新构建的应用程序的核心。

深度挖掘:电信客户流失预测系统用例

流失率在电信行业(无线和有线服务提供商、卫星电视提供商、互联网提供商等)非常重要。此用例中的流失率提供了业务质量的清晰度,显示了客户对产品或服务的满意度,并允许与竞争对手进行比较,以衡量可接受的流失率水平。

关于数据集

示例数据跟踪一个虚构的电信公司 Telco。这是来自 IBM 开发者平台的客户流失数据,在这里可以得到。它包括一个目标标签,指示客户是否在上个月离开,以及其他相关功能,包括人口统计、每个客户已注册的服务和客户帐户信息。它有 7043 个客户的数据,有 20 个特征。

你可以在我的 Github 上找到这个整个项目

探索性数据分析

让我们批判性地探索数据,以发现模式并可视化特征如何与标签交互(是否流失)。

让我们首先为 EDA 导入库,加载数据,并打印前五行:

import numpy as np 
import pandas as pd 
pd.set_option('display.max_columns', None)

import plotly.express as px 
import matplotlib.pyplot as plt 

data_df = pd.read_csv("../data/churn.csv")

def dataoveriew(df, message):
    print(f'{message}:n')
    print('Number of rows: ', df.shape[0])
    print("nNumber of features:", df.shape[1])
    print("nData Features:")
    print(df.columns.tolist())
    print("nMissing values:", df.isnull().sum().values.sum())
    print("nUnique values:")
    print(df.nunique())

dataoveriew(data_df, 'Overview of the dataset')

数据集有 7043 行和 21 列。

有 17 个分类特征:

  • CustomerID:每个客户的唯一客户 ID
  • 性别:顾客是男性还是女性
  • 老年人:客户是否是老年人(1,0)
  • 合作伙伴:客户是否有合作伙伴(是,否)
  • 受抚养人:客户是否有受抚养人(是,否)
  • 电话服务:客户是否有电话服务(是,否)
  • 多线路:客户是否有多条线路(是,否,无电话服务)
  • 互联网服务:客户的互联网服务提供商(DSL、光纤、否)
  • 在线安全:客户是否有在线安全(是,否,没有互联网服务)
  • OnlineBackup:客户是否有在线备份(是,否,无互联网服务)
  • 设备保护:客户是否有设备保护(是,否,无互联网服务)
  • 技术支持:客户是否有技术支持(是,否,无互联网服务)
  • 流媒体电视:客户是否有流媒体电视(是,否,无互联网服务)
  • 流媒体电影:客户是否有流媒体电影(是,否,无互联网服务)
  • 合同:客户的合同期限(逐月、一年、两年)
  • 无纸账单:客户的合同期限(逐月、一年、两年)
  • 付款方式:客户的付款方式(电子支票、邮寄支票、银行转帐(自动)、信用卡(自动))

接下来,有 3 个数字特征:

  • 任期:客户在公司工作的月数
  • 每月费用:每月向客户收取的金额
  • 总费用:向客户收取的总额

最后,还有一个预测功能:

  • 客户流失:客户是否流失(是或否)

这些功能还可以细分为:

  • 人口统计客户信息:
    • 性别、老年人、伴侣、受抚养人
  • 每位客户已注册的服务:
    • 电话服务,多线路,互联网服务,在线安全,在线备份,设备保护,技术支持,流媒体电视,流媒体电影,
  • 客户账户信息:
    • 任期,合同,无纸账单,付款方式,月费,总费用

让我们探索一下目标变量。

target_instance = data_df["Churn"].value_counts().to_frame()
target_instance = target_instance.reset_index()
target_instance = target_instance.rename(columns={'index': 'Category'})
fig = px.pie(target_instance, values='Churn', names='Category', color_discrete_sequence=["green", "red"],
             title='Distribution of Churn')
fig.show()

Output plot of distribution of churn rate

我们试图预测上个月离开公司的用户。这是一个目标不平衡的二元分类问题。

  • 流失率:否–73.5%
  • 客户流失率:是–26.5%

让我们探索分类特征。

def bar(feature, df=data_df ):

    temp_df = df.groupby([feature, 'Churn']).size().reset_index()
    temp_df = temp_df.rename(columns={0:'Count'})

    value_counts_df = df[feature].value_counts().to_frame().reset_index()
    categories = [cat[1][0] for cat in value_counts_df.iterrows()]

    num_list = [num[1][1] for num in value_counts_df.iterrows()]
    div_list = [element / sum(num_list) for element in num_list]
    percentage = [round(element * 100,1) for element in div_list]

    def num_format(list_instance):
        formatted_str = ''
        for index,num in enumerate(list_instance):
            if index < len(list_instance)-2:
                formatted_str=formatted_str+f'{num}%, ' 
            elif index == len(list_instance)-2:
                formatted_str=formatted_str+f'{num}% & '
            else:
                formatted_str=formatted_str+f'{num}%'
        return formatted_str

    def str_format(list_instance):
        formatted_str = ''
        for index, cat in enumerate(list_instance):
            if index < len(list_instance)-2:
                formatted_str=formatted_str+f'{cat}, '
            elif index == len(list_instance)-2:
                formatted_str=formatted_str+f'{cat} & '
            else:
                formatted_str=formatted_str+f'{cat}'
        return formatted_str

    num_str = num_format(percentage)
    cat_str = str_format(categories)

    fig = px.bar(temp_df, x=feature, y='Count', color='Churn', title=f'Churn rate by {feature}', barmode="group", color_discrete_sequence=["green", "red"])
    fig.add_annotation(
                text=f'Value count of distribution of {cat_str} are<br>{num_str} percentage respectively.',
                align='left',
                showarrow=False,
                xref='paper',
                yref='paper',
                x=1.4,
                y=1.3,
                bordercolor='black',
                borderwidth=1)
    fig.update_layout(

        margin=dict(r=400),
    )

    return fig.show()

现在,让我们画出人口统计特征。

bar('gender')

data_df.loc[data_df.SeniorCitizen==0,'SeniorCitizen'] = "No"   
data_df.loc[data_df.SeniorCitizen==1,'SeniorCitizen'] = "Yes"  
bar('SeniorCitizen')

bar('Partner')

bar('Dependents')

Output plot of the distribution of churn rate by gender

Output plot of the distribution of churn rate by senior citizen

Output plot of the distribution of churn rate by partner

Output plot of the distribution of churn rate by dependents

人口统计分析洞察:性别和伴侣以大致的百分比值均匀分布。女性客户流失的差异略高,但这种微小的差异可以忽略不计。年轻客户(老年人=否)、没有伴侣的客户和没有家属的客户的流失率更高。数据的人口统计部分强调了没有伴侣和受抚养人的 30 岁以上的老年人是可能流失的特定客户群.

接下来,我们来了解一下每位客户已经注册的服务。

bar('PhoneService')
bar('MultipleLines')
bar('InternetService')
bar('OnlineSecurity')
bar('OnlineBackup')
bar('DeviceProtection')
bar('TechSupport')
bar('StreamingTV')
bar('StreamingMovies')

Output plot of the distribution of churn rate by phone service

Output plot of the distribution churn rate by multiple lines

Output plot of the distribution churn rate by internet service

Output plot of the distribution of churn rate by online security service

Output plot of the distribution of churn rate by online backup service

Output plot of the distribution of churn rate by device protection service

Output plot of the distribution of churn rate by technology support service

Output plot of the distribution of churn rate by streaming TV service

*Output plot of the distribution of churn rate by streaming movies *

每位客户已签约 insight 的服务:这些特性显示了他们价值观的显著差异。如果客户没有电话服务,他们就不能有多条线路。约 90.3%的客户拥有电话服务,客户流失率较高。将光纤作为互联网服务的客户更有可能流失。这可能是由于高价格、竞争、客户服务和许多其他原因造成的。光纤服务比 DSL 贵很多,这可能是客户流失的原因之一。拥有在线安全、在线备份、设备保护和技术支持的客户更不可能流失。流媒体服务无法预测客户流失,因为它平均分布在是和否选项中。

是时候探索支付功能了。

bar('Contract')
bar('PaperlessBilling')
bar('PaymentMethod')

Output plot of the distribution of churn rate by contract

Output plot of the distribution of churn rate by paperless billing

Output plot of the distribution of churn rate by payment methods

支付洞察:合同越短,流失率越高。那些有更多延期计划的人在提前取消时会面临额外的障碍。这清楚地解释了公司与其客户建立长期关系的动机。选择无纸化计费的客户流失率更高。约 59.2%的客户使用无纸化计费。使用电子支票支付的客户更容易流失,这种支付方式比其他支付类型更常见。

现在,让我们探索数字特征。

Data_df.dtypes

可以观察到total charges 具有对象数据类型,这意味着它包含字符串组件。我们来换算一下。

try:
    data_df['TotalCharges'] = data_df['TotalCharges'].astype(float)
except ValueError as ve:
    print (ve)

这表示一些空值被存储为空白。让我们将该特征转换为数字格式,同时将这些空字符串空间等同为 NaN,如下所示:

data_df['TotalCharges'] = pd.to_numeric(data_df['TotalCharges'],errors='coerce')

data_df['TotalCharges'] = data_df['TotalCharges'].fillna(data_df['TotalCharges'].median())

接下来,让我们绘制所有数字特征的直方图来了解分布情况。

def hist(feature):
    group_df = data_df.groupby([feature, 'Churn']).size().reset_index()
    group_df = group_df.rename(columns={0: 'Count'})
    fig = px.histogram(group_df, x=feature, y='Count', color='Churn', marginal='box', title=f'Churn rate frequency to {feature} distribution', color_discrete_sequence=["green", "red"])
    fig.show()

对数字特征运行功能,如下所示:

hist('tenure')
hist('MonthlyCharges')
hist('TotalCharges')

Output plot of the histogram on tenure with respect to churn rate

Output plot of the histogram on monthly charges with respect to churn rate

Output plot of the histogram on total charges with respect to churn rate

客户账户信息洞察:任期直方图是正确倾斜的,显示大多数客户只在最初几个月(0-9 个月)与电信公司合作。流失率最高的也是最初几个月(0-9 个月)。75%最终离开电信公司的客户都是在头 30 个月内离开的。月费柱状图显示月费越高的客户流失率越高。这表明折扣和促销可能是吸引顾客留下来的一个原因。

让我们根据分位数将数字特征分成三个部分(低、中和高,以便从中获得更多信息)。

bin_df = pd.DataFrame()

bin_df['tenure_bins'] =  pd.qcut(data_df['tenure'], q=3, labels= ['low', 'medium', 'high'])
bin_df['MonthlyCharges_bins'] =  pd.qcut(data_df['MonthlyCharges'], q=3, labels= ['low', 'medium', 'high'])
bin_df['TotalCharges_bins'] =  pd.qcut(data_df['TotalCharges'], q=3, labels= ['low', 'medium', 'high'])
bin_df['Churn'] = data_df['Churn']

bar('tenure_bins', bin_df)
bar('MonthlyCharges_bins', bin_df)
bar('TotalCharges_bins', bin_df)

Output plot of the distribution of churn rate by binned tenure

Output plot of the distribution of churn rate by binned monthly charges

Output plot of the distribution of churn rate by binned total charges

根据宁滨,低任期和高每月收费箱有更高的流失率,正如前面的分析所支持的。同时,总费用低的仓位流失率较高。

数据预处理

在本节中,我们将获得更多见解,并将数据转换为适合各种机器学习算法的数据表示。

data_df.drop(["customerID"],axis=1,inplace = True)

def binary_map(feature):
    return feature.map({'Yes':1, 'No':0})

data_df['Churn'] = data_df[['Churn']].apply(binary_map)

data_df['gender'] = data_df['gender'].map({'Male':1, 'Female':0})

binary_list = ['SeniorCitizen', 'Partner', 'Dependents', 'PhoneService', 'PaperlessBilling']
data_df[binary_list] = data_df[binary_list].apply(binary_map)

data_df = pd.get_dummies(data_df, drop_first=True)

我们来看看数值之间的相关性

corr = data_df.corr()

fig = px.imshow(corr,width=1000, height=1000)
fig.show()

Customer churn correlation

Output plot of the correlation matrix of numeric features

相关性衡量两个变量之间的线性关系。相关性高的特征更具线性相关性,对因变量的影响几乎相同。所以,当两个特征高度相关时,我们可以去掉其中一个。在我们的情况下,我们可以放弃高度相关的功能,如多线、在线安全、在线备份、设备保护、技术支持、流媒体电视和流媒体电影。

客户流失预测是一个二元分类问题,因为在给定的时间段内,客户要么流失,要么被保留。需要回答两个问题来指导模型的建立:

  1. 哪些特性让客户流失或保留?
  2. 培养一个高性能的模型最重要的特征是什么?

让我们使用广义线性模型(GLM)来获得目标各自特征的一些统计数据。

import statsmodels.api as sm
import statsmodels.formula.api as smf

all_columns = [column.replace(" ", "_").replace("(", "_").replace(")", "_").replace("-", "_") for column in data_df.columns]

data_df.columns = all_columns

glm_columns = [e for e in all_columns if e not in ['customerID', 'Churn']]
glm_columns = ' + '.join(map(str, glm_columns))

glm_model = smf.glm(formula=f'Churn ~ {glm_columns}', data=data_df, family=sm.families.Binomial())
res = glm_model.fit()
print(res.summary())

对于第一个问题,您应该查看(P>|z|)列。如果绝对 p 值小于 0.05,则意味着该特性以统计显著的方式影响客户流失。例如:

  • 老年人
  • 任期
  • 合同
  • 无纸账单等。

关于特征重要性的第二个问题可以通过查看指数系数值来回答。指数系数通过一个单位的变化来估计给定特征的预期流失变化。

np.exp(res.params)

这将输出奇数比率。大于 1 的值表示流失增加。小于 1 的值表示客户流失较少。

所有要素的范围应进行归一化,以便每个要素对最终距离的贡献大致成比例,因此我们进行要素缩放。

from sklearn.preprocessing import MinMaxScaler
sc = MinMaxScaler()
data_df['tenure'] = sc.fit_transform(data_df[['tenure']])
data_df['MonthlyCharges'] = sc.fit_transform(data_df[['MonthlyCharges']])
data_df['TotalCharges'] = sc.fit_transform(data_df[['TotalCharges']])

让我们开始用逻辑回归算法创建一个基线模型,然后用其他机器学习模型进行预测,如支持向量分类器(SVC)、随机森林分类器、决策树分类器和朴素贝叶斯分类器。

from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNB

from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

from sklearn.model_selection import train_test_split
X = data_df.drop('Churn', axis=1)
y = data_df['Churn']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=50)

def modeling(alg, alg_name, params={}):
    model = alg(**params) 
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)

    def print_scores(alg, y_true, y_pred):
        print(alg_name)
        acc_score = accuracy_score(y_true, y_pred)
        print("accuracy: ",acc_score)
        pre_score = precision_score(y_true, y_pred)
        print("precision: ",pre_score)
        rec_score = recall_score(y_true, y_pred)
        print("recall: ",rec_score)
        f_score = f1_score(y_true, y_pred, average='weighted')
        print("f1_score: ",f_score)

    print_scores(alg, y_test, y_pred)
    return model

log_model = modeling(LogisticRegression, 'Logistic Regression')

接下来,我们进行特征选择以使机器学习算法能够更快地训练,降低模型复杂性,增加可解释性,并且如果选择了正确的特征子集,则提高模型准确性。

from sklearn.feature_selection import RFECV
from sklearn.model_selection import StratifiedKFold
log = LogisticRegression()
rfecv = RFECV(estimator=log, cv=StratifiedKFold(10, random_state=50, shuffle=True), scoring="accuracy")
rfecv.fit(X, y)

plt.figure(figsize=(8, 6))
plt.plot(range(1, len(rfecv.grid_scores_)+1), rfecv.grid_scores_)
plt.grid()
plt.xticks(range(1, X.shape[1]+1))
plt.xlabel("Number of Selected Features")
plt.ylabel("CV Score")
plt.title("Recursive Feature Elimination (RFE)")
plt.show()

print("The optimal number of features: {}".format(rfecv.n_features_))

X_rfe = X.iloc[:, rfecv.support_]

print(""X" dimension: {}".format(X.shape))
print(""X" column list:", X.columns.tolist())
print(""X_rfe" dimension: {}".format(X_rfe.shape))
print(""X_rfe" column list:", X_rfe.columns.tolist())

<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; color: rgb(51, 51, 51); background: rgb(248, 248, 248);"><span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;"># Splitting data with optimal features</span>
X_train, X_test, y_train, y_test = train_test_split(X_rfe, y, test_size=<span class="hljs-number" style="color: teal;">0.3</span>, random_state=<span class="hljs-number" style="color: teal;">50</span>)

<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;"># Running logistic regression model</span>
log_model = modeling(LogisticRegression, <span class="hljs-string" style="color: rgb(221, 17, 68);">'Logistic Regression Classification'</span>)
</pre>

svc_model = modeling(SVC, 'SVC Classification')

rf_model = modeling(RandomForestClassifier, "Random Forest Classification")

dt_model = modeling(DecisionTreeClassifier, "Decision Tree Classification")

nb_model = modeling(GaussianNB, "Naive Bayes Classification")

在选定的绩效指标中,逻辑回归算法在所有选定的指标中得分最高。它可以通过各种技术来改进,但是我们将通过超参数调整(随机搜索)来快速改进它。


model = LogisticRegression()

from sklearn.model_selection import RepeatedStratifiedKFold
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)

from scipy.stats import loguniform
space = dict()
space['solver'] = ['newton-cg', 'lbfgs', 'liblinear']
space['penalty'] = ['none', 'l1', 'l2', 'elasticnet']
space['C'] = loguniform(1e-5, 1000)

from sklearn.model_selection import RandomizedSearchCV
search = RandomizedSearchCV(model, space, n_iter=500, scoring='accuracy', n_jobs=-1, cv=cv, random_state=1)

result = search.fit(X_rfe, y)

params = result.best_params_

log_model = modeling(LogisticRegression, 'Logistic Regression Classification', params=params)

模型略有改进。让我们保存这个模型,并使用这个模型开始部署我们的客户流失预测应用程序。

import joblib

filename = 'model.sav'
joblib.dump(log_model, filename)

部署

重要的是部署你的模型,以便可以从其他人(无论是用户、管理人员还是其他系统)可以使用的经过训练的 ML 模型中做出预测。在本节中,我们将使用 Streamlit 。这是,一个开源的 Python 库,它使得为机器学习和数据科学创建和分享漂亮的、定制的 web 应用变得容易。

要部署的应用程序将通过操作用例运行:

  1. 在线预测:这个用例为每个数据点(在本文中是一个客户)逐个生成预测。
  2. 批量预测:该用途用于即时生成一组观察值的预测。

部署脚本如下所示:

import streamlit as st
import pandas as pd
import numpy as np
from PIL import Image

import joblib
model = joblib.load(r"./notebook/model.sav")

from preprocessing import preprocess

def main():

    st.title('Telco Customer Churn Prediction App')

    st.markdown("""
     :dart:  This Streamlit app is made to predict customer churn in a ficitional telecommunication use case.
    The application is functional for both online prediction and batch data prediction. n
    """)
    st.markdown("<h3></h3>", unsafe_allow_html=True)

    image = Image.open('App.jpg')
    add_selectbox = st.sidebar.selectbox(
    "How would you like to predict?", ("Online", "Batch"))
    st.sidebar.info('This app is created to predict Customer Churn')
    st.sidebar.image(image)

    if add_selectbox == "Online":
        st.info("Input data below")

        st.subheader("Demographic data")
        seniorcitizen = st.selectbox('Senior Citizen:', ('Yes', 'No'))
        dependents = st.selectbox('Dependent:', ('Yes', 'No'))
        st.subheader("Payment data")
        tenure = st.slider('Number of months the customer has stayed with the company', min_value=0, max_value=72, value=0)
        contract = st.selectbox('Contract', ('Month-to-month', 'One year', 'Two year'))
        paperlessbilling = st.selectbox('Paperless Billing', ('Yes', 'No'))
        PaymentMethod = st.selectbox('PaymentMethod',('Electronic check', 'Mailed check', 'Bank transfer (automatic)','Credit card (automatic)'))
        monthlycharges = st.number_input('The amount charged to the customer monthly', min_value=0, max_value=150, value=0)
        totalcharges = st.number_input('The total amount charged to the customer',min_value=0, max_value=10000, value=0)

        st.subheader("Services signed up for")
        mutliplelines = st.selectbox("Does the customer have multiple lines",('Yes','No','No phone service'))
        phoneservice = st.selectbox('Phone Service:', ('Yes', 'No'))
        internetservice = st.selectbox("Does the customer have internet service", ('DSL', 'Fiber optic', 'No'))
        onlinesecurity = st.selectbox("Does the customer have online security",('Yes','No','No internet service'))
        onlinebackup = st.selectbox("Does the customer have online backup",('Yes','No','No internet service'))
        techsupport = st.selectbox("Does the customer have technology support", ('Yes','No','No internet service'))
        streamingtv = st.selectbox("Does the customer stream TV", ('Yes','No','No internet service'))
        streamingmovies = st.selectbox("Does the customer stream movies", ('Yes','No','No internet service'))

        data = {
                'SeniorCitizen': seniorcitizen,
                'Dependents': dependents,
                'tenure':tenure,
                'PhoneService': phoneservice,
                'MultipleLines': mutliplelines,
                'InternetService': internetservice,
                'OnlineSecurity': onlinesecurity,
                'OnlineBackup': onlinebackup,
                'TechSupport': techsupport,
                'StreamingTV': streamingtv,
                'StreamingMovies': streamingmovies,
                'Contract': contract,
                'PaperlessBilling': paperlessbilling,
                'PaymentMethod':PaymentMethod,
                'MonthlyCharges': monthlycharges,
                'TotalCharges': totalcharges
                }
        features_df = pd.DataFrame.from_dict([data])
        st.markdown("<h3></h3>", unsafe_allow_html=True)
        st.write('Overview of input is shown below')
        st.markdown("<h3></h3>", unsafe_allow_html=True)
        st.dataframe(features_df)

        preprocess_df = preprocess(features_df, 'Online')

        prediction = model.predict(preprocess_df)

        if st.button('Predict'):
            if prediction == 1:
                st.warning('Yes, the customer will terminate the service.')
            else:
                st.success('No, the customer is happy with Telco Services.')

    else:
        st.subheader("Dataset upload")
        uploaded_file = st.file_uploader("Choose a file")
        if uploaded_file is not None:
            data = pd.read_csv(uploaded_file)

            st.write(data.head())
            st.markdown("<h3></h3>", unsafe_allow_html=True)

            preprocess_df = preprocess(data, "Batch")
            if st.button('Predict'):

                prediction = model.predict(preprocess_df)
                prediction_df = pd.DataFrame(prediction, columns=["Predictions"])
                prediction_df = prediction_df.replace({1:'Yes, the customer will terminate the service.',
                                                    0:'No, the customer is happy with Telco Services.'})

                st.markdown("<h3></h3>", unsafe_allow_html=True)
                st.subheader('Prediction')
                st.write(prediction_df)

if __name__ == '__main__':
        main()

导入到应用脚本中的预处理脚本可以在这里的项目报告中找到。

演示

结论

流失率是订阅型公司的一个重要指标。识别不满意的客户可以帮助经理识别产品或定价计划的弱点、运营问题以及客户的偏好和期望。当你知道了所有这些,就更容易引入主动减少流失的方法。

posted @ 2024-11-01 16:32  绝不原创的飞龙  阅读(12)  评论(0编辑  收藏  举报