奧胡斯大學密碼學PhD、Datadog機器學習工程師Morten Dahl介紹了如何實現基于加密數據進行訓練和預測的卷積神經網絡。
TL;DR我們選取了一個經典的CNN深度學習模型,經過一系列步驟的改造,使其得以基于加密數據進行訓練和預測。
通過卷積神經網絡(CNN)分析圖像在最近幾年極為流行,因為CNN在圖像相關任務上的表現超過了其他許多方法。
最近一個基于CNN分析圖像的應用是檢測皮膚癌,基于這一應用,任何人可以使用手機應用快速地拍攝一張皮膚損傷的照片,并得到“表現與專家相當的”分析(可以參考YouTube上的視頻demo(youtu.be/toK1OSLep3s))。得以獲取大量的臨床圖像在訓練模型上起到了關鍵作用——可以將這一數據集認為是敏感信息。
這導向了隱私問題以及安全多方計算(MPC):現在有多少應用因為缺乏可供訪問的數據而受到限制?在上述案例中,如果允許任何使用手機應用的人貢獻數據,模型會不會得到提升?如果答案是肯定的,有多少人自愿冒暴露與個人健康相關的信息呢?
基于MPC我們可以潛在地降低暴露信息的風險,從而增強參與的動機。更具體地說,通過轉而在加密數據上訓練,我們不僅可以防止任何人查看個人數據,還可以防止泄露學習到的模型參數。差別隱私等其他技術也可能避免從預測中泄露信息,但我們這里暫不討論。
本文將討論一個簡化了的圖像分析案例,介紹所有需要用到的技術。GitHub上有一些和本文配套的notebook(mortendahl/privateml),其中主要的notebook提供了概念證明實現。
此外,我最近在Paris Machine Learning meetup(巴黎機器學習會議)上做了關于本文的報告,相關的幻燈片發(fā)布在GitHub倉庫mortendahl/talks下的ParisML17.pdf。
非常感謝Andrew Trask、Nigel Smart、Adrià Gascón、OpenMined社區(qū)對這一話題的啟發(fā)和討論。
設定
我們假定訓練數據集由一些輸入提供者(input provider)共同所有,而數據由兩個不同服務器(方)進行,我們信任兩方不會在協議指定的范圍之外協作。例如,在實踐中,服務器可能是共享云環(huán)境下由兩個不同組織掌握的虛擬實例。
輸入提供者只需在一開始傳輸他們的(加密)訓練數據;在此之后所有的計算只涉及兩個服務器,這意味著事實上輸入提供者使用手機之類的設備是可行的。訓練之后,模型將保持由兩個服務器共同所有的加密形式,每個人都可以使用它做出進一步的加密預測。
出于技術原因,我們同時假設有一個不同的加密生產商(crypto producer)生成計算過程中使用的特定原始材料,以提供效率;存在消除這一額外實體的方法,不過本文暫不討論這些。
最后,就安全術語而言,我們追求的是實踐中常用的典型概念,即誠實而好奇(或被動)安全(honest-but-curious (or passive) security),即假定服務器將遵循協議,但除此之外會嘗試了解盡可能多的看到的信息。對服務器而言,盡管這個概念比完全惡意(或主動)安全(fully malicious (or active) security)要弱一點,它仍然針對任何可能在計算之后攻破其中一個服務器的行為提供強力的保護,不管攻擊者做了什么。注意,本文事實上允許訓練過程中的小部分隱私泄露,詳見后文。
基于CNN進行圖像分析
我們的用例是經典的MNIST手寫數字識別,即學習給定圖像中的阿拉伯數字,我們將使用Keras示例中的CNN模型作為基礎。
feature_layers = [
Conv2D(32, (3, 3), padding='same', input_shape=(28, 28, 1)),
Activation('relu'),
Conv2D(32, (3, 3), padding='same'),
Activation('relu'),
MaxPooling2D(pool_size=(2,2)),
Dropout(.25),
Flatten()
]
classification_layers = [
Dense(128),
Activation('relu'),
Dropout(.50),
Dense(NUM_CLASSES),
Activation('softmax')
]
model = Sequential(feature_layers + classification_layers)
model.compile(
loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
model.fit(
x_train, y_train,
epochs=1,
batch_size=32,
verbose=1,
validation_data=(x_test, y_test))
這里不討論這一模型的細節(jié),因為網上已經有很多介紹其原理的資源了。不過基本的想法是首先讓圖像通過一組特征層(feature layer),將輸入圖像的原始像素轉換為和我們的分類任務更相關的抽象屬性。接著通過一組分類層(classification layer)組合這些屬性,以生成可能數字的概率分布。最終輸出通常直接是概率最高的數字。
我們很快將看到,使用Keras的優(yōu)勢是我們可以快速地在未加密數據上進行試驗,看看模型本身的表現如何,同時,Keras提供了一個簡單的接口,供我們之后的加密設定效仿。
基于SPDZ安全計算
CNN就緒后,我們接著來看MPC。我們將使用當前最先進的SPDZ協議,因為它允許我們只使用兩個服務器,也允許我們通過將特定計算轉移到離線階段以改善在線表現。
和其他典型的安全計算協議一樣,所有計算在一個域中進行,此處的域由一個質數Q表示。這意味著我們需要編碼CNN使用的浮點數為以一個質數為模的整數,這給Q帶來一些限制,進而對性能有所影響。
此外,在SPDZ協議這樣的交互計算中,在典型的時間復雜度之外,同時還要考慮通訊和回合復雜度。通訊復雜度衡量在網絡中發(fā)送的字節(jié)數,一個相對較慢的過程。回合復雜度衡量兩個服務器之間的同步點數目,同步點可能阻塞其中一個服務器,使其無所事事,直到另一個服務器趕上來為止。因而兩者均對總執(zhí)行時間有很大的影響。
然而更重要的是,這些協議的“原生”操作只有加法和乘法。除法、比較等可以完成,但就它們的三項復雜度而言,要更昂貴。之后我們將看下如何緩解這引起的其中一些問題,而這里我們首先討論基本的SPDZ協議。
張量操作
下面的代碼為SPDZ協議實現PublicTensor和PrivateTensor兩個類,分別代表兩個服務器知道明文的張量和僅僅知道其秘密分享形式的加密值。
classPrivateTensor:
def __init__(self, values, shares0=None, shares1=None):
ifnot values isNone:
shares0, shares1 = share(values)
self.shares0 = shares0
self.shares1 = shares1
def reconstruct(self):
returnPublicTensor(reconstruct(self.shares0, self.shares1))
def add(x, y):
if type(y) isPublicTensor:
shares0 = (x.values + y.shares0) % Q
shares1 = y.shares1
returnPrivateTensor(None, shares0, shares1)
if type(y) isPrivateTensor:
shares0 = (x.shares0 + y.shares0) % Q
shares1 = (x.shares1 + y.shares1) % Q
returnPrivateTensor(None, shares0, shares1)
def mul(x, y):
if type(y) isPublicTensor:
shares0 = (x.shares0 * y.values) % Q
shares1 = (x.shares1 * y.values) % Q
returnPrivateTensor(None, shares0, shares1)
if type(y) isPrivateTensor:
a, b, a_mul_b = generate_mul_triple(x.shape, y.shape)
alpha = (x - a).reconstruct()
beta = (y - b).reconstruct()
return alpha.mul(beta) + \
alpha.mul(b) + \
a.mul(beta) + \
a_mul_b
代碼基本上還是直截了當的。當然,其中有一些技術上的細節(jié),詳見和本文配套的notebook。
上面的代碼用到的基本工具函數:
def share(secrets):
shares0 = sample_random_tensor(secrets.shape)
shares1 = (secrets - shares0) % Q
return shares0, shares1
def reconstruct(shares0, shares1):
secrets = (shares0 + shares1) % Q
return secrets
def generate_mul_triple(x_shape, y_shape):
a = sample_random_tensor(x_shape)
b = sample_random_tensor(y_shape)
c = np.multiply(a, b) % Q
returnPrivateTensor(a), PrivateTensor(b), PrivateTensor(c)
適配模型
雖然原則上基于我們現有的模型安全地計算任何函數是可能的,實踐中需要做的是先考慮對MPC更友好的模型變體,以及對模型更友好的加密協議。用稍微形象一點的話說,我們經常需要打開兩個黑箱,讓兩個技術更好地適配彼此。
這一做法的根源在于,加密操作下,有一些操作驚人地昂貴。我們之前提到過,加法和乘法相對廉價,而比較和基于私密分母的除法則不然。基于這一原因,我們對模型做了一些改動,以避免這一問題。
本節(jié)中涉及的許多改動和它們相應的性能詳見配套的Python notebook。
優(yōu)化器
首先涉及的是優(yōu)化器:盡管許多實現基于Adam的高效而選擇了它,Adam涉及對私密值取平方根,以及在除法中使用私密值作分母。盡管理論上安全地進行這些計算是可能的,在實踐中它會是性能的顯著瓶頸,因此需要避免使用Adam。
一個簡單的補救方案是轉而使用動量SGD(momentum SGD)優(yōu)化器,它可能意味著較長的訓練時間,但只使用簡單的操作。
model.compile(
loss='categorical_crossentropy',
optimizer=SGD(clipnorm=10000, clipvalue=10000),
metrics=['accuracy'])
還有一個額外的坑,很多優(yōu)化器使用裁剪(clipping)以避免梯度變得過小或過大。裁剪需要比較私密值,在加密設定下這又是一個某種程度上昂貴的操作,因此我們的目標是避免使用裁剪(在上面的代碼中,我們增加了界限)。
網絡層
說到比較,ReLU和最大池化層同樣有這個問題。CryptoNet用一個平方函數取代了前者,用平均池化取代了后者,而SecureML實現了一個類似ReLU的激活函數(不過,這增加了復雜度,為了保持簡單,本文打算避免這一點)。因此,我們這里使用了高階sigmoid激活函數和平均池化層。注意平均池化同樣用到了除法,不過這回分母是公開值,因而除法不過是對公開值取倒數,接著進行一次乘法。
feature_layers = [
Conv2D(32, (3, 3), padding='same', input_shape=(28, 28, 1)),
Activation('sigmoid'),
Conv2D(32, (3, 3), padding='same'),
Activation('sigmoid'),
AveragePooling2D(pool_size=(2,2)),
Dropout(.25),
Flatten()
]
classification_layers = [
Dense(128),
Activation('sigmoid'),
Dropout(.50),
Dense(NUM_CLASSES),
Activation('softmax')
]
model = Sequential(feature_layers + classification_layers)
模擬表明這一改動讓我們需要提高epoch數,相應地減慢訓練速度。學習率或動量的其他選擇可能可以改善這一點。
model.fit(
x_train, y_train,
epochs=15,
batch_size=32,
verbose=1,
validation_data=(x_test, y_test))
剩下的層很好處理。dropout和平層(flatten)不在乎是加密設定還是非加密設定,密集層和卷積層是矩陣點積,只需要基本操作。
softmax和損失函數
在加密設定下,最后的softmax層同樣會給訓練帶來復雜度,因為我們需要進行以私密值為指數的指數運算,以及基于私密分母除法的歸一化。
盡管這兩者都是可能達成的,我們這里選擇了一個更簡單的做法,允許向其中一個服務器暴露每個訓練樣本的預測分類的似然,該服務器接著基于暴露值計算結果。這當然導致了隱私泄露,這樣的泄露可能會,也可能不會形成可接受的風險。
一個啟發(fā)式的改進方案是在暴露任何值前先變換分類似然的向量,從而隱藏哪個分類對應哪個向量。然而,這可能起不到什么效果,比如,“健康”常常意味著收緊的分布,而“患病”常常意味著舒展的分布。
另一個方案是引入第三個服務器,專門進行這類小計算,其他任何訓練數據的信息對該服務器而言都將是不可見的,因而無法將標簽和樣本數據關聯起來。雖然這樣仍有部分信息泄露,但這一數量難以進行推理。
最后,我們可以將這樣的一對多方法替換為一對一方法,比如,使用sigmoid。如前所述,這允許我們在不解密的情況下完整地計算預測。不過我們仍然需要計算損失,我們也許可以同樣考慮使用一個不同的損失函數。
注意,在之后使用訓練過的網絡進行預測時,這里提到的問題都不存在,因為沒有損失需要計算,而服務器可以直接跳過softmax層,讓預測的接收方自行計算相應值:對于接收方而言,這只不過是一個如何解釋值的問題。
遷移學習
到此為止,看起來我們已經可以按現狀實際訓練模型并得到不錯的結果了。不過,依照CNN的慣例,我們可以利用遷移學習顯著加速訓練過程;事實上,某種程度上而言,“極少有人從頭訓練他們自己的卷積網絡,因為他們并不具備足夠的數據”,,“實踐中總是推薦使用遷移學習”,是眾所周知的事實。
在我們這里的設定中,遷移學習的特定應用可能是訓練分為兩階段:使用非敏感的公開數據的預訓練階段和使用敏感的隱私數據的調優(yōu)階段。例如,在檢測皮膚癌的案例中,研究人員可能選擇在公開照片集上進行預訓練,之后請求志愿者提供額外的照片以改進模型。
除了基數的不同以外,兩個數據集的主體也可能不同,因為CNN具有首先分解主體為有意義的子部分的傾向,識別哪部分是什么可以被遷移。換句話說,這一技術足夠強大,預訓練可以在和調優(yōu)不同類型的圖像上進行。
回到我們具體的字符識別用例中,我們可以讓0-4作為“公開”圖像,而讓5-9作為“私密”圖像。作為替代,讓a-z作為“公開”圖像,0-9作為“私密圖像”看起來也沒什么不合理的。
在公開數據集上進行預訓練
除了避免在公開數據集上進行加密數據訓練的額外開銷之外,在公開數據集上進行預訓練還讓我們得以使用更高級的優(yōu)化器。比如,這里我們可以轉回去使用Adam優(yōu)化器訓練圖像,以加快訓練進度。特別地,我們可以降低所需的epoch數。
(x_train, y_train), (x_test, y_test) = public_dataset
model.compile(
loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
model.fit(
x_train, y_train,
epochs=1,
batch_size=32,
verbose=1,
validation_data=(x_test, y_test))
一旦我們對預訓練的結果滿意,服務器可以直接共享模型參數,轉而開始訓練私密數據集。
在隱私數據集上進行調優(yōu)
我們開始進行加密訓練時,模型的參數已經“到了中途”,因此我們可以期望,不再需要那么多epoch了。如前所述,遷移學習還有一個優(yōu)勢,識別子部件傾向于發(fā)生在網絡的底層,在某些情形下可能可以按現狀使用。因此,我們現在凍結特征層的參數,集中訓練分類層。
for layer in feature_layers:
layer.trainable = False
不過,我們仍然需要讓所有私密訓練樣本前向通過這些層;唯一的差別是在反向傳播這一步我們跳過這些層,因此我們需要訓練的參數減少了。
接下來的訓練和前面一樣,只不過現在使用較低的學習率:
(x_train, y_train), (x_test, y_test) = private_dataset
model.compile(
loss='categorical_crossentropy',
optimizer=SGD(clipnorm=10000, clipvalue=10000, lr=0.1, momentum=0.0),
metrics=['accuracy'])
model.fit(
x_train, y_train,
epochs=5,
batch_size=32,
verbose=1,
validation_data=(x_test, y_test))
最終,我們在模擬中將epoch數從25降到了5.
預處理
還有少數可以應用的預處理優(yōu)化,不過這里我們不再進一步優(yōu)化下去了。
第一個優(yōu)化是將凍結層的計算轉移到輸入提供者那里,這樣,和服務器共享的將是平層而不是圖像的像素。在這一情形下,這些層進行的是特征提取(feature extraction),潛在地讓我們可能使用更強大的層。然而,如果我們想要保持模型專有,那么這會顯著增加復雜度,因為現在參數需要以某種形式分發(fā)到客戶端。
另一個典型的加快訓練的方法是首先應用諸如主成分分析之類的降維技術。BSS+’17的加密設定使用了這一方法。
適配協議
查看了模型之后,我們接著來看協議:同樣,正如我們即將看到的,理解我們需要進行的操作有助于提升速度。
特別地,許多計算可以轉移到加密提供者處,加密提供者生成的原始材料獨立于私密輸入,某種程度上甚至獨立于模型。因此,它的計算可以在方便的時候大批量地實現完成。
回憶一下先前提到的有必要同時優(yōu)化回合復雜度和通訊復雜度,而這里提議的擴展常常旨在優(yōu)化這兩者,不過作為代價,需要額外的本地計算。因此,需要進行實際的試驗以驗證它們在具體情形下的益處。
Dropout
從最簡單的網絡層類型開始,我們注意到沒有任何和安全計算特別相關的事情發(fā)生在這一層,這一層只是確保兩個服務器同意在每次訓練迭代中丟棄哪些值。這可以通過直接同意一個種子值達成。
平均池化
平均池化的前向傳播只需要一次累加以及隨后的基于公開分母的除法。因此,它可以通過乘以一個公開值實現:由于分母是公開的,我們可以很容易找到它的倒數,然后直接相乘并截斷。類似地,反向傳播不過是縮放,因而兩個方向的傳播都完全是本地操作。
密集層
密集層的前向傳播和反向傳播都需要進行點積操作,該操作當然可以通過經典的乘法和加法實現。如果我們想為形狀分別為(m, k)和(k, n)的矩陣x和y計算點積dot(x, y),那么這將需要m * n * k次乘法,意味著我們需要通訊同等數量的掩碼后的值。盡管這些可以并發(fā)發(fā)送,所以我們僅僅需要一回合,如果我們可以使用另一種預處理的三元組,那么我們可以降低一個數量級的通訊成本。
例如,我們的模型的第二個密集層計算(32, 128)和(128, 5)這兩個矩陣的點積。使用典型的方法,每個batch中需要發(fā)送32 * 5 * 128 == 22400掩碼后的值,但使用下面描述的預處理的三元組,我們只需發(fā)送32 * 128 + 5 * 128 == 4736掩碼后的值,幾乎有5倍的改善。第一個密集層的效果還要好,大約有25倍多的改善。
技巧在于確保矩陣中的每個私密值的掩碼僅發(fā)送一次。為了達成這一點,我們需要三元組(a, b, c),其中,a和b是形狀合適的隨機矩陣,c滿足c == dot(a, b)。
def generate_dot_triple(x_shape, y_shape):
a = sample_random_tensor(x_shape)
b = sample_random_tensor(y_shape)
c = np.dot(a, b) % Q
returnPrivateTensor(a), PrivateTensor(b), PrivateTensor(c)
給定這樣一個三元組,我們可以轉而通訊alpha = x - a和beta = y - b的值,接著通過本地計算得到dot(x, y)。
classPrivateTensor:
...
def dot(x, y):
if type(y) isPublicTensor:
shares0 = x.shares0.dot(y.values) % Q
shares1 = x.shares1.dot(y.values) % Q
returnPrivateTensor(None, shares0, shares1)
if type(y) isPrivateTensor:
a, b, a_dot_b = generate_dot_triple(x.shape, y.shape)
alpha = (x - a).reconstruct()
beta = (y - b).reconstruct()
return alpha.dot(beta) + \
alpha.dot(b) + \
a.dot(beta) + \
a_dot_b
使用這一三元組的安全性取決于三元組乘法的安全性:通訊的掩碼后的值完美地隱藏了x和y的值,而c是一個獨立的新的共享值,這確保了結果無法泄露任何有關其組成的信息。
注意,SecureML使用了這類三元組,SecureML同時給出了無需加密提供者幫助、由服務器自行生成三元組的技術。
卷積
類似密集層,卷積可以被看作一系列標量乘法或矩陣乘法,盡管后者首先需要將訓練樣本的張量擴展為帶有很多冗余的矩陣。一點也不讓人驚訝的是,兩者均導致通訊成本增加,通過引入另一種三元組,可以加以改進。
舉個例子,第一卷積層使用32個形狀為(3, 3, 1)的核將形狀為(m, 28, 28, 1)的張量映射為(m, 28, 28, 32)的張量(不考慮偏置向量)。對于batch尺寸m == 32而言,如果我們僅僅使用標量乘法,這意味著7,225,344個通訊元素,如果我們使用矩陣乘法,則是226,080個通訊元素。然而,由于總共只涉及(32*28*28) + (32*3*3) == 25,376個私密值(同樣不計算偏置向量,因為它們僅僅需要加法),我們看到這里大概有9倍的額外開銷。換句話說,每個私密值都被掩碼和發(fā)送了好幾次。基于一種新的三元組,我們可以消除這一額外開銷,節(jié)省通訊成本:對64位元素而言,這意味這每batch的成本為200KB,而不是相應的1.7MB和55MB。
我們這里需要的三元組(a, b, c)和點積中使用的類似,a和b具有匹配輸入的形狀,即(m, 28, 28, 1)和(32, 3, 3, 1),而c則匹配輸出形狀(m, 28, 28, 32)。
sigmoid激活
如同我們先前做的那樣,我們可以使用9項多項式來逼近sigmoid激活函數至足夠的精確程度。為私密值x演算這一多項式的值需要計算一系列x的次方,這些當然可以通過一系列乘法來完成——但這意味著許多回合和相應數量的通訊。
作為替代,我們一樣可以使用一種新的三元組,該三元組允許我們在一個回合中計算所有需要的次方。這些“三元組”的長度不是固定的,等于最高的指數,比如對應平方的三元組包含a和a**2的獨立共享,而對應立方的三元組包含a、a**2、a**3的獨立共享。
一旦我們具備了這些x的次方值,演算帶有公開系數的多項式就僅僅是本地的加權總和了。這一計算的安全性同樣來自于三元組中的所有次方是獨立共享的。
def pol_public(x, coeffs, triple):
powers = pows(x, triple)
return sum( xe * ce for xe, ce in zip(powers, coeffs) )
和先前一樣,我們會遇到關于定點數精度的坑,即次方的更高精度要求更多的空間:x**n有n倍x的精度,而我們想要確保它不會在以Q為模時溢出以致我們無法正確解碼。我們可以通過引入一個足夠大的域P,在計算次方時臨時切換過去,代價是額外的兩回合通訊。
實踐中的試驗將表明到底是保持Q使用更多的乘法回合更好,還是進行切換支付大數轉換和算術的代價更好。特別地,對低階多項式而言,前者看起來更好。
概念證明實現
有一個不帶網絡的概念證明實現可供實驗和重現。該實現尚未完工,目前代碼支持基于加密特征訓練一個新分類器,但不支持從加密圖像中提取特征。換句話說,它假定輸入提供者自行在特征提取層中運行圖像,然后將結果以加密形式發(fā)送給服務器;因此,模型相應部分的權重目前而言并未保持私密。以后的版本將處理這一點,使特征層可以在加密數據上運行,從而直接基于圖像訓練和預測。
from pond.nn importSequential, Dense, Sigmoid, Dropout, Reveal, Softmax, CrossEntropy
from pond.tensor importPrivateEncodedTensor
classifier = Sequential([
Dense(128, 6272),
Sigmoid(),
Dropout(.5),
Dense(5, 128),
Reveal(),
Softmax()
])
classifier.initialize()
classifier.fit(
PrivateEncodedTensor(x_train_features),
PrivateEncodedTensor(y_train),
loss=CrossEntropy(),
epochs=3
)
代碼分成幾個Python notebook,帶有預計算的權重,所以你也可以跳過某些步驟:
第一個notebook使用Keras處理公開數據上的預訓練,并為特征提取生成模型。可以跳過這一步,轉而使用倉庫中的預計算權重。
第二個notebook將上面的模型應用于私密數據上的特征提取,從而生成用于訓練新的加密分類器的特征。以后的版本將首先加密數據。這一步無法省略,因為提取的數據太大了。
第三個notebook接受提取的特征,并訓練一個新的加密分類器。這是目前為止最昂貴的一步,可以通過使用倉庫中的預計算權重跳過。
最后,第四個notebook使用新的分類器在新圖像上進行加密預測。同樣,特征提取目前是未加密的。
運行以上代碼需要先克隆倉庫
$ git clone https://github.com/mortendahl/privateml.git && \
cd privateml/image-analysis/
安裝依賴
$ pip3 install jupyter numpy tensorflow keras h5py
運行notebook
$ jupyter notebook
想法
一如既往,當先前的想法和疑問得到解答后,早已有一批新的等在那里了。
推廣三元組
嘗試減少通訊的時候,有人可能會好奇通過使用額外的三元組,有多少工作可以轉移到預處理階段完成。
前面已經好幾次提到了(同時也是BCG+’17等論文的主張),我們通常尋求確保每個私密值只發(fā)送掩碼一次。所以,如果我們,比如說,同時計算dot(x, y)和dot(x, z),那么,有一個三元組(r, s, t, u, v)會是有意義的,其中,r用于掩碼x,s用于掩碼y,u用于掩碼z,而t和u用于計算結果。比如,這一模式在訓練時出現,在前向傳播時計算的值有時可以被緩存下來,在反向傳播時加以復用。
不過,也許更重要的是我們僅僅基于一個模型做出預測的時候,即,基于固定的私有權重進行計算。在這一情形下,我們想要只掩碼權重一次然后在每次預測時加以復用。進行這樣的操作意味著我們的掩碼和通訊數量與通過模型的輸入向量成正比,而不是與輸入向量和權重成正比,JVC’18之類的論文就是這么做的。更一般地,理想情況下,我們想要通訊只與變動的值成正比,這可以通過特制的三元組(在分期付款的意義上)達成。
最后,原則上可以讓三元組執(zhí)行更多的功能,比如在一回合的通訊中同時演算密集層和它的激活函數,但最大的阻礙看起來是可伸縮性問題,包括三元組的儲存,和重組步驟中需要進行的計算量,特別是處理張量時。
激活函數
一個自然的問題是其他哪些典型的激活函數在加密配置下比較高效。如前所述,SecureML通過臨時切換到亂碼電路來使用ReLU,而CryptoDL給出了sigmoid、ReLU、Tanh的低階多項式逼近(通了提高精確度,使用了切比雪夫多項式)。
也許有必要考慮更簡單的非典型激活函數,比如CryptoNet等使用的平方,如果簡化計算和通訊最重要的話。
亂碼電路
前文提到通過使用亂碼電路更安全地演算更高級的激活函數,實際上,亂碼電路還可以用于更大的部分,包括作為安全計算的主要手段,像DeepSecure等所做的那樣。
和SPDZ之類的技術相比,亂碼電路的優(yōu)勢是僅使用固定數目的通訊回合。缺點是操作常常發(fā)生在字節(jié)上,而不是相對而言較大的域元素上,這意味著涉及更多計算。
精度
大量圍繞聯合學習(federated learning)的研究涉及梯度壓縮(gradient compression)以便減少通訊成本。接近我們設定的是BMMP’17,基于量子化應用同態(tài)加密到深度學習上,甚至未加密的生產環(huán)境就緒系統也常常考慮這一技術,以提高學習的性能。
浮點數運算
上面我們使用定點數將實數編碼為有限域元素,而未加密深度學習通常使用浮點數編碼。如ABZS’12和SPDZ的參考實現所展示的那樣,在加密設定下使用浮點數編碼也是可能的,顯然浮點數編碼在某些操作上性能更有優(yōu)勢。
出于性能考慮,今時今日深度學習通常在GPU上進行,因此很自然地就想到是否可以應用類似的加速手段到MPC計算上。亂碼電路已經有這方面的工作,而SPDZ之類的安全共享設定中這看起來不是那么流行。
這里面臨的最大問題可能是GPU上的任意精度算術的成熟度和實用度(不過,其實已經有一些這方面的研究了),因為在較大的域元素(比如64位之上)上的計算需要這個。不過,這里該記住兩點:首先,盡管我們計算的域元素大于那些原生支持的,它們仍然是有界的(模數);其次,我們可以在環(huán)上(而不是域上)進行我們的安全計算。
-
神經網絡
+關注
關注
42文章
4771瀏覽量
100714 -
機器學習
+關注
關注
66文章
8406瀏覽量
132563
原文標題:基于Keras實現加密卷積神經網絡
文章出處:【微信號:jqr_AI,微信公眾號:論智】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論