Delta
中文
搜索
K
Links
Comment on page

横向联邦学习

Delta中的横向联邦学习在横向联邦任务框架下执行:
横向联邦任务框架对横向的隐私计算任务进行了抽象,所有的横向任务都可被拆分为多个计算单元,每个计算单元包括select, map, aggregate, reduce四个步骤。
用户编写的不同的横向计算任务,在真正执行前,都会先由Delta做一次转化,将整个计算过程转化为包含这四个步骤的多个单元,然后再发送到Delta Node进行执行。
本文详细讲解横向联邦学习的任务从用户编写的计算代码,到可被Delta Node执行的多个计算单元的转化过程。

横向联邦学习任务的组成与流程

一个常见的机器学习任务,流程通常是这样的:
  1. 1.
    定义好机器学习模型
  2. 2.
    从外部加载数据集,将数据集分割为训练集与验证集
  3. 3.
    对数据进行预处理
  4. 4.
    对模型进行训练,更新模型的参数
  5. 5.
    对模型进行验证,测试模型的性能指标
  6. 6.
    如果模型的性能指标打到要求,任务完成;否则的话,跳转到第4步,进行训练
所以,我们可以把一个机器学习任务分解为以下几个部分:
  1. 1.
    模型
  2. 2.
    数据集,包含训练集与验证集
  3. 3.
    数据预处理
  4. 4.
    模型训练
  5. 5.
    模型验证
除了以上几个部分外,我们还需要明确任务的输入与输出。机器学习任务的输入包含两部分, 一是数据集,二是模型初始的权重;输出的是训练好的模型,也就是训练好的模型权重。
我们回到横向联邦学习任务。在我们定义横向联邦学习任务时,也只需要定义好上述的5个部分, 就可以完成机器学习相关的定义。
参考横向联邦学习的代码示例:
在横向联邦学习的示例中,除了构造函数,用户还定义了datasetmake_train_dataloadermake_validate_dataloadertrainvalidatestate_dict这6个方法。这6个方法与之前分解的机器学习任务 部分的对应关系如下:
  1. 1.
    模型:对应state_dict
  2. 2.
    数据集:对应dataset
  3. 3.
    数据预处理:对应make_train_dataloadermake_validate_dataloader
  4. 4.
    模型训练:对应train
  5. 5.
    模型验证:对应validate
用户在定义横向联邦学习任务时,只需要定义好这6个方法,就完成了机器学习部分的定义。 那么,接下来Delta要做的就是,将这些用户定义的方法,转化为多个可被执行的计算单元。

转化为横向联邦任务计算单元

要生成计算单元,Delta要做的,就是将用户定义的这6个函数,对应到map与reduce操作上来。
首先,我们需要明确,一个横向联邦学习任务,有多少个Round,每个Round,又对应用户定义的哪些部分呢? 这都是由用户在构造函数中定义的。在构造函数中,参数max_rounds定义了任务有多少个Round;而merge_epochmerge_iteration 这两个参数,定义了每个Round,对应于机器学习中的多少个epoch,或者多少个iteration。
我们想一下机器学习中的概念,每更新一次模型的权重,对应于一个iteration;每遍历完一次训练集,对应于一个epoch。 整个机器学习任务,会需要很多个epoch。而在横向联邦学习任务中,模型的权重更新分为本地权重更新,和全局权重更新。 本地权重的更新,还是一个iteration进行一次;而全局权重更新,就是一个Round进行一次。所以merge_epochmerge_iteration 这两个参数,其实就是定义好了全局权重更新的频率。
全局权重更新和本地权重更新的频率并不是一定相同的。这就带来一个问题,用户编写模型训练代码,也就是train方法,只对应于一个epoch的训练, 所以一个Round中,可能需要运行多次train方法,也可能只需要运行train的一部分就行了。运行多次容易做到,但是如果只需要 运行train的一部分,就很难办了。那么要怎么解决这个问题呢?
这其实是通过调整train方法的输入参数来实现的。用户在编写代码的时候认为,train方法的参数,就是一个完整的数据集。但是 Delta框架在运行过程中,会提前知道一个Round对应了多少个iteration,或者多少个epoch,也就知道一个Round实际上对应了多少数据, 只要对train方法的输入参数进行调整,使输入的数据集大小正好等于一个Round对应的数据集大小,就可以保证每个Round只对应一个train方法了。
接下来是validate。传统的机器学习中,验证的频率也是用户自行控制的,可以每隔一定的epoch验证一次,也可以每隔一定的iteration验证一次。 但是在横向联邦学习中,每个Round才会更新一次全局的模型权重,没有更新全局权重时,验证是没有意义的。所以,在横向联邦学习中,用户需要指定,每隔多少个Round进行一次验证。 在任务的构造函数中,用户可以通过validate_interval这个方法,来控制验证的频率:validate_interval=1,就表示 每个Round都进行一次validate,以此类推,默认第一个Round结束后,才开始运行第一次validate。通过这个参数,就可以知道 在哪一个Round中插入validate方法了。
剩下的方法就很简单了,state_dictdatasetmake_train_dataloadermake_validate_dataloader,分别对应的模型、数据集和预处理过的数据集, 每个Round中,它们都是不变的,所以只需要在任务开始的第一个Round中执行一次即可。
接下来,我们需要将这6个方法,对应到map与reduce操作中去。在对应的时候,需要遵守这个原则:map操作是在客户端执行的;reduce操作是在服务端执行的; 而map+reduce操作,需要聚合多个客户端的数据。从这个原则出发,我们可以得到:
  1. 1.
    state_dict:对应一个map操作,和一个reduce操作。因为在客户端上,需要提取出模型的权重进行安全聚合;在服务端上,需要全局更新模型的权重。
  2. 2.
    dataset:对应一个map操作。因为只有在客户端上,才有数据集。
  3. 3.
    make_train_dataloadermake_validate_dataloader:分别对应一个map操作。因为只有在客户端上,才有数据集。
  4. 4.
    train:对应一个map+reduce操作。因为一个Round训练完后,需要把本地的模型权重通过链上安全聚合系统提交,才能进行全局的更新。
  5. 5.
    validate:对应一个map+reduce操作。因为一个Round中验证完成之后,得到的只是模型在本地数据的验证结果,想要得到全局数据上的验证结果,还需要聚合多个客户端的结果。
将这些方法与map和reduce对应起来之后,构建任务就比较简单了。我们还是按照构建计算图的做法,先在图上添加datasetmake_train_dataloadermake_validate_dataloader 对应的操作,然后根据有多少个Round、验证的频率,依次添加train方法与validate对应的操作。然后与横向联邦统计中意义,通过计算图,构建出一个完整的隐私计算任务。