了解keras.layers.BatchNormalization计算

时间:2019-11-29 00:44:42

标签: keras batch-normalization batchnorm

我正在使用 BatchNormalization 层,但我不太清楚所得到的数值结果。

让我们考虑将BatchNormalization用于计算机视觉。

我们有4D张量。

尺寸包括:批量大小图像高度图像宽度通道

如果我理解正确,那么BatchNormalization将执行以下操作:

  1. 在培训时:
    • 对于每个批次,计算平均值 MU 和标准偏差 SIGMA 。这是按通道完成的,并且遍历了批次所有图像的所有行和所有列。
    • 保持 MU (例如 Msay )和 SIGMA (例如SIĜMA)的指数移动平均值所有批次
    • 使用SIĜMA归一化像素: normalized_pixel =((input_pixel-MÛ)/ sqrt(SIĜMA)) < / strong>
    • 将超参数ε添加到SIĜMA,以防止在训练过程中某一时刻SIĜMA为空时除以零的情况: normalized_pixel =((input_pixel-MÛ)/ sqrt(SIĜMA+ epsilon))
    • 使用缩放参数 GAMMA 和偏移量参数 BETA 重新缩放归一化像素: output_pixel =((GAMMA x normalized_pixel)+ BETA )
    • GAMMA BETA 是可训练的参数,它们在训练过程中已得到优化
  2. 推断时:
    • SIĜMA现在是固定参数,就像 GAMMA BETA
    • 适用相同的计算

现在,我的问题来了...

首先,我只对推断时发生的事情感兴趣。 我不在乎训练,我认为SIĜMA GAMMA BETA 是固定参数

我写了一段python在(1、3、4、1)张量上测试BatchNormalization。 由于只有一个频道,所以SIĜMA GAMMA BETA 分别只有1个元素。

我选择了MÛ= 0.0 SIĜMA= 1.0 GAMMA = 1.0 BETA = 0.0 , BatchNormalization无效。

代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import numpy
import keras
import math

input_batch                         =   numpy.array(
                                            [[
                                                [[ 1.0], [ 2.0], [ 3.0], [ 4.0]],
                                                [[ 5.0], [ 6.0], [ 7.0], [ 8.0]],
                                                [[ 9.0], [10.0], [11.0], [12.0]]
                                            ]],
                                            dtype=numpy.float32
                                        )


MU                                  = 0.0
SIGMA                               = 1.0
GAMMA                               = 1.0
BETA                                = 0.0

input_layer                         =   keras.layers.Input(
                                            shape = (
                                                        None,
                                                        None,
                                                        1
                                                    )
                                        )

BatchNormalization_layer            =   keras.layers.BatchNormalization(
                                            axis=-1,
                                            #epsilon=0.0,
                                            center=True,
                                            scale=True
                                        )(
                                            input_layer
                                        )

model                               =   keras.models.Model(
                                            inputs  = [input_layer],
                                            outputs = [BatchNormalization_layer]
                                        )

model.layers[1].set_weights(
    (
        numpy.array([GAMMA], dtype=numpy.float32),
        numpy.array([BETA],  dtype=numpy.float32),
        numpy.array([MU],    dtype=numpy.float32),
        numpy.array([SIGMA], dtype=numpy.float32),
    )
)

print model.predict(input_batch)

print ((((input_batch - MU) / math.sqrt(SIGMA)) * GAMMA) + BETA)

当我使用numpy明确编写计算((((input_batch - MU) / math.sqrt(SIGMA)) * GAMMA) + BETA)时,我得到了预期的结果。

但是,当我使用keras.layers.BatchNormalization层执行计算时,我得到类似的结果,只是存在某种舍入误差或不精确性:

Using TensorFlow backend.
[[[[ 0.9995004]
   [ 1.9990008]
   [ 2.9985013]
   [ 3.9980016]]

  [[ 4.997502 ]
   [ 5.9970026]
   [ 6.996503 ]
   [ 7.996003 ]]

  [[ 8.995503 ]
   [ 9.995004 ]
   [10.994504 ]
   [11.994005 ]]]]
[[[[ 1.]
   [ 2.]
   [ 3.]
   [ 4.]]

  [[ 5.]
   [ 6.]
   [ 7.]
   [ 8.]]

  [[ 9.]
   [10.]
   [11.]
   [12.]]]]

当我使用MU *,SIGMA *,GAMMA和BETA的值时,输出会受到预期的影响,因此我相信我会正确地为该层提供参数。

我还尝试将图层的超参数epsilon设置为0.0。它会稍微改变结果,但是并不能解决问题。

Using TensorFlow backend.
[[[[ 0.999995 ]
   [ 1.99999  ]
   [ 2.999985 ]
   [ 3.99998  ]]

  [[ 4.999975 ]
   [ 5.99997  ]
   [ 6.9999647]
   [ 7.99996  ]]

  [[ 8.999955 ]
   [ 9.99995  ]
   [10.999945 ]
   [11.99994  ]]]]
[[[[ 1.]
   [ 2.]
   [ 3.]
   [ 4.]]

  [[ 5.]
   [ 6.]
   [ 7.]
   [ 8.]]

  [[ 9.]
   [10.]
   [11.]
   [12.]]]]

有人可以解释发生了什么事吗?

谢谢

朱利安

1 个答案:

答案 0 :(得分:1)

我挖掘了张量流代码(被keras称为后端)。 在batch_normalization代码中,我读到:

  # Set a minimum epsilon to 1.001e-5, which is a requirement by CUDNN to
  # prevent exception (see cudnn.h).
  min_epsilon = 1.001e-5
  epsilon = epsilon if epsilon > min_epsilon else min_epsilon

解释为什么在喀拉拉邦设置 epsilon = 0.0 不起作用。

在脚本中考虑epsilon时,我得到了正确的结果...

((((input_batch - MU) / math.sqrt(SIGMA + EPSILON)) * GAMMA) + BETA)
Using TensorFlow backend.
[[[[ 0.99503714]
   [ 1.9900743 ]
   [ 2.9851115 ]
   [ 3.9801486 ]]

  [[ 4.975186  ]
   [ 5.970223  ]
   [ 6.96526   ]
   [ 7.960297  ]]

  [[ 8.955335  ]
   [ 9.950372  ]
   [10.945409  ]
   [11.940446  ]]]]
[[[[ 0.99503714]
   [ 1.9900743 ]
   [ 2.9851115 ]
   [ 3.9801486 ]]

  [[ 4.975186  ]
   [ 5.970223  ]
   [ 6.96526   ]
   [ 7.960297  ]]

  [[ 8.955335  ]
   [ 9.950372  ]
   [10.945409  ]
   [11.940446  ]]]]