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