Configure clients¶
En plus des paramètres du modèle, Flower peut envoyer des valeurs de configuration aux clients. Les valeurs de configuration peuvent être utilisées à diverses fins. Elles constituent, par exemple, un moyen populaire de contrôler les hyperparamètres côté client à partir du serveur.
Valeurs de configuration¶
Les valeurs de configuration sont représentées sous forme de dictionnaire avec des clés str` et des valeurs de type bool, bytes, double (float de précision 64 bits), int, ou str (ou des types équivalents dans d’autres langages). Voici un exemple de dictionnaire de configuration en Python :
config_dict = {
"dropout": True, # str key, bool value
"learning_rate": 0.01, # str key, float value
"batch_size": 32, # str key, int value
"optimizer": "sgd", # str key, str value
}
Flower sérialise ces dictionnaires de configuration (ou config dict en abrégé) dans leur représentation ProtoBuf, les transporte vers le client à l’aide de gRPC, puis les désérialise à nouveau en dictionnaires Python.
Note
Actuellement, il n’est pas possible d’envoyer directement des types de collections (par exemple, Set
, List
, Map
) en tant que valeurs dans les dictionnaires de configuration. Il existe plusieurs solutions pour envoyer des collections en tant que valeurs en les convertissant en l’un des types de valeurs pris en charge (et en les reconvertissant du côté client).
On peut, par exemple, convertir une liste de nombres à virgule flottante en une chaîne JSON, puis envoyer la chaîne JSON à l’aide du dictionnaire de configuration, et enfin reconvertir la chaîne JSON en une liste de nombres à virgule flottante sur le client.
Configuration par le biais de stratégies intégrées¶
The easiest way to send configuration values to clients is to use a built-in strategy
like FedAvg
. Built-in strategies support so-called configuration functions. A
configuration function is a function that the built-in strategy calls to get the
configuration dictionary for the current round. It then forwards the configuration
dictionary to all the clients selected during that round.
Commençons par un exemple simple. Imaginons que nous voulions envoyer (a) la taille du lot que le client doit utiliser, (b) le cycle global actuel de l’apprentissage fédéré et (c) le nombre d’époques à former du côté client. Notre fonction de configuration pourrait ressembler à ceci :
def fit_config(server_round: int):
"""Return training configuration dict for each round."""
config = {
"batch_size": 32,
"current_round": server_round,
"local_epochs": 2,
}
return config
To make the built-in strategies use this function, we can pass it to FedAvg
during
initialization using the parameter on_fit_config_fn
:
strategy = FedAvg(
..., # Other FedAvg parameters
on_fit_config_fn=fit_config, # The fit_config function we defined earlier
)
Côté client, nous recevons le dictionnaire de configuration dans fit
:
class FlowerClient(flwr.client.NumPyClient):
def fit(parameters, config):
print(config["batch_size"]) # Prints `32`
print(config["current_round"]) # Prints `1`/`2`/`...`
print(config["local_epochs"]) # Prints `2`
# ... (rest of `fit` method)
Il existe également une fonction on_evaluate_config_fn pour configurer l’évaluation, qui fonctionne de la même manière. Ce sont des fonctions séparées car on peut vouloir envoyer différentes valeurs de configuration à evaluate (par exemple, pour utiliser une taille de lot différente).
Les stratégies intégrées appellent cette fonction à chaque tour (c’est-à-dire à chaque fois que Strategy.configure_fit ou Strategy.configure_evaluate s’exécute). Appeler on_evaluate_config_fn à chaque tour nous permet de varier/changer le dict de config au cours de tours consécutifs. Si nous voulions mettre en place un calendrier d’hyperparamètres, par exemple, pour augmenter le nombre d’époques locales au cours des derniers tours, nous pourrions faire ce qui suit :
def fit_config(server_round: int):
"""Return training configuration dict for each round."""
config = {
"batch_size": 32,
"current_round": server_round,
"local_epochs": 1 if server_round < 2 else 2,
}
return config
The FedAvg
strategy will call this function every round.
Configuration des clients individuels¶
Dans certains cas, il est nécessaire d’envoyer des valeurs de configuration différentes à des clients différents.
This can be achieved by customizing an existing strategy or by implementing a
custom strategy from scratch. Here’s a nonsensical
example that customizes FedAvg
by adding a custom "hello": "world"
configuration
key/value pair to the config dict of a single client (only the first client in the
list, the other clients in this round to not receive this « special » config value):
class CustomClientConfigStrategy(fl.server.strategy.FedAvg):
def configure_fit(
self, server_round: int, parameters: Parameters, client_manager: ClientManager
) -> List[Tuple[ClientProxy, FitIns]]:
client_instructions = super().configure_fit(
server_round, parameters, client_manager
)
# Add special "hello": "world" config key/value pair,
# but only to the first client in the list
_, fit_ins = client_instructions[0] # First (ClientProxy, FitIns) pair
fit_ins.config["hello"] = "world" # Change config for this client only
return client_instructions
# Create strategy and run server
strategy = CustomClientConfigStrategy(
# ... (same arguments as plain FedAvg here)
)
fl.server.start_server(strategy=strategy)