使用回调函数

简介

可以定义回调函数在优化过程仍在运行时采取行动或做出决策。 常见的回调包括用于停止算法或记录产出的不同规则。 回调函数会被传递给GASearchCVGAFeatureSelectionCV类的.fit方法。

回调函数在训练开始时通过on_start方法执行, 在每一代拟合结束时通过on_step方法执行, 并在训练结束时通过on_end方法执行,流程如下:

../_images/callbacks_evaluation_0.png

当满足停止回调条件时,我们会看到类似这样的消息,模型将停止运行。它会保留直到该训练点为止的所有信息。

../_images/callbacks_log_0.png

现在让我们看看如何使用它们,我们将采用How to Use Sklearn-genetic-opt中使用的数据集和模型。可用的回调函数包括:

  • 进度条

  • 连续停止

  • Delta阈值

  • 计时器停止

  • 阈值停止

  • TensorBoard

  • 日志记录保存器

进度条

此回调函数会显示一个tqdm进度条,用于展示训练过程。进度条的长度代表算法运行的最大代数(population_size + 1),每一步代表一代。

您可以传递任何tqdm.auto.tqdm的有效参数作为kwargs,或保持默认设置。 要使用此进度条,请设置:

from sklearn_genetic.callbacks import ProgressBar
callback = ProgressBar()

现在我们只需要在拟合过程中将其传递给估计器

# Already defined GASearchCV instance
evolved_estimator.fit(X, y, callbacks=callback)

在训练过程中,界面将显示如下内容:

../_images/progress_bar.gif

连续停止

如果当前指标值不高于最近N代中的至少一个指标值,该回调函数将停止优化。

它要求我们定义要与当前代进行比较的代数,以及我们想要跟踪的指标名称。

例如,如果我们希望在5次迭代后停止优化,此时当前迭代(第六次)的适应度值比之前所有迭代(5次)的都差,我们可以这样定义:

from sklearn_genetic.callbacks import ConsecutiveStopping
callback = ConsecutiveStopping(generations=5, metric='fitness')

现在我们只需要在拟合过程中将其传递给估计器

# Already defined GASearchCV instance
evolved_estimator.fit(X, y, callbacks=callback)

Delta阈值

如果最近N代的最大值与最小值之间的绝对差小于或等于阈值,则停止优化。

当达到指定的代数后,将评估阈值;默认代数为2(当前代和上一代)。

它只需要阈值、指标名称和代数,例如使用'fitness_min'值并比较最后5代:

from sklearn_genetic.callbacks import DeltaThreshold
callback = DeltaThreshold(threshold=0.001, generations=5, metric='fitness_min')

evolved_estimator.fit(X, y, callbacks=callback)

计时器停止

如果第一组超参数拟合的起始时间与当前代数时间之间的秒数差异超过时间阈值,该回调将停止优化。

请注意,这个检查是在每一代拟合完成后进行的,因此如果第一代(或任何一代)的拟合耗时超过阈值,它不会立即停止拟合过程,而是会先完成当前代种群的拟合。

需要total_seconds参数,例如当时间超过一分钟时停止:

from sklearn_genetic.callbacks import TimerStopping
callback = TimerStopping(total_seconds=60)

evolved_estimator.fit(X, y, callbacks=callback)

阈值停止

如果当前指标大于或等于定义的阈值,则停止优化。

例如,如果我们希望在'fitness_max'超过0.98时停止优化:

from sklearn_genetic.callbacks import ThresholdStopping
callback = ThresholdStopping(threshold=0.98, metric='fitness_max')

evolved_estimator.fit(X, y, callbacks=callback)

TensorBoard

它会在每次迭代时将适应度指标保存到一个可由Tensorboard读取的日志文件夹中。

要使用此回调函数,您必须先安装tensorflow,由于它通常是一个敏感且重量级的依赖项,因此未包含在此软件包中:

pip install tensorflow

只需定义您想要记录运行的文件夹路径,并可选择性地指定一个run_id,这样您的连续运行记录就不会混淆。 如果没有提供run_id,系统会自动创建一个以当前运行日期时间命名的子文件夹。

from sklearn_genetic.callbacks import TensorBoard
callback = TensorBoard(log_dir="./logs")

evolved_estimator.fit(X, y, callbacks=callback)

在模型训练过程中,您可以实时查看Tensorboard中的指标。 如果您运行了多个GASearchCV模型,并使用相同的log_dir但不同的run_id来调用TensordBoard回调, 您可以比较每次运行的指标,对于三次不同运行的适应度情况如下所示:

../_images/tensorboard_log.png

日志记录保存器

它在每次迭代时保存Logbook对象,包含所有参数以及这些参数实现的交叉验证分数。它使用joblib.dump来保存文件。

from sklearn_genetic.callbacks import LogbookSaver
callback = LogbookSaver(checkpoint_path="./logbook.pkl")

evolved_estimator.fit(X, y, callbacks=callback)

然后可以恢复该对象:

from joblib import load

logbook = load("/.logbook.pkl")
print(logbook)

定义多重回调函数

您也可以同时指定多个回调函数。 定义方式是在.fit方法中传入一个回调函数列表。

然后估计器将在每次迭代中检查所有条件, 如果至少有一个停止回调条件被满足,该回调将终止进程:

from sklearn_genetic.callbacks import ThresholdStopping, DeltaThreshold
threshold_callback = ThresholdStopping(threshold=0.98, metric='fitness_max')
delta_callback = DeltaThreshold(threshold=0.001, metric='fitness')

callbacks = [threshold_callback, delta_callback]

evolved_estimator.fit(X, y, callbacks=callbacks)

完整示例

本示例使用了ThresholdStopping和DeltaStopping回调函数 当世代准确率超过0.98时,或 当前世代准确率与上一世代准确率 差值不超过0.001时将停止运行:

from sklearn_genetic import GASearchCV
from sklearn_genetic.space import Categorical, Integer, Continuous
from sklearn.model_selection import train_test_split, StratifiedKFold
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_digits
from sklearn.metrics import accuracy_score
from sklearn_genetic.callbacks import ThresholdStopping, DeltaThreshold


data = load_digits()
label_names = data['target_names']
y = data['target']
X = data['data']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)

clf = DecisionTreeClassifier()

params_grid = {'min_weight_fraction_leaf': Continuous(0, 0.5),
               'criterion': Categorical(['gini', 'entropy']),
               'max_depth': Integer(2, 20), 'max_leaf_nodes': Integer(2, 30)}

cv = StratifiedKFold(n_splits=3, shuffle=True)

threshold_callback = ThresholdStopping(threshold=0.98, metric='fitness_max')
delta_callback = DeltaThreshold(threshold=0.001, metric='fitness')

callbacks = [threshold_callback, delta_callback]

evolved_estimator = GASearchCV(clf,
                               cv=cv,
                               scoring='accuracy',
                               population_size=16,
                               generations=30,
                               tournament_size=3,
                               elitism=True,
                               crossover_probability=0.9,
                               mutation_probability=0.05,
                               param_grid=params_grid,
                               algorithm='eaMuPlusLambda',
                               n_jobs=-1,
                               verbose=True)

evolved_estimator.fit(X_train, y_train, callbacks=callbacks)
y_predict_ga = evolved_estimator.predict(X_test)
accuracy = accuracy_score(y_test, y_predict_ga)

print(evolved_estimator.best_params_)
print("accuracy score: ", "{:.2f}".format(accuracy))