我知道偏置就相当于在每层的输入向量中加入1
,或者说它就像一个输出恒定为1
的神经元。从偏置神经元输出的权重是正常的权重,这些权重会在训练过程中被训练。
现在我在研究一些Tensorflow中的神经网络代码。例如这个(这是CNN(VGGnet)的一部分,具体是卷积结束后开始全连接层的部分):
with tf.name_scope('conv5_3') as scope: kernel = tf.Variable(tf.truncated_normal([3, 3, 512, 512], dtype=tf.float32, stddev=1e-1), name='weights') conv = tf.nn.conv2d(self.conv5_2, kernel, [1, 1, 1, 1], padding='SAME') biases = tf.Variable(tf.constant(0.0, shape=[512], dtype=tf.float32), trainable=True, name='biases') out = tf.nn.bias_add(conv, biases) self.conv5_3 = tf.nn.relu(out, name=scope) self.parameters += [kernel, biases]# pool5self.pool5 = tf.nn.max_pool(self.conv5_3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool4')with tf.name_scope('fc1') as scope: shape = int(np.prod(self.pool5.get_shape()[1:])) fc1w = tf.Variable(tf.truncated_normal([shape, 4096], dtype=tf.float32, stddev=1e-1), name='weights') fc1b = tf.Variable(tf.constant(1.0, shape=[4096], dtype=tf.float32), trainable=True, name='biases') pool5_flat = tf.reshape(self.pool5, [-1, shape]) fc1l = tf.nn.bias_add(tf.matmul(pool5_flat, fc1w), fc1b) self.fc1 = tf.nn.relu(fc1l) self.parameters += [fc1w, fc1b]
现在我的问题是,为什么卷积层的偏置是0
,而全连接层的偏置是1
(这个模型中的每个卷积层偏置都是0
,而全连接层偏置是1
)?还是说我的解释只适用于全连接层,而卷积层的情况不同?
回答:
偏置(在任何层中)通常初始化为零,但也可以使用随机或特定的较小值。引用自斯坦福CS231n的说法:
初始化偏置。将偏置初始化为零是可能的,也是常见的做法,因为权重中的小随机数已经提供了对称性破坏。对于ReLU非线性,一些人喜欢对所有偏置使用如0.01这样的小常数值,因为这确保了所有的ReLU单元在开始时都能激活,从而获得并传播一些梯度。然而,是否这能提供一致的改进尚不清楚(实际上一些结果似乎表明这表现得更差),更常见的是简单地使用0偏置初始化。
其他例子:tf.layers.dense
函数,用于创建全连接层的快捷方式,默认使用zero_initializer
;而这个示例CNN对所有权重和偏置使用随机初始化,这并不会影响性能。
总之,偏置初始化并不那么重要(与权重初始化相比),我很确定使用零或小随机值初始化,你也会得到相似的训练速度。