Add an algorithm to fluke
¶
Introduction¶
In this section, we will show how to add a new algorithm to be used in fluke
.
Attention
This page will go into the details of the implementation of the server, the client, and the federated learning algorithm. For a gentle introduction, please refer to New federated algorithm with fluke tutorial.
When a new federated learning algorithm is defined, its functioning can be described by detailing
the behavior of the server and the clients. This is exactly what you need to do to add a new algorithm
to be used in fluke
. You must define:
The
Server
class that inherits from the fluke.server.Server class;The
Client
class that inherits from the fluke.client.Client class.
You are not obliged to redefine both the server and the client classes, it depends on the algorithm you want to implement. For example, if your algorithm only differs from the standard FedAvg only in the way the clients behave, you only need to redefine the client class.
After having defined the server and the client classes, you must define the class representing the federated learning algorithm itself. This class must inherit from the CentralizedFL class and it is responsible for the initialization of the server and the clients. There is no much more to it, as the actual execution of the algorithm is delegated to the server. However, you must override the following methods:
get_client_class
: this method must return the client class you defined (if any);get_server_class
: this method must return the server class you defined (if any).
As pointed out before, only one of the two methods can be overridden according to the needs of the algorithm you are implementing.
The details of the implementation of the server, the client, and the federated learning algorithm are provided in the following sections:
Running your algorithm using fluke
¶
Using the fluke
CLI to run your algorithm is as easy as changing a few lines in the configuration file of the algorithm.
Let’s assume to have defined our algorithm in a python file named my_algorithm.py
and that the class representing the algorithm is named MyAlgorithm
.
The configuration file of the algorithm must be structured as follows (please make sure to run fluke
from the right directory):
1# THIS IS KEY
2# The name of the algorithm must be the fully qualified name to the algorithm's class
3name: my_algorithm.MyAlgorithm
4# Please refer to the algorithm's implementation to know which are its HPs
5hyperparameters:
6 # HPs of the clients
7 client:
8 batch_size: 10 # only an example
9 local_epochs: 5 # only an example
10 loss: CrossEntropyLoss # only an example
11 # Your client-side extra hyper-parameters (if any)
12 hyperparam1: value1
13 hyperparam2: value2
14 ...
15 optimizer:
16 ...
17 scheduler:
18 ...
19 server:
20 # Your server-side hyper-parameters (if any)
21 hyperparam1: value1
22 hyperparam2: value2
23 ...
24model: ...
1from fluke.algorithms import CentralizedFL
2from typing import Iterable
3from fluke.client import Client
4from fluke.server import Server
5import numpy as np
6
7
8class MyServer(Server):
9
10 # we override the aggregate method to implement our aggregation strategy
11 def aggregate(self, eligible: Iterable[Client]) -> None:
12 # eligible is a list of clients that participated in the last round
13 # here we randomly select only two of them
14
15 selected = np.random.choice(eligible, 2, replace=False)
16
17 # we call the parent class method to aggregate the selected clients
18 return super().aggregate(selected)
19
20
21class MyClient(Client):
22
23 # we override the fit method to implement our training "strategy"
24 def fit(self, override_local_epochs: int = 0) -> float:
25 # we can override the number of local epochs and call the parent class method
26 new_local_epochs = np.random.randint(1, self.hyper_params.local_epochs + 1)
27 return super().fit(new_local_epochs)
28
29
30class MyFLAlgorithm(CentralizedFL):
31
32 def get_client_class(self) -> Client:
33 return MyClient
34
35 def get_server_class(self) -> Server:
36 return MyServer