首页 > 编程语言 >联邦学习算法介绍-FedAvg详细案例-Python代码获取

联邦学习算法介绍-FedAvg详细案例-Python代码获取

时间:2023-06-08 13:05:46浏览次数:72  
标签:20 val nn Python self args FedAvg 算法 np



联邦学习算法介绍-FedAvg详细案例-Python代码获取

  • 一、联邦学习系统框架
  • 二、联邦平均算法(FedAvg)
  • 三、联邦随梯度下降算法 (FedSGD)
  • 四、差分隐私随联邦梯度下降算法 (DP-FedSGD)
  • 五、差分隐私联邦平均算法 (DP-FedAVG)
  • 六、FedAVG 案例附代码
  • 1)案例背景
  • 2)参数设置
  • 3)结果展示
  • 4)代码详解
  • 七、完整项目代码获取方式


一、联邦学习系统框架

联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器


图1 中心化联邦学习框架

  由服务端收集各客户端的梯度信息,通过聚合计算后再分发给各客户端,从而实现多个客户端联合训练模型,且“原始数据不出岛”,从而保护了客户端数据隐私。

联邦学习算法介绍-FedAvg详细案例-Python代码获取_客户端_02


图2 去中心化联邦学习框架

  假设中心方是好奇的,那么客户端通过某种规则向其他客户端广播梯度信息,收到梯度信息的客户端聚合参数并训练,将新的梯度信息广播。

二、联邦平均算法(FedAvg)

联邦学习算法介绍-FedAvg详细案例-Python代码获取_客户端_03


图3 联邦平均算法框架

输入: 全局模型参数初始值 联邦学习算法介绍-FedAvg详细案例-Python代码获取_机器学习_04, 参与方个数 联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_05, 批样本大小 联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_06, 训练轮数 联邦学习算法介绍-FedAvg详细案例-Python代码获取_客户端_07, 参与方比例 联邦学习算法介绍-FedAvg详细案例-Python代码获取_机器学习_08, 局部模型学习率 联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_09, 各参与方的样本个数 联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_10

输出: 最后一次迭代的全局模型参数 联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_11

1.中央服务器初始化全局模型参数 联邦学习算法介绍-FedAvg详细案例-Python代码获取_机器学习_04, 并传输给所有参与方。

2.对 联邦学习算法介绍-FedAvg详细案例-Python代码获取_客户端_13, 迭代以下步骤直到全局模型参数 联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_11

联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_15, 计算参与第 联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_16

联邦学习算法介绍-FedAvg详细案例-Python代码获取_算法_17

联邦学习算法介绍-FedAvg详细案例-Python代码获取_机器学习_18 个参与方, 构成参与方集合 联邦学习算法介绍-FedAvg详细案例-Python代码获取_客户端_19

联邦学习算法介绍-FedAvg详细案例-Python代码获取_机器学习_20, 通过以下步骤更新局部模型参数:

联邦学习算法介绍-FedAvg详细案例-Python代码获取_机器学习_21 进行模型初始化 联邦学习算法介绍-FedAvg详细案例-Python代码获取_客户端_22

联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_23 按照批样本大小 联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_06 分为若干个批次, 记由这些批次构成的集合为 联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_25 。 对每次训练 联邦学习算法介绍-FedAvg详细案例-Python代码获取_机器学习_26, 使用 联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_27, 更新局部模型参数:

联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_28

将更新好的局部模型参数 联邦学习算法介绍-FedAvg详细案例-Python代码获取_算法_29

  (4) 中央服务器聚合所有参数,并传输回所有参与方
联邦学习算法介绍-FedAvg详细案例-Python代码获取_机器学习_30
     联邦学习算法介绍-FedAvg详细案例-Python代码获取_客户端_31

三、联邦随梯度下降算法 (FedSGD)

当训练轮数 联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_32, 且批样本大小 联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_06

使用各自的所有样本, 对参数 联邦学习算法介绍-FedAvg详细案例-Python代码获取_算法_29 进行一次梯度下降, 计算参数 联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_35 的梯度:
联邦学习算法介绍-FedAvg详细案例-Python代码获取_算法_36

或者计算参数更新值
联邦学习算法介绍-FedAvg详细案例-Python代码获取_算法_37

其中 联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_09

四、差分隐私随联邦梯度下降算法 (DP-FedSGD)

联邦学习算法介绍-FedAvg详细案例-Python代码获取_算法_39


图4 DP-FedSGD算法框架

1.参数更新量的裁剪方式ClipFn
裁剪方式分2种,即水平裁剪和分层裁剪。

(1) 水平裁剪。记参数更新量矢量为 联邦学习算法介绍-FedAvg详细案例-Python代码获取_客户端_40, 将其 2 -范数的上界设为 联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_41, 即:

联邦学习算法介绍-FedAvg详细案例-Python代码获取_客户端_42

(2)分层裁剪。面向神经网络模型, 假设网络总共有 联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_43 层, 每一层的参数更新量矢量分别为 联邦学习算法介绍-FedAvg详细案例-Python代码获取_客户端_44, 对应的 2 -范数上界分别为 联邦学习算法介绍-FedAvg详细案例-Python代码获取_客户端_45, 联邦学习算法介绍-FedAvg详细案例-Python代码获取_算法_46, 通过水平裁剪的方法, 分别对每一层的矢量进行裁剪:

联邦学习算法介绍-FedAvg详细案例-Python代码获取_机器学习_47

总体的参数更新量裁剪上界定义为
联邦学习算法介绍-FedAvg详细案例-Python代码获取_算法_48

2.中央服务器通过以下步骤对局部模型参数更新量进行聚合:

(1)计算聚合结果

关于加权聚合方式

联邦学习算法介绍-FedAvg详细案例-Python代码获取_客户端_49

(其中 联邦学习算法介绍-FedAvg详细案例-Python代码获取_算法_50 是参与方 联邦学习算法介绍-FedAvg详细案例-Python代码获取_机器学习_51 的参数更新量, 联邦学习算法介绍-FedAvg详细案例-Python代码获取_机器学习_08为一轮中参与迭代的参与方集合)的有界灵敏度(Bounded-sensitivity)的估计量,分为以下2种:

    [1]
联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_53

其中 联邦学习算法介绍-FedAvg详细案例-Python代码获取_客户端_54, 是每个参与方的权重; 联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_55, 联邦学习算法介绍-FedAvg详细案例-Python代码获取_客户端_56为每轮通信中参与方的选择概率。

    [2]
联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_57

其中 联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_58

(2)令 S 联邦学习算法介绍-FedAvg详细案例-Python代码获取_算法_59

联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_60

(3)聚合全局模型的参数为
联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_61
其中, 联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_62 是均值为 0 、方差为 联邦学习算法介绍-FedAvg详细案例-Python代码获取_算法_63 的高斯分布; 联邦学习算法介绍-FedAvg详细案例-Python代码获取_机器学习_64

(4)根据 联邦学习算法介绍-FedAvg详细案例-Python代码获取_算法_65联邦学习算法介绍-FedAvg详细案例-Python代码获取_算法_66

五、差分隐私联邦平均算法 (DP-FedAVG)

  在DP-FedSGD中,被选中的参与方使用全局模型参数对局部模型进行初始化,通过批梯度下降法进行多轮梯度下降,计算梯度更新量。而在DP-FedAVG中,是利用一个批次的数据进行一次梯度下降,计算梯度更新量。

六、FedAVG 案例附代码

1)案例背景

  收集2012年某10个城市每天每小时的电力数据。用前24时刻的电力负荷值以及该时刻的4个相关气象数据,来预测该时刻的电力负荷值。

  构造四层的深度网络:
联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_67

联邦学习算法介绍-FedAvg详细案例-Python代码获取_机器学习_68为sigmoid激活函数。

2)参数设置


表1 FedAVG参数

参数


聚合轮数

5

本地训练次数

20

客户端总数

10

学习率

0.08

本地批量样本大小

50

优化器

adam

3)结果展示

  设置每轮随机抽取参与训练的客户端数量为2、5、8、10。

联邦学习算法介绍-FedAvg详细案例-Python代码获取_机器学习_69


图5 FedAVG mae

联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_70


图6 FedAVG rmse

向梯度中添加随机噪声

联邦学习算法介绍-FedAvg详细案例-Python代码获取_服务器_71


图7 FedAVG+noise mae

联邦学习算法介绍-FedAvg详细案例-Python代码获取_算法_72


图8 FedAVG+noise rmse

4)代码详解

数据结构,在本地文件夹中,有10个csv文件,这10个文件各自代表一个客户端。

联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_73


在每个csv文件中,均有7个指标,6577条样本,其中第一列表示服务端id。

联邦学习算法介绍-FedAvg详细案例-Python代码获取_python_74


第一步,加载数据。首先需要划分每个客户端的训练集和测试集,本文设置了每个客户端数据结构与样本数量一致(也可以不一致,通过样本对齐方法即可)。

# -*- coding: utf-8 -*-
"""
@File :bp_nn.py
"""

import copy
import sys

import numpy as np
import pandas as pd
from torch import nn
from tqdm import tqdm

sys.path.append('../')
from sklearn.metrics import mean_absolute_error, mean_squared_error
from itertools import chain
from models import BP  ##自定义
import os
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"   #避免jupyter崩溃

clients_wind = ['Task1_W_Zone' + str(i) for i in range(1, 11)]
from args import args_parser  ##自定义参数


def load_data(file_name): #读取某一个文件---横向联邦学习
    df = pd.read_csv(os.path.dirname(os.getcwd()) + '/data/Wind_new/Task 1/Task1_W_Zone1_10/' + file_name + '.csv', encoding='gbk')
    columns = df.columns
    df.fillna(df.mean(), inplace=True)
    for i in range(3, 7): # 3,4,5,6
        MAX = np.max(df[columns[i]])
        MIN = np.min(df[columns[i]])
        df[columns[i]] = (df[columns[i]] - MIN) / (MAX - MIN) #将3,4,5,6列的值,标准化

    return df #0-6列,后4列已经标准化


def nn_seq_wind(file_name, B): #B 实则为本地批量大小
    print('data processing...')
    dataset = load_data(file_name)
    # split
    train = dataset[:int(len(dataset) * 0.6)] #前60%为训练集
    val = dataset[int(len(dataset) * 0.6):int(len(dataset) * 0.8)] #中间20%为验证集
    test = dataset[int(len(dataset) * 0.8):len(dataset)] #最后20%为测试集

    def process(data): #将特征与标签分开
        columns = data.columns
        wind = data[columns[2]]
        wind = wind.tolist()  #转换成列表 https://vimsky.com/examples/usage/python-pandas-series-tolist.html
        data = data.values.tolist()
        X, Y = [], []
        for i in range(len(data) - 30):
            train_seq = []
            train_label = []
            for j in range(i, i + 24):  #24小时
                train_seq.append(wind[j])

            for c in range(3, 7):
                train_seq.append(data[i + 24][c])
            train_label.append(wind[i + 24])
            X.append(train_seq)
            Y.append(train_label)

        X, Y = np.array(X), np.array(Y)

        length = int(len(X) / B) * B
        X, Y = X[:length], Y[:length]

        return X, Y

    train_x, train_y = process(train)
    val_x, val_y = process(val)
    test_x, test_y = process(test)

    return [train_x, train_y], [val_x, val_y], [test_x, test_y]


def get_val_loss(args, model, val_x, val_y): #验证集,计算损失,model即为nn
    batch_size = args.B
    batch = int(len(val_x) / batch_size) # 计算循环次数
    val_loss = []
    for i in range(batch):
        start = i * batch_size
        end = start + batch_size
        model.forward_prop(val_x[start:end], val_y[start:end])
        model.backward_prop(val_y[start:end])
    val_loss.append(np.mean(model.loss))

    return np.mean(val_loss)


def train(args, nn):
    print('training...')
    tr, val, te = nn_seq_wind(nn.file_name, args.B)
    train_x, train_y = tr[0], tr[1]
    val_x, val_y = val[0], val[1]
    nn.len = len(train_x)  # nn.len 训练集的长度
    batch_size = args.B    # 每批次大小
    epochs = args.E      # 迭代次数
    batch = int(len(train_x) / batch_size) #每一迭代,需要训练多少次
    # training
    min_epochs = 10  
    best_model = None
    min_val_loss = 5
    for epoch in tqdm(range(epochs)):
        train_loss = []
        for i in range(batch):
            start = i * batch_size
            end = start + batch_size
            nn.forward_prop(train_x[start:end], train_y[start:end])
            nn.backward_prop(train_y[start:end])
        train_loss.append(np.mean(nn.loss))
        # validation
        val_loss = get_val_loss(args, nn, val_x, val_y)
        if epoch + 1 >= min_epochs and val_loss < min_val_loss:
            min_val_loss = val_loss
            best_model = copy.deepcopy(nn)

        print('epoch {:03d} train_loss {:.8f} val_loss {:.8f}'.format(epoch, np.mean(train_loss), val_loss))

    return best_model


def get_mape(x, y):
    """
    :param x: true value
    :param y: pred value
    :return: mape
    """
    return np.mean(np.abs((x - y) / x))


def test(args, nn):
    tr, val, te = nn_seq_wind(nn.file_name, args.B)
    test_x, test_y = te[0], te[1]
    pred = []
    batch = int(len(test_y) / args.B)
    for i in range(batch):
        start = i * args.B
        end = start + args.B
        res = nn.forward_prop(test_x[start:end], test_y[start:end])
        res = res.tolist()
        res = list(chain.from_iterable(res))  
        #chain.from_iterable()属于终止迭代器类别 
        
        # print('res=', res)
        pred.extend(res)
    pred = np.array(pred)
    print('mae:', mean_absolute_error(test_y.flatten(), pred), 'rmse:',
          np.sqrt(mean_squared_error(test_y.flatten(), pred)))


def main():
    args = args_parser()
    for client in clients_wind:
        nn = BP(args, client)
        nn = train(args, nn)
        test(args, nn)


if __name__ == '__main__':
    main()

第二步,建立模型。在这里,前向传播计算结果,后向传播更新梯度。

# -*- coding:utf-8 -*-
"""
@File: models.py
"""

import numpy as np
from torch import nn


class BP:
    def __init__(self, args, file_name):
        self.file_name = file_name
        self.len = 0
        self.args = args
        self.input = np.zeros((args.B, args.input_dim))  # self.B samples per round  (本地批量大小=50,输入维度=28)
        
        self.w1 = 2 * np.random.random((args.input_dim, 20)) - 1  # limit to (-1, 1) (28,20)
        self.z1 = 2 * np.random.random((args.B, 20)) - 1  #np.random.random生成args.B=50行 20列的0-1浮点数;*2→(0-2),再-1,变成(-1,1)
        self.hidden_layer_1 = np.zeros((args.B, 20))     #(50,20)
        
        self.w2 = 2 * np.random.random((20, 20)) - 1     #(20,20)
        self.z2 = 2 * np.random.random((args.B, 20)) - 1  #(50,20)
        self.hidden_layer_2 = np.zeros((args.B, 20))     #(50,20)
        
        self.w3 = 2 * np.random.random((20, 20)) - 1     #(20,20)
        self.z3 = 2 * np.random.random((args.B, 20)) - 1  #(50,20)
        self.hidden_layer_3 = np.zeros((args.B, 20))     #(50,20)
        
        self.w4 = 2 * np.random.random((20, 1)) - 1     #(20,1)
        self.z4 = 2 * np.random.random((args.B, 1)) - 1  #(50,1)
        self.output_layer = np.zeros((args.B, 1))      #(50,1)
        
        self.loss = np.zeros((args.B, 1))           #(50,1)

    def sigmoid(self, x):
        return 1 / (1 + np.exp(-x))

    def sigmoid_deri(self, x):
        return x * (1 - x)

    def forward_prop(self, data, label):
        self.input = data
        # self.input(50,28)  self.w1(28, 20)  self.z1(50, 20)
        self.z1 = np.dot(self.input, self.w1) # np.dot 计算过程就是将向量中对应元素相乘,再相加所得。即普通的向量乘法运算。
        
        self.hidden_layer_1 = self.sigmoid(self.z1) # self.hidden_layer_1(50, 20)
        
        self.z2 = np.dot(self.hidden_layer_1, self.w2)  #self.w2(20,20) self.z2(50, 20)
        self.hidden_layer_2 = self.sigmoid(self.z2) # self.hidden_layer_2(50, 20)
        
        self.z3 = np.dot(self.hidden_layer_2, self.w3)  #self.w3(20,20) self.z3(50, 20)
        self.hidden_layer_3 = self.sigmoid(self.z3)    #(50,20)
        
        self.z4 = np.dot(self.hidden_layer_3, self.w4)  #self.w4 (20,1) self.z4(50,1)
        self.output_layer = self.sigmoid(self.z4)     #self.output_layer(50,1)
        # error

        self.loss = 1 / 2 * (label - self.output_layer) ** 2  ##(50,1)  why 1/2 ?

        return self.output_layer

    def backward_prop(self, label):
        # w4
        l_deri_out = self.output_layer - label
        l_deri_z4 = l_deri_out * self.sigmoid_deri(self.output_layer)
        l_deri_w4 = np.dot(self.hidden_layer_3.T, l_deri_z4)
        # w3
        l_deri_h3 = np.dot(l_deri_z4, self.w4.T)
        l_deri_z3 = l_deri_h3 * self.sigmoid_deri(self.hidden_layer_3)
        l_deri_w3 = np.dot(self.hidden_layer_2.T, l_deri_z3)
        # w2
        l_deri_h2 = np.dot(l_deri_z3, self.w3.T)
        l_deri_z2 = l_deri_h2 * self.sigmoid_deri(self.hidden_layer_2)
        l_deri_w2 = np.dot(self.hidden_layer_1.T, l_deri_z2)
        # w1
        l_deri_h1 = np.dot(l_deri_z2, self.w2.T)
        l_deri_z1 = l_deri_h1 * self.sigmoid_deri(self.hidden_layer_1)
        l_deri_w1 = np.dot(self.input.T, l_deri_z1)
        # update
        self.w4 -= self.args.lr * l_deri_w4  # self.args.lr 学习率=0.08  实则梯度下降
        self.w3 -= self.args.lr * l_deri_w3
        self.w2 -= self.args.lr * l_deri_w2
        self.w1 -= self.args.lr * l_deri_w1

第三步,设置参数。在实例化训练之前,为了便于调参,可将所有参数放在一个单独的文件中。

# -*- coding:utf-8 -*-
"""
@File: args.py
"""

# --E 相当于关键词参数,如果没有--直接是E,就是位置参数
# type=int 传入参数的类型
# default=20 当没有参数传入时,默认值为20, help='***' 表示对该参数的解释为***

'''
number of rounds of training: 训练次数
number of communication rounds:通信回合数,即上传下载模型次数。
number of total clients:客户端总数
input dimension :输入维度
learning rate :学习率
sampling rate :采样率
local batch size : 本地批量大小
type of optimizer : 优化器类型
--device:有GPU就用,不然就用CPU

weight_decay :权值衰减
weight decay(权值衰减)的使用既不是为了提高你所说的收敛精确度也不是为了提高收敛速度,其最终目的是防止过拟合。在损失函数中,weight decay是放在正则项(regularization)前面的一个系数,正则项一般指示模型的复杂度,所以weight decay的作用是调节模型复杂度对损失函数的影响,若weight decay很大,则复杂的模型损失函数的值也就大。

step size: 步长
gamma: 伽马参数
--clients: 10个客户端 Task1_W_Zone1、Task1_W_Zone2、Task1_W_Zone3...Task1_W_Zone10
'''

import argparse
import torch


def args_parser():
    parser = argparse.ArgumentParser() # 可选参数: description='描述程序内容' 通过命令行 python **.py--help 调用出

    parser.add_argument('--E', type=int, default=20, help='number of rounds of training')   
    parser.add_argument('--r', type=int, default=5, help='number of communication rounds')
    parser.add_argument('--K', type=int, default=10, help='number of total clients')
    parser.add_argument('--input_dim', type=int, default=28, help='input dimension')
    parser.add_argument('--lr', type=float, default=0.08, help='learning rate')
    parser.add_argument('--C', type=float, default=0.8, help='sampling rate')
    parser.add_argument('--B', type=int, default=50, help='local batch size')
    parser.add_argument('--optimizer', type=str, default='adam', help='type of optimizer')
    parser.add_argument('--device', default=torch.device("cuda" if torch.cuda.is_available() else "cpu"))
    parser.add_argument('--weight_decay', type=float, default=1e-4, help='weight_decay')
    parser.add_argument('--step_size', type=int, default=10, help='step size')
    parser.add_argument('--gamma', type=float, default=0.1, help='gamma')
    
    clients = ['Task1_W_Zone' + str(i) for i in range(1, 11)]
    parser.add_argument('--clients', default=clients)

    # args = parser.parse_args()
    # args,unknow = parser.parse_known_args()
    
    args = parser.parse_known_args()[0]
    return args

第4步,模型训练。

import numpy as np
import random
import copy
import sys

sys.path.append('../')
from algorithms.bp_nn import train, test
from models import BP 
from args import args_parser  # 一些传入参数,见args.py

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # 只看error


#-----------------tf用于设置随机数
import tensorflow as tf

clients_wind = ['Task1_W_Zone' + str(i) for i in range(1, 11)]

# Implementation for FedAvg by numpy. 通过numpy实现FedAvg。
class FedAvg:
    def __init__(self, args): #self 默认必须参数,有类中全局变量之效,args表示,调用FedAvg时,必须传入的参数
        self.args = args
        self.clients = args.clients
        self.nn = BP(args=args, file_name='server') # BP是models中的一个类,同样需要传入参数。file_name方便后面为每个客户端取名
        self.nns = []
        # distribution
        for i in range(self.args.K): #args.K,客户端总数; 子程序为每一个客户端构造了一个BP类
            #copy.deepcopy() 深复制的用法是将某个变量的值赋给另一个变量(此时两个变量地址不同),因为地址不同,所以变量间互不干扰
            s = copy.deepcopy(self.nn)  
            s.file_name = self.clients[i]
            self.nns.append(s)

    def server(self):
        for t in range(self.args.r): #通信回合数,即本地模型上传下载全局模型次数
            print('round', t + 1, ':') # 输出:round1、round2、round3、round4、round5
#             m = np.max([int(self.args.C * self.args.K), 1]) # 抽样率*客户端总数,即每一轮参与训练的客户端数量,至少有1个客户端参与
            m = 5
            print(m)
            # sampling
            index = random.sample(range(0, self.args.K), m) #在0-(k-1)之间共k个中抽取m个序号,注意是序号/索引
            print(len(index))
            # dispatch
            self.dispatch(index) # 下面定义了dispatch函数:抽中的m本地客户端从服务端下载4个参数
            # local updating
            self.client_update(index) # 下面定义了client_update函数:抽中的m个客户端进行本地训练
            # aggregation
            self.aggregation(index) # 下面定义了aggregation函数:抽中的m个客户端,上传本地训练结果参数

        # return global model
        return self.nn #返回最终聚合后的模型

    def aggregation(self, index):
        # update w
        s = 0 #用来计一轮抽中的m个本地客户端总的样本数
        for j in index:
            # normal
            s += self.nns[j].len
        w1 = np.zeros_like(self.nn.w1) #np.zeros_like:生成和self.nn.w1一样的零阵,下同
        w2 = np.zeros_like(self.nn.w2)
        w3 = np.zeros_like(self.nn.w3)
        w4 = np.zeros_like(self.nn.w4)
        
        #-----------------自增1018
        nois = 0.05
        for j in index: # 对上传的每一个本地模型进行权重的加权求和,权重为该客户端样本数/该轮中参与训练的总样本数
            # normal
            w1 += self.nns[j].w1 * (self.nns[j].len / s) + tf.random.normal([1],mean=0, stddev=nois).numpy()
            w2 += self.nns[j].w2 * (self.nns[j].len / s) + tf.random.normal([1],mean=0, stddev=nois).numpy()
            w3 += self.nns[j].w3 * (self.nns[j].len / s) + tf.random.normal([1],mean=0, stddev=nois).numpy()
            w4 += self.nns[j].w4 * (self.nns[j].len / s) + tf.random.normal([1],mean=0, stddev=nois).numpy()
        # update server 更新服务端参数
        self.nn.w1, self.nn.w2, self.nn.w3, self.nn.w4 = w1, w2, w3, w4

    def dispatch(self, index):
        # distribute
        for i in index:
            self.nns[i].w1, self.nns[i].w2, self.nns[i].w3, self.nns[i].w4 = self.nn.w1, self.nn.w2, self.nn.w3, self.nn.w4

    def client_update(self, index):  # update nn
        for k in index:
            self.nns[k] = train(self.args, self.nns[k])

    def global_test(self):
        model = self.nn #最终聚合后的模型
        c = clients_wind  # 10个客户端名称 Task1_W_Zone1、Task1_W_Zone2、Task1_W_Zone3...Task1_W_Zone10
        for client in c:
            print(client)
            model.file_name = client 
            test(self.args, model)

'''
L1损失函数: mae
均方根误差: rmse
'''

def main():
    args = args_parser()
    fed = FedAvg(args)
    fed.server()
    fed.global_test()

if __name__ == '__main__':
    main()

代码到此结束,以下是运行结果情况。

每次计算时,会输出结果,例如训练数据时情况

training...
data processing...
  0%|          | 0/20 [00:00<?, ?it/s]epoch 000 train_loss 0.00486654 val_loss 0.00703024
 50%|█████     | 10/20 [00:00<00:00, 95.47it/s]epoch 001 train_loss 0.00476797 val_loss 0.00696587
epoch 002 train_loss 0.00470252 val_loss 0.00693571
epoch 003 train_loss 0.00466028 val_loss 0.00693080
epoch 004 train_loss 0.00463130 val_loss 0.00694067
epoch 005 train_loss 0.00460982 val_loss 0.00695734
epoch 006 train_loss 0.00459274 val_loss 0.00697600
epoch 007 train_loss 0.00457843 val_loss 0.00699407
epoch 008 train_loss 0.00456600 val_loss 0.00701034
epoch 009 train_loss 0.00455495 val_loss 0.00702437
epoch 010 train_loss 0.00454502 val_loss 0.00703613
epoch 011 train_loss 0.00453605 val_loss 0.00704578
epoch 012 train_loss 0.00452794 val_loss 0.00705359
epoch 013 train_loss 0.00452062 val_loss 0.00705982
epoch 014 train_loss 0.00451403 val_loss 0.00706475
epoch 015 train_loss 0.00450812 val_loss 0.00706860
epoch 016 train_loss 0.00450283 val_loss 0.00707159
epoch 017 train_loss 0.00449813 val_loss 0.00707389
epoch 018 train_loss 0.00449396 val_loss 0.00707564

...

epoch 019 train_loss 0.00449026 val_loss 0.00707696
Task1_W_Zone1
data processing...
mae: 0.20787641855647404 rmse: 0.2836560807251283
Task1_W_Zone2
data processing...
mae: 0.1631928286850088 rmse: 0.21530131283252676
Task1_W_Zone3
data processing...

测试数据时,会输出每个客户端预测结果,例如

Task1_W_Zone10
data processing...
mae: 0.25128443075937873 rmse: 0.31826369651645525

最后收集这些结果,并可视化。
欢迎评论区交流沟通,博主将定期回复。

七、完整项目代码获取方式

以下方法,任一均可:
(1)点击 GitHub-numpy-FedAvg 自行下载。(访问: https://github.com/chenyiadam/FedAVG.git )
(2)私信留言、评论你的邮箱,我将定期回复。



标签:20,val,nn,Python,self,args,FedAvg,算法,np
From: https://blog.51cto.com/guog/6439016

相关文章

  • python爬虫技术实例详解及数据可视化库
    前言在当前数据爆发的时代,数据分析行业势头强劲,越来越多的人涉足数据分析领域。面对大量数据,人工获取信息的成本高、耗时长、效率低,那么是否能用代码去完成大量复杂的工作,从而从网络上获取到目标信息?由此,网络爬虫技术应运而生。本文目录,你将会看到网络爬虫简介网络爬虫(webcrawler,又......
  • python 安装包、基础学习资料、代码应用示例
    安装包python-3.7.0.rar链接:https://pan.baidu.com/s/1Gl5QUMrLFoTekENighd0iw提取码:ysgxpycharm5.0.3.zip链接:https://pan.baidu.com/s/1DpzRiMWSW2byWjB1cYmQKw提取码:9rgiAnaconda3jupyternotebook第一步进入:https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/第......
  • python 网络爬虫技术 运用正则表达式爬取当当网(实战演练)
    爬取网络:当当网代码importreimportrequestsimporttimeimportxlwturl_basic='http://search.dangdang.com/?key='heads={'Connection':'keep-alive','Accept-Language':'zh-CN,zh;q=0.9','......
  • CART——Classification And Regression Tree在python下的实现
    分类与回归树(CART——ClassificationAndRegressionTree))是一种非参数分类和回归方法,它通过构建二叉树达到预测目的。示例:1.样本数据集 2.运行结果-cart决策树的字典max_n_feats=3时tree_dict={house:{yes:agreen......
  • FTL潜规则:调优,才是算法精华
    前言在存储领域中有一个FTL的概念,这是一种Flash的内存管理算法,属于各个厂商的核心机密,每个厂商的处理方式不同,有的处理简单,有的处理复杂。FTL,即FlashTranslationslayer,也就是闪存转换层,可以完成从逻辑地址到物理地址的转换,简称为映射。 为什么需要FTL因为Flash的质量参差......
  • 基于OpenSSL(GMSSL)的国密算法的应用
    ===基于OpenSSL(GMSSL)的国密算法的应用1.gmssl介绍GmSSL是一个开源的加密包的python实现,支持SM2/SM3/SM4等国密(国家商用密码)算法、项目采用对商业应用友好的类BSD开源许可证,开源且可以用于闭源的商业应用。2.安装gmssl包相关包网址:https://pypi.org/project/gmssl/在终端输......
  • centos执行python脚本
    CentOS下载pyhon当pip下载失败,应该是版本太低了此时需要升级pip:#pip3执行pip3install--upgradepip#pip执行pipinstall--upgradepip#如果上面升级失败,可以试试python-mpipinstall--upgrade--forcepip解决方法1如果在升级过程中报标题中的错误,则通过g......
  • python selenium 浏览器操作 鼠标操作 键盘操作
    窗口截屏#截图driver.get_screenshot_as_file("C:\\Users\\95744\\Desktop\\test01\\test.png")关闭浏览器webdriver.quit()获取当前urldriver.current_url浏览器前进、后退、刷新#后退driver.back()#前进driver.forward()#刷新driver.refresh()......
  • python Qt实现最简单的程序
    1、创建一个程序,实例一个对象2、让这个对象跑起来3、创建组件4、设置标题5、展示出来点击查看代码fromPySide2.QtWidgetsimportQApplication,QMessageBoxfromPySide2.QtUiToolsimportQUiLoaderif__name__=="__main__":app=QApplication(sys.argv)w......
  • python 日志
    在自动化测试中,可以使用以下几种方式记录日志:1.使用内置的`print()`函数:#在需要记录日志的地方使用print()函数输出日志信息print("这是一条日志信息")2.使用标准库中的`logging`模块:importlogging#配置日志输出格式和级别logging.basicConfig(level=logging.INFO......