【问题标题】:Gradients returned by tape.gradient is None in Custom Training Looptape.gradient 返回的梯度在自定义训练循环中为无
【发布时间】:2020-06-12 13:33:22
【问题描述】:

我正在尝试实现加权二元交叉熵损失函数 另外,我正在使用自定义训练循环进行训练

def grads_ds(model_ds, ds_inputs,y_true,cw):
    with tf.GradientTape() as ds_tape:
        #ds_tape.watch(tf.convert_to_tensor(y_true.astype('float')))
        #ds_tape.watch(tf.convert_to_tensor(ds_inputs))

        y_pred = model_ds(ds_inputs)
        #print(y_true,y_pred)

        log_logits = np.append(np.log(y_pred),np.log(1-y_pred),axis=0).T
        org_labs = np.append(y_true,1-y_true,axis=0).T
        loss = K.sum(-1*org_labs*cw*log_logits,axis=1)
        loss_value_ds = K.sum(loss)

    ds_grads = ds_tape.gradient(loss_value_ds,model_ds.trainable_variables)

    return loss_value_ds, ds_grads

y_true 和 y_pred 的形状均为 (1,3),cw 的形状为 (3,2)

cw是

[[0.5145 3.6036]
 [1.7163 0.7127]
 [2.4231 0.6708]]

ds_tape.gradient 正在返回 None 渐变。 我什至尝试添加ds_tape.watch 作为输入和真实标签y_true。但仍然收到None。

在我的网络中,我在某一层之后使用了tf.math.reduce_max。这会是问题的根源吗?

还是因为我在张量 y_pred 上使用了 numpy 函数?

tf.GradientTape().gradient() 当目标和源是UNCONNECTED 时返回None。我无法弄清楚它是如何断开连接的。

注意:当我使用tf.keras.losses.binary_crossentropy(y_true,y_pred) 时,没有出现上述错误。只有当我使用自定义损失计算代码而不是 keras 函数时,才会出现此错误

有什么解决办法吗? 我在网上看到的方法都不起作用。

【问题讨论】:

    标签: python tensorflow neural-network conv-neural-network tf.keras


    【解决方案1】:

    我这样运行你的代码:

    import tensorflow as tf
    import numpy as np
    K = tf.keras.backend
    (x_trn,y_trn),(x_val,y_val) = tf.keras.datasets.mnist.load_data()
    model = get_simple_1conv_1dense_model(x_trn,y_trn)
    g = grads_ds(model, x_tst, y_tst, cw=1) # hopefully cw=1 makes sense
    

    最终,您的函数返回了一堆 None 渐变:

    (<tf.Tensor: shape=(), dtype=float32, numpy=nan>, [None, None, None, None])
    

    但是,原因似乎很简单。在运行时,它产生了一个错误:

    /path/to/anaconda3/bin/ipython:9: RuntimeWarning: divide by zero encountered in log
      if __name__ == '__main__':
    /path/to/anaconda3/bin/ipython:11: RuntimeWarning: invalid value encountered in multiply
      sys.exit(start_ipython())
    

    除以零很可能是你的罪魁祸首。

    稍微琢磨了一下,我发现这行导致错误:

    log_logits = np.append(np.log(y_pred),np.log(1-y_pred),axis=0).T
    

    【讨论】:

    • cw 实际上是一个 (3,2) 数组。我忘了提。您可以使用 1。在这种情况下,它会简化为 binary_crossentropy()。
    • 在我的代码中,至少在第一次迭代中,对于我的任何输入,y_pred 都不是 0 或 1。我已经更新了我的问题。请读一读
    • 您更新的问题肯定会提供更多信息。很高兴你想通了。 (当我复制并粘贴你的函数时,将np 换成K 应该引起了我的注意。很好。)
    【解决方案2】:

    我通过使用tf.keras.backend中的函数重写代码解决了这个问题

    def grads_ds(model_ds, ds_inputs,y_true,cw):
        with tf.GradientTape() as ds_tape:
            y_pred = model_ds(ds_inputs)
            logits_1 = -1*y_true*K.log(y_pred)*cw[:,0]
            loss = logits_1 + logits_0
            loss_value_ds = K.sum(loss)
        ds_grads = ds_tape.gradient(loss_value_ds,model_ds.trainable_variables,unconnected_gradients=tf.UnconnectedGradients.NONE)
        return loss_value_ds, ds_grads
    

    故事的寓意:numpy 函数不能用于张量。如果使用,计算图不会保持连接。

    【讨论】:

    • 我同意最好使用后端函数是可能的,但是当你说“如果使用,计算图不会保持连接”。即使包装在 tf.py_function 和 tf.numpy_function 等 TensorFlow 函数中也是如此吗?
    猜你喜欢
    • 1970-01-01
    • 2021-10-02
    • 2019-11-09
    • 1970-01-01
    • 2020-04-13
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多