調整用於學習的建議彙總

在 TensorFlow.org 上檢視 在 Google Colab 中執行 在 GitHub 上檢視原始碼 下載筆記本

tff.learning 模組包含許多彙總模型更新的方法,並提供建議的預設組態

在本教學課程中,我們將說明其基本動機、實作方式,並提供有關如何自訂其組態的建議。


pip install --quiet --upgrade tensorflow-federated
import math
import tensorflow_federated as tff
tff.federated_computation(lambda: 'Hello, World!')()
b'Hello, World!'

彙總方法由可傳遞至 tff.learning.algorithms.build_weighted_fed_avg (以及 build_unweighted_fed_avg) 作為其 model_aggregator 關鍵字引數的物件表示。因此,此處討論的彙總器可直接用於修改先前的 教學課程 (關於聯邦學習)。

可以使用 tff.aggregators.MeanFactory 表示 FedAvg 演算法中的基準加權平均值,如下所示

mean = tff.aggregators.MeanFactory()
iterative_process = tff.learning.algorithms.build_weighted_fed_avg(
    ...,
    model_aggregator=mean)

可用於擴充本教學課程涵蓋的加權平均值的技術包括

  • 歸零
  • 剪輯
  • 差分隱私
  • 壓縮
  • 安全彙總

擴充是透過組合完成的,其中 MeanFactory 包裝了內部工廠,它將部分彙總委派給該工廠,或者本身由另一個彙總工廠包裝。如需設計的更多詳細資訊,請參閱實作自訂彙總器教學課程。

首先,我們將說明如何個別啟用和組態這些技術,然後展示如何將它們組合在一起。

技術

在深入探討個別技術之前,我們先介紹分位數比對演算法,這對於組態以下技術很有用。

分位數比對

以下幾種彙總技術需要使用範數邊界來控制彙總的某些方面。此類邊界可以常數形式提供,但通常最好在訓練過程中調整邊界。建議的方式是使用 Andrew 等人 (2019) 的分位數比對演算法,最初是為了與差分隱私相容而提出,但更廣泛地適用。若要估計給定分位數的值,您可以使用 tff.aggregators.PrivateQuantileEstimationProcess。例如,若要調整為分佈的中位數,您可以使用

median_estimate = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=1.0, target_quantile=0.5, learning_rate=0.2)

使用分位數估計演算法的不同技術將需要演算法參數的不同值,我們將在稍後看到。一般而言,增加 learning_rate 參數表示更快地調整到正確的分位數,但變異數較高。no_noise 類別方法建構一個不新增雜訊以實現差分隱私的分位數比對程序。

歸零

歸零是指用零取代異常大的值。此處,「異常大」可能表示大於預先定義的閾值,或相對於先前運算回合中的值而言較大。歸零可以提高系統對錯誤用戶端上資料損毀的穩健性。

若要計算 L 無窮範數大於 ZEROING_CONSTANT 的值 (歸零) 的平均值,我們可以使用 tff.aggregators.zeroing_factory 包裝 tff.aggregators.MeanFactory,以執行歸零

zeroing_mean = tff.aggregators.zeroing_factory(
    zeroing_norm=MY_ZEROING_CONSTANT,
    inner_agg_factory=tff.aggregators.MeanFactory())

此處我們使用 zeroing_factory 包裝 MeanFactory,因為我們希望 zeroing_factory 的 (預先彙總) 效果應用於用戶端的值,然後再將這些值傳遞給內部 MeanFactory 以進行透過平均值進行彙總。

但是,對於大多數應用程式,我們建議使用具有分位數估計器的自適應歸零。若要執行此操作,我們可以使用分位數比對演算法,如下所示

zeroing_norm = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=10.0,
    target_quantile=0.98,
    learning_rate=math.log(10),
    multiplier=2.0,
    increment=1.0)
zeroing_mean = tff.aggregators.zeroing_factory(
    zeroing_norm=zeroing_norm,
    inner_agg_factory=tff.aggregators.MeanFactory())

# Equivalent to:
# zeroing_mean = tff.learning.robust_aggregator(clipping=False)

已選擇參數,以便程序非常快速地 (相對較大的 learning_rate) 適應略大於目前為止看到的最大值的值。對於分位數估計值 Q,用於歸零的閾值將為 Q * multiplier + increment

剪輯到 L2 範數邊界

剪輯用戶端更新 (投影到 L2 球上) 可以提高對離群值的穩健性。tff.aggregators.clipping_factory 的結構與上述討論的 tff.aggregators.zeroing_factory 完全相同,並且可以將常數或 tff.templates.EstimationProcess 作為其 clipping_norm 引數。建議的最佳做法是使用適度快速地適應適度高範數的剪輯,如下所示

clipping_norm = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=1.0,
    target_quantile=0.8,
    learning_rate=0.2)
clipping_mean = tff.aggregators.clipping_factory(
    clipping_norm=clipping_norm,
    inner_agg_factory=tff.aggregators.MeanFactory())

# Equivalent to:
# clipping_mean = tff.learning.robust_aggregator(zeroing=False)

根據我們在許多問題上的經驗,target_quantile 的精確值似乎不太重要,只要適當調整學習率即可。但是,相對於不使用剪輯,將其設定得非常低可能需要提高伺服器學習率以獲得最佳效能,這就是我們建議預設值為 0.8 的原因。

差分隱私

TFF 也支援差分隱私彙總,使用自適應剪輯和高斯雜訊。可以如下建構執行差分隱私平均的彙總器

dp_mean = tff.aggregators.DifferentiallyPrivateFactory.gaussian_adaptive(
    noise_multiplier=0.1, clients_per_round=100)

# Equivalent to:
# dp_mean = tff.learning.dp_aggregator(
#   noise_multiplier=0.1, clients_per_round=100, zeroing=False)

有關如何設定 noise_multiplier 引數的指南,請參閱 TFF DP 教學課程

有損壓縮

與 gzip 等無損壓縮相比,有損壓縮通常會產生更高的壓縮率,並且仍然可以與後續的無損壓縮結合使用。由於用戶端到伺服器通訊所需的時間更少,因此訓練回合完成得更快。由於學習演算法的固有隨機性,在達到一定閾值之前,有損壓縮的不準確性不會對整體效能產生負面影響。

預設建議是使用簡單的均勻量化 (例如,請參閱 Suresh 等人),並由兩個值參數化:張量大小壓縮 thresholdquantization_bits 的數量。對於每個張量 t,如果 t 的元素數量小於或等於 threshold,則不會壓縮它。如果它較大,則使用隨機捨入將 t 的元素量化為 quantizaton_bits 位元。也就是說,我們應用運算

t = round((t - min(t)) / (max(t) - min(t)) * (2**quantizaton_bits - 1)),

產生 [0, 2**quantizaton_bits-1] 範圍內的整數值。量化的值直接封裝到整數類型中以進行傳輸,然後應用逆轉換。

我們建議將 quantizaton_bits 設定為等於 8,並將 threshold 設定為等於 20000

compressed_mean = tff.aggregators.MeanFactory(
    tff.aggregators.EncodedSumFactory.quantize_above_threshold(
        quantization_bits=8, threshold=20000))

# Equivalent to:
# compressed_mean = tff.learning.compression_aggregator(zeroing=False, clipping=False)

調整建議

可以調整兩個參數 quantization_bitsthreshold,並且參與每個訓練回合的用戶端數量也會影響壓縮的有效性。

閾值。 選擇預設值 20000 是因為我們觀察到,元素數量少的變數 (例如常見層類型中的偏差) 對引入的雜訊更敏感。此外,實際上,從壓縮元素數量少的變數中幾乎沒有什麼好處,因為它們的未壓縮大小原本就相對較小。

在某些應用程式中,變更閾值的選擇可能是有意義的。例如,分類模型輸出層的偏差可能對雜訊更敏感。如果您正在訓練具有 20004 個詞彙的語言模型,您可能需要將 threshold 設定為 20004。

量化位元。 對於大多數使用者來說,quantization_bits 的預設值 8 應該沒問題。如果 8 的效果良好,並且您想要榨取更多效能,您可以嘗試將其降至 7 或 6。如果資源允許進行小型網格搜尋,我們建議您找出訓練變得不穩定或最終模型品質開始下降的值,然後將該值增加 2。例如,如果將 quantization_bits 設定為 5 有效,但將其設定為 4 會降低模型品質,我們會建議預設值為 6,以「安全起見」。

每個回合的用戶端。 請注意,顯著增加每個回合的用戶端數量可以使較小的 quantization_bits 值也能正常運作,因為量化引入的隨機不準確性可能會因對更多用戶端更新進行平均而變得均勻。

安全彙總

透過安全彙總 (SecAgg),我們指的是一種密碼協定,其中用戶端更新會以伺服器只能解密其總和的方式加密。如果回報的用戶端數量不足,伺服器將一無所知 - 而且在任何情況下,伺服器都無法檢查個別更新。這是使用 tff.federated_secure_sum_bitwidth 運算子實現的。

模型更新是浮點值,但 SecAgg 在整數上運作。因此,我們需要在離散化為整數類型之前,將任何較大的值剪輯到某個邊界。剪輯邊界可以是常數或自適應決定 (建議的預設值)。然後安全地對整數求和,並將總和對應回浮點域。

若要使用 SecAgg 和 MY_SECAGG_BOUND 作為剪輯邊界來計算加權值的平均值,請將 SecureSumFactory 傳遞給 MeanFactory,如下所示

secure_mean = tff.aggregators.MeanFactory(
    tff.aggregators.SecureSumFactory(MY_SECAGG_BOUND))

若要執行相同的操作,同時自適應地決定邊界

secagg_bound = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=50.0,
    target_quantile=0.95,
    learning_rate=1.0,
    multiplier=2.0)
secure_mean = tff.aggregators.MeanFactory(
    tff.aggregators.SecureSumFactory(secagg_bound))

# Equivalent to:
# secure_mean = tff.learning.secure_aggregator(zeroing=Fasle, clipping=False)

調整建議

已選擇自適應參數,以便邊界緊密 (我們不會在離散化中損失太多精確度),但很少發生剪輯。

如果調整參數,請記住 SecAgg 協定正在對加權模型更新求和,在平均值中加權之後。權重通常是本機處理的資料點數量,因此在不同任務之間,正確的邊界可能取決於此數量。

我們不建議在建立自適應 secagg_bound 時使用 increment 關鍵字引數,因為如果實際估計值最終很小,這可能會導致相對較大的精確度損失。

上述程式碼片段將僅對加權值使用 SecAgg。如果 SecAgg 也應該用於權重總和,我們建議將邊界設定為常數,因為在常見的訓練設定中,最大的可能權重將事先已知

secure_mean = tff.aggregators.MeanFactory(
    value_sum_factory=tff.aggregators.SecureSumFactory(secagg_bound),
    weight_sum_factory=tff.aggregators.SecureSumFactory(
        upper_bound_threshold=MAX_WEIGHT, lower_bound_threshold=0.0))

組合技術

上面介紹的用於擴充平均值的個別技術可以組合在一起。

我們建議在用戶端應用這些技術的順序為

  1. 歸零
  2. 剪輯
  3. 其他技術

tff.aggregators 模組中的彙總器是透過在「外部彙總器」內包裝「內部彙總器」(其預先彙總效果最後發生,而後彙總效果首先發生) 來組合的。例如,若要執行歸零、剪輯和壓縮 (依此順序),可以撰寫

# Compression is innermost because its pre-aggregation effects are last.
compressed_mean = tff.aggregators.MeanFactory(
    tff.aggregators.EncodedSumFactory.quantize_above_threshold(
        quantization_bits=8, threshold=20000))
# Compressed mean is inner aggregator to clipping...
clipped_compressed_mean = tff.aggregators.clipping_factory(
    clipping_norm=MY_CLIPPING_CONSTANT,
    inner_agg_factory=compressed_mean)
# ...which is inner aggregator to zeroing, since zeroing happens first.
final_aggregator = tff.aggregators.zeroing_factory(
    zeroing_norm=MY_ZEROING_CONSTANT,
    inner_agg_factory=clipped_compressed_mean)

請注意,此結構符合學習演算法的預設彙總器

其他組合也是可能的。當我們確信我們可以提供適用於多種不同應用程式的預設組態時,我們會擴充此文件。如需實作新想法,請參閱實作自訂彙總器教學課程。