tensorflow 2 keras shuffle 每行梯度问题
tensorflow 2 keras shuffle each row gradient problem
我需要一个神经网络,它将为相同输入的任何排列提供相同的输出。正在尝试搜索解决方案 ('permutation invariance'),找到了一些层,但未能使它们起作用。
我选择了不同的方法:我想创建一个层,像我第一次添加到模型中一样,它将随机打乱输入(每一行独立)——请让我们遵循这种方法,我知道它可以在外面完成模型,但我希望它成为模型的一部分。我试过了:
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: Variable has None
for gradient. Please make sure that all of your ops have a gradient defined (i.e. are differentiable). Common ops without
gradient: K.argmax, K.round, K.eval.
如何避免??我尝试使用 tf.stop_gradient
,但没有成功。
使用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):
定义,这似乎不太合逻辑)。
看来你在另一个地方做别的事情。错误是:您正在使用一些阻止反向传播的操作,因为不可能拥有该操作的导数。
由于导数是相对于模型的 "weights" 取的,这意味着操作必须在模型中的第一个权重张量之后(即:在包含可训练权重的第一层之后)。
您需要在模型中搜索任何没有导数的东西,如错误提示:round、argmax、return 常量的条件、return 排序的损失 y_true
但不要对 y_pred
进行 return 操作,等等
当然那个K.stop_gradients
也是一个阻塞反向传播的操作,你随便用肯定会报这个错。 (这甚至可能是您问题的 "cause",而不是解决方案)
下面有更简单的操作建议,但其中 none 将修复此错误,因为此错误在其他地方。
建议操作1
现在,使用 tf.random.shuffle
会更容易:
def shuffleColumns(x):
x = tf.transpose(x)
x = tf.random.shuffle(x)
return tf.transpose(x)
在模型中使用 Lambda(shuffleColumns)
层。确实,这会平等地洗牌所有列,但每批都会有不同的排列。并且由于您将有许多时期,并且您将在每个时期之间洗牌(我假设)样本(这在 fit
中是自动的),您几乎不会有重复的批次。所以:
- 每批都会有不同的排列
- 同一批次出现两次几乎是不可能的
这种方法可能比你的方法快得多。
建议操作2
如果你想要它们排列不变,为什么不使用 tf.sort
而不是排列?对列进行排序,而不是有无限的排列来训练,您只需消除排列的任何可能性。该模型应该学习得更快,但不会考虑输入中列的顺序。
使用图层Lambda(lambda x: tf.sort(x, axis=-1))
训练和推理都必须使用此建议。
我需要一个神经网络,它将为相同输入的任何排列提供相同的输出。正在尝试搜索解决方案 ('permutation invariance'),找到了一些层,但未能使它们起作用。
我选择了不同的方法:我想创建一个层,像我第一次添加到模型中一样,它将随机打乱输入(每一行独立)——请让我们遵循这种方法,我知道它可以在外面完成模型,但我希望它成为模型的一部分。我试过了:
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: Variable has
None
for gradient. Please make sure that all of your ops have a gradient defined (i.e. are differentiable). Common ops without gradient: K.argmax, K.round, K.eval.
如何避免??我尝试使用 tf.stop_gradient
,但没有成功。
使用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):
定义,这似乎不太合逻辑)。
看来你在另一个地方做别的事情。错误是:您正在使用一些阻止反向传播的操作,因为不可能拥有该操作的导数。
由于导数是相对于模型的 "weights" 取的,这意味着操作必须在模型中的第一个权重张量之后(即:在包含可训练权重的第一层之后)。
您需要在模型中搜索任何没有导数的东西,如错误提示:round、argmax、return 常量的条件、return 排序的损失 y_true
但不要对 y_pred
进行 return 操作,等等
当然那个K.stop_gradients
也是一个阻塞反向传播的操作,你随便用肯定会报这个错。 (这甚至可能是您问题的 "cause",而不是解决方案)
下面有更简单的操作建议,但其中 none 将修复此错误,因为此错误在其他地方。
建议操作1
现在,使用 tf.random.shuffle
会更容易:
def shuffleColumns(x):
x = tf.transpose(x)
x = tf.random.shuffle(x)
return tf.transpose(x)
在模型中使用 Lambda(shuffleColumns)
层。确实,这会平等地洗牌所有列,但每批都会有不同的排列。并且由于您将有许多时期,并且您将在每个时期之间洗牌(我假设)样本(这在 fit
中是自动的),您几乎不会有重复的批次。所以:
- 每批都会有不同的排列
- 同一批次出现两次几乎是不可能的
这种方法可能比你的方法快得多。
建议操作2
如果你想要它们排列不变,为什么不使用 tf.sort
而不是排列?对列进行排序,而不是有无限的排列来训练,您只需消除排列的任何可能性。该模型应该学习得更快,但不会考虑输入中列的顺序。
使用图层Lambda(lambda x: tf.sort(x, axis=-1))
训练和推理都必须使用此建议。