@@ -88,7 +88,7 @@ def _run_validation(
8888 return {key : total / total_samples for key , total in weighted_sums .items ()}
8989
9090
91- def run_training_loop (
91+ def run_training_loop ( # noqa: C901
9292 model : nn .Module ,
9393 loss_function : nn .Module ,
9494 learning_rate : float ,
@@ -121,7 +121,7 @@ def run_training_loop(
121121 :param val_check_interval: If set, validate every this many training steps.
122122 :param check_val_every_epoch: If set, validate every this many epochs.
123123 :param compute_metrics: Computes validation metrics from `(head_out, y, loss)`. Defaults to just `val_loss`.
124- :return: The model's state dict as of the last validation check before training stopped .
124+ :return: The model's state dict from the validation check with the best `val_metric` .
125125 """
126126 model .to (device )
127127 loss_function .to (device )
@@ -144,17 +144,22 @@ def run_training_loop(
144144
145145 max_epochs = _resolve_max_epochs (max_epochs )
146146
147- last_checkpoint = copy .deepcopy (model .state_dict ())
147+ best_checkpoint = copy .deepcopy (model .state_dict ())
148+ best_val_metric = float ("inf" ) if early_stopping_direction == "min" else float ("-inf" )
148149 current_epoch = 0
149150 global_step = 0
150151 postfix : dict [str , str ] = {}
151152 latest_val_loss : float | None = None
152153
153154 def validate_and_checkpoint () -> bool :
154- nonlocal last_checkpoint , latest_val_loss
155+ nonlocal best_checkpoint , best_val_metric , latest_val_loss
155156 metrics = _run_validation (model , loss_function , compute_metrics , val_loader , device )
156157 latest_val_loss = metrics ["val_loss" ]
157- last_checkpoint = copy .deepcopy (model .state_dict ())
158+ current = metrics [val_metric ]
159+ improved = current < best_val_metric if early_stopping_direction == "min" else current > best_val_metric
160+ if improved :
161+ best_val_metric = current
162+ best_checkpoint = copy .deepcopy (model .state_dict ())
158163 postfix .update ({key : f"{ value :.4f} " for key , value in metrics .items ()})
159164 if early_stopper is None :
160165 return False
@@ -178,17 +183,17 @@ def validate_and_checkpoint() -> bool:
178183 should_stop = validate_and_checkpoint ()
179184 pbar .set_postfix (postfix )
180185 if should_stop and (min_epochs is None or current_epoch >= min_epochs ):
181- return last_checkpoint
186+ return best_checkpoint
182187
183188 current_epoch += 1
184189
185190 if check_val_every_epoch is not None and current_epoch % check_val_every_epoch == 0 :
186191 should_stop = validate_and_checkpoint ()
187192 pbar .set_postfix (postfix )
188193 if should_stop and (min_epochs is None or current_epoch >= min_epochs ):
189- return last_checkpoint
194+ return best_checkpoint
190195
191196 _step_plateau_scheduler (scheduler , latest_val_loss )
192197
193198 if current_epoch >= max_epochs :
194- return last_checkpoint
199+ return best_checkpoint
0 commit comments