tf.estimator 时碰到的问题。tf.keras.layers.BatchNormalization 采坑tf.keras.layers.BatchNormalization 不会将修改mean/var/beta等操作自动添加到UPDATE_OPS中。model.updates 也存在问题,需要使用 model.get_updates_for 才行。model.load_weights 实现,真的坑。tf.train.init_from_checkpoints / tf.train.Scaffold / tf.estimator.WarmStartSettings 实现。本文介绍后两种。tf.train.SessionRunHook 实现。tf.keras.layers.BatchNormalization 采坑tf.keras 构建模型,通过自定义 tf.estimator.EstimatorSpec,构建了 tf.estimator.Estimator 对象。optimizer.minimize之前使用了 with tf.control_dependencies(update_ops)。tf.keras.layers.BatchNormalization 没有默认向 UPDATE_OPS 中添加默认操作,而tensorflow其他的bn实现都这么做了……tf.GraphKeys.UPDATE_OPS。model.updates,是不行的。model.get_updates_for().ops = tf.get_default_graph().get_operations()
update_ops = [x for x in ops if ("AssignMovingAvg" in x.name and x.type=="AssignSubVariableOp")]
tf.add_to_collection(tf.GraphKeys.UPDATE_OPS, update_ops)
That is by design. Global collections (and global states in general) are prone to various issues (like most global variables in software engineering) and should be avoided.
...
If you are writing your own custom training loops, you will have to run these updates as part of the call to sess.run(). But do note that tf.keras provides a built-in training loop in the form of model.fit(), as well as primitive methods for building your own custom training loops (in particular model.train_on_batch() and model.predict_on_batch()). If you are using Keras you should generally never have to manually manage your model‘s updates.
tf.variable_scpe、tf.device等对同一个计算图使用多个gpu创建。MirroredStrategy实现,强烈推荐。tensorflow.contrib.distribute.tf.distribute.MirroredStrategy来调用,但API有变动……libnccl.so.2: cannot open shared object file: No such file or directory。
/usr/local/cuda的对应文件夹中,方便很多,更多请参考上面参考资料中的链接。sudo dpkg -i nccl-repo-<version>.deb安装。sudo dpkg -i nvidia-machine-learning-repo-<version>.deb安装。sudo apt updatesudo apt install libnccl2=2.4.7-1+cuda9.0 libnccl-dev=2.4.7-1+cuda9.0。tf.estimator.Estimator的tf.estimator.RunConfig中指定train_distribute。NUM_GPUS = 2
strategy = tf.contrib.distribute.MirroredStrategy(num_gpus=NUM_GPUS)
config = tf.estimator.RunConfig(train_distribute=strategy)
estimator = tf.keras.estimator.model_to_estimator(model,
config=config)
train/predict/evaluate方法时,init_fn 参数注意事项tf.data.Dataset对象。tf.data.Dataset对象的过程必须在init_fn函数中。ValueError: Tensor(xxx) must be from the same graph as Tensor(xxx).的错误One of the key features of estimator is that it performs graph and session management for you.,大概意思是,所有的创建计算图的过程,最好都封装在init_fn和model_fn中,等Estimator调用时在创建计算图。tf.data.Dataset中有指定batch_size,且确定GPU数量为 num_gpus,则多GPU训练时,数据集实际batch size为batch_size * num_gpus。tf.data.Dataset对象时引入prefetch。MirroredStrategy时,可以在init_fn外创建好tf.data.Dataset,而在init_fn中只创建iterator并调用get_next函数。slim 构建模型,很可能会报错ExponentialMovingAverage操作上。slim.batch_norm 时会与 MirroredStrategy 冲突。batch_norm,可能模型可以正常运行。但有几个模型是完全不包括batch_norm的……tf.keras 构建模型;如果硬要使用 slim 模型,可以将slim.batch_norm改为tf.keras.layers.BatchNormalization。init_fn函数,用于构建tf.train.Scaffold对象。init_fn(scaffold, session),用于初始化模型参数。init_fn 可以用到 slim.assign_from_checkpoint_fn,细节就不描述了。tf.train.Scaffold 对象,作为 mode == tf.estimator.ModeKeys.PREDICT 时 tf.estimator.EstimatorSpec 对象的初始化参数。tf.train.SessionRunHook 来实现这个功能:def after_create_session(session, coord) 方法中将finetune模型参数导入,并将该hook添加到tf.estimator.EstimatorSpec中。model_dir中最新的模型参数。model_dir模型参数之后……tf.keras.applications 中的模型都有对应的预训练模型,想通过这些h5文件进进行fine-tune。load_weights,原因如下:load_weights的最后一步是通过 keras.backend.get_session() 执行 assign 操作,也就是说,会自动创建 tf.Session 对象。tf.estimator的目标是自动管理 tf.Session 的生命周期,会创建新的 Session 对象,而不会使用 keras.backend.get_session() 中的对象。tf.estimator 中导入fine-tune模型的方法有很多,可以使用以下几种:tf.train.init_from_checkpoint:改变的是变量的 initializer,看issue里有个Member提到这事推荐方法,不过我没试过。tf.train.Scaffold:定义其中的 init_fn,将scaffold对象传入 tf.estimator.Estimator 的初始化方法或train方法。tf.estimator.WarmStartSettings 对象,导入 tf.estimator.Estimator 初始化方法中。import tensorflow as tf
import os
os.environ["CUDA_DEVICE_ORDER"]="PCI_BUS_ID" # see issue #152
os.environ["CUDA_VISIBLE_DEVICES"]="1"
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
tf.keras.backend.set_session(tf.Session(config=config))
path_to_save_ckpt = ‘/path/to/keras-ckpt‘
model = tf.keras.applications.VGG16()
model_name = ‘vgg16‘
var_list = slim.get_variables_to_restore(include=None, exclude=[‘predictions‘])
saver = tf.train.Saver(var_list)
saver.save(tf.keras.backend.get_session(),
os.path.join(path_to_save_ckpt, model_name + ‘.ckpt‘))
tf.train.Scaffold 对象导入 ckpt 文件实现思路tf.train.Scaffold对象中init_fn方法的定义为:def init_fn(scaffold, session)。slim.get_variables_to_restore(include=[], exclude=[]) 获取对应的变量。slim.assign_from_checkpoint_fn 获取 def init_fn(session) 方法。{var.op.name: var for var in var_list}init_fn(session) 再自己创建一个 _init_fn(scaffold, session) wrap 一下就行了。tf.estimator.WarmStartSettings 对象导入 ckpt 文件实现思路:ckpt_to_initialize_from:必须填写,ckpt文件路径。vars_to_warm_start:需要导入的参数。.*,则表示所有 trainable 参数。[.*],则表示所有参数(包括non-trainable)。*xxx[^/]。var_name_to_vocab_info:不知道是啥玩意,没仔细研究。var_name_to_prev_var_name:如果ckpt name和当前模型tensor name不对应,可以在这里设置。var_name_to_prev_var_name 不用于过滤参数。var_name_to_prev_var_name 中进行配置。Momentum 结尾的参数。kernel或bias结尾的所有变量。ws = tf.estimator.WarmStartSettings(
# ckpt 文件路径
ckpt_to_initialize_from=os.path.join(ckpt_root_path, ckpt_name),
# 获取所有block开头、kernel/bias结尾的当前模型var
# 获取所有original_ranking/rank_fc开头、kernel/bias结尾的当前模型var
vars_to_warm_start=[‘block.+kernel[^/]‘,
‘block.+bias[^/]‘,
‘original_ranking/rank_fc.+kernel[^/]‘,
‘original_ranking/rank_fc.+bias[^/]‘],
# 若当前模型var name与ckpt name不匹配,则在这里进行处理
# 当前模型 var name to ckpt name
var_name_to_prev_var_name={
‘original_ranking/rank_fc1/bias‘: ‘fc1/bias‘,
‘original_ranking/rank_fc1/kernel‘: ‘fc1/kernel‘,
‘original_ranking/rank_fc2/bias‘: ‘fc2/bias‘,
‘original_ranking/rank_fc2/kernel‘: ‘fc2/kernel‘,
}
)

tf.estimator.Estimator中,基本的训练过程是类似于以下代码for i in range(args.num_epochs):
# train
estimator.train(_train_input_fn,
hooks=train_hooks,
steps=args.train_steps)
if i % args.validation_step == 0:
# val every {validation_step} steps
estimator.evaluate(_val_input_fn,
args.val_steps,
hooks=evaluate_hooks)
evaluate的结果保存 loss 最小或 accuracy 最大的模型。evaluate结束后记录loss/accuracy的平均数,如果loss/accuracy比之前记录的对应数值小/大,则保存该模型。tf.estimator.Estimator封装了evaluate的过程,无法直接获取loss/accuracy的平均值。evaluate中使用了类似 tf.metrics.mean 的操作,用于保存验证集中的平均loss/accuracy。tf.get_default_graph().get_tensor_by_name(tensor_name) 来获取tf.Tensor对象。evaluate方法中。class EvaluateCheckpointHook(tf.train.SessionRunHook):
def __init__(self,
eval_dir, # 模型保存路径
tensor_name=‘mean/value:0‘, # 需要对比的tensor名称
):
self._cur_min_value = 1e8 # 记录当前最小值
self._tensor_name = tensor_name
self._eval_dir = eval_dir
def begin(self):
self._saver = tf.train.Saver() # saver 必须在 begin 方法中创建
def end(self, session):
target_tensor = tf.get_default_graph().get_tensor_by_name(
self._tensor_name) # 获取tensor
cur_value = session.run(target_tensor)
if self._cur_min_value > cur_value:
self._cur_min_value = cur_value
self._saver.save(session, self._eval_dir,
global_step=tf.train.get_global_step())
原文:https://www.cnblogs.com/skydaddy/p/11596367.html