卷积层中的偏差真的会影响测试精度吗?

时间:2018-08-22 03:35:42

标签: python tensorflow deep-learning conv-neural-network bias-neuron

我知道在小型网络中需要偏置才能转移激活功能。但是,对于具有多个CNN层,合并,丢失和其他非线性激活的Deep网络而言,偏差确实会有所作为吗?卷积滤波器正在学习局部特征并针对给定的conv输出通道使用相同的偏置。

这不是this link的伪造。上面的链接仅说明了偏差在小型神经网络中的作用,而没有尝试说明偏差在包含多个CNN层,辍学,合并和非线性激活函数的深层网络中的作用。

我进行了一个简单的实验,结果表明,去除conv层的偏差对最终测试的准确性没有影响。 有两种训练过的模型,其测试精度几乎相同(在没有偏差的情况下,其准确性要稍好一点)。

  • model_with_bias,
  • model_without_bias(在转换层中未添加偏差)

仅出于历史原因使用它们吗?

如果使用偏置不能提高准确性,那么我们不应该忽略它们吗?需要学习的参数更少。

如果有人比我有更深的知识,可以解释这些偏见在深度网络中的意义(如果有的话),我将不胜感激。

这是完整的代码和实验结果bias-VS-no_bias experiment

batch_size = 16
patch_size = 5
depth = 16
num_hidden = 64

graph = tf.Graph()

with graph.as_default():

  # Input data.
  tf_train_dataset = tf.placeholder(
    tf.float32, shape=(batch_size, image_size, image_size, num_channels))
  tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels))
  tf_valid_dataset = tf.constant(valid_dataset)
  tf_test_dataset = tf.constant(test_dataset)

  # Variables.
  layer1_weights = tf.Variable(tf.truncated_normal(
      [patch_size, patch_size, num_channels, depth], stddev=0.1))
  layer1_biases = tf.Variable(tf.zeros([depth]))
  layer2_weights = tf.Variable(tf.truncated_normal(
      [patch_size, patch_size, depth, depth], stddev=0.1))
  layer2_biases = tf.Variable(tf.constant(1.0, shape=[depth]))
  layer3_weights = tf.Variable(tf.truncated_normal(
      [image_size // 4 * image_size // 4 * depth, num_hidden], stddev=0.1))
  layer3_biases = tf.Variable(tf.constant(1.0, shape=[num_hidden]))
  layer4_weights = tf.Variable(tf.truncated_normal(
      [num_hidden, num_labels], stddev=0.1))
  layer4_biases = tf.Variable(tf.constant(1.0, shape=[num_labels]))

  # define a Model with bias .
  def model_with_bias(data):
    conv = tf.nn.conv2d(data, layer1_weights, [1, 2, 2, 1], padding='SAME')
    hidden = tf.nn.relu(conv + layer1_biases)
    conv = tf.nn.conv2d(hidden, layer2_weights, [1, 2, 2, 1], padding='SAME')
    hidden = tf.nn.relu(conv + layer2_biases)
    shape = hidden.get_shape().as_list()
    reshape = tf.reshape(hidden, [shape[0], shape[1] * shape[2] * shape[3]])
    hidden = tf.nn.relu(tf.matmul(reshape, layer3_weights) + layer3_biases)
    return tf.matmul(hidden, layer4_weights) + layer4_biases

  # define a Model without bias added in the convolutional layer.
  def model_without_bias(data):
    conv = tf.nn.conv2d(data, layer1_weights, [1, 2, 2, 1], padding='SAME')
    hidden = tf.nn.relu(conv ) # layer1_ bias is not added 
    conv = tf.nn.conv2d(hidden, layer2_weights, [1, 2, 2, 1], padding='SAME')
    hidden = tf.nn.relu(conv) # + layer2_biases)
    shape = hidden.get_shape().as_list()
    reshape = tf.reshape(hidden, [shape[0], shape[1] * shape[2] * shape[3]])
    # bias are added only in Fully connected layer(layer 3 and layer 4)
    hidden = tf.nn.relu(tf.matmul(reshape, layer3_weights) + layer3_biases)
    return tf.matmul(hidden, layer4_weights) + layer4_biases

  # Training computation.
  logits_with_bias = model_with_bias(tf_train_dataset)
  loss_with_bias = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=tf_train_labels, logits=logits_with_bias))

  logits_without_bias = model_without_bias(tf_train_dataset)
  loss_without_bias = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=tf_train_labels, logits=logits_without_bias))

  # Optimizer.
  optimizer_with_bias = tf.train.GradientDescentOptimizer(0.05).minimize(loss_with_bias)
  optimizer_without_bias = tf.train.GradientDescentOptimizer(0.05).minimize(loss_without_bias)

  # Predictions for the training, validation, and test data.
  train_prediction_with_bias = tf.nn.softmax(logits_with_bias)
  valid_prediction_with_bias = tf.nn.softmax(model_with_bias(tf_valid_dataset))
  test_prediction_with_bias = tf.nn.softmax(model_with_bias(tf_test_dataset))

  # Predictions for without
  train_prediction_without_bias = tf.nn.softmax(logits_without_bias)
  valid_prediction_without_bias = tf.nn.softmax(model_without_bias(tf_valid_dataset))
  test_prediction_without_bias = tf.nn.softmax(model_without_bias(tf_test_dataset))

num_steps = 1001

with tf.Session(graph=graph) as session:
  tf.global_variables_initializer().run()
  print('Initialized')
  for step in range(num_steps):
    offset = (step * batch_size) % (train_labels.shape[0] - batch_size)
    batch_data = train_dataset[offset:(offset + batch_size), :, :, :]
    batch_labels = train_labels[offset:(offset + batch_size), :]
    feed_dict = {tf_train_dataset : batch_data, tf_train_labels : batch_labels}
    session.run(optimizer_with_bias, feed_dict=feed_dict)
    session.run(optimizer_without_bias, feed_dict = feed_dict)
  print('Test accuracy(with bias): %.1f%%' % accuracy(test_prediction_with_bias.eval(), test_labels))
  print('Test accuracy(without bias): %.1f%%' % accuracy(test_prediction_without_bias.eval(), test_labels))

输出:

已初始化

测试准确度(有偏差):90.5%

测试准确度(无偏差):90.6%

3 个答案:

答案 0 :(得分:3)

  通过学习算法,例如

偏差和权重一起进行调整   梯度下降。 偏见与权重不同的是   独立于先前图层的输出。概念上的偏见是   是由固定激活值为1的神经元输入引起的,因此   通过减去增量值和的乘积来更新   学习率。

在大型模型中,删除偏置输入几乎没有什么区别,因为每个节点都可以使偏置节点超出其所有输入的平均激活,这根据大数定律是大致正常的。在第一层,发生这种情况的能力取决于您的输入分布。例如,对于MNIST,输入的平均激活大致恒定。 在小型网络上,您当然需要一个偏差输入,但是在大型网络上,将其删除几乎没有任何作用

另请参阅:

Reference

答案 1 :(得分:0)

layer1_biaseslayer2_biases在卷积层中,但是在ReLU层中。 ReLU层的存在是有道理的,因为如Wikipedia所述,

  

ReLU是整流线性单位的缩写。该层应用了非饱和激活函数f(x)= max(0,x)。它增加了决策函数和整个网络的非线性特性,而不会影响卷积层的接收场。

答案 2 :(得分:0)

在大多数网络中,转换层之后的conv层都有一个batchnorm层,该层具有偏差。因此,如果您具有batchnorm图层,则不会获得收益。看到: Can not use both bias and batch normalization in convolution layers

否则,从数学的角度来看,您正在学习不同的功能。但是,事实证明,特别是如果您有一个非常复杂的网络来解决一个简单的问题,则可能会在没有偏见的情况下实现几乎与有偏见相同的目标,而最终会使用更多的参数。根据我的经验,使用比所需参数多2-4倍的参数很少会损害深度学习的性能-特别是如果您进行正则化。因此,很难发现任何差异。但是,您可能会尝试使用很少的渠道(我认为网络深度并没有卷积渠道的数量那么重要),看看偏差是否会有所作为。我猜是这样。