一、机器学习领域有个重要假设:独立同分布independent and identically distributed (i.i.d.)
二、Batch Normalization原理
三、Tensorflow中BN使用方法
BN层的设定一般是按照conv->bn->relu的顺序来形成一个block,在 TensorFlow 中,Batch Normlization 有以下几个实现(API):
tf.layers.BatchNormalization
tf.layers.batch_normalization
tf.keras.layers.BatchNormalization
tf.nn.batch_normalization
上述四个 API 按层次可分为两类:
高阶 API:tf.layers.BatchNormalization、tf.layers.batch_normalization、tf.keras.layers.BatchNormalization
低阶 API:tf.nn.batch_normalization
上述四个 API 按行为可以分为两类:
TensorFlow API:tf.layers.BatchNormalization、tf.layers.batch_normalization、tf.nn.batch_normalization
Keras API:tf.keras.layers.BatchNormalization
当is_training = True时,意味着创建Update ops,利用当前batch的均值和方差去更新moving averages(即某层累计的平均均值和方差)。这里提供两种方式创建update_ops,一是自己显式的创建update_ops,手动更新。update_ops默认放置在tf.GraphKeys.UPDATE_OPS中,因此这里在执行train_ops的同时更新均值方差即可,对于单卡来说很容易理解,对于多卡来说,相当于collection所有卡的batch的均值方差后统一更新,也可以只collection第一块卡的均值方差(理论上需要积累其他卡,但是由于这操作积累得很快,所以只取第一块卡也不影响性能,在TensorFlow高阶API的样例代码cifar10_main.py中如是说)。代码如下:
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies(update_ops):#保证train_op在update_ops执行之后再执行。
train_op = optimizer.minimize(loss)
或者
update_ops = tf.group(*tf.get_collection(tf.GraphKeys.UPDATE_OPS))
train_op = tf.group(train_op, update_ops)
二是自动的更新, 只需在初始化前 bn = BatchNorm(update_ops_collection=None)即可。不过这种方式下,会在完成更新前阻塞网络的forward,因此会带来时间上的成本。具体而言,这时bn的参数mean,var是立即更新的,也是计算完当前layer的mean,var就更新,然后进行下一个layer的操作。这在单卡下没有问题的, 但是多卡情况下就会写等读的冲突,因为可能存在GPU0更新(写)mean但此时GPU1还没有计算到该层,所以GPU0就要等GPU1读完mean才能写。
若代码通过创建输入标志位来判断BN层是否训练,代码形式如下:
# 定义模型的输入输出
x = tf.placeholder(dtype=tf.float32, shape=[None, height, width, 3], name='input') # 输入的图像48*16
y = tf.placeholder("float", shape=(None, FLAGS.classes), name="output") # 输出的标签 1*2
is_training = tf.placeholder(tf.bool, name="flag") # 标志位,是训练还是预测
......
......
......
for i in range(total_batch):
images, labels = sess.run([train_batch_xs, train_batch_ys])
feeds = {x: images, y: labels, is_training: True}
......
......
......
for j in range(test_photo_batch_cnt):
images, labels = sess.run([test_batch_xs, test_batch_ys])
test_feeds = {x: images, y: labels, is_training: False}
这种用法会诱发两个错误问题,查找了很多资料,也没找出相应的最佳解决方案
1.Ckpt转化为pb
在使用命令冻结时候:python reeze_graph.py \--input_graph=./model/graph.pbtxt --input_checkpoint=./model/model- 10000.ckpt \--output_graph=./model/output_graph.pb --output_node_names=softmax_tensor;会出现这样的现象:训练过程中准确率很高,用ckpt的模型进行测试,准确率也高;可是使用pb模型在前向推断时候,得到概率得分值特别低,即pb模型中BN层并未被真正冻结,is_training并没有真正设置为False。
2.转化为TFlite时
import tensorflow as tf
saved_model_dir = '/content/generated/'
converter = tf.contrib.lite.TFLiteConverter.from_saved_model(saved_model_dir, input_arrays=['phase_train'], input_shapes=(1,160,160,3),
output_arrays=['embeddings'])
tflite_model = converter.convert()
open("converted_model_savedModel.tflite", "wb").write(tflite_model)
错误如下:19 operators, 369 arrays (0 quantized)\n2019-05-08 18:28:23.560264: I tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc:39] After Removing unused ops pass 1: 146 operators, 255 arrays (0 quantized)\n2019-05-08 18:28:23.561756: I tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc:39] Before general graph transformations: 146 operators, 255 arrays (0 quantized)\n2019-05-08 18:28:23.561883: F tensorflow/contrib/lite/toco/graph_transformations/resolve_batch_normalization.cc:42] Check failed: IsConstantParameterArray(*model, bn_op->inputs[1]) && IsConstantParameterArray(*model, bn_op->inputs[2]) && IsConstantParameterArray(*model, bn_op->inputs[3]) Batch normalization resolution requires that mean, multiplier and offset arrays be constant.\nAborted (core dumped)\n';
问题参考链接TOCO failed Batch normalization resolution requires that mean, multiplier and offset arrays be constant. #23253 与TFLiteConverter.from_saved_model - batchNorm is not supported? #23627
中心思想:不要使用is_training = tf.placeholder(tf.bool, name="flag") 这种形式,而是在代码中使用bool变量类型,判断是网络是否训练;首先把网络bool变量中设置为False,其次构建网络图模型,最后,先恢复已经保存好的模型,然后用新构建的网络图模型进行保存;这样可以用新保存的ckpt模型进行冻结,以及用构建好的pb模型转化为TFlite模型;以下是伪代码:
.....
model= tf.estimator.Estimator(
model_fn=train.my_model_fn,
model_dir=model_dir)
features,labels = eval_input_fn(image_path)
predictions = train.my_model_fn(
features,
labels,
tf.estimator.ModeKeys.PREDICT).predictions
# Manually load the latest checkpoint
saver = tf.train.Saver()
with tf.Session() as sess:
ckpt = tf.train.get_checkpoint_state(model_dir)
saver.restore(sess, ckpt.model_checkpoint_path)
savename = ckpt.model_checkpoint_path
tf.train.write_graph(sess.graph_def, model_dir, 'graph.pbtxt', as_text=True)
saver.save(sess=sess, save_path=savename)
.....
附录: