【问题标题】:Tensorflow loss function having no gradients没有梯度的张量流损失函数
【发布时间】:2021-05-12 03:15:00
【问题描述】:

我可能需要一些帮助来实现损失函数的特定正则化项。但是它没有渐变,我想知道是否有任何方法可以改变它。我已经在一篇论文中阅读了这种方法,但是阅读这篇论文对于实际帮助我并不重要。我将仅描述问题所在的方法并在 Google-Colab 中显示测试代码。

神经网络仅由 2 个卷积层组成,最后一层是 Sigmoid 激活函数。因此,由于 Sigmoid,输出介于 0 和 1 之间。这个值将被视为输出层中每个神经元为 0 或 1 的概率。所以我想用 'tf.keras.backend.switch' 函数以这种方式实现它:

def regularization_term(y_true, y_pred):
    zeros = tf.zeros_like(y_pred)
    ones = tf.ones_like(y_pred)
    random = tf.random.uniform(tf.shape(y_pred),minval=0,maxval=1,dtype=tf.dtypes.float64)
    y_pred_new = tf.keras.backend.switch(random > y_pred, zeros, ones)
    return y_pred_new

我绘制一个随机数并检查一个条件以使每个值都为 0 或 1。这应该从代码中清楚。但是,当我这样做时,该术语实际上没有渐变:

ValueError:没有为任何变量提供梯度:['conv2d_4/kernel:0', 'conv2d_4/bias:0', 'conv2d_5/kernel:0', 'conv2d_5/bias:0']。

完整的测试代码可以在这个colab中找到:https://colab.research.google.com/drive/1YuX00BUAj-BVCZRbr4opo5wHbcaVbYvx?usp=sharing

有没有什么方法可以实现这种方法,同时保持让网络学习的梯度?如果有任何不清楚的地方,请询问,我尽力使我的问题尽可能容易理解。我真的很高兴能得到任何帮助。

非常感谢!

[编辑,从 GOOGLE_COLAB 复制粘贴,否则忽略:]

#just importing some libraries
import tensorflow as tf
import numpy as np
from tensorflow.python.framework import ops
from tensorflow.keras import datasets, layers, models
tf.keras.backend.set_floatx('float64')
#length of the dataset
L=16
#THIS REGULARIZATION TERM NEEDS SOME AID

def regularization_term(y_true, y_pred):
    zeros = tf.zeros_like(y_pred)
    ones = tf.ones_like(y_pred)
    random = tf.random.uniform(tf.shape(y_pred),minval=0,maxval=1,dtype=tf.dtypes.float64)
    y_pred_new = tf.keras.backend.switch(random > y_pred, zeros, ones)
    #here is actually some additional operatios, but they dont need to be taken into consideration so I've removed them
    return tf.reduce_sum(y_pred_new)

def my_custom_loss(y_true, y_pred):
    # I try this only with the regularization term to get the 'No gradients provided' error message
    return regularization_term(y_true, y_pred)
    #actually i would add a binary crossentropy term to this, i did not here for showcase purpose
    enter code here
#creating a dataset for input (initial) and true data (target) for testing purposes
initial = np.random.randint(2,size=(10000,L+2,L+2)).astype("float")
target = np.random.randint(2,size=(10000,L,L)).astype("float")

#adding a model with CNN and 1 hidden layer with relu and 1 output layer with sigmoid
EPOCHS = 2
BATCH_SIZE = 1000
model = models.Sequential()
model.add(layers.Conv2D(1,2,activation='relu',input_shape=[L+2,L+2,1]))
model.add(layers.Conv2D(1,2,activation='sigmoid',input_shape=[L,L,1]))
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3),loss=my_custom_loss)
model.fit(initial.reshape(10000,L+2,L+2,1),target.reshape(10000,L,L,1),batch_size = BATCH_SIZE, epochs=EPOCHS, verbose=1)

【问题讨论】:

  • 对不起,我的意思是,'return tf.reduce_sum(y_pred_new)' 在示例代码中。我的意思是无论如何都没关系,但返回将是一个标量,而不是一个矩阵。
  • 你能把代码贴在这里吗?
  • 我不认为tf.random.uniform 是可微的,但我可能错了。
  • @NicolasGervais:是的,我已经编辑了原帖
  • @Frightera 我认为问题不在于 tf.random.uniform。如果我添加: y_pred_new = tf.keras.backend.switch(random > y_pred, zeros, y_pred) ...您在 else/if 语句中看到 y_pred 而不是“ones”,它突然有一个可区分的术语,并且错误消息消失了。然而,这不是我需要的。我可能需要某种替代我的代码。我不完全确定。

标签: python tensorflow keras conv-neural-network loss-function


【解决方案1】:

您在 normalization_term 函数中创建的那 2 个张量(0 和 1)正在阻止 tf 找到可训练变量的路径。

只需将您的代码更改为以下代码即可

def regularization_term(y_true, y_pred):
    random = tf.random.uniform(tf.shape(y_pred),minval=0,maxval=1,dtype=tf.dtypes.float64)

    y_pred_new = tf.keras.backend.switch(random > y_pred,  y_pred * 0,  (y_pred*0)+1)

    return tf.reduce_sum(y_pred_new)

【讨论】:

  • 嗯,是的,你是对的,在这种情况下它没有错误消息,但它也无法学习任何东西。损失值只是在某个值附近随机波动。我相信现在存在一个梯度,因此代码可以再次运行,但它可能类似于 0。这个问题真的可以解决吗?无论如何,谢谢。
  • 根据您提供的代码是不可能的。您总是返回 0 或所有的总和。
  • @hegal 对此还有什么顾虑吗?
  • 好吧,我不确定。理论上是的,我仍然有一些担忧,因为它不能完全按照我认为的方式工作。很高兴你再次来看我,我最近几天有点忙。我打算给论文的作者写一个关于这个问题的详细问题,希望他做出回应。除此之外,我想知道是否还有一种方法可以创建一个函数,为输出层中的每个神经元指定 0 或 1,同时仍然具有梯度。类似于 Maxpool 或舍入。不确定这样的东西是否可以区分。很难说。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-07
  • 2020-09-29
  • 2016-08-20
  • 2019-11-12
  • 1970-01-01
  • 1970-01-01
  • 2018-09-18
相关资源
最近更新 更多