我想在TensorFlow中实现在这个 Paper 中引入的“引导反向传播”技术,并在此 recipe 中进行了描述。
计算上意味着当我计算例如输入wrt的梯度时。 NN的输出,我将不得不修改每个RELU单元计算的梯度。具体地说,这些单元上的反向传播信号必须在零上设置阈值,以使该技术起作用。换句话说,必须忽略RELU的负面偏导数。
鉴于我有兴趣仅在测试示例中应用这些梯度计算,即我不想更新模型的参数 - 我该怎么做?
到目前为止,我尝试过两件事(不成功):
我用两种方法都失败了,因为他们需要一些目前我没有的TF内部知识。
任何人都可以建议任何其他路线,或草拟代码?
非常感谢。
使用ops.RegisterGradient
和tf.Graph.gradient_override_map
的更好的解决方案(您的方法1)。它们一起覆盖预定义Op的梯度计算,例如,仅使用python代码在gradient_override_map
上下文中重新调用。
@ops.RegisterGradient("GuidedRelu")
def _GuidedReluGrad(op, grad):
return tf.where(0. < grad, gen_nn_ops._relu_grad(grad, op.outputs[0]), tf.zeros(grad.get_shape()))
...
with g.gradient_override_map({'Relu': 'GuidedRelu'}):
y = tf.nn.relu(x)
这是引导relu的完整示例实现:https://gist.github.com/falcondai/561d5eec7fed9ebf48751d124a77b087
更新:在Tensorflow> = 1.0中,tf.select
重命名为tf.where
。我相应地更新了片段。 (感谢@sbond将此引起我的注意:)
tf.gradients
具有可用于此目的的grad_ys
参数。假设您的网络只有一个relu
层,如下所示:
before_relu = f1(inputs, params)
after_relu = tf.nn.relu(before_relu)
loss = f2(after_relu, params, targets)
首先,计算导数到after_relu
。
Dafter_relu = tf.gradients(loss, after_relu)[0]
然后对您发送的渐变进行阈值处理。
Dafter_relu_thresholded = tf.select(Dafter_relu < 0.0, 0.0, Dafter_relu)
计算w.r.t到params
的实际梯度。
Dparams = tf.gradients(after_relu, params, grad_ys=Dafter_relu_thresholded)
对于具有许多relu
图层的网络,您可以轻松扩展此相同方法。