【问题标题】:How to implement gradient reversal layer in TF 2.0?如何在 TF 2.0 中实现梯度反转层?
【发布时间】:2019-07-01 19:08:40
【问题描述】:

这一层是静态的,它是一个伪函数。在前向传播中,它不做任何事情(恒等函数)。然而,在反向传播中,它将梯度乘以 -1。 github 上有很多实现,但它们不适用于 TF 2.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()

【问题讨论】:

  • @PedroMarques 感谢您的链接。但是文档仍然不明显。例如,他们定义了一个函数 clip_gradient_by_norm,但没有解释在哪里使用它。
  • 例如,如果您使用 Keras 构建图表,您可以从 Lambda 层调用此函数。默认情况下,Tensorflow 跟踪图定义中的张量操作,并使用其自动微分规则来计算梯度。自定义梯度告诉它使用用户定义的 grad 函数而不是通过自动微分计算的梯度(对于这个函数的范围)。

标签: tensorflow keras tensorflow2.0


【解决方案1】:

反转渐变的虚拟操作

这可以使用装饰器tf.custom_gradient 来完成,如in this example 所述:

@tf.custom_gradient
def grad_reverse(x):
    y = tf.identity(x)
    def custom_grad(dy):
        return -dy
    return y, custom_grad

那么,你就可以把它当作普通的TensorFlow op来使用了,例如:

z = encoder(x)
r = grad_reverse(z)
y = decoder(r)

Keras API?

TF 2.0 的一大便利是它对 Keras API 的原生支持。你可以定义一个自定义的GradReverse op,享受 Keras 带来的便利:

class GradReverse(tf.keras.layers.Layer):
    def __init__(self):
        super().__init__()

    def call(self, x):
        return grad_reverse(x)

然后,您可以将这一层用作 Keras 的任何其他层,例如:

model = Sequential()
conv = tf.keras.layers.Conv2D(...)(inp)
cust = CustomLayer()(conv)
flat = tf.keras.layers.Flatten()(cust)
fc = tf.keras.layers.Dense(num_classes)(flat)

model = tf.keras.models.Model(inputs=[inp], outputs=[fc])
model.compile(loss=..., optimizer=...)
model.fit(...)

【讨论】:

  • Stackoverflow 社区需要更多像你这样的人。谢谢。
  • 还有一件事,我不是专家,但我认为您应该将函数包装为 lambda 层而不是有状态层,因为它是静态的。我说的对吗?
  • @FalconUA,使用 Keras API 的解决方案很优雅,但我无法让它工作。我尝试了基本代码(参见dropbox.com/s/cld1ntar1zb3z89/file.py?dl=0)并得到错误 ValueError: Attempt to convert a value () 与不支持的类型() 到张量。
  • @Jatala 看起来您将前一层本身作为参数传递,而不是调用它并传递结果。我没有看过你的代码,但这通常是由于括号放错了。
猜你喜欢
  • 2019-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-09
  • 1970-01-01
  • 2021-03-05
  • 2018-09-16
  • 2017-03-20
相关资源
最近更新 更多