在keras的反向传播中跳过层

skipping layer in backpropagation in keras

我正在使用带有 tensorflow 后端的 Keras,我很好奇是否可以在反向传播期间跳过一个层,但让它在前向传播中执行。这就是我的意思

Lambda (lambda x: a(x))

我想在正向传递中将 a 应用到 x,但我不希望在发生反向传播时将 a 包含在推导中。

我试图找到一个解决方案,但我找不到任何东西。有人可以帮我吗?

更新 2

除了tf.py_func, there is now an official guide on how to add a custom op


更新

参见 for an example of writing a custom op with gradient purely in Python without needing to rebuild anything. Note that there are some limitations to the method (see the documentation of tf.py_func)。


不完全是问题的解决方案,但仍然是一种答案,但评论时间太长。

这甚至不是 Keras 问题,而是 TensorFlow 问题。每个操作都定义了在反向传播期间使用的自己的梯度计算。我 真的 想要这样的东西,你需要自己将 op 实现到 TensorFlow 中(这不是一件容易的事)并定义你想要的梯度 - 因为你不能 "no gradient",如果有的话,它将是 1 或 0(否则你不能继续进行反向传播)。 TensorFlow 中有一个 tf.NoGradient 函数,它会导致 op 传播零,但我不认为它意味着/可以在 TensorFlow 自己的内部结构之外使用。

更新

好吧,更多的上下文。 TensorFlow 图由 ops 构建,由 kernels 实现;这基本上是一个 1 对 1 的映射,除了可能有一个 CPU 和一个 GPU 内核用于操作,因此存在差异。 TensorFlow 支持的操作集通常是静态的,我的意思是它可以随着更新的版本而改变,但原则上你不能添加自己的操作,因为图形的操作进入 Protobuf 序列化格式,所以如果你自己制作操作那么你将无法分享你的图表。然后在 C++ 级别使用宏 REGISTER_OP 定义操作(参见示例 here), and kernels with REGISTER_KERNEL_BUILDER (see for example here)。

现在,渐变在哪里发挥作用?好吧,有趣的是操作的梯度不是在 C++ 级别定义的; ops(和内核)实现了其他ops的梯度(如果你查看以前的文件,你会发现ops/kernels名称以[=15=结尾]),但是(据我所知)在这个级别上这些并不是明确的 "linked"。似乎 ops 和它们的梯度之间的关联是在 Python 中定义的,通常是通过 tf.RegisterGradient 或前面提到的 tf.NoGradient(例如参见 [​​= 65=]here, Python 以 gen_ 开头的模块是在 C++ 宏的帮助下自动生成的);这些注册通知反向传播算法如何计算图形的梯度。

那么,如何实际解决这个问题呢?那么,您需要在 C++ 中创建至少一个 op,并使用相应的 kernel/s 实现您想要用于前向传递的计算。然后,如果你想使用的梯度计算可以用现有的 TensorFlow ops 表达(这很可能),你只需要在 [=104 中调用 tf.RegisterGradient =] 并在 "standard" TensorFlow 中进行计算。这相当复杂,但好消息是 可能,甚至还有一个 example (尽管我认为他们有点忘记了其中的渐变配准部分)!正如您将看到的,该过程涉及将新的操作代码编译到一个库中(顺便说一句,我不确定其中任何一个是否可以在 Windows 上运行)然后从 Python 加载(显然这涉及经历 使用 Bazel 手动编译 TensorFlow 的痛苦过程)。一个可能更真实的例子可以在 TensorFlow Fold 中找到,它是 TensorFlow 的扩展,用于结构化数据,在 此处 注册(从一个开始)一个自定义操作通过在此处定义的调用REGISTER_OP的宏,然后在Python中加载库并在此处注册其梯度通过他们自己定义的注册函数 here 简单地调用 tf.NotDifferentiabletf.NoGradient 的另一个名称)

tldr:这很难,但是可以完成,甚至还有几个例子。

如@jdehesa 的评论所述。您可以使用 "alternative gradient" 实现您的功能。如果我的数学不正确,请原谅我,但我认为返回“1”的导数是对反向传播没有影响同时仍然通过学习的正确方法。构造方法见here。我引用的示例更进一步,允许您从 python 函数构造激活函数。所以代替 spiky 函数,替换你的函数 a,并用

代替他的导数 d_spiky
def constant(x):
       return 1

因此,在前向传播中,a 应用于图层,向后传播 1 应用,应该简单地通过权重调整。

然后您可以使用此函数在 Keras 中创建一个 Activation 层。