Skip to content

Commit 8330bab

Browse files
authored
[Major] simplify learning rate finder and use log-mean of default and smooth suggestion (#1630)
* simplify learning rate finder * set learning rate to logarithmic mean of smooth and default. * move logic to util
1 parent 982e152 commit 8330bab

File tree

3 files changed

+20
-10
lines changed

3 files changed

+20
-10
lines changed

neuralprophet/configure.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def set_lr_finder_args(self, dataset_size, num_batches):
208208
Set the lr_finder_args.
209209
This is the range of learning rates to test.
210210
"""
211-
num_training = 150 + int(np.log10(100 + dataset_size) * 25)
211+
num_training = 100 + int(np.log10(dataset_size) * 20)
212212
if num_batches < num_training:
213213
log.warning(
214214
f"Learning rate finder: The number of batches ({num_batches}) is too small than the required number \
@@ -217,7 +217,7 @@ def set_lr_finder_args(self, dataset_size, num_batches):
217217
# num_training = num_batches
218218
self.lr_finder_args.update(
219219
{
220-
"min_lr": 1e-6,
220+
"min_lr": 1e-7,
221221
"max_lr": 10,
222222
"num_training": num_training,
223223
"early_stop_threshold": None,

neuralprophet/forecaster.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2805,13 +2805,12 @@ def _train(
28052805
lr_finder = tuner.lr_find(
28062806
model=self.model,
28072807
train_dataloaders=train_loader,
2808-
val_dataloaders=val_loader,
2808+
# val_dataloaders=val_loader, # not be used, but may lead to Lightning bug if not provided
28092809
**self.config_train.lr_finder_args,
28102810
)
28112811
# Estimate the optimal learning rate from the loss curve
28122812
assert lr_finder is not None
2813-
_, _, lr_suggestion = utils.smooth_loss_and_suggest(lr_finder.results)
2814-
self.model.learning_rate = lr_suggestion
2813+
_, _, self.model.learning_rate = utils.smooth_loss_and_suggest(lr_finder)
28152814
start = time.time()
28162815
self.trainer.fit(
28172816
self.model,
@@ -2832,8 +2831,7 @@ def _train(
28322831
)
28332832
assert lr_finder is not None
28342833
# Estimate the optimal learning rate from the loss curve
2835-
_, _, lr_suggestion = utils.smooth_loss_and_suggest(lr_finder.results)
2836-
self.model.learning_rate = lr_suggestion
2834+
_, _, self.model.learning_rate = utils.smooth_loss_and_suggest(lr_finder)
28372835
start = time.time()
28382836
self.trainer.fit(
28392837
self.model,

neuralprophet/utils.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ def set_log_level(log_level: str = "INFO", include_handlers: bool = False):
751751
set_logger_level(logging.getLogger("NP"), log_level, include_handlers)
752752

753753

754-
def smooth_loss_and_suggest(lr_finder_results, window=10):
754+
def smooth_loss_and_suggest(lr_finder, window=10):
755755
"""
756756
Smooth loss using a Hamming filter.
757757
@@ -769,10 +769,12 @@ def smooth_loss_and_suggest(lr_finder_results, window=10):
769769
suggested_lr: float
770770
Suggested learning rate based on gradient
771771
"""
772+
lr_finder_results = lr_finder.results
772773
lr = lr_finder_results["lr"]
773774
loss = lr_finder_results["loss"]
774775
# Derive window size from num lr searches, ensure window is divisible by 2
775-
half_window = math.ceil(round(len(loss) * 0.1) / 2)
776+
# half_window = math.ceil(round(len(loss) * 0.1) / 2)
777+
half_window = math.ceil(window / 2)
776778
# Pad sequence and initialialize hamming filter
777779
loss = np.pad(np.array(loss), pad_width=half_window, mode="edge")
778780
window = np.hamming(half_window * 2)
@@ -798,7 +800,17 @@ def smooth_loss_and_suggest(lr_finder_results, window=10):
798800
"samples or manually set the learning rate."
799801
)
800802
raise
801-
return (loss, lr, suggestion)
803+
suggestion_default = lr_finder.suggestion(skip_begin=10, skip_end=3)
804+
if suggestion is not None and suggestion_default is not None:
805+
log_suggestion_smooth = np.log(suggestion)
806+
log_suggestion_default = np.log(suggestion_default)
807+
lr_suggestion = np.exp((log_suggestion_smooth + log_suggestion_default) / 2)
808+
elif suggestion is None and suggestion_default is None:
809+
log.error("Automatic learning rate test failed. Please set manually the learning rate.")
810+
raise
811+
else:
812+
lr_suggestion = suggestion if suggestion is not None else suggestion_default
813+
return (loss, lr, lr_suggestion)
802814

803815

804816
def _smooth_loss(loss, beta=0.9):

0 commit comments

Comments
 (0)