UPDATE 2
此外tf.py_func https://www.tensorflow.org/api_docs/python/tf/py_func,现在有一个有关如何添加自定义操作的官方指南 https://www.tensorflow.org/extend/adding_an_op.
UPDATE
See 这个问题 https://stackoverflow.com/questions/39048984/tensorflow-how-to-write-op-with-gradient-in-python有关纯粹用 Python 编写带有渐变的自定义操作而不需要重建任何内容的示例。请注意,该方法有一些限制(请参阅文档tf.py_func https://www.tensorflow.org/api_docs/python/tf/py_func).
不完全是问题的解决方案,但仍然是一种答案,而且评论太长。
这甚至不是 Keras 问题,而是 TensorFlow 问题。每个操作都定义了自己的梯度计算,该计算在反向传播过程中使用。你我really想要类似的东西,你需要自己将操作实现到 TensorFlow 中(这不是一件容易的事)并定义你想要的梯度 - 因为你不能有“无梯度”,如果有的话它会是 1 或 0 (否则你不能继续反向传播)。有一个tf.NoGradient https://www.tensorflow.org/api_docs/python/tf/NoGradientTensorFlow 中的函数会导致操作传播零,但我不认为它意味着/可以在 TensorFlow 自己的内部结构之外使用。
UPDATE
好的,更多一点背景信息。 TensorFlow 图是由以下内容构建的ops,它们是由kernels;这基本上是一个 1 对 1 的映射,除了一个操作可能有一个 CPU 和一个 GPU 内核,因此存在差异。 TensorFlow支持的操作集通常是静态的,我的意思是它可以随着新版本的变化而改变,但原则上你不能添加自己的操作,因为图的操作进入Protobuf序列化格式,所以如果你制作了自己的操作那么您将无法共享您的图表。然后使用宏在 C++ 级别定义操作REGISTER_OP
(例如参见here https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/ops/nn_ops.cc),以及内核REGISTER_KERNEL_BUILDER
(例如参见here https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/kernels/conv_ops_fused.cc).
现在,渐变在哪里发挥作用?有趣的是,op 的梯度不是在 C++ 级别定义的;那里are实现其他操作梯度的操作(和内核)(如果您查看之前的文件,您会发现名称以结尾的操作/内核Grad
),但是(据我所知)这些在这个级别上没有明确的“链接”。操作和梯度之间的关联似乎是在 Python 中定义的,通常通过tf.RegisterGradient https://www.tensorflow.org/api_docs/python/tf/RegisterGradient或前述的tf.NoGradient https://www.tensorflow.org/api_docs/python/tf/NoGradient(例如参见here https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/ops/nn_grad.py, Python 模块开头gen_
在 C++ 宏的帮助下自动生成);这些注册告知反向传播算法如何计算图的梯度。
那么,如何实际解决这个问题呢?那么,您需要在 C++ 中创建至少一个操作,并使用相应的内核来实现您的前向传递所需的计算。然后,如果您想要使用的梯度计算可以用现有的 TensorFlow 操作来表达(这是最有可能的),您只需要调用tf.RegisterGradient https://www.tensorflow.org/api_docs/python/tf/RegisterGradient在 Python 中并在“标准”TensorFlow 中进行计算。这相当复杂,但好消息是possible,甚至还有一个example https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/adding_an_op为此(尽管我认为他们有点忘记了其中的梯度注册部分)!正如您将看到的,该过程涉及将新的操作代码编译到一个库中(顺便说一句,我不确定其中是否可以在 Windows 上运行),然后从 Python 加载该库(显然这涉及到经历以下痛苦的过程)手动编译TensorFlow https://www.tensorflow.org/install/install_sources with Bazel https://bazel.build)。一个可能更现实的例子可以在TensorFlow 折叠 https://github.com/tensorflow/fold,TensorFlow 的扩展,适用于结构化数据,可注册(从一个)一个自定义操作here https://github.com/tensorflow/fold/blob/master/tensorflow_fold/loom/deserializing_weaver_op.cc通过宏定义here https://github.com/tensorflow/fold/blob/master/tensorflow_fold/loom/weaver_op_base.h那个叫REGISTER_OP
,然后在 Python 中加载库并注册其梯度here https://github.com/tensorflow/fold/blob/master/tensorflow_fold/loom/deserializing_weaver_op.py通过自己定义的注册函数here https://github.com/tensorflow/fold/blob/master/tensorflow_fold/loom/weaver_op_base.py这只是调用tf.NotDifferentiable https://www.tensorflow.org/api_docs/python/tf/NoGradient(另一个名称为tf.NoGradient https://www.tensorflow.org/api_docs/python/tf/NoGradient)
tldr:这相当困难,但它can已经完成了,甚至还有几个例子。