阅读笔记联邦学习实战——用FATE从零实现横向逻辑回归

Posted HERODING23

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了阅读笔记联邦学习实战——用FATE从零实现横向逻辑回归相关的知识,希望对你有一定的参考价值。

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

前言

FATE是微众银行开发的联邦学习平台,是全球首个工业级的联邦学习开源框架,在github上拥有近4000stars,可谓是相当有名气的,该平台为联邦学习提供了完整的生态和社区支持,为联邦学习初学者提供了很好的环境,否则利用python从零开发,那将会是一件非常痛苦的事情。本篇博客内容涉及《联邦学习实战》第四章和第五章内容,使用的fate版本为1.6.0,下面就让我们开始吧。


1. FATE平台

1.1 FATE平台架构概述


FATE的官方文档提供了FATE的架构图,可以看到FATE的架构自上而下分为了四层,最上面一层是FATE提供的服务,包括FATE云服务,FATE面板,FATE任务调度管理,生命周期管理等,往下一层是FATE的机器学习核心组件,包括横向联邦学习、纵向联邦学习等,再往下一层是应用在FATE中的安全协议(隐私保护算法),包括同态加密,FedAvg,RSA等,最后一层是底层框架,又可以分为平行的三层,包括计算框架(TensorFlow,Pytorch,Spark),消息队列协议,以及存储框架。
FATE的主要功能如下:

  • 提供了一种基于数据隐私保护的分布式安全计算框架;
  • 为机器学习、深度学习等常用算法提供高性能的安全计算支持;
  • 支持同态加密、秘密共享等多种多方安全计算协议,确保数据和模型的安全;
  • 提供友好的跨域交互信息管理方案和开发文档,极大方便开发人员使用。

2. Docker镜像安装FATE

FATE支持Linux和Mac系统,支持单机部署、集群部署和KubeFATE部署三种方式,具体的部署安装请查看FATE的官方文档,这里只提供利用Docker镜像配置FATE单机部署。

2.1 Docker的安装

Docker的安装见我的另一篇博客,里面安装步骤很详细,官方文档推荐的是18.09版本,但是在Ubuntu20.04中,只提供了19以上的版本,所以我下载的是19版本,但是不影响FATE的使用。

2.2 FATE的安装

2.2.1 拉取镜像

设置部署的环境变量

$ export version=本次部署的FATE版本号, 如1.7.0

通过镜像包

$ wget https://webank-ai-1251170195.cos.ap-guangzhou.myqcloud.com/fate/$version/release/standalone_fate_docker_image_$version_release.tar;
$ docker load < standalone_fate_docker_image_$version_release.tar;
$ docker images | grep federatedai/standalone_fate

能看到对应的版本则镜像下载成功。

通过公共镜像拉取

$ docker pull federatedai/standalone_fate:$version

2.2.2 启动

$ docker run -d --name standalone_fate -p 8080:8080 federatedai/standalone_fate:$version;
$ docker ps -a | grep standalone_fate

端口映射到8080,启动的容器名称为standalone_fate ,后面是镜像名(仓库+镜像名)。后面的指令输入后能看到对应的版本容器启动则成功。
ps:在启动的时候我遇到过端口占用的情况,用指令杀死占用端口的进程,还要注意删除容器,再重复run,不然会显示容器重复,如果杀死进程还是有端口占用,建议重启。

2.2.3 测试

进入容器

$ docker exec -it $(docker ps -aqf "name=standalone_fate") bash

如果报错(参数不匹配),就把$中的内容换成容器的ID即可,后面的bash表示用shell界面操作容器。
Toy测试

$ flow test toy -gid 10000 -hid 10000

如果成功,屏幕会显示

$ success to calculate secure_sum, it is 2000.0

单元测试

$ fate_test unittest federatedml --yes

如果成功,会显示下方语句

$ there are 0 failed test

有些用例算法在examples文件夹下,可以自行使用。

3. FATE编程范式

FATE构建联邦学习模型有两种不同编程范式。

  • 组件化配置:模型训练拆分为不同的任务,每个任务以组建的形式通过有向无环图相连,联邦学习所需的配置参数在配置文件中定义。该模式中,用户只需自定义和提交配置文件,就可以直接执行联邦训练。
  • 脚本编程:FATE提供API接口,用户通过脚本编程的方式实现联邦模型,类似直接使用Python编程。

由于脚本编程不够稳定,这里只使用组件化配置阐述。组件化配置需要提供两个配置文件。

  • dsl配置文件:FATE内置的一套自定义领域特定语言,在dsl中,常见的机器学习任务划分为不同的模块,如数据读写、模型训练、模型评估可以通过一个有向无环图连接。
  • conf配置文件:设置dsl中组件模块的参数。

利用FATE组件化配置的优点:

  • 提供多种安全策略机制;
  • 部署简单方便;
  • 提供可视化界面;
  • 支持常用的机器学习算法。

4. 用FATE从零实现横向逻辑回归

4.1 数据集

本章实验使用的数据集是威斯康星州临床科学中心开源的乳腺癌肿瘤数据集,该数据集内置在sklearn库中,可以直接加载查看。

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['y'] = breast_dataset.target
# 查看前五组数据
breast.head()

可以看到,数据总共有30个特征(10个属性分别以均值、标准差、最大差值出现三次),569个样本中,恶性肿瘤样本212个,良性有357个。

4.2 逻辑回归

这是一个典型的二分类模型的训练,数据集并不大,使用简单的逻辑回归作为实验模型。
传统的线性回归定义:

y = W T X + b y=W^TX+b y=WTX+b
但是对于二分类模型来说,简单的函数线性映射是不能够分类的,还需要一个非线性函数映射到离散标签,

y = f ( W T X + b ) y=f(W^TX+b) y=f(WTX+b)

在逻辑回归中,使用logistic函数进行非线性映射,logistic表示为:

f ( z ) = 1 1 + e − z f(z)=\\frac11+e^-z f(z)=1+ez1

图像表示为:

可以看出, z = W T X + b ≥ 0 z=W^TX+b\\ge 0 z=WTX+b0,则判断为正例,否则判断为反例。

4.3 横向数据切分

假设当前有两方参与横向联邦学习训练,取乳腺癌数据集前469条数据作为训练集,后100条作为测试集,数据切分的策略如下:

  • 训练数据切分:前200条作为公司A的本地数据,存为breast_1_train.csv,剩余269条作为公司B的本地数据,存为breast_2_train.csv
  • 测试数据集:不切分,由双方共用,存为breast_eval.csv

横向数据切分代码:

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.head()

# z-score标准化
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)

# 插入每行序列和y
breast['y'] = breast_dataset.target
idx = range(breast.shape[0])
breast.insert(0, 'idx', idx)

# 打乱数据并生成csv
breast = breast.sample(frac=1)
train = breast.iloc[:469]
eval =  breast.iloc[469:]
breast_1_train = breast.iloc[:200]
breast_2_train = breast.iloc[200:]
breast_1_train.to_csv('breast_1_train.csv', index=False, header=True)
breast_2_train.to_csv('breast_2_train.csv', index=False, header=True)
eval.to_csv('breast_eval.csv', index=False, header=True)

4.4 横向联邦模型训练

FATE构建联邦学习模型工作:

  • 数据输入:将文件转换为支持的DTable格式。DTable是一个分布式数据集合,FATE所有运算都基于DTable格式进行。
  • 模型训练:FATE为模型训练构建流水线。
  • 模型评估:将训练好的模型在测试集上评估。

4.4.1 数据输入

首先确定基目录,在运行FATE后,可以输入pwd查看,我的基目录为:

fate_dir=/data/projects/fate/

根据数据切分的结果,把三组数据集(.csv)上传到$fate_dir/examples/data/中。
由于文件需要上传到docker容器中,所以要特殊的文件上传工具,这里使用rz,如果docker中没有,则在docker中输入:

$ sudo apt-get install lrzsz

如果是在ubuntu本机上运行的,建议更换设备用xshell远程连接,否则在本机上输入:

$ rz -be

会出现一堆乱码,等半天也不跳出文件框,而在xshell中瞬间弹出,如果出现传输失败,那就要检查要传输的文件是否被使用。

用ls查看,左边一列即是上传的文件。

4.4.2 上传配置文件

由于FATE所有运算都基于DTable格式进行,所以要把上传的文件转换为DTable。首先上传配置文件,配置文件的实例文件有两种,对应v1和v2两个版本。

  • example/dsl/v1
    upload_data.jsonupload_host.jsonupload_guest.json,结构如下:

    "file": "examples/data/breast_hetero_guest.csv",	// 数据文件路径,相对于当前所在路径
    "head": 1,	// 指定数据文件是否包含表头,1: 是,0: 否
    "partition": 16,	// 指定用于存储数据的分区数
    "work_mode": 0, 	 // 指定工作模式,0: 单机版,1: 集群版
    "table_name": "breast_hetero_guest",	// 需要转换为DTable格式的表名(相当于后续需要使用的表)
    "namespace": "experiment"	// DTable格式的表名对应的命名空间

  • example/dsl/v2/upload

	"file": "/data/projects/fate/examples/data/breast_hetero_guest.csv",	// 数据文件路径,相对于当前所在路径
	"table_name": "breast_hetero_guest",	// 需要转换为DTable格式的表名
	"namespace": "experiment",// DTable格式的表名对应的命名空间
	"head": 1,	// 指定数据文件是否包含表头,1: 是,0: 否
	"partition": 8,	// 指定用于存储数据的分区数
	"work_mode": 0,	 // 指定工作模式,0: 单机版,1: 集群版
	"backend": 0	// 指定后端,0:EggRoll, 1: Spark _ RabbitMQ, 2: Spark + Pulsar

在FATE-1.6.0版本中,fate_flow的目录存放在fateflow/python/中,所以执行upload的过程和书中不一样,为:

python /fate/python/fate_flow/fate_flow_client.py -f upload -c upload_data.json

从FATE-1.5开始,推荐使用FATE-Flow-Client Command Line执行FATE-Flow任务,上传命令格式为:

$ flow data upload -c example/dsl/v2/upload/upload_conf.json

本文使用v1版本的上传数据操作,如果有想使用v2的朋友,可以访问参考链接的第一个链接。

配置文件如下:

  • 上传数据至公司A。

    "file": "/fate/example/data/breast_1_train.csv",
    "head": 1,
    "partition": 8,
    "work_mode": 0,
    "table_name": "homo_breast_1_train",
    "namespace": "homo_host_breast_train"


  • 上传数据至公司B。

    "file": "/fate/example/data/breast_2_train.csv",
    "head": 1,
    "partition": 8,
    "work_mode": 0,
    "table_name": "homo_breast_2_train",
    "namespace": "homo_guest_breast_train"


  • 上传测试数据至公司A 。

    "file": "/fate/example/data/breast_eval.csv",
    "head": 1,
    "partition": 8,
    "work_mode": 0,
    "table_name": "homo_breast_1_eval",
    "namespace": "homo_host_breast_eval"


  • 上传测试数据至公司B 。

在根目录下,输入python /fate/python/fate_flow/fate_flow_client.py -f upload -c upload_data.json (视每个人的环境而定)。返回如下代码则成功


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


还可以在FATEboard上查看可视化结果。

4.4.3 模型训练

FATE支持常用的机器学习模型,如:

  • 线性模型:横向、纵向的线性回归、logistic回归等线性模型。
  • 树模型:基于纵向的GBDT实现。
  • 神经网络:支持横向的深度神经网络模型DNN。


可以看到在fate dsl_conf的V2版本,模型种类又比书中所描述的详细不少。
V2版本在预设任务配置上有一些改变和提升,最直观的一点是不会自动为训练任务生成预测dsl,需要用户自定义,也可以使用flow命令自动配置预测dsl。
为了在V2中使用命令行客户端,即flow命令,需要进行一系列配置。参考官方文档FATE Client包含了FATE项目多个客户端:Pipeline, FATE Flow ClientFATE Test
获取所有命令分类和子命令:

    [IN]
    flow

    [OUT]
    Usage: flow COMMAND [OPTIONS]

      Fate Flow Client

    Options:
      -h, --help  Show this message and exit.

    Commands:
      component   Component Operations
      data        Data Operations
      init        Flow CLI Init Command
      job         Job Operations
      model       Model Operations
      queue       Queue Operations
      table       Table Operations
      task        Task Operations

安装FATE CLient

$ pip install fate-client
# 或者
$ pip install fate-client==$version

集群上安装请移步官方文档。
初始化

# 指定fateflow的IP地址和端口进行初始化
$ flow init --ip 192.168.0.1 --port 9380

获得如下返回视为初始化成功:


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

验证
查询任务情况

$ flow job query

返回以下即可:


    "data": [],
    "retcode": 0,
    "retmsg": "no job could be found"

本章使用逻辑回归模型,进入$fate_dir/examples/dsl/v1/homo_logistic_regression目录,该目录下已经有很多预设的dsl文件和conf文件。修改homo_lr_train_dsl.jsonhomo_lr_train_conf.json。修改推荐用vim,如果没有,用yumapt-get进行安装:

$ yum install -y vim
# 如果yum没有
$ apt-get install -y vim
  • test_homolr_train_dsl.json:描述任务模块,将任务模块以有向无环图形式组合。包括dataio_0homo_lr_0evaluation_0,这些组件分别用作数据格式转换、自带横向逻辑回归组件、模型评估。

  • test_homolr_train_conf.json:设置各个组建的参数。找到role字段,修改三个参数,train_data下的namenamespace,以及表示标签列对应的属性名label_name接着是algorithm_parameters字段,它是用来设置训练的超参数信息,包括学习率,优化函数,迭代次数等,可以根据实际需要自行修改。

文件配置结束,在当前位置输入:

$ python /fate/python/fate_flow/fate_flow_client.py -f submit_job -d test_homolr_train_job_dsl.json -c test_homolr_train_job_conf.json

在FATEboard上查看任务运行情况。

4.4.4 模型评估

常用的模型评估方法包括留出法和交叉验证法。

  • 留出法:将数据按照一定比例切分,预留一部分数据作为评估模型数据。
  • 交叉验证法: 将数据集D切分为k份,D1,D2,…,Dk,这样可以获得k组不同的训练数据集和评估数据集,得到k个评估的结果,取其平均值作为最终模型评估结果。

由于之前已经有了额外的数据集作为评估数据集,这里用留出法。为了将留出的数据用于模型评估,需要修改dsl组建配置。具体来说,在test_homolr_train_job_dsl文件中,在components组件下添加一个新的数据输入组件dataio_1,用来读取测试数据,如下所示。


    "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"] # 表示测试数据采用conf文件中的args.eval_data设置的文件
                ,
                "model": ["dataio_0.dataio"] # 使用数据训练模块"dataio_0.dataio"的输出作为"dataio_1"的模型输入
            ,
            "output": 
                "data": ["eval_data"] # 设置输出的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"]
                
            
                
    


然后修改conf文件,在role_parameters字段中为guest和host添加测试数据的DTable表名。


    "initiator": 
        "role": "guest",
        "party_id": 10000
    ,
    "job_parameters": 
        "work_mode": 0
    ,
    "role": 
        "guest": [10000],
        "host": [10000],
        "arbiter": [10000]
    ,
    "role_parameters": 
        "guest": 
            "args": 
                "data": 
                    "train_data": [
                        
                            "name": "homo_breast_2_train",
 

以上是关于阅读笔记联邦学习实战——用FATE从零实现横向逻辑回归的主要内容,如果未能解决你的问题,请参考以下文章

阅读笔记联邦学习实战——用FATE从零实现纵向线性回归

Fate实战——实现集群横向逻辑回归

阅读笔记联邦学习实战——用Python从零实现横向联邦图像分类

阅读笔记联邦学习实战——联邦学习攻防实战

联邦学习实战-1:用python从零开始实现横向联邦学习

阅读笔记联邦学习实战——联邦学习视觉案例