联邦学习实战-2-用FATE从零实现横向逻辑回归

网友投稿 958 2022-05-30

文章目录

一、安装FATE平台

三、利用FATE构建横向联邦学习Pipeline

3.1 数据转换输入

3.2 模型训练

3.2.1 DSL配置文件

3.2.2 运行配置 Submit Runtime Conf

3.2.3 提交参数,训练模型

3.3 评估模型

3.4 多参与方环境配置

四、Tips

4.1. 重新启动fate-flow和fateboard

4.2. ‘NoneType’ object has no attribute ‘count’

4.3. list index out of range

四、Tips

4.1. 重新启动fate-flow和fateboard

4.2. ‘NoneType’ object has no attribute ‘count’

4.3. list index out of range

一、安装FATE平台

FATE是微众银行开源的联邦学习框架

官方地址:https://fate.fedai.org 文档:https://fate.readthedocs.io/en/latest/_build_temp/standalone-deploy/doc/Fate-standalone_deployment_guide_zh.html https://github.com/FederatedAI/Practicing-Federated-Learning/tree/main/chapter05_FATE_HFL

1

2

3

4

5

注意:书本使用的FATE是1.4.0版本,而我使用的是1.6.0版本(2021-8-13),文中的配置文件中的注释在使用时要去除

采用在主机安装FATE的安装模式

官方文档中的命令都是用sh运行,因为本机的环境不同,所以采用bash

wget https://webank-ai-1251170195.cos.ap-guangzhou.myqcloud.com/standalone_fate_master_1.6.0.tar.gz tar -xzvf standalone_fate_master_1.6.0.tar.gz cd standalone_fate_master_1.6.0 source bin/init_env.sh bash init.sh init

1

2

3

4

5

6

7

8

问题:service.sh: [[ not found 解决:修改init.sh文件中的sh命令为bash

1

2

3

测试:

cd standalone_fate_master_1.6.0 source bin/init_env.sh bash ./python/federatedml/test/run_test.sh

1

2

3

4

会输出一系列的测试输出,最终:

toy测试

python ./examples/toy_example/run_toy_example.py 10000 10000 0

1

运行起来之后可以看到:

控制台(IP:8080):

安装FATE-Client和FATE-Test

为方便使用FATE,我们提供了便捷的交互工具FATE-Client以及测试工具FATE-Test.

请在环境内使用以下指令安装:

python -m pip install fate-client python -m pip install fate-test

1

2

二、切分数据集

数据集:威斯康星州临床科学中心开源的乳腺癌肿瘤数据集

from sklearn.datasets import load_breast_cancer

为了模拟横向联邦建模的场景,我们首先在本地将乳腺癌数据集切分为特征相同的横向联邦形式,当前的breast数据集有569条样本,我们将前面的469条作为训练样本,后面的100条作为评估测试样本。

从469条训练样本中,选取前200条作为公司A的本地数据,保存为breast_1_train.csv,将剩余的269条数据作为公司B的本地数据,保存为breast_2_train.csv。

测试数据集可以不需要切分,两个参与方使用相同的一份测试数据即可,文件命名为breast_eval.csv。

splitDataset.py

from sklearn.datasets import load_breast_cancer import pandas as pd breast_dataset = load_breast_cancer() breast = pd.DataFrame(breast_dataset.data, columns=breast_dataset.feature_names) breast = (breast-breast.mean())/(breast.std()) col_names = breast.columns.values.tolist() columns = {} for idx, n in enumerate(col_names): columns[n] = "x%d"%idx breast = breast.rename(columns=columns) breast['y'] = breast_dataset.target breast['idx'] = range(breast.shape[0]) idx = breast['idx'] breast.drop(labels=['idx'], axis=1, inplace = True) breast.insert(0, 'idx', idx) breast = breast.sample(frac=1) train = breast.iloc[:469] eval = breast.iloc[469:] breast_1_train = train.iloc[:200] breast_1_train.to_csv('breast_1_train.csv', index=False, header=True) breast_2_train = train.iloc[200:] breast_2_train.to_csv('breast_2_train.csv', index=False, header=True) eval.to_csv('breast_eval.csv', index=False, header=True)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

注意:官方地址中的csv文件是有问题的,要运行这个切割数据集自己生成新的数据集文件

三、利用FATE构建横向联邦学习Pipeline

用FATE构建横向联邦学习Pipeline,涉及到三个方面的工作:

数据转换输入

将数据文件(csv、txt)等转换成为FATE独有的基础数据结构DTable,从而方便进一步的操作

模型训练

FATE以模型训练构建流水线pipeline

模型评估:(可选)

评估模型性能的手段

如果只使用框架自带的模型,那么其实我们需要修改的就是配置文件即可

3.1 数据转换输入

新建一个项目目录chapter05(我这里创建的叫chapter05因为对应书第五章内容,可自行修改)

将数据集放到该目录下的data目录中:

完成数据转换,需要一个配置文件和一个启动程序:

配置文件

upload_data.json文件编写配置,内容为:

{ "file": "data/breast_1_train.csv", "head": 1, "partition": 16, "work_mode": 0, "table_name": "homo_breast_1_train", "namespace": "homo_host_breast_train" }

1

2

3

4

5

6

7

8

字段说明:

file: 数据文件路径,相对于当前所在路径

head: 指定数据文件是否包含表头

partition: 指定用于存储数据的分区数

work_mode: 指定工作模式,0代表单机版,1代表集群版

table_name:转换为DTable格式的表名

namespace: DTable格式的表名对应的命名空间

backend: 指定后端,0代表EGGROLL, 1代表SPARK加RabbitMQ, 2代表SPARK加Pulsar (暂时未用到)

fate-flow上传数据

使用fate-flow上传数据。从FATE-1.5开始,推荐使用 FATE-Flow Client Command Line 执行FATE-Flow任务。

提示:

{ "retcode": 100, "retmsg": "Fate flow CLI has not been initialized yet or configured incorrectly. Please initialize it before using CLI at the first time. And make sure the address of fate flow server is configured correctly. The configuration file path is: /ai/xwj/federate_learning/fate_dir/standalone_fate_master_1.6.0/venv/lib/python3.6/site-packages/flow_client/settings.yaml." }

1

2

3

4

解决:先初始化flow

使用flow首先要初始化一下:

flow init文档

Fate Flow 命令行初始化命令。用户可选择提供fate服务器配置文件路径或指定fate服务器ip地址及端口进行初始化。注意:若用户同时使用上述两种方式进行初始化,CLI将优先读取配置文件内容,而用户所配置的服务器ip地址及端口信息将被忽略。

因为之前init命令直接已经启动了flow,所以直接初始化即可

flow init --ip 127.0.0.1 --port 9380

1

{ "retcode": 0, "retmsg": "Fate Flow CLI has been initialized successfully." }

1

2

3

4

因为之前上传命令会自动将原始的本地文件转为DTable格式

flow data upload -c upload_data.json

1

注意,我使用的是新版本,新版本支持命令行直接使用

如果提示没有flow命令,那么可能没有使用提供的conda环境,解决如下:

source bin/init_env.sh

1

{ "data": { "board_url": "http://127.0.0.1:8080/index.html#/dashboard?job_id=202108151639113656812&role=local&party_id=0", "job_dsl_path": "/home/jiangbo/FATE/standalone_fate_master_1.6.0/jobs/202108151639113656812/job_dsl.json", "job_id": "202108151639113656812", "job_runtime_conf_on_party_path": "/home/jiangbo/FATE/standalone_fate_master_1.6.0/jobs/202108151639113656812/local/job_runtime_on_party_conf.json", "job_runtime_conf_path": "/home/jiangbo/FATE/standalone_fate_master_1.6.0/jobs/202108151639113656812/job_runtime_conf.json", "logs_directory": "/home/jiangbo/FATE/standalone_fate_master_1.6.0/logs/202108151639113656812", "model_info": { "model_id": "local-0#model", "model_version": "202108151639113656812" }, "namespace": "homo_host_breast_train", "pipeline_dsl_path": "/home/jiangbo/FATE/standalone_fate_master_1.6.0/jobs/202108151639113656812/pipeline_dsl.json", "table_name": "homo_breast_1_train", "train_runtime_conf_path": "/home/jiangbo/FATE/standalone_fate_master_1.6.0/jobs/202108151639113656812/train_runtime_conf.json" }, "jobId": "202108151639113656812", "retcode": 0, "retmsg": "success" }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

访问board_url可以在浏览器中看到对应的详情:

对于breast_2_train.csv以及测试集合同样的过程:

测试集上传到两个参与方,并各自转换为DTable格式

{ "file": "data/breast_2_train.csv", "head": 1, "partition": 16, "work_mode": 0, "table_name": "homo_breast_2_train", "namespace": "homo_guest_breast_train" } // host { "file": "data/breast_eval.csv", "head": 1, "partition": 16, "work_mode": 0, "table_name": "homo_breast_1_eval", "namespace": "homo_host_breast_eval" } // guest { "file": "data/breast_eval.csv", "head": 1, "partition": 16, "work_mode": 0, "table_name": "homo_breast_2_eval", "namespace": "homo_guest_breast_eval" }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

3.2 模型训练

借助FATE,我们可以使用组件的方式来构建联邦学习,而不需要用户从新开始编码,FATE构建联邦学习Pipeline是通过自定义dsl和conf两个配置文件来实现:

DSL 配置和运行配置 V1

dsl文件:用来描述任务模块,将任务模块以有向无环图(DAG)的形式组合在一起。

conf文件:设置各个组件的参数,比如输入模块的数据表名;算法模块的学习率、batch大小、迭代次数等。

我们本实验使用的是模型:逻辑回归

进入examples/dsl/v1/homo_logistic_regression文件夹中:

使用test_homolr_train_job_dsl.json、test_homolr_train_job_conf.json两个文件来辅助构建横向联邦学习模型

3.2.1 DSL配置文件

为了让任务模型的构建更加灵活,目前 FATE 使用了一套自定的领域特定语言 (DSL) 来描述任务。在 DSL 中,各种任务模块(例如数据读写 data_io,特征工程 feature-engineering, 回归 regression,分类 classification)可以通向一个有向无环图 (DAG) 组织起来。通过各种方式,用户可以根据自身的需要,灵活地组合各种算法模块。

DSL 的配置文件采用 json 格式,实际上,整个配置文件就是一个 json 对象 (dict)。在这个 dict 的第一级是 “components”,用来表示这个任务将会使用到的各个模块。用户需要使用模块名加数字 _num 作为对应模块的 key,例如 dataio_0,并且数字应从 0 开始计数。

具体的参数见官方文档连接(上面)

test_homolr_train_job_dsl.json:

定义了四个模块已经构成了基本的联邦学习流水线(feature_scale_0为1.6.0新增),可直接使用(复制一份)

{ "components" : { // 数据IO组件,用于将本地数据转为DTable "dataio_0": { "module": "DataIO", "input": { "data": { "data": [ "args.train_data" ] } }, "output": { "data": ["train"], "model": ["dataio"] } }, // 特征工程模块 "feature_scale_0": { "module": "FeatureScale", "input": { "data": { "data": [ "dataio_0.train" ] } }, "output": { "data": ["train"], "model": ["feature_scale"] } }, // 横向逻辑回归组件 "homo_lr_0": { "module": "HomoLR", "input": { "data": { "train_data": [ "feature_scale_0.train" ] } }, "output": { "data": ["train"], "model": ["homolr"] } }, // 模型评估组件,如果未提供测试数据集则自动使用训练集 "evaluation_0": { "module": "Evaluation", "input": { "data": { "data": [ "homo_lr_0.train" ] } } } } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

这里的args.train_data是根据下面的运行配置conf来的

其次配置文件之间的指定关系如下:

3.2.2 运行配置 Submit Runtime Conf

每个模块都有不同的参数需要配置,不同的 party 对于同一个模块的参数也可能有所区别。为了简化这种情况,对于每一个模块,FATE 会将所有 party 的不同参数保存到同一个运行配置文件(Submit Runtime Conf)中,并且所有的 party 都将共用这个配置文件。

除了 DSL 的配置文件之外,用户还需要准备一份运行配置(Submit Runtime Conf)用于设置各个组件的参数。

test_homolr_train_job_conf.json 修改如下:

{ // 创始人 "initiator": { "role": "guest", "party_id": 10000 }, "job_parameters": { "work_mode": 0 // 0代表单机版,1代表集群版 }, // 所有参与此任务的角色 // 每一个元素代表一种角色以及承担这个角色的party_id,是一个列表表示同一角色可能有多个实体ID "role": { "guest": [ 10000 ], "host": [ 10000 ], // 仲裁者 "arbiter": [ 10000 ] }, // 对于权限角色的进一步参数配置 "role_parameters": { "guest": { "args": { "data": { "train_data": [ { "name": "homo_breast_2_train", // 修改DTable的表名 "namespace": "homo_guest_breast_train" // 修改命名空间 } ] } }, "dataio_0": { "label_name": ["y"] // 添加标签对应的列属性名称 } }, "host": { "args": { "data": { "train_data": [ { "name": "homo_breast_1_train", // 同理修改 "namespace": "homo_host_breast_train" } ] } }, "dataio_0": { "label_name": ["y"] // 添加标签对应的列属性名称 }, "evaluation_0": { "need_run": [ false ] } } }, // 设置模型训练的超参数信息 "algorithm_parameters": { "dataio_0": { "with_label": true, "label_name": "y", "label_type": "int", "output_format": "dense" }, "homo_lr_0": { "penalty": "L2", "optimizer": "sgd", "tol": 1e-05, "alpha": 0.01, "max_iter": 10, "early_stop": "diff", "batch_size": 500, "learning_rate": 0.15, "decay": 1, "decay_sqrt": true, "init_param": { "init_method": "zeros" }, "encrypt_param": { "method": null }, "cv_param": { "n_splits": 4, "shuffle": true, "random_seed": 33, "need_cv": false } } } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

关于角色,解释如下:

arbiter是用来辅助多方完成联合建模的,它的主要作用是聚合梯度或者模型。比如纵向lr里面,各方将自己一半的梯度发送给arbiter,然后arbiter再联合优化等等。

guest代表数据应用方。

host是数据提供方。

local是指本地任务, 该角色仅用于upload和download阶段中。

3.2.3 提交参数,训练模型

Job submit

介绍: 提交执行pipeline任务。

参数:

执行:

1

flow job submit -c test_homolr_train_job_conf.json -d test_homolr_train_job_dsl.json

1

注意:需要全部为勾号才说明运行成功

可以看到运行的结果:

3.3 评估模型

为了评估模型的效果,我们重新修改配置以检查效果:

在上传数据时,我们已经将两个评估模型的数据上传,并且转换为DTable格式

现在我们修改dsl配置文件:

{ "components" : { "dataio_0": { "module": "DataIO", "input": { "data": { "data": [ "args.train_data" ] } }, "output": { "data": ["train"], "model": ["dataio"] } }, "dataio_1": { "module": "DataIO", "input": { "data": { "data": [ "args.eval_data" ] }, "model": ["dataio_0.dataio"] }, "output": { "data": ["eval_data"] } }, "feature_scale_0": { "module": "FeatureScale", "input": { "data": { "data": [ "dataio_0.train" ] } }, "output": { "data": ["train"], "model": ["feature_scale"] } }, "feature_scale_1": { "module": "FeatureScale", "input": { "data": { "data": [ "dataio_1.eval_data" ] } }, "output": { "data": ["eval_data"], "model": ["feature_scale"] } }, "homo_lr_0": { "module": "HomoLR", "input": { "data": { "train_data": [ // 注意这里是指定训练数据 "feature_scale_0.train" ] } }, "output": { "data": [ "train" ], "model": ["homolr"] } }, "homo_lr_1": { "module": "HomoLR", "input": { "data": { "eval_data": [ // 注意:这里是指定评估数据 "feature_scale_1.eval_data" ] }, "model": [ // 这里指定好模型 "homo_lr_0.homolr" ] }, "output": { "data": [ "eval_data" ], "model": ["homolr"] } }, "evaluation_0": { "module": "Evaluation", "input": { "data": { "data": [ "homo_lr_0.train" ] } } }, "evaluation_1": { "module": "Evaluation", "input": { "data": { "data": [ "homo_lr_1.eval_data" // 指定评估数据集 ] } } } } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

修改conf文件:

{ ... "role_parameters": { "guest": { "args": { "data": { "train_data": [ { "name": "homo_breast_2_train", "namespace": "homo_guest_breast_train" } ], "eval_data": [ // 添加测试集合 { "name": "homo_breast_2_eval", "namespace": "homo_guest_breast_eval" } ] } }, "dataio_0": { "label_name": ["y"] } }, "host": { "args": { "data": { "train_data": [ { "name": "homo_breast_1_train", "namespace": "homo_host_breast_train" } ], "eval_data": [ // 添加测试集合 { "name": "homo_breast_1_eval", "namespace": "homo_host_breast_eval" } ] } }, ... } }, .... }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

重新提交任务,查看结果:

flow job submit -c test_homolr_train_job_conf.json -d test_homolr_train_job_dsl.json

1

DAG图:

3.4 多参与方环境配置

上面的方案中有两个参与角色:

联邦学习实战-2-用FATE从零实现横向逻辑回归

guest代表数据应用方。

host是数据提供方。

下面考虑更多的客户端参与,修改conf文件中的role添加更多的参与方:

(这里为了方便起见,就不再对数据集根据不同的host进行进一步的划分,测试集也是如此)

{ "initiator": { "role": "guest", "party_id": 10000 }, "job_parameters": { "work_mode": 0 }, "role": { "guest": [ 10000 ], "host": [ 10000, 10001, 10002 // 新建两个Host ], "arbiter": [ 10000 ] }, "role_parameters": { "guest": { ... }, "host": { "args": { "data": { // 训练数据、测试数据的list都要与上面的host的list大小一样,一一对应 "train_data": [ { "name": "homo_breast_1_train", "namespace": "homo_host_breast_train" }, { "name": "homo_breast_1_train", "namespace": "homo_host_breast_train" }, { "name": "homo_breast_1_train", "namespace": "homo_host_breast_train" } ], "eval_data": [ { "name": "homo_breast_1_eval", "namespace": "homo_host_breast_eval" }, { "name": "homo_breast_1_eval", "namespace": "homo_host_breast_eval" }, { "name": "homo_breast_1_eval", "namespace": "homo_host_breast_eval" } ] } }, // dataio_0 标签指定、测试集是否需要跑也是一样,大小一致、一一对应 "dataio_0": { "label_name": ["y", "y", "y"] }, "evaluation_0": { "need_run": [ false, false, false ] } } }, ... }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

运行后效果如图:

四、Tips

4.1. 重新启动fate-flow和fateboard

在根目录下

bash ./python/fate_flow/service.sh restart bash ./fateboard/service.sh restart

1

2

4.2. ‘NoneType’ object has no attribute ‘count’

解决:检查conf中的配置name、namespace与upload的配置是否一一匹配

4.3. list index out of range

运行后效果如图:

四、Tips

4.1. 重新启动fate-flow和fateboard

在根目录下

bash ./python/fate_flow/service.sh restart bash ./fateboard/service.sh restart

1

2

4.2. ‘NoneType’ object has no attribute ‘count’

解决:检查conf中的配置name、namespace与upload的配置是否一一匹配

4.3. list index out of range

检查数据集分割(样本大小)是否处理好

机器学习

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Python 前端开发之CSS浮动
下一篇:C# 4 中的 Dynamic 关键字
相关文章