-
Notifications
You must be signed in to change notification settings - Fork 3.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add early stopping in dart mode #4805
Comments
Thanks for using LightGBM and for your question! Per #1893 (comment)
You can learn more about DART in the original DART paper (link), especially the section "Description of the DART Algorithm".
One way to do this is to use hyperparameter tuning over parameter Maybe others will be able to propose alternative ideas. If you are sure you want to use early stopping even knowing that it will produce unstable results because of how DART works, I think it's possible by providing a custom callback function in the Python API. But I don't have time at the moment to create an example of that and I'm not certain which examples / docs to point you to. |
Thanks a lot for the suggestions! |
This issue has been automatically closed because it has been awaiting a response for too long. When you have time to to work with the maintainers to resolve this issue, please post a new comment and it will be re-opened. If the issue has been locked for editing by the time you return to it, please open a new issue and reference this one. Thank you for taking the time to improve LightGBM! |
Hello @jameslamb and @benwu232, With reference to this:
I have referenced this kaggle notebook to write an early stopping and model checkpoint function for DART. def dart_early_stopping(save_path: str, stopping_rounds: int):
best_score = None
best_iteration = -1
counter = 0
def _callback(env):
nonlocal best_score
nonlocal best_iteration
nonlocal counter
if env.evaluation_result_list is not None:
# Format of example entry in env.evaluation_result_list:
# ('valid_0', 'binary_logloss', 0.2946547510575049, False)
# Index 0 = Result group name, in this case valid_0
# Index 1 = Metric name, in this case binary_logloss
# Index 2 = Numeric score, in this case 0.2946547510575049
# Index 3 = Higher is Better, in this case False because lower loss is better
score = env.evaluation_result_list[0][2]
higher_is_better = 1 if env.evaluation_result_list[0][3] else -1
if best_score is None or higher_is_better * best_score < higher_is_better * score:
# Best score improved
counter = 0
print(f"\tBest score improved from {best_score} to {score}, saving model at iteration {env.iteration}")
best_score = score
best_iteration = env.iteration
env.model.save_model(save_path, env.iteration)
return
counter += 1
if counter >= stopping_rounds:
print(f"\tBest score did not improve for {stopping_rounds} iterations, early stopping at iteration {env.iteration}")
payload = [
(
env.evaluation_result_list[0][0],
env.evaluation_result_list[0][1],
best_score,
higher_is_better
)
]
raise lgbm.callback.EarlyStopException(best_iteration=best_iteration, best_score=payload)
return _callback This is how I used it: clf = lgbm.LGBMClassifier(
boosting_type='dart',
num_leaves=31,
max_depth=10,
learning_rate=0.003,
n_estimators=1000,
objective='binary',
random_state=42,
importance_type='gain',
metric=None
)
clf.fit(
x_train,
y_train,
eval_set=[(x_val, y_val)],
feature_name='auto',
callbacks=[dart_early_stopping('model_bestscore.txt', 50)]
) Note that in my setup, I only have one evaluation metric and one evaluation set.
The callback above is designed to work only when Extending functionalityBear in mind how the Case 1: More than one evaluation metricclf.fit(
x_train,
y_train,
eval_set=[(x_val, y_val)],
eval_metric=['auc', 'logloss']
feature_name='auto',
callbacks=[dart_early_stopping('model_bestscore.txt', 50)]
)
Case 2: More than one evaluation setclf.fit(
x_train,
y_train,
eval_set=[(x_train, y_train), (x_val, y_val)],
feature_name='auto',
callbacks=[dart_early_stopping('model_bestscore.txt', 50)]
)
Case 3: More than one evaluation metric and more than one evaluation setclf.fit(
x_train,
y_train,
eval_set=[(x_train, y_train), (x_val, y_val)],
eval_metric=['auc', 'logloss']
feature_name='auto',
callbacks=[dart_early_stopping('model_bestscore.txt', 50)]
)
Thank you! |
You shouldn't use dart with early stopping. In dart mode, you should expect the validation error to be roughly monotonically decreasing (it will always has some fluctuations but the overall trend should be decreasing). I think one major advantage of dart is to get rid of the tuning of boosting rounds which in some cases is very sensitive and contributes to high variance. |
It seems that there are actually cases where early stopping is needed in dart mode. (Below is the metric plot when the diabetes dataset was trained with |
Well sometimes you cannot prevent overfitting by simply using default dart. That's why there are several hyperparameters for dart. For your example, I just decrease the
|
I don't know much about dart, but I think the reason your example seems to work is because of the slower convergence. Here is an example of your script changing n_iter to 10000. By the way, for some reason, the results were different when using GPU. |
Yes. It might ultimately overfit. My point is that by tuning dart parameters you don't need to care too much about number of iterations. You can simply set it to a moderately large number and that's it. |
This issue has been automatically locked since there has not been any recent activity since it was closed. To start a new related discussion, open a new issue at https://github.com/microsoft/LightGBM/issues including a reference to this. |
I checed #1893 and #1895. It is said that early stopping is disabled in dart mode. The question is I don't know when to stop training in dart mode. Is it possible to add early stopping in dart mode? or is there any way found best model in dart mode?
Thanks a lot for the brilliant lgb!
The text was updated successfully, but these errors were encountered: