|
7 | 7 |
|
8 | 8 | import torch |
9 | 9 | import torch.nn as nn |
10 | | -from flwr.client import NumPyClient |
11 | 10 | from flwr.common.logger import log |
12 | 11 | from flwr.common.typing import Config, NDArrays, Scalar |
13 | 12 | from torch.nn.modules.loss import _Loss |
|
16 | 15 | from torch.utils.data import DataLoader |
17 | 16 |
|
18 | 17 | from fl4health.checkpointing.client_module import CheckpointMode, ClientCheckpointAndStateModule |
| 18 | +from fl4health.clients.basic_client import BasicClient |
19 | 19 | from fl4health.metrics.base_metrics import TEST_LOSS_KEY, TEST_NUM_EXAMPLES_KEY, Metric |
20 | 20 | from fl4health.metrics.metric_managers import MetricManager |
21 | 21 | from fl4health.parameter_exchange.full_exchanger import FullParameterExchanger |
|
30 | 30 | process_and_check_validation_steps, |
31 | 31 | set_pack_losses_with_val_metrics, |
32 | 32 | ) |
33 | | -from fl4health.utils.config import narrow_dict_type, narrow_dict_type_and_set_attribute |
| 33 | +from fl4health.utils.config import narrow_dict_type |
34 | 34 | from fl4health.utils.early_stopper import EarlyStopper |
35 | 35 | from fl4health.utils.logging import LoggingMode |
36 | 36 | from fl4health.utils.losses import EvaluationLosses, LossMeter, LossMeterType, TrainingLosses |
37 | 37 | from fl4health.utils.random import generate_hash |
38 | 38 | from fl4health.utils.typing import LogLevel, TorchFeatureType, TorchInputType, TorchPredType, TorchTargetType |
39 | 39 |
|
40 | 40 |
|
41 | | -class FlexibleClient(NumPyClient): |
| 41 | +class FlexibleClient(BasicClient): |
42 | 42 | def __init__( |
43 | 43 | self, |
44 | 44 | data_path: Path, |
@@ -1420,49 +1420,19 @@ def transform_gradients(self, losses: TrainingLosses) -> None: |
1420 | 1420 |
|
1421 | 1421 | def _save_client_state(self) -> None: |
1422 | 1422 | """ |
1423 | | - Saves checkpoint dict consisting of client name, total steps, lr schedulers, metrics reporter and |
1424 | | - optimizers state. Method can be overridden to augment saved checkpointed state. |
| 1423 | + Save a checkpoint of the client's state as defined by the state_checkpointer's snapshot_attrs. |
| 1424 | + By default, snapshot_attrs includes attributes such as client name, total steps, lr schedulers, |
| 1425 | + metrics reporter, and optimizer states. You can override snapshot_attrs in the state_checkpointer to |
| 1426 | + customize which attributes are saved in the checkpoint. |
1425 | 1427 | """ |
1426 | | - |
1427 | | - state = { |
1428 | | - "lr_schedulers_state": {key: scheduler.state_dict() for key, scheduler in self.lr_schedulers.items()}, |
1429 | | - "total_steps": self.total_steps, |
1430 | | - "client_name": self.client_name, |
1431 | | - "reports_manager": self.reports_manager, |
1432 | | - "optimizers_state": {key: optimizer.state_dict()["state"] for key, optimizer in self.optimizers.items()}, |
1433 | | - } |
1434 | | - |
1435 | | - self.checkpoint_and_state_module.save_state(self.state_checkpoint_name, state) |
| 1428 | + assert self.checkpoint_and_state_module.state_checkpointer is not None |
| 1429 | + self.checkpoint_and_state_module.save_state(self) |
1436 | 1430 |
|
1437 | 1431 | def _load_client_state(self) -> bool: |
1438 | 1432 | """ |
1439 | 1433 | Load checkpoint dict consisting of client name, total steps, lr schedulers, metrics reporter and optimizers |
1440 | 1434 | state. Method can be overridden to augment loaded checkpointed state. |
1441 | 1435 | """ |
1442 | | - client_state = self.checkpoint_and_state_module.maybe_load_state(self.state_checkpoint_name) |
1443 | | - |
1444 | | - if client_state is None: |
1445 | | - return False |
1446 | | - |
1447 | | - narrow_dict_type_and_set_attribute(self, client_state, "client_name", "client_name", str) |
1448 | | - narrow_dict_type_and_set_attribute(self, client_state, "total_steps", "total_steps", int) |
1449 | | - narrow_dict_type_and_set_attribute(self, client_state, "reports_manager", "reports_manager", ReportsManager) |
1450 | | - |
1451 | | - assert "lr_schedulers_state" in client_state and isinstance(client_state["lr_schedulers_state"], dict) |
1452 | | - assert "optimizers_state" in client_state and isinstance(client_state["optimizers_state"], dict) |
1453 | | - |
1454 | | - # Optimizer is updated in setup_client to reference model weights from server |
1455 | | - # Thus, only optimizer state (per parameter values such as momentum) |
1456 | | - # should be loaded |
1457 | | - for key, optimizer in self.optimizers.items(): |
1458 | | - optimizer_state = client_state["optimizers_state"][key] |
1459 | | - optimizer_state_dict = optimizer.state_dict() |
1460 | | - optimizer_state_dict["state"] = optimizer_state |
1461 | | - optimizer.load_state_dict(optimizer_state_dict) |
1462 | | - |
1463 | | - # Schedulers initialized in setup_client to reference correct optimizers |
1464 | | - # Here we load in all other aspects of the scheduler state |
1465 | | - for key in self.lr_schedulers: |
1466 | | - self.lr_schedulers[key].load_state_dict(client_state["lr_schedulers_state"][key]) |
1467 | | - |
1468 | | - return True |
| 1436 | + assert self.checkpoint_and_state_module.state_checkpointer is not None |
| 1437 | + log(INFO, "Loading client state from checkpoint") |
| 1438 | + return self.checkpoint_and_state_module.maybe_load_state(self) |
0 commit comments