在这篇文章中,我们将演示python-paillier 库的用法和灵活性,作为更安全的机器学习的工具。特别是

640_wx_fmt_jpeg

在这篇文章中,我们将演示python-paillier 库的用法和灵活性,作为更安全的机器学习的工具。特别是,我们将为联合机器学习建立一个简单的安全协议,这是受最近Google在这个主题上的工作的启发。 分布式机器学习和部分同态加密-part1 在这篇文章中,我们将演示python-paillier 库的用法和灵活性,作为更安全的机器学习的工具。我们将假设一些关于Paillier部分同态加密和线性回归的基本知识。 特别是,我们将为联合机器学习建立一个简单的安全协议,这是受最近Google在这个主题上的工作的启发。 API简介

让我们从API的快速演示开始。首先,让我们通过使用足够长的密钥长度来创建公钥和私钥,以获得适当的加密保证:

import phe as paillier

pubkey, privkey = paillier.generate_paillier_keypair(n_length=1024)

 

Paillier是一种非对称密码(如RSA),其中公钥用于加密,私钥用于解密。

secret_numbers = [3.141592653, 300, -4.6e-12]

encrypted_numbers = [pubkey.encrypt(x) for x in secret_numbers]

 »> [privkey.decrypt(x) for x in encrypted_numbers] [3.141592653, 300, -4.6e-12]

 

但这些加密数字是什么样的呢?您可以打开对象并查看内部的整数表示形式。

print(encrypted_numbers[0])

print(encrypted_numbers[0].ciphertext()) 5072752399058920189730182586811912902463474480667712432717959774819587074489325225214240998778150373197112637448816662931016970373407389034275190558182343858721113940870709409924017166597407543355101815707936636905640749963575027963216011646497564724153729103147138747511854121934327406877629294760278241554316409859573065893681767802219202771728963191523152254974808451269262932426358339707361034738737940843867971577772899191177890333880357061518134745146513228505813785268901991647262058355794072849790632418679961213162239495600291127208408082882305219363330327154890172539087918477378211986323886814727480557038

 

Paillier加密是在加密空间中保留简单算术运算的绝佳工具。我们可以将两个加密数字相加并解密结果,这将等于原始数字的总和。

x, y = 2, 0.5 

encrypted_x = pubkey.encrypt(x)

encrypted_y = pubkey.encrypt(y)

encrypted_sum = encrypted_x + encrypted_y

 »> privkey.decrypt(encrypted_sum) 2.5

以同样的方式,加密数字乘以明确的数字。

z = 10 

privkey.decrypt(z * encrypted_x) 20

请注意,我们不能将两个加密数字相乘。这是Paillier密码系统的极限,与完全同态相比,Paillier密码系统是部分同态加密方案。尽管存在这种限制,但通过这两个允许的操作,我们已经可以在一个有趣的空间中进行游戏,其中线性代数的子集可用于实现机器学习原语。

 

安全的联合学习 在这个例子中,我们假设我们有442名医院患者的敏感数据,糖尿病的进展程度不同。记录的变量是年龄,性别,体重指数,平均血压和六次血清测量。最后一个变量是疾病进展的定量度量,我们希望从之前的变量中预测。由于此度量是连续的,我们将通过执行线性回归来解决问题。原始数据在此处托管 ,我们通过sklearn访问它。 数据分布在3家医院中,称为“客户”。目标是利用整个(虚拟)训练集来改进可以在本地训练的模型。这种情况通常被称为“水平分区”。50个患者记录将作为测试集保留,不用于培训。另一个代理是“服务器”,它将在以下限制条件下促进医院之间的信息交换。由于隐私政策:

1. 每个医院的患者记录数据都不能离开其场所,甚至不能以加密形式离开

2. 即使来自任何单个客户的数据集的信息/摘要(读取:梯度)也不能离开医院,除非它首先被加密。

3. 任何一方(客户和服务器)都不能够推断训练集中的患者在哪里受过治疗(在哪家医院)。

我们去看看代码。我们将使用numpy并sklearn为此。随机数发生器被明确地播种以实现实验的再现性。

import numpy as np

from sklearn.datasets import load_diabetes

import phe as paillier

seed = 42 np.random.seed(seed)

让我们先准备好数据,然后全部包装成一个函数。

def get_data(n_clients): 

diabetes = load_diabetes()

 y = diabetes.target

X = diabetes.data

# Add constant to emulate intercept 

X = np.c_[X, np.ones(X.shape[0])]

# The features are already preprocessed 

# Shuffle 

perm = np.random.permutation(X.shape[0])

X, y = X[perm, :], y[perm]

# Select test at random 

test_size = 50 

test_idx = np.random.choice(X.shape[0], size=test_size, replace=False) 

train_idx = np.ones(X.shape[0], dtype=bool) 

train_idx[test_idx] = False

X_test, y_test = X[test_idx, :], y[test_idx]

X_train, y_train = X[train_idx, :], y[train_idx]

# Split train among multiple clients. 

# The selection is not at random. We simulate the fact that each client 

# sees a potentially very different sample of patients. 

X, y = [], []

step = int(X_train.shape[0] / n_clients)

for c in range(n_clients):

X.append(X_train[step * c: step * (c + 1), :])

 y.append(y_train[step * c: step * (c + 1)])

return X, y, X_test, y_test

从学习的角度来看,注意到我们并不是假设每一家医院都从同一病人的分布中看到一个不偏不倚的样本:医院可能在地理上非常遥远,也可能为不同的人群服务。我们用不均匀的随机抽样来模拟这种情况,而是以一种偏颇的方式进行抽样。相反,测试集是来自整个分布的无偏见样本。

我们还在列表上定义了一些加密/解密操作。

def encrypt_vector(pubkey, x): 

return [pubkey.encrypt(x[i]) for i in range(x.shape[0])]

 def decrypt_vector(privkey, x): 

return np.array([privkey.decrypt(i) for i in x]) d

ef sum_encrypted_vectors(x, y): 

if len(x) != len(y): raise Exception('Encrypted vectors must have the same size')

return [x[i] + y[i]  for i in range(len(x))]

为了评估模型,我们将计算地面实况和预测标签之间的均方误差。

def mean_square_error(y_pred, y): 

return np.mean((y - y_pred) ** 2)

我们通过梯度下降进行线性回归。服务器拥有私钥,客户端拥有公钥。该协议的工作原理如下。收敛之前:1。医院1计算其梯度,加密并将其发送到医院2; 医院2计算其梯度,加密并将其总和到医院1; 3.医院3也做同样的事情并将总和传递给服务器。4.服务器获得整个(虚拟)训练集的梯度; 它解密它并将其以明文形式发送回每个客户端,每个客户端都可以更新相应的本地模型。我们假设此聚合梯度未公开任何有关个人数据的敏感信息 - 否则[差异隐私](https://en.wikipedia.org/wiki/Differential_privacy)可用于我们的协议之上。

class Server:

 “““Hold the private key. Decrypt the average gradient”““ 

def __init__(self, key_length=1024): 

self.pubkey, self.privkey = \

paillier.generate_paillier_keypair(n_length=key_length)

def decrypt_aggregate(self, input_model, n_clients): 

Return

 decrypt_vector(self.privkey, input_model) / n_clients

class Client:

 “““Run linear regression either with local data or by gradient steps,

where gradients can be send from remotely.

Hold the private key and can encrypt gradients to send remotely.

“““ 

def __init__(self, name, X, y, pubkey):

 self.name = name

self.pubkey = pubkey

self.X, self.y = X, y

self.weights = np.zeros(X.shape[1])

def fit(self, n_iter, eta=0.01): 

“““Linear regression for n_iter”““ 

for _ in range(n_iter):

gradient = self.compute_gradient()

self.gradient_step(gradient, eta)

def gradient_step(self, gradient, eta=0.01):

 “““Update the model with the given gradient”“”

 self.weights -= eta * gradient

def compute_gradient(self):

 “““Return the gradient computed at the current model on all training

 set”““ 

delta = self.predict(self.X) - self.y

return delta.dot(self.X)

def predict(self, X):

 “““Score test data”““ 

return X.dot(self.weights)

def encrypted_gradient(self, sum_to=None):

 “““Compute gradient. Encrypt it.

When `sum_to` is given, sum the encrypted gradient to it, assumed

to be another vector of the same size

 “““ 

gradient = encrypt_vector(self.pubkey, self.compute_gradient())

if sum_to is not None:

if len(sum_to) != len(gradient):

raise Exception('Encrypted vectors must have the same size')

return sum_encrypted_vectors(sum_to, gradient)

else:

return gradient

现在我们拥有了所有必要的框架。让我们设置一堆参数并准备好数据。

n_iter, eta = 50, 0.01 

names = ['Hospital 1', 'Hospital 2', 'Hospital 3']

n_clients = len(names)

X, y, X_test, y_test = get_data(n_clients=n_clients)

我们实例化服务器和客户端。每个客户端在创建时获取公钥以及其自己的本地数据集。

server = Server(key_length=1024)

clients = []

for i in range(n_clients):

clients.append(Client(names[i], X[i], y[i], server.pubkey))

每个客户端都根据自己的数据训练线性回归量。每个客户端仅通过自己的本地数据进行培训,可以获得测试集的错误(MSE)是多少?

for c in clients: 

c.fit(n_iter, eta)

y_pred = c.predict(X_test)

print('{:s}:\t{:.2f}'.format(c.name, mean_square_error(y_pred, y_test)))

Hospital 1: 3933.78

Hospital 2: 4176.48 

Hospital 3: 3795.95

最后,联合学习与梯度下降。

for i in range(n_iter):

# Compute gradients, encrypt and aggregate »> encrypt_aggr = clients[0].encrypted_gradient(sum_to=None)

for i in range(1, n_clients):

encrypt_aggr = clients[i].encrypted_gradient(sum_to=encrypt_aggr)

 »>

# Send aggregate to server and decrypt it 

aggr = server.decrypt_aggregate(encrypt_aggr, n_clients)

# Take gradient steps 

for c in clients:

c.gradient_step(aggr, eta)

运行协议后每个客户端获得的错误(MSE)是多少?

for c in clients: 

y_pred = c.predict(X_test)

print('{:s}:\t{:.2f}'.format(c.name, mean_square_error(y_pred, y_test)))

Hospital 1: 3695.77 

Hospital 2: 3855.14

Hospital 3: 3598.63

正如预期的那样,每个客户的MSE都在减少。(它们并不相同,因为客户端的初始模型是不同的,即本地数据的最佳模型。)

从安全角度来看,我们认为所有各方都“诚实但好奇”。即使通过明确看到聚合梯度,参与者也无法确定患者数据的来源。如果此RING协议由至少3个客户端运行,则这是正确的,这样可以简单地通过差异来防止重建彼此的梯度。

 

 

 

 

你可能还会喜欢:

什么是后量子密码学?

区块链杂谈节目荟萃

全同态加密算法深入解析-1

全同态加密算法深入解析-2

区块链在国家安全领域的应用

量子计算真的那么牛么?(一)

量子计算真的那么牛么?(二)

比特币网络动量——比特币价格在主要市场周期中的一个新的领先指标

你需要区块链吗?——各种有趣的判断模型

什么是量子密码学

金钱的本质是什么——为什么比特币不能解决根本问题

加密货币的熊市案例

革命与进化:全同态加密

欢迎收听“区块链杂谈”节目,国内最有质量的区块链知识分享节目。

640_wx_fmt_jpeg 1

宁波格密链网络科技有限公司,专注于区块链上的密码技术研发。

640_wx_fmt_png

1533292188682485.jpg

格密链专注于区块链上的密码学技术长按扫码可关注