关于联邦学习的背景这里就不做过多介绍了,感兴趣的同学可以去百度一下。联邦学习主要是为了解决数据孤岛和多方安全计算问题的,简单地说就是大家都拿出各自的数据一起建模,但是对方又不能看到或者得到自己的数据,训练的模型大家都可以用。
联邦学习分为:横向联邦学习,在两个数据集的用户特征重叠较多而用户重叠较少的情况下,我们把数据集按照横向 (即用户维度)切分,并取出双方用户特征相同而用户不完全相同的那部分数据进行训练,例如,银行A和银行B都有自己的客户流水信息,特征是一样的,交易时间、金额等,但是用户不同,那么银行A和银行B就可以一起进行横向联邦学习建模了,相当于是增加了训练集;纵向联邦学习,在两个数据集的用户重叠较多而用户特征重叠较少的情况下,我们把数据集按照纵向 即特征维度)切分,并取出双方用户相同而用户特征不完全相同的那部分数据进行训练,例如,银行A有客户的流水信息,收单机构或者ERP服务商B有顾客的消费信息,且A和B的客户有很大部分是相同的,那么A和B就可以联合进行纵向联邦学习建模了,例如风控模型、用户画像等,纵向联邦学习相当于是数据集大小不变,但是特征维度增加了;迁移联邦学习,在两个数据集的用户与用户特征重叠都较少的情况下,我们不对数据进行切分,而可以利用迁移学习来克服数据或标签不足的情况。
目前主要的联邦学习解决方案有:微众银行的fate,谷歌的ttf(基于tensorflow),PySyft(基于PyTorch),蚂蚁金服共享机器学习等,本文主要介绍基于k8s部署fate框架kubefate。
fate提供了多种部署方式,包括单机版部署、本地集群部署、k8s部署、docker compose部署等方式,具体可参考下面链接:
FATE:https://github.com/FederatedAI/FATE
KubeFate(k8s):https://github.com/FederatedAI/KubeFATE/tree/master/k8s-deploy
KubeFate(docker compose):https://github.com/FederatedAI/KubeFATE/tree/master/docker-deploy
FATE官网:https://cn.fedai.org/
FATE API:https://fate.readthedocs.io/en/latest/
如果单机版的可以满足需求,自然以版本单机部署最好。对于集群版,可以采用本地部署或者kubefate部署,本地部署的缺点就是步骤比较麻烦,需要部署的组件比价多,而且要修改很多配置文件,如ip地址、端口等,非常容易出错,这也是fate官方做的不好的地方,没有一键部署脚本,很多地方都要修改。KubeFate可以基于docker compose部署,也可以基于k8s部署,官方推荐在开发或者测试环境可以基于docker compose部署,生产环境基于k8s部署,不过我想一般很少有人会把测试和生产使用不同的环境,基于k8s部署KubeFate的好处是部署简单,无需关心内部的很多细节配置,只要把相关镜像和文件加载进去即可。但是对于不熟悉k8s的同学来说,最好还是采用本地部署的方式,毕竟维护k8s本身也需要专业的团队。
FATE cluster有两种部署模式: exchange模式和直连模式,本文只有两个集群,使用的是直连模式。
exchange模式:每一方都连接到exchange,它有所有各方的代理地址。对于exchange集群的cluster.yaml,只需要配置partyList,无需exchange配置信息。对于其他party,只需要填写exchange ip和port即可,无需partylist配置项。
直连模式:party之间直接连接,不需要配置exchange信息,把各party信息配置到partyList即可。
在部署之前,首先保证有两个可以正常运行的k8s集群(或者一个k8s集群,使用namespace隔离也是可以的),并且两个集群有公网访问功能,集群之间网络互通(对于内网服务器可以先在有外网的测试环境下载镜像然后拷贝到内网环境)。本文使用的为两个单master的k8s集群,每个集群三台机器,kubefate版本为1.4.0。k8s集群ip如下:
k8s集群1(party1)IP | k8s集群2(party2)IP |
172.30.251.178/app1(k8s master) | 172.30.251.51(k8s master) |
172.30.251.179/app2 | 172.30.251.50 |
172.30.251.180/app3 | 172.30.251.49 |
(1)在k8s master节点服务器上下载kubefate文件并解压:
https://github.com/FederatedAI/KubeFATE/releases/download/v1.4.0/kubefate-k8s-v1.4.0.tar.gz
下面步骤默认不说明的情况下是在两个集群master节点上都执行。
(2)配置rbac
kubectl apply -f ./rbac-config.yaml
(3)安装kubefate server
kubectl apply -f ./kubefate.yaml
kubefate.yaml文件主要是一些组件服务配置,如用户密码等,具体可以参考官方说明。
查看部署结果如下,如果两个pod的状态都是Running说明kubefate server已经部署成功了。:
(4)查看ingress的pod运行的的node的名称
(5)设置对应的host
party1
echo "172.30.251.179 kubefate.net" >> /etc/hosts
party2
echo "172.30.251.50 kubefate.net" >> /etc/hosts
(6) 查看是否连通
如果可以正确打印版本信息,且没有任何错误,则表示连通。
(7)创建namespace
在party1上执行:
kubectl create namespace fate-9999
在party2上执行:
kubectl create namespace fate-10000
为了便于识别,9999和10000也是两个集群的partyId。
(8)修改cluster.yaml
这里需要注意如本章2.2节介绍的那样,并没有使用exchange模式,使用的是直连模式,所以删除了exchange配置信息。cluster.yaml的配置信息可以参见官方说明。
修改party1的cluster.yaml如下:
name: fate-9999
namespace: fate-9999 ##和(4)中的namespace一致
chartName: fate
chartVersion: v1.4.0
partyId: 9999 ##partyId
registry: ""
pullPolicy:
persistence: false
modules:
- rollsite
- clustermanager
- nodemanager
- mysql
- python
# - client
rollsite:
type: NodePort
nodePort: 30009 ##己方的nodePort
partyList: ##在此添加所有参与方信息
- partyId: 10000 ##对方partyId
partyIp: 172.30.251.50 ##对方ip
partyPort: 30010 ##对方partyPort
nodeSelector: {}
nodemanager:
count: 3
sessionProcessorsPerNode: 4
list:
- name: nodemanager
nodeSelector: {}
sessionProcessorsPerNode: 2
subPath: "nodemanager"
existingClaim: ""
storageClass: "nodemanager"
accessMode: ReadWriteOnce
size: 1Gi
python:
fateflowType: NodePort
fateflowNodePort: 30109
nodeSelector: {}
mysql:
nodeSelector: {}
ip: mysql
port: 3306
database: eggroll_meta
user: fate
password: fate_dev
subPath: ""
existingClaim: ""
storageClass: "mysql"
accessMode: ReadWriteOnce
size: 1Gi
# If use external MySQL, uncomment and change this section
# externalMysqlIp: mysql
# externalMysqlPort: 3306
# externalMysqlDatabase: eggroll_meta
# externalMysqlUser: fate
# externalMysqlPassword: fate_dev
# If FATE-Serving deployed, uncomment and change
# servingIp: 192.168.9.1
# servingPort: 30209
修改party2的cluster.yaml如下:
name: fate-10000
namespace: fate-10000 ##和(4)中创建的namespace保持一致
chartName: fate
chartVersion: v1.4.0
partyId: 10000 ## partyId
registry: ""
pullPolicy:
persistence: false
modules:
- rollsite
- clustermanager
- nodemanager
- mysql
- python
# - client
rollsite:
type: NodePort
nodePort: 30010 ##己方nodePort
partyList: ##把各参与方信息都加到下面
- partyId: 9999 ##对方partyId
partyIp: 172.30.251.179 ##对方ip
partyPort: 30009 ##对方nodePort
nodeSelector: {}
nodemanager:
count: 3
sessionProcessorsPerNode: 4
list:
- name: nodemanager
nodeSelector: {}
sessionProcessorsPerNode: 2
subPath: "nodemanager"
existingClaim: ""
storageClass: "nodemanager"
accessMode: ReadWriteOnce
size: 1Gi
python:
fateflowType: NodePort
fateflowNodePort: 30109
nodeSelector: {}
mysql:
nodeSelector: {}
ip: mysql
port: 3306
database: eggroll_meta
user: fate
password: fate_dev
subPath: ""
existingClaim: ""
storageClass: "mysql"
accessMode: ReadWriteOnce
size: 1Gi
# If use external MySQL, uncomment and change this section
# externalMysqlIp: mysql
# externalMysqlPort: 3306
# externalMysqlDatabase: eggroll_meta
# externalMysqlUser: fate
# externalMysqlPassword: fate_dev
# If FATE-Serving deployed, uncomment and change
# servingIp: 192.168.9.1
# servingPort: 30209
(9)部署fate cluster
kubefate cluster install -f ./cluster-A.yaml
执行命令后,会显示一条部署的job id,可以使用./kubefate job describe命令查看部署状态,直到Result显示为:Cluster install success(这一步可能需要很长时间):
如果忘记job id,可以使用 ./kubefate job list 查看
(10)查看fate运行状态
下面命令查看(9)中的ClusterId运行状态,可以看到 Status 为 Running,并打印出cluster信息。
./kubefate cluster describe 632176c5-7667-4177-abe7-eb39ac485d01
安装完毕以后,就可以测试 kubefate 了。
(1)分别打开party1和party2的python container:
kubectl exec -it svc/fateflow -c python -n fate-9999 -- bash
kubectl exec -it svc/fateflow -c python -n fate-10000 -- bash
(2)执行toy_example脚本
cd examples/toy_example/
python run_toy_example.py 10000 9999 1
最后可以看到 success to calculate secure_sum, it is 1999.9999999999999999 结果。