with the help of the Event-driven Architecture, FederatedScope allows developers to customize FL applications via introducing new types of messages and the corresponding handling functions. Here we provide the implementation details.
Define new message type
Firstly developers should define a new type of message that is exchanged in the customized FL course. The new message should include sender, receiver, msg_type, and payload.
For example, we define
Message(sender=server, receiver=client, msg_type='gradients', payload=MODEL_GRADIENTS) to denote a new message containing gradients that is passed from the server to the client.
Add handling function
After that, users should implement the handling function for the receiver (here is the client) to handle the newly defined message. The operations in the handling function might include parsing the payload, updating models, aggregating, triggering some events, returning feedback, and so on. For example:
class Client(object): ... ... # A handling function of client for 'gradients' def callback_for_messgae_gradients(self, message): # parse the payload sender, model_gradients = message.sender, message.content assert sender == self.server_ID # update model via trainer self.trainer.update_by_gradients(model_gradients) # trigger some events if self.trainer.get_delta_of_model() > self.threshold: # local training updated_model = self.trainer.local_train() else: updated_model = self.model # return the feedback via communivator self.comm_manager.send( Message(sender=self.ID, receiver=sender, msg_type='updated_model', content=updated_model))
Note that in some cases, the newly added handling function includes returning a message, such as updated_model in the example. Users might need to define a new handling function for the returned message if it is also a new type, or accordingly modify the implemented handling functions if necessary.
Register the handling function
FederatedScope allows users to add the new handling functions for servers or clients by registering:
self.register_handlers( message_type='gradients', callback_func=callback_for_messgae_gradients)
Thus, a new type of message can be exchanged and handled in a customized FL task.