Skip to content

Commit 2a8a99b

Browse files
committed
lint
1 parent 75a99eb commit 2a8a99b

3 files changed

Lines changed: 67 additions & 206 deletions

File tree

fl4health/mixins/personalized/ditto.py

Lines changed: 25 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)