TensorFlow 1.10+ 自定义估算器提前停止 train_and_evaluate

TensorFlow 1.10+ custom estimator early stopping with train_and_evaluate

假设您正在训练自定义 tf.estimator.Estimator with tf.estimator.train_and_evaluate using a validation dataset in a setup similar to that of :

classifier = tf.estimator.Estimator(
    model_fn=model_fn,
    model_dir=model_dir,
    params=params)

train_spec = tf.estimator.TrainSpec(
    input_fn = training_data_input_fn,
)

eval_spec = tf.estimator.EvalSpec(
    input_fn = validation_data_input_fn,
)

tf.estimator.train_and_evaluate(
    classifier,
    train_spec,
    eval_spec
)

通常,当训练数据集的损失继续改善但验证数据集的损失没有改善时,人们通常使用验证数据集来切断训练以防止过度拟合。

目前 tf.estimator.EvalSpec 允许指定在多少 steps(默认为 100)之后评估模型。

如何(如果可能不使用 tf.contrib 函数)指定在 n 次评估调用 (n * steps) 后终止训练,其中评估损失没有改善,然后将 "best" 模型/检查点(由验证数据集确定)保存为唯一的文件名(例如 best_validation.checkpoint

我现在明白你的困惑了。 stop_if_no_decrease_hook 的文档指出(强调我的):

max_steps_without_decrease: int, maximum number of training steps with no decrease in the given metric.

eval_dir: If set, directory containing summary files with eval metrics. By default, estimator.eval_dir() will be used.

浏览 the code of the hook (version 1.11),您会发现:

def stop_if_no_metric_improvement_fn():
    """Returns `True` if metric does not improve within max steps."""

    eval_results = read_eval_metrics(eval_dir) #<<<<<<<<<<<<<<<<<<<<<<<

    best_val = None
    best_val_step = None
    for step, metrics in eval_results.items(): #<<<<<<<<<<<<<<<<<<<<<<<
      if step < min_steps:
        continue
      val = metrics[metric_name]
      if best_val is None or is_lhs_better(val, best_val):
        best_val = val
        best_val_step = step
      if step - best_val_step >= max_steps_without_improvement: #<<<<<
        tf_logging.info(
            'No %s in metric "%s" for %s steps, which is greater than or equal '
            'to max steps (%s) configured for early stopping.',
            increase_or_decrease, metric_name, step - best_val_step,
            max_steps_without_improvement)
        return True
    return False

代码的作用是加载评估结果(使用您的 EvalSpec 参数生成)并提取评估结果和 global_step(或您用来计数的任何其他自定义步骤)具体评价记录

这是文档training steps部分的来源:提前停止不是根据非改进评估的数量触发的,而是根据某个步骤中非改进评估的数量触发的范围(恕我直言,这有点违反直觉)。

所以,回顾一下:,提前停止钩子使用评估结果来决定什么时候停止训练,但是 您需要输入要监控的训练步骤数,并记住在该步骤数中将发生多少次评估。

带有数字的例子希望能澄清更多

假设您无限期地训练,每 1k 步进行一次评估。评估如何运行的具体细节无关紧要,只要它每 1k 步运行一次即可生成我们要监控的指标。

如果您将挂钩设置为 hook = tf.contrib.estimator.stop_if_no_decrease_hook(my_estimator, 'my_metric_to_monitor', 10000),则挂钩将考虑在 10k 步范围内发生的评估。

由于您 运行 每 1k 步进行 1 次评估,如果连续 10 次评估没有任何改善,这归结为提前停止。 如果您决定每 2k 步重新运行一次 eval,则挂钩将只考虑 5 个连续 eval 的序列而没有改进。

保持最佳模型

首先,重要说明:这与提前停止无关,通过训练保留最佳模型副本的问题以及停止的问题一旦性能开始下降,训练就完全无关了。

EvalSpec 中定义 tf.estimator.BestExporter 可以很容易地保持最佳模型(摘自 link 的片段):

  serving_input_receiver_fn = ... # define your serving_input_receiver_fn
  exporter = tf.estimator.BestExporter(
      name="best_exporter",
      serving_input_receiver_fn=serving_input_receiver_fn,
      exports_to_keep=5) # this will keep the 5 best checkpoints

  eval_spec = [tf.estimator.EvalSpec(
    input_fn=eval_input_fn,
    steps=100,
    exporters=exporter,
    start_delay_secs=0,
    throttle_secs=5)]

如果你不知道如何定义 serving_input_fn have a look here

这允许您保留获得的 5 个最佳模型,存储为 SavedModels(这是目前存储模型的首选方式)。