我正在使用具有张量流后端的Keras,我很好奇是否可以在反向传播期间跳过一个层但是它在正向传递中执行。所以这就是我的意思
Lambda (lambda x: a(x))
我想在前向传递中将a
应用于x
,但我不希望在backprop发生时将其包含在推导中。
我试图找到一个解决方案,我找不到任何东西。有人可以帮助我吗?
答案 0 :(得分:3)
更新2
除tf.py_func
外,现在还有official guide on how to add a custom op。
更新
有关使用渐变式编写自定义op的示例,请参阅this question,而无需重建任何内容。请注意,该方法存在一些限制(请参阅tf.py_func
的文档)。
不完全是问题的解决方案,但仍然是一种答案,而且评论时间太长。
这甚至不是Keras问题,而是TensorFlow问题。每个op都定义了自己在反向传播过程中使用的梯度计算。我真的想要这样的东西,你需要自己实现操作TensorFlow(不容易做到)并定义你想要的渐变 - 因为你不能有“无渐变”,如果它是1或0(否则你不能继续反向传播)。 TensorFlow中有一个tf.NoGradient
函数会导致op传播零,但我不认为它可以用于/可以在TensorFlow自己的内部使用。
更新
好的,更多的上下文。 TensorFlow图由 ops 构建,由内核实现;这基本上是一对一的映射,除了可能存在例如用于op的CPU和GPU内核,因此区别。 TensorFlow支持的一组操作通常是静态的,我的意思是它可以随着更新的版本而改变,但原则上你不能添加自己的操作,因为图形的操作会进入Protobuf序列化格式,所以如果你自己做了操作然后你将无法分享您的图表。然后使用宏REGISTER_OP
(例如参见here)和带REGISTER_KERNEL_BUILDER
的内核在C ++级别定义Ops(参见例如here)。
现在,渐变在哪里发挥作用?好吧,有趣的是,op的渐变没有在C ++级别定义;有是操作(和内核)来实现其他操作的渐变(如果你查看以前的文件,你会发现名称以Grad
结尾的操作/内核),但是(据我所知,这些并没有明确地“链接”在这个层面。似乎ops和它们的渐变之间的关联是在Python中定义的,通常是通过tf.RegisterGradient
或前面提到的tf.NoGradient
(参见例如here),以gen_
开头的Python模块是在C ++宏的帮助下自动生成);这些注册告知反向传播算法如何计算图的梯度。
那么,如何实际解决这个问题呢?好吧,你需要在C ++中创建至少一个op,并使用相应的内核实现前向传递所需的计算。然后,如果您想要使用的梯度计算可以用现有的TensorFlow操作表示(最有可能),您只需要在Python中调用tf.RegisterGradient
并在“标准”TensorFlow中进行计算。这是非常复杂的,但好消息是可能,甚至还有 example (尽管我认为他们有点忘记了梯度注册部分那个)!正如您将看到的,该过程涉及将新的操作代码编译到库中(顺便说一下,我不确定这些是否可以在Windows上运行),然后从Python加载(显然这涉及到{{{{{{ 3}}与manual compilation of TensorFlow)。一个可能更现实的例子可以在Bazel中找到,TensorFlow是结构化数据的扩展,它通过调用{{{4}}的宏定义TensorFlow Fold来注册(作为一个)一个自定义操作here 1}},然后在Python中加载库并通过他们自己定义的here注册函数注册其渐变here,该函数只调用here(tf.NotDifferentiable
的另一个名称)
tldr:这很难,但可以完成,甚至还有几个例子。
答案 1 :(得分:0)
如@jdehesa的评论中所述。您可以使用“替代渐变”来实现您的功能。如果我的数学不正确,请原谅我,但是我认为返回“ 1”的导数将是对反向传播没有影响的正确方法,同时仍然使学习通过。有关如何构造的信息,请参见here。我引用的示例更进一步,它允许您从python函数构造一个激活函数。因此,代替spiky
函数,用您的函数a
代替,并将其派生词d_spiky
替换为
def constant(x):
return 1
因此,在向前传递时,在图层中应用a
,在向后传递1
时,应该简单地将权重调整传递通过。
然后您可以使用此功能在Keras中创建Activation
层。