*本文做者系VMware雲原生實驗室工程師 彭路html
FATE(Federated AI Technology Enabler)是聯邦機器學習技術的一個框架,其旨在提供安全的計算框架來支持聯邦 AI 生態。FATE 實現了基於同態加密和多方計算(MPC)的安全計算協議,它支持聯邦學習架構和各類機器學習算法的安全計算,包括邏輯迴歸、基於樹的算法、深度學習和轉移學習。python
聯邦機器學習又名聯邦學習、聯合學習與聯盟學習,它能有效幫助多個機構在知足用戶隱私保護、數據安全和相關法規的要求下,進行數據使用和機器學習建模,消除因爲行業競爭、隱私安全與行政手續等問題帶來的數據孤島,讓以數據爲基礎的機器學習順利進行。mysql
KubeFATE支持經過Docker Compose和Kubernetes進行FATE部署。咱們建議使用Docker Compose安裝快速開發和學習FATE集羣,同時使用Kubernetes安裝生產環境。linux
深度神經網絡(DNN)是在輸入和輸出層之間具備多層的人工神經網絡(ANN)。git
本文以經典的神經網絡MNIST爲例子,展現聯邦學習版的深度神經網絡訓練過程。咱們使用KubeFATE快速進行FATE框架的部署。由於模擬聯邦學習的雙方,咱們須要準備兩臺Ubuntu的機器(物理機或虛擬機)。github
一.安裝docker和docker-compose
Ubuntu 安裝docker:redis
$ 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-compo se-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose $ sudo chmod +x /usr/local/bin/docker-compose
二.安裝KubeFATE
學習環境推薦使用Docker方式部署。使用Docker方式部署分爲兩步,先根據parties.conf配置文件生成docker-compose文件。經過scp把docker-compose文件複製到目標機器上,而後經過ssh命令登陸到目標機器並運「docker-compose up」。sql
選擇兩臺機器其中之一做爲部署機。docker
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 ...
三.準備數據集
本文使用MNIST數據集,MNIST是手寫數字識別的數據集。從kaggle下載csv格式的數據集。
FATE訓練時須要數據集有id,MNIST數據集裏有6w條數據,模擬橫向聯邦學習,把數據集分爲兩個各有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容器中文件系統的共享目錄,使容器能夠訪問宿主機的文件。
四,準備FATE Pipeline
本文在FATE裏使用Keras運行DNN,參考文章。
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"}
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"
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,以下圖所示爲成功:
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查看任務,下圖爲完成訓練:
五.使用模型預測
咱們用以前訓練的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. 定義預測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的數據的名字和命名空間都和訓練時一致。
2. 進行預測
$ python fate_flow/fate_flow_client.py -f submit_job -c examples/federatedml-1.x-examples/homo_nn/test_predict_conf.json
登陸Fateboard查看是否完成預測。
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@vmware.com聯繫咱們。