【FATE联邦学习】如何获得训练好的联邦学习联邦模型进行预测?

已经提issue

背景

在平时写python时候,可以直接model eval后输入数据进行下游任务评估就可以。但是FATE好像没有local mode进行prediction。

FATE中的情景

FATE这里只能通过先部署模型,再新起一个pipeline进行predict。

具体来说,在进行完训练(也就是pipeline.fit())之后,需要把模块deploy到FATE上pipeline.deploy_component(),使得FATE服务上带有了训练好的模型,然后再新起一个pipeline,比如叫predict_pipeline,读取数据,然后使用predict pipeleine进行predict_pipeline.predict()获得结果。

这个推断是从文档:https://fate.readthedocs.io/en/latest/api/fate_client/pipeline/#predict-with-pipeline中获得的,因为找不到其他关于这个问题的描述。

意义

换另外一个考虑的角度,其实联邦学习之后,各方的数据都不能够被泄露。FATE这里就极端一些,每个参与方都直接不能获得这个联邦的模型,只能通过FATE提供的借口进行使用,这样就“杜绝”了各方通过逆向进行推断攻击。

所以,在开发者的角度,只能把训练好的模型部署到FATE后,再起新任务提交到FATE后,进行predict,各方只能获取predict结果,但不能拿到联邦后的模型。

使用pipeline的示例

在train后直接获得

适用于train一下,直接获得结果,不进行模型部署。

from pipeline.component.nn import DatasetParam

dataset_param = DatasetParam(dataset_name='mnist_dataset', flatten_feature=True)  # specify dataset, and its init parameters
from pipeline.component.homo_nn import TrainerParam  # Interface

model = t.nn.Sequential(
    t.nn.CustModel(module_name='image_net',class_name='ImgNet',class_num=10)
)

nn_component = HomoNN(name='nn_0',
                      model=model, # model
                      loss=t.nn.CrossEntropyLoss(),  # loss
                      optimizer=t.optim.Adam(model.parameters(), lr=0.01), # optimizer
                      dataset=DatasetParam(dataset_name='mnist_dataset', flatten_feature=True),  # dataset
                      trainer=TrainerParam(trainer_name='fedavg_trainer', epochs=2, batch_size=1024, validation_freqs=1),
                      torch_seed=100 # random seed
                      )

nn_predict = HomoNN(name='predict_nn')
pipeline.add_component(reader_0)
pipeline.add_component(nn_component, data=Data(train_data=reader_0.output.data))
pipeline.add_component(Evaluation(name='eval_0', eval_type='multi'), data=Data(data=nn_component.output.data))
pipeline.add_component(nn_predict, data=Data(test_data=reader_0.output.data), model=Model(model=nn_component.output.model))


pipeline.compile()
pipeline.fit()

pipeline.get_component('predict_nn').get_output_data()

这是由FATE官方群友cwj同志给的例子,文档中没有。注意nn_predict的位置和写法。

先部署,后predict

适用于生产环境。先保存training的pipeline,在predict文件里面再次加载后才能方便使用。

...
pipeline训练代码
网络名字叫nn_component
...
pipeline.deploy_component([nn_component]) # 部署全部组件,也可以挑选component部署

部署完成后,新起一个pipeline

reader_0=...
data=...

predict_pipeline = PipeLine()
predict_pipeline.add_component(reader_0)
predict_pipeline.add_component(pipeline,
                               data=data)

predict_pipeline.predict()

以上内容,依据全部来自官方文档

例子:
train_fed_model.py:

## at first: source /home/user01/standalone_fate_install_1.11.2_release/bin/init_env.sh 
import torch.nn as nn
import os
from torchvision.datasets import ImageFolder
from torchvision import transforms
from federatedml.nn.model_zoo.sanet import SANet
# from pipeline.component.nn.backend.torch.cust import *
from federatedml.nn.dataset.base import Dataset
import torch.nn.functional as F
import numpy as np
import torch
# import albumentations as A
import cv2
from torch.utils.data import DataLoader,Dataset
# from albumentations.pytorch import ToTensorV2
import os
from torchvision import transforms

# 必须在federatedml.nn.datasets目录下  手动加入新的数据集的信息!https://blog.csdn.net/Yonggie/article/details/129404212
# real training
import torch as t
from torch import nn
from pipeline import fate_torch_hook
from pipeline.component import HomoNN
from pipeline.backend.pipeline import PipeLine
from pipeline.component import Reader, Evaluation, DataTransform
from pipeline.interface import Data, Model

t = fate_torch_hook(t)

import os
fate_project_path = os.path.abspath('/data/yzc/Fed/data/test')
host = 1
guest = 2
arbiter = 3
pipeline = PipeLine().set_initiator(role='guest', party_id=guest).set_roles(guest=guest, host=host,
                                                                            arbiter=arbiter)

data_0 = {
    
    "name": "sa_guest", "namespace": "sanet"}
data_1 = {
    
    "name": "sa_host", "namespace": "sanet"}

data_path_0 = fate_project_path + '/CVC-300'
data_path_1 = fate_project_path + '/CVC-300'

pipeline.bind_table(name=data_0['name'], namespace=data_0['namespace'], path=data_path_0)
pipeline.bind_table(name=data_1['name'], namespace=data_1['namespace'], path=data_path_1)



reader_0 = Reader(name="reader_0")
reader_0.get_party_instance(role='guest', party_id=guest).component_param(table=data_0)
reader_0.get_party_instance(role='host', party_id=host).component_param(table=data_1)



from pipeline.component.nn import DatasetParam

datapath='/data/yzc/Fed/data/test/CVC-300'
dataset_param = DatasetParam(dataset_name='sanet_dataset',datapath=datapath)

from pipeline.component.homo_nn import TrainerParam  # Interface
from federatedml.nn.loss.bcedice_loss import BCEDiceLoss


model = t.nn.Sequential(
    t.nn.CustModel(module_name='sanet',class_name='SANet')
)

loss=t.nn.CustLoss(loss_module_name='bcedice_loss',class_name='BCEDiceLoss')

nn_component = HomoNN(name='sanet',
                      model=model, # model
                      loss=loss,
                      optimizer=t.optim.Adam(model.parameters(), lr=0.01), # optimizer
                      dataset=dataset_param,  # dataset
                      trainer=TrainerParam(trainer_name='sa_trainer', epochs=2, batch_size=2,cuda=True),
                      torch_seed=100 # random seed
                      )


pipeline.add_component(reader_0)
pipeline.add_component(nn_component, data=Data(train_data=reader_0.output.data))


pipeline.compile()
pipeline.fit()
# 训练完成后,保存这个pipeline
pipeline.dump('./trained_pip.pkl')

然后新起一个fed_model_predict.py

from pipeline.interface import Data
from pipeline.backend.pipeline import PipeLine
from pipeline.component import Reader
import os

# 加载训练好的模型
model=PipeLine.load_model_from_file('trained_pip.pkl')
model.deploy_component([model.sanet])


# 重新定义reader、bind测试数据
guest = 2
host = 1
test_data = {
    
    "name": "sa_guest", "namespace": "sanet"}
fate_project_path = os.path.abspath('/data/yzc/Fed/data/test')
data_path_0 = fate_project_path + '/CVC-300'



test_reader = Reader(name="test_reader")
test_reader.get_party_instance(role='guest', party_id=guest).component_param(table=test_data)
test_reader.get_party_instance(role='host', party_id=host).component_param(table=test_data)


predict_pipeline= PipeLine()
from pipeline.component.nn import DatasetParam

datapath='/data/yzc/Fed/data/test/CVC-300'
dataset_param = DatasetParam(dataset_name='sanet_dataset',datapath=datapath)

# 直接本地添加table,定义其name和namespace
predict_pipeline.bind_table(name=test_data['name'], namespace=test_data['namespace'], path=data_path_0)
predict_pipeline.add_component(test_reader)\
        .add_component(model,data=Data(predict_input={
    
    'sanet.input.data':test_reader.output.data}))
        

predict_pipeline.predict()

result=predict_pipeline.get_component('sanet').get_output_data()
# 处理result

以上内容是原创+官方文档,文档中没有说明,是我自己参考多个文档总结+实践的。各位看官可以自行参考修改。

或者使用model loader获取部署的模型

文档

 param = {
    
    
        "model_id": "arbiter-9999#guest-10000#host-9999#model",
        "model_version": "202108311438379703480",
        "component_name": "hetero_lr_0",
        "step_index": 2
    }
    # 获取已经部署了的模型,主要靠param定位模型
   model_loader_0 = ModelLoader(name="model_loader_0", **param)

命令行(DSL)方式

我调查了使用命令行进行model相关的命令。其实使用命令行的步骤也是可以的。

相关文档在这里,个人感觉里面已经很全了,而且写起来好像比pipeline的方法简单。

这里要注意的一点是,deploy model后,返回结果会有一个新的model version,在生成get predict config后,要手动把生成文件的 model version、table name等名字替换

如果不清楚自己训练的模型名字叫什么,可以使用flow model get-model-info命令。

注意:model version就是Fateboard中的训练id!model id是类似于arbiter-3#guest-2#host-1#model这样子的字符串,也可以通过get model info获取到。

猜你喜欢

转载自blog.csdn.net/Yonggie/article/details/131169797