文章目录
题目:FederBoost: Private Federated Learning for GBDT
1. 每文三问
-
文章在解决什么问题?
FL 有两个问题尚未解决:
- unable to handle vertically partitioned data
- unable to support decision trees
现有的用于垂直分区数据或决策树的 FL 解决方案需要大量的加密操作。
-
用了什么方法 (创新方法) ?
提出框架 FederBoost,它支持在 both horizontally and vertically partitioned data 训练 GBDT。vertical FederBoost 不需要任何加密操作,horizontal FederBoost 只需要轻量级的安全聚合。
-
效果如何?
对于 vertical and horizontal FederBoost 都实现了相同水平的 AUC ,即使是在广域网中,也能在半小时内完成训练。
AUC是一个用于二分类模型的模型评价指标 https://zhuanlan.zhihu.com/p/33407505
2. Introduction
设计 FederBoost 的一个关键启发是:GBDT 的整个训练过程依赖于 the order of samples instead of their samples/feature values.
为什么 vertical(vertical partitioned data) FederBoost 不需要任何加密操作?
在 vertical FederBoost 中,让持有标签的参与者从其他参与者那里收集样本的顺序就可以 实现 与集中式学习完全相同的方式来运行 GBDT训练算法。
我们进一步利用 bucketization and differential privacy 来保护样本的顺序:参与者将一个特征的排序样本划分为桶,这只揭示了桶的顺序;并为每个桶添加不同的噪声。
因此,vertical FederBoost 无需使用任何加密操作就可以实现隐私。
horizontally partitioned data 的情况较复杂**(待看)**
原因 :样本和标签分布在所有参与者中,没有人知道一个特征的样本顺序。
解决:提出一种分布式桶构建的新方法,xxxxxx
本文的贡献:
- 提出 FederBoost :一个用于 GBDT 的 private 联邦学习框架。它支持 both horizontally and vertically partitioned data
- 在 horizontal FederBoost 中,提出一种分布式桶构造新方法
3. Preliminaries
3.1 GBDT
1)决策树由 nodes and edges 组成:
- 每个 internal node 代表一个特征的 “test”
- 每个 edge 代表 “test” 的结果
- 每个 leaf node 表示预测结果
从根节点到叶节点的路径表示一条预测规则。
2)描述 GBDT 算法如何工作(对于给定数据集 X ∈ R n ∗ m {X \in R^{n*m}} X∈Rn∗m):
-
首先,对 each sample 初始化预测结果 ${\hat{y}_i^0} $ with random values
-
训练第 t {t} t 棵决策树
-
对于每个 sample ,计算 一阶、二阶梯度 g i 、 h i { g_i 、 h_i } gi、hi
-
对树从 root 到 leaf 的每一个节点 run the following steps
a)对个每个特征,找到样本的最佳分割,使得 L s p l i t {L_{split}} Lsplit 最大
注: I L 、 I R 、 I {I_L、I_R、I} IL、IR、I 中 samples 均按 feature value 排了序
b)选择对应 maximal L s p l i t {L_{split}} Lsplit 的 feature,并按该 feature split samples
-
计算叶节点的权重:落入该叶节点上的样本的预测结果
w = − ∑ i ∈ I g i ∑ i ∈ I h i + λ w = - { \sum_{i \in I} g_i \over \sum_{i \in I} h_i + \lambda } w=−∑i∈Ihi+λ∑i∈Igi
-
3)通过梯度直方图找到 a feature 的 best split
大多数 GBDT 框架通过为每个特征构建梯度直方图来 summarize 梯度信息,然后找到该特征的 best spilt。具体来说,对于每个特征,训练算法基于 feature value 对 samples 进行排序,然后将样本划分到 q {q} q 个 bucket 中。对于每个桶,计算 G = ∑ i ∈ b u c k e t g i {G = \sum_{i \in bucket} g_i } G=∑i∈bucketgi 和 H = ∑ i ∈ b u c k e t h i {H = \sum_{i \in bucket} h_i } H=∑i∈buckethi 。一个特征的梯度直方图由所有桶的 G s 、 H s {G_s 、H_s} Gs、Hs 组成。Then,一个特征的 beat split 通过最大化下面式子得到:
注:该过程仅需要 g i 、 h i { g_i 、 h_i } gi、hi 、样本的顺序(the order of samples)
3.2 FL
谷歌提出的 horizontal FL method 是通过迭代地将局部训练的模型聚合为一个联合的全局模型,将深度神经网络的模型训练过程分布到多个参与者。在该协议中有两个角色:一个参数服务器、 l {l} l 个参与方。
训练过程:
- 参数服务器初始化模型 with random values,并发送给所有参与方
- 在每次迭代中,每个参与方用其本地数据训练接收到的模型,并将梯度发送给参数服务器
- 参数服务器聚合接收到的梯度并更新全局模型
这种优雅的范式不能直接应用于 vertical FL ,因为参与者具有不同的特征空间,所以不能在局部训练模型。
4. Vertical FederBoost
4.1 Training
训练 GBDT 模型,我们需要: P l {P_l} Pl 中的标签 y {y} y 、先前树的预测结果汇总、样本的顺序
原始训练GBDT步骤:每个参与者对本地样本按特征值排序,并告诉 P l {P_l} Pl 顺序。 P l {P_l} Pl 独自完成整个训练过程
优点:
- 参与者只需要传递样本顺序而不是样本值,仅需传递更少的信息
- 排序信息只需要传输一次, P l {P_l} Pl 可以使用它对模型进行微调,无需进一步通信
缺点:
-
样本的顺序会泄露信息
举例:对于特征 “salary” , P l {P_l} Pl 获取到 Alice’s salary ≤ Bob’s salary ≤ Charly’s salary,if P l {P_l} Pl knows Alice’s salary and Charly’s salary, it can infer Bob’s salary (or at least the range)
解决上面的问题:
-
putting samples into buckets and adding differentially private noise.
具体地,对于每个特征, P i {P_i} Pi 根据特征值对样本进行排序,并将样本分区到 q {q} q 个桶中。这样 P l {P_l} Pl 只知道桶的顺序,不知道桶内样本的顺序;为了进一步保护不同桶中两个样本的顺序,对每个桶中添加不同的 noise。也就是说,对于最初分配给第 i {i} i 个桶的样本:
- with probability p = e ϵ e ϵ + q − 1 {p = {e^\epsilon \over {e^\epsilon + q - 1}}} p=eϵ+q−1eϵ,it stays in the ith bucket
- with probability q = 1 e ϵ + q − 1 {q = {1 \over {e^\epsilon + q - 1}}} q=eϵ+q−11,it moves to another bucket
完善后的GBDT训练步骤:
-
被动参与者(没有标签的参与者) P 1 . . . P l − 1 {P_1 ... P_{l-1}} P1...Pl−1 首先在本地构建他们的桶,并把每个桶中的样本id 发送给 P l {P_l} Pl 。该过程只需要完成一次, P l {P_l} Pl 即可使用这些桶来微调模型(即:使用不同的超参数多次训练模型)
-
接下来全是 P l {P_l} Pl 的工作
- 首先,计算每个样本的一阶和二阶梯度。当一个新树初始化时,需要根据先前树的预测结果 y ^ 1 , . . . , y ^ n {\hat{y}_1, ... , \hat{y}_n} y^1,...,y^n 来更新这些梯度。
- P l {P_l} Pl 根据梯度直方图找到 the best split feature s p l i t j {split_j} splitj ,然后把 s p l i t j {split_j} splitj 发送给 P j {P_j} Pj (目的:用于接下来的 prediction)
- P l {P_l} Pl 根据 s p l i t j {split_j} splitj 对 buckets 进行 split