每个程序员都应该知道的 40 个算法(四)

原文:zh.annas-archive.org/md5/8ddea683d78e7bd756401ec665273969

译者:飞龙

协议:CC BY-NC-SA 4.0

第十三章:大规模算法

大规模算法旨在解决庞大的复杂问题。大规模算法的特征是由于其数据规模和处理要求的缘故,需要多个执行引擎。本章首先讨论了什么类型的算法最适合并行运行。然后,讨论了与并行化算法相关的问题。接下来,介绍了计算统一设备架构CUDA)架构,并讨论了如何使用单个图形处理单元GPU)或一组 GPU 来加速算法。还讨论了需要对算法进行哪些更改才能有效利用 GPU 的性能。最后,本章讨论了集群计算,并讨论了 Apache Spark 如何创建弹性分布式数据集RDDs)以创建标准算法的极快并行实现。

在本章结束时,您将能够理解与设计大规模算法相关的基本策略。

本章涵盖了以下主题:

  • 大规模算法介绍

  • 并行算法的设计

  • 利用 GPU 的算法

  • 利用集群计算理解算法

  • 如何利用 GPU 运行大规模算法

  • 如何利用集群的能力运行大规模算法

让我们从介绍开始。

大规模算法介绍

人类喜欢受到挑战。几个世纪以来,各种人类创新使我们能够以不同的方式解决真正复杂的问题。从预测蝗虫袭击的下一个目标区域到计算最大的质数,为我们周围的复杂问题提供答案的方法不断发展。随着计算机的出现,我们发现了一种强大的解决复杂算法的新方法。

定义良好的大规模算法

良好设计的大规模算法具有以下两个特征:

  • 它旨在使用现有资源池最佳地处理大量数据和处理需求。

  • 它是可扩展的。随着问题变得更加复杂,它可以通过提供更多资源来处理复杂性。

实现大规模算法的一种最实用的方法是使用分而治之的策略,即将较大的问题分解为可以独立解决的较小问题。

术语

让我们来看看一些用于量化大规模算法质量的术语。

延迟

延迟是执行单个计算所需的端到端时间。如果Compute[1]表示从t[1]开始到t[2]结束的单个计算,则我们可以说以下内容:

延迟 = t[2]-t[1]

吞吐量

在并行计算的背景下,吞吐量是可以同时执行的单个计算的数量。例如,如果在t[1]时,我们可以同时执行四个计算,C[1]C[2]C[3]C[4],那么吞吐量为四。

网络双分带宽

网络中两个相等部分之间的带宽称为网络双分带宽。对于分布式计算要有效工作,这是最重要的参数。如果我们没有足够的网络双分带宽,分布式计算中多个执行引擎的可用性带来的好处将被慢速通信链路所掩盖。

弹性

基础设施对突然增加的处理需求做出反应并通过提供更多资源来满足需求的能力称为弹性。

三大云计算巨头,谷歌、亚马逊和微软可以提供高度弹性的基础设施。由于它们共享资源池的巨大规模,很少有公司有潜力与这三家公司的基础设施弹性相匹敌。

如果基础设施是弹性的,它可以为问题创建可扩展的解决方案。

并行算法的设计

重要的是要注意,并行算法并不是万能的。即使设计最好的并行架构也可能无法达到我们期望的性能。广泛使用的一个定律来设计并行算法是安达尔定律。

安达尔定律

Gene Amdahl 是 20 世纪 60 年代研究并行处理的第一批人之一。他提出了安达尔定律,这个定律至今仍然适用,并可以成为理解设计并行计算解决方案时涉及的各种权衡的基础。安达尔定律可以解释如下:

它基于这样一个概念,即在任何计算过程中,并非所有过程都可以并行执行。将会有一个无法并行化的顺序部分。

让我们看一个具体的例子。假设我们想要读取存储在计算机上的大量文件,并使用这些文件中的数据训练机器学习模型。

整个过程称为 P。很明显,P 可以分为以下两个子过程:

  • P1:扫描目录中的文件,创建与输入文件匹配的文件名列表,并传递它。

  • P2:读取文件,创建数据处理管道,处理文件并训练模型。

进行顺序过程分析

运行P的时间由T[seq]**(P)表示。运行P1P2的时间由TseqTseq表示。很明显,当在单个节点上运行时,我们可以观察到两件事:

  • P2P1完成之前无法开始运行。这由P1 --> P2表示

  • Tseq = Tseq + Tseq

假设 P 在单个节点上运行需要 10 分钟。在这 10 分钟中,P1 需要 2 分钟运行,P2 需要 8 分钟在单个节点上运行。如下图所示:

现在要注意的重要事情是P1的性质是顺序的。我们不能通过并行化来加快它。另一方面,P2可以很容易地分成可以并行运行的并行子任务。因此,我们可以通过并行运行它来加快运行速度。

使用云计算的主要好处是拥有大量资源池,其中许多资源可以并行使用。使用这些资源解决问题的计划称为执行计划。安达尔定律被广泛用于识别给定问题和资源池的瓶颈。

进行并行执行分析

如果我们想要使用多个节点加速P,它只会影响P2,乘以一个大于 1 的因子s>1

过程 P 的加速可以很容易地计算如下:

进程的可并行部分与其总体的比例由b表示,并计算如下:

例如,在前面的情景中,b = 8/10 = 0.8

简化这些方程将给我们安达尔定律:

在这里,我们有以下内容:

  • P是整个过程。

  • bP的可并行部分的比例。

  • s是在P的可并行部分实现的加速。

假设我们计划在三个并行节点上运行过程 P:

  • P1是顺序部分,不能通过使用并行节点来减少。它将保持在 2 秒。

  • P2现在需要 3 秒而不是 9 秒。

因此,P的总运行时间减少到 5 秒,如下图所示:

在前面的例子中,我们可以计算以下内容:

  • n[p] = 处理器的数量 = 3

  • b = 并行部分 = 9/11 = 81.81%

  • s = 速度提升 = 3

现在,让我们看一个典型的图表,解释阿姆达尔定律:

在前面的图表中,我们绘制了不同b值的sn[p]之间的图表。

理解任务粒度

当我们并行化算法时,一个更大的任务被分成多个并行任务。确定任务应该被分成的最佳并行任务数量并不总是直截了当的。如果并行任务太少,我们将无法从并行计算中获得太多好处。如果任务太多,那么将会产生太多的开销。这也是一个被称为任务粒度的挑战。

负载平衡

在并行计算中,调度程序负责选择执行任务的资源。在没有实现最佳负载平衡的情况下,资源无法充分利用。

局部性问题

在并行处理中,应该避免数据的移动。在可能的情况下,应该在数据所在的节点上本地处理数据,否则会降低并行化的质量。

在 Python 中启用并发处理

在 Python 中启用并行处理的最简单方法是克隆一个当前进程,这将启动一个名为子进程的新并发进程。

Python 程序员,虽然不是生物学家,但已经创造了他们自己的克隆过程。就像克隆的羊一样,克隆副本是原始过程的精确副本。

制定多资源处理策略

最初,大规模算法是在称为超级计算机的巨大机器上运行的。这些超级计算机共享相同的内存空间。资源都是本地的——物理上放置在同一台机器上。这意味着各种处理器之间的通信非常快,它们能够通过共同的内存空间共享相同的变量。随着系统的发展和运行大规模算法的需求增长,超级计算机演变成了分布式共享内存DSM),其中每个处理节点都拥有一部分物理内存。最终,发展出了松散耦合的集群,依赖处理节点之间的消息传递。对于大规模算法,我们需要找到多个并行运行的执行引擎来解决复杂的问题:

有三种策略可以拥有多个执行引擎:

  • 向内寻找:利用计算机上已有的资源。使用 GPU 的数百个核心来运行大规模算法。

  • 向外寻找:使用分布式计算来寻找更多的计算资源,这些资源可以共同用于解决手头的大规模问题。

  • 混合策略:使用分布式计算,并在每个节点上使用 GPU 或 GPU 阵列来加速算法的运行。

介绍 CUDA

GPU 最初是为图形处理而设计的。它们被设计来满足处理典型计算机的多媒体数据的优化需求。为此,它们开发了一些特性,使它们与 CPU 有所不同。例如,它们有成千上万的核心,而 CPU 核心数量有限。它们的时钟速度比 CPU 慢得多。GPU 有自己的 DRAM。例如,Nvidia 的 RTX 2080 有 8GB 的 RAM。请注意,GPU 是专门的处理设备,没有通用处理单元的特性,包括中断或寻址设备的手段,例如键盘和鼠标。以下是 GPU 的架构:

GPU 成为主流后不久,数据科学家开始探索 GPU 在高效执行并行操作方面的潜力。由于典型的 GPU 具有数千个 ALU,它有潜力产生数千个并发进程。这使得 GPU 成为优化数据并行计算的架构。因此,能够执行并行计算的算法最适合于 GPU。例如,在视频中进行对象搜索,GPU 的速度至少比 CPU 快 20 倍。图算法在第五章 图算法中讨论过,已知在 GPU 上比在 CPU 上运行得快得多。

为了实现数据科学家充分利用 GPU 进行算法的梦想,Nvidia 在 2007 年创建了一个名为 CUDA 的开源框架,全称为 Compute Unified Device Architecture。CUDA 将 CPU 和 GPU 的工作抽象为主机和设备。主机,即 CPU,负责调用设备,即 GPU。CUDA 架构有各种抽象层,可以表示为以下形式:

请注意,CUDA 在 Nvidia 的 GPU 上运行。它需要在操作系统内核中得到支持。最近,Windows 现在也得到了全面支持。然后,我们有 CUDA Driver API,它充当编程语言 API 和 CUDA 驱动程序之间的桥梁。在顶层,我们支持 C、C+和 Python。

在 CUDA 上设计并行算法

让我们更深入地了解 GPU 如何加速某些处理操作。我们知道,CPU 设计用于顺序执行数据,这导致某些类别的应用程序运行时间显著增加。让我们以处理尺寸为 1,920 x 1,200 的图像为例。可以计算出有 2,204,000 个像素需要处理。顺序处理意味着在传统 CPU 上处理它们需要很长时间。像 Nvidia 的 Tesla 这样的现代 GPU 能够产生惊人数量的 2,204,000 个并行线程来处理像素。对于大多数多媒体应用程序,像素可以独立地进行处理,并且会实现显著加速。如果我们将每个像素映射为一个线程,它们都可以在 O(1)常数时间内进行处理。

但图像处理并不是唯一可以利用数据并行性加速处理的应用。数据并行性可以用于为机器学习库准备数据。事实上,GPU 可以大大减少可并行化算法的执行时间,包括以下内容:

  • 为比特币挖矿

  • 大规模模拟

  • DNA 分析

  • 视频和照片分析

GPU 不适用于单程序,多数据SPMD)。例如,如果我们想要计算一块数据的哈希值,这是一个无法并行运行的单个程序。在这种情况下,GPU 的性能会较慢。

我们想要在 GPU 上运行的代码使用特殊的 CUDA 关键字标记为内核。这些内核用于标记我们打算在 GPU 上并行处理的函数。基于这些内核,GPU 编译器分离出需要在 GPU 和 CPU 上运行的代码。

在 Python 中使用 GPU 进行数据处理

GPU 在多维数据结构的数据处理中非常出色。这些数据结构本质上是可并行化的。让我们看看如何在 Python 中使用 GPU 进行多维数据处理:

  1. 首先,让我们导入所需的 Python 包:
import numpy as np
import cupy as cp
import time
  1. 我们将使用 NumPy 中的多维数组,这是一个传统的使用 CPU 的 Python 包。

  2. 然后,我们使用 CuPy 数组创建一个多维数组,它使用 GPU。然后,我们将比较时间:

### Running at CPU using Numpy
start_time = time.time()
myvar_cpu = np.ones((800,800,800))
end_time = time.time()
print(end_time - start_time)

### Running at GPU using CuPy
start_time = time.time()
myvar_gpu = cp.ones((800,800,800))
cp.cuda.Stream.null.synchronize()
end_time = time.time()
print(end_time - start_time)

如果我们运行这段代码,它将生成以下输出:

请注意,使用 NumPy 创建此数组大约需要 1.13 秒,而使用 CuPy 只需要大约 0.012 秒,这使得在 GPU 中初始化此数组的速度快了 92 倍。

集群计算

集群计算是实现大规模算法并行处理的一种方式。在集群计算中,我们有多个通过高速网络连接的节点。大规模算法被提交为作业。每个作业被分成各种任务,并且每个任务在单独的节点上运行。

Apache Spark 是实现集群计算的最流行方式之一。在 Apache Spark 中,数据被转换为分布式容错数据集,称为Resilient Distributed DatasetsRDDs)。RDDs 是 Apache Spark 的核心抽象。它们是不可变的元素集合,可以并行操作。它们被分割成分区,并分布在节点之间,如下所示:

通过这种并行数据结构,我们可以并行运行算法。

在 Apache Spark 中实现数据处理

让我们看看如何在 Apache Spark 中创建 RDD 并在整个集群上运行分布式处理:

  1. 为此,首先,我们需要创建一个新的 Spark 会话,如下所示:
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName('cloudanum').getOrCreate()
  1. 一旦我们创建了一个 Spark 会话,我们就可以使用 CSV 文件作为 RDD 的来源。然后,我们将运行以下函数-它将创建一个被抽象为名为df的 DataFrame 的 RDD。在 Spark 2.0 中添加了将 RDD 抽象为 DataFrame 的功能,这使得处理数据变得更加容易:
df = spark.read.csv('taxi2.csv',inferSchema=True,header=True)

让我们来看看 DataFrame 的列:

  1. 接下来,我们可以从 DataFrame 创建一个临时表,如下所示:
df.createOrReplaceTempView("main")
  1. 一旦临时表创建完成,我们就可以运行 SQL 语句来处理数据:

需要注意的重要一点是,尽管它看起来像一个常规的 DataFrame,但它只是一个高级数据结构。在幕后,它是将数据分布到整个集群的 RDD。同样,当我们运行 SQL 函数时,在幕后,它们被转换为并行转换器和减少器,并充分利用集群的能力来处理代码。

混合策略

越来越多的人开始使用云计算来运行大规模算法。这为我们提供了结合向外看向内看策略的机会。这可以通过在多个虚拟机中配置一个或多个 GPU 来实现,如下面的屏幕截图所示:

充分利用混合架构是一项非常重要的任务。首先将数据分成多个分区。在每个节点上并行化需要较少数据的计算密集型任务在 GPU 上进行。

总结

在本章中,我们研究了并行算法的设计以及大规模算法的设计问题。我们研究了使用并行计算和 GPU 来实现大规模算法。我们还研究了如何使用 Spark 集群来实现大规模算法。

在本章中,我们了解了与大规模算法相关的问题。我们研究了与并行化算法相关的问题以及在此过程中可能产生的潜在瓶颈。

在下一章中,我们将探讨实现算法的一些实际方面。

第十四章:实际考虑

本书中介绍的一堆算法可以用于解决现实世界问题。本章是关于本书中介绍的算法的一些实际考虑。

本章的组织如下。我们将从介绍开始。然后,我们将介绍算法可解释性的重要主题,即算法内部机制能否以可理解的方式解释的程度。接下来,我们将介绍使用算法的道德和在实施时可能产生偏见的可能性。然后讨论处理 NP 难问题的技术。最后,我们将探讨在选择算法之前应考虑的因素。

在本章结束时,您将了解在使用算法时需要牢记的实际考虑。

在本章中,我们将涵盖以下主题:

  • 介绍实际考虑

  • 算法的可解释性

  • 理解伦理和算法

  • 减少模型中的偏见

  • 解决 NP 难问题

  • 何时使用算法

让我们从介绍开始,

介绍实际考虑

除了设计、开发和测试算法外,在许多情况下,考虑开始依赖机器解决现实世界问题的某些实际方面也很重要,因为这会使解决方案更有用。对于某些算法,我们可能需要考虑可靠地整合预计会在部署算法后继续变化的新重要信息的方法。整合这些新信息会以任何方式改变我们经过良好测试的算法的质量吗?如果是,我们的设计如何处理?然后,对于一些使用全局模式的算法,我们可能需要关注捕捉全球地缘政治局势变化的实时参数。此外,在某些用例中,我们可能需要考虑在使用时强制执行的监管政策,以使解决方案有用。

当我们使用算法解决现实世界问题时,我们在某种程度上依赖机器进行问题解决。即使是最复杂的算法也是基于简化和假设的,并且无法处理意外情况。我们甚至还远远没有完全将关键决策交给我们设计的算法。

例如,谷歌设计的推荐引擎算法最近面临欧盟的监管限制,原因是隐私问题。这些算法可能是其领域中最先进的。但如果被禁止,这些算法实际上可能会变得无用,因为它们无法用于解决它们本应解决的问题。

事实上,不幸的是,算法的实际考虑仍然是在初始设计阶段通常不考虑的事后想法。对于许多用例来说,一旦算法部署并且提供解决方案的短期激动感过去后,使用算法的实际方面和影响将随着时间的推移被发现,并将定义项目的成功或失败。

让我们看一个实际例子,其中不注意实际考虑导致了一家世界顶尖 IT 公司设计的备受关注的项目失败。

一个 AI Twitter 机器人的悲伤故事

让我们来看看 Tay 的经典例子,它是微软于 2016 年创建的第一个 AI Twitter 机器人。由 AI 算法操作,Tay 应该从环境中学习并不断改进自己。不幸的是,在网络空间生活了几天后,Tay 开始从不断发出的种族主义和粗鲁的推文中学习。它很快开始发表冒犯性的推文。尽管它表现出了智能,并迅速学会根据实时事件创建定制推文,但同时,它严重冒犯了人们。微软将其下线并尝试重新调整,但没有成功。微软最终不得不终止该项目。这是一个雄心勃勃的项目的悲伤结局。

请注意,尽管微软内置的智能令人印象深刻,但该公司忽视了部署自学习 Twitter 机器人的实际影响。NLP 和机器学习算法可能是最好的,但由于明显的缺陷,这实际上是一个无用的项目。如今,Tay 已成为忽视允许算法在飞行中学习的实际影响而导致失败的典型案例。Tay 的失败所带来的教训肯定影响了后来几年的 AI 项目。数据科学家也开始更加关注算法的透明度。这将引出下一个主题,探讨使算法透明的需求和方法。

算法的可解释性

黑匣子算法是指其逻辑由于复杂性或逻辑以混乱的方式表示而无法被人类解释的算法。另一方面,白匣子算法是指其逻辑对人类可见和可理解的算法。换句话说,可解释性帮助人类大脑理解算法为何给出特定结果。可解释性的程度是特定算法对人类大脑可理解的程度。许多类别的算法,特别是与机器学习相关的算法,被归类为黑匣子。如果算法用于关键决策,了解算法产生结果的原因可能很重要。将黑匣子算法转换为白匣子算法还可以更好地了解模型的内部工作。可解释的算法将指导医生哪些特征实际上被用来将患者分类为患病或非患病。如果医生对结果有任何疑问,他们可以回头检查这些特定特征的准确性。

机器学习算法和可解释性

算法的可解释性对于机器学习算法非常重要。在许多机器学习应用中,用户被要求相信模型能帮助他们做出决策。在这种情况下,可解释性在需要时提供透明度。

让我们深入研究一个具体的例子。假设我们想使用机器学习来预测波士顿地区房屋价格,基于它们的特征。还假设当地的城市法规只允许我们使用机器学习算法,只要我们能在需要时提供任何预测的详细信息来进行辩解。这些信息是为了审计目的,以确保房地产市场的某些部分不会被人为操纵。使我们的训练模型可解释将提供这些额外信息。

让我们看看实现我们训练模型可解释性的不同选项。

提供可解释性策略

对于机器学习,基本上有两种策略可以为算法提供可解释性:

  • 全球可解释性策略:这是为了提供模型整体的制定细节。

  • 局部可解释性策略: 这是为我们训练模型所做的一个或多个个体预测提供理由。

对于全局可解释性,我们有诸如概念激活向量测试TCAV)之类的技术,用于为图像分类模型提供可解释性。TCAV 依赖于计算方向导数来量化用户定义的概念与图片分类之间的关系程度。例如,它将量化将一个人分类为男性的预测对图片中面部毛发的敏感程度。还有其他全局可解释性策略,如部分依赖图和计算排列重要性,可以帮助解释我们训练模型中的公式。全局和局部可解释性策略都可以是特定于模型的或模型不可知的。特定于模型的策略适用于某些类型的模型,而模型不可知的策略可以应用于各种模型。

以下图表总结了机器学习可解释性的不同策略:

现在,让我们看看如何使用这些策略之一来实施可解释性。

实施可解释性

局部可解释模型不可知解释LIME)是一种模型不可知的方法,可以解释训练模型所做的个体预测。作为模型不可知,它可以解释大多数类型的训练机器学习模型的预测。

LIME 通过对每个实例的输入进行微小更改来解释决策。它可以收集该实例的局部决策边界的影响。它迭代循环以提供每个变量的详细信息。通过查看输出,我们可以看到哪个变量对该实例的影响最大。

让我们看看如何使用 LIME 使我们的房价模型的个体预测变得可解释:

  1. 如果您以前从未使用过 LIME,您需要使用pip安装该软件包:
!pip install lime
  1. 然后,让我们导入我们需要的 Python 软件包:
import sklearn as sk
import numpy as np
from lime.lime_tabular import LimeTabularExplainer as ex
  1. 我们将训练一个能够预测特定城市房价的模型。为此,我们将首先导入存储在housing.pkl文件中的数据集。然后,我们将探索它具有的功能:

基于这些功能,我们需要预测房屋的价格。

  1. 现在,让我们训练模型。我们将使用随机森林回归器来训练模型。首先,我们将数据分为测试和训练分区,然后使用它来训练模型:
from sklearn.ensemble import RandomForestRegressor
X_train, X_test, y_train, y_test = sklearn.model_selection.train_test_split(
    housing.data, housing.target)

regressor = RandomForestRegressor()
regressor.fit(X_train, y_train)
  1. 接下来,让我们识别类别列:
cat_col = [i for i, col in enumerate(housing.data.T)
                        if np.unique(col).size < 10]
  1. 现在,让我们使用所需的配置参数实例化 LIME 解释器。请注意,我们正在指定我们的标签是'price',表示波士顿房屋的价格:
myexplainer = ex(X_train,
    feature_names=housing.feature_names,
    class_names=['price'],
    categorical_features=cat_col,
    mode='regression')
  1. 让我们尝试查看预测的详细信息。首先让我们从 matplotlib 中导入绘图器。
exp = myexplainer.explain_instance(X_test[25], regressor.predict,
        num_features=10)

exp.as_pyplot_figure()
from matplotlib import pyplot as plt
plt.tight_layout()
  1. 由于 LIME 解释器适用于个体预测,我们需要选择要分析的预测。我们已要求解释器解释索引为135的预测的理由:

让我们尝试分析 LIME 的上述解释,它告诉我们以下内容:

  • 个体预测中使用的功能列表:它们在前面的截图中显示在y轴上。

  • 决策中功能的相对重要性: 条形的长度越长,重要性越大。数字的值在x轴上。

  • 每个输入功能对标签的正面或负面影响: 红色条表示负面影响,绿色条表示特定功能的正面影响。

理解伦理和算法

通过算法制定模式可能会直接或间接导致不道德的决策。在设计算法时,很难预见潜在的道德影响的全部范围,特别是对于大规模算法,其中可能涉及多个用户。这使得分析人类主观性的影响变得更加困难。

越来越多的公司将算法的道德分析作为其设计的一部分。但事实是,问题可能直到我们发现一个有问题的用例才会变得明显。

学习算法存在的问题

能够根据不断变化的数据模式进行自我调整的算法被称为学习算法。它们处于实时学习模式,但这种实时学习能力可能具有道德影响。这可能导致它们的学习结果在道德上存在问题。由于它们被创建为处于持续进化阶段,几乎不可能对它们进行持续的道德分析。

随着算法复杂性的增加,要完全理解它们对社会中个人和群体的长期影响变得越来越困难。

理解道德考虑

算法解决方案是没有感情的数学公式。负责开发算法的人有责任确保它们符合我们试图解决的问题周围的道德敏感性。这些算法的道德考虑取决于算法的类型。

例如,让我们看看以下算法及其道德考虑。一些需要仔细考虑道德问题的强大算法的例子如下:

  • 分类算法在社会上的使用决定了个人和群体的塑造和管理方式。

  • 在推荐引擎中使用算法时,可以将简历与求职者(个人和群体)进行匹配。

  • 数据挖掘算法用于从用户那里挖掘信息,并提供给决策者和政府。

  • 政府开始使用机器学习算法来决定是否向申请人发放签证。

因此,算法的道德考虑将取决于使用情况以及它们直接或间接影响的实体。在开始使用算法进行关键决策之前,需要从道德角度进行仔细分析。在接下来的部分中,我们将看到在进行算法的仔细分析时应该牢记的因素。

不确定的证据

用于训练机器学习算法的数据可能没有确凿的证据。例如,在临床试验中,由于有限的可用证据,一种药物的有效性可能无法得到证实。同样,可能存在有限的不确定证据表明某个城市的某个邮政编码更有可能涉及欺诈。我们在基于通过这些有限数据找到的数学模式做出决策时应该谨慎。

基于不确定的证据做出的决定很可能导致不合理的行为。

可追溯性

机器学习算法在训练阶段和测试阶段之间的脱节意味着如果算法造成了一些伤害,很难追踪和调试。此外,当发现算法中存在问题时,很难确定受到影响的人。

误导的证据

算法是数据驱动的公式。垃圾进,垃圾出GIGO)原则意味着算法的结果只能像其基础数据一样可靠。如果数据中存在偏见,它们也会反映在算法中。

不公平的结果

算法的使用可能会对已处于不利地位的脆弱社区和群体造成伤害。

此外,已经证明使用算法分配研究资金在多个场合上对男性人口存在偏见。用于授予移民的算法有时会无意中对脆弱人口群体存在偏见。

尽管使用高质量的数据和复杂的数学公式,如果结果是不公平的,那么整个努力可能会带来更多的伤害而不是好处。

减少模型中的偏见

在当前世界中,基于性别、种族和性取向已知的、有充分记录的一般偏见。这意味着我们收集的数据预计会展现出这些偏见,除非我们处理的是一个在收集数据之前已经努力消除这些偏见的环境。

算法中的所有偏见,直接或间接地都是由人类偏见造成的。人类偏见可以体现在算法使用的数据中,也可以体现在算法本身的制定中。对于遵循CRISP-DM跨行业标准流程)生命周期的典型机器学习项目,该生命周期在第五章中有解释,图算法,偏见看起来像这样:

减少偏见最棘手的部分是首先识别和定位无意识的偏见。

解决 NP-hard 问题

NP-hard 问题在第四章中得到了广泛讨论,设计算法。一些 NP-hard 问题很重要,我们需要设计算法来解决它们。

如果由于其复杂性或可用资源的限制而发现解决 NP-hard 问题似乎是不可能的,我们可以采取以下其中一种方法:

  • 简化问题

  • 定制一个已知解决方案以解决类似问题

  • 使用概率方法

让我们逐一看看它们。

简化问题

我们可以基于某些假设简化问题。解决的问题仍然给出的解决方案并不完美,但仍然具有洞察力和有用。为了使其起作用,所选择的假设应尽可能不受限制。

示例

在回归问题中,特征和标签之间的关系很少是完全线性的。但在我们通常的操作范围内可能是线性的。将关系近似为线性大大简化了算法,并且被广泛使用。但这也引入了一些影响算法准确性的近似。近似和准确性之间的权衡应该被仔细研究,并且应选择适合利益相关者的正确平衡。

定制一个已知解决方案以解决类似问题

如果已知类似问题的解决方案,那么可以将该解决方案用作起点。它可以定制以解决我们正在寻找的问题。机器学习中的迁移学习TL)就是基于这一原则。其思想是使用已经预先训练的模型的推理作为训练算法的起点。

示例

假设我们想要训练一个二元分类器,它可以基于实时视频流使用计算机视觉在企业培训期间区分苹果和 Windows 笔记本电脑。从视频流中,模型开发的第一阶段将是检测不同的物体并确定哪些物体是笔记本电脑。一旦完成,我们可以进入第二阶段,制定可以区分苹果和 Windows 笔记本电脑的规则。

现在,已经有经过良好训练、经过充分测试的开源模型,可以处理这个模型训练的第一阶段。为什么不以它们作为起点,并将推理用于第二阶段,即区分 Windows 和苹果笔记本电脑?这将使我们有一个快速起步,解决方案在第一阶段已经经过充分测试,因此错误更少。

使用概率方法

我们使用概率方法来获得一个相当不错的解决方案,但并非最佳解决方案。当我们在第七章中使用决策树算法来解决给定问题时,解决方案是基于概率方法的。我们没有证明这是一个最佳解决方案,但它是一个相当不错的解决方案,可以为我们在需求定义中规定的约束条件下提供一个有用的答案。

例子

许多机器学习算法从一个随机解决方案开始,然后迭代地改进解决方案。最终的解决方案可能是有效的,但我们无法证明它是最好的。这种方法用于解决复杂问题,以在合理的时间范围内解决它们。这就是为什么对于许多机器学习算法来说,获得可重复的结果的唯一方法是使用相同的种子来使用相同的随机数序列。

何时使用算法

算法就像从业者工具箱中的工具。首先,我们需要了解在给定情况下哪种工具是最好的。有时,我们需要问自己,我们是否有解决问题的解决方案,以及部署解决方案的正确时间是什么。我们需要确定算法的使用是否能够提供一个实际有用的解决方案,而不是其他替代方案。我们需要分析使用算法的效果,从三个方面来看:

  • 成本:能否证明与实施算法相关的成本?

  • 时间:我们的解决方案是否比更简单的替代方案使整个过程更有效?

  • 准确性:我们的解决方案是否比更简单的替代方案产生更准确的结果?

为了选择正确的算法,我们需要找到以下问题的答案:

  • 我们是否可以通过做出假设来简化问题?

  • 我们将如何评估我们的算法?关键指标是什么?

  • 它将如何部署和使用?

  • 它需要解释吗?

  • 我们是否理解了三个重要的非功能性要求-安全性、性能和可用性?

  • 是否有预期的截止日期?

一个实际的例子-黑天鹅事件

算法输入数据,处理并制定它,并解决问题。如果收集的数据是关于一个极具影响力且非常罕见的事件,我们如何使用由该事件生成的数据以及可能导致大爆炸的事件?让我们在本节中探讨这个方面。

纳西姆·塔勒布在他的 2001 年的书《被随机愚弄》中用黑天鹅事件的比喻来代表这些极其罕见的事件。

在黑天鹅首次在野外被发现之前,几个世纪以来,它们被用来代表不可能发生的事情。在它们被发现后,这个术语仍然很受欢迎,但它所代表的含义发生了变化。现在它代表着一些如此罕见以至于无法预测的事情。

塔勒布提供了将事件分类为黑天鹅事件的四个标准。

将事件分类为黑天鹅事件的四个标准

决定罕见事件是否应该被分类为黑天鹅事件有点棘手。一般来说,为了被归类为黑天鹅,它应该符合以下四个标准。

  1. 首先,一旦事件发生,对观察者来说,它必须是一个令人震惊的惊喜,例如在广岛投下原子弹。

  2. 事件应该是一场轰动一时的事件-一场颠覆性的重大事件,比如西班牙流感的爆发。

  3. 一旦事件发生并尘埃落定,作为观察者群体的数据科学家应该意识到实际上这并不是那么令人惊讶。观察者们从未注意到一些重要的线索。如果他们有能力和主动性,黑天鹅事件本来是可以预测的。例如,西班牙流感爆发之前有一些被忽视的线索。此外,曼哈顿计划在原子弹实际投放广岛之前已经运行了多年。观察者群体只是无法将这些线索联系起来。

  4. 当事件发生时,虽然黑天鹅事件的观察者们感到终身的惊讶,但也许有些人对他们来说根本不是什么惊讶。例如,多年来致力于开发原子弹的科学家们,使用原子能从未是一个惊讶,而是一个预期的事件。

将算法应用于黑天鹅事件

黑天鹅事件与算法相关的主要方面有:

  • 有许多复杂的预测算法可用。但如果我们希望使用标准的预测技术来预测黑天鹅事件作为预防措施,那是行不通的。使用这种预测算法只会提供虚假的安全感。

  • 一旦黑天鹅事件发生,通常不可能准确预测其对包括经济、公众和政府问题在内的更广泛社会领域的影响。首先,作为一种罕见事件,我们没有正确的数据来供给算法,也没有掌握我们可能从未探索和理解的更广泛社会领域之间的相关性和相互作用。

  • 需要注意的一点是,黑天鹅事件并不是随机事件。我们只是没有能力关注最终导致这些事件发生的复杂事件。这是算法可以发挥重要作用的领域。我们应该确保在未来有一种策略来预测和检测这些小事件,这些事件随着时间的推移组合在一起产生了黑天鹅事件。

2020 年初的 COVID-19 爆发是我们这个时代最好的黑天鹅事件的例子。

前面的例子显示了首先考虑和理解我们试图解决的问题的细节,然后提出我们可以通过实施基于算法的解决方案来为解决方案做出贡献的重要性。没有全面的分析,如前所述,使用算法可能只能解决复杂问题的一部分,达不到预期。

总结

在本章中,我们了解了在设计算法时应考虑的实际方面。我们探讨了算法可解释性的概念以及我们可以在不同层面提供它的各种方式。我们还研究了算法中潜在的道德问题。最后,我们描述了在选择算法时要考虑的因素。

算法是我们今天所见证的新自动化世界中的引擎。了解、实验和理解使用算法的影响是很重要的。了解它们的优势和局限性以及使用算法的道德影响将在使这个世界成为一个更好的居住地方方面产生深远影响。这本书正是为了在这个不断变化和发展的世界中实现这一重要目标而做出的努力。

posted @ 2024-04-16 15:28  绝不原创的飞龙  阅读(5)  评论(0编辑  收藏  举报