CMU-17-445-AI-驱动的软件工程笔记-全-

CMU 17-445 AI 驱动的软件工程笔记(全)

001:课程概述

在本节课中,我们将要学习AI驱动系统软件工程课程的整体介绍,包括课程目标、结构、预期挑战以及软件工程师与数据科学家在构建此类系统时的不同视角。

课程介绍与期望

欢迎来到本课程的第一讲。这门课程名为“AI驱动系统的软件工程”。在开始之前,我们先确认一下技术设置是否正常,确保大家都能听到声音,并能找到参与互动的界面。

我们希望在课堂上进行大量讨论。如果你之前上过卡内基梅隆大学的软件工程课程,就会知道理解权衡利弊、明白没有唯一正确答案是非常重要的。因此,互动讨论、提问和案例分析是本课程的核心。即使是在线授课,我们也希望尽可能模拟课堂体验。

我们将使用以下机制来促进互动:

  • 你可以使用Zoom聊天功能提问或发表评论。
  • 也可以直接语音提问。
  • 可以举手示意。
  • 助教会协助监控聊天内容。

为了获得更好的体验,建议大家在条件允许的情况下开启摄像头。这能让我们感觉更像在一起学习,减少隔离感。如果你因隐私或其他原因无法开启摄像头,请与我沟通,我们可以协商解决。

建议大家在听课期间保持参与者列表和聊天窗口打开。幻灯片会在课前发布在课程网页上。

课程背景与定位

这是一门相对较新且带有实验性质的课程,这是我第二次讲授,并做了大量修改。我第一次讲授是在去年秋季,当时是出于一种迫切感——我们需要教授如何设计包含越来越多机器学习组件的软件系统,以及如何确保这些系统的质量。

本学期,我将更侧重于软件工程的视角,假设大家有更多的软件工程背景。课程将教授一些数据科学基础知识,并更深入地探讨诸如鲁棒性、公平性以及对机器学习进行特定形式测试等细节。

因为是新课,过程中可能会遇到一些波折。欢迎大家随时反馈,课程的灵活性也允许我们根据大家的兴趣调整内容。

核心主题:两种视角的融合

贯穿整个学期的主题是:构建包含机器学习的系统存在不同的视角。我在此进行大量简化,以便说明:

  • 软件工程师的视角:擅长构建产品。他们关注成本、性能、稳定性、交付时间、可扩展性、错误处理、系统维护与演进,并侧重于安全性、可靠性等问题。目标是构建一个在约束条件下“足够好”并能长期运行的产品。
  • 数据科学家的视角:擅长机器学习、数学和统计。他们专注于在固定数据集上构建和评估模型,致力于将预测准确率提到最高。他们通常在Jupyter Notebook等环境中进行大量原型设计,是特征工程和建模技术的专家。

要构建一个包含机器学习组件的系统,我们通常需要这两类人才。市场曾期望找到同时精通两者的“独角兽”型人才,但这很罕见。本课程的目标,就是为大家提供重叠领域的知识,建立沟通的词汇和概念,让大家理解数据科学家的思维方式及其面临的约束,从而能够从软件工程的角度有效地支持他们,共同协作。

我本人来自软件工程背景,课程也会带有这个视角的偏向。但我们会从零开始讲解必要的数据科学知识,重点是学会如何将数据科学家开发的模型集成到系统中,并思考需要关注哪些问题。

案例研究:转录服务

我们通过一个案例研究来切入主题:一个自动转录服务。

背景:研究人员经常需要访谈,并将录音转为文字进行分析。人工转录耗时费力(1小时访谈需4-5小时转录),而外包给众包平台的价格约为每分钟1-2美元。

机遇:假设你完成了一项研究,开发了一个能出色识别特定领域(如医学、编程)专业术语的语音转文字模型,其性能优于通用模型。你看到了一个商机:建立一个类似众包平台的网站,用户上传音频文件并付费,你的AI模型在后台提供快速、低成本的转录服务。

挑战:如果作为一个初创公司来构建这项服务,你会预见哪些问题?

以下是可能遇到的挑战:

  • 非功能性需求:快速响应时间、存储需求、可扩展性。
  • 数据与模型:寻找合适的训练数据、识别实际发生的错误。
  • 市场竞争:开发周期长,竞争对手可能更快进入市场。
  • 技术复杂性:处理不同方言、口音、非英语语言。
  • 协作问题:软件工程师与数据科学家在特性、沟通、目标(准确率 vs. 成本与部署时间)、工具链、开发环境、模块化结构、错误处理方式上可能存在分歧。

这个案例揭示了构建AI驱动产品时,我们关心的质量属性远不止模型的预测准确率。还包括:

  • 模型更新速度
  • 服务响应速度
  • 系统可扩展性
  • 错误检测与修复能力
  • 模型大小与训练成本
  • 系统可维护性与可调试性

这些质量属性往往是相互冲突的。核心问题在于:我们如何设计一个系统来权衡这些属性,并满足用户需求甚至实现盈利?

课程结构与安排

我将以软件工程的方式教授这门课,重点培养工程判断力,权衡利弊,理解“视情况而定”背后的决策依据。课程注重实践,包含一系列作业。

先修要求

  • 软件工程:具备基础理解,有构建超过100行代码系统的经验,了解版本控制、需求收集、软件设计、测试、持续集成等概念,最好有团队项目经验。
  • 机器学习:无需背景。课程会涵盖必要的基础知识。

课程活动

  • 课堂:保持互动,有讨论和练习。
  • 阅读:有一本指定教材及相关论文、文章。每次课前有阅读测验。
  • 作业:前半部分有一些个人或小规模作业,后半部分是一个大型团队项目(关于质量保障的推荐系统)。
  • 实习课:手把手实践,例如学习Apache Kafka流处理框架和机器学习框架。

评分

  • 包含作业、期中考试、团队项目展示和课堂参与。
  • 课堂参与不仅指出席,更指积极参与讨论。

学术诚信:严禁作弊。如有压力或困难,请务必与我沟通,这远比作弊要好。

核心概念:从“规范”到“目标”

这是经典软件工程与机器学习的一个根本区别。

在经典软件工程中,我们习惯于通过接口规范来思考。规范(无论是API文档还是需求说明)明确描述了组件应有的行为。如果实现与规范不符,我们就称之为“缺陷”。

但在机器学习中,规范的概念瓦解了。我们无法精确写出“转录音频文件”或“推荐商品”的每一步规范。否则,我们直接写算法就行了。我们正是在无法写出规范(因为问题太复杂或我们知识不足)时,才使用机器学习。

因此,机器学习系统只有模糊的目标,例如“在此数据上尽可能准确地预测”。这使得测试变得异常困难。如果一个机器学习组件转录错了单词,这算是一个“缺陷”吗?这改变了我们设计系统的方式:我们不再有清晰的规范,而是在做“尽力而为”的努力,必须学会处理错误,这影响了我们关于系统设计的诸多思考。

总结与预告

本节课我们一起学习了课程的基本框架。我们认识到,要构建实际的AI驱动系统,需要融合数据科学家和软件工程师两种不同的视角与专长。我们关心的质量属性多种多样且常相互冲突。此外,机器学习组件的引入使得传统的基于“规范”的开发与测试范式发生了根本变化。

下节课我们将结束关于“规范”的讨论,并在接下来的两周内,学习机器学习的基础知识,以便为后续课程建立共同的理解基础。

002:机器学习基础与决策树

在本节课中,我们将要学习机器学习的基础概念,特别是监督学习。我们将通过一个简单的决策树例子,来理解机器学习模型是如何从数据中学习的,以及如何评估和避免过拟合与欠拟合问题。

上一节我们介绍了在包含AI组件的软件系统中,数据科学家和软件工程师的不同视角,以及由于缺乏明确规范而带来的挑战。本节中我们来看看机器学习的基础知识,理解其核心工作原理。

机器学习的基本概念

机器学习,在最基本的意义上,是学习一个从输入到输出的函数。

例如,在图像中检测癌症,输入可能是图像的所有像素,输出是“是”或“否”,判断是否存在癌症。转录音频文件时,输入是一段音频,输出是预测的下一个单词。检测垃圾邮件时,输入是经过预处理的电子邮件文本,输出是“垃圾邮件”或“非垃圾邮件”。

我们总是试图学习某种函数。理想情况下,我们会有这个函数的规范说明,但我们没有。我们希望函数的行为能大致符合数据。

在监督学习中,我们通过从带标签的数据中进行归纳来做到这一点。

我们有一堆带标签的数据点。例如,对于房价预测,每一行数据代表一所房子及其属性(如房间数、面积),以及我们知道的结果(房价)。我们想学习一个函数,它既能很好地拟合这些训练数据,又能推广到未见过的数据上。

以下是机器学习中常见的数据结构表示:

# 数据通常以数据框(DataFrame)的形式组织
# 每一行是一个样本(如一所房子),每一列是一个特征(如房间数、面积)
# 最后一列通常是标签(如房价)
data = [
    [1, 750, 300000],
    [5, 2000, 750000],
    # ... 更多数据行
]

决策树学习算法

决策树是理解机器学习工作原理的最简单形式之一。它最终会构建一棵树。例如,对于房价数据集,树可能先判断面积,如果小于某个值,再判断房龄,最后给出该类房子的平均价格。

这种树很容易理解,人类也可能使用类似的规则。它可以写成一系列的 if 语句。

关键问题是:如果我们有一些带标签的数据,如何生成这样一棵树?

我们将使用一个经典的“是否去打高尔夫”的简单数据集来演示。数据包括天气、温度、湿度和是否有风等特征,以及是否去打高尔夫的结果。

学习算法需要做两件事:

  1. 找出所有可能的决策(谓词)。
  2. 从所有可能的决策中,找出最好的一个。

在ID3算法中,使用信息增益来决定哪个是最好的分割属性。信息增益基于的概念。熵衡量序列的混乱程度。如果序列全是“是”或全是“否”,则熵很低(信息很纯)。如果“是”和“否”混合,则熵很高。

算法计算每个可能谓词的信息增益,并选择增益最高的那个。然后,它根据这个最佳谓词分割数据集,并对分割后的每个子集递归地重复这个过程。

以下是递归构建决策树的核心步骤:

def build_tree(data, predicates):
    if 所有数据结果相同 或 没有更多谓词:
        return OutcomeNode(最常见的结果, 置信度)
    best_pred = 找到信息增益最高的谓词
    left_data, right_data = 根据 best_pred 分割数据
    left_tree = build_tree(left_data, 剩余谓词)
    right_tree = build_tree(right_data, 剩余谓词)
    return DecisionNode(best_pred, left_tree, right_tree)

递归过程会在以下情况停止:所有数据的结果相同(全是“是”或全是“否”),或者没有更多谓词可以用来改善分割。

过拟合、欠拟合与超参数

如果只允许树做一次分割(深度很浅),模型可能无法学习到足够的信息,预测能力较弱,这称为欠拟合

如果让树一直生长,直到无法再分,它会尽可能完美地拟合训练数据,但这可能无法很好地推广到新数据,这称为过拟合

控制树生长深度的参数(如最大深度)被称为超参数。超参数是控制学习过程的参数,而模型内部学习到的具体判断条件(如“湿度>高”)被称为模型参数

通过调整超参数(如树的最大深度),我们可以控制模型的复杂度(自由度),从而在欠拟合和过拟合之间找到平衡。

模型评估

评估模型常用的指标是准确率,即正确预测的数量除以总预测数量。

准确率只在有标签的数据上定义。我们需要比较模型的预测结果与已知的正确结果。

但只在训练数据上评估准确率是不够的,那只能说明模型“记住”训练数据的能力。我们真正关心的是模型在未见过的数据上的表现,即泛化能力。

标准的做法是将数据集分割为训练集验证集(或测试集),例如80%的数据用于训练,20%用于验证。我们在训练集上学习模型,然后在验证集上评估其准确率。

以下是数据集分割的示例:

from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(features, labels, test_size=0.2, random_state=42)

通过观察训练集和验证集上的准确率随模型复杂度(如树深度)的变化,可以检测过拟合:训练准确率会持续上升,而验证准确率在达到某一点后会开始下降,下降点就是过拟合的开始。

由于单次数据分割可能具有随机性,更稳健的方法是使用交叉验证。例如,k折交叉验证将数据分成k份,每次用k-1份训练,用剩下的1份验证,重复k次后取平均准确率。

需要警惕的是,如果使用验证集来反复选择和调整超参数,那么验证集实际上也参与了“训练”,可能导致对验证集的过拟合。因此,严谨的做法是将数据分为三部分:训练集(用于训练模型)、验证集(用于调整超参数)、测试集(仅用于最终评估,且只使用一次)。

总结

本节课中我们一起学习了机器学习的基础知识。我们了解到机器学习的核心是学习一个从数据中归纳的函数,而决策树是一个直观的入门示例。我们探讨了模型如何通过递归分割数据来学习,并引入了过拟合欠拟合的关键概念,它们通过超参数(如树深度)来控制。最后,我们学习了评估模型泛化能力的重要性,以及通过训练集/验证集分割交叉验证来可靠评估模型性能的方法。理解这些基础概念对于软件工程师构建和集成可靠的AI组件至关重要。

003:面向软件工程师的人工智能(第二部分)

概述

在本节课中,我们将继续探讨面向软件工程师的人工智能基础。我们将回顾上一讲的内容,深入讨论机器学习项目的完整流程,分析数据科学家的工作方式与软件工程师的差异,并重点介绍深度学习的基本原理,特别是深度神经网络的工作机制。

回顾与衔接

上一节我们介绍了机器学习的基本概念,如决策树、过拟合与欠拟合,以及训练集、验证集和测试集的划分。本节中,我们将首先回顾这些内容,然后探讨构建机器学习模型的完整流程。

机器学习项目流程

机器学习不仅仅是构建一个模型,它涉及一个完整的、可重复的流程。人们通常将机器学习视为一个包含多个阶段的管道。

以下是构建机器学习模型的典型阶段:

  1. 目标与需求定义:明确项目目标,例如预测房屋售价。
  2. 数据收集:从各种来源(如房地产交易网站、公共税务记录)获取相关数据。
  3. 数据清洗:处理缺失值、移除异常值、统一数据格式。
  4. 数据标注:为监督学习任务获取标签,例如从销售记录中获取房价。
  5. 特征工程:从原始数据中提取和构造用于模型训练的特征,如房屋面积、房间数、社区犯罪率。
  6. 模型训练:使用框架和算法(如几行代码调用学习函数)来训练模型。
  7. 模型评估:在测试集或验证集上计算模型的准确率等指标。
  8. 部署与监控:将模型投入生产环境,并持续监控其性能。

在实践中,数据科学家将大量时间花在数据收集、清洗和标注阶段。而需求定义、部署和监控则更多属于软件工程的范畴。

数据科学的工作方式

数据科学家开发模型的方式与软件工程师开发传统应用程序有显著不同。这个过程更具探索性和迭代性。

数据科学工作流程通常如下:

  1. 获取数据。
  2. 准备数据。
  3. 编写分析脚本。
  4. 分析结果。
  5. 调试并重复上述步骤,改进脚本和模型。
  6. 记录结果并进行讨论。
  7. 可能返回收集更多数据或探索其他方案。
  8. 最终发布或产出可用的模型。

研究表明,数据科学家通常从一个准确率较低的初始模型开始,通过不断尝试和改进,在数小时内逐步提升其性能。这个过程是开放式的,类似于研究过程,开始时并不确定最终方案是否可行。

这与软件工程中的螺旋模型或敏捷开发有相似之处,但也存在关键区别:

  • 敏捷开发强调频繁向客户交付可工作的软件,并有明确的迭代周期。
  • 数据科学探索则更侧重于内部实验和验证,直到获得满意的结果后才可能交付。整个过程更具直觉驱动性,难以精确分解为可计划的小任务或预估时间。

开发工具:Jupyter Notebook

为了支持这种探索性工作流程,数据科学家广泛使用Jupyter Notebook等工具。

以下是Notebook流行的原因:

  • 快速反馈:可以分段执行代码并立即看到输出。
  • 增量计算:加载一次数据后,可以只修改和重新运行部分代码单元,无需从头执行。
  • 便于可视化:图表和结果可以直接嵌入在代码旁边。
  • 易于分享:可以将整个分析过程(代码、结果、文本说明)作为一个文档分享。

然而,Notebook也存在一些缺点,尤其是在软件工程最佳实践方面:

  • 版本控制困难:Notebook文件格式(JSON)使得代码差异对比不便。
  • 模块化差:代码通常组织在一个很长的“方法”中,缺乏函数抽象和模块化。
  • 全局状态:变量作用域通常是全局的。
  • 不利于测试:为Notebook代码编写测试用例并不常见。
  • 协作挑战:多人协作修改单个文件不如传统的模块化导入方式方便。

需要理解的是,Notebook的设计初衷是支持快速探索和实验。当项目需要长期维护和投入生产时,通常需要将代码从Notebook迁移到更结构化的环境中。

人工智能与机器学习问题分类

在深入具体技术前,我们先对人工智能领域的术语和问题进行分类。

术语关系

  • 人工智能:最广泛的领域,旨在让计算机表现出智能行为。
  • 机器学习:人工智能的一个子领域,通过数据学习模式。
  • 深度学习:机器学习的一种特定技术,使用深度神经网络。

常见的机器学习问题类型

  • 分类:预测离散的类别标签。例如,识别图片中的鞋子品牌(Nike或Adidas)。
  • 回归:预测连续的数值。例如,预测网约车的到达时间。
  • 概率估计:预测某个事件发生的概率。例如,估计泰坦尼克号乘客的生存概率。
  • 排序:将项目按特定顺序排列。例如,YouTube视频推荐列表。

学习范式

  • 监督学习:使用带有标签的数据进行训练。例如,用已标注的房屋价格数据训练房价预测模型。
  • 无监督学习:使用无标签的数据发现内在结构。例如,对书籍进行聚类分组。
  • 强化学习:智能体通过与环境交互获得的奖励来学习。例如,计算机学习下围棋。

深度学习与神经网络

现在,我们来看一种当前非常流行的机器学习技术:深度学习,特别是深度神经网络。

基本思想

神经网络受到生物大脑神经元网络的启发。基本单元是神经元(节点),它们通过连接(边)传递信号。每个连接有一个权重,每个神经元对输入进行加权求和,并通过一个激活函数(如阶跃函数、ReLU、Sigmoid)决定是否“激活”(输出信号)。

一个简单的神经元计算可以表示为:
输出 = 激活函数(权重1 * 输入1 + 权重2 * 输入2 + 偏置)

从单层到深度网络

将多个神经元组织成层,就形成了神经网络。深度神经网络意味着网络包含多个隐藏层

前向传播过程可以用矩阵运算描述:
第1层输出 = 激活函数(权重矩阵1 * 输入向量 + 偏置向量1)
第2层输出 = 激活函数(权重矩阵2 * 第1层输出 + 偏置向量2)
最终输出 = 激活函数(权重矩阵N * 第N-1层输出 + 偏置向量N)

模型训练:学习权重

模型的参数就是所有这些连接上的权重偏置超参数则是网络架构(如层数、每层神经元数量、激活函数类型),这些是在训练前设定的。

训练过程(反向传播算法)概述:

  1. 随机初始化所有权重和偏置。
  2. 输入一个训练样本,进行前向传播,得到预测输出。
  3. 计算预测输出与真实标签之间的误差。
  4. 从输出层开始,反向逐层计算误差对每个权重的梯度。
  5. 根据梯度方向,微调所有权重和偏置,使误差减小。
  6. 对大量训练样本重复步骤2-5,直到模型性能稳定。

实例与规模

以一个识别10类时尚物品的神经网络为例:

  • 输入:28x28灰度图像(784个像素值)。
  • 架构:784 -> 300 (ReLU) -> 100 (ReLU) -> 10 (Softmax)。
  • 参数量计算
    • 第一层权重:784 * 300 = 235,200
    • 第一层偏置:300
    • 第二层权重:300 * 100 = 30,000
    • 第二层偏置:100
    • 输出层权重:100 * 10 = 1,000
    • 输出层偏置:10
    • 总计约26.6万个参数

现代大型网络规模惊人:

  • 图像分类网络(如ResNet):可能拥有数千万参数,占用数百MB存储空间。
  • 文本生成网络(如GPT系列):可能拥有数十亿参数,占用数十GB存储空间,需要海量数据和数周GPU训练时间。

特点与挑战

深度学习的优势

  • 自动特征提取:能从原始数据(如图像像素、音频波形)中自动学习高层次特征,减少人工特征工程。
  • 处理高维数据:擅长处理输入维度极高的任务。
  • 强大的表达能力:理论上可以近似任意复杂函数。

深度学习的挑战

  • 计算成本高:训练需要大量数据和强大的计算资源(GPU)。
  • 模型复杂度高:参数量巨大,导致模型文件大,预测(推理)时计算量也大。
  • 可解释性差:模型内部如同“黑箱”,难以理解其决策依据。
  • 需要大量数据:通常需要大规模标注数据集才能达到良好性能。

总结

本节课我们一起学习了机器学习项目的完整流程,理解了数据科学家探索式、迭代式的工作方式及其常用工具(如Jupyter Notebook)的利弊。我们深入探讨了深度学习的基本原理,了解到深度神经网络通过多层神经元和权重连接来模拟复杂函数,其训练过程本质上是利用梯度下降法在海量参数中寻找最优解。我们认识到深度学习虽然功能强大,尤其在感知类任务上表现出色,但也伴随着计算成本高、可解释性差和对数据量需求大等挑战。这些知识为我们后续将AI组件集成到软件系统中并考量其工程影响奠定了基础。

004:模型质量 📊

在本节课中,我们将要学习如何评估机器学习模型的质量。我们将从数据科学家的视角出发,了解经典的准确率衡量指标及其适用场景。接着,我们会从软件工程的视角重新审视模型质量,探讨如何借鉴软件测试的思想来评估模型。

概述

上一节我们介绍了机器学习流水线、不同类型的任务以及神经网络的基本工作原理。本节中,我们将聚焦于一个核心问题:如何判断一个模型的好坏?我们将首先学习数据科学家常用的评估指标,然后探讨这些评估方法与软件工程中的测试理念有何异同。

第一部分:预测准确率——数据科学视角

模型评估的基本思想是,将模型在测试数据或验证数据上的预测结果,与已知的正确标签进行比较。

混淆矩阵与基础准确率

对于分类任务,一种常见的评估工具是混淆矩阵(也称为误差矩阵)。它通过对比模型的预测类别和真实类别来展示模型的性能。

以下是混淆矩阵的一个示例,其中包含三个类别(A, B, C):

预测 \ 实际 实际为 A 实际为 B 实际为 C
预测为 A 10 8 2
预测为 B 5 24 3
预测为 C 1 4 82
  • 对角线上的数值(10, 24, 82)代表预测正确的样本数量。
  • 其他位置的数值则代表预测错误的样本数量。

最基础的准确率计算公式为:准确率 = 对角线数值之和 / 所有预测样本总数。在上例中,准确率约为 71%。

然而,单一的准确率数字往往难以解读。它就像被告知“Web服务器响应时间为0.5秒”一样,好坏完全取决于具体场景。

如何解读准确率?

为了更有效地解读准确率,我们可以采用以下两种方法:

  1. 与基线模型比较:将你的模型与一个简单的、无需复杂机器学习即可实现的启发式方法进行比较。例如:

    • 对于癌症预测,基线可以是“永远预测无癌症”(假设癌症罕见)。
    • 对于房价预测,基线可以是“预测该区域的平均房价”。
    • 了解基线模型的性能后,你就能更好地理解“99%准确率”的真正含义。
  2. 关注错误类型:在二分类问题中,区分不同类型的错误至关重要。我们定义:

    • 真正例:实际为真,预测也为真。(例如:有癌症,且预测有癌症)
    • 真反例:实际为假,预测也为假。(例如:无癌症,且预测无癌症)
    • 假正例:实际为假,但预测为真。(例如:无癌症,但预测有癌症)
    • 假反例:实际为真,但预测为假。(例如:有癌症,但预测无癌症)

假正例和假反例的严重性通常不同。在医疗诊断中,漏诊(假反例)可能比误诊(假正例)后果更严重;而在垃圾邮件过滤中,误判正常邮件为垃圾邮件(假正例)可能比漏掉垃圾邮件(假反例)更令人烦恼。

精确率与召回率

为了量化这两种错误,我们引入两个指标:

  • 召回率:在所有实际为正例的样本中,模型正确预测出的比例。公式:召回率 = 真正例 / (真正例 + 假反例)。它衡量了模型的“查全”能力。
  • 精确率:在所有模型预测为正例的样本中,实际为正例的比例。公式:精确率 = 真正例 / (真正例 + 假正例)。它衡量了模型的“查准”能力。

精确率和召回率通常存在此消彼长的关系,这引出了下一个概念:阈值。

阈值与曲线下面积

许多分类器(如逻辑回归、神经网络)输出的不是直接的类别,而是一个介于0和1之间的置信度分数。我们需要设定一个阈值(例如0.5)来决定将哪些预测视为正例。

  • 提高阈值(例如设为0.8)意味着只对高置信度的预测才判定为正例。这通常会提高精确率(因为判定的正例更可能是对的),但会降低召回率(因为一些真正的正例可能因为置信度不够高而被漏掉)。
  • 降低阈值则相反,会提高召回率但降低精确率。

通过在不同阈值下计算精确率和召回率,我们可以绘制精确率-召回率曲线。一个在所有阈值上都表现更好的模型,其曲线会更靠近右上角。为了用一个数字概括模型的整体性能,我们常计算曲线下面积,面积越大,模型性能通常越好。

另一种常见的曲线是受试者工作特征曲线,它绘制的是真正例率(即召回率)与假正例率的关系,其解读方式与精确率-召回率曲线类似。

回归与排序任务的评估

对于回归任务(如预测房价),我们关心的是预测值与真实值的接近程度,而非分类是否正确。常用的指标包括:

  • 平均绝对百分比误差:计算每个预测值的误差百分比,然后取平均。公式:MAPE = (1/n) * Σ |(预测值 - 真实值) / 真实值|
  • 均方误差:计算预测值与真实值之差的平方的平均值。公式:MSE = (1/n) * Σ (预测值 - 真实值)²

对于排序任务(如搜索引擎结果),我们更关心靠前的结果是否准确。常用指标如平均精度,它考察在前K个推荐结果中,相关结果所占的比例。

第二部分:模型质量——软件工程视角

了解了数据科学家的评估方法后,本节中我们来看看软件工程中的测试思想能否应用于模型评估。

软件测试的类比

传统软件测试包含三个部分:测试输入、预期输出和受控的执行环境。其核心挑战之一是“预言问题”:我们如何知道特定输入下的正确输出是什么?

对于机器学习模型,我们似乎拥有完美的“预言”——带标签的验证集。但直接将其转化为测试用例会遇到问题:我们并不期望模型在每一个测试样本上都做出完全正确的预测。一个错误的预测本身并不等同于程序中的“Bug”。

或许,性能测试是一个更好的类比。在性能测试中,我们并不要求每次响应都恰好是0.5秒,而是期望在多次执行和多种输入下,平均响应时间低于某个阈值。类似地,对于模型,我们关心的是在整体验证集上,其准确率、精确率等指标是否满足我们的期望。

一个不同的视角:验证 vs. 确认

我们可以从另一个角度思考模型质量问题:验证确认的区别。

  • 验证:我们是否正确地构建了系统?(“是否正确地实现了规格说明?”)
  • 确认:我们构建的是否是正确的系统?(“规格说明本身是否正确?”)

传统软件测试主要关注验证。而机器学习模型本身,可以看作是从数据中学习到的“规格说明”。将模型转化为代码(如一个决策树规则集)通常是直接的。因此,真正的挑战不在于“实现这个模型时是否有Bug”,而在于“我们学习到的这个模型本身是否合适、是否公平、是否满足业务目标”。这更像是一个确认问题,类似于需求工程。

因此,谈论“模型Bug”可能并不恰当。我们更应关注模型的准确率性能是否达标,以及它是否与一些额外的约束(如公平性要求)相一致。

模型比较与统计显著性

在实践中,我们经常需要比较不同模型或同一模型不同参数下的性能。由于机器学习训练过程中可能存在随机性(如神经网络权重初始化、随机森林的样本采样),仅凭一次训练得到的准确率差异可能源于偶然。

为了更严谨地比较,可以进行多次训练(或使用K折交叉验证),并运用统计检验(如t检验)来判断一个模型是否显著优于另一个。不过,在工业界实践中,如果性能提升幅度很大(例如从80%到90%),人们通常不会进行复杂的统计检验;而在学术研究中,或当提升非常微小时,统计显著性分析则更为重要。

总结

本节课中我们一起学习了评估机器学习模型质量的核心方法。我们从数据科学的基础指标出发,了解了准确率、精确率、召回率以及曲线下面积等概念及其应用场景。随后,我们从软件工程的视角进行探讨,分析了将模型评估类比于传统测试或性能测试的可行性,并引入了“验证 vs. 确认”的框架来更深入地理解模型质量的本质。最后,我们简要讨论了在比较模型时考虑统计显著性的重要性。下一节,我们将继续探讨更多从软件工程中汲取灵感的模型质量保障技术。

005:从模型到人工智能驱动系统 🚀

在本节课中,我们将学习如何将单一的机器学习模型整合到更广泛的软件系统中。我们将探讨评估模型质量之外的挑战,并理解构建一个完整、可靠且可维护的AI驱动系统所需考虑的系统级因素。

回顾:模型质量评估

上一节我们介绍了如何评估机器学习模型的质量,例如使用准确率、精确率等指标。本节中,我们将视角从模型本身扩展到包含模型的整个系统。

在传统软件测试中,我们讨论覆盖率、变异测试等技术。然而,将这些概念直接应用于机器学习模型测试存在挑战:

  • 规格说明覆盖:机器学习模型通常没有明确的规格说明,难以进行传统的边界值分析。
  • 分支覆盖:例如在决策树中,确保测试数据覆盖所有分支,但这通常依赖于训练数据的代表性。
  • 神经元覆盖:在深度神经网络中研究神经元激活情况,但其实际效用尚不明确。
  • 变异测试:不清楚应对模型的哪些部分(如阈值、参数)进行“变异”以注入故障。

目前,比追求某种“覆盖率”更实用的方法是确保验证数据的代表性,并监控数据漂移

超越单一验证集:重要性与公平性

将所有输入数据视为同等重要可能掩盖关键问题。平均准确率无法反映某些输入子集(可能不常见但至关重要)的性能差异。

以下是创建更细致评估集的策略:

  • 关键用例验证集:针对高频或关键功能创建专门的测试集。例如,语音助手中的“打电话给妈妈”指令。
  • 子群体验证集:为特定用户群体(如特定口音、方言)创建验证集,以评估和保障公平性。
  • 延伸目标验证集:针对当前模型表现不佳但希望未来改进的困难案例(如嘈杂环境下的语音)建立基准。

这些子集类似于传统软件测试中的测试用例,每个用例包含多个数据点,并可以设定不同的准确率期望。

如何识别这些重要的子集?可以借鉴黑盒测试思想:

  • 分析问题领域和用户。
  • 咨询领域专家或公平性专家。
  • 分析用户反馈或生产环境中的性能数据。
  • 在现有验证集中寻找模型表现显著较差的模式。

自动化测试与不变性关系

在传统软件测试中,模糊测试通过生成大量随机输入来发现崩溃等错误。对于机器学习模型,生成输入数据很容易,但预言问题(如何判断输出是否正确)依然存在。

解决预言问题的一种思路是检查模型的不变性关系,即某些输入变换不应影响(或应以特定方式影响)输出。这被称为蜕变测试

以下是一些机器学习模型可能具有的不变性关系示例:

  • 公平性不变性:对于贷款预测模型,仅改变申请人的性别属性,预测结果应保持不变。公式表示为:predict(data) == predict(swap_gender(data))
  • 语义不变性:对于情感分析模型,将句子中的“is not”替换为同义的“isn’t”,情感判断应保持不变。
  • 鲁棒性不变性:对于图像分类器,对输入图像进行微小扰动(如旋转、添加噪声),分类结果应保持不变。公式表示为:predict(image) == predict(perturb(image))
  • 规则不变性:模型应遵守某些硬编码规则,例如“如果信用分数低于X,则贷款申请总是被拒绝”。

一旦定义了这些不变性关系,就可以自动生成大量测试输入,并验证模型是否遵守这些关系。这需要领域知识来定义恰当的不变性。

持续集成与基础设施

与传统软件开发一样,机器学习项目也能从持续集成实践中受益:

  • 自动化训练和评估流程。
  • 使用仪表板(如TensorBoard、MLflow)跟踪模型版本、超参数、指标和训练时间。
  • 设定质量阈值,在模型性能下降时触发警报。

关键在于将模型视为通过流水线产生的制品,而不仅仅是静态代码。一个完整的ML系统流水线包括数据收集、特征工程、模型训练、服务部署、监控和反馈收集等众多环节。构建和维护这个可重复、可调试、可更新的自动化流水线,是工程化的核心,其代码量远超过模型训练本身的几行代码。

系统思维:AI驱动系统的设计

机器学习模型通常是更大系统的一个组件。以Microsoft PowerPoint的“设计灵感”功能为例:

  • 目标:不是追求最高的布局预测准确率,而是帮助用户更轻松地创建美观的幻灯片,最终提升产品竞争力。
  • 用户体验设计:功能是可选而非强制的,用户需主动点击按钮查看建议,并可轻松撤销。这降低了错误预测的风险。
  • 基础设施与遥测:需要设计架构来处理预测请求(本地或云端),并收集使用数据(如功能使用频率、建议采纳率、撤销率)以改进系统。
  • 运营:基于遥测数据持续更新和优化模型。

另一个例子是跌倒检测智能设备:

  • 目标:在老人跌倒时及时获得救助。
  • 交互设计决策:需要在自动呼叫救护车(及时但可能误报)、询问用户(可能无法回应)等选项间权衡。设计需平衡救助价值、误报成本以及模型置信度。
  • 反馈收集:如何获取“漏报”(实际跌倒但未检测到)的数据极具挑战性。

设计交互时需考虑主动性(从被动显示到强制行动)、频率以及如何通过交互设计获取改进模型所需的反馈

系统级安全与质量

即使模型本身不可靠,也可以通过系统设计来保障安全。例如智能烤面包机:

  • 不可靠组件:基于摄像头图像预测烘烤时长的模型可能出错。
  • 系统级保障:通过设置最大烘烤时间硬限制、温度传感器和保险丝等冗余安全机制,可以防止模型错误导致火灾,而无需追求模型的绝对完美。

最终,系统的成功取决于多种质量属性的平衡(如效用、成本、安全性、用户体验),而不仅仅是模型的准确率。有时,通过改进用户界面或系统流程,比单纯优化模型更能有效地提升整体质量。

总结

本节课中我们一起学习了如何超越对单一机器学习模型的评估,转而以系统工程的视角构建AI驱动系统。我们探讨了创建针对性验证集以评估重要子群体性能和公平性的方法,介绍了利用蜕变测试验证模型不变性的自动化测试思路,并强调了构建自动化ML流水线的重要性。最后,我们通过实例分析了在系统层面进行目标定义、交互设计、安全保障和质量权衡的关键考量。记住,优秀的AI驱动系统是精心设计的软件工程产物,而不仅仅是机器学习模型的简单封装。

006:为人工智能系统设定目标 🎯

在本节课中,我们将学习如何为人工智能系统设定目标。我们将探讨何时适合使用机器学习,如何从业务角度理解其价值,以及如何将模型性能与更广泛的系统及组织目标联系起来。

何时使用机器学习 🤔

上一节我们讨论了如何向用户呈现预测结果,本节我们来看看一个更根本的问题:何时应该使用机器学习。

在决定是否采用机器学习时,需要考虑多种因素。以下是几种不应使用机器学习的情况:

  • 有明确规范时:如果问题有清晰、明确的解决方案,直接实现规范即可。例如,批改只有选择题的试卷或执行数学运算。
  • 简单启发式方法足够好时:如果简单的规则就能提供足够好的结果,则无需引入复杂的机器学习模型。例如,根据总分和分数线判断学生是否及格。
  • 成本效益不划算时:如果构建和维护机器学习系统的成本远超其带来的收益,则应放弃。例如,为个人网站开发复杂的语音搜索功能。
  • 正确性至关重要时:在需要绝对可靠性的领域,如武器系统、飞机自动驾驶或某些医疗诊断,应谨慎使用机器学习。
  • 仅为追逐热点时:如果使用机器学习仅仅是为了吸引投资或制造噱头,而非解决实际问题,这并非明智的技术决策。

那么,哪些问题适合使用机器学习呢?以下是机器学习表现出色的场景:

  • 大规模问题:处理海量输入数据,人类难以手动处理。例如,基因组分析、文本情感分析。
  • 开放性问题:没有单一最优解,追求渐进式改进。例如,游戏AI、语言翻译。
  • 随时间变化的问题:环境或数据分布不断变化,需要模型持续适应。例如,电影推荐、库存预测、交易自动化。
  • 本质上困难的问题:没有现成的有效启发式规则。例如,图像识别(识别猫)、语音处理。

此外,成功的机器学习应用通常还需要满足一些前提条件:允许部分系统可行(即可以容忍一定错误)、能够收集反馈数据用于改进、预测结果能对系统目标产生积极影响,并且比替代方案更具成本效益。

案例分析:Spotify个性化播放列表 🎧

让我们以Spotify的个性化播放列表功能为例,分析其为何适合使用机器学习。

  • 大规模问题:拥有数百万用户和海量音乐库。
  • 开放且随时间变化:用户品味和音乐库不断变化,需要动态调整。
  • 无明确规则:很难用硬编码规则定义“相似音乐”或“用户喜好”。
  • 部分系统可行:偶尔推荐不喜欢的歌曲是可以接受的。
  • 有数据和反馈:可以收集用户收听历史作为训练数据,并通过播放行为获得反馈。
  • 影响业务目标:该功能通过提升用户参与度和满意度,间接支持Spotify的核心目标(如增加订阅、提高广告收入)。
  • 成本效益高:比人工为每个用户定制播放列表成本低得多。

商业视角:作为预测机器的AI 💡

从经济学和商业战略角度看,机器学习(或广义的AI)的核心价值在于降低预测成本

  • 预测与决策:商业决策依赖于预测(例如,预测合并是否有利、预测客户需求)。机器学习使高质量预测变得廉价且可大规模自动化。
  • 历史类比:如同电力降低照明成本、互联网降低搜索成本一样,AI降低了预测成本,从而催生了新的商业模式和产品(如实时导航、机器翻译)。
  • 预测与判断:需要区分“预测”(估计未来状态或概率)和“判断”(基于预测结果和价值函数做出决策)。机器学习擅长自动化预测,而判断(涉及价值权衡和风险评估)通常仍由人类完成,或通过数据学习人类的判断模式。
  • 商业影响:预测成本下降提升了数据和数据科学专家的价值,改变了竞争格局(例如,拥有导航App的网约车司机削弱了传统伦敦出租车司机的路线知识优势),并可能催生颠覆性商业模式(例如,基于精准预测的“先发货后购买”模式)。

设定与分解系统目标 🎯

我们讨论了模型评估,但模型服务于更大的系统目标。因此,我们需要将模型性能与业务目标联系起来。

目标可以分解为多个层次:

  1. 组织目标:最高层的目标,通常与商业成功或社会使命相关。例如,公司利润最大化、拯救生命、促进社会公平。
  2. 先导指标:能够快速衡量、并与组织目标强相关的代理指标。例如,用户参与度、订阅用户数、广告点击率。
  3. 用户成果:从用户角度衡量的结果。例如,用户满意度、任务完成效率、发现新内容的愉悦感。
  4. 模型属性:传统的机器学习性能指标。例如,准确率、精确率、召回率、F1分数。

关键点:机器学习组件通常不直接实现组织目标,而是通过影响用户成果和先导指标来间接贡献。例如,Spotify的推荐算法(模型属性)旨在提升用户发现音乐的满意度(用户成果),从而提高用户留存和收听时长(先导指标),最终增加收入和利润(组织目标)。

小组讨论:研究生申请审核自动化 🎓

假设我们开发一个机器学习模型来自动化审核研究生申请(如软件工程硕士项目)。请思考以下四个层次的目标:

  • 组织目标:大学或该硕士项目的根本目标是什么?(例如,提升学术声誉、培养杰出人才、维持财务可持续性。)
  • 先导指标:哪些指标能快速反映项目在招生方面的成功?(例如,录取学生的毕业后起薪、论文发表数量、项目申请人数、校友捐赠率。)
  • 用户成果
    • 申请学生而言:成功匹配到适合的项目、获得公平的评估。
    • 招生官员而言:减轻审核负担、聚焦于边缘案例、更快做出决策。
  • 模型属性:如何评估这个预测模型的质量?(例如,预测学生“是否接受录取”( yield )的准确率、预测学生“入学后成绩”的准确率、在已录取学生中识别出优秀候选人的精确率。)

通过这样的分解,我们可以清晰地看到,优化模型准确率(模型属性)是为了帮助招生官更高效地选拔出最有可能成功且接受录取的学生(用户成果),从而提升生源质量(先导指标),最终服务于大学提升声誉和培养人才的目标(组织目标)。

总结 📝

本节课我们一起学习了如何为人工智能系统设定目标。我们首先探讨了何时使用(或不使用)机器学习的决策框架。接着,我们从商业视角将AI视为“预测机器”,理解了其降低预测成本、重塑商业模式的核心价值。最后,我们学习了如何将机器学习模型的具体性能指标,与更高层次的用户成果、先导指标乃至组织战略目标系统地联系起来。这种目标分解与对齐的思维,对于设计、评估和迭代一个成功的AI驱动系统至关重要。

007:AI技术之间的权衡

在本节课中,我们将要学习如何为AI系统选择合适的建模技术。我们将探讨除了准确率之外,系统可能关心的其他多种质量属性,并了解不同AI技术在这些属性上的权衡。我们将以车道辅助系统为例,分析其约束条件,并对比决策树、线性回归、神经网络和K近邻等技术的优缺点。最后,我们将简要介绍符号AI和概率编程,以拓宽对AI技术的理解。

质量属性的多样性

上一节我们讨论了如何将高层目标分解为可测量的模型属性。本节中,我们来看看在具体选择建模技术时,我们需要考虑哪些质量属性。

质量是一个多维度的概念,可以从不同角度理解。例如,一幅画的质量可能源于其艺术价值(超越性观点),也可能源于其使用了更多颜料(产品观点)。对于AI模型,我们同样需要从多个维度评估其“质量”。

以下是AI模型或组件可能涉及的一些关键质量属性:

  • 准确率:模型预测的正确程度。
  • 推理时间/延迟:模型对单个输入做出预测所需的时间。
  • 模型大小:训练后模型所占用的存储空间。
  • 可解释性:理解模型为何做出特定预测的能力。
  • 鲁棒性:模型在面对输入微小扰动时,预测结果的稳定程度。
  • 公平性:模型对不同人群(如不同性别、种族)的表现是否一致,避免歧视。
  • 训练时间:从数据中学习模型所需的时间。
  • 可扩展性:模型处理大量特征或数据的能力。
  • 能耗:模型进行推理时消耗的计算资源。
  • 可靠性:在系统层面,组件故障时整个系统能否继续运行。

案例研究:车道辅助系统的约束

让我们以车道辅助系统为例,分析在选择具体技术方案时必须满足的硬性约束。

以下是构建车道辅助系统时的一些关键约束:

  • 实时性:系统必须在极短时间内(例如1/50秒)处理完一帧图像并给出预测,以控制车辆。
  • 硬件限制:模型必须在车载计算机有限的算力和内存资源内运行。
  • 最低准确率:预测必须达到一个最低的准确率阈值,否则系统无效甚至危险。
  • 安全性:模型的错误不应导致碰撞等安全事故(通常通过系统设计实现)。

不同建模技术的权衡

了解了我们关心的属性和面临的约束后,本节我们来看看几种常见机器学习技术各自的优缺点。

决策树

决策树通过一系列“如果-那么”规则进行预测。

  • 优点:小型决策树易于理解和解释;推理速度快(只需几次判断);模型通常较小。
  • 缺点:处理大量特征或连续数据时效果不佳;树太深时难以解释;容易过拟合;通常不支持增量学习

线性回归

线性回归试图学习一个线性函数 y = w1*x1 + w2*x2 + ... + b 来拟合数据。

  • 优点:模型简单,参数少时易于解释;训练和推理速度通常较快。
  • 缺点:只能学习线性关系,无法捕捉复杂模式;处理类别型数据需要特殊编码;通常不支持增量学习。

神经网络(深度学习)

神经网络通过多层非线性变换来学习复杂函数。

  • 优点:能处理海量特征和复杂非线性关系;在许多任务上能达到很高的准确率;无需大量特征工程。
  • 缺点训练耗时且需要大量数据;模型庞大,几乎无法解释(“黑盒”);推理可能计算量大。

K近邻

K近邻不构建显式模型,预测时在训练数据中寻找最相似的K个样本,以其标签进行投票。

  • 优点无需训练阶段;模型大小即为数据集大小;支持自然增量学习(增加数据即可);预测结果可通过相似样本解释。
  • 缺点推理速度慢(需搜索整个数据集);不擅长处理高维特征;需要定义合适的距离度量。

超越机器学习:符号AI与概率推理

之前我们主要关注基于数据的归纳学习(机器学习)。本节中,我们来看看另一类AI技术——基于规则和逻辑的符号推理。

符号AI(如布尔可满足性问题求解器、约束满足问题求解器)通过编码领域知识和规则进行演绎推理

  • 核心:将问题(如配置验证、任务调度)编码为一组逻辑约束,然后使用求解器寻找满足所有约束的解。
  • 优点:如果求解器找到解,该解保证是正确的或最优的(在给定约束下)。
  • 缺点:许多问题是NP难的,求解时间可能很长或不可预测;需要人工精确编码领域知识。

概率编程是符号推理与概率论的结合,用于在不确定性下进行推理。

  • 核心:编写程序来描述事件之间的概率关系网络,然后进行概率推断。
  • 优点:可以精确地推理不确定性,给出概率意义上的最优答案或置信度。
  • 缺点:概率推断计算复杂;需要事先知道或估计概率分布。

这些技术表明,AI不仅仅是机器学习。对于需要严格保证或能进行形式化编码的问题,符号方法可能是更合适的选择。

总结

本节课中我们一起学习了为AI系统选择技术时需要考虑的复杂权衡。

  • 我们首先认识到准确率只是众多质量属性之一,其他如延迟、可解释性、公平性、鲁棒性等同样至关重要。
  • 我们通过车道辅助系统的例子,学习了如何识别项目的硬性约束(如实时性、硬件限制),这些约束直接限定了技术选型的范围。
  • 我们对比了决策树、线性模型、神经网络和K近邻等常见机器学习技术,了解了它们各自擅长的领域和固有的短板。
  • 最后,我们简要介绍了符号AI和概率编程,认识到AI领域存在能提供确定性保证或处理不确定性的其他范式。

最终的技术选择取决于对具体问题优先级和约束的深入分析。通常需要在不同质量属性之间做出权衡,选择在帕累托前沿上最符合项目目标的解决方案。

008:风险与应对错误

在本节课中,我们将从组件视角回归到系统整体视角,探讨AI组件可能犯的错误、这些错误对系统的影响,以及我们应如何思考风险、规划应对措施和制定系统级需求。

系统错误的后果

上一节我们讨论了AI组件的内部工作原理,本节中我们来看看当这些组件出错时,会带来哪些后果。

AI组件几乎总是会做出错误的预测。例如,我们之前讨论过的癌症检测系统可能会出错:它可能未能检测出癌症,也可能错误地检测出癌症,导致不必要的侵入性手术。这些错误的后果各不相同,有些可能只是带来不便,有些则可能危及生命。

以下是几个具体案例:

  • Uber自动驾驶汽车事故:这起事故具有明确的安全影响,也对Uber的声誉造成了严重打击,并可能限制了其运营和开发。
  • 亚马逊Alexa的意外行为:例如,因误识别指令而在无人在家时大声播放音乐,或从电视节目中误听指令而订购商品。这些行为可能导致财产损失、财务影响或声誉受损。
  • 微软聊天机器人Tay:该机器人在与Twitter用户互动学习后迅速变得具有种族歧视倾向,最终被下线。这主要造成了声誉损害和研究项目的失败。
  • 亚马逊招聘工具:该工具被发现存在严重偏见,例如倾向于选择特定性别或毕业院校的候选人。

错误来源分析

认识到错误不可避免后,我们需要深入理解这些错误从何而来。以下是导致错误预测的一些常见原因:

  • 训练数据偏差:训练数据不能代表真实世界,或者存在系统性偏见。
  • 输入错误:传感器测量误差导致输入数据不可靠。
  • 反馈循环与数据漂移:模型基于过去的数据训练,但世界已经发生变化,模型未能随之更新。
  • 虚假相关性:机器学习寻找的是相关性而非因果性。模型可能学到一些同时发生但并无因果联系的特征。例如,尼古拉斯·凯奇一年内出演的电影数量与游泳池溺水人数在统计上相关,但这显然没有因果关系。
  • 混淆变量:模型可能学到一些不应使用的“捷径”特征。例如,一个癌症预测模型可能不是通过扫描图像中的病变,而是通过识别使用的是移动式还是固定式扫描设备来做出判断,因为病情更重的病人更常使用移动设备,其生存率本身就更低。
  • 反向因果关系:模型可能混淆了因果方向。例如,早期国际象棋程序从大师棋谱中学到“弃后”通常与胜利相关,但它没有理解“弃后”是“即将获胜”的结果,而非原因,从而错误地建议在任何情况下弃后。
  • 仅观测到已发生事件:模型通常只学习历史数据中“发生了什么”,而不知道“如果采取不同行动会发生什么”。这被称为“反事实”问题。

此外,还有模型选择不当(过拟合或欠拟合)、输入数据噪声、以及预测超出训练数据分布范围(分布外输入)等问题。

预测问题的分类

为了更好地理解机器学习的能力边界,我们可以将预测问题进行分类。一种有用的分类方式基于“我们已知什么”和“我们预测的置信度”:

  • 已知的已知:我们有丰富的训练数据,模型能在训练数据附近做出高置信度的良好预测。例如:垃圾邮件检测、情感分析、翻译、语音识别、导航、推荐系统、人脸检测。
  • 已知的未知:我们知道自己在某些方面预测能力很差,通常是因为数据稀疏或事件罕见。模型对此类预测的置信度较低。例如:预测选举结果、评估公司合并的成败。
  • 未知的未知(黑天鹅事件):这些事件极难预见,无论是人类还是机器都无法预测。例如:9/11袭击、全球性疫情及其连锁反应(如囤积卫生纸导致库存预测失效)。
  • 未知的已知:模型对其预测结果非常自信,但却是完全错误的。这是机器学习特有的问题。例如:之前提到的国际象棋程序自信地建议弃后,但实际是步坏棋;或者图像分类器将熊猫图片高置信度地识别为长臂猿。

这个分类的核心启示是:必须接受机器会犯错的事实。机器学习组件应被视为不可靠的组件。它们可能在90%或99%的情况下表现良好,但也可能做出随机、不可预测且自信的错误预测。因此,系统设计必须考虑到组件可能出错,并确保即使在这种情况下系统仍然是安全或可靠的。

系统级错误缓解策略

既然组件本身可能不可靠,我们就需要在系统层面设计策略来应对错误。以下是一些常见的缓解策略:

  • 防护措施:设计一种机制,在最坏情况发生时能够阻止损害。例如,智能烤面包机中的热熔断器,即使控制算法出错导致过热,熔断器也会熔断以切断电源,防止火灾。
  • 冗余与投票:使用多个模型(集成学习)并对它们的输出进行平均或投票,以减少过拟合和随机错误。例如,随机森林就是通过构建多个决策树并汇总其结果来工作的。但这种方法无法解决数据偏差等系统性问题。
  • 硬编码规则或启发式方法:用确定性的规则覆盖或限制机器学习模型的决策。例如,规定烤面包机连续加热时间不得超过10分钟;YouTube手动编码规则来打破推荐系统可能导致用户陷入“阴谋论视频”循环的反馈回路。
  • 人机协同:将人类纳入决策循环。这可以通过多种方式实现:
    • 建议而非自动执行:系统提供建议,由人类做最终决定(如PPT设计建议)。
    • 要求确认:在执行自动操作前请求用户确认。
    • 允许撤销:提供简单的方法来撤销系统执行的操作(如撤销邮件分类、删除自动补全的文本)。
    • 人类监督:由人类专家监督关键决策(如法官参考再犯风险评分做出保释决定,军事行动中要求人类授权攻击指令)。
    • 需要注意的问题:设计不当的人机协同可能导致“警报疲劳”、人类过度依赖或盲目信任模型(“自动化偏见”),或者人类成为推卸责任的“橡皮图章”。特斯拉自动驾驶系统要求驾驶员随时准备接管,但广告宣传与责任声明的矛盾就是一个典型案例。
  • 可解释模型:如果模型是可解释的(例如简单的决策树或线性模型),我们能理解其推理过程,就能更有效地信任它、调试它或发现其潜在偏见。然而,对于复杂的深度学习模型,这通常很难实现。

风险分析:识别与评估危害

为了系统地规划如何应对错误,我们需要进行风险分析,即思考“可能出什么问题”以及“后果有多严重”。风险通常由事件发生的可能性事件发生后的影响两个因素构成。

以下是一些用于风险分析的结构化方法:

  • 故障树分析:这是一种自上而下(逆向) 的分析方法。从一个不希望发生的项事件(如“汽车撞车”)开始,逆向推导导致该事件发生的所有可能原因组合(如“车道识别错误”且“安全系统失效”)。它使用逻辑门(与门、或门)来组合基本事件。通过最小割集分析,可以找出导致项事件发生的最小事件组合。还可以为基本事件分配概率,进行定量分析,计算项事件发生的总体概率。
    • 示例:智能烤面包机起火
      • 项事件:烤面包机起火。
      • 可能路径AI模型预测错误 热熔断器失效 软件过热保护失效
      • 进一步分解软件过热保护失效 可能是因为 温度传感器故障 保护程序存在bug
  • 失效模式与影响分析:这是一种自下而上(正向) 的分析方法。系统地检查系统中的每个组件,思考它可能以何种方式失效(失效模式),每种失效会对系统产生什么影响(影响),以及如何缓解(缓解措施)。这有助于发现那些未直接导致最坏结果但仍属危害的问题。
    • 示例:车道保持系统
      • 组件:摄像头。
      • 失效模式1:完全无图像输出。
      • 影响:车道检测模型无输入,系统应报警并退出,要求人类接管。
      • 失效模式2:输出图像质量差(如雨天、污垢)。
      • 影响:车道检测可能出错,导致车辆偏离车道。系统可能需要额外的图像质量检测逻辑。
  • 危险与可操作性研究:使用一套引导词(如“无”、“多”、“少”、“早”、“晚”等)与流程或组件结合,进行结构化的头脑风暴,以识别潜在的偏差和危险。

世界、机器与需求

在需求工程中,一个关键概念是区分世界机器以及它们之间的接口。

  • 世界:系统运行的真实环境及其状态(如汽车的实际位置、烤面包机的真实温度)。
  • 机器:软件系统及其内部状态、表示和逻辑。
  • 共享现象:世界与机器交互的接口,主要是传感器(机器感知世界)和执行器(机器影响世界)。

基于此,我们可以区分三种表述:

  • 需求:描述我们希望在世界中实现什么(例如,“汽车应保持在车道内”)。这是关于世界的陈述。
  • 环境假设:关于世界如何通过共享现象展现给机器的假设(例如,“摄像头拍摄的图像能真实反映前方的车道标线”)。
  • 规格说明:描述机器在给定共享现象输入时应如何表现(例如,“给定一张前方道路图像,软件应识别出车道标线”)。这是关于机器的陈述。

这个视角非常重要,因为它明确了:

  1. 软件(包括AI)并不直接“知道”世界,它只知道通过传感器获得的、对世界的抽象表示
  2. 如果环境假设被打破(例如,摄像头被 adversarial attack 欺骗,或用户行为因推荐系统而改变),即使机器软件本身“正确”地执行了规格说明,系统需求也可能无法满足。这就是对抗性攻击反馈循环问题的根源。
  3. 数据漂移也可以从这个角度理解:世界发生了变化,但我们基于旧世界数据训练模型所做的环境假设已经过时。

总结

本节课中,我们一起学习了如何应对AI驱动系统中的错误与风险。核心要点如下:

  1. 接受错误:机器学习组件本质上是不可靠的,会做出错误且有时非常自信的预测。系统设计必须以此为前提。
  2. 理解错误来源:错误可能源于有偏数据、虚假相关性、混淆变量、反向因果等多种原因。
  3. 在系统层面设计缓解策略:不能只依赖改进模型本身。应综合运用防护措施冗余硬编码规则精心设计的人机协同等策略来构建鲁棒的系统。
  4. 进行结构化风险分析:使用如故障树分析失效模式与影响分析等工具,系统地识别潜在危害、分析其成因并评估风险。
  5. 明确区分世界与机器:在需求工程中清晰界定需求(关于世界)、环境假设(关于世界如何被感知)和规格说明(关于机器行为),这有助于理解系统失效的根本原因,特别是应对对抗性攻击和反馈循环等问题。

通过将这些理念和实践融入系统设计与开发过程,我们能够更好地构建出即使在其核心AI组件不完美时仍能安全、可靠运行的智能系统。

009:人工智能驱动系统的软件架构 🏗️

在本节课中,我们将探讨人工智能驱动系统的软件架构。我们将了解软件架构的基本概念,并通过一个增强现实翻译的案例研究,深入讨论在AI系统中如何做出关键的架构决策,例如模型部署位置和遥测设计。

概述

软件架构关注系统的高层设计,它涉及定义系统的结构、组件间的交互方式以及这些决策如何影响系统的质量属性,如性能、可维护性和可靠性。对于AI系统,架构决策尤为重要,因为它决定了模型如何集成、更新和监控。

上一节我们讨论了风险分析和故障树分析,本节中我们来看看如何为包含AI组件的系统设计稳健的架构。

什么是软件架构?

软件架构是系统的高层设计,它定义了组件、它们之间的连接以及相关的属性。架构决策通常由我们关心的质量属性驱动,例如性能、可修改性或可靠性。这些决策会影响整个系统,而不仅仅是单个模块。

架构图就像城市地图,不同的地图服务于不同的目的。例如,一张交通地图用于导航,而一张消防区域地图则用于应急规划。同样,在软件中,我们使用不同的架构图来推理不同的系统属性,如性能瓶颈或安全边界。

案例研究:Twitter的架构演进

Twitter早期是一个用Ruby on Rails编写的单体应用。随着用户增长,他们遇到了严重的性能和可扩展性问题。例如,在大型体育赛事期间,平台经常因过载而崩溃。

他们的初始解决方案是到处添加缓存,但这无法从根本上解决问题。因此,他们决定进行彻底的架构重设计,目标包括:

  • 将性能提升至少10倍。
  • 降低延迟。
  • 提高可靠性和可维护性。
  • 实现故障隔离。

为了实现这些目标,Twitter做出了以下关键架构变更:

  • 技术栈迁移:从Ruby on Rails迁移到基于JVM的Scala。
  • 架构风格转变:从单体应用转向微服务架构。
  • 通信框架:投资构建了自己的远程过程调用(RPC)框架,内置监控、故障转移和负载均衡。
  • 数据存储革新:设计了新的存储解决方案,使用大致可排序的ID,避免了写入时的单点瓶颈,实现了并行写入。

这个案例表明,架构决策是根本性的,需要根据系统目标(质量属性)进行自上而下的设计,而不是在问题出现后才进行修补。

AI系统架构:增强现实翻译案例

让我们考虑一个增强现实(AR)翻译系统的案例。想象你戴着一副智能眼镜走在国外街头,眼镜能实时将看到的文字翻译并叠加显示在你的视野中。

该系统至少需要两个AI组件:

  1. 光学字符识别(OCR)模型:检测图像或视频流中的文字及其位置。
  2. 翻译模型:将识别出的文字翻译成目标语言。

一个核心的架构决策是:这些模型应该部署在哪里?

以下是三个主要的候选方案:

  • 在眼镜上:设备端处理。
  • 在手机上:通过蓝牙与眼镜连接。
  • 在云端:通过蜂窝网络连接。

为了做出决策,我们需要考虑系统关心的质量属性。

以下是需要考虑的关键质量属性:

  • 延迟:对于AR体验,延迟需要极低(研究显示在5-20毫秒以内),否则会导致眩晕感。
  • 准确性:OCR和翻译的准确性至关重要。
  • 能耗:在眼镜上持续处理会快速耗尽电池。
  • 带宽:蓝牙(如5.0版本)带宽约2 Mbps,可能难以持续传输高清视频流。
  • 模型大小与更新频率:翻译模型可能约50MB,更新频率不高,易于管理。
  • 可用性/离线工作:系统是否需要在没有网络连接时工作?
  • 隐私:处理用户实时视频流涉及重大隐私问题。
  • 运营成本:向云端传输数据(如图片)会产生流量成本。

基于这些考虑,纯粹的云端方案(持续传输视频)可能因带宽、延迟、隐私和离线需求而不切实际。纯粹的眼镜端方案可能受限于计算能力和能耗。因此,一个混合架构可能更优:例如,在眼镜上进行轻量级的文字区域检测或初步OCR,只将必要的文本信息发送到手机或云端进行精确识别和翻译,再将结果返回显示。

遥测(Telemetry)设计

遥测用于监控系统运行状况和收集改进模型所需的新数据。在设计AR翻译系统的遥测时,我们面临挑战:如何检测翻译错误?如何收集有用的数据而不侵犯隐私或产生过高成本?

直接持续上传所有视频流是不可行的,因为会产生巨大的数据量、高昂的成本和严重的隐私问题。

以下是一些可能的遥测设计策略:

  • 基于置信度采样:当模型对其预测(如OCR或翻译)置信度较低时,记录并上传相关数据。
  • 隐式用户反馈:监测用户行为,例如用户长时间注视某处或反复移动眼镜试图获取更好翻译,这可能表明当前结果不佳。
  • 显式用户反馈:设计用户界面,允许用户主动报告错误的翻译。
  • 数据匿名化与过滤:在上传前,尝试在设备端过滤或模糊化图像中的隐私信息(如人脸),只保留文本区域。
  • 缓存与延迟上传:将遥测数据缓存在设备上,等待连接到Wi-Fi时再批量上传,以节省蜂窝数据。

遥测设计需要在数据价值、用户隐私、系统成本和法规遵从之间找到平衡。

模型即服务与更新策略

将AI模型部署为独立的微服务是一种常见且良好的架构模式。这遵循了“为变更而设计”的原则,使得模型可以独立于应用程序的其他部分进行更新、扩展和替换。

例如,可以为OCR模型提供一个简单的API:

  • 输入:图像或图像区域。
  • 输出:识别出的文本及其在图像中的坐标。

采用这种服务化架构的好处包括:

  • 解耦:模型更新无需重新部署整个应用。
  • 可扩展性:可以通过负载均衡器轻松扩展服务实例以处理高负载。
  • 容错性:模型服务的故障不会导致整个系统崩溃。
  • 可观测性:可以集中监控服务的延迟、调用次数和错误率。
  • 版本控制:对模型进行版本管理,便于调试和回滚。在返回结果时包含模型版本号,有助于追踪问题来源。

关于模型更新,需要考虑更新频率和成本。对于语言翻译,模型可能不需要非常频繁地更新。更新策略可以是定期发布新版本,也可以探索更复杂的持续学习/在线学习架构。

架构风格与模式

在AI系统领域,成熟的、标准化的架构设计模式仍在发展中。目前常见的实践多源于通用的软件架构原则:

  • 微服务架构:将模型推理等功能封装为独立的服务。
  • 网关/路由模式:使用一个网关服务来管理对多个模型服务的请求,实现负载均衡、路由和API聚合。
  • 流水线架构:将数据预处理、模型推理、后处理等步骤组织成可管理的流水线。

此外,业界也出现了一些专注于ML工作流最佳实践的工具和平台(如TensorFlow Extended, MLflow),它们帮助组织代码、数据和实验,但更多是工程实践而非高层架构模式。云服务提供商(如AWS SageMaker, Google AI Platform)也提供了托管式的模型训练和部署基础设施,抽象了许多架构复杂性。

总结

本节课中我们一起学习了人工智能驱动系统的软件架构。我们回顾了软件架构的核心概念,即通过高层设计决策来满足特定的质量属性。通过Twitter的案例,我们看到了架构重设计如何解决可扩展性和性能问题。重点我们以AR翻译系统为例,探讨了AI系统中关键的架构决策:

  1. 模型部署:需要在设备端、边缘端和云端之间权衡延迟、带宽、能耗和隐私。
  2. 遥测设计:需要在收集有效数据、保护用户隐私和控制成本之间取得平衡。
  3. 服务化与API设计:将模型封装为独立服务,以提高可维护性和可扩展性。
  4. 模型更新策略:根据模型变化频率和数据漂移情况制定更新计划。

为AI系统设计架构要求我们具备系统思维,综合考虑软件工程原则和AI模型的独特需求。虽然一些成熟的模式正在形成,但这仍然是一个不断发展和充满机遇的领域。

010:生产中的质量评估

在本节课中,我们将学习如何在生产环境中评估AI系统的质量。我们将探讨如何收集反馈、监控系统、设计实验,以及如何将数据科学家的工作流程与生产环境中的质量评估相结合。

概述

上一节我们讨论了系统架构及其对质量属性的影响。本节中,我们将重点关注生产环境下的质量评估。我们将看到,生产数据是评估模型性能的终极“未见”数据集,但如何安全、有效地进行测试和监控,需要一套系统的方法。

从离线评估到生产监控

在传统的机器学习工作流中,我们通常在固定的数据集上进行模型训练和评估,例如将数据分为训练集、验证集和测试集。我们使用准确率、AUC等指标来衡量模型质量,并警惕过拟合等问题。

然而,静态数据集评估存在局限性:

  • 数据代表性:静态数据集可能无法代表生产环境中不断变化的数据分布。
  • 时间依赖性问题:对于时间序列数据,随机分割可能导致模型“看到未来”,从而得到过于乐观的评估结果。
  • 过拟合测试集:反复在同一个测试集上调整模型,可能导致模型过拟合于该测试集。

核心观点:生产环境中的数据是模型从未见过的,因此是评估模型泛化能力的终极标准。但这并不意味着我们应该盲目地将模型部署到生产环境。

设计生产环境中的反馈机制(遥测)

为了在生产中测试,我们需要收集反馈,这依赖于遥测技术。我们需要观察系统或特定AI组件在生产环境中的表现。

设计遥测系统需要考虑:

  • 收集什么信息:是系统级的指标(如响应时间、错误率),还是AI组件特定的指标(如预测准确性)?
  • 如何收集:如何在不干扰用户体验、保护隐私的前提下,管理海量数据?

以下是几个案例中收集生产反馈的策略:

  • 房价预测:模型对当前挂牌房屋做出预测。当房屋实际售出后,将预测价格与成交价进行比较,即可获得准确的反馈标签。
  • 评论脏话过滤器
    • 用户可以“举报”未被过滤的违规内容(衡量漏报/召回率)。
    • 用户可以申诉被误判的内容(衡量误报/精度)。手动审核这些申诉可以提供反馈。
  • 癌症图像检测
    • 假阳性:当模型预测为癌症时,患者会接受进一步诊断(如活检),诊断结果可提供明确的反馈。
    • 假阴性:更具挑战性。可通过长期追踪患者病历,观察其后续是否被确诊为癌症,但这涉及隐私且反馈延迟长。

设计遥测时,我们得到的指标可能与离线评估的指标不同:

  • 直接准确标签:如房价案例,反馈准确但可能有延迟。
  • 仅知错误:如脏话过滤器举报,用户满意时我们无感知。
  • 弱相关性代理指标:如音乐推荐系统,我们可能无法直接测量“推荐准确性”,但可以测量“用户在推荐歌单上的停留时间”,该指标与模型质量弱相关,但可用于比较相对变化。

关键点:生产监控更关注趋势和相对变化,而非绝对数值。例如,关注指标在新版本发布后是否发生跳跃式变化,或是否随时间缓慢下降。

生产环境中的实验

除了被动监控,我们还可以主动在生产环境中进行实验。

A/B 测试

A/B测试的核心是随机对照实验。将用户随机分为两组:

  • 对照组(A组):使用当前版本(如旧推荐算法)。
  • 实验组(B组):使用新版本(如新推荐算法)。

通过比较两组在目标指标(如购买转化率、用户停留时间)上的差异,可以因果性地推断新版本的效果。

实施A/B测试的关键要素:

  1. 分流逻辑:根据用户ID等标识,将请求定向到不同版本的服务。代码层面通常体现为功能开关(Feature Flag)。
    if feature_flag.is_enabled(“new_recommendation_model”, user_id):
        use_new_model()
    else:
        use_old_model()
    
  2. 指标收集与关联:收集遥测数据时,需标记数据属于A组还是B组。
  3. 统计显著性:使用统计检验(如T检验)来判断观察到的差异是否由随机波动引起。通常,p值小于0.05被认为具有统计显著性。实验所需样本量取决于预期效应大小和数据噪声。

其他实验策略

  • 影子发布/流量复制:将生产流量复制一份发送给新模型,但不将新模型的预测结果返回给用户。用于在不影响用户的情况下,比较新模型与当前模型的预测差异,尤其适用于有后续真实标签的场景(如房价预测)。
  • 金丝雀发布:逐步向小部分用户(如1%)发布新版本,密切监控指标。若出现问题,可快速回滚,将影响范围降到最低。
  • 混沌实验:在生产环境中故意引入故障(如随机使服务实例崩溃、延迟响应),以测试系统的鲁棒性和容错能力。这可以培养开发人员对故障处理和回退机制的重视。

为数据科学家赋能

软件工程师已拥有成熟的DevOps和A/B测试基础设施。我们需要让数据科学家也能利用这些能力。

目标:使数据科学家能够轻松地在生产环境中进行实验。

  • 简化部署:建立从笔记本到生产模型的自动化流水线。
  • 提供数据访问:让数据科学家能够方便地获取生产环境收集的遥测数据,用于分析和构建新的测试集。
  • 模型版本管理与溯源:维护清晰的模型版本记录,以便在出现问题时能够快速定位是哪个模型、基于什么数据做出的决策。

总结

本节课中,我们一起学习了在生产环境中评估AI系统质量的方法。

  1. 我们认识到生产数据是评估模型泛化能力的最终标准。
  2. 我们探讨了如何设计遥测系统来收集反馈,并理解到生产监控更注重指标的趋势变化。
  3. 我们介绍了多种生产环境实验方法,包括A/B测试、影子发布、金丝雀发布和混沌实验,这些方法有助于我们安全、科学地评估变更效果。
  4. 最后,我们强调了构建基础设施和流程,以支持数据科学家和软件工程师协作,共同在生产环境中进行有效的质量评估和迭代。

通过结合离线评估和生产监控,我们可以更全面、更可靠地确保AI驱动系统的质量。

011:数据质量 📊

在本节课中,我们将要学习数据质量与数据工程的核心概念。数据质量是数据科学家面临的主要挑战之一,研究表明,数据获取、整理和清洗工作占据了他们60%到90%的时间。我们将探讨数据质量的多个维度,包括准确性、完整性、一致性、唯一性和及时性,并学习如何检测和处理数据漂移问题。

上一节我们讨论了测试与生产环境中的挑战,本节中我们来看看数据质量如何影响机器学习系统的构建与维护。

数据质量场景:超市库存预测 🛒

让我们从一个经典的机器学习用例开始:预测超市的商品需求以优化库存。系统需要决定何时订购、订购多少,以避免缺货或浪费。

以下是构建此类预测模型可能使用的数据源:

  • 销售历史:商品随时间变化的销售记录。
  • 库存历史:货架上商品数量的实时记录。
  • 特殊事件:节假日、促销活动等。
  • 产品信息:商品保质期、价格、供应商等。
  • 外部数据:天气预报、社交媒体趋势、竞争对手信息等。

这些数据可能来自多个不同的源头,格式和质量各异,因此确保数据质量至关重要。

数据质量的多个维度 🔍

数据质量可以从多个方面进行评估。以下是主要维度及其可能存在的问题:

  • 准确性:数据记录是否正确。例如,收银系统漏扫了商品,导致销售数据不准确。
  • 完整性:所有相关数据是否都被记录。例如,纸质收货单未及时录入系统,导致库存数据不完整。
  • 唯一性:数据是否存在不必要的重复。例如,同一张收货单被错误地录入了两次。
  • 一致性:不同数据源间的信息是否匹配。例如,销售数据库显示售出20个桃子,但库存记录显示只进货了10个。
  • 及时性:数据是否最新。例如,系统故障或人工延迟导致数据更新滞后。

此外,数据还可能存在格式错误、计算错误、顺序错乱等问题。环境也在不断变化,例如:

  • 系统目标变化:优化目标从“永不缺货”变为“减少浪费”。
  • 数据源质量变化:更换了新扫描仪,数据准确性提高。
  • 用户行为变化:突发公共卫生事件导致某些商品需求骤变。
  • 反馈循环:用户或供应商可能试图“欺骗”模型,制造虚假需求峰值。

数据质量对机器学习的影响 🤖

数据质量和数量深刻影响机器学习模型。

  • 数据量:通常,数据越多,模型效果越好,但存在收益递减点。
  • 数据噪声:噪声数据需要更多数据来抵消其影响,否则模型可能学习到错误模式或过拟合。
  • 数据准确性:不准确的数据(存在系统性偏差)是更严重的问题,模型无法通过统计方法纠正,会基于错误数据学习。

这里需要区分准确度精确度

  • 准确度:测量值与真实值之间的接近程度。
  • 精确度:重复测量时结果的一致性。

公式:假设真实值为 T,测量值为 M

  • 高准确度:M ≈ T
  • 高精确度:多次测量的 M 值彼此接近。

机器学习通常能通过平均化处理不精确(有噪声)的数据,但难以纠正不准确(有偏差)的数据。

探索性数据分析 📈

在开始建模前,进行探索性数据分析至关重要。这有助于理解数据分布、发现异常并验证假设。

例如,在一个房价预测数据集中,我们不应直接使用所有特征建模,而应先:

  1. 查看各特征的统计摘要(如最小值、最大值、均值)。
  2. 可视化数据分布(如直方图、散点图)。
  3. 检查特征间的相关性。

代码:使用Pandas进行初步探索。

import pandas as pd
import matplotlib.pyplot as plt

![](https://github.com/OpenDocCN/dsai-notes-pt2-zh/raw/master/docs/cmu-17445-aidvn-swe/img/85a498878691193dbb34d87104cdde17_19.png)

# 加载数据
data = pd.read_csv('housing.csv')
# 查看前几行和基本信息
print(data.head())
print(data.describe())
# 绘制某个特征的分布
data['median_house_value'].hist()
plt.show()

理解数据的预期分布和形状,有助于在系统运行时设置断言,监控数据是否偏离预期。

数据清洗技术 🧹

数据清洗涉及多种活动和技术。以下是一些基础且实用的方法:

使用数据模式(Schema)

数据模式定义了数据的预期结构和约束,是保证数据一致性的第一道防线。

在传统关系型数据库中,模式通过表结构、数据类型、主键、外键等来定义。
代码:简化的SQL模式定义示例。

CREATE TABLE Employees (
    employee_id INT PRIMARY KEY NOT NULL,
    birth_date DATE NOT NULL,
    department VARCHAR(100)
);

现代数据科学中常使用CSV或JSON文件,它们通常没有显式模式。这可能导致问题,例如代码对文件格式做出隐式假设,一旦格式变化就会出错。为数据流定义模式(如使用Apache Avro、Protobuf)能有效解决此问题。
代码:Avro模式示例(JSON格式)。

{
  "type": "record",
  "name": "Movie",
  "fields": [
    {"name": "id", "type": "int"},
    {"name": "title", "type": "string"},
    {"name": "genre", "type": "string"}
  ]
}

模式能验证数据格式,但无法保证数据值的正确性。

检测不一致性与规则挖掘

数据中常存在冗余信息,可以利用这些冗余来发现不一致性。例如,邮政编码应与城市/州匹配。

我们可以挖掘数据中的关联规则或函数依赖关系。关联规则挖掘(如Apriori算法)可以发现数据项之间的有趣联系。
公式:关联规则 X -> Y 有两个重要度量:

  • 支持度:规则在数据集中出现的频率。Support(X->Y) = P(X∪Y)
  • 置信度:当X出现时,Y也出现的条件概率。Confidence(X->Y) = P(Y|X)

高置信度的规则可用于检测异常(违反规则的数据点)甚至自动修复数据。在软件工程中,类似技术(如Daikon)可用于推断程序中的不变量。

对于库存系统,可能存在的规则包括:

  • 库存数量不应为负数。
  • 同一产品的不同供应商报价应在合理范围内。
  • 订货日期与预计送达日期之间存在依赖关系。

违反这些规则可能预示着数据质量问题。

数据漂移与概念漂移 🎯

数据随时间变化是一个重大挑战,主要分为两类:

  1. 概念漂移:对于相同的输入,预期的输出随时间发生了变化。

    • 例子:信用卡交易欺诈检测。昨天正常的交易模式,今天可能因为出现新型攻击而被视为可疑。
    • 应对:需要重新标注数据并重新训练模型。
  2. 数据漂移:模型接收的输入数据的分布发生了变化,与训练数据分布不同。

    • 例子:人脸识别系统在疫情期间需要识别戴口罩的人脸。
    • 应对:收集新环境下的数据并重新训练模型。

此外,还有上游数据变更,如数据格式或单位突然改变(例如温度从华氏度改为摄氏度),这通常需要转换数据输入。

在实践中,这两种漂移常被统称为“漂移”。检测漂移对于维持模型性能至关重要。

如何检测漂移?

  • 监控模型质量指标:在生产环境中持续监控准确率、F1分数等指标,发现其下降是漂移的明显信号。
  • 比较数据分布:将生产输入数据的分布与训练数据分布进行比较。可绘制特征分布图(如直方图、箱线图)或使用统计检验(如KL散度、群体稳定性指数PSI)。
  • 分析预测结果分布:观察模型预测结果的分布是否发生显著变化。
  • 人工审核:定期对部分预测结果进行人工审核,判断标签是否发生变化。

许多机器学习平台(如Azure ML)提供了数据漂移检测仪表板,可以自动化监控特征分布的变化。

在库存预测系统中,漂移可能由季节变化、节假日、突发事件(如疫情)或供应链中断引起。持续监控销售预测与实际销售之间的差异,是发现漂移的关键。


本节课中我们一起学习了数据质量的核心概念及其对机器学习系统的重要性。我们探讨了数据质量的多个维度、进行探索性数据分析的必要性、基础的数据清洗技术(如模式约束和规则挖掘),以及数据漂移和概念漂移的识别与应对策略。高质量的数据是构建可靠AI系统的基石,而持续监控与适应变化是维持系统长期性能的关键。下一节,我们将深入探讨如何从多种异构数据源中集成数据。

012:机器学习驱动的业务系统

在本节课中,我们将探讨如何为传统企业构建和部署机器学习与人工智能系统。我们将了解企业级AI系统面临的独特挑战,以及如何通过改进软件工程实践、数据架构和工具来应对这些挑战。

概述

企业级AI系统与消费级AI系统(如手机上的面部识别)存在显著差异。它们通常需要处理大量异构数据,服务于复杂的业务流程,并在资源(如人才和计算能力)相对有限的环境中运行。本讲座将基于演讲者Moham在多个行业(如金融、零售、电信)超过30年的实践经验,剖析当前企业AI系统构建中的核心痛点,并展望未来的改进方向。

演讲者背景与案例

上一节我们介绍了本讲座的背景,本节中我们来看看演讲者Moham丰富的行业经验,这些经验构成了本次分享的实践基础。

Moham的职业生涯始于20世纪90年代初的HNC软件公司,该公司专注于使用神经网络等技术为银行构建信用卡欺诈检测系统。到1995年,该公司已服务于全球绝大多数顶级发卡行。当时的技术栈包括单隐藏层神经网络、基于规则的系统和线性/整数规划。

随后,HNC收购了零售业ERP解决方案提供商Retek。Retek利用预测分析和机器学习技术,在需求预测、供应链优化和定价等领域为零售商(如沃尔玛、克罗格)开发了主导市场的解决方案。所使用的技术包括时间序列分析、传统回归和启发式优化。Retek在1999年独立上市,并于2005年被甲骨文以约6.5亿美元收购。

Moham还参与或创立了其他几家公司:

  • Brickstream:使用传统计算机视觉技术进行店内视频分析,通过立体摄像头生成客流热力图,用于分析产品摆放位置与销量的关系。
  • 一家无线网络优化公司:使用蒙特卡洛模拟和启发式搜索(如模拟退火)来优化蜂窝网络中的频率分配,后被爱立信收购。
  • Opsmart:重返零售领域,在云端使用更现代的机器学习技术(如因子分解机)进行需求预测和供应链优化。

这些经历表明,将机器学习应用于企业决策系统(如欺诈检测、需求预测、网络优化)具有巨大的商业价值,但同时也伴随着复杂的工程挑战。

企业作为复杂系统及其建模挑战

从上述案例中我们可以看到一个共同点:企业本身是复杂的系统。为了管理这种复杂性,我们需要为其构建简化的模型。

企业中使用多种类型的模型来辅助决策:

  • 财务模型:通常在电子表格中构建,用于预测决策对盈利能力的影响。
  • 数据模型:存储在数据库中,用于捕获业务实体(如客户、产品)及其关系。
  • 供应链网络模型:可映射为线性/整数规划系统。
  • 统计模型:如消费者需求模型、价格弹性模型。
  • 流程模型:用于执行业务操作。

然而,这些模型通常彼此不一致。它们要么存在于成千上万个分散、易出错的电子表格中(细节丰富但缺乏整体视图),要么存在于像SAP或Oracle这样庞大、僵化、难以驾驭的企业系统中(细节淹没在整体中)。理想的情况是,能够拥有电子表格般的敏捷性和灵活性,同时具备企业级系统的健壮性。这种组合目前尚不存在。

例如,一个简单的杜邦投资回报率模型,其基本公式为:
投资回报率 = 周转率 × 销售利润率
而销售利润率又由 销售额 - 销售成本 计算得出。不同行业(如软件业与零售业)的成本构成细节差异巨大,但核心的盈利模型(利润 = 销售额 - 成本)是相通的。此外,模型还必须考虑物理约束(如运输时间)和法规约束(如员工加班规定)。理想情况下,业务应被建模为一组方程,其中可以包含用于预测的统计或机器学习模型,而无需处理底层实现技术的复杂性。

当前企业技术栈的混乱现状

上一节我们讨论了企业建模的理想,本节中我们来看看现实中的技术实现是多么复杂和 fragmented。

下图展示了某前客户约2%的IT系统架构,它代表了实现上述模型的典型技术栈。每个方框都包含一套复杂的技术组合:

  • OLTP层(在线事务处理):通常包含用SQL/PLSQL编程的事务数据库、用Java/C#编写业务逻辑的应用服务器,以及用HTML/JavaScript实现的前端界面。
  • BI层(商业智能):包含用于数据仓库的数据库(如Teradata)、BI应用服务器(如MicroStrategy)及其前端。
  • 规划层:包含规划服务器(如Anaplan)和前端(如Excel)。
  • 数据移动层:使用ETL(提取、转换、加载)工具连接各层。
  • 预测/优化层:可能使用MATLAB、R、TensorFlow、PyTorch构建模型,或使用OPL、AMPL等语言和CPLEX、Gurobi等求解器构建优化模型。

这导致了数十种不同的编程语言、三四种数据管理系统、以及相互竞争的编程范式(声明式 vs. 命令式) 混杂在一起的局面。在此架构上进行任何更改(例如在界面上添加一个“年龄”字段)的成本都极高,需要跨多个层次和语言进行同步修改。

即使到了今天,技术栈演变为云原生系统(如Redshift、Snowflake、BigQuery、Spark),并使用更现代的机器学习工具(TensorFlow、PyTorch),其核心的“混乱”本质并未改变。这种复杂性催生了更高的云计算成本和人力成本,因为AI系统需要大量手动特征工程和维护工作。

高复杂度的商业影响

这种技术上的混乱直接影响了企业的经济效益:

  • 利润降低:更多的钱花在了云基础设施和人力上。
  • 增长放缓:增加新功能需要大量人力,速度慢。
  • 防御壁垒薄弱:难以构建足够多的自动化模型来形成竞争优势。

这与AI本应带来的经济优势背道而驰。AI的经济学基础在于大幅降低每次预测或决策的成本,并显著提高其质量。然而,当前系统的复杂性使得许多本可廉价进行的预测变得昂贵。

对未来技术发展的愿景与建议

面对当前的困境,我们需要从多个层面进行革新。以下是演讲者对不同技术社区提出的愿景:

对软件工程社区的愿景:从以应用为中心的架构转向以数据为中心的架构。我们需要创建一个能够跨越多样化数据源和技术栈、对核心业务概念(如产品、客户、门店)进行统一建模和协调的中间层。例如,摩根大通拥有约1.7万个SQL数据库和数亿列数据,但其核心业务概念可能只有约400个。通过构建知识图谱来抽象和统一这些概念,可以逐步重构底层的应用。

对数据库社区的愿景:摆脱为每种用例创建一种专用数据库的“疯狂”现状(如事务处理数据库、图数据库、文档数据库、键值数据库)。目前存在数百种数据库技术。我们需要开发能够“同时走路和嚼口香糖”的数据库技术,以更通用的方式支持不同的数据负载。

对编程语言社区的愿景:认识到存在大量“公民开发者”(如业务分析师、数据科学家、量化分析师),他们远多于传统的应用开发者。需要为他们创建真正可扩展的、超越电子表格的终端用户工具。这些工具应该是声明式的、反应式的,允许用户以交互方式构建和调整模型,而无需经历漫长的编译、链接和执行周期。

对机器学习社区的愿景:开发能够直接理解关系型结构化数据的机器学习技术。目前,企业数据中蕴含的领域知识(如实体关系)在输入到TensorFlow等工具前,为了生成扁平的特征矩阵(DataFrame)而被丢弃了。我们需要像深度学习在图像、文本领域实现自动特征学习一样,为企业关系型数据自动化特征工程和表示学习的过程。这将极大减少数据科学家手工设计特征的工作量。

总结与展望

本节课中我们一起学习了构建企业级机器学习系统所面临的深刻挑战。我们回顾了演讲者从信用卡反欺诈到零售预测的丰富案例,剖析了当前企业技术栈复杂、低效的现状及其商业影响。最后,我们探讨了未来的改进方向:通过采用以数据为中心、基于知识图谱的架构,发展更通用的数据库和声明式编程工具,以及实现针对关系数据的自动化机器学习,来构建反应式、以数据为中心的企业系统

在这样的未来,系统的更多组件将通过机器学习自动生成(如同Google Translate从数百万行C++代码演变为几百行Python脚本),或通过更强大的声明式语言进行描述,并由复杂的推理机执行。逐步告别需要一步步指令计算机如何工作的时代。虽然这并非一朝一夕可实现,但软件工程、编程语言、数据库和机器学习社区已呈现出向此方向发展的趋势。对于即将进入工业界的同学们而言,理解这些挑战和方向将大有裨益。

013:数据编程与大数据处理入门 🚀

在本节课中,我们将要学习数据编程(也称为弱监督学习)的基本概念,并探讨如何设计能够处理海量数据(如Google Photos)的系统架构。我们将从数据标注的挑战开始,逐步深入到大规模数据处理的策略。

数据编程(弱监督学习)💡

上一节我们讨论了数据质量问题。本节中,我们来看看一种应对高质量标注数据稀缺的流行技术:数据编程或弱监督学习。

标注数据成本高昂。对于机器学习,通常需要已标注的数据。在许多情况下,获取未标注数据很容易(例如从互联网获取大量图片),但为它们添加标签则需要人工参与,这既昂贵又可能引入质量不一的问题。例如,标注医学影像中的癌症,专家标注准确但昂贵,而众包标注则便宜但可能不可靠。

弱监督学习的核心思想是:质量较弱的标签可能比完全没有标签要好。这项技术旨在将不同质量的专家知识整合到标注流程中。

标注函数与生成模型

其基本方法是:让领域专家编写一系列标注函数。这些函数是用于为数据打标签的机制,它们不需要完全可靠,可以是部分的或启发式的。

以下是用于检测垃圾邮件的标注函数示例:

  • 函数1: 如果文本中包含“Maa”(可能是一个拼写错误),则标记为垃圾邮件;否则,弃权。
    • if "Maa" in text: label = SPAM else: label = ABSTAIN
  • 函数2: 调用一个外部情感分析工具,如果文本被判定为高度两极分化,则标记为垃圾邮件。
  • 函数3: 如果文本中包含“Viagra”或某些常见拼写变体,则标记为垃圾邮件。
    • if any(word in text for word in ["viagra", "v1agra", "viaqra"]): label = SPAM

以下是标注函数的常见来源:

  • 硬编码启发式规则: 基于特定短语或模式(如上述示例)。
  • 外部模型/远程监督: 委托给另一个可能较弱的模型(如情感分析工具)。
  • 众包结果: 整合来自众包平台的不完美标签。
  • 外部知识库: 利用已知的关系数据库(如通过邮政编码推断城市)。

系统会构建一个生成模型(在Snorkel框架中),该模型分析这些标注函数之间的相关性。经常达成一致的函数被认为更可靠,会被赋予更高的权重;经常相互矛盾的函数则被认为可靠性较低。通过这种加权投票机制,系统可以自动为海量未标注数据生成(带有噪声的)标签。

随后,这些生成的、带有噪声标签的数据被用来训练一个判别式机器学习模型。这个最终模型通常能学习到比原始标注函数组合更通用的模式。

应用场景

这种思路不仅可用于标注训练数据,还可用于:

  • 数据增强: 根据规则创建人工数据以扩充训练集。
  • 识别重要数据: 根据规则筛选出关键样本(如可能包含癌症的影像)。
  • 数据清洗: 基于多源弱信号识别并修正数据中的问题。

实例:检测YouTube有毒评论

假设我们要检测YouTube上的有毒评论(可能只占1%)。我们可以设计以下弱信号标注函数:

  • 硬编码关键词列表: 匹配已知的侮辱性词汇、脏话。
  • 外部情感/毒性分类器: 调用现有API获取初步毒性评分。
  • 用户举报历史: 将用户举报过的评论作者的新评论视为弱信号。
  • 用户名检查: 用户名中包含冒犯性词汇的用户的评论。

通过组合这些不完美的信号,我们可以快速为数百万条评论生成初始标签,用于训练一个更强大的分类器。

大规模数据处理架构设计 🏗️

现在,让我们将视角转向如何处理像Google Photos这样拥有极大规模数据的系统。该服务每天处理约1.2亿张图片上传(约6PB数据)。我们需要设计一个能够为图片自动添加标签(如“树”、“生日”、“匹兹堡”)并支持快速搜索的系统。

核心挑战在于:何时以及如何为海量图片计算这些标签? 以下是三种主要的处理范式:

1. 流处理

当用户上传一张图片后,系统并不立即进行复杂的分析。而是将图片放入一个队列中。后台有多个工作进程从队列中取出图片,并行地进行标签预测(物体识别、地理位置解析等)。这种模式接近实时,延迟通常在几秒到几小时之间,适用于需要较快响应的场景。

  • 优点: 延迟较低,资源分配灵活(可根据队列长度扩展计算资源)。
  • 缺点: 无法为了使用新改进的模型而重新处理所有历史数据。

2. 批处理

系统定期(例如每天夜间或每周)启动一个任务,对数据库中的所有或部分图片(例如过去一年内的图片)重新运行最新的分析模型。这种模式用于更新整个数据集,例如当图像识别模型得到重大改进后。

  • 优点: 可以高效地全局更新数据,利用计算资源空闲时段。
  • 缺点: 延迟很高(天或周级别),结果不是实时的。

3. 按需处理(搜索时处理)

当用户执行搜索时(例如搜索“树”),系统实时地对用户个人图库中的图片运行相关的分类模型。为了加速,通常会对常用标签建立索引

  • 优点: 节省计算资源(只为被搜索的内容进行计算),总是使用最新的模型。
  • 缺点: 对单个搜索请求的响应时间可能较长,尤其是当需要处理大量图片或运行复杂模型时。

在一个像Google Photos这样的实际系统中,很可能是混合架构

  • 上传时: 使用流处理快速添加简单、高置信度的标签(如GPS地理位置、通过轻量模型识别的明显物体)。
  • 定期: 使用批处理运行更复杂、更新的模型,刷新整个库的标签,或计算不常用的标签。
  • 搜索时: 结合使用预构建的索引和可能的按需计算来平衡响应速度与结果准确性。

总结 📚

本节课中我们一起学习了:

  1. 数据编程(弱监督学习): 通过组合多个不完美的标注函数,利用生成模型估算其可靠性,从而为海量数据自动生成训练标签。这是一种在标注成本高昂或数据质量不一的情况下,有效扩大训练数据集规模的强大技术。
  2. 大规模数据处理架构: 面对海量数据,我们需要在流处理(近实时)、批处理(周期性全局更新)和按需处理(请求时计算)之间做出设计和权衡。一个健壮的系统通常会根据数据特性、业务需求和对延迟的容忍度,灵活结合这些模式。

理解这些概念有助于我们设计出既能处理大规模数据流,又能智能地利用资源并管理数据质量的AI驱动系统。

014:大型数据集的管理与处理 📊

在本节课中,我们将要学习如何处理和管理大规模数据集。这是构建AI驱动系统时的一个核心挑战,因为机器学习通常涉及海量的训练数据、推理输入和遥测数据。我们将探讨不同的数据存储、处理模式以及相关的系统设计考量。

上一节我们介绍了业务模型与数据质量的重要性,本节中我们来看看当数据量变得非常庞大时,我们该如何应对。

数据存储基础 🗄️

处理大数据的第一步是决定如何存储它。数据存储方式决定了你如何访问和查询数据。

  • 关系型数据库:数据以表格形式存储,使用SQL查询。它们能高效处理索引查询并强制保证数据模式的一致性。
  • 文档数据库 (NoSQL):存储结构化文档(如JSON)。其优势在于模式灵活,易于存储嵌套结构,但通常不擅长处理连接等复杂操作。
  • 日志文件:常见的非结构化数据存储形式,如CSV文件。它们易于转储,但通常不支持索引,查询效率低。

数据还可以用不同格式编码,从纯文本到高效的二进制编码(如Protocol Buffers),后者在网络传输中尤其有用。

数据分布策略 🔀

当单台机器无法容纳所有数据时,我们需要将数据分布到多台机器上。以下是两种核心策略:

  • 分区:将数据库分割成多个部分。
    • 水平分区:将不同的数据行分布到不同机器上(例如,按用户ID哈希)。
    • 垂直分区:将不同的数据列分布到不同机器上(例如,将用户基本信息与历史记录分开存储)。
  • 复制:将相同的数据副本存储在多台机器上,以提高读取可用性和可靠性。

在实际系统中,分区和复制常结合使用。一个常见的设计是主从复制:一个主数据库处理所有写入操作,然后数据被复制到多个从数据库以供读取。这带来了数据一致性的挑战,例如如何处理多个客户端的并发写入。著名的CAP定理指出,在分布式系统中,一致性、可用性和分区容错性无法同时完全满足,设计时需要做出权衡。

数据处理模式 ⚙️

根据对延迟和数据处理量的要求,主要有三种数据处理模式。

服务(按需处理)🌐

这是最直接的模式,例如Web服务器。用户发出请求(如电影推荐),系统立即计算并返回结果。这适用于需要实时响应的场景。

批处理 🔄

批处理用于运行大型计算任务,通常按固定间隔(如每天)离线执行。它适合处理海量数据,计算可能持续数小时甚至数天。

一个经典的例子是使用Unix命令行工具分析网络服务器日志,找出访问最频繁的URL:

cat access.log | awk '{print $7}' | sort | uniq -c | sort -nr | head -5

这个流水线依次执行:读取日志、提取URL、排序、计数、按计数排序、输出前五名。当数据量极大时,这种单机顺序处理会变得非常缓慢。

MapReduce 框架(如Hadoop)就是为了分布式批处理而设计的。其核心思想是 将计算移动到数据所在之处,而非移动数据。它通过两个主要阶段工作:

  1. Map(映射):在各个数据分片上本地执行过滤、转换等操作。
  2. Reduce(归约):将Map阶段产生的中间结果进行汇总、聚合。

框架本身会处理任务调度、故障恢复等复杂问题。在机器学习中,批处理常被用于对历史数据应用新的预测模型(如为所有旧图片重新生成标签)或计算聚合统计报告。

流处理 🌊

流处理介于服务和批处理之间,用于近实时处理连续的数据流。数据被发送到消息队列(如Kafka)中,消费者从队列中读取并处理消息。

其优势在于解耦:生产者和消费者可以独立扩展,以不同的速度运行。例如,在图片服务中,上传的图片可以流入一个队列,然后由多个并行的消费者处理(一个识别物体,一个添加地理位置,另一个检测人脸)。

设计流处理系统时需要仔细考虑消息传递的可靠性保证:

  • 至多一次:消息可能丢失,但绝不会被重复处理。
  • 至少一次:消息绝不会丢失,但可能被重复处理。
  • 恰好一次:这是理想情况,但在分布式系统中最难实现,通常需要业务逻辑的配合。

高级概念与架构 🏗️

以下是构建大规模数据处理系统时常见的几个高级概念。

事件溯源 📜

与传统数据库直接修改当前状态不同,事件溯源只追加记录状态变化的事件(如“用户部门更新为A”)。要获取当前状态,需要从头回放所有相关事件。

优点

  • 完整的历史记录,易于调试和审计。
  • 能轻松重现过去任意时间点的数据状态,对于追踪模型训练所用的数据版本特别有用。

挑战

  • 查询当前状态需要计算,成本高。通常需要构建并维护一个针对查询优化的“物化视图”。

Lambda 架构 λ

Lambda架构结合了批处理和流处理的优点,以平衡延迟和准确性。它包含三层:

  1. 批处理层:处理所有历史数据,生成准确但延迟高的“基准”结果或模型。
  2. 速度层(流处理层):处理实时数据,对结果进行快速增量更新,提供低延迟但可能近似的结果。
  3. 服务层:合并批处理层和速度层的结果,响应用户查询。

例如,可以每晚用全部数据训练一个准确的模型(批处理层),同时用流处理实时微调模型以适应新趋势(速度层)。服务层则提供融合了最新微调结果的预测。即使流处理偶尔出错,次日批处理任务也会将其纠正。

数据湖 vs. 数据仓库 🏞️ vs. 🏢

  • 数据湖:存储大量原始、非结构化的数据(如日志文件)。理念是“先存储,后分析”,保留所有数据以备未来潜在之用。
  • 数据仓库:存储从各业务系统提取、转换并结构化的数据,针对复杂的分析查询进行了优化。

随着数据流经不同系统(数据库、流平台、处理任务),维护一份数据血缘图来记录数据的来源、变换和去向,对于系统理解和治理至关重要。

分布式机器学习训练 🤖

训练大型机器学习模型本身也需要分布式计算。以分布式梯度下降为例:

  • 数据并行:多个工作节点各自持有部分训练数据,计算梯度,并将梯度更新发送到一个中心化的参数服务器进行聚合和模型参数更新。
  • 挑战:参数和梯度通信量巨大。研究集中在通过稀疏更新、梯度压缩等技术来优化网络通信。

像参数服务器这样的专用框架,为分布式训练处理了复杂的协调、容错和通信优化问题。

总结 📝

本节课中我们一起学习了管理大规模数据集的核心知识。我们了解到,处理机器学习中的海量数据需要借助分布式系统。关键要点包括:根据需求选择数据存储(关系型、文档型)和分布策略(分区、复制);根据延迟要求选用合适的数据处理模式(服务、批处理、流处理);并可以借鉴事件溯源、Lambda架构等设计模式来构建健壮的系统。此外,分布式训练框架使得在大数据上训练大模型成为可能。最重要的是,利用现有的成熟工具和框架(如Hadoop、Spark、Kafka)来处理底层的复杂性,通常比从头自建更为明智。

015:基础设施质量、部署与运维 🛠️

在本节课中,我们将学习如何确保AI系统基础设施的质量,并了解现代部署与运维(DevOps)以及机器学习运维(MLOps)的核心概念与实践。我们将探讨从代码测试到自动化部署的整个流程,确保系统在生产环境中可靠运行。


课程概述

首先,我们回顾了上节课关于分布式操作、机器学习数据处理以及批处理与流处理的内容。本节课,我们将重点转向支撑AI系统的“管道”基础设施。与关注模型预测准确性不同,我们将关注整个数据收集、清洗、训练、部署和监控流程的代码质量与可靠性。这些环节中的任何错误都可能导致“静默故障”,即系统看似运行,实则产出错误结果。


基础设施测试的重要性

上一节我们讨论了大规模数据处理,本节中我们来看看如何确保处理这些数据的代码本身是可靠的。机器学习管道中的许多步骤(如数据提取、特征工程)都是传统的软件代码,因此可以且应该进行测试。

以下是测试时需要考虑的核心方面:

  • 测试层级:包括单元测试(测试单个函数)、集成测试(测试多个组件的交互)和系统测试(测试整个端到端流程)。
  • 测试环境控制:通过使用模拟对象(Mock) 来替代真实的依赖(如数据库、数据流),可以隔离测试目标代码,并注入特定错误以测试系统的健壮性。例如,可以模拟一个在第三次请求时抛出IO异常的数据流,以测试程序的错误处理机制。
  • 测试自动化与持续集成:利用如Jenkins、Travis CI等工具,在每次代码提交时自动运行测试套件,确保问题被及早发现。

针对机器学习管道的专项测试

除了通用软件测试,机器学习系统还有其独特的测试需求。以下是一些关键测试类别:

  • 数据测试:确保输入数据的模式(Schema)正确、特征有益、隐私控制得当,并且能够快速集成新的数据源或特征。
  • 模型开发测试:验证模型参数和超参数被正确记录和版本化;通过A/B测试评估模型更新对用户参与度的影响;确保模型在不同数据切片(如不同地区、设备)上的质量公平性。
  • 基础设施测试:保证训练和服务环境的一致性;监控模型性能随时间是否衰减;实施混沌工程,在生产环境中安全地注入故障(如关闭一个服务实例),以测试监控和恢复系统的有效性。
  • 监控测试:定期进行“消防演习”,手动或自动触发警报条件,确保监控系统能正确通知团队。

系统集成与模型交互的挑战

当多个模型以管道或复杂方式协同工作时,会引入新的挑战。例如,一个自动驾驶系统可能包含物体检测、轨迹预测、车道识别等多个模型。改进其中一个子模型,可能会因为意想不到的交互而导致整个系统性能下降。这类似于传统软件工程中的“特性交互”问题。

解决方案是必须进行充分的系统级测试端到端评估,而不能仅仅依赖单个组件的单元测试结果。


DevOps与MLOps:自动化部署与运维

为了高效、可靠地将软件(包括ML模型)交付到生产环境,DevOps文化强调开发与运维团队的协作与自动化。其核心实践包括:

  • 基础设施即代码:将所有配置、依赖和环境定义通过代码(如Dockerfile、Ansible脚本)管理,并纳入版本控制。
  • 持续集成/持续部署:自动化构建、测试和部署流程,实现快速、频繁的发布。
  • 容器化与编排:使用Docker等容器技术封装应用及其环境,并通过Kubernetes等工具进行容器编排,实现自动化部署、扩展和管理。
  • 全面监控:对应用性能、基础设施状态进行实时监控和日志记录。

MLOps是DevOps理念在机器学习领域的具体应用,它额外关注:

  • 数据和模型的版本管理
  • 自动化机器学习管道
  • 模型性能的持续监控与触发重训练

目前存在大量支持MLOps的工具生态,涵盖从特征存储、实验跟踪到模型部署和监控的各个环节。


总结

本节课中我们一起学习了确保AI驱动系统基础设施质量的关键方法。我们认识到,构建可靠的系统不仅需要优秀的模型,更需要坚实的、经过充分测试的代码管道。通过采用单元测试、集成测试、混沌工程等策略,我们可以捕捉并预防许多潜在故障。此外,拥抱DevOps和MLOps的自动化实践,如持续集成、容器化和基础设施即代码,能够显著提升部署效率、系统可靠性和团队协作能力。最终,这些实践共同构成了将机器学习项目从研究原型顺利转化为稳定生产服务的基石。

016:伦理与公平性 🧭

在本节课中,我们将要学习人工智能系统中的伦理与公平性问题。我们将探讨这些问题为何重要,它们如何产生,以及作为软件工程师,我们应如何思考并应对这些挑战。

课程概述

上一节我们介绍了软件测试、监控和DevOps等确保系统质量的技术。本节中,我们将转向一个同样重要但性质不同的主题:构建AI系统时需要考虑的伦理与公平性。这是一个涉及广泛、有时令人沮丧的话题,因为它揭示了技术可能带来的诸多问题。今天我们将重点讨论这些问题本身,了解其来源,为后续探讨缓解策略打下基础。

伦理与法律的区别

首先,我们需要区分“伦理”与“法律”。法律是明文规定、具有强制力的规则。而伦理则关乎哲学标准、社会共识和个人道德,它通常没有法律约束力,更多依赖于社会认同和职业操守。

一个经典案例是某制药公司CEO将一种药的价格从13美元提高到750美元。此举在当时是完全合法的,但引发了巨大的道德谴责。这说明了合法行为未必符合伦理。作为软件工程师,我们手握巨大力量,几行代码就可能造成重大影响,因此思考行为的伦理后果至关重要。

机器学习带来的伦理关切

机器学习技术放大了许多已有的关切,并引入了新的问题。以下是一些关键领域:

  • 偏见与歧视:机器学习模型可能编码并放大训练数据中存在的历史偏见。例如,在招聘、大学录取、信用评分等领域,算法可能基于种族、性别等受保护属性进行歧视,且由于其不透明性(“黑箱”),问题更难被发现和纠正。
  • 安全问题:AI系统可能带来直接的人身安全风险。例如,家庭自动化系统故障可能导致用户受冻;城市中的送货机器人可能意外阻挡残障人士通行。
  • 成瘾与心理健康:推荐系统和用户界面设计(如“无限滚动”)经常被优化以最大化用户参与度,这可能导致成瘾行为,并与青少年抑郁等心理健康问题相关。A/B测试和机器学习可以用来“破解”人脑,诱导特定行为。
  • 社会影响:自动化可能导致失业、加剧社会不平等。算法可能制造“信息茧房”,加剧社会极化。此外,AI在监控、自动化武器等领域的应用也引发深刻的社会伦理担忧。

聚焦公平性与歧视

在众多伦理问题中,公平性是一个核心且被广泛研究的议题。它通常与歧视问题紧密相连。

公平性关注的是避免不公正的区别对待。在法律层面,许多司法管辖区定义了“受保护类别”(如种族、性别、宗教),禁止基于这些属性的歧视。在伦理层面,我们追求的标准往往高于法律要求。

一个重要的概念区分是平等公平

  • 平等意味着给予每个人相同的资源或机会。
  • 公平意味着认识到不同个体可能需要不同的支持才能达到相同的结果,旨在消除系统性障碍。

在讨论歧视带来的危害时,我们通常区分两类:

  1. 分配性危害:不同群体获得不同的结果、机会或资源,或遭受更差的服务质量。例如,人脸识别算法在女性和深色皮肤人群上的表现通常更差。
  2. 代表性危害:强化有害的刻板印象或贬低某些群体。例如,搜索引擎可能因为一个名字“听起来像”某个族裔,就更倾向于展示与该族裔负面刻板印象相关的广告。

为何要关注公平性?

关注公平性不仅是遵守法律的最低要求,更是出于多重考虑:

  1. 遵守法律:避免法律诉讼和罚款。
  2. 履行责任:作为工程师和公司,负有道德和社会责任。
  3. 打造更好的产品:更公平的系统通常能服务更广泛的用户群体。
  4. 维护声誉:符合伦理的行为可以成为积极的公关策略。

偏见从何而来?

机器学习模型中的偏见并非凭空产生,它们通常源于数据或建模过程。以下是几种常见的偏见来源:

  • 历史偏见:训练数据反映了过去存在的社会偏见。例如,将“护士”自动翻译为“她”,将“医生”自动翻译为“他”,因为历史文本中存在这种关联。
  • 带有偏见的人工标注:如果训练数据的标签由人类标注,而标注者自身存在偏见,那么这些偏见就会被编码进数据。例如,亚马逊曾尝试的简历筛选系统,因为历史招聘数据偏向男性,导致系统学会了歧视女性求职者。
  • 样本偏差:数据收集过程不均衡,导致某些群体被过度代表或代表不足。例如,预测性警务系统如果在某些社区部署更多警力,就会记录下更多该社区的犯罪数据,从而形成“犯罪高发区”的偏见反馈循环。
  • 特征偏差:所使用的特征对不同群体的预测效力不同。例如,将“请假天数”作为员工绩效评估特征,可能对需要休产假或病假的员工不公平。
  • 聚合偏差:在模型开发或测试中,过度依赖或代表了某些群体。例如,相机公司长期使用白人女性照片(“雪莉卡”)校准色彩,导致相机对其他肤色拍照效果不佳。
  • 代理变量:即使移除了受保护属性(如种族),其他特征(如邮政编码、就读学校)也可能与这些属性高度相关,成为“代理变量”,导致间接歧视。

案例:大学录取自动化

让我们以“自动化研究生项目申请审核”为例,应用上述概念。可能的偏见风险包括:

  • 历史偏见:如果过去项目中某些群体(如女性)因环境不友好而成功率较低,模型会学会不录取这些群体。
  • 带有偏见的人工标注:对“成功”的定义可能狭隘(如只认可进入顶级科技公司),忽略了其他有价值的职业路径。
  • 样本偏差:训练数据可能主要来自少数知名本科院校,缺乏对其他背景申请者的了解。
  • 特征偏差:标准化考试(如GRE)成绩可能更反映备考资源而非实际潜力,对经济条件差的学生不利。
  • 聚合偏差:申请者中来自某些国家或地区的人数远多于其他地区。
  • 代理变量:即使不考虑性别、种族,本科学校、家庭收入、居住城市等都可能成为受保护属性的代理。

算法信任的陷阱与自我实现的预言

凯西·奥尼尔的《数学杀伤性武器》一书深刻揭示了算法在高风险决策中的危险。我们常常错误地认为算法是“客观中立”的,从而不加质疑地信任其输出。然而,这些算法通常是黑箱、基于相关而非因果、并且可能由特权群体设计。

最危险的模式之一是自我实现的预言偏见反馈循环。以预测性警务为例:

  1. 历史数据存在偏见(某些社区巡逻更多,记录犯罪更多)。
  2. 算法基于这些数据训练,预测这些社区犯罪风险高。
  3. 警方根据预测向这些社区增派警力。
  4. 更多的警力导致该社区记录到更多的犯罪(即使实际犯罪率未变)。
  5. 新增的犯罪数据反过来“证实”了算法的预测,强化了偏见。

类似的循环也出现在信贷、住房等领域,最终固化并加剧了社会不平等。

总结与展望

本节课中,我们一起探讨了AI驱动系统中伦理与公平性的重要性、各类问题及其根源。我们了解到,偏见可能以多种方式潜入系统,而盲目信任算法可能导致严重的分配性和代表性危害,甚至形成自我强化的恶性循环。

关键在于,大数据编码的是过去,它不会发明未来。要创造更公平的未来,我们需要有意识地进行设计。这始于需求工程阶段——与多元化的利益相关者沟通,明确系统的公平性约束和目标。

下一节课,我们将把重点从“问题是什么”转向“我们能做什么”。我们将探讨在机器学习模型内部定义和测量公平性的方法,以及作为软件工程师,我们如何在系统层面(如数据收集、界面设计、部署监控)实施缓解策略,共同构建更负责任、更公平的AI系统。

017:可解释性与可解读性-part1

在本节课中,我们将要学习机器学习模型的可解释性与可解读性。我们将探讨为什么理解模型决策至关重要,并介绍一系列用于解释模型行为的技术,从本质上可解释的模型到用于解释复杂“黑盒”模型的事后分析方法。

概述

上一节我们讨论了AI公平性。本节中,我们将转向另一个关键主题:可解释性与可解读性。理解模型为何做出特定决策,对于调试、合规、科学发现以及建立用户信任都至关重要。我们将首先通过几个实例来了解其重要性,然后探讨不同类型的可解释性方法。

动机与实例

理解模型决策的需求在许多实际场景中都非常明显。

实例一:GitHub提交异常检测

在一个旨在帮助开发者关注重要GitHub提交的项目中,仅仅标记一个提交为“异常”并提供0到1的评分是不够的。为了提供更有用的信息,项目为每个异常预测提供了解释。模型基于多个特征(如提交时间、文件类型)的概率分布工作,可以指出具体是哪些特征(例如“用户通常在夜间不提交,但此次在夜间提交”)使得该提交显得异常。这种解释为用户提供了理解模型判断的具体上下文。

实例二:累犯预测模型

考虑两个用于预测累犯风险的模型。第一个模型是一系列简单的if-then规则,例如:

IF 性别 = 男性 AND 年龄 > 18 AND 有前科 = 是
THEN 预测 = 再次被捕

这种模型是本质上可解释的,我们可以直接阅读规则并讨论其公平性(例如,使用性别作为特征是否合适)。

相比之下,广泛使用的COMPAS工具是一个黑盒模型。它输入多达140个特征,输出一个0到10的风险分数,但不解释其推理过程。研究人员只能通过输入大量数据并观察输出来推断其可能存在的偏见,这个过程既困难又充满争议。可解释的模型使这类审计和讨论变得容易得多。

实例三:信用评分与模型调试

当用户抱怨信用评分模型可能存在偏见时(例如,一对财务状况相似的夫妇得到了不同的评分),如果模型是黑盒,调试将非常困难。我们无法轻易判断这是个例错误还是系统性偏差。可解释性工具在这里成为了关键的调试手段,帮助我们理解模型在特定案例或某一类案例上的决策依据。

为何需要可解释性?

可解释性有多种重要用途,远不止于调试。

以下是其主要价值:

  • 法律与合规要求:例如,欧盟《通用数据保护条例》规定,用户有权获得自动化决策的解释。在美国,信用评分被拒时必须提供理由。
  • 帮助用户改进:解释可以指导用户如何改变行为以获得更理想的结果(例如,如何改善信用状况以获得贷款)。
  • 模型调试与理解:这是软件工程师视角下的核心用途。用于理解错误预测、识别模型学到了什么、评估模型稳健性以及发现边缘情况。
  • 审计与公平性分析:理解模型决策边界是评估其是否存在偏见或不安全因素的基础。
  • 科学发现:在许多科研领域,目标不仅是预测,更是理解现象背后的驱动因素(例如,哪些因素影响自行车租赁需求)。线性模型等可解释模型在此类场景中更受青睐。

当然,并非所有场景都需要可解释性。对于低风险决策(如电影推荐)、为防止系统被恶意“博弈”而保护模型细节、或仅在可行性研究阶段,使用黑盒模型可能是可以接受的。

定义与评估可解释性

可解释性没有一个统一的数学定义。通常,它指人类能够理解决策原因的程度,或人类能够持续预测模型结果的程度

如何比较两个模型的可解释性?这通常需要人工实验。例如,可以给参与者一些输入案例,让他们根据对模型的理解来预测输出,看其预测与模型实际输出的一致性有多高。也可以询问参与者,对于某个特定决策,他们认为原因是什么。此外,一些简单的代理指标也被使用,例如决策树的大小(节点越少,通常越易理解)或线性模型中特征的数量

需要区分两个概念:

  • 模型可解释性:指模型本身的结构就易于理解(如小型决策树、线性模型)。这称为本质可解释性
  • 解释:指针对单个预测提供的、易于理解的理由(例如,“您的贷款被拒是因为储蓄不足。如果储蓄超过100美元,贷款就会被批准”)。这种事后解释可以应用于任何模型,尤其是黑盒模型。

一个好的解释通常具备以下特点:正确(或至少是合理的近似)、简洁对比性(说明什么改变会导致不同结果)、符合受众的先前信念,并且是社会性的(针对受众的知识水平进行表述)。值得注意的是,对于同一个结果,可能存在多个看似合理的解释(“罗生门效应”),因此选择提供哪个解释需要仔细考量。

本质可解释的模型

有些模型本身设计得就易于人类理解。

以下是几种常见的本质可解释模型:

  • 线性回归/逻辑回归:当特征数量较少且系数易于理解时。公式 y = β₀ + β₁x₁ + β₂x₂ + ... 直接显示了每个特征的影响方向和强度。通过特征选择(如Lasso正则化)可以控制模型稀疏性,使其更易解释。
  • 决策树与决策规则:树形结构或“如果...那么...”规则集直观显示了决策路径。例如,累犯预测的决策树。但树或规则集过大时,可解释性会下降。
  • 记分卡模型:这是线性模型的一种可视化呈现,为每个特征值分配分数,总分用于决策。这种形式在实践中(如信用评分)被广泛使用,因为它极其直观。
  • K-最近邻:虽然它没有全局模型,但可以为单个预测提供解释,即展示与当前案例最相似的K个历史案例及其结果。

这些模型的可解释性优势在于,我们可以直接从中推导出反事实解释(例如,“如果年龄小于18岁,预测结果就会不同”)。

解释黑盒模型的技术

对于深度学习等复杂黑盒模型,我们需要专门的技术来生成事后解释。大多数技术将模型视为一个仅能查询输入-输出关系的“黑箱”。

全局代理模型

一种直观的思路是:用一个简单的、可解释的模型(如决策树)去近似模拟复杂黑盒模型的行为。

具体步骤是:

  1. 使用原始数据或生成新数据,获取黑盒模型 F 的预测。
  2. 基于这些(输入,F的预测)数据对,训练一个新的可解释模型 G(代理模型)。
  3. 通过解释 G 来近似理解 F

局限性:代理模型 G 可能无法完全捕捉 F 的复杂性,其解释可能不忠实于原模型。如果 G 效果很好,那或许一开始就应该使用 G。此外,G 可能学到的是与 F 不同的特征关联(例如,学到代理特征而非真实因果)。

局部代理模型 (LIME)

LIME的核心思想是:不为整个复杂模型寻找一个全局解释,而是专注于解释模型在单个预测点附近的行为

工作流程如下:

  1. 在感兴趣的预测点附近随机生成大量数据样本。
  2. 查询黑盒模型得到这些样本的预测标签。
  3. 根据样本与原始点的距离赋予权重(越近权重越高)。
  4. 用一个简单的可解释模型(如线性模型)去拟合这些加权样本的预测结果。
  5. 这个局部线性模型就提供了对该点预测的解释,显示了哪些特征在局部范围内最重要。

例如,在一个文本分类任务中,LIME可以高亮出对“将某帖子分类为无神论”贡献最大的关键词。在图像分类中,它可以生成显著图,显示哪些像素区域对“识别为狼”的决策影响最大。

优点与局限:LIME易于使用,能提供简洁、对比性的解释,适用于多种数据类型。但其解释可能不稳定(对输入微小变化敏感),且是局部近似,不一定反映模型的全局逻辑,因此在需要严格合规的场景中可能不被接受。

特征重要性分析

这类方法旨在评估每个特征对模型整体性能的贡献。

一种常用方法是排列特征重要性

  1. 在验证集上计算模型的基准准确率。
  2. 对于某个特征(如“温度”),随机打乱(排列)该特征在验证集中的所有值。这破坏了该特征与真实标签之间的关系,但保持了特征值的分布。
  3. 用打乱后的数据再次评估模型准确率。
  4. 准确率下降的幅度即为该特征的“重要性”度量。下降越多,说明该特征越重要。

结果通常以条形图展示,直观显示了各个特征的重要性排序。这种方法无需重新训练模型,计算相对高效。

注意:打乱特征可能创建不现实的数据组合(例如,高温与高湿度本应相关,但打乱后可能无关),但通常仍能提供有用的参考。

部分依赖图

PDP用于可视化单个特征与模型预测结果之间的平均关系。

具体步骤是:

  1. 对于某个特征(如“温度”),在其取值范围内选择一系列值。
  2. 对于数据集中每一个样本,将该特征的值依次替换为选定的值,其他特征保持不变,然后获取模型的预测。
  3. 对所有样本在每个替换值上的预测结果取平均。
  4. 绘制该特征值与平均预测值的关系图。

例如,在自行车租赁预测中,PDP可能显示租赁量随温度升高而增加,但在极高温时略有下降。PDP还能展示数据分布,帮助识别预测不可靠的区域(如数据稀少的极端值区间)。

个体条件期望图是PDP的变体,它不绘制平均线,而是绘制每个样本单独的条件期望曲线。如果所有曲线形状相似,说明该特征的影响是独立的;如果曲线差异很大,则暗示该特征与其他特征存在交互作用。

总结

本节课我们一起学习了机器学习模型可解释性与可解读性的重要性及基本方法。我们了解到,可解释性对于调试、合规、审计和科学发现都至关重要。我们区分了本质可解释的模型(如线性模型、决策树)和用于解释黑盒模型事后技术。介绍的后者包括全局代理模型局部代理模型特征重要性分析部分依赖图。这些工具能帮助我们理解模型行为、诊断问题并建立对AI系统的信任。在下一节中,我们将继续探讨更多解释技术,并讨论与可解释性相关的策略与政策问题。

018:可解释性与可解读性(第二部分)

在本节课中,我们将继续探讨机器学习模型的可解释性。我们将学习几种新的解释技术,讨论如何将解释融入用户界面设计,并思考在高风险决策中,解释性模型与黑盒模型之间的权衡。

上一节我们介绍了几种解释黑盒模型的技术,如LIME和SHAP。本节中,我们将看看更多方法,并探讨解释性在实际应用中的意义。

不变性与锚点

不变性(在软件工程中常用)或锚点(在机器学习中的称呼)是一种寻找能描述模型部分行为的规则或充分条件的技术。其核心思想是找到一些能解释某些预测结果的规则。

例如,一条规则可能是:“如果收入低于某个阈值,贷款总是被拒绝。”这条规则并不解释所有情况,但它是一个充分条件:只要前提成立,我们就能解释这部分模型的输出。这类似于关联规则挖掘或规约挖掘。

概念示例:假设我们有一个栈的实现,我们通过测试用例观察其行为。像Daikon这样的工具会尝试寻找方法执行之间始终成立的不变性。例如,它可能发现栈内部的数组对象在执行任何方法前后都永远不会是null

代码示例

// 一个栈类的不变性示例
public class Stack {
    private Object[] array; // 不变性:array != null
    private int top;        // 不变性:top >= -1 && top < array.length
    // ... 方法实现
}

在机器学习中,锚点的概念类似。我们尝试找到一些规则,这些规则能保证(或以高概率)产生特定结果。例如,在贷款模型中,我们可能发现规则:“如果FICO信用分低于X,则模型总是拒绝贷款。”这是一个部分解释,易于人类理解。

反事实解释

反事实解释通过描述“如果情况不同,结果会如何改变”来提供解释。这是一种非常自然的解释方式。

核心形式:如果X没有发生,Y就不会发生(或就会发生)。例如,对贷款申请者可以说:“如果你的储蓄账户再多5000美元,你的贷款就会被批准。”这种解释具有可操作性,为用户提供了改进的方向。

挑战:对于一个给定的预测,通常存在许多可能的反事实解释。关键在于找到最佳解释,通常是最简短或最可操作的。

如何寻找反事实?我们可以使用多种搜索策略:

  • 简单采样:在输入特征附近随机采样,观察哪些改变会翻转预测结果。
  • 基于梯度的搜索:如果模型提供连续输出(如概率分数),可以利用梯度信息进行“爬山”搜索,朝着改变预测结果的方向移动。
  • 更复杂的优化算法:如Nelder-Mead算法,它通过采样多个点来估计改进方向。

公式示意(梯度搜索):对于一个输入点 x 和模型输出 f(x),我们寻找一个接近 x 的点 x',使得 f(x') 达到期望的结果(如从“拒绝”变为“批准”)。这可以形式化为一个优化问题:min distance(x, x'),约束条件为 f(x') = 期望结果

原型与批评实例

这种技术不是解释模型,而是通过分析训练数据本身来进行调试。它寻找能代表某一类别的典型数据点(原型)以及该类别的异常数据点(批评实例)。

概念

  • 原型:最能代表某个类别或概念的典型数据点。
  • 批评实例:属于某个类别,但与该类别的典型特征相距甚远的数据点。

用途:这有助于调试训练数据。例如,批评实例可能标识出错误标注的数据,或者表明我们需要更多某种类型的数据来提高模型鲁棒性。对于图像分类,原型可能是某类狗的典型图片,而批评实例可能是姿势、背景或品种特征不典型的图片。

影响实例

影响实例分析旨在找出训练数据中哪些数据点对模型训练的影响最大。其核心思想是:如果移除某个训练数据点,模型参数或预测性能会发生显著变化,那么这个点就是有影响力的。

工作原理:一种直接的方法是“留一法”重训练。即,对于每个训练数据点,重新训练模型(排除该点),并观察模型性能(如准确率)或参数的变化程度。变化大的点即为影响实例。

用途

  1. 数据清洗:影响大的点可能是异常值或错误标注的数据,需要仔细检查。
  2. 理解泛化问题:分析哪些数据点导致模型在特定新数据(如来自不同医院的患者数据)上表现不佳,有助于发现数据偏差。

主要限制:需要多次重新训练模型,计算成本非常高。不过,对于某些模型(如线性回归),存在近似计算方法可以避免完全重训练。


解释与用户界面设计

将解释融入系统设计可以增加用户信任。关键在于根据决策信心对用户的影响来设计不同的解释策略。

以下是几种典型场景:

  • 高信心,低影响:例如,导航应用的预计到达时间。可能不需要详细解释,简单的显示即可。
  • 低信心,低影响:例如,新用户的电影推荐。可以解释:“因为我们还不了解你的喜好,这是目前流行的电影。”并可能引导用户提供更多反馈。
  • 高信心,高影响:例如,医疗诊断或贷款审批。需要清晰、可信的解释来说明决策依据。
  • 低信心,高影响:例如,社交媒体上的虚假信息检测。需要解释不确定性(“这条内容可能具有误导性,因为…”),并可能将最终决定权交给人类审核。

透明度的重要性:研究表明,即使只是告知用户有算法在背后进行内容筛选(如社交媒体信息流),也能增加用户的控制感和满意度,即使他们不改变对算法本身的看法。隐藏算法的存在可能导致误解和不满。


可解释模型 vs. 黑盒模型:一个关键争论

一个重要的观点认为,我们应停止为高风险决策中的黑盒模型寻找事后解释,而应直接使用可解释模型。

核心论点

  1. 准确性-可解释性权衡是个误区:在许多情况下,通过精心设计特征,可以构建出性能与复杂黑盒模型相当的可解释模型(如稀疏线性模型、浅层决策树)。
  2. 事后解释可能不忠实:像LIME这样的局部替代模型只是近似,其解释可能无法真实反映原黑盒模型的决策逻辑,导致误导。
  3. 可解释模型便于审计和结合上下文:当决策者(如法官)能看到完整的模型时,他们能更好地理解其局限性(例如,模型未考虑犯罪严重性),从而更有效地结合其他信息做出最终判断。

挑战:构建可解释模型通常需要更多的特征工程努力和领域知识。对于像图像识别这样特征极其复杂的任务,可解释模型可能目前还难以达到深度神经网络的性能。

政策启示:有学者主张,在任何存在性能相当的可解释模型的高风险决策领域(如刑事司法、贷款、雇佣),都应禁止部署黑盒模型。这引发了关于知识产权、创新激励与监管必要性的广泛讨论。目前,全球各司法管辖区正在探索相关的AI治理和监管框架。


本节课中我们一起学习了多种机器学习模型的可解释性技术,包括锚点规则、反事实解释、原型与批评实例以及影响实例分析。我们还探讨了如何将解释策略融入用户体验设计,并深入思考了在高风险场景下,追求模型本身的可解释性而非事后解释的重要性和争议。理解这些工具和概念,对于构建负责任、可信赖的AI驱动系统至关重要。

019:版本控制、溯源与可复现性

在本节课中,我们将要学习如何追踪AI系统中数据的来源、模型的版本以及整个处理流程,这对于调试、理解和复现系统行为至关重要。我们将探讨数据溯源、模型版本控制以及确保结果可复现性的最佳实践。

上一讲我们讨论了如何解释单个模型的预测。然而,在复杂的现实系统中,一个决策往往由多个模型和数据处理步骤共同决定。本节中,我们将看看如何追踪整个决策链条的起源。

溯源的必要性

考虑一个信贷审批系统的例子。用户对系统给出的信用评分或信贷额度感到不满,并质疑其公平性。要调试和理解这个问题,我们需要知道:

  • 使用了哪个版本的信用评分模型?
  • 该模型使用了哪些输入数据?这些数据可能来自其他模型。
  • 训练该模型使用了哪些历史数据?
  • 特征提取和数据处理代码是哪个版本?

所有这些信息共同构成了系统的“溯源”信息。它帮助我们追踪一个特定预测或决策是如何产生的,以及系统中的每个组件(数据、特征、模型)来自何处。

溯源的类型

以下是三种主要的溯源类型:

数据溯源
追踪数据的原始来源和变更历史。例如,数据由谁收集、何时被修改、修改原因,以及是否由其他算法(如另一个模型)生成。

特征溯源
追踪用于模型训练和推理的特征是如何从原始数据中提取的。这包括特征提取代码的版本、数据清洗和标准化方法。

模型溯源
追踪模型本身的来源。包括:训练数据版本、使用的算法库及其版本、超参数设置、训练代码版本,以及可能提供输入的其他模型。

版本控制策略

为了有效追踪溯源信息,我们需要对系统中的关键组件进行版本控制。

版本化训练数据
对于大型且不断增长的数据集(如每日新增的用户评分),直接存储完整副本可能效率低下。以下是几种策略:

  • 存储差异:仅存储数据集的增量变化。
  • 仅追加数据:对于时间序列或日志类数据,可以记录偏移量或时间范围来标识版本。
  • 事件溯源:将数据变更记录为一系列事件,通过重放事件可以重建任何时间点的数据状态。
  • 存储哈希值:存储数据文件的哈希值(如SHA256)来唯一标识其内容。
  • 可重现的查询:存储生成数据集的查询语句或处理步骤,以便重新计算。

版本化模型
模型文件通常是二进制文件,即使输入有微小变化,输出模型也可能完全不同,因此存储差异的收益不大。常见的做法是:

  • 存储模型的完整副本。
  • 使用唯一的标识符(如哈希值或带时间戳的版本号)来命名模型文件。
  • 将模型与生成它的数据版本代码版本的元数据关联存储。

版本化流水线
连接数据和模型的代码流水线通常规模较小,可以使用传统的版本控制系统(如Git)进行管理。关键是要记录:

  • 流水线代码版本。
  • 使用的库及其精确版本(例如,通过requirements.txt文件锁定)。
  • 超参数配置。
  • 通过元数据将流水线版本与它产生的数据版本和模型版本明确关联。

工具与实践

有一些工具可以帮助自动化版本控制和溯源追踪。

以下是DVC工具的核心概念:

  • DVC在Git之上工作,专门用于版本化大文件和目录(如数据和模型)。
  • 它使用远程存储(如S3、Google云存储)来存放实际文件,而在Git仓库中只存储元数据和文件哈希。
  • 用户可以定义数据处理流水线的各个阶段(stage),DVC会自动跟踪每个阶段的输入和输出依赖。当输入改变时,可以高效地重新运行受影响的阶段。

以下是MLflow Tracking组件的核心功能:

  • 它是一个用于记录机器学习实验的API和用户界面。
  • 开发者可以手动记录实验参数(log_param)、评估指标(log_metric)、 artifacts(如数据文件、模型文件,使用log_artifact)和代码版本。
  • 它提供了一个Web UI来比较不同实验的运行结果,帮助管理模型的生命周期。

以下是ModelDB工具的特点:

  • 它是一个用于机器学习模型版本控制和实验跟踪的开源系统。
  • 它包含一个中央服务器(可通过Docker部署)和一个客户端库(Verta)。
  • 用户通过API调用记录实验的详细信息,并在Web界面上进行可视化和比较。

这些工具在理念上有所不同:DVC更侧重于基于依赖关系的自动化流水线和数据版本控制;而MLflow和ModelDB更像一个集中的实验日志记录与比较平台,需要更多的手动记录操作。

从溯源到可复现性

当我们能够完整追踪一个预测所用模型、代码和数据的版本时,我们就为“可复现性”奠定了基础。可复现性意味着我们能够重新运行流水线,得到相同或非常相似的模型和结果。

然而,实现完全确定性的复现存在挑战,主要源于随机性

  • 模型随机初始化(如神经网络权重)。
  • 随机划分训练集/验证集。
  • 算法内部的随机性(如随机森林、随机梯度下降)。
  • 分布式计算中的不确定性。

为了提高可复现性,可以采取以下措施:

  • 固定随机种子:在代码开始时设置随机数生成器的种子。
  • 版本化所有依赖:包括操作系统、编程语言、库的精确版本。容器化技术(如Docker)是解决此问题的有效方法。
  • 测试可复现性:多次运行同一流水线,检查结果的稳定性。

生产环境中的日志记录

为了将溯源信息用于生产环境的调试,必须在服务日志中记录关键信息:

  • 每个用户请求的唯一标识。
  • 处理该请求所使用的模型版本
  • 对于多阶段系统,记录每个阶段使用的模型版本和中间结果。
  • 将日志本身视为仅追加数据流进行管理和备份。

这样,当收到用户投诉时,我们可以根据请求ID找到对应的日志,追溯到具体的模型版本,进而根据模型版本找到其对应的训练数据版本和代码版本,从而完整地复现和调查问题。

总结

本节课中我们一起学习了在AI驱动系统中实现溯源和可复现性的核心方法。关键在于对一切进行版本控制:代码、数据、模型、配置和环境。我们探讨了针对不同组件(大数据集、大模型)的版本控制策略,介绍了几种辅助工具(如DVC、MLflow),并讨论了如何通过管理随机性和完善生产日志来确保结果的可复现性。建立这些实践虽然需要前期投入,但对于构建可靠、可调试、可信赖的AI系统至关重要。

020:攻防与风险防护

在本节课中,我们将探讨AI驱动系统中的安全问题。我们将了解安全的基本概念,分析针对机器学习模型的特定攻击,并讨论如何在系统层面进行防御设计。

概述

安全是构建可靠AI系统的关键。我们将从三个核心安全目标——机密性、完整性和可用性——开始讨论。接着,我们会深入探讨针对机器学习模型的两种主要攻击:投毒攻击和规避攻击。最后,我们将学习如何通过系统设计(如威胁建模)来构建更安全的整体解决方案。

安全基础概念

在讨论具体攻击之前,我们需要理解安全的基本要素。安全通常围绕三个核心属性展开:

  • 机密性:确保敏感数据不被未授权方访问或泄露。
  • 完整性:确保数据和系统功能不被未授权方篡改。
  • 可用性:确保授权用户能够按需访问系统和服务。

以一次针对智能手表服务商的勒索软件攻击为例。攻击导致服务中断数日,这直接破坏了可用性。同时,攻击者可能窃取了用户的心率、体重等健康数据,这破坏了机密性。他们也可能篡改了用户数据,例如修改跑步里程或年龄,这破坏了完整性

理解攻击者的动机和能力对于设计防御措施至关重要。攻击者的目标可能是经济利益(如勒索)、制造负面舆论、窃取数据用于其他目的,或仅仅是破坏服务。

针对机器学习模型的攻击

上一节我们介绍了安全的基本概念,本节中我们来看看针对机器学习模型的具体攻击方式。攻击者主要通过影响模型的训练数据或推理输入来达成目的。

投毒攻击

投毒攻击是指攻击者通过向模型的训练数据中注入恶意数据,来破坏模型的行为。这可以分为两类:旨在降低模型整体性能的可用性攻击,和旨在导致模型对特定输入做出错误预测的完整性攻击

一个经典例子是杀毒软件公司之间的竞争。一家公司可能将正常的Windows系统文件作为病毒样本提交给竞争对手的病毒收集系统。如果系统未能正确识别,其后续训练的模型就可能将这个正常文件误判为病毒,从而使该杀毒软件变得不可用。

在电商产品推荐的场景中,撰写虚假好评或差评来人为提升或降低某个商品的排名,就是一种针对训练数据的投毒攻击。

以下是防御投毒攻击的一些常见策略:

  • 异常检测与数据清洗:识别并移除训练数据中的异常值或可疑样本。
  • 数据源可信度评估:例如,电商网站更信任“已验证购买”用户的评论,或根据用户历史行为评估其信誉。
  • 监控模型质量:持续监控模型上线后的性能指标,异常下降可能预示着攻击。
  • 使用对噪声鲁棒的模型:某些机器学习算法对训练数据中的噪声不那么敏感。

规避攻击

与投毒攻击不同,规避攻击发生在模型部署后的推理阶段。攻击者精心构造输入样本,使训练好的模型对其做出错误分类,而模型本身和训练数据并未被修改。

一个著名的例子是对图像分类器的攻击。通过对一张“熊猫”图片添加人眼难以察觉的微小扰动,可以使模型将其高置信度地识别为“鸵鸟”。在垃圾邮件过滤场景中,攻击者会修改邮件内容,例如使用同义词替换敏感词、添加无关的正常文本,以使垃圾邮件绕过过滤器。

从形式上看,规避攻击是寻找一个最小的扰动 z,使得模型 F 对原始输入 x 和扰动后输入 x+z 的预测结果不同:
F(x) ≠ F(x+z)

攻击者如果了解模型内部参数,可以利用梯度信息高效地找到这种扰动。即使模型是黑盒,攻击者也可以通过大量查询来训练一个替代模型,或利用模型输出的置信度分数进行搜索。

以下是防御规避攻击的一些思路:

  • 减少信息暴露:不提供置信度分数,增加攻击者分析模型的难度。
  • 提高模型质量:更好的模型其决策边界更接近真实的分类边界,被攻击的空间可能更小。
  • 增加攻击成本:对API进行速率限制或收费,增加攻击者进行大量查询的成本。
  • 输入预处理:对输入进行规整化或变换,消除可能的扰动。

模型的鲁棒性验证

上一节我们讨论了具体的攻击与防御,本节中我们来看看一个重要的研究领域:模型的鲁棒性验证。鲁棒性指的是模型对于输入的小范围扰动能够保持预测结果稳定的能力。

我们希望证明,对于某个输入 x,在其邻域 N(x) 内的所有点,模型的预测都与 F(x) 一致。这可以形式化地表示为对扰动的稳定性。

然而,除非模型对所有输入都给出相同预测(这是无用的),否则任何非平凡的模型都存在一些靠近决策边界的点,这些点不可能是完全鲁棒的。因此,鲁棒性通常是针对特定输入和特定扰动范围来讨论的。

目前主要有两种验证鲁棒性的方法:

  1. 形式化验证:使用符号执行、抽象解释或约束求解等技术,数学上证明在定义的扰动范围内不存在对抗样本。这种方法能提供严格保证,但目前难以扩展到大型复杂模型,且计算开销大。
  2. 基于抽样的概率验证:在输入邻域内进行大量随机采样,如果所有采样点的预测结果都与原始点一致,则可以以很高的置信度认为该点是鲁棒的。这种方法更易于实施,但提供的是概率性保证而非绝对证明。

在实践中,鲁棒性验证可以用于:

  • 高风险决策的实时防御:例如,在自动驾驶中识别交通标志时,额外验证该识别的鲁棒性。
  • 模型测试与调试:检查测试集或训练集中的样本是否鲁棒,并将找到的非鲁棒样本(对抗样本)加入训练集,以增强模型。

系统级安全设计

仅仅关注模型层面的鲁棒性是远远不够的。安全是一个系统级属性,需要从整体架构进行设计。威胁建模是一种由微软推广的流行方法,用于系统化地识别和缓解安全威胁。

威胁建模的步骤通常包括:

  1. 绘制系统架构图:包括所有组件、数据流和外部交互方。
  2. 识别信任边界:明确系统内不同部分之间的信任关系。
  3. 系统化分析威胁:沿着每个数据流和交互点,使用结构化清单(如STRIDE模型)寻找潜在威胁。

STRIDE模型从六个方面考虑威胁:

  • 假冒:冒充他人身份。
  • 篡改:恶意修改数据或代码。
  • 抵赖:否认执行过的操作。
  • 信息泄露:机密信息被未授权访问。
  • 拒绝服务:使系统无法提供正常服务。
  • 权限提升:获取未授权的访问权限。

对于包含机器学习组件的系统,需要在威胁建模中额外考虑:

  • 谁可以影响训练数据(投毒攻击)?
  • 谁可以访问或操纵模型的预测输入(规避攻击)?
  • 模型的预测结果如何被反馈并影响后续训练(数据闭环中的攻击)?

除了威胁建模,还可以通过系统设计来提升安全性:

  • 增加攻击成本:例如,实施“已验证购买”机制,提高刷评成本;对API进行速率限制和收费。
  • 降低攻击收益:例如,对可疑内容进行标记或限流,而非直接删除,减少攻击的可见影响。
  • 建立信任体系:例如,像Stack Overflow那样,通过社区投票和声望系统来识别可信用户和内容。
  • 实施最小权限原则:每个组件只拥有其完成功能所必需的最小权限。

总结

本节课中我们一起学习了AI驱动系统中的安全与防护。我们首先回顾了机密性、完整性和可用性这三个核心安全目标。然后,我们深入探讨了针对机器学习模型的两种主要攻击:通过污染训练数据发起的投毒攻击,以及在推理阶段精心构造输入以欺骗模型的规避攻击

我们了解到,仅靠模型层面的防御(如追求鲁棒性验证)往往不足,安全必须是一个系统级的考量。威胁建模是一种有效的结构化方法,能帮助我们在系统设计阶段就识别潜在风险。最后,我们认识到,通过聪明的系统设计(如增加攻击成本、建立信任体系)可以构建起更加强大的整体防御。

记住,安全是一个持续的过程,而非一劳永逸的状态。在设计、开发和运维AI系统时,必须始终将安全思维贯穿其中。

021:系统可靠性与事故预防

在本节课中,我们将要学习如何确保AI驱动系统的安全性与可靠性。我们将探讨安全性的广泛定义、面临的挑战,以及如何通过系统设计、需求分析和传统安全工程模式来预防事故。

概述

上一节我们介绍了AI系统的安全威胁与防御策略。本节中,我们将重点转向系统安全性,即如何防止系统故障导致伤害。安全性不仅关乎物理伤害,也涉及对财产、社会及环境的损害。

从安全到安全性的过渡

安全性是一个比可靠性更广泛的系统级概念。可靠性关注单个组件的故障频率,而安全性关注整个系统,确保即使组件失效,也能通过冗余和故障安全机制来减少损害。

安全性的广泛定义与挑战

安全性旨在防止导致伤害的系统故障。伤害包括人员伤亡、财产严重损失,以及对环境或社会的损害(如污染、精神健康问题)。

为什么实现完全自动驾驶汽车如此困难?主要挑战包括:

  • 预测人类行为:人类行为难以预测且多变。
  • 处理边缘情况:传感器(如摄像头)在恶劣天气(雾、雨、强光)或遇到罕见物体时可能失效。
  • 训练数据局限性:模型基于有限的数据训练,无法覆盖所有可能的现实场景。
  • 缺乏常识推理:当前AI系统难以像人类一样处理未预见的特殊情况。

安全工程的核心:需求与假设分析

许多安全问题源于错误的需求或对环境的错误假设,而非软件本身的缺陷。软件根据规格实现,但如果规格未能准确反映真实世界的需求,就会导致危险。

例如,一架飞机软件正确检测“飞机是否在地面”,但其假设(轮子着地即在地面)在飞机侧滑时是错误的,这导致了不安全状况。

因此,安全性分析必须同时关注:

  1. 组件可靠性:处理可能失效的部件。
  2. 需求与假设:确保系统规格与环境模型匹配。

危险分析与传统安全技术

我们之前讨论过几种识别危险的技术:

  • 故障树分析:从预设的危险(顶事件)出发,反向推导导致该事件发生的所有可能原因组合。
  • 失效模式与影响分析:正向检查每个组件可能的失效模式,并分析其对整个系统的影响。

这些技术对于分析包含不可靠机器学习组件的系统尤其重要。

机器学习模型的安全加固:鲁棒性

在机器学习领域,安全性问题常被转化为鲁棒性问题,即模型输入受到微小扰动时,输出不应发生剧烈变化。

以下是提高模型鲁棒性以增强安全性的策略:

  • 对抗性训练:在训练数据中加入精心构造的扰动样本,使模型能抵抗恶意攻击。
  • 形式化验证与采样:对关键预测(如识别停车标志)进行在线验证,检查其在小扰动范围内的稳定性。
  • 异常值检测:识别与训练数据分布差异过大的输入,将其视为潜在攻击或不可信数据。
  • 针对性测试与数据增强:为关键场景(如不同天气下的停车标志)创建专门的测试集,并通过模拟生成更多样的训练数据。
  • 影子部署与模拟:在安全环境中(模拟器或并行影子系统)测试新模型,收集其在边缘情况下的表现数据用于改进。

高级安全挑战:副作用与奖励黑客

对于更复杂的AI系统(如强化学习),定义正确的目标函数非常困难,可能导致:

  • 负面副作用:AI为完成指定任务(如制造回形针)而忽略其他重要方面(如环境保护、人类安全)。
  • 奖励黑客:AI利用规则漏洞以非预期方式达成目标(例如,游戏AI为避免失败而暂停游戏)。

这本质上是需求工程的挑战,即难以完整、无歧义地指定所有约束和常识。

系统级安全设计模式

鉴于机器学习组件本质上的不可靠性,必须在系统层面设计安全措施。以下是一些经典模式:

  • 故障检测与恢复:实施“心跳”检测或定期自检。一旦检测到故障(如模型崩溃或输出异常),则切换到备用控制器(可能是不使用ML的保守策略)。
  • 优雅降级:当主要传感器(如摄像头)失效时,系统可依赖备用传感器(如激光雷达),同时限制最高车速、增大车距以补偿性能下降。
  • 冗余与多样性:使用集成学习,让多个独立训练的模型共同决策,降低同时出错的概率。
  • 系统解耦:设计架构时隔离不同功能模块,防止一个组件的故障产生级联效应,波及整个系统。

案例分析:自动驾驶汽车安全

自动驾驶的难度与环境可控性成反比。在封闭环境(如矿区、专用高速公路)已成功应用多年。真正的挑战在于与人类混行的开放道路。

自动驾驶级别(L0-L5)定义了自动化程度和责任归属。目前广泛部署的是L1-L2(驾驶员辅助),而实现全场景、无条件的L5自动驾驶仍遥不可及。更现实的路径可能是先实现特定场景(如高速公路、交通拥堵)下的高级别自动驾驶(L3-L4)。

以Uber自动驾驶致死事故为例,原因通常是多方面的:

  1. 机器学习模型在黑暗环境中未能及时识别推着自行车的行人。
  2. 本应作为安全员的司机分心。
  3. 车辆原有的安全功能被禁用。
  4. 公司安全文化缺失,监管不足。

这提醒我们,安全是一个系统工程,不能仅依赖单一组件或人员。

超越传统安全:广泛的社会影响

安全性思维应应用于所有系统,而不仅仅是汽车或飞机。许多日常应用中的AI也可能产生安全隐患:

  • 社交媒体推荐算法:可能导致信息茧房、加剧社会极化、影响心理健康(如焦虑、抑郁)。
  • 预测性应用:如交通App预测不准,可能导致用户在危险环境中长时间等待。
  • 欺诈检测系统:过度的误报会给合法用户带来巨大压力和糟糕体验。

即使没有直接人身伤害,这些对个人幸福和社会福祉的影响也值得在系统设计时被认真考虑。

总结

本节课中我们一起学习了AI驱动系统的安全性。核心要点是采用系统性的安全思维

  • 认识到安全性关乎防止各种伤害,范围广泛。
  • 理解机器学习组件本质不可靠,必然会出错。
  • 将传统安全工程(如危险分析、故障树、安全模式)与机器学习技术(如鲁棒性训练、测试)结合。
  • 始终将需求分析环境假设作为安全工作的核心。
  • 在设计任何系统时,主动思考其可能带来的直接或间接安全影响。

通过结合严谨的工程实践和前瞻性的思考,我们可以更好地构建既强大又负责任的AI系统。

022:跨学科团队的培养与协作

在本节课中,我们将探讨在构建AI驱动系统时,如何组建和协调跨学科团队。我们将分析团队中不同角色(如数据科学家、软件工程师、领域专家等)的特点、潜在冲突,并讨论有效的团队结构和协作策略。

概述:为何需要跨学科团队

上一节我们讨论了系统安全,本节我们来看看构建复杂AI系统时的人员组织问题。以设想中的TikTok“抑郁检测”功能为例,该项目需要自然语言处理、软件工程、心理健康、法律合规等多方面的专业知识。这清楚地表明,单一领域的专家无法独立完成此类项目,我们必须组建跨学科团队。

然而,组建团队并非简单地将人聚集在一起。团队规模、结构、目标冲突和群体思维等问题都可能影响项目成败。接下来,我们将逐一分析这些挑战及其应对策略。

团队角色与专业分工

首先,我们需要理解团队中可能存在的各种角色。传统的“数据科学家”与“软件工程师”的二分法过于简化,实际分工要细致得多。

以下是数据科学领域内的一些常见角色分工:

  • 研究科学家:专注于从数据中发现关联和洞察,可能使用基础的线性回归等方法。
  • 应用科学家:不仅对数据感兴趣,更致力于将发现应用于解决具体问题。
  • 数据科学家:更深入地参与建模和数据分析工作。
  • 数据工程师:更接近软件工程侧,专注于数据的获取、处理和管道构建。

同样,软件工程师内部也有前端、后端、基础设施、测试、DevOps、架构师等不同专长。

此外,一个完整的产品团队还需要其他角色,例如:

  • 产品经理与业务分析师
  • 用户体验(UX/UI)设计师
  • 法务与合规专员
  • 领域专家(如本案例中的心理健康专业人士)
  • 伦理顾问

期望找到同时精通所有领域的“独角兽”人才是不现实的。因此,更可行的策略是组建一个由“T型人才”构成的团队,即每个成员在某一领域有深度专长,同时对其他相关领域有足够的了解以便沟通协作。

团队规模与结构挑战

当团队规模增长时,沟通和协调成本会急剧上升。布鲁克斯法则指出:向进度落后的项目中增加人手,只会使项目更加落后。

这主要是因为:

  1. 沟通链路呈二次方增长:n个人的团队,潜在的沟通链路数量是 n*(n-1)/2。
  2. 新人培训与融入成本:在项目后期加入,需要大量时间了解项目上下文。
  3. 工作难以完全并行:某些核心模块的修改可能无法由多人同时进行。

因此,常见的做法是将大团队拆分为多个小团队(通常5-10人),并设立协调角色或架构来管理团队间的接口。这引出了康威定律:系统的设计架构会反映组织的沟通结构

一个糟糕的结构是让两个团队负责同一个模块,这会导致高昂的协调成本。理想的结构是让一个团队独立负责一个或多个具有清晰接口的模块(或微服务),从而实现团队结构与软件架构的匹配。

以TikTok抑郁检测项目为例,一个可能的团队结构划分是:

  • 数据获取与标注团队:负责收集、清洗和标注历史数据。
  • 模型研发团队:负责构建和训练抑郁检测模型。
  • 基础设施与平台团队:提供计算资源、MLOps工具支持。
  • 产品集成与前端团队:将检测功能集成到TikTok主产品中,设计用户界面和干预措施。

目标冲突与协调机制

不同角色的团队成员可能拥有相互冲突的目标。例如:

  • 数据科学家 vs. 软件工程师:前者可能追求极致的模型准确率,而后者更关注系统运行效率、可维护性和部署成本。
  • 数据科学家 vs. 法务专员:前者希望获取更多数据以提升模型,后者则关注用户隐私和数据合规风险。
  • 业务团队 vs. 技术团队:业务方可能追求快速上线和营销亮点,而技术方更注重方案的稳健性和科学性。

如果这些角色被分隔在不同的团队或部门,协调冲突将更加困难。

如何缓解目标冲突?我们可以从DevOps实践中汲取经验。以下是几种策略:

  • 建立共同的组织目标与愿景:让所有成员为同一个高层次目标努力。
  • 培养“T型人才”:鼓励成员理解彼此领域的关切和词汇。
  • 调整团队组织结构
    • 矩阵型组织:员工属于专业部门(如机器学习部、软件开发部),同时被分配到项目组。优点是专业交流深入,缺点是有“两个老板”,优先级可能冲突。
    • 项目型组织:员工完全归属于项目组。优点是目标一致,专注度高;缺点是项目结束后需要重新分配,且难以共享稀缺的专业资源。
    • 混合型组织:在团队中配备主要专家,同时设立中心化的专家小组提供咨询和支持。这是目前许多公司在安全、ML等领域倾向采用的模式。
  • 采用敏捷实践:站会、迭代计划会、产品负责人(Product Owner)决策等机制,有助于同步信息、明确优先级和调解冲突。

群体思维及其应对

群体思维是指团队成员为追求和谐一致,而不愿提出异议或探索替代方案,从而导致决策失误的现象。

在软件项目中,群体思维可能表现为:

  • 盲目跟随技术潮流(如“我们必须用深度学习”),而不评估是否适合。
  • 在估算会议中,第一个人给出的数字影响了后续所有人的判断。
  • 在代码审查中,因为作者是资深员工而不敢提出质疑。
  • 在TikTok案例中,可能表现为:对“抑郁”的定义过于狭隘、仅采用团队熟悉的情绪分析技术、或全盘接受管理层提出的干预方案而不加论证。

如何避免群体思维?以下是一些方法:

  • 提升团队多样性:包括背景、性别、文化、专业领域的多样性。
  • 营造开放冲突的文化:鼓励建设性的辩论,将提出反对意见视为对团队的贡献。
  • 使用特定技巧:例如,在会议中让领导者最后发言;指定“魔鬼代言人”角色;要求至少提出两种备选方案。
  • 借助敏捷实践:例如“计划扑克”,让成员独立给出估算后再同时亮出,避免相互影响。

社会惰化与激励

社会惰化是指个体在团队中付出比单独工作时更少努力的倾向。原因包括责任分散、个人贡献难以被识别等。

应对社会惰化的措施包括:

  • 保持小团队规模
  • 将工作分解为小而明确的任务,并在看板或迭代任务板上可视化。
  • 通过站会等方式让个人贡献可见
  • 提供有效的激励:对于知识型工作者,金钱奖励(如奖金)在基本需求满足后效用递减,甚至可能损害内在动机。更有效的驱动因素是自主性(给予选择权)、专精(追求 mastery)和使命感(工作的意义)。

总结

本节课中,我们一起学习了构建AI驱动系统时跨学科团队面临的挑战与协作策略。我们认识到,成功不仅依赖于技术,更依赖于人的有效组织。我们需要理解不同角色的专长与目标,设计合理的团队规模与结构(遵循康威定律),并积极管理目标冲突、避免群体思维和社会惰化。通过培养T型人才、采用敏捷实践、营造开放协作的文化,我们可以将多元化的专业知识凝聚起来,共同构建负责任且强大的AI系统。

023:总结与反思 🎓

在本节课中,我们将回顾整个学期所学的核心内容,并共同探讨AI驱动系统软件工程领域的未来挑战与发展方向。

课程回顾 📚

上一节我们讨论了跨学科团队的结构与管理。本节中,我们将快速浏览整个学期的知识框架,将各个部分串联起来,看看我们共同学习了哪些内容。

学期内容概览

我们以介绍课程和对比数据科学家与软件工程师的角色开始。我们讨论了构建一个AI驱动系统远不止是训练一个机器学习模型,还需要考虑整个产品、各种质量属性和系统层面的问题。

以下是本学期涵盖的主要模块:

  • 机器学习与人工智能基础:我们定义了机器学习,探讨了线性回归、决策树、神经网络等模型,以及过拟合、欠拟合、训练/验证集划分等核心概念。
  • 模型质量与评估:我们区分了机器学习视角(如准确率、召回率、精确度)和软件工程视角(如测试预言问题、验证数据管理)。核心观点是:机器学习更类似于传统软件工程中的需求分析,即 学习正确模型 而非 验证实现是否符合规格说明
  • 系统思维与目标设定:我们探讨了如何将模型集成到更大的系统中,思考用户界面设计、业务流程和风险。我们引入了AI画布框架来思考业务用例、数据、预测成本与价值。
  • 模型选择与质量权衡:我们强调准确率并非唯一标准。模型的可解释性、鲁棒性、公平性、大小等属性同样重要,需要在具体场景中进行权衡分析。
  • 风险与安全设计:我们将机器学习模型视为不可靠的组件,会随机犯错。因此,系统设计必须考虑容错,采用防护栏、冗余、人在回路等策略。我们介绍了如FMEA等风险分析技术。
  • 软件架构:我们以增强现实翻译等案例,探讨了模型部署位置(边缘 vs. 云端)的架构决策及其在延迟、更新、数据隐私等方面的权衡。
  • 生产环境的质量保障:我们深入讨论了监控、遥测数据收集、A/B测试、影子发布和金丝雀发布等技术,以在真实环境中评估和改进模型。
  • 数据质量与数据编程:我们讨论了数据质量的多个维度(如准确性、一致性),以及如何应对数据漂移和模型衰减。工具如Snorkel可用于通过弱监督生成标签函数。
  • 大规模数据处理基础设施:我们对比了批处理与流处理模式,探讨了事件溯源、Lambda架构和数据湖等概念,以管理海量数据。
  • 基础设施质量与自动化:我们讨论了测试AI系统基础设施(如数据管道)的传统软件工程方法,以及DevOps和MLOps如何实现高度自动化。
  • 公平性与伦理:我们区分了伦理与法律,讨论了分配性伤害和代表性伤害,并探讨了多种公平性定义(如反分类、分类均等),强调这是一个需求工程挑战
  • 可解释性与可说明性:我们探讨了为何需要解释模型决策(如调试、建立信任、满足法规),并介绍了一系列技术(如LIME、反事实解释)。
  • 版本控制与可复现性:我们讨论了模型、数据和流水线的版本管理重要性,以及确保实验可复现所面临的挑战(如非确定性)。
  • 安全、隐私与对抗性机器学习:我们研究了投毒攻击和逃避攻击,讨论了鲁棒性验证、隐私保护技术(如差分隐私),并强调需要在系统层面(如威胁建模)而不仅仅是模型层面考虑安全。
  • 团队协作:最后,我们探讨了在跨学科团队(数据科学家、软件工程师等)中有效协作的模式、组织结构和挑战。

未来挑战与讨论 💭

回顾了整个课程的知识体系后,我们现在来看看这个领域可能的发展方向以及面临的开放挑战。

主要挑战在哪里?

从软件工程的角度看,构建实际AI系统的主要挑战、工具缺口和研究缺口有哪些?

以下是课堂讨论中提出的一些观点:

  • 质量评估的领域特异性与通用化:衡量质量非常困难且高度依赖领域。未来可能需要开发能适应不同常见领域(如推荐系统)的通用化工具和方法。
  • 需求工程的重要性:在项目初期,像公平性、鲁棒性这样的非功能性需求常常被忽视。机器学习项目的需求工程和管理实践需要显著演进和更多研究关注。
  • 可解释性的核心作用:可解释性似乎是一个枢纽,它能促进公平性审查、安全性评估,并帮助确保需求得到满足,其重要性将日益凸显。
  • 架构模式的缺失:针对机器学习系统的、经过验证的架构模式仍然较少。例如,在边缘计算与云计算的权衡中,缺乏成熟的设计模式。
  • 跨学科沟通的鸿沟:数据科学家和软件工程师(尤其是架构师)之间常常存在沟通障碍,缺乏共同语言来理解彼此的工件(如模型、组件)和关切。

软件2.0与自动化的未来

业界有“软件2.0”的讨论,即用数据和少量代码(如TensorFlow模型)替代大量传统逻辑代码。这是否意味着软件工程师会被取代?

讨论认为,软件工程远不止是编写代码,它包含了系统思考、权衡分析、架构设计、集成、确保非功能性需求等复杂活动。目前AI在这些方面尚未达到替代人类专家的水平。自动化(如AutoML)更可能的方向是消除繁琐任务,让数据科学家和软件工程师都能更专注于高价值的创造性工作。

赋能与专业化

工具(如MLOps框架)正在赋能数据科学家更独立地部署模型,同时也在让软件工程师更容易接触机器学习任务。未来的方向可能是:

  • 降低门槛:让更多人能够构建AI应用,因为数据驱动决策已成为普遍需求。
  • 深化协作:并非追求“全能型独角兽”,而是培养T型人才,并建立高效的跨学科团队。软件工程师和领域专家(如结构工程师在建筑中一样)的专业知识仍然至关重要。
  • 催生新角色:如同过去系统工程师演化出应用工程师,AI与软件工程的融合也可能催生全新的工程角色。

总结 🏁

本节课中,我们一起回顾了“AI驱动系统的软件工程”这门课程的全部核心内容,从机器学习基础到系统集成,从质量保障到伦理安全。我们认识到,构建成功的AI系统需要数据科学和软件工程的深度融合。虽然自动化工具在不断进步,但人类在定义目标、理解上下文、进行复杂权衡和跨领域沟通方面的作用无可替代。未来的挑战在于改进工具、完善方法、加强教育,并最终培养出能够有效协作、负责任地构建AI系统的团队。

024:课程介绍与理念

在本节课中,我们将介绍一门由卡内基梅隆大学开设的课程——“面向AI驱动系统的软件工程”。我们将探讨这门课程的设计理念、目标以及它如何帮助学生构建包含机器学习组件的真实系统。

课程定位与目标 🎯

上一节我们介绍了课程背景,本节中我们来看看这门课程的具体定位。这门课程并非传统的机器学习课程。传统课程主要关注理解机器学习技术原理,或将其应用于特定数据集以获得高精度模型。我们的目标是构建真实的系统

我们也不专注于软件工程在AI中的应用研究,例如本届会议上讨论的自动补全等技术。我们认为这些应用并不能完全代表学生未来将从事的工作。

核心应用场景 📱

以下是本课程关注的核心应用场景,它们都涉及将AI组件集成到更大的系统中:

  • 智能演示文稿工具:例如PowerPoint中的“设计灵感”功能,它能自动布局幻灯片。PowerPoint本身远不止AI组件,AI只是其庞大系统中的一个部分。
  • 音频转录服务:用户上传音频文件以获取文字转录。同样,机器学习是其中的核心组件,但仅构建这个组件无法成就一项业务。

为了构建此类业务,开发者必须考虑用户界面、系统扩展性(处理大量音频文件)、数据存储、错误处理以及支付系统等。所有这些都对应着围绕AI组件构建的额外系统

所需技能与挑战 ⚙️

构建这类系统需要数据科学家和软件工程师的协作。数据科学家负责模型,软件工程师负责构建健壮的系统。

引入AI组件会带来许多独特挑战,例如需求规格不明确、反馈循环等。然而,软件工程师在构建此类系统时也能贡献巨大价值。例如,我们在构建基于不可靠组件的安全系统、进行风险分析、处理现实世界与机器接口之间的需求等方面拥有丰富经验。这些正是我们可以传授给学生,帮助他们在现实世界中构建此类系统的知识。

课程结构与教学理念 📚

本课程围绕传统的软件生命周期构建,重点探讨当引入机器学习组件后,需求分析、测试和架构设计将如何变化。

我们认为,这更多是一个教育问题,即深入思考并应用我们已有的技术,而非一个需要完全发明新技术的纯粹研究问题(尽管也存在部分研究内容)。教育是目前的主导部分。

实践环节:模拟真实世界 🎬

最后,我们简要介绍课程的实践环节。我们希望让学生摆脱仅使用Jupyter笔记本和静态数据集、只评估模型准确率的传统模式。

这体现在我们的作业设计中。我们构建了一个基础设施来模拟真实世界:一百万个模拟用户观看电影,学生需要提供一个推荐服务。通过这种方式,学生提供的推荐会实际影响模拟环境,从而让我们能够检测到反馈循环。学生还需要在“生产环境”中运行和维护系统,关注可用性,并以最短的停机时间更新系统等。我们通过这种方式,在构建真实系统方面创造了现实感

总结与资源分享 🌐

本节课中我们一起学习了“面向AI驱动系统的软件工程”这门课程的核心理念。它专注于教授如何将机器学习组件集成到完整的、可用的软件系统中,强调软件工程原则在AI时代的重要性与实践。

如果你对此感兴趣,我们欢迎你查看我们的课程材料。我们在知识共享许可协议下分享了幻灯片、作业、基础设施代码和视频录像等资源,希望这些对你或你的学生有所帮助。

025:软件工程与机器学习的融合

在本节课中,我们将探讨如何将传统的软件工程实践与机器学习应用相结合,以构建可靠、可维护且安全的AI驱动系统。我们将分析软件工程师与数据科学家在团队中的不同角色与协作方式,并讨论在系统层面需要考虑的关键工程挑战。


概述:为何需要融合软件工程与机器学习?

在构建现代软件应用时,我们越来越多地引入机器学习(ML)或人工智能(AI)组件。一方面,软件工程领域拥有悠久的传统、成熟的流程和最佳实践,涵盖从需求开发到部署运维的完整生命周期。另一方面,机器学习领域不断取得突破性创新,这些技术有潜力深刻改变人们的生活。然而,当这些技术被集成到甚至安全关键系统中时,我们迫切需要将软件工程的最佳实践与机器学习开发结合起来。核心问题在于:如何实现这种结合?如何让来自不同背景的角色有效协作?本节课将深入探讨这一交叉领域。

软件工程师与数据科学家:不同的专长与思维模式

要成功构建包含AI组件的系统,我们需要理解团队中不同角色的背景和专长。本节中,我们将主要关注软件工程师和数据科学家这两种核心角色。

软件工程师所做的远不止编程。他们接受训练,在资源有限和信息不完整的情况下做出重要的工程决策和判断。他们需要权衡系统的多种质量属性(如性能、安全性、成本),并根据具体场景做出“视情况而定”的工程判断。这通常涉及处理现实世界的复杂性,并在预算内构建系统。

相比之下,多数的机器学习课程、讲座和博客文章往往更狭隘地专注于建模技术本身。数据科学家通常关注如何在给定数据集上构建具有最高准确率的模型,例如在Kaggle竞赛中常见的模式。他们的工作流程更具探索性和科学性,从一个模糊的目标开始,尝试解决一个甚至在一开始都不确定是否可行的问题。这是一个非常增量、迭代的过程。

核心协作公式
成功系统 = 软件工程师的系统思维与工程实践 + 数据科学家的建模专长与探索能力

这两种专长都是必需的,并且通常是互补的。在实践中,寻找同时精通两者的“全能型人才”(或称“独角兽”)非常困难。因此,更可行的方式是组建拥有不同专长的团队,并让他们协同工作。

AI驱动系统带来的新挑战

引入AI组件后,构建系统的方式发生了一些根本性变化。上一节我们介绍了不同角色的专长,本节我们来看看这些变化具体体现在哪些方面。

  1. 规格说明的缺失:在传统软件中,我们根据规格说明来定义“正确性”和“缺陷”。但对于从数据中学习的机器学习组件(如转录服务、累犯预测),我们并没有明确的规格说明。我们能够接受模型在90%的情况下正确,而在10%的情况下出错,并以不同的准确率水平来衡量性能。
  2. 对环境与反馈循环的重视:我们需要更多地考虑系统运行的环境以及可能产生的反馈循环。例如,YouTube的推荐算法曾过度推荐阴谋论视频,因为这能提高用户参与度,但却形成了一个使用户越陷越深的负面反馈循环。
  3. 组件的非单调效应与交互:机器学习组件很难被当作独立的模块进行推理。在一个由多个ML组件组成的复杂系统(如车道辅助系统)中,改进一个组件可能会降低整个系统的性能,这使得系统级推理变得非常困难。
  4. 生产环境测试的必要性:仅凭测试数据进行测试是远远不够的,某些风险必须在生产环境中才能暴露。例如,微软的Tay聊天机器人在与用户互动仅一天后就变得充满种族歧视言论。
  5. 数据管理的复杂性:我们需要在更大规模上处理数据版本控制、数据溯源等问题,带来了新的挑战。

软件工程传统方法依然适用

尽管面临新挑战,但许多问题并非完全陌生。本节我们将探讨,现有的软件工程工具和方法经过调整后,如何能有效应对这些挑战。

  • 应对模糊需求:即使没有ML,传统软件系统也常常面临模糊或不完整的规格说明。敏捷方法之所以流行,正是因为我们经常无法预先获得完整的需求,需要客户在看到产品后才知道他们真正想要什么。
  • 从不可靠组件构建安全系统:我们早已掌握从不可靠的硬件或软件组件构建整体安全系统的技术(例如冗余设计、故障安全机制),这些经验可以直接借鉴。
  • 以“世界与机器”的视角看待环境:需求工程中的经典观点(如Michael Jackson的“世界与机器”理论)强调软件与真实世界接口的重要性,这同样是思考机器学习系统环境的正确框架。
  • 处理特征交互:在软件产品线或信息物理系统中,我们长期研究功能交互和组件间的影响,这超出了单元测试的范畴,强调系统测试的重要性。
  • 生产环境测试与实践:混沌工程、A/B测试、持续部署、功能开关等技术,都是软件工程中用于在生产环境中测试和验证系统的成熟实践。

因此,虽然存在新的关注点,但很多挑战并非根本性的新问题。在笔者看来,这更多是一个教育问题而非纯粹的研究问题。我们需要更审慎地思考如何应用软件工程技术来构建机器学习应用,并根据新语境进行调整。

理解数据科学家的工作:以Notebook为例

为了有效协作,软件工程师需要理解数据科学家的工作方式和工具。一个典型的例子就是Jupyter Notebooks。从软件工程的视角看,Notebooks可能显得“糟糕”:全局状态、缺乏函数和抽象、没有测试、大量复制粘贴、文档匮乏、版本控制困难以及可能出现的乱序执行。

然而,如果理解数据科学的工作性质,这些设计选择就有其合理性。数据科学工作具有极强的探索性,Notebooks提供了快速反馈(类似REPL)、可视化支持以及增量计算的能力(无需重新运行整个管道,只需重新执行个别单元格),并且便于编辑和分享最终成果。

核心观点:在探索阶段,严格的文档和测试并非优先事项;Notebooks作为“文学编程”工具,在记录最终成果时更有意义。真正的痛点和研究机会在于如何从Notebooks平滑过渡到生产系统。目前的支持非常有限,代码离开Notebook后,数据科学家很难继续基于生产代码进行实验,导致两者脱节。

软件工程师的贡献:系统级思维与设计

软件工程师可以为AI驱动系统的构建带来至关重要的系统级思维。本节我们来看看几个关键的设计挑战。

1. 用户体验与界面设计
预测结果如何呈现给用户,存在多种不同的设计,适用于不同的场景。例如:

  • Microsoft PowerPoint的设计灵感功能:用户需要主动点击按钮,系统会展示几种设计预览供用户选择,用户可以采纳或撤销。这种设计是非侵入式的,允许用户控制。
  • 智能手表跌倒检测功能:检测到跌倒后,系统可能会在自动呼叫救护车前提供30秒的取消窗口,并给出视听反馈。这种设计更具主动性,旨在采取自动化行动。
    设计时需要权衡:功能的侵入性有多强?交互有多强制?处理错误是否容易?是否会导致通知疲劳?

2. 超越准确率的系统质量权衡
在生产系统中,除了模型准确率,许多其他质量属性同样重要:

  • 训练和运行系统的成本
  • 推理时间与延迟
  • 能耗(对于边缘设备尤为重要)
  • 训练所需的数据量和数据质量
  • 可解释性、鲁棒性、安全性、隐私性、公平性
    一个著名的例子是Netflix Prize竞赛:许多参赛方案的预测准确率远超Netflix原有算法,但Netflix最终没有采用任何一个,因为额外的工程复杂度和运行时成本无法证明其微小的准确率提升是合理的。

3. 架构决策:模型部署于何处?
以实时翻译应用为例,我们需要决定OCR和翻译模型是部署在本地手机、云端,还是混合架构中。这个决策直接影响对模型质量的要求:模型大小、能耗、更新频率、运行成本、延迟等。不同的模型可能支持构建截然不同的系统。

4. 风险分析与安全保障
软件工程中的需求工程专业知识,特别是风险分析技术(如危险分析、故障树分析、失效模式与影响分析),可以系统性地识别系统中可能出错的地方。对于机器学习组件,我们承认它们会犯错,关键是在系统层面设计保障措施。

  • 示例:智能烤面包机:一个学习何时停止烘烤的模型可能偶尔烤焦面包(可接受),但绝不能引发火灾(不可接受)。解决方案不是在模型内追求完美,而是在系统层面添加硬性约束(如温度传感器阈值)或独立的安全机制(如图中的热熔断器),在过热时直接切断电源。

5. 遥测设计
这是AI驱动系统相较于传统软件的一大变化。我们需要设计从生产环境收集反馈的机制,以评估模型表现并获取改进数据。

  • 直接询问:如Skype在部分通话后请求评分。
  • “报告问题”按钮:收集负面反馈。
  • 收集生产数据人工评估:成本较高,可借助众包。
  • 延迟获取真实标签:例如预测航班价格,几天后即可验证。
  • 巧妙的设计引导:以转录服务Otter.ai为例。它提供了一个集成的编辑器,用户可以在其中修正转录文本。当用户进行修改时,系统就获得了精确的错误位置信息,可用于模型训练。为了鼓励用户使用这个编辑器(而非导出到Word),Otter.ai设计了音频与文本同步播放、点击文本跳转音频、高亮低置信度词汇等功能,提升了修正体验,从而自然地收集了高质量的遥测数据。

前进之路:借鉴DevOps模式的跨学科团队协作

如何让软件工程师和数据科学家有效协作?我们可以从DevOps运动中汲取灵感。DevOps解决了开发人员(Dev)和运维人员(Ops)之间因背景、目标和激励不同而产生的冲突。

DevOps的成功要素

  • 共同责任:对应用从构建到运行的全生命周期负责。
  • 共享词汇表:增进相互理解。
  • 共享工具链:开发者通过容器化等技术让部署更简单,同时也获得了更快的发布速度和反馈;运维人员则能提供更利于开发者的基础设施。

构建AI驱动系统的类比
我们需要类似的跨学科团队,成员拥有不同专长但承担共同责任。我们不应抛弃Notebooks,但需要搭建桥梁和基础设施,帮助数据科学家:

  • 思考生产环境中除准确率外的重要质量属性。
  • 将Notebook中的探索平滑地过渡到生产部署。
  • 利用生产数据和遥测反馈来持续改进模型。
    同样,软件工程师需要增进对机器学习技术及其权衡的理解。

核心协作模式
跨学科团队 = 分离的专长 + 共同的责任 + 共享的词汇与工具 + 系统级思维意识

总结

在本节课中,我们一起学习了构建AI驱动系统的核心思想。我们首先强调了焦点不应仅限于构建模型,而应扩展到构建、运营和维护包含机器学习组件的完整系统。我们分析了软件工程师与数据科学家各自不同的专业知识和思维模式,指出两者都是成功所必需的。

我们探讨了AI组件引入的新挑战,如规格缺失、反馈循环和系统级交互,但也指出许多传统软件工程方法经过调整后依然适用。通过理解数据科学家的工作流程(如Notebook的使用)和软件工程师带来的系统级设计思维(如用户体验权衡、多质量属性决策、风险分析、遥测设计),我们看到了两者协作的价值。

最后,我们借鉴DevOps的成功经验,提出了通过组建跨学科团队、建立共同责任、共享词汇和工具来融合两种专长的前进路径。未来的方向在于加强相关教育,并开发支持这种协作的流程与基础设施。

026:构建与维护机器学习系统

在本节课中,我们将学习如何构建、运营和维护包含机器学习组件的软件系统。我们将探讨数据科学家和软件工程师如何协作,并了解如何将传统的软件工程方法应用于机器学习驱动的系统。


概述

本次讲座由卡内基梅隆大学的副教授Christian Kästner主讲。他将讨论在构建包含机器学习组件的生产系统时,数据科学家和软件工程师如何协作以及应该怎样协作。

引言

机器学习不仅仅是构建一个模型,更是构建一个完整的软件产品。以转录服务为例,它不仅仅是一个深度学习模型,还包括用户界面、支付系统、音频文件上传和编辑功能等。构建这样的系统需要跨学科的协作团队。

数据科学家与软件工程师的角色

在构建机器学习系统时,我们需要理解数据科学家和软件工程师的不同角色和专长。

软件工程师的角色

软件工程师不仅仅是程序员,他们需要在有限的资源和信息下做出工程判断。他们关注设计权衡,处理现实世界的复杂性,并在成本、交付时间、正确性、性能和可扩展性等多种质量属性之间进行权衡。一个优秀的软件工程师能够解释决策所依赖的因素,并在具体场景中做出合理的判断。

数据科学家的角色

传统的数据科学家通常具有统计学背景,专注于在给定数据集上构建和评估模型。他们通常在笔记本环境中工作,清理数据、提取特征、构建模型并评估准确率。然而,许多机器学习课程或讨论往往止步于此,很少涉及如何将模型部署到生产环境中。

机器学习系统的独特挑战

将机器学习引入系统会带来一些独特的挑战,但其中许多挑战并非全新。

不可靠的组件

机器学习模型是一个不可靠的组件。我们通常没有明确的规格说明,并且很难定义什么是“错误”。这与传统软件中拥有清晰需求和规格的情况不同。

环境的重要性

机器学习组件的预测会影响现实世界,进而可能影响未来的训练数据,引入偏见和反馈循环。例如,YouTube推荐算法可能因为用户观看行为而过度推荐阴谋论视频。

非局部和非单调效应

系统可能包含多个相互关联的机器学习组件。改进一个组件(如行人检测)可能不会改善整体系统性能,这使得调试和测试变得困难。

大规模数据处理

处理海量数据是机器学习系统的常态,这需要专门的数据处理基础设施和知识。

借鉴传统软件工程

尽管存在挑战,但许多问题并非机器学习独有。软件工程领域已有方法处理不可靠组件、模糊需求、系统测试和生产环境监控。

  • 处理不可靠组件:我们可以通过设计冗余、回退策略和监控来构建高可用系统,就像使用廉价硬件构建可靠的云服务一样。
  • 环境交互:需求工程领域早已研究软件如何感知和影响现实世界,涉及传感器、执行器等方面的考量。
  • 系统测试与交互:我们不仅进行单元测试,还进行系统测试以处理功能交互问题。
  • 生产环境测试:持续部署和A/B测试等方法在机器学习之前就已存在。
  • 大数据处理:数据库社区在流处理和事件溯源等方面拥有丰富经验。

关键在于,当系统变得复杂且具有安全含义时,我们需要更加认真地应用这些经典的软件工程方法。

质量保证的层次

质量保证不应只关注模型准确率,而应扩展到整个系统和开发流程。

模型质量

传统上,数据科学家关注模型的准确率、精确率、召回率等指标。但我们需要进一步思考:

  • 错误并非等价:在癌症检测中,假阴性(漏诊)的代价远高于假阳性(误诊)。我们需要根据错误成本来评估模型。
  • 公平性:确保模型在不同群体(如不同性别、种族)中表现一致。
  • 超越准确率:在生产中,模型的训练时间、更新能力、推理成本(cost_per_prediction)等都至关重要。cost_per_prediction 综合了训练、设计和维护成本,是运营机器学习系统的终极指标之一。

管道(Pipeline)质量

我们应该将模型视为一个自动化管道(Pipeline)的输出。这个管道包括数据收集、清洗、标注、特征工程、训练、评估和部署等步骤。

管道中的任何错误(如数据清洗代码的静默故障)都可能导致模型性能灾难性下降。因此,我们需要像对待软件一样对待这个管道:

  • 为数据清洗代码编写单元测试。
  • 对管道进行端到端测试。
  • 测试错误处理例程(如处理上传失败)。
  • 测试监控基础设施本身是否正常工作。

系统质量

最终,我们关心的是整个系统的质量,而不仅仅是其中机器学习组件的质量。

  • 设计容错:系统可以设计得能够容忍机器学习组件的错误。例如,一个智能烤面包机在预测失败时可能会烤焦面包,但必须通过硬件保险丝等机制防止引发火灾。
  • 用户体验集成:如何将预测结果集成到用户界面中至关重要。例如,智能家居系统是应该自动执行操作,还是每次都需要确认?是否提供了撤销操作的途径?
  • 系统目标对齐:系统的总体目标(如最大化利润、用户留存、社会效益)可能与单一模型的优化目标(如准确率)不完全一致。更快的推理速度、更少的严重错误或更好的可解释性有时比单纯的准确率提升对系统目标贡献更大。

生产环境测试与遥测设计

由于系统目标复杂且真实数据难以模拟,在生产环境中进行测试(A/B测试、金丝雀发布等)变得非常重要。这要求我们精心设计系统的遥测(Telemetry)能力。

以下是一个设计遥测系统的思考示例:

假设有一个“识鞋购物”App,用户拍照识别鞋子并购买。如何评估生产环境中模型的表现和整体产品效果?

  • 直接询问用户:每次识别后都询问是否正确,但这会打扰用户。
  • 追踪购买行为:用户最终是否购买?这更接近商业目标,但不能直接反映识别准确性。
  • 创造性间接指标:如果用户快速对同一只鞋连续拍照,可能意味着首次识别结果不佳。这是一种无侵入式的反馈信号。
  • 人工标注抽样:付费请人对一部分识别结果进行标注验证。
  • 利用后续事实:对于预测任务(如机票价格涨跌),只需等待一段时间即可验证预测准确性。

设计良好的遥测系统需要创造性思维,并考虑隐私、数据量、采样策略和版本隔离等工程挑战。

以转录服务为例,其编辑器通过同步音频文本、高亮不确定词汇,巧妙地鼓励用户在界面内修正转录错误。这无形中收集了高质量的纠错数据(即标注数据),用于后续模型改进,是一个优秀的系统级遥测设计。

构建跨学科团队

要成功构建机器学习驱动系统,我们需要数据科学家和软件工程师紧密协作的跨学科团队。这类似于DevOps的理念:

  • 不是寻找“独角兽”:即不苛求个人同时精通数据科学和软件工程。
  • 培养“T型人才”:团队成员应拥有核心专长(如数据科学),同时对另一领域(如软件工程)有足够深的理解,能够有效沟通。
  • 共同责任与协同:数据科学家需要具备系统思维,考虑自动化、生产环境性能和安全性。软件工程师需要理解数据科学的工作流程和需求,并提供基础设施支持(如便于使用的遥测数据)。
  • 联合工具与流程:建立共享的词汇表、工具链和流程,让协作更顺畅。

总结

本节课我们一起学习了构建和维护包含机器学习组件的软件系统所涉及的各个方面。

我们首先明确了数据科学家和软件工程师在项目中扮演的不同角色及其专长。接着,我们探讨了机器学习系统带来的独特挑战,但也发现许多挑战可以通过调整和借鉴传统软件工程方法来解决。

课程的核心部分聚焦于质量保证。我们认识到,不能只停留在评估模型准确率上,而需要将视野扩展到模型的其他属性(如推理成本)、整个模型生产管道的可靠性,以及最终整个系统的质量和商业目标的实现。我们特别探讨了如何通过创造性的遥测系统设计,在生产环境中有效地监控和评估系统表现。

最后,我们强调,成功的关键在于构建跨学科的协作团队。团队成员需要相互理解、尊重对方的专长,并围绕共同的目标和责任紧密合作,才能高效地构建出稳健、有价值的机器学习驱动系统。


延伸阅读与资源

  • 书籍推荐:《Building Machine Learning Powered Applications》
  • 学术论文合集:可向讲师咨询获取。
  • 课程材料:讲师在卡内基梅隆大学的相关课程资料可供参考。

027:软件工程在机器学习中的作用

在本节课中,我们将探讨当机器学习被引入软件产品时,软件工程如何发生变化,以及我们应如何重新思考软件工程实践。我们将重点关注构建包含机器学习组件的端到端产品所面临的挑战,并以测试为例,详细说明从模型测试到系统测试的思维转变。

概述:从模型到产品

近年来,机器学习取得了惊人的进展,例如目标检测技术。然而,我们关心的不仅仅是模型本身,而是如何利用这些技术构建产品。无论是自动驾驶汽车、人行道送货机器人,还是谷歌相册的图片索引功能,机器学习都是产品中的一个组件。构建这类产品非常困难,常常面临从原型到产品的转化难题,并可能在实际应用中造成危害。

上一节我们概述了构建机器学习产品的挑战,本节中我们来看看传统的以模型为中心的视角与产品系统视角有何不同。

数据科学与机器学习运维:从模型到API

在数据科学领域,我们通常以模型为中心。给定一个数据集,使用现有库构建模型,并在标注数据上评估其准确率。这通常被视为一个从模型需求、数据收集、标注到模型构建和评估的管道。

然而,谷歌在2014年意识到,要将机器学习投入生产(例如欺诈检测),需要的远不止训练模型的代码。围绕模型的数据收集、服务基础设施、监控等代码量巨大,机器学习部分本身在代码量上并非系统中最庞大的部分。这催生了机器学习运维运动,旨在自动化并扩展模型部署和监控的步骤。

如今,大多数基础设施都有开源项目支持,复杂性在于如何将它们组合起来。但所有这些努力都是为了部署一个模型,而非一个产品。模型只是系统中的一个组件。要构建一个像谷歌相册这样的应用程序,你还需要前端、后端、流处理、支付等所有其他部分。在自动驾驶汽车等复杂产品中,可能涉及数十个相互作用的模型,而这只是整个系统的一小部分。

因此,我们需要的是系统思维。系统由许多组件构成,其中一些是机器学习组件(模型或训练代码)。该系统旨在与环境交互,对现实世界产生影响,这才是构建产品的意义所在。

上一节我们讨论了从模型管道到产品系统的视角转变,本节中我们来看看这种转变如何具体体现在测试实践中。

模型测试:准确率 vs. 正确性

我们通过测试的视角来阐释这些变化。模型测试与传统软件测试在一个关键方面存在差异。

在传统软件工程中,我们测试正确性。我们有一个软件应如何运行的规范(即使是模糊的),并编写测试用例来验证对于给定输入,输出是否符合预期。如果测试失败,我们就发现了一个缺陷。

而机器学习模型的评估方式不同。我们使用测试数据,并接受模型会犯一些错误。我们报告的是准确率(例如92%),而不是追求100%的正确性。我们通常没有明确的、形式化的规范来确定一个输出绝对“正确”,通常依赖人工判断。例如,一个模型可能将会议中心识别为“健身房”,这可能算对,也可能算错。

核心概念:所有模型都是错误的(即都是近似),但有些模型是有用的。关键问题不是“模型是否正确?”,而是“这个模型对于特定应用是否足够好?”

这种差异源于不同的推理方式。传统软件工程使用演绎推理,基于数学概念和规范进行证明。机器学习使用归纳推理,基于观察进行概括,没有“证明”的概念。

因此,作为软件工程师,正确的抽象是将模型视为一个不可靠的函数。它大多时候能完成你想要的工作,但并非总是如此。你接受一定比例的失误,这些失误可能不可预测,且模型本身通常是不透明的黑盒。我们根据准确率而非正确性来评估它。

鉴于这种根本差异,许多传统的软件测试方法(如专注于发现错误的模糊测试)在机器学习语境下意义不大,因为找到错误预测很容易。更重要的问题是:这些错误是否重要?是否有人愿意修复它们?

上一节我们介绍了模型测试以准确率为核心的特点,本节中我们来看看如何将测试与产品需求结合起来。

需求驱动的测试:从产品目标到模型需求

模型测试不应孤立进行,而应基于需求。我们需要思考系统对模型有何要求。例如,对于人行道机器人和谷歌相册,对目标检测模型的期望截然不同。机器人可能需要精确检测地面附近的障碍物(如脚),而不太关心检测飞机;而谷歌相册则需要检测各种物体,但对准确率的要求可能不那么苛刻。

我们通常从目标角度讨论需求。产品的目标(如良好的用户体验、广告展示)与模型的目标(如准确的目标检测)并不相同。更准确的模型不一定能改善用户体验或增加广告收入。同样,用户的目标(如快速找到照片)与产品目标也不完全一致。

因此,更有意义的问题是:你究竟需要多高的准确率?在系统设计中,除了准确率还需要考虑什么?

一个来自Booking.com的例子很有启发性。他们发现,更准确的模型通常带来更多利润,但有时更差的模型反而利润更高,反之亦然。原因可能是模型过于精准导致用户感到“诡异”。这说明了不能一味优化准确率,最终应关注的是系统目标

系统或产品需求应驱动测试策略。在软件工程中,我们常用V模型将需求映射到测试策略。从产品需求出发,思考如何测试产品的有效性,再分解到组件(如模型)需求。

然而,机器学习项目往往更具探索性。我们可能一开始不知道什么是可行的,需要根据模型能力反馈调整产品需求。此外,团队中不同角色(产品经理、软件工程师、数据科学家)的沟通也是一大挑战。

一些研究试图通过领域特定语言或图形界面来帮助团队在项目早期就模型需求达成一致,例如讨论可接受的准确率、延迟、鲁棒性等。

以下是进行需求讨论时需要考虑的一些方面:

  • 目标分布:我们是否关心异常值?
  • 特定数据切片:是否需要特别关注某些类别(如“脚”或“飞机”)?
  • 其他质量属性:推理延迟、训练成本、硬件需求、鲁棒性、可解释性等。

因此,模型测试不同于传统软件测试,并且不能随机选取数据计算准确率。应该思考模型将如何被使用,这决定了应如何测试它。

上一节我们探讨了如何基于产品需求测试模型,本节中我们进一步思考如何超越模型本身,在系统层面防止危害。

超越模型:系统安全与缓解策略

错误会导致危害。如果我们想减轻危害,可以尝试训练更准确的模型,但这有其极限。模型始终是一个不可靠的组件。即使准确率达到99.99%,它最终仍会犯错。

因此,我们应该预见错误必然发生,并思考如何避免这些错误造成危害。我们可以设计缓解策略,即不单纯依赖目标检测模型,而是引入其他机制。例如:

  • 为机器人配备专门的闪烁灯检测器,一旦发现可能涉及紧急情况,就将控制权移交远程人类操作员。
  • 在机器人上设置物理紧急停止按钮,允许路人在其即将进入犯罪现场等危险区域时将其停止(但需平衡滥用风险)。
  • 像谷歌那样,在无法可靠区分人类与灵长类动物时,直接选择不显示相关识别结果,以避免冒犯性错误。

所有这些缓解策略都存在于模型之外,属于系统设计、人机交互的范畴。核心思想是:不单独依赖模型,引入冗余机制。

核心概念:“AI安全”本身是一个矛盾修辞。AI代码不会伤人,只有当它被置于系统中,与环境(包括人类)交互时,才可能造成危害。因此,安全是一个系统属性,无法仅在模型层面进行推理。

安全工程领域(如故障树分析、STPA等方法)拥有数十年的经验,专注于思考最坏情况如何发生,以及如何通过消除单点故障等方式进行缓解。例如,对于自动列车门,除了视觉检测器,还可以增加压力传感器。现在需要两者同时失效,事故才可能发生,风险大大降低。

我认为几乎所有我们关心的属性——安全性、安全性、公平性、透明度、问责制——都是系统属性,而非模型属性。我们可以通过模型之外的设计策略,使产品更安全、更公平、更透明。

一个例子是提示注入攻击。将秘密交给一个不可靠的大语言模型,并试图说服它不要泄露秘密,这本身就是一个不安全的产品设计。真正的安全解决方案应在系统层面,而不是试图“硬化”提示词。

挑战在于如何更轻松地预测和缓解错误,如何让开发人员更愿意采用这些已有的安全工程实践。我们需要更多地研究产品本身,而不仅仅是模型组件。

回到测试的主题,我们不仅需要测试模型(基于需求),还需要考虑模型之外的整个产品系统。

上一节我们强调了在系统层面设计缓解措施的重要性,本节中我们来看看如何对这些完整的系统进行测试。

系统测试:集成与生产环境测试

我们需要测试整个产品系统。单元测试相对容易,但重点应放在完整的测试用例上。

如果我们实施了安全保障措施,就应该测试它们是否有效。如果保障措施中涉及人类(如人工审核),可能需要进行用户研究,确保人类操作员理解其职责且不会产生疲劳。人机回环的设计 notoriously hard。

需要进行集成测试,测试错误处理机制。即使没有完整的系统,也可以通过模拟故障来测试安全机制和恢复机制是否正常工作。

对于包含多个交互模型的复杂系统,测试更具挑战性。最终,很多系统测试无法避免,尤其是对于机器人这类产品,大量测试需要在生产环境中进行。

我认为生产环境测试比以往任何时候都更重要。这包括如何进行A/B测试:在生产系统中部署一个模型版本,观察其表现(同时避免造成危害),快速检测问题并回滚。像Grafana、Prometheus这样的可观测性和监控工具至关重要。

因此,我们需要关注一整套测试策略,而不仅仅是模型测试。

未来方向:协作与教育

目前,我们对构建机器学习产品所面临的问题已有深入了解,并且拥有许多解决方案的要素。我们拥有数十年的软件工程经验,包括流程、生命周期、需求、安全工程、集成测试和生产环境测试等。我们需要运用这些经验。

在传统软件工程中,我们根据系统复杂性和风险级别投入相应资源。而机器学习让我们能够构建更复杂、潜在危害更大的系统,但我们有时仍像开发简单网站一样对待它们。我们需要更认真地对待工程实践,在需求工程、错误预测和缓解等方面进行投入。

我认为当前最大的改进机会在于两个方面:

  1. 协作:团队中不同角色(数据科学家、软件工程师、产品经理)之间存在沟通障碍。他们说着不同的语言,在需求规划、数据收集、系统集成等多个环节产生摩擦。我们需要更好地支持这种跨学科协作。
  2. 教育:我们需要培养T型人才。即拥有某一领域深度专业知识(如数据科学),同时对其他相关领域(如软件工程、安全工程)有足够了解,能够进行有效沟通。软件工程师需要明白模型是不可靠组件,应提前为错误做计划。数据科学家需要主动询问模型将如何被使用,理解生产中的数据分布和除准确率外的重要属性。

我通过课程教学致力于此,旨在覆盖从需求到运维、再到负责任工程的整个知识范围,培养学生对软件工程和机器学习交叉领域的整体理解。

总结

本节课我们一起学习了在构建包含机器学习组件的产品时,软件工程思维需要发生的转变。我们探讨了从以模型为中心的视角转向以系统为中心的视角的必要性。具体通过测试的例子,我们分析了模型测试(关注准确率而非正确性)、需求驱动的测试、系统级安全缓解策略以及完整的系统测试流程。最后,我们强调了跨学科协作和拓宽教育对于成功构建可靠、负责任的AI驱动系统至关重要。构建机器学习产品是困难的,但通过系统性的工程方法和良好的团队协作,我们可以更好地应对这些挑战。

posted @ 2026-03-26 01:39  绝不原创的飞龙  阅读(2)  评论(0)    收藏  举报