tensorflow教程6:Supervisor长期训练帮手

使用TensorFlow训练一个模型,可以多次运行训练操作,并在完成后保存训练参数的检查点(checkpoint)。这对能够在几个小时内训练的小模型很有效。但是如果是训练的数据量比较大,可能需要训练几天或者几个月。。。

那原生的tensorflow的健壮性可能就比较堪忧。。。

万一断电了之类。。。

这时候我们就可以使用supervisor

需要长时间训练的较大模型,需要更鲁棒(robust)的训练过程:

  • 能处理关机以及彻底崩溃的情况。
  • 可以在关机或崩溃后恢复。
  • 可以通过TensorBoard进行监控。

为了能够在停机或崩溃后恢复训练,训练过程必须周期保存检查点。在重新启动时,它必须查找最新的检查点,并在恢复训练之前加载它。supervisor可以看做一个工具,或者说是对原生tensorflow的一层封装,目的主要是通过定期save的方法增强训练健壮性,

就算程序挂掉了也可以从上一次save的checkpoint恢复,而不是从头再来(虽然这些也可以手动实现,同时也可以简化代码量

tf.train.Supervisor提供了一套有助于实施鲁棒的训练过程的服务。除了supervisor,还有tf.learn库,里面提供对原生tensorflow更高层的封装,也提供更丰富的功能。

请注意,Supervisor对训练大模型非常有帮助,但也可以用于较小型号,不会有任何不好的地方。

supervisor可以看做一个工具,或者说是对原生tensorflow的一层封装,目的主要是通过定期save的方法增强训练健壮性。

1.一个简单方案

使用Supervisor的最简单的方案是:

  • 创建一个Supervisor对象,将其传递到保存检查点和summary的目录。

  • tf.train.Supervisor.managed_sessionSupervisor请求一个会话(session)。

  • 使用会话执行训练操作,如果Supervisor要求训练停止,请检查每一步。

...create graph...
my_train_op = ...
 
sv = tf.train.Supervisor(logdir="/my/training/directory")
with sv.managed_session() as sess:
  for step in range(100000):
    if sv.should_stop():
      break
    sess.run(my_train_op)

开始服务

managed_session()启动一些服务,它们在自己的线程中运行,并利用managed session在图中运行各种操作。
如果图中包含一个名为global_step的整型变量,则服务使用其值来测量执行的训练步骤数量。有关如何创建global_step变量,请参阅MNIST训练教程

  • 检查点服务:在logdir中保存图形变量的副本。global_step如果添加到您的图中,则检查点文件名将使用该变量的值。默认运行10分钟。

  • summary服务:运行所有summary操作,并将其输出附加到logdir 中的 事件文件中。默认情况下每2分钟运行一次。

  • 步骤计数器:通过查看global_step变量的更改来计算执行了多少步。向事件文件追加一个summary,报告每秒钟的全局步数。 summary tag 为“global_step / sec”。这也默认每2分钟运行一次。

  • Queue Runners:如果tf.train.QueueRunner添加到图形中,Supervisor将在自己的线程中启动它们。

构建Supervisor对象时可以更改所有时间间隔。有关详细信息,请参阅Supervisor参考

检查停止

在主训练循环中对停止的检查是重要和必要的。

在服务线程中引发的异常报告给Supervisor,然后将其should_stop()条件设置为true。其他服务线程告知此情形并合理终止。managed_session()块内的主训练循环 还必须检查停止条件并终止。

请注意managed_session()捕获从训练循环中引发的异常情况,将其报告给Supervisor。主循环不需要对异常做任何特别的处理。它只需要检查停止条件。

复苏

如果训练程序关闭或崩溃,其最新的检查点和事件文件将留在logdir中。当重新启动程序时, managed_session()从最近的检查点恢复图形,并恢复停止的训练。

创建一个新的事件文件。如果启动TensorBoard并将其指向logdir,它将会知道如何合并两个事件文件的内容,并将在检查点的最后一个全局步骤中显示训练恢复。

2.较大的模式场景

最简单的情景已经足以处理大多数小到中模型的训练。更大的模型也许会在运行summary sevice的时候耗尽内存:summary ops是与main loop中的train op一起并行地run的。这会导致内存使用达到通常使用的两倍多。
对于打得模型你可以通知supervisor不要运行summary服务,作为替代,你在自己的主训练循环中来运行:创建supervisor的时候传递summary_op=None。

例如,该代码在训练循环中每100个步骤运行摘要:

...create graph...
my_train_op = ...
my_summary_op = tf.summary.merge_all()
 
sv = tf.train.Supervisor(logdir="/my/training/directory",
                   summary_op=None) # Do not run the summary service
with sv.managed_session() as sess:
  for step in range(100000):
    if sv.should_stop():
      break
    if step % 100 == 0:
      _, summ = session.run([my_train_op, my_summary_op])
      sv.summary_computed(sess, summ)
    else:
      session.run(my_train_op)

预训练的模型情景

managed_session()调用很关心在session中初始化模型。模型会在可能的时候从一个checkpoint中加载,亦或从scratch中初始化。
一个常见的情景是要用加载的预训练的checkpoint来初始化模型,而该预训练模型和当前模型有些许的不同。
你可以通过给supervisor传递init function的方式来加载预训练的checkpoint。这个函数只有在模型需要从scratch初始化时才被调用,而模型从logdir中的checkpoint恢复的时候并不会。
为了加载预训练模型,init 函数需要一个tf.train.Saver对象,所以你应该创建一个saver。新模型也许包含一些预训练的checkpoint中不存在的变量,所以这是一个很好的思想:这个saver必须只加载预训练的变量。如果你正在使用默认的saver,你会在尝试加载所有变量的时候得到一个错误。

...create graph...
  my_train_op = ...
  my_summary_op = tf.summary.merge_all()

  sv = tf.train.Supervisor(logdir="/my/training/directory",
                     summary_op=None) # Do not run the summary service
  with sv.managed_session() as sess:
    for step in range(100000):
      if sv.should_stop():
        break
      if step % 100 == 0:
        _, summ = session.run([my_train_op, my_summary_op])
        sv.summary_computed(sess, summ)
      else:
        session.run(my_train_op)

运行你自己的服务

Supervisor服务,比如checkpointing服务,与主训练循环并行运行。有时候你想加入你自己的服务,比如取出和 通常的summaryschedule不一样的不同设置的summaries
使用supervisor中的tf.train.Supervisor.loop来达成这个目的。它会根据你选择的定时器重复地调用一个函数,直到supervisorstop condition为true,所以它和其他服务很协调。
例如:每20分钟调用一次my_additional_summaries():


def my_additional_sumaries(sv, sess):
 ...fetch and write summaries, see below...
 
...
  sv = tf.train.Supervisor(logdir="/my/training/directory")
  with sv.managed_session() as sess:
    # Call my_additional_sumaries() every 1200s, or 20mn,
    # passing (sv, sess) as arguments.
    sv.loop(1200, my_additional_sumaries, args=(sv, sess))
    ...main training loop...

写summaries

supervisor总是在其logdir中生成一个事件文件,同时用一个tf.summary.FileWriter将事件和summaries添加到事件文件。如果你想写自己的summaries,也可以将它们添加到同一个事件文件中去:TensorBoard很喜欢在目录中只有一个事件文件。
supervisor提供了一个辅助函数来添加summariestf.train.Supervisor.summary_computed:只需要传递一份summary_op的返回输出函数。以下是使用该函数实现之前例子中my_additional_sumaries()的例子:

def my_additional_sumaries(sv, sess):
  summaries = sess.run(my_additional_summary_op)
  sv.summary_computed(sess, summaries)

更多前沿的用法参看tf.train.Supervisor.summary_writer属性。

supervisor 参考

在简单的情景以及更大的模型方案的情景展示了supervisor的基本用法。更高级的情景可以用supervisor提供的很多选项来创建。

Checkpointing:何时何处

managed_session()调用开启了checkpointing服务,而这可以通过对Supervisor()创建时以下的参数来配置:

  • logdir: checkpointing服务床创建checkpoints的目录路径。如果需要,创建该目录。传递None禁用checkpointing以及summary服务。
  • checkpoint_basename: 欲创建的checkpoint文件的名称,默认为”model.ckpt”。

如果模型包含一个名为的标量整数变量global_step,则该变量的值将附加到检查点文件名。

例如,在global_step 1234,checkpoint 文件名就是 “model.ckpt-1234”。

  • save_model_secs: 每个checkpoint之间的秒数。默认为600,即10分钟。

当选择一个值时,要考虑一旦有crash时你要丢失多少工作:你永远不会丢失多于save_model_secs秒的工作。设置为0就禁用了checkpointing服务。

  • saver: 一个tf.train.Saver对象,用来checkpointing。

如果不传递saver,supervisor会调用tf.train.Saver()来创建一个,该saver会把所有的ops保存,并加载你模型中所有的变量。你通常也需要这么做。

示例:每30秒使用自定义保护程序和检查点。

...create graph...
my_saver = tf.train.Saver(<only some variables>)
sv = tf.train.Supervisor(logdir="/my/training/directory",
                   saver=my_saver,
                   save_model_secs=30)
with sv.managed_session() as sess:
  ...training loop...

Summaries:何时何处

类似checkpointing,logdir对summaries的作用也是一样的。事件文件在此创建,如果None则禁用了summary服务。

  • save_summaries_secs:该参数代表每次运行summary sevice服务的间隔的秒数。默认为120秒,即两分钟。同样,设置为0时则禁用了summary服务。

  • summary_op,用来取得summaries的op。

    如果没指定,supervisor会使用tf.GraphKeys.SUMMARY_OP图集合(graph collection)中第一个op。如果该集合为空,supervisor则创建一个op,它会将图中的所有summaries使用tf.summary.merge_all()聚集在一起。

    如果给summary_op传递None则禁用了summary服务。

  • global_step:用来计算全局步数的张量。

    如果没有指明,supervisor使用tf.GraphKeys.GLOBAL_STEP图集合(graph collection)中第一个tensor,如果该集合为空,

    supervisor在图中寻找一个name为global_step的整型的变量的标量。

    如果找到,global step张量被用来衡量训练步数执行的数量。注意,你的训练op会增加global step的值。

模型的初始化和恢复

managed_session()调用野专注于初始化以及恢复一个session。它返回一个session同时伴随一个全部初始化了的模型,准备去训练。如果managed_session()调用时logdir里有一个checkpoint,模型会通过加载checkpoint初始化,否则会通过调用一个初始化op或者选择一个init function。

如果没有可用的checkpoint,模型的初始化则有下面的参数传递给supervisor()的创建器来控制:

  • init_op: 需要被运行来初始化模型的op。

    如果没有指定,supervisor会使用tf.GraphKeys.INIT_OP图集合( collection)中第一个op。如果集合是空的,则会通过调用tf.global_variables_initializer()添加一个初始化所有变量的op。

    传递None则不适用初始化op。

  • init_fn: 调用它来初始化模型。

    如果指定则这样调用 :init_fn(sess),这里的sess是managed session。如果init op同时使用,则init function在init op之后被调用。

  • local_init_op: 一个额外的op,用来初始化图段一部分,这部分没有被保存在checkpoints中。比如比如tables以及一些local variables。local init op在init op以及 init function之后运行。

    如果没有指定,supervisor使用tf.GraphKeys.LOCAL_INIT_OP集合里的第一个op。如果集合为空,则通过调用tf.tables_initializer() 和 tf.local_variables_initializer()添加一初始化所有tables以及local variables的op。

    传递None禁用local init op。

  • ready_op: 核查模型是否被初始化的op。

运行了local init op,init op以及init function之后,supervisor会通过执行ready op来验证模型是否被完全初始化。如果初始化则该op返回空字符串,否则返回模型那部分未被初始化的一个描述。

如果未指定,supervisor会使用tf.GraphKeys.READY_OP 集合中的第一个op。若集合未空,supervisosr通过调用tf.report_uninitialized_variables()创建一个ready op来确保所有变量都被初始化。

传递None来禁用ready op。在这种情况下模型初始化之后不进行核查。

checkpoint的恢复是由以下传给superfisor()创建器的参数控制:

  • logdir:寻找checkpoints的路径。checkpoint服务保存了一个metadata文件,名为 “checkpoint”,在这个checkpoint目录中指明最近的一个checkpoint的路径。

    这个文件是文本格式的。你可以手工编辑它来从一个不同于最近的checkpoint的checkpoint中恢复。

  • ready_op:和上面的一样。ready op在加载checkpoint之前和之后运行。第一次运行检查模型是否需要被初始化,第二次验证模型完全被初始化。

  • local_init_op:和上面的一样。local init op在第一次运行ready op之前运行,来初始化局部变量以及tables。

  • saver:和上面的一样。用来加载checkpoint的的Saver对象。

    原文作者:是neinei啊
    原文地址: https://www.jianshu.com/p/7490ebfa3de8
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞