本文檔介紹了 TFF 的核心層,該核心層是聯邦學習以及未來可能的非學習聯邦演算法的基礎。
如需聯邦核心的簡要介紹,請閱讀以下教學課程,其中透過範例介紹了一些基本概念,並逐步示範如何建構簡單的聯邦平均演算法。
我們也建議您熟悉聯邦學習以及關於圖片分類和文字產生的相關教學課程,因為聯邦核心 API (FC API) 在聯邦學習中的應用,為我們在設計此層時所做的一些選擇提供了重要的背景資訊。
總覽
目標、預期用途和範圍
聯邦核心 (FC) 最適合理解為用於實作分散式運算的程式設計環境,即涉及多部電腦 (手機、平板電腦、嵌入式裝置、桌上型電腦、感應器、資料庫伺服器等) 的運算,這些電腦各自可以在本機執行重要的處理,並透過網路進行通訊以協調其工作。
「分散式」一詞非常通用,而 TFF 並非針對所有可能類型的分散式演算法,因此我們偏好使用較不通用的詞彙「聯邦運算」來描述可以在此架構中表示的演算法類型。
雖然以完全正式的方式定義「聯邦運算」一詞不在本文檔的範圍內,但您可以思考在描述新的分散式學習演算法的研究出版物中,您可能會看到的以虛擬碼表示的演算法類型。
簡而言之,FC 的目標是以類似的虛擬碼抽象層級,實現類似精簡的表示法,來表示非虛擬碼的程式邏輯,而是可以在各種目標環境中執行的程式邏輯。
FC 旨在表示的演算法類型的關鍵定義特徵是,系統參與者的動作是以集體方式描述的。因此,我們傾向於談論每個裝置在本機轉換資料,以及裝置透過集中協調器廣播、收集或彙總其結果來協調工作。
雖然 TFF 的設計目的是能夠超越簡單的用戶端-伺服器架構,但集體處理的概念至關重要。這是因為 TFF 源自聯邦學習,這項技術最初旨在支援在用戶端裝置控制下,且可能基於隱私原因而無法簡單下載到集中位置的潛在敏感資料上進行運算。雖然此類系統中的每個用戶端都為系統計算結果貢獻資料和處理能力 (我們通常預期該結果對所有參與者都有價值),但我們也力求保護每個用戶端的隱私和匿名性。
因此,雖然大多數分散式運算架構旨在從個別參與者的角度表示處理 - 也就是說,在個別點對點訊息交換的層級,以及參與者本機狀態轉換與傳入和傳出訊息的相互依賴性,但 TFF 的聯邦核心旨在從全域系統範圍的角度描述系統的行為 (類似於例如MapReduce)。
因此,雖然用於一般用途的分散式架構可能會提供諸如 send 和 receive 之類的操作作為建構區塊,但 FC 提供了諸如 tff.federated_sum
、tff.federated_reduce
或 tff.federated_broadcast
等建構區塊,它們封裝了簡單的分散式協定。
語言
Python 介面
TFF 使用內部語言來表示聯邦運算,其語法由 computation.proto 中的可序列化表示法定義。FC API 的使用者通常不需要直接與此語言互動。相反地,我們提供 Python API (tff
命名空間),它會將其包裝起來,作為定義運算的方式。
具體來說,TFF 提供了 Python 函數裝飾器,例如 tff.federated_computation
,它會追蹤裝飾函數的主體,並以 TFF 語言產生聯邦運算邏輯的可序列化表示法。以 tff.federated_computation
裝飾的函數充當此類可序列化表示法的載體,並且可以將其作為建構區塊嵌入另一個運算的主體中,或在調用時按需執行。
這只是一個範例;更多範例可以在自訂演算法教學課程中找到。
@tff.federated_computation(tff.FederatedType(np.float32, tff.CLIENTS))
def get_average_temperature(sensor_readings):
return tff.federated_mean(sensor_readings)
熟悉非 Eager TensorFlow 的讀者會發現,這種方法類似於編寫 Python 程式碼,該程式碼在定義 TensorFlow 圖表的 Python 程式碼區段中使用諸如 tf.add
或 tf.reduce_sum
等函數。雖然程式碼在技術上是以 Python 表示的,但其目的是建構 tf.Graph
的可序列化表示法,並且是由 TensorFlow 執行階段在內部執行的圖表,而不是 Python 程式碼。同樣地,可以將 tff.federated_mean
視為將聯邦運算元插入由 get_average_temperature
表示的聯邦運算中。
FC 定義語言的部分原因與上述事實有關,即聯邦運算指定分散式集體行為,因此,它們的邏輯是非本機的。例如,TFF 提供了運算元,其輸入和輸出可能存在於網路中的不同位置。
這需要一種語言和類型系統來捕捉分散式的概念。
類型系統
聯邦核心提供以下類型類別。在描述這些類型時,我們指出了類型建構函式,並介紹了一種簡潔的表示法,因為它是描述運算和運算元類型的一種便捷方式。
首先,以下是概念上與現有主流語言中發現的類型相似的類型類別
張量類型 (
tff.TensorType
)。與 TensorFlow 中一樣,這些具有dtype
和shape
。唯一的區別是,此類型的物件不僅限於 Python 中的tf.Tensor
執行個體,這些執行個體表示 TensorFlow 圖表中 TensorFlow 運算元的輸出,而且還可以包括可以產生的資料單位,例如,作為分散式彙總協定的輸出。因此,TFF 張量類型只是 Python 或 TensorFlow 中此類型的具體實體表示法的抽象版本。TFF 的
TensorTypes
在其 (靜態) 形狀處理方面可能比 TensorFlow 更嚴格。例如,TFF 的類型系統將具有未知秩的張量視為可從相同dtype
的任何其他張量指派,但不可指派至任何具有固定秩的張量。這種處理方式防止了某些執行階段失敗 (例如,嘗試將未知秩的張量重新塑形為元素數量不正確的形狀),但代價是在 TFF 接受為有效的運算方面更為嚴格。張量類型的簡潔表示法是
dtype
或dtype[shape]
。例如,int32
和int32[10]
分別是整數和整數向量的類型。序列類型 (
tff.SequenceType
)。這些是 TFF 的抽象等效項,相當於 TensorFlow 的具體概念tf.data.Dataset
。序列的元素可以依序使用,並且可以包括複雜類型。序列類型的簡潔表示法是
T*
,其中T
是元素的類型。例如,int32*
表示整數序列。具名元組類型 (
tff.StructType
)。這些是 TFF 建構元組和類似字典結構的方式,這些結構具有預定義數量的元素,這些元素具有特定類型,具名或未具名。重要的是,TFF 的具名元組概念涵蓋 Python 引數元組的抽象等效項,即元素集合,其中某些 (但並非全部) 已命名,而某些是位置性的。具名元組的簡潔表示法是
<n_1=T_1, ..., n_k=T_k>
,其中n_k
是可選的元素名稱,而T_k
是元素類型。例如,<int32,int32>
是未具名整數對的簡潔表示法,而<X=float32,Y=float32>
是名為X
和Y
的浮點數對的簡潔表示法,它們可以表示平面上的點。元組可以巢狀,也可以與其他類型混合,例如,<X=float32,Y=float32>*
將是點序列的簡潔表示法。函數類型 (
tff.FunctionType
)。TFF 是一個函數式程式設計架構,函數被視為一級值。函數最多有一個引數,且只有一個結果。函數的簡潔表示法是
(T -> U)
,其中T
是引數的類型,而U
是結果的類型,如果沒有引數,則為( -> U)
(雖然無引數函數是一個退化的概念,主要只存在於 Python 層級)。例如,(int32* -> int32)
是將整數序列縮減為單個整數值的函數類型的表示法。
以下類型解決了 TFF 運算的分散式系統方面。由於這些概念對於 TFF 來說有些獨特,因此我們建議您參考自訂演算法教學課程,以取得額外的註解和範例。
放置類型。除了
tff.SERVER
和tff.CLIENTS
這 2 個常值形式 (您可以將其視為此類型的常數) 之外,此類型尚未在公開 API 中公開。但是,它在內部使用,並將在未來的版本中引入公開 API。此類型的簡潔表示法是placement
。放置表示扮演特定角色的系統參與者集合。初始版本針對用戶端-伺服器運算,其中有 2 組參與者:用戶端和伺服器 (您可以將後者視為單例群組)。但是,在更精細的架構中,可能會有其他角色,例如多層系統中的中繼彙總器,它們可能會執行不同類型的彙總,或使用與伺服器或用戶端使用的資料壓縮/解壓縮類型不同的資料壓縮/解壓縮類型。
定義放置概念的主要目的是作為定義聯邦類型的基礎。
聯邦類型 (
tff.FederatedType
)。聯邦類型的值是由特定放置 (例如tff.SERVER
或tff.CLIENTS
) 定義的系統參與者群組託管的值。聯邦類型由放置值 (因此,它是相依類型)、成員組成的類型 (每個參與者在本機託管的內容類型),以及額外的位元all_equal
(指定所有參與者是否在本機託管相同的項目) 定義。聯邦類型值的簡潔表示法,包括類型
T
的項目 (成員組成),每個項目由群組 (放置)G
託管,為T@G
或{T}@G
,分別設定或未設定all_equal
位元。例如
{int32}@CLIENTS
表示聯邦值,它由一組可能不同的整數組成,每個用戶端裝置一個整數。請注意,我們談論的是單個聯邦值,它包含網路中多個位置出現的多個資料項目。一種考慮方式是將其視為具有「網路」維度的張量,儘管這種類比並不完美,因為 TFF 不允許對聯邦值的成員組成進行隨機存取。{<X=float32,Y=float32>*}@CLIENTS
表示聯邦資料集,它是由多個XY
座標序列組成的值,每個用戶端裝置一個序列。<weights=float32[10,5],bias=float32[5]>@SERVER
表示伺服器上的權重和偏差張量的具名元組。由於我們已刪除大括號,這表示已設定all_equal
位元,即只有一個元組 (無論託管此值的叢集中可能有多少個伺服器複本)。
建構區塊
聯邦核心的語言是一種lambda 演算形式,帶有一些額外的元素。
它提供了目前在公開 API 中公開的以下程式設計抽象概念
TensorFlow 運算 (
tff.tensorflow.computation
)。這些是 TensorFlow 程式碼的區段,使用tff.tensorflow.computation
裝飾器包裝為 TFF 中的可重複使用元件。它們始終具有函數類型,並且與 TensorFlow 中的函數不同,它們可以採用序列類型的結構化參數或傳回結構化結果。這是一個範例,類型為
(int32* -> int)
的 TF 運算,它使用tf.data.Dataset.reduce
運算元來計算整數總和@tff.tensorflow.computation(tff.SequenceType(np.int32)) def add_up_integers(x): return x.reduce(np.int32(0), lambda x, y: x + y)
內建函數 或聯邦運算元 (
tff.federated_...
)。這是一個函數程式庫,例如tff.federated_sum
或tff.federated_broadcast
,它們構成了 FC API 的主體,其中大多數表示用於 TFF 的分散式通訊運算元。我們將這些稱為內建函數,因為它們有點像內建函數,它們是一組開放式、可擴充的運算元,TFF 可以理解它們,並將其編譯為較低層級的程式碼。
這些運算元大多數具有聯邦類型的參數和結果,並且大多數是可以應用於各種資料類型的範本。
例如,
tff.federated_broadcast
可以視為函數類型T@SERVER -> T@CLIENTS
的範本運算元。Lambda 運算式 (
tff.federated_computation
)。TFF 中的 lambda 運算式相當於 Python 中的lambda
或def
;它由參數名稱和包含對此參數的參照的主體 (運算式) 組成。在 Python 程式碼中,這些可以透過使用
tff.federated_computation
裝飾 Python 函數並定義引數來建立。以下是我們先前已提及的 lambda 運算式的範例
@tff.federated_computation(tff.FederatedType(np.float32, tff.CLIENTS)) def get_average_temperature(sensor_readings): return tff.federated_mean(sensor_readings)
放置常值。目前,僅有
tff.SERVER
和tff.CLIENTS
允許定義簡單的用戶端-伺服器運算。函數調用 (
__call__
)。任何具有函數類型的物件都可以使用標準 Python__call__
語法調用。調用是一個運算式,其類型與被調用函數的結果類型相同。例如
add_up_integers(x)
表示先前定義的 TensorFlow 運算在引數x
上的調用。此運算式的類型為int32
。tff.federated_mean(sensor_readings)
表示在sensor_readings
上調用聯邦平均運算元。此運算式的類型為float32@SERVER
(假設來自上述範例的環境定義)。
形成元組和選取其元素。表單
[x, y]
、x[y]
或x.y
的 Python 運算式,出現在以tff.federated_computation
裝飾的函數主體中。