对 Tensorflow 中的 Dropout 实现感到困惑

机器算法验证 神经网络 深度学习 优化 张量流 退出
2022-04-12 07:29:18

我有一个输入大小为 100,输出大小为 2 的网络。只有这些层。我应用了 keep_prob 为 0.8 的 dropout,并试图了解结果。

正如预期的那样,每次运行时,dropout 掩码都有大约 17-23 个零,但是,几乎所有的权重都会更新。根据论文:

该训练案例的前向和反向传播仅在此细化网络上完成。

所以我期望在训练的每一步中我的权重中大约有 80 个会发生变化,但实际上它们都在变化(开始时大约 90-95 个变化,在接下来的迭代中它们都发生了变化)。

我不知道这是否与在 Tensorflow 中实现 Dropout 的方式有关。有人知道为什么会这样吗?

这是我正在运行以检查它的代码。

import numpy as np
import tensorflow as tf

# As input, 100 random numbers.
input_size = 100
output_size = 2

x = tf.placeholder(tf.float32,[None, input_size],name="input")
y = tf.placeholder(tf.float32,[None, output_size],name="labels")

with tf.variable_scope("dense1") as scope:
    W = tf.get_variable("W",shape=[input_size,output_size],initializer=tf.keras.initializers.he_uniform())
    b = tf.get_variable("b",initializer=tf.zeros([output_size]))
    dropped = tf.nn.dropout(x,0.8)
    dense = tf.matmul(dropped,W)+b

eval_pred = tf.nn.sigmoid(dense,name="prediction")

cost = tf.reduce_mean(tf.losses.absolute_difference(eval_pred,y))
train_step = tf.train.AdamOptimizer(learning_rate=0.01).minimize(cost)


# 20 epochs, batch size of 1
epochs = 20

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    allWeights = []
    for i in range(epochs):

        x_raw = np.random.random((1,input_size))
        y_raw = np.random.random((1,output_size))
        [_,c,d,w]=sess.run([train_step,cost,dropped,W], feed_dict={x: x_raw, y: y_raw})
        #print("Epoch {0}/{1}. Loss: {2}".format(i+1,epochs,c))

        # Numbers will be around 20% of input_size (17-22)
        print(np.sum(d==0))
        allWeights.append(w)

print("Calculate the difference between W_i and W_{i-1}")
for wi in range(1,len(allWeights)):
    difference = allWeights[wi]-allWeights[wi-1]
    # I expect that there will be around 20 weights that won't be updated
    # so the difference between the current weight and the previous one
    # should be zero.
    print(np.sum(difference==0))
2个回答

这是因为您使用的是 Adam 优化器。Adam 优化器是一种动量优化器(具体来说,它跟踪更新的第一个和第二个时刻),因此即使存在 dropout,所有模型参数仍然会发生更新。

Dropout: Tensorflow 中 Dropout 的实现与原始论文略有不同:更新权重(其中 p 是 dropout 率)后,神经元输出(例如,来自ReLUs) 在前向和后向传递过程中按 1/(1-p) 缩放。以这种方式,权重不必在更新后进行缩放。

随机梯度下降 (SGD) 优化器: SGD 通过对每个 epoch 的训练数据进行混洗并使用负梯度乘以学习率来更新权重来进行操作。请注意,它不考虑任何过去的权重更新。

具有自适应学习率的优化方法: Adagrad、Adadelta 和 RMSprop 是三个优化器,它们使用先前的梯度值来调整学习率。注意,作为 SGD,权重更新仍然只使用当前梯度乘以这个变量学习率;因此,对于大小为 1 的 mini-batch,这些方法在使用 dropout 时不会更新某些权重。

使用动量的优化方法: Nesterov 加速梯度 (NAG) 和 Adam 等方法提出了一个动量项,它考虑当前更新的先前梯度因此,对于大小为 1 的 mini-batch,这些方法不会仅在前几个数据样本期间更新某些权重 - 之后,很可能所有神经元都已被激活,并且每个权重都将具有非零梯度。

我建议验证小批量大小为 1 的前几个训练数据样本的权重更新。这将阐明这些不同优化方法在使用 dropout 时对当前权重更新的影响。请注意,对于较大的 mini-batch 大小,梯度是通过平均更新计算的;因此,即使在第一个 mini-batch 之后,很可能所有的权重更新都是非零的。