Tensorflow 如何在TF2.0中实现梯度反转层?

Tensorflow 如何在TF2.0中实现梯度反转层?,tensorflow,keras,tensorflow2.0,Tensorflow,Keras,Tensorflow2.0,这一层是静态的,它是一个伪函数。在正向传播中,它不做任何事情(标识函数)。然而,在反向传播中,它将梯度乘以-1。github上有很多实现,但它们不适用于TF2.0 这里有一个供参考 import tensorflow as tf from tensorflow.python.framework import ops class FlipGradientBuilder(object): def __init__(self): self.num_calls = 0

这一层是静态的,它是一个伪函数。在正向传播中,它不做任何事情(标识函数)。然而,在反向传播中,它将梯度乘以-1。github上有很多实现,但它们不适用于TF2.0

这里有一个供参考

import tensorflow as tf
from tensorflow.python.framework import ops

class FlipGradientBuilder(object):
    def __init__(self):
        self.num_calls = 0

    def __call__(self, x, l=1.0):
        grad_name = "FlipGradient%d" % self.num_calls
        @ops.RegisterGradient(grad_name)
        def _flip_gradients(op, grad):
            return [tf.negative(grad) * l]

        g = tf.get_default_graph()
        with g.gradient_override_map({"Identity": grad_name}):
            y = tf.identity(x)

        self.num_calls += 1
        return y

flip_gradient = FlipGradientBuilder()
反转渐变的虚拟操作 这可以使用decorator
tf.custom_gradient
完成,如下所述:

@tf.custom\u梯度
def梯度反转(x):
y=tf.identity(x)
def自定义梯度(dy):
返回dy
返回y,自定义梯度
然后,您可以将其当作正常的TensorFlow op来使用,例如:

z=编码器(x)
r=梯度_反向(z)
y=解码器(r)
凯拉斯API? TF2.0的一大便利是它对KerasAPI的本机支持。您可以定义自定义的
GradReverse
op,享受Keras的便利:

class梯度反转(tf.keras.layers.Layer):
定义初始化(自):
super()。\uuuu init\uuuuu()
def呼叫(自我,x):
反向返回梯度(x)
然后,您可以将该层用作任何其他Keras层,例如:

model=Sequential()
conv=tf.keras.layers.Conv2D(…)(inp)
cust=CustomLayer()(conv)
flat=tf.keras.layers.flant()(cust)
fc=tf.keras.layers.Dense(数量级)(平坦)
model=tf.keras.models.model(输入=[inp],输出=[fc])
compile(损失=…,优化器=…)
模型拟合(…)

这里有文档:@PedroMarques感谢您的链接。但文件仍然不明显。例如,他们定义了一个函数clip\u gradient\u by\u norm,但没有解释在何处使用它。例如,如果您使用Keras构建图形,您将从Lambda层调用此函数。默认情况下,Tensorflow跟踪图形定义内的张量操作,并使用其自动微分规则计算梯度。自定义渐变告诉它使用用户定义的渐变函数,而不是自动微分计算的渐变(对于此函数的范围)。Stackoverflow社区需要更多像您这样的人。谢谢。还有一件事,我不是专家,但我认为您应该将函数包装为lambda层,而不是有状态层,因为它是静态的。我说的对吗?@FalconUA,使用kerasapi的解决方案很优雅,但我无法让它工作。我尝试了裸骨代码(参见),并获取了错误值error:尝试将不支持类型()的值()转换为张量。@Jatala看起来您是将上一层本身作为参数传递,而不是调用它并传递结果。我没有看过你的代码,但这通常是由于放错了位置。