Tensorflow:批归一化和l1l2正则化

Posted -柚子皮-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tensorflow:批归一化和l1l2正则化相关的知识,希望对你有一定的参考价值。

Batch Nomalization

tf.nn.batch_normalization()是一个低级的操作函数,调用者需要自己处理张量的平均值和方差。

tf.nn.fused_batch_norm是另一个低级的操作函数,和前者十分相似,不同之处在于它针对4维输入张量进行了优化,这是卷积神经网络中常见的情况,而前者tf.nn.batch_normalization则接受任何等级大于1的张量。

tf.nn.batch_norm_with_global_normalization是另一个被弃用的操作,现在这个函数会委托给tf.nn.batch_normalization执行,在未来这个函数会被放弃。

tf.contrib.layers.batch_norm是batch_norm的早期实现,其升级的核心api版本为(tf.layers.batch_normalization),不推荐使用它,因为它可能会在未来的版本中丢失。

tf.layers.batch_normalization是对先前操作的高级封装,最大的不同在于它负责创建和管理运行张量的均值和方差,并尽可可能地快速融合计算,通常,这个函数应该是你的默认选择。

tf.keras.layers.BatchNormalization是BN算法的keras实现,这个函数在后端会调用tensorflow的tf.nn.batch_normalization函数。

Note: 

1 tf.nn.batch_normalization(),tf.layers.batch_normalization和tensorflow.contrib.layers.batch_norm()这三个batch normal函数的封装程度逐渐递增,都会自动将 update_ops 添加到tf.GraphKeys.UPDATE_OPS这个collection中。[TensorFlow踩坑指南]

2 tf.keras.layers.BatchNormalization 不会自动将 update_ops 添加到 tf.GraphKeys.UPDATE_OPS 这个 collection 中。所以在 TensorFlow 训练 session 中使用 tf.keras.layers.BatchNormalization 时,需要手动将 keras.BatchNormalization 层的 updates 添加到 tf.GraphKeys.UPDATE_OPS 中。[TensorFlow 中 Batch Normalization API 的一些坑]

[tensorflow中Batch Normalization的不同实现]

BN头号大坑:没有调用 update_ops

Batch Normalization 中需要计算移动平均值,所以 BN 中有一些 update_ops,在训练中需要通过 tf.control_dependencies() 来添加对 update_ops 的调用:

1update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)

with tf.control_dependencies(update_ops):

        train_op = tf.train.AdamOptimizer(lrn_rate).minimize(cost)

在使用 update_ops 前,需要将 BN 层的 update_ops 添加到 tf.GraphKeys.UPDATE_OPS 这个 collection 中。

tf.layers.BatchNormalization 和 tf.layers.batch_normalization 会自动将 update_ops 添加到 tf.GraphKeys.UPDATE_OPS 这个 collection 中(注:training 参数为 True 时,才会添加,False 时不添加)。

检测是否添加了 updates 的方法:

print(tf.get_collection(tf.GraphKeys.UPDATE_OPS))

Note: 要生效,在优化时,都需要加(下面的所有示例没写出来)

update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies(update_ops):
    self.train_op = layers.optimize_loss(self.loss, tf.train.get_global_step(), optimizer=self.optimizer, learning_rate=self.learning_rate, clip_gradients=self.clip_norm)

[TensorFlow 中 Batch Normalization API 的一些坑]

tensorflow Batch Normalization使用示例

示例1:高阶kpi,先定义再使用

self.bn_layers = [
    tf.layers.BatchNormalization(name='bn' + str(i), trainable=self.is_training, _reuse=tf.AUTO_REUSE)
    for i in range(layers_cnt)]
#_reuse=tf.AUTO_REUSE是用于再次定义(不是再次使用时)的参数共享,再次使用应该不需要此参数就是直接用的,参数当然一样
fc = self.bn_layers[i](fc, training=training)

Note: tf.keras.layers.BatchNormalization应该和这个差不多。

示例2:老版本示例,不太建议

import tensorflow.contrib.layers as layers
x = layers.batch_norm(
  x, center=True, scale=True, reuse=tf.AUTO_REUSE, scope=scope, is_training=is_training
)

BN中的变量

定义tf.layers.BatchNormalization后,

Trainable Variable:

<tf.Variable 'bn0/gamma:0' shape=(64,) dtype=float32_ref>
<tf.Variable 'bn0/beta:0' shape=(64,) dtype=float32_ref>

非Trainable的Global Variable:
<tf.Variable 'bn0/moving_mean:0' shape=(64,) dtype=float32_ref>
<tf.Variable 'bn0/moving_variance:0' shape=(64,) dtype=float32_ref>

[深度学习:批归一化和层归一化Batch Normalization、Layer Normalization]

-柚子皮-

L2正则化

tensorflow实现

示例1:

from tensorflow.python.keras.regularizers import l2
self.kernels = [self.add_weight(name='kernel' + str(i),
                shape=(hidden_units[i], hidden_units[i + 1]),
                initializer=glorot_normal(seed=self.seed),
                regularizer=l2(self.l2_reg), 
                trainable=self.is_training,
                getter=tf.get_variable)
                for i in range(layers_cnt)]
#self.bias不需要正则
self.reg_loss = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
self.reg_loss = tf.reduce_sum(self.reg_loss)
self.loss = self.loss + self.reg_loss

示例2:

from tensorflow.contrib.layers.python.layers import regularizers
x = layers.fully_connected(
  x,
  activation_fn=activation,
  num_outputs=out_size,
  weights_initializer=initializer_map.get(initializer)(),
  weights_regularizer=regularizers.l1_l2_regularizer(scale_l1=l1_reg,         scale_l2=l2_reg),
  biases_initializer=init_ops.zeros_initializer(),
  scope=scope
)
loss部分同示例1

示例3:

weight_decay=0.1
tmp=tf.constant([0,1,2,3],dtype=tf.float32)
l2_reg=tf.contrib.layers.l2_regularizer(weight_decay)
a=tf.get_variable("I_am_a",regularizer=l2_reg,initializer=tmp) 
#上面代码的等价代码
'''
a=tf.get_variable("I_am_a",initializer=tmp)
a2=tf.reduce_sum(a*a)*weight_decay/2;
tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES,a2)
'''
loss部分同示例1

等价代码的说明:

        首先定义a变量:a=tf.get_variable("I_am_a",initializer=tmp)

        然后将a进行正则化处理:a2=tf.reduce_sum(a*a)*weight_decay/2,最后将处理后的变量加入tf.GraphKeys.REGULARIZATION_LOSSES集合,所有经过正则化处理的变量都会加入这个集合:tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES,a2)。

        对变量执行完L2正则化后,利用tf.get_collection()函数将所有正则化后的变量取出来放入一个列表:keys = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES),将该列表中的值加起来,再加到loss上,就完成了整个正则化过程:l2_loss=loss + tf.add_n(keys)。

解释[Tensorflow中实现正则化]

Note: L2正则化的预处理数据是平方和除以2,这是方便处理加的一个系数,因为w平方求导之后会多出来一个系数2,有没有系数,优化过程都是一样进行的,减小a和减小10a是一样的训练目标。如果说正则化和主loss的比例不同,还有衰减系数可以调。

[tensorflow使用L2 regularization正则化修正overfitting过拟合]

L2正则化衰减系数

如 [Tensorflow中实现正则化]中的0.1

如 [tensorflow使用L2 regularization正则化修正overfitting过拟合]中的0.004

第一次尝试的话,lz一般设置成0.001

from: -柚子皮-

ref:

以上是关于Tensorflow:批归一化和l1l2正则化的主要内容,如果未能解决你的问题,请参考以下文章

Tensorflow:批归一化和l1l2正则化

Tensorflow:批归一化和l1l2正则化

Tensorflow:批归一化和l1l2正则化

批归一化(Batch Normalization)

TensorFlow实现条件批归一化(Conditional Batch Normalization)

深度学习笔记:归一化问题总结