【问题标题】:How to correctly create a batch normalization layer for a convolutional layer in TensorFlow?如何在 TensorFlow 中为卷积层正确创建批量归一化层?
【发布时间】:2016-09-19 03:33:47
【问题描述】:

我在 TensorFlow 中查看 official batch normalization layer (BN),但它并没有真正解释如何将它用于卷积层。有人知道该怎么做吗?尤其重要的是它应用和学习每个特征图的相同参数(而不是每个激活)。以其他顺序应用和学习每个过滤器的 BN。

在一个特定的玩具示例中说我想在 MNIST 上使用 BN 进行 conv2d(本质上是 2D 数据)。因此可以这样做:

W_conv1 = weight_variable([5, 5, 1, 32]) # 5x5 filters with 32 filters
x_image = tf.reshape(x, [-1,28,28,1]) # MNIST image
conv = tf.nn.conv2d(x_image, W_conv1, strides=[1, 1, 1, 1], padding='VALID') #[?,24,24,1]
z = conv # [?,24,24,32]
z = BN(z) # [?,24,24,32], essentially only 32 different scales and shift parameters to learn, per filer application
a = tf.nn.relu(z) # [?,24,24,32]

z = BN(z) 将 BN 应用于每个过滤器创建的每个特征。在伪代码中:

x_patch = x[h:h+5,w:w+h,1] # patch to do convolution
z[h,w,f] = x_patch * W[:,:,f] = tf.matmul(x_patch, W[:,:,f]) # actual matrix multiplication for the convolution

我们对其应用了适当的批处理规范层(在伪代码中省略了重要细节):

z[h,w,f] = BN(z[h,w,f]) = scale[f] * (z[h,w,f]  - mu / sigma) + shift[f]

即对于每个过滤器f,我们应用 BN。

【问题讨论】:

    标签: machine-learning neural-network tensorflow conv-neural-network


    【解决方案1】:

    重要提示:我在此处提供的链接会影响 tf.contrib.layers.batch_norm 模块,而不是通常的 tf.nn(请参阅下面的 cmets 和帖子)

    我没有测试它,但 TF 期望你使用它的方式似乎记录在 convolution2d docstring

    def convolution2d(inputs,
                  num_outputs,
                  kernel_size,
                  stride=1,
                  padding='SAME',
                  activation_fn=nn.relu,
                  normalizer_fn=None,
                  normalizer_params=None,
                  weights_initializer=initializers.xavier_initializer(),
                  weights_regularizer=None,
                  biases_initializer=init_ops.zeros_initializer,
                  biases_regularizer=None,
                  reuse=None,
                  variables_collections=None,
                  outputs_collections=None,
                  trainable=True,
                  scope=None):
      """Adds a 2D convolution followed by an optional batch_norm layer.
      `convolution2d` creates a variable called `weights`, representing the
      convolutional kernel, that is convolved with the `inputs` to produce a
      `Tensor` of activations. If a `normalizer_fn` is provided (such as
      `batch_norm`), it is then applied. Otherwise, if `normalizer_fn` is
      None and a `biases_initializer` is provided then a `biases` variable would be
      created and added the activations.
    

    按照这个建议,您应该将normalizer_fn='batch_norm' 作为参数添加到您的 conv2d 方法调用中。

    关于特征图与激活问题,我的猜测是 TF 在构建图形时会将归一化层作为新的“节点”添加到 conv2d 的顶部,并且它们都会修改相同的权重变量(在您的情况下为 W_conv1 对象)。无论如何,我不会将规范层的任务描述为“学习”,但我不太确定我是否理解您的观点(如果您详细说明,我可能会尝试进一步提供帮助)

    编辑: 仔细查看函数的主体证实了我的猜测,并解释了如何使用normalized_params 参数。读自line 354

    outputs = nn.conv2d(inputs, weights, [1, stride_h, stride_w, 1],
    padding=padding)
    if normalizer_fn:
      normalizer_params = normalizer_params or {}
      outputs = normalizer_fn(outputs, **normalizer_params)
    else:
      ...etc...
    

    我们看到,保存每一层各自输出的outputs 变量被顺序覆盖。因此,如果在构建图形时给出normalizer_fn,则nn.conv2d 的输出将被额外的层normalizer_fn 覆盖。这是**normalizer_params 发挥作用的地方,它作为kwarg 可迭代地传递给给定的normalizer_fn。您可以找到 batch_norm here 的默认参数,因此将字典传递给 normalizer_params 以及您希望更改的参数应该可以解决问题,如下所示:

    normalizer_params = {"epsilon" : 0.314592, "center" : False}
    

    希望对你有帮助!

    【讨论】:

    • 你知道normalizer_params是做什么的吗?
    • 是的,谢谢!顺便说一句,你有没有设法有一个运行的例子?我遇到了一些问题。
    • 不幸的是不是...我意识到我正在使用tf.nn.conv2d 函数,这与“contrib/layers...等(您提供的文件)”中描述的不同。然后我 grep,潜入 github.com/tensorflow/tensorflow/blob/… 中的 nn.py 和 nn_ops.py 文件,但由于一些涉及 local_response_normalization 的别名系统或类似的东西而完全迷失了......也许我会在未来,但我会先尝试直接使用 tf.contrib.layers.whateverElse.conv2d 函数
    【解决方案2】:

    以下示例似乎对我有用:

    import numpy as np
    
    import tensorflow as tf
    
    
    normalizer_fn = None
    normalizer_fn = tf.contrib.layers.batch_norm
    
    D = 5
    kernel_height = 1
    kernel_width = 3
    F = 4
    x = tf.placeholder(tf.float32, shape=[None,1,D,1], name='x-input') #[M, 1, D, 1]
    conv = tf.contrib.layers.convolution2d(inputs=x,
        num_outputs=F, # 4
        kernel_size=[kernel_height, kernel_width], # [1,3]
        stride=[1,1],
        padding='VALID',
        rate=1,
        activation_fn=tf.nn.relu,
        normalizer_fn=normalizer_fn,
        normalizer_params=None,
        weights_initializer=tf.contrib.layers.xavier_initializer(dtype=tf.float32),
        biases_initializer=tf.zeros_initializer,
        trainable=True,
        scope='cnn'
    )
    
    # syntheitc data
    M = 2
    X_data = np.array( [np.arange(0,5),np.arange(5,10)] )
    print(X_data)
    X_data = X_data.reshape(M,1,D,1)
    with tf.Session() as sess:
        sess.run( tf.initialize_all_variables() )
        print( sess.run(fetches=conv, feed_dict={x:X_data}) )
    

    控制台输出:

    $ python single_convolution.py
    [[0 1 2 3 4]
     [5 6 7 8 9]]
    [[[[ 1.33058071  1.33073258  1.30027914  0.        ]
       [ 0.95041472  0.95052338  0.92877126  0.        ]
       [ 0.57024884  0.57031405  0.55726254  0.        ]]]
    
    
     [[[ 0.          0.          0.          0.56916821]
       [ 0.          0.          0.          0.94861376]
       [ 0.          0.          0.          1.32805932]]]]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-16
      • 2018-02-25
      • 1970-01-01
      • 1970-01-01
      • 2017-10-21
      • 2021-02-28
      • 2021-07-08
      • 1970-01-01
      相关资源
      最近更新 更多