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 update
sudo 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