【译】Secure Computations as Dataflow Programs Implementing the SPDZ Protocol using TensorFlow
TL; DR:使用TensorFlow作為數(shù)據(jù)流程序的分布式計算框架,我們通過聯(lián)網(wǎng)實現(xiàn)了SPDZ協(xié)議的全面實施,從而實現(xiàn)了對加密數(shù)據(jù)的優(yōu)化機(jī)器學(xué)習(xí)。
與之前我們關(guān)注安全計算背后的概念以及潛在的應(yīng)用程序不同?,我們在這里構(gòu)建了一個完全正常工作(被動安全)的實現(xiàn),其中運(yùn)行在不同機(jī)器上的玩家以及通過典型網(wǎng)絡(luò)堆棧進(jìn)行通信。?作為其中的一部分,我們研究了在實驗安全計算時使用現(xiàn)代分布式計算平臺的好處,而不是從頭開始構(gòu)建一切。
此外,這也可以看作是將私人機(jī)器學(xué)習(xí)掌握在從業(yè)者手中的一個步驟,與TensorFlow等現(xiàn)有和流行工具的集成起著重要作用。?具體而言,雖然我們這里只做了一個相對較淺的集成,但沒有使用TensorFlow附帶的一些強(qiáng)大的工具(例如自動分化?),但我們確實展示了如何克服基本的技術(shù)障礙,為更深入的研究鋪平道路集成。
向前看,回想起來,TensorFlow是一個明顯的候選框架,可以快速嘗試安全計算協(xié)議,至少在私人機(jī)器學(xué)習(xí)的背景下。
所有代碼都可以在本地或在Google Cloud上使用?。?為了簡單起見,我們運(yùn)行的示例始終是使用邏輯?回歸的私人預(yù)測,這意味著給定一個私有的(即加密的)輸入x我們希望安全地為私有但預(yù)先訓(xùn)練的權(quán)重計算sigmoid(dot(w, x) + b)?w和偏見b?(?w和b私人培訓(xùn)被視為后續(xù)職位)。?實驗表明,對于具有100個特征的模型,這可以在TensorFlow中完成,延遲低至60ms,速率高達(dá)每秒20,000個預(yù)測。
非常感謝Andrew Trask?,?Kory Mathewson?,?Jan?Leike和OpenMined社區(qū)為這個主題提供靈感和有趣的討論!
免責(zé)聲明?:此實現(xiàn)僅適用于實驗,可能無法達(dá)到所需的安全性。?特別是,TensorFlow目前似乎并沒有考慮到這個應(yīng)用程序的設(shè)計,雖然現(xiàn)在看起來并非如此,但是例如在未來的版本中,可能會在該場景后面執(zhí)行優(yōu)化來打破預(yù)期的安全屬性。?下面更多注釋?。
動機(jī)
正如上文所暗示的那樣,實施安全計算協(xié)議(如SPDZ?)由于其分布式性質(zhì)是一項不平凡的任務(wù),只有在我們開始引入各種優(yōu)化(?但?可以?完成?)時才會變得更糟。?例如,必須考慮如何最好地協(xié)調(diào)多個程序的同時執(zhí)行,如何最小化跨網(wǎng)絡(luò)發(fā)送數(shù)據(jù)的開銷,以及如何有效地將其與計算交錯,以便一臺服務(wù)器很少在另一臺服務(wù)器上等待。最重要的是,我們可能還想支持不同的硬件平臺,包括CPU和GPU等,并且對于任何認(rèn)真的工作來說,使用可視化檢查,調(diào)試和分析工具來識別問題和瓶頸是非常有價值的。
此外,還應(yīng)該很容易地嘗試各種優(yōu)化,例如改進(jìn)計算以提高性能,?重新使用中間結(jié)果和屏蔽值?,以及在執(zhí)行期間以三元組形式提供新鮮的“原材料”,而不是僅生成大批量提前在離線階段。?獲得所有這一切都是正確的,這是以前的博客文章集中在安全計算協(xié)議背后的原理并簡單地在本地完成的一個原因。
幸運(yùn)的是,現(xiàn)代分布式計算框架,如TensorFlow?,由于其在大型數(shù)據(jù)集上的高級機(jī)器學(xué)習(xí)中的使用,?近來正在接受大量研究和工程關(guān)注。?由于我們的重點(diǎn)是私人機(jī)器學(xué)習(xí),所以存在一個自然的大的基本重疊。?特別是,我們感興趣的安全操作是張量加法,減法,乘法,點(diǎn)積,截斷和采樣,它們在TensorFlow中都具有不安全但高度優(yōu)化的對應(yīng)物。
先決條件
我們假設(shè)TensorFlow和SPDZ協(xié)議背后的主要原理已經(jīng)被理解了 - 如果不是這樣的話,前者(包括白皮書?)和后者的前期?博客?文章都有很多?優(yōu)秀的?資源?。?至于涉及到的不同方面,我們在這里也假定有兩個服務(wù)器,一個加密生產(chǎn)者,一個輸入提供者和一個輸出接收者。
但是一個重要的注意事項是TensorFlow的工作原理是首先構(gòu)造一個隨后在會話中執(zhí)行的靜態(tài)計算圖?。?例如,檢查我們從TensorBoard中的sigmoid(dot(w, x) + b)得到的圖表顯示如下。
這意味著我們在這篇文章中的努力關(guān)注于構(gòu)建這樣一個圖表,而不是像之前的實際執(zhí)行:我們在某種程度上制作了一個小型編譯器,將用簡單語言表達(dá)的安全計算轉(zhuǎn)換為TensorFlow程序。?因此,我們不僅可以從更高層次的抽象中受益,而且可以從TensorFlow中已經(jīng)進(jìn)入優(yōu)化圖形執(zhí)行的大量工作中受益。
查看完整代碼示例的實驗?。
基本
我們的需求與TensorFlow已經(jīng)提供的操作很好地吻合,如下所示,除了一個主要的例外:當(dāng)在安全設(shè)置中處理固定點(diǎn)數(shù)字時,為了匹配浮點(diǎn)數(shù)的典型精度,我們最終編碼并操作整數(shù)大于32或64位的典型字長,但今天這些是TensorFlow提供操作的唯一尺寸(與當(dāng)前GPU支持有關(guān)的限制)。
幸運(yùn)的是,對于我們需要的操作,有效的方法可以讓我們模擬使用一組具有相同形狀但是例如32位整數(shù)的張量列表對?120位整數(shù)的張量進(jìn)行算術(shù)運(yùn)算。?此外,這種分解還具有我們可以獨(dú)立地對列表中的每個張量進(jìn)行操作的好特性,因此除了啟用TensorFlow之外,這還允許大多數(shù)操作并行執(zhí)行,并且實際上可以提高效率盡管它聽起來可能聽起來更加昂貴,但它的數(shù)量更大。
我們在其他地方討論這個細(xì)節(jié)?,并在本文的其余部分簡單地假定在張量列表上執(zhí)行預(yù)期操作的操作crt_add?,?crt_sub?,?crt_mul?,?crt_dot?,?crt_mod和sample。?請注意,?crt_mod?,?crt_mul和crt_sub一起允許我們?yōu)槎c(diǎn)截斷定義右移操作。
私人張量
每個私人張量由兩臺服務(wù)器決定。?由于上面提到的原因,每個份額都由張量列表給出,這些張量由圖中的節(jié)點(diǎn)列表表示。?為了隱藏這種復(fù)雜性,我們引入一個簡單的類如下。
class PrivateTensor : def __init__ ( self , share0 , share1 ): self . share0 = share0 self . share1 = share1 @property def shape ( self ): return self . share0 [ 0 ] . shape @property def unwrapped ( self ): return self . share0 , self . share1并且感謝TensorFlow,我們可以在圖形創(chuàng)建時知道張量的形狀,這意味著我們不必自己跟蹤這些。
簡單的操作
由于安全操作通常會用幾個TensorFlow操作來表示,因此我們使用抽象操作(如add,?mul和dot作為構(gòu)造計算圖的便捷方式。?第一個是add?,其中結(jié)果圖簡單地指示兩臺服務(wù)器在本地合并它們各自使用由crt_add構(gòu)建的子圖的crt_add?。
def add ( x , y ): assert isinstance ( x , PrivateTensor ) assert isinstance ( y , PrivateTensor ) x0 , x1 = x . unwrapped y0 , y1 = y . unwrapped with tf . name_scope ( 'add' ): with tf . device ( SERVER_0 ): z0 = crt_add ( x0 , y0 ) with tf . device ( SERVER_1 ): z1 = crt_add ( x1 , y1 ) z = PrivateTensor ( z0 , z1 ) return z注意使用tf.device()來表示哪個服務(wù)器正在做什么很容易!?該命令將計算及其結(jié)果值綁定到指定主機(jī),并指示TensorFlow自動插入適當(dāng)?shù)木W(wǎng)絡(luò)操作,以確保輸入值在需要時可用!
例如,在上面的例子中,如果x0先前是輸入提供者,那么TensorFlow將插入發(fā)送和接收指令,將SERVER_0作為計算add一部分復(fù)制到SERVER_0?。?所有這些都被抽象出來,框架將嘗試找出最佳策略,以便準(zhǔn)確優(yōu)化何時執(zhí)行發(fā)送和接收,包括批量更好地利用網(wǎng)絡(luò)并保持計算單元繁忙。
另一方面,?tf.name_scope()命令僅僅是一個邏輯抽象,它不會影響計算,但可用于通過將子圖組合為單個組件來使圖更容易在TensorBoard中可視化,如前所述。
請注意,如上所述,選擇TensorBoard中的Device?coloring,我們也可以使用它來驗證操作實際計算的位置,在這種情況下,添加確實是由兩臺服務(wù)器在本地完成的(綠色和綠松石)。
點(diǎn)產(chǎn)品
接下來我們轉(zhuǎn)向點(diǎn)產(chǎn)品。?這是比較復(fù)雜的,至少因為我們現(xiàn)在需要涉及加密生產(chǎn)者,還因為兩個服務(wù)器必須相互通信作為計算的一部分。
def dot ( x , y ): assert isinstance ( x , PrivateTensor ) assert isinstance ( y , PrivateTensor ) x0 , x1 = x . unwrapped y0 , y1 = y . unwrapped with tf . name_scope ( 'dot' ): # triple generation with tf . device ( CRYPTO_PRODUCER ): a = sample ( x . shape ) b = sample ( y . shape ) ab = crt_dot ( a , b ) a0 , a1 = share ( a ) b0 , b1 = share ( b ) ab0 , ab1 = share ( ab ) # masking after distributing the triple with tf . device ( SERVER_0 ): alpha0 = crt_sub ( x0 , a0 ) beta0 = crt_sub ( y0 , b0 ) with tf . device ( SERVER_1 ): alpha1 = crt_sub ( x1 , a1 ) beta1 = crt_sub ( y1 , b1 ) # recombination after exchanging alphas and betas with tf . device ( SERVER_0 ): alpha = reconstruct ( alpha0 , alpha1 ) beta = reconstruct ( beta0 , beta1 ) z0 = crt_add ( ab0 , crt_add ( crt_dot ( a0 , beta ), crt_add ( crt_dot ( alpha , b0 ), crt_dot ( alpha , beta )))) with tf . device ( SERVER_1 ): alpha = reconstruct ( alpha0 , alpha1 ) beta = reconstruct ( beta0 , beta1 ) z1 = crt_add ( ab1 , crt_add ( crt_dot ( a1 , beta ), crt_dot ( alpha , b1 ))) z = PrivateTensor ( z0 , z1 ) z = truncate ( z ) return z但是,通過tf.device()我們發(fā)現(xiàn)這仍然是相對直接的,至少如果安全點(diǎn)產(chǎn)品的協(xié)議已經(jīng)被理解了。?我們首先構(gòu)造一個圖形,使加密生成器生成一個新的點(diǎn)三元組。?該圖的輸出節(jié)點(diǎn)是a0, a1, b0, b1, ab0, ab1
隨著crt_sub我們?nèi)缓蠓謩e為使用a和b屏蔽x和y的兩臺服務(wù)器構(gòu)建圖。?TensorFlow將再次SERVER_0在執(zhí)行期間插入將例如a0的值發(fā)送到SERVER_0網(wǎng)絡(luò)代碼。
在第三步中,我們在每臺服務(wù)器上重建alpha和beta?,并計算重組步驟以獲得點(diǎn)積。?請注意,我們必須為每個服務(wù)器定義alpha和beta兩次,因為雖然它們包含相同的值,但如果我們只在一臺服務(wù)器上定義它們,但在兩臺服務(wù)器上都使用它們,那么我們會隱式插入其他網(wǎng)絡(luò)操作,因此減慢了計算速度。
回到TensorBoard,我們可以驗證節(jié)點(diǎn)確實與正確的玩家綁定在一起,黃色是加密制作者,綠色和綠松石是兩個服務(wù)器。?注意這里有tf.name_scope()的方便。
組態(tài)
為了充分聲明這使得安全計算的分布式方面更容易表達(dá),我們還必須看到td.device()實際上需要什么才能按預(yù)期工作。?在下面的代碼中,我們首先定義一個任意的作業(yè)名稱,后面跟著我們五個玩家的標(biāo)識符?更有意思的是,我們只需指定他們的網(wǎng)絡(luò)主機(jī)并將其包裝在ClusterSpec?。?而已!
JOB_NAME = 'spdz' SERVER_0 = '/job:{}/task:0' . format ( JOB_NAME ) SERVER_1 = '/job:{}/task:1' . format ( JOB_NAME ) CRYPTO_PRODUCER = '/job:{}/task:2' . format ( JOB_NAME ) INPUT_PROVIDER = '/job:{}/task:3' . format ( JOB_NAME ) OUTPUT_RECEIVER = '/job:{}/task:4' . format ( JOB_NAME ) HOSTS = [ '10.132.0.4:4440' , '10.132.0.5:4441' , '10.132.0.6:4442' , '10.132.0.7:4443' , '10.132.0.8:4444' , ] CLUSTER = tf . train . ClusterSpec ({ JOB_NAME : HOSTS })請注意,在截圖中,我們實際上是在同一主機(jī)上運(yùn)行輸入提供者和輸出接收者,因此都顯示為3/device:CPU:0?。
最后,每個玩家執(zhí)行的代碼都是如此簡單。
server = tf . train . Server ( CLUSTER , job_name = JOB_NAME , task_index = ROLE ) server . start () server . join ()這里ROLE的值是五個玩家運(yùn)行的程序之間唯一不同的東西,通常作為命令行參數(shù)給出。
改進(jìn)
隨著基礎(chǔ)知識的到位,我們可以看一些優(yōu)化。
跟蹤節(jié)點(diǎn)
我們的第一個改進(jìn)允許我們重復(fù)使用計算。?例如,如果我們需要兩次dot(x, y)的結(jié)果,那么我們希望避免第二次計算它,而是重新使用第一次。?具體而言,我們希望跟蹤圖中的節(jié)點(diǎn)并盡可能地鏈接到它們。
為此,我們只需在構(gòu)建圖時維護(hù)一個全局的PrivateTensor引用字典,并在添加新節(jié)點(diǎn)之前使用它查找已經(jīng)存在的結(jié)果。?例如,?dot現(xiàn)在變成如下。
def dot ( x , y ): assert isinstance ( x , PrivateTensor ) assert isinstance ( y , PrivateTensor ) node_key = ( 'dot' , x , y ) z = nodes . get ( node_key , None ) if z is None : # ... as before ... z = PrivateTensor ( z0 , z1 ) z = truncate ( z ) nodes [ node_key ] = z return z雖然對于某些應(yīng)用來說已經(jīng)很重要,但是這一改變也為我們的下一個改進(jìn)打開了。
重新使用蒙版張量
我們已經(jīng)?提到過?,我們最好想要掩蓋每個私人張量最多一次,主要是為了節(jié)省網(wǎng)絡(luò)。?例如,如果我們計算dot(w, x)和dot(w, y)那么我們希望在兩者中都使用相同的w掩碼版本。?具體而言,如果我們使用相同的掩蔽張量進(jìn)行多項操作,那么掩蓋它的成本可以分?jǐn)偂?/span>
但是就目前的設(shè)置而言,我們每次計算時都會掩蓋,例如dot或多dot?,因為掩模會被燒入這些點(diǎn)。?所以為了避免這種情況,我們只是簡單地做一個明確的操作,另外還允許我們在不同的操作中使用相同的屏蔽版本。
def mask ( x ): assert isinstance ( x , PrivateTensor ) node_key = ( 'mask' , x ) masked = nodes . get ( node_key , None ) if masked is None : x0 , x1 = x . unwrapped shape = x . shape with tf . name_scope ( 'mask' ): with tf . device ( CRYPTO_PRODUCER ): a = sample ( shape ) a0 , a1 = share ( a ) with tf . device ( SERVER_0 ): alpha0 = crt_sub ( x0 , a0 ) with tf . device ( SERVER_1 ): alpha1 = crt_sub ( x1 , a1 ) # exchange of alphas with tf . device ( SERVER_0 ): alpha_on_0 = reconstruct ( alpha0 , alpha1 ) with tf . device ( SERVER_1 ): alpha_on_1 = reconstruct ( alpha0 , alpha1 ) masked = MaskedPrivateTensor ( a , a0 , a1 , alpha_on_0 , alpha_on_1 ) nodes [ node_key ] = masked return masked請注意,我們引入了一個MaskedPrivateTensor類作為其中的一部分,這也是對從mask(x)得到的五個張量列表進(jìn)行抽象的簡便方法。
class MaskedPrivateTensor ( object ): def __init__ ( self , a , a0 , a1 , alpha_on_0 , alpha_on_1 ): self . a = a self . a0 = a0 self . a1 = a1 self . alpha_on_0 = alpha_on_0 self . alpha_on_1 = alpha_on_1 @property def shape ( self ): return self . a [ 0 ] . shape @property def unwrapped ( self ): return self . a , self . a0 , self . a1 , self . alpha_on_0 , self . alpha_on_1有了這個,我們可以像下面這樣重寫dot?,它現(xiàn)在只負(fù)責(zé)重組步驟。
def dot ( x , y ): assert isinstance ( x , PrivateTensor ) or isinstance ( x , MaskedPrivateTensor ) assert isinstance ( y , PrivateTensor ) or isinstance ( y , MaskedPrivateTensor ) node_key = ( 'dot' , x , y ) z = nodes . get ( node_key , None ) if z is None : if isinstance ( x , PrivateTensor ): x = mask ( x ) if isinstance ( y , PrivateTensor ): y = mask ( y ) a , a0 , a1 , alpha_on_0 , alpha_on_1 = x . unwrapped b , b0 , b1 , beta_on_0 , beta_on_1 = y . unwrapped with tf . name_scope ( 'dot' ): with tf . device ( CRYPTO_PRODUCER ): ab = crt_dot ( a , b ) ab0 , ab1 = share ( ab ) with tf . device ( SERVER_0 ): alpha = alpha_on_0 beta = beta_on_0 z0 = crt_add ( ab0 , crt_add ( crt_dot ( a0 , beta ), crt_add ( crt_dot ( alpha , b0 ), crt_dot ( alpha , beta )))) with tf . device ( SERVER_1 ): alpha = alpha_on_1 beta = beta_on_1 z1 = crt_add ( ab1 , crt_add ( crt_dot ( a1 , beta ), crt_dot ( alpha , b1 ))) z = PrivateTensor ( z0 , z1 ) z = truncate ( z ) nodes [ node_key ] = z return z作為驗證,我們可以看到TensorBoard向我們展示了預(yù)期的圖結(jié)構(gòu),在這種情況下,在sigmoid圖中。
這里square(x)值首先被計算出來,然后被屏蔽,最后被重復(fù)使用四次。
雖然效率低下,但TensorFlow的數(shù)據(jù)流性質(zhì)一般只會重新計算圖表中在兩次執(zhí)行之間發(fā)生變化的部分,但這不適用于涉及通過例如tf.random_uniform進(jìn)行采樣的操作,該操作用于我們的分享和掩飾。?因此,掩碼不會在執(zhí)行過程中重復(fù)使用。
緩存值
為了解決上述問題,我們可以引入在圖的不同執(zhí)行過程中存活的值的緩存,并且一個簡單的方法是將張量存儲在變量中?。?正常執(zhí)行將從這些讀取,而明確的cache_populators操作集允許我們填充它們。
例如,用這種cache操作包裝我們的兩張張量w和b可以得到下面的圖。
執(zhí)行緩存填充操作時,TensorFlow會自動計算出需要執(zhí)行的圖的哪些子部分以生成要緩存的值,哪些可以忽略。
同樣,在預(yù)測時,在這種情況下跳過共享和屏蔽。
緩沖三元組
回想一下,?三元組的主要目的是將加密生產(chǎn)者的計算轉(zhuǎn)移到離線階段,并提前將其結(jié)果分發(fā)給兩個服務(wù)器,以便稍后在在線階段加快計算速度。
到目前為止,我們還沒有做過任何事情來指定這會發(fā)生,但通過閱讀上述代碼,假設(shè)加密生產(chǎn)者將與兩臺服務(wù)器同步計算,在其計算過程中注入空閑等待時間并非不合理。?然而,從實驗看來,TensorFlow似乎已經(jīng)足夠聰明,可以優(yōu)化圖形來做正確的事情和批量三重分配,這大概是為了節(jié)省網(wǎng)絡(luò)。?盡管我們?nèi)匀挥幸粋€初始等待期,但我們可以通過引入一個單獨(dú)的計算和分配執(zhí)行來填補(bǔ)緩沖區(qū),從而擺脫困境。
我們現(xiàn)在將跳過這個問題,而是在看私人培訓(xùn)時回到它,因為通過提前分發(fā)培訓(xùn)數(shù)據(jù)來期待顯著的性能改進(jìn)并不是不合理的。
剖析
作為在TensorFlow中構(gòu)建數(shù)據(jù)流程序感到興奮的最后一個理由,我們還會查看內(nèi)置的運(yùn)行時統(tǒng)計信息?。?我們已經(jīng)在上面看到了內(nèi)置的詳細(xì)跟蹤支持,但在TensorBoard中我們也可以很容易地看到每個操作在計算和內(nèi)存方面的成本。?這里報告的數(shù)字來自下面的實驗?。
上面的熱圖表明,?sigmoid是運(yùn)行中最昂貴的操作,dot產(chǎn)品需要大約30ms才能執(zhí)行。?此外,在下圖中,我們已經(jīng)進(jìn)一步導(dǎo)航到點(diǎn)塊,并看到在這個特定運(yùn)行中共享大約3ms。
通過這種方式,我們可以識別瓶頸并比較不同方法的性能。?如果需要,我們當(dāng)然可以切換到追蹤更多細(xì)節(jié)。
實驗
GitHub存儲庫包含實驗所需的代碼,包括用于設(shè)置主機(jī)的本地配置或GCP配置的示例和說明。?對于使用邏輯回歸模型的私人預(yù)測的運(yùn)行示例,我們使用GCP配置,即各方在位于同一Google Cloud區(qū)域的不同虛擬主機(jī)上運(yùn)行,??這里是一些較弱的實例,即雙核和10 GB內(nèi)存。
我們的程序的一個稍微簡化的版本如下,我們首先公開訓(xùn)練一個模型,為私人預(yù)測計算建立一個圖形,然后在新的會話中運(yùn)行它。?該模型有點(diǎn)隨意挑選有100個功能。
from config import session from tensorspdz import ( define_input , define_variable , add , dot , sigmoid , cache , mask , encode_input , decode_output ) # publicly train `weights` and `bias` weights , bias = train_publicly () # define shape of unknown input shape_x = X . shape # construct graph for private prediction input_x , x = define_input ( shape_x , name = 'x' ) init_w , w = define_variable ( weights , name = 'w' ) init_b , b = define_variable ( bias , name = 'b' ) if use_caching : w = cache ( mask ( w )) b = cache ( b ) y = sigmoid ( add ( dot ( x , w ), b )) # start session between all players with session () as sess : # share and distribute `weights` and `bias` to the two servers sess . run ([ init_w , init_b ]) if use_caching : # compute and store cached values sess . run ( cache_populators ) # prepare to use `X` as private input for prediction feed_dict = encode_input ([ ( input_x , X ) ]) # run secure computation and reveal output y_pred = sess . run ( reveal ( y ), feed_dict = feed_dict ) print decode_output ( y_pred )以不同的X大小運(yùn)行這幾次會給出下面的計時,整個計算被考慮在內(nèi),包括三次生成和分配;?有點(diǎn)令人驚訝的是,高速緩存屏蔽值之間沒有真正的區(qū)別。
處理大小為1,10和100的批處理時間大致相同,平均約為60ms,這可能意味著由于網(wǎng)絡(luò)而導(dǎo)致的更低延遲限制。?在1000時間跳到?110ms,在10000到600ms之間,最后在100,000到5s之間。?因此,如果延遲比我們可以每秒執(zhí)行?1600次預(yù)測更重要,而如果更靈活,那么至少每秒至少20,000次。
然而,這只是測量分析報告的時間,實際執(zhí)行時間會稍長一些;?希望TensorFlow?tf.serving一些面向生產(chǎn)的工具(如tf.serving可以改進(jìn)這一點(diǎn)。
思考
在私人預(yù)測之后,看私人訓(xùn)練當(dāng)然也會很有趣。?緩存蒙面訓(xùn)練數(shù)據(jù)在這里可能更加相關(guān),因為它在整個過程中保持固定。
模型的服務(wù)也可以改進(jìn),例如使用生產(chǎn)就緒的tf.serving?,可以避免很多當(dāng)前的編排開銷,以及具有可以安全地向公眾公開的端點(diǎn)。
最后,在五方之間的溝通等方面還有安全方面的改進(jìn)。?特別是,在當(dāng)前版本的TensorFlow中,所有通信都是通過未加密和未經(jīng)身份驗證的gRPC連接進(jìn)行的,這意味著原則上監(jiān)聽網(wǎng)絡(luò)流量的人可以了解所有私有值。?由于對gRPC的支持已經(jīng)存在,所以在TensorFlow中使用它可能會很簡單,而且不會對性能產(chǎn)生重大影響。?同樣,TensorFlow目前不會為tf.random_uniform使用強(qiáng)大的偽隨機(jī)生成器,因此共享和屏蔽并不像它們可能的那樣安全;?增加一個密碼強(qiáng)的隨機(jī)性操作可能是直截了當(dāng)?shù)?#xff0c;應(yīng)該給出大致相同的性能。
https://mortendahl.github.io/2018/03/01/secure-computation-as-dataflow-programs/
總結(jié)
以上是生活随笔為你收集整理的【译】Secure Computations as Dataflow Programs Implementing the SPDZ Protocol using TensorFlow的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【译】Private Image Ana
- 下一篇: 【译】Making Sense of E