题图摄于北海公园

(本文系转发VMware云原生实验室工程师彭路的文章)

FATE(Federated AI Technology Enabler)是联邦机器学习技术的一个框架,其旨在提供安全的计算框架来支持联邦 AI 生态。FATE 实现了基于同态加密和多方计算(MPC)的安全计算协议,它支持联邦学习架构和各种机器学习算法的安全计算,包括逻辑回归、基于树的算法、深度学习和转移学习。

联邦机器学习又名联邦学习、联合学习与联盟学习,它能有效帮助多个机构在满足用户隐私保护、数据安全和政府法规的要求下,进行数据使用和机器学习建模,消除由于行业竞争、隐私安全与行政手续等问题带来的数据孤岛,让以数据为基础的机器学习顺利进行。

KubeFATE支持通过Docker Compose和Kubernetes进行FATE部署。我们建议使用Docker Compose安装快速开发和学习FATE集群,同时使用Kubernetes安装生产环境。

深度神经网络(DNN)是在输入和输出层之间具有多层的人工神经网络(ANN)。

本文以经典的神经网络MNIST为例子,展示联邦学习版的深度神经网络训练过程。我们使用KubeFATE快速进行FATE框架的部署。因为模拟联邦学习的双方,我们需要准备两台Ubuntu的机器(物理机或虚拟机)。

1

安装docker和docker-compose

Ubuntu 安装docker:

$ sudo apt-get update

$ sudo apt-get install \

    apt-transport-https \

    ca-certificates \

    curl \

    gnupg-agent \

    software-properties-common

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

$ sudo apt-get update

$ sudo apt-get install docker-ce docker-ce-cli containerd.io

安装docker-compose:

$ sudo curl -L https://github.com/docker/compose/releases/download/1.23.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

$ sudo chmod +x /usr/local/bin/docker-compose

2

安装KubeFATE

学习环境推荐使用Docker方式部署。使用Docker方式部署分为两步,先根据parties.conf配置文件生成docker-compose文件。通过scp把docker-compose文件复制到目标机器上,然后通过ssh命令登录到目标机器并运“docker-compose up”。

选择两台机器其中之一作为部署机。

1.在KubeFATE的release页面下载软件包kubefate-docker-compose.tar.gz并解压:

$ wget https://github.com/FederatedAI/KubeFATE/releases/download/v1.3.0-a/kubefate-docker-compose.tar.gz

$ tar xzf kubefate-docker-compose.tar.gz

2.进入docker-deploy/ 目录,修改parties.conf文件:

$ cd docker-deploy

$ vi parties.conf

parties.conf:

user=root

dir=/data/projects/fate

partylist=(10000 9999)

partyiplist=(10.160.175.20 10.160.162.5)

servingiplist=(10.160.175.20 10.160.162.5)

exchangeip=

说明:

user:两台目标机器的用户id,建议用户root或权限合适的用户。

dir:目标机器上存放docker-compose文件的目录。

partylist:FATE集群的party列表。这里是两方,用数字表示。

partyiplist:FATE训练集群的IP地址,与partylist对应,例如上例id为10000的训练集群ip地址是10.160.175.20。注意这里要替换成你准备的两台机器对应的IP。

servingiplist:FATE在线推理集群的IP地址,与partylist对应,可以和训练集群在一台机器上,也可以单独是一台机器。本文里训练集群和在线推理集群使用同一台机器。

exchangeip:多于两方部署的时候推荐使用exchange模式。Exchange是一个集中交换数据的节点,记录了所有party的IP地址,每个party只需要知道exchange节点的IP地址就可交换数据。本文是两方直连,所有不填写exchange。

3.生成部署FATE的docker-compose文件

$ bash generate_config.sh

命令会在outputs文件夹下面生成对应的压缩包:confs-<partyID>.tar和serving-<partyID>.tar。

4.部署FATE

$ bash docker_deploy.sh all

因为用到了scp和ssh命令,所以运行这条命令的时候需要输入密码。为了方便可以在部署机和目标机之间做免密码处理。

两台机器在互联网可用环境下,Docker会自动下载FATE需要的镜像。如果是没有互联网的环境,参考Github上使用离线镜像文章。 (https://github.com/FederatedAI/KubeFATE/tree/master/registry)

5.免密处理(可选)

用10.160.175.20作为部署机,需要可以免密码登录本机和10.160.162.5 (目标机)。

生成ssh key:

$ ssh-keygen -t rsa

一直回车即可,会在~/.ssh/目录下生成一个id_rsa.pub文件。分别在两个机器的~/.ssh/目录下新建一个authorized_keys文件,并把刚刚生成id_rsa.pub的内容填写进去。

6.验证是否部署成功。分别登录两台机器运行以下命令来验证:

$ docker ps

CONTAINER ID    IMAGE                                       ...

11e86440c02d    redis:5                                     ...

16570fa47d36    federatedai/serving-server:1.2.2-release    ...

b64b251e9515    federatedai/serving-proxy:1.2.2-release     ...

75603d077a94    federatedai/fateboard:1.3.0-release         ...

38cb63178b79    federatedai/python:1.3.0-release            ...

80876768cd35    federatedai/roll:1.3.0-release              ...

955bab0ae542    federatedai/meta-service:1.3.0-release      ...

89928bf28b37    federatedai/egg:1.3.0-release               ...

63e4ae852d0d    mysql:8                                     ...

3cc1a4709765    federatedai/proxy:1.3.0-release             ...

0e1d945b852c    federatedai/federation:1.3.0-release        ...

f51e2e77af88    redis:5                                     ...

3

准备数据集

本文使用MNIST数据集,MNIST是手写数字识别的数据集。从kaggle下载csv格式的数据集。

FATE训练时需要数据集有id,MNIST数据集里有6w条数据,模拟横向l联邦学习,把数据集分为两个各有3w条记录的数据集。

$ awk -F'\t' -v OFS=',' '

  NR == 1 {print "id",$0; next}

  {print (NR-1),$0}' mnist_train.csv > mnist_train_with_id.csv

这句话是在第一行最前面加上id,第二行开始加序号,并用逗号作为分隔符。

$ sed -i "s/label/y/g" mnist_train_with_id.csv

将表头的label替换成y,在FATE里label的名字通常为y。

$ split -l 30001 mnist_train_with_id.csv mnist_train_3w.csv

将mnist_train_with_id.csv分割,每一个文件有30001行(一行标题和30000行数据)。会生成两个文件:mnist_train_3w.csvaa和mnist_train_3w.csvab。将两个文件重命名:

$ mv mnist_train_3w.csvaa mnist_train_3w_a.csv

$ mv mnist_train_3w.csvab mnist_train_3w_b.csv

$ sed -i "`cat -n mnist_train_3w_a.csv |head -n 1`" mnist_train_3w_b.csv

将mnist_train_3w_a.csv文件的第一行(csv的表头)插入mnist_train_3w_b.csv的最前面。这样我们就得到了两个有表头和id的数据集,各有30000条数据。

分别将两个文件拷贝到两台机器上的/data/projects/fate/confs-<partyID>/shared_dir/examples/data目录里。

Shared_dir目录是本地文件系统和docker容器中文件系统的共享目录,使容器可以访问宿主机的文件。

4

准备FATE Pipeline

本文在FATE里使用Keras运行DNN,参考文章。(https://github.com/FederatedAI/FATE/tree/master/examples/federatedml-1.x-examples/homo_nn)

1.1.     准备Keras模型:

进入guest方(本文选用9999作为guest)的python容器:

$ docker exec -it confs-9999_python_1 bash

进入Python解释器:

$ python

构建一个Keras模型:

>>>import keras

>>>from keras.models import Sequential

>>>from keras.layers import Dense, Dropout, Flatten

>>>model = Sequential()

>>>model.add(Dense(512,activation='relu',input_shape=(784,)))

>>>model.add(Dense(256,activation='relu'))

>>>model.add(Dense(10,activation='softmax'))

得到json格式的模型:

>>>json = model.to_json()

>>>print(json)

{"class_name": "Sequential", "config": {"name": "sequential_1", "layers": [{"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "batch_input_shape": [null, 784], "dtype": "float32", "units": 512, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "units": 256, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "units": 10, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}]}, "keras_version": "2.2.4", "backend": "tensorflow"}

1.2.     修改test_homo_nn_keras_temperate.json

vi examples/federatedml-1.x-examples/homo_nn/test_homo_nn_keras_temperate.json 

将刚刚输出的json格式的模型替换到algorithm_parameters. homo_nn_0.$nn_define位置。

将work_mode设置为1,将guest设置为9999,host和arbiter为10000,将

{

    "initiator": {

        "role": "guest",

        "party_id": 9999

    },

    "job_parameters": {

        "work_mode": 1

    },

    "role": {

        "guest": [

            9999

        ],

        "host": [

            10000

        ],

        "arbiter": [

            10000

        ]

    },

修改guest和host数据集的名字和命名空间,role_parameters. guest.args.data. train_data:

"name": "homo_mnist_guest",

"namespace": "homo_mnist_guest"

role_parameters. host.args.data. train_data:

"name": "homo_mnist_host",

"namespace": "homo_mnist_host"

1.3.     分别上传host方(10000)和guest方(9999)数据

新建upload_data_guest.json

$ vi examples/federatedml-1.x-examples/homo_nn/upload_data_guest.json

{

    "file": "examples/data/mnist_train_3w_b.csv",

    "head": 1,

    "partition": 10,

    "work_mode": 1,

    "table_name": "homo_mnist_guest",

    "namespace": "homo_mnist_guest"

}

上传数据到FATE:

$ python fate_flow/fate_flow_client.py -f upload -c examples/federatedml-1.x-examples/homo_nn/upload_data_guest.json

登陆到host(10000)机器的Python容器,并对应新建upload_data_host.json

$ docker exec -it confs-10000_python_1 bash

$ vi examples/federatedml-1.x-examples/homo_nn/upload_data_host.json

{

    "file": "examples/data/mnist_train_3w_a.csv",

    "head": 1,

    "partition": 10,

    "work_mode": 1,

    "table_name": "homo_mnist_host",

    "namespace": "homo_mnist_host"

}

上传数据到FATE:

$ python fate_flow/fate_flow_client.py -f upload -c examples/federatedml-1.x-examples/homo_nn/upload_data_host.json

登录到FateBoard可以查看上传任务情况,FateBoard的地址是http://party-IP:8080,如下图所示为成功:

                                             

1.4.     用fate_flow运行DNN

FATE的训练应该由guest方发起,所以我们登录到guest的Python容器:

$ docker exec -it confs-9999_python_1 bash

使用fate_flow运行DNN任务:

$ python fate_flow/fate_flow_client.py -f submit_job -c examples/federatedml-1.x-examples/homo_nn/test_homo_nn_keras_temperate.json -d examples/federatedml-1.x-examples/homo_nn/test_homo_nn_train_then_predict.json

得到输出:

{

    "data": {

        "board_url": "http://fateboard:8080/index.html#/dashboard?job_id=202003191510586887818&role=guest&party_id=9999",

        "job_dsl_path": "/data/projects/fate/python/jobs/202003191510586887818/job_dsl.json",

        "job_runtime_conf_path": "/data/projects/fate/python/jobs/202003191510586887818/job_runtime_conf.json",

        "logs_directory": "/data/projects/fate/python/logs/202003191510586887818",

        "model_info": {

            "model_id": "arbiter-10000#guest-9999#host-10000#model",

            "model_version": "202003191510586887818"

        }

    },

    "jobId": "202003191510586887818",

    "retcode": 0,

    "retmsg": "success"

}

model_id和model_version合起来是确定一个模型的依据,下一步进行预测时候会用到。

登录fateboard查看任务,下图为完成训练:

5

使用模型预测

我们用之前训练的MNIST数据集来做预测,所以就不用再上传数据了。

$ awk -F'\t' -v OFS=',' '

  NR == 1 {print "id",$0; next}

  {print (NR-1),$0}' mnist_test.csv > mnist_test_with_id.csv

$ sed -i "s/label/y/g" mnist_test_with_id.csv

1.1.       定义预测pipeline

预测也是由guest(9999)方发起,新建test_predict_conf.json

$ vi examples/federatedml-1.x-examples/homo_nn/test_predict_conf.json

{

    "initiator": {

        "role": "guest",

        "party_id": 9999

    },

    "job_parameters": {

        "work_mode": 1,

        "job_type": "predict",

        "model_id": "arbiter-10000#guest-9999#host-10000#model",

        "model_version": "202003191510586887818"

    },

    "role": {

        "guest": [9999],

        "host": [10000],

        "arbiter": [10000]

    },

    "role_parameters": {

        "guest": {

            "args": {

                "data": {

                    "eval_data": [{"name": "homo_mnist_guest", "namespace": "homo_mnist_guest"}]

                }

            }

        },

        "host": {

            "args": {

                "data": {

                    "eval_data": [{"name": "homo_mnist_host", "namespace": "homo_mnist_host"}]

                }

            }

        }

    }

}

job_parameters 里面的model_id和model_version就是刚刚训练时输出里面的,guest和host的数据的名字和命名空间都和训练时一致。

1.2.       进行预测

$ python fate_flow/fate_flow_client.py -f submit_job -c examples/federatedml-1.x-examples/homo_nn/test_predict_conf.json

登录Fateboard查看是否完成预测。

1.3.     下载预测结果

$ python fate_flow/fate_flow_client.py -f component_output_data -j 2020032001133193102117 -p 9999 -r guest -cpn homo_nn_1 -o examples/federatedml-1.x-examples/homo_nn

f:fate_flow的任务种类,component_output_data是获取模块输出用的。

j:jobID,在刚刚预测时候输出里。

p:partyID,guest方是9999。

r:角色,guest。

cpn:模块名称,是训练模型时pipeline(examples/federatedml-1.x-examples/homo_nn/test_homo_nn_train_then_predict.json)定义的,本次是homo_nn_1。

o是下载结果的输出路径。

运行完这条命令之后,会发现examples/federatedml-1.x-examples/homo_nn/目录下多了一个job_2020032001133193102117_homo_nn_1_guest_9999_output_data目录。

查看一下这个目录里面的内容:

ls job_2020032001133193102117_homo_nn_1_guest_9999_output_data

output_data.csv  output_data_meta.json

output_data.csv:预测的结果集。

output_data_meta.json:结果集的元数据,就是结果集表头。

往期精彩回顾

KubeFATE:用云原生技术赋能联邦学习(一)

KubeFATE:用云原生技术赋能联邦学习(二)

欢迎对KubeFATE感兴趣的朋友们,加入社群!

消息一则:

VMware招聘云原生前端开发工程师(北京)

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐