keras Tensorflow GradientTape间歇性显示“变量不存在梯度”

pn9klfpd  于 2023-02-04  发布在  其他
关注(0)|答案(8)|浏览(179)

在训练我的网络时,我偶尔会遇到这样的警告:
W0722 11:47:35.101842 140641577297728 optimizer_v2.py:928] Gradients does not exist for variables ['model/conv1d_x/Variable:0'] when minimizing the loss.
这种情况偶尔会发生(可能每20步成功一次),我的模型基本上有两条路径,它们在网络的不同位置连接在一起,为了说明这一点,这里有一个简化的例子来说明我的意思。

class myModel(tf.keras.Model):

  def __init__(self):

    self.conv1 = Conv2D(32)
    self.conv2 = Conv2D(32)
    self.conv3 = Conv2D(16)

  def call(self, inputs):

    net1 = self.conv1(inputs)
    net2 = self.conv2(inputs)
    net = tf.concat([net1, net2], axis=2)
    net = self.conv3(net)
    end_points = tf.nn.softmax(net)

model = myModel()

with tf.GradientTape() as tape:

  predicition = model(image)
  loss = myloss(labels, prediction)

gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))

实际上我的网络要大得多,但是通常没有梯度的变量往往是网络顶部的变量。在每个Conv2D层之前,我也有一个自定义梯度。有时当我出现错误时,我会注意到该层的梯度函数还没有被调用。
我的问题是,当梯度带在网络中反向传播时,它有时候会采取不同的路径。我的第二个问题是,这是否是由于网络中有两条独立的路径(即conv1和conv2)造成的?这种网络架构是否存在根本缺陷?
理想情况下,我是否可以定义GradientTape()必须找到每个顶层的渐变?

qzwqbdag

qzwqbdag1#

我遇到过一个类似的问题--可能会有帮助,也可能不确定,这取决于网络的实际情况,但基本上,我有一个多输出网络,我意识到,当我分别应用与输出相对应的梯度时,对于每个单独的损耗,网络中都有一个分支的梯度为零,但这是完全有效的并且每次都对应于紧接在非目标输出之前的终端层。为此,最后我用tf.zeros_like替换了所有None梯度,这样就可以继续训练了。如果你的网络有多个输入头,你会遇到同样的问题吗?如果它总是在图表的顶端呢
(ETA下面Nguy n Thu的解决方案是我上面描述的代码版本--与我处理它的方式完全相同)
我见过其他答案,其中梯度不计算,因为Tensor默认情况下不受监视-您必须添加它们,但看起来这不是您的问题,因为您应该只处理model.trainable_variables,或者您的myLoss函数可能会获得NaN结果或偶尔强制转换为numpy数组,具体取决于您的批处理组成。这可以解释偶发性(例如,如果您的数据非常不平衡,可能是在没有少数类别示例的批次上?)

ebdffaop

ebdffaop2#

Nguyun和gkennos给出的解决方案可以抑制错误,因为它会将所有None替换为零。然而,梯度在任何时间点都为空是一个大问题。上述问题肯定是由unconnected variables引起的(默认情况下PyTorch会抛出运行时错误)。
未连接层最常见的情况可以举例如下:

def some_func(x):
       x1 = x * some variables
       x2 = x1 + some variables #x2 discontinued after here
       x3 = x1 / some variables
       return x3

现在注意到x2是不连接的,所以梯度不会通过它传播。仔细调试代码中不连接的变量。

7vhp5slm

7vhp5slm3#

如果预期梯度丢失,则可通过this workaround抑制此警告:

optimizer.apply_gradients(
    (grad, var) 
    for (grad, var) in zip(gradients, model.trainable_variables) 
    if grad is not None
)
nsc4cvqm

nsc4cvqm4#

我也遇到了同样的问题。找到了自定义渐变的解决方案

def _compute_gradients(tensor, var_list):
      grads = tf.gradients(tensor, var_list)
  return [grad if grad is not None else tf.zeros_like(var)
      for var, grad in zip(var_list, grads)]

github trouble shoot开始

zazmityj

zazmityj5#

渐变带的gradient方法有一个unconnected_gradients参数,允许您指定未连接的渐变应该是还是。www.example.comhttps://www.tensorflow.org/api_docs/python/tf/GradientTape#gradient
所以你可以换句话说:

gradients = tape.gradient(loss, model.trainable_variables)

gradients = tape.gradient(loss, model.trainable_variables, 
                unconnected_gradients=tf.UnconnectedGradients.ZERO)

这对我很有效。

    • 编辑-重要信息**:只有当您实际上期望某些梯度为零时,这才是一个解决方案。如果错误是由反向传播中断引起的,则这不是一个解决方案。在这种情况下,您需要找到并修复中断的位置。
wgx48brx

wgx48brx6#

我也遇到了同样的错误。这是因为我在tape.gradient()函数中给出了错误的可训练变量。如果它能帮助一些人的话。
在我的示例中,self.encoder_model.get_trainable_variables()没有返回正确的变量:

@tf.function
def train_step(x_batch):
    with tf.GradientTape() as tape:
        loss = self.encoder_model.loss.compute_loss(x_batch)
    gradients = tape.gradient(loss, self.encoder_model.get_trainable_variables())
    self.optimizer.apply_gradients(zip(gradients, self.encoder_model.get_trainable_variables()))
xoshrz7s

xoshrz7s7#

TLDR确保您使用的是分类交叉熵,而不是二进制交叉熵
应用程序的损失函数不正确可能会导致此问题。例如,如果输出是one-hot编码的分类标签,如[0,1]或[1,0],则需要使用分类交叉熵损失。如果错误地使用了类似二进制交叉熵损失的函数,则不会为导致NN输出的非零分量的梯度生成梯度。

c9qzyr3d

c9qzyr3d8#

有是no梯度因为这变量doesn't影响这答案.在这代码,这调用功能是丢失一个return

class myModel(tf.keras.Model):

  def __init__(self):

    self.conv1 = Conv2D(32)
    self.conv2 = Conv2D(32)
    self.conv3 = Conv2D(16)

  def call(self, inputs):

    net1 = self.conv1(inputs)
    net2 = self.conv2(inputs)
    net = tf.concat([net1, net2], axis=2)
    net = self.conv3(net)
    return end_points = tf.nn.softmax(net)  # Change this line

相关问题