【问题标题】:skipping layer in backpropagation in keras在keras的反向传播中跳过层
【发布时间】:2017-09-02 19:10:59
【问题描述】:

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

Lambda (lambda x: a(x))

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

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

【问题讨论】:

  • 您要冻结它(= 不更新该特定层的权重)吗?
  • 没有。假设 a(x) = 1/(1+e^x)。然后在前向传递中,我想通过 sigmoid 函数推动 x,但在反向传播中,我不想包含 sigmoid 的导数
  • 抱歉不能帮助你...我真的不明白派生另一个函数的目的,而不是你想要最小化的函数?反向传播失去了它的目的
  • 你解决了吗?我需要相同的功能。你能展示你的解决方案吗?

标签: tensorflow keras keras-layer


【解决方案1】:

更新 2

除了tf.py_func,现在还有一个official guide on how to add a custom op


更新

请参阅this question 以获取纯粹在 Python 中编写具有渐变的自定义操作的示例,而无需重新构建任何内容。请注意,该方法有一些限制(请参阅tf.py_func 的文档)。


不完全是问题的解决方案,但仍然是一个答案,对于 cmets 来说太长了。

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

更新

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

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

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

tldr:这相当困难,但它可以完成,甚至有几个例子。

【讨论】:

  • 感谢您的回答。好吧,如果你想用一个不可微的函数计算前向传播,然后用一个非常相似但可微的函数进行反向传播,这是有道理的,我们将看到。你能给我链接,他们描述了如何实现操作并将其嵌入到 Keras 层中吗?
  • @DalekSupreme 哦,我明白了,所以它不是“删除”渐变,而是用“替代”计算代替它,好吧,是的,这是有道理的。我会看看我是否能找到一个例子,但除非是错误的(我可能是),我认为这将涉及 C++ 方面的变化和重新编译......但至少应该是可能的。
  • 嗯,我有点希望有一个更简单的解决方案,但如果是这样的话,那么我至少知道它很难实现。让我们希望有人有更简单的解决方案。如果没有这样的事情,我会接受你的回答。感谢您的帮助:)
  • @DalekSupreme 我已经用更多信息更新了答案。但是,我一直在谈论“硬”的方法。也许还有其他一些技巧或解决方法可以做我不知道的事情。如果您认为它不能回答您的问题,则无需接受答案,我很高兴看到有人提出更好/更简单的解决方案。
  • 感谢您的详细描述。当然它对我有用。
【解决方案2】:

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

def constant(x):
       return 1

因此,在前向传播中,a 应用于层,而后向传播1 应用于应该只是传递权重调整。

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

【讨论】:

    猜你喜欢
    • 2021-03-19
    • 2018-05-05
    • 1970-01-01
    • 2022-10-30
    • 2017-01-12
    • 1970-01-01
    • 2017-07-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多