# 访问控制简介
现在,我们可以开始使用 CrypTen 在一些常见用例中进行私有计算。在本教程中,我们将演示 CrypTen 如何应用于导言中描述的场景。在所有场景中,我们将使用简单的双方设置,并演示如何学习线性 SVM。在此过程中,我们将了解 CrypTen 如何进行访问控制。
像往常一样,我们将首先导入 `crypten` 和 `torch` 库,并使用 `crypten.init()` 初始化 `crypten`。
import crypten
import torch
crypten.init()
torch.set_num_threads(1)
###设置
在本教程中,我们将训练线性SVM来执行二进制分类。我们将首先使用100个特征和随机生成的超平面来生成1000个地面实况样本,以分离正示例和负示例。
(注意:这将导致我们的类是线性可分离的,因此在给定正确参数的情况下,线性SVM将能够以完美的精度进行分类。)
我们还将包括一组测试示例(这些示例也可由同一超平面线性分离),以表明模型学习一般超平面,而不是记忆训练数据。
import crypten
import torch
crypten.init()
torch.set_num_threads(1)
num_features = 100
num_train_examples = 1000
num_test_examples = 100
epochs = 40
lr = 3.0
# Set random seed for reproducibility
torch.manual_seed(1) #生成随机数生成所需要的种子,保证每次生成的随机数一样
features = torch.randn(num_features, num_train_examples)
w_true = torch.randn(1, num_features)
b_true = torch.randn(1)
labels = w_true.matmul(features).add(b_true).sign() #sign()返回符号,matmul是乘法
test_features = torch.randn(num_features, num_test_examples)
test_labels = w_true.matmul(test_features).add(b_true).sign()
现在我们已经生成了数据集,我们将在四种不同的访问控制场景中对 SVM 进行训练,这些场景涉及 Alice 和 Bob 两方:
- 数据标签: Alice 可以访问特征,而 Bob 可以访问标签
- 特征聚合: Alice 可以访问前 50 个特征,而 Bob 可以访问后 50 个特征
- 数据扩充: 爱丽丝可以访问前 500 个示例,而鲍勃可以访问后 500 个示例
- 模型隐藏: Alice 可以访问 `w_true` 和 `b_true`,而 Bob 可以访问待分类的数据样本
在本教程中,我们将假设 Alice 使用秩 0 进程,而 Bob 使用秩 1 进程。此外,我们将使用随机值初始化权重。
ALICE = 0
BOB = 1
在每个示例中,一旦特征和标签被正确加密,我们将使用相同的代码来训练线性 SVM。这些代码包含在 "examples/mPC_linear_svm "中,但要正确使用访问控制,不需要理解训练代码。训练过程本身将在后面的教程中深入讨论。
from examples.mpc_linear_svm.mpc_linear_svm import train_linear_svm, evaluate_linear_svm
## 保存/加载数据
现在,我们已经生成了供模型学习的特征和标签。在本教程探讨的场景中,我们希望确保每一方只能访问我们生成的数据的某些子集。为此,我们将使用 CrypTen 提供的特殊保存/加载方法来处理只加载给指定方和跨进程同步的问题。
我们将在这里使用 `crypten.save_from_party()`保存来自特定来源的数据,然后在每个示例中使用 `crypten.load_from_party()`加载特定来源的数据。下面的代码将把我们要使用的所有数据保存到文件中,然后每个示例将根据需要加载其数据。
(请注意,由于我们是在一台机器上运行,所有进程都可以访问我们使用的所有文件。不过,在跨机器运行时,这仍然可以正常工作)。
from crypten import mpc
# Specify file locations to save each piece of data
filenames = {
"features": "/tmp/features.pth",
"labels": "/tmp/labels.pth",
"features_alice": "/tmp/features_alice.pth",
"features_bob": "/tmp/features_bob.pth",
"samples_alice": "/tmp/samples_alice.pth",
"samples_bob": "/tmp/samples_bob.pth",
"w_true": "/tmp/w_true.pth",
"b_true": "/tmp/b_true.pth",
"test_features": "/tmp/test_features.pth",
"test_labels": "/tmp/test_labels.pth",
}
@mpc.run_multiprocess(world_size=2)
def save_all_data():
# Save features, labels for Data Labeling example
crypten.save(features, filenames["features"])
crypten.save(labels, filenames["labels"])
# Save split features for Feature Aggregation example
features_alice = features[:50]
features_bob = features[50:]
crypten.save_from_party(features_alice, filenames["features_alice"], src=ALICE)
crypten.save_from_party(features_bob, filenames["features_bob"], src=BOB)
# Save split dataset for Dataset Aggregation example
samples_alice = features[:, :500]
samples_bob = features[:, 500:]
crypten.save_from_party(samples_alice, filenames["samples_alice"], src=ALICE)
crypten.save_from_party(samples_bob, filenames["samples_bob"], src=BOB)
# Save true model weights and biases for Model Hiding example
crypten.save_from_party(w_true, filenames["w_true"], src=ALICE)
crypten.save_from_party(b_true, filenames["b_true"], src=ALICE)
crypten.save_from_party(test_features, filenames["test_features"], src=BOB)
crypten.save_from_party(test_labels, filenames["test_labels"], src=BOB)
save_all_data()
示例 1:数据标签方案
我们的第一个示例将侧重于数据标签方案。在这个示例中,Alice 可以访问特征,而 Bob 可以访问标签。我们将通过加密 Alice 的特征和 Bob 的标签来训练线性 SVM,然后使用加密数据的聚合来训练 SVM。
为了指明给定加密张量的来源,我们使用 `crypten.load()`(从文件)或 `crypten.cryptensor()`(从张量)加密张量,并使用关键字参数 `src`。这个 `src` 参数取我们要加密的一方的等级(请记住,ALICE 是 0,BOB 是 1)。
(如果未指定 `src`,则默认为等级为 0 的一方。在加密公共值时,我们将使用默认值,因为在这种情况下来源并不重要)。
from crypten import mpc
#ning:注意要把examples/mpc_linear_svm/mpc_linear_svm.py粘贴到和当前.py同一目录下,并加上下面两句
from mpc_linear_svm import train_linear_svm
from mpc_linear_svm import evaluate_linear_svm
@mpc.run_multiprocess(world_size=2)
def data_labeling_example():
"""Apply data labeling access control model"""
# Alice loads features, Bob loads labels
features_enc = crypten.load_from_party(filenames["features"], src=ALICE)
labels_enc = crypten.load_from_party(filenames["labels"], src=BOB)
# Execute training
w, b = train_linear_svm(features_enc, labels_enc, epochs=epochs, lr=lr)
# Evaluate model
evaluate_linear_svm(test_features, test_labels, w, b)
data_labeling_example()
WARNING:root:module 'torchvision.models.mobilenet' has no attribute 'ConvBNReLU'
Epoch 0 --- Training Accuracy 53.40%
Epoch 1 --- Training Accuracy 58.70%
Epoch 2 --- Training Accuracy 63.80%
Epoch 3 --- Training Accuracy 68.30%
Epoch 4 --- Training Accuracy 73.60%
Epoch 5 --- Training Accuracy 78.00%
Epoch 6 --- Training Accuracy 81.00%
Epoch 7 --- Training Accuracy 84.60%
Epoch 8 --- Training Accuracy 87.00%
Epoch 9 --- Training Accuracy 90.40%
Epoch 10 --- Training Accuracy 91.50%
Epoch 11 --- Training Accuracy 92.90%
Epoch 12 --- Training Accuracy 93.80%
Epoch 13 --- Training Accuracy 94.30%
Epoch 14 --- Training Accuracy 95.50%
Epoch 15 --- Training Accuracy 95.80%
Epoch 16 --- Training Accuracy 96.30%
Epoch 17 --- Training Accuracy 96.60%
Epoch 18 --- Training Accuracy 96.70%
Epoch 19 --- Training Accuracy 97.40%
Epoch 20 --- Training Accuracy 98.30%
Epoch 21 --- Training Accuracy 98.00%
Epoch 22 --- Training Accuracy 98.10%
Epoch 23 --- Training Accuracy 98.00%
Epoch 24 --- Training Accuracy 98.70%
...
Epoch 37 --- Training Accuracy 100.00%
Epoch 38 --- Training Accuracy 100.00%
Epoch 39 --- Training Accuracy 100.00%
Test accuracy 92.00%
##场景2:功能聚合
接下来,我们将展示如何在<i>特征聚合</i>场景中使用CrypTen。这里,Alice和Bob每个样本都有50个特征,并希望使用它们的组合特征来训练模型。和以前一样,Alice和Bob希望将各自的数据保密。当多方测量类似系统的不同特征时,可能会出现这种情况,并且他们的测量可能是专有的或敏感的。
与上一种情况不同的是,我们的一个变量在两党之间分裂。这意味着我们必须将各方加密的张量连接起来,然后再将其传递给训练代码。
@mpc.run_multiprocess(world_size=2)
def feature_aggregation_example():
"""Apply feature aggregation access control model"""
# Alice loads some features, Bob loads other features
features_alice_enc = crypten.load_from_party(filenames["features_alice"], src=ALICE)
features_bob_enc = crypten.load_from_party(filenames["features_bob"], src=BOB)
# Concatenate features
features_enc = crypten.cat([features_alice_enc, features_bob_enc], dim=0)
# Encrypt labels
labels_enc = crypten.cryptensor(labels)
# Execute training
w, b = train_linear_svm(features_enc, labels_enc, epochs=epochs, lr=lr)
# Evaluate model
evaluate_linear_svm(test_features, test_labels, w, b)
feature_aggregation_example()
Epoch 0 --- Training Accuracy 53.40%
Epoch 1 --- Training Accuracy 58.70%
Epoch 2 --- Training Accuracy 63.80%
Epoch 3 --- Training Accuracy 68.30%
Epoch 4 --- Training Accuracy 73.60%
Epoch 5 --- Training Accuracy 78.00%
Epoch 6 --- Training Accuracy 81.00%
Epoch 7 --- Training Accuracy 84.60%
Epoch 8 --- Training Accuracy 87.00%
Epoch 9 --- Training Accuracy 90.40%
Epoch 10 --- Training Accuracy 91.50%
Epoch 11 --- Training Accuracy 92.90%
Epoch 12 --- Training Accuracy 93.80%
Epoch 13 --- Training Accuracy 94.40%
Epoch 14 --- Training Accuracy 95.30%
Epoch 15 --- Training Accuracy 96.30%
Epoch 16 --- Training Accuracy 96.20%
Epoch 17 --- Training Accuracy 96.80%
Epoch 18 --- Training Accuracy 96.80%
Epoch 19 --- Training Accuracy 97.20%
Epoch 20 --- Training Accuracy 97.90%
Epoch 21 --- Training Accuracy 97.80%
Epoch 22 --- Training Accuracy 98.00%
Epoch 23 --- Training Accuracy 98.90%
Epoch 24 --- Training Accuracy 99.20%
...
Epoch 37 --- Training Accuracy 100.00%
Epoch 38 --- Training Accuracy 100.00%
Epoch 39 --- Training Accuracy 100.00%
Test accuracy 92.00%
##场景3:数据集扩充
下一个例子展示了我们如何在<i>数据增强</i>场景中使用CrypTen。这里,Alice和Bob各有500个样本,他们想在组合的样本数据上学习分类器。这种情况可能发生在这样的应用程序中,即多个方面可能各自都可以访问少量敏感数据,而没有一个方面有足够的数据来训练准确的模型。
与上一种情况一样,我们的一个变量在各方之间分配,因此我们必须连接来自不同各方的加密张量。与上一个场景的主要区别在于,我们连接在另一个维度(样本维度而不是特征维度)上。
@mpc.run_multiprocess(world_size=2)
def dataset_augmentation_example():
"""Apply dataset augmentation access control model"""
# Alice loads some samples, Bob loads other samples
samples_alice_enc = crypten.load_from_party(filenames["samples_alice"], src=ALICE)
samples_bob_enc = crypten.load_from_party(filenames["samples_bob"], src=BOB)
# Concatenate features
samples_enc = crypten.cat([samples_alice_enc, samples_bob_enc], dim=1)
labels_enc = crypten.cryptensor(labels)
# Execute training
w, b = train_linear_svm(samples_enc, labels_enc, epochs=epochs, lr=lr)
# Evaluate model
evaluate_linear_svm(test_features, test_labels, w, b)
dataset_augmentation_example()
##场景4:模型隐藏
我们将探讨的最后一个场景涉及<i>模型隐藏</i>。在这里,Alice有一个预训练的模型,它不能被揭示,而Bob希望使用这个模型来评估私有数据样本。当预先训练的模型是专有的或包含敏感信息,但可以为具有敏感数据的其他方提供价值时,就会出现这种情况。
这个场景与前面的例子有些不同,因为我们对训练模型不感兴趣。因此,我们不需要标签。相反,我们将通过加密来自Alice的真实模型参数(“w_true”和“b_true”)和加密来自Bob的测试集来演示此示例以进行评估。
(注意:因为我们使用的是用于生成测试标签的真实权重和偏差,所以我们将获得100%的准确性。)
@mpc.run_multiprocess(world_size=2)
def model_hiding_example():
"""Apply model hiding access control model"""
# Alice loads the model
w_true_enc = crypten.load_from_party(filenames["w_true"], src=ALICE)
b_true_enc = crypten.load_from_party(filenames["b_true"], src=ALICE)
# Bob loads the features to be evaluated
test_features_enc = crypten.load_from_party(filenames["test_features"], src=BOB)
# Evaluate model
evaluate_linear_svm(test_features_enc, test_labels, w_true_enc, b_true_enc)
model_hiding_example()
在本教程中,我们回顾了CrypTen可以用于执行加密训练/推理的四种技术。这些技术中的每一种都可以用于促进不同隐私保护场景中的计算。然而,这些技术也可以结合起来,以增加CrypTen可以维护隐私的场景数量。
例如,我们可以将特征聚合和数据标记相结合,以训练三方之间的数据分割模型,其中两方各有权访问特征子集,第三方有权访问标签。
在退出本教程之前,请清理使用以下代码生成的文件。