It seems that fit() is not called normally

This is the log of my server.py, all of which are 0 results and 2 failures

INFO :
INFO : [ROUND 1]
INFO : configure_fit: strategy sampled 2 clients (out of 2)
INFO : aggregate_fit: received 0 results and 2 failures
[Server] Round 1: 0 results, 2 failures
Round 1 evaluation loss: 2.3127, accuracy: 0.0989
INFO : fit progress: (1, 2.3127286434173584, {‘accuracy’: 0.09888888895511627}, 9.558189600007609)
INFO : configure_evaluate: strategy sampled 2 clients (out of 2)
INFO : aggregate_evaluate: received 0 results and 2 failures
INFO :
INFO : [ROUND 2]
INFO : configure_fit: strategy sampled 2 clients (out of 2)
INFO : aggregate_fit: received 0 results and 2 failures
[Server] Round 2: 0 results, 2 failures
Round 2 evaluation loss: 2.3127, accuracy: 0.0989
INFO : fit progress: (2, 2.3127286434173584, {‘accuracy’: 0.09888888895511627}, 9.695105200007674)
INFO : configure_evaluate: strategy sampled 2 clients (out of 2)
INFO : aggregate_evaluate: received 0 results and 2 failures
INFO :
INFO : [ROUND 3]
INFO : configure_fit: strategy sampled 2 clients (out of 2)
INFO : aggregate_fit: received 0 results and 2 failures
[Server] Round 3: 0 results, 2 failures
Round 3 evaluation loss: 2.3127, accuracy: 0.0989
INFO : fit progress: (3, 2.3127286434173584, {‘accuracy’: 0.09888888895511627}, 9.825406700008898)
INFO : configure_evaluate: strategy sampled 2 clients (out of 2)
INFO : aggregate_evaluate: received 0 results and 2 failures

I don’t know where the problem is… This is my server.py
import flwr as fl
import pandas as pd
import numpy as np
from model import dnn_model
from data_process import split_data
from flwr.common import parameters_to_ndarrays, FitIns, EvaluateIns

#split_data()

server_mean = np.load(“server_data/mean.npy”)
server_std = np.load(“server_data/std.npy”)

val_df = pd.read_csv(“server_data/val.csv”)
y_val = val_df[“Label”].values
x_val = val_df.drop(columns=[“Label”]).values.astype(np.float32)
x_val = (x_val - server_mean) / (server_std + 1e-6)

model = dnn_model()

class SaveClientsData(fl.server.strategy.FedAvg):
def init(self, model, val_data, Global_mean, Global_std, **kwargs):
super().init(**kwargs)
self.model = model
self.x_val, self.y_val = val_data
self.global_mean = Global_mean
self.global_std = Global_std

def configure_fit(self, server_round, parameters, client_manager):
    config = {
        "global_mean": self.global_mean.tolist(),
        "global_std": self.global_std.tolist(),
    }

    allclients = client_manager.sample(
        num_clients=self.min_fit_clients, min_num_clients=self.min_fit_clients
    )

    return [(client, FitIns(parameters, config)) for client in allclients]

def configure_evaluate(self, server_round, parameters, client_manager):
    cfg = {
        "global_mean": self.global_mean.tolist(),
        "global_std":  self.global_std.tolist(),
    }
    allclients = client_manager.sample(
        num_clients=self.min_fit_clients, min_num_clients=self.min_fit_clients
    )
    return [(client, EvaluateIns(parameters, cfg)) for client in allclients]

def aggregate_fit(self, rnd, result, failure):
    print(f"[Server] Round {rnd}: {len(result)} results, {len(failure)} failures")
    if not result:
        return None, {}

    acc = []
    for _, fit_res in result:
        metrics = fit_res.metrics
        if metrics and "accuracy" in metrics:
            acc.append(metrics["accuracy"])

    if acc:
        print(f"Round {rnd} accuracies: {acc}")

    return super().aggregate_fit(rnd, result, failure)

def evaluate(self, server_rnd, parameters, config=None):
    weights = parameters_to_ndarrays(parameters)
    self.model.set_weights(weights)
    loss, accuracy = self.model.evaluate(x_val, y_val, verbose=0)
    print(f"Round {server_rnd} evaluation loss: {loss:.4f}, accuracy: {accuracy:.4f}")
    return loss, {"accuracy": accuracy}

print(“[Server] Waiting for clients to connect…”)
fl.server.start_server(
server_address=“0.0.0.0:8080”,
config=fl.server.ServerConfig(num_rounds=10, round_timeout=60),
strategy=SaveClientsData(
model = model,
val_data=(x_val, y_val),
Global_mean=server_mean,
Global_std=server_std,
min_fit_clients = 2,
min_evaluate_clients = 2,
min_available_clients = 2,
fraction_fit=1.0
)
)

And this is my client.py:
import flwr as fl
import pandas as pd
import numpy as np
from model import dnn_model
import argparse

class FlClient(fl.client.NumPyClient):
def init(self , client_num):
self.model = dnn_model()
self.client_num = client_num
self.load_data()
self.is_standardized = False

    print(f"[Client {self.client_num}] Samples: {self.x_train.shape}, {self.y_train.shape}")
    

def load_data(self):
    df = pd.read_csv(f'client_data/client_{self.client_num}.csv')

    y = df["Label"].values
    x = df.drop(columns=["Label", "Split"]).values.astype(np.float32)
    is_split = df["Split"].values

    self.x_train = x[is_split == "train"]
    self.y_train = y[is_split == "train"]

    self.x_test = x[is_split == "test"]
    self.y_test = y[is_split == "test"]

def standardize(self, server_mean, server_std):
    self.x_train = (self.x_train - server_mean) / server_std
    self.x_test = (self.x_test - server_mean) / server_std
    if np.any(np.isnan(self.x_train)) or np.any(np.isinf(self.x_train)):
        print(f"[Client {self.client_num}]  Data has NaN or inf after standardization")
    self.is_standardized = True

def get_parameters(self, config):
    return self.model.get_weights()

def __del__(self):
    print(f"[Client {self.client_num}] shutting down")

def fit(self, parameters, config):
    try:
        print(f"[Client {self.client_num}] fit() triggered.")
        print(f"Received parameters: {[w.shape for w in parameters]}")
        print(f"Model expects: {[w.shape for w in self.model.get_weights()]}")

        if not self.is_standardized:
            if "global_mean" in config and "global_std" in config:
                server_mean = np.array(config["global_mean"])
                server_std = np.array(config["global_std"])
                self.standardize(server_mean, server_std)
            else:
                print(f"[Client {self.client_num}] Missing standardization config.")

        self.model.set_weights(parameters)
        history = self.model.fit(self.x_train, self.y_train, epochs=10, batch_size=32, verbose=0)
        acc = history.history["accuracy"][-1]
        return self.model.get_weights(), len(self.x_train), {"accuracy": acc}

    except Exception as e:
        import traceback
        traceback.print_exc()
        raise e 

def evaluate(self, parameters, config):
    if not self.is_standardized:
        if "global_mean" in config and "global_std" in config:
            server_mean = np.array(config["global_mean"])
            server_std = np.array(config["global_std"])
            self.standardize(server_mean, server_std)
        else:
            print(f"[Client {self.client_num}] Missing standardization config. Skipping standardization.")


    self.model.set_weights(parameters)
    loss, acc = self.model.evaluate(self.x_test, self.y_test, verbose=0)
    return loss, len(self.x_test), {"accuracy": acc}  

def main():
parser = argparse.ArgumentParser()
parser.add_argument(“–client_num”, type=int, required=True)
args = parser.parse_args()

fl.client.start_numpy_client(
    server_address="127.0.0.1:8080",
    client=FlClient(args.client_num)
)

if name == “main”:
main()

Hi @josephkung, welcome to the Flower Community!

Having 0 results and 2 failures indicates that something on the client side might be wrong. The code also uses start_numpy_client, which is deprecated.

My recommendation would be to create a new project using flwr new. This project can be directly started using flwr run. Once that’s confirmed to work (the built-in templates are well tested and work out of the box), you can start to move the code from the project above into this new project step-by-step.

Hello @daniel ! First of all, thank you very much for your reply.

In your suggestion (using flwr new), does it mean that my flower version is too low?
I use vscode for programming, and the version of flower is 1.19.0.

How should I implement your suggestion? Do you mean to use pip install -U flwr to upgrade the version and then try again?
Or if there are relevant practical articles for me to refer to, I am also very willing to learn.

Thank you!

Flower 1.19 is the latest version. Once installed, you can use the flwr CLI to create and run projects using a number of templates (via flwr new and flwr run).

Here’s a tutorial that covers it: Quickstart PyTorch - Flower Framework

Thank you very much for your quick reply and the article!

Since it’s getting late, I will study it carefully tomorrow.
I hope I will have this opportunity to ask you for advice when I encounter difficulties.