How to dynamically update num_rounds on the server and ensure clients keep training

Hello,
I’m implementing a Federated Learning system using Flower, and I’d like to know how I can dynamically update the server’s num_rounds according to the client’s parameters sent to the server. I have already tried setting a high value for num_rounds and making the server stop before reaching the maximum. However, since I work with online learning, the ideal approach is incrementally adding rounds instead.

Objective:

  • The server should start with num_rounds=1 , but dynamically increase as long as clients still have tasks.
  • Clients should continue sending updates until a threshold is reached.
  • The server should not stop too early , but it also shouldn’t run indefinitely .
1 Like

Hello @paularaissa,

What you propose doing is pretty interesting. It’s doable, but it requires some “advance” usage of Flower. Essentially you need to do two things. I’ll try to explain this below, but please ask if I should provide more details. I also want to mention that while the solution i propose below seems a bit convoluted, it’s the only way to achieve this as of today.

A different, much much simpler way of doing this will be possible in a future version of Flower that we are going to be presenting in the Flower Summit in 5 weeks from now ( register if you haven’t already!! → Flower AI Summit 2025)

When you create your ServerApp you need to use a custom strategy as well as a custom Server class. The former is needed so you can implement the logic to trigger that keeps extending the num_rounds. The latter is needed so the main for loop in the ServerApp (which is this one ) can run for as long or as short as needed based on what your clients return to the server.

  1. You need a custom strategy that, for example, computes by how many extra rounds the initial num_rounds should be increased by. Something like this:
class MyStrategy(FedAvg):
    def __init__(self, ...):
        self.increase_num_rounds_by = 0

    def aggregate(self, ....):
        .... # aggregate as usual
        # based on returned models or how the resulting global model looks like
        # update the variable, for example set it to 2
        self.increate_num_rounds_by = 2
  1. You need to use a custom Server class. You can do this by inheriting from the default one and only modify the fit() method (since it’s the one that has fixed num_rounds). This fit() method is the one that always calls the various methods in the strategy to trigger the rounds of fit and evaluate etc. With the new server class you implement, you can read the self.increase_num_rounds_by in the strategy and use it to increment the num_rounds variable. Something along these lines should do:
class MyServer(Server):

     def fit(self, ....):
     ...
     # for current_round in range(1, num_rounds + 1):
     num_rounds_left = num_rounds
     current_round = 0
     while num_rounds_left:
         current_round += 1
         # Do fit round
            res_fit = self.fit_round(
                server_round=current_round,
                timeout=timeout,
            )
         # Now inspect the strategy to see if we should increase number of rounds
         print(f"Increasing rounds by: { self.strategy.increase_num_rounds_by}")
         num_rounds_left += self.strategy.increase_num_rounds_by

         # Do everything as usual

         # at the end decrease
         num_rounds_left -= 1

I hope this brings some light on how you can accomplish what you want. Let us know if you get it done!

1 Like

Thank you so much! I was able to find a solution using your idea. I appreciate your help and insights!

1 Like