【问题标题】:tensorflow 2 keras shuffle each row gradient problemtensorflow 2 keras shuffle 每行梯度问题
【发布时间】:2019-12-26 22:09:28
【问题描述】:

我需要一个神经网络,它将为相同输入的任何排列提供相同的输出。正在尝试搜索解决方案(“排列不变性”),找到了一些层,但未能使它们工作。

我选择了不同的方法:我想创建一个层,在模型中添加我的第一个,这将随机打乱输入(每行独立) - 请按照这种方法,我知道它可以在模型之外完成,但我希望它作为模型的一部分。我试过了:

class ShuffleLayer(tf.keras.layers.Layer):
    def __init__(self, **kwargs):
        super(ShuffleLayer, self).__init__(**kwargs)

    def call(self, inputs):
        batchSize = tf.shape(inputs)[0]
        cols = tf.shape(inputs)[-1]
        order0 = tf.tile(tf.expand_dims(tf.range(0, batchSize), -1), [1, cols])
        order1 = tf.argsort(tf.random.uniform(shape=(batchSize, cols)))
        indices = tf.stack([tf.reshape(order0, [-1]), tf.reshape(order1, [-1])], axis=-1)
        outputs = tf.reshape(tf.gather_nd(inputs, indices), [batchSize, cols])
        return outputs

我收到以下错误:

ValueError: 变量有None 用于渐变。请确保您的所有操作都定义了渐变(即可微分)。没有的常见操作 梯度:K.argmax、K.round、K.eval。

如何避免??我尝试使用tf.stop_gradient,但没有成功。

【问题讨论】:

  • 我添加了一个答案,但是为了解决这个错误,你需要展示你的整个模型以及它包含的所有自定义操作,包括损失函数。不是你的层造成的。

标签: python keras gradient shuffle tensorflow2.0


【解决方案1】:

使用Lambda层:

首先,如果您的层没有可训练的权重,您应该使用Lambda 层,而不是自定义层。它更简单,更容易。

def shuffleColumns(inputs):
    batchSize = tf.shape(inputs)[0]
    cols = tf.shape(inputs)[-1]
    order0 = tf.tile(tf.expand_dims(tf.range(0, batchSize), -1), [1, cols])
    order1 = tf.argsort(tf.random.uniform(shape=(batchSize, cols)))
    indices = tf.stack([tf.reshape(order0, [-1]), tf.reshape(order1, [-1])], axis=-1)
    outputs = tf.reshape(tf.gather_nd(inputs, indices), [batchSize, cols])
    return outputs

在模型中,使用Lambda(shuffleColumns) 层。

关于错误

如果这是第一层,这个错误很可能不是这个层引起的。 (除非较新版本的 Tensorflow 要求自定义层具有权重并定义 def build(self, input_shape):,这似乎不太合乎逻辑)。

您似乎在另一个地方做其他事情。错误是:您正在使用一些阻止反向传播的操​​作,因为不可能有该操作的导数。

由于导数是相对于模型的“权重”进行的,这意味着该操作必须在模型中的第一个权重张量之后(即:在包含可训练权重的第一层之后)。

您需要在模型中搜索任何没有导数的东西,就像错误提示的那样:round、argmax、返回常量的条件、返回排序的损失 y_true 但不返回 y_pred 上的操作等。

当然K.stop_gradients也是一个阻塞反向传播的操​​作,如果你这样使用肯定会导致这个错误。 (这甚至可能是你问题的“原因”,而不是解决方案)

下面有一些更简单的操作建议,但它们都不会修复此错误,因为此错误在其他地方。

建议操作1

现在,使用tf.random.shuffle 会更容易:

def shuffleColumns(x):
    x = tf.transpose(x)
    x = tf.random.shuffle(x)
    return tf.transpose(x)

在您的模型中使用Lambda(shuffleColumns) 层。确实,这将平等地洗牌所有列,但每批都会有不同的排列。而且由于您将有很多 epoch,并且您将在每个 epoch 之间改组(我假设)样本(这在 fit 中是自动的),您几乎不会有重复的批次。所以:

  • 每批都有不同的排列
  • 几乎不可能有两次相同的批次

这种方法可能会比您的方法快得多。

建议操作2

如果您希望它们排列不变,为什么不使用tf.sort 而不是排列?对列进行排序,而不是有无限的排列来训练,您只需消除任何排列的可能性。模型应该学习得更快,但不会考虑输入中列的顺序。

使用层Lambda(lambda x: tf.sort(x, axis=-1))

此建议必须用于训练和推理。

【讨论】:

  • 感谢您快速而全面的答复。我的模型的其余部分相当简单,只是一些 BatchNormalization 和 Dense 层,并且它可以在没有第一个“shuffle”层的情况下完美地工作(训练和预测)。 Lambda(shuffleColumns) 层似乎可以工作,但在 tf.keras.models.Sequential.save() 上给出错误
  • 我在 ShuffleColumn 类中发现了一个愚蠢的错误(我在这里发布了简化版),所以不再有梯度错误。我也必须考虑您的建议,如果仍然没有相关性,仍然不确定第一个建议。第二个可能实际上对我有用(在我的情况下,我必须对列组而不是单列进行排序,因此指定排序键变得有点复杂)。感谢您的帮助!
猜你喜欢
  • 2021-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多