发新帖

Keras + Estimator API训练过程中切换优化算法失败

[复制链接]
780 2

快来加入 TensorFlowers 大家庭!

您需要 登录 才可以下载或查看,没有帐号?加入社区

x
我的代码使用keras定义模型,然后使用 tf.keras.estimator.model_to_estimator 接口将其转换为了官方推荐的Estimator API,然后进行训练。Estimator API定期将模型保存为Tensorflow Checkpoint,而如果我在训练的途中希望更改优化算法,例如从Adam切换为SGD,则抛出如下异常:
tensorflow.python.framework.errors_impl.NotFoundError: Key training/SGD/Variable_10 not found in checkpoint
原因是因为SGD相关的变量在Checkpoint中找不到
有没有小伙伴,知道如何解决?


1. 我尝试过手动修改Checkpoint文件,但没找到有效的途径
yunhai_luo已获得悬赏 10 金币+5 金币

最佳答案

首先声明一下,我并没有在实际应用中用过这种方法,尽管下面假想的例子里貌似可行,但如果跟楼主实际需要有出入,还请见谅并指出,共同学习。 楼主的需要从大面上讲就是选择性的从checkpoint中恢复estimator的参数 ...
本楼点评(0) 收起

精彩评论2

舟3332  TF芽芽  发表于 2018-5-21 23:38:26 | 显示全部楼层
我觉得可能是 optimizer 也写到了图里。所以换了 optimizer 有些东西的参数就没有办法读取了。
本楼点评(1) 收起
  • winter是这个原因,estimator 做 checkpoint时默认保存环境中的所有变量。
    2018-5-25 10:57 回复
yunhai_luo  TF豆豆  发表于 2018-5-22 12:01:08 | 显示全部楼层
本帖最后由 yunhai_luo 于 2018-5-22 12:07 编辑

首先声明一下,我并没有在实际应用中用过这种方法,尽管下面假想的例子里貌似可行,但如果跟楼主实际需要有出入,还请见谅并指出,共同学习。

楼主的需要从大面上讲就是选择性的从checkpoint中恢复estimator的参数。就我所学所见大概有三种做法:
1. 用Scaffold:貌似不是tensorflow开发者认为最好的做法,我也就偷懒不看了。
2. 用tf.train.init_from_checkpoint:下面用到的方法。
3. 用WarmStartSettings:貌似是更好的方法,但是要求构建Estimator时从warm_start_from传入,而tf.keras.estimator.model_to_estimator并没有这样的实现,所以在楼主这个问题中应用应该很难。
实际上,上述三种方法在Github的一个issue中都有提到,楼主可以参看:
https://github.com/tensorflow/tensorflow/issues/14713

使用tf.train.init_from_checkpoint的思路主要是,在改变优化器后重开模型路径,重新训练,这样的话Estimator就没有办法从checkpoint恢复参数(因为模型路径下没有以前的checkpoint),这时候用tf.train.init_from_checkpoint从原来的模型路径下找到checkpoint来恢复参数。鉴于楼主这里Estimator的构建来源于tf.keras.estimator.model_to_estimator,所以还需要用SessionRunHook来插入tf.train.init_from_checkpoint。测试代码如下:
  1. import tensorflow as tf
  2. from tensorflow.python.tools import inspect_checkpoint as chkp

  3. tf.logging.set_verbosity(tf.logging.INFO)

  4. # 第一组:使用Adam优化器的原始模型
  5. current_model_dir = 'test_Adam'
  6. old_model_dir = 'test_Adam'
  7. optimizer = 'Adam'

  8. # 第二组:改为SGD优化器的模型
  9. # current_model_dir = 'test_SGD'
  10. # old_model_dir = 'test_Adam'
  11. # optimizer = 'SGD'

  12. # For a single-input model with 2 classes (binary classification):
  13. model = tf.keras.models.Sequential()
  14. model.add(tf.keras.layers.Dense(32, activation='relu', input_dim=100))
  15. model.add(tf.keras.layers.Dense(1, activation='sigmoid'))
  16. model.compile(optimizer=optimizer,
  17.               loss='binary_crossentropy',
  18.               metrics=['accuracy'])
  19. model.summary()
  20. keras_estimator = tf.keras.estimator.model_to_estimator(
  21.     keras_model=model, model_dir=current_model_dir)

  22. # Generate dummy data
  23. import numpy as np
  24. train_input_fn = tf.estimator.inputs.numpy_input_fn(
  25.     x={model.input_names[0]: np.random.random((1000, 100))},
  26.     y=np.random.randint(2, size=(1000, 1)),
  27.     batch_size=200,
  28.     shuffle=False)

  29. class InitHook(tf.train.SessionRunHook):
  30.     def __init__(self, ckpt_dir_or_file):
  31.         self.ckpt_dir_or_file = ckpt_dir_or_file

  32.     def begin(self):
  33.         print('-----------------------------------------------------------------')
  34.         try:
  35.             ckpt_var_list = [vt[0] for vt in tf.train.list_variables(self.ckpt_dir_or_file)]
  36.             assignment_map = {v.op.name: v
  37.                               for v in tf.global_variables()
  38.                               if v.op.name in ckpt_var_list}
  39.             tf.train.init_from_checkpoint(self.ckpt_dir_or_file, assignment_map)
  40.         except:
  41.             tf.logging.info('No custom variable initialization.')        
  42.         print('-----------------------------------------------------------------')

  43. # Train the model with all data from train_input_fn
  44. keras_estimator.train(train_input_fn, hooks=[InitHook(old_model_dir)])
复制代码

测试方法:
1. 首先,用Adam优化器,新旧模型路径都是test_Adam,这时候尽管Estimator可以从checkpoint恢复参数,但是tf.train.init_from_checkpoint会覆盖其操作,实质还是通过tf.train.init_from_checkpoint恢复参数。当然,这部分楼主可以按照自己原来的做法训练模型,我这里一方面是为了第二部分真正解决问题做准备,另一方面是尽可能贴近第二部分的模型,便于比较理解。
2. 这部分的目的在于模拟楼主的情况:换为SGD优化器。这时候新开模型路径test_SGD,test_Adam为旧模型路径,在InitHook中tf.train.init_from_checkpoint会恢复新旧模型共有的变量,而没被初始化的SGD变量则会由Estimator负责初始化。
3. 多说一句的是,如果楼主没有修改模型,那么不同批次的训练完全可以用楼主原来的方法,没有必要用这种做法。4. 放在最后的一点,也是我比较想弱化的一点就是,keras转过去的Estimator模型跟纯粹新建的Estimator模型在初始化参数上略有不同,但就上述的傻瓜示例而言应该不重要,且我能力有限,在这里就点一下不展开了。


本楼点评(2) 收起
  • winter我暂时切换到了纯keras的环境进行训练,后面对你的方法进行一个验证,到时候有什么问题再和你交流。
    非常感谢你的回答
    2018-5-25 10:55 回复
  • yunhai_luo
    2018-5-25 11:55 回复
您需要登录后才可以回帖 登录 | 加入社区

本版积分规则

主题

帖子

36

积分
快速回复 返回顶部 返回列表