1+ from __future__ import annotations
2+
13from collections .abc import Sequence
24from enum import Enum
35from logging import INFO
4- from typing import Any
6+ from typing import TYPE_CHECKING
57
68import torch .nn as nn
79from flwr .common .logger import log
810from flwr .common .typing import Scalar
911
10- from fl4health .checkpointing .checkpointer import PerRoundStateCheckpointer , TorchModuleCheckpointer
12+ if TYPE_CHECKING :
13+ from fl4health .clients .basic_client import BasicClient
14+
15+ from fl4health .checkpointing .checkpointer import TorchModuleCheckpointer
16+ from fl4health .checkpointing .state_checkpointer import ClientStateCheckpointer
1117
1218ModelCheckpointers = TorchModuleCheckpointer | Sequence [TorchModuleCheckpointer ] | None
1319
@@ -18,11 +24,12 @@ class CheckpointMode(Enum):
1824
1925
2026class ClientCheckpointAndStateModule :
27+
2128 def __init__ (
2229 self ,
2330 pre_aggregation : ModelCheckpointers = None ,
2431 post_aggregation : ModelCheckpointers = None ,
25- state_checkpointer : PerRoundStateCheckpointer | None = None ,
32+ state_checkpointer : ClientStateCheckpointer | None = None ,
2633 ) -> None :
2734 """
2835 This module is meant to hold up three to major components that determine how clients handle model and state
@@ -44,9 +51,9 @@ def __init__(
4451 post_aggregation (ModelCheckpointers, optional): If defined, this checkpointer (or sequence
4552 of checkpointers) is used to checkpoint models based on their validation metrics/losses **AFTER**
4653 server-side aggregation. Defaults to None.
47- state_checkpointer (PerRoundStateCheckpointer | None, optional): If defined, this checkpointer is used to
48- preserve client state (not just models), in the event one wants to restart federated training.
49- Defaults to None.
54+ state_checkpointer (ClientStateCheckpointer | None, optional): If defined, this checkpointer
55+ is used to preserve client state (not just models), in the event one wants to restart
56+ federated training. Defaults to None.
5057 """
5158 self .pre_aggregation = (
5259 [pre_aggregation ] if isinstance (pre_aggregation , TorchModuleCheckpointer ) else pre_aggregation
@@ -119,52 +126,42 @@ def maybe_checkpoint(
119126 else :
120127 raise ValueError (f"Unrecognized mode for checkpointing: { str (mode )} " )
121128
122- def save_state (self , state_checkpoint_name : str , state : dict [ str , Any ] ) -> None :
129+ def save_state (self , client : BasicClient ) -> None :
123130 """
124131 This function is meant to facilitate saving state required to restart an FL process on the client side. This
125- function will simply save whatever information is passed in the state variable using the file name in
126- ``state_checkpoint_name``. This function should only be called if a ``state_checkpointer`` exists in this
127- module
132+ function will simply save all the attributes stated in ``ClientStateCheckpointer.snapshot_attrs``.
133+ This function should only be called if a ``state_checkpointer`` exists in this module.
128134
129135 Args:
130- state_checkpoint_name (str): Name of the state checkpoint file. The checkpointer itself will have a
131- directory to which state will be saved.
132- state (dict[str, Any]): State to be saved so that training might be resumed on the client if federated
133- training is interrupted. For example, this might contain things like optimizer states, learning rate
134- scheduler states, etc.
136+ client (BasicClient): The client object from which state will be saved.
135137
136138 Raises:
137139 ValueError: Throws an error if this function is called, but no state checkpointer has been provided
138140 """
139141
140142 if self .state_checkpointer is not None :
141- self .state_checkpointer .save_checkpoint ( state_checkpoint_name , state )
143+ self .state_checkpointer .save_client_state ( client )
142144 else :
143145 raise ValueError ("Attempting to save state but no state checkpointer is specified" )
144146
145- def maybe_load_state (self , state_checkpoint_name : str ) -> dict [ str , Any ] | None :
147+ def maybe_load_state (self , client : BasicClient ) -> bool :
146148 """
147- This function facilitates loading of any pre-existing state (with the name ``state_checkpoint_name ``) in the
148- directory of the ``state_checkpointer ``. If the state already exists at the proper path, the state is loaded
149- and returned . If it doesn't exist, we return None .
149+ This function facilitates loading of any pre-existing state (with the name ``checkpoint_name ``) in the
150+ directory of the ``checkpoint_dir ``. If the state already exists at the proper path, the state is loaded
151+ and will be automatically saved into client's attributes . If it doesn't exist, we return False .
150152
151153 Args:
152- state_checkpoint_name (str): Name of the state checkpoint file. The checkpointer itself will have a
153- directory from which state will be loaded (if it exists).
154+ client (BasicClient): client object into which state will be loaded if a checkpoint exists
154155
155156 Raises:
156157 ValueError: Throws an error if this function is called, but no state checkpointer has been provided
157158
158159 Returns:
159- dict[str, Any] | None : If the state checkpoint properly exists and is loaded correctly, this dictionary
160- carries that state . Otherwise, we return a None (or throw an exception).
160+ bool : If the state checkpoint properly exists and is loaded correctly, client's attributes
161+ are set to the loaded values, and True is returned . Otherwise, we return False (or throw an exception).
161162 """
162163
163164 if self .state_checkpointer is not None :
164- if self .state_checkpointer .checkpoint_exists (state_checkpoint_name ):
165- return self .state_checkpointer .load_checkpoint (state_checkpoint_name )
166- else :
167- log (INFO , "State checkpointer is defined but no state checkpoint exists." )
168- return None
165+ return self .state_checkpointer .maybe_load_client_state (client )
169166 else :
170167 raise ValueError ("Attempting to load state, but no state checkpointer is specified" )
0 commit comments