@@ -37,9 +37,7 @@ class DittoPersonalizedProtocol(AdaptiveDriftConstrainedProtocol, Protocol):
3737 def get_global_model (self , config : Config ) -> nn .Module :
3838 pass # pragma: no cover
3939
40- def _copy_optimizer_with_new_params (
41- self , original_optimizer : Optimizer
42- ) -> Optimizer :
40+ def _copy_optimizer_with_new_params (self , original_optimizer : Optimizer ) -> Optimizer :
4341 pass # pragma: no cover
4442
4543 def set_initial_global_tensors (self ) -> None :
@@ -79,9 +77,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
7977 super ().__init__ ()
8078
8179 if not isinstance (self , FlexibleClientProtocolPreSetup ):
82- raise RuntimeError (
83- "This object needs to satisfy `FlexibleClientProtocolPreSetup`."
84- ) # pragma: no cover
80+ raise RuntimeError ("This object needs to satisfy `FlexibleClientProtocolPreSetup`." ) # pragma: no cover
8581
8682 def __init_subclass__ (cls , ** kwargs : Any ) -> None :
8783 """This method is called when a class inherits from AdaptiveMixin."""
@@ -133,9 +129,7 @@ def optimizer_keys(self: DittoPersonalizedProtocol) -> list[str]:
133129 """
134130 return ["local" , "global" ]
135131
136- def _copy_optimizer_with_new_params (
137- self : DittoPersonalizedProtocol , original_optimizer : Optimizer
138- ) -> Optimizer :
132+ def _copy_optimizer_with_new_params (self : DittoPersonalizedProtocol , original_optimizer : Optimizer ) -> Optimizer :
139133 """
140134 Helper method to make a copy of the original optimizer for the global model.
141135
@@ -165,13 +159,9 @@ def _copy_optimizer_with_new_params(
165159 "Unable to get the original `lr` for the global optimizer, falling back to `1e-3`." ,
166160 )
167161
168- optimizer_kwargs = {
169- k : v for k , v in param_group .items () if k not in ("params" , "initial_lr" )
170- }
162+ optimizer_kwargs = {k : v for k , v in param_group .items () if k not in ("params" , "initial_lr" )}
171163 assert self .global_model is not None
172- global_optimizer = optim_class (
173- self .global_model .parameters (), ** optimizer_kwargs
174- )
164+ global_optimizer = optim_class (self .global_model .parameters (), ** optimizer_kwargs )
175165
176166 # maintain initial_lr for schedulers
177167 for param_group in global_optimizer .param_groups :
@@ -196,9 +186,7 @@ def get_global_model(self: DittoPersonalizedProtocol, config: Config) -> nn.Modu
196186 return model_copy .to (self .device )
197187
198188 @ensure_protocol_compliance
199- def get_optimizer (
200- self : DittoPersonalizedProtocol , config : Config
201- ) -> dict [str , Optimizer ]:
189+ def get_optimizer (self : DittoPersonalizedProtocol , config : Config ) -> dict [str , Optimizer ]:
202190 """
203191 Returns a dictionary with global and local optimizers with string keys "global" and "local" respectively.
204192
@@ -207,9 +195,7 @@ def get_optimizer(
207195 """
208196 if self .global_model is None :
209197 # try set it here
210- self .global_model = self .get_global_model (
211- config
212- ) # is this the same config?
198+ self .global_model = self .get_global_model (config ) # is this the same config?
213199 log (
214200 INFO ,
215201 f"global model set: { type (self .global_model ).__name__ } within `get_optimizer`" ,
@@ -219,9 +205,7 @@ def get_optimizer(
219205 optimizer = super ().get_optimizer (config = config ) # type: ignore[safe-super]
220206 if isinstance (optimizer , dict ):
221207 try :
222- original_optimizer = next (
223- el for el in optimizer .values () if isinstance (el , Optimizer )
224- )
208+ original_optimizer = next (el for el in optimizer .values () if isinstance (el , Optimizer ))
225209 except StopIteration as e :
226210 log (ERROR , "Unable to find an ~torch.optim.Optimizer object." )
227211 raise e
@@ -242,9 +226,7 @@ def set_optimizer(self: DittoPersonalizedProtocol, config: Config) -> None:
242226 config (Config): The config from the server.
243227 """
244228 optimizers = self .get_optimizer (config )
245- assert isinstance (optimizers , dict ) and set (self .optimizer_keys ) == set (
246- optimizers .keys ()
247- )
229+ assert isinstance (optimizers , dict ) and set (self .optimizer_keys ) == set (optimizers .keys ())
248230 self .optimizers = optimizers
249231
250232 @ensure_protocol_compliance
@@ -286,16 +268,12 @@ def get_parameters(self: DittoPersonalizedProtocol, config: Config) -> NDArrays:
286268 # NOTE: the global model weights are sent to the server here.
287269 if self .global_model is None :
288270 raise ValueError ("Unable to get parameters with unset global model." )
289- global_model_weights = self .parameter_exchanger .push_parameters (
290- self .global_model , config = config
291- )
271+ global_model_weights = self .parameter_exchanger .push_parameters (self .global_model , config = config )
292272
293273 # Weights and training loss sent to server for aggregation
294274 # Training loss sent because server will decide to increase or decrease the penalty weight, if adaptivity
295275 # is turned on
296- packed_params = self .parameter_exchanger .pack_parameters (
297- global_model_weights , self .loss_for_adaptation
298- )
276+ packed_params = self .parameter_exchanger .pack_parameters (global_model_weights , self .loss_for_adaptation )
299277 log (INFO , "Successfully packed parameters of global model" )
300278 return packed_params
301279
@@ -324,17 +302,9 @@ def set_parameters(
324302 the server.
325303 """
326304 # Make sure that the proper components exist.
327- assert (
328- self .global_model is not None
329- and self .model is not None
330- and self .parameter_exchanger is not None
331- )
332- server_model_state , self .drift_penalty_weight = (
333- self .parameter_exchanger .unpack_parameters (parameters )
334- )
335- log (
336- INFO , f"Lambda weight received from the server: { self .drift_penalty_weight } "
337- )
305+ assert self .global_model is not None and self .model is not None and self .parameter_exchanger is not None
306+ server_model_state , self .drift_penalty_weight = self .parameter_exchanger .unpack_parameters (parameters )
307+ log (INFO , f"Lambda weight received from the server: { self .drift_penalty_weight } " )
338308
339309 current_server_round = narrow_dict_type (config , "current_server_round" , int )
340310 if current_server_round == 1 and fitting_round :
@@ -346,13 +316,9 @@ def set_parameters(
346316 else :
347317 # Route the parameters to the GLOBAL model in Ditto after the initial stage
348318 log (INFO , "Setting the global model weights" )
349- self .parameter_exchanger .pull_parameters (
350- server_model_state , self .global_model , config
351- )
319+ self .parameter_exchanger .pull_parameters (server_model_state , self .global_model , config )
352320
353- def initialize_all_model_weights (
354- self : DittoPersonalizedProtocol , parameters : NDArrays , config : Config
355- ) -> None :
321+ def initialize_all_model_weights (self : DittoPersonalizedProtocol , parameters : NDArrays , config : Config ) -> None :
356322 """
357323 If this is the first time we're initializing the model weights, we initialize both the global and the local
358324 weights together.
@@ -363,24 +329,19 @@ def initialize_all_model_weights(
363329 """
364330 parameter_exchanger = cast (FullParameterExchanger , self .parameter_exchanger )
365331 parameter_exchanger .pull_parameters (parameters , self .model , config )
366- parameter_exchanger .pull_parameters (
367- parameters , self .safe_global_model (), config
368- )
332+ parameter_exchanger .pull_parameters (parameters , self .safe_global_model (), config )
369333
370334 def set_initial_global_tensors (self : DittoPersonalizedProtocol ) -> None :
371335 """
372336 Saving the initial **GLOBAL MODEL** weights and detaching them so that we don't compute gradients with
373337 respect to the tensors. These are used to form the Ditto local update penalty term.
374338 """
375339 self .drift_penalty_tensors = [
376- initial_layer_weights .detach ().clone ()
377- for initial_layer_weights in self .safe_global_model ().parameters ()
340+ initial_layer_weights .detach ().clone () for initial_layer_weights in self .safe_global_model ().parameters ()
378341 ]
379342
380343 @ensure_protocol_compliance
381- def update_before_train (
382- self : DittoPersonalizedProtocol , current_server_round : int
383- ) -> None :
344+ def update_before_train (self : DittoPersonalizedProtocol , current_server_round : int ) -> None :
384345 """
385346 Procedures that should occur before proceeding with the training loops for the models. In this case, we
386347 save the global models parameters to be used in constraining training of the local model.
@@ -420,22 +381,16 @@ def train_step(
420381 self .safe_global_model (), self .optimizers ["global" ], input , target
421382 )
422383 # local
423- local_losses , local_preds = self ._compute_preds_and_losses (
424- self .model , self .optimizers ["local" ], input , target
425- )
426- local_loss_clone = local_losses .backward [
427- "backward"
428- ].clone () # need a clone for later
384+ local_losses , local_preds = self ._compute_preds_and_losses (self .model , self .optimizers ["local" ], input , target )
385+ local_loss_clone = local_losses .backward ["backward" ].clone () # need a clone for later
429386
430387 # take step global
431388 global_losses = self ._apply_backwards_on_losses_and_take_step (
432389 self .safe_global_model (), self .optimizers ["global" ], global_losses
433390 )
434391 # take step local
435392 penalty_loss = self .compute_penalty_loss ()
436- local_losses .backward ["backward" ] = (
437- local_losses .backward ["backward" ] + penalty_loss
438- )
393+ local_losses .backward ["backward" ] = local_losses .backward ["backward" ] + penalty_loss
439394 local_losses = self ._apply_backwards_on_losses_and_take_step (
440395 self .model , self .optimizers ["local" ], local_losses
441396 )
@@ -450,9 +405,7 @@ def train_step(
450405 local_losses .additional_losses = additional_losses
451406
452407 # combined preds
453- if isinstance (global_preds , torch .Tensor ) and isinstance (
454- local_preds , torch .Tensor
455- ):
408+ if isinstance (global_preds , torch .Tensor ) and isinstance (local_preds , torch .Tensor ):
456409 combined_preds = {"global" : global_preds , "local" : local_preds }
457410 elif isinstance (global_preds , dict ) and isinstance (local_preds , dict ):
458411 combined_preds = {f"global-{ k } " : v for k , v in global_preds .items ()}
@@ -464,9 +417,7 @@ def val_step(
464417 self : DittoPersonalizedProtocol , input : TorchInputType , target : TorchTargetType
465418 ) -> tuple [EvaluationLosses , TorchPredType ]:
466419 # global
467- global_losses , global_preds = self ._val_step_with_model (
468- self .safe_global_model (), input , target
469- )
420+ global_losses , global_preds = self ._val_step_with_model (self .safe_global_model (), input , target )
470421 # local
471422 local_losses , local_preds = self ._val_step_with_model (self .model , input , target )
472423
@@ -520,9 +471,5 @@ def compute_evaluation_loss(
520471 indexed by name.
521472 """
522473 # Check that both models are in eval mode
523- assert (
524- self .global_model is not None
525- and not self .global_model .training
526- and not self .model .training
527- )
474+ assert self .global_model is not None and not self .global_model .training and not self .model .training
528475 return super ().compute_evaluation_loss (preds , features , target ) # type: ignore[safe-super]
0 commit comments