第十八节,TensorFlow中使用批量归一化(BN)
目录
在深度学习章节里,已经介绍了批量归一化的概念,详情请点击这里:第九节,改善深层神经网络:超参数调试、正则化以优化(下)
神经网络在进行训练时,主要是用来学习数据的分布规律,如果数据的训练部分和测试部分分布不一样,那么网络的泛化能力会变得非常差.而且对于训练的数据,每批分布也是不一样的,那么网络在迭代的过程中也要学习和适应不同的分布.这会大大降低网络的训练速度.此外,数据的分布对于激活函数来说也非常重要,有时数据分布范围太大不利于利用激活函数的非线性特性,比如激活函使用Sigmoid函数时,会导致训练时出现饱和的问题。而批量归一化就是为了缓解这个问题提出的。在实际应用中,批量归一化的收敛非常快,并且具有很强的泛化能力,某种情况下完全可以替代正则化和弃权。
一 批量归一化函数
归一化算法可以描述为:
其中xi是batch_size样本中的第i个样本,μB是求得的每个特征均值,σB2是求得每个特征的方差。
1.TensorFlow中自带BN函数的定义:
def batch_normalization(x, mean, variance, offset, scale, variance_epsilon, name=None):
各个参数的说明如下:
- x:代表任意维度的输入张量。
- mean:代表样本的均值。
- variance:代表样本的方差。
- offset:代表偏移,即相加一个转化值,也是公式中的beta。
- scale:代表缩放,即乘以一个转化值,也是公式中的gamma。
- variance_epsilon:是为了避免分母为0的情况下,给分母加上的一个极小值,默认即可。
- name:名称。
要想使用这个整数,必须由另一个函数配合使用,tf.nn.moments,由它来计算均值和方差,然后就可以使用BN了。
2.tf.nn.moment()函数的定义如下:
def moments(x, axes, shift=None, name=None, keep_dims=False):
- x:输入张量。
- axes:指定沿哪个轴计算平均值和方差。
- shift:A `Tensor` containing the value by which to shift the data for numerical stability, or `None` in which case the true mean of the data is used as shift. A shift close to the true mean provides the most numerically stable results.
- name:名称。
- keep_dims:是否保留维度,即形状是否和输入一样。
有了以上两个函数还不够,因为如果使用tf.nn.moment()函数计算均值和方差,我们需要保存每批次训练的均值和方差,然后求平均。为了有更好的效果,我们通常使用指数加权平均的方法来优化每次的均值和方差,于是就用到了tf.train.ExponentialMovingAverage()类,它的作用是让上一次的值对本次的值有个衰减后的影响,从而使每次的值连起来后会相对平滑一下:详细内容可以点击这里:第八节,改善深层神经网络:超参数调试、正则化以优化(中)
我们可以用一个表达式来表示这个函数的功能:
shadow_variable = decay * shadow_variable + (1 - decay) *variable
各参数说明如下:
- decay:代表衰减指数,是在ExponentialMovingAverage()中指定的,一般为0.9.
- variable:代表本批次样本中的值。
- 等式右边的shadow_variable:代表上次总样本的值。
- 等式左边的shadow_variable:代表本次次总样本的值。
对于shadow_variable的理解,你可以将其人为该数值表示的是1/(1-β)次的平均值,本次样本所占的权重为(1-decay),上次样本所占权重为(1-decay)decay,上上次样本所占权重为(1-decay)decay^2,以此类推....
3.tf.train.ExponentialMovingAverage类的定义如下:
def __init__(self, decay, num_updates=None, zero_debias=False, name="ExponentialMovingAverage"): def apply(self, var_list=None):
参数说明如下:
- decay: Float. The decay to use.
- num_updates: Optional count of number of updates applied to variables. actual decay rate used is: `min(decay, (1 + num_updates) / (10 + num_updates))
- zero_debias: If `True`, zero debias moving-averages that are initialized with tensors.
- name: String. Optional prefix name to use for the name of ops added in.
-
var_list: A list of Variable or Tensor objects. The variables and Tensors must be of types float16, float32, or float64.apply
通过调用apply()函数可以更新指数加权平均值。
二 批量归一化的简单用法
上面的函数虽然参数不多,但是需要几个函数联合起来使用,于是TensorFlow中的layers模块里又实现了一次BN函数,相当于把几个函数合并到了一起,使用起来更加简单。下面来介绍一下,使用时需要引入:
from tensorflow.contrib.layers.python.layers import batch_norm
或者直接调用tf.contrib.layers.batch_norm(),该函数的定义如下:
def batch_norm(inputs, decay=0.999, center=True, scale=False, epsilon=0.001, activation_fn=None, param_initializers=None, param_regularizers=None, updates_collections=ops.GraphKeys.UPDATE_OPS, is_training=True, reuse=None, variables_collections=None, outputs_collections=None, trainable=True, batch_weights=None, fused=False, data_format=DATA_FORMAT_NHWC, zero_debias_moving_mean=False, scope=None, renorm=False, renorm_clipping=None, renorm_decay=0.99):
参数说明如下:
- inputs: A tensor with 2 or more dimensions, where the first dimension has `batch_size`. The normalization is over all but the last dimension if `data_format` is `NHWC` and the second dimension if `data_format` is `NCHW`.代表输入,第一个维度为batch_size
- dacay:Decay for the moving average. Reasonable values for `decay` are close to 1.0, typically in the multiple-nines range: 0.999, 0.99, 0.9, etc. Lower `decay` value (recommend trying `decay`=0.9) if model experiences reasonably good training performance but poor validation and/or test performance. Try zero_debias_moving_mean=True for improved stability.代表加权指数平均值的衰减速度,是使用了一种叫做加权指数衰减的方法更新均值和方差。一般会设置为0.9,值太小会导致均值和方差更新太快,而值太大又会导致几乎没有衰减,容易出现过拟合,这种情况一般需要把值调小点。
- center: If True, add offset of `beta` to normalized tensor. If False, `beta` is ignored. 指定是否使用偏移beta。
- scale: If True, multiply by `gamma`. If False, `gamma` is not used. When the next layer is linear (also e.g. `nn.relu`), this can be disabled since the scaling can be done by the next layer.是否进行变换(通过乘以一个gamma进行缩放),我们习惯在BN后面接一个线性变化,如Relu,所以scale一般都设置为Flase,因为后面有对数据的转换处理,所以这里就不用再处理了。
- epsilon: Small float added to variance to avoid dividing by zero.是为了避免分母为0的情况下,给分母加上的一个极小值,默认即可。
- activation_fn: Activation function, default set to None to skip it and maintain a linear activation.激活函数,默认为None,即使用线性激活函数。
- param_initializers: Optional initializers for beta, gamma, moving mean and moving variance.可选的初始化参数。
- param_regularizers: Optional regularizer for beta and gamma.可选的正则化项。
- updates_collections: Collections to collect the update ops for computation. The updates_ops need to be executed with the train_op. If None, a control dependency would be added to make sure the updates are computed in place.其变量默认是tf.GraphKeys.UPDATE_OPS,在训练时提供了一种内置的均值和方差更新机制,即通过图中的tf.Graphs.UPDATE_OPS变量来更新,但它是在每次当前批次训练完成后才更新均值和方差,这样就导致当前数据总是使用前一次的均值和方差,没有得到最新的更新。所以一般都会将其设置为None,让均值和方差即时更新。这样虽然相比默认值在性能上稍慢点,但是对模型的训练还是有很大帮助的。
- is_training: Whether or not the layer is in training mode. In training mode it would accumulate the statistics of the moments into `moving_mean` and `moving_variance` using an exponential moving average with the given `decay`. When it is not in training mode then it would use the values of the `moving_mean` and the `moving_variance`.当它为True,代表是训练过程,这时会不断更新样本集的均值与方差。当测试时,要设置成False,这样就会使用训练样本集的均值和方差。
- reuse: Whether or not the layer and its variables should be reused. To be able to reuse the layer scope must be given.支持共享变量,与下面的scope参数联合使用。
- variables_collections: Optional collections for the variables.
- outputs_collections: Collections to add the outputs.
- trainable: If `True` also add variables to the graph collection `GraphKeys.TRAINABLE_VARIABLES` (see `tf.Variable`).
- batch_weights: An optional tensor of shape `[batch_size]`, containing a frequency weight for each batch item. If present, then the batch normalization uses weighted mean and variance. (This can be used to correct for bias in training example selection.)
- used: Use nn.fused_batch_norm if True, nn.batch_normalization otherwise.
- data_format: A string. `NHWC` (default) and `NCHW` are supported.
- zero_debias_moving_mean: Use zero_debias for moving_mean. It creates a new air of variables 'moving_mean/biased' and 'moving_mean/local_step'.
- scope: Optional scope for `variable_scope`.指定变量的作用域variable_scope。
- renorm: Whether to use Batch Renormalization https://arxiv.org/abs/1702.03275). This adds extra variables during raining. The inference is the same for either value of this parameter.
- renorm_clipping: A dictionary that may map keys 'rmax', 'rmin', 'dmax' to scalar `Tensors` used to clip the renorm correction. The correction `(r, d)` is used as `corrected_value = normalized_value * r + d`, with `r` clipped to [rmin, rmax], and `d` to [-dmax, dmax]. Missing rmax, rmin, dmax are set to inf, 0, inf, respectively.
- renorm_decay: Momentum used to update the moving means and standard deviations with renorm. Unlike `momentum`, this affects training and should be neither too small (which would add noise) nor too large (which would give stale estimates). Note that `decay` is still applied to get the means and variances for inference.
三 为CIFAR10分类添加BN
这里继续在第十三节cifar10分类的代码基础上修改:
1.添加BN函数
def avg_pool_6x6(x): ''' 全局平均池化层,使用一个与原有输入同样尺寸的filter进行池化,'SAME'填充方式 池化层后 out_height = in_hight / strides_height(向上取整) out_width = in_width / strides_width(向上取整) args; x:输入图像 形状为[batch,in_height,in_width,in_channels] ''' return tf.nn.avg_pool(x,ksize=[1,6,6,1],strides=[1,6,6,1],padding='SAME') def batch_norm_layer(value,is_training=False,name='batch_norm'): ''' 批量归一化 返回批量归一化的结果 args: value:代表输入,第一个维度为batch_size is_training:当它为True,代表是训练过程,这时会不断更新样本集的均值与方差。当测试时,要设置成False,这样就会使用训练样本集的均值和方差。 默认测试模式 name:名称。 ''' if is_training is True: #训练模式 使用指数加权函数不断更新均值和方差 return tf.contrib.layers.batch_norm(inputs=value,decay=0.9,updates_collections=None,is_training = True) else: #测试模式 不更新均值和方差,直接使用 return tf.contrib.layers.batch_norm(inputs=value,decay=0.9,updates_collections=None,is_training = False)
2.为BN函数添加占位符参数
亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。
日期 | 姓名 | 金额 |
---|---|---|
2023-09-06 | *源 | 19 |
2023-09-11 | *朝科 | 88 |
2023-09-21 | *号 | 5 |
2023-09-16 | *真 | 60 |
2023-10-26 | *通 | 9.9 |
2023-11-04 | *慎 | 0.66 |
2023-11-24 | *恩 | 0.01 |
2023-12-30 | I*B | 1 |
2024-01-28 | *兴 | 20 |
2024-02-01 | QYing | 20 |
2024-02-11 | *督 | 6 |
2024-02-18 | 一*x | 1 |
2024-02-20 | c*l | 18.88 |
2024-01-01 | *I | 5 |
2024-04-08 | *程 | 150 |
2024-04-18 | *超 | 20 |
2024-04-26 | .*V | 30 |
2024-05-08 | D*W | 5 |
2024-05-29 | *辉 | 20 |
2024-05-30 | *雄 | 10 |
2024-06-08 | *: | 10 |
2024-06-23 | 小狮子 | 666 |
2024-06-28 | *s | 6.66 |
2024-06-29 | *炼 | 1 |
2024-06-30 | *! | 1 |
2024-07-08 | *方 | 20 |
2024-07-18 | A*1 | 6.66 |
2024-07-31 | *北 | 12 |
2024-08-13 | *基 | 1 |
2024-08-23 | n*s | 2 |
2024-09-02 | *源 | 50 |
2024-09-04 | *J | 2 |
2024-09-06 | *强 | 8.8 |
2024-09-09 | *波 | 1 |
2024-09-10 | *口 | 1 |
2024-09-10 | *波 | 1 |
2024-09-12 | *波 | 10 |
2024-09-18 | *明 | 1.68 |
2024-09-26 | B*h | 10 |
2024-09-30 | 岁 | 10 |
2024-10-02 | M*i | 1 |
2024-10-14 | *朋 | 10 |
2024-10-22 | *海 | 10 |
2024-10-23 | *南 | 10 |
2024-10-26 | *节 | 6.66 |
2024-10-27 | *o | 5 |
2024-10-28 | W*F | 6.66 |
2024-10-29 | R*n | 6.66 |
2024-11-02 | *球 | 6 |
2024-11-021 | *鑫 | 6.66 |
2024-11-25 | *沙 | 5 |
2024-11-29 | C*n | 2.88 |

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了