""" This is a non-official implementation of personalized FL method APPLE (https://www.ijcai.org/proceedings/2022/301). The original implementation is in github repo https://github.com/ljaiverson/pFL-APPLE """ import copy import torch import numpy as np import flgo.utils.fmodule as fmodule import flgo.algorithm.fedbase class Server(flgo.algorithm.fedbase.BasicServer): def initialize(self): self.init_algo_para({'M':self.num_clients-1, 'mu':0.1, 'lr_dr':1e-3, 'ratioL':0.1, 'type_loss_scheduler':'cos', }) self.L = self.num_rounds*self.ratioL for cid,c in enumerate(self.clients): c.L = self.L c.cid = cid self.core_models = [copy.deepcopy(self.model) for _ in self.clients] client_data_vols = torch.FloatTensor([len(c.train_data) for c in self.clients]) self.p0 = client_data_vols/client_data_vols.sum() self.select_mat = np.eye(self.num_clients) self.pss = torch.stack([self.p0.clone() for _ in self.clients]) self.sample_option = 'full' def pack(self, client_id, mtype=0): # select core models for client_id res = [] # select clients that never have been selected zero_clients= np.where(self.select_mat[client_id]==0.0)[0] if len(zero_clients)>0: if len(zero_clients)>self.M: client_js = np.random.choice(zero_clients, self.M, replace=False).tolist() else: client_js = zero_clients.tolist() res.extend(client_js) for j in res: self.select_mat[client_id][j] = 1. if len(res)0:torch.nn.utils.clip_grad_norm_(parameters=self.core_model.parameters(), max_norm=self.clip_grad) optimizer.step() self.p = pi self.model = fmodule._model_average(self.core_models, self.p) return