编者按:保护隐私和保障安全的冲突,在多大程度上仅仅是一个技术限制?让我们和DeepMind数据科学家、Udacity深度学习导师Andrew Trask一起,基于Paillier加密算法和词袋逻辑回归实现犯罪检测。
TLDR:监控是否能够只侵犯犯罪嫌疑人和恐怖分子的隐私,避免殃及无辜?本文用Python实现了一个原型。
摘要:现代的犯罪嫌疑人和恐怖分子藏身于无辜居民的模式之中,精确地镜像无辜居民的日常生活,直到变得致命的最后一刻,比如一辆冲上人行道的汽车,或大街上掏出刀子的人。由于即时发生的致命事件不可能通过警力干预,执法部门转而利用监控检测犯罪事件,立法上的努力加速了这一转向,例如爱国者法案、美国自由法案和英国的反恐法案。这些立法引起了激烈的争议。在本文中,我们将探索隐私和安全的折衷在多大程度上仅仅是一个技术限制,一个可以通过同态加密和深度学习克服的技术限制。我们同时给出了一个原型实现,并讨论了哪里可以追加技术投入,使这一技术更成熟。我很乐观,觉得未来的犯罪检测工具会比今天的更强大,在提供更高效的监控的同时,保护居民隐私。潜在的滥用可以通过加密人工智能这样的现代技术缓解。
当我写完新文章后,我通常会发推说一下。如果你对我的文章感兴趣,欢迎关注 @iamtrask,也欢迎向我反馈。
如果你对训练加密神经网络感兴趣,可以看看OpenMined的PySyft库。
国际机场常常使用缉毒犬检测毒品。如果没有缉毒犬,检测乘客是否携带毒品需要打开每个箱包,检查其中的物品,这是一个昂贵、费时、侵犯隐私的过程。然而,有了缉毒犬,需要搜查的箱包仅仅是那些确实包含毒品的箱包(在缉毒犬看来)。缉毒犬的应用同时增加了隐私和效率。
图片来源:vivapets.com
类似地,电子烟雾报警器和防盗报警器的应用取代了更低效、更侵犯隐私的昂贵系统:24x7站在房门口的保安或防火员。
这两个场景几乎不存在隐私和安全的折衷。这是监控的理想状态。监控是有效的,而隐私得到了保护:
仅当很可能发现危险/犯罪活动时才侵犯隐私。
设备是精确的,假阳性率低。
可以访问设备的人(陪同缉毒犬的警员和房产业主)并不试图愚弄这些设备。因此,这些设备的工作机制可以公开,其对隐私的保护可以被大家知晓,并接受审计。
隐私保护、精确性、可审计性的结合是达到监控理想状态的关键。这一点很直观。只有不到0.001%的飞机乘客会携带毒品的情况下,为什么每个包都要打开,每个乘客的隐私都要被侵犯?既然99.999%的时间既没有发生火灾,也没有发生入室盗窃,为什么要让保安监看业主家中的监控视频?
在我写作本文的两周内,仅仅在曼彻斯特、伦敦、埃及、阿富汗就有超过50人死于恐怖袭击。我为遇难者和他们的家庭祈祷,我极其希望我们能够找到更好的保障人们安全的方式。对最近在威斯敏斯特发生的恐怖袭击的调查显示,恐怖分子通过Whatsapp交换信息。这引起了一场关于隐私和安全的折衷的激烈争论。政府希望在Whatsapp一类的应用中置入后门(包括无限制的读取权限),但很多人不信任老大哥保护WhatsApp用户隐私的自律能力。另外,置入后门也让这些应用容易受到攻击,进一步增加了公众的风险。
恐怖主义也许是隐私和安全的折衷中讨论最多的领域,它并不是唯一被讨论的领域。谋杀之类的犯罪夺去了世界上成千上万人的生命。仅仅在美国,每年就有大约16000起谋杀。
“相当理由”的鸡和蛋问题 FBI和当地执法部门面对的挑战和恐怖主义极其相似。保护公民隐私的法律导致了一个鸡和蛋问题,发现“相当理由”(接着获取搜查令)和得以访问取得“相当理由”的信息。而在缉毒犬和烟雾报警器这样的情形中,这不再是一个问题,因为犯罪可以在不对隐私造成显著附加伤害的前提下被检测出来,因此“相当理由”不再是限制保障公共安全的因素。
在理想世界中,会有一个针对谋杀、恐怖袭击等不可逆的严重犯罪的“火警”设备,该设备能够保护隐私、精确、可审计。幸运的是,商业实体对这类检测设备的研发投入巨大。这些投入并不是由保护消费者隐私驱动的。相反,这些设备的研发是为了实现大规模检测。考虑一下Gmail的研发,Gmail想要提供垃圾邮件过滤功能。你可以侵犯人们的隐私,人工读取他们的邮件,但创建一个可以检测垃圾邮件的机器更快、更便宜。由于执法部门想要保护广大人口,不难想见这一过程是高度自动化的。所以,基于这一假设,我们真正欠缺的是转换AI智能体满足如下条件的能力:
可供受信任方审计其隐私保护
部署后无法被逆向工程
被监控者无法知道预测
部署方无法篡改预测(比如聊天软件)
高效、可伸缩
为了完整地说明这一概念,我们将创建一个原型。在下一节,我们将使用双层神经网络创建一个检测器的基础版本。之后,我们将升级这一检测器,使其满足上面列出的要求。这个检测器将在垃圾邮件数据库上进行训练,因此将只能检测垃圾邮件。不过,可以想像,经过训练,它可以检测你想要检测的任何特定事件(例如,谋杀、纵火,等等)。我选择垃圾邮件的原因是因为这相对容易训练,便于我演示这一方法。
所以,我们的示范案例将是一位当地的执法部门官员(让我们叫他“Bob”)希望打击发送垃圾邮件这一犯罪行为。然而,Bob并不打算亲自阅读每个人的邮件,相反,Bob希望检测发送垃圾邮件这一行为,这样他就可以申请禁制令和搜查令,并进行进一步调查。这一过程的第一部分是创建一个有效的垃圾邮件检测器。
Enron Spam Dataset 我们需要大量标记为“垃圾邮件”和“非垃圾邮件”的邮件让算法学习区分两种不同的邮件。幸运的是,一家知名的能源公司安然犯下了一些罪行,这些罪行被记录在邮件中,因此,这家公司相当多的邮件被公开了。由于其中许多邮件是垃圾邮件,因此人们基于这些公开邮件构建了一个Enron Spam Dataset(安然垃圾邮件数据集)。我对这一数据集进行了预处理,生成了两个文件:
ham.txt 非垃圾邮件,共22032封。
spam.txt 垃圾邮件,共9000封。
文件的每行是一封邮件。我们将留置每个类别中的最后1000封邮件作为测试数据集,其余邮件用作训练数据集。
模型 我们将使用一个能够快速训练的简单模型,词袋逻辑分类器(bag-of-words Logistic Classifier)。这是一个双层的神经网络(输入层和输出层)。我们本可以使用更复杂的模型,比如LSTM,但本文的主题不是过滤垃圾邮件,另外,词袋LR在垃圾邮件检测上效果非常好(令人惊讶的是,它在其他许多任务上同样表现出色)。所以不用过度复杂化。下面是创建这一分类器的代码。如果你吃不准它是如何工作的,可以参考我之前的文章基于Numpy实现神经网络:反向传播。
(在我的机器上,以下代码在Python 2和Python 3上均能运行。)
import numpy as np
from collections import Counter
import random
import sys
np.random.seed(12345)
f = open('spam.txt','r')
raw = f.readlines()
f.close()
spam = list()
for row in raw:
spam.append(row[:-2].split(" "))
f = open('ham.txt','r')
raw = f.readlines()
f.close()
ham = list()
for row in raw:
ham.append(row[:-2].split(" "))
class LogisticRegression(object):
def __init__(self, positives,negatives,iterations=10,alpha=0.1):
# 创建词汇表 (真实世界的案例将增加几百万其他词汇
# 以及从网络上抓取的其他词汇)
cnts = Counter()
for email in (positives+negatives):
for word in email:
cnts[word] += 1
# 转换为查找表
vocab = list(cnts.keys())
self.word2index = {}
for i,word in enumerate(vocab):
self.word2index[word] = i
# 初始化未加密权重
self.weights = (np.random.rand(len(vocab)) - 0.5) * 0.1
# 在未加密信息上训练模型
self.train(positives,negatives,iterations=iterations,alpha=alpha)
def train(self,positives,negatives,iterations=10,alpha=0.1):
for iter in range(iterations):
error = 0
n = 0
for i in range(max(len(positives),len(negatives))):
error += np.abs(self.learn(positives[i % len(positives)],1,alpha))
error += np.abs(self.learn(negatives[i % len(negatives)],0,alpha))
n += 2
print("Iter:" + str(iter) + " Loss:" + str(error / float(n)))
def softmax(self,x):
return 1/(1+np.exp(-x))
def predict(self,email):
pred = 0
for word in email:
pred += self.weights[self.word2index[word]]
pred = self.softmax(pred)
return pred
def learn(self,email,target,alpha):
pred = self.predict(email)
delta = (pred - target)# * pred * (1 - pred)
for word in email:
self.weights[self.word2index[word]] -= delta * alpha
return delta
model = LogisticRegression(spam[0:-1000],ham[0:-1000],iterations=3)
# 在留置集上评估
fp = 0
tn = 0
tp = 0
fn = 0
for i,h in enumerate(ham[-1000:]):
pred = model.predict(h)
if(pred < 0.5):
tn += 1
else:
fp += 1
if(i % 10 == 0):
sys.stdout.write('\rI:'+str(tn+tp+fn+fp) + " % Correct:" + str(100*tn/float(tn+fp))[0:6])
for i,h in enumerate(spam[-1000:]):
pred = model.predict(h)
if(pred >= 0.5):
tp += 1
else:
fn += 1
if(i % 10 == 0):
sys.stdout.write('\rI:'+str(tn+tp+fn+fp) + " % Correct:" + str(100*(tn+tp)/float(tn+tp+fn+fp))[0:6])
sys.stdout.write('\rI:'+str(tn+tp+fn+fp) + " Correct: %" + str(100*(tn+tp)/float(tn+tp+fn+fp))[0:6])
print("\nTest Accuracy: %" + str(100*(tn+tp)/float(tn+tp+fn+fp))[0:6])
print("False Positives: %" + str(100*fp/float(tp+fp))[0:4] + " <- privacy violation level out of 100.0%")
print("False Negatives: %" + str(100*fn/float(tn+fn))[0:4] + " <- security risk level out of 100.0%")
结果:
Iter:0 Loss:0.0455724486216
Iter:1 Loss:0.0173317643148
Iter:2 Loss:0.0113520767678
I:2000 Correct: %99.798
Test Accuracy: %99.7
False Positives: %0.3 <- privacy violation level out of 100.0%
False Negatives: %0.3 <- security risk level out of 100.0%
特性:可审计性 这个分类器有一个很棒的特性,它是一个具有高可审计性的算法。它不仅给出了测试数据上的精确评分,我们还能打开它,看看它给不同词汇的权重有何不同,以确保它基于Bob长官所需标记垃圾邮件。基于这些洞见,Bob长官可以从他的上级那里得到对辖区内的客户端进行极为有限的监控的许可。注意,Bob无法阅读任何人的邮件,他仅仅可以检测他需要检测的目标。
好,我们的分类器得到了Bob的上级(警长?)的批准。大致上,Bob将在辖区内的所有邮件客户端上加上这一分类器。每个客户端在发送邮件前会使用分类器作出预测。预测将发送给Bob,渐渐地,Bob将找出在自己的辖区内每天匿名发送10000封垃圾邮件的人。
问题一:预测可以伪造 过了一周以后,每个人仍然收到成吨的垃圾邮件。而Bob的分类器看起来不能标记任何垃圾邮件,尽管在Bob自己的机器上测试时可以正常工作。Bob怀疑有人拦截了算法的预测,让垃圾邮件看起来都是“阴性”。他应该怎么做?
问题二:模型可以被逆向工程 此外,Bob注意到他可以从预训练的模型中得到权重值:
尽管从可审计的角度来说,这是一个优势(让Bob的上级确信模型将仅仅找出设计目的所需的信息),这很容易被攻击!人们不仅可以拦截和修改模型的预测,甚至还可以逆向工程系统找出需要避免哪些单词。换句话说,模型的能力和预测易受攻击。Bob需要一道额外的防线。
在之前的文章中,我概述了如何使用同态加密以加密状态训练神经网络(训练数据未加密),算法实现基于高效整数向量同态加密。不过,之前的文章提到,有很多同态加密方案可供选择。本文将使用一个不同的方案,Paillier加密。我更新了Paillier加密的Python库,加入了处理long类型的密文和明文的功能,并修改了一处日志功能的bug.
你可以通过以下命令安装我修改的Paillier库:
git clone https://github.com/iamtrask/python-paillier.git
cd python-paillier
python setup.py install
接着运行以下代码:
import phe as paillier
pubkey, prikey = paillier.generate_paillier_keypair(n_length=64)
a = pubkey.encrypt(123)
b = pubkey.encrypt(-1)
prikey.decrypt(a) # 123L
prikey.decrypt(b) # -1L
prikey.decrypt(a + a) # 246
prikey.decrypt(a + b) # 122
如你所见,我们可以使用公钥加密(正或负)数,接着将加密值相加,然后解密所得结果。我们使用这些操作就可以加密我们的训练后的逻辑回归分类器。如果想了解这些是如何工作的,请参考我上一篇文章。
import phe as paillier
import math
import numpy as np
from collections import Counter
import random
import sys
np.random.seed(12345)
print("Generating paillier keypair")
pubkey, prikey = paillier.generate_paillier_keypair(n_length=64)
print("Importing dataset from disk...")
f = open('spam.txt','r')
raw = f.readlines()
f.close()
spam = list()
for row in raw:
spam.append(row[:-2].split(" "))
f = open('ham.txt','r')
raw = f.readlines()
f.close()
ham = list()
for row in raw:
ham.append(row[:-2].split(" "))
class HomomorphicLogisticRegression(object):
def __init__(self, positives,negatives,iterations=10,alpha=0.1):
self.encrypted=False
self.maxweight=10
# 创建词汇表 (真实世界的案例将增加几百万其他词汇
# 以及从网络上抓取的其他词汇)
cnts = Counter()
for email in (positives+negatives):
for word in email:
cnts[word] += 1
# 转换为查找表
vocab = list(cnts.keys())
self.word2index = {}
for i,word in enumerate(vocab):
self.word2index[word] = i
# 初始化未加密权重
self.weights = (np.random.rand(len(vocab)) - 0.5) * 0.1
# 在未加密信息上训练模型
self.train(positives,negatives,iterations=iterations,alpha=alpha)
def train(self,positives,negatives,iterations=10,alpha=0.1):
for iter in range(iterations):
error = 0
n = 0
for i in range(max(len(positives),len(negatives))):
error += np.abs(self.learn(positives[i % len(positives)],1,alpha))
error += np.abs(self.learn(negatives[i % len(negatives)],0,alpha))
n += 2
print("Iter:" + str(iter) + " Loss:" + str(error / float(n)))
def softmax(self,x):
return 1/(1+np.exp(-x))
def encrypt(self,pubkey,scaling_factor=1000):
if(not self.encrypted):
self.pubkey = pubkey
self.scaling_factor = float(scaling_factor)
self.encrypted_weights = list()
for weight in model.weights:
self.encrypted_weights.append(self.pubkey.encrypt(\\
int(min(weight,self.maxweight) * self.scaling_factor)))
self.encrypted = True
self.weights = None
return self
def predict(self,email):
if(self.encrypted):
return self.encrypted_predict(email)
else:
return self.unencrypted_predict(email)
def encrypted_predict(self,email):
pred = self.pubkey.encrypt(0)
for word in email:
pred += self.encrypted_weights[self.word2index[word]]
return pred
def unencrypted_predict(self,email):
pred = 0
for word in email:
pred += self.weights[self.word2index[word]]
pred = self.softmax(pred)
return pred
def learn(self,email,target,alpha):
pred = self.predict(email)
delta = (pred - target)# * pred * (1 - pred)
for word in email:
self.weights[self.word2index[word]] -= delta * alpha
return delta
model = HomomorphicLogisticRegression(spam[0:-1000],ham[0:-1000],iterations=10)
encrypted_model = model.encrypt(pubkey)
# 生成加密预测。接着解密它们,并进行评估。
fp = 0
tn = 0
tp = 0
fn = 0
for i,h in enumerate(ham[-1000:]):
encrypted_pred = encrypted_model.predict(h)
try:
pred = prikey.decrypt(encrypted_pred) / encrypted_model.scaling_factor
if(pred < 0):
tn += 1
else:
fp += 1
except:
print("overflow")
if(i % 10 == 0):
sys.stdout.write('\r I:'+str(tn+tp+fn+fp) + " % Correct:" + str(100*tn/float(tn+fp))[0:6])
for i,h in enumerate(spam[-1000:]):
encrypted_pred = encrypted_model.predict(h)
try:
pred = prikey.decrypt(encrypted_pred) / encrypted_model.scaling_factor
if(pred > 0):
tp += 1
else:
fn += 1
except:
print("overflow")
if(i % 10 == 0):
sys.stdout.write('\r I:'+str(tn+tp+fn+fp) + " % Correct:" + str(100*(tn+tp)/float(tn+tp+fn+fp))[0:6])
sys.stdout.write('\r I:'+str(tn+tp+fn+fp) + " % Correct:" + str(100*(tn+tp)/float(tn+tp+fn+fp))[0:6])
print("\n Encrypted Accuracy: %" + str(100*(tn+tp)/float(tn+tp+fn+fp))[0:6])
print("False Positives: %" + str(100*fp/float(tp+fp))[0:4] + " <- privacy violation level")
print("False Negatives: %" + str(100*fn/float(tn+fn))[0:4] + " <- security risk level")
输出:
Generating paillier keypair
Importing dataset from disk...
Iter:0 Loss:0.0455724486216
Iter:1 Loss:0.0173317643148
Iter:2 Loss:0.0113520767678
Iter:3 Loss:0.00455875940625
Iter:4 Loss:0.00178564065045
Iter:5 Loss:0.000854385076612
Iter:6 Loss:0.000417669805378
Iter:7 Loss:0.000298985174998
Iter:8 Loss:0.000244521525096
Iter:9 Loss:0.000211014087681
I:2000 % Correct:99.296
Encrypted Accuracy: %99.2
False Positives: %0.0 <- privacy violation level
False Negatives: %1.57 <- security risk level
这个模型相当特别(而且很快!……在我的笔记本上,单线程运行,每秒可以处理大约1000封邮件)。注意我们在预测时没有使用sigmoid(仅在训练时使用了sigmoid),因为其后的阈值为0.5. 因此,测试时我们可以简单地跳过sigmoid,并将之后的阈值设为0. 好了,已经谈了够多技术方面的内容了,让我们回到Bob那里。
Bob之前遇到的问题是人们可以看到预测并伪造预测。然而,现在所有预测都是加密的。
此外,Bob之前还遇到人们读取权重并逆向工程的问题。然而,现在所有权重也是加密的(并且可以在加密状态下预测)!
这一模型具有很多我们想要的性质。它可以被第三方审计,预测是加密的,对于想要窃取/愚弄这一系统的人来说,它的智能也是加密的。除此之外,它相当精确(测试数据集上没有假阳性结果),也很快。
让我们考虑下这样的模型对执法部门来说意味着什么。今时今日,为了预测谋杀和恐怖袭击之类的事件,执法部门需要不受限制地访问数据流。因此,为了检测在数据中有0.0001%的可能性发生的事件,执法部门需要访问100%的数据,将这些数据转到一个秘密的数据仓库,(我假定)数据仓库中部署了机器学习模型。
然而,这些现在用来识别犯罪的机器学习模型其实可以加密自身,并部署在数据流上(例如,聊天应用)。执法部门仅仅访问模型的预测,而不是访问整个数据集。这类似机场中的缉毒犬。缉毒犬消除了执法部门搜查每个人的箱包以寻找可卡因的需要。相反,狗通过训练(如同机器学习模型一样)可以排他性地检测毒品的存在。叫 == 有毒品。不叫 == 没毒品。阳性的神经网络预测意味着“在这个手机上策划一场恐怖活动”,阴性的神经网络预测意味着“不在这个手机上策划恐怖活动”。执法部门不需要看到数据。他们只需要这一个数据点。此外,由于模型是分散的智能,它可以被独立地评估以确保它只检测需要检测之物(正如我们可以通过评估缉毒犬在测试中的精确度以独立地审计缉毒犬用来训练什么)。然而,和缉毒犬不同,加密人工智能可以提供检测任何可由电子证据检测出的犯罪的能力。
审计考量 所以,我们应该信任谁进行审计?我不是一个政治科学专家,所以我将把这个问题留给其他人。然而,我认为,第三方监察人,政府雇员,甚至开源软件开发者可以承担这一角色。如果每种检测器有足够多的版本,恶意用户要找出部署的是哪个版本会很困难(因为它们是加密的)。我想这里有许多可行的选项,审计实体的问题已经有很多人讨论过了,因此我将把这部分留给专家。
伦理考量 文艺作品对导致直接定罪的犯罪预测的伦理和道德影响有很多评论(比如《少数派报告》)。然而,犯罪预测的主要价值不在于高效的惩罚和监禁,而在于预防伤害。因此,有两种微不足道的方法可以防止这一伦理困境。首先,大部分重大犯罪需要一些较轻的犯罪作为预备,通过更精确地检测较轻的犯罪预测重大犯罪可以避免许多道德困境。其次,预防犯罪的技术可以被用来优化警力资源分配,触发搜查/调查的方法。一个阳性的预测应该导致调查,而不是直接把人投入监狱。
法律考量 United States v. Place案判决,由于缉毒犬能够排他性地检测毒品的气味(而不检测其他东西),使用缉毒犬不认为是“搜查”。换句话说,由于它们可以在无需居民泄露其他信息的情况下分类犯罪,它不认为是对隐私的侵犯。此外,我认为公众对此的一般看法和法律是一致的。在机场中,一个毛茸茸的狗狗过来快速地嗅了下你的袋子是非常高效的保护隐私的监控形式。说来也怪,狗无疑可以训练来检测你包中任何令人尴尬的东西。然而,它仅仅训练检测犯罪的迹象。同样,智能体可以训练仅仅检测犯罪的迹象,而不检测其他东西。因此,达到足够精确度的模型,其法律地位应该比照缉毒犬。
腐败考量 也许你想问:“为何在这方面进行创新?为何提出新的监控方法?我们受到的监控还不多吗?”我的回答是:企业或政府应当无法监控任何没有伤害他人的人(无辜者)。相反地,我们想要检测任何即将伤害他人的人,以阻止他们。在最近的技术进展之前,这两者明显无法同时达到。本文想要主张:我相信在技术上同时保障安全和隐私是可行的。我的意思是,隐私不取决于当局的突发奇想,而取决于像加密人工智能一样的可审计的技术。该由谁负责审计这一技术,而不泄露给恶意之人?我不确定。也许是第三方监察机构。也许这会是人们可以选择加入的系统(就像烟雾报警器),然后通过社会契约让人们避免接触那些不加入的人。也许它完全通过开源的方式开发,但是足够有效,无法被绕过?这是问题值得进一步讨论。本文不是一个完整的解决方案。社会结构和政府结构无疑需要为这类工具作出调整。然而,我相信这是一个值得追寻的目标,我也期待本文引起的讨论。
首先,也是首要的,我们需要有主流深度学习框架(PyTorch、TensorFlow、Keras等)支持的现代的浮点向量同态加密算法(FV、YASHE等)。其次,探索如何提升这些算法的速度和安全性是一项高度创新和极其重要的工作。最后,我们需要设想社会结构可以如何配合这些新的工具,在不侵犯隐私的前提下保护人们的安全(并继续降低当局滥用此项技术的风险)。
原文地址:http://iamtrask.github.io/2017/06/05/homomorphic-surveillance/