Hello,
I have tried to take over the scaffold implementation from the niid_bench (git_hub). I made a few changes but the logic of the scaffold remained unchanged.
The error occurs that > torch.from_numpy(cv + cv_multiplier * aggregated_cv_update[i])
> IndexError: list index out of range.
I have created a few outputs to show me the problem
Aggregated parameters are empty (None).
The dictionary with additional results is empty.
aggregated_result (None, {})
Size of server_cv: %d, Size of aggregated_cv_update: %d 105 0
Length of self.server_cv: 105
Length of aggregated_cv_update: 0
It shows that the aggregated_ results are empty. Here is the fit_round function from the Scaffold_Server class
def fit_round(
self,
server_round: int,
timeout: Optional[float],
) -> Optional[
Tuple[Optional[Parameters], Dict[str, Scalar], FitResultsAndFailures]
]:
"""Perform a single round of federated averaging."""
# Get clients and their respective instructions from strateg
client_instructions = self.strategy.configure_fit(
server_round=server_round,
parameters=update_parameters_with_cv(self.parameters, self.server_cv),
client_manager=self._client_manager,
)
if not client_instructions:
log(INFO, "fit_round %s: no clients selected, cancel", server_round)
return None
log(
DEBUG,
"fit_round %s: strategy sampled %s clients (out of %s)",
server_round,
len(client_instructions),
self._client_manager.num_available(),
)
# Collect `fit` results from all clients participating in this round
results, failures = fit_clients(
client_instructions=client_instructions,
max_workers=self.max_workers,
timeout=timeout,
)
log(
DEBUG,
"fit_round %s received %s results and %s failures",
server_round,
len(results),
len(failures),
)
# Aggregate training results
aggregated_result: Tuple[Optional[Parameters], Dict[str, Scalar]] = (
self.strategy.aggregate_fit(server_round, results, failures)
)
# Check if the first element (aggregated parameters) is None or not
if aggregated_result[0] is None:
print("Aggregated parameters are empty (None).")
else:
print("Aggregated parameters are available.")
# Check if the second element (the dictionary) is empty or not
if not aggregated_result[1]:
print("The dictionary with additional results is empty.")
else:
print("The dictionary with additional results contains data.")
aggregated_result_arrays_combined = []
if aggregated_result[0] is not None:
aggregated_result_arrays_combined = parameters_to_ndarrays(
aggregated_result[0]
)
print('aggregated_result', aggregated_result)
aggregated_parameters = aggregated_result_arrays_combined[
: len(aggregated_result_arrays_combined) // 2
]
aggregated_cv_update = aggregated_result_arrays_combined[
len(aggregated_result_arrays_combined) // 2 :
]
# convert server cv into ndarrays
server_cv_np = [cv.numpy() for cv in self.server_cv]
# update server cv
total_clients = len(self._client_manager.all())
cv_multiplier = len(results) / total_clients
It should also be noted that I do not use the main method but start the server via
server = ScaffoldServer(strategy=strategy) fl.server.start_server(server_address=“0.0.0.0:8080”, server=server, config=fl.server.ServerConfig(num_rounds=1)).
In the Github project it is done via the main method with start_simulation …