隐私保护的机器学习-全-
隐私保护的机器学习(全)
原文:
annas-archive.org/md5/66e779fb01ae94762b26e79699043d34译者:飞龙
前言
在当今互联的世界中,个人和组织生成的大量数据已成为开发强大机器学习模型的有价值资源。这些模型有可能彻底改变行业、改善服务和揭示前所未有的洞察。然而,这个巨大的机会也伴随着一个重大的挑战:保护敏感数据的隐私和安全。
随着数据泄露和隐私问题继续成为头条新闻,个人和组织越来越意识到与共享和分析他们的数据相关的潜在风险。对能够同时利用机器学习力量并保护个人隐私以及保护敏感信息的创新解决方案的需求日益增长。
这本书,《隐私保护机器学习》,旨在解决这些紧迫的问题,并探索旨在调和机器学习力量与数据隐私必要性的最新技术和方法。我们深入探讨隐私保护技术、算法和框架的复杂世界,这些技术、算法和框架使组织能够在遵守严格的隐私法规和伦理考量的情况下,充分发挥其数据潜力。
在本书的每一页中,我们提供了该领域的全面概述,涵盖了基本概念和高级技术。我们讨论了与机器学习相关的各种隐私威胁和风险,包括成员推断攻击和模型反演攻击。此外,我们还探讨了机器学习中的隐私法律和伦理方面,揭示了诸如通用数据保护条例(GDPR)和加州消费者隐私法案(CCPA)等法规。
本书的一个核心主题是探索能够实现安全且隐私保护的机器学习的隐私增强技术。我们深入研究了差分隐私、同态加密、安全多方计算和联邦学习等领域。我们考察了它们的底层原理、优势和局限性,为您提供选择最适合您特定隐私需求的技术所需的必要工具。
随着人工智能和数据科学领域的持续进步,确保隐私始终处于创新的前沿至关重要。
本书旨在为对隐私与机器学习交叉领域感兴趣的研究人员、实践者和政策制定者提供宝贵的资源。通过理解隐私保护机器学习中的挑战、解决方案和新兴趋势,我们可以共同塑造一个隐私与创新和谐共存的未来。让我们共同踏上探索隐私保护机器学习世界的旅程,并解锁人工智能的变革潜力,同时维护个人和组织的权利和隐私。
本书面向的读者
这本书面向对隐私和机器学习交叉领域感兴趣的广泛读者。目标受众包括以下几类:
-
数据科学家和机器学习从业者:与数据和开发机器学习模型工作的专业人士将发现这本书非常有价值。它提供了隐私保护技术和框架的见解,这些技术和框架可以集成到他们现有的工作流程中,使他们能够构建安全且具有隐私意识的机器学习系统。
-
研究人员和学者:计算机科学、数据科学、人工智能和隐私领域的学者和研究人员将从对隐私保护机器学习技术的全面覆盖中受益。本书探讨了该领域的最新进展和挑战,为深入研究提供了坚实的基础。
-
隐私专业人士和数据保护官:负责确保符合隐私法规和保护敏感数据的隐私专业人士将发现这本书与他们的工作高度相关。它涵盖了机器学习中隐私的法律和伦理方面,为将隐私增强技术纳入组织实践提供了指导。
-
政策制定者和政府官员:参与制定隐私法规和指南的政策制定者和政府官员可以从这本书中获得宝贵的见解。它探讨了监管环境,并讨论了隐私保护机器学习对政策制定和实施的影响。
-
行业领袖和决策者:来自各个行业的执行人员、经理和决策者将发现这本书有助于理解机器学习中隐私的重要性。它提供了实际案例和使用场景,展示了隐私保护技术的益处,使他们在数据保护策略方面做出明智的决策。
-
隐私倡导者和活动家:倡导隐私权利和数据保护的个人和组织将发现这本书有助于理解隐私保护机器学习的技术方面。它为他们提供了知识,使他们能够参与有见地的讨论,并为发展隐私友好的实践和政策做出贡献。
无论你在机器学习或隐私方面的专业知识水平如何,这本书都提供了对该主题的全面介绍,并逐步建立基础概念。它提供了理论洞察力和实际应用,使不同背景的读者能够应对隐私保护机器学习带来的挑战和机遇。
本书涵盖的内容
第一章,《数据隐私、隐私泄露和威胁建模导论》,作为数据隐私各个方面的入门介绍。我们首先探讨数据隐私的概念,区分敏感数据和个人信息敏感数据。此外,我们还深入研究数据隐私法规领域,强调其在保护个人信息的意义。本章还介绍了隐私设计概念,强调其在确保数据生命周期中隐私的重要性。此外,我们通过讨论显著的案例和针对大型企业公司施加的罚款,来考察隐私泄露的现实影响。这些例子揭示了未能充分保护敏感数据所带来的后果。然后,本章深入探讨使用 LINDDUN 框架的隐私威胁建模。我们解释了可链接性和可识别性威胁的概念,并提供实例以增强理解。通过全面涵盖这些主题,本章为书中讨论的隐私保护技术和方法的深入探索奠定了基础。它使你具备理解数据隐私的重要性、隐私泄露的风险以及减轻这些风险的策略,同时实现数据分析和利用的必要知识。
第二章,《机器学习阶段及每个阶段的隐私威胁/攻击》,概述了各种类型的机器学习,包括监督学习、无监督学习和强化学习,并探讨了机器学习阶段和流程。它还提供了持久化 ML 模型的各种格式以及模型持久化所面临的挑战。此外,它强调了在机器学习过程的每个阶段考虑隐私的重要性。我们深入研究与机器学习不同阶段相关的隐私需求,即训练数据隐私、输入数据隐私、模型隐私和推理/输出数据隐私。本章接着考察针对每个阶段的特定隐私攻击。我们关注对训练数据、模型持久化和推理过程构成的威胁。我们深入探讨模型反演攻击、模型推理攻击和训练数据提取攻击,并提供了使用开源框架详细说明这些攻击如何工作的实例。
第三章, 隐私保护数据分析概述与差分隐私简介,作为隐私保护数据分析、隐私增强技术和差分隐私概念的介绍。这些主题被探讨以提供理解和实施数据分析与机器学习中隐私保护措施的基础。本章还涵盖了 SQL 的重建攻击,探讨了实际应用案例,并介绍了如何使用提供强大隐私保护的 Open Diffix 框架来预防此类攻击。具体来说,详细探讨了差分隐私的概念,包括隐私损失、隐私预算、差分隐私机制以及局部/全局差分隐私。
第四章, 差分隐私算法与差分隐私的局限性,深入探讨了在差分隐私中使用的各种算法(拉普拉斯、高斯、计数、求和、均值、方差、标准差和阈值算法)以及差分隐私的局限性。
第五章, 使用开源框架开发具有差分隐私的应用程序,深入探讨了使用开源框架的差分隐私(DP)以及使用机器学习(ML)和深度学习(DL)开源框架实现欺诈检测用例的实施。本章还概述了利用差分隐私的实际情况。
第六章, 联邦学习的需求与使用开源框架实现联邦学习,涵盖了联邦学习(FL)的重要性以及与将数据发送到中央服务器进行模型训练相关的隐私问题。它探讨了独立同分布(IID)和非 IID 数据集的概念,以及非 IID 数据的不同类别。理解这些数据特征对于有效地实施联邦学习至关重要。此外,它讨论了联邦学习技术(FedAvg、FedYogi、FedSGD 等)并介绍了支持联邦学习实现的可用开源框架。它还使用 Flower 开源框架在金融领域实现了一个用例。
第七章,联邦学习基准、初创企业和下一个机会,专注于联邦学习数据集和基准的比较。它深入探讨了可用的联邦学习基准,并提供了如何使用它们来评估联邦学习算法和技术的方法。此外,它讨论了选择最适合您特定项目的联邦学习基准的过程,考虑了数据特性和评估标准等因素。它还探讨了联邦学习领域的最先进研究,突出了该领域的最新进展、方法和挑战,并揭示了正在积极从事联邦学习并专注于特定领域的初创企业。
第八章,同态加密和多方安全计算,探讨了各种增强隐私的技术,包括加密、匿名化和去标识化。它讨论了这些技术的原理和局限性,了解它们在保护敏感数据的同时保持数据有效性的有效性。它涵盖了同态加密(HE)的概念及其数学基础,并探讨了如何在机器学习场景中应用 HE,允许在加密数据上直接执行计算而不损害隐私。此外,我们讨论了多方安全计算(SMC)及其用例,并展示了使用私有集交互(PSI)SMC 技术的一个用例实现。在章节末尾,我们提供了零知识证明(ZKP)的高级概述,这是一种密码学协议,允许一方在不透露信息本身的情况下证明对某些信息的了解。
第九章,保密计算——是什么、为什么以及当前状态,深入探讨了针对存储在内存中的数据的隐私和安全攻击。我们讨论了此类攻击的漏洞和潜在风险,强调了在整个生命周期中保护数据的重要性。我们介绍了保密计算的概念,重点关注可信执行环境(TEEs),并探讨了源代码认证的概念及其在减轻内部威胁攻击方面的作用。通过验证源代码的完整性和真实性,组织可以建立信任并确保恶意行为者无法危害其系统的安全性。此外,我们比较了主要云服务提供商(如 AWS、Azure、GCP 和 Anjuna)对安全区域的支持。我们评估了这些提供商提供的功能、特性和安全措施,使您在选择部署需要安全区域的平台时能够做出明智的决定。
第十章,大型语言模型中的隐私保护,介绍了生成式人工智能和 LLMs 的基础知识,以及与之相关的隐私漏洞,以及在使用这些模型时保护隐私的技术和方法。本章涵盖了使用开源 LLMs 开发 LLM 应用程序以及保护它们免受隐私攻击(提示注入攻击、成员推理攻击等),并以 LLMs 的最新隐私研究结束。
要充分利用本书
虽然不需要了解人工智能(AI)、机器学习(ML)和生成式人工智能(GenAI),但对此中任何一种有所了解将有助于理解本书中涵盖的一些概念。了解 Python 将有助于执行每章提供的示例源代码。
| 本书涵盖的软件/硬件 | 操作系统要求 |
|---|---|
| Python 3.7 或更高版本 | Windows、macOS 或 Linux |
| Jupyter Notebook |
为了深入探讨本书中一些更复杂的概念,我们在 GitHub 上创建了 Jupyter Notebook 文件(详情见下文)。
如果您使用的是本书的数字版,我们建议您亲自输入代码或从本书的 GitHub 仓库(下一节中提供链接)获取代码。这样做将有助于您避免与代码复制和粘贴相关的任何潜在错误。
下载动手实验室和示例代码文件
您可以从 GitHub(github.com/PacktPublishing/Privacy-Preserving-Machine-Learning)下载本书的动手实验室和示例代码文件。如果动手实验室或任何代码有更新,这将在之前提到的 GitHub 仓库中更新。
我们还提供其他丰富的图书和视频的代码包,可在 GitHub(github.com/PacktPublishing/)上找到。查看它们吧!
使用的约定
本书中使用了多种文本约定。
文本中的代码:表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称。以下是一个示例:“安装 Jupyter Notebook(pip install notebook)。”
代码块设置如下:
import numpy as np
from sklearn.linear_model import LinearRegression
# Prepare sample input data with two features (feature 1, feature 2
X = np.array([[10, 10], [10, 20], [20, 20], [20, 30]])
# Assume that target feature has some relationship with the input features with the formula y = 3 * x_1 + 5 * x_2 + 50
y = np.dot(X, np.array([3, 5])) + 50
当我们希望您注意代码块中的特定部分时,相关的行或项目将以粗体显示:
SELECT DEPTNO, DEPTNAME, MGRNO, MGRNAME, MGREMAILID,LOCATION FROM DEPARTMENT;
任何命令行输入或输出都如下所示:
!pip3 install tmlt-analytics
!pip3 install onnx --user
粗体:表示新术语、重要单词或您在屏幕上看到的单词。例如,菜单或对话框中的单词以粗体显示。以下是一个示例:“攻击者的代码旨在通过在相同的数据集上训练一个新的LogisticRegression模型(extracted_model)来执行模型提取攻击。”
小贴士或重要注意事项
看起来是这样的。
联系我们
我们始终欢迎读者的反馈。
customercare@packtpub.com,并在邮件主题中提及书名。
勘误表:尽管我们已经尽一切努力确保内容的准确性,但错误仍然可能发生。如果您在此书中发现了错误,我们将非常感激您向我们报告。请访问www.packtpub.com/support/errata并填写表格。
copyright@packt.com,并附上材料的链接。
如果您有兴趣成为作者:如果您在某个领域有专业知识,并且您有兴趣撰写或为书籍做出贡献,请访问authors.packtpub.com。
分享您的想法
一旦您阅读了《隐私保护机器学习》,我们很乐意听听您的想法!请点击此处直接访问此书的亚马逊评论页面并分享您的反馈。
您的评论对我们和科技社区都很重要,并将帮助我们确保我们提供高质量的内容。
下载此书的免费 PDF 副本
感谢您购买此书!
您喜欢在路上阅读,但无法携带您的印刷书籍到处走?
您的电子书购买是否与您选择的设备不兼容?
请放心,现在,每购买一本 Packt 书籍,您都可以免费获得该书的 DRM 免费 PDF 版本。
在任何地方、任何设备上阅读。直接从您喜欢的技术书籍中搜索、复制和粘贴代码到您的应用程序中。
优惠不会就此结束,您还可以获得独家折扣、时事通讯和每日免费内容的每日电子邮件。
按照以下简单步骤获取优惠:
- 扫描二维码或访问以下链接

packt.link/free-ebook/9781800564671
-
提交您的购买证明
-
就这样!我们将直接将免费 PDF 和其他优惠发送到您的电子邮件。
第一部分:数据隐私和机器学习简介
本部分介绍了数据隐私的基本概念,以及敏感数据与个人敏感数据的区别,并讨论了数据隐私法规的重要性。隐私设计概念被讨论,强调将隐私措施主动集成到系统和流程中。此外,还考察了主要企业公司中的显著隐私泄露事件,突出了此类事件可能带来的后果和风险。本简介为理解数据隐私的重要性以及需要强大的隐私措施奠定了基础。本部分还详细介绍了使用 LINDDUN 框架进行隐私威胁建模。
本部分的第二章专注于机器学习管道的不同阶段以及在每个阶段可能发生的隐私威胁和攻击。我们将探讨数据收集、数据预处理、模型训练和推理的阶段。在每个阶段内,将详细讨论特定的隐私威胁和攻击,例如模型反演攻击和训练数据提取攻击,并提供示例说明。强调了保护训练数据隐私、输入数据隐私、模型隐私和推理/输出数据隐私的重要性。本部分突出了与机器学习中的隐私相关的潜在风险和挑战,强调了在整个过程中需要强大的隐私保护技术。对机器学习管道每个阶段的隐私威胁和攻击的探索,有助于揭示在机器学习系统中保护隐私的挑战。
本部分包含以下章节:
-
第一章**,数据隐私、隐私泄露和威胁建模简介
-
第二章**,机器学习阶段及每个阶段的隐私威胁/攻击
第一章:数据隐私、隐私泄露和威胁建模简介
在当今数字时代,隐私保护机器学习(ML)变得越来越重要,因为个人数据在各种行业中无处不在,包括医疗保健、金融和营销。虽然机器学习可以带来许多好处,如提高准确性和效率,但它也引发了关于隐私和安全的重大担忧。许多人越来越关注使用他们个人数据的风险,包括未经授权的访问、滥用和滥用。此外,还有如通用数据保护条例(GDPR)和加州消费者隐私法案(CCPA)等法规,要求组织在处理个人数据时遵守严格的隐私指南。
本书全面介绍了在有效实现机器学习(ML)的同时保护个人隐私的技术和工具。本书将帮助研究人员、机器学习工程师、软件工程师和从业者理解隐私的重要性以及如何将其融入他们的机器学习算法和数据处理流程中。本书架起了隐私理论基础与隐私保护机器学习技术实际应用之间的桥梁,使得在不妨碍个人隐私的前提下实现数据驱动的决策。
在本章的介绍中,我们将学习关于隐私的知识,包括数据隐私;敏感数据与个人敏感数据的区别;数据隐私法规;隐私设计(PbD)概念;以及为什么数据隐私很重要。在讨论了这些概念之后,我们将详细介绍使用 LINDDUN 框架进行隐私威胁建模,并通过示例解释可链接性和可识别性威胁。本章将帮助您更好地理解隐私及其重要性。我们将从高层次讨论关键的隐私法规,如 GDPR 和 CPRA,以及隐私威胁建模。在本章末尾,我们将讨论隐私保护机器学习的必要性以及一个用例。
我们将涵盖以下主要主题:
-
隐私和数据隐私的含义是什么?
-
隐私设计及案例研究
-
隐私泄露
-
隐私威胁建模
-
隐私保护机器学习的必要性
隐私和数据隐私的含义是什么?
Alan Westin 的理论将隐私描述为对个人信息处理和传达给他人的控制。Irwin Altman 补充说,隐私包括限制社交互动,并包括调节个人空间和领土。
个人数据包括任何可以单独使用或与其他元素结合使用以识别个人的信息,例如他们的姓名、年龄、性别、个人识别号码、种族、宗教、地址、电子邮件地址、生物识别数据、设备 ID、医疗数据和遗传数据,这些信息基于数据起源国规定的法规。
隐私是指个人保留其信息(无论是个人信息还是非个人信息)的能力,并基于他们的同意共享数据。隐私帮助个人维持对其个人生活的自主权。
数据隐私侧重于个人数据的用途和管理,以及确保数据以适当的方式收集、处理、共享和使用/推断。
隐私法规
根据联合国贸易和发展会议(UNCTAD)的最新统计数据,71%的国家都有自己的隐私法律,这显示了全球隐私和数据保护的重要性。
大多数隐私法律处理敏感个人数据的收集、数据处理、与其他方共享数据以及数据主体权利。世界上 194 个国家的 137 个国家都有法律立法来保护数据和个人的数据隐私。

图 1.1 – 截至 2021 年 12 月的全球隐私立法
来源:unctad.org/page/data-protection-and-privacy-legislation-worldwide
在全球范围内的这些隐私法规中,最受欢迎和最广泛实施的是欧洲的GDPR和美国 的CCPA。
根据GDPR,个人数据被定义为如下:
数据主体如果可以通过直接或间接的方式被识别,特别是通过诸如姓名、身份证号码、位置数据、在线标识符或几个特殊特征(这些特征表达了这些自然人的身体、生理、遗传、心理、商业、文化或社会身份)来识别,则被视为可识别的。在实践中,这还包括所有可以以任何方式分配给个人的数据。例如,个人的电话、信用卡或员工编号、账户数据、车牌、外貌、客户编号或地址都是个人数据。
在这个定义中,关键词是个人是否可以通过提及的标识符(如姓名)直接或间接地被识别。我们将了解更多关于间接识别的信息,以及个人如何通过间接标识符被识别,以及他们的隐私在“隐私威胁建模”部分是如何被侵犯的。
GDPR还定义了敏感个人数据,包括遗传、生物识别和健康数据,以及揭示种族和民族起源、政治观点、宗教或意识形态信念或工会成员资格的个人数据。大多数法规在处理个人数据、非个人数据和敏感个人数据时都有涵盖以下内容的条款/部分:
-
个人数据的目的、范围和定义:隐私法的目的,指定其范围,概述受法律保护的数据类型和实体。它明确了法律框架的意图、适用性和术语的定义,如个人数据和敏感个人数据。
-
隐私执法机构:法规定义了数据保护机构或监督机构的作用,负责监督法律遵守情况,提供指导,并处理投诉。
-
罚款和处罚:大多数法律根据该国隐私违规的性质有不同的罚款/处罚。例如,GDPR 规定罚款为 2000 万欧元,或公司前一年度全球总营业额的 4%,以较高者为准,对于严重违规。
-
权利:一些国家将隐私视为该国人民的基本权利。每个个人都有权对自己的数据进行管理,即知情、删除、遗忘和删除数据。
以下表格列出了全球范围内流行隐私法定义的数据主体权利:
| 隐私法 | 数据主体权利 |
|---|---|
| GDPR | 知情权 |
| CCPA | 知情权 |
| LGPD(这是巴西的一般个人数据保护法 – Lei Geral de Proteção de Dados(LGPD)) | 知情权 |
表 1.1 – 数据主体权利
我们已经概述了隐私、各国隐私法规以及数据主体请求(个人权利)。
现在我们来了解更多关于 PbD 的信息,它是什么,以及它是如何帮助保护数据隐私的。
隐私设计原则与案例研究
PbD 的概念由 Ann Cavoukian 在 20 世纪 90 年代创造,并在她的 2009 年演讲“隐私设计:终极研讨会”中提出。正如 Cavoukian 所说,PbD 的概念不仅包括技术。
PbD 是一个框架,它促进了隐私和数据保护原则在系统、产品和服务的开发和设计中的整合。
PbD 框架有七个基础原则。这些原则的目标是确保隐私被嵌入到系统开发的每个阶段,并保护数据主体的隐私权利:
-
主动而非被动措施:PbD 要求从系统设计和开发之初就将隐私考虑因素整合进去,而不是作为事后补充。
-
隐私作为默认设置:PbD 要求默认将隐私设置设置为最高级别,并且用户必须选择接受更侵入性的设置。
-
端到端安全:PbD 要求在整个系统的生命周期中,从设计、开发到部署和退役,将隐私和安全措施整合在一起。我强烈建议采用“从隐私开始”的方法,而不是左移隐私。这样,隐私从软件需求阶段就开始了。
-
完整功能:PbD 要求隐私和数据保护措施以不损害系统或产品功能的方式整合。
-
可见性和透明度:PbD 要求用户了解与系统或产品相关的隐私风险,并且能够获取有关其数据如何被收集、使用和共享的信息。
-
尊重用户隐私:PbD 要求用户对其个人数据拥有控制权,并且其隐私偏好应受到尊重。
-
全面方法:PbD 要求将隐私和数据保护考虑整合到系统或产品的所有方面,包括其技术设计、操作程序和商业实践。
近年来,随着数据驱动技术的快速扩张,隐私问题日益突出,PbD 方法的重要性也日益增加。
PbD 现在被广泛认为是处理个人数据的组织的一种最佳实践,并且是数据保护法规(如欧盟的 GDPR)的一个重要组成部分。
总体而言,PbD 是一个旨在确保隐私是任何系统或产品的组成部分,并且数据保护从开发过程的开始就被考虑,而不是事后考虑的全面框架。
让我们通过一个例子来详细了解 PbD。
示例 - 社交媒体平台中的隐私设计
PbD 是一个框架,倡导从设计、架构开始将隐私考虑嵌入到系统、产品和服务的各个方面。通过将隐私作为核心组件,组织可以主动解决隐私问题并确保用户数据得到保护。这个案例研究示例说明了社交媒体平台如何实施 PbD 原则。
案例研究描述
让我们考虑一个假设的社交媒体平台,名为“MyConnect”,该平台旨在通过在其开发和运营的整个过程中实施 PbD 原则来优先考虑用户隐私和数据保护。我们将逐一探讨其原则。
-
最小化数据收集:MyConnect 通过仅收集必要用户数据来遵循以隐私为中心的方法。它只请求与提供平台核心功能直接相关的信息。故意避免不必要的个人信息或侵入性跟踪信息等数据点。
-
以隐私为导向的默认设置:MyConnect 默认实施以隐私为导向的设置,通过默认保护用户隐私。例如,它将用户资料设置为私有,限制用户信息仅对批准的连接可见。此外,它还启用了对功能如位置共享的同意选择,确保用户必须主动选择分享他们的位置。
-
细粒度隐私控制:MyConnect 提供细粒度隐私控制,赋予用户管理他们的隐私偏好的能力。用户可以控制谁可以查看他们的帖子、访问他们的个人资料信息以及发送连接请求。该平台提供易于使用的隐私设置,允许用户根据他们的偏好自定义隐私级别。
-
安全数据存储和加密:MyConnect 通过采用强大的加密机制优先考虑用户数据的安全性。用户数据,包括个人信息和通讯,在静止和传输过程中都得到安全存储和加密。这确保即使发生数据泄露,数据也保持不可读且受保护。
-
定期安全审计和更新:MyConnect 定期进行安全审计,以识别潜在漏洞并及时解决。它保持与最新安全措施同步,并修补任何识别出的安全弱点,以确保用户数据的持续保护。
-
透明度与用户教育:MyConnect 通过提供清晰简洁的隐私政策和服务条款,与用户保持透明度。它教育用户关于他们的权利、收集的数据及其使用方式。该平台还提供用户友好的指南和资源,教育用户关于隐私最佳实践以及如何保护他们的信息。MyConnect 还通过“隐私数据表”实施了一种新的方式,来分享其平台如何保护数据隐私的细节。
以下映射显示了在社交媒体平台公司中如何实施 PbD 原则:
| 隐私设计原则 | MyConnect 实施 |
|---|---|
| 积极而非被动措施 | 最小化数据收集 |
| 隐私为默认设置 | 以隐私为导向的默认设置 |
| 尊重用户隐私 | 细粒度隐私控制 |
| 端到端安全 | 安全数据存储和加密 |
| 全面的方法 | 定期安全审计和更新 |
| 可视性与透明度 | 透明度与用户教育 |
表 1.2 - MyConnect 实施
效益和成果
在 MyConnect 中实施 PbD 原则带来几个关键效益:
-
增强的用户信任:MyConnect 的用户感到自信,他们的隐私受到尊重,他们的数据得到保护。该平台对隐私的承诺赋予用户参与和分享内容的权利,无需过度担心他们的个人信息被滥用。
-
遵守隐私法规:通过整合 PbD 原则,MyConnect 确保符合隐私法规,如 GDPR。这保护了平台免受与隐私泄露相关的法律和声誉风险。
-
积极的声誉和差异化:MyConnect 通过将自己宣传为一个注重隐私的社交媒体平台来获得竞争优势。其 PbD 方法可以吸引注重保护个人信息的隐私意识用户。
-
减少隐私事件和泄露:PbD 实践减少了隐私事件和数据泄露的可能性。通过在项目开始时就考虑隐私因素,MyConnect 最小化了可能导致未经授权访问或用户数据滥用的潜在漏洞。我们将在下一节中更详细地介绍隐私泄露。
MyConnect 实施 PbD 原则展示了在社交媒体平台的设计和运营中将隐私视为基本组成部分的重要性,通过优先考虑最小化数据收集、以隐私为导向的默认设置、细粒度隐私控制、安全数据存储、定期审计、透明度和用户教育。
隐私泄露
什么是隐私泄露?
隐私泄露,也称为数据泄露,是指未经授权的个人或实体在没有适当授权的情况下获取机密或敏感信息的事件。这种隐私泄露可能以各种形式发生,例如黑客攻击、盗窃、意外泄露或数据不当处理。通常涉及未经授权的访问、获取、披露或使用个人信息,这可能包括个人身份信息(PII),如姓名、地址、社会保障号码、财务细节和登录凭证。
隐私泄露对个人、组织甚至社会都可能产生严重后果。它们可能导致身份盗窃、财务欺诈、声誉损害、信任丧失、法律后果和情感压力。保护个人数据和维护隐私对于确保个人安全和维持对数字系统和服务的信任至关重要。
以下是一些隐私泄露的例子:一个涉及一家公司在其产品中使用网络技术,另一个涉及一家公司将人工智能(AI)和机器学习(ML)集成到其产品和服务中。
Equifax 隐私泄露事件
Equifax 隐私泄露事件指的是 2017 年发生的一次大规模数据泄露事件,大约有 1.47 亿人的个人信息受到损害。Equifax 是美国最大的消费者信用报告机构之一,此次泄露是历史上最重大的数据泄露事件之一。
破绽发生在黑客利用 Equifax 网站软件中的漏洞时,这使他们能够访问敏感信息,如姓名、社会保障号码、出生日期、地址,在某些情况下还包括驾照号码和信用卡信息。
破绽在几个月内未被察觉,在此期间黑客能够访问并窃取信息。Equifax 的数据泄露事件是一个重大事件,它突显了网络安全的至关重要性以及公司采取主动措施保护客户数据的必要性。
该泄露事件还导致了对 Equifax 的多次调查、诉讼和和解,公司最终同意支付超过 7 亿美元作为赔偿金和罚款。除了财务影响外,该泄露事件对受影响的个人产生了严重后果,他们面临身份盗窃和其他欺诈活动的风险。该泄露事件突显了个人需要警惕监控他们的信用报告、保护个人信息并采取措施保护自己免受身份盗窃的必要性。
攻击者使用了一系列技术,包括 SQL 注入和跨站脚本(XSS),以获取存储在 Equifax 数据库中的敏感数据。SQL 注入是一种攻击方式,攻击者将恶意代码注入 SQL 语句中,从而允许他们在数据库上执行未经授权的操作。在这种情况下,攻击者使用 SQL 注入绕过 Equifax 的安全控制并获取数百万个人的个人信息。
攻击者还使用了跨站脚本攻击(XSS 攻击),这种攻击涉及向网站注入恶意代码以窃取用户的敏感数据。在这种情况下,攻击者能够将恶意代码注入 Equifax 的网站。一旦攻击者获得了 Equifax 系统的访问权限,他们能够在几个月的时间里提取大量数据而未被察觉。被盗的数据包括姓名、社会保障号码、出生日期、地址、驾照号码和信用卡信息。
Equifax 的数据泄露事件突显了网络安全的至关重要性以及公司采取主动措施保护其系统和数据免受攻击者的必要性。它还强调了持续监控和检测的重要性,以便快速识别和应对潜在的安全威胁。
来源:en.wikipedia.org/wiki/2017_Equifax_data_breach
Clearview AI 隐私泄露
Clearview AI 是一家开发有争议的面部识别系统的科技公司。该公司的软件旨在将个人图像与公开可用的照片相匹配,从互联网上的各种来源抓取数据,包括社交媒体平台。由于对隐私和伦理影响的担忧,该系统引起了广泛关注。
2020 年初,Clearview AI 发现自己成为了一起重大隐私泄露事件的中心。揭露该公司在不知情或未经相关个人同意的情况下积累了数十亿面部图像的庞大数据库。这些图像来自各种在线平台,包括 Facebook、Instagram 和 X(前身为 Twitter)。
这起泄露事件是由调查报告和研究人员的发现而曝光的,他们发现 Clearview AI 的数据库可以供执法机构和其它组织访问。这引发了关于技术潜在滥用的重大担忧,因为它可能被用于大规模监控、追踪个人或未经个人知晓侵犯他们的隐私。
关于 Clearview AI 实践的主要担忧之一是缺乏透明度和同意。照片被包含在数据库中的个人并未给予他们的许可,甚至都不知道他们的图像正以这种方式被使用。Clearview AI 抓取公开可用的数据绕过了许多社交媒体平台的服务条款,进一步加剧了隐私问题。
这起泄露事件引发了关于面部识别技术使用和需要更强监管的法律和伦理辩论。批评者认为,Clearview AI 的实践侵犯了隐私,因为人们的面孔被用作生物识别标识而没有得到他们的同意。
此外,还担忧系统可能存在种族偏见和歧视,因为面部识别算法已被证明对某些群体不太准确。在隐私泄露事件揭露之后,Clearview AI 遭到了隐私倡导者、技术专家和公众的强烈反对。有几起诉讼针对该公司,指控其违反隐私法律和规定。因此,Clearview AI 受到了多个监管机构的调查。
作为对反作用的回应,Clearview AI 努力改进其做法并解决隐私问题。该公司声称已经实施了更严格的数据访问政策,并为潜在客户建立了一个验证系统。然而,关于这些措施的有效性和公司整体运营的道德性仍然存在怀疑。
Clearview AI 的隐私泄露事件成为了一个关于未经检查的面部识别技术潜在危险和保障个人隐私重要性的警示故事。它引发了关于隐私法律、新兴技术的监管以及大规模监控的伦理影响的讨论。随着辩论的持续,在技术进步和保护个人权利和隐私之间取得平衡仍然至关重要。
隐私威胁建模
在日益数字化的世界中,隐私已成为个人、组织和整个社会至关重要的关注点。随着个人数据的广泛收集和处理,评估和有效缓解隐私威胁变得至关重要。
隐私威胁建模 – 定义
隐私威胁建模是一个主动的过程,旨在在隐私威胁显现之前识别和理解潜在的隐私威胁。通过检查系统的架构、数据流和交互,隐私威胁建模能够识别可能损害个人隐私的漏洞和风险。它帮助组织在设计和开发阶段预见并解决隐私问题,确保隐私保护从一开始就集成到系统中。
隐私威胁建模的重要性
隐私威胁建模提供了几个关键好处,包括以下内容:
-
风险识别:通过系统地评估潜在的隐私威胁,组织可以识别和理解他们面临的风险。这种知识使他们能够优先考虑隐私控制并有效分配资源。
-
隐私设计方法:隐私威胁建模鼓励在系统设计和开发中采取以隐私为中心的方法。通过在早期整合隐私考虑因素,组织可以节省时间、精力和可能需要用于改造隐私保障的成本。
-
合规性和问责制:隐私法规和标准,如 GDPR,要求组织实施隐私措施。隐私威胁建模通过识别和解决潜在的合规差距,帮助组织满足这些要求。
-
利益相关者信任:展示对隐私保护的承诺可以增强利益相关者的信任。隐私威胁建模提供了一种系统化的方式来展示组织对保护个人隐私的承诺,从而在使用者(内部和外部)和客户中增加信心。它建立了一种负责任的发展文化。
持续的隐私威胁建模有助于明确隐私要求,并使组织能够朝着构建标准隐私功能和模式迈进。专注于主动问题识别和修复有助于公司建立以隐私为导向的文化。
隐私威胁建模与隐私设计原则的契合
隐私威胁建模涉及识别系统内的潜在隐私风险和漏洞。虽然它并不直接涵盖所有隐私设计原则,但它是有效实施这些原则的关键步骤。
下面是隐私威胁建模如何与不同的隐私设计原则相契合的说明:
-
数据最小化:有助于识别数据收集可能过度或不必要的地方,从而导致潜在的隐私风险
-
目的指定:识别收集的数据可能被用于非预期目的的场景,有助于确保数据使用得到适当指定。
-
同意机制:突出显示可能在没有适当用户同意的情况下收集或使用数据的情况,协助设计有效的同意流程。
-
访问控制:识别潜在的未经授权的访问点,指导实施访问控制以防止未经授权的数据泄露
-
数据加密:揭示可能导致数据泄露的数据存储或传输中的漏洞,告知加密的必要性。
-
用户赋权:帮助识别用户可能缺乏对其数据的控制区域,促使实施用户数据管理工具。
-
安全措施:识别可能损害用户数据的潜在安全弱点,有助于实施强大的安全措施。
-
定期审计和评估:通过识别需要定期监控和评估的潜在漏洞区域,支持持续评估。
虽然隐私威胁建模不是 PbD 原则的直接替代品,但它通过识别潜在风险和漏洞,在塑造设计和开发过程中发挥着关键作用。从威胁建模中获得的认识使组织能够有效地应用 PbD 原则来应对这些风险并增强其系统的整体隐私状况。
隐私威胁建模的步骤
进行有效的隐私威胁评估涉及以下步骤:
-
定义系统:明确界定待评估的系统或应用的范围。识别其组件、数据流和与其他系统的接口。
-
识别数据类型:确定系统处理和存储的个人数据类型。根据敏感性和监管要求对数据进行分类。
-
识别威胁来源:列举可能尝试损害系统数据或用户隐私的潜在威胁来源,包括内部和外部来源。
-
分析威胁场景:通过结合威胁来源和系统组件,开发现实可行的威胁场景。考虑可能利用数据处理、存储、传输或用户交互中的漏洞的场景。
-
评估影响和可能性:评估每个威胁场景实现的可能性和潜在影响。考虑对个人的潜在伤害、监管处罚、声誉损害和其他相关因素。
-
识别控制措施:识别并实施适当的隐私控制和安全措施来减轻已识别的威胁。考虑技术、组织和程序措施来解决漏洞并保护隐私。
-
文档和沟通:记录隐私威胁评估过程,包括已识别的威胁、缓解措施和剩余风险。将发现结果传达给利益相关者,如系统设计师、开发者、隐私官和管理层,以确保集体意识和支持。
-
审查和更新:定期审查和更新隐私威胁评估,随着系统的发展或新威胁的出现。
隐私威胁建模是一个迭代的过程,应该整合到组织的持续隐私管理实践中
隐私威胁建模框架
可用的隐私威胁建模框架有多种,它们提供了结构化的方法和指南,以有效地评估和减轻隐私风险。让我们来探讨一些广为人知的隐私威胁建模框架:
-
STRIDE(微软):STRIDE 框架最初由微软开发,专注于识别对系统安全和隐私的威胁。它代表以下内容:
-
身份欺骗:未经授权的参与者伪装成合法用户
-
篡改数据:未经授权的数据修改或销毁
-
否认:恶意行为者否认行动或交易
-
信息泄露:未经授权访问敏感信息
-
拒绝服务:系统可用性的中断或退化
-
权限提升:未经授权的权限提升
STRIDE 框架通过考虑每个威胁类别可能如何影响系统用户和数据隐私,帮助识别潜在的隐私威胁。
-
-
LINDDUN:这是一个隐私威胁建模框架。它提供了一种全面的方法来识别和解决隐私问题。LINDDUN 框架的组成部分如下:
-
可链接性:评估将各种数据点链接起来识别个人的可能性
-
可识别性:评估个人可以从数据中被识别或重新识别的程度
-
不可否认性:确保行动和交易不能被否认
-
可检测性:评估检测隐私泄露或未经授权访问的能力
-
数据泄露:过度收集、存储、处理或共享个人数据
-
无意识:评估用户对数据收集和使用的意识和控制水平
-
不合规:识别违反隐私法规和标准的风险
LINDDUN 提供了一个对隐私威胁的整体视角,并帮助组织分析这些威胁对个人隐私的影响。
-
-
PLOT4AI:人工智能威胁隐私库(PLOT4AI)是一个精心构建的全面资源,旨在解决与人工智能技术交织在一起的复杂隐私问题。目前,该库包含 86 个独特的威胁,细致地分为八个不同的类别:
-
技术和流程:本类别涵盖了可能源自流程或技术操作对个人产生不利影响的潜在弊端。
-
可访问性:这旨在纠正 AI 系统对各种个人在可访问性和用户友好性方面的不足。
-
可识别性和可链接性:这突出了将个人与特定属性或其他个人联系起来所面临的威胁,以及围绕识别的担忧。
-
安全性:这聚焦于由于 AI 系统和程序对安全漏洞防御不足而可能出现的潜在危险。
-
安全性:这集中精力识别危险,保护个人免受可能伤害或危险。
-
无意识:这直面了忽视通知个人的问题,并给予他们干预的机会。
-
伦理和人权:这揭示了可能对个人产生的不良影响,以及由于忽视价值观和原则而造成的伤害。
-
不合规:这关注于由于未能遵守数据保护法和其他相关法规而产生的威胁。
这个存储库作为一个强大的武器库,旨在赋予 AI 社区和利益相关者权力,保护隐私至高无上的重要性,因为 AI 继续展现其潜力。
图书馆引入了一种简化的四阶段开发生命周期(DLC)方法,与 SEMMA、CRISP-DM、ASUM-DM、TDSP 和 MDM 等多种方法相一致。这种简化方法确保了非技术利益相关者的可访问性,同时保持与既定方法的协调一致。
数据流图(DFDs)被用作分析中系统的视觉表示。PLOT4AI 强调了彻底的威胁建模的重要性,并建议为不同类别的威胁使用基本和详细的 DFDs。
威胁以卡片的形式呈现,类似于 LINDDUN GO,按颜色和图标分类,代表威胁类别和 DLC 阶段。某些威胁可能有多个类别图标或 DLC 图标,反映了它们多样化的影响。
为了实际应用 PLOT4AI,它可以以实体和数字格式作为卡牌游戏使用。会议时间被限制以保持参与度和专注力,涉及多样化的利益相关者和协调者。在会议中,参与者被引导通过每张威胁卡的提问、讨论和潜在建议。
通过使用 PLOT4AI,组织可以加强其隐私实践,降低风险,简化流程,并在利益相关者之间促进合作。图书馆的输出还可以有助于数据隐私影响评估,并促进合规工作。
在开发过程中,PLOT4AI 提供了诸如改进流程、减少返工、明确目的和利益相关者之间的一致性等好处。该资源通过隐私威胁建模的视角提供了关于人性化 AI 的宝贵见解。
公司提供了一款在线评估工具,通过回答其问题,个人可以辨别出与他们负责增强的机器学习系统或产品相关的威胁模型。
这里是评估工具的链接:
plot4.ai/assessments/。 -
让我们通过一个详细的例子深入探讨 LINDDUN 框架,以更好地了解隐私威胁建模。
LINDDUN 框架
LINDDUN是一种隐私威胁建模方法,它支持分析师在软件架构中系统地识别和缓解隐私威胁。这个框架是由鲁汶大学(KU Leuven)的隐私专家开发的。
LINDDUN 框架由三个主要步骤组成:
-
建模系统。
-
识别威胁。
-
缓解威胁。

图 1.2 – LINDDUN 框架步骤
第 1 步 – 建模系统
在这一步,全面了解正在开发中的系统或产品至关重要,包括对数据流的详细知识。这包括理解数据是如何收集、处理、利用、保留和共享的,以及识别系统的用户及其访问方法。此外,了解系统与其他系统如何交互也是必不可少的。为了便于分析隐私威胁,LINDDUN 采用 DFD(数据流图)作为捕捉系统或产品知识的方法,就像 STRIDE(微软的安全威胁建模方法)用于安全威胁建模一样。
第 2 步 – 识别和记录威胁
LINDDUN 包含七个不同的威胁类别,通过利用威胁树来识别威胁。该框架提供了以下七个威胁类别的概述:
| 威胁类别 | 隐私 威胁详情 |
|---|---|
| 连接性 | 这个类别涉及将两个或更多公开可用的数据集联系起来以获得见解。通常,数据主体并不了解他们的数据可以与网络上的其他数据集联系起来,从而导致个人信息泄露,例如,将患有类似疾病的人联系起来或联系访问特定商场的个人。 |
| 可识别性 | 可识别性指的是根据其他可用的数据通过其他方式识别特定个人信息的能力,例如,根据交易数据识别消费者或根据特定网站的读者识别个人。 |
| 不可否认性 | 不可否认性确保数据主体不能否认他们在特定行动中的参与。这可以适用于社交媒体评论或帖子,这些评论或帖子可以归因于特定个人。 |
| 可检测性 | 可检测性涉及确定与数据主体相关的特定感兴趣项目是否存在的能力。通常可以根据可用数据推导出新的个人信息,例如,通过分析社交媒体帖子类型来识别作者并提取更多信息。 |
| 信息披露 | 此类别涉及了解关于数据主体的特定感兴趣项目的具体内容的能力。它包括访问和获取有关个人的个人信息。 |
| 无知 | 无知指的是数据主体对其个人数据相关的收集、处理、存储或共享活动(包括相应目的)不知情的情况。例如,未经用户同意收集个人数据、与第三方共享数据或处理数据以生成见解,所有这些活动都在数据主体不知情的情况下进行。 |
| 不合规 | 当系统收集和处理个人数据而不遵守隐私法规时,就会产生不合规问题。这可能包括未经同意收集数据、未经适当加密处理和共享数据,或保留数据时间超过必要期限等行为。这些威胁类别为在 LINDDUN 中分析隐私威胁提供了一个框架,从而全面理解与个人数据相关的潜在风险。 |
表 1.3 – LINDDUN 高级别类别
步骤 2a – 将 DFD 元素映射到威胁类别
为系统中的每个 DFD 项目和 LINDDUN 威胁准备映射表:
| 数据 流 元素 | L | I | N | D | D | U | N |
|---|---|---|---|---|---|---|---|
| 实体 | X | ||||||
| 数据存储 | X | X | X | X | |||
| 数据流 | X | ||||||
| 流程 | X | X | X |
表 1.4 – DFD 和威胁类别之间的映射
在 DFD 元素可能对威胁类别构成潜在隐私威胁的地方打上“X”标记。
步骤 2b – 激发和记录威胁

图 1.3 – 威胁文档步骤
使用 LINDDUN 树来激发和记录每个 DFD 类别的威胁。在前面的示例中,可链接性类别树包括数据存储链接性的可能隐私树模型。
步骤 3 – 缓解威胁
在此步骤中,将适当处理已识别的隐私威胁。
步骤 3a – 优先排序威胁
将隐私威胁优先排序为低、中或高风险。
步骤 3b – 缓解策略
对于每个已识别的威胁,制定缓解策略。LINDDUN 框架为隐私威胁提供了以下缓解策略的分类法。

图 1.4 – 隐私威胁缓解策略
来源:LINDDUN 缓解策略分类法 (www.linddun.org/linddun)
步骤 3c – 选择隐私增强解决方案
框架的最后一步涉及为每种威胁缓解策略规划隐私增强解决方案。
让我们考虑一个实际例子来解释 LINDDUN 框架。
示例 – 社交媒体平台(MyConnect)隐私威胁建模
在本例中,我们将使用 LINDDUN 框架来评估本章前面提到的社交媒体平台的隐私威胁。目标是识别可能损害用户隐私的风险和漏洞:
-
可链接性:可链接性指的是将不同的数据点链接起来以识别个人的能力。在社交媒体平台的案例中,可链接性威胁可能包括以下内容:
-
用户资料链接:评估用户资料在不同社交媒体平台或服务之间被链接的程度,可能揭示比预期更多的个人信息
-
跨设备追踪:评估追踪用户在多个设备上的活动以创建全面资料和跟踪其在线行为的风险
-
-
可识别性:可识别性关注个人可能从数据中被识别或重新识别的潜力。与可识别性相关的隐私威胁可能包括以下内容:
-
去匿名化:评估对手通过结合和分析各种数据集来去匿名化用户数据的风险
-
重新识别攻击:评估攻击者通过将看似匿名的数据与外部数据集关联起来重新识别用户的可能性
-
-
不可否认性:不可否认性确保了行为和交易不能被否认。在社交媒体平台的背景下,不可否认性威胁可能包括以下内容:
-
用户内容篡改:评估未经授权修改或篡改用户生成内容的风险,可能导致错误归因或否认用户行为
-
账户劫持:评估恶意行为者未经授权访问用户账户并代表合法用户执行操作的可能性,从而导致用户参与的否认
-
-
可检测性:可检测性关注检测隐私泄露或未经授权访问的能力。对于社交媒体平台,此类威胁可能包括以下内容:
-
未经授权访问监控:评估平台检测和应对恶意行为者试图获取用户数据的未经授权访问尝试的能力
-
数据泄露监控:评估平台监控和检测数据泄露事件的能力,例如未经授权将用户数据与第三方共享
-
-
无意识:无意识指的是用户对数据收集和使用的了解和控制程度。与无意识相关的隐私威胁可能包括以下内容:
-
数据收集透明度:评估平台在告知用户收集的数据类型、目的以及与哪些第三方共享数据方面的透明度
-
同意管理:评估平台在获取用户对数据处理活动的明确同意方面的有效性
-
-
不合规:这涉及到识别与隐私法规和标准不符的风险。对于社交媒体平台,潜在的不合规威胁可能包括以下内容:
-
隐私政策不充分:评估平台的隐私政策,以确保其符合适用的隐私法律,并向用户提供关于数据处理实践的信息
-
跨司法管辖区数据传输:评估与数据传输到具有不同隐私法规的司法管辖区相关的风险,并评估跨境数据传输要求的合规性
-
通过将 LINDDUN 框架应用于社交媒体平台示例,我们可以确定每个类别中的具体威胁和漏洞。这允许平台背后的组织开发适当的隐私控制和保护措施,以减轻已识别的风险,增强用户隐私保护和遵守隐私法规。
在探讨了数据隐私、隐私威胁和威胁建模等概念之后,现在是深入探讨本书的核心焦点:保护隐私的机器学习。在本节中,我们将了解为什么它是必要的,并探索与保护隐私的机器学习相关的各种技术。
保护隐私的机器学习的必要性
保护隐私的机器学习(Privacy-preserving ML)作为对人工智能和机器学习中日益增长的数据隐私担忧以及保护敏感信息同时利用机器学习算法能力的回应而出现。你将在下一章中学习关于机器学习和保护隐私的机器学习技术。
以下是一些为什么保护隐私的机器学习是必要的理由:
-
敏感数据的保护:保护隐私的机器学习技术使组织能够在不将其暴露于潜在的安全漏洞或未经授权的访问的情况下利用敏感数据。通过实施隐私保护措施,组织可以保护敏感信息,如个人身份信息(PII)、医疗记录、财务数据或专有商业数据。你将在第五章到第八章中了解更多关于如何使用不同的保护隐私技术来保护敏感数据。
-
遵守隐私法规:许多司法管辖区已经实施了严格的隐私法规和数据保护法律,例如欧盟的GDPR和CCPA。保护隐私的机器学习技术通过确保用户数据以隐私意识的方式处理,帮助组织遵守这些法规。
-
保护用户信任:隐私泄露和数据滥用事件会严重损害处理个人数据的组织在用户中的信任。通过采用保护隐私的机器学习技术,组织表明了他们保护用户隐私的承诺,从而增强信任并促进与客户或用户的长期关系。
-
合作与数据共享:保护隐私的机器学习技术使多个组织之间能够进行安全合作和数据共享。这些技术允许组织在不直接暴露敏感信息的情况下合并他们的数据集,促进联合研究,并在尊重数据隐私的同时实现集体见解。
-
公平性和偏差缓解:保护隐私的机器学习还可以有助于解决与机器学习模型中的公平性和偏差相关的问题。通过应用隐私技术,组织可以保护敏感属性,并降低基于种族、性别或民族等因素的歧视风险,从而在机器学习应用中促进公平性。
-
医疗保健和研究中的机密性:在医疗保健和研究等领域,保护隐私的机器学习技术对于维护敏感医疗记录和个人健康信息的机密性至关重要。这些技术允许医疗保健提供者和研究人员从汇总数据中提取有价值见解,同时保护患者隐私。您将在第三章和第四章中了解更多关于汇总数据集、隐私问题和如何保护个人敏感性和隐私的内容。
-
防范内部威胁:保护隐私的机器学习技术可以通过降低组织内部人员未经授权访问敏感数据的风险,帮助防范内部威胁。这些技术使组织能够限制对敏感信息的访问,并确保即使在内部员工中也能保持用户或客户的隐私。您将在第九章中了解更多关于内部威胁的内容。
保护隐私的机器学习技术对于组织来说至关重要,它们需要在利用数据获取有价值见解的同时,保护个人隐私。
通过采用这些技术,组织可以遵守隐私法规,维护用户信任,促进合作,并在机器学习应用中促进公平性,同时保护敏感信息免受未经授权的访问或滥用。
案例研究 – 金融机构中的保护隐私的机器学习
金融机构处理大量敏感客户数据,包括个人和财务信息。随着机器学习技术在金融领域的日益普及,在从这些数据中获取见解的同时保护客户隐私的需求变得至关重要。本案例研究考察了一个现实场景,突出了在金融机构中实施保护隐私的机器学习的必要性。
案例研究描述
ARDHA 银行(为说明目的而虚构的银行),一家领先的全球银行,旨在利用机器学习算法来提高其欺诈检测能力。该银行拥有大量的交易数据,包括信用卡交易、账户活动和客户档案。然而,确保客户数据的隐私和机密性是 ARDHA 银行的首要任务。为了解决这一担忧,ARDHA 银行正在探索采用以下保护隐私的机器学习技术:
-
差分隐私:ARDHA 银行采用差分隐私技术来保护客户隐私,在训练机器学习模型时。差分隐私通过向数据添加噪声或扰动来确保个人客户信息保持模糊,同时仍然允许准确地进行模型训练和分析。您将在第三章至第五章中了解更多关于差分隐私的信息。
-
安全数据聚合:为了在不暴露个人层面细节的情况下从客户数据中获取洞察,ARDHA 银行采用了安全数据聚合技术。这使得银行能够从数据中提取有意义的统计信息,同时保护客户隐私。聚合数据可用于训练机器学习模型,而无需透露特定客户的敏感信息。您将在第四章中了解更多相关信息。
-
联邦学习:ARDHA 银行实施了联邦学习,这是一种保护隐私的技术,用于在多个分布式数据源上训练机器学习模型。客户数据保持去中心化和加密,允许在每个数据源上本地训练本地模型,而不必共享原始数据。然后,训练好的模型被结合和汇总,以创建一个全局模型,而不暴露个人数据。您将在第六章和第七章中了解更多关于联邦学习的信息。
-
加密推理:在实时执行欺诈检测或其他机器学习任务时,ARDHA 银行采用加密推理技术。通过使用同态加密或安全多方计算,银行可以在加密的客户数据上执行机器学习模型,而无需解密。这确保了在预测阶段敏感信息得到保护。您将在第八章中了解更多相关信息。
效益和成果
ARDHA 银行已实施隐私保护技术以确保客户数据的安全。他们使用差分隐私、安全数据聚合、联邦学习和加密推理等方法,在机器学习过程中保护个人客户信息。尽管重视隐私保护,但银行通过分析汇总和匿名化数据,开发了有效的欺诈检测模型,使其能够在尊重个人隐私的同时识别欺诈模式。这些努力也确保了符合数据保护法规,如 GDPR 和金融行业标准。通过重视客户隐私,ARDHA 银行建立了信任,提升了其声誉,并加强了客户关系。该银行的方法展示了在金融领域利用高级分析同时保护客户数据的重要性。
隐私保护机器学习在其他领域也具有同等的重要性,例如医疗保健、教育和社交网络。
摘要
总结来说,我们已经对隐私、数据隐私、PbD 概念和隐私威胁建模有了高层次的理解。此外,我们通过案例研究探讨了隐私保护机器学习的重要性。
展望未来,下一章将简要概述不同类型的机器学习(监督学习和无监督学习)以及机器学习涉及的各个阶段(数据提取、数据准备、模型开发、模型部署和推理)。此外,我们还将检查每个阶段相关的隐私威胁和攻击。
第二章:机器学习阶段和每个阶段的隐私威胁/攻击概述
在本章中,我们将快速回顾不同类型的机器学习(ML):监督学习、无监督学习和强化学习。我们还将回顾 ML 的基本阶段或流程。你可能已经熟悉这些内容;如果不熟悉,本章将作为一个基础性的介绍。
随后,我们将深入研究 ML 过程中的每个阶段隐私保护的关键主题。具体来说,我们将探讨在训练数据、输入数据、模型存储和推理/输出数据中保持隐私的重要性。此外,我们还将检查每个阶段可能发生的各种隐私攻击,例如训练数据提取攻击、模型反演攻击和模型推理攻击。通过详细的示例,我们将了解这些攻击是如何工作的,并讨论防范策略。
我们将涵盖以下主要主题:
-
机器学习类型
-
ML 阶段概述
-
机器学习阶段中的隐私威胁/攻击
机器学习类型
一些人对不同的 ML 类型可能已经熟悉,即监督学习、无监督学习和强化学习。在接下来的章节中,我们将快速回顾这些 ML 类型,总结你可能已经学到的内容。
监督学习
监督学习模型涉及使用一组输入数据和相应的实际输出开发一个数学模型。输入数据被称为训练数据,而输出被称为预测输出。这些模型使用数学函数从训练数据中学习,并旨在使用最优函数最小化预测输出和预期输出之间的误差。由输入示例组成的数据通常以数组、向量、矩阵或张量等格式表示。这种数据通常被称为特征数据或特征向量,其中数据中的每个属性都被视为一个特征。
| 类型 | 示例 | 细节 |
|---|---|---|
| 标量 | 1 | 标量是一个单独的数字。 |
| 向量 | [ 1 2 3 4 ] | 向量是由不同数据类型的数字或对象组成的数组。 |
| 矩阵 | [1 2 3 4 5 6 7 8 9] | 矩阵是按行和列排列的数字数组。为了访问矩阵,我们需要两个索引:列号和行号。 |
| 张量 | [[ 1 2] [ 3 4] [ 5 6][ 7 8 ] [9 0] [ 0 1]] | 张量是一个n-维数组,其中n>2。 |
表 2.1 – 标量、向量、矩阵和张量的示例
在数学术语中,ML 中的监督学习可以用一个带有参数𝜃的模型来表示。该模型充当输入x和输出y之间的映射函数,表示为y = 𝑓 (x, 𝜃). 在这个上下文中,x代表一个具有𝑛维度的属性或特征向量。输出或标签y的维度可以根据特定的学习任务而变化。
为了训练模型,使用了一个训练集 T,它由形式为 T = {(x, y𝑖)}的数据点组成,其中𝑖的范围从 1 到 n,代表输入-输出对的数目。
监督机器学习算法通常分为两类:回归和分类。这些算法旨在学习训练数据中的模式和关系,以便对新、未见过的数据进行预测或分配标签。
回归
在机器学习中,目标变量是我们旨在预测或预测的变量。它也常被称为因变量。它是机器学习模型训练用来使用独立或特征变量预测的变量。例如,在房价预测模型中,房价将是目标变量。
回归是机器学习中的一个基本概念,它侧重于根据输入变量预测连续数值。它是一种监督学习技术,涉及分析输入特征与目标变量之间的关系。回归的目标是构建一个数学模型,当提供新的输入数据时,可以准确地估计或近似目标变量的值。
在回归中,目标变量,也称为因变量,是一个连续值。输入变量,也称为独立变量或特征,可以是数值或分类的。回归模型旨在理解这些输入变量与目标变量之间的关系,从而能够对未见数据做出预测。
回归模型的性能通常通过评估其预测值与实际目标值之间的接近程度来衡量。存在各种回归算法,如线性回归、多项式回归,以及更复杂的支持向量回归和随机森林回归等技术。这些算法使用数学优化方法来拟合回归函数,以最小化预测值与目标变量的真实值之间的差异。
回归分析在众多领域都有应用,包括金融、经济学、医疗保健和社会科学,其中它被用于诸如价格预测、需求预测、风险评估和趋势分析等任务。通过利用回归算法,可以从数据中获得有价值的见解,从而实现明智的决策和准确的预测。
回归模型示例
这是一个使用两个输入特征预测目标变量的简单示例。在这种情况下,模型是在一组历史数据上训练的,通常代表过去 X 天的数据。
目的是根据提供的输入数据预测或预测目标变量。通过分析历史数据集中的模式和关系,训练好的模型可以在呈现新的输入数据时对目标变量进行预测。这个过程允许根据给定的输入预测未来的值或理解潜在的结果。模型的准确性和性能是根据其预测目标变量的能力与实际值相比来评估的。通过利用历史数据和利用机器学习算法,可以获得有价值的见解,从而实现准确的预测和明智的决策。
| 特征 1 值 | 特征 2 值 | 目标变量值 |
|---|---|---|
| 10 | 10 | 130 |
| 10 | 20 | 180 |
| 20 | 20 | 210 |
| 20 | 30 | 260 |
| 30 | 50 | ?? |
表 2.2 – 回归模型示例
此示例使用 scikit-learn 库实现。我使用了 Python 3.8 和 scikit-learn 1.2.1 版本。
这些是在本例中遵循的步骤:
-
安装 Jupyter Notebook(pip install notebook)。
-
打开一个 Python Jupyter 笔记本(jupyter notebook)。
-
安装 sci-kit learn 库(pip install -****U scikit-learn)。
-
输入以下代码并运行模型代码。
您可以直接使用本书 GitHub 位置提供的 Jupyter 笔记本执行代码—LinearRegression.ipynb—位于github.com/PacktPublishing/Privacy-Preserving-Machine-Learning/blob/main/Chapter%202/LinearRegression.ipynb:
import numpy as np
from sklearn.linear_model import LinearRegression
# Prepare sample input data with two features (feature 1, feature 2
X = np.array([[10, 10], [10, 20], [20, 20], [20, 30]])
# Assume that target feature has some relationship with the input features with the formula y = 3 * x_1 + 5 * x_2 + 50
y = np.dot(X, np.array([3, 5])) + 50
# Run the model with the input data and output values
reg = LinearRegression().fit(X, y)
reg.score(X, y)
reg.coef_
reg.intercept_
reg.predict(np.array([[30, 50]]))
Output: array([390.])
在此示例中,目标变量 y 与输入变量 X0 和 X1 呈线性相关,线性方程为 y= 3X0+ 5X1+50(50 是直线的截距)。
模型使用均方根值作为最优函数,并预测目标变量。在这种情况下,由于特征和目标变量之间强烈的线性关系,它预测了 100%的准确率。
模型持久化和检索持久化模型以进行推理
在使用训练数据开发和测试模型以及使用测试数据进行验证之后,下一步是持久化模型。这允许与其他开发人员或工程师轻松共享,而无需透露训练数据和复杂的模型细节。此外,如果模型在训练期间表现出足够的准确度,它可以在生产环境中部署。
为了持久化模型,支持多种格式以将其存储在磁盘或文件系统中。具体使用的格式取决于开发机器学习或深度学习(DL)模型所使用的框架。通过使用这些格式,模型可以高效地存储和访问,便于无缝集成到生产系统或与其他团队成员的合作中。
持久化模型可以实现可重复性和可扩展性,因为它可以在不同的环境中共享、重用和部署,而无需从头开始重新训练。它还有助于保护与模型相关的专有信息和知识产权,使组织能够保护其宝贵的研究和开发工作。

图 2.1 – 模型持久化和检索
下表显示了社区中广泛使用和接受的格式:
| 框架 | 模型持久化格式 | 详情 |
|---|---|---|
scikit-learnscikit-learn.org/ |
JoblibPickle | Joblib 和 pickle 格式不需要任何代码更改。pickle 格式存在安全问题,因此大多数框架不建议使用 pickle 格式进行模型持久化,因为在反序列化过程中可以执行任意代码。 |
TensorFlow/Keraswww.tensorflow.org/ |
JSONYAMLHDF5 | 这是以 JSON 或 YAML 格式存储的模型数据,这些格式是基于文本的格式,因此它们是语言无关的。权重以 HDF5 格式保存。 |
PyTorchpytorch.org/ |
state_dictPickle | 用于神经网络模型存储权重和偏差。 |
| ONNX | Onnx | 模型需要转换为 ONNX 格式,并使用 ONNX Runtime 导出和加载/执行,以便它们可以在基于 CPU 或 GPU 的服务器上运行。 |
表 2.3 – 标量、向量、矩阵和张量的示例
以下代码展示了如何使用 Python 存储和检索 Joblib 格式的模型:
什么是 Joblib?
Joblib (joblib.readthedocs.io/en/latest/) 是一组工具,用于在 Python 中提供轻量级管道,以持久化(或序列化)Python 对象。本代码中使用 Joblib 版本 1.2.0。
本例的 Jupyter 笔记本为 LinearRegression_SaveModel.ipynb:
# Persist the model in python Joblib file
# Retrieve the model weights and use it further prediction
import joblib
import numpy as np
from sklearn.linear_model import LinearRegression
X = np.array([[10, 10], [10, 20], [20, 20], [20, 30]])
# Assume that target feature has some relationship with the input features with the formula y = 3 * x_1 + 5 * x2 + 50
y = np.dot(X, np.array([3, 5])) + 50# Run the model with the input data and output values
reg = LinearRegression().fit(X, y)
# Persist the model in python Joblib file
filename = "sample_model.sav"
joblib.dump(reg, filename)
# regression model which is used earlier
# Share this file alone to others for deploying in to production and for inferencing/predictions
一旦模型在文件系统或文件中持久化,则可以与其他开发人员或工程师共享该文件,而无需共享代码中使用的任何训练数据或模型细节。其他开发人员/工程师然后可以加载此文件并用于进一步的预测或将其部署到生产环境中进行生产使用。这已在 *图 2**.1 中解释。该模型保存在当前目录中,名称为 sample_model.sav;您可以使用任何扩展名,因为它并不重要使用哪个扩展名。源代码在 Linear_Regression_Load_Model.ipynb 中:
import joblib
import numpy as np
filename = "sample_model.sav"
# Load the model from disk
loaded_model = joblib.load(filename)
result = loaded_model.predict(np.array([[30, 50]]))
print(result)
Output: [390.]
分类
分类模型使用不同的算法根据输入变量之间的关系预测输出或因变量。分类算法专门设计用于预测离散值,例如垃圾邮件/非垃圾邮件、男性/女性、是/否等。这些预测值中的每一个都被称为标签或类别。
在二元分类场景中,只有两个可能的类别标签,例如,确定一封电子邮件是否为垃圾邮件。另一方面,多标签分类涉及同时预测多个类别标签。一个例子是将图像分类到各种类别,如猫、狗和鸟。
分类模型使用包含输入变量及其对应类别标签的历史数据进行训练。算法从这些有标签的数据中学习,并建立模式和关系,以便在新、未见过的数据上做出准确的预测。分类模型的性能基于准确率、精确率、召回率和 F1 分数等指标进行评估。这些指标评估模型根据其输入特征正确分配适当的类别标签到新实例的能力。
分类模型在各个领域都有广泛的应用,包括垃圾邮件过滤、情感分析、客户流失预测、欺诈检测和医疗诊断。通过利用不同的分类算法,可以从数据中获得有价值的见解,从而实现明智的决策和高效的问题解决。
| 分类类型 | 详细信息 | 示例 | 算法 |
|---|---|---|---|
| 二元 | 基于训练数据预测两个类别中的一个 | 是/否垃圾邮件/非垃圾邮件通过/失败癌症/无癌症 | 逻辑回归 K 最近邻决策树支持向量机朴素贝叶斯 |
| 多分类 | 预测两个以上类别中的一个 | 基于症状,例如,感冒、流感或 COVID-19 | K 最近邻决策树朴素贝叶斯随机森林梯度提升 |
| 多标签 | 有两个或更多类别标签 | 根据内容预测主题:金融、政治、科学、语言或所有这些 | 多标签决策树多标签随机森林多标签梯度提升 |
| 极端 | 候选标签数量巨大的分类任务 | 亚马逊 3M 数据集,其中标签数量为 2,812,281 | 深度学习算法更多算法:manikvarma.org/downloads/XC/XMLRepository.html |
表 2.4 – 分类类型和相关算法
分类示例
在这个例子中,我们将利用决策树分类算法,根据两个特征:年龄和是否有既往癌症状况,来确定患者生存的可能性。
决策树分类算法是机器学习中广泛使用的技术,它构建了一个决策的树状模型。它分析提供的数据以创建一个表示决策过程的结构。
在我们的场景中,患者的年龄和他们的癌症状态将被用作分类的输入特征。通过检查包含患者信息的有标签数据集,包括年龄、癌症状态和生存结果,算法学习模式并建立决策规则。
一旦模型经过训练,它就能够预测之前未曾遇到的新患者的存活结果。通过考虑这些患者的年龄和癌症状况,模型遍历决策树,直到达到表示预测结果的叶节点:患者是否预期会存活。
通过在这个例子中使用决策树分类算法,我们的目标是根据患者的年龄和癌症状况来分类患者的存活概率。这一宝贵的见解可以帮助医疗专业人员评估患者预后并告知治疗决策。
| 年龄(年) | 是否有/曾经有癌症(1 = 是,0 = 否) | 存活(1 = 是,0 = 否) |
|---|---|---|
| 10 | 1 | 1 |
| 20 | 1 | 1 |
| 30 | 1 | 1 |
| 80 | 1 | 0 |
| 75 | 0 | 0 |
| 78 | 0 | 0 |
| 35 | 1 | ?? (预测) |
| 78 | 1 | ?? (预测) |
表 2.5 – 分类示例的玩具数据集
在这个玩具数据集中,模型需要根据模型训练的历史数据预测最后两位患者的存活情况(具有两个标签的分类)。
源代码位于Classification_Example.ipynb。
Scikit-learn 为分类算法提供了各种 Python 类。由于我们在这个例子中选择了决策树算法,因此导入必要的类并准备模型接受的格式化的数据:
from sklearn import tree
X = [[10,1],[20,1],[30,1],[80,1],[75,0],[78,0]]
Y = [1,1,1,0,0,0]
clf = tree.DecisionTreeClassifier()
clf = clf.fit(X, Y)
clf.predict([[35,1]])
Output: array([1])
clf.predict([[78,1]])
Output: array([0])
在这种情况下,模型根据提供的训练数据预测,35 岁的患者会存活,而 78 岁的患者不会存活。
要了解决策树及其分裂方式,让我们看看以下代码行:
tree.plot_tree(clf)
这将基于输入特征和树的分裂方式绘制树。当训练数据中有更多特征,我们需要知道哪个特征更重要时,这很有用:
[Text(167.4, 163.07999999999998, ‘X[0] <= 52.5\ngini = 0.5\nsamples = 6\nvalue = [3, 3]’),
Text(83.7, 54.360000000000014, ‘gini = 0.0\nsamples = 3\nvalue = [0, 3]’),
Text(251.10000000000002, 54.360000000000014, ‘gini = 0.0\nsamples = 3\nvalue = [3, 0]’)]

图 2.2 - 树分裂的可视化
一旦模型经过训练和测试,它就可以在文件系统中持久化或直接用于生产。
在上一个例子中,我们使用 Joblib 格式持久化了模型。
现在我们尝试使用 ONNX 格式持久化模型,以了解更多信息。
使用 ONNX 格式持久化模型和执行模型
ONNX,即开放神经网络交换,是一个为机器学习和深度学习模型设计的开源格式。其目的是促进不同框架之间模型的互操作性。它通过提供一个可扩展的计算图模型并定义一组内置运算符和标准数据类型来实现这一点。
使用 ONNX,ML/DL 模型可以轻松转换为 ONNX 格式,允许使用 ONNX Runtime 无缝部署、导出、加载和执行。ONNX Runtime 是一个强大的工具,它可以在 CPU 或 GPU 上实现高性能的 ML 模型执行。重要的是,它不依赖于用于开发模型的特定训练框架的依赖项。通过利用 ONNX 和 ONNX Runtime,开发者可以确保他们的模型可以在各种框架之间移植,并且可以高效地执行。有关 ONNX 的更多详细信息,请参阅github.com/onnx/onnx。
将 sklearn 样本模型转换为 ONNX 格式
将模型转换为 ONNX 格式需要onnx、onnxruntime和skl2onnx框架。以下是如何安装这些框架的方法:
pip3 install onnx --user
pip3 install onnxruntime --user
pip3 install skl2onnx --user
框架安装完成后,执行以下代码将模型转换为 ONNX 格式(源代码位于Model_Persistence_Load_ONNX_Format.ipynb):
import numpy as np
from sklearn.linear_model import LinearRegression
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
initial_type = [('float_input', FloatTensorType([None, 2]))]
onx = convert_sklearn(clf, initial_types=initial_type)
with open("survive.onnx", "wb") as f:
f.write(onx.SerializeToString())
在此情况下,要将使用sklearn开发的 ML 模型转换为 ONNX 格式,首先需要提供训练中使用的数据类型:
initial_type = [(‘float_input’, FloatTensorType([None, 2]))]
然后,使用提供的方法将模型转换为 ONNX 格式,并指定在sklearn中使用的分类器。在我们的示例中,我们使用了决策树,并将模型命名为clf:
onx = convert_sklearn(clf, initial_types=initial_type)
一旦模型转换为 ONNX 格式,将其存储在磁盘上,并命名模型文件(在我们的例子中,为survive.onnx):
with open(“survive.onnx”, “wb”) as f:
f.write(onx.SerializeToString())
现在模型已存储为 ONNX 格式,并且可以在支持 ONNX Runtime 的任何框架上加载和执行。
使用 ONNX 格式加载 ML 模型并执行模型
以下代码行展示了如何加载存储在 ONNX 格式的模型以及如何使用该模型进行推理。本代码使用 ONNX 版本 1.14.1(源代码位于Model_Persistence_Load_ONNX_Format.ipynb):
import onnxruntime as rt
import numpy as np
sess = rt.InferenceSession("survive.onnx")
input_name = sess.get_inputs()[0].name
# To test whether the patient will survive or not with 78 years age and doesn’t have prior cancer
X_test = np.array([[78.0, 0.0]])
pred_onx = sess.run(None, {input_name: X_test.astype(np.float32)})[0]
print(pred_onx)
Output: [0]
无监督机器学习
在无监督机器学习中,模型使用未标记的训练数据进行训练,这意味着没有提供目标标签或类别。相反,无监督机器学习模型专注于理解数据中的内在模式和结构。与监督学习不同,监督学习中的模型从标记的示例中学习,无监督机器学习模型在没有任何预定义的类别标签的情况下揭示数据中的隐藏模式和关系。这允许发现以前未知的见解和模式,这些模式可能并不明显。通过利用无监督机器学习技术,分析师和数据科学家可以从未标记的数据中获得有价值的见解,揭示隐藏的结构,并根据数据集中发现的内在模式做出数据驱动的决策。
聚类
聚类是用于无监督机器学习的主要技术。它涉及根据数据点的内在特征将相似的数据点分组在一起。通过检查数据和识别相似性,无监督模型创建聚类,这些聚类代表了数据集中的不同组或模式。
聚类算法,如 k-means 聚类、层次聚类或基于密度的聚类,在无监督机器学习中常用于将数据组织成有意义的组。这些簇有助于数据探索、异常检测、客户细分和其他数据驱动任务。
聚类示例
让我们考虑一个公司旨在为其员工提供运输服务,并希望根据他们的居住地对他们进行聚类的场景。为了实现这一点,公司可以利用一个聚类模型,该模型以每个员工居住地的经纬度坐标作为输入数据。机器学习模型将根据指定的簇大小对员工进行聚类,簇大小可以等于可用于运输的车辆数量。通过分析员工的地理位置空间数据,聚类模型将把居住地相近的个人分组。这种分组使公司能够有效地将车辆分配到每个簇。
一旦聚类模型训练并建立,它可以根据新员工的居住坐标预测他们适当的簇。这使得公司可以轻松地确定新员工应加入哪个簇,从而便于无缝的运输安排。
通过在这个场景中利用机器学习聚类技术,公司可以有效地组织其运输服务,并根据员工的居住地优化资源配置。
| 员工编号 | 纬度(****北纬) | 经度(****东经) |
|---|---|---|
| 1 | 12.93 | 77.4472 |
| 2 | 12.32 | 77.4472 |
| 3 | 12.51 | 77.4472 |
| 4 | 12.62 | 77.4472 |
| 5 | 12.73 | 77.4472 |
| 6 | 12.84 | 76.4158 |
| 7 | 12.91 | 76.4158 |
| 8 | 12.41 | 76.4158 |
| 9 | 12.92 | 76.4158 |
| 10 | 12.55 | 76.4158 |
表 2.6 – 聚类示例的玩具数据集
sklearn 框架支持各种聚类算法,在本例中我们将使用 K-means 聚类算法对给定数据进行聚类。
K-means 算法是一种基于质心的算法,其中每个簇都与一个质心相关联。该算法的主要目的是最小化输入数据点与其对应簇之间的距离之和。
源代码位于 Clustering_Example.ipynb。
导入 sklearn K-means 聚类类,并将训练数据准备为 numpy 数组格式:
from sklearn.cluster import KMeans
import numpy as np
from sklearn.cluster import KMeans
import numpy as np
X = np.array([
[12.93,77.4472],
[12.32,77.4472],
[12.51,77.4472],
[12.62,77.4472],
[12.73,77.4472],
[12.84,76.4158],
[12.91,76.4158],
[12.41,76.4158],
[12.92,76.4158],
[12.55,76.4158],
])
kmeans = KMeans(n_clusters=2, random_state=0).fit(X)
kmeans.labels_
array([1, 1, 1, 1, 1, 0, 0, 0, 0, 0], dtype=int32)
kmeans.cluster_centers_
array([[12.726 , 76.4158],
[12.622 , 77.4472]])
kmeans.predict([[12.88, 76.88]])
array([0], dtype=int32
在这种情况下,前五个员工被分配到簇 1,其余的分配到簇 0:
| 员工编号 | 纬度(北纬) | 经度(东经) | 分配的簇 |
|---|---|---|---|
| 1 | 12.93 | 77.4472 | 1 |
| 2 | 12.32 | 77.4472 | 1 |
| 3 | 12.51 | 77.4472 | 1 |
| 4 | 12.62 | 77.4472 | 1 |
| 5 | 12.73 | 77.4472 | 1 |
| 6 | 12.84 | 76.4158 | 0 |
| 7 | 12.91 | 76.4158 | 0 |
| 8 | 12.41 | 76.4158 | 0 |
| 9 | 12.92 | 76.4158 | 0 |
| 10 | 12.55 | 76.4158 | 0 |
表 2.7 - 分配的簇
基于输入学习并形成的聚类模型分为两个簇。K-means 是一种聚类算法,它找到簇的中心,将数据划分为簇,并根据最近的簇预测新数据。
以下是由sklearn框架支持的聚类算法列表:
-
相似性传播
-
聚类
-
BIRCH
-
DBSCAN
-
K-means
-
Mini-batch K-means
-
均值漂移
-
OPTICS
-
谱聚类
-
高斯混合模型
强化机器学习
强化学习(RL)是一种机器学习技术,它使智能体能够通过尝试错误,利用自身行动和经验中的反馈在交互式环境中学习。智能体学习一系列导致最终目标的行动,最大化其总奖励。RL 与监督学习不同,因为模型是从采取行动和观察结果中学习,而不是从明确的教学中学习。
强化学习的一个经典用例是在游戏领域,例如教模型下棋并取得优异成绩。模型开始时对游戏一无所知,但通过移动和观察所玩游戏的结果来学习,目标是最大化奖励(即赢得游戏)。
在强化学习的背景下,探索和利用是智能体可以用来在环境中导航的两个策略:
-
探索:这是智能体试图了解更多关于其环境的时候。这意味着尝试不同的行动并收集更多信息,以了解每个可能行动的奖励。智能体的目标是平衡从已知信息中获得的奖励与从未知区域获得更高奖励的可能性。然而,探索可能涉及智能体做出非最优选择的风险。
-
利用:在这里,智能体使用它已经学习到的信息来采取最佳行动,以最大化其奖励。这意味着使用已知信息来最大化成功,而不是进一步探索。利用的好处是它允许获得更确定、即时的奖励,但过度利用可能导致次优结果,因为它可能忽略了更好的选项。挑战在于找到正确的平衡,因为过分关注探索可能意味着智能体会失去即时奖励,而过分关注利用可能阻止智能体探索可能导致未来更大奖励的选项。这种权衡通常被称为探索-利用困境。
使用 RL 的示例问题——多臂老丨虎丨机问题
多臂老丨虎丨机问题是强化学习领域的一个经典问题,它捕捉了探索与利用之间的基本权衡。这个名字来源于一个假设的实验,在这个实验中,你面对几个具有不同固定收益的老丨虎丨机(也称为“单臂老丨虎丨机”)。由于这些不同的收益,你的目标是通过对哪些机器进行游戏、每次玩多少次以及以何种顺序进行游戏来最大化在一定次数尝试中的总收益——因此,这就是“多臂老丨虎丨机问题”。
多臂老丨虎丨机问题的主要挑战在于平衡来自利用性动作(玩你认为当前具有最高预期收益率的机器)的即时奖励与来自探索(尝试其他可能具有更高预期收益但不太确定的机器)的潜在收益。这种探索与利用之间的紧张关系是许多强化学习问题的核心。
以下为强化学习的示例代码——源代码位于BandIt_RL_Example.ipynb中:
import numpy as np
# This example will use a 4-armed bandit.
# Initialization
num_trials = 1000
bandit_probabilities = [0.1, 0.15, 0.3, 0.35] # The probability of each bandit to give reward
reward_counts = np.zeros(4)
selected_bandit = 0
for i in range(num_trials):
# Select a bandit
selected_bandit = np.random.randint(0, 4)
# Pull bandit’s arm
random_num = np.random.random()
if random_num <= bandit_probabilities[selected_bandit]:
reward = 1
else:
reward = 0
reward_counts[selected_bandit] += reward
print(“Most successful bandit:”, np.argmax(reward_counts))
Most successful bandit: 3
在本例中,使用了ε-贪婪策略,其中ε为1。
这是一个非常简单的例子,而现实世界的强化学习问题需要更复杂的算法(例如 Q 学习、策略梯度等),因此使用专门的库来实现。
在本节中,我们介绍了不同类型的机器学习,并提供了如何保存和加载模型以进行推理和预测的示例。接下来,下一节将深入探讨机器学习的各个阶段,提供详细的探索。
机器学习阶段概述
机器学习包含各种技术和方法,它涉及在开发和部署机器学习模型过程中的几个不同的阶段或阶段。这些阶段有助于指导工程师通过机器学习项目的迭代和循环性质,使他们能够构建有效且准确的模型。
机器学习过程通常包括几个关键阶段,每个阶段都服务于特定目的,并有助于项目的整体成功。这些阶段并不总是严格线性,它们之间可能发生迭代,以精炼和改进模型。具体步骤和术语的使用可能因采用的机器学习方法而异,但核心阶段保持一致。
机器学习阶段提供了一个系统框架,用于开发和部署机器学习模型,指导实践者通过构建有效解决方案固有的复杂性和挑战。通过遵循这些阶段,实践者可以最大化成功的机会,并创建能够在广泛应用中提供有价值和预测的机器学习模型。
机器学习的主要阶段
以下为机器学习的主要阶段:
-
数据收集:这个阶段涉及从各种来源收集相关数据,例如数据库、API 或手动收集。数据应代表问题域,并涵盖广泛的场景。
-
数据准备:在这个阶段,收集到的数据被预处理并转换为适合分析的形式。这可能包括诸如清理数据、处理缺失值、去除异常值以及归一化或缩放特征等任务。
-
特征工程:特征工程涉及从可用数据中选择和创建相关特征,这些特征将增强模型的预测能力。这个阶段需要领域知识和创造力,以从数据中提取有意义的见解。
-
模型开发:在这个阶段,根据手头的问题选择合适的机器学习算法或模型。模型在准备好的数据上训练,以学习数据中的模式和关系。
-
模型评估:使用适当的评估指标对训练好的模型进行评估,以评估其性能。这有助于了解模型在未见过的数据上的泛化能力以及它是否满足准确性和可靠性方面的预期标准。
-
模型优化:如果模型的性能不满意,这个阶段涉及通过调整超参数或尝试不同的算法来微调模型,以提高其性能。优化过程旨在实现最佳可能的结果。
-
模型部署:一旦模型经过训练和优化,它就被部署到生产环境中,可以在新的、未见过的数据上进行预测。这个阶段涉及将模型集成到现有系统中或为用户创建与模型交互的界面。
-
模型监控和维护:部署后,需要监控模型以确保其随着时间的推移继续表现良好。监控涉及跟踪性能指标、识别数据分布的漂移,并在必要时更新模型。定期维护对于保持模型最新和准确至关重要。
这些阶段提供了一个系统的方法来构建和部署机器学习模型,使组织能够利用数据的力量并做出明智的决策。
机器学习过程中的子阶段
下面的图显示了机器学习过程的阶段:

图 2.3 – 机器学习阶段
这些是主要阶段:
-
数据准备阶段
-
机器学习模型阶段(设计和开发)
-
机器学习操作阶段
让我们更详细地看看这些。
数据准备阶段
数据准备阶段处理数据收集、提取和操作。
| 阶段 | 子阶段 | 细节 |
|---|---|---|
| 数据准备 | 数据收集 | 确定需要分析的数据 |
| 数据提取 | 从数据源中提取数据 | |
| 数据操作 | 数据转换、缺失数据、重复数据、噪声和数据预处理 | |
| 探索性数据分析(EDA) | EDA 和数据处理 |
表 2.8 - 数据准备阶段
下图展示了数据准备子阶段:
数据准备阶段

图 2.4 – 机器学习数据准备子阶段
机器学习模型阶段
此阶段被细分为几个阶段,以处理特征工程、实际模型识别、模型的训练和测试等。
| 阶段 | 子阶段 | 详细信息 |
|---|---|---|
| 机器学习模型 | 模型识别 | 这涉及到分类、聚类、强化学习、时间序列分析等。 |
| 特征工程 | 在此阶段,从数据中选择特征。 | |
| 为模型准备输入数据 | 这涉及到以模型期望的格式处理和准备的数据。 | |
| 分割数据(训练、测试和验证) | 将整个数据分割成三个部分——训练数据、测试数据和验证数据,以训练、测试和验证模型。 | |
| 使用训练数据集训练模型 | 在此阶段,模型使用训练数据进行训练。 | |
| 使用测试数据集测试模型 | 使用测试数据测试机器学习模型,以找出预测的准确性。 | |
| 数据、模型、模型参数和结果版本 | 对使用的数据集、模型及其参数以及每个实验的结果应用版本控制。 | |
| 使用训练模型验证数据集 | 这类似于测试数据,但样本来自验证数据集。 | |
| 使用新数据预测结果(推理) | 对于推理,使用新数据并找出结果。 |
表 2.9 - 机器学习模型阶段
下图展示了机器学习模型子阶段:

图 2.5 – 机器学习模型子阶段
机器学习操作阶段
此阶段主要关注生产中模型的操作。
| 阶段 | 子阶段 | 详细信息 |
|---|---|---|
| 机器学习操作(MLOps) | 打包模型工件 | 将模型(存储权重和偏差)持久化存储为 ONNX 格式或其他格式。 |
| 部署模型 | 这涉及到模型的实际生产部署。(A/B 测试、金丝雀部署、影子模型等) | |
| 验证推理结果 | ||
| 监控模型性能 | 监控模型性能,即准确性是否在一段时间内保持不变或下降。 | |
| 重新训练模型并重复机器学习模型生命周期 | 如果模型性能下降,则重新训练模型,并相应地处理模型漂移和数据漂移。 |
表 2.10 - 机器学习操作
下图展示了机器学习操作子阶段:

图 2.6 – 机器学习操作子阶段
我们已经详细介绍了机器学习模型的发展以及该过程中涉及的各种阶段。在接下来的部分,我们的重点将转向探索机器学习每个阶段可能发生的隐私威胁和攻击。我们将深入了解这些威胁,并讨论有效的缓解策略,以保护数据和模型涉及的隐私。通过在每个阶段解决这些隐私问题,我们可以确保机器学习技术的负责任和安全实施。
机器学习阶段中的隐私威胁/攻击
机器学习项目是由数据工程师、机器学习工程师和软件工程师协作开发的,每个角色都在开发端到端系统以预测和提供见解中扮演不同的角色。
机器学习项目中的协作角色
机器学习项目是涉及各种角色如数据工程师、机器学习工程师和软件工程师的协作努力。每个角色以不同的方式为开发端到端系统做出贡献,这些系统能够预测结果并提供有价值的见解。让我们来探讨在机器学习项目生命周期中各个角色的职责:
-
数据工程师:数据工程师主要关注数据准备阶段。他们负责从一个或多个来源提取数据,并确保其质量适合机器学习项目。数据工程师从事数据清洗、转换和特征选择等任务,以准备数据用于机器学习建模。
-
机器学习工程师:机器学习工程师在设计和开发机器学习模型中扮演着至关重要的角色。他们利用数据工程师提供的数据来训练和测试模型。机器学习工程师负责选择合适的算法或模型架构,调整超参数,并优化模型以提高准确性和效率。他们使用验证测试数据验证模型,并提供推理或模型导出/部署到生产环境的 API。
-
模型消费者:模型消费者可以是个人或另一个与机器学习模型交互的应用程序。他们通过 API 调用向模型提供输入以进行预测或推理。模型消费者利用机器学习模型生成的见解做出明智的决策或采取适当的行动。
机器学习中的隐私威胁/攻击
在机器学习的背景下,对手指的是一个试图积极破坏或利用机器学习模型或系统的实体或系统。对手的目标通常是操纵模型的行为,未经授权访问敏感信息,或者通过利用漏洞欺骗系统。
对手可以采取各种形式,具有不同的动机。
这里有一些例子:
-
对抗样本:在这种情况下,攻击者的目标是创建旨在误导或欺骗 ML 模型的输入样本(例如,图像或文本)。对抗样本旨在利用模型决策过程中的漏洞,导致错误预测或误分类。
-
数据中毒:攻击者可能会尝试将恶意或误导性数据注入训练数据集中。通过插入精心制作的样本,攻击者旨在操纵模型的训练过程,导致结果偏差或受损。这在从不可信或不可靠来源收集训练数据的情况下尤其成问题。
-
模型反演:攻击者可能会尝试从训练好的模型中提取敏感信息。通过提供特定输入并观察模型的输出,攻击者旨在推断用于训练模型的机密或私人数据,例如个人身份信息(PII)或专有知识。
-
逃避攻击:攻击者也可以在部署阶段发起逃避攻击,也称为对抗攻击。在这些攻击中,攻击者通过仔细修改输入样本来尝试绕过或操纵模型的防御机制。例如,在垃圾邮件分类器的情况下,攻击者可能会添加特定的模式或关键词来欺骗模型,将其分类为合法的恶意邮件。
为了减轻攻击者的影响,研究人员和从业者开发了鲁棒的 ML 模型和技术,例如对抗训练、防御蒸馏和输入净化。这些方法旨在增强 ML 系统对对抗攻击的弹性,并在潜在威胁存在的情况下保持其性能和可靠性。
在整个 ML 生命周期中,隐私威胁或攻击都可能发生,对敏感信息的机密性构成风险。在 ML 的背景下,攻击者试图未经授权访问用于 ML 的机密数据、核心 ML 模型或数据的特定特征。
有两种主要的攻击类型,白盒和黑盒:
-
白盒攻击:白盒攻击假设攻击者对 ML 模型有全面的知识和访问权限,包括其架构、输入、输出和权重。攻击者利用这些信息来提取机密细节。
-
黑盒攻击:相比之下,黑盒攻击假设攻击者只能访问 ML 模型的输入和输出。他们对底层架构或 ML/DL 模型中使用的权重一无所知。尽管信息有限,但他们旨在从模型中推断敏感信息。
隐私威胁/攻击分类:
以下是对分类机器学习模型的隐私攻击
-
成员推理攻击:这种攻击旨在确定特定数据点是否是用于训练机器学习模型的训练数据集的一部分。攻击者试图通过利用模型的响应来推断成员信息。
-
模型提取攻击:在这种攻击中,攻击者试图提取整个或部分机器学习模型架构、权重或参数。这种攻击允许攻击者复制机器学习模型以供自己使用,可能导致知识产权盗窃。
-
重建攻击:这种攻击专注于从机器学习模型的输出中重建敏感信息。攻击者的目标是推断出用于生成模型预测的私有数据或特定特征。通过理解和应对这些隐私威胁,机器学习从业者可以采取适当的措施来保护敏感数据,并确保机器学习模型在其整个生命周期中的安全性。
我们将在接下来的章节中更详细地探讨这些问题。
成员推理攻击
假设开发了一个分类模型,使用某些输入训练数据 X {x1, x2, x3, …. Xn},通过函数 F 预测某些标签 y。
成员推理攻击试图确定输入样本 x 是否是训练数据集 X 的一部分。基本上,攻击者(攻击者)需要找出当前数据点是否属于用于训练机器学习模型的原始数据集。

图 2.7 – 成员推理攻击 - 示例
(图片来源:Suha Hussain,PrivacyRaven,blog.openmined.org/privacyraven-comprehensive-privacy-testing-for-deep-learning/)
让我们来看一个例子。假设一个攻击者想要确定某个特定人的数据是否被用于训练数据中,而不需要知道这个人。后来,这些数据被用来推断是否批准该人的保险政策。
这是攻击中最受欢迎的类别,最初由 Shokri 等人提出。
这里是完整论文的引用:Reza Shokri, Marco Stronati, Congzheng Song, and Vitaly Shmatikov. 2017. Membership inference attacks against machine learning models. In 2017 IEEE Symposium on Security and Privacy (SP). IEEE, San Francisco, CA, USA, 3–18.
这是一种黑盒测试攻击,因为攻击者没有实际机器学习模型的详细信息;他们所拥有的只是输入数据集和模型推断结果。
论文关于这种方法是这样说的:
“攻击者用一个数据记录查询目标模型,并获取该模型对该记录的预测。预测是一个向量,每个类别一个概率,表示记录属于某个类别的概率。这个预测向量,连同目标记录的标签一起,被传递给攻击模型,该模型确定记录是否在目标模型的训练数据集中。”
下一个图也来自上述论文(arxiv.org/pdf/1610.05820.pdf):

图 2.8 – 成员推理攻击 - 示例
成员推理攻击—基本示例
在成员推理攻击中,攻击者试图确定特定数据点是否被用于机器学习模型的训练集中,如前所述。
这里是一个使用简单的决策树分类器的例子(源代码可以在Membership_Inference_basic_example.ipynb中找到):
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
# Load the dataset (e.g., Iris dataset)
iris = datasets.load_iris()
X = iris.data
y = iris.target
# Split the data into training and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=42)
# Train a decision tree classifier on the training set
clf = DecisionTreeClassifier()
clf.fit(X_train, y_train)
for i in range (0,75):
# Select a data point from the test set
target_data = X_test[i]
#Determine if the target data point was in the training set
predicted_class = clf.predict([target_data])
is_in_training_set = predicted_class == y_test[i]
# Print the result
if is_in_training_set:
print(target_data, "Membership Inference Attack successful! Target data point was in the training set.")
else:
print( target_data, "Membership Inference Attack unsuccessful. Target data point was not in the training set.")
Output:
[6.9 3.1 5.1 2.3] Membership Inference Attack successful! Target data point was in the training set.
[6.2 2.2 4.5 1.5] Membership Inference Attack unsuccessful. Target data point was not in the training set.
在这个例子中,我们从 scikit-learn 中加载了Iris数据集,并将其分为训练集和测试集。然后我们在训练集上训练一个决策树分类器。接下来,我们从测试集中选择一个数据点(或一组数据点),并通过预测其类别来尝试确定它是否存在于训练集中。如果预测的类别与测试集中的实际类别相匹配,我们推断目标数据点在训练集中,这表明攻击成功。记住,未经适当授权进行成员推理攻击是不道德的,通常是非法的。
成员推理攻击—高级示例
让我们考虑一个场景,其中攻击者试图确定特定个人的数据是否存在于训练数据中,而对该个人没有任何先前的了解。这个场景涉及发现一个人的名字是否存在于医院的敏感临床数据中。攻击者打算利用这些信息来做出决策,例如根据从训练数据中获得的认识来授予或拒绝保险政策。
为了说明这种情况,让我们使用一个类似我们之前讨论的分类示例的样本数据集(仅用于说明目的)。该数据集侧重于根据年龄和现有疾病等因素预测患者是否能在未来 5 到 10 年内生存。
在这种情况下,攻击者的目标是确定与特定人员相关的数据(他们不知道该人员的身份)是否存在于训练数据中。通过发现这些信息,攻击者可以基于从训练数据中获得的认识来操纵与保险政策相关的决策。
需要注意的是,此示例旨在突出潜在的隐私威胁,并不旨在验证其准确性或实际应用性。目标是提高人们对保护敏感数据以及实施强大的隐私措施以防止未经授权的访问和滥用的认识。
| 年龄(年) | 是否患有癌症(1 = 是,0 = 否) | 是否存活(1 = 是,0 = 否) |
|---|---|---|
| 10 | 1 | 1 |
| 20 | 1 | 1 |
| 30 | 1 | 1 |
| 80 | 1 | 0 |
| 75 | 0 | 0 |
| 78 | 0 | 0 |
表 2.11 - 训练数据
该机器学习模型的源代码可在 Membership_Inference_advanced_example.ipynb 中找到:
from sklearn import tree
X = [[10,1],[20,1],[30,1],[80,1],[75,0],[78,0]]
Y = [1,1,1,0,0,0]
clf = tree.DecisionTreeClassifier()
clf = clf.fit(X, Y)
clf.predict([[35,1]])
样本测试数据的推理结果
攻击者创建具有不同输入的合成测试数据以评估模型性能。他们的目标是确定给定的患者数据是否存在于训练数据集中,使用模型预测:
testY=[
[25,1],[25,0],[30,1],[30,0],[45,0],[45,1],
[50,1],[50,0],[60,1],[60,0],[75,0],[75,1],
[80,1],[80,0],[90,1],[90,0],[100,0],[100,1],
[10,1],[20,1],[30,1],[78,0]
]
clf.predict(testY)
array([1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0])
clf.predict_proba(testY)
array([[0., 1.],
[0., 1.],
[0., 1.],
[0., 1.],
[0., 1.],
[0., 1.],
[0., 1.],
[0., 1.],
[1., 0.],
[1., 0.],
[1., 0.],
[1., 0.],
[1., 0.],
[1., 0.],
[1., 0.],
[1., 0.],
[1., 0.],
[1., 0.],
[0., 1.],
[0., 1.],
[0., 1.],
[1., 0.]])
结果以表格形式呈现;1 表示该人患有癌症,预测概率列显示预测概率的百分比:
| 年龄 | 癌症 | 预测类别 | 预测概率 |
|---|---|---|---|
| 25 | 1 | 1 | 100 |
| 25 | 0 | 1 | 100 |
| 30 | 1 | 1 | 100 |
| 30 | 0 | 1 | 100 |
| 45 | 1 | 1 | 100 |
| 45 | 0 | 1 | 100 |
| 50 | 1 | 1 | 100 |
| 50 | 0 | 1 | 100 |
| 60 | 1 | 0 | 0 |
| 60 | 0 | 0 | 0 |
| 75 | 1 | 0 | 0 |
| 75 | 0 | 0 | 0 |
| 80 | 1 | 0 | 0 |
| 80 | 0 | 0 | 0 |
| 90 | 1 | 0 | 0 |
| 90 | 0 | 0 | 0 |
| 100 | 1 | 0 | 0 |
| 100 | 0 | 0 | 0 |
| 10 | 1 | 0 | 100 |
| 20 | 1 | 0 | 100 |
| 30 | 1 | 0 | 100 |
| 78 | 0 | 1 | 0 |
表 2.12 - 预测概率
接下来,攻击者开始开发影子模型和最终的攻击模型。这些模型旨在预测给定的数据记录是否用于训练数据集。通过利用每个记录及其预测类别,以及相应的预测概率,攻击者推断该数据记录是否是训练集的一部分。

图 2.9 – 影子模型
前面的图表来源于论文arxiv.org/pdf/1610.05820.pdf。
攻击模型使用类别标签 'In' 表示用于训练的给定输入记录,而 'out' 表示它没有被使用。
这是最终攻击模型的训练数据:
| 年龄 | 癌症 | 预测类别 | 预测概率 | 训练集中使用的记录(in = 1,out = 0) |
|---|---|---|---|---|
| 25 | 1 | 1 | 100 | 1 |
| 25 | 0 | 1 | 100 | 1 |
| 30 | 1 | 1 | 100 | 1 |
| 30 | 0 | 1 | 100 | 1 |
| 45 | 1 | 1 | 100 | 1 |
| 45 | 0 | 1 | 100 | 1 |
| 50 | 1 | 1 | 100 | 1 |
| 50 | 0 | 1 | 100 | 1 |
| 10 | 1 | 0 | 100 | 1 |
| 20 | 1 | 0 | 100 | 1 |
| 30 | 1 | 0 | 100 | 1 |
| 60 | 1 | 0 | 0 | 0 |
| 60 | 0 | 0 | 0 | 0 |
| 75 | 1 | 0 | 0 | 0 |
| 75 | 0 | 0 | 0 | 0 |
| 80 | 1 | 0 | 0 | 0 |
| 80 | 0 | 0 | 0 | 0 |
| 90 | 1 | 0 | 0 | 0 |
| 90 | 0 | 0 | 0 | 0 |
| 100 | 1 | 0 | 0 | 0 |
| 100 | 0 | 0 | 0 | 0 |
| 78 | 0 | 1 | 0 | 0 |
表 2.13 - 最终攻击模型的训练数据
成员推理攻击可以在简单的线性模型中轻松执行,并且准确性非常高,如前例所示。托管在云中的机器学习模型容易受到此类推理攻击,因为研究人员已经成功演示了准确率超过 90%的成员攻击模型。
减轻成员推理攻击的技术
在涉及敏感数据的机器学习模型中,成员推理攻击可能是一个问题。
以下是一些减轻成员推理攻击的技术:
-
限制对敏感信息的访问:减轻成员推理攻击的一种简单方法就是限制对敏感信息的访问。通过最小化暴露的敏感数据量,可以减少攻击者执行成员推理的可能性。
-
差分隐私:差分隐私是一种向训练数据或模型输出添加噪声的技术,使得攻击者更难确定特定记录是否是训练集的一部分。应用差分隐私机制可以帮助抵御成员推理攻击。我们将在下一章学习差分隐私。
-
训练集增强:通过向训练集添加额外的合成或生成数据,可以使得攻击者更难区分真实训练实例和潜在成员。数据生成、扰动或添加噪声等增强技术可以帮助提高训练集的隐私性。
-
正则化和 dropout:应用 L1 或 L2 正则化技术,并在神经网络中引入 dropout 层可以提高模型的鲁棒性并减少过拟合。正则化有助于减少训练实例的记忆,使得攻击者更难推断成员身份。
-
模型压缩:在共享模型或进行预测时,考虑使用模型压缩技术以减少关于训练数据的泄露信息量。例如,量化、剪枝或知识蒸馏等技术可以帮助降低模型对训练集的敏感性。
-
集成方法:通过训练具有不同架构或使用不同算法的多个模型,可以使得攻击者更难执行准确的成员推理。集成方法使得攻击者更难学习训练数据中的特定模式。
-
安全聚合:如果模型是在分布式环境中训练的,可以使用安全聚合协议来确保不同各方贡献的个体信息得到保护,并且成员信息不会被泄露。
-
随机响应:在推理过程中,可以使用随机响应技术向模型输出引入噪声,使攻击者更难确定成员资格状态。随机响应机制确保了个人记录的可信否认性。
-
访问控制和授权:实施访问控制措施和强大的授权机制可以帮助限制对敏感模型和数据的访问,减少潜在攻击者的暴露。
-
模型监控:持续监控模型的行为,以检测任何异常模式或意外的输出,有助于检测潜在的成员推断攻击。监控可能涉及异常检测、对抗鲁棒性检查或模型输出的统计分析等技术。
重要的是要注意,没有单一的技术可以提供对成员推断攻击的完全保护。通常需要结合多种技术和对隐私和安全的全面方法来有效地减轻这些攻击。
模型提取攻击
模型提取攻击是一种黑盒攻击,其中攻击者通过创建一个替代模型(表示为 𝑓’),该模型紧密模拟被针对的原始模型(表示为 𝑓)的行为,旨在提取信息,并可能重新创建模型。
让我们考虑一个场景,即我们开发了一个专门用于预测给定帖子/推文是否与灾难相关的机器学习模型。我们向消费者提供 API,使他们能够访问这些预测功能,并对每个 API 请求收费。

图 2.10 - 保护机器学习模型完整性
对手利用提供的 API,系统地提交数千条输入推文以获取相应的预测。随后,对手继续构建一个新的机器学习模型,这些推文是通过查询原始作者暴露的 API 获得的。从 API 获得的预测结果作为新模型的类别标签,指示推文是否被分类为与灾难相关。

图 2.11 – 模型提取攻击—对手的机器学习模型
在某些情况下,对手开发的机器学习模型可能比原始作者的机器学习模型具有更高的准确性。因此,这可能会严重影响原始作者公司的收入。对手可能通过公开类似的推理 API,收取比原始作者低得多的费用,并可能涉及知识产权的盗窃。此外,模型提取攻击使对手能够访问与机器学习模型相关的私人信息,进一步加剧了可能造成的损害。
模型提取攻击的示例
本例的源代码可以在Model Extraction_Attack Example.ipynb中找到。
在本例中,我们首先创建一个包含两个特征(X)及其对应标签(y)的样本数据集。随后,我们使用 scikit-learn 的LogisticRegression类在这个数据集上训练逻辑回归模型。
攻击者的代码旨在通过在相同的数据集上训练一个新的LogisticRegression模型(extracted_model)来执行模型提取攻击。攻击者的目标是复制原始模型的行为,而不直接访问其内部工作原理。
一旦提取的模型成功生成,它可以被用于未经授权的目的,例如在新数据(new_data)上做出预测,而无需访问原始模型。这种未经授权的使用引发了关于原始模型功能安全和完整性的担忧。
以下是为模型提取攻击编写的源代码(Model Extraction_Attack Example.ipynb):
import numpy as np
from sklearn.linear_model import LogisticRegression
# Create a sample dataset for demonstration
X = np.array([[1, 1], [2, 2], [3, 3], [4, 4], [5, 5]])
y = np.array([0, 0, 0, 1, 1])
# Train a simple logistic regression model on the dataset
model = LogisticRegression()
model.fit(X, y)
# Attacker's code to perform model extraction attack
extracted_model = LogisticRegression()
extracted_model.fit(X, y)
# Extracted model can be further used for unauthorized purposes
# such as making predictions on new data without access to the original model
new_data = np.array([[6, 6], [7, 7]])
predictions = extracted_model.predict(new_data)
print(predictions)
[1 1]
减缓模型提取攻击的技术
缓解模型提取攻击,即对手试图提取底层模型的架构、参数或功能,对于保护知识产权和维护敏感模型的安全至关重要。
减缓模型提取攻击的一些技术如下:
-
模型水印: 将一个独特的水印嵌入模型的参数或架构中,可以帮助识别模型的来源并阻止未经授权的提取。水印技术可以设计成对移除尝试或修改具有抵抗力,同时在正常模型操作中保持不可察觉。
-
模型混淆: 对模型的代码或架构应用混淆技术可以使攻击者更难理解模型的内部工作原理。混淆可能涉及代码混淆、函数重命名、控制流多样化或加密等技术,以保护模型的实现细节。
-
安全模型共享: 当与授权用户或合作者共享模型时,重要的是要采用安全的共享机制。这可能包括在传输和静止状态下的加密、强大的访问控制措施以及安全的身份验证和授权协议,以防止对模型的未经授权访问。
-
模型压缩: 使用量化、剪枝或知识蒸馏等模型压缩技术可以使模型更加紧凑,并减少可以提取的信息量。压缩模型通常具有更少的参数和结构细节,这使得它们对模型提取攻击更具抵抗力。
-
细粒度访问控制:实施细粒度访问控制机制可以限制敏感模型的暴露。这可能包括根据用户角色和权限仅提供对模型必要组件或功能的访问。
-
安全执行环境:在安全的执行环境中运行模型可以帮助防止提取攻击。例如,安全区域(如英特尔 SGX 或 AMD SEV)、可信执行环境(TEEs)和安全多方计算(MPC)等技术可以为执行模型提供隔离和完整性保证,防止未经授权访问模型的内部信息。我们将在第九章中了解更多关于 TEE 的内容。
-
模型元数据保护:保护与模型相关的元数据,如训练数据、超参数或训练过程细节,可以使攻击者更难提取有关模型的有意义信息。例如,差分隐私或数据扰动等技术可以帮助在模型元数据中保持隐私。
-
监控异常模型使用:实施模型监控和异常检测机制可以帮助识别可疑活动,如重复查询或过度模型交互,这可能表明未经授权的提取尝试。当检测到潜在攻击时,监控可以触发警报或启动防御行动。
-
法律和许可措施:实施法律保护,如版权、专利或许可协议,可以提供额外的法律救济并阻止未经授权的模型提取和使用。
正如我们讨论的成员推理攻击,需要注意的是,没有单一的技术可以提供对模型提取攻击的完全保护;通常需要多种技术的组合。缓解技术的选择取决于具体的威胁模型、模型敏感性以及所需的保护水平。
我们已经了解了针对机器学习模型的成员推理攻击和模型提取攻击。现在让我们探索机器学习模型的第三种隐私攻击:重建攻击。
重建攻击——模型反转攻击
重建攻击试图重建一个或多个训练数据实例及其相应的类标签。重建可能是部分或完整的,这取决于原始模型的力量。一次完全成功的攻击可以生成更真实的训练数据和各种样本,以匹配精确的类标签预测。
模型反转或属性推理都是重建攻击的一种。它们属于黑盒攻击类别,因为攻击者不需要了解模型结构的细节或内部工作原理。他们只需要根据一些输入数据访问模型的输出。利用这一点,他们可以推断出用于训练模型的数据的详细信息。
创建模型反转攻击的逐步示例
在本例中,我们首先创建一个包含两个输入特征(X)和二进制标签(y)的简单数据集。我们使用此数据集训练一个逻辑回归模型。model_inversion_attack 函数试图通过找到产生所需输出概率的输入来反转模型。
请注意,这是一个基本示例,用于说明模型反转攻击的概念。在实际场景中,模型反转攻击可能更加复杂,需要更高级的技术来处理更大和更复杂的模型。
完整的源代码可以在 Model_Inversion_LR_Sample.ipynb 中找到:
from sklearn.linear_model import LogisticRegression
import numpy as np
# Create a sample dataset
X = np.array([[1, 2], [3, 4], [5, 6], [7, 8]]) # Input features
y = np.array([0, 0, 1, 1]) # Corresponding labels
# Train a logistic regression model on the dataset
model = LogisticRegression()
model.fit(X, y)
# Function to perform model inversion attack
def model_inversion_attack(model, output):
# Generate a random input within a certain range
input_range = np.arange(0, 10, 0.01)
best_input = None
best_loss = float('inf')
# Find the input that minimizes the loss function
for i in input_range:
input_guess = np.array([[i, i]])
predicted_output = model.predict_proba(input_guess)
loss = abs(predicted_output[0][1] - output)
if loss < best_loss:
best_input = input_guess
best_loss = loss
return best_input
# Perform model inversion attack on a specific output
target_output = 0.8
inverted_input = model_inversion_attack(model, target_output)
print("Inverted Input:", inverted_input)
target_output = 1
inverted_input = model_inversion_attack(model, target_output)
print("Inverted Input:", inverted_input)
target_output = 0.5
inverted_input = model_inversion_attack(model, target_output)
print("Inverted Input:", inverted_input)
target_output = 0
inverted_input = model_inversion_attack(model, target_output)
print("Inverted Input:", inverted_input)
Inverted Input: [[5.64 5.64]]
Inverted Input: [[9.99 9.99]]
Inverted Input: [[4.5 4.5]]
Inverted Input: [[0\. 0.]]
让我们探索一个更复杂的例子来理解模型反转攻击。
神经网络中的模型反转攻击
神经网络是一类受人类大脑结构和功能启发的机器学习模型。它们被设计用来识别数据中的复杂模式和关系。神经网络由相互连接的人工神经元层组成,称为节点或单元,共同形成一个网络。
每个神经元接收输入信号,对它们应用数学运算,并产生输出信号。这些信号通过网络传递,神经元之间的连接权重决定了信号的强度。神经网络通过称为反向传播的过程进行训练,该过程根据预测输出和实际输出之间的误差调整权重。
神经网络的隐藏层使其能够学习并表示数据中的复杂非线性关系,使其能够解决高度复杂的问题,如图像和语音识别、自然语言处理,甚至玩游戏。流行的神经网络架构包括前馈神经网络、卷积神经网络(CNNs)和循环神经网络(RNNs)。
神经网络在各个领域取得了显著的成功,在许多领域展示了最先进的性能。它们已成为机器学习的一个基本工具,并通过实现复杂的决策和模式识别能力,继续推动人工智能的边界。
我们不会深入探讨神经网络的复杂性,因为这超出了本书的范围。
在本例中,我们将演示攻击者如何利用神经网络模型的输出生成输入数据。攻击者的目标是利用模型行为的特征,重建导致特定输出预测的原始输入。通过逆向工程模型输出与相应输入数据之间的关系,攻击者可以深入了解用于训练模型的原始数据点。

图 2.12 – 原作者和对手的神经网络模型
输入数据
在这个例子中,我们使用 Modified National Institute of Standards and Technology (MNIST)数据集来训练一个神经网络模型。MNIST 数据集包含 60,000 张 0 到 9 之间的手写单数字的灰度图像。每张图像都是一个 28 x 28 像素的小正方形。
原作者模型
mnist_data.pkl. We open the file in binary read mode and load the dataset using the pickle.load() function. The dataset is then split into the training and test sets, with the corresponding labels.
注意
从 Github (github.com/pytorch/tutorials/blob/main/_static/mnist.pkl.gz) 下载数据集并将其保存在 data/mnist 目录中。
完整的源代码可以在 Model_Inversion_Attack_Example.ipynb 中找到。这里我们使用 PyTorch 版本 1.13.1:
from pathlib import Path
import requests
import pickle
import gzip
DATA_PATH = Path(“data”)
PATH = DATA_PATH / “mnist”
PATH.mkdir(parents=True, exist_ok=True)
# 10.195.33.40 - Github
URL = "https://10.195.33.40/pytorch/tutorials/raw/main/_static/"
FILENAME = “mnist.pkl.gz”
with gzip.open((PATH / FILENAME).as_posix(), “rb”) as f:
((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding=”latin-1”)
加载数据后,您可以使用 Matplotlib 库可视化一个样本图像并获取其形状。以下是代码片段:
from matplotlib import pyplot
import numpy as np
pyplot.imshow(x_train[0].reshape((28, 28)), cmap=”gray”)
print(x_train.shape, y_train[0])
这将产生以下输出:

(50000, 784) 5
现在,将训练样本转换为张量格式,以便在神经网络模型中作为输入使用:
import torch
x_train, y_train, x_valid, y_valid = map(
torch.tensor, (x_train, y_train, x_valid, y_valid)
)
n, c = x_train.shape
print(x_train, y_train)
print(x_train.shape)
print(y_train.min(), y_train.max())
tensor([[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]])
tensor([5, 0, 4, ..., 8, 4, 8])
print(x_train.shape)
torch.Size([50000, 784])
print(y_train.min(), y_train.max())
tensor(0) tensor(9)
让我们使用作为激活函数的 rectified linear unit (ReLU)构建一个简单的顺序神经网络模型:
from torch import nn, optim
class AuthorsNN(nn.Module):
def __init__(self):
super().__init__()
self.first_sec = nn.Sequential(
nn.Linear(784, 450),
nn.ReLU(),
)
self.second_sec = nn.Sequential(
nn.Linear(450, 450),
nn.ReLU(),
nn.Linear(450, 10),
nn.Softmax(dim=-1),
)
def forward(self, x):
return self.second_sec(self.first_sec(x))
AuthorsNN 类扩展了 PyTorch 的 nn.Module 类。此类代表一个用于分类任务的神经网络模型。以下是前面代码及其功能的分解:
-
The AuthorsNN 类:此类代表作者(们)设计的神经网络模型。它继承自 PyTorch 中所有神经网络模块的基类 nn.Module。
-
init 方法:此方法是 AuthorsNN 类的构造函数,在创建类的实例时被调用。在此方法内部,定义了模型的架构:
-
self.first_sec 是一个由两个层组成的顺序模块:
-
nn.Linear(784, 450) 代表一个具有 784 个输入特征和 450 个输出特征的线性层。
-
nn.ReLU() 应用 ReLU 激活函数以引入非线性。
-
-
self.second_sec 是另一个由三个层组成的顺序模块:
-
nn.Linear(450, 450) 代表一个具有 450 个输入特征和 450 个输出特征的线性层。
-
nn.ReLU() 应用 ReLU 激活函数。
-
nn.Linear(450, 10) 代表一个具有 450 个输入特征和 10 个输出特征的线性层,对应于类别的数量。
-
nn.Softmax(dim=-1) 将原始输出分数应用 softmax 激活函数转换为概率,确保它们在各个类别中总和为 1。
-
-
-
前向方法:此方法定义了模型的前向传递,指定输入数据如何通过网络。输入 x 通过 self.first_sec,然后是 self.second_sec,最终返回输出结果。
以下代码创建了一个名为auth_nn的AuthorsNN类实例。此实例代表初始化的神经网络模型:
auth_nn = AuthorsNN()
auth_nn
打印auth_nn将显示有关模型的信息,例如其架构和可训练参数的数量:
AuthorsNN(
(first_sec): Sequential(
(0): Linear(in_features=784, out_features=450, bias=True)
(1): ReLU()
)
(second_sec): Sequential(
(0): Linear(in_features=450, out_features=450, bias=True)
(1): ReLU()
(2): Linear(in_features=450, out_features=10, bias=True)
(3): Softmax(dim=-1)
)
)
接下来,我们定义一个损失函数来衡量实际数据与预测数据之间的误差:
loss_func = nn.CrossEntropyLoss()
loss_func
CrossEntropyLoss()
为了增强网络,让我们添加 Adam 优化器函数。这是一个优化算法,用于替换训练深度学习模型时使用的随机梯度下降(SGD)。
它结合了AdaGrad和RMSProp算法的优点,使其适合处理噪声问题场景中的稀疏梯度:
from torch import optim
optimizer = optim.Adam(auth_nn.parameters(), lr = 0.01)
在这里,我们从 PyTorch 中导入optim模块。在实例化AuthorsNN类之后,我们使用optim.Adam()函数定义 Adam 优化器。优化器使用模型的参数(auth_nn.parameters())初始化,使其能够在训练过程中优化模型。
接下来,打印optimizer以提供有关模型优化器配置的详细信息:
optimizer
这将产生以下输出:
Adam (
Parameter Group 0
amsgrad: False
betas: (0.9, 0.999)
capturable: False
differentiable: False
eps: 1e-08
foreach: None
fused: False
lr: 0.01
maximize: False
weight_decay: 0
)
现在,使用我们之前加载的 MNIST 训练数据集来训练神经网络模型,并将其封装在一个 Python 函数中:
def train(num_epochs, ann):
ann.train()
for epoch in range(num_epochs):
output = ann(x_train)
loss = loss_func(output, y_train)
# clear gradients for this training step
optimizer.zero_grad()
# backpropagation, compute gradients
loss.backward()
# apply gradients
optimizer.step()
print(epoch, loss.item())
pass
让我们分解这段代码:
-
train 函数:此函数使用指定的 epoch 数量(num_epochs)训练神经网络模型(ann)。该函数假定存在用于训练模型的数据(x_train)和相应的目标标签(y_train)。在此,调用ann.train()将模型设置为训练模式,启用诸如 dropout 和批量归一化等功能。
-
训练循环:在num_epochs的范围内,对每个 epoch 执行以下步骤:
-
output = ann(x_train):通过模型进行前向传递,获得输出预测。
-
loss = loss_func(output, y_train):计算预测输出与真实标签之间的损失。
-
optimizer.zero_grad():清除之前迭代累积的梯度。
-
loss.backward():执行反向传播以计算模型参数相对于损失的梯度。
-
optimizer.step():通过应用计算出的梯度并使用选择的优化器来更新模型的参数。
-
print(epoch, loss.item()): 打印当前 epoch 编号和loss值。
-
pass 语句:在此上下文中什么都不做的占位符,如果不需要可以删除。
-
现在,使用我们之前加载的 MNIST 训练数据集以及作者在之前步骤中构建的神经网络模型(使用100个 epoch)来训练神经网络模型:
train(100,auth_nn)
0 1.6085695028305054
1 1.6047792434692383
2 1.59657621383667
….
100 1.4667187929153442
一旦模型训练完成,就可以用于进一步的预测。现在,我们将构建一个对抗攻击者模型,其目标是重新创建训练数据。
对抗模型以获取训练输入数据
考虑到作者的模型是在 MNIST 数据集上训练的,并且我们有访问模型第一部分(first_sec)输出的450向量大小,我们可以利用这些信息进行攻击。接下来,我们将开发我们的对抗模型。这个模型以一个大小为450的向量作为输入,这对应于目标的第一部分的输出。对抗模型的目标是生成一个大小为784的向量,与原始输入数据的大小相匹配:
class Adversary(nn.Module):
def __init__(self):
super().__init__()
self.layers= nn.Sequential(
nn.Linear(450, 800),
nn.ReLU(),
nn.Linear(800, 784),
)
def forward(self, x):
return self.layers(x)
根据现有信息,作者的原模型是在包含手写图像的数据集上训练的。这一知识使我们能够理解模型的训练数据来源。
为了训练我们的对抗模型,我们可以利用 MNIST 测试数据。具体来说,我们将使用 MNIST 测试数据的前 1000 行来训练我们的对抗模型。训练完成后,我们可以使用从第 1000 行到第 2000 行的 MNIST 测试数据来评估对抗模型的准确性。
让我们训练对抗模型:
adversary = Adversary()
optimizer = optim.Adam(adversary.parameters(), lr=1e-4)
for i in range (0,1000):
optimiser.zero_grad()
#print(x_train[i])
target_outputs = auth_nn.first_sec(x_valid[i])
adversary_outputs = adversary(target_outputs)
#print(adversary_outputs)
loss = ((x_valid[i] - adversary_outputs)**2).mean()
#print(loss.item())
loss.backward()
optimiser.step()
Now, let’s test the adversary model:
for i in range (1000,2000):
target_outputs = auth_nn.first_sec(x_train[i])
recreated_data = adversary(target_outputs)
#print(recreated_data)
为了评估重建数据与训练数据集中原始训练图像之间的相似性,我们可以利用 Matplotlib 库来可视化图像。通过绘制重建图像,我们可以确定它与原始训练图像的相似程度:
With torch.no_grad():
pyplot.imshow(recreated_data.reshape((28, 28)), cmap=”gray”)
这导致了以下输出:

显然,使用模型反演攻击生成的图像与训练数据非常相似。这个例子展示了成功重建训练数据而不需要完全了解模型细节,从而实现了模型反演攻击。
减轻模型反演攻击的技术
减轻模型反演攻击,即攻击者试图从训练模型的输出中推断敏感训练数据,对于保护隐私和敏感信息至关重要。
减轻模型反演攻击的一些技术包括以下内容:
-
差分隐私:在训练过程中应用差分隐私机制可以帮助抵御模型反演攻击。差分隐私通过向训练数据或模型的输出添加受控噪声,使得攻击者从模型的预测中提取特定敏感信息变得更加困难。我们将在接下来的两章中学习更多关于差分隐私的知识。
-
限制对敏感输出的访问:限制对敏感模型输出或预测的访问可以帮助减轻模型反演攻击。通过仔细控制谁可以访问输出以及在什么情况下访问,可以降低攻击者推断敏感训练数据的风险。
-
预处理和后处理:对数据和模型输出应用预处理和后处理技术可以帮助抵御模型反演攻击。例如,可以应用数据匿名化、聚合或转换技术来从输入或输出中移除或模糊敏感信息。我们将在后续章节中了解更多关于数据匿名化和聚合的内容。
-
正则化:在模型训练过程中结合正则化技术,如 L1 或 L2 正则化,可以帮助通过减少模型对特定敏感特征的依赖来提高隐私性。正则化可以帮助防止过拟合并限制通过模型预测泄露的敏感信息。
-
生成对抗网络(GANs):使用生成模型,如 GANs,可以帮助抵御模型反演攻击。通过生成保留原始数据统计特性的合成数据,GANs 可以为攻击者提供替代输出,而不会泄露特定的敏感训练实例。
-
安全多方计算(MPC):利用安全 MPC 协议可以使多个方能够协作训练模型,同时保持各自的训练数据私密。安全 MPC 确保没有任何一方可以访问其他方的敏感数据,从而减轻模型反演攻击。
-
安全聚合:在模型使用分布式设置进行训练的情境中,可以采用安全聚合协议来防止在模型更新聚合过程中敏感信息泄露。这可以在训练过程中保护免受模型反演攻击。
-
访问控制和授权:实施访问控制措施和强大的授权机制可以帮助限制对敏感模型输出的访问,减少潜在攻击者的暴露。只有授权实体应有权访问敏感预测或输出。
-
合成数据生成:不是直接在敏感数据上训练模型,而是使用从原始数据生成的合成数据可以帮助缓解模型反演攻击。合成数据保留了原始数据的统计特性,但不会暴露敏感信息。
-
模型监控:持续监控模型的行为,寻找任何异常模式或意外输出,可以帮助检测潜在的模型反演攻击。监控可能涉及异常检测、对抗鲁棒性检查或模型预测的统计分析等技术。
与前两次攻击一样,需要注意的是,选择缓解技术取决于具体情境、数据的敏感性和所需的隐私保护水平。可以将多种技术结合起来,以实现更强的隐私保障,抵御模型反演攻击。
摘要
总结来说,我们已经涵盖了不同类型的机器学习(监督学习和无监督学习),并探讨了如何以各种格式保存和执行模型。此外,我们还深入探讨了机器学习的不同阶段(数据提取、数据准备、模型开发、模型部署和推理),并详细讨论了与每个阶段相关的隐私威胁和攻击。
在下一章中,我们将更深入地探讨隐私保护数据分析,并专注于理解差分隐私的概念。这将使我们能够探索确保在执行数据分析任务时保持隐私的技术和方法。通过全面理解差分隐私,我们可以更好地保护敏感信息并减轻机器学习环境中的隐私风险。
第二部分:隐私保护机器学习用例及差分隐私深入探讨
本部分重点关注隐私保护数据分析,并探讨隐私增强技术,特别强调差分隐私。
我们介绍了隐私保护数据分析的概念,并深入探讨了允许在保护个人隐私的同时分析数据的技术和方法。
我们强调了与 SQL 中的重建攻击相关的风险,其中攻击者试图从看似匿名化的数据中重建敏感信息。我们讨论了可以采取的各种预防方法和对策,以减轻此类攻击并保护个人隐私。
本部分还概述了隐私增强技术,如差分隐私、联邦学习、安全多方计算(SMC)和同态加密。
我们介绍了差分隐私和机器学习,并探讨了如何将差分隐私纳入机器学习算法,为在学习过程中使用的数据提供隐私保障。
我们还深入探讨了差分隐私中使用的各种算法。这些算法包括拉普拉斯、高斯、计数、求和、均值、方差、标准差和阈值算法。
我们探讨了使用 OpenMined PyDP 框架开发差分隐私应用。在这里,我们关注使用 OpenMined PyDP 框架开发差分隐私应用的实际步骤。
我们还涵盖了使用差分隐私的深度学习,并考察了一个欺诈检测用例。这展示了如何利用如 PyTorch 和 Opacus 等开源框架在深度学习模型中实现差分隐私。
最后,我们概述了利用差分隐私的实际应用。在这里,我们强调了在医疗保健、金融和社会科学等领域,差分隐私如何成功应用于平衡数据分析与隐私保护的使用案例。
本部分包含以下章节:
-
第三章**,隐私保护数据分析概述及差分隐私简介
-
第四章**,差分隐私算法与差分隐私局限性
-
第五章**,使用开源框架开发具有差分隐私的机器学习应用
第三章:隐私保护数据分析概述及差分隐私简介
在本章中,我们将探讨大数据背景下隐私的概念及其相关风险。我们将深入研究数据分析中的隐私,重点关注隐私与效用之间的权衡。此外,我们将研究各种隐私保护技术,如匿名化、k-匿名性、t-接近性和ℓ-多样性,同时讨论它们的局限性。随后,我们将介绍一种关键的隐私增强方法,即差分隐私。我们将对差分隐私提供一个高级概述,涵盖隐私损失、隐私预算和差分隐私机制等基本概念。
本章涵盖的主要内容包括以下内容:
-
数据分析中的隐私:
- 数据分析中的隐私,数据分析中隐私的必要性以及数据分析中隐私的目标
-
隐私保护技术:
-
研究各种隐私保护技术,包括匿名化、k-匿名性、t-接近性和ℓ-多样性
-
数据聚合
-
数据聚合中的隐私攻击
-
用于保护 SQL 中数据隐私的工具/框架
-
-
增强隐私的技术:
- 介绍差分隐私作为一种隐私增强技术以及联邦学习和同态加密
-
差分隐私:
- 深入探讨差分隐私概念,包括隐私损失、隐私预算和差分隐私机制
数据分析中的隐私
数据分析中的隐私是一个关键方面,它确保个人敏感信息不会被泄露或滥用。这涉及到实施数据匿名化和加密等措施,以保护个人的身份和个人详细信息,同时仍然允许进行有意义的数据分析。
数据分析中隐私的必要性
许多企业、社交网络公司、电子商务平台、网络公司、出租车/出租车聚合器、食品配送服务以及政府机构等,收集和处理大量数据——包括个人和非个人信息——以使用机器学习和人工智能技术得出见解。这些实体收集的数据涵盖了广泛的信息,如浏览历史、购买记录、社交网络互动、健康数据、位置数据、内容消费模式、设备信息等。需要注意的是,这些数据通常包含敏感的个人信息。在必要之外(考虑基于数据类别的数据保留法律)分享或保留这些数据可能导致隐私风险,并可能导致违反隐私和法律法规。正如我们在第一章中讨论的,一些隐私风险/违规与以下相关:
-
窃取个人信息:这包括未经授权访问个人的凭证,如信用卡号码、密码和其他敏感数据
-
身份盗窃:个人身份信息,如美国的社会安全号码或印度的 Aadhaar 唯一身份标识、姓名、银行信息、生物识别数据和驾驶执照,可能成为身份盗窃的目标。
-
歧视和针对个人:某些类型的数据,如病历,可能被用来基于个人的宗教信仰进行歧视,或导致诸如保险拒绝等后果。其他例子包括政治帖子、社交媒体上的评论/意见等。
为了解决这些担忧,全球范围内实施了隐私法律。例如,欧洲的通用数据保护条例(GDPR)和美国加州的加州消费者隐私法案(CCPA)为敏感数据的保护提供了指南和规定,并解决了与隐私相关的违规和问题。
对于组织来说,了解数据分析中的隐私实践至关重要,以便了解隐私风险,遵守相关的隐私法律和规定,并采取必要的措施保护个人数据隐私。
数据分析中的隐私指的是在保护数据隐私和机密性的同时执行数据分析任务的过程。它涉及应用各种技术和方法从数据中提取有意义的见解,而不损害被分析的个人数据的隐私权利。目标是平衡数据效用和隐私,这在隐私数据分析中至关重要。然而,每种方法都有其权衡:
-
高数据隐私:强调严格的隐私措施可能会导致数据效用较差。例如,如果为了保护隐私而删除或匿名化敏感个人信息,如社会安全号码或病历,那么将这些数据与其他相关数据点联系起来就变得困难。因此,由此产生的见解可能对分析目的不那么有用。
-
高数据效用:优先考虑高数据效用可能会导致隐私保护较弱。在这种情况下,数据对于分析仍然非常有用和有价值。然而,敏感信息的保护可能不足,增加了重新识别或意外泄露个人细节的风险。

图 3.1 – 隐私与效用权衡

图 3.2 – 隐私与效用权衡
图片来源:Churi, Prathamesh & Pawar, Dr. Ambika & Moreno Guerrero, Antonio. (2021). A Comprehensive Survey on Data Utility and Privacy: Taking Indian Healthcare System as a Potential Case Study. Inventions. 6. 1-30. 10.3390/inventions6030045.
在隐私和效用之间找到正确的平衡是数据分析中隐私保护的一个关键挑战。组织必须实施隐私保护技术,如匿名化、聚合和噪声添加,以保护敏感信息,同时仍然能够进行有意义的分析。通过仔细考虑隐私和效用两个方面,有可能从数据中获得有价值的见解,同时保护个人的隐私权利。
数据分析中隐私保护的目标
数据分析中隐私保护的目标如下:
-
隐私保护:主要关注保护数据集中包含的敏感信息,确保个人的隐私得到尊重和保护。这包括防止未经授权的访问、披露或从数据中识别个人。
-
数据效用:在保护隐私的同时,分析还应提供有价值且准确的结果,以保持数据的有用性和质量。挑战在于找到允许有效分析的同时最小化对数据效用影响的方法。
-
风险评估:数据分析中的隐私保护涉及识别和评估与被分析数据相关的潜在隐私风险。这包括评估重新识别的可能性或分析过程中意外披露敏感信息的可能性。
-
匿名化技术:采用各种匿名化技术从数据集中删除或模糊化识别信息。这可能包括数据泛化、抑制、噪声添加和数据扰动等方法,以保护个人的身份。
-
隐私保护算法/技术:利用专门的算法和方法来执行分析任务,同时最小化隐私风险。这些算法确保结果揭示的是汇总和匿名化的见解,而不是个人层面的细节。
-
合规性和伦理考量:数据分析中的隐私保护遵守相关的隐私法律和法规,以确保对敏感数据的合规和伦理处理。组织必须遵守法律要求和伦理指南,以保护个人的隐私权利。
通过在数据分析技术中保护隐私,组织可以从敏感数据中获得有价值的见解,同时尊重隐私限制。这种方法在分析个人数据的人之间建立信任,并促进负责任的数据处理实践。
隐私保护技术
重要的是要注意,数据隐私是一项基本权利,个人有权控制其个人信息如何被收集、使用和共享。此外,如上所述,缺乏数据隐私保护可能导致严重的后果,如身份盗窃、金融欺诈和歧视。
在数据分析的背景下,对手是指积极寻求未经授权访问或利用敏感数据、干扰数据分析过程或操纵结果以谋取自身利益或恶意意图的实体或当事人。数据分析中的对手可能包括个人、组织或旨在损害数据或分析过程本身完整性、机密性或可用性的自动化系统。
组织可以实施各种隐私保护技术,允许分析数据同时保护个人的隐私。我们将介绍以下隐私保护技术和相关的隐私攻击:
-
数据匿名化技术和算法:
- K-匿名性、ℓ-多样性、t-接近性
-
数据聚合和与数据聚合相关的隐私攻击
数据匿名化和数据匿名化算法
保护隐私和遵守数据保护法规的技术之一是数据匿名化。通过匿名化数据,组织可以在保留数据的效用和分析价值的同时,减轻与未经授权披露和滥用个人信息相关的风险。
通常,数据集由三种类型的属性组成——即关键标识符、准标识符和敏感属性:
-
关键标识符:这些属性在数据集中唯一地识别个人。
-
准标识符:准标识符是间接标识符,当与其他属性结合使用时,可以用来识别个人或揭露个人信息。它们提供提示或部分识别。
-
敏感属性:这些属性包含需要保护以维护隐私的敏感个人信息。
让我们考虑一个来自医院或医疗诊所的示例数据集,该数据集收集并维护患者数据。假设医院为每位患者收集各种数据,包括姓名、出生日期、性别、邮政编码/邮编、身高、体重、血压、SpO2 水平、当前医疗状况、上次就诊日期等。
下面是关于这个数据集的一些详细信息:
-
姓名作为一个关键属性,因为它可以唯一地识别每个人。
-
准标识符包括出生日期、性别、邮政编码和身高等属性。虽然仅知道出生日期可能不足以识别个人,但将其与其他准标识符(如性别、邮政编码和医疗状况)结合使用,可能会使识别个人成为可能。
-
敏感属性包括与患者所患疾病类型相关的信息。保护这些信息对于维护患者的隐私至关重要。
通过了解数据集中不同类型的属性,组织可以实施适当的匿名化技术,以保护个人的隐私,同时仍允许进行有价值的分析和研究。
现在我们了解了不同类型的属性,让我们尝试在一个样本玩具数据集上进行数据匿名化,并分析结果。
让我们考虑一个包含个人年龄和医疗状况信息的示例数据集。在这种情况下,敏感属性是医疗状况,我们希望在保护数据有效性的同时保护它。
| 关键属性 | 准标识符 | 敏感属性 | 其他数据 … | |
|---|---|---|---|---|
| 姓名 | 出生日期 | 性别 | 邮编 | 身高(厘米) |
| John | 2000-09-15 | 男 | 90001 | 170 |
| Rosy | 2002-12-08 | 女 | 96162 | 165 |
| Robin | 1945-07-24 | 男 | 92348 | 180 |
| Hellen | 1950-01-13 | 女 | 95411 | 156 |
| Antonio | 1970-01-13 | 男 | 95416 | 180 |
表 3.1 – 样本数据集
显然,收集的数据包含诸如姓名、出生日期等个人信息,因此为了保护个人,让我们尝试数据匿名化技术,看看它是否有帮助。数据匿名化意味着移除或修改个人可识别信息,以便其他人无法从数据中检测到个人。
让我们尝试一个简单的解决方案,即从给定的数据中移除个人信息(在这种情况下,是人的姓名)。移除姓名后,数据看起来如下。
| 姓名 | 出生日期 | 性别 | 邮编 | 身高(厘米) | 诊断疾病 | 其他数据 … |
|---|---|---|---|---|---|---|
| 2000-09-15 | 男 | 90001 | 170 | COVID | …. | |
| 2002-12-08 | 女 | 96162 | 165 | COVID | ||
| 1945-07-24 | 男 | 92348 | 180 | 癌症 | ||
| 1950-03-13 | 女 | 95411 | 156 | 癌症 | ||
| 1970-01-13 | M | 95416 | 180 | 发热 | ….. |
表 3.2 – 无姓名的数据集
移除姓名是否足以保护敏感数据?现在能否与他人共享这些数据?是否有人能从这些数据中准确识别出患有癌症的个人?
根据前面的数据表,看起来人们将无法找到信息,因为我们已经从数据中移除了个人的姓名。这是从这些数据中得到的第一印象。从数据集中移除个人的姓名是保护敏感数据并保留隐私的一个步骤。
然而,重要的是要注意,仅仅移除姓名并不能保证完全的隐私保护。数据集中的其他准标识符和敏感属性仍然可能潜在地导致个人的重新识别。
让我们看看对手将如何能够使用这个所谓的匿名化数据集来识别个人。
政府机构每 5 年或 10 年进行一次人口普查数据调查(人口调查和选民名单更新/添加等),并根据国家规定与其他部门共享。
匿名化数据集(如前面的数据表)可能与由政府机构或非营利组织发布的公开数据集链接,从而得出见解或识别个人,即可以找到敏感个人信息。
以下是从政府获取的选民 ID 数据样本:
| 姓名 | 出生日期 | 性别 | 邮政编码 | 上次投票年份 | 注册日期 | 其他数据 … |
|---|---|---|---|---|---|---|
| John | 2000-09-15 | M | 90001 | 2020 | 2018 | …. |
| Rosy | 2002-12-08 | F | 96162 | - | 2020 | |
| Robin | 1945-07-24 | M | 92348 | 2020 | 1963 | |
| Hellen | 1950-03-13 | F | 92411 | 2020 | 1968 | |
| Antonio | 1970-01-13 | M | 95416 | - | 1988 |
表 3.3 – 样本选民 ID 数据集
非常可能将这两个数据集链接起来,即患者的数据与选民的数据(参考 LINDDUN 框架的隐私威胁链接类别,该类别在 第一章 中描述)并从给定的邮政编码中找出谁患有癌症。

图 3.3 – 链接两个数据集
很明显,Robin 住在邮政编码 92348,因此对手可以链接选民 ID 和医疗数据记录,并确定他患有癌症。一旦对手找到此案例中的敏感信息,即谁患有癌症,那么作为此数据隐私泄露的副作用,可能的歧视可能是拒绝为 Robin 提供医疗保险。
因此,仅仅从数据集中删除一个或两个字段是不够保护个人敏感信息的。
让我们尝试另一种数据匿名化技术,称为 k-匿名性。
K-匿名性 – 数据匿名化
Latanya Sweeney 和 Pierangela Samarati 在 1998 年引入了 k-匿名性,其描述如下:
给定特定于个人的字段结构化数据,产生一个数据发布,保证数据主体在数据保持实际有用的同时不能被重新识别。如果发布的数据中每个个人的信息不能与至少 k-1 个信息也出现在发布中的个人区分开来,则称数据发布具有 k-匿名性属性。
(**来源:维基百科)
为了应用 k-匿名性匿名化,需要执行以下操作:
-
识别给定数据集中的准标识符。
-
对数据集中的属性进行泛化(而不是使用确切日期,使用范围)或抑制属性(而不是显示完整的邮政编码,只显示部分邮政编码)至少 k-1 条记录。
| 姓名 | 出生日期 | 性别 | 邮政编码 | 身高(厘米) | 诊断疾病 | 其他数据… |
|---|---|---|---|---|---|---|
| 2000-09-15 | M | 90001 | 170 | COVID | …. | |
| 2002-12-08 | F | 96162 | 165 | COVID | ||
| 1945-07-24 | M | 92348 | 180 | 癌症 | ||
| 1950-03-13 | F | 92411 | 156 | 癌症 | ||
| 1970-01-13 | M | 95416 | 180 | 发烧 |
表 3.4 – 无姓名的数据集
在本例中,准标识符是邮编和出生日期。这些被认为是间接标识符,因为可能有具有相同邮编和出生日期的个人,但这两个因素不一定能识别出特定的个人。一旦确定了准标识符,就可以选择抑制它们或泛化属性。让我们尝试用***抑制邮编的最后三位,并使用范围而不是确切的出生日期来泛化出生日期。
更新后的数据(匿名化)如下所示:
| 姓名 | 出生日期 | 性别 | 邮编 | 身高(厘米) | 诊断疾病 | 其他数据… |
|---|---|---|---|---|---|---|
| 20-30 | M | 90*** | 170 | COVID | …. | |
| 20-30 | F | 96*** | 165 | COVID | ||
| 70-80 | M | 92*** | 180 | CANCER | ||
| 70-80 | F | 92*** | 156 | CANCER | ||
| 50-60 | M | 95*** | 180 | FEVER |
表 3.5 – 泛化和抑制后的数据集
请过一遍这些问题:
-
现在是否足够保护敏感数据,因为我们已经使用 k-匿名性对数据进行匿名化(准标识符)?
-
现在能否与他人共享这些数据?
-
现在是否有人能从这个数据中找出确切的癌症患者是谁?
在这种情况下,仍然有可能识别出个人,因为在相同的年龄范围内(70-80),每个人都有癌症。这种脆弱性被称为同质性攻击,它可能在 k-匿名性中发生,当一组 k 个记录具有精确的敏感值时。尽管数据已经进行了 k-匿名化,但由于我们示例中敏感值“癌症”的日期范围相同,因此 k 个记录集的敏感值仍然可以准确预测。
现在我们将使用 Python 实现一个示例数据集的 k-匿名性。
源代码:K-Anonymity_Example.ipynb
我们将创建一个包含准标识符(年龄和性别)和敏感属性(诊断)的医学记录合成数据集:
import pandas as pd
import random
# Step 1: Define the parameters
num_records = 1000 # Number of records in the dataset
k = 5 # Desired k-anonymity level
# Step 2: Generate the synthetic dataset
age_range = (20, 80)
gender_list = ["Male", "Female"]
diagnosis_list = ["Covid", "Cancer", "Fever", "Obesity"]
data = []
for _ in range(num_records):
age = random.randint(age_range[0], age_range[1])
gender = random.choice(gender_list)
diagnosis = random.choice(diagnosis_list)
data.append({"age": age, "gender": gender, "diagnosis": diagnosis})
dataset = pd.DataFrame(data)
dataset.to_csv("dataset.csv", index=False)
# Step 3: Apply k-anonymity
groups = dataset.groupby(["age", "gender"])
anonymized_data = pd.DataFrame()
for _, group in groups:
if len(group) < k:
group["age"] = generalize(group["age"])
group["gender"] = generalize(group["gender"])
anonymized_data = anonymized_data.append(group)
# Save the anonymized dataset to a file
anonymized_data.to_csv("k_anonymized_dataset.csv", index=False)
def generalize(attribute):
if attribute.name == "age":
# Generalize age into predefined ranges
age_ranges = [(0, 20), (20, 40), (40, 60), (60, 80)]
for start, end in age_ranges:
if start <= attribute.iloc[0] < end:
return f"{start}-{end}"
elif attribute.name == "gender":
# Generalize gender to binary values
return "Other"
else:
# Handle other attributes if needed
return attribute.
在本例中,我们首先定义参数,包括所需的记录数(num_records)和所需的 k-匿名性级别(k)。然后,我们通过随机分配准标识符(年龄和性别)和敏感属性(诊断)的值来生成一个合成数据集。在生成数据集后,我们根据准标识符对记录进行分组,并检查组大小是否小于 k。如果组大小小于 k,我们就通过应用合适的泛化技术来泛化准标识符。
generalize()函数接受一个属性(例如,年龄或性别)作为输入,并应用特定的泛化技术。在这里,我们通过将其划分为预定义的年龄范围(例如,0-20,20-40,40-60 和 60-80)来实现对年龄属性的泛化。对于性别属性,我们将其泛化为"其他"。
我们可以根据数据集特定的泛化要求修改和扩展此功能。例如,我们可能需要以不同的方式处理其他属性,或者为不同的准标识符定义额外的泛化规则。
最后,匿名化后的数据集被保存到名为k_anonymized_dataset.csv的文件中。
让我们尝试另一种匿名化技术,称为ℓ-diversity,看看它是否能够解决我们在 k 匿名性分析中讨论的隐私问题。
ℓ-diversity – 数据匿名化
ℓ-diversity 是一种旨在减轻对匿名化数据同质性攻击的脆弱性的方法。它通过确保每个准标识符序列都与一个“良好表示”的敏感属性相关联来实现这一点。换句话说,ℓ-diversity 旨在在具有相同准标识符的记录组内引入多样性,确保存在多个敏感属性值。通过这样做,ℓ-diversity 降低了从匿名化数据中准确推断敏感信息的风险。
原始数据集
| Quasi-Identifiers | Sensitive Attribute |
|---|---|
| 出生日期 | 邮编 |
| 2000-09-15 | 90001 |
| 2002-12-08 | 96162 |
| 1945-07-24 | 92348 |
| 1950-03-13 | 95411 |
| 1970-01-13 | 95416 |
表 3.6 – 原始数据集
K 匿名化数据集
| Quasi-Identifiers | Sensitive Attribute |
|---|---|
| 出生日期 | 邮编 |
| 20-30 | 90*** |
| 20-30 | 96*** |
| 70-80 | 92*** |
| 70-80 | 92*** |
| 50-60 | 95*** |
表 3.7 – K 匿名化数据集
当与其他人共享这些数据时,这些数据不具有多样性。
为了使这个数据集达到ℓ多样性(对于ℓ=2),我们需要在每个具有相同出生日期和邮编的组中至少引入一种独特的疾病。以下是我们如何修改数据集的一个示例:
| ℓ -Diversity Dataset Quasi-Identifiers | Sensitive Attribute |
|---|---|
| 出生日期 | Zip Code |
| 20-30 | 90*** |
| 70-80 | 92*** |
| 50-60 | 95*** |
| 20-30 | 96*** |
| 70-80 | 92*** |
表 3.8– ℓ-diversity 数据集(具有一定多样性)
具有邮编 96的 20-30 岁年龄组,其疾病已更改为流感。70-80 岁年龄组中,邮编为 92的记录,其疾病已更改为心脏病。现在,每个具有相同出生日期和邮编的相似日期集合至少有两种独特的疾病,这使得数据集具有 2 种多样性。
在较小的数据集上实现ℓ多样性可能看起来很简单,正如我们的示例所示。然而,它的适用性存在局限性,尤其是在处理包含数百万或数十亿记录的大型数据集时。在这种情况下,实现ℓ多样性变得具有挑战性,并且在所有情况下可能都不是必要的。需要注意的是,尽管ℓ多样性有帮助,但它并不是保护敏感信息的全面解决方案。虽然它引入了记录组内的多样性,但它不能保证完全的隐私。可能需要额外的隐私保护技术和措施来提供对敏感数据的更强保护。
现在我们使用 Python 在样本数据集上实现ℓ多样性。
源代码:L-Diversity_Example.ipynb
让我们在之前生成的合成数据集上实现ℓ-diversity。我们将诊断属性视为敏感属性,并确保每个组至少有ℓ个不同的敏感属性值:
import pandas as pd
import random
# Step 1: Define the parameters
num_records = 1000 # Number of records in the dataset
l = 3 # Desired l-diversity level
# Step 2: Generate the synthetic dataset
age_range = (20, 70)
gender_list = ["Male", "Female"]
diagnosis_list = ["Covid", "Cancer", "Fever", "Obesity"]
data = []
for _ in range(num_records):
age = random.randint(age_range[0], age_range[1])
gender = random.choice(gender_list)
diagnosis = random.choice(diagnosis_list)
data.append({"age": age, "gender": gender, "diagnosis": diagnosis})
dataset = pd.DataFrame(data)
dataset.to_csv("dataset_before_l_diversity.csv", index=False)
# Step 3: Apply l-diversity
groups = dataset.groupby(["age", "gender"])
anonymized_data = pd.DataFrame()
for _, group in groups:
if len(group["diagnosis"].unique()) < l:
# Generalize or suppress the sensitive attribute
group["diagnosis"] = generalize(group["diagnosis"])
anonymized_data = anonymized_data.append(group)
else:
anonymized_data = anonymized_data.append(group)
# Save the anonymized dataset to a file
anonymized_data.to_csv("l_diversity_dataset.csv", index=False)
我们生成一个与之前类似的合成数据集。之后,我们根据准标识符(年龄和性别)对记录进行分组,并检查不同敏感属性值(诊断)的数量是否少于“ℓ”。如果条件满足,我们将对敏感属性应用泛化或抑制,以确保组内至少有“ℓ”个不同的值。请注意,在这个示例中,对诊断属性调用了generalize()函数。最后,匿名化后的数据集被保存到名为l_diversity_dataset.csv的文件中:
def generalize(attribute):
if attribute.name == "diagnosis":
# Generalize diagnosis to a higher-level category
diagnosis_mapping = {
"Covid": "Chronic Condition",
"Cancer": "Chronic Condition",
"Fever": "Non-Chronic Condition",
"Obesity": "Non-Chronic Condition"
}
return attribute.map(diagnosis_mapping)
else:
# Handle other attributes if needed
return attribute
在这个示例中,generalize()函数接受一个属性(例如,诊断)作为输入,并应用特定的泛化技术。在这里,我们通过将特定的诊断映射到更高级别的类别来演示对诊断属性的泛化。例如,诊断如"Fever"和"Obesity"被泛化到类别"Non-Chronic Condition",而"Cancer"和"Covid"被泛化到"Chronic Condition"。
现在,让我们深入了解另一种方法,称为 t 接近度。
t 接近度
t 接近度方法确保个体组中敏感属性分布与整体人口中相同属性的分布没有显著差异。它通过设置一个阈值值,用t表示,来维护隐私和数据实用性的平衡,该阈值代表分布之间的最大允许差异。
为了满足 t 接近度,数据集应在每个个体组中展示与整体数据集相似的敏感属性(如年龄、收入和性别)的概率分布。如果组与整体分布之间的差异超过指定的 t 值,可能需要额外的匿名化措施。
让我们通过一个例子来说明 t-closeness。假设我们有一个包含个人年龄和医疗状况信息的数据集。在这种情况下,敏感属性是医疗状况,我们希望在保护数据效用性的同时保护它。
我们根据一组准标识符将数据集划分为组,例如年龄范围和性别。为了简单起见,让我们专注于年龄范围。我们有两组:A 组(年龄范围 30-40)和 B 组(年龄范围 40-50)。
为了满足 t-closeness,我们需要比较每个组内医疗状况的分布与数据集中整体分布。假设整体数据集的医疗状况分布如下:60%癌症,30%糖尿病,10%哮喘。
在 A 组中,我们发现医疗状况的分布是 70%癌症,20%糖尿病,10%哮喘。在 B 组中,分布是 50%癌症,30%糖尿病,20%哮喘。
为了确定数据集是否满足 t-closeness,我们计算组分布与整体分布之间的差异。假设我们将阈值值设定为 t = 0.2(20%)。
在 A 组中,癌症的差异是 10%(70%-60%),在 t 值范围内。对于糖尿病,差异是 10%(20%-30%),也在阈值内。哮喘的情况相同,差异为 0%(10%-10%)。
在 B 组中,癌症的差异是 10%(50%-60%),在 t 值范围内。对于糖尿病,差异是 0%(30%-30%),对于哮喘,差异是 10%(20%-10%)。这两个差异都在指定的阈值内。
由于组分布与整体分布之间的所有差异都在 t 值范围内,我们可以得出结论,该数据集对于给定的阈值满足 t-closeness。
这个例子演示了 t-closeness 如何确保每个组中敏感属性的分布与整体数据集中的分布没有显著差异,从而在保持数据效用性的同时提供更高的隐私级别。
与 k 匿名性相比,t-closeness 提供了更严格的隐私要求,因为它考虑了敏感属性的实际情况分布,而不仅仅是群体大小。然而,在保持数据效用性的同时实现 t-closeness 可能具有挑战性。已经开发出各种技术和算法,以在数据匿名化过程中应用 t-closeness 时在隐私和效用之间取得平衡。
现在我们将使用 Python 实现一个示例数据集的 t-closeness。
源代码:t_Closeness_Example.ipynb
让我们看看在之前生成的合成数据集上实现 t-closeness 的例子。我们将诊断属性视为敏感属性,并确保每个组中敏感属性值的分布与整体分布没有显著偏差:
import pandas as pd
import random
# Step 1: Define the parameters
num_records = 1000 # Number of records in the dataset
t = 0.2 # Desired t-closeness threshold
# Step 2: Generate the synthetic dataset
age_range = (20, 70)
gender_list = ["Male", "Female"]
diagnosis_list = ["Covid", "Cancer", "Fever", "Obesity"]
data = []
for _ in range(num_records):
age = random.randint(age_range[0], age_range[1])
gender = random.choice(gender_list)
diagnosis = random.choice(diagnosis_list)
data.append({"age": age, "gender": gender, "diagnosis": diagnosis})
dataset = pd.DataFrame(data)
dataset.to_csv("t-close_before_dataset.csv", index=False)
# Step 3: Calculate the overall distribution of the sensitive attribute
overall_distribution = dataset["diagnosis"].value_counts(normalize=True)
# Step 4: Apply t-closeness
groups = dataset.groupby(["age", "gender"])
anonymized_data = pd.DataFrame()
for _, group in groups:
group_distribution = group["diagnosis"].value_counts(normalize=True)
max_divergence = max(abs(group_distribution - overall_distribution))
if max_divergence > t:
# Generalize or suppress the sensitive attribute
group["diagnosis"] = generalize(group["diagnosis"])
anonymized_data = anonymized_data.append(group)
# Save the anonymized dataset to a file
anonymized_data.to_csv("t_closeness_dataset.csv", index=False)
def generalize(attribute):
if attribute.name == "diagnosis":
# Generalize diagnosis to a higher-level category
diagnosis_mapping = {
"Covid": "Chronic Condition",
"Cancer": "Chronic Condition",
"Fever": "Non-Chronic Condition",
"Obesity": "Non-Chronic Condition"
}
return attribute.map(diagnosis_mapping)
else:
# Handle other attributes if needed
return attribute
在这个例子中,我们像以前一样生成一个合成数据集。我们计算数据集中敏感属性(诊断)的整体分布。然后,我们根据准标识符(年龄和性别)对记录进行分组,并计算每个组中敏感属性的分布。如果组分布与整体分布之间的最大差异超过指定的阈值t,我们对敏感属性应用泛化或抑制。
k-anonymity、l-diversity 和 t-closeness 的比较
| 隐私技术 | 优点 | 缺点 |
|---|---|---|
| k-anonymity |
-
简单性和易于实现
-
提供强大的身份隐私保证
-
有效防止属性关联攻击
-
在一定程度上保留数据效用
|
-
未考虑敏感属性的分布,可能导致属性披露
-
可能导致过度泛化,降低数据效用
-
敏感属性抑制可能导致信息丢失
-
容易受到背景知识攻击
|
| ℓ -diversity |
|---|
-
通过考虑组内的多样性增强 k-anonymity
-
提供更好的属性披露保护
-
允许对多样性要求进行细粒度控制
-
在隐私和数据效用之间提供权衡
|
-
泛化和抑制可能导致信息丢失和降低数据效用
-
“ℓ”值的选取可能具有主观性且具有挑战性
-
仍然容易受到背景知识攻击
-
不能保证对所有类型的属性披露提供保护
|
| t-closeness |
|---|
-
通过考虑敏感属性的分布扩展ℓ-diversity
-
提供对属性披露的统计保证
-
考虑多样性和分布,在隐私和数据效用之间取得平衡
-
允许对 t-closeness 阈值进行细粒度控制
|
-
泛化和抑制仍可能导致信息丢失
-
确定适当的 t-closeness 阈值可能具有挑战性
-
统计措施可能需要领域专业知识
-
容易受到背景知识攻击和相关性攻击
|
表 3.9– k-anonymity、ℓ-diversity 和 t-closeness 的比较
这份数据提供了每种技术优缺点的高级概述。每种技术的实际有效性和局限性可能因具体实现、数据集特征和隐私要求而异。根据具体用例仔细评估和选择最合适的技术非常重要。
让我们探索数据聚合技术,这是另一种隐私保护技术。我们将尝试实现数据聚合,看看聚合是否解决了预测敏感数据的问题。
数据聚合
正如我们所见,数据不能完全匿名化同时保持有用。让我们尝试聚合数据集,看看聚合数据是否有助于保护隐私。
数据聚合是指将来自多个来源或个人的数据点或记录进行组合和汇总,以获得综合视图或分析的过程。它包括收集数据点或记录并将它们转换成更简洁的表示形式,通常以统计指标或汇总值的形式出现。数据聚合的目的是从大量数据集中提取有意义的洞察和模式,同时降低复杂性和维护数据隐私。
数据聚合的关键方面
根据数据性质和预期结果,采用不同的聚合方法。常见的技术包括求和、平均、计数、最大/最小值、百分位数或其他统计指标。这些方法有助于压缩数据,同时保留基本特征或模式。
数据聚合可以在不同的粒度级别上进行,具体取决于分析需求。它可能涉及在个人层面、组层面、地理层面、时间间隔或其他相关分组标准上聚合数据。调整粒度允许从数据中获得不同的视角和洞察。
汇总数据提供了对原始数据集更易于管理和简洁的表示,使得有效的分析、可视化和决策过程成为可能。它有助于识别趋势、模式、相关性或异常,这些在检查单个数据点时可能并不明显。
与数据聚合相关的隐私攻击
数据聚合,虽然是一种从大量数据集中提取洞察的有用技术,但也可能引入隐私风险。以下是一些与数据聚合相关的隐私攻击:
-
再识别攻击:即使移除了个人标识符或匿名化,汇总数据仍然可能容易受到再识别攻击。通过结合多个汇总数据集或利用外部信息,攻击者可能能够识别汇总数据中的个人,从而损害他们的隐私。
-
推断攻击:当攻击者可以通过分析汇总数据推断出有关个人的敏感信息时,就会发生推断攻击。通过识别汇总数据集中的模式、相关性或统计指标,攻击者可能能够推断出个人的一些旨在保持保密的私人属性或行为。
-
成员推断攻击:成员推断攻击旨在确定特定个人的数据是否包含在汇总数据集中。通过利用统计分析技术,攻击者可以利用汇总数据中的模式或特征来推断某些个人的存在或不存在,从而侵犯他们的隐私。
-
属性泄露攻击:即使移除了直接标识符,汇总数据也可能无意中泄露敏感属性或关于个人的信息。通过分析汇总数据并结合外部知识,攻击者可能能够推断出个人的私人属性、偏好或特征。
-
合成攻击:合成攻击利用多个汇总数据集的组合来揭示敏感信息。即使单个数据集本身不构成隐私风险,多个数据集的汇总可能使攻击者能够通过交叉引用不同来源的数据来识别个人或提取私人信息。
在数据汇总过程中减轻隐私攻击风险,需要在数据实用性和隐私保护之间取得平衡。
让我们通过汇总数据集的关键隐私攻击进行探讨。
差分隐私攻击与汇总数据集
差分隐私攻击利用不同查询输出的统计差异来推断个人或其数据点的敏感信息。
示例
对手试图通过利用提供薪酬汇总统计输出的查询或输出,来推断个别员工的薪酬信息。
考虑一个包含公司员工薪酬信息的数据集。该数据集包括员工姓名、年龄和薪酬等属性。
玩具数据集示例(****原始数据集):
| 员工姓名 | 年龄 | 薪酬(美元,千) |
|---|---|---|
| John | 30 | 200 |
| Rosy | 35 | 300 |
| Robin | 40 | 250 |
| Hellen | 50 | 315 |
表 3.10 – 玩具数据集示例
假设汇总数据默认保护了个人隐私。
如果这家公司的人力资源部门每周发布一个汇总数据集而不是分享原始数据集,这有助于减轻与个人薪酬信息相关的隐私风险。通过仅提供汇总统计数据,人力资源部门可以保护个人薪酬的敏感细节,同时仍然向利益相关者提供有用的见解。
汇总数据集 – 第 1 周:
| 平均年龄 | 平均薪酬 |
|---|---|
| 38.75 | 266.25 |
表 3.11 – 汇总数据集 – 第 1 周
假设在下个星期,公司又雇佣了一名新员工。然后,原始数据被更新为新员工的详细信息,并发布了汇总数据集。
| 员工姓名 | 年龄 | 薪酬(美元,千) |
|---|---|---|
| John | 30 | 200 |
| Rosy | 35 | 300 |
| Robin | 40 | 250 |
| Hellen | 50 | 315 |
| Fedrick | 55 | 335 |
表 3.12 – 汇总数据集 – 第 1 周
汇总数据集 – 第 2 周:
| 平均年龄 | 平均薪酬 |
|---|---|
| 42 | 280 |
表 3.13 – 汇总数据集 – 第 2 周
由于人力资源部门只分享了汇总数据而没有实际数据集,这足够保护个人信息吗?在这种情况下,个人的薪酬信息是个人信息。
由于我们有新员工加入前后的平均工资,任何人都可以猜出新员工在第二周加入时的薪水。
新员工薪水 = (加入后员工总数 * 平均薪水)-(加入前员工总数 * 平均薪水)= 5 * 280 - 4 * 266.25 = 335
这被称为差异攻击,即通过组合多个聚合查询来获取关于特定个人的精确信息。因此,聚合数据集在差异攻击方面存在问题,仅通过聚合数据并不能完全保护个人的个人信息。
重构攻击
让我们考虑一个假设的数据集,从中可以推断出以下信息:
“确定了三个特定疾病的发病率较高的群体,并收集了与该特定疾病相关的症状和治疗数据。”
利用这些知识,攻击者缩小了可能性,并在目标年龄组中确定了一个潜在候选人。他们将个人在公共来源中可用的特征、症状和治疗历史与聚合数据进行比较,以找到匹配项。
通过利用统计技术、机器学习算法或特定领域的知识,攻击者细化他们的假设,并逐步重构目标个人的医疗历史。他们可以揭露敏感信息,例如具体疾病、相关共病、既往治疗和潜在的健康风险。
这种重构攻击展示了对手如何利用聚合数据、外部信息和统计分析来推断详细的个人级信息。通过结合公开数据、聚合统计数据中观察到的模式以及辅助知识,攻击者可以侵犯个人的隐私并揭露敏感的个人信息。
让我们通过另一个针对公共数据的重构攻击来详细了解聚合数据集中的问题。
数据库重构攻击
如前所述,大多数国家每 5 年或 10 年进行一次人口普查调查(对其人口的调查),并将聚合数据与组织以及各种政府门户网站共享。
让我们通过以下数据的重构攻击示例来了解:
| 姓名 | 年龄(年) | 性别 | 城市 | 教育 |
|---|---|---|---|---|
| A | 15 | M | 印度班加罗尔 | 本科在读 |
| B | 80 | M | 印度班加罗尔 | 文盲 |
| C | 25 | M | 印度班加罗尔 | 毕业 |
| D | 45 | F | 印度班加罗尔 | 毕业 |
| E | 40 | F | 印度班加罗尔 | 毕业 |
| F | 20 | F | 印度班加罗尔 | 毕业 |
| G | 15 | F | 印度班加罗尔 | 毕业 |
表 3.14 - 重构攻击数据
假设一个中间人可以访问前面的原始数据,但只允许他们公开发布聚合数据。中间人基于原始数据发布了以下基于统计的统计数据集:
| 性别 | 数量 | 平均年龄 | 中位数年龄 |
|---|---|---|---|
| 男性 | 3 | 40 | 25 |
| 女性 | 4 | 30 | 40 |
| 总计 | 7 | 34.28 | 25 |
表 3.15 – 统计数据集
仅使用聚合数据集,是否可以找出个人的大致年龄(考虑男性性别的情况)?
让我们尝试使用 SAT 求解器来解决这个问题。SAT 求解器是一个旨在解决布尔可满足性问题的程序。我使用 Python 的 Google 开源 OR-Tools 包来解决这个问题。
根据前面的数据,数据集中有 3 名男性,平均年龄为 40 岁,中位数为 25 岁。假设 x、y 和 z 是 3 名男性的年龄,那么 y 将是 25 岁(因为中位数是 25)。x、y 和 z 的平均年龄是 40 岁,所以他们的年龄总和等于 120 岁。假设一个人的最大寿命是 110 岁:
from ortools.sat.python import cp_model
def AgeFindSATprogram():
# Creates the model.
model = cp_model.CpModel()
# Creates 3 variable
num_vals = 3
x = model.NewIntVar(1,110, 'x')
y = 25
z = model.NewIntVar(1,110, 'z')
# Creates the constraints.
model.Add(x+y+z==120)
# Creates a solver and solves the model.
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
print('x = %i' % solver.Value(x))
print('y = %i' % solver.Value(y))
print('z = %i' % solver.Value(z))
else:
print('No solution found.')
AgeFindSATprogram()
这将返回以下输出:
x = 94
y = 25
z = 1
这样,可以通过使用聚合数据集来求解原始数据集的大致值。这就是为什么一些国家的政府(如印度)不允许发布聚合数据集,只发布原始计数。
| 性别 | 数量 |
|---|---|
| 男性 | 3 |
| 女性 | 4 |
| 总计 | 7 |
表 3.16 – 聚合数据集
缓解数据库重建攻击
为了缓解重建攻击并保护数据隐私,可以采用以下技术:
-
强匿名化:对发布的数据应用稳健的匿名化技术,如泛化、抑制或聚合。通过以保护隐私的方式转换数据,攻击者更难以准确重建个人记录。
-
噪声添加:向发布的数据或查询中引入受控噪声,以增加额外的隐私保护层。通过注入随机扰动,攻击者揭露原始数据或推断精确信息的可能性降低。
-
数据扰动:通过扰动或修改某些属性或值来修改数据,同时保持数据的整体效用。这可以使攻击者更难以准确重建原始信息。
-
查询限制:限制可以对数据进行查询的类型或数量,以减少敏感信息的暴露。通过限制对某些查询的访问或应用基于查询的隐私机制,可以降低重建攻击的风险。
用于使用 SQL 查询保护隐私的工具/框架
Open Diffix 是 Diffix 的开源实现,它允许使用 SQL 进行隐私保护的数据分析。它为需要分析敏感数据同时保护个人隐私的组织或研究人员提供了解决方案。Open Diffix 采用强大的匿名化技术来实现这一目标,确保数据库查询的结果不会泄露关于个人的敏感信息。
Diffix 充当客户端(对手或善意)与数据库之间的 SQL 代理。Diffix 返回 SQL 查询结果并添加最小量的噪声。Open Diffix 旨在确保个人敏感信息不能从发布的数据中推断出来。Open Diffix 背后的关键思想是在查询响应或统计汇总中引入受控噪声,以防止识别个人记录。

图 3.4– diffix 系统流程
Open Diffix 具有以下关键特性:
-
噪声添加
-
抑制
让我们快速回顾一下这两个特性的更多细节。
噪声添加
Open Diffix 支持向查询结果添加噪声。噪声可以以不同的方式添加:
-
固定数量的噪声:在这种情况下,向查询结果添加有限数量的噪声。这被称为隐私预算。
-
粘性噪声:每次执行查询时,都会添加随机噪声,但重复执行相同的查询将给出相同的结果,即向查询添加相同数量的噪声。
-
成比例的噪声:根据实际数据和数据的分布(时间序列数据),工具将添加相应的噪声。
抑制
Open Diffix 支持抑制某些数据(例如,数字中的极端值以及某些文本数据),并返回 SQL 查询的结果。这样,除了添加噪声外,抑制还将有助于防止揭示极端值,从而有助于保护隐私。
在 Postgres DB 上使用 Open Diffix 的示例用例
让我们通过 Postgres DB 的示例数据库,使用 Open Diffix 执行 SQL 查询,并了解 Open Diffix 如何通过添加噪声来匿名化和汇总结果,以保护个人的隐私。
这些是我们将在以下示例中执行的步骤:
-
数据库创建
-
用户角色创建和授权访问
-
在数据库表上启用 Diffix 以保护隐私
数据库创建
在这种情况下,我们将创建两个表(Employee和Department)以及一个示例数据库(sample_db)。
sample_db
schema_owner, analyst_trusted, analyst_untrusted
Employee, Department
CREATE TABLE department(
deptno INT GENERATED ALWAYS AS IDENTITY,
deptname VARCHAR(255) NOT NULL,
mgrno INT NOT NULL,
mgrname VARCHAR(255) NOT NULL,
mgremailid VARCHAR(255) NOT NULL,
location VARCHAR(255) NOT NULL,
PRIMARY KEY(deptno));
| 列名称 | 列类型 | 描述 | PII 数据 | 数据被屏蔽 |
|---|---|---|---|---|
| DEPTNO | 整数(主键) | 部门编号或 ID | 否 | 否 |
| DEPTNAME | 文本 | 部门名称 | 否 | 否 |
| MGRNO | 整数 | 部门主管员工 ID | 否 | 否 |
| MGRNAME | 文本 | 部门主管员工姓名 | 否 | 否 |
| MGREMAILID | 文本 | 部门主管员工电子邮件 ID | 是 | 是 |
| 位置 | 文本 | 部门位置 | 否 | 否 |
表 3.17 - 创建示例数据库
CREATE TABLE employee(
empno INT GENERATED ALWAYS AS IDENTITY,
ename VARCHAR(255) NOT NULL,
job VARCHAR(255) NOT NULL,
emailid VARCHAR(255) NOT NULL,
mgr INT NOT NULL,
hiredate DATE NOT NULL,
deptno INT NOT NULL,
PRIMARY KEY(empno),
CONSTRAINT fk_department
FOREIGN KEY(deptno) REFERENCES department(deptno)
);
| 列名称 | 列类型 | 描述 | PII 数据 | 数据被屏蔽 |
|---|---|---|---|---|
| EMPNO | 整数(主键) | 员工编号或 ID | 否 | 否 |
| ENAME | 文本 | 员工姓名 | 否 | 否 |
| JOB | 文本 | 职位名称 | 否 | 否 |
| EMAILID | 文本 | 员工电子邮件 ID | 是 | 是 |
| MGR | 整数 | 经理的员工 ID | 否 | 否 |
| HIREDATE | 日期 | 加入日期 | 否 | 否 |
| DEPTNO | 整数 | 部门编号或 ID | 否 | 否 |
表 3.18 - 创建示例数据库
一旦创建了表,按照以下方式插入示例数据并运行一个示例查询:
SELECT DEPTNO, DEPTNAME, MGRNO, MGRNAME, MGREMAILID,LOCATION FROM DEPARTMENT;
| DEPTNO | DEPTNAME | MGRNO | MGRNAME | MGREMAILID | LOCATION |
|---|---|---|---|---|---|
| 1 | 研发 | 45 | Michael | o64jDLFOfpfCe1fENtwVSAAT | 印度 |
| 2 | IT 服务 | 47 | Anna | i1ALN8ApLAaQrccuuGqAZgAP | 印度 |
| 3 | 销售和营销 | 43 | Srinivas | yvGkdh5dKQcN41nXWyYOjgAM | 印度 |
| 4 | 账户和财务 | 44 | Sankara | 4jDkdh5LAN841nX9yYOjQrc2 | 印度 |
| 5 | 人力资源 | 43 | Meena | 2II8Wq_aJDy1hGuNdYMeKQAB | 印度 |
| 6 | 基础设施 | 42 | Deepa | o2xkrwTjAcHghtiNWX5zSgAF | 印度 |
表 3.19 - 插入示例数据
SELECT EMPNO,ENAME,JOB,EMAILID,MGR,HIREDATE,DEPTNO FROM EMPLOYEE LIMIT 5;
| EMPNO | ENAME | JOB | EMAILID | MGR | HIREDATE | DEPTNO |
|---|---|---|---|---|---|---|
| 1 | Melissa | 测试员 | RGk3h5dKccN41nyYOj | 45 | 2020-01-17 | 1 |
| 2 | Lzenson | 网络安全工程师 | FJDy1hGuNdYMeKQAB | 43 | 2020-06-11 | 2 |
| 3 | Dyer | 项目经理 | Hy1hGuNdYMeKQAthy | 43 | 2020-11-13 | 4 |
| 4 | Kesavan | 法律助理 | HghtiNWX5zStsadgA1 | 42 | 2021-03-11 | 4 |
| 5 | Jonathan | 数据工程师 | pfC3e1fE3Nt4wVSAer | 47 | 2021-10-06 | 6 |
表 3.20 - 插入示例数据
用户创建
用户可以拥有以下数据库访问级别之一——Diffix 支持三种类型的用户:
-
direct:直接(非匿名)访问数据。本文件中列出的限制在直接模式下不适用。
-
anonymized_trusted:匿名访问数据。防止意外泄露个人数据。
-
CREATE USER schema_owner WITHPASSWORD 'schema_owner';CREATE USER analyst_trusted WITHPASSWORD 'analyst_trusted';CREATE USER analyst_untrusted WITHPASSWORD 'analyst_untrusted';
授予访问权限
授予这三个用户访问权限,以便他们可以选择数据和执行功能:
GRANT SELECT ON ALL TABLES IN SCHEMA public TO schema_owner;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO schema_owner;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO analyst_trusted;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO analyst_trusted;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO analyst_untrusted;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO analyst_untrusted;
定义角色
通过调用 Diffix 的标记角色函数为每个用户定义一个角色:
-
直接访问:
CALLdiffix.mark_role('schema_owner', 'direct'); -
受信任访问:
CALLdiffix.mark_role('analyst_trusted', 'anonymized_trusted'); -
不受信任访问:
CALLdiffix.mark_role('analyst_untrusted', 'anonymized_untrusted');
在表上启用 Diffix
通过执行以下代码在表上启用 Diffix:
CALL diffix.mark_personal('employee', 'empno');
CALL diffix.mark_personal('department', 'deptno');
运行 SQL 查询并查看隐私是如何受到保护的。
使用不同的用户(直接和匿名受信任及不受信任的用户)执行此查询并观察结果:
SELECT deptname, count(*), diffix.count_noise(*) FROM employee GROUP BY deptname
针对直接用户:
| Deptname | Count | Count_noise |
|---|---|---|
| 学习与发展 | 15959 | 0.0 |
| 销售和营销 | 737 | 0.0 |
| 账户和财务 | 573 | 0.0 |
| 人力资源 | 435 | 0.0 |
| 基础设施 | 20448 | 0.0 |
| IT 服务 | 21021 | 0.0 |
表 3.21 - 直接用户的实际结果
匿名可信 匿名不可信用户:
| 部门名称 | 计数 | 计数噪声 |
|---|---|---|
| 培训与发展 | 15957 | 1.0 |
| 销售和营销 | 736 | 1.0 |
| 账户和财务 | 571 | 1.0 |
| 人力资源 | 436 | 1.0 |
| 基础设施 | 20446 | 1.0 |
| IT 服务 | 21018 | 1.0 |
表 3.22 - 匿名用户受保护的结果
对于直接用户,Diffix 将提供实际结果。对于匿名用户,它通过添加噪声提供结果,这样对手将无法找到实际结果。
子查询
任何 SQL 查询都可以在匿名子查询的输出上执行,因为它们的输出不再被视为个人信息。直接用户与匿名用户之间的查询结果不同:
SELECT avg(tab.deptwise_count) FROM
(SELECT deptname, count(*) AS deptwise_count
FROM employee
GROUP BY deptname) tab
- 对于 直接用户:
| 平均值 |
|---|
| 8578.1428571428571429 |
表 3.23 - 直接用户的平均值
- 对于 匿名可信 和 匿名不可信 用户:
| 平均值 |
|---|
| 8576.8571428571428571 |
表 3.24 - 匿名用户的平均值
抑制
让我们考虑一个场景,一个组织总共有 874 名员工。通过特定表上的查询,可以明显看出那天只有一名员工被雇佣。这一观察结果引发了隐私担忧,因为没有适当的匿名化,如果我们知道个人的雇佣日期,那么通过查询数据库中的其他表,我们很可能提取出关于该个人的其他信息。
表格中未出现同一天雇佣多个员工的情况,这表明隐私保护可能存在潜在漏洞。如果攻击者或未经授权的实体获得了个人的雇佣日期,他们可能会通过在其他相互关联的表上执行查询来利用这一知识,从而推断出额外的个人信息。这可能会损害员工的敏感数据的隐私和机密性。
为了减轻这种风险并保护隐私,实施适当的隐私保护技术,如抑制,至关重要。
查询员工确切入职日期的 SQL 语句
SELECT hiredate, count(*) FROM employee
where deptname='Research and Development'
GROUP BY hiredate ORDER BY count(*) DESC LIMIT 5
对于 直接 用户:
| 入职日期 | 计数 |
|---|---|
| 2021-12-10 | 723 |
| 2020-03-03 | 98 |
| 2020-03-01 | 36 |
| 2021-01-13 | 1 |
| 2020-03-19 | 1 |
表 3.25 - 单一员工入职日期和隐私风险的分析
从这个结果来看,只有两个日期有单个员工加入该组织。这种特定的模式可能构成隐私风险,因为了解这些信息的个人可能会将其与其他数据源联系起来,从而揭示额外的个人信息。为了保护这些敏感信息并防止未经授权的推断,对于匿名可信和匿名不可信用户,提供与实际结果不同的替代结果至关重要。
作为一种隐私保护技术,Diffix 通过确保不受信任且匿名化的用户不会收到实际的查询结果来解决这个问题。相反,Diffix 抑制了结果计数太小以至于无法揭示有意义信息的数据。通过这样做,它有效地隐藏了精确细节,同时仍然提供统计洞察和分析。
| 招聘日期 | 数量 |
|---|---|
| 2021-12-10 | 723 |
| 2020-03-03 | 96 |
| 2020-03-01 | 37 |
| * | 18 |
表 3.26 - 员工招聘日期的抑制数据计数
在前面的表中,我们看到几乎所有数据都被抑制了。只显示了四个日期的计数。* 符号代表与个别员工相关的招聘日期,并且由于不同的招聘日期可能会泄露敏感信息,因此没有显示 18 名员工的精确招聘日期。
Diffix Elm 自动识别这一点并抑制日期,将它们合并为一个包含值 * 的单个区间,我们称之为抑制区间。除了抑制外,计数中也包含了噪声。
通过抑制结果计数较低的数据,Diffix 限制了通过查询发现敏感信息的机会。这种方法保护了个人的隐私,并防止了潜在的关联攻击,攻击者试图关联多个数据集以揭示个人细节。Diffix 通过在不损害统计准确性的情况下改变查询结果,为数据添加了额外的保护层。
总结来说,我们已经探讨了不同的匿名化技术和聚合数据集,了解了每种方法的优缺点。然而,需要注意的是,这些技术可能无法为个人提供完整的隐私保护。这一认识促使我们开发了一种名为差分隐私的新技术,我们将在下一节中详细学习。
隐私增强技术
隐私增强技术(PETs)是一套技术和方法,有助于在允许对数据进行有用分析和处理的同时保护敏感信息。以下是关于一些常用 PETs 的高级介绍。
差分隐私
这是一种向数据集中添加一定量噪声的技术,以保护个人记录的隐私,同时仍然允许进行统计分析。差分隐私确保对数据集进行的任何查询都不会泄露关于特定个人的信息,使其成为保护大型数据集中隐私的有力工具。我们将在本章以及后续章节的其他 PETs 中介绍差分隐私。
联邦学习
这是一种在不需要集中数据的情况下,在多个设备或服务器上训练机器学习模型的技术。在联邦学习中,模型在每个设备上本地训练,然后更新的模型被发送回中央服务器进行聚合。这种方法有助于保护个人数据的隐私,同时仍然允许进行有用的分析和处理。我们将在第七章中了解更多关于联邦学习的内容。
安全多方计算(SMC)
这是一种使多个参与方能够在不向彼此透露各自输入的情况下对各自的输入进行函数计算的技术。SMC 可用于一系列保护隐私的计算,包括安全投票、隐私保护数据挖掘和安全拍卖。我们将在第九章中了解更多关于 SMC 的内容。
同态加密
这是一种允许在未先解密数据的情况下对加密数据进行计算的技术。这意味着数据可以在受到保护的同时进行处理,使得同态加密成为保护数据分析隐私的强大工具。我们将在第九章中了解更多关于同态加密的内容。
匿名化
这是从数据集中移除识别信息的过程,例如姓名、地址和其他个人信息。匿名化有助于保护数据集中个人的隐私,同时仍然允许进行有用的分析。我们已经在上一节中学习了数据匿名化。
去标识化
这是一种从数据集中移除识别信息的技术,同时仍然保持数据在分析中的有用性。去标识化涉及以使数据难以追溯到个人的方式转换数据,但仍然保持其统计特性。单向哈希是实施数据去标识化以保护隐私的技术之一。
总体而言,PETs 是保护数据分析隐私的重要工具集,允许组织在有用数据分析和保护个人隐私的需求之间取得平衡。
让我们现在更多地了解差分隐私。
差分隐私
差分隐私是数据隐私中的一个概念,它为量化和控制数据分析算法的隐私保证提供了一个严格的框架。它确保个人数据的出现或缺失不会显著影响分析结果。
从数学上讲,差分隐私使用两个关键概念来定义:敏感性和隐私预算。
敏感性(Δf)
敏感性衡量函数 f 的输出在向数据集添加或从数据集中删除单个数据点时可能的最大变化量。它量化了个体数据对分析结果的影响。敏感性通常使用称为 L1 或 L2 范数的度量来定义。
隐私预算(ε)
隐私预算,也称为隐私参数,控制着差分隐私算法提供的隐私保护量。ε 的较小值表示更强的隐私保证。它表示算法输出在包含或排除单个个体数据时发生显著变化的允许最大概率。
使用这些概念,我们可以将差分隐私定义为如下:
一个随机化的机制或算法 L,如果存在两个相邻数据集 D1 和 D2,它们仅在一个人的数据上有所不同,并且对于任何定义为 S 的输出子集,则提供 ε-差分隐私。
从数学的角度来看,差分隐私被定义为如下:
Pr ( L[D1] ∈ S ) ≤ exp( ε) . Pr. ( L[D2] [[OMML-EQ-4]] S ) + δ
其中 Pr 是概率:
-
D1 和 D2 是两个仅在一项记录上有所不同的数据集。
-
S 是应用随机算法/机制的 L 的所有子集。
-
ε(epsilon)是一个控制隐私损失或隐私预算的正实数。
ε 决定了算法在两个数据库之间的差异程度,并捕捉了算法在数据库上运行时的隐私损失。
当 ε 设置为零时,两个查询的答案将非常相似,从而导致隐私的减少。
这个不等式表明,当算法在数据集 D1 上操作时,获得集合 S 中输出的概率至多为 exp(ε) 倍,当算法在相邻数据集 D2 上操作时获得相同输出的概率。
exp(ε) 因子量化了隐私保证,其中 ε 的较小值提供更强的隐私保护。
注意,差分隐私定义的变体和扩展包括额外的参数,例如查询次数或多次分析中的隐私损失。
差分隐私提供了一种严格且可量化的方法来平衡隐私和效用,允许在最小化隐私泄露风险的同时分析数据集。
差分隐私具有以下属性,这在整体隐私中非常有用:
-
隐私保证
-
可组合性
-
群组隐私
-
对辅助信息的鲁棒性
隐私保证
差分隐私提供了一种正式的保证,即查询的输出不会泄露数据集中任何个人的敏感信息。这意味着即使攻击者能够访问除一个人之外的所有数据,他们也不会以高概率确定该个人的信息。
以下是一个示例,用于说明差分隐私中的隐私保证。
让我们考虑一个场景,其中一家公司希望发布关于其员工平均工资的汇总信息。然而,他们也想保护个别员工的隐私。为了实现这一点,他们决定使用差分隐私。
使用差分隐私,公司在发布汇总结果之前向数据添加随机噪声。假设员工的实际平均工资是$50,000。通过应用差分隐私,发布的结果可能会略有扰动,例如$50,150 或$49,850,以确保隐私保护。
现在,让我们假设一个外部攻击者试图通过分析发布的汇总信息来识别特定员工的工资。由于添加了噪声,攻击者无法准确确定任何个别员工的工资。差分隐私引入的随机性确保发布的数据不会透露任何个人工资的精确信息。
通过控制添加噪声的水平(基于 epsilon 参数),公司可以调整隐私保证。例如,如果选择较小的 epsilon 值,添加的噪声将更高,提供更强的隐私保证,但可能会牺牲一些汇总结果的准确性。
在这个例子中,差分隐私保证了即使发布汇总统计数据,个人工资信息仍然受到保护。它确保没有任何外部方可以精确识别任何特定员工的工资,从而在保护隐私的同时,仍然可以从数据中得出有用的见解。
随机响应
差分隐私通过向查询输出添加随机噪声来实现其隐私保证。噪声的量被校准以平衡隐私保证与输出准确性的平衡。
随机响应是一种将随机性引入数据收集过程以保护个人隐私的方法。让我们用另一个例子来解释这项技术。
假设进行一项调查以收集关于人群非法活动的敏感信息。目标是估计参与非法活动的人数百分比,同时不透露具体个人的回答。
由于隐私问题可能导致人们不愿意或说谎,调查员采用随机响应技术,而不是直接询问个人是否参与非法活动。
这就是它的工作原理:
-
每个参与者都会得到一枚公平的硬币(正面和反面出现的概率相等)。
-
参与者在私下翻转硬币,而不透露结果。
-
如果硬币落在正面,参与者将诚实地回答关于非法活动的问题。
-
如果硬币落在反面,参与者提供随机响应,与其实际行为无关。例如,他们可能会说“是”,无论他们是否参与非法活动。
通过使用这种随机响应方法,任何个体的真实响应被随机性所掩盖。提供真实响应或随机响应的概率是相等的(例如,本例中为 50%),这使得根据个体的响应推断其真实行为变得困难。
现在,当分析调查结果时,研究人员会考虑随机响应和整体统计数据来估计参与非法活动的人数百分比。这种估计结合了随机响应技术引入的随机性,为个人提供隐私保护,同时仍然允许从汇总数据中得出有价值的见解。
随机响应技术只是差分隐私中用于确保隐私保证的许多方法之一。它有效地向个体响应添加噪声和不确定性,使得识别特定个体及其敏感信息变得具有挑战性。
可组合性
可组合性是差分隐私的一个关键特性,它指的是以保持整体隐私保证的方式组合多个差分隐私机制的能力。
在差分隐私中,如果一个机制被称为ε-差分隐私,那么两个相邻数据集产生相同输出的概率最多是单个数据集产生输出的概率的 eε倍。
可组合性特性确保了如果我们依次应用多个ε-差分隐私机制,整体隐私保证仍然保持ε-差分隐私。也就是说,由于多个机制的组合而产生的总隐私损失最多是各个隐私损失的总和。
这一特性很重要,因为它允许我们设计使用不同差分隐私机制来完成不同任务的复杂系统,同时仍然提供强大的隐私保证。
例如,我们可以使用差分隐私机制从多个来源收集敏感数据,然后汇总数据以获得有用的见解,同时保护隐私。现在让我们用一个例子来说明这一点。
考虑一家收集客户数据,包括他们的购买历史记录的公司。该公司希望在确保使用差分隐私保护隐私的同时为客户提供个性化推荐。他们决定应用差分隐私机制来保护数据。首先,公司使用差分隐私根据每个客户的购买历史生成个性化的推荐。这种分析向推荐算法引入随机噪声,确保在推荐中不会精确地揭示任何个人的购买历史。接下来,公司想要进行一项单独的分析,以确定不同年龄组客户平均消费金额。他们利用相同的差分隐私机制来计算平均消费,并引入随机噪声以保护个人消费信息。
差分隐私中可组合性的关键方面是,即使这些分析被组合在一起,隐私保证仍然有效。在这个例子中,当对同一数据集执行个性化推荐和平均消费分析时,隐私保证得到保留。
假设一个外部攻击者试图识别特定客户的购买历史或消费细节。由于添加的噪声和差分隐私的可组合性属性,攻击者无法准确区分分析期间生成的随机数据与真实个人数据。差分隐私提供的隐私保证跨越多个分析,即使在同一数据集上执行多个查询时也能保护个人隐私。
可组合性确保差分隐私的隐私保证保持完整,允许组织在保持一致隐私保护水平的同时对敏感数据进行各种分析。
然而,可组合性属性假设差分隐私机制是独立的,并且不共享任何信息。如果机制共享信息或者它们之间存在相关性,那么整体隐私保证可能比单个隐私保证的总和要弱。因此,仔细设计和分析差分隐私机制的组合以确保隐私得到保护是很重要的。
群体隐私
差分隐私中的一个关键概念是群体隐私,它指的是对个人群体隐私的保护,而不是对个人隐私的保护。
在差分隐私中,通过确保数据分析的结果不泄露任何特定个人或个人子组的任何信息来实现群体隐私。
这通常是通过以这种方式向数据添加噪声来实现的,即数据的统计属性保持基本不变,但任何个人或子组的具体细节被掩盖。
例如,假设一位研究人员想要分析某个特定人口群体的平均收入。在微分隐私框架中,研究人员首先会对群体中每个个体的收入数据添加随机噪声,这样数据的整体统计特性得以保留,但任何个体的收入都无法确定。然后,研究人员可以计算群体的平均收入,而不透露任何个体的收入。
在微分隐私中,群体隐私非常重要,因为它确保即使攻击者对个体子集有一些额外的信息,他们也无法利用这些信息来了解群体中其他个体的任何信息。
这使得微分隐私成为保护数据分析和个体及群体隐私的强大工具。
在数据集术语中,隐私不仅可以在一行上得到保护,还可以在数据集中的 X 行上得到保护:
Pr ( L[D1] ∈ S ) ≤ exp( X * ε) . Pr( L[D2] ∈ S ) + δ
X 定义了需要使用微分隐私保护的、数据集中需要保护的个人(行)数量。
对辅助信息的鲁棒性
对辅助信息的鲁棒性是微分隐私的一个关键特性,它确保即使攻击者(对手)对正在分析的个人有一些额外的信息,框架的隐私保证仍然保持完整。
在我们研究过的隐私框架中,例如 k-匿名性和ℓ-多样性,通过确保每个个体的数据至少与其他 k 或ℓ-1 个个体不可区分来保护个体的隐私。然而,这些框架没有考虑到攻击者可能关于个体的任何额外信息。例如,即使根据这些框架对数据进行匿名化,攻击者可能仍然能够根据个人的邮政编码或职业推断出个人的敏感信息。
另一方面,微分隐私即使在面对这样的辅助信息时也能提供强大的隐私保证。这是通过以这种方式向数据添加随机噪声来实现的,即噪声使得无法以高置信度确定特定个体的数据是否包含在数据集中,无论攻击者可能拥有的任何额外信息。
即使攻击者知道群体中某一个人的确切收入,添加的噪声使得无法以高置信度确定该个体的数据是否包含在数据集中。对辅助信息的鲁棒性是微分隐私的一个重要特性,因为它确保即使在面对可能访问数据集中个体额外信息的对手的复杂攻击时,框架的隐私保证仍然保持完整。
本地与全局微分隐私
差分隐私是一个概念,它有助于在仍然允许对数据进行有用分析的同时保护个人的隐私。
局部差分隐私(LDP)和全局差分隐私(GDP)是两种实现差分隐私的不同方法。LDP 是一种差分隐私方法,涉及在数据点共享之前向其添加噪声。这意味着在发布之前每个数据点都会受到扰动,这有助于保护数据集中个人的隐私。LDP 常用于个人提供自己的数据的情况,例如在移动应用中,并确保数据即使在服务器上也是私密的。
另一方面,GDP 涉及向汇总数据添加噪声。这意味着隐私保护应用于分析的整体结果,而不是单个数据点。GDP 常用于数据集中式收集的情况,例如在医院或政府机构,必须保护数据集中个人的隐私。
LDP 和 GDP 都有其自身的优缺点。LDP 在保护单个数据点的隐私方面更为有效,但在分析数据时可能不够准确。另一方面,GDP 更为准确,但可能不会为单个数据点提供同样强大的隐私保护。最终,LDP 和 GDP 之间的选择将取决于具体情况以及所需的准确性和隐私之间的权衡。
摘要
总之,我们探讨了数据分析中的隐私领域和隐私保护技术的重要性。我们讨论了匿名化、k-匿名性、t-接近性和ℓ-多样性等概念,它们在数据分析期间保护隐私中起着至关重要的作用。然而,我们也承认了这些技术的局限性。此外,我们深入探讨了隐私增强技术的概述,特别关注差分隐私。我们探讨了隐私损失、隐私预算和差分隐私机制等基本概念,了解它们如何有助于隐私保护。我们还考察了差分隐私属性的实现及其在确保隐私保证中的重要性。
在下一章中,我们的重点将转向差分隐私算法。我们将对这些算法进行概述,并探讨在差分隐私的背景下,敏感性、截断等概念的重要性。此外,我们将深入研究使用差分隐私生成汇总的方法,了解这种方法如何提供统计洞察力同时保护隐私。通过深入研究这些主题,我们将增强对差分隐私的实际应用的理解,以及如何有效地实施以平衡隐私和数据效用。
第四章:差分隐私算法概述及差分隐私应用
差分隐私的概念在数据隐私领域具有重大意义,随着收集和分析的数据越来越多,其重要性也在持续增长。差分隐私算法提供了一种在保护个人隐私的同时,仍能从这些数据中得出有价值见解的方法。
在本章中,我们将对差分隐私算法有一个概述,并理解在差分隐私背景下敏感性和剪裁等关键概念。此外,我们还将探讨如何通过使用差分隐私生成聚合数据,包括在现实世界中的应用。
本章将涵盖以下主要内容:
-
差分隐私算法:
-
差分隐私的拉普拉斯算法
-
差分隐私的高斯算法
-
使用差分隐私生成聚合数据
-
-
敏感性及其在差分隐私聚合生成算法中的作用:
- 使用差分隐私的查询:计数、求和和平均值 计数、求和和平均值
-
剪裁:
- 理解其在差分隐私领域中的重要性及其示例
-
差分隐私在现实世界中的应用概述
差分隐私算法
差分隐私是一个旨在保护个人隐私同时允许对敏感数据进行统计分析的基本概念。它建立了一个数学框架,在数据分析与共享过程中保证了个人隐私的保留。差分隐私算法通过在数据中引入随机噪声,使得识别特定记录变得困难,从而发挥着至关重要的作用。
在上一章中,我们了解到差分隐私的核心思想是在数据分析过程中引入随机噪声。这种噪声使得攻击者难以确定特定个人的数据是否包含在分析中,从而保护隐私。基本概念是任何个人的数据包含或排除不应显著影响分析结果:

图 4.1 – 差分隐私基本概念的说明
差分隐私可以数学定义。对于两个仅在一项记录上有所不同的数据集,D1 和 D2,应用到 D1 的随机算法或机制,L(如计数、求和、平均值等),在子集 S 中得到结果的概率被ε(ε)的指数乘以 L 应用到 D2 在 S 中得到结果的概率加上δ(δ)项所界定。
从数学上讲,这可以表示如下:
P(L[D1] ∈ S) ≤ exp(ε) * P(L[D2] ∈ S) + δ
在此方程中,以下适用:
-
P 表示概率。
-
D1 和 D2 代表两个数据集,它们只相差一条记录。
-
S 包含了随机算法或机制的所有子集,L。
-
ε(epsilon)是一个正实数,它控制着隐私损失,被称为隐私预算。它决定了算法在两个数据库之间可以有多大差异,并量化了算法应用于数据库时产生的隐私损失。如果 ε 为零,查询将产生相似的答案,这在一定程度上牺牲了隐私。
为了确保差分隐私,会在结果中添加随机噪声(以随机数的形式)。这种噪声阻止对手确定返回的结果是真实的还是添加了噪声,以及添加的噪声的大小。添加的噪声保证了数据不能被用来识别个人,同时仍然允许计算有用的统计属性。
随机数分布的选择取决于如何选择正确的随机数。接下来,我们将探讨两种著名的分布,即拉普拉斯分布和高斯分布,以评估它们对隐私参数 ε 的适用性,并保证差分隐私。
拉普拉斯分布
拉普拉斯分布,也称为双指数分布,是一种以著名数学家皮埃尔-西蒙·拉普拉斯命名的连续概率分布。它是由合并两个指数分布得来的,一个正的,一个负的。
为了更好地理解拉普拉斯分布,让我们先了解指数分布。指数分布由以下函数定义:
f(x) = e -x
当 x 等于 0 时,f(x) 等于 1,随着 x 的增加,f(x) 逐渐接近 0。
为了观察这种行为,你可以尝试一个简单的 Python 程序来分析指数分布。
尝试一个简单的 Python 程序并测试这种行为:
源代码:Exponential_Laplace_Guassian_Clipping.ipynb
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0,10, 0.25)
# define f(x) = e power (-x)
plt.plot(x, np.exp(-x));
plt.xlabel("x")
plt.ylabel("f(x)")
这里是输出结果:

图 4.2 – 指数分布
拉普拉斯分布 – 数学定义
拉普拉斯分布的概率密度函数定义如下:

在这里,x 是一个随机变量,μ 是位置参数,它决定了分布的中心,而 b > 0 是尺度参数,它控制着分布的扩散或变异性。
拉普拉斯分布有几个重要的特性。它在均值(μ)周围是对称的,峰值在 μ 处。分布的尾部较重,这意味着与高斯(正态)分布相比,它有更高的概率观察到极端值。这一特性使得拉普拉斯分布适合于建模具有异常值或重尾行为的数据。拉普拉斯分布在统计学、信号处理、图像处理和机器学习等多个领域都有应用。它在需要鲁棒性以抵抗异常值或假设数据具有拉普拉斯噪声的场景中特别有用。
如果 μ 等于 0 且 b 等于 1,那么方程如下:
𝔣(x) = 1 / 2 * e^(-x)
这实际上就是指数分布的一半。让我们用简单的 Python 代码实现拉普拉斯分布,并进一步理解它:
def laplace_dist(x, μ, b):
return 1 / (2 * b) * np.exp(-np.abs(x - μ) / b)
def plot_laplace_dist(x, μ, b):
plt.plot(x, laplace_dist(x, μ, b),
label="μ={}, b={}".format(μ, b))
x = np.arange(-10, 10, 0.1)
plot_laplace_dist(x, -2, 4)
plt.axvline(x=-2, linestyle='dotted', linewidth=3, label='mean')
plot_laplace_dist(x, 4, 8)
plt.axvline(x=4, color='orange', linestyle='dotted', linewidth=3, label='mean')
plt.legend();
这是输出结果:

图 4.3 – 不同均值和缩放参数的拉普拉斯分布
从这张图中,我们可以看到,随着拉普拉斯分布中的缩放参数(b)增加,与中心点相比,尾部贡献了更大的比例。这一特性可以通过利用更大的缩放参数来增强隐私。
通过增加缩放参数,拉普拉斯分布的尾部变得更重,导致极端值发生的可能性更高。这种增加的变异性使得对手更难提取敏感信息或准确识别单个数据点。因此,可以使用更大的缩放参数作为隐私增强措施,因为它们有助于分布的更广泛扩散,并提供更高的隐私保护水平。
为什么拉普拉斯分布是差分隐私算法选择之一?
看看下面的例子,它表明拉普拉斯分布是实现差分隐私的正确算法之一:
ε = 0.5
x = np.arange(90.2, 110, 0.20)
query_result=np.average(x)
dist1 = laplace_dist(x, query_result, 1 / ε)
dist2 = laplace_dist(x, query_result + 1, 1 / ε)
plt.plot(x, dist1, label="distribution 1")
plt.plot(x, dist2, label="distribution 2")
plt.axvline(x=query_result, c="black", linestyle='dotted', label="query result")
plt.legend()
在这里,我们选取了一个简单的数据集,该数据集包含从 90 到 110 的数字,增量是 0.2。这些数字的平均值接近 100,即查询结果——也就是说,查询找到了这些数字的平均值。
我们使用该数据集的均值作为查询结果,并将缩放因子(b)设置为 2,在这种情况下等于 1 / ε,来找到拉普拉斯分布:

图 4.4 – 使用拉普拉斯的分布
查询结果可以来自这些可能的分布中的任何一个。根据差分隐私公式(DP),当比较时,来自一个分布的查询结果应该小于或等于 eε 倍的第二个分布。
在这个特定的情况下,查询结果中的 100 这个值是从分布 1 中得出的。然而,无法完全排除它来自第二个分布的可能性,尤其是如果结果概率小于或等于 eε倍的情况下:
p1 = laplace_dist(query_result, query_result, 1 / ε)
p2 = laplace_dist(query_result, query_result+1, 1 / ε)
print(p1,p2)
结果是 0.25 0.15163266492815836。
p1, p2 * np.exp(ε)
结果是 0.25 0.25。
这证明了拉普拉斯分布可以用作差分隐私的一种机制,并且 b 缩放参数可以设置为 1/ε,即隐私预算。
高斯分布
高斯分布,也称为正态分布,是一个连续概率分布,在统计分析中广泛用于模拟现实世界现象。它以其对称于均值值的钟形曲线为特征。
高斯分布 – 数学定义
高斯分布也称为正态分布,它是一个连续概率分布。
高斯分布的公式定义如下:

在这里,x 是高斯分布中的随机变量;μ是位置参数,即它是数据的平均值;σ是标准差;σ²是数据的方差。
以下代码是高斯函数的一个实现:
def guissan_dist(x, μ, σ):
return (1/(σ * np.sqrt(2 * np.pi)) * np.exp(-(x - μ)**2 / (2 * σ**2)))
def plot_guissan(x, μ, σ ):
plt.plot(x, guissan_dist(x, μ, σ),
label="μ={}, σ ={}".format(μ, σ ))
x = np.arange(-10, 10, 0.1)
stdv=np.std(x)
plot_guissan(x, -2, stdv)
plot_laplace_dist(x,-2,4)
plt.legend()
让我们使用我们创建的随机数据集为高斯分布和拉普拉斯分布生成绘图:

图 4.5 – 不同均值和标准差的高斯分布
根据这个图表,我们可以看到拉普拉斯分布的峰值比高斯分布更尖锐。
现在,让我们确定高斯机制是否符合ε差分隐私:
query_result=100
p1 = guissan_dist(query_result, query_result, 1 / ε)
p2 = guissan_dist(query_result, query_result+1, 1 / ε)
print(p1,p2)
0.19947114020071635 0.17603266338214976
p1, p2 * np.exp(ε)
0.19947114020071635, 0.29022879645614585
高斯机制不满足ε差分隐私。让我们通过在这个情况下添加一个δ值来检查它是否满足(ε, δ)差分隐私:
p1, p2 * np.exp(ε)-0.09075
0.19947114020071635, 0.19947879645614586
这表明高斯机制支持(ε, δ)差分隐私,由于添加了 delta(δ),有时也称为近似差分隐私。
添加噪声算法以应用差分隐私的比较
以下表格提供了三种噪声添加机制的概要比较:
| 指数机制 | 拉普拉斯机制 | 高斯机制 | |
|---|---|---|---|
| 用途 | 主要用于选择特定的记录或选择最佳元素,特别是用于非数值或分类数据 | 由于其在隐私和效用之间的平衡以及其实施的简便性,广泛应用于数值聚合 | 用于处理较小规模的数据,并且需要反复应用差分隐私 |
| 噪声类型 | 指数噪声 | 拉普拉斯(双指数)噪声 | 高斯噪声 |
| 隐私 | 由于输出概率的指数分布,具有高隐私级别 | 随机噪声可能会显著改变结果,损害数据效用 | 实现了 delta 隐私或 epsilon-delta 隐私,这是为了更好的效用而进行的权衡 |
| 实现 | 由于指数分布的特性,实现较为复杂 | 由于拉普拉斯分布的特性,实现相对容易 | 实现较为复杂,但在数据敏感性低时通常适用 |
| 适应性 | 主要用于分类数据 | 主要用于数值数据 | 适用于低敏感度和多查询数据 |
表 4.1 - 三种噪声添加机制的概要比较
使用差分隐私生成聚合数据
差分隐私是一种技术,用于在收集和共享数据时保护个人的隐私。差分隐私可以使用的其中一种方式是在生成聚合数据,这些数据是数据的统计摘要,可以在保护个人隐私的同时提供有用的见解。
一旦向数据中添加了噪声,就可以计算并发布统计聚合,而不会损害个人隐私。可以使用差分隐私生成的统计聚合示例包括平均值、中位数和直方图。使用差分隐私生成聚合数据的一个挑战是平衡隐私和准确性。添加到数据中的噪声量将影响生成的统计聚合的准确性。因此,通常在隐私保护和结果准确性之间有一个权衡。总的来说,使用差分隐私生成聚合数据是保护个人隐私的同时仍然允许计算有用统计属性的有力工具。然而,它需要仔细考虑具体用例以及隐私和准确性之间的权衡。
敏感性
敏感性在差分隐私领域发挥着至关重要的作用。它指的是当单个个体的数据点被添加到或从数据集中移除时,函数或计算输出的最大变化量。敏感性提供了与在敏感数据上执行计算相关的隐私风险度量。
让我们来看一个现实场景的例子,它说明了使用敏感性分析来衡量更改数据集影响的需求。
场景 - 财务风险评估模型
假设一家金融机构开发了一个机器学习模型来评估贷款申请人的信用风险。该模型考虑了各种特征,如收入、信用记录、就业状况和未偿还债务,以预测贷款违约的可能性。该机构希望确保模型是健壮的,并且对数据集中任何个人的存在或不存在不敏感。在这种情况下,敏感性分析可以用来评估更改数据集的影响,特别是通过删除或修改某些个人的数据。该机构希望确定删除或修改特定个人的数据是否会显著改变模型的预测或引入偏差,并衡量与此变化相关的隐私风险。
让我们用数学术语来分解这一点。
例如,如果我们有一个函数 f,它接受一个数据集 D 作为输入并返回一个数值输出,那么函数 f 的敏感性定义为在两个数据集 D 和 D’ 之间,D 和 D’ 通过单个个体的数据点的存在或不存在而不同,f 在这两个数据集上的输出的最大绝对差异。
因此,在这里,函数 f 的敏感性定义为 sensitivity(f) = max_{D, D’} ||f(D) - f(D’)||。
函数的敏感性是差分隐私中的一个基本概念,因为它决定了需要添加到函数输出中的噪声量以保证隐私。自然地,敏感性较高的函数更容易泄露数据集中个人的信息,因此需要向它们的输出中添加更多的噪声以保持隐私。
为了理解敏感性,让我们考虑以下数据集:
X = [ 0, 1,2,3,4,5,6,7,8,9,10,11,…..N]
在这个数据集中定义了两个函数/查询:𝔣1(x) = x 和 f2(x) = x3。
让我们定义另一个函数/查询,它计算以下差异:
∆ f(xa, xb) = | f(xa) − f(xb) |
让我们计算 f1, f2, ∆ f1, ∆ f2 并观察数据:
| X | X0 | X1 | X2 | X3 | X4 | X5 | X6 | X7 | …. |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | … | |
| f1(xi)=x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | … |
| f2(xi)=x3 | 0 | 1 | 8 | 27 | 64 | 125 | 216 | 343 | … |
| ∆f1(xi, xi+1) | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | …. |
| ∆f2(xi, xi+1) | 1 | 7 | 21 | 37 | 61 | 91 | 127 | … | ... |
表 4.2 - 函数/查询在数据集上的敏感性分析
敏感性指的是底层数据集的变化对查询结果的影响。
让 xA, xB 是 X 所有可能的数据集中的一个,这些数据集与 X 的所有可能数据集最多只有一个元素的不同。
因此,敏感性是通过以下方程计算的:
敏感性 = max | f(xa) − f(xb) ||,其中 Xa,Xb ⊆ X
根据这个定义,很明显,f₁(𝑥) = 𝑥 的敏感性为 1,因为最大差异是恒定的。在第二个查询 f₂(𝑥)=𝑥³ 中,差异不是恒定的,它是无界的,根据数据集中的数据元素数量增长。为了计算第二个函数/查询的敏感性,我们需要指定下限和上限 - 例如,从 x⁵ 到 x¹⁰,x⁰ 到 x⁵,等等。
让我们定义另一个查询,该查询在 5 到 10 或 0 到 5 的输入值范围内使用相同的函数进行限制:
f³(𝑥) = 𝑥³,其中 0≤𝑥≤5
Δ𝑓(𝑥𝑎, 𝑥𝑏) = | 𝑓(𝑥𝑎) − 𝑓(𝑥𝑏) |
这里是表格:
| X→ | X₀ | X₁ | X₂ | X₃ | X₄ | X₅ |
|---|---|---|---|---|---|---|
| 0 | 1 | 2 | 3 | 4 | 5 | |
| 𝑓𝑥(𝑥𝑖)=𝑥³ | 0 | 1 | 8 | 27 | 64 | 125 |
| Δ𝑓₂(𝑥𝑖, 𝑥𝑖+1) | 1 | 7 | 21 | 37 | 61 | 91 |
表 4.3 - 查询在输入值范围内限制的敏感性分析
在这种情况下,敏感性将是最大 | 1+7+21+37+61+91 | = 216:
def f(x):
return x ** 3
def sensitivity(f, xa, xb):
sensitivity = abs(f(xa) - f(xb))
return sensitivity
# Sensitivity calculation for the input range 0 to 6 and summing the sensitivities
total_sensitivity = 0
for x in range(6):
xa = x
xb = x + 1
sensitivity_value = sensitivity(f, xa, xb)
print(sensitivity_value)
total_sensitivity += sensitivity_value
print("Total Sensitivity within the range 0 to 6:", total_sensitivity)
输出:
1
7
19
37
61
91
Total sensitivity within the range 0 to 6: 216
查询的敏感性可以根据是否使用通用数据集或局部数据集来计算,进一步分为全局敏感性和局部敏感性。
全局敏感性
全局敏感性指的是在考虑所有可能的数据集时查询结果可能的最大变化。它是基于整个群体或通用数据集计算的。全局敏感性提供了潜在隐私风险的界限,并捕捉了最坏情况。
局部敏感性
另一方面,局部敏感性关注基于特定局部数据集的查询敏感性。它衡量在从该局部数据集中添加或删除单个数据点时查询结果的最大变化。局部敏感性提供了对隐私风险的更精细和特定于上下文的度量。
基于此,我们可以制定以下方案:
| 查询/函数 | 全局敏感性 | 注释 |
|---|---|---|
| 𝑓(𝑥) = 𝑥 | 1 | 改变 𝑥 的值 1 将导致 𝑓(𝑥) 改变 1 |
| 𝑓(𝑥) = 𝑥² | 无界 | 𝑓(𝑥) 的变化取决于 𝑥 的值 |
| 𝑓(𝑥) = 𝑥 + 𝑥 | 2 | 改变 𝑥 的值 1 将导致 𝑓(𝑥) 改变 2 |
| 𝑓( 𝑥) = 5 × 𝑥 | 5 | 改变 𝑥 的值 1 将导致 𝑓(𝑥) 改变 5 |
表 4.4 - 查询结果局部敏感性分析
通过向查询结果添加噪声来实现差分隐私,从而保证隐私。
在差分隐私中需要添加的噪声量取决于四个关键参数:
-
隐私参数 (ε):隐私参数 ε 控制差分隐私提供的隐私保护水平。ε 的值越小,隐私保证越强,但可能会导致查询结果中添加的噪声更高。
-
隐私预算 (Δε):隐私预算表示在多个查询或操作中可以消耗的总隐私量。它通常在各个查询之间平均分配,以确保整体隐私保证得到维持。
-
敏感性(Δf):敏感性指的是当添加或删除单个数据点时,查询结果可以变化的最高量。它量化了个人数据对查询结果的影响,并有助于确定需要添加的噪声量。
-
数据大小(N):正在分析的数据集的大小也会影响在差分隐私中添加的噪声量。一般来说,较大的数据集允许添加较少的噪声,从而提高准确性,而较小的数据集可能需要添加更多的噪声以保护隐私。
通过仔细选择这些参数的适当值并考虑隐私和准确度之间的权衡,可以调整噪声以提供有效的隐私保护,同时仍然产生有用且可靠的查询结果:

图 4.6 – 影响噪声添加的参数
使用差分隐私的查询
使用差分隐私的查询允许分析师和数据科学家从数据集中检索汇总信息,同时确保保护单个数据点的隐私。这些查询旨在向查询结果添加一定量的噪声,使得难以辨别数据集中任何特定个人的贡献。
可以使用差分隐私执行各种类型的查询。以下是一些常用的查询类型:
-
计数查询:这些查询旨在确定满足数据集中特定条件记录的数量,同时保护隐私。查询结果通过向真实计数添加噪声而受到干扰,确保个人贡献无法被准确确定。
-
求和查询:求和查询涉及在保持隐私的同时计算数据集中特定值的总和 – 例如,计算一组个人的总收入,同时保护个人收入值的机密性。
-
平均查询:平均查询计算数据集中特定属性的平均值,同时确保隐私。向计算出的平均值添加噪声以保护个人数据点。
-
Top-K 查询:Top-K 查询旨在在保护隐私的同时识别数据集中最大的 K 个值或记录。向查询结果添加噪声以隐藏个人的具体贡献。
-
范围查询:范围查询涉及从数据集中检索特定范围内的记录或值,同时保持隐私。向查询结果添加噪声以防止已识别的个人数据点落在该范围内。
为了实现差分隐私,使用了各种机制向查询结果添加噪声。这些机制包括拉普拉斯机制、高斯机制和随机响应等。机制的选择取决于查询的具体要求和所需的隐私保证。
重要的是要注意,差分隐私提供的隐私保护水平可以通过一个称为 epsilon(ε)的隐私参数来量化。ε 的值越小,提供的隐私保证越强,但可能会在查询结果中引入更多的噪声,从而可能降低其准确性。
使用差分隐私的查询在数据实用性和隐私保护之间提供了平衡。它们允许从敏感数据集中提取有意义的分析和见解,同时保护个人信息的机密性。通过将差分隐私技术纳入数据分析过程,组织可以确保遵守隐私法规并与他们的用户或客户建立信任。
让我们逐一深入分析以下数据集中的这些查询:
| 姓名 | 年龄 | 薪水 | 性别 | 职位 |
|---|---|---|---|---|
| A | 32 | 200K | M | 工程师 |
| B | 44 | 300K | F | 经理 |
| C | 55 | 400K | F | 主任 |
| D | 66 | 500K | M | 副总裁 |
表 4.6 - 使用提供的数据集进行的差分隐私查询分析
使用差分隐私的计数查询
分析以下查询的结果,并找出敏感性是如何运作的:
-
这个数据集中总共有多少名员工?答案是 4。
-
有多少人薪水低于 300K?答案是 1。
-
有多少男性员工在工作?答案是 2。
为了确保答案包括噪声并保证差分隐私,确定计数查询的敏感性和用于敏感性的适当值是至关重要的。
计数查询的敏感性为 1,这意味着如果添加一条记录,查询结果将增加 1,或者如果删除一行,查询结果将减少 1。通过理解计数查询的敏感性,我们可以在保护隐私的同时准确加入噪声。
我们将利用 NumPy 库为样本计数查询生成差分隐私结果。
NumPy 提供基于给定敏感性、平均值和 epsilon 值的拉普拉斯噪声生成:
import numpy as np
Total_employees = 4
sensitivity = 1
print("sensitivity:",sensitivity )
# epsilon =privacy loss or budget
epsilon= 0.8
noise = np.random.laplace(loc=0, scale=sensitivity/epsilon)
print("noise:",noise)
count_employee_dp = Total_employees + noise
print ("count with DP:", count_employee_dp)
输出:
sensitivity: 1
noise: 2.247932787995729
count with DP: 6.24793278799573
使用差分隐私的求和查询
让我们分析以下查询并了解在这种情况下敏感性是如何工作的:
-
这个数据集中所有员工的薪水总额是多少?报告的总额为 1,400K(未应用差分隐私)。
-
员工的总年龄是多少?报告的总年龄和为 197(未应用差分隐私)。
为了确保答案包括由保证的差分隐私添加的噪声,重要的是确定求和查询的敏感性并确定用于敏感性的适当值。
与计数查询不同,对于求和查询的敏感性并不直接,因为新增一行会增加输出值。
因此,在这种情况下,敏感性是无界的,因为它取决于要添加的记录的数据。
对于关于一个人年龄的查询,我们可以通过考虑人类历史上所知的最大寿命来估计上限,这个最大寿命大约是 126 岁。因此,我们可以假设这个查询的上限为 126 岁。
然而,确定工资查询的真实上限是具有挑战性的。它可能是 100 万、1000 万、1 亿,甚至更高。因此,在求和查询中,敏感性取决于提供给查询的下限和上限。
为了自动计算下限和上限,可以使用称为裁剪的技术,我们将在下一节中探讨:
Total_salary = 1400
Lower_bound=100
Upper_bound=9999
sensitivity = Upper_bound - Lower_bound
print("sensitivity:",sensitivity )
# epsilon =privacy loss or budget
epsilon= 0.9
noise = np.random.laplace(loc=0, scale=sensitivity/epsilon)
print("noise:",noise)
Total_salary_dp = Total_salary + noise
print ("total salary with DP:",Total_salary_dp)
输出:
sensitivity: 9899
noise: 4724.329480136737
total salary with DP: 6124.329480136737
差分隐私结果中的准确性和隐私受到其敏感性(由求和查询指定的下限和上限确定)的严重影响。
使用差分隐私的平均查询
分析以下查询,并找出敏感性在这种情况下是如何工作的:
-
平均工资是多少?答案是 35 万。
-
平均年龄是多少?答案是 49.26。
为了确保平均查询的答案包括由保证的差分隐私添加的噪声,重要的是确定这些查询的敏感性,并确定在差分隐私算法中用于敏感性参数的适当值。
考虑平均查询的一种方法是将它们视为两个独立的查询:求和查询和计数查询。可以使用已知方法计算计数查询的敏感性;求和查询的敏感性也可以类似地确定。
通过理解计数查询和求和查询的敏感性,我们可以为平均查询提供差分隐私结果。这涉及到以保留隐私的同时确保平均计算准确性的方式添加噪声。
Average_salary = 350
Total_salary_dp = 6124.329480136737
count_dp = 6.24793278799573
dp_average = (Total_salary_dp)/count_dp
dp_average
980.2169274137402
带有差分隐私的噪声平均工资会因为添加的噪声而失真,而没有差分隐私的平均工资保持不变。
现在,让我们使用差分隐私技术,如敏感性、裁剪和噪声,来实现相同的使用案例。我们将使用拉普拉斯机制向平均计算中注入噪声。
虽然当前的讨论旨在提供对基础概念的了解,但重要的是要注意,实现差分隐私的生产级框架会更详细地考虑各种复杂性。这些框架处理诸如在计算过程中处理数字溢出以及采用适当的算法以确保准确性和隐私保护计算等因素。这些框架优先考虑鲁棒性和可靠性,以满足现实场景的需求。
裁剪
如前所述,无界查询具有无限大的敏感性值,不能直接用于提供具有差分隐私的结果。解决这一问题的方法之一是通过指定它们的下限和上限将无界查询转换为有界查询。
在差分隐私中,剪辑是一种技术,通过限制函数的输出在特定范围内来绑定函数的敏感性。基本概念是将函数的输出剪辑或限制在预定的范围内,例如 [-c, c],其中 c 是一个正的常数。之后,向剪辑后的输出引入噪声以确保隐私保证。
剪辑过程涉及两个步骤:
-
缩放函数的输出:函数的输出通过除以缩放因子 s 进行缩放。这种缩放确保缩放输出的绝对值小于或等于剪辑阈值 c。
从数学上讲,这可以表示为 f’(D) = f(D) / s,其中 |f’(D)| <= c。
-
添加噪声:一旦输出被剪辑,就会引入噪声以维护差分隐私。这种噪声可以来自拉普拉斯或高斯分布,具体参数取决于所需的隐私级别。
剪辑技术旨在限制个别数据点对函数输出的影响,并促进足够噪声的添加以有效保护隐私。通过使用剪辑来限制敏感性,差分隐私机制可以在提供准确结果的同时保持数据机密性。
让我们回顾一下我们之前使用的简单数据集:
| 姓名 | 年龄 | 薪水 | 性别 | 职位 |
|---|---|---|---|---|
| A | 32 | 200K | M | 工程师 |
| B | 44 | 300K | F | 经理 |
| C | 55 | 400K | F | 导演 |
| D | 66 | 500K | M | 副总裁 |
表 4.7 - 使用剪辑技术进行敏感性边界分析
给定实际的查询,“这个数据集中所有员工的总薪水是多少?”以及实际的答案,即 1,400K,使用差分隐私提供总薪水需要使用如拉普拉斯或高斯机制之类的噪声机制添加噪声。这种噪声机制依赖于查询的敏感性。
要继续进行,我们必须将下限和上限设定为任意固定值。通过计算下限和上限之间的差值,我们获得查询的敏感性。然而,为了深入了解这个过程,我们将对输入数据应用剪辑函数。
通过应用剪辑函数,我们将输入数据限制在特定范围内,这有助于管理查询的敏感性。这项技术有助于限制个别数据点的影响,并促进以可控方式添加噪声。通过使用剪辑,我们可以在数据隐私和实用性之间取得平衡,确保准确的结果同时保护敏感信息的机密性。
让我们在数据集上玩一下剪辑函数,进一步了解这一点。
剪辑示例 1
让我们考虑以下用例示例:一个社交媒体平台希望确定给定帖子的每个用户的平均点赞数。该平台希望在保护用户隐私的同时,仍然获得准确的估计。
这里是一个没有差分隐私的 Python 实现:
源代码 DP_End_to_End.ipynb
import random
# Generate a list of simulated likes per user
likes_per_user = [random.randint(0, 100) for _ in range(1000)]
print(likes_per_user)
# Calculate the average number of likes per user
average_likes = sum(likes_per_user) / len(likes_per_user)
print("Average likes per user (without differential
privacy):", average_likes)
平均每个用户的点赞数(无差分隐私):51.146
现在,让我们使用差分隐私技术(如灵敏度、剪切和噪声)实现相同的用例。我们将使用拉普拉斯机制向平均计算中注入噪声:
import random
import numpy as np
# Generate a list of simulated likes per user
likes_per_user = [random.randint(0, 100) for _ in range(1000)]
average_likes = sum(likes_per_user) / len(likes_per_user)
print("Average likes per user (without differential
privacy):", average_likes)
# Set the sensitivity
sensitivity = 1
# Clip the likes per user to a specified range
clipped_likes_per_user = np.clip(likes_per_user, 0, 100)
# Calculate the average number of likes per user
clipped_average_likes = np.mean(clipped_likes_per_user)
# Define the privacy budget and epsilon value
privacy_budget = 1.0
epsilon = 0.1
# Calculate the scale parameter for the Laplace distribution
scale = sensitivity / (privacy_budget * epsilon)
# Inject noise using the Laplace mechanism
noisy_average_likes = clipped_average_likes + np.random.laplace(0, scale)
print("Average likes per user (with differential privacy):", noisy_average_likes)
Average likes per user (without differential privacy): 51.252
Average likes per user (with differential privacy): 41.61714462702061
在这个例子中,我们将灵敏度设置为 1,因为平均计算的灵敏度是 1(一个用户的点赞数最多可以影响平均数 1)。然后,我们限制了每个用户的点赞数,以确保它们落在特定的范围内(在这个例子中,是 0 到 100)。
接下来,我们计算了剪切后的平均点赞数,并定义了隐私预算和 epsilon 值。隐私预算代表可用的总隐私保护量,而 epsilon 值控制隐私级别。
最后,我们根据灵敏度、隐私预算和 epsilon 计算了拉普拉斯分布的尺度参数。我们使用拉普拉斯机制对剪切后的平均点赞数添加噪声,考虑到尺度参数。
resulting_noisy_average_likes 值提供了每个用户平均点赞数的估计,同时结合了差分隐私技术来保护用户隐私。
剪切示例 2
以下是一个剪切的另一个例子:
源代码: DP_End_to_End.ipynb
import pandas as pd
data = {'age': [32, 44, 55, 66],
'salary': [200, 300, 400, 500]}
df = pd.DataFrame(data)
df['salary'].clip(lower=0, upper=999)
输出:
0 200
1 300
2 400
3 500
Name: salary, dtype: int64
在这种情况下,如果我们使用Pandas提供的clip函数,范围设置为 0 到 9,999,那么由于clip函数中的上下限值,工资不会改变。
剪切示例 3
以下是一个剪切的另一个例子:
源代码 DP_End_to_End.ipynb
import pandas as pd
data = {'age': [32, 44, 55, 66], 'salary': [200, 300, 400, 500]}
df = pd.DataFrame(data)
df['salary'].clip(lower=250, upper=400)
输出:
0 250
1 300
2 400
3 400
Name: salary, dtype: int64
在这种情况下,当我们设置上限为 400,下限为 250 时,剪切函数将超过 400 的工资改为 400,低于 250 的工资改为 250(例如,200 变为 250,500 变为 400)。
pandas 的clip函数将强制输入数据在指定的剪切界限内。如果其中一个值太小,它将被转换为下限剪切界限,如果值太大,它将被转换为上限剪切界限。
以下架构说明了这个操作:
剪切(250,200,300,400,500,400)

图 4.7 – 说明剪切功能
由于这是一个玩具数据集,我们可以查看数据并为剪切数据提出适当的上下限。
让我们在剪切的输入总和上添加灵敏度(剪切范围差)和 epsilon 的噪声:
def laplace_mech(v, sensitivity, epsilon):
return v + np.random.laplace(loc=0, scale=sensitivity/epsilon)
epsilon = 0.9
sensitivity=400-100
print(laplace_mech(df['salary'].clip(lower=100, upper=400).sum(),sensitivity,epsilon))
print(laplace_mech(df['salary'].sum(),sensitivity,epsilon))
输出:
1693.8114539575836. (With clipped)
1793.7575175454226. (without clipping)
通过使用适当的上下限,使用差分隐私获得的结果更接近实际值,与使用随机界限相比,提高了准确性。在这个例子中,实际的总薪资是 1,400K,但添加了噪声后,返回的值是 1,693K。
然而,使用特定上下限的一个潜在缺点是,它们可能会无意中泄露数据集中个人的实际薪资,从而损害隐私。
另一种方法是使用零或一个合适的低值初始化下限,并逐渐增加上限。这个过程涉及观察查询结果并监控其何时停止变化或变得稳定。在此点,停止上限的值,确保查询结果不会泄露敏感信息,同时保护隐私。
这种迭代方法允许在准确性和隐私之间取得平衡,因为它根据数据的特征动态确定边界。它有助于防止泄露特定的薪资信息,同时在差分隐私的范围内提供合理准确的结果。
让我们通过玩具数据集来探索这种方法:
源代码:DP_End_to_End.ipynb
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
data = {'age': [32, 44, 55,66], 'salary': [200, 300, 400, 500]}
df = pd.DataFrame(data)
def laplace_mech(queryresult, sensitivity, epsilon):
return queryresult + np.random.laplace(loc=0, scale=sensitivity/epsilon)
epsilon = 0.5
plt.plot([laplace_mech(df['salary'].clip(lower=0, upper=i).sum(), i, epsilon) for i in range(100,800,100)])
plt.xlabel('Clipping ranges for salary')
plt.ylabel('Total salary');
这是输出结果:

图 4.8 – 薪资与裁剪范围的总薪资对比
由于数据集规模较小,确定查询结果的理想裁剪值相对简单——在这种情况下,薪资总和不会超过 500。然而,对于更大的数据集,噪声有时可能会变得过于突出,以至于无法分析所有不同的敏感度或裁剪值。
差分隐私在现实生活中的应用概述
在本节中,我们将对一些利用差分隐私的实际情况进行简要概述。
差分隐私在 Uber 的应用
Uber Technologies, Inc. 提供作为服务的移动性——即,叫车服务。它必须保护使用其服务的客户的隐私,同时分析其数据以提供更好的服务。它开发了一个开源框架,通过 SQL 查询实现差分隐私,并将其用于分析和提取见解。所有 SQL 查询都通过 Uber 的差分隐私框架进行转换,该框架执行 SQL 查询并提供具有差分隐私保证的查询结果。
它可以在 GitHub 上找到:github.com/uber-archive/sql-differential-privacy。
差分隐私在 Apple 的应用
苹果公司在其产品中大规模集成了本地差分隐私技术,旨在理解和提升用户体验。他们采用了私有计数均值草图算法,该算法利用计数、均值、草图和隐私预算(ε)。对于每个关键特征,他们设定了隐私预算和最大记录数(差分隐私记录数),在移除敏感特征(如 IP 地址)后,这些记录可以传输到远程服务器:
| 关键特征 | ε(epsilon) | 每天每设备的记录数 |
|---|---|---|
| 表情符号建议 | 4 | 1 |
| 查找提示 | 4 | 2 |
| 快速输入 | 8 | 2 |
| …. |
表 4.8 - 苹果公司本地差分隐私的实现
它使用哈希函数对输入向量进行编码后注入噪声,并以 1/(1 + 𝑒 𝜀/2)的概率翻转每个向量元素,其中ε是隐私预算。
更多关于此算法的详细信息可以在machinelearning.apple.com/research/learning-with-privacy-at-scale找到。
Jun Tang、Aleksandra Korolova、Xiaolong Bai、Xueqiang Wang、Xiaofeng Wang 等人通过对客户端代码进行调试,对苹果公司的差分隐私实现进行了详细分析,并在 Arxiv 上发表了研究论文。我强烈建议您阅读这篇论文,以更好地理解苹果公司的实现以及考虑到的额外细节:《苹果公司在 MacOS 上实现差分隐私的隐私损失》10.12 (arxiv.org/abs/1709.02753)。
美国人口普查中的差分隐私应用
美国人口普查局使用差分隐私对 2020 年的人口普查数据进行噪声处理,以保护收集和共享的普查数据中受访者的隐私。
更多详细信息可以在www.census.gov/data/academy/webinars/2021/disclosure-avoidance-series/differential-privacy-101.html找到。
谷歌的差分隐私
谷歌在其 Chrome 浏览器中使用差分隐私来了解频繁访问的页面;谷歌地图和谷歌助手也具有此功能。它开发的差分隐私系统称为随机可聚合的隐私保护有序响应(RAPPOR),提供 2 作为下限,8 到 9 作为上限的ε值。
谷歌开源了 RAPPOR 的实现。您可以在github.com/google/rappor了解更多信息。
摘要
在本章中,我们介绍了差分隐私的概念,并探讨了拉普拉斯和高斯机制如何生成噪声以确保隐私,同时生成汇总查询结果。我们讨论了 epsilon、delta 和敏感度等参数的重要性,以及它们如何用于使用拉普拉斯或高斯分布计算噪声。此外,我们还学习了如何使用裁剪技术确定上下限。最后,我们总结了差分隐私在苹果和优步以及美国人口普查局等现实世界应用中的使用情况。
在下一章中,我们将深入探讨差分隐私的开源框架。我们将探索如何使用这些框架开发应用程序,并详细探讨在差分隐私背景下的机器学习领域。这将提供一个全面的理解,了解如何在实际场景中实现差分隐私,以及如何在机器学习应用中利用其优势。
第五章:使用开源框架开发具有差分隐私的应用程序
在本章中,我们将探讨用于开发具有差分隐私能力的机器学习、深度学习和大规模应用程序的开源框架(PyDP、PipelineDP、tmlt-analytics、PySpark、diffprivlib、PyTorch 和 Opacus)。
我们将涵盖以下主要主题:
-
实现差分隐私的开源框架:
-
PyDP 框架及其关键特性的介绍
-
PyDP 的应用示例和演示
-
使用 PyDP 开发一个示例银行应用程序,以展示差分隐私技术
-
-
防止成员推理攻击:
-
理解成员推理攻击及其潜在风险
-
在应用差分隐私时,防止成员推理攻击的技术和策略
-
-
在大型数据集上应用差分隐私以保护敏感数据:
-
利用开源的 PipelineDP 框架在大型数据集上应用差分隐私
-
利用开源的 Tumult Analytics 和 PySpark 框架在大型数据集上应用差分隐私
-
-
带有差分隐私的机器学习:
-
使用差分隐私在合成数据上运行欺诈检测分类模型
-
一个聚类示例,应用差分隐私,使用 IBM 的开源 diffprivlib 框架
-
-
带有差分隐私的深度学习:
-
使用 PyTorch 深度学习框架实现欺诈检测模型
-
利用开源的 PyTorch 和 Opacus 框架开发具有差分隐私的欺诈检测深度学习模型
-
-
差分隐私机器学习框架
-
差分隐私的局限性以及一些克服策略
实现差分隐私的开源框架
有几个开源框架可用于实现差分隐私。在本节中,我们将详细介绍 PyDP 框架。
PyDP 框架及其关键特性的介绍
Google 发布了一个名为差分隐私的开源框架,该框架简化了差分隐私的实施。此框架支持 ε- 和 (ε, δ)-差分隐私统计。它包括各种功能,例如使用拉普拉斯和高斯机制引入噪声的能力。此外,该框架还提供了对包括总和、计数、平均值、方差和标准差在内的聚合差分隐私算法的支持。此框架中的库是用 C++、Java 和 Go 语言实现的,并且它还提供了一个 命令行界面 (CLI) 来执行差分隐私 SQL 查询。有关更多信息,您可以访问 GitHub 仓库 github.com/google/differential-privacy。
PyDP 是由 OpenMined 于 2020 年开发的另一个框架,它实现了 Google 差分隐私工具的 Python 包装函数。虽然 PyDP 不是 Google 差分隐私工具包的完整实现,但它支持 Google 工具包中ε-差分隐私算法的一个子集。这些算法能够生成包含私人或敏感信息的数值数据集的聚合统计信息。您可以在github.com/OpenMined/PyDP找到 PyDP 框架。
PyDP 的实际应用示例和演示
PyDP 的安装
PyDP 的安装方式与其他 Python 包的安装方式相同。
对于 Python 3.x 版本,请使用以下命令:
pip3 install python-dp
对于 Python 的早期版本,请使用以下行:
pip install python-dp
使用 PyDP 计算平均值的示例程序
PyDP 支持拉普拉斯噪声机制,并提供了一系列聚合函数,如求和、平均值、计数等。在计算平均值时,PyDP 需要提供以下限和上限值形式表示的界限。为此,PyDP 提供了一个名为BoundedMean的类,它提供了以下构造函数:
BoundedMean(epsilon: float, delta: float = 0, lower_bound: int, upper_bound)
BoundedMean(epsilon: float)
PyDP 中的BoundedMean类用于计算有界数据的差分隐私平均值。它利用 epsilon 和 delta 参数提供隐私保证。此类支持拉普拉斯噪声机制,向平均值计算中添加隐私保护噪声。
下面是演示有界平均值的示例代码:
源代码:Sample_Mean_Using_PyDP.ipynb
import pydp as dp
import numpy as np
from pydp.algorithms.laplacian import BoundedMean
#Generate simple data number from 1 to 10 in an array
data = np.arange(1,10,1)
# privacy budget as 0.6, delta as 0 and lower and upper bounds as 1 and 10
x = BoundedMean(0.6,0,1,10)
privacy_mean = x.quick_result(data)
mean = np.mean(data)
print("Data", data)
print("Normal Mean", mean)
print("Mean with differential privacy",privacy_mean )
这将产生以下输出:
Data [1 2 3 4 5 6 7 8 9]
Normal Mean 5.0
Mean with differential privacy 6.960764656372703
使用 PyDP 开发一个示例银行应用程序以展示差分隐私技术
在此应用场景中,我们以一家旨在与商家、公司和其他银行合作开展营销活动同时保护其客户敏感个人信息的金融银行为例。客户在两种不同场景下使用他们的信用卡或借记卡进行购买:在商家网点进行的线下交易,卡被物理刷过(称为卡面交易),以及在线交易,其中输入卡号、姓名、到期日期和 CVV 等卡详情(称为无卡交易)。目标是提供信用卡交易数据以支持活动,同时不泄露个人客户详情。
为了成功启动营销活动或忠诚度计划,银行需要共享某些交易细节,例如购买类型、交易量和与特定位置相关的交易价值。这些信息使银行能够与感兴趣的银行/商家合作,从而促进大规模产品销售并向客户发放福利。
在此背景下,我们将使用预定义的业务规则合成大量交易,并计算每个位置的计数、平均值和总和等统计数据。目的是在不损害客户隐私的情况下,与合作伙伴公司共享这些汇总统计数据。
共有两种方法来共享这些统计数据。第一种方法涉及直接共享汇总数据,这可能会泄露有关个别客户的私人信息。第二种方法利用差分隐私来生成汇总数据,确保在保护隐私的同时不泄露任何敏感客户信息。
通过应用差分隐私技术,银行可以通过向汇总统计数据引入精心校准的噪声来保护客户隐私。这种噪声确保共享的汇总数据不会披露特定个人的详细信息,同时仍为营销活动和忠诚度计划规划提供有价值的见解。
通过采用差分隐私,银行可以在数据效用和隐私保护之间取得平衡,使其能够在与公司和企业合作的同时保持客户信息的机密性。
让我们生成开发此银行应用程序所需的合成数据集。
以下为客户数据:

图 5.1 – 客户数据集
在此背景下使用的数据集包括各种属性,包括客户 ID、表示为经纬度坐标的位置、每天的交易次数和平均交易金额。需要注意的是,与每个客户的卡关联的实际信用卡号、卡验证值(CVV)代码和到期日期保存在单独的表中,并且不在提供的数据集中显示。此外,这些参数在生成统计数据时并未使用。在此特定示例中,生成的交易涉及在各个商家位置发生的卡面交易场景,使用销售点(POS)终端刷卡。
以下为样本 POS 终端数据:

图 5.2 – 终端数据集
在此场景中,假设客户主要访问附近的商家门店进行日常购买,客户位置与商家位置之间的距离通常在约 5 英里范围内。
为了生成交易,计算客户位置与可用商家位置之间的欧几里得距离。使用这些距离信息,从附近的选项中随机选择商家。这种方法确保生成的交易反映了客户在特定距离半径内前往附近商家购买的现实行为。
以下为交易数据:

图 5.3 – 交易数据集
让我们使用差分隐私在此数据集上生成聚合数据,以便随后与商家/银行共享,以便设计营销活动和忠诚度计划。
来源 代码:Sample_Finance_App_DP.ipynb
# 解压 transactions.csv.zip 文件(本书 GitHub 仓库中提供 作为 transactions.csv)。
数据加载:
import pydp as dp
from pydp.algorithms.laplacian import BoundedSum, BoundedMean, Count, Max
import pandas as pd
url = "transactions.csv"
df_actual = pd.read_csv(url, sep=",")
df = df_actual[['TRANSACTION_ID',
'TX_DATETIME','CUSTOMER_ID','TERMINAL_ID','TX_AMOUNT']]
df.head()

图 5.4 – 示例交易数据
在本节中,我们将为各种场景生成不同的差分隐私聚合数据。重点将放在比较使用传统统计方法获得的结果与通过差分隐私技术实现的结果。以下场景将被探讨:
-
指定终端的平均交易金额
-
终端 ID 1 至 100 的平均交易金额
-
通过终端 1 至 100 购买价值 25 美元或以上的客户数量
-
指定终端的最大交易金额
-
指定日或月每个终端的交易金额总和
指定终端的平均交易金额
为了通过特定的 POS 终端计算指定日或月的平均交易金额,我们可以定义以下方法。这些方法将用于比较使用传统统计方法获得的结果与通过差分隐私技术生成的聚合结果:
-
传统平均计算:我们将实现一种方法,使用传统统计方法计算特定 POS 终端在指定日或月的平均交易金额。此方法将输入相关的交易数据,例如交易金额和感兴趣的日或月日期。平均将通过将所有交易金额相加并除以所选 POS 终端在指定日或月上的总交易次数来计算。传统的平均数将作为比较的基准。
-
差分隐私平均计算:我们将开发一种利用差分隐私技术来计算选定 POS 终端给定一天或一个月的平均交易金额的方法。此方法将采用与传统平均计算方法相同的输入。它将利用差分隐私机制,如向汇总统计数据添加噪声,以保护个人交易的隐私,同时生成平均值。差分隐私平均将提供一种保护隐私的传统平均值的替代方案。通过使用这些方法并比较结果,我们可以评估传统平均计算与通过差分隐私技术生成的平均值的差异。
此分析将展示差分隐私对汇总计算的影响,并强调在特定 POS 终端通过一天或一个月生成平均交易金额时在准确性和隐私保护之间的权衡:
def mean_tx_amount(tid:int) -> float:
dft = df[df["TERMINAL_ID"] == tid]
return statistics.mean(list(dft["TX_AMOUNT"]))
mean_tx_amount(1)
56.22097378277154
# calculates mean applying differential privacy
def private_mean_tx_amount(privacy_budget: float, tid:int) -> float:
x = BoundedMean(privacy_budget,1,1,300)
dft = df[df["TERMINAL_ID"] == id]
return x.quick_result(list(dft["TX_AMOUNT"]))
private_mean_tx_amount(0.6,1)
220.98103940917645
在先前的计算中,我们可以看到使用传统方法生成的平均值为 56.22,而差分隐私版本为 POS 终端 ID 1 生成平均值为 220.98。这样,私有平均值有助于不泄露实际的平均值。
终端 ID 1 到 100 的平均交易金额
让我们生成终端 1 到 100 的平均交易金额,并使用之前定义的私有平均函数:
terminal_mean_vs_privacy_means=[]
for i in range (1, 100):
mean = mean_tx_amount(i)
privacy_mean = private_mean_tx_amount(0.9,i)
terminal_mean_vs_privacy_means.append([i, mean,privacy_mean])
terminal_mean_vs_privacy_means_df =
pd.DataFrame(terminal_mean_vs_privacy_means,
columns=['Terminal Id','Mean','privacy_mean'])
terminal_mean_vs_privacy_means_df.head(10)

图 5.5 – 实际平均值与隐私平均值
在接下来的章节中,我们还将生成特定 POS 终端在给定一天或一个月的交易金额的计数和总和,并将使用传统统计方法获得的结果与通过差分隐私技术生成的结果进行比较。
通过终端 1 到 100 进行购买价值 25 美元或以上的客户数量
接下来,我们将实施一种计算终端 1 到 100 上进行 25 美元或以上购买的客户数量的方法。
此方法将以交易数据作为输入,包括终端号和相应的交易金额。它将遍历每个终端 ID 从 1 到 100 的交易,并计算交易金额超过 25 美元的客户数量。这个计数将提供有关进行了高价值购买的客户基础的指示,有助于分析差分隐私对识别此类客户的影响。通过使用此方法,我们可以比较使用传统统计方法获得的结果与通过差分隐私技术生成的计数。
这项分析将揭示不同方法之间的差异,并展示差分隐私在识别终端 1 到 100 上进行了价值超过 25 美元购买的客户时的有效性,同时保护个人隐私:
def count_tx_amount_above(limit: float,tid) -> int:
dft = df[df["TERMINAL_ID"] == tid]
return dft[dft.TX_AMOUNT > limit].count()[0]
count_tx_amount_above(25.0,1)
232
def private_tx_amount_above(privacy_budget: float, limit: float,tid:int) -> float:
dft = df[df["TERMINAL_ID"] == tid]
x = Count(privacy_budget, dtype="float")
return x.quick_result(list(dft[dft.TX_AMOUNT > limit]["TX_AMOUNT"]))
private_tx_amount_above(0.1,25.0,1)
257
terminal_amount_vs_privacy_amont=[]
for i in range (1, 100):
count = count_tx_amount_above(25.0,i)
privacy_count = private_tx_amount_above(0.1,25.0,i)
terminal_amount_vs_privacy_amont.append([i, count,privacy_count])
terminal_amount_vs_privacy_amont_df =
pd.DataFrame(terminal_amount_vs_privacy_amont, columns=['Terminal Id','Count','privacy_count'])
terminal_amount_vs_privacy_amont_df.head(10)

图 5.6 – 实际交易次数与增加的隐私次数对比
通过采用这种方法,我们确保不会泄露或与银行/商家共享实际购买价值超过 25 美元的客户数量。相反,我们向这些方提供差分隐私计数,从而在提供有价值的见解的同时保护个人隐私。这使得银行/商家可以根据差分隐私计数启动忠诚度计划,根据可用数据定制他们的倡议。因此,通过采用差分隐私技术,机构可以在为忠诚度计划提供有用信息和保护单个客户敏感细节之间取得平衡。
给定终端的最大交易金额
让我们定义计算最大交易金额和差分隐私金额的函数:
def max_tx_amount(tid:int) -> int:
dft = df[df["TERMINAL_ID"] == tid]
return dft.max()["TX_AMOUNT"]
max_tx_amount(1)
87
def private_max_tx_amount(privacy_budget: float,tid:int) -> int:
dft = df[df["TERMINAL_ID"] == tid]
x = Max(epsilon = privacy_budget, lower_bound = 100.0, upper_bound = 50000.0, dtype="float"
return x.quick_result(list(dft["TX_AMOUNT"]))
private_max_tx_amount(0.5,1)
167.51941105013407
如前述代码所示,通过采用差分隐私技术,我们可以在保护单个交易隐私的同时,计算给定终端的大致最大交易金额。这些值取决于隐私预算。本例中使用了 0.5 作为隐私预算。这使我们能够在不泄露单个客户敏感细节的情况下,与银行/商家分享有价值的汇总信息。在本例中,实际的最大交易金额为 87。根据隐私预算(即 0.5)添加的噪声,该值变为 167。因此,在效用方面可能不太有用。这说明了隐私与效用之间的权衡。需要通过实验不同的隐私预算来决定最适合用例/应用的方案,决定是更优先考虑隐私和较少的效用,还是更优先考虑效用和较少的隐私。
每个终端在给定日期或月份的交易金额总和
让我们定义计算交易金额总和以及差分隐私金额总和的函数:
def sum_tx_amount(tid:int) -> float:
dft = df[df["TERMINAL_ID"] == tid]
return dft.sum()["TX_AMOUNT"]
sum_tx_amount(1)
15011
def private_sum_tx_amount(privacy_budget: float, tid:int) -> float:
dft = df[df["TERMINAL_ID"] == tid]
x = BoundedSum(epsilon = privacy_budget, delta = 0,
lower_bound= 100.0, upper_bound = 50000.0, dtype="float")
return x.quick_result(list(dft["TX_AMOUNT"]))
private_sum_tx_amount(0.6,1)
27759.46144104004
作为练习,你可以实现所有 POS 终端上的 count 和 sum 函数,并将使用传统统计方法获得的结果与通过差分隐私技术生成的结果进行比较。
防御成员推理攻击
成员推理攻击对机器学习系统中个人的隐私构成重大威胁。这些攻击旨在确定特定数据点是否是用于创建机器学习模型的训练数据集的一部分,可能暴露有关个人的敏感信息。为了减轻此类攻击的风险,可以采用差分隐私技术。
为了抵御使用差分隐私的成员推理攻击,可以采用以下几种方法:
-
噪声添加:在训练过程中,向计算中添加噪声以引入随机性和掩盖单个数据点。这使得攻击者难以识别特定数据点是否被用于训练。
-
隐私预算管理:差分隐私在隐私预算下运行,该预算决定了允许的最大隐私损失量。通过仔细管理和分配隐私预算,可以最大限度地降低成员推断攻击的风险。
-
泛化和聚合:应用泛化和聚合技术有助于模糊单个数据点。通过将相似的数据点分组在一起,任何特定个人的信息变得不那么容易区分。
-
扰动机制:利用扰动机制,例如向模型的输出或梯度添加噪声,可以增强隐私保护。这些机制使得攻击者更难以准确推断成员资格状态。
-
对抗训练:结合对抗训练技术有助于训练对成员推断攻击具有鲁棒性的模型。这涉及到训练模型以对抗一个复杂的攻击者,该攻击者试图区分特定数据点的存在。
通过结合这些策略并采用隐私设计方法,机器学习系统可以更好地保护免受成员推断攻击。需要注意的是,虽然差分隐私提供了强大的隐私保证,但在某些情况下,可能还需要额外的隐私保护技术或后处理来应对特定的攻击场景。
下面是一个示例来演示这一点:
让我们生成两个数据集,它们正好相差一条记录。我们将创建原始数据集的副本,并将其称为红 acted 数据集。在红 acted 数据集中,我们将删除一条记录以创建差异。
下面是如何进行操作的说明:
-
从包含所需记录的原始数据集开始。这个数据集代表基线或完整的记录集。
-
创建原始数据集的副本并将其标记为redact_dataset。这个数据集将非常接近原始数据集,但会删除一条记录。从红 acted 数据集中选择任何记录并将其删除以创建差异。在示例中,第一条记录被删除。
通过将红 acted 数据集作为原始数据集的修改版本创建,特别是通过删除一条记录,我们建立了一个独特的数据集,该数据集与原始数据集的不同之处仅在于那条单一记录。
使用以下源代码创建一个红 acted 版本。
源代码:Sample_Finance_App_DP.ipynb
import pandas as pd
url = "2023-07-08.csv"
df = pd.read_csv(url, sep=",")
redact_dataset = df.copy()
redact_dataset = redact_dataset[1:]
df.head()

图 5.7 - 示例交易数据集
redact_dataset.head()

图 5.8 – 红 act 数据集
我们已从原始数据集中删除了一条记录(客户 ID 2079),该客户进行了 36 美元的交易。这是为了形成编辑后数据集。
让我们计算原始数据集和编辑后数据集的交易金额总和,以确定差异。这个差异将对应于客户 ID 2079 实际进行的交易金额:
sum_original_dataset = round(sum(df["TX_AMOUNT"].to_list()), 2)
sum_redact_dataset =
round(sum(redact_dataset["TX_AMOUNT"].to_list()), 2)
tx_amount_2079 = round((sum_original_dataset - sum_redact_dataset), 2)
tx_amount_2079
36
让我们应用差分隐私技术来计算原始数据集和编辑后数据集的交易金额总和。这两个总和之间的差异不应揭示客户 ID 2079 实际进行的交易金额。以下是您可以采取的方法:
在原始数据集上使用差分隐私计算的总和:
dp_sum_original_dataset = BoundedSum(
epsilon=1, lower_bound=1.0, upper_bound=500.0, dtype="float"
)
dp_sum_original_dataset.reset()
dp_sum_original_dataset.add_entries(
df["TX_AMOUNT"].to_list()
)
dp_sum_og = round(dp_sum_original_dataset.result(), 2)
print(dp_sum_og)
1300958.19
在编辑后数据集上使用差分隐私计算的总和:
dp_redact_dataset = BoundedSum(epsilon=1, lower_bound=1.0, upper_bound=500.0, dtype="float")
dp_redact_dataset.add_entries(redact_dataset["TX_AMOUNT"].to_list())
dp_sum_redact = round(dp_redact_dataset.result(), 2)
print(dp_sum_redact)
1302153.33
使用差分隐私计算的两个数据集之间的差异:
round(dp_sum_og - dp_sum_redact, 2)
-1195.14
在本例中,当使用差分隐私计算原始数据集和编辑后数据集的交易金额总和时,这两个总和之间的差异产生了负数。然而,重要的是要注意,这些负值并不代表客户 ID 2079 实际进行的交易金额。
差分隐私计算过程中引入的固有噪声导致差异值中出现负值。差分隐私技术通过引入随机化来保护个人隐私,而这种随机噪声有时会导致汇总结果中出现负扰动。
因此,正确解释这些负值至关重要。它们不应被视为客户 ID 2079 实际进行的交易金额,而应被视为差分隐私机制成功引入噪声以保护个人隐私并提供了近似汇总结果的指示。
理解这一点至关重要,即差分隐私侧重于保护隐私,而不是计算结果的精确性。负差异值作为差分隐私提供的隐私保证的提醒,确保即使在汇总计算的情况下,个人交易细节也得到了保护。
将差分隐私应用于大数据集
在前面的例子中,我们专注于在较小的数据集上计算差分隐私汇总(如计数、总和和平均值),这些数据集涉及单个终端或有限数量的终端。然而,在本节中,我们将探讨如何在包含数百万甚至数十亿条记录的大数据集上生成差分隐私汇总。具体来说,我们将考虑一个涉及约 500 万张信用卡交易数据集的用例,这些交易发生在 1,000 个销售终端和 5,000 名客户之间。
用例 - 在大数据集上生成差分隐私汇总
让我们生成包含在 1,000 个 POS 终端上按日记录的信用卡交易的数据库。这些交易涉及总共 5,000 名客户,结果是一个大约 5 百万条记录的庞大集合。
要计算如此大数据集的差异隐私聚合,需要采用专门的技术和框架来处理数据的规模和复杂性。这些技术确保在提供有意义的聚合统计信息的同时保护隐私。
通过在大数据集上利用差异隐私,组织可以在不损害单个客户隐私的情况下提取有价值的见解。生成的差异隐私聚合允许数据驱动的决策和分析,同时保护敏感信息。值得注意的是,用于在大数据集上应用差异隐私的方法和框架可能因具体要求和可用资源而异。数据分区、并行处理和优化算法等技术在大规模数据集上高效计算差异隐私聚合中起着至关重要的作用。
通过了解如何在大数据集上生成差异隐私聚合,组织可以从其数据中提取可操作的见解,同时维护交易涉及的个人的隐私。数据集按特定格式组织,每天的交易存储在包含日期的单独文件中。为了说明,让我们考虑一个示例,其中数据集对应于 2022 年 2 月 1 日的交易。该天的文件使用以下格式:
文件名:2022-02-01.csv
文件名由特定日期按YYYY-MM-DD格式组成。在这种情况下,2022-02-01代表文件中包含的交易日期。
文件的实际内容将是该特定日期的交易数据,包括客户 ID、交易金额、POS 终端 ID 以及其他任何相关信息。
这种文件格式,其中每天的交易存储在单独的文件中,文件名包含日期,有助于按时间顺序组织和管理工作集。
它使得从特定日期检索和分析交易数据变得容易,从而便于基于时间的分析和报告任务:
| 交易 ID | 交易时间 | 客户 ID | 终端 ID | 交易金额 |
|---|---|---|---|---|
| 0 | 2023-02-01 00:43:37 | 901 | 8047 | 82 |
| 1 | 2023-02-01 01:20:13 | 2611 | 7777 | 15 |
| 2 | 2023-02-01 01:22:52 | 4212 | 3336 | 53 |
| 3 | 2023-02-01 01:26:40 | 1293 | 7432 | 59 |
| 4 | 2023-02-01 01:52:23 | 2499 | 1024 | 25 |
| 5 | 2023-02-01 02:11:03 | 2718 | 168 | 68 |
| 6 | 2023-02-01 02:11:56 | 2998 | 5513 | 80 |
表 5.1 – 交易数据的前几行
| 交易 ID | 交易时间 | 客户 ID | 终端 ID | 交易金额 |
|---|---|---|---|---|
| 24901 | 2023-02-02 01:34:52 | 4999 | 4536 | 43 |
| 24902 | 2023-02-02 01:44:39 | 580 | 3511 | 29 |
| 24903 | 2023-02-02 01:48:04 | 3309 | 7661 | 50 |
| 24904 | 2023-02-02 01:58:12 | 2919 | 5322 | 94 |
| 24905 | 2023-02-02 02:07:07 | 3868 | 3217 | 97 |
| 24906 | 2023-02-02 02:08:43 | 1822 | 489 | 15 |
表 5.2 – 交易数据的最后几行
对于我们的用例场景,核心练习是创建差分隐私聚合,让我们假设系统接收覆盖数月的数据,目标是为每个 POS 终端生成差分隐私聚合的交易数据。
| POS 终端 | 差分 隐私聚合 |
|---|---|
| 计数 | |
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| .. |
表 5.3 – 差分隐私聚合
虽然使用 Pytorch、pandas 和 PyDP 等框架可以有效地生成差分隐私聚合,但确实,仅使用这些方法处理大量数据可能耗时且不可扩展。然而,有其他方法和工具可供选择,以应对这些挑战。
这些方法包括以下内容:
-
并行处理:我们可以利用并行处理技术将计算分布在多个处理器或机器上。这可以显著减少处理时间,并在处理大量数据时实现可扩展性。
-
分布式计算:我们可以采用 Apache Spark 或 Hadoop 等分布式计算框架来处理大数据。这些框架提供了分布式数据处理能力,允许高效处理大规模数据集。
-
云计算:我们可以利用如亚马逊网络服务(AWS)或谷歌云平台(GCP)这样的云计算平台来利用可扩展基础设施的力量。这些平台提供如 Amazon EMR、Google Dataproc 或 Azure HDInsight 等服务,可以以成本效益和可扩展的方式处理大规模数据处理。
-
优化后的差分隐私库:我们可以探索专门设计的差分隐私库,例如 PipelineDP、TensorFlow Privacy 或 Opacus,这些库旨在提供高效且可扩展的差分隐私算法实现。这些库提供了针对隐私保护计算的优化,使得处理更快、更可扩展。
-
数据分区和预聚合:我们可以将数据划分为可管理的分区,并执行预聚合以减少整体计算负载。这种方法通过最小化每一步处理的数据量来提高性能。
通过结合这些方法和工具,可以在生成差分隐私聚合时克服处理大数据集的挑战。这些方法可以显著减少处理时间并提高可扩展性,使组织能够高效地分析和从其数据中提取见解,同时保护隐私。
以下是一些需要考虑的问题/设计:
-
你如何在大数据集上解决或生成 DP 聚合?
-
你如何对数据进行分区?(例如,基于日期或基于 POS 终端的分区)
-
你如何在给定的分区内应用 DP?
-
你如何找出最大和最小值界限来计算(剪辑)函数
-
我们是否应该在分区中的每个数据值上应用 DP(界限/敏感性)以生成 DP 聚合?或者
-
我们应该先生成统计聚合,然后再在分区内应用 DP 吗?
-
PipelineDP 高级架构
PipelineDP 框架旨在解决在生成大数据集的差分隐私聚合时提到的先前问题和考虑因素。
PipelineDP (pipelinedp.io) 是一个开源框架,它支持使用开源框架(如 Apache Spark 和 Apache Beam)在大数据集上生成差分隐私聚合。PipelineDP 框架由 Google 与 OpenMined 合作开发。截至撰写本书时,PipelineDP 团队声明此框架不建议用于生产部署,但被认为足够用于开发模式和演示目的,以增强你的理解。

图 5.9 – PipelineDP 架构
PipelineDP 提供三种模式的 API(Apache Spark、Apache Beam 和本地模式)以及通过 DP 引擎访问其相应实现的方式。
这里是 PipelineDP 中使用的核心概念:

图 5.10 – 示例展示样本数据的隐私单元、隐私-id 和分区键
-
记录是 PipelineDP 中输入数据集中的元素。
-
分区是数据的一个子集,对应于聚合标准的给定值。在我们的案例中,我们想要每个 POS 终端的结果,因此分区将是TERMINAL_D。
-
分区键是对应于分区的聚合键。在本例中,TERMINAL_D 是分区键。
-
隐私单元是我们想要使用差分隐私保护的实体。
-
隐私 ID是隐私单元的标识符。在我们的例子中,CUSTOMER_ID 是隐私 ID。
现在我们已经了解了高级架构和关键概念,让我们使用 PipelineDP 在大数据集上实现差分隐私。
以下代码行安装 PipelineDP 框架。
pip install PipelineDP
源代码: Large_Data_Sets-DP_PipelineDP.ipynb
Import pipeline_dp
Import pandas as pd
Import numpy as np
url ="transactions.csv"
df_actual = pd.read_csv(url, sep=",")
df_transactions = df_actual[['TRANSACTION_ID', 'TX_DATETIME','CUSTOMER_ID','TERMINAL_ID','TX_AMOUNT']]
df_transactions

图 5.11 – 交易数据
rows =
[index_row[1] for index_row in transactions_df.iterrows()]
以下代码将生成每个终端的不同隐私计数(客户总数):
#In this example we use a local backend, but Spark and Apache #backends also can be tried in a similar way by making use of the provided classes.
backend = pipeline_dp.LocalBackend()
# Define the total budget.
budget_accountant = pipeline_dp.NaiveBudgetAccountant(total_epsilon=1, total_delta=1e-6)
# Create DPEngine which will execute the logic to generate the aggregates
dp_engine = pipeline_dp.DPEngine(budget_accountant, backend)
# Define privacy ID, partition key, and aggregated value extractors.
# The aggregated value extractor isn't used for Count aggregates, but this is required for SUM, AVERAGE aggregates
data_extractors = pipeline_dp.DataExtractors(
partition_extractor=lambda row: row.TERMINAL_ID,
privacy_id_extractor=lambda row: row.CUSTOMER_ID,
value_extractor=lambda row: 1)
# Configure the aggregation parameters. Number of partitions is 10000 because the number of terminals is 10,000
params = pipeline_dp.AggregateParams(
noise_kind=pipeline_dp.NoiseKind.LAPLACE,
metrics=[pipeline_dp.Metrics.COUNT],
max_partitions_contributed=100,
max_contributions_per_partition=10)
public_partitions=list(range(1, 10000))
#Create a computational graph for the aggregation.
dp_result = dp_engine.aggregate(rows, params, data_extractors, public_partitions)
#Compute budget per each DP operation.
budget_accountant.compute_budgets()
dp_result = list(dp_result)
dp_dict=dict(dp_result)
myKeys = list(dp_dict.keys())
myKeys.sort()
sorted_dict = {i: dp_dict[i] for I in myKeys}
print(sorted_dict)
dp_count = [0] * 100
for count_sum_per_day in dp_result:
index = count_sum_per_day[0] – 1
dp_count[index] = count_sum_per_day[1][0]
print(dp_count[index])
现在生成实际的计数并与差分隐私计数进行比较:
df_counts = df_transactions.groupby(by='TERMINAL_ID').agg('count')
df_counts

图 5.12 – 交易聚合
通过利用 PipelineDP 框架,我们可以解决生成大型数据集的差分隐私聚合所涉及到的挑战和考虑因素。它提供了一个综合的解决方案,结合了可扩展性、隐私保护和精确聚合,使我们能够有效地利用差分隐私技术进行大规模数据分析。
Tumult Analytics
Tumult Analytics 是一个功能丰富且健壮的 Python 库,旨在执行表格数据的聚合查询,同时确保差分隐私的原则。该库提供了一个直观的界面,使得熟悉 SQL 或 PySpark 的用户能够使用。它提供了一系列的聚合函数、数据转换操作符和隐私定义,确保在分析任务中的多功能性。由差分隐私领域的专家团队开发和维护,Tumult Analytics 保证可靠性,甚至被像美国人口普查局这样的知名机构在生产环境中使用。由 Spark 驱动,该库展示了卓越的可扩展性,能够高效处理大型数据集。凭借其全面的功能和对隐私保护的重视,Tumult Analytics 是一个专注于维护数据隐私的数据分析的有价值工具。
以下是对 Tumult Analytics 开源框架的引用:
@software{tumultanalyticssoftware,
author = {Tumult Labs},
title = {Tumult {{Analytics}}},
month = dec,
year = 2022,
version = {latest},
url = {https://tmlt.dev}
}
Tumult Analytics 安装
要使用 Tumult Analytics,必须安装 Python,因为该库是用 Python 构建的。它与 Python 版本 3.7 到 3.10 兼容。此外,由于 Tumult Analytics 使用 PySpark 进行计算,因此还需要安装 Java 8 或 11。
以下代码安装 Tumult Analytics 框架。
pip3 install tmlt.analytics
Tumult Analytics 的关键特性
Tumult Analytics 提供了类和方法,用于在大型数据集上使用差分隐私构建聚合。以下是一些高级类:
| 类 | 方法 |
|---|---|
| Session(tmlt.analytics.session) | Session 模块提供了一个方便的接口来管理数据源并对它们执行差分隐私查询。创建会话很简单,使用 Session.from_dataframe() 来创建一个涉及单个私有数据源的简单会话,或者使用 Session.Builder 来处理涉及多个数据源的更复杂场景。一旦会话设置完成,就可以使用 Session.evaluate() 在数据上执行查询。当初始化 Session 的实例类型时,指定 PrivcyBudget 以确保在私有数据上执行的查询不超过此分配的预算。默认情况下,Session 实例在行级别强制执行隐私保护。这意味着查询阻止任何潜在的攻击者推断出是否将单个行添加或从私有表中删除。然而,这个隐私保证仅适用于查询本身,并假设私有数据在计算过程中没有在其他地方使用。 |
| PureDPBudget(tmlt.analytics.privacy_budget ) | 提供纯差分隐私的隐私预算。 |
| ApproxDPBudgettmlt.analytics.privacy_budget ) | 提供近似差分隐私的隐私预算。 |
| QueryBuilder(tmlt.analytics.query_builder) | 一个用于指定 DP 查询的高级接口。QueryBuilder 类可以应用转换,如连接或过滤,以及计算包括计数、总和和标准差在内的聚合。 |
| KeySet(tmlt.analytics.keyset) | KeySet 指定一个或多个列的值列表。目前,KeySets 被用作指定 groupb``y 转换域的更简单方式。 |
表 5.4 – tmlt.analytics.session 描述
使用 Tumult Analytics 的示例应用
让我们使用 tmlt-analytics 在上一节中使用的大型数据集(即我们的交易数据)上生成聚合数据。
源代码:DP_Large_Data_Sets_TMLT.ipynb
让我们按照以下方式导入所需的 Python 包:
import os
from pyspark import SparkFiles
from pyspark.sql import SparkSession
from tmlt.analytics.privacy_budget import PureDPBudget
from tmlt.analytics.protected_change import AddOneRow
from tmlt.analytics.query_builder import QueryBuilder
from tmlt.analytics.session import Session
接下来,初始化 Spark 会话:
spark = SparkSession.builder.getOrCreate()
让我们加载包含信用卡交易信息的数据集。我们从本地目录获取数据并将其加载到 Spark DataFrame 中:
#创建一个下载目录并解压 transactions.csv.zip 文件以复制 transactions.csv 文件:
spark.sparkContext.addFile(
"/downloads/transactions.csv")
trans_df = spark.read.csv(
SparkFiles.get("/downloads/transactions.csv"), header=True, inferSchema=True
)
trans_df.head(5)
[Row(_c0=0, TRANSACTION_ID=0, TX_DATETIME=datetime.datetime(2023, 2, 1, 0, 43, 37), CUSTOMER_ID=901, TERMINAL_ID=8047, TX_AMOUNT=82, TX_TIME_SECONDS=2617, TX_TIME_DAYS=0),
Row(_c0=1, TRANSACTION_ID=1, TX_DATETIME=datetime.datetime(2023, 2, 1, 1, 20, 13), CUSTOMER_ID=2611, TERMINAL_ID=7777, TX_AMOUNT=15, TX_TIME_SECONDS=4813, TX_TIME_DAYS=0),
Row(_c0=2, TRANSACTION_ID=2, TX_DATETIME=datetime.datetime(2023, 2, 1, 1, 22, 52), CUSTOMER_ID=4212, TERMINAL_ID=3336, TX_AMOUNT=53, TX_TIME_SECONDS=4972, TX_TIME_DAYS=0),
Row(_c0=3, TRANSACTION_ID=3, TX_DATETIME=datetime.datetime(2023, 2, 1, 1, 26, 40), CUSTOMER_ID=1293, TERMINAL_ID=7432, TX_AMOUNT=59, TX_TIME_SECONDS=5200, TX_TIME_DAYS=0),
Row(_c0=4, TRANSACTION_ID=4, TX_DATETIME=datetime.datetime(2023, 2, 1, 1, 52, 23), CUSTOMER_ID=2499, TERMINAL_ID=1024, TX_AMOUNT=25, TX_TIME_SECONDS=6743, TX_TIME_DAYS=0)]
启动 tmlt-analytics 会话
Session by wrapping a DataFrame containing private data using the from_dataframe() method:
session = Session.from_dataframe(
privacy_budget=PureDPBudget(3.5),
source_id="transactions",
dataframe=trans_df,
protected_change=AddOneRow(),
)
当会话使用有限的隐私预算初始化时,它提供了一个直接的接口承诺:在这个会话上执行的查询,总体上,将产生具有最大 epsilon 值 3.5 的差分隐私结果。Epsilon 是衡量潜在隐私损失的一个指标,较低的 epsilon 表示对隐私损失有更严格的限制,从而提供更高的保护水平。在这种情况下,接口承诺对应于隐私保证,确保对私有数据有最低级别的保护。
除了数据本身之外,还需要一些额外的信息:
-
隐私预算参数指定了会话将提供的隐私保证。
-
source_id参数作为 DataFrame 的标识符。它将被用来在构建查询时引用这个特定的 DataFrame。
-
protected_change参数定义了差分隐私保证应用的数据单元。在这个例子中,AddOneRow()用于保护数据集中的单个行。
使用 Session 执行 DP 查询
我们第一次查询是在启用 DP 的情况下找到数据中的总交易数量:
count_query = QueryBuilder("transactions").count()
要在所需私有数据上执行查询,我们在第一步使用 QueryBuilder("transactions"),这表示我们想要查询的特定源数据(数据源),对应于之前指定的 source_id 参数。在下一行,使用 count() 语句检索数据集中的总记录数。一旦构建了查询,我们就通过使用会话的 evaluate 方法在数据上运行它。为此,我们将隐私预算分配给评估过程。在这种情况下,我们使用差分隐私评估查询,将 ε=1 设置为隐私参数:
total_count = session.evaluate(
count_query,
privacy_budget=PureDPBudget(epsilon=1)
)
查询的结果以 Spark DataFrame 的形式返回。我们可以使用这个 DataFrame 的 show() 方法来查看它们。我们为这个查询使用了 3.5 个隐私预算中的 1 个,所以剩余的隐私预算将是 2.5:
total_count.show()
+-------+
| count|
+-------+
|4557168|
+-------+
如果你正在跟随示例并执行代码,你可能会观察到不同的值。这种变化是差分隐私的基本方面,因为它在查询执行期间引入了随机化(称为噪声)。为了展示这一特性,让我们再次评估相同的查询并查看结果。
查询计算中添加的噪声量可能取决于隐私参数、聚合类型和基础数据。然而,在许多情况下,查询结果仍然提供了对原始数据的可靠见解。在这个特定场景中,我们可以通过直接在原始 DataFrame 上执行计数查询来确认这一点,这将产生真实和准确的结果:
total_count = trans_df.count()
print(total_count)
4557166
玩转隐私预算
描述会话对象以了解其属性和剩余的隐私预算。
session.describe()
The session has a remaining privacy budget of PureDPBudget(epsilon=2.5).
The following private tables are available:
Table 'transactions' (no constraints):
Columns:
- '_c0' INTEGER
- 'TRANSACTION_ID' INTEGER
- 'TX_DATETIME' TIMESTAMP
- 'CUSTOMER_ID' INTEGER
- 'TERMINAL_ID' INTEGER
- 'TX_AMOUNT' INTEGER
- 'TX_TIME_SECONDS' INTEGER
- 'TX_TIME_DAYS' INTEGER
利用隐私预算进行隐私查询
让我们找出购买金额低于 25 美元的客户数量。
此查询消耗了我们的总预算中的 epsilon=1:
low_purchagers= QueryBuilder("transactions").filter("TX_AMOUNT < 25").count()
low_purchagers_count = session.evaluate(
low_purchagers,
privacy_budget=PureDPBudget(epsilon=1),
)
low_purchagers_count.show()
+-------+
| count|
+-------+
|1024844|
+-------+
print(session.remaining_privacy_budget)
PureDPBudget(epsilon=1.5)
我们已经使用了剩余总隐私预算中的 1 个单位,所以还剩下 1.5 个单位。让我们尝试另一个查询来消耗另一个 1 个单位的隐私预算:
让我们找出购买金额大于 25 美元但小于 50 美元的客户数量。
med_purchagers= QueryBuilder("transactions").filter("TX_AMOUNT >25 AND TX_AMOUNT <50").count()
med_purchagers_count = session.evaluate(
med_purchagers,
privacy_budget=PureDPBudget(epsilon=1),
)
med_purchagers_count.show()
+-------+
| count|
+-------+
|1165384|
+-------+
print(session.remaining_privacy_budget)
PureDPBudget(epsilon=0.5)
我们已经使用了 3 个单位中的 3.5 个单位,所以还剩下 0.5 个单位。让我们尝试另一个查询来消耗 1 个单位的隐私预算(运行查询超过可用预算并观察结果)。
high_purchagers= QueryBuilder("transactions").filter("TX_AMOUNT > 50").count()
high_purchagers_count = session.evaluate(
high_purchagers,
privacy_budget=PureDPBudget(epsilon=1),
)
high_purchagers_count.show()
它将抛出以下运行时错误:
---------------------------------------------------------------------------
InsufficientBudgetError Traceback (most recent call last)
/usr/local/lib/python3.10/dist-packages/tmlt/analytics/session.py in evaluate(self, query_expr, privacy_budget)
1283 try:
-> 1284 answers = self._accountant.measure(
1285 measurement, d_out=adjusted_budget.value
/usr/local/lib/python3.10/dist-packages/tmlt/core/measurements/interactive_measurements.py in measure(self, measurement, d_out)
1343 if not self._privacy_budget.can_spend_budget(d_out):
-> 1344 raise InsufficientBudgetError(
1345 self.privacy_budget,
InsufficientBudgetError: PrivacyAccountant's remaining privacy budget is 1/2, which is insufficient for this operation that requires privacy loss 1.
RuntimeError: Cannot answer query without exceeding the Session privacy budget.
Requested: ε=1.000
Remaining: ε=0.500
Difference: ε=0.500
让我们显示剩余的隐私预算,以便在后续查询中使用。
print(session.remaining_privacy_budget)
PureDPBudget(epsilon=0.5)
重新编写最后一个查询,使其能够利用剩余的可用预算,以便完全使用隐私预算,而不是浪费未使用的预算。在这种情况下,我们不会指定隐私预算为 1 或 2,而是将使用Session类本身的剩余隐私预算:
high_purchagers= QueryBuilder("transactions").filter("TX_AMOUNT > 50").count()
high_purchagers_count = session.evaluate(
high_purchagers,
privacy_budget=session.remaining_privacy_budget,
)
high_purchagers_count.show()
+-------+
| count|
+-------+
|2271804|
+-------+
通过应用差分隐私计算的高购买次数总数。
分组查询
在 Tumult Analytics 中,KeySet 类被用来定义分组键的列表。它允许我们指定我们打算按哪些列对数据进行分组,以及与这些列关联的潜在值。KeySet 类在 Tumult Analytics 中作为指定分组标准的一种便捷方式。
现在让我们编写一个查询来查找每个终端的平均交易金额(在这个例子中仅取前 10 个终端)。
创建一个隐私预算设置为 2.5 的会话:
budget = PureDPBudget(epsilon=2.5) # maximum budget consumed in the Session
session = Session.from_dataframe(
privacy_budget=budget,
source_id="transactions",
dataframe=trans_df,
protected_change=AddOneRow(),
)
使用KeySet类并定义分组列(TERMINAL_ID)或列和值,以进行过滤:
from tmlt.analytics.keyset import KeySet
terminal_ids = KeySet.from_dict({
"TERMINAL_ID": [
1,2,3,4,5,6,7,8,9,10
]
})
执行查询并提供剪裁TX_AMOUNT的下限和上限:
average_purchase_query = (
QueryBuilder("transactions")
.groupby(terminal_ids)
.average("TX_AMOUNT", low=5, high=100)
)
average_purchages= session.evaluate(
average_purchase_query,
privacy_budget=PureDPBudget(1),
)
average_purchages.show(truncate=False)
+-----------+------------------+
|TERMINAL_ID|TX_AMOUNT_average |
+-----------+------------------+
|1 |55.93609022556391 |
|2 |52.93446601941748 |
|3 |40.95974576271186 |
|4 |52.02414486921529 |
|5 |47.511428571428574|
|6 |52.276595744680854|
|7 |51.566233766233765|
|8 |50.12273641851107 |
|9 |52.88358208955224 |
|10 |48.98945147679325 |
+-----------+------------------+
这样,我们可以使用差分隐私生成汇总,确保它们与实际汇总不同。
使用隐私 ID 的查询
之前,我们专注于处理每个数据集中的个体都链接到单行表的表格。然而,这并不总是情况。在某些数据集中,同一个人可能出现在多个行中。在这种情况下,通常会给每个人分配一个唯一的标识符(即跨不同行)。目标随后转向隐藏与特定标识符关联的所有行是否都存在于数据中。
Tumult Analytics 将这些标识符称为隐私 ID。每个隐私 ID 与一个人或任何其他需要保护的实体进行一对一映射。目标是通过对数据集中存在的匿名性进行保护来保护个人或实体的隐私。这可以通过使用 AddRowsWithID 受保护更改来实现。此受保护更改将防止任意添加和删除许多具有相同 ID 的行。
使用隐私 ID 初始化会话:
from tmlt.analytics.protected_change import AddRowsWithID
budget = PureDPBudget(epsilon=2.5) # maximum budget consumed in the Session
session = Session.from_dataframe(
privacy_budget=budget,
source_id="transactions",
dataframe=trans_df,
protected_change=AddRowsWithID(id_column="CUSTOMER_ID"),
)
使用隐私 ID 执行查询:
keyset = KeySet.from_dataframe(
trans_df.select("TERMINAL_ID", "TX_AMOUNT")
)
count_query = (
QueryBuilder("transactions")
.groupby(keyset)
.count()
)
result = session.evaluate(count_query, PureDPBudget(1))
让我们执行此代码并观察输出:
RuntimeError: A constraint on the number of rows contributed by each ID is needed to perform this query (e.g. MaxRowsPerID).
此错误是由于缺少对单个个人可以向数据集贡献的行数的限制。单个客户可能进行许多交易,甚至超过 1,000 行或更多。然而,差分隐私需要通过引入统计噪声来隐藏个人数据的影响。
为了解决这个问题,有必要在执行聚合之前对单个客户对计算统计量的最大影响建立限制。此限制被应用于数据以减轻任何潜在的影响。最直接的约束,称为 MaxRowsPerID,限制了每个隐私 ID 贡献的总行数。为了强制执行此约束,我们可以简单地将它作为参数传递给 enforce() 操作。对于当前的具体查询,我们将设置每个图书馆成员贡献的最大行数为 100:
from tmlt.analytics.constraints import (
MaxGroupsPerID,
MaxRowsPerGroupPerID,
MaxRowsPerID,
)
keyset = KeySet.from_dataframe(
trans_df.select("TERMINAL_ID", "TX_AMOUNT")
)
count_query = (
QueryBuilder("transactions")
.enforce(MaxRowsPerID(100))
.groupby(keyset)
.count()
)
result = session.evaluate(count_query, PureDPBudget(1))
top_five = result.sort("count", ascending=False).limit(5)
top_five.show()
+-----------+---------+-----+
|TERMINAL_ID|TX_AMOUNT|count|
+-----------+---------+-----+
| 3001| 98| 1240|
| 3536| 42| 1217|
| 4359| 71| 1212|
| 9137| 97| 1145|
| 7179| 76| 1143|
+-----------+---------+-----+
result.show()
+-----------+---------+-----+
|TERMINAL_ID|TX_AMOUNT|count|
+-----------+---------+-----+
| 0| 4| 401|
| 0| 7| 224|
| 0| 11| -7|
| 0| 12| 131|
| 0| 16| -35|
| 0| 18| -68|
| 0| 20| -126|
| 0| 24| -46|
| 0| 26| -162|
| 0| 28| -30|
| 0| 31| 447|
| 0| 33| 23|
| 0| 35| 20|
| 0| 44| 96|
| 0| 49| -56|
| 0| 51| 211|
| 0| 58| -88|
| 0| 59| -27|
| 0| 60| -254|
| 0| 61| 525|
+-----------+---------+-----+
前面的输出仅显示了前 20 行。
Tumult Analytics 提供了数据过滤、连接和转换功能,以执行复杂查询,对大型数据集应用差分隐私,并利用 Spark 分布式处理。我们已经涵盖了基本的关键特性,但基于应用/系统中的用例,还有许多更多特性可以探索。
使用差分隐私的机器学习
在本节中,我们的目标是开发一个机器学习分类模型,能够准确地区分欺诈和真实的信用卡交易。为了确保隐私保护,我们还将对模型应用差分隐私技术。分类模型将在包含历史信用卡交易的历史数据集上训练,其中每笔交易都被标记为欺诈或真实。像逻辑回归、决策树或神经网络这样的流行机器学习算法可以应用于构建分类模型,在我们的案例中我们将使用神经网络。
为了引入差分隐私,我们将利用向训练过程添加噪声和使用隐私保护算法等技术。这些技术确保模型的训练过程和随后的预测不会损害单个交易或敏感客户信息的隐私。
通过将差分隐私集成到分类模型中,我们可以在保持识别欺诈交易的高准确性的同时提供强大的隐私保证。这确保了模型可以有效地保护客户的隐私,并防止未经授权访问敏感的财务数据。
在本节中,我们将探讨训练分类模型、评估其性能以及应用差分隐私技术以增强隐私保护的步骤。最终,我们将拥有一个功能强大的模型,能够准确地将信用卡交易分类为欺诈或真实,同时确保涉及个人的隐私。
生成合成数据集:引入欺诈交易
我们将使用之前使用的相同交易数据,在数据集中添加一个名为 TX_FRAUD 的列,并将任何大于 $75 的交易标记为欺诈。这显然并不反映现实世界,但我们将使用此规则生成我们的示例合成数据。在此数据集中,大约 25% 的数据被标记为欺诈交易,而 75% 的数据是真实的。在现实世界中,欺诈交易在大多数数据集中可能不到 1%,这会导致数据高度不平衡。
源代码:Fraud_Transactions_Generator.ipynb
import pandas as pd
import numpy as np
url="transactions.csv"
df_actual = pd.read_csv(url, sep=",")
df_actual.head()
df_transactions = df_actual[['TRANSACTION_ID', 'TX_DATETIME','CUSTOMER_ID','TERMINAL_ID','TX_AMOUNT']]
df_transactions
df_transactions.insert(5, 'TX_FRAUD', 0, True)
df_transactions

图 5.13 – 交易数据
4557166 行 × 6 列
df_transactions.loc[df_transactions.TX_AMOUNT>75, 'TX_FRAUD']=1
nb_frauds=df_transactions.TX_FRAUD.sum()
print("Number of fraud transaction",nb_frauds)
Number of fraud transaction 1106783
df_transactions.head()

图 5.14 – 交易数据的最初几行
df_transactions.to_csv("fraud_transactions.csv")
使用 scikit-learn 开发分类模型
以下是为开发分类模型制定的高级步骤:
-
加载欺诈交易数据集。
-
以 70:30 的比例将数据集分为训练集和测试集。
-
初始化分类器(来自 sci-kit learn 的逻辑回归)。
-
使用训练数据(70% 的交易)训练分类器。
-
使用测试数据集(30% 的交易)找出分类器的准确率。
-
找出在逻辑回归模型中用于决策函数和截距的计算权重/系数。
源代码:Noise_Gradient_Final.ipynb
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
import numpy as np
import pandas as pd
url = "fraud_transactions.csv"
df_actual = pd.read_csv(url, sep=",")
df_transactions =
df_actual[['CUSTOMER_ID','TERMINAL_ID','TX_AMOUNT','TX_FRAUD']]
df_transactions

图 5.15 – 欺诈交易数据集
print('No Frauds', round(df_transactions['TX_FRAUD'].value_counts()[0]/len(df_transactions) * 100,2), '% of the dataset')
print('Frauds', round(df_transactions['TX_FRAUD'].value_counts()[1]/len(df_transactions) * 100,2), '% of the dataset')
No Frauds 75.71 % of the dataset
Frauds 24.29 % of the dataset
X = df_transactions.drop('TX_FRAUD', axis=1)
y = df_transactions['TX_FRAUD']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# Turn the values into an array for feeding the classification algorithms.
X_train = X_train.values
X_test = X_test.values
y_train = y_train.values
y_test = y_test.values
logreg = LogisticRegression(random_state=0)
logreg.fit(X_train, y_train)
training_score = cross_val_score(logreg, X_train, y_train, cv=2)
print('Logistic Regression Cross Validation Score: ',
round(training_score.mean() * 100, 2).astype(str) + '%')
Logistic Regression Cross Validation Score: 100.0%
np.sum(logreg.predict(X_test) == y_test)/X_test.shape[0]
1.0
logreg.intercept_[0], logreg.coef_[0]
(-1168.308115256604,
array([-2.47724513e-05, 3.17749573e-06, 1.54748556e+01]))
一旦我们知道了分类器的梯度/系数以及截距,那么计算预测值将变得容易。在我们的案例中,我们有三个特征,CUSTOMER_ID、TERMINAL_ID 和 TRANSACTON_AMOUNT。线性方程将包含三个特征:
y = w1 * x1 + w2 * x2 + w3 * x3 + b
一旦我们知道了特征值(x1, x2, x3… xn)、权重(w1, w2, w3, …, wn)和 b 值(偏差/截距),我们就可以计算 y-hat 值(预测值)。逻辑回归使用逻辑函数来估计/预测概率。在我们的案例中,它将是以下形式:
y-hat = 1.0 / (1.0 + e – (w1 * x1 + w2 * x2 + w3 * x3 + b))
我们将取一个实际交易并使用从模型获得的权重来计算预测值:
| CUSTOMER_ID | TERMINAL_ID | TX_AMOUNT | TX_FRAUD |
|---|---|---|---|
| 79 | 3115 | 78 | 1 |
表 5.16 – 对 CUSTOMER_ID 的预测
data=[79,3115,78]
weights = [-2.47724513e-05, 3.17749573e-06, 1.54748556e+01]
intercept = -1168.308115256604
def predict(data,coefficients,intercept):
yhat = intercept
for i in range(len(data)):
yhat += coefficients[i] * data[i]
return 1.0 / (1.0 + np.exp(-yhat))
yhat = predict(data,weights,intercept)
yhat
1.0
逻辑回归在内部使用随机梯度下降算法来计算梯度/系数。
让我们实现自己的随机梯度下降算法来计算权重,而不是使用逻辑回归模型中 scikit-learn 提供的算法。
SGD 算法的高级实现
实现 SGD 算法的步骤如下:
-
将初始权重初始化为零(每个特征一个零,偏置/截距也设为零):初始权重 = [0,0,0] 和截距=0
-
对训练数据中的每一行执行以下操作:
-
根据初始权重和截距计算预测。
-
查找实际值和预测值之间的误差:
误差 = 实际值 – 预测值
- 根据误差和学习率值更新截距:
intercept= intercept + l_rate * error * yhat * (1.0 - yhat)
- 更新训练集中所有训练数据的权重。
-
-
根据 epoch 的数量,重复前面的步骤。
def predict(data,coefficients,intercept):
yhat = intercept
for i in range(len(data)):
yhat += coefficients[i] * data[i]
return 1.0 / (1.0 + np.exp(-yhat))
def final_gradients(gradients):
length_grads=len(grads)
avg_grads=[0,0,0]
for i in range(0,length_grads):
avg_grads[0]+=grads[i][0]
avg_grads[1]+=grads[i][1]
avg_grads[2]+=grads[i][2]
avg_grads=[i/length_grads for i in avg_grads]
return avg_grads
def sgd(train,y_train,l_rate, n_epoch):
coef = [0,0,0]
final_grads = [0,0,0]
intercept = 0
for epoch in range(n_epoch):
predictions=[]
gradients=[]
sum_error = 0.0
for i in range(len(train)):
yhat = predict(train[i], coef,intercept)
predictions.append(yhat)
error = y_train[i] - yhat
sum_error += error**2
intercept= intercept + l_rate * error * yhat * (1.0 - yhat)
## intercept
temp=train[i]
for j in range(3):
coef[j] = coef[j] + l_rate * error * yhat * (1.0 - yhat) * temp[j]
gradients.append(coef)
final_grads = final_gradients(gradients)
print('>epoch=%d, lrate=%.3f, error=%.3f, intercept=%.3f '% (epoch, l_rate, sum_error,intercept))
return final_grads
l_rate = 0.24
n_epoch = 4
coef = sgd(X_train[:10],y_train[:10],l_rate, n_epoch)
print(coef)
>epoch=0, lrate=0.240, error=2.250, intercept=-0.030
>epoch=1, lrate=0.240, error=2.000, intercept=-0.030
>epoch=2, lrate=0.240, error=2.000, intercept=-0.030
>epoch=3, lrate=0.240, error=2.000, intercept=-0.030
[-136.44000000000003, -263.88000000000005, -0.5099999999999999]
这样,我们可以计算系数。最终系数是所有系数/梯度的平均值。
使用机器学习应用差分隐私选项
将差分隐私应用于前面的算法意味着生成具有差分隐私的梯度,这样模型就不会泄露训练示例的细节。当将差分隐私应用于 SGD 时,目标是将隐私保护集成到机器学习模型的训练过程中。这涉及到在 SGD 优化步骤中添加噪声到计算的梯度,以确保训练好的模型不会泄露关于任何单个数据点的具体细节。
在具有差分隐私的 SGD 中添加噪声有助于通过使区分任何特定训练示例对模型更新的影响变得困难来防止潜在的隐私泄露。它确保模型的参数不会记住或过度拟合特定的训练样本,从而为在训练过程中使用的数据的个体提供隐私保证。
使用差分隐私生成梯度
在机器学习环境中使用差分隐私生成梯度有两种方法。
方法 1:
-
使用正常 SGD 算法在训练数据上生成最终梯度。
-
计算从前一个 SGD 步骤获得的梯度的总和。
-
使用拉普拉斯机制对梯度的总和添加噪声,考虑到所需的敏感性和隐私预算。
方法 2:
-
对每个训练示例或整体训练数据应用剪裁方法。
-
使用剪裁的训练数据输入生成梯度。
-
计算上一步获得的梯度的总和。
-
使用高斯或拉普拉斯机制对梯度总和添加噪声,考虑所需的敏感度和隐私预算。
-
使用差分隐私计算训练示例的数量,将其视为敏感度设置为 1 的计数查询,并利用所需的隐私预算。
-
计算噪声梯度总和和噪声计数的平均值,以获得差分隐私梯度平均值。
这两种方法都旨在将差分隐私纳入梯度计算过程,从而在训练机器学习模型的同时保护单个训练示例的隐私。选择这两种方法之间的差异取决于应用的特定要求和期望的隐私保证水平。
通过添加适当的噪声并应用隐私保护机制,这些方法确保用于更新模型参数的梯度不会泄露关于单个训练示例的敏感信息。这使得训练过程能够在提供隐私保证的同时,仍然实现准确和可靠的模式性能。
现在,让我们为我们的欺诈检测示例实现方法 2。
如我们所知,裁剪是设置数据上下限的过程,因此实现以下clip函数:
def clip(iv, b):
norm = np.linalg.norm(iv, ord=2)
if norm > b:
return b * (iv / norm)
else:
return iv
print( clip([[4548, 8796, 17]],5.0) )
[[2.29645183 4.44142267 0.00858392]]
clip(X_train[:5], 5)
array([[1.35772596e+00, 2.62589215e+00, 5.07505304e-03],
[3.40625619e-01, 2.83605905e-02, 1.55236917e-02],
[1.41504420e+00, 1.98583840e+00, 1.52251591e-02],
[1.06964206e+00, 1.67446897e+00, 2.08972772e-02],
[6.95282267e-01, 2.50737474e+00, 1.19413013e-03]])
def dp_final_gradients(gradients):
length_grads=len(grads)
sensitivity = 1
epsilon= 0.8
noise = np.random.laplace(loc=0, scale=sensitivity/epsilon)
noise_lenth = length_grads + noise
avg_grads=[0,0,0]
for i in range(0,length_grads):
avg_grads[0]+=grads[i][0]
avg_grads[1]+=grads[i][1]
avg_grads[2]+=grads[i][2]
avg_grads=[i/noise_lenth for i in avg_grads]
return avg_grads
def dp_sgd(train,y_train,l_rate, n_epoch):
train = clip(train, 5)
coef = [0,0,0]
final_grads = [0,0,0]
intercept = 0
for epoch in range(n_epoch):
predictions=[]
gradients=[]
sum_error = 0.0
for i in range(len(train)):
yhat = predict(train[i], coef,intercept)
predictions.append(yhat)
error = y_train[i] - yhat
sum_error += error**2
intercept= intercept + l_rate * error * yhat * (1.0 - yhat)
## intercept
temp=train[i]
for j in range(3):
coef[j] = coef[j] + l_rate * error * yhat * (1.0 - yhat) * temp[j]
gradients.append(coef)
final_grads = dp_final_gradients(gradients)
print('>epoch=%d, lrate=%.3f, error=%.3f, intercept=%.3f '% (epoch, l_rate, sum_error,intercept))
return final_grads
l_rate = 0.24
n_epoch = 4
print("Gradients using Normal SGD ")
coef = sgd(X_train[:10],y_train[:10],l_rate, n_epoch)
print("Gradients using Differentially Private SGD ")
coef = dp_sgd(X_train[:10],y_train[:10],l_rate, n_epoch)
print(coef)
Gradients using Normal SGD
>epoch=0, lrate=0.240, error=2.250, intercept=-0.030
>epoch=1, lrate=0.240, error=2.000, intercept=-0.030
>epoch=2, lrate=0.240, error=2.000, intercept=-0.030
>epoch=3, lrate=0.240, error=2.000, intercept=-0.030
[-136.44000000000003, -263.88000000000005, -0.5099999999999999]
Gradients using Differentially Private SGD
>epoch=0, lrate=0.240, error=2.146, intercept=-0.127
>epoch=1, lrate=0.240, error=1.654, intercept=-0.193
>epoch=2, lrate=0.240, error=1.478, intercept=-0.229
>epoch=3, lrate=0.240, error=1.396, intercept=-0.249
[-115.01700212848986, -222.44713076565455, -0.42992283117509383]
通过将随机梯度下降(SGD)与差分隐私相结合,正如我们在这里所做的那样,我们可以开发出既提供准确预测又为敏感数据提供隐私保护的机器学习模型。这使组织能够在遵守隐私法规和道德考量的情况下利用大规模数据集。
使用差分隐私进行聚类
让我们考虑一个场景,其中我们有一个用户浏览行为的数据库集。在这种情况下,k-means 聚类的目标是识别k个点,称为聚类中心,这些点使数据点到其最近聚类中心的平方距离之和最小化。这种分区使我们能够根据用户的浏览模式对用户进行分组。此外,我们还可以根据最近聚类中心将新用户分配到一组。然而,聚类中心的发布可能会泄露关于特定用户的敏感信息。例如,如果某个用户的浏览行为与大多数用户显著不同,标准的 k-means 聚类算法可能会为该用户分配一个特定的聚类中心,从而泄露关于其浏览习惯的敏感细节。为了解决这个隐私问题,我们将实现具有差分隐私的聚类。通过这样做,我们旨在保护单个用户的隐私,同时仍然根据他们的浏览行为提供有意义的聚类结果。
首先,为了说明问题的本质,让我们在不使用差分隐私的情况下生成我们的聚类中心:
源代码:Clustering_Differential_Privacy_diffprivlib.ipynb
import numpy as np
from scipy import stats
from sklearn.cluster import KMeans
# Example dataset
data = np.array([[1, 2], [1.5, 1.8], [5, 8], [8, 8], [1, 0.6], [9, 11]])
#apply clustering on this dataset and cluster the data 2 clusters
kmeans = KMeans(n_clusters=2)
kmeans.fit(data)
clusters = kmeans.labels_
original_centroids = kmeans.cluster_centers_
# Print the original data points, clusters and centroids
print("Original Data Points:\n", data)
print("Clusters:\n", clusters)
print("Original Centroids:\n", original_centroids)
Original Data Points:
[[ 1. 2\. ]
[ 1.5 1.8]
[ 5. 8\. ]
[ 8. 8\. ]
[ 1. 0.6]
[ 9. 11\. ]]
Clusters:
[1 1 0 0 1 0]
Original Centroids:
[[7.33333333 9. ]
[1.16666667 1.46666667]]
在前面的示例中,我们有一个包含两个敏感数据属性的合成数据集。我们使用 scikit-learn 中的 KMeans 算法进行聚类,而不包含差分隐私。我们使用cluster_centers_属性检索聚类中心。
这种方法的缺点是,代表每个聚类中心的聚类中心可能会泄露关于数据的敏感信息。在这种情况下,聚类中心可能会暴露敏感属性的均值。为了解决这个隐私问题,可以应用差分隐私技术向聚类中心添加噪声,使其更难以推断敏感信息。然而,请注意,在聚类算法中应用差分隐私需要仔细考虑隐私-效用权衡和适当的隐私参数选择。
让我们通过向数据集添加噪声来生成中心点。
按照以下步骤操作:
-
定义add_noise函数,该函数接受原始数据、隐私参数 epsilon 和敏感性作为输入。它生成拉普拉斯分布的噪声并将其添加到数据点。噪声按敏感性比例和隐私参数 epsilon 缩放。
-
计算敏感性,即由于添加或删除单个数据点而引起的数据点的最大变化。在这种情况下,我们计算任何数据点与数据集均值的最大绝对差异。
-
指定隐私参数 epsilon,它决定了要添加的噪声量。使用add_noise函数向数据点添加噪声。
-
使用 k-means 聚类对噪声数据进行聚类,使用两个聚类。检索算法分配的聚类标签。打印原始数据点、噪声数据点和分配给每个点的聚类。
def add_noise(data, epsilon, sensitivity):
beta = sensitivity / epsilon
laplace_noise = np.random.laplace(0, beta, data.shape)
noisy_data = data + laplace_noise
return noisy_data
# Sensitivity is the maximum change in data points due to the
addition or removal of a single data point
sensitivity = np.max(np.abs(data - np.mean(data, axis=0)))
# Privacy parameter epsilon determines the amount of noise to be added
epsilon = 0.1
# Add noise to the data points
noisy_data = add_noise(data, epsilon, sensitivity)
# Perform clustering on the noisy data
kmeans = KMeans(n_clusters=2)
kmeans.fit(noisy_data)
noisy_clusters = kmeans.labels_
noise_centroids = kmeans.cluster_centers_
print("Noisy Data Points:\n", noisy_data)
print("Noisy Clusters:\n", noisy_clusters)
print("Noisy Centroids :\n", noise_centroids)
Noisy Data Points:
[[ -8.22894996 -25.09225801]
[ 48.29852161 -93.63432789]
[ 2.61671234 86.87531981]
[ 10.03114688 7.72529685]
[-27.57009962 59.88763296]
[ 16.99705384 -94.28428515]]
Noisy Clusters:
[1 1 0 0 0 1]
Noisy Centroids :
[[ -4.97408014 51.49608321]
[ 19.0222085 -71.00362369]]
使用 IBM 的 diffprivlib 框架生成不同的隐私中心,作为“浏览 行为场景”相同用例的替代方法。
diffprivlib 框架是一个 Python 库,提供了执行差分隐私数据分析的工具和算法。Diffprivlib由四个主要组件组成,这些组件有助于其功能:
-
机制:这些组件是差分隐私的基本构建块,并被用于所有实现差分隐私的模型中。diffprivlib 中的机制是可定制的,旨在供实施自己模型的专家使用。
-
模型:此模块包含与差分隐私集成的机器学习模型。Diffprivlib提供了多种实现差分隐私的模型,包括聚类、分类、回归、降维和预处理。这些模型旨在在执行各自任务的同时确保隐私。
-
工具:Diffprivlib提供了一系列通用的工具,旨在用于差分隐私数据分析。这些工具提供了如差分隐私直方图等功能,其格式与 NumPy 的直方图函数相同。它们使用户能够在保护隐私的同时执行各种数据分析任务。
-
会计:会计组件包括BudgetAccountant类,它通过高级组合技术促进隐私预算的跟踪和计算总隐私损失。这一功能对于管理和控制多个差分隐私操作中的隐私支出至关重要,确保隐私保证得到维持。diffprivlib 中的这些组件共同构成了一个全面的框架,用于在各种数据分析场景中实现差分隐私。它们提供了必要的工具、模型、机制和隐私会计能力,以支持隐私保护的数据分析任务。
让我们使用 diffprivlib 框架生成聚类中心。
使用pip安装diffprivlib框架:
!pip3 install diffprivlib
按照以下步骤操作:
-
从diffprivlib.models导入KMeans类。
-
指定 epsilon 隐私参数=,它决定了隐私保护强度。
-
创建一个具有epsilon参数和所需簇数的 KMeans 实例。
-
使用fit方法将差分隐私 KMeans 模型拟合到数据。
-
最后,使用 KMeans 模型的cluster_centers_属性检索差分隐私聚类中心。
from diffprivlib.models import KMeans
epsilon = 1.0
# Perform clustering with differential privacy
dp_kmeans = KMeans(epsilon=epsilon, n_clusters=2)
dp_kmeans.fit(data)
# Get the differentially private cluster centroids
dp_centroids = dp_kmeans.cluster_centers_
# Print the differentially private cluster centroids
print("Differentially Private Cluster Centroids:\n", dp_centroids)
Differentially Private Cluster Centroids:
[[8.71915573 9.51643083]
[5.96366996 3.84980361]]
需要注意的是,diffprivlib 中的差分隐私是在假设有一个可信的监管者的前提下运行的,如果监管者正确遵循隐私保护机制,则提供隐私保证。
然而,为了完整实现差分隐私,还需要仔细考虑一些额外的因素,例如选择合适的隐私参数以及数据效用的影响。
使用差分隐私的深度学习
在本节中,我们将专注于使用 PyTorch 框架开发一个欺诈检测模型。此外,我们将使用如 PyTorch 和 Opacus 等开源框架,通过差分隐私训练深度学习模型。使用 PyTorch 框架,我们将开发一个专门针对欺诈检测的深度学习模型。PyTorch 是一个流行的开源深度学习库,它提供了一个灵活且高效的平台,用于构建和训练神经网络。其丰富的工具和 API 使其非常适合开发复杂的机器学习模型。
为了将差分隐私纳入训练过程,我们将利用 Opacus 库。Opacus 是一个开源的 PyTorch 扩展,为训练具有差分隐私的深度学习模型提供工具。它提供了梯度裁剪、噪声添加和隐私分析等机制,有助于确保训练的模型保护单个数据点的隐私。
通过结合 PyTorch 和 Opacus,我们可以为欺诈检测训练具有差分隐私的深度学习模型。这种方法使我们能够从深度学习的表达能力中受益,同时遵守隐私法规并保护敏感信息。在本节中,我们将探讨数据预处理、模型架构设计、训练和评估的技术。我们将考虑与欺诈检测相关的独特挑战和考虑因素,例如不平衡数据集、特征工程和性能评估指标。
到本节结束时,你将全面了解如何使用 PyTorch 开发欺诈检测模型,并使用 Opacus 等框架通过差分隐私进行训练。这些知识将使你能够构建用于欺诈检测和类似应用的稳健且保护隐私的机器学习模型。
使用 PyTorch 的欺诈检测模型
为了使用 PyTorch 开发深度学习模型,我们可以遵循以下步骤:
-
加载交易数据:首先,将交易数据加载到 pandas DataFrame 对象中。
-
分割数据:将加载的数据分割成训练集和测试集。
-
将数据转换为 PyTorch 张量:为了使用 PyTorch,我们需要将数据转换为 PyTorch 张量。PyTorch 张量是高效的数据结构,允许我们使用 GPU 进行加速训练。我们使用 torch.tensor 函数转换数据。
-
创建一个简单的线性模型:使用 PyTorch 的 nn.Module 类定义深度学习模型架构。对于简单的线性模型,我们使用 nn.Linear 模块创建线性层。为了将交易分类为欺诈或非欺诈,我们在模型末尾添加一个 sigmoid 层,使用 nn.Sigmoid 激活函数。
-
训练模型:设置训练循环,遍历训练数据并根据定义的损失函数和优化算法更新模型的参数。使用 PyTorch 的 nn.CrossEntropyLoss 作为损失函数,并选择合适的优化器,如 torch.optim.SGD 或 torch.optim.Adam 来更新模型的参数。
-
监控损失:在训练过程中,跟踪每一步的损失。损失表示模型预测输出与真实标签之间的差异。通过监控损失,你可以评估模型训练的进度,并在必要时进行调整。
通过遵循这些步骤,我们使用 PyTorch 开发了一个用于欺诈检测的深度学习模型。需要注意的是,这是一个简化的概述,你可能需要根据你的欺诈检测任务的具体要求自定义模型架构、集成额外的层或技术,并微调超参数。
源代码: Fraud_Detection_Deep Learning.ipynb
# 解压提供的 GitHub 仓库中的 fraud_transactions.csv.zip 文件(作为本书的 fraud_transactions.csv )
import pandas as pd
import torch
url ="fraud_transactions.csv"
df_actual = pd.read_csv(url, sep=",")
df_actual.head()
df_transactions = df_actual[['CUSTOMER_ID','TERMINAL_ID','TX_AMOUNT','TX_FRAUD']]
df_transactions=df_transactions.head(50000)
df_transactions
from sklearn.model_selection import train_test_split
from sklearn.model_selection import StratifiedShuffleSplit
print("No of Fraud Transactions:", df_transactions['TX_FRAUD'].value_counts()[0])
print("No of Non Fraud Transactions:", df_transactions['TX_FRAUD'].value_counts()[1])
print('No Frauds', round(df_transactions['TX_FRAUD'].value_counts()[0]/len(df_transactions) * 100,2), '% of the dataset')
print('Frauds', round(df_transactions['TX_FRAUD'].value_counts()[1]/len(df_transactions) * 100,2), '% of the dataset')
No of Fraud Transactions: 37870
No of Non Fraud Transactions: 12130
No Frauds 75.74 % of the dataset
Frauds 24.26 % of the dataset
X = df_transactions.drop('TX_FRAUD', axis=1)
y = df_transactions['TX_FRAUD']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# Convert into Pytorch Tensors
x_train = torch.FloatTensor(X_train.values)
x_test = torch.FloatTensor(X_test.values)
y_train = torch.FloatTensor(y_train.values)
y_test = torch.FloatTensor(y_test.values)
if torch.cuda.is_available():
DEVICE = "cuda"
else:
DEVICE = "cpu"
print("Selected device is",DEVICE)
class FraudDataset(torch.utils.data.Dataset):
def __init__(self, x, y):
'Initialization'
self.x = x
self.y = y
def __len__(self):
'Returns the total number of samples'
return len(self.x)
def __getitem__(self, index):
'Generates one sample of data'
# Select sample index
if self.y is not None:
return self.x[index].to(DEVICE), self.y[index].to(DEVICE)
else:
return self.x[index].to(DEVICE)
train_loader_params = {'batch_size': 64,
'shuffle': True,
'num_workers': 0}
test_loader_params = {'batch_size': 64,
'num_workers': 0}
# Loaders
training_set = FraudDataset(x_train, y_train)
testing_set = FraudDataset(x_test, y_test)
train_loader = torch.utils.data.DataLoader(training_set, **train_loader_params)
test_loader = torch.utils.data.DataLoader(testing_set, **test_loader_params)
class SimpleFraudMLP(torch.nn.Module):
def __init__(self):
super().__init__()
self.first_sec = torch.nn.Sequential(
torch.nn.Linear(3, 450),
torch.nn.ReLU(),
)
self.second_sec = torch.nn.Sequential(
torch.nn.Linear(450, 450),
torch.nn.ReLU(),
torch.nn.Linear(450, 1),
torch.nn.Sigmoid(),
)
def forward(self, x):
return self.second_sec(self.first_sec(x))
fraud_nn_model = SimpleFraudMLP().to(DEVICE)
from torch import nn, optim
loss_func = torch.nn.BCELoss().to(DEVICE)
optimizer = torch.optim.SGD(fraud_nn_model.parameters(), lr = 0.07)
def train(fraud_nn_mode,num_epochs):
fraud_nn_model.train()
for epoch in range(num_epochs):
for x_batch, y_batch in train_loader:
output = fraud_nn_model(x_train)
print(output.squeeze())
print(y_train)
loss = loss_func(output.squeeze(), y_train)
# clear gradients for this training step
optimizer.zero_grad()
# backpropagation, compute gradients
loss.backward()
# apply gradients
optimizer.step()
print(epoch, loss.item())
pass
train (fraud_nn_model, 10)
tensor([0., 0., 0., ..., 0., 0., 0.], grad_fn=<SqueezeBackward0>)
tensor([1., 1., 1., ..., 0., 0., 0.])
0 24.191429138183594
使用 Opacus 框架实现的具有差分隐私的欺诈检测模型
Opacus,一个开源库,是支持差分隐私的 SGD-DP 算法的 PyTorch 实现。Opacus 在限制对最终模型准确率影响的同时,保护了每个训练样本的隐私。这样,异常值的隐私也得到了保护。Opacus 在每次迭代中向梯度添加噪声,以防止模型简单地记住训练示例。Opacus 通过查看梯度的范数来添加适当的噪声尺度(噪声过多会降低准确率,而过少则无法帮助保护隐私)。
更多关于 Opacus 的详细信息可以在 opacus.ai/ 找到。
安装 Opacus 库的代码如下(我在这个例子中使用了以下版本:opacus==1.1.2):
pip install opacus==1.1.2
我们将开发相同的深度学习模型,并使用 PyTorch 的 Opacus 框架进行差分隐私训练。
实施以下步骤:
-
加载交易数据。
-
使用 pandas DataFrames 将数据分为训练集和测试集。
-
将数据转换为 PyTorch 张量。
-
创建一个简单的线性模型,并在最后使用 sigmoid 层来对交易进行欺诈或非欺诈的分类。
-
使用 Opacus 提供的 PrivacyEngine 实例将模型变为私有(即,将差分隐私应用于模型),以保护训练数据。
-
训练模型并测量 epsilon(隐私预算)。
来源: Fraud_Detection_DP.ipynb
import pandas as pd
url=" fraud_transactions.csv"
df_actual = pd.read_csv(url, sep=",")
df_actual.head()
df_transactions = df_actual[['CUSTOMER_ID','TERMINAL_ID','TX_AMOUNT','TX_FRAUD']]
df_transactions=df_transactions.head(50000)
df_transactions
from sklearn.model_selection import train_test_split
from sklearn.model_selection import StratifiedShuffleSplit
print("No of Fraud Transactions:", df_transactions['TX_FRAUD'].value_counts()[0])
print("No of Non Fraud Transactions:", df_transactions['TX_FRAUD'].value_counts()[1])
print('No Frauds', round(df_transactions['TX_FRAUD'].value_counts()[0]/len(df_transactions) * 100,2), '% of the dataset')
print('Frauds', round(df_transactions['TX_FRAUD'].value_counts()[1]/len(df_transactions) * 100,2), '% of the dataset')
X = df_transactions.drop('TX_FRAUD', axis=1)
y = df_transactions['TX_FRAUD']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
x_train = torch.FloatTensor(X_train.values)
x_test = torch.FloatTensor(X_test.values)
y_train = torch.FloatTensor(y_train.values)
y_test = torch.FloatTensor(y_test.values)
if torch.cuda.is_available():
DEVICE = "cuda"
else:
DEVICE = "cpu"
print("Selected device is",DEVICE)
class FraudDataset(torch.utils.data.Dataset):
def __init__(self, x, y):
'Initialization'
self.x = x
self.y = y
def __len__(self):
'Returns the total number of samples'
return len(self.x)
def __getitem__(self, index):
'Generates one sample of data'
# Select sample index
if self.y is not None:
return self.x[index].to(DEVICE), self.y[index].to(DEVICE)
else:
return self.x[index].to(DEVICE)
train_loader_params = {'batch_size': 64,
'shuffle': True,
'num_workers': 0}
test_loader_params = {'batch_size': 64,
'num_workers': 0}
# Generators
training_set = FraudDataset(x_train, y_train)
testing_set = FraudDataset(x_test, y_test)
train_loader = torch.utils.data.DataLoader(training_set, **train_loader_params)
test_loader = torch.utils.data.DataLoader(testing_set, **test_loader_params)
fraud_nn_model = SimpleFraudMLP().to(DEVICE)
import warnings
warnings.simplefilter("ignore")
MAX_GRAD_NORM = 1.2
EPSILON = 90.0
DELTA = 1e-5
EPOCHS = 20
LR = 1e-3
from opacus.validators import ModuleValidator
errors = ModuleValidator.validate(fraud_nn_model, strict=False)
errors[-5:]
from torch import nn, optim
#loss_func = nn.CrossEntropyLoss()
loss_func = torch.nn.BCELoss().to(DEVICE)
optimizer = torch.optim.SGD(fraud_nn_model.parameters(), lr = 0.07)
from opacus import PrivacyEngine
fraud_nn_model.train()
privacy_engine = PrivacyEngine()
model, optimizer, train_loader = privacy_engine.make_private_with_epsilon(
module=fraud_nn_model,
optimizer=optimizer,
data_loader=train_loader,
epochs=EPOCHS,
target_epsilon=EPSILON,
target_delta=DELTA,
max_grad_norm=MAX_GRAD_NORM,
)
print(f"Using sigma={optimizer.noise_multiplier} and C={MAX_GRAD_NORM}")
import numpy as np
import time
n_epochs = 10
#Setting the model in training mode
fraud_nn_model.train()
#Training loop
start_time=time.time()
epochs_train_losses = []
epochs_test_losses = []
for epoch in range(n_epochs):
train_loss=[]
train_loss1=0
for x_batch, y_batch in train_loader:
fraud_nn_model.train()
y_pred = fraud_nn_model(x_batch)
loss = loss_func(y_pred.squeeze(), y_batch)
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss.append(loss.item())
train_loss1 += loss.item()*x_batch.size(0)
epsilon = privacy_engine.get_epsilon(DELTA)
print('ε epsilon{} : delta:{}'.format(epsilon, DELTA))
epochs_train_losses.append(np.mean(train_loss))
print('Epoch {}: train loss: {}'.format(epoch, np.mean(train_loss)))
ε epsilon33.98911164791893 : delta:1e-05
Epoch 0: train loss: 22.66661006201338
ε epsilon38.786904746786384 : delta:1e-05
Epoch 1: train loss: 23.087044257350552
ε epsilon42.819749628256126 : delta:1e-05
Epoch 2: train loss: 23.234367423345226
ε epsilon46.852594509725854 : delta:1e-05
Epoch 3: train loss: 23.257508610022786
ε epsilon50.8854393911956 : delta:1e-05
Epoch 4: train loss: 23.949310037727983
ε epsilon54.91828427266533 : delta:1e-05
Epoch 5: train loss: 22.498504093839657
在每个纪元中,训练损失波动,但与此同时,隐私损失(预算)ε 增加。
这样,使用 Opacus 和 PyTorch,可以以最小的代码更改对深度学习模型进行差分隐私训练,并保护训练数据的隐私。
差分隐私机器学习框架
以下是一些流行的差分隐私机器学习框架:
| 框架 | 实现 |
|---|---|
| Opacus | PyTorch. |
| Tensor Flow Privacy | TensorFlow。 |
| Pyvacy | TensorFlow Privacy,但针对 PyTorch。 |
| JAX(DP) | JAX 是 Autograd 和 XLA 的结合,用于高性能机器学习研究。 |
| Pysyft | Pysyft 是一个用于使用联邦学习和差分隐私进行私有、安全机器学习的 Python 库。它允许在多个设备上安全且私有地训练和推理机器学习模型。 |
表 5.17 – DP ML 框架
差分隐私的局限性和克服策略
由于差分隐私能够在隐私和效用之间取得平衡,它在学术界和工业界都受到了显著的关注和采用。然而,像任何其他技术一样,差分隐私有其局限性和挑战,需要解决以确保其有效实施。以下是差分隐私的一些主要局限性和克服它们的潜在策略:
-
噪声与效用权衡:差分隐私通过向查询响应中添加噪声来实现隐私保护,这引入了隐私与效用之间的权衡。添加的噪声量决定了隐私水平,但过多的噪声会显著降低发布数据的效用。在隐私与效用之间取得平衡是一个挑战。
- 克服策略:缓解这种限制的一种方法是为算法设计更好的算法,以最小化噪声对效用的影响。研究人员正在不断开发先进的机制和技术来优化噪声注入过程,例如自适应噪声校准、通过子采样进行隐私放大或利用机器学习生成更准确且具有隐私保护的响应。
-
推理攻击:差分隐私侧重于通过限制单个记录的影响来保护个人隐私。然而,攻击者可能会采用复杂的推理攻击,通过组合多个噪声查询或利用外部辅助信息来获取信息。这些攻击利用数据中存在的模式或相关性来推断敏感细节。
- 克服策略:为了克服推理攻击,可以将额外的隐私保护技术与差分隐私相结合。例如,可以使用安全的多方计算(MPC)协议来计算汇总统计信息,而不泄露单个数据点,从而增强隐私保护。
-
隐私预算耗尽:差分隐私使用隐私预算,它表示在一系列查询中允许的最大隐私损失。每次查询都会消耗一部分预算,一旦预算耗尽,在保持差分隐私保证的情况下,就不能再进行进一步的查询。这种限制在需要回答大量查询的场景中提出了挑战。
- 克服策略:解决隐私预算耗尽的一种方法是根据数据的敏感性或查询的具体上下文动态分配预算。通过调整预算分配策略,可以优化发布数据的效用,并扩展允许的查询次数,而不会损害隐私。此外,可以采用高级组合技术,如 Rényi 差分隐私,以更有效地管理隐私预算并允许更细粒度的控制。
-
外部数据和辅助信息:差分隐私假设发布的数据是攻击者可用的唯一信息来源。然而,攻击者可能利用外部数据源或辅助信息来改进他们的攻击。这些外部来源可能揭示有关个人的额外细节或包含相关数据,这使得保持隐私保证变得具有挑战性。
- 克服策略:为了克服这一限制,仔细分析外部数据源和辅助信息对隐私的潜在影响至关重要。采用数据集成技术,如安全多方计算或加密协议,可以帮助抵御利用外部信息的攻击。此外,采取主动措施,如数据去标识化和最小化数据关联,可以进一步增强对这种威胁的隐私保护。
-
对复杂数据类型的支持有限:差分隐私主要关注数值或分类数据,这限制了其在文本、图像或图等更复杂数据类型上的适用性。在这些领域保持隐私同时保持有意义的效用是一个挑战。
- 克服策略:研究人员正在积极探索将差分隐私扩展到复杂数据类型的技术。例如,对于文本数据,正在开发差分隐私文本生成或隐私保护的自然语言处理模型。对于图像,正在研究具有隐私保证的差分隐私深度学习或生成对抗网络。这些进步旨在为更广泛的数据类型提供隐私保证。使用差分隐私训练的 LLMs 也暴露了某些隐私泄露。有关更多信息,我们强烈建议阅读研究论文
arxiv.org/pdf/2202.05520.pdf。
- 克服策略:研究人员正在积极探索将差分隐私扩展到复杂数据类型的技术。例如,对于文本数据,正在开发差分隐私文本生成或隐私保护的自然语言处理模型。对于图像,正在研究具有隐私保证的差分隐私深度学习或生成对抗网络。这些进步旨在为更广泛的数据类型提供隐私保证。使用差分隐私训练的 LLMs 也暴露了某些隐私泄露。有关更多信息,我们强烈建议阅读研究论文
-
对内部攻击的保护有限:差分隐私主要关注保护数据免受外部对手的攻击。然而,在内部攻击成为关注点的情况下,它可能并不那么有效。能够访问原始数据的内部人员可能会故意修改数据或利用他们的知识来侵犯隐私。
- 克服策略:将差分隐私与额外的安全措施相结合可以帮助减轻内部攻击。例如,可以使用安全区域或安全硬件来保护敏感数据的隐私,即使是有直接访问权限的人也无法获取。采用访问控制、审计日志和严格的数据治理政策也可以威慑内部威胁并确保问责制。我们将在第九章中了解更多关于安全区域的内容。
-
保护时间隐私的困难:差分隐私主要设计用于静态数据集,在处理时间数据或时间序列分析时保护隐私可能具有挑战性。数据中的时间相关性可能导致隐私泄露或推理攻击。
- 克服策略:为了解决时间隐私问题,研究人员正在探索个性化差分隐私等技术,其中隐私参数根据个人的数据历史进行调整。另一种方法是在保持隐私的同时,引入考虑连续查询或时间间隔之间相关性的时间一致性机制。这些技术旨在保护动态和不断发展的数据集中的隐私。
-
对机器学习模型的有限支持:差分隐私技术在应用于机器学习模型时往往面临挑战,尤其是在深度学习架构中。模型参数或梯度的扰动可能会降低模型性能或引入漏洞。
- 克服策略:为了克服这一限制,研究人员正在开发针对差分隐私的隐私保护机器学习技术。例如,联邦学习技术,在无需共享敏感信息的情况下,在去中心化数据上训练模型,可以确保隐私同时保持效用。此外,隐私保护深度学习算法的进步,如差分隐私随机梯度下降,旨在在模型性能和隐私保证之间取得平衡。我们将在下一章更深入地介绍联邦学习。
-
缺乏标准化和互操作性:缺乏标准化框架和互操作性可能会阻碍差分隐私的广泛应用。不同的实现和方案使得比较结果或在不同平台或系统间集成隐私保护技术变得具有挑战性。
- 克服策略:建立标准化的指南和框架可以帮助解决互操作性挑战。组织和企业联盟可以合作开发差分隐私的通用 API、协议和评估指标。开源库和工具的努力,以及社区驱动的倡议,可以促进知识共享,并使差分隐私技术能够无缝集成到现有系统和工作流程中。
总体来说,虽然微分算法有很多优点,但它们并不是万能的解决方案,在实际应用中使用它们时必须仔细考虑。
摘要
总结来说,在本章中,我们探讨了包括 PyDP、PipelineDP、Tumult Analytics 和 PySpark 在内的开源框架,以实现差分隐私。我们通过开发一个私有的随机梯度下降算法,实现了带有和没有差分隐私的欺诈检测机器学习模型。我们还实现了深度学习模型,并使用基于 PyTorch 的 Opacus 框架,通过差分隐私训练了这些模型。最后,我们讨论了差分隐私的局限性以及克服这些局限性的策略。
在下一章中,我们将深入了解联邦学习的必要性,包括使用的算法和支撑联邦学习的框架,并探讨使用联邦学习实现欺诈检测用例的端到端实现。
第三部分:动手实践联邦学习
本部分涵盖了联邦学习(FL)的需求以及使用开源框架实现 FL 的方法。它还涉及 FL 基准、初创企业和该领域的未来机遇。
我们强调联邦学习作为一种保护隐私的机器学习方法的重要性,并强调在由于隐私问题或监管限制而无法集中聚合数据的情况下,联邦学习的必要性。此外,我们讨论了使用开源框架实现联邦学习,这些框架提供了可访问和可定制的工具,用于部署 FL 算法和模型。
我们探讨了 FL 基准在评估和比较 FL 算法和技术方面的重要性,并强调了需要标准化基准来评估不同场景下 FL 模型的表现和有效性。通过利用 FL 基准,研究人员和实践者可以识别各种 FL 方法的优点和局限性,从而促进该领域的发展。
我们探讨了致力于 FL 的初创企业的存在,并强调了它们的贡献和重点领域。我们揭示了这些初创企业正在开发的新颖应用和解决方案,这些进一步促进了 FL 的采用和发展。此外,我们还触及了 FL 的未来机遇,包括隐私保护技术的进步、FL 框架的可扩展性和与新兴技术的集成。
总体而言,本书的这一部分强调了联邦学习的必要性,使用开源框架实现联邦学习,FL 基准的重要性以及初创企业在 FL 领域的贡献。它还承认了未来的潜在机遇,推动 FL 在各个领域的进一步发展和采用。
本部分包含以下章节:
-
第六章**,联邦学习的需求以及使用开源框架实现联邦学习
-
第七章**,联邦学习基准、初创企业和下一机遇
第六章:联邦学习与使用开源框架实现 FL
在本章中,您将了解联邦学习(FL)以及如何使用开源框架实现它。我们将涵盖为什么需要它以及如何保护数据隐私。我们还将探讨 FL 的定义、其特性和涉及的步骤。
我们将涵盖以下主要主题:
-
FL
-
FL 算法
-
实现 FL 涉及的步骤
-
实现 FL 的开源框架
-
使用 FL 实现欺诈检测的端到端用例
-
带有差分隐私的 FL
通过探讨这些主题,您将全面了解 FL 的需求以及实现 FL 的开源框架。
联邦学习
FL 已成为解决在数据隐私和数据本地性至关重要的场景中传统集中式机器学习(ML)方法挑战的解决方案。
我们需要 FL 的关键原因如下:
-
保护数据隐私:在许多情况下,数据是敏感的,由于法律、伦理或隐私问题无法共享。FL 允许您在分布式数据源上直接训练模型,而不共享原始数据,确保隐私保护。通过保持数据本地化并在本地执行模型更新,FL 最大限度地降低了暴露敏感信息的风险。
-
数据本地化和法规遵从性:FL 允许组织遵守数据本地化要求和法规。无需将数据传输到中央服务器,数据保持在生成或收集数据的管辖范围内,解决了与跨境数据传输相关的担忧。
-
可扩展性和效率:集中式机器学习方法在处理大量数据时往往面临挑战,因为从各种来源汇总和处理数据可能耗时且资源密集。FL 将训练过程分散化,允许数据保持去中心化,同时从所有参与设备或数据源的集体智慧中受益。这种去中心化方法提高了可扩展性和计算效率。
-
访问多样化的数据:FL 促进了来自多个来源的数据汇集,使模型能够在不直接共享数据的情况下从多样化的数据集中学习。这在数据来源具有不同特征的情况下特别有益,例如不同的人口统计、地理区域或用户偏好。访问多样化的数据范围增强了机器学习模型的泛化能力和鲁棒性。
-
增强的安全性和弹性:使用 FL,数据分布在设备或边缘节点上,降低了单点故障或漏洞的风险。这种分布式特性增强了整个系统的安全性和弹性,使其对攻击或入侵的抵抗力降低。
-
用户赋权和包容性:联邦学习(FL)为用户参与和控制他们的数据提供了机会。用户不必将数据所有权和控制权交给中央权威机构,他们可以在保留对个人信息的控制的同时积极参与学习过程。这赋予了个人权力,并促进了包容性和透明度。
需要联邦学习(FL)的原因在于保护数据隐私、遵守监管框架、实现可扩展性和效率、访问多样化的数据源、确保安全以及赋予用户权力等关键要求。
通过利用联邦学习(FL),组织可以克服集中式方法的局限性,并释放分布式数据用于训练强大且保护隐私的机器学习模型。
保护隐私
让我们考虑 ARDHA 银行(仅用于说明目的的虚构银行)的案例。ARDHA 银行是一家在美国运营多年的金融机构,遵守特定国家的法规。该银行向客户提供一系列服务,包括欺诈预防、忠诚度计划和数字支付。最初,ARDHA 银行采用基于静态规则的系统来检测和预防欺诈活动。然而,意识到需要更先进的方法,他们转向利用机器学习算法来增强欺诈检测和预防。
通过访问包含历史和当前交易数据的综合数据集,ARDHA 银行开发了针对其运营的机器学习和深度学习(DL)算法。这些算法在这个广泛的数据集上进行了训练,使银行能够以极高的准确性有效地识别和预防金融欺诈。通过利用机器学习和深度学习技术的力量,ARDHA 银行显著提高了其检测和减轻欺诈性数字交易的能力,从而保护了客户的财务利益。

图 6.1 – 金融银行中的简单机器学习模型
ARDHA 银行在美国取得了成功之后,做出了战略决策,扩大其业务并在两个额外的国家设立分支机构——法国(针对欧洲)和印度。随着扩张,ARDHA 银行旨在为其两个地区的客户提供相同的服务套件。为了在法国和印度提供数字支付服务,ARDHA 银行考虑的一个选项是将两个国家的定期交易数据传输到其美国服务器。然后,美国服务器将作为运行机器学习模型的中央位置。在结合所有地区的综合数据上训练机器学习模型后,训练好的模型将被部署到法国和印度的区域服务器上。通过采用这种方法,ARDHA 银行旨在利用其美国服务器的基础设施来高效地处理和分析交易数据。集中训练机器学习模型允许采取统一的方法进行欺诈检测和预防,确保在不同地区的一致性和准确性。这一策略使 ARDHA 银行能够在欧洲和印度提供可靠有效的数字支付服务,同时保持数据安全和隐私。通过利用区域服务器并在本地部署训练好的机器学习模型,银行确保了快速和本地化的决策制定,满足每个地区的特定需求和监管要求。

图 6.2 – 在三个地点的金融银行中的简单机器学习模型
所提出的解决方案,涉及将数据传输到中央服务器并在该数据上运行机器学习模型,由于欧洲和印度的隐私法规和数据本地化法律而面临挑战。这些法规,如欧洲的通用数据保护条例(GDPR)和印度的数据本地化要求,规定在这些国家生成的数据必须存储在本地的数据中心。数据必须保持在创建它的国家境内。
考虑到这些隐私和本地化限制,需要一种替代方法。一个可能的替代方案是在银行的每个分支或地点本地运行机器学习(ML)模型。这种方法包括部署利用每个地点可用的本地数据的客户端模型。本地模型将在各自国家的边界内处理数据,确保符合隐私法规。为了实施这种替代方案,只有模型权重和参数,而不是客户使用的交易数据,会与中央服务器共享。任何国家的中央服务器将负责运行一个全局模型,使用来自每个位置的聚合模型权重和参数。然后,生成的全局模型可以定期分发给每个国家的本地客户端。这种方法使银行能够利用机器学习模型的好处,同时遵守隐私法规和数据本地化法律。通过在本地进行机器学习计算并仅共享模型相关信息,银行确保了合规性、数据安全和隐私。此外,这种分布式方法允许进行本地适应和定制,同时仍然受益于全局模型获得的见解。

图 6.3 – 本地模型与全局模型的交互
这种方法被称为联邦机器学习,或 FL。在 FL 中,将数据移动到中央位置的传统范式被颠倒。相反,模型和计算被带到数据那里。
在联邦学习中,机器学习(ML)模型直接部署并在数据所在的本地区域或设备上执行。这消除了将原始数据传输到中央服务器的需求,解决了隐私问题和监管要求。模型使用每个设备上的数据进行本地训练,并且只有模型更新,如梯度或权重,才会安全地传输到中央聚合器。
通过保持数据去中心化和本地执行计算,联邦学习(FL)确保了数据隐私并减少了与数据传输相关的风险。它允许组织利用分布式数据源的知识和洞察力,同时不损害个人数据隐私。这种方法在数据因法律、监管或隐私限制而难以共享的场景中尤其有益。
联邦学习代表了机器学习(ML)的一个范式转变,它实现了协作和隐私保护模型训练。它促进了一种分布式方法,其中数据保持在数据所有者的控制之下,同时为共享模型做出贡献。这种去中心化和注重隐私的框架为利用大规模数据的力量打开了可能性,同时不牺牲隐私和安全。
FL 定义
以下是根据在 arxiv/1912.04977 发表的 Federated Learning 的进展和开放问题 论文提出的 FL 的正式定义:
“联邦学习是一种机器学习设置,其中多个实体(客户端)在中央服务器或服务提供商的协调下协作解决机器学习问题。每个客户端的原始数据都存储在本地,不进行交换或传输;相反,用于立即聚合的聚焦更新用于实现学习目标”
根据这个定义,以下是 FL 的特点:
-
多个客户端(实体)协作解决机器学习问题。
-
服务提供商或中央服务器与这些实体协调。
-
原始数据(带有样本的数据)存储在每个客户端位置,并且不会传输到服务器。
-
定义了学习目标(或损失函数)。为了最小化损失(预测与实际之间的差异),客户端将聚焦更新(权重和偏差)发送到服务器,在服务器上进行权重的聚合(平均或动态聚合),然后将这些更新发送回客户端。
让我们进一步详细探讨每一个,以更好地理解它们。
FL 的特点
以下小节将深入探讨 FL 的特点。
多个客户端(实体)协作解决机器学习问题
在 FL 中,参与要求通常涉及至少两个客户端,而客户端的最大数量可以根据特定的用例和客户端类型而变化。
参与 FL 的客户端可以大致分为两类 – 跨设备和跨数据存储库:
-
跨设备客户端是个人设备,如智能手机、笔记本电脑或物联网设备,它们为模型训练贡献本地数据。这些设备在 FL 框架中作为客户端,允许其数据被利用同时保护隐私。
-
跨数据存储库客户端,另一方面,代表分布在不同的组织数据存储库或实体中的数据源。这些数据存储库可以是组织内部的不同部门,独立的机构,甚至是不同的地理区域。每个数据存储库作为客户端,为其协作模型训练贡献本地数据。

图 6.4 – FL 客户端的分类
FL 设置中客户端的最大数量取决于特定的用例和分布式数据源的规模。例如,在多个组织协作构建全球模型同时保持数据隐私的场景中,参与客户端的数量可能很大。另一方面,在更专注或本地化的用例中,客户端的数量可能限制在一个较小的群体。
跨数据存储库 FL 客户端
跨部门客户端包括金融机构、机构、医院和制药公司等实体。这些客户端可以进一步分为两组:
-
同一机构内的不同客户端:这包括同一银行的分支机构、医院网络内的不同分支机构,以及类似设置,其中多个分支机构或一个机构的多个部门参与联邦学习。
-
不同机构间的不同客户端:这涉及不同组织,如不同银行或医院,进行合作并向联邦学习过程贡献数据。这些客户端代表机构间的合作。
跨部门类别中的最大客户端数量可以根据具体用例而变化,但通常在数十到数百之间。由于合作性质和参与机构的规模,参与客户端的数量通常受到限制。
跨设备联邦学习客户端
相反,跨设备客户端包括作为联邦学习中的客户端或节点的各种设备。这些设备可以是同质或异质的,例如苹果 iPhone、谷歌手机和 Brave 浏览器等设备。
在跨设备联邦学习客户端的情况下,每个设备都根据该特定设备上可用的本地数据运行自己的机器学习模型。仅根据设备条件和其他配置设置将模型权重和偏差传输到服务器。
在这种情况下,客户端的最大数量可以达到数千甚至数百万,因为它涵盖了不同地点和用户基础中参与联邦学习的广泛设备。
通过同时容纳跨部门和跨设备客户端,联邦学习实现了协作和知识共享,同时尊重数据隐私并确保机构间和设备间的可扩展参与。
服务提供商或中央服务器与这些实体进行协调
在联邦学习中,服务器根据参与客户端的网络拓扑和参与过程的总客户端数量做出决策。服务器确定何时向客户端分发初始模型或更新模型,考虑因素包括网络结构和具体参与客户端的数量。它根据学习任务的要求,决定是否向所有客户端或仅向其中一部分发送模型更新。
客户端接收到模型后,根据其本地数据计算并更新权重和偏差。然后,客户端将这些更新的权重和偏差发送回服务器。服务器汇总接收到的数据,并使用目标函数进行计算,以最小化损失或优化学习目标。
根据汇总信息,服务器生成一个更新的模型。它决定哪些客户端需要更新为新模型,哪些客户端可以继续运行现有模型而不做任何更改。这个决定基于学习进度、更新的需要或客户端与更新模型的兼容性等因素。
通过精心安排这些步骤,服务器管理模型的分布,收集客户端更新,汇总数据,并最终将更新的模型发送回适当的客户端。在联邦学习(FL)中,这个迭代过程确保了协作模型改进,同时考虑到参与客户端的个别需求和能力。
原始数据(带有样本的数据)在每个客户端位置本地存储,并且不会传输到服务器。
在 FL 中,原始数据在每个客户端位置本地存储,而不是集中存储在单个服务器上。这种去中心化的方法确保数据始终处于各自客户端的控制和所有权之下,保护隐私并符合数据法规。
每个客户端位置的数据都表现出特定的分布,这种分布可能在不同客户端之间有所不同。数据的分布指的是数据集中存在的统计特性和模式。客户端数据集中的数据样本可能相互独立,这意味着它们之间没有关系或它们的价值或属性不依赖于彼此。或者,数据样本可能是相关的,表明它们之间存在某种形式的关联或关系。
此外,数据分布可以在客户端之间是相同的或不同的。相同的数据分布意味着不同客户端的数据集的统计特性是相同的。另一方面,不同的数据分布表明数据集在统计特性上存在差异,例如均值、方差或其他相关参数。
独立或相关、相同或不同的数据分布的存在,在 FL 中引入了挑战和复杂性。尽管如此,FL 方法被设计来处理这些变化,并使跨去中心化数据源进行协作模型训练成为可能,同时利用集体知识,尊重数据隐私和分布特性。
具有独立同分布(IID)和非独立同分布(non-IID)数据的集合
独立同分布(IID)数据指的是数据样本之间相互独立,且所有样本的数据分布相同的数据集。在这种情况下,每个数据样本的结果不依赖于先前样本,数据的统计特性保持一致。
例如,考虑一个数据集,其中抛掷硬币五次并记录出现正面的次数。在这种情况下,每次抛掷硬币都是独立的,每次抛掷出现正面的概率是相同的。这导致了一个 IID 数据集,其中每次抛掷硬币的结果分布是相同的。
在 FL 中,不同客户端之间的数据可能表现出非-IID特征。这意味着数据样本不是同质分布的,它们也可能相互依赖。各种因素可能导致非-IID 数据,例如标签数据的数量变化、样本中存在的特征差异、数据漂移、概念漂移或不平衡数据。
例如,在公司内部的跨部门实体中,每个客户端可能具有相同的特征和标签用于分类。然而,每个位置的数据样本数量可能不同,导致数据不平衡。此外,每个位置可能没有所有类别的数据,或者表现出不同的实例分布。
FL 中跨部门实体的原始数据
在处理 FL 中的跨部门实体时,原始数据表现出某些特征。具体来说,在内部公司场景中,可以观察到以下情况:
-
跨部门实体中的每个客户端都将拥有相同类型的特征。这意味着可用于分析的数据属性或变量的类型将在所有客户端中保持一致。
-
用于分类任务的标签或类别在客户端之间也将是相同的。这确保了参与实体中的分类目标类别或结果的一致性。
-
每个客户端位置的数据样本数量可能不同。这意味着可用的数据量可能在不同的位置或同一公司内的不同分支之间有所不同。一些客户端可能有更广泛的数据集,而其他客户端可能有较少的样本。
-
并非所有类别或类别可能在每个客户端的数据中都有表示。这导致数据不平衡,某些类别可能相对于其他类别被过度或不足表示。这种不平衡可能会对模型训练和评估造成挑战。
-
实例的分布可能不会在所有客户端中相同。这意味着统计特征,如均值、方差或其他属性,可能在不同的客户端位置之间有所不同。每个客户端的数据可能表现出独特的分布模式,这些模式需要在 FL 过程中予以考虑。
考虑到这些特征,FL 技术必须解决数据样本的变异性、类别分布的不平衡以及跨部门实体间的数据分布差异。
在我们讨论的银行示例的背景下,由于它是同一银行在不同国家运营,因此特征(如客户 ID、金额、交易日期、源账户、目标账户和地址)和标签(欺诈或非欺诈)将是相同的。然而,数据样本和标签的分布可能因每个位置的客户数量和交易类型等因素而异。这给数据引入了非独立同分布(non-IID)的特性,需要在联邦学习方法中谨慎处理。

图 6.5 – 三地金融银行中的机器学习模型
数据以以下方式分配给每个客户端。标签数据存在偏斜,但每个位置/客户端/实体中均存在具有所有特征的样本。
| 不同客户端的数据 | 特征 X= | 标签 y = |
|---|---|---|
| X1 | X2 | X3 |
| 欧洲(客户端 1) | 是 | 是 |
| 美国(客户端 2) | 是 | 是 |
| 印度(客户端 3) | 是 | 是 |
表 6.1 – 标签数据偏斜
在机构内部的情况下,即同一行业内不同机构参与联邦学习(FL)以提供类似的机器学习(ML)服务时,数据可能表现出以下特征:
-
每个客户端,代表不同的机构,可能具有或不具有相同类型的特征。这意味着根据它们的具体背景或数据收集实践,不同机构之间可用的数据属性或变量可能不同。
-
每个客户端位置的数据样本数量可能不同。这表明不同机构可用于分析的数据量可能不同。一些机构可能拥有更大的数据集,而其他机构可能拥有相对较小的数据集。
-
并非所有类别或类别都可能在每个客户端的数据中存在。这可能导致数据不平衡,某些类别可能在某些机构的数据集中代表性不足或完全缺失。在联邦学习过程中处理不平衡数据是一个重要的考虑因素。
-
参与机构之间的示例分布也可能不同。每个机构的数据可能具有其独特的分布模式,包括均值、方差或其他统计特性的变化。这些差异需要在协作模型训练过程中予以考虑。
![图 6.6 – FL 客户端和服务器通信(发送和接收)模型参数]()
图 6.6 – FL 客户端和服务器通信(发送和接收)模型参数
数据以以下方式分配给每个客户端。在此场景中,特征和标签数据存在偏斜。
| 不同客户端的数据 | 特征 X= | 标签 y = |
|---|---|---|
| X1 | X2 | X3 |
| --- | --- | --- |
| 客户端 1 | 是 | |
| 客户端 2 | 是 | |
| 客户端 3 | 是 | 是 |
表 6.2 – 不同客户端的特征和标签数据偏斜
学习目标
在 FL 中,中央服务器承担执行学习目标和最小化损失函数的责任。它通过利用从参与客户端接收到的模型权重(Wt)和偏差来实现这一点。服务器确定需要从客户端获取的数据轮数以及需要参与的特定客户端。
让我们考虑一个例子,其中涉及三个参与 FL 过程的客户端。每个客户端将其各自的模型权重和偏差发送到中央服务器。然后,服务器执行以下目标或学习函数以最小化损失:
minimize loss (**Wt, biases)
服务器的目标是优化由权重(Wt)和偏差表示的模型参数,以最小化损失函数。通过利用从参与客户端接收到的权重和偏差,服务器执行迭代更新以细化模型并提高其性能。
学习目标和损失函数的具体细节取决于特定的 ML 算法和手头的任务。中央服务器协调客户端更新的聚合,管理训练过程,并将更新的模型发送回客户端。这种协作方法使客户端能够集体贡献其本地知识,同时从服务器提供的改进的全球模型中受益。
这就是目标函数:
Min f(w) = ∑ i=1 n £i * Fi(w)
这里,w 是模型参数(权重等),f(w) 是目标函数,n 是参与 FL 的客户端数量。
在下一节中,将使用一些数学术语,包括以下内容。
-
Wt: 在通信轮次 t 中的模型权重(客户端到服务器)
-
Wt k: 在客户端 k 的通信轮次中的模型权重
-
C: 每轮更新模型和计算权重的参与客户端数量
-
B: 本地客户端数据样本的批量大小
-
Pk: 客户端 k 的数据样本集
-
nk: 客户端 k 的数据点数量
-
fi (w): loss L ( xi, yi, w) – 损失函数
在服务器端,可以根据 FL 过程的特定需求和目标实现各种目标函数。
FL 算法
FL 算法,如 FedSGD、FedAvg 和自适应联邦优化,在确保隐私和安全的同时,在机器学习模型的分布式训练中发挥着关键作用。在本节中,我们将探讨这些算法及其关键特性。
FedSGD
联邦随机梯度下降(FedSGD)是 FL 中使用的根本算法。它将传统的 SGD 优化方法扩展到联邦设置。在 FedSGD 中,每个客户端(实体)在其本地数据上计算梯度,并将它们发送到中央服务器。服务器聚合梯度并相应地更新全局模型参数。FedSGD 适用于大规模分布式训练,但可能受到与非-IID 数据和通信效率相关的问题的影响。

图 6.7 – FedSGD 模型权重与服务器交换
让我们看看 FedSGD 算法:
| 服务器端算法 | 客户端算法 |
|---|
| 初始化每个轮次 t = 1,2, …m = max (C, K, 1)st = 随机选择的 m 个客户端 for 客户端 k 在 st 中,wt+1 = 客户端函数(k, wt)wt+1 = 权重的平均值 | 客户端函数(k, w):
-
将数据分成k个批次,每个批次基于批次大小B(完整本地数据集)
-
对于每个批次:
-
fi (w) = 损失 L (xi, yi, w)
-
w = w – 学习率 * 损失
|
表 6.3 - FedSGD 算法
在客户端,每个参与客户端执行以下步骤:
-
数据分区:客户端拥有自己的本地数据集,并将它们分成更小的子集以确保隐私。
-
本地模型训练:每个客户端独立使用其本地数据训练共享模型。这涉及到使用 SGD 或其变体在本地数据集上计算模型参数(权重和偏差)的梯度。
-
模型更新:在本地模型训练后,客户端将计算的梯度发送到服务器进行聚合。
在服务器端,中央服务器执行以下步骤:
-
聚合:服务器从所有参与客户端接收梯度,并使用各种聚合技术(如平均或加权平均)进行聚合。
-
模型更新:聚合的梯度用于更新全局模型参数。服务器将接收到的梯度应用于全局模型,调整其权重和偏差以反映所有客户端的集体知识。
-
模型分发:然后,更新后的全局模型被发送回客户端进行下一轮训练,确保每个客户端都能从集体知识中受益,同时保护数据隐私。
FedSGD 旨在通过仅交换模型梯度而不是原始数据来最小化客户端和服务器之间的通信开销。这允许在保持数据隐私和安全的同时进行分布式模型训练。然而,解决诸如数据异质性和非-IID 数据分布等挑战非常重要,这些挑战可能会影响 FL 过程的收敛性和性能。
总体而言,FedSGD 以去中心化的方式实现了协作模型训练,利用了多个客户端的计算资源,同时保护了数据隐私。它是联邦学习的基础算法,为更高级的技术的开发铺平了道路,以改进分布式机器学习的效率和效果。
FedAvg
联邦平均(FedAvg)是一种广泛采用的联邦学习算法,旨在解决非独立同分布数据和非高效通信的挑战。在 FedAvg 中,类似于 FedSGD,每个客户端在其本地数据上计算梯度。然而,FedAvg 不是直接使用单个梯度更新全局模型,而是采用加权平均来组合客户端模型的参数。这种方法可以更好地处理数据异构性,并减少客户端与服务器之间的通信开销。

图 6.8 – FedAvg 模型与服务器之间的权重交换
让我们看看 FedAvg 算法:
| 服务器端算法 | 客户端算法 |
|---|
| 初始化每轮 t = 1,2, …m = max (C, K, 1)的权重(w0)st = 随机选择 m 个客户端 for 客户端 k 在 st 中,wt+1 = 客户端函数(k, wt)wt+1 = 梯度的平均值 | 客户端函数(k, w):
-
将数据分成k个批次,每个批次基于批次大小B
-
对于训练中的每个 epoch E
-
对于每个批次:
-
fi (w) = 损失 L (xi, yi, w)
-
w = w – 学习率 * 损失
-
|
表 6.4 – FedAVG 算法
FedAvg 利用平均的概念来组合不同客户端的本地训练模型,这有助于减轻数据异构性和非独立同分布数据分布的影响。通过平均模型参数,FedAvg 有效地创建了一个全局模型,该模型捕捉了所有参与客户端的见解,同时保护了个人数据的隐私。FedAvg 的迭代性质允许共享模型在每一轮训练中逐步改进。随着过程的继续,全局模型变得更加精细,代表了所有客户端的集体知识。
总体而言,FedAvg 以保护隐私的方式实现了共享模型的协作训练。它解决了与数据隐私和分布相关的挑战,允许多个客户端在不共享原始数据的情况下为模型改进做出贡献。FedAvg 在联邦学习的领域中发挥了重要作用,使得在各个领域中的应用成为可能,同时保持了数据隐私和安全。
Fed Adaptative Optimization
在跨设备联邦学习中,众多客户端与一个中央服务器通信,每个客户端拥有独特的数据集。
例如,在手机上的下一个单词预测的背景下,不同用户的手机根据国家、地区和语言等因素包含不同的单词集。然而,当面对来自不同客户端的异构数据时,传统的 FL 算法如 FedSGD 和 FedAvg 可能无法表现最佳。挑战源于客户端之间数据分布和特性的固有差异。异构数据引入的复杂性可能会影响 FL 算法的收敛性和性能。因此,与客户端具有同质数据的情况相比,处理异构数据构成了相当大的障碍。
正在努力解决跨设备联邦学习(FL)中与异构数据相关联的挑战。
为了克服这一点,谷歌的研究人员(Sashank J. Reddi 等人,2021 年)在 arxiv.org/abs/2003.00295 发表的论文中提出了新的自适应优化方法。
这里是详细的算法(图片来源于前面的 URL):

图 6.9 – 谷歌研究人员提出的 Fed Adaptive Optimization 算法
请参阅文章以获取自适应优化算法的详细解释。简而言之,这个想法是优化通信成本,类似于 FEDAVG,并在跨设备环境中工作。
实施联邦学习所涉及的步骤
以下通常是实现联邦学习(FL)所遵循的五个步骤。这些步骤可能有替代方案/变化,但最初,这些是需要遵循的步骤:
服务器端 – 全局模型的初始化:在这个步骤中,服务器启动并接受客户端请求。在实际启动服务器之前,服务器端的模型将使用模型参数进行初始化。通常,模型参数将初始化为零或从之前的检查点模型中获取。
服务器将模型参数发送到所有或部分客户端:在这个步骤中,服务器将初始模型参数发送到所有客户端(对于跨沙盒 FL 客户端,它们将位于同一机构内,可能只有几十个)或部分客户端(在跨设备 FL 的情况下,设备数以百万计,服务器决定只从总数中选择一部分)。每个客户端将使用这些初始模型参数进行模型的本地训练。
客户端训练模型并将模型权重/参数发送回服务器:在这个步骤中,每个客户端将使用其本地数据训练模型,一次性使用全部本地数据,将数据分成几个批次,或者随机分割数据并利用不同轮次(客户端和服务器之间多次交换模型参数)的不同分割。客户端只会将模型参数或权重发送到服务器。
服务器执行一个 FL 算法,更新全局模型,并将更新的权重发送给客户端进行下一轮:在这一步中,服务器将运行一个 FL 算法,并利用从客户端接收到的权重来更新全局模型。在 FedAvg 的情况下,它将计算从客户端接收到的权重的加权平均值,并将更新的权重发送回客户端进行下一轮。
根据配置的轮数重复步骤 2 到 4:对于每一轮重复步骤 2 到 4。如果配置了五轮,那么重复步骤 2 到 4 五次,在最后一轮之后,客户端将利用从服务器接收到的权重来使用最终的机器学习模型。客户端可以在最后一轮结束时或每一轮中使用这些模型权重,并使用测试数据评估模型的准确性。
以下序列图详细展示了这些步骤:

图 6.10 – FL 序列图中的步骤
序列图显示了参与联邦学习(FL)的服务器和客户端之间的详细交互,按照本节所述执行四个高级步骤。
实现 FL 的开源框架
有几个开源框架可以用于大规模实现 FL。以下是一些最受欢迎的。
PySyft(github.com/OpenMined/PySyft),由 OpenMined 开发,是一个开源栈,它提供了在 Python 中安全且私有的数据科学能力。它引入了私有数据和模型训练之间的分离,使得 FL、差分隐私和加密计算等功能成为可能。最初,PySyft 利用 Opacus 框架来支持差分隐私,如差分隐私章节所述。然而,PySyft 的最新版本集成了自己的差分隐私组件,以提供在执行数据分析任务时保护隐私的同时增强功能和效率。
TensorFlow Federated
TensorFlow Federated(TFF)是由谷歌开发的一个库,它通过使用客户端的本地数据来简化跨多个客户端训练共享机器学习模型的过程(www.tensorflow.org/federated)。TFF 由两层组成——联邦核心 API 和联邦学习 API。
联邦核心 API 提供了低级接口,用于数据序列化、服务器和客户端之间的分布式通信以及 FL 算法的实现。它提供了构建 FL 系统所需的基础组件。
相反,联邦学习 API 提供了一个高级接口,使用户能够轻松构建联邦学习模型或将现有模型包装为联邦学习模型。它提供了一套 API,用于使用联邦计算和数据集进行模型训练和评估。这个高级接口抽象了一些构建和训练联邦学习模型所涉及到的复杂性,使得它对开发者来说更加易于访问和方便。
通过提供这两层,TFF 使研究人员和开发者能够在其项目中利用联邦学习的力量。它简化了在去中心化数据上构建和训练模型的过程,同时确保隐私和数据安全。
Flower
Flower (flower.dev/) 是一个开源框架,旨在提供用户友好的体验。它支持使用各种框架开发的机器学习和深度学习模型,例如 scikit-learn、TensorFlow、PyTorch、PyTorch Lightning、MXNet 和 JAX。Flower 使得将这些模型转换为联邦学习模型变得容易。
Flower 的一个关键特性是其通信实现,它建立在双向 gRPC 流之上。这允许客户端和服务器之间高效且无缝地交换多个消息,而无需为每个消息请求建立新的连接。
Flower 提供了一系列策略,并在服务器端实现了几个联邦学习算法。这些算法包括 FedAvg、FedSGD、容错 FedAvg、FedProxy 和 FedOptim(包括 FedAdagrad、FedYogi 和 FedAdam)。这些算法在联邦学习场景中提供了不同的模型聚合和训练方法。

图 6.11 – Flower 框架架构图(简化)
为了验证其性能,Flower 已经进行了广泛的基准测试。该框架已经证明了仅使用两个 GPU 服务器就能扩展到 1500 万客户端的能力。这些实验与另一个联邦学习引擎和基准测试套件 FedScale 进行了比较,以评估 Flower 在大型联邦学习环境中的性能和效率。
使用联邦学习实现欺诈检测的端到端用例
欺诈检测对许多行业,包括金融、电子商务和医疗保健,都是一个关键任务。传统的欺诈检测方法通常依赖于集中式数据收集,其中敏感的客户信息在单一地点收集和分析。然而,这种方法引发了关于数据隐私和安全以及遵守 GDPR 等法规的担忧。
FL 为解决这些挑战提供了一个有希望的解决方案。通过利用分布式计算和协作学习的力量,FL 使得欺诈检测模型可以直接在单个机构的设备或本地服务器上训练,无需共享数据。这种去中心化的方法确保敏感客户数据保持私密和安全,因为它从未离开本地环境。
使用联邦学习(FL)实现欺诈检测涉及几个关键步骤。首先,由银行或电子商务平台等机构或组织组成的联盟需要建立一个 FL 框架,使他们能够在保护数据隐私的同时协作进行模型训练。这可能涉及采用 FL 库或平台,如 TFF 或 Flower。
接下来,参与机构定义一个共同的欺诈检测目标并开发共享的模型架构。然后,每个机构使用自己的私有数据训练其本地模型,这些数据可能包括交易记录、用户行为模式和其他相关特征。模型在本地进行训练,确保敏感数据始终处于相应机构的控制之下。
为了促进协作学习,机构定期将模型更新与中央服务器共享。这些更新通常包括模型权重和参数,通过联邦平均或其他聚合技术进行汇总,以创建一个全局模型,该模型能够捕捉到所有参与者的洞察,同时保护个人数据的隐私。
负责监督聚合过程的中央服务器确保全局模型基于参与机构的集体知识进行优化。这个过程允许模型从各种欺诈模式中学习,并适应不断发展的欺诈活动,同时保持数据隐私并符合法规。
使用 FL 实现欺诈检测提供了几个优势。它允许机构利用更大、更多样化的数据集,从而提高欺诈检测的准确性。它还降低了数据泄露或未经授权访问的风险,因为敏感数据始终处于相应机构的控制之下。此外,FL 可以实现实时更新和更快的模型部署,使机构能够迅速应对新出现的欺诈模式。
使用 FL 实现欺诈检测为各种行业中的欺诈提供了隐私保护和协作的方法。通过结合分布式计算和共享学习的力量,组织可以增强欺诈检测能力,同时保护敏感客户数据。
让我们使用 Flower 框架和开源数据集来实现这个用例。
使用 Flower 框架开发用于欺诈检测的 FL 模型
在本例中,我们将利用 Flower 框架开发用于欺诈检测的 FL 模型。实现将涉及服务器端和客户端组件。为了说明这个过程,我们将设置一个服务器和两个客户端。
服务器和客户端之间的通信将在多个轮次中进行,涉及权重和参数的交换。具体的轮次数量可能因具体场景而异,但通常,通信会持续到权重收敛或达到预定的收敛标准。
在服务器端,我们将实现 FedAvg 算法来聚合从客户端接收到的权重。FedAvg 是 FL 中广泛使用的算法,它结合了多个客户端的知识来创建一个全局模型。
对于欺诈检测任务,我们将使用 scikit-learn 库开发一个实际的线性回归模型。此模型将使用每个客户端可用的数据进行训练,这些数据包括交易记录和相关特征。目标是分类交易是否为欺诈。
客户端实现将涉及使用各自客户端的数据训练本地线性回归模型。然后,客户端将与服务器通信,在预定义的轮次中交换他们的模型权重和参数。这种协作学习过程允许客户端将其本地见解贡献给全局模型,同时保护其数据的隐私。
服务器将从客户端接收模型更新,并使用 FedAvg 算法执行聚合步骤。此聚合过程确保全局模型结合了所有参与客户端学习到的知识,从而增强了欺诈检测能力。
在整个实现过程中,Flower 框架为服务器和客户端之间的通信提供了必要的基础设施。它抽象了分布式计算的底层复杂性,并处理模型更新的同步。通过开发用于欺诈检测的 FL 模型,我们可以利用多个客户端的分布式知识和数据来提高欺诈分类的准确性。联邦方法还通过将敏感的交易数据保留在每个客户端本地来解决隐私问题。
总结来说,这个项目展示了使用 Flower 框架实现 FL 模型的过程。服务器和客户端协作训练一个用于欺诈检测的全局模型,在多个通信轮次中交换模型权重和参数。通过使用 FedAvg 聚合客户端模型,我们可以利用多个参与者的集体智慧,同时确保数据隐私。
本例中使用的数据集
Lopez, Elmir, 和 Axelsson 开发了一个用于欺诈检测的移动货币数据集,并在 Kaggle 上也有展示(E. A. Lopez-Rojas, A. Elmir, 和 S. Axelsson, PaySim: A financial mobile money simulator for fraud detection, 第 28 届欧洲建模与仿真研讨会-EMSS,拉纳卡,塞浦路斯。2016)。
我们将利用此数据集通过 FL 进行欺诈检测,但也可以通过修改模型以适应反洗钱用例,数据集可在github.com/EdgarLopezPhD/PaySim找到。
下载此数据集,并将文件保存在第六章目录中,文件名为PS_20174392719_1491204439457_log.csv。
此数据集包含 630 万条交易记录,具有以下特征:
| 字段 | 数据类型 | 详细信息 |
|---|---|---|
Step |
数值 | 现实世界中的时间单位。一步是 1 小时。 |
Type |
对象 | CASH-IN,CASH-OUT,DEBIT,PAYMENT和TRANSFER。 |
Amount |
数值 | 交易金额。 |
nameOrig |
对象 | 开始交易的客户。 |
nameDest |
对象 | 交易的接收者 ID。 |
oldbalanceOrg |
数值 | 交易前的初始余额。 |
newbalanceOrig |
数值 | 交易后客户的余额。 |
oldbalanceDest |
数值 | 交易前初始接收者的余额。 |
newbalanceDest |
数值 | 交易后接收者的余额。 |
isFraud |
布尔值 | 识别欺诈(1)和非欺诈(0)交易。 |
isFlaggedFraud |
布尔值 | 标记非法尝试在单笔交易中转账超过 20 万金额。 |
表 6.5 – 数据集特征
Flower 的安装
使用python -m pip install flwr命令安装 Flower。
服务器的实现
欺诈检测的 FL 模型的服务器端实现涉及几个高级步骤。我们将利用 Flower 框架提供的示例代码,并将其扩展以适应我们的特定用例。
以下步骤概述了该过程:
-
初始化模型参数:
-
将初始模型权重设置为0,并将截距初始化为0(因为我们正在使用回归模型)。
-
确定分类的类别或标签数量。
-
确定模型中使用的特征数量。
-
确定参与客户端的数量。
-
-
定义支持函数:开发额外的函数以从客户端加载数据,定义损失函数,并评估模型的性能。这些函数将有助于数据处理,计算训练过程中的损失,并评估模型的准确性。
-
选择服务器端策略:选择 FedAvg 算法作为从客户端接收权重的聚合策略。FedAvg 是结合多个客户端的模型更新并生成更新全局模型的一个流行选择。
-
启动 服务器:
-
启动服务器端组件,该组件将协调 FL 过程。
-
服务器将与参与客户端通信,接收他们的模型更新,并使用 FedAvg 算法汇总权重。
-
它还将处理客户端之间的模型更新同步,并确保全局模型的收敛。
-
通过遵循这些步骤,我们可以实现 FL 模型的服务器端功能。模型参数的初始化、支持函数的定义、服务器端策略(FedAvg)的选择以及启动服务器本身对于促进客户端之间的协作训练过程至关重要。通过此实现,服务器将作为中央协调者,接收并汇总来自客户端的模型更新。它在确保模型收敛和生成包含所有参与客户端知识的更新全局模型中发挥着关键作用。
将以下代码保存为FL_AML_Server.py:
import pandas as pd
url ="PS_20174392719_1491204439457_log.csv"
df_actual = pd.read_csv(url, sep=",")
df_actual
这将产生以下输出:

图 6.12 – 少行少列的 dataset 信息
在此示例实现中,我们不会使用全部 600 万条记录,而只会使用前 25,000 条记录:
df_transactions=df_actual.head(25000)
from sklearn.model_selection import train_test_split
from sklearn.model_selection import StratifiedShuffleSplit
print("No of Fraud Transactions:",
df_transactions["isFraud"].value_counts()[0])
print("No of Non Fraud Transactions:",
df_transactions["isFraud"].value_counts()[1])
print('No Frauds',
round(df_transactions['isFraud'].value_counts()[0]/len(df_t
ransactions) * 100,2), '% of the dataset')
print('Frauds',
round(df_transactions['isFraud'].value_counts()[1]/len(df_t
ransactions) * 100,2), '% of the dataset')
这将产生以下输出:
No of Fraud Transactions: 24917
No of Non Fraud Transactions: 83
No Frauds 99.67 % of the dataset
Frauds 0.33 % of the dataset
让我们找出数据集中每个字段的类型:
df_transactions.dtypes
这将产生以下输出:
step int64
type object
amount float64
nameOrig object
oldbalanceOrg float64
newbalanceOrig float64
nameDest object
oldbalanceDest float64
newbalanceDest float64
isFraud int64
isFlaggedFraud int64
dtype: object
使用LabelEncoder将对象数据类型字段编码为标签:
from sklearn.preprocessing import LabelEncoder
encoder = {}
for i in df_transactions.select_dtypes('object').columns:
encoder[i] = LabelEncoder()
df_transactions[i] = encoder[i].fit_transform(df_transactions[i])
X = df_transactions.drop('isFraud', axis=1)
y = df_transactions['isFraud'
from typing import Tuple, Union, List
import numpy as np
from sklearn.linear_model import LogisticRegression
XY = Tuple[np.ndarray, np.ndarray]
Dataset = Tuple[XY, XY]
LogRegParams = Union[XY, Tuple[np.ndarray]]
XYList = List[XY]
def get_model_parameters(model: LogisticRegression) -> LogRegParams:
if model.fit_intercept:
params = [
model.coef_,
model.intercept_,
]
else:
params = [
model.coef_,
]
return params
def set_model_params(
model: LogisticRegression, params: LogRegParams
) -> LogisticRegression:
model.coef_ = params[0]
if model.fit_intercept:
model.intercept_ = params[1]
return model
def shuffle(X: np.ndarray, y: np.ndarray) -> XY:
rng = np.random.default_rng()
idx = rng.permutation(len(X))
return X[idx], y[idx]
def partition(X: np.ndarray, y: np.ndarray, num_partitions: int) -> XYList:
return list(
zip(np.array_split(X, num_partitions), np.array_split(y, num_partitions))
)
def set_initial_params(model: LogisticRegression):
n_classes = 2 # Fraud Detection has only classes
n_features = 9 # Number of features in dataset
model.classes_ = np.array([i for i in range(n_classes)])
model.coef_ = np.zeros((n_classes, n_features))
if model.fit_intercept:
model.intercept_ = np.zeros((n_classes,))
import flwr as fl
from sklearn.metrics import log_loss
from sklearn.linear_model import LogisticRegression
from typing import Dict
def fit_round(server_round: int) -> Dict:
"""Send round number to client."""
return {"server_round": server_round}
def get_evaluate_fn(model: LogisticRegression,X_test,y_test):
# The `evaluate` function will be called after every round
def evaluate(server_round, parameters: fl.common.NDArrays, config):
# Update model with the latest parameters
set_model_params(model, parameters)
loss = log_loss(y_test, model.predict_proba(X_test))
accuracy = model.score(X_test, y_test)
return loss, {"accuracy": accuracy}
return evaluate
# Start Flower server for five rounds of federated learning
def Server():
model = LogisticRegression(max_iter=10000)
set_initial_params(model)
strategy = fl.server.strategy.FedAvg(
min_available_clients=2,
evaluate_fn=get_evaluate_fn(model,X_test,y_test),
on_fit_config_fn=fit_round,
)
fl.server.start_server(
server_address="0.0.0.0:8080",
strategy=strategy,
config=fl.server.ServerConfig(num_rounds=5),
)
Server()
打开终端并运行此程序(python3 FL_AML_Server.py)
这将产生以下输出:

图 6.13 – 服务器启动日志
服务器将运行并等待来自客户端的数据进行处理。
客户端的实现
欺诈检测 FL 模型的客户端实现涉及以下步骤。我们将利用 Flower 示例中提供的NumPyClient。步骤如下:
-
加载 数据:
-
加载相关数据以训练和测试欺诈检测模型。
-
确保数据格式正确且可用于处理。
-
-
分割 数据:
将加载的数据分割成训练集和测试集。这种划分允许你在未见过的数据上评估模型的性能。
-
洗牌/分区 数据:
-
将训练数据洗牌或分区成批次。
-
在与服务器通信的每一轮中随机选择一个分区。这确保了在每一轮中使用不同的训练数据子集。
-
-
创建线性 回归模型:
-
使用所选框架(例如,scikit-learn)开发一个简单的线性回归模型。
-
为欺诈检测任务配置模型适当的设置。
-
-
与服务器建立连接:
-
与服务器建立连接以发送和接收模型权重。
-
利用提供的通信协议(例如,gRPC)交换信息。
-
-
训练模型:
-
使用从服务器接收的初始权重初始化模型。
-
使用客户端的本地数据和服务器在每个轮次更新的权重来训练模型。
-
应用适当的优化技术(例如,梯度下降)来更新模型参数。
-
-
测试模型:
-
使用测试数据评估训练模型的性能。
-
计算相关指标,如准确率、精确率、召回率或 F1 分数。
-
确定模型在检测欺诈交易方面的有效性。
-
通过遵循这些步骤,我们可以实现 FL 模型的客户端功能。客户端将加载数据并对其进行分区,创建线性回归模型,与服务器建立连接,使用本地数据和更新的权重训练模型,并评估其性能。客户端在贡献本地知识的同时保护数据隐私的作用至关重要。通过在各自本地数据上训练并参与 FL 过程,客户端共同提高全局欺诈检测模型,而不共享敏感信息。
创建一个非 IID 数据集
要将数据集转换为非 IID 设置,我们可以采用以下方法:
-
第一个客户端(客户端 1):
-
对欺诈交易应用合成少数类过采样技术(SMOTE)以增加样本量
-
这种技术生成少数类(欺诈交易)的合成示例以平衡数据集
-
因此,客户端 1 将有一个包含 50,000 个样本的训练数据集,其中包括 25,000 个原始交易和 25,000 个使用 SMOTE 创建的合成欺诈示例
-
欺诈与非欺诈交易的分布将在每个类别中平衡至 50%
-
-
第二个客户端(客户端 2):
-
不对交易进行任何过采样或修改
-
客户端 2 将有一个包含最后 25,000 个交易的训练数据集
-
类别分布将反映原始分布,只有 2%的交易被分类为欺诈
-
通过采用这种方法,我们在两个客户端之间引入了非相同和不平衡的数据集。客户端 1 将有一个平衡的数据集,欺诈和非欺诈交易的代表性相等,而客户端 2 将有一个与原始分布相似的数据集。
这种非 IID 设置使我们能够模拟现实世界场景,其中不同的客户端可能具有不同的数据分布。通过联邦学习(FL),两个客户端都可以贡献其本地知识,同时在不同的数据集上训练模型,从而最终提高整体欺诈检测模型的性能。
| 客户端 1 | 客户端 2 | |
|---|---|---|
| 原始交易 | 25,000 | 25,000 |
| 使用 SMOTE 生成的事务 | 25,000 | 0 |
| 总交易数 | 50,000 | 25,000 |
| 欺诈与非欺诈 | 50% 和 50% | 欺诈:2.43%(608)非欺诈:97.57%(24,392) |
| 训练和测试分割 | 70:30 | 70:30 |
| 在每个分区大小相等的情况下,对训练数据进行洗牌后的分区数 | 10 | 10 |
表 6.6 – 客户端侧的非 IID 训练数据分布
这里是客户端 1 的代码。将此代码保存为 FL_AML_Client1.py:
import pandas as pd
import torch
url ="PS_20174392719_1491204439457_log.csv"
df_actual = pd.read_csv(url, sep=",")
df_actual
df_transactions=df_actual.head(25000)
from sklearn.model_selection import train_test_split
from sklearn.model_selection import StratifiedShuffleSplit
print("No of Fraud Transactions:", df_transactions["isFraud"].value_counts()[0])
print("No of Non Fraud Transactions:", df_transactions["isFraud"].value_counts()[1])
print('No Frauds', round(df_transactions['isFraud'].value_counts()[0]/len(df_transactions) * 100,2), '% of the dataset')
print('Frauds', round(df_transactions['isFraud'].value_counts()[1]/len(df_transactions) * 100,2), '% of the dataset')
这将产生以下输出:
No of Fraud Transactions: 24917
No of Non Fraud Transactions: 83
No Frauds 99.67 % of the dataset
Frauds 0.33 % of the dataset
在这个数据集中,欺诈交易占总数据的 0.33%,表明数据集高度不平衡。这种不平衡在现实场景中很典型,欺诈交易比真实(非欺诈)交易少得多。
df_transactions.dtypes
这将产生以下输出:
step int64
type object
amount float64
nameOrig object
oldbalanceOrg float64
newbalanceOrig float64
nameDest object
oldbalanceDest float64
newbalanceDest float64
isFraud int64
isFlaggedFraud int64
dtype: object
使用 sci-kit learn 的 LabelEncoder 将对象类型编码为标签:
from sklearn.preprocessing import LabelEncoder
encoder = {}
for i in df_transactions.select_dtypes('object').columns:
encoder[i] = LabelEncoder()
df_transactions[i] = encoder[i].fit_transform(df_transactions[i])
X = df_transactions.drop('isFraud', axis=1)
y = df_transactions['isFraud']
应用 SMOTE 生成合成数据:
from imblearn.over_sampling import SMOTE
over_sample = SMOTE(random_state=0)
X,y = over_sample.fit_resample(X,y)
y.value_counts()
这将产生以下输出:
0 24917
1 24917
Name: isFraud, dtype: int64
X = df_transactions[['step', 'type', 'amount','nameOrig', 'oldbalanceOrg', 'newbalanceOrig','nameDest', 'oldbalanceDest', 'isFlaggedFraud']]
y= df_transactions['isFraud']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
X_train = X_train.values
X_test = X_test.values
y_train = y_train.values
y_test = y_test.values
from typing import Tuple, Union, List
import numpy as np
from sklearn.linear_model import LogisticRegression
XY = Tuple[np.ndarray, np.ndarray]
Dataset = Tuple[XY, XY]
LogRegParams = Union[XY, Tuple[np.ndarray]]
XYList = List[XY]
def get_model_parameters(model: LogisticRegression) -> LogRegParams:
if model.fit_intercept:
params = [
model.coef_,
model.intercept_,
]
else:
params = [
model.coef_,
]
return params
def set_model_params(
model: LogisticRegression, params: LogRegParams
) -> LogisticRegression:
model.coef_ = params[0]
if model.fit_intercept:
model.intercept_ = params[1]
return model
def shuffle(X: np.ndarray, y: np.ndarray) -> XY:
rng = np.random.default_rng()
idx = rng.permutation(len(X))
return X[idx], y[idx]
def partition(X: np.ndarray, y: np.ndarray, num_partitions: int) -> XYList:
return list(
zip(np.array_split(X, num_partitions), np.array_split(y, num_partitions))
)
def set_initial_params(model: LogisticRegression):
n_classes = 2 # only 2 classes Fraud or Genuine
n_features = 9 # Number of features in dataset
model.classes_ = np.array([i for i in range(n_classes)])
model.coef_ = np.zeros((n_classes, n_features))
if model.fit_intercept:
model.intercept_ = np.zeros((n_classes,))
partition_id = np.random.choice(10)
(X_train, y_train) = partition(X_train, y_train, 10)[partition_id]
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(
penalty="l2",
max_iter=1, # local epoch
warm_start=True, # prevent refreshing weights when fitting
)
model.fit(X_train, y_train)
class AML_Detection_Client(fl.client.NumPyClient):
def get_parameters(self, config):
return get_model_parameters(model)
def fit(self, parameters, config):
set_model_params(model, parameters)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
model.fit(X_train, y_train)
print(f"Training finished for round {config['server_round']}")
return get_model_parameters(model), len(X_train), {}
def evaluate(self, parameters, config):
set_model_params(model, parameters)
loss = log_loss(y_test, model.predict_proba(X_test))
accuracy = model.score(X_test, y_test)
print(loss,accuracy)
return loss, len(X_test), {"accuracy": accuracy}
fl.client.start_numpy_client(server_address="0.0.0.0:8080", client=AML_Detection_Client())
打开第二个终端并运行客户端 1 的代码(python3 FL_AML_Client1.py)
这将产生以下输出:

图 6.14 – 客户端 1 的执行及其日志
现在,让我们看看客户端 2 的代码。将此代码保存为 FL_AML_Client2.py。客户端 2 的代码将与客户端 1 相同,但不会使用 SMOTE 方法增加欺诈交易。为了全面性,以下是第二个客户端的完整代码:
import pandas as pd
import torch
url ="PS_20174392719_1491204439457_log.csv"
df_actual = pd.read_csv(url, sep=",")
df_actual
df_transactions=df_actual.head(25000)
from sklearn.model_selection import train_test_split
ffrom sklearn.model_selection import StratifiedShuffleSplit
print("No of Fraud Transactions:", df_transactions["isFraud"].value_counts()[0])
print("No of Non Fraud Transactions:", df_transactions["isFraud"].value_counts()[1])
print('No Frauds', round(df_transactions['isFraud'].value_counts()[0]/len(df_transactions) * 100,2), '% of the dataset')
print('Frauds', round(df_transactions['isFraud'].value_counts()[1]/len(df_transactions) * 100,2), '% of the dataset')
这将产生以下输出:
No of Fraud Transactions: 24917
No of Non Fraud Transactions: 83
No Frauds 99.67 % of the dataset
Frauds 0.33 % of the dataset
df_transactions.dtypes
step int64
type object
amount float64
nameOrig object
oldbalanceOrg float64
newbalanceOrig float64
nameDest object
oldbalanceDest float64
newbalanceDest float64
isFraud int64
isFlaggedFraud int64
dtype: object
使用 sci-kit learn 的 LabelEncoder 将对象类型编码为标签:
from sklearn.preprocessing import LabelEncoder
encoder = {}
for i in df_transactions.select_dtypes('object').columns:
encoder[i] = LabelEncoder()
df_transactions[i] = encoder[i].fit_transform(df_transactions[i])
X = df_transactions.drop('isFraud', axis=1)
y = df_transactions['isFraud']
y.value_counts()
这将产生以下输出:
0 24392
1 608
Name: isFraud, dtype: int64
X = df_transactions[['step', 'type', 'amount','nameOrig', 'oldbalanceOrg', 'newbalanceOrig','nameDest', 'oldbalanceDest', 'isFlaggedFraud']]
y= df_transactions['isFraud']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
X_train = X_train.values
X_test = X_test.values
y_train = y_train.values
y_test = y_test.values
from typing import Tuple, Union, List
import numpy as np
from sklearn.linear_model import LogisticRegression
XY = Tuple[np.ndarray, np.ndarray]
Dataset = Tuple[XY, XY]
LogRegParams = Union[XY, Tuple[np.ndarray]]
XYList = List[XY]
def get_model_parameters(model: LogisticRegression) -> LogRegParams:
if model.fit_intercept:
params = [
model.coef_,
model.intercept_,
]
else:
params = [
model.coef_,
]
return params
def set_model_params(
model: LogisticRegression, params: LogRegParams
) -> LogisticRegression:
model.coef_ = params[0]
if model.fit_intercept:
model.intercept_ = params[1]
return model
def shuffle(X: np.ndarray, y: np.ndarray) -> XY:
rng = np.random.default_rng()
idx = rng.permutation(len(X))
return X[idx], y[idx]
def partition(X: np.ndarray, y: np.ndarray, num_partitions: int) -> XYList:
return list(
zip(np.array_split(X, num_partitions), np.array_split(y, num_partitions))
)
def set_initial_params(model: LogisticRegression):
n_classes = 2 # only 2 classes Fraud or Geninue
n_features = 9 # Number of features in dataset
model.classes_ = np.array([i for i in range(n_classes)])
model.coef_ = np.zeros((n_classes, n_features))
if model.fit_intercept:
model.intercept_ = np.zeros((n_classes,))
partition_id = np.random.choice(10)
(X_train, y_train) = partition(X_train, y_train, 10)[partition_id]
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(
penalty="l2",
max_iter=1, # local epoch
warm_start=True, # prevent refreshing weights when fitting
)
model.fit(X_train, y_train)
class AML_Detection_Client(fl.client.NumPyClient):
def get_parameters(self, config):
return get_model_parameters(model)
def fit(self, parameters, config):
set_model_params(model, parameters)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
model.fit(X_train, y_train)
print(f"Training finished for round {config['server_round']}")
return get_model_parameters(model), len(X_train), {}
def evaluate(self, parameters, config):
set_model_params(model, parameters)
loss = log_loss(y_test, model.predict_proba(X_test))
accuracy = model.score(X_test, y_test)
print(loss,accuracy)
return loss, len(X_test), {"accuracy": accuracy}
fl.client.start_numpy_client(server_address="0.0.0.0:8080", client=AML_Detection_Client())
在另一个终端中运行客户端 2 的代码(python3 FL_AML_Client2.py):

图 6.15 – 运行客户端 2 及其日志
一旦运行客户端 2 的代码,请密切关注服务器端的日志语句。服务器将与两个客户端进行通信,启用初始参数的交换,并在随后的每一轮中更新每个客户端的权重。监控服务器日志将提供关于联邦学习过程进展和客户端与服务器之间共享信息的见解:

图 6.16 – 服务器端日志
观察客户端和服务器端的日志。这些指标提供了关于每个客户端在联邦学习过程的多个回合中损失(表示模型的性能)和准确度(表示模型的正确性)的概述:
| 服务器 | 客户端 1 | 客户端 2 |
|---|---|---|
| INFO flwr 2023-03-14 17:46:49,202 | app.py:139 | Starting Flower server, config: ServerConfig(num_rounds=5, round_ timeout=None)INFO flwr 2023-03-14 17:51:21,810 | server.py:101 | FL starting | ||
| DEBUG flwr 2023-03-14 17:51:21,778 | connection.py:38 | ChannelConnectivity.READY | ||
| ChannelConnectivity. DEBUG flwr 2023-03-14 17:53:46,338 | connection.py:38 | ChannelConnectivity.READY | ||
| DEBUG flwr 2023-03-14 17:53:46,338 | server.py:215 | fit_round 1: strategy sampled 2 clients (out of 2)DEBUG flwr 2023-03-14 17:53:46,351 | server.py:229 | fit_round 1 received 2 results and 0 failuresWARNING flwr 2023-03-14 17:53:46,354 | fedavg.py:242 | No fit_metrics_aggregation_fn providedINFO flwr 2023-03-14 17:53:46,362 | server.py:116 | fit progress: (1, 0.06756539217831908, {‘accuracy’: 0.9962666666666666}, 144.549737353)DEBUG flwr 2023-03-14 17:53:46,363 | server.py:165 | evaluate_round 1: strategy sampled 2 clients (out of 2)DEBUG flwr 2023-03-14 17:53:46,377 | server.py:179 | evaluate_round 1 received 2 results and 0 failures | ||
| INFO flwr 2023-03-14 17:53:46,400 | server.py:116 | fit progress: (2, 0.40485776608772656, {‘accuracy’: 0.9633333333333334}, 144.58791799899996) | ||
| INFO flwr 2023-03-14 17:53:46,432 | server.py:116 | fit progress: (3, 0.11833075507570899, {‘accuracy’: 0.9962666666666666}, 144.61946266499996) | ||
| INFO flwr 2023-03-14 17:53:46,465 | server.py:116 | fit progress: (4, 0.1145626928425223, {‘accuracy’: 0.9962666666666666}, 144.65267561899998) | ||
| INFO flwr 2023-03-14 17:53:46,497 | server.py:116 | fit progress: (5, 0.27867744042157033, {‘accuracy’: 0.9861333333333333}, 144.68508043599996) | ||
| INFO flwr 2023-03-14 17:53:46,511 | app.py:202 | app_fit: losses_distributed [(1, 0.4398987330496311), (2, 0.4606742262840271), (3, 0.5105149038136005), (4, 0.5070083439350128), (5, 0.5951354652643204)] | ||
| 第 1 轮训练完成:0.06756539217831908 0.9962666666666666 第 2 轮训练完成:0.40485776608772656 0.9633333333333334 第 3 轮训练完成:0.11833075507570899 0.9962666666666666 第 4 轮训练完成:0.1145626928425223 0.9962666666666666 第 5 轮训练完成:0.27867744042157033 0.9861333333333333 第 1 轮训练完成:0.8122320748323023 0.9745333333333334 第 2 轮训练完成:0.5164906830160562 0.9541333333333334 第 3 轮训练完成:0.9026990471833415 0.9745333333333334 第 4 轮训练完成:0.8994540131249842 0.9745333333333334 第 5 轮训练完成:0.9115935132282235 0.9736 | ||
| DEBUG flwr 2023-03-14 17:53:46,521 | connection.py:109 | gRPC channel closedINFO flwr 2023-03-14 17:53:46,522 | app.py:153 | Disconnect and shut down | DEBUG flwr 2023-03-14 17:53:46,521 | connection.py:109 | gRPC channel closedINFO flwr 2023-03-14 17:53:46,522 | app.py:153 | Disconnect and shut down |
表 6.8 – 服务器和客户端的日志数据
根据日志,客户端和服务器之间有 5 轮通信,在每一轮中,准确率和损失根据权重变化。
| 客户端 1 | 损失 | 准确率 |
|---|---|---|
| 第一轮 | 0.06756539217831908 | 0.9962666666666666 |
| 第二轮 | 0.40485776608772656 | 0.9633333333333334 |
| 第三轮 | 0.11833075507570899 | 0.9962666666666666 |
| 第四轮 | 0.1145626928425223 | 0.9962666666666666 |
| 第五轮 | 0.27867744042157033 | 0.9861333333333333 |
表 6.9 – 客户端 1 的准确度和损失指标
根据调试日志,客户端 1 的损失和准确度有所变化。让我们也观察一下客户端 2 的损失和准确度结果。
| 客户端 2 | 损失 | 准确度 |
|---|---|---|
| 第一轮 | 0.8122320748323023 | 0.9745333333333334 |
| 第二轮 | 0.5164906830160562 | 0.9541333333333334 |
| 第三轮 | 0.9026990471833415 | 0.9745333333333334 |
| 第四轮 | 0.8994540131249842 | 0.9745333333333334 |
| 第五轮 | 0.9115935132282235 | 0.9736 |
表 6.10 – 客户端 2 的准确度和损失指标
我们已经使用联邦学习实现了一个样本欺诈检测应用,并使用了 Flower 等开源框架。在下一节中,让我们尝试学习和实现使用差分隐私的联邦学习。
FL 与差分隐私
联邦学习与差分隐私(FL-DP)是一种结合了 FL 和差分隐私(DP)原则的方法,以确保分布式机器学习系统中的隐私和安全。FL-DP 旨在保护敏感数据,同时允许在多个设备或实体之间进行协作模型训练。
FL-DP 的目标是在不损害个别数据贡献者隐私的情况下实现准确的模型训练。它解决了在聚合来自不同参与者的模型更新时防止数据泄露的挑战。通过在聚合之前对模型更新或梯度添加噪声或扰动,FL-DP 通过 DP 技术提供了强大的隐私保证。
实现联邦差分隐私(FL-DP)的方法有多种。一种常见的方法是每个客户端使用自己的数据训练一个本地机器学习模型。客户端会对模型的梯度或权重应用剪枝和噪声添加等技术。然后,客户端将更新后的数据发送到服务器。在服务器端,使用诸如安全聚合或隐私保护 FL 算法等技术对更新进行聚合,同时保护隐私。这确保了个人客户端数据保持隐私,同时允许协作模型训练。
FL-DP 算法可能因所使用的特定差分隐私机制而异,例如高斯噪声添加、子采样或如私有教师集成聚合(PATE)等高级技术。技术选择取决于所需的隐私级别和分布式数据集的特征。
实施 FL-DP 需要对隐私、准确性和计算开销进行仔细考虑。它涉及在保护隐私和保持模型效用之间取得平衡。各种框架和库,如 Flower 和 TensorFlow Privacy,提供了工具和技术,以促进 FL-DP 的实施。
FL-DP 有可能在数据隐私和安全至关重要的场景中释放协作机器学习的优势。通过保护隐私,FL-DP 使组织和个人能够在模型训练中协作,同时保护敏感信息。
FL-DP 提供了一种在 FL 过程中实施隐私保护技术的方法,确保客户端数据保持安全。
在本节中,我们将探讨实现 FL-DP 的两种通用方法,尽管具体的框架和实现可能略有不同。
第一种方法
这种方法与谷歌研究团队引入的差分隐私联邦平均(DP-FedAvg)类似。通过遵循这些方法,FL-DP 允许您在客户端数据上训练机器学习模型,同时通过剪裁和添加噪声等技术来保护隐私。
每个客户端执行以下操作:
-
使用其本地数据训练机器学习/深度学习模型。
-
使用标准 SGD 算法计算梯度/权重。
-
对权重应用剪裁以限制其敏感性。
-
向权重添加噪声以引入随机性和隐私。
-
将修改后的权重发送到服务器。
服务器执行以下操作:
-
计算从每个客户端接收到的权重的平均值。
-
将更新的权重广播回客户端。
-
或者,在步骤 1 中,在广播之前对最终权重应用剪裁并添加噪声。

图 6.17 – 与服务器交换的 DP-FedAvg 模型权重
在这种方法中,每个客户端在其本地数据上训练其模型,并处理服务器发送的更新后的平均权重。
第二种方法
在这种方法中,每个客户端在其本地数据上训练其模型,并应用隐私保护技术来计算梯度/权重。然后服务器将这些噪声权重合并,并使用 FD-SGD 算法进行聚合,确保在整个 FL 过程中保持隐私。
每个客户端执行以下操作:
-
使用其本地数据训练机器学习模型。
-
使用带有噪声的 SGD 或 DP-SGD(DP 随机梯度)算法计算梯度/权重,这些算法在梯度计算过程中引入噪声以保护隐私。
-
将权重发送到服务器。
服务器执行以下操作:
-
利用从客户端接收到的噪声权重。
-
遵循联邦差分 SGD(FD-SGD)算法,该算法在服务器上的聚合过程中采用了隐私保护技术。

图 6.18 – 与服务器交换的 DP-FedSGD 模型权重
设计了各种不同的差分隐私联邦学习(FL-DP)算法变体,旨在解决不同的场景,如跨设备和跨存储库的 FL,以及同质化和异质化数据。在我们的实现中,我们将应用 FL-DP 到之前相同的示例中,确保在整个 FL 过程中保持隐私保护。
一个使用 FL-DP 的示例应用
在撰写本文时,Flower 框架(版本 1.3)目前提供对 FL-DP 的实验性支持。它提供了一个策略类(类似于 FedAvg、FedYogi 等),专门设计来支持 FL-DP。设计来支持这一功能的类名为DPFedAvg。
Flower 框架中的DPFedAvg类是一个专门设计来支持 FL-DP 的组件。它通过结合差分隐私技术来扩展 FedAvg 算法的功能,以保护在模型聚合过程中个人客户端数据的隐私。
DPFedAvg实现了一种隐私保护机制,确保客户端更新的隐私性,同时允许协作模型训练。它通过在聚合到服务器端之前向每个客户端收到的模型更新或梯度添加噪声或扰动来实现这一点。
DPFedAvg类的关键特性和功能包括以下内容:
-
DP:DPFedAvg将差分隐私技术集成到 FL 过程中,确保在模型训练过程中个人客户端数据的隐私得到保护。
-
噪声添加:DPFedAvg在聚合之前将对每个客户端收到的梯度或模型更新应用噪声。添加的噪声量基于隐私参数和隐私预算分配。
-
隐私预算管理:DPFedAvg包含管理和有效分配隐私预算的机制,确保在整个训练过程中保持所需的隐私保证。
-
隐私参数:DPFedAvg允许用户自定义隐私参数,如隐私预算、噪声分布和模型更新的敏感性。这些参数使得对隐私和效用之间的权衡可以进行精细控制。
-
模型聚合:DPFedAvg使用 DP 平均算法执行客户端更新的聚合。这确保了个人更新的隐私得到保护,同时生成一个更新的全局模型。
-
与 Flower 框架的兼容性:DPFedAvg被设计成可以无缝集成到 Flower 框架中,使用户能够通过现有的 Flower 基础设施将 DP 纳入他们的 FL 管道。
通过在 Flower 框架中使用DPFedAvg类,开发者和机器学习工程师可以简单高效地实现 FL-DP。它提供了一个强大的工具,以确保在分布式机器学习场景中的隐私性,同时保持联邦学习的协作优势。
让我们详细了解一下 Flower 提供的类。
DPFedAvgFixed 类
这个类是一个包装类,它向权重添加裁剪和高斯噪声。该类的构造函数支持设置服务器端噪声、裁剪范数值和噪声乘数参数。
让我们在服务器端使用这个类。服务器代码如下:
def DP_Fed_Server():
model = LogisticRegression(max_iter=10000)
set_initial_params(model)
strategy = fl.server.strategy.FedAvg(
min_available_clients=2,
evaluate_fn=get_evaluate_fn(model,X_test,y_test),
on_fit_config_fn=fit_round,
)
dps = DPFedAvgFixed(strategy,
num_sampled_clients=2,
clip_norm=0.03,
noise_multiplier=0.5)
fl.server.start_server(
server_address="0.0.0.0:8080",
strategy=dps,
config=fl.server.ServerConfig(num_rounds=5),
)
DP_Fed_Server()
服务器和客户端的 Jupyter 笔记本源代码位于第六章文件夹中:
-
服务器代码:Fed-DP-AML-Server.ipynb
-
客户端 1 代码:DP-FL-AML_Client1.ipynb
-
客户端 2 代码:DP-FL-AML-Client2.ipynb
让我们看看客户端和服务器模型的准确率:
| 客户端 1 | 客户端 2 | 服务器 |
|---|---|---|
| 0.99626666666666660.71626666666666670.98760.93720.7714666666666666 | 0.97453333333333340.59786666666666670.96933333333333340.94480.7708 | 0.99626666666666660.71626666666666670.98760.93720.7714666666666666 |
| 表 6.11 – 服务器和客户端的准确率结果 |
将 DP 应用于 FL 会在计算成本、通信开销以及可能降低模型性能方面引入一些开销。在我们的示例案例中,到第四轮时,准确率为 93%,但在第五轮时,准确率突然下降。这告诉我们,我们需要在训练过程中监控准确率,以帮助我们决定每个客户端需要参与的轮数,并在准确率下降时停止进一步的轮次。
摘要
在本章中,我们解释了为什么需要联邦学习(FL),并详细探讨了其定义和特性。我们涵盖了实现 FL 的步骤,讨论了独立同分布(IID)和非独立同分布(non-IID)数据集以及 FL 算法。我们使用开源 FL 框架实现了一个示例应用。最后,我们使用差分隐私(DP)将同一应用进行了转换。
在下一章中,我们将学习 FL 基准测试,并了解正在开发或已经拥有 FL 产品的关键初创公司。
第七章:联邦学习基准、初创公司和下一个机会
本章重点介绍了联邦学习(FL)基准的重要性,并突出了该领域初创公司提供的产品。
我们将涵盖以下主要主题:
-
FL 基准:
-
FL 基准的介绍,包括其重要性
-
设计 FL 基准时的考虑因素
-
FL 数据集概述
-
各类 FL 基准套件的高级概述
-
选择适合项目的适当 FL 框架
-
-
FL 领域的最先进研究
-
FL 的下一个机会和关键初创公司产品
通过探讨这些主题,您将全面了解 FL 基准的需求以及该领域的最新进展。此外,我们将展示与 FL 密切相关的一些初创公司开发的显著产品。
FL 基准
FL 是一种机器学习技术,允许多个设备/客户端或服务器协作训练模型并保持其数据隐私。对标准化基准的需求不断增加,以评估不同 FL 算法和框架/平台的表现。
IEEE 3652.1-2020 标准,正式名称为IEEE 关于联邦机器学习架构和应用指南,是一本综合指南,提供了联邦机器学习(FML)的架构框架。有关 IEEE 3652.1-2020 标准的更多详细信息,请参阅ieeexplore.ieee.org/document/9382202。
FL 基准是用于比较和评估不同 FL 算法和框架/平台性能的数据集和评估指标。这些基准可以帮助工程师和研究人员识别不同算法的优缺点以及不同 FL 框架的利弊。
接下来,我们将讨论 FL 基准的重要性以及设计它们时应考虑的关键因素。
FL 基准的重要性
FL 基准对于多个原因至关重要。
首先,它们帮助研究人员评估不同 FL 算法在标准公共数据集上的性能,这有助于确定哪些算法对特定用例最有效。比较不同算法的性能可以帮助通过确定需要新算法或现有算法需要改进的领域来推动该领域的进步。
其次,这些基准还有助于比较不同 FL 框架的性能,并确定哪个框架最适合使用 FL 解决业务用例。
最后,基准可以通过提供标准化的指标和评估程序来帮助提高研究结果的再现性。
设计 FL 基准时的关键考虑因素:在设计 FL 基准时,应考虑几个关键因素。以下是一些例子:
-
数据分布:联邦学习算法旨在处理分布在多个设备或服务器上的数据。因此,基准测试应包括代表可能在实际使用案例中遇到的数据类型的数据集。
-
异构性:联邦学习涉及在不同设备或服务器上训练数据分布的模型,每个设备可能具有不同的硬件能力和网络条件。因此,基准测试应包括多样化的数据集,并反映不同类型的设备和网络条件。
-
隐私:联邦学习(FL)的主要优势之一是能够通过在用户设备上保留数据来保护数据的隐私。因此,基准测试应确保用于训练的数据能够代表真实世界的使用案例,同时仍然保护用户的隐私。
-
评估指标:基准测试应包括标准指标来评估联邦学习算法的性能。这些指标应经过仔细选择,以确保它们能够准确反映算法的性能并适用于特定的使用案例。
-
可重现性:联邦学习基准测试应设计成可重现的,这意味着数据集和评估程序应被明确记录并可供他人使用。
我们已经讨论了设计联邦学习基准测试时的关键考虑因素。接下来,我们将进一步探讨在联邦学习基准测试中需要考虑的数据集。
联邦学习数据集
联邦学习的关键方面之一是选择用于训练模型的数据库集。接下来,我们将探讨在选择联邦学习数据集时需要考虑的各种因素:
-
数据隐私:在选择联邦学习数据集时,最关键的考虑因素是数据隐私。由于数据存储在每个设备上,因此确保数据不会被任何未经授权的第三方访问至关重要。可以通过使用加密技术或匿名化数据来确保数据隐私。此外,从设备所有者那里获得适当的同意和许可以使用他们的数据用于联邦学习也很重要。还需要考虑对差分隐私的支持,因为仅仅数据匿名化可能不足以保证。
-
数据多样性:在为联邦学习选择数据集时,数据多样性是另一个重要的考虑因素。数据集应该足够多样化,以捕捉广泛的数据模式和特征。这对于确保模型不会偏向特定数据集是至关重要的。例如,如果数据集只包括来自特定地区或人口统计数据的数据,那么模型可能无法很好地推广到其他地区或人口统计数据。
-
数据质量:在选择联邦学习的数据集时,数据质量也是一个重要的考虑因素。数据集应该是干净的,没有错误或不一致之处。可能需要数据清洗和预处理技术来确保数据适合训练模型。此外,数据应该代表现实世界场景,以确保模型在实际情况下能表现良好。
-
数据大小:数据集的大小也是联邦学习的一个重要考虑因素。数据集应该足够大,以便有效地训练模型,但又不能太大,以至于难以处理。需要在数据集的大小和用于训练模型的计算资源之间找到一个良好的平衡。
-
数据分布:最后,数据在设备间的分布也是联邦学习的一个重要考虑因素。数据应该以这种方式分布,使得每个设备都能访问到数据的代表性样本。这确保了每个设备都能以有意义的方式为模型的训练做出贡献。此外,数据分布应该是平衡的,以避免任何设备因数据过载而超负荷。
数据集在基准测试联邦学习系统时至关重要。接下来,我们将探讨以下流行的标准数据集,这些数据集被用于基准测试联邦学习系统:
-
FLAIR
-
联邦 EMNIST
-
莎士比亚
-
CIFAR-10
-
OpenStreetMap
-
医学图像分析数据集
FLAIR
联邦学习标注图像库(FLAIR)是一个开源项目,旨在为联邦学习提供一个集中式的标注图像存储库。该存储库包含了一系列多样化的图像,包括医学图像、卫星图像和自然图像,以及相应的标注。FLAIR 为研究人员和开发者提供了一个平台,用于评估基于图像的任务上的联邦学习算法,如图像分类和目标检测。该存储库允许您共享和协作标注图像,减少单个组织收集和标注自身数据的需要。FLAIR 中的标注旨在保护隐私,敏感信息被移除或模糊化。隐私保护标注和标准化格式使 FLAIR 成为评估基于图像任务的联邦学习算法的有价值资源,使其能够轻松集成到流行的机器学习框架和工具中。
FLAIR 已成为联邦学习社区中流行的资源,几个联邦学习框架已将其集成到它们的评估流程中。该存储库持续更新,定期添加新的数据集和标注。它由来自 51,000 名 Flickr 用户的 430,000 张图像组成,这些图像映射到 17 个粗粒度标签,如艺术、食物、植物和户外。
欲了解更多信息,请访问以下 GitHub 网址:github.com/apple/ml-flair。
联邦 EMNIST
联邦扩展 MNIST(Federated EMNIST)是谷歌开发的一个联邦学习基准数据集。它由一组手写数字和字母的图像组成,类似于 MNIST 数据集。该数据集分布在多个设备上,目标是训练一个模型,能够在保持数据隐私的同时正确分类图像。
莎士比亚
该数据集包含莎士比亚文本的集合,可用于训练用于文本生成的语言模型。
CIFAR-10
这是一个广泛使用的计算机视觉任务基准数据集,由 10 个不同类别的 60,000 张彩色图像组成。它用于训练一个模型,以在保持数据隐私的同时正确分类图像。
OpenStreetMap
这是一个地理数据集,包括地图、卫星图像和 GPS 坐标。该数据集可以在多个设备上分布,目标是训练一个模型,能够在保护数据隐私的同时预测交通模式或其他环境特征。
医学图像分析数据集
有几个医学图像数据集可以用于联邦学习,例如脑肿瘤分割(BraTS)挑战数据集和前列腺磁共振图像分割(PROMISE12)挑战数据集。这些数据集包含可用于训练诊断和治疗规划模型的医学图像,同时保护患者数据的隐私。
联邦学习基准框架
开源社区和商业领域都有几个联邦学习基准框架可用。联邦学习框架提供库/平台,用于基准测试联邦学习系统和应用。
一些最受欢迎的联邦学习系统和基准包括以下内容:
-
LEAF
-
FedML
-
FATE
-
FedScale
-
PySyft
-
MLCommons – MLPerf
-
MedPerf
-
TensorFlow Federated (TFF)
-
花朵(我们在上一章中已经讨论过,所以本章不再详细说明)
我们将在接下来的小节中更详细地探讨这些内容。
LEAF FL 基准测试套件
LEAF FL 基准测试套件是由卡内基梅隆大学发起的一个项目,旨在为联邦学习算法提供一个标准化的基准测试套件(leaf.cmu.edu/)。
LEAF 基准使研究人员和开发者能够评估不同领域和配置下联邦学习算法的性能。LEAF 提供了一套标准化的任务和数据集,用于评估联邦学习算法在各种指标上的性能,包括收敛速度、通信效率和准确性。广泛的任务包括图像分类、文本分类和回归任务。
在基准测试中使用的数据库旨在代表现实世界场景,具有不同的数据分布、数据大小和数据复杂度水平。基准测试在各种设置下进行,例如改变客户端数量、通信轮次以及每个客户端可用的数据量。基准测试还评估算法对对抗攻击和噪声数据的鲁棒性。
LEAF 的核心组件如下:
-
数据集
-
参考实现
-
指标

图 7.1 – LEAF 的核心组件和流程
更多关于 LEAF 基准测试的详细信息可以在 arxiv.org/abs/1812.01097 获取。
FedML
FedML (github.com/FedML-AI/FedML) 是一个用于联邦学习的基准套件,包括多个数据集和任务,如图像分类、语言建模和语音识别。FedML 在 非独立同分布(non-iid)的数据分布、对大数据集的可扩展性和通信效率方面评估联邦学习算法的鲁棒性。
该框架支持各种类型的联邦学习设置,如水平、垂直和联邦迁移学习,以及不同类型的优化算法,包括联邦平均、FedProx 和 FedAdapt。FedML 框架旨在模块化、灵活和可扩展,使用户能够轻松定制和扩展现有算法或开发新算法。它还提供了一套基准数据集和评估指标,以促进不同算法的比较。
FedML 社区积极开发和维护该框架,并组织研讨会和挑战赛,以促进联邦学习的研究和创新。该社区还与行业合作伙伴合作,将联邦学习应用于现实世界的用例,如医疗保健、金融和电信。FedML 是一个重要的倡议,旨在解决联邦学习的挑战和机遇,并使分布式环境中开发安全、隐私保护和高效的机器学习模型成为可能。FedML 支持三种类型的计算平台 – 物联网/移动、分布式计算和独立模拟。
更多详细信息可以在以下参考研究 URL 中找到:arxiv.org/abs/2007.13518。

图 7.2 – FedML 架构
FATE
联邦人工智能技术赋能器(FATE)是一个开源项目,它提供了一种安全且保护隐私的方式来协作开发人工智能(AI)模型。FATE 旨在实现联邦学习(FL),这是一种分布式机器学习方法,允许多个参与者训练一个共享模型,而无需共享他们的数据。FATE 由腾讯的子公司微众银行 AI 部门开发。github.com/FederatedAI/FATE
FATE 为开发者提供了一个平台,使他们能够在自己的 AI 应用中实现联邦学习技术。它支持不同类型的联邦学习,如横向和纵向,并提供工具来管理不同设备间模型的通信、同步和聚合。FATE 采用多种加密技术来确保联邦学习过程的隐私和安全。例如,FATE 使用差分隐私向训练数据添加噪声,防止泄露关于单个用户的敏感信息。FATE 还使用同态加密来允许对加密数据进行计算,这使得各方可以在不向彼此透露数据的情况下进行协作。我们将在下一章中学习同态加密。
FATE 建立在 Kubernetes 之上,这是一个流行的开源容器编排系统。Kubernetes 为 FATE 提供了管理容器和自动化联邦学习基础设施的部署、扩展和监控的能力。FATE 利用加密技术和 Kubernetes 来确保联邦学习过程的隐私和安全。FATE 为开发者提供了一个基于 Web 的图形用户界面(GUI),以便与平台交互、监控训练过程和可视化结果。它已被各种公司和组织采用,以构建保护隐私的 AI 应用。例如,腾讯已使用 FATE 为其电商平台开发了一个保护隐私的推荐系统。华为也使用 FATE 为医疗保健行业构建了一个联邦学习平台。随着联邦学习在 AI 行业中的重要性日益增加,FATE 的普及度预计将增长。
FATE 的架构
下面的图显示了 FATE 架构:

图 7.3 – FATE 架构
前面的图来源于fate.readthedocs.io/en/latest/architecture/。
FedScale 基准测试平台
FedScale 基准测试套件包括几个数据集和工作负载,旨在评估联邦学习算法和系统的性能。这些数据集被选中以反映现实世界数据的异构性和非独立同分布(non-IIDness)。工作负载被设计来模拟现实世界联邦学习场景的通信开销和计算复杂性,以及评估这些场景中联邦学习算法和系统的性能。
包含在 FedScale 基准套件中的数据集之一是 Synthetic IID 数据集,它由随机生成并均匀分布在客户端之间的合成数据组成。该数据集旨在评估联邦学习算法和系统的可扩展性和效率。FedScale 基准套件中包含的另一个数据集是异构图像数据集,它由来自不同来源和领域的图像组成。该数据集旨在评估联邦学习算法和系统对异构数据的鲁棒性。
FedScale 基准套件还包括更复杂的工作负载,例如联邦元学习工作负载,涉及客户端从彼此的数据中学习。

图 7.4 – 运行 FL 基准的 FedScale 运行时
前面的图来自 github.com/SymbioticLab/FedScale/blob/master/docs/fedscale-sim-mode.png。
MLCommons
MLCommons 是一个非营利组织,旨在通过为其成员提供一个协作和资源共享的平台来加速机器学习创新和发展。它由机器学习领域的几位领先研究人员、工程师和企业家于 2020 年 6 月成立。
该组织的主要关注点是开发和推广设计及部署机器学习系统的最佳实践,包括硬件和软件框架、数据集、基准和评估指标。MLCommons 的一个关键倡议是 MLPerf 基准套件,该套件旨在衡量机器学习系统在一系列应用中的性能,包括计算机视觉、自然语言处理和推荐系统。这些基准由全球的研究人员和工程师社区开发和维护,并用于评估机器学习硬件和软件平台的性能。MLPerf 已迅速成为衡量机器学习性能的行业标准,并被全球领先的技术公司、研究人员和政府机构所采用。
MedPerf
MedPerf 是一个用于医疗人工智能的开放基准平台,使用联邦学习。MLCommons 团队与多个机构和大学合作,试点了多个用例,使用 MDPerf 基准运行联邦学习模型。这些用例包括脑肿瘤分割、胰腺分割、手术流程阶段识别和云实验。

图 7.5 – 云实验的 MedPerf 架构
前面的图来自 github.com/mlcommons/medperf。
选择一个联邦学习框架
选择最佳的联邦学习(FL)框架可能是一项具有挑战性的任务,因为需要考虑多个因素,例如功能、可扩展性、安全性、易用性、文档、支持的学习机器算法(开箱即用)、神经网络支持以及学习曲线。
选择 FL 框架时的一些关键考虑因素如下:
-
功能:考虑框架提供的功能很重要。一些需要寻找的关键功能包括支持不同的机器学习算法、分布式训练、数据隐私和数据验证。你应该选择一个具有与你的用例需求相匹配的功能的框架。
-
可扩展性:另一个关键考虑因素是可扩展性。框架应该能够处理大量数据集和大量参与者。你还应该考虑框架是否能够进行横向或纵向扩展。在跨设备(移动、网页等)的情况下,框架应该能够处理大量客户端。
-
安全和隐私:联邦学习涉及多个方共享数据,因此选择一个提供强大安全功能的框架至关重要。框架应该具备加密和认证功能,以保护数据免受未经授权的访问。你还应该考虑框架是否具有透明的安全模型,允许你审计实施的安全措施。你需要考虑框架是否默认支持隐私保护,例如差分隐私。
-
易用性:框架的易用性也是一个关键考虑因素。框架应该拥有直观的用户界面,使其易于设置、配置和使用。你还应该考虑框架是否具有良好的文档和社区支持,因为这可以帮助你解决出现的任何问题。
-
学习曲线:你应该考虑框架的学习曲线,包括用户文档、部署设置、编程语言支持、提供的示例和样本等。
-
兼容性:最后,你应该考虑框架是否与你的现有技术堆栈和编程语言兼容。例如,如果你正在使用 TensorFlow 进行机器学习,你可能希望选择一个与 TensorFlow 兼容的 FL 框架。
总之,选择最佳框架需要仔细考虑多个因素,包括功能、可扩展性、安全性、隐私、易用性、学习曲线以及与现有技术堆栈的兼容性。通过考虑这些因素,你可以选择一个满足你要求的框架,以使用联邦学习解决业务用例。
FedScale、FATE、Flower 和 TensorFlow Federated 的比较
FedScale、FATE、Flower、FedML 和 TensorFlow Federated(TFF)是一些流行的联邦学习框架,它们提供独特的功能和能力。在以下小节中,我们将比较这些功能和能力。
功能
FedScale 是一个支持广泛机器学习模型的框架,包括深度神经网络、决策树和支持向量机(SVMs)。它还支持各种优化算法,如联邦随机梯度下降(SGD)和联邦近端算法。相反,FATE 提供了一套全面的联邦学习工具,支持各种机器学习算法,包括逻辑回归、决策树和深度学习模型。Flower 是一个轻量级的框架,支持各种机器学习模型,包括神经网络、决策树和逻辑回归。TFF 是一个广泛使用的联邦学习框架,支持基于 TensorFlow 的机器学习模型。
可扩展性
FedScale 和 FATE 是为大规模部署设计的,可以处理大量的参与者。Flower 是一个轻量级的框架,非常适合小型到大型规模的联邦学习项目。TFF 是一个可扩展的框架,可以处理大型规模的联邦学习项目,并且可以用于在生产环境中部署联邦学习算法。
安全性
所有四个框架都提供强大的安全功能,如加密和身份验证,以保护在联邦学习过程中的数据。FATE 有额外的功能,如差分隐私和同态加密,以增强数据隐私。TFF 还提供了安全的多方计算(MPC)协议,使多个方能够在联邦学习项目中安全地协作。
易用性
与 Flower 和 TFF 相比,FedScale 和 FATE 的学习曲线更陡峭,因为它们提供了更复杂的功能和工具。Flower 和 TFF 都易于使用,具有直观的 API 和文档,使得入门变得容易。TFF 还提供了一个高级 API,使用户能够在不要求深入了解底层细节的情况下构建联邦学习算法。
社区支持
所有四个框架都有活跃的开源贡献者,提供支持和文档。TFF 由 Google 开发,拥有最大的社区和支持,其次是 Flower、FedScale 和 FATE。
这些框架中的每一个都有其独特的功能和能力,使它们适用于不同的用例。FedScale 和 FATE 适用于大规模的联邦学习部署,而 Flower 和 TFF 更适合小型到中型项目。TFF 拥有最大的社区和支持,是寻找具有广泛支持和资源的联邦学习框架的开发者的绝佳选择。最终,框架的选择将取决于具体的用例、需求和框架的熟悉程度。
研究论文
每个框架都在研究期刊中发布了其自己的基准和结果,包括支持的特性和准确度指标。目前,还没有像 TPC.Org 或 SPEC.org 那样被广泛接受的行业标准基准。
联邦学习(FL)的最新研究
FL 是一个快速发展的技术,在这个领域有几种最先进的研究方向。以下是 FL 研究中的一些最新进展。
这里是不同 FL 框架的高级比较:
| 高级功能 | FATE | FedML | Flower | FedScale | TFF |
|---|---|---|---|---|---|
| 回归模型 | Y | Y | Y | Y | Y |
| 神经网络 | Y | Y | Y | Y | Y |
| 基于树的模型 | Y | N | N | N | N |
| 通信协议 | 定制化 | MPI | gRPC | gRPC | gRPC |
| 支持差分隐私 | N | N | Y | Y | Y |
| 单主机部署 | Y | Y | Y | Y | Y |
| 跨设备部署 | N | Y | Y | Y | N |
| 研究论文 | Y | Y | Y | Y | Y |
表 7.1 – 不同 FL 框架的比较
通信高效的 FL
FL 中的一个主要挑战是在设备和中心服务器之间传输模型更新时的高通信成本。最近的研究集中在通过开发新的压缩技术,如量化、稀疏化和差分压缩来降低 FL 中的通信成本。这些技术可以在不牺牲模型准确度的前提下显著降低通信成本。一些研究人员和研究小组正在积极进行通信高效的 FL(CE-FL)研究:
-
谷歌研究:谷歌研究一直在积极从事 CE-FL 研究,并开发了多种降低 FL 中通信成本的技术。他们最近的一项工作是 Communication-Efficient Learning of Deep Networks from Decentralized Data,提出了一种名为量化随机梯度下降(QSGD)的新压缩技术,可以显著降低 FL 中的通信成本。这是一个允许在每个节点压缩梯度更新的压缩方案,同时保证在标准假设下的收敛。请参阅 Arxiv 论文
arxiv.org/abs/1602.05629。 -
联邦学习社区:联邦学习社区是一个由从事 FL 研究的学者和实践者组成的开放社区。该社区有几个工作组,包括一个专注于开发降低 FL 中通信成本新技术的 CE-FL 工作组。
-
卡内基梅隆大学:卡内基梅隆大学的机器学习系有几位研究人员正在从事 CE-FL 研究。他们最近的一项工作是 Communication-Efficient Distributed Learning with Feature-Selective Sampling,提出了一种新的采样技术,可以降低 FL 中的通信成本。
-
IBM 研究院:IBM 研究员和密歇根大学正在从事 CE-FL 研究工作,他们最新的工作是 Federated Learning with Matched Averaging,提出了一种新的聚合技术,可以降低 FL 中的通信成本。请参阅 Arxiv 论文
arxiv.org/abs/2002.06440。
这些只是众多积极从事 CE-FL 研究的研究人员和研究团队中的几个例子。随着 FL 领域的持续发展,预计将有更多的研究人员和研究团队专注于开发新的技术来降低 FL 中的通信成本。
隐私保护 FL
隐私在 FL 中是一个关键问题,因为数据分布在多个设备上,每个设备的所有者都希望保护他们的数据隐私。最近的研究主要集中在开发新的隐私保护技术,如差分隐私和安全的多方计算,以在允许协作模型训练的同时保护设备所有者的数据隐私。这些技术可以在保持模型准确性的同时提供强大的隐私保证。一些研究人员和研究团队正在积极从事 隐私保护 FL (PP-FL) 研究工作。
这里有一些值得注意的例子:
-
OpenMined:OpenMined 是一个致力于推进 PP-FL 研究的开源社区。它开发了几个 PP-FL 框架,包括 PySyft,这是一个用于 PP-FL 的 Python 库。
-
谷歌研究院:谷歌研究院一直在积极从事 PP-FL 研究工作,并开发了多种保护 FL 中用户隐私的技术。他们最近的一项工作是 Privacy-Preserving Federated Learning with Byzantine Robust Aggregation,提出了一种新的聚合技术,可以在存在恶意行为者的情况下保护用户隐私。
-
卡内基梅隆大学:卡内基梅隆大学的 CyLab 安全与隐私研究所有多位研究人员正在从事 PP-FL 研究工作。他们最近的一项工作是 Privacy-Preserving Federated Learning via Randomized Smoothing,提出了一种新技术,通过向用户数据添加噪声来保护用户隐私。
-
牛津大学:牛津大学有几位研究人员正在从事 PP-FL 研究工作。他们最近的一项工作是 Secure Federated Learning on Curves,提出了一种新技术,通过使用椭圆曲线加密用户数据来保护用户隐私。
-
微软研究院:微软研究院一直在积极从事 PP-FL 研究工作,并开发了多种保护 FL 中用户隐私的技术。他们最近的一项工作是 Private Federated Learning with Secure Aggregation,提出了一种新的聚合技术,通过使用同态加密来保护用户隐私。
这些是许多积极从事 PP-FL 研究的研究人员和研究小组的例子。随着 FL 领域的持续演变,预计将有更多研究人员和研究小组专注于开发新的技术来保护 FL 中用户数据的隐私。
联邦元学习
联邦元学习(FML)是一个新的研究方向,它结合了联邦学习和元学习,以从多个数据源和任务中学习同时保护隐私。FML 允许在多个设备和组织之间进行协作模型训练,同时保护设备所有者的数据隐私。最近的研究探索了新的 FML 技术和应用,如个性化医疗和个性化推荐。FML 是 FL 中的一个相对较新的研究方向,只有少数研究小组正在积极从事相关工作。
这里有一些例子:
-
谷歌研究:谷歌研究一直在积极从事 FML 研究,并开发了多种从多个客户端的元知识中学习同时保护其隐私的技术。其研究工作之一是推荐任务的联邦元学习,该研究提出了一种新的 FML 框架用于推荐任务。
-
卡内基梅隆大学:卡内基梅隆大学的机器学习系有多位研究人员正在从事 FML 研究。其最近的一项工作是联邦元学习在医疗保健中的快速模型自适应,该研究提出了一种在保护多个医疗保健机构隐私的同时从这些机构学习的新方法。
-
牛津大学:牛津大学有多位研究人员正在从事 FML 研究。其最近的一项工作是具有隐私保护和通信高效的模型聚合的推荐任务联邦元学习,该研究提出了一种新的 FML 方法用于推荐任务,既保护隐私又降低通信成本。
-
加州大学伯克利分校:加州大学伯克利分校的 RISELab 有多位研究人员正在从事 FML 研究。其最近的一项工作是跨异构设备的少量样本学习联邦元学习,该研究提出了一种新的 FML 方法,可以从异构设备上的数据中学习。
这些是正在积极从事 FML 研究的几个研究小组的例子。随着 FML 领域的持续发展,预计将有更多研究人员和研究小组专注于开发适用于各种应用的 FML 新技术。
自适应 FL
在 FL 中,设备的数据分布可能会随时间变化,导致概念漂移问题,这可能会降低模型的表现。最近的研究集中在开发新的自适应学习技术,这些技术可以在保护隐私的同时有效地更新模型。这些技术可以使模型适应变化的数据分布,并随着时间的推移提高模型的表现。自适应联邦学习(AFL)是 FL 中的一个新兴研究方向,它侧重于动态调整 FL 系统以适应不断变化的情况。
以下是一些正在积极从事 AFL 研究的知名研究人员和研究团队的例子:
-
卡内基梅隆大学:卡内基梅隆大学的机器学习系有几位研究人员正在从事 AFL 研究。他们最近的一项工作是自适应联邦优化,该研究提出了一种新的 AFL 框架,该框架根据网络条件调整学习率和聚合策略。
-
谷歌研究:谷歌研究一直在积极从事 AFL 研究,并开发了几种技术来适应 FL 系统不断变化的情况。他们最近的一项工作是具有局部下降的自适应联邦优化,该研究提出了一种新的 AFL 方法,该方法根据客户端的本地数据分布调整学习率和聚合策略。
-
南加州大学:南加州大学的计算机科学系有几位研究人员正在从事 AFL 研究。他们最近的一项工作是去中心化自适应联邦学习与梯度压缩,该研究提出了一种新的 AFL 方法,该方法根据网络条件调整学习率和聚合策略,同时压缩梯度以降低通信成本。
-
清华大学:清华大学的计算机科学与技术系有几位研究人员正在从事 AFL 研究。他们最近的一项工作是通过二次信息交换的自适应联邦学习,该研究提出了一种新的 AFL 方法,该方法基于客户端之间的二次信息交换来调整学习率和聚合策略。
这些只是积极从事 AFL 研究的几个研究团队的例子。随着 AFL 领域的不断发展,预计将有更多研究人员和研究团队专注于开发新技术,以适应不断变化的情况。
联邦强化学习
强化学习(RL)是一种机器学习范式,它使代理能够通过试错来学习。联邦强化学习(FRL)是一个新的研究方向,它将 FL 和 RL 相结合,以实现决策任务中的隐私保护协作学习。最近的研究探索了新的 FRL 算法和应用,例如自动驾驶和机器人技术。
许多研究人员和组织正在积极研究 FRL,以改进保护用户隐私和数据安全的机器学习技术。
这里有一些例子:
-
Google 的联邦学习群体(FLoC)团队正在开发 FRL,以创建用于广告定位的隐私保护用户模型。
-
斯坦福大学的研究人员一直在探索使用 FRL 来训练自主机器人。卡内基梅隆大学的研究团队正在研究 FRL 作为提高医疗机器学习模型效率和隐私的方法。
-
OpenMined 项目是一个社区驱动的倡议,旨在创建一个隐私保护机器学习的生态系统,包括联邦学习。
-
微软研究院正在开发用于分布式机器人应用的 FRL 方法。
这些只是许多正在研究 FRL 的研究人员和组织的少数例子,FRL 是一个快速发展的领域,有许多令人兴奋的发展和应用。
联邦肿瘤分割(FeTs)是由英特尔和宾夕法尼亚大学(UPenn)开发的现实世界医疗联邦学习平台。他们使用 OpenFL 作为平台的后端。
与联邦学习相关的关键公司产品
正如我们所见,联邦学习是一个快速发展的领域,已经引起了初创公司的广泛关注。以下是一些正在工作或提供联邦学习产品的公司的总结:
-
DynamoFL:DynamoFL 是由来自麻省理工学院(MIT)和哈佛的隐私和机器学习专家构建的,他们在 Google AI 构建了领先的联邦学习解决方案,在微软构建了增强隐私的技术。根据其网站,当前的大规模语言模型(LLMs)不是私有的,但 DynamoFL 的 LLMs 是私有的。他们提供个性化的联邦学习,这是另一个关键的研究领域。LLMs 在隐私保护生成 AI部分的第十章中有介绍。
-
NVIDIA FLARE:NVIDIA 的联邦学习应用运行环境(FLARE)是一个由 NVIDIA 开源的联邦学习 SDK。FLARE 支持各种联邦学习算法(FedAvg、FedProx、FedOpt 等)、神经网络和机器学习算法。它支持差分隐私和同态加密功能,作为安全和隐私保护堆栈的一部分。该 SDK 还提供了一个模拟器,可用于启动服务器和客户端,并执行联邦学习笔记本和应用程序。
-
OpenMined:OpenMined 是一个开源社区,提供了一个隐私保护机器学习的平台,包括联邦学习工具和库,用于安全的聚合和差分隐私。
-
DataFleets:DataFleets 提供了一个隐私保护数据访问和分析的平台,包括用于安全数据处理和分析的联邦学习工具。
-
Scaleout:Scaleout 提供了一个分布式机器学习的平台,包括用于隐私保护和协作模型训练的联邦学习工具。
-
Edge Impulse: Edge Impulse 提供了一个平台,用于在边缘设备上开发和部署机器学习模型,包括用于隐私保护模型训练和推理的联邦学习工具。
-
去中心化机器学习: 去中心化机器学习提供了一个平台,用于隐私保护和去中心化机器学习,包括用于安全聚合和差分隐私的联邦学习工具。
-
PySyft: PySyft 是一个用于联邦学习和多方安全计算的开放源代码库,它使分布式数据上的隐私保护和协作机器学习成为可能。
-
Intellegens: Intellegens 的产品起源于剑桥大学和 Ichnite,是一个可以部署在云端或本地环境的联邦学习平台产品(
intellegens.com/)。
这些公司积极贡献于联邦学习的发展与进步,为分布式数据上的隐私保护和协作机器学习提供工具和平台。随着联邦学习的持续发展,预计将有更多初创公司涌现,为这一领域的发展和创新做出贡献。
摘要
在本章中,我们探讨了联邦学习基准、它们的重要性以及如何设计基准,以及其他内容。我们还讨论了各种联邦学习框架,并探讨了在选择框架以实现联邦学习应用时需要考虑的因素。最后,我们介绍了各企业与关键大学合作进行的尖端研究,突出了一些积极工作并提供产品/平台以支持联邦学习的关键公司。
在下一章中,我们将了解同态加密和多方安全计算以及它们如何帮助在机器学习模型中实现隐私。
第四部分:同态加密、SMC、机密计算和 LLMs
本部分涵盖了同态加密和 SMC(安全多方计算)。它详细介绍了在大语言模型(LLMs)中的隐私保护。
我们介绍了同态加密(HE)和 SMC 作为隐私增强技术。我们强调了这些加密方法在实现对加密数据的加密计算而不损害隐私方面的重要性。
SMC 允许多个参与方在保持各自输入隐私的同时协同计算结果。我们的总结强调了在需要以隐私保护方式分析或处理敏感数据的情况下,HE(同态加密)和 SMC 的重要性。通过利用这些技术,组织和个人可以在获取有价值见解和结果的同时保护他们的数据。
本部分的第二章探讨了机密计算的概念,旨在为处理敏感数据提供一个可信和安全的 环境。本章还概述了机密计算的当前状态,突出了该领域的进步和正在进行的研究。它承认了可信执行环境(TEEs)和基于硬件的解决方案的出现,这些解决方案为机密计算提供了安全的区域。
最后一章介绍了生成式 AI 和 LLMs 的基本原理,以及与之相关的隐私漏洞,以及在使用这些模型时保护隐私的技术和方法。本章涵盖了使用开源 LLMs 开发 LLM 应用,并保护它们免受隐私攻击(提示注入攻击、成员推理攻击等),并以 LLMs 的最新隐私研究结束。
总体而言,本书的这一部分强调了 HE、SMC 和机密计算在保护敏感数据中的重要性。它强调了这些技术的当前状态,突出了它们解决隐私问题和在各种环境中实现安全数据处理潜力。
本部分包含以下章节:
-
第八章**,同态加密和 Secure Multiparty Computation
-
第九章**,机密计算 – 什么是、为什么以及当前状态
-
第十章**,大语言模型中的隐私保护
第八章:同态加密和安全多方计算
同态加密是一种密码学技术,它允许在加密数据上执行计算,而无需解密它。它有可能彻底改变数据隐私和安全,使得在不泄露数据本身的情况下安全地计算敏感数据。在本章中,你将了解同态加密和安全的多方计算。
本章我们将涵盖以下主要内容:
-
加密、匿名化和去标识化
-
同态加密及其背后的数学
-
用于同态加密和 Paillier 方案的开放源代码 Python 框架
-
使用同态加密(HE)进行机器学习
-
联邦学习与部分同态加密PHE
-
同态加密的限制
-
-
安全多方计算(SMC)及其用例
-
使用私有集交互(PSI)SMC 技术的一个用例实现
-
零知识证明的高级概述
加密、匿名化和去标识化
加密、匿名化和去标识化都是用于保护敏感数据的技巧,但它们在方法和限制上有所不同。
加密
加密是将数据转换为只有有权访问解密密钥的授权方才能读取的形式的过程。加密的目的是确保数据的机密性和完整性。加密数据对于拥有适当解密密钥的人来说仍然是可读的,但对于没有密钥的拦截者来说则是不可理解的。加密被广泛用于保护传输中和静止状态下的敏感数据,如信用卡号、密码和个人可识别信息。
下面是一些简单的 Python 代码,用于实现基本的加密
源代码:Encryption_Example.ipynb
开发一个函数,使用基本的加密算法加密给定的文本。
def simple_encryption(text, shift):
"""
Encrypts the given text using the Caesar Cipher algorithm.
"""
result = ""
# Loop through each character in the text
for i in range(len(text)):
char = text[i]
# If the character is a letter, shift its position in the alphabet
if char.isalpha():
if char.isupper():
result += chr((ord(char) + shift - 65) % 26 + 65)
else:
result += chr((ord(char) + shift - 97) % 26 + 97)
else:
result += char
return result
simple_encryption("Privacy Preserved Machine Learning",5)
上述代码的输出如下:
'Uwnafhd Uwjxjwaji Rfhmnsj Qjfwsnsl'
这个函数接受两个参数:text,表示要加密的明文,以及shift,表示明文中的每个字母在字母表中应该移动的位置数。该函数返回加密后的文本。
例如,如果你调用 simple_encryption(“Privacy Preserved Machine Learning”,5),那么该函数将返回字符串“Uwnafhd Uwjxjwaji Rfhmnsj Qjfwsnsl”,这是“Privacy Preserved Machine Learning”加密后的版本,移动了 5 个位置。
加密算法
今天有许多流行的加密算法用于保护数据和通信。最常见的是以下几种:
-
高级加密标准(AES):一种对称密钥加密算法,广泛用于保护传输中和静止状态下的数据
-
Rivest-Shamir-Adleman(RSA):一种用于安全通信和数字签名的非对称密钥加密算法
-
数据加密标准(DES):一种过去广泛使用的对称密钥加密算法,但现在被认为不够安全
-
Blowfish:一种对称密钥加密算法,专为高速和高效加密大量数据而设计
-
Twofish:一种对称密钥加密算法,是 Blowfish 的后继,旨在提供更高的安全性和灵活性
-
ChaCha20:一种对称密钥加密算法,由于其高安全性和性能而越来越受欢迎
-
椭圆曲线密码学(ECC):一种非对称密钥加密算法,使用椭圆曲线而不是素数,从而实现更小的密钥大小和更快的性能
这些只是最受欢迎的加密算法中的一部分。还有很多其他的算法,随着计算能力和安全需求的不断演变,新的算法也在不断被开发。
使用 AES 加密的加密示例
源代码:Encryption_Example.ipynb
开发一个函数,使用 AES 加密算法加密给定的文本:
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
def aes_encrypt(key, plaintext):
# initialization vector to random bytes
ini_vec = get_random_bytes(AES.block_size)
# Create the AES cipher object with the given key
aes_ciper = AES.new(key, AES.MODE_CBC, ini_vec)
# Pad the plaintext to a multiple of the block size
plaintext = pad_plain_text(plaintext, AES.block_size)
# Encrypt the plaintext using the AES cipher object
ciphertext = aes_ciper.encrypt(plaintext)
return ini_vec + ciphertext
def aes_decrypt(key, ciphertext):
ini_vec = ciphertext[:AES.block_size]
cipher = AES.new(key, AES.MODE_CBC, ini_vec)
plaintext = cipher.decrypt(ciphertext[AES.block_size:])
plaintext = unpad_decrypted_text(plaintext, AES.block_size)
return plaintext.decode('utf-8')
def pad_plain_text(data, block_size):
padding_length = block_size – (len(data) % block_size)
padding = bytes([padding_length] * padding_length)
return data + padding
def unpad_decrypted_text(data, block_size):
padding_length = data[-1]
if padding_length < 1 or padding_length > block_size:
raise ValueError("Padding is not Valid ")
padding = data[-padding_length:]
if not all(padding[i] == padding_length for i in range(padding_length)):
raise ValueError("Padding is not Valid ")
return data[:-padding_length]
key = b'ThisIsASecretKey'
plaintext = b'Privacy Preserved Machine Learning'
ciphertext = aes_encrypt(key, plaintext)
print('Encrypted message:', ciphertext)
decrypted_plaintext = aes_decrypt(key, ciphertext)
print('Decrypted message:', decrypted_plaintext)
这产生了以下输出:
Encrypted message: b'\xe3\x00\xe8\x10\xc6E\x0cn\x1bO,\x89-\x8d\xee\xb3\xc6\x1a\xbf\x95\\l\x0e\x8d\xb0\xaa\x93\xf4_$?h\x1a`O\xf4N\x89!4\xf7(\xd3\x8e\xde\xc7\xf7\xb8\x87\xea\n5W\x8e\xa5D\xec]\x80\xa8+\x92?\xa9'
Decrypted message: Privacy Preserved Machine Learning
在这个示例程序中,我们使用了 PyCrypto 库来实现 AES 加密,使用密码块链接(CBC)模式。
aes_encrypt函数接受 128 位密钥和明文消息作为输入,并返回加密的密文。aes_decrypt函数接受密钥和密文作为输入,并返回解密后的明文消息。我们使用了 PKCS7 填充方案来将明文填充到块大小的倍数,并在解密后移除填充。它为每次加密操作生成一个随机的初始化向量,以增加额外的安全层。
加密的局限性
加密并不提供匿名化或数据去标识化。加密数据可能包含可用于识别个人的敏感信息。加密仅保护数据在传输(数据在运动中)或存储(静止数据,即在持久存储中)时的安全,但它不控制谁有权访问它或解密后如何使用它。
数据匿名化
匿名化是从数据中移除可识别信息的过程,这样个人就无法被识别。匿名化的主要目的是在允许数据用于分析或研究用例的同时保护个人的隐私。
下面是一些用于数据匿名化的 Python 代码示例:
源代码:Example_Data_annomization.ipynb
import hashlib
import random
# Example dataset
dataset = [
{"name": "Alice", "age": 23, "email": "alice@example.com"},
{"name": "Bob", "age": 32, "email": "bob@example.com"},
{"name": "Gandhi", "age": 55, "email": "gandhi@example.com"},
]
# Create a random salt value for anonymization
salt = str(random.getrandbits(128))
# Loop through the dataset and anonymize each record
for record in dataset:
# Hash the name and email using the salt value name_hash = hashlib.sha256((record['name'] +salt).encode()).hexdigest() email_hash = hashlib.sha256((record['email'] + salt).encode()).hexdigest()
# Replace the original name and email with the hashed values
record['name'] = name_hash
record['email'] = email_hash
print(dataset)
这产生了以下输出:
[{'name': 'e807ef3ca985de8ef481ddf8af4d3ac4c34089519cf225a7863306ced0a691fa', 'age': 23, 'email': '474f2b3dce2701b08651d64364ab5e83575e9bd8ff7e0e14d654afbdf19f6683'}, {'name': '36cbc209f7afaba2a3a4d8830c2b85b3813f467f4bf442bb439b3f112be00bd0', 'age': 32, 'email': '6a7b3de0488fc3a81436b5c70e943ca7139c93d1832430db2e6bac3f2c25cce5'}, {'name': '096aca9f2b7872c89b9c71ff1a649e7fe53fc7eb1a04354792ea58aaee3bbecf', 'age': 55, 'email': 'e15e4e48f0161e7a64b8ef604e6d9bd5d9d6f2da3c8d848268aeec0ff5da2ef8'}]
在前面的代码中,我们使用了 Python 的hashlib库,使用随机盐值对数据集中的每个记录的名称和电子邮件字段进行哈希处理。然后,将这些哈希值存储在原始值的位置。这种技术可以用来保护数据集中敏感信息的隐私。
单独的匿名化是否足以保护敏感数据?简而言之,不够,正如我们将在以下真实案例研究中看到的那样。
真实世界的案例研究(Netflix 用户数据匿名化)
我们的 Netflix 数据匿名化案例研究可以追溯到 2006 年,当时 Netflix 推出了 Netflix Prize,这是一项旨在提高公司推荐算法准确性的竞赛。
作为比赛的一部分,Netflix 发布了一个包含 50 万订阅者观看历史的数据集,其中已移除个人可识别信息。该数据集可供研究人员开发更好的算法。2009 年,研究人员发表了一篇论文,表明可以通过使用互联网电影数据库(IMDb)的信息来重新识别 Netflix 数据集中的个人。研究人员能够将匿名化的观看历史与用户在 IMDb 上发布的评论相匹配,从而以高精度重新识别个人。
在这一发现之后,Netflix 采取了措施改进其匿名化技术,但到了 2010 年,研究人员再次表明,在 Netflix 数据集中重新识别个人是可能的。这一次,研究人员使用了外部数据源,如社交网络和电影评分网站来重新识别个人。
针对这些隐私问题,Netflix 于 2010 年停止向研究人员发布匿名化数据集。相反,公司创建了一个内部研究项目,研究人员可以在不共享任何个人可识别信息的情况下分析 Netflix 数据。然而,到了 2020 年,德克萨斯大学奥斯汀分校和加州大学欧文分校的一组研究人员表明,他们可以通过分析观看历史并将其与公开可用的数据集相关联来重新识别 Netflix 用户。研究人员能够在 Netflix 数据集中没有个人可识别信息的情况下准确重新识别用户。
这些发现表明,仅靠匿名化技术不足以保护用户隐私,因为它们容易受到数据关联攻击的影响,我们在第一章中了解到这一点。
匿名化的局限性
匿名化可能无法完全消除重新识别的风险。如果数据足够充分,通过将匿名化数据与其他可用信息(如公共数据集)关联,可能识别出个人。
匿名化可能导致数据质量或准确性的损失,因为在过程中可能会删除或掩盖某些数据元素。
去标识化
去标识化是去除或掩盖数据中的可识别信息的过程,以便无法用于识别个人。去标识化的目的是在允许数据用于研究、分析或其他应用的同时保护个人隐私。去标识化数据可用于医疗保健研究、市场营销分析、金融用例、物联网用例和其他需要敏感数据的用例。
去标识化算法
单向哈希算法可用于对数据进行去标识化处理。单向哈希算法,也称为加密哈希函数,是数学函数,它接受任何长度的输入消息并生成一个固定大小的输出,这被称为哈希或信息摘要。单向哈希算法的关键特性是它们被设计成从哈希值中逆向工程原始输入消息在计算上是不可行的。
有许多不同的哈希算法,并且新的算法正在不断被开发。
以下是一些最广泛使用的哈希算法:
-
信息摘要 5 (MD5): 这是一个广泛使用的哈希算法,它产生一个 128 位的哈希值。由于设计中的漏洞,现在被认为是不安全的。
-
安全哈希算法 1 (SHA-1): 这是另一个广泛使用的哈希算法,它产生一个 160 位的哈希值。现在它被认为是不安全的。
-
安全哈希算法 2 (SHA-2): 这是一个包括 SHA-224、SHA-256、SHA-384 和 SHA-512 的哈希算法系列。这些算法分别产生 224 位、256 位、384 位和 512 位的哈希值。
-
安全哈希算法 3 (SHA-3): 这是一个包括 SHA3-224、SHA3-256、SHA3-384 和 SHA3-512 的哈希算法系列。这些算法被设计为 SHA-2 的替代品,并分别产生 224 位、256 位、384 位和 512 位的哈希值。
-
BLAKE2: 这是一个包括 BLAKE2b 和 BLAKE2s 的哈希算法系列。这些算法被设计得比 SHA-3 更快,同时仍然提供强大的安全性。
-
RACE 完整性原语评估信息摘要 (RIPEMD): 这是一个包括 RIPEMD-128、RIPEMD-160、RIPEMD-256 和 RIPEMD-320 的哈希算法系列。这些算法被设计为 MD4 和 MD5 算法的替代品,并分别产生 128 位、160 位、256 位和 320 位的哈希值。
-
Whirlpool: 这是一个产生 512 位哈希值的哈希算法。它被设计为 SHA-2 算法系列的替代品。
这些是可用的哈希算法的一些示例。选择使用哪种算法将取决于具体的应用和所需的在安全性、速度和其他因素之间的平衡。
用于去标识化数据的示例 Python 代码
如前所述,去标识化是删除或屏蔽数据中的可识别信息的过程,以便无法用它来识别原始数据。在下面的代码中,我们将使用 SHA256 哈希算法对给定的数据(在这种情况下是一个字符串)进行去标识化。
源代码: De-Identify_Exmple.ipynb
import hashlib
# Define a function to hash a given string using SHA256 Algorithm
def hash_string(s):
return hashlib.sha256(s.encode()).hexdigest()
# Define a function to de-identify a given input data
def deidentify_data(data):
# Remove leading/trailing whitespace and convert to lowercase
data = data.strip().lower()
# Hash the name using SHA-256
hashed_data = hash_string(name)
# Return the hashed data
return hashed_data
# input
person_name = "Sundar P"
hashed_name = deidentify_data(person_name)
print(hashed_name)
这将产生以下输出:
"6cea57c2fb6cbc2a40411135005760f241fffc3e5e67ab99882726431037f908""
在此示例中,使用 hashlib 库计算给定输入字符串的 SHA-256 哈希。我们定义了一个 deidentify_data 函数,该函数接受数据作为输入,删除任何前导/尾随空白,将数据转换为小写,然后使用 hash_string 函数对其进行哈希处理。
这确保了相同的输入名称将始终产生相同的输出哈希。请注意,由于单向哈希是一个不可逆的过程,因此无法从哈希值中检索原始名称。
Python 中的 hashlib 库提供了一系列哈希算法。hashlib 库中可用的方法如下:
-
hashlib.md5(): 此方法返回一个 MD5 哈希对象
-
hashlib.sha1(): 此方法返回一个 SHA-1 哈希对象
-
hashlib.sha224(): 此方法返回一个 SHA-224 哈希对象
-
hashlib.sha256(): 此方法返回一个 SHA-256 哈希对象
-
hashlib.sha384(): 此方法返回一个 SHA-384 哈希对象
-
hashlib.sha512(): 此方法返回一个 SHA-512 哈希对象
-
hashlib.blake2s(): 此方法返回一个 BLAKE2s 哈希对象
-
hashlib.blake2b(): 此方法返回一个 BLAKE2b 哈希对象
-
hashlib.sha3_224(): 此方法返回一个 SHA3-224 哈希对象
-
hashlib.sha3_256(): 此方法返回一个 SHA3-256 哈希对象
-
hashlib.sha3_384(): 此方法返回一个 SHA3-384 哈希对象
-
hashlib.sha3_512(): 此方法返回一个 SHA3-512 哈希对象
去标识化的目的是使个人信息难以或无法识别个人。
去标识化的局限性
去标识化可能无法完全消除重新识别的风险。如果数据足够多,可能根据其他可用信息识别个人。去标识化可能导致数据质量或准确性下降,因为在处理过程中可能会删除或掩盖某些数据元素。
总结来说,每种技术都有其自身的优势和局限性,应根据具体的使用场景和需求选择合适的技术。加密是保护数据最安全的方式,但它不提供匿名性或去标识化。匿名化和去标识化都可以提供隐私保护,但在所有情况下可能并不足够,并可能导致数据质量或准确性问题。
探索同态加密
同态加密(HE)是一种加密技术,允许在不解密数据的情况下对加密数据进行计算。换句话说,可以对密文执行操作,生成新的密文,这些密文解密后即为对明文操作的结果。HE 有潜力彻底改变数据隐私和安全,允许在不泄露数据本身的情况下安全地计算敏感数据。HE 基于数学概念,如代数结构、数论和多项式理论。最常见的 HE 类型基于以下代数结构。
基于环
在密码学的背景下,代数结构指的是可以在集合的元素上以特定方式执行的一组数学运算。在环的情况下,元素集合在加法和乘法下是封闭的,并且操作满足某些性质,例如结合性、交换性和存在单位元素和逆元素。在 HE 的背景下,代数结构用于在加密数据上执行计算,而无需首先解密它。底层代数结构是一个环,它是一组元素,具有满足某些性质的两个二元运算(加法和乘法)。最广泛使用的基于环的 HE 是Brakerski-Gentry-Vaikuntanathan(BGV)方案。
BGV 方案是基于学习错误(LWE)问题的全同态加密(FHE)方案。
现在我们来考察该方案的数学描述。
密钥生成
为了生成公钥,执行以下步骤:
-
选择两个整数 n 和 q,其中 q 是素数。
-
生成一个具有整数项且在范围[-q/2, q/2]内的随机矩阵 A。
-
生成一个具有整数项且在范围[-q/2, q/2]内的随机向量。
-
计算向量 b = As + e,其中 e 是具有范围[-B/2, B/2]的随机向量,B 是某个整数。
-
将公钥设置为(A, b)。
为了生成私钥,选择一个具有整数项且在范围[-q/2, q/2]内的随机向量 s。
加密
要加密消息 m,执行以下步骤:
-
将消息 m 表示为具有模 q 整数系数的多项式 m(x)。
-
选择一个具有模 q 整数系数的随机多项式 r(x)。
-
计算 c = (Ar + b + m(x)t)/q,其中 t 是控制密文噪声的缩放因子。
生成的密文 c 由一个矩阵和一个多项式组成。
解密
要解密密文 c,执行以下步骤:
-
计算新的 c’ = c*s/q。
-
将 c’的每个条目四舍五入到最接近的整数。
-
通过从 c’中减去 A*r 来恢复多项式 m(x)。
同态操作
BGV 方案允许在密文上执行同态加法和乘法。这些操作如下所示:
同态加法:为了将两个密文 c1 和 c2 相加,将它们对应的多项式在模 q 下相加,并逐元素地将它们的矩阵相加,模 q。
同态乘法:为了将两个密文 c1 和 c2 相乘,使用多项式乘法算法计算它们在模 q 下的乘积,并使用模 q 的矩阵乘法来乘以它们的矩阵。
自举
要执行多个同态乘法,BGV 方案使用一种称为引导(bootstrapping)的技术来“刷新”密文。引导过程包括解码密文,执行同态运算,然后使用一组新密钥重新加密结果。引导过程允许在保持方案安全性的同时,在密文中执行任意数量的同态运算。
基于格的
基于格的 HE 使用数学概念格,这是高维空间中的几何结构,允许高效地计算某些类型的问题。最广泛使用的基于格的 HE 是 FHE 方案。
基于椭圆曲线的
基于椭圆曲线的 HE 使用有限域上的椭圆曲线来创建加密方案。这种类型的 HE 相对较新,不如其他两种类型广泛使用。
探索 HE 背后的数学
HE 背后的数学基于两个主要概念:加密和同态。
加密
加密是将明文通过加密算法和密钥转换成密文的过程。密文可以在网络上传输或存储在数据库中,而不用担心未授权的访问。要解密密文并获取明文,接收者必须拥有用于加密数据的密钥。
同态
同态是一种数学属性,允许在密文中执行运算,生成一个新的密文,它是明文运算的结果。这意味着如果我们有两个明文 x 和 y,以及它们各自的密文 C(x)和 C(y),我们可以在 C(x)和 C(y)上执行一个运算,以获得一个新的密文 C(x+y),该密文可以解密以获得 x 和 y 运算的结果。
最常用的同态运算是加法和乘法,但也可以执行减法和除法等其他运算。同态运算的水平决定了在加密过程中引入的噪声变得过高,密文变得无法使用之前,可以在密文中执行多少操作。
HE 基于向密文中添加噪声的概念,使得没有密钥就无法恢复明文。噪声以这种方式添加,使得可以在不泄露明文的情况下对密文执行同态运算。添加的噪声量决定了加密的安全性级别。噪声也是同态运算水平受限的原因,因为过多的同态运算会导致噪声过高,使得密文无法使用。
HE 的类型
HE 有三种实现类型。现在让我们来探讨它们。
完全同态加密(FHE)
FHE 是一种允许在加密数据上执行计算而不解密的加密类型。这意味着密文可以用作计算的输入,计算结果也将是密文,该密文可以被解密以获取计算结果。FHE 是一种强大的工具,可用于各种应用,如云计算、机器学习和安全外包。FHE 的主要挑战之一是其计算复杂性,这使得它在许多应用中不切实际。然而,FHE 的近期进展导致了更高效算法的发展,这些算法降低了 FHE 的计算开销。
Gentry 方案是早期且最著名的 FHE 方案之一,但它具有很高的计算成本。更近期的方案,如 CKKS 方案和 BFV 方案,提供了更高效的 FHE 算法,适用于实际应用。
部分同态加密(SHE)
SHE 是一种允许在加密数据上执行有限计算的加密类型。与 FHE 不同,SHE 不能在加密数据上执行任意计算。相反,它只能在加密数据上执行有限的操作集,例如加法和乘法。虽然 SHE 在功能上不如 FHE 强大,但它仍然在许多应用中很有用,例如安全投票、安全消息传递和安全数据库查询。SHE 的计算复杂度低于 FHE,这使得它在某些应用中更加实用。
部分同态加密(PHE)
PHE 是一种允许对加密数据进行计算的加密类型,但仅限于一种操作,要么是加法要么是乘法。PHE 在功能上不如 FHE 和 SHE 强大,但在某些应用中仍然有用,例如安全密钥生成、安全函数评估和安全标量积计算。PHE 的计算复杂度低于 FHE 和 SHE,这使得它在某些应用中更加实用。然而,其有限的功能意味着它不如 FHE 和 SHE 灵活,并且不能用于那么多的应用。
FHE、SHE 和 PHE 是三种相关的加密方案,提供了不同层次的功能和计算复杂性。FHE 功能最强大,但计算复杂度也最高,而 PHE 功能最弱,但计算复杂度也最低。SHE 在功能和计算复杂性方面介于 FHE 和 PHE 之间。
Paillier 方案
Paillier 方案是一种用于数据加密和解密的公钥密码系统。它基于数学假设,即决策复合剩余性假设(DCRA),这是一个计算难题。该方案以它的创造者 Pascal Paillier 的名字命名,他在 1999 年引入了它。
Paillier 方案是一种非对称加密算法,这意味着它使用两个不同的密钥:一个公钥用于加密,一个私钥用于解密。该方案被设计为概率性的,这意味着对给定明文的每次加密都会产生不同的密文。该方案也是同态的,这意味着它支持对加密数据执行某些类型的操作。
密钥生成
要使用 Paillier 方案,用户首先生成一个公钥和一个相应的私钥。公钥由两个大素数 p 和 q 组成,这些数是保密的。然后,用户计算 n = p * q 和 lambda = LCM(p - 1, q - 1),其中 LCM 是最小公倍数函数。lambda 的值用于生成私钥。
加密
要加密消息,发送者使用接收者的公钥。明文消息表示为一个整数 m,其中 0 <= m < n。然后,发送者选择一个随机数 r,其中 0 <= r < n,并计算 c = g^m * r^n mod n²,其中 g 是 n² 模下的随机生成器。然后,将密文 c 发送给接收者。
解密
要解密密文,接收者使用他们的私钥。接收者首先计算以下值
mu = (L(g^lambda mod n²)^-1 mod n)(lambda-1 mod n)
其中
L(x) = (x - 1) / n
使用 mu 值来计算明文消息 m,如下所示:
m = L(c^lambda mod n²) * mu mod n
然后,接收者可以从 m 中恢复原始消息。
同态属性
Paillier 方案支持两种同态属性:加法和乘法。
加法属性允许接收者对加密数据进行加法操作。给定两个对应于明文消息 m1 和 m2 的密文 c1 和 c2,接收者可以通过将 c1 * c2 模 n² 来计算一个新的密文 c3,该密文对应于 m1 和 m2 的和。
乘法属性允许接收者对加密数据进行乘法操作。给定一个对应于明文消息 m 的密文 c,接收者可以通过将 c 提升到 k 次幂并取模 n² 来计算一个新的密文 c',该密文对应于 m 和常数 k 的乘积。
安全性
Paillier 方案也抵抗已知的明文攻击和选择明文攻击。该方案被用于各种应用中,包括电子投票、隐私保护数据挖掘和安全的多方计算。
在下一节中,我们将介绍用于实现 HE 的 Python 框架。我们将详细实现一些示例,以便更好地理解同态操作。
Pyfhel
Pyfhel 是一个用于 FHE 的 Python 库。它提供了一个易于使用的接口,用于在加密数据上执行 FHE 操作。
URL: pyfhel.readthedocs.io/en/latest/
SEAL Python
SEAL Python 是一个用于 Simple Encrypted Arithmetic Library (SEAL) C++ 库的 Python 封装。SEAL Python 提供了一个高级接口,用于使用 Brakerski/Fan-Vercauteren (BFV) 和 Cheon-Kim-Kim-Song (CKKS) 方案在数据上执行同态加密和解密操作。
URL: github.com/Huelse/SEAL-Python
TenSEAL
TenSEAL 是一个在 n 张张量上执行同态加密的 Python 库,基于 Microsoft SEAL 并使用 CKKS 方案。它提供了一个易于使用的接口,用于在加密数据上执行 FHE 操作,并支持批处理和批处理旋转。
TenSEAL 提供的主要功能如下:
-
使用 BFV 对整数向量进行加密/解密
-
使用 CKKS 对实数向量进行加密/解密
-
加密-加密向量和加密-明文向量逐元素加法、减法和乘法
-
点积和向量-矩阵乘法
URL: github.com/OpenMined/TenSEAL
phe
phe 是一个使用 Paillier 方案进行 部分同态加密 (PHE) 的 Python 库。它提供了一个 API,用于在加密数据上执行 PHE 操作。
它是一个简单易用的库。它只支持四个操作中的三个(加法、减法和标量乘法)在 HE 上。
Paillier 密码系统的同态属性工作如下。
加密的数字可以相加:
Enc(m1)+Enc(m2)≡Enc(m1+m2)

图 8.1 – 同态加法
加密的数字可以相互减去:
Enc(m1)-Enc(m2)≡Enc(m1-m2)

图 8.2 – 同态减法
加密的数字可以乘以一个非加密标量:
n⋅Enc(m) ≡ Enc(n*m)

图 8.3 – 同态加密的数字乘以非加密标量
加密的数字可以加到非加密标量上:
n+Enc(m) ≡ Enc(n+m)

图 8.4 – 同态加密的数字加到非加密标量上
实现 HE
要实现 HE,从之前概述的库中选择一个合适的 HE 库。确保你的选择基于你的特定用例,然后执行以下步骤:
-
生成加密方案所需的公钥和私钥。
-
将需要加密的明文数据转换为加密方案所需的合适格式,例如多项式。
-
使用在 步骤 2 中生成的公钥加密明文数据。
-
在密文数据上执行同态操作,而不进行解密。
-
使用在 步骤 2 中生成的私钥解密生成的密文数据,以获得对明文数据进行同态运算的结果。
实现 HE 可能很复杂,需要密码学和数学方面的专业知识。确保实现既安全又高效很重要,因为 HE 可能计算密集。
实现 PHE
我们将使用开源的 phe Python 库实现 Paillier PHE 的一个示例。
首先,我们按照以下方式安装 phe 库:
pip3 install phe
然后我们执行以下步骤:
-
使用 phe.paillier 类中的 generate_paillier_keypair 方法生成公钥和私钥。
-
使用 encrypt 方法加密明文数据(本例中为 15)。
-
对密文数据进行同态运算:
-
ciphertext1 = ciphertext * 3 // 加密数字乘以一个标量
-
ciphertext2 = ciphertext + ciphertext1 // 两个加密数字相加
-
ciphertext3 = ciphertext1 + 250 // 将标量加到一个加密数字上
-
ciphertext4 = ciphertext3 - ciphertext2
-
-
最后,使用 decrypt 方法解密生成的密文数据,并打印解密结果。
源代码:FHE-Example.ipynb
import phe as paillier
pubkey, privkey = paillier.generate_paillier_keypair(n_length=1024)
print("public key",pubkey)
print("private key", privkey)
public key <PaillierPublicKey 18dced683d>
private key <PaillierPrivateKey for <PaillierPublicKey 18dced683d>>
plaintext = 15
ciphertext = pubkey.encrypt(plaintext)
# Perform homomorphic operations on the ciphertext data
ciphertext1 = ciphertext * 3
ciphertext2 = ciphertext + ciphertext1
ciphertext3 = ciphertext1 + 250
ciphertext4 = ciphertext3 - ciphertext2
# Decrypt the resulting ciphertext data
decrypted1 = privkey.decrypt(ciphertext1)
decrypted2 = privkey.decrypt(ciphertext2)
decrypted3 = privkey.decrypt(ciphertext3)
decrypted4 = privkey.decrypt(ciphertext4)
# Print the decrypted results
print("ciphertext1 decrypted: ", decrypted1)
print("ciphertext2 decrypted: ", decrypted2)
print("ciphertext3 decrypted: ", decrypted3)
print("ciphertext4 decrypted: ", decrypted4)
ciphertext1 decrypted: 45
ciphertext2 decrypted: 60
ciphertext3 decrypted: 295
ciphertext3 decrypted: 235
ciphertext1 : <phe.paillier.EncryptedNumber object at 0x7fd51856afa0>
ciphertext2 : <phe.paillier.EncryptedNumber object at 0x7fd5185c3580>
ciphertext3 : <phe.paillier.EncryptedNumber object at 0x7fd51856ac70>
ciphertext4 : <phe.paillier.EncryptedNumber object at 0x7fd5185c3460>
用一个加密数字乘以另一个加密数字怎么样?
以下操作与 PHE 是否兼容?
Enc(m1) * Enc(m2)≡Enc(m1 * m2)
让我们试试这个,看看结果如何:
m1=15
m2=20
pubkey.encrypt(m1) * pubkey.encrypt(m2)
File ~/Library/Python/3.8/lib/python/site-packages/phe/paillier.py:508, in EncryptedNumber.__mul__(self, other)
506 """Multiply by an int, float, or EncodedNumber."""
507 if isinstance(other, EncryptedNumber):
--> 508 raise NotImplementedError('Good luck with that...')
510 if isinstance(other, EncodedNumber):
511 encoding = other
NotImplementedError: Good luck with that...
它抛出 NotImplementedError,这基本上意味着 phe 不支持这个(将一个加密数字与另一个加密数字相乘)HE 属性。
当你的需求需要开发涉及张量、矩阵、数组以及所有同态运算的应用程序时,TenSEAL 是最佳框架。
使用 TenSEAL 库实现 HE
我们将使用开源的 TenSEAL Python 库实现 HE 的一个示例。
首先,我们按照以下方式安装 TenSEAL 库:
pip3 install tenseal
源代码:TenSeal_Example.ipynb
按照以下方式开发示例应用程序。
import tenseal as ts
# Step 1: Create context
context = ts.context(
ts.SCHEME_TYPE.CKKS,
poly_modulus_degree=8192,
coeff_mod_bit_sizes=[60, 40, 40, 60]
)
context.generate_galois_keys()
context.global_scale = 2**40
# Step 2: Create and encrypt data
data1 = [1.0, 2.0, 3.0, 4.0]
data2 = [5.0, 6.0, 7.0, 8.0]
encrypted_data1 = ts.ckks_vector(context, data1)
encrypted_data2 = ts.ckks_vector(context, data2)
# Step 3: Perform operations on encrypted data
encrypted_sum = encrypted_data1 + encrypted_data2
encrypted_product = encrypted_data1 * encrypted_data2
encrypted_dot_product = encrypted_data1.dot(encrypted_data2)
matrix_a = [[73],[69],[87],[45],]
mat_product = encrypted_data1.matmul(matrix_a)
# Step 4: Decrypt result
sum_result = encrypted_sum.decrypt()
product_result = encrypted_product.decrypt()
dot_product_result = encrypted_dot_product.decrypt()
mat_result = mat_product.decrypt()
print("Sum: ", sum_result)
print("Product: ", product_result)
print("Dot product: ", dot_product_result)
print("Matrix Multiplication : ", mat_result)
Sum: [6.000000000650802, 8.000000001433328, 10.0000000008995, 12.000000000314097]
Product: [5.000000671234171, 12.000001615240716, 21.000002823083314, 32.000004292130704]
Dot product: [70.00000937472286]
Matrix Multiplication : [652.000087556169]
在前面的示例代码中,我们首先使用 CKKS 方案创建一个上下文,其多项式模数度为 8,192,四个系数模数位大小为 60、40、40 和 60。然后,我们创建两个 CKKS 向量并加密我们的数据。接下来,我们在加密数据上执行两个操作:加法和乘法。最后,我们解密这些操作的成果并打印出来。
此库还支持使用 BFV 方案创建上下文,以及以相同方式使用 BFV 方案进行同态运算。
这是一个简单的示例,在实践中,HE 可能计算密集,需要专用硬件或云资源。同时,确保实现的安全性也很重要,以防止在计算过程中加密数据泄露。
HE 框架的比较
让我们回顾一下 Python 中一些最受欢迎的 HE 框架的比较。
Pyfhel
Pyfhel 是一个基于 Python 的完全 HE 库,支持在加密整数和向量上执行操作。它建立在 HElib C++ 库之上,并为 Python 开发者提供了简化的接口。Pyfhel 具有良好的性能,可以高效地处理大整数和向量。然而,它目前还不支持浮点数的操作。
TenSEAL
TenSEAL 是一个基于 Python 的 HE 库,支持 FHE 和 PHE。它使用 CKKS 和 BFV 加密方案,并提供加密浮点数和矩阵操作的 API。TenSEAL 设计得易于使用,与一些其他 HE 库相比,API 更简单。它在加密浮点数操作方面具有相对较高的性能。
PALISADE
PALISADE 是一个具有 Python 绑定的 C++ HE 库。它支持 FHE 和 PHE,并提供包括 CKKS、BFV 和 GSW 在内的广泛加密方案。PALISADE 设计用于性能,可以高效地处理大明文和大密文。Python 绑定相对较新,API 相比其他基于 Python 的 HE 库可能更复杂。
PySEAL
PySEAL 是一个基于 Python 的 HE 库,支持在加密整数和向量上执行 FHE 操作。它建立在 SEAL C++ 库之上,并为 Python 提供了简化的接口。PySEAL 在整数和向量操作方面具有良好的性能,可以处理大明文和大密文。然而,它目前还不支持浮点数的操作。
TFHE
TFHE 是一个具有 Python 绑定的 C++ HE 库。它支持在加密整数和布尔值上执行 PHE 操作,并设计用于高性能。TFHE 可以高效地处理大密文,并且具有相对简单的 API。Python 绑定相对较新,文档可能有限。
下表提供了一个关于前面 HE 库之间比较的高级概述:
| 操作 | PySEAL | TenSEAL | Paillier | Pyfhel |
|---|---|---|---|---|
| 加法 | 是 | 是 | 是 | 是 |
| 减法 | 是 | 是 | 是 | 否 |
| 乘法 | 是 | 是 | 否 | 是 |
| 除法 | 否 | 否 | 否 | 否 |
| 比较运算(<, >, <=, >=, 和 ==) | 否 | 否 | 否 | 否 |
| 支持向量操作(加法、点积等) | 是 | 是 | 否 | 否 |
| 矩阵操作 | 是 | 是 | 否 | 否 |
| 加密数与标量(非加密数)相加 | 是 | 是 | 是 | 是 |
| 加密数与标量(非加密数)相乘 | 是 | 是 | 是 | 是 |
表 8.1 – HE 框架的高级比较
每个 HE 框架都有其自身的优点和缺点,最佳选择将取决于您的具体用例和需求。Pyfhel 和 PySEAL 是用于整数和向量 FHE 操作的不错选择,而 TenSEAL 是用于浮点数和矩阵 FHE 操作的不错选择。PALISADE 提供了广泛的加密方案,并针对性能设计,而 TFHE 是用于整数和布尔值 PHE 操作的不错选择。
使用 HE 进行机器学习
HE 可用于机器学习(ML)模型,以加密训练数据、测试数据,甚至整个模型本身,以实现模型安全。
以下是一些实现使用 HE 的 ML 模型选项:
-
加密权重(模型参数)和截距,并利用它们来计算测试数据上模型的准确率。
-
加密测试数据,并使用加密模型和加密数据来找出准确率。
-
使用加密的训练数据构建模型,并计算明文模型以及加密训练数据模型的准确率。
-
加密训练数据,在加密数据上训练模型,然后运行推理并解密结果。
在本例中,我们将加密模型参数并执行以下操作:
-
使用欺诈检测模型示例:
-
加载欺诈交易数据
-
将数据分为训练集和测试集
-
使用逻辑回归模型训练数据
-
从模型中找出截距和系数(权重)
-
-
使用 Paillier PHE 库,执行以下操作:
-
使用公钥对模型参数(即截距值和模型权重)进行 HE 操作
-
使用加密的截距和加密模型权重找出预测:
-
通过同态操作(加密权重乘以测试特征数据并添加加密数字)计算分数
-
使用同态解密解密计算出的分数,并找出错误/准确率
-
-

图 8.5 – 使用 HE 加密模型参数
来源 代码: FHE_Logistic.ipynb
以下代码实现了上述步骤。
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
url="fraud_transactions.csv"
df_actual = pd.read_csv(url, sep=",")
df_actual.head()
df_transactions = df_actual[['CUSTOMER_ID','TERMINAL_ID','TX_AMOUNT','TX_FRAUD']]
df_transactions
from sklearn.model_selection import train_test_split
from sklearn.model_selection import StratifiedShuffleSplit
X = df_transactions.drop('TX_FRAUD', axis=1)
y = df_transactions['TX_FRAUD']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
X_train = X_train.values
X_test = X_test.values
y_train = y_train.values
y_test = y_test.values
from sklearn.model_selection import cross_val_score
logreg = LogisticRegression(random_state=0)
logreg.fit(X_train, y_train)
training_score = cross_val_score(logreg, X_train, y_train, cv=2)
print('Logistic Regression Cross Validation Score: ', round(training_score.mean() * 100, 2).astype(str) + '%')
import numpy as np
np.sum(logreg.predict(X_test) == y_test)/X_test.shape[0]
logreg.intercept_[0], logreg.coef_[0]
这将产生以下输出:
(-1168.308115256604,
array([-2.47724513e-05, 3.17749573e-06, 1.54748556e+01]))
### Encrypt the Weights and Bias ( intercept) using paillier encryption
import phe as paillier
pubkey, privkey = paillier.generate_paillier_keypair(n_length=1024)
coef = logreg.coef_[0, :]
encrypted_weights = [pubkey.encrypt(coef[i]) for i in range(coef.shape[0])]
encrypted_intercept =pubkey.encrypt(logreg.intercept_[0])
print(encrypted_weights)
[<phe.paillier.EncryptedNumber object at 0x7ff005a9c9d0>, <phe.paillier.EncryptedNumber object at 0x7fefe3b2c520>, <phe.paillier.EncryptedNumber object at 0x7ff010760cd0>]
print(encrypted_intercept)
<phe.paillier.EncryptedNumber at 0x7fefb812f100>
### calculate score using encrypted weights for the 100 sample in the tests data and calculate the accuracy
y=np.zeros(100)
for i in range(1,100):
c1 = X_test[i][0]
c2 = X_test[i][1]
c3 = X_test[i][2]
score = encrypted_intercept
score += c1 * encrypted_weights[0] + c2 * encrypted_weights[1] + c3 * encrypted_weights[2]
dscore = privkey.decrypt(score)
y[i] = dscore
print(y[0],y_test[0])
error = np.mean(np.sign(y) != y_test[1:100])
print(error)
Output:
0.0 0
1.0
这样,ML 工程师能够在保持其 ML 模型安全性的同时,与他人共享使用 HE 生成的公钥以及加密的模型权重。
加密评估 ML 模型和推理
为了执行加密评估和推理,请遵循以下步骤:
-
使用公钥(即 HE 密钥)加密训练数据。
-
使用加密数据训练模型。
-
获取加密结果。
-
使用密钥(即私钥)解密结果。

图 8.6 – 加密评估 ML 模型和推理
HE 的局限性
HE 是一种强大的密码学技术,允许在加密数据上执行计算,而无需解密。虽然 HE 有多个优点,但它也有一些限制,我们现在将探讨这些限制:
-
性能:HE 计算密集,可能运行缓慢,尤其是在处理大量数据时。与加密和解密相关的开销可能会显著影响系统的性能。
-
功能有限:HE 仍然是一个发展中的领域,当前的实现具有有限的功能。复杂的计算通常难以使用 HE 执行,并且并非所有类型的计算都可以使用当前的 HE 技术执行。
-
密钥管理:HE 需要管理大量的加密密钥,这可能具有挑战性,尤其是在分布式系统中。随着参与计算各方数量的增加,密钥管理问题变得更加复杂。
-
安全假设:HE 基于某些安全假设,如果这些假设被违反,系统的安全性可能会受到损害。例如,如果攻击者可以访问密钥或加密数据泄露,系统的安全性可能会受到损害。
-
存储需求:HE 可能导致大的密文,需要比明文更多的存储空间。在存储空间有限的情况下,这可能是一个挑战。
在考虑在系统中使用 HE(同态加密)时,需要考虑上述限制。虽然 HE 有潜力提供一种安全和隐私保护解决方案,但在将其用于现实世界系统之前,仔细评估其限制和权衡是至关重要的。
安全多方计算
安全多方计算(SMC)是一种密码学技术,它允许两个或多个各方在他们的私有数据上共同计算一个函数,而无需向彼此透露他们的数据。
SMC(安全多方计算)是隐私保护计算中的一个重要工具,在这种计算中,各方可能不信任彼此或中心权威机构,并且可能拥有他们不想与其他方共享的敏感数据。
在本节中,我们将了解 SMC 的基本原则、其应用以及用于 SMC 的一些技术。
SMC 的基本原则
SMC 的基本原则是,每个方都有他们希望保密的私有数据,但他们希望对共同联合数据上的函数进行计算。SMC 通过将计算划分为更小、更不敏感的子计算,并在每个方的私有数据上本地执行这些子计算,使多个方能够安全地这样做。然后,各方相互沟通,仅揭示计算的最终输出。
SMC 确保没有任何一方能够了解其他各方数据的任何信息,除非是计算最终输出所必需的。在 SMC 中进行的计算设计得使得任何一方都无法通过分析计算过程中发送的消息来了解其他各方的数据。
SMC 的安全性依赖于诸如秘密共享、HE 和 oblivious transfer 等密码学技术。这些技术确保每个方只能看到输入数据的一小部分,并且输出是以一种方式计算的,使得任何一方都无法确定其他各方的输入数据。
SMC 的应用
SMC 在各个领域都有多个应用,包括医疗保健、金融和数据隐私。现在我们将更详细地探讨这些应用:
-
数据分析:在许多情况下,数据分布在不同的各方之间,不可能或不需要将数据集中在一个位置。SMC 可以用来使各方能够在不向彼此泄露数据的情况下对其私有数据进行计算。
-
ML:SMC 可以用来使多个各方能够在他们的私有数据上联合训练 ML 模型,而无需相互共享他们的数据。这在数据隐私是关注点的情况下非常有用,例如在医疗保健或金融服务中。
-
隐私保护 认证:SMC 可以用来使多个各方能够在不向彼此泄露身份的情况下进行认证。例如,一组用户可以使用 SMC 与服务提供商进行认证,而不向彼此泄露他们的身份。
-
欺诈检测:SMC 可以用来使不同的各方能够检测欺诈活动,而不泄露任何敏感信息。例如,多个银行可以使用 SMC 来计算它们的交易列表的交集,以检测欺诈交易,而不泄露任何客户数据。我们已经讨论了使用带有差分隐私的联邦学习,但同样的用例,即检测欺诈交易,也可以使用 SMC 来实现。
SMC 使用的技巧
SMC 可以使用各种技巧进行,包括秘密共享、HE 和 oblivious transfer。现在让我们回顾这些技巧:
-
秘密共享:这是一种密码学技术,将秘密分成多个份额,每个份额分配给不同的方。只有当足够数量的份额结合在一起时,才能恢复秘密。在 SMC 中,秘密共享可以用来将输入数据分成多个份额,然后用于在每个方的数据上本地执行计算。
-
HE:这是一种允许在密文上执行计算而不需要解密的加密类型。在 SMC 中,HE 可以用来计算计算的中间值,而不泄露各方的数据。HE 计算成本高昂,因此不适合所有 SMC 应用。
-
** oblivious transfer**:这是一种加密协议,其中发送者有多条消息,接收者选择其中一条消息,而不泄露其他消息。
实施 SMC – 高级步骤
以下是实现 SMC 所需步骤的高级概述:
-
定义计算:实施 SMC 的第一步是定义需要在私有数据上执行的计算。这个计算应该被分成更小的子计算,每个子计算都可以在每个参与方的私有数据上本地执行。
-
安全通信:参与 SMC 计算的各方需要通过安全通信协议(如 SSL 或 TLS)相互安全通信,以交换消息而不泄露他们的私有数据。
-
秘密共享:输入数据需要分成份额,这些份额被分配给各方。每个参与方持有输入数据的一个份额,计算是在每个参与方的份额上本地执行的。秘密共享可以使用如 Shamir 秘密共享方案之类的密码学技术实现。
-
计算:一旦输入数据在各方之间共享,就可以在每个参与方数据的份额上本地执行计算。计算的中间值需要使用 HE 进行加密,以防止任何一方了解其他方的数据。
-
揭示输出:计算完成后,各方只向彼此揭示计算的最终输出。输出可以通过组合各方持有的输出份额来重建。
SMC 需要密码学、编程和网络安全的专长。这是一个复杂的过程,需要仔细设计和实施,以确保参与方的安全和隐私。
可以用于实现 SMC 的 Python 框架
以下是可以用于实现 SMC 的几个 Python 框架:
-
PySyft 是一个用于 SMC 和联邦学习的开源框架。它提供了用于安全多方计算、差分隐私和同态加密的工具。它建立在 PyTorch 之上,提供了一个简单且易于使用的接口来实施 SMC。
-
Obliv-C 是一个用于在 C 和 Python 中实现 SMC 的语言和框架。它提供了一个高级编程接口来实施 SMC,以及用于构建自定义协议的低级原语。
-
Charm 是一个提供 SMC、HE 和其他密码学原语支持的 Python 库。它提供了一个高级编程接口来实施 SMC,以及用于构建自定义协议的低级原语。
-
MPyC 是一个用于 SMC 的 Python 库,它提供了一个高级编程接口来实施安全计算。它建立在 asyncio 库之上,该库提供了对异步编程的支持。
-
SecureML 是一个用于实现 SMC 和其他隐私保护机器学习技术的 Python 库。它提供了一个高级编程接口来实现 SMC,以及支持差分隐私和联邦学习等其他隐私保护技术。
实施私有集合交互(PSI)SMC – 案例研究
私有集合交集(PSI)是一种密码学技术,它允许两个或多个参与方在不泄露其集合中任何其他信息的情况下安全地计算其私有集合的交集。PSI 可用于各种金融科技应用,在这些应用中,需要在各方之间共享敏感的财务数据,同时保护隐私。
现在我们来分析一个关于在金融科技领域实施 PSI SMC 用于欺诈检测的案例研究。
欺诈检测:在金融科技行业,欺诈检测是一项关键任务,需要银行、金融机构和支付处理器之间共享信息以识别欺诈交易。然而,在这些实体之间共享客户数据可能会侵犯其客户的隐私。为了克服这个问题,PSI 可以用来实现不同实体之间安全的数据共享,而不泄露任何敏感信息。
例如,假设一家银行想要与另一家银行共享其可疑交易列表,而不透露交易或涉及的客户的详细信息。PSI 可以用于计算两家银行交易列表的交集。银行的交易列表将形成一个子集,另一家银行的交易列表将形成另一个子集。通过使用 PSI,两家银行可以安全地计算其交易列表的交集,而不透露任何关于其交易或客户的敏感信息。
要在此用例中实施 PSI SMC,可以使用 SMC 技术。SMC 确保参与方可以共同计算其数据集的交集,而不泄露关于其数据集的任何其他信息。计算可以使用诸如 隐写传输(OT)或 乱码电路(GC)等技术进行,以确保计算的隐私和安全。

图 8.7 – 使用共享密钥的保密多方计算示例
源代码:PSI-SMC_Example.ipynb
让我们实现一个简单的 SMC 示例,以了解步骤:
import random
# Define two parties
Bank1_data = [0.1, 0.2, 0.3]
Bank2_data = [0.5, 0.6, 0.7]
# Define the computation
def compute(x, y):
# Multiply the input data element-wise
z = [x[i] * y[i] for i in range(len(x))]
# Sum the result
result = sum(z)
return result
# Randomly generate private keys for the parties
Bank1_key = random.randint(0, 1000)
Bank2_key = random.randint(0, 1000)
# Bank1 encrypts their data using Bank1 private key
Bank1_encrypted_data = [x + Bank1_key for x in Bank1_data]
# Bank2 encrypts their data using Bank2 private key
Bank2_encrypted_data = [x + Bank2_key for x in Bank2_data]
# The parties send their encrypted data to each other
Bank1_received_data = Bank2_encrypted_data
Bank2_received_data = Bank1_encrypted_data
# The parties compute the multiplication of their data
Bank1_result = compute(Bank1_data, Bank2_received_data)
print(Bank1_result)
Bank2_result = compute(Bank2_data, Bank1_received_data)
print(Bank2_result)
# The parties add their private keys to the result
final_result = Bank1_result + Bank1_key + Bank2_result + Bank2_key
print("Result:", final_result)
output this program as follows :
31.34
1669.6999999999998
Result: 2680.04
零知识证明
零知识证明(ZKPs)是一种加密协议,允许一方(证明者)向另一方(验证者)证明他们知道特定信息,而不透露关于该知识的任何其他信息。零知识的概念最早由 Goldwasser、Micali 和 Rackoff 于 1985 年提出。从那时起,零知识协议在密码学中得到了广泛的应用,尤其是在保护隐私的协议中。
基本概念
零知识的概念基于交互式证明系统的理念。在交互式证明系统中,证明者通过向验证者发送一系列消息来试图说服验证者一个陈述是真实的。验证者检查每条消息,并接受或拒绝该陈述。在零知识证明中,证明者可以在不透露任何其他信息(除了他们知道该陈述是真实的事实之外)的情况下,说服验证者该陈述的真实性。ZKPs 背后的核心思想是展示证明者知道一些秘密信息,而不透露关于该信息的任何细节。
例如,想象一下,Alice 想要向 Bob 证明她知道一个秘密数字 x 的值,而不透露 x 本身的值。使用 ZKP,Alice 可以通过与 Bob 的互动来证明她知道 x 的值,使他确信她知道 x 的值,但不会了解到其他任何信息。
ZKPs 的类型
ZPKs 主要有三种类型:
-
零知识证明知识(ZKPK):在 ZKPK 中,证明者向验证者证明他们知道某个秘密,而不透露关于该秘密的任何信息。例如,证明你知道某个账户的密码,而不透露密码本身。
-
零知识证明拥有(ZKPP):在零知识证明中,证明者向验证者证明他们拥有某个特定物品,而不透露任何关于该物品的信息。例如,证明你有有效的驾照,而不透露驾照上未打印的任何个人信息。
-
零知识证明身份(ZKPI):在 ZKPI 中,证明者向验证者证明他们是之前已识别的同一人或实体,而不透露关于他们自己的任何其他信息。例如,证明你是之前注册过在线服务的同一人,而不透露任何其他个人信息。
ZKPs 的应用
ZKPs 在密码学中有许多应用,包括以下内容:
-
保护隐私的认证:ZKPs 可以用来认证用户,而不透露他们的身份或任何其他个人信息。
-
安全消息传递:零知识证明可以用来确保两个当事人之间交换的消息的机密性和完整性,而不透露消息的内容。
-
安全计算:ZKPs 可以用来证明计算的正确性,而不泄露关于计算或输入的任何细节。
-
加密货币:ZKPs 被用于某些加密货币(如 Zcash)中,以确保交易的隐私和匿名性。
ZKPs 是密码学中的一个强大工具,它允许安全且私密的通信和计算。它们在金融、医疗保健和在线身份验证等众多领域都有广泛应用。随着技术的不断进步,ZKPs 的使用可能会变得更加普遍,有助于保护个人和组织双方的隐私和安全。
以下是一个示例 Python 程序,它实现了一个 ZKPK,用于简单场景,其中证明者想要向验证者证明他们知道一个秘密数字的值:
源代码:ZNP_Example.ipynb
import random
# Set up the scenario
secret_number = 42 # The secret number the Prover wants to prove knowledge of
upper_bound = 100 # The upper bound of the possible values for the secret number
# Generate random values for the parameters used in the ZKPK
a = random.randint(1, upper_bound) # Random value for the first parameter
b = random.randint(1, upper_bound) # Random value for the second parameter
r = random.randint(1, upper_bound) # Random value for the blinding factor
# Calculate the commitments
commitment_x = (a * secret_number + b) % upper_bound
commitment_r = (a * r + b) % upper_bound
# Send the commitments to the Verifier
print("Prover sends commitments: ", commitment_x, commitment_r)
# Verifier sends a random challenge value to the Prover
challenge = random.randint(0, 1)
# Prover responds with the value of the secret number or the blinding factor, depending on the challeng
if challenge == 0:
response = secret_number
else:
response = r
# Verifier checks the response against the commitments
if challenge == 0:
if (a * response + b) % upper_bound == commitment_x:
print("Prover has proven knowledge of the secret number!")
else:
print("Prover has failed to prove knowledge of the secret number.")
else:
if (a * response + b) % upper_bound == commitment_r:
print("Prover has proven knowledge of the blinding factor!")
else:
print("Prover has failed to prove knowledge of the blinding factor.")
Prover sends commitments: 39 94
Prover has proven knowledge of the blinding factor!
在前面的示例中,证明者基于秘密数字和一个随机盲化因子生成两个承诺,并将它们发送给验证者。验证者随后向证明者发送一个随机挑战值,证明者则根据挑战值回应秘密数字或盲化因子。验证者将回应与承诺进行核对,以确定证明者是否成功证明了其对秘密数字的了解。
以下是一些流行的用于 ZKPs 的 Python 框架:
-
PyZPK:一个用于构建和验证零知识简洁非交互式知识论证(zk-SNARKs)方案的 Python 库。它提供了一个简单直观的接口来构建 ZKPs,并设计得与 NumPy 和 SciPy 等其他 Python 库良好协作。
-
Bulletproofs-Builder:一个用于构建和验证 bulletproofs 的 Python 库。它提供了一个高级接口来创建范围证明和其他类型的 ZKPs。它设计得易于使用,并且可以轻松集成到其他 Python 库中。
-
starkware-libs:一组用于构建和验证可扩展透明知识论证(STARKs)的 Python 库。它包括构建 STARK 友好哈希函数、构建约束系统以及执行快速傅里叶变换(FFT)操作的库。
总结
总结来说,在本章中,我们详细介绍了加密、匿名化和去标识化技术,以及一些 Python 实现示例和它们局限性的讨论。我们学习了 HE 和安全的多方计算的基础和类型,并了解了它们如何帮助在处理 ML 模型时实现隐私(包括加密训练数据、测试数据、模型、模型参数和推理结果等应用)。
在下一章中,我们将学习更多关于机密计算的知识,了解为什么它必不可少,以及它是如何帮助我们抵御内存中数据所面临的隐私威胁的。我们还将学习如何通过可信执行环境来确保机器学习模型的安全。
第九章:机密计算 – 什么是、为什么以及当前状态
对于处理敏感数据的企业来说,数据保护是一个重要的考虑因素,这些数据可以是个人数据或非个人数据。数据在组织内部可以存在于三种主要状态:静态数据、运动中的数据和内存中的数据。每种状态都有独特的安全和隐私问题,需要不同的安全方法和数据保护措施。在本章中,你将了解机密计算,包括它是什么、为什么需要它、它如何帮助保护内存中的数据攻击,以及当前技术的状态。
我们将涵盖以下主要主题:
-
对内存中数据的隐私/安全攻击:
-
机密计算的介绍
-
可信执行环境(TEE) – 源代码的证明及其如何帮助保护免受内部威胁攻击
-
TEE 中机器学习的行业标准
-
机密计算联盟
-
Intel、AWS、Azure、GCP 和 Anjuna 对安全区域支持的比较
对内存中数据的隐私/安全攻击
数据泄露指的是从计算机或网络到攻击者控制的远程位置的敏感信息的未授权传输或盗窃。这可以通过各种手段发生,例如黑客攻击、恶意软件、钓鱼或社会工程学。攻击者通常使用数据泄露来窃取有价值的知识产权、财务信息、个人身份信息(PII)或商业机密以谋取私利。一旦数据被盗,它可以在暗网出售、用于身份盗窃或被勒索。为了防止数据泄露,组织可以实施诸如防火墙、入侵检测和预防系统、加密、访问控制和员工培训计划等安全措施。
静态数据
在典型的产品/应用程序中,数据将持久化在物理存储系统上,例如文件系统、数据库系统(SQL/NoSQL)、Hadoop 文件系统、磁带、驱动器或云。这种数据被称为静态数据。如果存储设备落入错误的手中,静态数据容易受到盗窃或未授权访问的威胁。加密是保护静态数据最常见的方法之一,使用强大的加密算法(如上一章所述)并保持加密密钥安全至关重要。保持密钥安全的一种方法是通过使用安全保险库(开源或商业的,基于软件或硬件)。HashiCorp(github.com/hashicorp/vault)是最著名的开源软件保险库之一,用于保护安全密钥。

图 9.1 – 静态数据的安全机制
运动中的数据
在数据在运动的情况下,数据在两个或多个系统(客户端和服务器)或两个或多个设备(相同或不同)之间流动。数据在运动可以是同步的或异步的。异步通信使用 Kafka 或 ActiveMQ 等消息系统,通过互联网或本地/广域网等网络进行。数据在运动也容易在传输过程中被拦截或篡改。为了保护数据在运动,应使用 HTTPS、安全套接字层(SSL)、传输层安全性(TLS)和安全外壳(SSH)等安全通信协议。

图 9.2 – 数据在运动中的保护机制
内存中的数据
内存中的数据是指在程序执行/运行期间临时存储在计算机内存(RAM 或缓存)中的数据。如果系统被黑客或企业内部人员破坏,内存中的数据也容易受到未经授权的访问、篡改或盗窃。在这种情况下,如何保护正在使用或存储在内存中的数据,以及哪种技术支持内存数据保护?

图 9.3 – 内存中数据的保护机制
示例程序展示存储在内存中的数据也容易受到内存攻击
在这个示例演示中,我们将展示一个简单的机器学习(ML)模型,该模型容易受到内部人员或通过恶意软件注入的程序进行的内存攻击。
内存攻击涉及的步骤如下:
-
开发一个简单的 ML 模型,该模型使用敏感信息进行训练。
-
执行模型。
-
生成进程的内存转储。
-
分析内存转储以发现 PII。

图 9.4 – 内部人员进行的内存数据攻击
让我们看看这个演示中涉及的步骤。
步骤 1 – 生成敏感数据
在这个例子中,我们将使用 Faker 框架生成合成数据,具有以下特征 – name、age、e-mail、gender、address和has_cancer(是/否) – 以及 1,000 个样本。每次执行此代码时,都会生成不同的合成数据示例,因此您在环境中执行此代码时可能不会得到相同的数据:
生成合成数据
from faker import Faker
import random
import pandas as pd
fake = Faker()
# Set random seed for reproducibility
random.seed(42)
# Generate 1000 random samples of sensitive data
data = []
for i in range(1000):
name = fake.name()
email = fake.email()
age = random.randint(18, 80)
address = fake.address()
gender = random.choice(['Male', 'Female', 'Non-binary'])
has_cancer = random.choice([1, 0])
data.append([name, email, age, address, gender, has_cancer])
# Convert data to a pandas dataframe
df = pd.DataFrame(data, columns=['Name', 'Email', 'Age', 'Address', 'Gender', 'HasCancer'])
这是 DataFrame:

图 9.5 – 样本敏感数据集
步骤 2 – 开发 ML 模型
使用生成的数据,使用随机森林算法开发一个机器学习模型:
from sklearn.feature_extraction.text import HashingVectorizer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
import time
# Encode string features using HashingVectorizer
vectorizer = HashingVectorizer(n_features=4)
X = pd.DataFrame(
vectorizer.fit_transform(df[['Name', 'Email', 'Address', 'Gender']].apply(lambda x: ' '.join(x), axis=1)).toarray(),
columns=[f'feature_{i}' for i in range(4)]
)
# Concatenate encoded features with numeric features
X = pd.concat([X, df[['Age']]], axis=1)
print (X)
# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(
X, df['HasCancer'], test_size=0.2, random_state=42
)
# Create an instance of the logistic regression model with default hyperparameters
model = LogisticRegression()
# Train the model on the training set
model.fit(X_train, y_train)
# Make predictions on the testing set
y_pred = model.predict(X_test)
# Evaluate the accuracy of the model
accuracy = accuracy_score(y_test, y_pred)
print(f'Accuracy: {accuracy}')
time.sleep(10000)
将整个代码存储在CancerPredictionML.py文件中,以便执行。
步骤 3 – 执行此 ML 模型
要执行模型,只需使用以下命令:
python CancerPredictionML.py
步骤 4 – 内存转储和泄露
gcore是 Unix 系统中的一个命令行实用程序,用于生成运行进程的核心转储。核心转储是一个文件,包含转储时进程内存的快照,可用于调试和法医分析目的。
识别ps命令:
ps aux | grep CancerPredictionML
在这个例子中,CancerPredictionML程序进程的 PID 是736:
user 736 0.5 0.0 604740 112264 pts/2 S+ 09:07 0:01 python CancerPredictionML.py
user 768 0.0 0.0 14476 1108 pts/3 S+ 09:11 0:00 grep CancerPredictionML
使用gcore生成进程的核心转储:
gcore 736
此命令将在当前目录中创建一个名为core.736的文件,其中包含转储时的进程内存:
[Thread debugging using libthread_db enabled]
Using host libthread_db library “/lib/x86_64-linux-gnu/libthread_db.so.1”.
0x00007fa2eab12d1f in select () from /lib/x86_64-linux-gnu/libc.so.6
warning: target file /proc/736/cmdline contained unexpected null characters
Saved corefile core.736
使用适合您调查的工具和技术分析内存转储文件。
第 5 步 - 分析内存转储并找到敏感数据
要使用 Python 分析内存转储,可以使用strings等框架。
例如,您可以使用以下strings命令在内存转储中搜索敏感数据:
strings dump_file | grep -i text_to search
此命令将在内存转储文件中搜索包含单词Shelly的字符串,并列出详细信息:
strings core.736 | grep -i Shelly
Shelly Chen jacobsmith@example.net 7711 Brianna Springs
Shelly Chen jacobsmi
Shelly Chen
Shellyberg, CA 45423
现在,我们已经知道了Shelly的完整地址——她的电子邮件地址和物理地址。这样,内部人员就能在不接触源代码或训练或测试数据的情况下攻击机器学习模型并获取敏感信息。
注意,分析核心转储需要计算机系统和法医分析技术的专业知识。此外,未经适当授权和同意创建运行进程的核心转储是非法的,并可能导致严重的法律后果。
机密计算
机密计算是指在一个安全和可信的环境中处理敏感数据的做法,即使基础设施的所有者,数据的机密性也会得到保护。
机密计算旨在为计算系统的用户提供隐私、安全和完整性的保证,即使基础设施被黑客或恶意软件破坏。
我们将在下一节讨论机密计算的概念以及机密计算的好处。
什么是机密计算?
机密计算提供了一个安全和可信的空间,在称为安全区域(enclaves)的隔离和保护环境中处理数据。安全区域是内存中的安全区域,受到其他进程和操作系统的保护。安全区域对于隐私保护机器学习(PPML)应用非常有用,在这些应用中,敏感数据用于训练机器学习模型。在 PPML 中,确保数据的隐私得到保护,同时仍然允许模型有效训练是至关重要的。安全区域可以通过提供一个安全和可信的环境来帮助实现这一点,在该环境中,敏感数据可以处理而不会暴露给宿主系统或其他应用程序。
可以使用硬件安全功能,如英特尔软件保护扩展(SGX)或 ARM Trust Zone 来创建安全区域。
机密计算的好处
机密计算的主要好处如下:
-
机密性:机密计算通过在安全且可信的环境中处理数据来确保数据的机密性,防止未经授权的数据访问
-
完整性:机密计算通过验证数据在处理过程中未被篡改来确保数据的完整性
-
信任:机密计算提供了一个可信的环境,其中敏感数据可以在无需信任主机系统或其他应用程序的情况下进行处理
-
合规性:机密计算可以帮助组织遵守需要保护敏感数据的法规和行业标准
可信执行环境 - 源代码的认证及其如何帮助保护免受内部威胁攻击
可信执行环境(TEE)是计算机系统中的一个安全区域,它确保敏感数据和代码的机密性、完整性和可用性。TEE 提供了一个安全且隔离的执行环境,该环境与主操作系统隔离,旨在防止各种类型的攻击。
认证是验证软件或硬件组件身份的过程。它用于在计算系统中的不同实体之间建立信任。认证可以用来确保在 TEE 中运行的代码是真实的,并且未被篡改。
认证有多种类型,包括源代码认证、二进制认证和运行时认证。源代码认证涉及验证用于构建软件组件的源代码的完整性。二进制认证涉及验证由编译源代码产生的二进制代码的完整性。运行时认证涉及验证在系统中实际运行的代码的完整性。
认证可以帮助通过确保仅在 TEE 中执行授权代码来保护免受内部威胁攻击。内部威胁可能特别难以防御,因为它们涉及有合法访问敏感数据和系统的可信个人。认证可以通过确保只有授权个人有权访问敏感数据和系统来帮助减轻内部威胁的风险。
源代码认证的一种方法是通过使用加密哈希函数为源代码生成哈希值。然后可以使用数字签名算法对哈希值进行签名,以创建数字签名。数字签名可以用来验证源代码的完整性。
源代码认证的另一种方法是使用在构建过程中为源代码生成加密哈希值的加密构建系统。然后可以使用数字签名算法对哈希值进行签名,以创建数字签名。数字签名可以用来验证源代码的完整性。
除了源代码认证之外,还可以使用其他技术来防止内部威胁攻击。例如,可以使用访问控制策略来限制内部人员对敏感数据和系统的访问。加密可以用来保护静态和传输中的敏感数据。监控和审计可以用来检测可疑活动,并为法医分析提供活动记录。
通过使用这些和其他技术,组织可以帮助减轻内部威胁攻击的风险,并保护其敏感数据和系统。
英特尔 SGX 如何帮助在 PPML 中
英特尔 SGX 可以通过创建安全区域来帮助解决隐私和安全问题,在这些区域中,机器学习算法可以安全地执行,而不会使敏感数据面临暴露给其他软件或操作系统的风险。
英特尔 SGX 的一个关键特性是它能够在 CPU 内部创建隔离的安全区域,这些区域可以以安全加密的方式执行代码和存储数据。这些区域的内容受到其他软件和操作系统的保护,这意味着即使攻击者获得了对宿主系统的访问权限,他们也无法访问区域的内容。
这一特性对于 PPML 应用尤为重要,因为它允许敏感数据,如病历或财务数据,在 enclave 中安全存储和处理,而不会面临暴露给未经授权的方的风险。
除了提供隔离的 enclave 外,英特尔 SGX 还提供了认证功能,允许远程方验证 enclave 的身份,并确保其中的代码和数据没有被篡改。
这一特性对于涉及敏感数据的应用至关重要,因为它使各方能够验证机器学习算法是在可信环境中执行的,并且没有被破坏。英特尔 SGX 还可以帮助解决多方机器学习场景中关于数据隐私和安全的担忧,在这些场景中,多个方向共享模型贡献数据。
在这些场景中,使用安全区域可以使每一方都能控制自己的数据,同时仍然为共享模型做出贡献。这有助于在各方之间建立信任,并促进更有效的机器学习模型的创建。
TEEs 中机器学习的行业标准
为了使用加密数据训练机器学习模型并将它们部署到第三方 TEE 中进行执行,各种标准机构定义了架构。
IEEE 2830-2021 是 IEEE 定义的标准之一,作为基于共享机器学习的可信执行环境的技术框架和要求的标准化文件 (ieeexplore.ieee.org/document/9586768)。
本标准规定了在 TEE 中执行机器学习应用的功能组件、工作流程、安全要求、技术要求和协议。本标准中定义的高级协议步骤如下:
-
数据提供者从计算平台下载并部署工具。
-
数据提供者执行数据准备,包括数据加密和授权。
-
数据提供者将加密数据上传到计算平台。
-
任务发起者在平台上启动计算任务,包括要训练的模型和算法。
-
计算平台创建了一个 TEE。
-
计算平台在 TEE 内部解密加密数据。
-
计算平台使用解密数据在 TEE 内部执行计算,从而产生计算结果。
-
计算结果由计算平台交付给结果接收者。
-
然后,计算平台销毁 TEE 及其中的数据。
机密计算联盟
机密计算联盟(confidentialcomputing.io/)是由一些公司和组织组成的团体,他们共同努力推广机密计算技术的采用。该联盟成立于 2019 年,由 Linux 基金会主办。
机密计算联盟旨在通过推广行业标准与实践、教育开发者和用户关于机密计算的好处和用例,以及开发开源工具和框架以支持机密计算,来加速机密计算技术的采用。
联盟包括广泛的公司和组织,包括云服务提供商、硬件制造商、软件供应商和学术机构。联盟成员共同努力开发开源项目和工具,以实现机密计算,例如英特尔 SGX、AMD SEV 和谷歌 Asylo。
通过推广机密计算的采用,机密计算联盟旨在使新一代应用能够在安全和可信的环境中处理敏感数据,为 PPML、安全数据库和其他需要强大数据保护的应用开辟新的可能性。
高级比较:英特尔 SGX、AWS Nitro Enclaves、谷歌 Asylo、Azure enclaves 和 Anjuna
英特尔 SGX、AWS Nitro Enclaves、谷歌 Asylo、Azure enclaves 和 Anjuna 都是能够在更大计算系统内创建安全区域或安全计算环境的技术。
英特尔 SGX是一种基于硬件的技术,为应用提供安全的执行环境,以保护敏感数据和代码免受未经授权的访问。SGX 通过结合硬件和软件功能来创建隔离的区域,从而保护敏感数据和代码免受其他软件甚至操作系统本身的侵害。
AWS Nitro Enclaves与 Intel SGX 类似的技术,但作为亚马逊网络服务(AWS)中的一个服务提供,并在亚马逊的 Nitro 虚拟机上运行。Nitro Enclaves 允许在 AWS 实例中创建隔离的安全区域以保护敏感数据和代码。Nitro Enclaves 还与其他 AWS 服务集成,例如密钥管理服务(KMS)和 AWS 身份和访问管理(IAM)。
Google Asylo是一个开源框架,它允许开发者在不同平台上构建和运行在安全区域中的应用程序,包括 Intel SGX 和 AMD 安全加密虚拟化(SEV)。Asylo 提供了一个软件开发工具包(SDK),使得构建和部署利用安全区域的应用程序变得容易。
Azure 安全区域是微软 Azure 中的一个功能,它允许创建安全区域以保护敏感数据和代码。Azure 安全区域使用 Intel SGX 技术,在 Azure 虚拟机内创建隔离的安全区域。
Anjuna (www.anjuna.io/)是一个平台,它使组织能够使用可以在本地或云中运行的安全区域来保护应用程序和数据。Anjuna 支持 Intel SGX 和 AMD SEV 技术,并提供了一系列用于构建、部署和管理安全区域的工具。使用 Anjuna 平台非常简单,无需对现有产品进行任何更改;您只需运行/开始使用它们的库即可。
这里是功能级别的比较:
| 功能/TEE | Intel SGX | AWS Nitro Enclaves | Google Asylo | Azure 安全区域 | Anjuna |
|---|---|---|---|---|---|
| 平台支持 | 基于 Intel 的平台 | AWS EC2 实例 | 多平台(包括 Intel SGX、SEV 和 ARM 架构上的 TEE) | Azure 机密计算虚拟机 | 多平台(包括 Intel SGX 和 AMD SEV) |
| 隔离机制 | 基于硬件的安全区域 | 基于硬件的安全区域 | 软件基础(带有硬件选项) | 基于硬件的安全区域 | 基于硬件的安全区域 |
| 认证 | 本地和远程 | AWS 认证服务 | 本地和远程 | 微软 Azure 认证 | 本地和远程 |
| 支持的语言 | C、C++、Rust、Go、Python 和 Java | C、C++和 Python | C、C++、Go、Java、Python 和 Rust | C、C++、.NET、Python、Go、Java 和 Rust | C、C++、Go、Python、Java 和 Rust |
| 开源 | 否(SDK 是开源的) | 否 | 是 | 否 | 否 |
| 易用性 | 中等(需要理解安全区域) | 高(完全集成到 AWS 服务中) | 高(灵活且可跨各种安全区域技术移植) | 高(集成到 Azure 服务中) | 高(提供了一种简单的方式来保护应用程序而无需对其进行修改) |
表 9.1 – TEE 的比较
总结来说,所有这些技术都使得创建安全区域以保护敏感数据和代码成为可能。然而,它们在支持的平台上、提供的工具以及与其他服务的集成程度方面有所不同。最终,技术的选择将取决于组织的具体需求和需求。
TEE 的优缺点
假设我们正在为一个医疗保健组织开发一个机器学习模型。该模型旨在根据各种患者数据预测疾病结果。这些数据非常敏感,包括个人标识符和健康记录。为了保护这些数据,我们决定使用 TEE。
优点
使用 TEE 的优点包括:
-
安全性:TEE 在处理器内部提供了一个安全区域,其中执行机器学习模型。这个区域与系统其他部分隔离,降低了数据泄露或暴露的风险。
-
数据隐私:患者数据被加载到安全的区域,在处理过程中永远不会离开。这确保了数据不能被系统上的任何其他进程访问或查看,从而保护患者隐私。
-
完整性:TEE 确保区域内的代码和数据不会被篡改。这意味着机器学习模型做出的预测可以信任是准确和无偏见的,因为它们没有被干扰。
缺点
使用 TEE 的缺点包括:
-
复杂性:实现 TEE 可能很复杂。它需要仔细管理密钥和证书,以确保只有授权的代码和数据可以进入区域。这可能会增加系统的复杂性,并需要深入了解安全原则。
-
性能开销:TEE 引入的额外安全措施可能会引入性能开销。这可能会减慢机器学习模型的执行速度,如果需要实时预测,这可能会成为一个问题。
-
调试有限:在 TEE 内部调试机器学习模型可能更困难。区域的安全性质意味着传统的调试工具可能无法访问它,这使得识别和修复问题更加困难。
-
潜在漏洞:虽然 TEE 被设计成安全的,但它们对侧信道攻击等攻击免疫。如果在 TEE 本身中发现漏洞,可能会被利用来获取对安全区域的访问权限。这可能会暴露敏感的患者数据并损害机器学习模型的完整性。
对 TEE 的侧信道攻击
TEE 并非对所有类型的威胁免疫。一种特别阴险的攻击类型可以破坏 TEE,那就是侧信道攻击。
侧信道攻击利用程序执行过程中泄露的信息,如时间信息、功耗,甚至电磁辐射。这些攻击并不直接针对 TEE 保护的算法或数据,而是利用间接信息,这些信息可以用来推断敏感数据。
侧信道攻击对 TEE 特别有效有几个原因。首先,TEE 通常处理高度敏感的数据,使其成为攻击者的诱人目标。其次,由于 TEE 被设计为与系统其他部分隔离,它们可能无法访问其他部分系统中可用的相同类型的保护和对策。最后,TEE 的性质可能使得检测和应对侧信道攻击变得困难。
几种类型的侧信道攻击对 TEE(可信执行环境)特别有效。例如,时间攻击可以利用 TEE 执行某些操作所需时间的差异。通过仔细测量这些时间,攻击者可以推断出 TEE 正在处理的数据信息。功率分析攻击可以类似地利用功耗的变化,而电磁攻击可以利用非预期的电磁辐射。
为了防御侧信道攻击,TEE 可以采用各种对策。例如,它们可以使用恒定时间编程技术来消除时间变化。它们还可以使用功率分析对策,如随机化功耗或使用功率平滑技术。此外,它们可以使用屏蔽或其他技术来减少电磁辐射。
尽管有这些对策,侧信道攻击仍然是 TEE 的重大威胁。随着 TEE 在保护现代计算系统中继续发挥关键作用,行业必须继续研究和开发新的防御措施来对抗这些以及其他类型的攻击。
总之,虽然 TEE 在现代计算系统中提供了关键的安全层,但它们并非对侧信道攻击免疫。这些攻击利用程序执行过程中泄露的间接信息,并且对 TEE 特别有效。因此,开发并实施强大的对策来保护 TEE 免受侧信道攻击至关重要。
摘要
在本章中,我们介绍了针对内存中数据的隐私攻击以及保护机器学习应用免受内存攻击的框架和标准。在下一章中,我们将讨论涉及生成式 AI 和大型语言模型的隐私攻击,以及一些用于保护个人隐私的技术。
第十章:在大型语言模型中保护隐私
大型语言模型(LLMs)已成为人工智能(AI)领域的一项变革性技术,它使高级自然语言处理(NLP)任务和生成能力成为可能。这些模型,如 OpenAI 的 GPT-3.5 和 Meta 的 Llama 2,在生成类似人类的文本和展示对语言模式深入理解方面表现出卓越的技能。在本章中,你将从高层次上了解封闭源和开源 LLMs,以及这些 LLMs 的隐私问题,以及 LLMs 隐私保护技术的最先进(SOTA)研究。
我们将涵盖以下主要主题:
-
LLMs 中使用的关键概念/术语
-
提示工程:使用 ChatGPT(封闭源 LLM)以及开源 LLM 进行句子翻译
-
开源 LLM 和封闭源 LLM 的比较
-
-
AI 标准和攻击术语
-
国家标准与技术研究院(NIST)的可信和负责任的 AI
-
开放式全球应用安全项目(OWASP)的 Top 10 LLMs
-
-
对 LLMs 的隐私攻击
-
LLMs 中隐私泄露的真实世界事件
-
对生成模型进行的成员推理攻击
-
从 LLMs 中提取训练数据
-
提示注入攻击
-
-
LLMs 的隐私保护技术
-
对机器学习(ML)和生成式 AI(GenAI)的文本攻击
-
使用私有 transformer 进行差分隐私训练 LLMs
-
隐私保护 LLMs 的 SOTA 研究
-
LLMs 中使用的关键概念/术语
LLMs 是自然语言处理(NLP)的一个复杂领域,与之相关的术语有几个。
在 LLMs 的背景下使用的一些关键术语和概念如下:
-
Transformer 架构:大多数 LLMs 的基础架构,以其自注意力机制而闻名,这使得模型能够在句子中权衡不同单词的重要性。
-
预训练:LLM 在从互联网上的大量文本数据语料库中训练的初始阶段,以学习语言模式和上下文。这个预训练模型通常被称为“基础模型”。
-
微调:随后的阶段,预训练模型被调整以执行特定的 NLP 任务,如文本分类、翻译、摘要或问答。微调有助于模型在这些任务上专业化。
-
参数:这些是 LLM 的可训练组件,由数值表示。参数的数量是确定 LLM 大小和能力的关键因素。
-
注意力机制:变压器架构的核心组件,它使模型在处理输入序列时能够关注不同的部分,从而提高上下文理解。
-
自注意力: 一种特定的注意力机制,模型根据句子中不同单词之间的相关性为它们分配权重,使其能够捕捉单词之间的依赖关系。大多数 transformer 都是基于谷歌的研究论文《Attention Is All You Need》构建的(
arxiv.org/abs/1706.03762)。 -
嵌入: 词嵌入或 token 嵌入是单词或 token 在连续空间中的向量表示。这些嵌入捕捉了单词之间的语义关系。
-
上下文嵌入: 与静态词嵌入不同,这些嵌入根据句子的上下文而变化,使 LLM 能够理解不同上下文中单词的含义。位置嵌入和旋转位置嵌入属于上下文嵌入的范畴。
-
分词: 将文本分解成单个 token(单词或子词)以输入到模型中的过程。LLM 使用分词器来完成这项任务。
-
解码: 将模型生成的表示(通常是 logits 或 token ID)转换为人类可读文本的过程。解码是生成最终输出的必要步骤。
-
迁移学习(TL): 将从一个任务或领域获得的知识转移到另一个任务或领域上的概念。LLM 通常从 TL 中受益,因为它们在微调特定任务之前已经在广泛的文本上进行了预训练。
-
提示工程: 设计输入提示或指令的过程,以引导 LLM 生成所需的输出。制作有效的提示对于控制模型的行为至关重要:

图 10.1 – 简单提示流程
-
零样本学习: 一种迁移学习类型,其中模型被要求执行它没有明确微调的任务。LLM 在一定程度上具有零样本学习能力。
-
少样本学习: 与零样本学习类似,但在微调新任务时,模型提供了有限数量的示例。
-
思维链(CoT): CoT 提示是一种技术,指导 LLM 在处理难题时遵循推理过程。这是通过向模型展示一些逐步推理清晰展示的例子来实现的。
-
思维树(ToT): ToT 提示将问题分解为一系列较小的步骤——或称为“思维”——这些步骤分别解决。这种方法并不限制模型一次性输出所有这些步骤。相反,每个思维都是独立生成或解决的,然后传递给下一个步骤以解决问题。
-
思维图(GoT): 将 LLM 生成的数据概念化为一个图,其中每个节点代表一个信息单元,通常称为“LLM 思维”。这些节点之间的连接代表了不同思维单元之间的依赖关系或关联。
使用 ChatGPT(闭源 LLM)的提示示例
让我们用一个例子来试试 ChatGPT (chat.openai.com/),并提问将一句话从英语翻译成德语。
在这种情况下,问题被称为提示,ChatGPT(LLM)的响应被称为完成/结果:

图 10.2 – 简单的提示请求和完成
使用开源 LLM 的提示示例
让我们尝试使用 Python 程序化地使用开源 LLM 的例子。
Transformers library, specifically the T5Tokenizer and T5ForConditionalGeneration classes.
确保你已经安装了 Hugging Face Transformers 库,并且你有权限使用"google/flan-t5-large"模型,以便此代码能够成功运行。按照以下步骤实现此示例:
-
使用以下命令安装库:
pip install transformers -
此外,如果你还没有下载模型,你需要使用transformers.AutoModel.from_pretrained("google/flan-t5-large")来下载模型。
-
从 Transformers 库中导入必要的类,即T5Tokenizer和T5ForConditionalGeneration。
-
使用预训练的"google/flan-t5-large"模型初始化 T5 分词器和模型。此模型是为翻译任务设计的。
-
定义你想要从英语翻译成德语的输入文本,即"translate English to German: How old are you?"。
-
使用分词器对输入文本进行分词,并将其转换为 PyTorch 张量。这一步为将文本输入到模型中做准备。
-
通过将分词后的输入传递给模型的generate方法,使用 T5 模型生成翻译。翻译输出存储在outputs变量中。
-
使用分词器的decode方法解码生成的输出,并打印翻译后的文本,这将是对输入文本的德语翻译。
源代码:Ex_LLM_Opensource.ipynb以下是一个示例的详细源代码:
!pip install transformers
from transformers import T5Tokenizer,
T5ForConditionalGeneration
tokenizer = T5Tokenizer.from_pretrained("google/flan-t5-large")
model =
T5ForConditionalGeneration.from_pretrained("google/flan-t5-large")
input_text = "translate English to German: How old are you?"
input_ids = tokenizer(input_text, return_tensors="pt").input_ids
outputs = model.generate(input_ids)
print(tokenizer.decode(outputs[0]))

图 10.3 – T5 模型权重、分词器和配置下载
input_text = "Who is the prime minister of India?"
input_ids = tokenizer(input_text, return_tensors="pt").input_ids
outputs = model.generate(input_ids)
print(tokenizer.decode(outputs[0]))
这将产生以下输出
<pad> narendra modi</s>
开源 LLM 和闭源 LLM 的比较
开源和闭源 LLM 代表了 LLM 开发和可用性的两种不同方法。
开源 LLM
让我们看看一些开源 LLM 的属性:
-
可访问性:开源 LLM 是公开可访问的,它们的架构和参数可以被社区检查、修改和共享。这种透明度促进了合作和创新。
-
社区贡献:它们经常从来自不同研究者和开发者的贡献和改进中受益,从而实现快速改进并解决潜在的偏差。
-
定制:用户有自由对开源 LLM 进行微调和适应特定任务、语言或领域,使它们高度灵活和多功能。
-
成本效益:通常,开源大型语言模型是免费使用的,这对于研究人员、初创公司和开发者来说特别有利。
-
硬件基础设施:开源模型需要托管在 GPU 上进行推理,并且相关的成本需要自行承担。
-
安全:开源大型语言模型可能存在安全漏洞或底层软件版本问题,因此需要单独管理这些安全漏洞(通用漏洞和暴露,或 CVE)。
示例:Google 的 FLAN-T5、Meta 的 Llama 模型、GPT-3 以及 Hugging Face 的转换器都是开源的,并且广泛可访问。
闭源大型语言模型
现在,让我们将注意力转向闭源大型语言模型的属性:
-
专有:闭源大型语言模型由组织或公司开发和拥有,其架构和参数不公开披露。
-
控制:闭源大型语言模型的开发者保留对其模型、算法和知识产权(IP)的控制权,使他们能够保护其创新。
-
有限的定制:闭源大型语言模型的用户可能对微调或调整模型以满足特定需求的选择有限,因为源代码不可公开获取。
-
成本:闭源大型语言模型通常附带许可费或使用费,这可能对某些用户或组织是一个重要因素。
-
硬件基础设施:闭源模型由供应商在 GPU 上部署,并提供通过 REST 或 gRPC 访问的 API,因此基础设施成本由供应商承担(在 GPT-4 或 GPT-3.x 的情况下,OpenAI 和微软将拥有托管版本)。
-
安全:闭源大型语言模型可能在底层软件版本中存在安全漏洞,因此大型语言模型提供商将解决这些安全漏洞(CVE),而对于使用这些模型的用户来说,这是一个黑盒。
示例:商业语言模型如 GPT-3.5 或 GPT-4 模型以及科技公司使用的专有模型可能是闭源的。
开源和闭源大型语言模型之间的选择取决于预算、数据隐私担忧、定制需求以及所需的控制水平。
开源大型语言模型提供可访问性、协作和成本节约,但可能需要更多的技术专业知识进行定制。闭源大型语言模型提供知识产权保护,可能附带专业支持和功能,但代价是有限的透明度和可能的许可费。
组织和开发者在选择这两种方法之间应仔细考虑其具体需求。
人工智能标准和攻击术语
在下一节中,我们将探讨一些人工智能标准和攻击术语。
NIST
NIST 可信和负责任的人工智能发布了一篇关于攻击和缓解中使用的分类和术语的论文。它涵盖了预测性人工智能(传统机器学习)和生成人工智能。

图 10.4 – 对生成式 AI 系统攻击的分类
图片来源:“对抗性机器学习:攻击和缓解的分类与术语”论文,来自NIST.* doi.org/10.6028/NIST.AI.100-2e2023
OWASP Top 10 for LLM applications
OWASP Top 10 for Large Language Model Applications 项目旨在教育开发者、设计师、架构师、经理和组织了解在部署和管理 LLMs 时可能存在的安全风险。LLM 应用的 OWASP Top 10 如下。
-
LLM01: 提示注入
-
LLM02:不安全的 输出处理
-
LLM03:训练 数据中毒
-
LLM04:模型拒绝 服务
-
LLM05:供应链漏洞
-
LLM06:敏感 信息泄露
-
LLM07:不安全的 插件设计
-
LLM08:过度的 代理权
-
LLM09:过度依赖
-
LLM10:模型盗窃
详细的安全漏洞、如何检测每个漏洞以及可能的解决方案已在owasp.org/www-project-top-10-for-large-language-model-applications/assets/PDF/OWASP-Top-10-for-LLMs-2023-v1_1.pdf中记录。
在下一节中,我们将更详细地介绍 LLMs/GenAI 的隐私攻击。
LLMs 的隐私攻击
近年来,LLMs 已经彻底改变了自然语言理解(NLU)和自然语言生成(NLG),为从聊天机器人、虚拟助手到内容推荐系统和语言翻译服务等各种应用提供了动力。然而,这些模型快速发展的同时也引发了关于隐私和安全的重大担忧。LLM 应用有可能通过其输出暴露敏感数据、专有算法或其他机密信息。这可能导致对敏感数据、知识产权、隐私侵犯和其他安全违规行为的未授权访问。随着 LLMs 在我们数字景观中的日益普及,迫切需要有效的策略来保护敏感信息和维护用户隐私。
如前几章所述,机器学习模型容易受到隐私攻击,生成式 AI 模型(LLMs)也不例外。
以下两篇最近的文章提供了关于企业中 GenAI 隐私问题的详细信息:
Cyberhaven 的调查:根据 Cyberhaven 的文章(www.cyberhaven.com/blog/4-2-of-workers-have-pasted-company-data-into-ChatGPT/),当员工将公司数据粘贴到聊天机器人(如 OpenAI 的 GPT-3)时,数据泄露的潜在风险。该公司对美国和英国的 2,000 名员工进行了调查,发现其中 4.2%的人将公司数据粘贴到了聊天机器人中。尽管像 GPT-3 这样的聊天机器人在对话结束后会忘记信息,但风险在于这些聊天机器人在对话过程中可能会记住并复制敏感信息。文章还提到,如果黑客在对话期间控制了聊天机器人,他们可以访问敏感数据。文章强调,公司需要制定明确的数据共享政策,并教育员工关于潜在风险。它还建议公司实施数据丢失预防(DLP)解决方案,以自动阻止敏感数据与聊天机器人共享。文章最后指出,尽管 AI 聊天机器人有许多好处,但公司需要意识到潜在的安全和隐私风险,并采取适当的措施来保护敏感数据。
三星的知识产权泄露:根据techcrunch.com/2023/05/02/samsung-bans-use-of-generative-ai-tools-like-ChatGPT-after-april-internal-data-leak/上的文章,三星员工在用 ChatGPT 处理工作相关任务时无意中泄露了机密信息,突显了潜在的隐私和安全风险。三星半导体部门允许工程师使用 ChatGPT 进行源代码检查和其他任务。然而,韩国的《经济学人》报道了三起敏感数据意外暴露给 ChatGPT 的事件。
在一个事件中,一名员工将机密源代码复制到聊天中,以识别错误。另一名员工分享了代码并请求优化。第三名员工分享了会议录音,以便转录成演示文稿笔记。这些数据现在可以通过 ChatGPT 访问。
三星公司迅速作出反应,通过限制每个用户上传容量为 1,024 字节并启动对数据泄露负责人员的调查来应对 ChatGPT 的问题。此外,三星正在考虑开发内部 AI 聊天机器人,以加强未来的数据安全和隐私保护。然而,由于 ChatGPT 的数据政策,除非用户明确退出,否则将用于模型训练,因此三星不太可能恢复泄露的数据。ChatGPT 使用指南明确警告在对话中不要分享敏感信息。
这些事件说明了隐私专家长期以来一直警惕的现实世界场景,例如为了文本分析或摘要而共享机密法律或医疗文件,这些文件可能被用来改进模型。隐私专家警告,这可能会违反通用数据保护条例(GDPR)的合规性,从而导致监管后果。
对生成模型的成员身份推断攻击
我们在第四章中学习了关于机器学习模型上的成员身份推断攻击。生成 AI 模型也容易受到类似成员身份推断攻击的影响:
-
生成模型旨在估计数据集的基本分布,从而可以根据该分布创建逼真的样本。
-
当面对一个数据点时,攻击者会判断它是否被用于训练模型。
-
这些攻击基于对目标模型的白盒和黑盒访问,针对多个 SOTA 生成模型
让我们通过一个例子来了解。
此示例提供了一个使用 PyTorch 对生成模型进行基本成员身份推断攻击的例子。攻击旨在确定特定数据点是否是生成模型训练数据集的一部分。它包括以下组件:
使用变分****自动编码器(VAE)的样本生成 AI 模型:
-
VAE:使用一个简单的 VAE 作为生成模型。VAE 能够编码和解码二进制数据点。
-
攻击模型:攻击模型被实现为两层
-
前馈神经网络(FNN):此模型经过训练,用于预测给定数据点是否是训练数据集的成员。
-
合成数据:为了演示目的,生成了合成二进制数据。在实际应用中,您应将其替换为您的实际数据集。
-
训练过程:VAE 和攻击模型独立训练。VAE 学习编码和解码数据,而攻击模型学习预测成员身份。
-
成员身份推断攻击:成员身份推断攻击函数接受一个目标数据点,使用 VAE 对其进行编码,然后使用攻击模型预测目标数据点是否是训练数据集的成员或非成员。
源代码组件:
-
SampleGenModel 类:定义 VAE 的架构
-
攻击类:定义攻击模型的架构
-
数据生成:生成用于训练和测试的合成二进制数据
-
训练:基于 VAE 的SampleGenModel类和攻击模型的训练循环
-
成员身份推断攻击:进行成员身份推断攻击的函数
-
主要执行:初始化 VAE 和攻击模型,并对目标数据点进行攻击
源代码:MemberShipInference_LLM.ipynb
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
# Define a simple generative model
class SampleGenModel(nn.Module):
def __init__(self, input_dim, hidden_dim, latent_dim):
super(SampleGenModel, self).__init__()
self.encoder = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, latent_dim * 2)
# Two times latent_dim for mean and log-variance
)
self.decoder = nn.Sequential(
nn.Linear(latent_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, input_dim),
nn.Sigmoid()
)
def reparameterize(self, mu, log_var):
std = torch.exp(0.5 * log_var)
eps = torch.randn_like(std)
return mu + eps * std
def forward(self, x):
x = self.encoder(x)
mu, log_var = x[:, :latent_dim], x[:, latent_dim:]
z = self.reparameterize(mu, log_var)
reconstructed = self.decoder(z)
return reconstructed, mu, log_var
# Generate synthetic data for demonstration
num_samples = 1000
data_dim = 20
data = torch.tensor(np.random.randint(2, size=(num_samples, data_dim)), dtype=torch.float32)
print(data)
# Initialize the SampleGenModel
input_dim = data_dim
hidden_dim = 64
latent_dim = 16
vae = SampleGenModel(input_dim, hidden_dim, latent_dim)
# Define an adversary model (a simple feedforward neural network)
class Adversary(nn.Module):
def __init__(self, input_dim):
super(Adversary, self).__init__()
self.fc = nn.Sequential(
nn.Linear(input_dim, 32),
nn.ReLU(),
nn.Linear(32, 1),
nn.Sigmoid()
)
def forward(self, x):
return self.fc(x)
# Train the SampleGenModel
# Train the adversary model
adversary = Adversary(latent_dim)
optimizer = optim.Adam(adversary.parameters(), lr=0.001)
criterion = nn.BCELoss()
# Prepare target data for the membership inference attack
target_data_point = torch.tensor(np.random.randint(2, size=data_dim), dtype=torch.float32)
# Membership inference attack function
def membership_inference_attack(vae, adversary, target_data_point):
# Encode the target data point using the VAE
with torch.no_grad():
target_data_point = target_data_point.unsqueeze(0) # Add batch dimension
reconstructed, mu, log_var = vae(target_data_point)
# Use the adversary to predict membership
prediction = adversary(mu)
# If the prediction is close to 1, the target data point is likely a member
if prediction.item() > 0.5:
return "Member"
else:
return "Non-Member"
# Perform the membership inference attack
result = membership_inference_attack(vae, adversary, target_data_point)
# Output the result
print("Membership Inference Result:", result)
这导致以下输出:
tensor([[0., 0., 1., ..., 1., 0., 1.],
[0., 1., 1., ..., 0., 0., 1.],
[1., 0., 1., ..., 1., 0., 1.],
...,
[0., 0., 0., ..., 1., 0., 0.],
[0., 1., 0., ..., 0., 1., 1.],
[1., 0., 1., ..., 0., 0., 0.]])
Membership Inference Result: Member
成员身份推断攻击在实践中更为复杂,此代码仅作为基本演示。在部署生成模型时,请实施隐私和安全措施以防止此类攻击。我们将在下一节详细介绍如何以隐私保护的方式保护 GenAI 模型。
从生成模型中提取训练数据攻击
从 LLM(大型语言模型)中提取训练数据可能是一项具有挑战性的任务,因为训练数据通常无法直接从模型中获取。相反,LLM 是在互联网上的大量数据集上预训练的。如果我们有特定的 LLM 并希望提取与其相关的训练数据,我们可能需要访问用于预训练的原始数据源,这些数据源可能并非公开可用。
这里有一个 Python 代码片段示例,展示了我们如何从预训练的 Hugging Face Transformers 模型(如 GPT-2)中提取文本数据。请注意,此代码仅用于说明目的,不会检索实际训练数据,而是从模型中生成文本样本:
在此代码中,我们执行以下操作:
-
我们从 Hugging Face Transformers 库中加载了一个预训练的 GPT-2 模型和分词器。您可以根据需求选择其他模型。
-
我们定义一个提示,它作为生成文本的起点。您可以根据需要更改提示。
-
我们指定从模型中生成文本样本的数量(num_samples)。
-
在循环内部,我们使用分词器对提示进行编码,并使用模型生成文本序列。我们将输出解码以获得可读性强的文本。
请注意,生成的文本不是用于模型的实际训练数据,而是基于提供的提示由模型产生的合成文本。要访问用于训练 LLM 的实际训练数据,您需要访问原始数据源,这些数据源通常是大型且多样化的网络语料库。
源代码:Training_Data_Extraction_Gen_AI.ipynb
!pip install torch
!pip install transformers
import torch
from transformers import GPT2LMHeadModel, GPT2Tokenizer
# Load a pretrained GPT-2 model and tokenizer
model_name = "gpt2"
# You can choose other pretrained models as well
model = GPT2LMHeadModel.from_pretrained(model_name)
tokenizer = GPT2Tokenizer.from_pretrained(model_name)
# Generate text samples from the model
prompt = "Once upon a time"
num_samples = 5
for _ in range(num_samples):
input_ids = tokenizer.encode(prompt, return_tensors="pt")
output = model.generate(input_ids, max_length=100, num_return_sequences=1, no_repeat_ngram_size=2)
generated_text = tokenizer.decode(output[0], skip_special_tokens=True)
print("Generated Text:\n", generated_text)
print("="*80)

图 10.5 – GPT2 模型权重、分词器和配置下载
来自谷歌、苹果、OpenAI、哈佛大学、加州大学伯克利分校、东北大学和斯坦福大学的研究人员演示了对 GPT-2 的攻击,GPT-2 是一个基于公共互联网抓取数据的语言模型,他们能够从模型的训练数据中提取出数百个逐字逐句的文本序列。这些提取的示例包括(公开的)个人可识别信息或PII(姓名、电话号码和电子邮件地址):arxiv.org/pdf/2012.07805.pdf。
提示注入攻击
提示注入攻击,也称为数据或命令注入,是一种安全漏洞,当攻击者可以影响发送到数据处理系统(如 LLM)的提示或命令时发生。这些攻击可能允许攻击者操纵系统的行为或提取敏感或私人数据。
在 LLM 的背景下,提示注入攻击可能涉及攻击者提供一个精心设计的输入,以欺骗模型提供其训练过的信息,如果训练数据没有正确匿名化或清理,这可能包括敏感或机密信息。此外,攻击者可以注入恶意提示,使模型产生有害的输出,例如生成攻击性、诽谤性或非法内容。这可以用于针对性钓鱼、散布虚假信息、诽谤个人或实体,以及许多其他恶意目的。
LangChain (www.langchain.com/) 是提供构建 LLM 应用程序工具的开源框架之一。2023 年 8 月,NVIDIA AI Red Team 在 LangChain 中发现了三个通过提示注入的漏洞;它们如下列出:
-
CVE-2023-29374: 在 LangChain 0.0.131 版本中,LLMMathChain链允许通过 Python exec方法执行任意代码的提示注入攻击。
-
CVE-2023-32786: 在 Langchain 0.0.155 版本中,提示注入允许攻击者强制服务从任意 URL 检索数据,本质上提供了服务器端请求伪造(SSRF)并可能将内容注入到下游任务中。
-
CVE-2023-36189: 在 LangChain v0.0.247 之前的 SQL 注入漏洞允许远程攻击者通过SQLDatabaseChain组件获取敏感信息。
目前,LLM 对这些攻击的受影响程度尚未完全了解。还值得一提的是,这些模型的设计目的是不直接回忆任何关于其训练数据的详细信息,包括它们训练过的文档或来源,并且它们通常没有访问或检索个人数据的能力,除非它们被明确编程这样做,或者它们是在包含敏感个人信息的训练数据上训练的。尽管如此,始终以强大的安全措施和对潜在风险的了解来使用 LLM 或任何 AI 系统,这一点至关重要。
示例: PromptInjection.ipynb
class SimpleModel:
def __init__(self):
self.data={
'Unique ID':'123-45-6789',
'email':'example@example.com',
'password':'mypassword'
}
def generate_text(self,prompt):
return self.data.get(prompt,'Sorry,I don\'t have the data')
model=SimpleModel()
## Normal Request
print(model.generate_text('favorite_color'))
## Malicious request , simulating an attempt to a prompt injection attack
print(model.generate_text('Unique ID'))
这导致以下输出。
Sorry,I don't have the data
123-45-6789
LLM 的隐私保护技术
差分隐私是可用于 LLM 的隐私保护技术之一。
对 ML 模型和 LLM 的文本攻击
TextAttack 是一个 Python 框架,旨在在 NLP 领域进行对抗攻击、对抗训练和数据增强。这个多功能的工具简化了探索 NLP 模型鲁棒性的过程,提供了一个无缝、快速且用户友好的体验。此外,它在 NLP 模型训练、对抗训练和数据增强方面非常有价值。TextAttack 提供了针对典型 NLP 任务的各个组件,包括句子编码、语法检查和词替换,这些也可以独立使用。
如何安装 TextAttack 包的说明可以在以下 GitHub URL 找到:github.com/QData/TextAttack。
使用以下方式通过pip install安装 TextAttack 框架:
!pip install textattack
TextAttack 提供了各种配方来攻击 NLP 模块。以下示例利用各种库和组件,使用 TextAttack 框架对 NLP 模型进行对抗攻击。
下面是实现此示例的高级步骤:
-
导入库: 导入必要的库,包括来自 Hugging Face 的transformers,PyTorch 的torch,math,textattack和random。
-
环境设置: 将CUDA_VISIBLE_DEVICES环境变量设置为空字符串,实际上禁用了 GPU 的使用。它指定用于 PyTorch 操作的设备为"cpu"。
-
模型定义: 定义一个名为Model的自定义 PyTorch 模型。该模型使用Bidirectional Encoder Representations from Transformers(BERT)进行 NLP 任务。模型从 Hugging Face 的 Transformers 库中加载预训练的'bert-base-uncased' BERT 模型。它包括一个 dropout 层和一个线性层用于分类。
-
模型和分词的初始化:
-
模型初始化: 创建Model类的一个实例,并将其移动到 CPU 上进行评估。使用model.eval()将模型设置为评估模式。
-
分词器初始化: 初始化一个 BERT 分词器(BertTokenizer)用于对文本进行分词。
-
-
自定义模型包装器: 定义一个名为CustomWrapper的自定义模型包装器类,该类包装了 PyTorch 模型。这个包装器允许模型与TextAttack库一起使用。
-
使用 TextAttack 库,通过TextFoolerJin2019配方构建攻击。将CustomWrapper实例传递给攻击:
-
数据集: 定义一个名为dataset的列表,包含文本样本和相应的标签。这些样本是执行对抗攻击的示例。
-
攻击执行: 创建一个Attacker实例,指定攻击、数据集和其他攻击参数。最后,在攻击者上调用attack_dataset()方法对数据集进行对抗攻击。
-
总体而言,此代码设置了一个 PyTorch 模型,使用 TextAttack 库初始化攻击,然后将此攻击应用于文本样本数据集,以评估 NLP 模型的鲁棒性。
源代码:Privacy_attacks_LLMs.ipynb
import pandas as pd
import os
from transformers import BertTokenizer, BertModel
from torch import nn
import torch
import math
import textattack
import random
#from train_bert import Model
os.environ["CUDA_VISIBLE_DEVICES"] = ""
#torch.cuda.is_available = lambda : False
textattack.shared.utils.device = "cpu"
class Model(torch.nn.Module):
def __init__(self):
super(Model, self).__init__()
self.bert_model = BertModel.from_pretrained('bert-base-uncased')
#self.bert_model.parallelize()
self.drop = torch.nn.Dropout(p=0.1)
self.l1 = torch.nn.Linear(768,2)
def forward(self, text):
tokenized_text = tokenizer(text , max_length=512, truncation=True, return_tensors='pt').input_ids#.to('cuda:3')
text_rep = self.drop(self.bert_model(tokenized_text).pooler_output)
out = self.l1(text_rep)
print(out)
return out.squeeze().tolist()
model = Model()
model.load_state_dict(torch.load('bert-base-uncased'))
model = model.to('cpu')
model.eval()
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
class CustomWrapper(textattack.models.wrappers.ModelWrapper):
def __init__(self, model):
self.model = model#.to('cuda:3')
self.model.eval()
def __call__(self, list_of_texts):
results = []
self.model.requires_grad = False
for text in list_of_texts:
results.append(self.model(text))
return results
class_model = CustomWrapper(model)
from textattack.datasets import Dataset
from textattack.attack_recipes.textfooler_jin_2019 import TextFoolerJin2019
from textattack import Attacker, AttackArgs
attack = TextFoolerJin2019.build(class_model)
attack#.cuda_()
dataset = [
["This film is a masterpiece! The story is incredibly moving, and the performances are outstanding. It's a true classic.", 1],
["The Godfather is a cinematic gem. The storytelling and performances are top-notch. A true classic in every sense.", 1],
["The Emoji Movie is a complete disappointment. The plot is weak, and it feels like one big advertisement. A waste of time.", 0],
["Mind-bending and visually stunning! Inception keeps you guessing from start to finish. Christopher Nolan at his best.", 1],
["Twilight is a guilty pleasure for some, but the acting and dialogue are cringe-worthy. Not a cinematic masterpiece.", 0],
["Forrest Gump is a heartwarming journey through history. Tom Hanks delivers an unforgettable performance.", 1],
["Explosions and CGI can't make up for the lackluster story in Transformers: The Last Knight. Disappointing.", 0],
["The Dark Knight is a dark and gripping superhero film. Heath Ledger's Joker is iconic. A must-see.", 1],
["Avatar is visually breathtaking, but the story is somewhat predictable. Still, it's a cinematic experience.", 1],
["The Room is so bad that it's almost good. The unintentional humor makes it a cult classic.", 1]
]
random.shuffle(dataset)
attacker = Attacker(attack, textattack.datasets.Dataset(dataset[:10]), AttackArgs(num_examples=10))
attacker.attack_dataset()
这导致以下输出:
+-------------------------------+--------+
| Attack Results | |
+-------------------------------+--------+
| Number of successful attacks: | 1 |
| Number of failed attacks: | 2 |
| Number of skipped attacks: | 7 |
| Original accuracy: | 30.0% |
| Accuracy under attack: | 20.0% |
| Attack success rate: | 33.33% |
| Average perturbed word %: | 40.91% |
| Average num. words per input: | 17.3 |
| Avg num queries: | 213.33 |
+-------------------------------+--------+
以类似的方式,GPT-2 模型也可以用于 NLP 攻击(对于完整的源代码,请参阅 GitHub 仓库 github.com/PacktPublishing/Privacy-Preserving-Machine-Learning/blob/main/Chapter10/Privacy_attacks_LLMs.ipynb):
class ClassificationModel(nn.Module):
def __init__(self, model, pos_prompt, neg_prompt):
super(ClassificationModel, self).__init__()
self.tokenizer = GPT2Tokenizer.from_pretrained('gpt2')
self.model = GPT2LMHeadModel.from_pretrained(model)
self.model.eval()
self.pos_prompt = pos_prompt
self.neg_prompt = neg_prompt
def score(self, prompt, sentence, model):
tokenized_prompt = self.tokenizer.encode(prompt , max_length=1024, truncation=True, return_tensors='pt').to('cpu')
tokenized_all = self.tokenizer.encode(prompt + ' ' + sentence, max_length=1024, truncation=True, return_tensors='pt').to('cpu')
loss1=model(tokenized_all, labels=tokenized_all).loss
loss2 = model(tokenized_prompt, labels=tokenized_prompt).loss*len(tokenized_prompt[0])/len(tokenized_all[0])
loss = loss1-loss2
return math.exp(loss)
def forward(self, sentence):
pos = 0
neg = 0
for prompt in self.pos_prompt:
pos += self.score(prompt, sentence, self.model)#.cpu()
for prompt in self.neg_prompt:
neg += self.score(prompt, sentence, self.model)#.cpu()
result = torch.FloatTensor([5000-neg/10.0e+52, 5000-pos/10.0e+52])
result = torch.softmax(result, 0)
if abs(result[0].item()+result[1].item()-1) >= 1e-6:
print('detected something')
result = torch.FloatTensor([1,0])
return torch.softmax(result, 0)
model = ClassificationModel('gpt2', ['Positive:'], ['Negative:'])
class_model = CustomWrapper(model)
attacker = Attacker(attack, textattack.datasets.Dataset(dataset[:10]), AttackArgs(num_examples=10))
attacker.attack_dataset()
这导致以下输出:
-------------------------------+-------+
| Attack Results | |
+-------------------------------+-------+
| Number of successful attacks: | 0 |
| Number of failed attacks: | 3 |
| Number of skipped attacks: | 7 |
| Original accuracy: | 30.0% |
| Accuracy under attack: | 30.0% |
| Attack success rate: | 0.0% |
| Average perturbed word %: | nan% |
| Average num. words per input: | 17.3 |
| Avg num queries: | 250.0 |
+-------------------------------+-------+
私有变压器 – 使用差分隐私训练 LLMs
本节的完整源代码可在 github.com/lxuechen/private-transformers 找到。
Xuechen Li, Florian Tramer, Percy Liang, Tatsunori Hashimoto 等人提供了使用差分隐私训练 LLMs 的私有变压器。
他们修改了 Opacus 框架,将其与 Hugging Face 的 transformers 库集成,并提供了一个 隐私引擎 以隐私保护的方式训练 LLMs。使用此代码库,他们成功地对异常大的预训练模型进行了微调,实现了迄今为止一些最令人印象深刻的差分隐私 NLP 结果。事实上,某些模型的表现与鲁棒的私有基线方法相当。这为高度有效的差分隐私 NLP 模型甚至可以构建于相对较小的数据集上提供了令人信服的经验支持。此外,对 ghost-clipping 技术的支持使得可以以显著降低的内存需求私密地训练大型变压器。在许多情况下,内存占用几乎与私有训练一样轻量,仅略微增加了运行时开销。目前,私有变压器仅支持以下 LLMs:
-
OpenAIGPTLMHeadModel
-
OpenAIGPTDoubleHeadsModel
-
GPT2LMHeadModel
-
GPT2DoubleHeadsModel
-
BertForSequenceClassification
-
RobertaForSequenceClassification
-
AlbertForSequenceClassification
-
BartForConditionalGeneration
-
T5ForConditionalGeneration
-
OPTForCausalLM
-
ViTForImageClassification
-
DeiTForImageClassification
-
BeitForImageClassification
私密训练 Hugging Face 变压器简单分为四个步骤:
-
创建您喜欢的变压器模型和优化器;将此优化器附加到 PrivacyEngine 实例。
-
为数据的小批量计算每个示例的损失(1-D 张量)。
-
将损失传递给 optimizer.step 或 optimizer.virtual_step 作为关键字参数。
-
从 步骤 2 重复。
示例
下面的代码是为了训练具有隐私保护功能的语言模型而设计的。它利用了 Hugging Face Transformers 库和 PyTorch。以下是实现这些详细步骤的步骤。
下一步骤中涵盖了以下内容:
-
库和导入
-
Dataset 类
-
从文本文件加载数据
-
前向步骤
-
训练函数
-
运行训练
-
导入必要的库和模块。以下是一些例子:
-
tqdm: 一个在训练期间显示进度条的库。
-
transformers: 用于处理基于 transformer 的模型的库。
-
torch: 用于深度学习(DL)的 PyTorch 库。
-
transformers中的GPT2Tokenizer和GPT2LMHeadModel: 这些类提供了访问 GPT-2 模型和分词器的接口。
-
private_transformers中的PrivacyEngine: 用于在隐私约束下训练模型的自定义隐私引擎。
-
-
Dataset 类: 定义了一个自定义的Dataset类来处理训练数据。该类具有以下方法:
-
init(self, texts, labels, eos_token): 使用文本、标签和一个序列结束(EOS)标记(eos_token)初始化数据集。
-
len(self): 返回数据集的长度。
-
getitem(self, index): 在指定索引处检索特定的文本及其对应的标签。
-
-
从文本文件加载数据: 使用get_data_from_txt(path)函数从文本文件中加载数据和标签。文件中的每一行包含一个标签后跟一个文本。此函数读取文件,提取标签和文本,并将它们作为列表返回。
-
前向步骤: forward_step(correct_texts, wrong_texts, tokenizer, model, mismatch_loss, mismatch_weight) 函数在训练期间执行前向步骤。它接受正确和错误文本的列表、分词器、模型以及不匹配损失和不匹配权重的参数。它对文本进行分词,计算语言模型损失,并在指定的情况下应用不匹配损失。结果是损失张量。
-
训练函数: train_llm(args_model_out, return_results, train_data, train_loader) 函数用于训练语言模型。它初始化 GPT-2 模型、分词器、优化器和隐私引擎。本例中使用了一个隐私预算(epsilon)值为0.5,但可以更改为所需的隐私预算。然后它遍历训练的各个 epoch,批量处理数据并计算损失。在每个 epoch 结束时保存模型。
-
运行训练: 在代码的末尾,使用train_llm()函数从一个文本文件中加载样本数据集,并开始训练过程。该函数接受诸如保存模型的输出路径、是否返回结果、训练数据和数据加载器等参数。
所有的前六个步骤在以下代码片段中实现:
源代码: Privacy_Transformer.ipynb
!pip install transformers
!pip install git+https://github.com/lxuechen/private-transformers.git
!pip install tqdm
from tqdm import tqdm
import transformers
import torch
from transformers import GPT2Tokenizer, GPT2LMHeadModel
from private_transformers import PrivacyEngine
class Dataset(torch.utils.data.Dataset):
def __init__(self, texts, labels, eos_token):
self.texts = texts
self.y = labels
self.eos_token = eos_token
def __len__(self):
return len(self.texts)
def __getitem__(self, index):
text = self.texts[index] + ' ' + self.eos_token
label = self.y[index]
return text, label
def get_data_from_txt(path: str):
texts = []
labels = []
with open(path, 'r') as f:
for line in f:
texts.append(' '.join(line.split(' ')[1:]).replace('\n', ''))
labels.append(int(line.split(' ')[0]))
return texts, labels
def forward_step(texts,tokenizer, model):
tokenized_texts = tokenizer(texts, truncation=True, max_length=500, return_tensors='pt', padding=True).input_ids.to('cpu')
lm_loss = model(tokenized_texts, labels=tokenized_texts).loss.unsqueeze(dim=0)
return lm_loss
def train_llm(train_data, train_loader, ):
model = GPT2LMHeadModel.from_pretrained("gpt2")
#model.parallelize()
model.train()
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
tokenizer.pad_token = tokenizer.eos_token
optimizer = torch.optim.Adam(model.parameters(),lr = 8e-6)
args_epochs=2
print(args_epochs)
epsilon=0.5
privacy_engine = PrivacyEngine(
model,
batch_size=1,
sample_size=10,
epochs=args_epochs,
max_grad_norm=0.1,
target_epsilon=epsilon,
)
privacy_engine.attach(optimizer)
for epoch in range(args_epochs):
total_loss = 0
for texts, labels in tqdm(train_loader):
lm_loss = forward_step(texts,tokenizer, model)
optimizer.step(loss=lm_loss)
total_loss += lm_loss.item()
return model
train_texts, train_labels = get_data_from_txt('imdb_train.txt')
train_texts = train_texts[0:100]
train_labels =train_labels[0:100]
train_data = Dataset(train_texts, train_labels, '<|endoftext|>')
train_loader = torch.utils.data.DataLoader(train_data, shuffle=False, batch_size=1)
pmodel = train_llm(train_data,train_loader)
print(pmodel)
Output of this program as follows:
2
0.5
training epoch 0

图 10.6 训练损失和模型参数
STOA – LLM 的隐私保护技术
以下部分提供了关于 LLM 隐私保护技术的 SOTA 研究工作的高级概述。这不是一个详尽的列表,但详细介绍了当前的研究趋势。
提示 – 隐私:“随机鹦鹉群:大型语言模型差分隐私提示学习” 研究论文:arxiv.org/pdf/2305.15594.pdf
大型语言模型(LLM)擅长理解上下文信息;然而,关于提示中包含的数据的隐私影响引起了担忧。这项研究通过展示对 LLM 提示所使用数据的简单但非常有效的成员身份推断攻击来验证这些担忧。为了解决这种漏洞,一个选择是放弃提示,转而专注于使用私有无梯度下降算法对 LLM 进行微调。然而,这种方法牺牲了提示方法提供的实用性和效率。因此,作者提出了一个新的解决方案:隐私提示学习。他们首先展示了通过下游数据的梯度下降获得软提示的可行性。然而,挑战在于处理离散提示。为了克服这一点,设计了一个过程,其中一组 LLM 与各种提示互动,类似于一群多样化的鹦鹉。这些 LLM 之间的噪声投票将整个集体的知识私下转移到单个公共提示中。他们的结果表明,使用他们的私有算法提示的 LLM 在性能上接近其非隐私的对应物。例如,当使用 GPT-3 作为基础模型时,他们在 sst2 数据集上实现了 92.7%的下游准确率,具有(ε = 0.147,δ = 10^-6)差分隐私,而基线非隐私的准确率为 95.2%。
提示 – 隐私:LLM 可以理解加密提示:面向隐私计算友好的 Transformer
在这项研究中,学者们说明了通过在 transformer 框架内用隐私计算兼容的近似值替换计算和通信密集型函数,显著降低了与隐私推理相关的成本,同时对模型的有效性影响很小。与最先进的 Iron 框架(NeurIPS 2022)相比,他们为隐私计算量身定制的模型推理过程在计算速度上提高了五倍,在通信开销上减少了 80%,同时保持了几乎相同的准确率水平。
差分隐私注意力计算
研究论文:arxiv.org/abs/2305.04701
注意力机制在大型语言模型(LLMs)中起着至关重要的作用,使它们能够选择性地关注输入文本的各个部分。计算注意力矩阵是 LLM 计算过程中的一个公认且重要的任务。因此,确定如何为注意力矩阵的计算提供可验证的隐私保证是一个重要的研究方向。在理论计算机科学研究生教科书中发现的一个自然数学概念,用于量化隐私,是差分隐私。
在这项研究中,受 Vyas、Kakade 和 Barak(2023)的工作启发,研究人员提出了一种可证明的结果,展示了如何差分隐私地近似注意力矩阵。从技术角度来看,这些结果借鉴了 Alabi、Kothari、Tankala、Venkat 和 Zhang(2022)在差分隐私领域的开创性研究。
LLMs 中的差分隐私解码
研究人员提出了一种简单、易于解释且计算效率高的扰动技术,旨在在预训练模型的解码阶段实施。这种扰动机制是模型无关的,并且与任何 LLM 兼容。他们的工作包括对所提出机制差分隐私属性的理论分析,以及说明隐私与效用之间权衡的实验结果。
差分隐私模型压缩
研究 论文:arxiv.org/abs/2206.01838
大型预训练 LLMs 已经证明了在私有数据上进行微调的能力,在众多下游自然语言处理(NLP)任务中实现了与无隐私模型相当的性能水平,同时确保了差分隐私。然而,这些包含数亿个参数的模型通常会产生过高的推理成本。因此,在实际应用中,LLMs 在部署前通常需要进行压缩。研究人员开始探索差分隐私模型压缩,并提出能够实现 50%稀疏度水平同时保留几乎全部性能的框架。他们的研究包括使用 BERT 模型进行标准通用语言理解评估(GLUE)基准的实践演示,从而为该领域的未来研究建立了基准。
摘要
总之,本章深入探讨了语言模型(LLMs)的世界及其使用过程中的关键考虑因素,特别是隐私和安全方面。我们涵盖了诸如提示工程等关键概念,并比较了开源与闭源 LLMs。此外,我们还探讨了 AI 标准和攻击术语,强调了 NIST 的指南和 OWASP Top 10 LLMs 漏洞。
此外,我们讨论了针对 LLMs 的各种隐私攻击,包括现实中的隐私泄露事件、成员推断攻击和提示注入攻击。这些例子强调了在 LLMs 中采用稳健的隐私保护技术的重要性。我们探讨了使用带有私有 Transformer 的差分隐私来训练 LLMs 的技术,以减轻隐私风险同时保持模型性能。
总体而言,本章旨在赋予读者必要的知识和工具,以便在导航 LLMs 的复杂性时保护用户隐私并确保负责任的 AI 部署。随着该领域的持续发展,保持对 LLMs 中隐私问题的了解和积极应对变得越来越重要。通过理解提示工程、AI 标准、隐私攻击和隐私保护技术的细微差别,利益相关者可以做出明智的决定,以促进 LLMs 在各种应用中的可信和负责任的使用。



浙公网安备 33010602011771号