【问题标题】:The gradient of an output w.r.t network weights that holds another output constant保持另一个输出常数的输出 w.r.t 网络权重的梯度
【发布时间】:2017-06-30 03:36:36
【问题描述】:

假设我有一个简单的 MLP

我有一个关于输出层的一些损失函数的梯度,以获得 G = [0, -1](即增加第二个输出变量会减少损失函数)。

如果我根据我的网络参数获取 G 的梯度并应用梯度适当的权重更新,那么第二个输出变量应该会增加,但是没有关于第一个输出变量的任何说明,并且梯度的缩放应用几乎肯定会改变输出变量(增加或减少)

如何修改我的损失函数或任何梯度计算,以确保第一个输出不会改变?

【问题讨论】:

    标签: tensorflow neural-network gradient-descent


    【解决方案1】:

    更新:我误解了这个问题。这是新的答案。

    为此,您只需要更新隐藏层和第二个输出单元之间的连接,同时保持隐藏层和第一个输出单元之间的连接不变。

    第一种方法是引入两组变量:一组用于隐藏层和第一个输出单元之间的连接,一组用于其余的。然后您可以使用tf.stack 组合它们,并传递一个var_list 以获得相应的导数。就像(仅用于说明。未经测试。小心使用):

    out1 = tf.matmul(hidden, W_h_to_out1) + b_h_to_out1
    out2 = tf.matmul(hidden, W_h_to_out2) + b_h_to_out2
    out = tf.stack([out1, out2])
    out = tf.transpose(tf.reshape(out, [2, -1]))
    loss = some_function_of(out)
    optimizer = tf.train.GradientDescentOptimizer(0.1)
    train_op_second_unit = optimizer.minimize(loss, var_list=[W_h_to_out2, b_h_to_out2])
    

    另一种方法是使用掩码。当您使用某些框架(例如,slim、Keras 等)时,这更容易实现且更灵活,我会推荐这种方式.将第一个输出单元隐藏到损失函数的想法,同时不改变第二个输出单元。 这可以使用二进制变量来完成:如果你想保留它,乘以 1,然后乘以 0 删除它。这是代码:

    import tensorflow as tf
    import numpy as np
    
    # let's make our tiny dataset: (x, y) pairs, where x = (x1, x2, x3), y = (y1, y2),
    # and y1 = x1+x2+x3, y2 = x1^2+x2^2+x3^2
    
    # n_sample data points
    n_sample = 8
    data_x = np.random.random((n_sample, 3))
    data_y = np.zeros((n_sample, 2))
    data_y[:, 0] += np.sum(data_x, axis=1)
    data_y[:, 1] += np.sum(data_x**2, axis=1)
    data_y += 0.01 * np.random.random((n_sample, 2))  # add some noise
    
    
    # build graph
    # suppose we have a network of shape [3, 4, 2], i.e.: one hidden layer of size 4.
    
    x = tf.placeholder(tf.float32, shape=[None, 3], name='x')
    y = tf.placeholder(tf.float32, shape=[None, 2], name='y')
    mask = tf.placeholder(tf.float32, shape=[None, 2], name='mask')
    
    W1 = tf.Variable(tf.random_normal(shape=[3, 4], stddev=0.1), name='W1')
    b1 = tf.Variable(tf.random_normal(shape=[4], stddev=0.1), name='b1')
    hidden = tf.nn.sigmoid(tf.matmul(x, W1) + b1)
    W2 = tf.Variable(tf.random_normal(shape=[4, 2], stddev=0.1), name='W2')
    b2 = tf.Variable(tf.random_normal(shape=[2], stddev=0.1), name='b2')
    out = tf.matmul(hidden, W2) + b2
    loss = tf.reduce_mean(tf.square(out - y))
    
    # multiply out by mask, thus out[0] is "invisible" to loss, and its gradient will not be propagated
    masked_out = mask * out
    loss2 = tf.reduce_mean(tf.square(masked_out - y))
    
    optimizer = tf.train.GradientDescentOptimizer(0.1)
    train_op_all = optimizer.minimize(loss)  # update all variables in the network
    train_op12 = optimizer.minimize(loss, var_list=[W2, b2])  # update hidden -> output layer
    train_op2 = optimizer.minimize(loss2, var_list=[W2, b2])  # update hidden -> second output unit
    
    
    sess = tf.InteractiveSession()
    sess.run(tf.global_variables_initializer())
    mask_out1 = np.zeros((n_sample, 2))
    mask_out1[:, 1] += 1.0
    # print(mask_out1)
    print(sess.run([hidden, out, loss, loss2], feed_dict={x: data_x, y: data_y, mask: mask_out1}))
    
    # In this case, only out2 is updated. You see the loss and loss2 decreases.
    sess.run(train_op2, feed_dict={x: data_x, y:data_y, mask: mask_out1})
    print(sess.run([hidden, out, loss, loss2], feed_dict={x: data_x, y:data_y, mask: mask_out1}))
    
    # In this case, both out1 and out2 is updated. You see the loss and loss2 decreases.
    sess.run(train_op12, feed_dict={x: data_x, y:data_y, mask: mask_out1})
    print(sess.run([hidden, out, loss, loss2], feed_dict={x: data_x, y:data_y, mask: mask_out1}))
    
    # In this case, everything is updated. You see the loss and loss2 decreases.
    sess.run(train_op_all, feed_dict={x: data_x, y:data_y, mask: mask_out1})
    print(sess.run([hidden, out, loss, loss2], feed_dict={x: data_x, y:data_y, mask: mask_out1}))
    sess.close()
    

    ========================下面是老答案=================== ===========

    要获得 w.r.t. 的导数。不同的变量,您可以传递var_list 来决定要更新哪个变量。这是一个例子:

    import tensorflow as tf
    import numpy as np
    
    # let's make our tiny dataset: (x, y) pairs, where x = (x1, x2, x3), y = (y1, y2),
    # and y1 = x1+x2+x3, y2 = x1^2+x2^2+x3^2
    
    # n_sample data points
    n_sample = 8
    data_x = np.random.random((n_sample, 3))
    data_y = np.zeros((n_sample, 2))
    data_y[:, 0] += np.sum(data_x, axis=1)
    data_y[:, 1] += np.sum(data_x**2, axis=1)
    data_y += 0.01 * np.random.random((n_sample, 2))  # add some noise
    
    
    # build graph
    # suppose we have a network of shape [3, 4, 2], i.e.: one hidden layer of size 4.
    
    x = tf.placeholder(tf.float32, shape=[None, 3], name='x')
    y = tf.placeholder(tf.float32, shape=[None, 2], name='y')
    
    W1 = tf.Variable(tf.random_normal(shape=[3, 4], stddev=0.1), name='W1')
    b1 = tf.Variable(tf.random_normal(shape=[4], stddev=0.1), name='b1')
    hidden = tf.nn.sigmoid(tf.matmul(x, W1) + b1)
    W2 = tf.Variable(tf.random_normal(shape=[4, 2], stddev=0.1), name='W2')
    b2 = tf.Variable(tf.random_normal(shape=[2], stddev=0.1), name='b2')
    out = tf.matmul(hidden, W2) + b2
    
    loss = tf.reduce_mean(tf.square(out - y))
    optimizer = tf.train.GradientDescentOptimizer(0.1)
    # You can pass a variable list to decide which variable(s) to minimize.
    train_op_second_layer = optimizer.minimize(loss, var_list=[W2, b2])
    # If there is no var_list, all variables will be updated.
    train_op_all = optimizer.minimize(loss)
    
    sess = tf.InteractiveSession()
    sess.run(tf.global_variables_initializer())
    print(sess.run([W1, b1, W2, b2, loss], feed_dict={x: data_x, y:data_y}))
    
    # In this case, only W2 and b2 are updated. You see the loss decreases.
    sess.run(train_op_second_layer, feed_dict={x: data_x, y:data_y})
    print(sess.run([W1, b1, W2, b2, loss], feed_dict={x: data_x, y:data_y}))
    
    # In this case, all variables are updated. You see the loss decreases.
    sess.run(train_op_all, feed_dict={x: data_x, y:data_y})
    print(sess.run([W1, b1, W2, b2, loss], feed_dict={x: data_x, y:data_y}))
    sess.close()
    

    【讨论】:

    • 如何设置trainable=False,Variable
    • 这不是一回事——问题在于两个输出都受到权重变化的影响——应用输出相对于权重的梯度会导致两个输出都发生变化,但我们希望梯度以某种方式解释这样一个事实,即一个输出在梯度步骤之后应该保持不变
    • @Robert 哦,我明白了。我误解了你的问题。我会更新我的答案。
    • @Robert 我的新答案有帮助吗?您需要知道输出本身不是变量:它只是其他变量的组合。如果要控制输出,则需要控制影响输出的变量。
    • @xxi 是的,你可以。但是恐怕如果您将变量设置为不可训练,您将无法再次训练它。有时人们可能想训练一个变量几个步骤,然后冻结它,然后再次训练。 (比方说,在 GAN 的训练过程中)对于这种情况,最好使用var_list
    猜你喜欢
    • 2018-10-14
    • 2017-01-26
    • 2019-09-24
    • 2020-02-27
    • 2019-01-10
    • 2022-01-14
    • 2020-04-03
    • 2022-01-13
    相关资源
    最近更新 更多