Node#

class fl_sim.nodes.Node[source]#

Bases: ReprMixin, ABC

An abstract base class for the server and client nodes.

static aggregate_results_from_json_log(d: dict | str | Path, part: str = 'val', metric: str = 'acc') → ndarray[source]#

Aggregate the federated results from json log.

Thin static-method wrapper kept for backward compatibility; see fl_sim.utils.misc.aggregate_results_from_json_log() for the (maintained) implementation and the expected log structure.

abstract communicate(target: Node) → None[source]#

Communicate with the target node.

The current node communicates model parameters, gradients, etc. to target node.

The typed API (recommended) sends ClientToServer / ServerToClient messages via Server.receive_one() / Client.receive(); the base classes provide working default implementations for the common cases:

# client -> server (typed, default implementation of Client.communicate)
target.receive_one(
    ClientToServer(
        client_id=self.client_id,
        train_samples=...,
        metrics=self._metrics,
        parameters=self.get_detached_model_parameters(),
    )
)
# server -> client (typed, default implementation of Server.communicate)
target.receive(ServerToClient(parameters=self.get_detached_model_parameters()))

The legacy API (kept working, used by the built-in algorithms) manipulates the _received_messages containers directly:

# client -> server (legacy)
target._received_messages.append(
    ClientMessage(
        {
            "client_id": self.client_id,
            "parameters": self.get_detached_model_parameters(),
            "train_samples": ...,
            "metrics": self._metrics,
        }
    )
)
# server -> client (legacy)
target._received_messages = {"parameters": self.get_detached_model_parameters()}
compute_gradients(at: Sequence[Tensor] | None = None, dataloader: DataLoader | None = None) → List[Tensor][source]#

Compute the gradients of the model on the node.

The gradients are computed on the model parameters at or the current model parameters, as the average of the gradients on the mini-batches from dataloader or self.train_loader.

Parameters:
  • at (list of torch.Tensor, optional) – The model parameters to compute the gradients. None for the current model parameters.

  • dataloader (torch.utils.data.DataLoader, optional) – The dataloader to compute the gradients. None for self.train_loader.

get_detached_model_parameters() → List[Tensor][source]#

Get the detached model parameters.

get_gradients(norm: str | int | float | None = None, model: Module | None = None) → float | List[Tensor][source]#

Get the gradients or norm of the gradients of the model on the node.

Parameters:
  • norm (str or int or float, optional) – The norm of the gradients to compute. None for the raw gradients (list of tensors). Refer to torch.linalg.norm() for more details.

  • model (torch.nn.Module, optional) – The model to get the gradients, default to self.model.

Returns:

The gradients or norm of the gradients.

Return type:

float or List[torch.Tensor]

get_model_state() → Dict[str, Tensor][source]#

Get the model state as a named tensor mapping (ModelState).

The (recommended) named-parameter exchange format: an ordered mapping from component names to tensors. The model does NOT need to be a torch.nn.Module; the default implementation here is an adapter for module models (wrapping torch.nn.Module.state_dict()), and models of any other kind get first-class support by overriding this method and set_model_state() on the node (server or client) holding the model.

Returns:

The named model parameters (detached clones).

Return type:

Dict[str, torch.Tensor]

static get_norm(tensor: Number | Tensor | ndarray | Parameter | GeneratorType | Sequence[ndarray | Tensor | Parameter | GeneratorType], norm: str | int | float = 'fro') → float[source]#

Get the norm of a tensor.

Parameters:
Returns:

The norm of the tensor.

Return type:

float

abstract property is_convergent: bool#

Whether the training process on the node is convergent.

set_model_state(state: Mapping[str, Tensor]) → None[source]#

Set the model state from a named tensor mapping (ModelState).

The counterpart of get_model_state(); module models are handled by the default implementation (torch.nn.Module.load_state_dict()), and other model kinds override this method on the node holding the model.

Parameters:

state (Mapping[str, torch.Tensor]) – The named model parameters to load.

set_parameters(params: Iterable[Parameter], model: Module | None = None) → None[source]#

Set the parameters of the model on the node.

Parameters:
Return type:

None

abstract update() → None[source]#

Update model parameters, gradients, etc. according to self._reveived_messages.