网络安全的机器学习秘籍(四)
原文:
annas-archive.org/md5/ccb0ce37f50c14ac9195f73f7edac92e译者:飞龙
第七章:使用机器学习保护和攻击数据
在本章中,我们将学习如何利用机器学习(ML)来保护和攻击数据。我们将介绍如何使用机器学习评估密码强度,以及如何利用深度学习破解密码。同样,我们还会介绍如何利用隐写术将信息藏匿在明面上,以及如何使用机器学习检测隐写术。此外,我们还将将机器学习与硬件安全结合,利用 AI 攻击物理不可克隆函数(PUF)。
在本章中,我们将涵盖以下内容:
-
使用机器学习评估密码安全性
-
使用深度学习进行密码破解
-
深度隐写术
-
基于机器学习的隐写分析
-
针对 PUF 的机器学习攻击
-
使用深度学习进行加密
-
HIPAA 数据泄露——数据探索与可视化
技术要求
在本章中,我们将使用以下技术:
-
PyTorch
-
TensorBoardX
-
XGBoost
-
scikit-learn
-
pandas
-
TensorFlow
-
Keras
-
Octave
本章的代码和数据集可以在github.com/PacktPublishing/Machine-Learning-for-Cybersecurity-Cookbook/tree/master/Chapter07找到。
使用机器学习评估密码安全性
密码破解是系统化地发现安全系统密码的过程。破解可以包括使用常见密码、巧妙生成的候选密码(例如,将字母 O 替换为数字 0 或将单词反向书写),或直接使用暴力穷举搜索。为了使密码更难破解,必须选择一个强密码。
准备工作
为了准备这个配方,我们需要在pip中安装pandas、sklearn和xgboost。使用以下代码进行安装:
pip install pandas sklearn xgboost
此外,解压归档数据集,即PasswordDataset.7z。
如何操作…
在接下来的步骤中,我们将读取一个包含密码及其强度标签的数据集,并构建一个分类器来评估密码强度。让我们开始吧:
- 导入
pandas并将密码读取到数据框中:
import pandas as pd
df = pd.read_csv(
"passwordDataset.csv", dtype={"password": "str", "strength": "int"}, index_col=None
)
- 随机打乱数据:
df = df.sample(frac=1)
- 将数据框拆分为两个独立的数据框,一个用于训练,一个用于测试:
l = len(df.index)
train_df = df.head(int(l * 0.8))
test_df = df.tail(int(l * 0.2))
- 创建所需的标签和特征数据:
y_train = train_df.pop("strength").values
y_test = test_df.pop("strength").values
X_train = train_df.values.flatten()
X_test = test_df.values.flatten()
- 定义一个函数,将字符串拆分为其字符:
def character_tokens(input_string):
"""Break string into characters."""
return [x for x in input_string]
- 创建一个管道,对密码的字符进行 TF-IDF 处理,然后进行梯度提升:
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import TfidfVectorizer
from xgboost import XGBClassifier
password_clf = Pipeline(
[("vect", TfidfVectorizer(tokenizer=character_tokens)), ("clf", XGBClassifier()),]
)
- 训练和测试管道:
password_clf.fit(X_train, y_train)
password_clf.score(X_test, y_test)
以下是输出结果:
0.9137365878426307
- 设置一个变量为常用密码,另一个变量为计算机生成的高熵密码:
common_password = "qwerty"
strong_computer_generated_password = "c9lCwLBFmdLbG6iWla4H"
- 检查分类器对两个密码强度的预测:
password_clf.predict([common_password, strong_computer_generated_password])
以下是输出结果:
array([0, 2])
它是如何工作的…
我们首先导入pandas,然后将数据读取到一个数据框中(步骤 1)。数据中有两个字段:密码和密码强度。密码强度分为三种难度等级。我们在步骤 2中打乱数据,以创建更强健的训练。接着,在步骤 3中,我们通过 80-20 的比例划分数据框,然后将特征和标签分配到数组中(步骤 4)。在步骤 5中,我们定义一个函数,将密码字符串拆分成字符,从而将密码分词为字符,而不是单词。这样可以让分类器学习密码数据集中的细粒度信息。在步骤 6中,我们定义一个管道,对密码的字符进行自然语言处理(NLP),然后使用 XGBoost 分类器。接下来,在步骤 7中,我们训练并测试我们的分类器。对于这样的主观任务,分类器的表现不一定会在高分或低分上体现。
完成训练后,我们进行合理性检查/演示分类器的有效性。在步骤 8中,我们选择最常见的密码之一和一个使用密码管理系统生成的密码。在步骤 9中,我们可以看到分类器确实将常见密码分类为弱(强度 0),而强密码分类为强(强度 2)。成功。
密码破解的深度学习
现代的密码破解工具,如John the Ripper,允许黑客在几秒钟内测试数十亿个潜在密码。这些工具不仅能让黑客尝试字典中所有常见密码,还可以通过连接(例如,password1234)、键盘替换(p4s5w0rd)等技巧自动转换密码。虽然这些技巧有前景,但发现其他有效的转换方法是一个困难的任务。被称为 PassGAN 的机器学习系统使用生成对抗网络(GAN),通过观察大量实际密码泄露数据集,自动学习这些规则,并生成高概率的密码候选。 在这个食谱中,你将训练 PassGAN 来处理泄露的密码语料库,并使用它生成密码猜测。
该项目需要一台配有 GPU 的机器。
准备工作
为了准备这个食谱,请执行以下步骤:
- 使用以下命令克隆
PassGAN仓库:
git clone https://github.com/emmanueltsukerman/PassGAN.git
- 将数据集放置在
data文件夹下。例如,你可以使用以下命令下载著名的rockyou密码数据集:
curl -L -o data/train.txt https://github.com/brannondorsey/PassGAN/releases/download/data/rockyou-train.txt
在运行密码数据集时,你应该看到如下内容:
此外,本食谱要求预先安装 CUDA 8。所需的 pip 包可以通过运行以下命令来安装:
pip install -r requirements.txt
如何做……
在接下来的步骤中,我们将使用泄露的密码语料库来训练 PassGAN,并用它生成新的密码猜测。让我们开始吧:
- 通过运行以下命令,使用数据集训练你的神经网络:
python train.py --output-dir output --training-data data/train.txt
- 通过运行以下命令生成(100,000)个密码猜测的列表:
python sample.py \
--input-dir pretrained \
--checkpoint pretrained/checkpoints/195000.ckpt \
--output gen_passwords.txt \
--batch-size 1024 \
--num-samples 100000
你的终端应该显示如下内容:
它是如何工作的…
在本教程中,我们在步骤 1中直接训练了我们的神经网络。根据需要,还可以使用几个附加的标志来定制训练。现在我们已经训练好了模型,接下来需要输出一个包含 100,000 个密码的列表,所有这些密码都是由模型生成的(步骤 2)。这些密码是可能的智能猜测。通过检查步骤 2的输出,我们可以看到密码的展示方式如下:
现在,我们可以将这些作为破解密码的候选项。
还有更多内容
描述 PassGAN 的原始论文可以在arxiv.org/abs/1709.00440找到。
深度隐写术
隐写术是将一条消息(即秘密)隐藏在另一种媒介中的实践,比如文件、文本、图像或视频(即封面)。当秘密嵌入到封面中时,结果称为容器。在本教程中,我们将使用深度神经网络来创建隐藏和揭示过程。与常见的隐写方法不同,深度学习将秘密分布在所有位上,而不是仅仅编码在封面的最低有效位(LSB)中。
准备就绪
在这个教程中,你将需要访问一个 GPU。
如何操作…
- 使用以下命令克隆仓库:
git clone https://github.com/emmanueltsukerman/PyTorch-Deep-Image-Steganography.git
- 准备一个预训练模型:
cat ./checkPoint/netH.tar.gz* | tar -xzv -C ./checkPoint/
- 在
example_pics文件夹中准备一个秘密图像和一个封面图像:
如你所见,我们使用以下图像作为封面图像:
我们使用以下图像作为秘密图像:
- 执行预训练模型生成容器图像和重建的秘密:
CUDA_VISIBLE_DEVICES=0 python main.py –test=./example_pics
输出的第一部分显示在以下截图中:
输出的第二部分显示在以下截图中:
输出的最后一部分显示在以下截图中:
- 在训练文件夹下查看结果。你应该能看到以下图像:
第 1 行:封面。第 2 行:容器。第 3 行:秘密。第 4 行:重建的秘密
它是如何工作的…
在步骤 1中,我们简单地克隆了深度隐写术项目的存储库。关于该项目的理论和实现的背景可以在论文在明处隐藏图像:深度隐写术中找到(papers.nips.cc/paper/6802-hiding-images-in-plain-sight-deep-steganography)。
基本思想是有一个隐藏网络(H-net)和一个揭示网络(R-net),两者都是通过对抗训练的。继续到步骤 2,我们准备我们的预训练模型。我们在这里使用的模型是在 ImageNet 的 45000 张图像上训练的,并在 5000 张图像上进行了评估。所有图像都被调整为 256×256,没有归一化,任务在一块 NVIDIA GTX 1080 Ti 上进行了 24 小时的训练。接下来,我们选择两张我们选择的图像作为封面和秘密(步骤 3)。请随意使用您自己的图像对。在步骤 4和5中,我们运行模型,创建一个容器图像(包含隐藏秘密的图像),并生成一个显示我们结果的图像。正如您所看到的,容器图像和封面图像在人眼中是无法区分的,这意味着没有人能够看出您在封面图像中隐藏了一个秘密。
基于机器学习的隐写分析
隐写术中的主要技术之一是通过改变像素的最低有效位(LSB)来隐藏消息在图像中。结果是一个带有隐藏消息的图像,人眼无法区分其与原始图像的区别。这是因为在改变图像像素的 LSB 时,像素值只会被微小地改变,导致一个视觉上相似的图像。
LSB 有两种显著的方法:
-
天真的方法被称为 LSB 替换。在这种方法中,如果消息位与 LSB 相同,则 LSB 位保持不变;否则,该位被改变。因此,奇数像素的强度减少 1,而偶数像素值增加 1。然而,这会导致图像直方图的不平衡,可以很容易地通过统计方法检测到进行隐写分析。
-
LSB 隐写术的第二种方法,LSB 匹配,通过在 LSB 位不匹配的情况下随机增加或减少像素值 1 来解决这个问题。这避免了直方图不平衡的问题,并使得仅仅使用简单的统计方法进行隐写分析变得困难。
以下图像展示了 LSB 隐写术的一个实例。
以下图像将被表示为封面图像:
以下图像将被表示为秘密图像:
以下图像将被表示为容器图像:
以下图像将被显示为恢复的秘密图像:
准备工作
推荐你在 Linux 机器上完成此配方。按照以下步骤设置好环境:
- 安装
octave以及其包image和signal:
sudo apt-get install octave octave-image octave-signal
- 克隆
aletheia的代码库,如以下代码所示:
git clone https://github.com/emmanueltsukerman/aletheia.git
- 下载
BOSS数据集,你可以通过以下链接下载:
wget http://dde.binghamton.edu/download/ImageDB/BOSSbase_1.01.zip
这将检索一个灰度图像数据库。
- 解压数据集并重命名
BOSSbase文件夹:
unzip BOSSbase_1.01.zip
为了方便你,处理过的数据集,即bossbase.7z和bossbase_lsb.7z,可以在本书的代码库中找到。
如何操作…
在本配方中,我们将策划一个 LSB 数据集,然后训练和测试一个机器学习模型,检测图像中是否存在 LSB 隐写术。让我们开始吧:
- 使用以下命令创建一个 LSB 数据库:
python aletheia.py lsbm-sim bossbase 0.40 bossbase_lsb
结果是一个名为bossbase_lsb的新文件夹,包含了带有嵌入的 BOSS 图像。它通过 LSB 匹配模拟器完成此操作。
- 对
BOSS数据集进行特征化,如以下代码所示:
./aletheia.py srm bossbase bossbase.fea
- 对 LSB 数据集进行特征化,如以下代码所示:
./aletheia.py srm bossbase_lsb bossbase_lsb.fea
剩余的步骤可以在 Python 环境中运行,方便你使用。
- 创建一些指向提取特征路径的变量:
bossbase_features_path = "bossbase.fea"
bossbase_lsb_features_path = "bossbase_lsb.fea"
features_with_labels = [(bossbase_features_path, 0), (bossbase_lsb_features_path, 1)]
- 收集特征和标签并将它们放入数组中:
X = []
y = []
for feature_path, label in features_with_labels:
with open(feature_path, "r") as f:
for line in f:
fv = line.split()
X.append(fv)
y.append(label)
- 执行训练-测试集划分:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=11
)
- 实例化一个
RandomForestClassifier并进行训练:
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier()
clf = clf.fit(X_train, y_train)
- 在测试集上对分类器进行评分:
print(clf.score(X_test, y_test))
以下是输出结果:
0.825
它是如何工作的…
我们从使用被称为 Aletheia 的软件创建一个大型 LSB 隐写容器图像数据集开始(步骤 1)。Aletheia 提供了广泛的功能。运行以下命令,不带任何参数:
$ ./aletheia.py
上述命令将打印出关于aletheia的以下信息:
./aletheia.py <command>
COMMANDS:
Attacks to LSB replacement:
- spa: Sample Pairs Analysis.
- rs: RS attack.
ML-based detectors:
- esvm-predict: Predict using eSVM.
- e4s-predict: Predict using EC.
Feature extractors:
- srm: Full Spatial Rich Models.
- hill-maxsrm: Selection-Channel-Aware Spatial Rich Models for HILL.
- srmq1: Spatial Rich Models with fixed quantization q=1c.
- scrmq1: Spatial Color Rich Models with fixed quantization q=1c.
- gfr: JPEG steganalysis with 2D Gabor Filters.
Embedding simulators:
- lsbr-sim: Embedding using LSB replacement simulator.
- lsbm-sim: Embedding using LSB matching simulator.
- hugo-sim: Embedding using HUGO simulator.
- wow-sim: Embedding using WOW simulator.
- s-uniward-sim: Embedding using S-UNIWARD simulator.
- j-uniward-sim: Embedding using J-UNIWARD simulator.
- j-uniward-color-sim: Embedding using J-UNIWARD color simulator.
- hill-sim: Embedding using HILL simulator.
- ebs-sim: Embedding using EBS simulator.
- ebs-color-sim: Embedding using EBS color simulator.
- ued-sim: Embedding using UED simulator.
- ued-color-sim: Embedding using UED color simulator.
- nsf5-sim: Embedding using nsF5 simulator.
- nsf5-color-sim: Embedding using nsF5 color simulator.
Model training:
- esvm: Ensemble of Support Vector Machines.
- e4s: Ensemble Classifiers for Steganalysis.
- xu-net: Convolutional Neural Network for Steganalysis.
Unsupervised attacks:
- ats: Artificial Training Sets.
Naive attacks:
- brute-force: Brute force attack using a list of passwords.
- hpf: High-pass filter.
- imgdiff: Differences between two images.
- imgdiff-pixels: Differences between two images (show pixel values).
- rm-alpha: Opacity of the alpha channel to 255.
在步骤 2和步骤 3中,我们使用 Aletheia 的srm命令提取原始图像和容器图像的特征。srm命令提取了完整且空间丰富的特征集。还有其他替代的特征集可供选择。接下来,我们创建指向数据集路径的变量(步骤 4),然后将我们的特征和标签收集到数组中(步骤 5)。在步骤 6至步骤 8中,我们创建训练集和测试集,训练分类器,并进行测试。通过查看在平衡数据集上 80%的表现,我们可以看出这些特征确实有助于我们区分原始图像和容器图像。换句话说,我们可以得出结论:机器学习可以检测隐写术。
针对 PUF 的机器学习攻击
经典密码学提供了多种保护电子设备的措施。这些措施主要依赖于一个秘密密钥和昂贵的资源,因为设备会永久存储一段对我们的对手未知的数字信息。实际上,很难保持这些信息的机密性。这个问题促使了 PUF 的发明——物理设备,它能快速评估输出,但却难以预测。
要使用 PUF 进行身份验证,我们需要构建一个**挑战-响应对(CRP)**的数据库。挑战是一个二进制字符串(例如,1100101...01),长度为n,响应是另一个二进制字符串,长度为m。为了判断一个未知设备是否为前述的 PUF,我们需要向其发出多个挑战,验证它是否产生正确的响应,直到我们达到所期望的概率,确认它确实是同一个 PUF。请注意,PUF 本身并不是 100%可靠的,相同的挑战可能由于环境条件和噪声的变化而产生不同的响应:
图 8:基于 PUF 的商业 RFID 标签
在此食谱中,我们将使用机器学习攻击一个特定的 PUF。请注意,该领域不断发展,已经提出了其他更安全的 PUF,以及利用机器学习提高 PUF 可靠性和安全性的方法。
准备工作
对于此食谱,我们需要通过pip安装pandas、sklearn和xgboost。使用以下代码来安装:
pip install pandas sklearn xgboost
此外,已为此食谱提供了CRPDataset.csv数据集。
如何做...
让我们学习如何用机器学习破解一个 PUF:
- 加载一个 CRP 数据集,在本例中为
CRPDataset.csv:
import pandas as pd
df = pd.read_csv("CRPdataset.csv")
数据由对(x,y)组成,其中x是长度为 64 的二进制字符串,y是一个二进制数字。这里,x是挑战,y是响应。
- 将
pandas数据框转换为 NumPy 特征和标签数组:
y = df.pop("Label").values
X = df.values
- 执行训练-测试拆分:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=11
)
- 实例化并训练 XGBoost 分类器:
from xgboost import XGBClassifier
clf = XGBClassifier()
clf.fit(X_train, y_train)
print(clf.score(X_train, y_train))
以下是输出结果:
0.6405208333333333
- 测试分类器,如以下代码所示:
clf.score(X_test, y_test)
以下是输出结果:
0.6270833333333333
它是如何工作的…
我们首先将一个 CRP 数据集读取到一个数据框中(步骤 1)。在步骤 2中,我们创建 x 和 y 的 NumPy 数组来保存特征和标签。接下来,我们对数据进行训练-测试拆分(步骤 3),然后训练和测试一个针对 CRP 的分类器(步骤 4和步骤 5)。根据性能结果,我们可以看到,机器学习可以准确预测 PUF 挑战的响应。其意义在于,在使用我们训练好的模型时,我们可以构建一个 PUF 的软件克隆,并用它来(虚假地)进行身份验证。
还有更多
该食谱的原始未处理数据集可以在archive.ics.uci.edu/ml/datasets/Physical+Unclonable+Functions找到。更多背景信息可以在论文《基于机器学习的资源受限物联网 XOR PUF 安全漏洞研究》(Aseeri, A. O.,Zhuang, Y.,和 Alkatheiri, M. S.,2018 年 7 月,发表于 2018 年 IEEE 国际物联网大会(ICIOT)(第 49-56 页),IEEE)中找到。
使用深度学习进行加密
加密是将信息转换为代码以防止未经授权的访问的过程。在此食谱中,我们将利用卷积神经网络对数据进行加密和解密。
准备工作
对于这个食谱,你需要在pip中安装click、keras、tensorflow和tqdm包。使用以下代码来安装:
pip install click keras tensorflow tqdm
此外,请使用以下命令克隆该仓库:
git clone https://github.com/emmanueltsukerman/convcrypt.git
如何操作…
以下步骤将指导你如何使用 ConvCrypt 来加密图片。让我们开始吧:
- 运行
encrypt.py脚本,对你希望加密的图片或文件进行加密:
python encrypt.py --input_file "input file path" --output_file "encrypted file path" --key_file "key file name"
上述代码的输出显示在以下截图中:
若要确认文件已被加密,尝试打开它。你会发现它无法打开,因为它已经被加密:
- 若要解密文件,执行
decrypt.py脚本,传入加密文件和密钥文件:
python decrypt.py --input_file "encrypted file path" --output_file "reconstructed file path" --key_file "key file name"
结果是原始文件。
它是如何工作的…
我们通过使用 ConvCrypt 对图片进行加密开始这个食谱(步骤 1)。ConvCrypt 是一种概念验证实验性加密算法,使用n维卷积神经网络。目前,它仅支持三维卷积。然后,在步骤 2中,我们将逆向解密并进行测试,以确保结果是原始文件。成功!
对于有兴趣的朋友,ConvCrypt 算法首先做的事情是将数据分成块。然后,为 3D 卷积生成一个密钥;这是一个随机生成的比特立方体,大小与数据块相同。最后,训练一个卷积神经网络,将密钥卷积到每个数据块中,这样每个数据块就会有自己训练好的网络。加密后的数据是每个网络的权重(即核张量的值)。
HIPAA 数据泄露——数据探索与可视化
数据探索是数据分析的初步步骤,通过可视化探索来理解数据集及其特点。数据可视化帮助我们通过将数据置于光学背景中,利用我们强大的视觉处理中心快速发现数据中的模式和相关性。
在这个食谱中,你将探索并可视化一个关于 HIPAA 机密信息泄露的公共数据集。
准备开始
对于这个食谱,你需要在pip中安装pandas和sklearn。使用以下代码来安装:
pip install pandas sklearn
此外,提供了HIPAA-breach-report-2009-to-2017.csv数据集,供你在本食谱中使用。
如何操作…
在接下来的步骤中,你将使用 pandas 可视化 HIPAA 泄露数据集,并使用 TF-IDF 从泄露描述中提取重要关键词。让我们开始吧:
- 使用
pandas加载并清洗 HIPAA 泄露数据集:
import pandas as pd
df = pd.read_csv("HIPAA-breach-report-2009-to-2017.csv")
df = df.dropna()
上述代码的输出显示在以下截图中:
- 使用以下代码绘制受泄露影响的个人数量与泄露事件频率的直方图:
%matplotlib inline
def_fig_size = (15, 6)
df["Individuals Affected"].plot(
kind="hist", figsize=def_fig_size, log=True, title="Breach Size Distribution"
)
以下输出展示了泄露大小分布:
- 基于实体类型绘制平均泄露大小:
df.groupby("Covered Entity Type").mean().plot(
kind="bar", figsize=def_fig_size, title="Average Breach Size by Entity Type"
)
以下截图显示了按实体类型划分的平均泄露大小:
- 绘制一个饼图,显示按州划分的每个州受泄露影响的个人数量,并筛选出前 20 个州:
df.groupby("State").sum().nlargest(20, "Individuals Affected").plot.pie(
y="Individuals Affected", figsize=def_fig_size, legend=False
)
以下图表展示了每个州受泄露影响的个人数量:
- 绘制平均泄露大小与泄露类型(盗窃、丢失、黑客攻击等)之间的关系:
df.groupby("Type of Breach").mean().plot(
kind="bar", figsize=def_fig_size, title="Average Breach Size by Entity Type"
)
以下图表显示了泄露类型:
- 实例化 TF-IDF 向量化器:
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer()
- 将向量化器拟合到泄露描述,并进行向量化:
df["Web Description"] = df["Web Description"].str.replace("\r", " ")
X = df["Web Description"].values
X_transformed = vectorizer.fit_transform(X)
- 根据 TF-IDF 选择泄露描述中最重要的 15 个特征:
import numpy as np
feature_array = np.array(vectorizer.get_feature_names())
tfidf_sorting = np.argsort(X_transformed.toarray()).flatten()[::-1]
n = 15
top_n = feature_array[tfidf_sorting][:n]
print(top_n)
输出如下:
['this' 'review' '842' 'south' 'ransomware' 'memorial' 'specific' 'birthdates' 'consolidated' 'malware' 'license' 'driver' 'found' 'clinic' 'information']
- 打印出包含
review关键词的几个泄露描述:
k = 2
i = 0
for x in df["Web Description"].values:
if "review" in x:
i += 1
print(x)
print()
if i == k:
break
以下是部分输出片段:
A laptop was lost by an employee... all employees received additional security training.
The covered entity's (CE) business associate (BA) incorrectly... BA to safeguard all PHI.
它是如何工作的…
我们首先将 HIPAA 数据集读取到数据框中,并删除包含 NAs 的行(步骤 1)。接下来,在步骤 2中,我们可以看到大多数泄露规模相对较小,但少数泄露事件规模巨大。这与帕累托原则一致。在步骤 3中,我们按行业绘制泄露事件,以确保最大规模的泄露发生在商业合作伙伴中。然后,在步骤 4中,我们检查哪些州发生了最多的 HIPAA 泄露事件。在步骤 5中,我们得知最大规模的泄露原因通常未知!在步骤 6和7中,我们对泄露描述进行基本的自然语言处理(NLP)。这将帮助我们提取更多感兴趣的信息。在步骤 8中,我们可以看到 TF-IDF 能够找到一些非常有信息量的关键词,比如ransomware(勒索软件)和driver(驱动程序)。最后,在步骤 9中,我们打印出包含关键词review的泄露描述。结果表明,review(回顾)是一个极其重要的词,它在质量控制和事件响应工具中经常出现。
第八章:安全与私密的人工智能
机器学习可以帮助我们诊断和对抗癌症,决定哪个学校最适合我们的孩子,甚至做出最聪明的房地产投资。但你只有在能访问私人和个人数据的情况下才能回答这些问题,这就需要一种全新的机器学习方法。这种方法叫做安全与私密的人工智能,近年来已经取得了显著进展,正如你在以下食谱中所看到的那样。
本章包含以下食谱:
-
联邦学习
-
加密计算
-
私有深度学习预测
-
测试神经网络的对抗鲁棒性
-
使用 TensorFlow Privacy 的差分隐私
技术要求
本章的技术前提如下:
-
TensorFlow Federated
-
Foolbox
-
PyTorch
-
Torchvision
-
TensorFlow Privacy
安装说明、代码和数据集可以在github.com/PacktPublishing/Machine-Learning-for-Cybersecurity-Cookbook/tree/master/Chapter08找到。
联邦学习
在本食谱中,我们将使用 TensorFlow federated 框架训练一个联邦学习模型。
为了理解联邦学习的价值,考虑你在手机上写短信时使用的下一个词预测模型。出于隐私原因,你不希望你的数据,也就是你的短信,发送到中央服务器上用于训练下一个词预测器。但你依然希望有一个准确的下一个词预测算法。该怎么办?这时,联邦学习就派上用场了,这是一种为解决此类隐私问题而开发的机器学习技术。
联邦学习的核心思想是训练数据集由数据的生产者保管,既能保持隐私和所有权,又能用于训练一个集中式模型。这一特点在网络安全领域尤其有吸引力,例如,从多个不同来源收集良性和恶性样本对于创建强大的模型至关重要,但由于隐私问题,这一过程相当困难(例如,良性样本可以是个人或机密文件)。
顺便提一下,联邦学习因数据隐私重要性日益增加而越来越受到关注(例如,GDPR 的实施)。大型公司,如苹果和谷歌,已经开始大量投资这一技术。
准备工作
为了准备本食谱,需通过 pip 安装 tensorflow_federated、tensorflow_datasets 和 tensorflow 包。命令如下:
pip install tensorflow_federated==0.2.0 tensorflow-datasets tensorflow==1.13.1
我们将安装这些包的特定版本,以防止代码出现中断。
如何操作…
在接下来的步骤中,你将创建两个虚拟数据集环境——一个属于爱丽丝,另一个属于鲍勃——并使用联邦平均算法来保持数据的保密性。
- 导入 TensorFlow 并启用急切执行:
import tensorflow as tf
tf.compat.v1.enable_v2_behavior()
- 准备一个数据集,通过导入 Fashion MNIST 并将其分成 Alice 和 Bob 两个独立环境:
import tensorflow_datasets as tfds
first_50_percent = tfds.Split.TRAIN.subsplit(tfds.percent[:50])
last_50_percent = tfds.Split.TRAIN.subsplit(tfds.percent[-50:])
alice_dataset = tfds.load("fashion_mnist", split=first_50_percent)
bob_dataset = tfds.load("fashion_mnist", split=last_50_percent)
- 现在,定义一个
helper函数将数据类型从整数转换为浮点数:
def cast(element):
"""Casts an image's pixels into float32."""
out = {}
out["image"] = tf.image.convert_image_dtype(element["image"], dtype=tf.float32)
out["label"] = element["label"]
return out
- 然后,定义一个
helper函数,将数据展平以便输入到神经网络中:
def flatten(element):
"""Flattens an image in preparation for the neural network."""
return collections.OrderedDict(
[
("x", tf.reshape(element["image"], [-1])),
("y", tf.reshape(element["label"], [1])),
]
)
- 现在,定义一个
helper函数来预处理数据:
import collections
BATCH_SIZE = 32
def preprocess(dataset):
"""Preprocesses images to be fed into neural network."""
return dataset.map(cast).map(flatten).batch(BATCH_SIZE)
- 预处理数据:
preprocessed_alice_dataset = preprocess(alice_dataset)
preprocessed_bob_dataset = preprocess(bob_dataset)
federated_data = [preprocessed_alice_dataset, preprocessed_bob_dataset]
- 现在,定义一个用于神经网络的
loss函数:
def custom_loss_function(y_true, y_pred):
"""Custom loss function."""
return tf.reduce_mean(
tf.keras.losses.sparse_categorical_crossentropy(y_true, y_pred)
)
- 定义一个函数来实例化一个简单的 Keras 神经网络:
from tensorflow.python.keras.optimizer_v2 import gradient_descent
LEARNING_RATE = 0.02
def create_compiled_keras_model():
"""Compiles the keras model."""
model = tf.keras.models.Sequential(
[
tf.keras.layers.Dense(
10,
activation=tf.nn.softmax,
kernel_initializer="zeros",
input_shape=(784,),
)
]
)
model.compile(
loss=custom_loss_function,
optimizer=gradient_descent.SGD(learning_rate=LEARNING_RATE),
metrics=[tf.keras.metrics.SparseCategoricalAccuracy()],
)
return model
- 然后,创建一个虚拟样本批次并定义一个函数,从 Keras 模型返回一个联邦学习模型:
batch_of_samples = tf.contrib.framework.nest.map_structure(
lambda x: x.numpy(), iter(preprocessed_alice_dataset).next()
)
def model_instance():
"""Instantiates the keras model."""
keras_model = create_compiled_keras_model()
return tff.learning.from_compiled_keras_model(keras_model, batch_of_samples)
- 声明一个联邦平均的迭代过程,并运行一个计算阶段:
from tensorflow_federated import python as tff
federated_learning_iterative_process = tff.learning.build_federated_averaging_process(
model_instance
)
state = federated_learning_iterative_process.initialize()
state, performance = federated_learning_iterative_process.next(state, federated_data)
- 然后,通过运行以下命令显示计算的指标:
performance
输出结果如下:
AnonymousTuple([(sparse_categorical_accuracy, 0.74365), (loss, 0.82071316)])
它是如何工作的...
我们首先导入 TensorFlow 并启用急切执行模式(步骤 1)。通常,在 TensorFlow 中,操作不会立即执行,而是构建一个计算图,并在最后一起执行所有操作。在急切执行模式下,计算会尽可能快地执行。接下来,在步骤 2中,我们导入 Fashion MNIST 数据集。这个数据集已经成为 MNIST 的事实替代品,相比 MNIST 提供了几项改进(如增加了挑战)。然后,我们将数据集按 50:50 的比例分配给 Alice 和 Bob。接下来,我们定义一个函数,将 Fashion MNIST 的像素值从整数转换为浮点数,以便用于训练神经网络(步骤 3),并定义另一个函数将图像展平为单个向量(步骤 4)。这样,我们就可以将数据输入到全连接神经网络中。在步骤 5和步骤 6中,我们使用之前定义的便捷函数对 Alice 和 Bob 的数据集进行预处理。
接下来,我们定义一个适合我们 10 类分类任务的损失函数(步骤 7),然后定义我们的 Keras 神经网络以准备训练(步骤 8)。在步骤 9中,我们创建一个虚拟样本批次并定义一个函数,从 Keras 模型返回一个联邦学习模型。虚拟样本批次指定了模型预期的输入形状。在步骤 10中,我们运行一个联邦平均过程的阶段。关于该算法的详细信息,请参阅题为《从分散数据中高效学习深度网络的通信》的论文。
从基本层面来看,算法结合了每个客户端数据的局部随机梯度下降(SGD),然后使用一个执行模型平均的服务器。结果是为客户端(在我们的例子中是 Alice 和 Bob)保留了保密性。最后,在步骤 11中,我们观察性能,发现算法确实能够训练并提高准确率,如预期那样。
加密计算
在这个配方中,我们将介绍加密计算的基础知识。特别地,我们将重点讲解一种流行的方法,称为安全多方计算。你将学习如何构建一个简单的加密计算器,可以对加密数字进行加法操作。这个配方中的理念将在私有深度学习预测配方中派上用场。
准备工作
以下配方除了 Python 外没有其他安装要求。
如何操作…
- 导入随机库并选择一个大素数
P:
import random
P = 67280421310721
- 定义一个用于三方的加密函数:
def encrypt(x):
"""Encrypts an integer between 3 partires."""
share_a = random.randint(0, P)
share_b = random.randint(0, P)
share_c = (x - share_a - share_b) % P
return (share_a, share_b, share_c)
- 对一个数值变量进行加密:
x = 17
share_a, share_b, share_c = encrypt(x)
print(share_a, share_b, share_c)
16821756678516 13110264723730 37348399908492
- 定义一个函数来解密,给定三个分享份额:
def decrypt(share_a, share_b, share_c):
"""Decrypts the integer from 3 shares."""
return (share_a + share_b + share_c) % P
- 解密加密变量
x:
decrypt(share_a, share_b, share_c)
输出如下:
17
- 定义一个函数来对两个加密数字进行加法操作:
def add(x, y):
"""Addition of encrypted integers."""
z = list()
z.append((x[0] + y[0]) % P)
z.append((x[1] + y[1]) % P)
z.append((x[2] + y[2]) % P)
return z
- 对两个加密变量进行加法并解密它们的和:
x = encrypt(5)
y = encrypt(9)
decrypt(*add(x, y))
14
工作原理…
我们从导入随机库开始,第 1 步,以便在第 2 步中生成随机整数。我们还定义了一个大素数 P,因为我们需要对其进行随机分布模 P 操作。在第 2 步中,我们定义了一个函数,通过将整数分割给三个参与方来加密该整数。这里的 x 值在三个参与方之间随机地加法拆分。所有操作都在模 P 的整数域内进行。接下来,在第 3 步中,我们展示了使用我们的方法加密整数的结果。在第 4 步和第 5 步中,我们定义了一个函数来反向加密,即解密,然后证明该操作是可逆的。在第 6 步中,我们定义了一个函数来对两个加密数字进行加法操作(!)。请注意,加密加法只是对单个组件进行加法操作,并对结果进行模 P 处理。在加密深度学习预测配方中,PySyft 中的.share(client, server,...)命令被使用。这个命令实际上和我们在这个配方中使用的加密程序是相同的,所以请记住,这些加密方案使用的是我们在这里讨论的技术。最后,在第 7 步中,我们展示了如何在加密实体上进行计算。
私有深度学习预测
在许多情况下,A 公司可能拥有一个训练好的模型,并希望将其作为服务提供。然而,A 公司可能不愿分享这个模型,以避免其知识产权被盗用。这个问题的简单解决方法是让客户将数据发送到 A 公司,然后从公司获得预测结果。然而,当客户希望保持数据隐私时,这就成了一个问题。为了解决这个棘手的情况,公司和客户可以利用加密计算。
在这个配方中,你将学习如何与客户共享一个加密的预训练深度学习模型,并允许客户使用加密模型对他们自己的私人数据进行预测。
准备工作
这个配方的准备工作包括在pip中安装 PyTorch、Torchvision 和 PySyft。命令如下:
pip install torch torchvision syft
此外,还包括一个名为 server_trained_model.pt 的预训练模型,将在此食谱中使用。
如何操作……
以下步骤利用 PySyft 模拟客户端-服务器交互,其中服务器拥有一个预训练的深度学习模型,模型被保留为一个黑盒,而客户端希望使用该模型对保密数据进行预测。
- 导入
torch并访问其数据集:
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import datasets, transforms
- 导入 PySyft 并将其挂载到
torch上:
import syft as sy
hook = sy.TorchHook(torch)
client = sy.VirtualWorker(hook, id="client")
server = sy.VirtualWorker(hook, id="server")
crypto_provider = sy.VirtualWorker(hook, id="crypto_provider")
- 定义一个简单的神经网络:
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(784, 500)
self.fc2 = nn.Linear(500, 10)
def forward(self, x):
x = x.view(-1, 784)
x = self.fc1(x)
x = F.relu(x)
x = self.fc2(x)
return x
- 实例化模型并加载其在 MNIST 上训练的预训练权重:
model = Net()
model.load_state_dict(torch.load("server_trained_model.pt"))
model.eval()
- 加密
client和server之间的网络:
model.fix_precision().share(client, server, crypto_provider=crypto_provider)
- 定义一个 MNIST 数据的加载器:
test_loader = torch.utils.data.DataLoader(
datasets.MNIST(
"data",
train=False,
download=True,
transform=transforms.Compose(
[transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]
),
),
batch_size=64,
shuffle=True,
)
- 定义一个私有加载器,利用 MNIST 数据的加载器:
private_test_loader = []
for data, target in test_loader:
private_test_loader.append(
(
data.fix_precision().share(client, server, crypto_provider=crypto_provider),
target.fix_precision().share(
client, server, crypto_provider=crypto_provider
),
)
)
- 定义一个函数来评估私有测试集:
def test(model, test_loader):
"""Test the model."""
model.eval()
n_correct_priv = 0
n_total = 0
- 遍历私密数据,使用模型进行预测,解密结果,然后打印出来:
with torch.no_grad():
for data, target in test_loader:
output = model(data)
pred = output.argmax(dim=1)
n_correct_priv += pred.eq(target.view_as(pred)).sum()
n_total += 64
n_correct =
n_correct_priv.copy().get().float_precision().long().item()
print(
"Test set: Accuracy: {}/{} ({:.0f}%)".format(
n_correct, n_total, 100.0 * n_correct / n_total
)
)
- 执行测试过程:
test(model, private_test_loader)
结果如下:
Test set: Accuracy: 63/64 (98%)
Test set: Accuracy: 123/128 (96%)
Test set: Accuracy: 185/192 (96%)
Test set: Accuracy: 248/256 (97%)
Test set: Accuracy: 310/320 (97%)
Test set: Accuracy: 373/384 (97%)
Test set: Accuracy: 433/448 (97%)
<snip>
Test set: Accuracy: 9668/9920 (97%)
Test set: Accuracy: 9727/9984 (97%)
Test set: Accuracy: 9742/10048 (97%)
它是如何工作的……
我们首先导入 torch 及其数据集,和一些相关库(步骤 1)。然后我们导入 pysyft 并将其挂载到 torch 上(步骤 2)。我们还为客户端和服务器创建虚拟环境,以模拟数据的真实隔离。在此步骤中,crypto_provider 作为一个可信的第三方,用于加密和解密。接着在 步骤 3 中,我们定义一个简单的神经网络,并在 步骤 4 中加载它的预训练权重。请注意,在 步骤 5 中,以及一般来说,每当使用 .share(...) 命令时,你应该将共享的对象视为已加密,并且只有在所有相关方的协助下才能解密。特别地,在 步骤 9 中,测试函数执行加密评估;模型的权重、数据输入、预测和用于评分的目标都是加密的。然而,为了验证模型是否正常工作,我们解密并显示其准确性。在 步骤 5 中,我们加密网络,确保只有在服务器和客户端协作时,才能解密网络。
在接下来的两个步骤中,我们为 MNIST 数据定义常规和私有加载器。常规加载器仅加载 MNIST 数据,而私有加载器加密常规加载器的输出。在 步骤 8 和 步骤 9 中,我们定义了一个 helper 函数来评估私有测试集。在该函数中,我们遍历私有数据,使用模型进行预测,解密结果,然后打印出来。最后,我们应用 步骤 8 和 步骤 9 中定义的函数,以确保模型在保护隐私的同时能够良好地执行。
测试神经网络的对抗鲁棒性
对神经网络进行对抗性攻击的研究揭示了它们对对抗性扰动的惊人敏感性。即使是最准确的神经网络,在没有防护的情况下,也已被证明容易受到单像素攻击和对人眼不可见的噪声干扰的影响。幸运的是,近期该领域的进展已提供了解决方案,帮助神经网络抵御各种对抗性攻击。其中一种解决方案是名为综合分析(ABS)的神经网络设计。该模型背后的主要思想是它是一个贝叶斯模型。模型不仅直接预测给定输入的标签,还利用变分自编码器(VAEs)学习类条件样本分布。更多信息请访问arxiv.org/abs/1805.09190。
在这个教程中,你将加载一个预训练的 ABS 网络用于 MNIST,并学习如何测试神经网络的对抗性鲁棒性。
正在准备中
以下教程已在 Python 3.6 中测试过。准备这个教程需要在pip中安装 Pytorch、Torchvision、SciPy、Foolbox 和 Matplotlib 包。命令如下:
pip install torch torchvision scipy foolbox==1.8 matplotlib
如何实现...
在接下来的步骤中,我们将加载一个预训练的 ABS 模型和一个传统的 CNN 模型用于 MNIST。我们将使用 Foolbox 攻击这两个模型,以查看它们在防御对抗性攻击方面的表现:
- 首先导入一个预训练的 ABS 模型:
from abs_models import models
from abs_models import utils
ABS_model = models.get_VAE(n_iter=50)
- 定义一个
convenience函数,使用模型预测一批 MNIST 图像:
import numpy as np
def predict_on_batch(model, batch, batch_size):
"""Predicts the digits of an MNIST batch."""
preds = []
labels = []
for i in range(batch_size):
point, label = utils.get_batch()
labels.append(label[0])
tensor_point = utils.n2t(point)
logits = model(tensor_point)[0]
logits = [x for x in logits]
pred = np.argmax(logits)
preds.append(int(pred))
return preds, labels
- 对一批数据进行预测:
batch = utils.get_batch()
preds, labels = predict_on_batch(ABS_model, batch, 5)
print(preds)
print(labels)
结果如下:
[4, 4, 9, 1, 8]
[4, 4, 9, 1, 8]
- 使用 Foolbox 包装模型,以启用对抗性测试:
import foolbox
if ABS_model.code_base == "tensorflow":
fmodel = foolbox.models.TensorFlowModel(
ABS_model.x_input, ABS_model.pre_softmax, (0.0, 1.0), channel_axis=3
)
elif ABS_model.code_base == "pytorch":
ABS_model.eval()
fmodel = foolbox.models.PyTorchModel(
ABS_model, bounds=(0.0, 1.0), num_classes=10, device=utils.dev()
)
- 从 Foolbox 导入攻击库并选择一个 MNIST 图像:
from foolbox import attacks
images, labels = utils.get_batch(bs=1)
- 选择攻击类型,在本例中为边界攻击:
attack = attacks.DeepFoolL2Attack(fmodel)
metric = foolbox.distances.MSE
criterion = foolbox.criteria.Misclassification()
- 使用 Matplotlib 显示原始图像及其标签:
from matplotlib import pyplot as plt
%matplotlib inline
plt.imshow(images[0, 0], cmap="gray")
plt.title("original image")
plt.axis("off")
plt.show()
生成的图像如下:
- 使用 Foolbox 查找对抗性实例:
gradient_estimator = foolbox.gradient_estimators.CoordinateWiseGradientEstimator(0.1)
fmodel = foolbox.models.ModelWithEstimatedGradients(fmodel, gradient_estimator)
adversary = foolbox.adversarial.Adversarial(
fmodel, criterion, images[0], labels[0], distance=metric
)
attack(adversary)
- 显示发现的对抗性样本:
plt.imshow(a.image[0], cmap="gray")
plt.title("adversarial image")
plt.axis("off")
plt.show()
print("Model prediction:", np.argmax(fmodel.predictions(adversary.image)))
生成的对抗性图像如下:
- 实例化一个在 MNIST 上训练的传统 CNN 模型:
from abs_models import models
traditional_model = models.get_CNN()
模型架构如下:
CNN(
(net): NN(
(conv_0): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
(bn_0): BatchNorm2d(20, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(nl_0): ELU(alpha=1.0)
(conv_1): Conv2d(20, 70, kernel_size=(4, 4), stride=(2, 2))
(bn_1): BatchNorm2d(70, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(nl_1): ELU(alpha=1.0)
(conv_2): Conv2d(70, 256, kernel_size=(3, 3), stride=(2, 2))
(bn_2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(nl_2): ELU(alpha=1.0)
(conv_3): Conv2d(256, 10, kernel_size=(5, 5), stride=(1, 1))
)
(model): NN(
(conv_0): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
(bn_0): BatchNorm2d(20, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(nl_0): ELU(alpha=1.0)
(conv_1): Conv2d(20, 70, kernel_size=(4, 4), stride=(2, 2))
(bn_1): BatchNorm2d(70, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(nl_1): ELU(alpha=1.0)
(conv_2): Conv2d(70, 256, kernel_size=(3, 3), stride=(2, 2))
(bn_2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(nl_2): ELU(alpha=1.0)
(conv_3): Conv2d(256, 10, kernel_size=(5, 5), stride=(1, 1))
)
)
- 执行合理性检查,确保模型按预期运行:
preds, labels = predict_on_batch(traditional_model, batch, 5)
print(preds)
print(labels)
输出结果如下:
[7, 9, 5, 3, 3]
[7, 9, 5, 3, 3]
- 使用 Foolbox 包装传统模型:
if traditional_model.code_base == "tensorflow":
fmodel_traditional = foolbox.models.TensorFlowModel(
traditional_model.x_input,
traditional_model.pre_softmax,
(0.0, 1.0),
channel_axis=3,
)
elif traditional_model.code_base == "pytorch":
traditional_model.eval()
fmodel_traditional = foolbox.models.PyTorchModel(
traditional_model, bounds=(0.0, 1.0), num_classes=10, device=u.dev()
)
- 攻击传统 CNN 模型:
fmodel_traditional = foolbox.models.ModelWithEstimatedGradients(fmodel_traditional, GE)
adversarial_traditional = foolbox.adversarial.Adversarial(
fmodel_traditional, criterion, images[0], labels[0], distance=metric
)
attack(adversarial_traditional)
- 显示发现的对抗性样本:
plt.imshow(adversarial_traditional.image[0], cmap="gray")
plt.title("adversarial image")
plt.axis("off")
plt.show()
print(
"Model prediction:",
np.argmax(fmodel_traditional.predictions(adversarial_traditional.image)),
)
生成的对抗性图像如下:
它是如何工作的...
我们首先导入一个预训练的 ABS 模型(步骤 1)。在步骤 2和步骤 3中,我们定义了一个convenience函数,用于预测一批 MNIST 图像并验证模型是否正常工作。接下来,我们使用 Foolbox 包装模型,为测试其对抗鲁棒性做准备(步骤 4)。请注意,Foolbox 可以通过相同的 API 攻击 TensorFlow 或 PyTorch 模型,一旦被包装。太棒了!在步骤 5中,我们选择了一张 MNIST 图像作为攻击的媒介。为了明确,这张图像会被调整和变形,直到结果能欺骗模型。在步骤 6中,我们选择了要实施的攻击类型。我们选择了边界攻击,这是一种基于决策的攻击,从一个大的对抗扰动开始,然后逐渐减小扰动,同时保持对抗性。这种攻击需要很少的超参数调整,因此无需替代模型或梯度计算。有关基于决策的攻击的更多信息,请参考arxiv.org/abs/1712.04248。
此外,请注意,这里使用的度量标准是均方误差(MSE),它用于衡量对抗样本与原始图像之间的接近程度。使用的标准是误分类,意味着一旦目标模型误分类了图像,搜索就会停止。替代标准可能包括置信度或特定类型的误分类。在步骤 7-9中,我们展示了原始图像以及从其生成的对抗样本。在接下来的两步中,我们实例化一个标准的 CNN 并验证它是否正常工作。在步骤 12-14中,我们在标准 CNN 上重复之前步骤中的攻击。通过查看结果,我们可以看出,该实验强烈表明,ABS 模型在对抗扰动方面比普通的 CNN 更具鲁棒性。
使用 TensorFlow Privacy 的差分隐私
TensorFlow Privacy (github.com/tensorflow/privacy) 是 TensorFlow 家族中的一个相对较新的成员。这个 Python 库包括用于训练具有差分隐私的机器学习模型的 TensorFlow 优化器的实现。一个经过差分隐私训练的模型,在从其数据集中删除任何单一训练实例时,不会发生非平凡的变化。差分隐私(近似值)使用epsilon和delta来量化,衡量模型对单个训练示例变化的敏感性。使用 Privacy 库的方法很简单,只需包装常见的优化器(例如 RMSprop、Adam 和 SGD)即可将它们转换为差分隐私版本。这个库还提供了方便的工具来衡量隐私保证、epsilon 和 delta。
在这个教程中,我们将展示如何使用 Keras 和 TensorFlow Privacy 实现并训练一个用于 MNIST 的差分隐私深度神经网络。
准备工作
本教程的准备工作包括安装 Keras 和 TensorFlow。相关命令如下:
pip install keras tensorflow
TensorFlow Privacy 的安装说明可以在 github.com/tensorflow/privacy 找到。
如何实现...
- 开始时定义几个便捷函数来预处理 MNIST 数据集:
import tensorflow as tf
def preprocess_observations(data):
"""Preprocesses MNIST images."""
data = np.array(data, dtype=np.float32) / 255
data = data.reshape(data.shape[0], 28, 28, 1)
return data
def preprocess_labels(labels):
"""Preprocess MNIST labels."""
labels = np.array(labels, dtype=np.int32)
labels = tf.keras.utils.to_categorical(labels, num_classes=10)
- 编写一个便捷函数来加载 MNIST 数据集:
def load_mnist():
"""Loads the MNIST dataset."""
(X_train, y_train), (X_test, y_test) = tf.keras.datasets.mnist.load_data()
X_train = preprocess_observations(X_train)
X_test = preprocess_observations(X_test)
y_train = preprocess_labels(y_train)
y_test = preprocess_labels(y_test)
return X_train, y_train, X_test, y_test
- 加载 MNIST 数据集:
import numpy as np
X_train, y_train, X_test, y_test = load_mnist()
训练集大小为 60k,测试集大小为 10k。
- 导入差分隐私优化器并定义几个控制学习率和差分隐私程度的参数:
from privacy.optimizers.dp_optimizer import DPGradientDescentGaussianOptimizer
optimizer = DPGradientDescentGaussianOptimizer(
l2_norm_clip=1.0, noise_multiplier=1.1, num_microbatches=250, learning_rate=0.15
)
loss = tf.keras.losses.CategoricalCrossentropy(
from_logits=True, reduction=tf.losses.Reduction.NONE
)
- 为了衡量隐私性,定义一个函数来计算 epsilon:
from privacy.analysis.rdp_accountant import compute_rdp
from privacy.analysis.rdp_accountant import get_privacy_spent
def compute_epsilon(steps):
"""Compute the privacy epsilon."""
orders = [1 + x / 10.0 for x in range(1, 100)] + list(range(12, 64))
sampling_probability = 250 / 60000
rdp = compute_rdp(
q=sampling_probability, noise_multiplier=1.1, steps=steps, orders=orders
)
return get_privacy_spent(orders, rdp, target_delta=1e-5)[0]
- 为 MNIST 定义一个标准的 Keras CNN:
NN_model = tf.keras.Sequential(
[
tf.keras.layers.Conv2D(
16, 8, strides=2, padding="same", activation="relu", input_shape=(28, 28, 1)
),
tf.keras.layers.MaxPool2D(2, 1),
tf.keras.layers.Conv2D(32, 4, strides=2, padding="valid", activation="relu"),
tf.keras.layers.MaxPool2D(2, 1),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(32, activation="relu"),
tf.keras.layers.Dense(10),
]
)
- 编译
model:
NN_model.compile(optimizer=optimizer, loss=loss, metrics=["accuracy"])
- 拟合并测试
model:
NN_model.fit(
X_train, y_train, epochs=1, validation_data=(X_test, y_test), batch_size=250
)
- 计算
epsilon值,即隐私性的度量:
eps = compute_epsilon(1 * 60000 // 250)
它是如何工作的...
我们从 步骤 1-3 开始,准备并加载 MNIST 数据集。接下来,在 步骤 4 中,我们导入 DPGradientDescentGaussianOptimizer,这是一种优化器,使模型具备差分隐私。此阶段使用了多个参数,并且这些参数有待进一步解释。l2_norm_clip 参数表示在每个小批量数据点的训练过程中,每个梯度的最大范数。该参数限制了优化器对单个训练点的敏感度,从而使模型朝着差分隐私的方向发展。noise_multiplier 参数控制向梯度中添加的随机噪声量。通常,噪声越多,隐私性越强。完成此步骤后,在 步骤 5 中,我们定义一个计算差分隐私的 epsilon-delta 定义的 epsilon 值的函数。我们在 步骤 6 中实例化一个标准的 Keras 神经网络,步骤 7 中编译它,然后使用差分隐私优化器在 MNIST 上训练它 (步骤 8)。最后,在 步骤 9 中,我们计算 epsilon 的值,该值衡量模型的差分隐私程度。本教程的典型 epsilon 值大约为 1。
附录
在本章中,我们为读者提供了一份创建基础设施的指南,以应对机器学习在网络安全数据中的挑战。特别是,我们提供了设置虚拟实验室环境的操作步骤,以便进行安全有效的恶意软件分析。我们还提供了使用虚拟 Python 环境的指南,允许用户在避免包冲突的同时无缝地进行不同的 Python 项目工作。
本章将介绍以下操作:
-
设置虚拟实验室环境
-
使用 Python 虚拟环境
设置虚拟实验室环境
为了保护自己和网络,在处理和分析恶意软件时采取预防措施是至关重要的。最好的方法之一是设置一个隔离的虚拟实验室环境。虚拟实验室环境由一个或多个虚拟机(VM)组成,并且在一个隔离的网络中。隔离网络可以防止恶意软件通过网络传播,虽然这会牺牲一些更真实的恶意软件行为。
准备工作
为了准备这个操作,请执行以下步骤:
- 安装虚拟机监控程序。
虚拟机监控程序是允许你控制虚拟机的软件。一个实例是 VirtualBox,可以免费下载,www.virtualbox.org/:
- 下载虚拟镜像。
虚拟镜像是虚拟机的模板。可以在developer.microsoft.com/en-us/microsoft-edge/tools/vms/找到多个 Windows 虚拟镜像:
如何操作...
以下步骤将指导你设置和使用一个简单的虚拟实验室环境:
- 使用虚拟镜像创建虚拟机。
打开虚拟机镜像时,你的屏幕应该看起来像这样:
- 配置虚拟机的性能和安全性。例如,你可以将其完全从网络中断开。
以下截图展示了如何将虚拟机从网络中断开:
- 创建一个快照。
你可以在这里查看哪个菜单选项允许你创建快照:
- (可选)在虚拟机中引爆并分析恶意软件。
例如,我在我的虚拟机中运行了勒索软件,如下所示:
- (可选)将虚拟机恢复到之前的快照。
按下恢复按钮,如下所示:
工作原理...
我们通过创建一个虚拟机(步骤 1)开始了本章节的操作。虚拟机的创建取决于提供镜像的格式。对于引用的虚拟镜像,双击 .ovf 文件即可设置虚拟机。有时,你可能需要创建一个全新的操作系统安装,并挂载虚拟镜像。接下来,在步骤 2中,我们为恶意软件分析配置了虚拟机。有几个配置更改你可能需要进行。这些包括设置基础内存、处理器数量、视频内存和虚拟光驱;选择合适的网络设置;以及创建共享文件夹。
完成此操作后,在步骤 3中,我们保存了一个快照,允许我们保存所有重要的状态信息。快照的一个优点是,它们使用户能够轻松地回滚对虚拟机所做的更改。因此,如果你犯了错误,没关系——只需恢复到先前的快照即可。接下来,在步骤 4中,我们在虚拟机中引爆了恶意软件。我们建议在此步骤中要小心,并且仅在你知道自己在做什么的情况下进行操作。在这种情况下,你将在本书的仓库中找到一份恶意软件数据集。最后,在步骤 5中,我们点击了 VirtualBox 中的恢复按钮,将虚拟机恢复到创建快照时的状态。
最后,我们向 Yasser Ali 表示感谢,他提供了以下建议:在 macOS 上安装 VirtualBox 时,用户应该为 Adobe 软件设置安全例外,以使用安全设置。
使用 Python 虚拟环境
假设你有两个项目——项目 A 和项目 B——它们的 Python 库需求相互冲突。例如,项目 A 需要 scikit-learn 版本 0.21,而项目 B 需要 scikit-learn 版本 >0.22。或者,也许一个项目需要 Python 3.6,而另一个项目需要 Python 3.7。你可以在从一个项目切换到另一个项目时卸载并重新安装相应的库或 Python 版本,但这样做既繁琐又不现实。为了解决依赖冲突问题,我们推荐使用 Python 虚拟环境。在本章节中,你将看到如何使用 Python 虚拟环境。
准备就绪
虚拟环境模块 venv 包含在 Python 3.3 及更高版本的标准库中。
如何操作...
创建并激活虚拟 Python 环境,请按照以下步骤操作:
- 在终端中,运行以下命令:
python -m venv "name-of-your-environment"
- 在 Linux 或 macOS 终端中,运行以下命令:
source "name-of-your-environment"/bin/activate
在 Windows 上,运行此命令:
"name-of-your-environment"/Scripts/activate.bat
- 安装所需的包。
工作原理...
我们从第一步开始,创建了一个虚拟的 Python 环境。-m标志表示要使用的模块,在这个例子中是venv。接下来,在第二步中,我们激活了我们的 Python 环境,这样我们就可以使用它并进行更改。请注意,Python 环境的文件夹结构在 Windows 上与 Linux 或 Mac 上有所不同。一个标志,表明该环境当前是激活状态的,是在终端中看到环境的名称,如下所示:
("name-of-your-environment")
在第三步中,您可以像往常一样安装包,如下面这个例子:
pip install numpy
并且放心,这不会影响您在该环境外的包。太棒了!