所以本篇博客重新梳理一下这个问题,首先对线性回归算法和同态加密进行一个简单的回顾,然后按照这篇论文中的思路对纵向联邦学习中的线性回归进行讲解。
线性回归的内容可以参考 [吴恩达机器学习课程(4)-Linear Regression with Multiple Variables](http://forestneo.com/2020/02/26/ML-吴恩达机器学习课程-04-Linear Regression with Multiple Variables/)。为了方便描述,我们采用了论文《Federated Machine Learning: Concept and Applications》中的 loss 函数,当然我们默认这个文章中的 loss 中少写了一个 1 2 \frac{1}{2} 21 的校正,下一节会提到。假如有 m m m 条数据 n n n 个特征, loss 函数为:
L = ∑ i = 1 m 1 2 ( h ( x i ) − y i ) 2 = ∑ i = 1 m 1 2 ( θ 0 ⋅ x i , 0 + θ 1 ⋅ x i , 1 + . . . + θ n ⋅ x i , n − y i ) 2 \begin{aligned} L &= \sum_{i=1}^{m} \frac{1}{2}\left( h(x_i)-y_i \right)^2\\ &=\sum_{i=1}^{m} \frac{1}{2}\left( \theta_0 \cdot x_{i,0} + \theta_1 \cdot x_{i,1} + ... + \theta_{n} \cdot x_{i,n} - y_i \right)^2 \end{aligned} L=i=1∑m21(h(xi)−yi)2=i=1∑m21(θ0⋅xi,0+θ1⋅xi,1+...+θn⋅xi,n−yi)2
为了得到最优解,我们采用梯度下降方法,给定学习率 η \eta η,优化的过程为:
θ j = θ j − η ⋅ ∑ i = 1 m ( h ( x i ) − y i ) ⋅ x i , j \theta_j = \theta_j - \eta \cdot \sum_{i=1}^{m} \left(h(x_i)-y_i\right) \cdot x_{i,j} θj=θj−η⋅i=1∑m(h(xi)−yi)⋅xi,j
更为主要的,Paillier 算法系统满足以下性质:
为了使得含义更明确,就这么记一下: [ [ x + y ] ] = [ [ x ] ] ⊕ [ [ y ] ] [\![x+y]\!] = [\![x]\!] \oplus [\![y]\!] [[x+y]]=[[x]]⊕[[y]],以及 [ [ x × y ] ] = [ [ x ] ] ⊗ y [\![x\times y]\!] = [\![x]\!] \otimes y [[x×y]]=[[x]]⊗y,这样子根据就可以直接看出来密文上的操作是想做加法还是做乘法了。
关于 Paillier 算法系统是如何实现同态加法和同态乘法的,可以参考:密码学-公钥加密算法 Paillier。
我们假设 A 端的数据为 x i A x_i^A xiA,B 端的数据为 x i B , y i x_i^B, y_i xiB,yi,那么线性回归对应的参数就是 Θ A , Θ B \Theta_A, \Theta_B ΘA,ΘB,假设归一化参数为 λ \lambda λ,那么优化目标就可以表示为(论文里面少了一个 1 2 \frac{1}{2} 21):
min Θ A , Θ B ∑ i 1 2 ∥ Θ A x i A + Θ B x i B − y i ∥ 2 + λ 2 ( ∥ Θ A ∥ 2 + ∥ Θ B ∥ 2 ) \min _{\Theta_{A}, \Theta_{B}} \sum_{i} \frac{1}{2}\left\|\Theta_{A} x_{i}^{A}+\Theta_{B} x_{i}^{B}-y_{i}\right\|^{2}+\frac{\lambda}{2}\left(\left\|\Theta_{A}\right\|^{2}+\left\|\Theta_{B}\right\|^{2}\right) ΘA,ΘBmini∑21∥∥ΘAxiA+ΘBxiB−yi∥∥2+2λ(∥ΘA∥2+∥ΘB∥2)
为了方便描述,我们简化一下,令 u i A = Θ A x i A , u i B = Θ B x i B u_{i}^{A}=\Theta_{A} x_{i}^{A}, u_{i}^{B}=\Theta_{B} x_{i}^{B} uiA=ΘAxiA,uiB=ΘBxiB,那么加密之后对应的 Loss 函数就可以写成以下形式。当然,也是为了方便,加密过程用双括号 [ [ ⋅ ] ] [\![\cdot]\!] [[⋅]] 表示(在 Latex 中,用[\![ ]\!]
表示,其中 \!
表示一个单位的负距离 ),正常的括号还是用圆括号表示。
L = ∑ i 1 2 ( u i A + u i B − y i ) 2 + λ 2 ( ∥ Θ A ∥ 2 + ∥ Θ B ∥ 2 ) \mathcal{L}=\sum_{i} \frac{1}{2}\left(u_{i}^{A}+u_{i}^{B}-y_{i}\right)^{2}+\frac{\lambda}{2}\left(\left\|\Theta_{A}\right\|^{2}+\left\|\Theta_{B}\right\|^{2}\right) L=i∑21(uiA+uiB−yi)2+2λ(∥ΘA∥2+∥ΘB∥2)
在梯度下降的过程中,对于第 j j j 个参数有:
∂ L ∂ θ A , j = ∑ i ( u i A + u i B − y i ) ⋅ x j + λ θ A , j ∂ L ∂ θ B , j = ∑ i ( u i A + u i B − y i ) ⋅ x j + λ θ B , j \begin{aligned} \frac{\partial \mathcal{L}}{\partial \theta_{A,j}} &= \sum_i (u_i^A + u_i^B - y_i) \cdot x_j + \lambda \theta_{A,j}\\ \frac{\partial \mathcal{L}}{\partial \theta_{B, j}} &= \sum_i (u_i^A + u_i^B - y_i) \cdot x_j + \lambda \theta_{B,j} \end{aligned} ∂θA,j∂L∂θB,j∂L=i∑(uiA+uiB−yi)⋅xj+λθA,j=i∑(uiA+uiB−yi)⋅xj+λθB,j
根据 SGD 的过程,现在问题就变成了参与方 A 和 B 如何得到 ∂ L ∂ θ A , j \frac{\partial \mathcal{L}}{\partial \theta_{A,j}} ∂θA,j∂L 和 ∂ L ∂ θ B , j \frac{\partial \mathcal{L}}{\partial \theta_{B,j}} ∂θB,j∂L 了。当然,在训练过程中,如果想知道 Loss 是多少,我们也可以算一下 Loss。接下来就面临着这么几个问题了:
当然,以上的三个问题都需要在不知道数据情况下给算出来。为了实现这个需求呢,我们引入一个参与方 C(半诚信的)来计算这些东西,总体思路呢是 A 和 B 把自己能算的加密之后给 C,然后 C 把中间结果利用同态的性质和合并一下,再返还给 A 和 B,这时候 A 和 B 一解密,哎,知道要的结果了,就很美滋滋。然后根据这个流程,我们回头看看上面的三个问题怎么解决。
因为数据不能泄露,所以肯定要加密,可以看一下这个过程:
[ [ ∂ L ∂ θ A , j ] ] = [ [ ∑ i ( u i A + u i B − y i ) ⋅ x j + λ θ A , j ] ] = [ [ ∑ i ( u i A + u i B − y i ) ⋅ x j ] ] ⊕ [ [ λ θ A , j ] ] = [ [ ( u 1 A + u 1 B − y 1 ) ⋅ x j ] ] ⏟ ⊕ . . . ⊕ [ [ ( u m A + u m B − y m ) ⋅ x j ] ] ⏟ ⊕ [ [ λ θ A , j ] ] \begin{aligned} \left[\!\!\left[\frac{\partial \mathcal{L}}{\partial \theta_{A,j}}\right]\!\!\right] &= \left[\!\!\left[\sum_i (u_i^A + u_i^B - y_i) \cdot x_j + \lambda \theta_{A,j}\right]\!\!\right]\\ &= \left[\!\!\left[\sum_i (u_i^A + u_i^B - y_i) \cdot x_j\right]\!\!\right] \oplus [\![\lambda \theta_{A,j}]\!]\\ &= \underbrace{\left[\!\!\left[(u_1^A + u_1^B - y_1) \cdot x_j \right]\!\!\right]} \oplus ... \oplus \underbrace{\left[\!\!\left[(u_m^A + u_m^B - y_m) \cdot x_j\right]\!\!\right]} \oplus [\![\lambda \theta_{A,j}]\!] \end{aligned} [[∂θA,j∂L]]=[[i∑(uiA+uiB−yi)⋅xj+λθA,j]]=[[i∑(uiA+uiB−yi)⋅xj]]⊕[[λθA,j]]= [[(u1A+u1B−y1)⋅xj]]⊕...⊕ [[(umA+umB−ym)⋅xj]]⊕[[λθA,j]]
对于 A 来说,最右边的 λ θ A , j \lambda \theta_{A,j} λθA,j 是可以自己算出来然后再加密的。对于第 i i i 条数据,自己是有 u i A u_i^A uiA 和 x j x_j xj 的,因此我们看上式花括号的咋算
[ [ ( u i A + u i B − y i ) ⋅ x j ] ] = [ [ u i A + u i B − y i ] ] x j = ( [ [ u i A ] ] ⊕ [ [ u i B − y i ] ] ) x j \begin{aligned} \left[\!\!\left[(u_i^A + u_i^B - y_i) \cdot x_j\right]\!\!\right] &= \left[\!\!\left[u_i^A + u_i^B - y_i \right]\!\!\right]^{x_j}\\ &= \left([\![u_i^A ]\!] \oplus [\![u_i^B - y_i ]\!]\right)^{x_j} \end{aligned} [[(uiA+uiB−yi)⋅xj]]=[[uiA+uiB−yi]]xj=([[uiA]]⊕[[uiB−yi]])xj
所以呢,实际上对于 A 来说,偏导就是:
[ [ ∂ L ∂ θ A , j ] ] = [ [ ∑ i ( u i A + u i B − y i ) ⋅ x j + λ θ A , j ] ] = [ [ ( u 1 A + u 1 B − y 1 ) ⋅ x j ] ] ⏟ ⊕ . . . ⊕ [ [ ( u m A + u m B − y m ) ⋅ x j ] ] ⏟ ⊕ [ [ λ θ A , j ] ] = ( [ [ u i A ] ] ⊕ [ [ u i B − y i ] ] ) x j ⏟ ⊕ . . . ⊕ ( [ [ u i A ] ] ⊕ [ [ u i B − y i ] ] ) x j ⏟ ⊕ [ [ λ θ A , j ] ] \begin{aligned} \left[\!\!\left[\frac{\partial \mathcal{L}}{\partial \theta_{A,j}}\right]\!\!\right] &= \left[\!\!\left[\sum_i (u_i^A + u_i^B - y_i) \cdot x_j + \lambda \theta_{A,j}\right]\!\!\right]\\ &= \underbrace{\left[\!\!\left[(u_1^A + u_1^B - y_1) \cdot x_j \right]\!\!\right]} \oplus ... \oplus \underbrace{\left[\!\!\left[(u_m^A + u_m^B - y_m) \cdot x_j\right]\!\!\right]} \oplus [\![\lambda \theta_{A,j}]\!]\\ &= \underbrace{\left([\![u_i^A ]\!] \oplus [\![u_i^B - y_i ]\!]\right)^{x_j}} \oplus ... \oplus\underbrace{\left([\![u_i^A ]\!] \oplus [\![u_i^B - y_i ]\!]\right)^{x_j}} \oplus [\![\lambda \theta_{A,j}]\!] \end{aligned} [[∂θA,j∂L]]=[[i∑(uiA+uiB−yi)⋅xj+λθA,j]]= [[(u1A+u1B−y1)⋅xj]]⊕...⊕ [[(umA+umB−ym)⋅xj]]⊕[[λθA,j]]= ([[uiA]]⊕[[uiB−yi]])xj⊕...⊕ ([[uiA]]⊕[[uiB−yi]])xj⊕[[λθA,j]]
所以呢,现在对于 A 来说怎么算偏导,思路就清晰了,大概是这么个流程:
上述流程看着挺 OK 的,并且 B 也可以进行这些操作得到偏导,但是存在这么一个问题:C 可以解密得到有数据含义的中间数据。这当然是不被接受的。注意到同态的性质,任何一个人都能对密文进行处理。所以我们可以对以上流程这么改进一下:
这个过程中,C 只作为中间数据的计算方,是得不到任何原始数据的。对于 A 来说,添加随机数也是为了防止 C C C 得到偏导。
实际上,知道梯度就可以完成模型参数更新的流程了。但是为了对 Loss 进行跟踪,一般参与方也需要知道每一轮的 Loss 值是多少,要是发现 Loss 不下降了,就知道模型训练的差不多了。回到开头,这个 Loss 为:
[ [ L ] ] = [ [ ∑ i 1 2 ( u i A + u i B − y i ) 2 + λ 2 ( ∥ Θ A ∥ 2 + ∥ Θ B ∥ 2 ) ] ] = [ [ ∑ i 1 2 ( u i A + u i B − y i ) 2 ] ] ⊕ [ [ λ 2 ∥ Θ A ∥ 2 ] ] ⊕ [ [ λ 2 ∥ Θ B ∥ 2 ] ] = [ [ 1 2 ( u i A + u i B − y i ) 2 ] ] ⏟ ⊕ . . . ⊕ [ [ 1 2 ( u i A + u i B − y i ) 2 ] ] ⏟ ⊕ [ [ λ 2 ∥ Θ A ∥ 2 ] ] ⊕ [ [ λ 2 ∥ Θ B ∥ 2 ] ] \begin{aligned} [\![\mathcal{L}]\!] &= \left[\!\!\left[ \sum_{i} \frac{1}{2}\left(u_{i}^{A}+u_{i}^{B}-y_{i}\right)^{2} +\frac{\lambda}{2}\left(\left\|\Theta_{A}\right\|^{2}+\left\|\Theta_{B}\right\|^{2}\right) \right]\!\!\right]\\ &= \left[\!\!\left[\sum_{i} \frac{1}{2}\left(u_{i}^{A}+u_{i}^{B}-y_{i}\right)^{2} \right]\!\!\right] \oplus \left[\!\!\left[\frac{\lambda}{2}\left\|\Theta_{A}\right\|^{2} \right]\!\!\right] \oplus \left[\!\!\left[\frac{\lambda}{2}\left\|\Theta_{B}\right\|^{2}\right]\!\!\right]\\ &= \underbrace{\left[\!\!\left[\frac{1}{2}\left(u_{i}^{A}+u_{i}^{B}-y_{i}\right)^{2}\right]\!\!\right]} \oplus ... \oplus \underbrace{\left[\!\!\left[\frac{1}{2}\left(u_{i}^{A}+u_{i}^{B}-y_{i}\right)^{2}\right]\!\!\right]} \oplus \left[\!\!\left[\frac{\lambda}{2}\left\|\Theta_{A}\right\|^{2}\right]\!\!\right] \oplus \left[\!\!\left[\frac{\lambda}{2}\left\|\Theta_{B}\right\|^{2}\right]\!\!\right] \end{aligned} [[L]]=[[i∑21(uiA+uiB−yi)2+2λ(∥ΘA∥2+∥ΘB∥2)]]=[[i∑21(uiA+uiB−yi)2]]⊕[[2λ∥ΘA∥2]]⊕[[2λ∥ΘB∥2]]= [[21(uiA+uiB−yi)2]]⊕...⊕ [[21(uiA+uiB−yi)2]]⊕[[2λ∥ΘA∥2]]⊕[[2λ∥ΘB∥2]]
然后我们看左边的这一项,为了看着舒服, 上面的 1 2 \frac{1}{2} 21 就先不讨论了,因此有:
[ [ ( u i A + u i B − y i ) 2 ] ] = [ [ ( u i A ) 2 + ( u i B − y i ) 2 + 2 u i A ( u i B − y i ) ] ] = [ [ ( u i A ) 2 ] ] ⊕ [ [ ( u i B − y i ) 2 ] ] ⊕ [ [ 2 u i A ( u i B − y i ) ] ] = [ [ ( u i A ) 2 ] ] ⊕ [ [ ( u i B − y i ) 2 ] ] ⊕ ( [ [ 2 ( u i B − y i ) ] ] u i A ) \begin{aligned} \left[\!\!\left[(u_i^A+u_i^B-y_i)^2 \right]\!\!\right] &= \left[\!\!\left[(u_i^A)^2 + (u_i^B-y_i)^2 + 2u_i^A(u_i^B-y_i)\right]\!\!\right]\\ &= [\![(u_i^A)^2]\!] \oplus [\![(u_i^B-y_i)^2]\!] \oplus [\![2 u_i^A(u_i^B-y_i)]\!]\\ &= [\![(u_i^A)^2]\!] \oplus [\![(u_i^B-y_i)^2]\!] \oplus \left([\![2(u_i^B-y_i)]\!]^{u_i^A}\right) \end{aligned} [[(uiA+uiB−yi)2]]=[[(uiA)2+(uiB−yi)2+2uiA(uiB−yi)]]=[[(uiA)2]]⊕[[(uiB−yi)2]]⊕[[2uiA(uiB−yi)]]=[[(uiA)2]]⊕[[(uiB−yi)2]]⊕([[2(uiB−yi)]]uiA)
我们假设 A 要算这个东西,那么可以这么做:
根据这个原理,A 就能把 [ [ L ] ] [\![L]\!] [[L]] 计算出来了,然后让 C 把这个解密就好了,当然,为了不让 C 获得中间数据,也可以加上一个随机数 R A R_A RA。当然这个 Loss 不仅仅是 A,B也是可以算的。
有了偏导和 loss 的计算方法,都被 A 和 B 知道了,也就是模型就可以训练成功了。
由于 A 和 B 是分布式地获得了模型,数据也是分布在 A 和 B 两边,那么这个模型如何应用呢。也就是说,现在有一个新数据 x = ( x A , x B ) x=(x^A,x^B) x=(xA,xB),怎么预测对应的 y y y ?预测的过程中有(和训练过程一样,常数项已经隐含在 x A x^A xA 或者 x B x^B xB 中了):
y = θ A x A + θ B x B y=\theta_A x^A + \theta_B x^B y=θAxA+θBxB
所以各自计算然后汇总一下就可以估计出 y y y 了,更进一步如果想保护 y y y 的话(我们假设是 B 想算 y y y),可以让 B 根据 [ [ y ] ] = [ [ θ A x A ] ] ⊕ [ [ θ B x B ] ] ⊕ [ [ R B ] ] [\![y]\!] = [\![\theta_A x^A]\!] \oplus [\![\theta_B x^B]\!] \oplus [\![R_B]\!] [[y]]=[[θAxA]]⊕[[θBxB]]⊕[[RB]],然后让 C 解密之后减去 R B R_B RB 来得到 y y y。
到这里为止,看上去一开始论文中出现的疑问就都消除了,但是,现在依然有存在着一些问题:
这个我目前也没想到好的方法,可能一种潜在的解决方案是把某些特征都加上一个量使得中间结果不出现负数吧。但是感觉这个解决方案不完美,因为 u i B − y i = θ B x B − y i u_i^B-y_i=\theta_B x^B - y_i uiB−yi=θBxB−yi,这个 θ B \theta_B θB 是在训练过程中出现的,不可控的。对于第二个疑问, y y y 出现负数,这个感觉可以解决,直接对所有的 y i y_i yi 加上一个偏移量估计就好了。
本篇内容到这里就结束了,若想知道更多和信息安全有关的技术可在公众号留言。识别以下二维码可以成文本公众号的小粉丝,关注更多前沿技术。