在TF 2.0中计算GradCam的梯度

时间:2020-02-06 09:57:36

标签: python-3.x tensorflow keras

我已将Python中的tensorflow从1.14更新为2.0。现在我在渐变计算方面遇到了问题,以便查看图层的GradCam可视化效果。

例如,对于一个名为my_cnn_model的模型,该模型已经适用于数据,可以解决三个类别的分类问题。例如,如果要为名为“ conv2d_3”的给定层“计算gradCam”,我将从1.14中的以下内容开始:

layer_conv = my_cnn_model.get_layer( "conv2d_3" )

#I want it with respect to the first class (so 0), because for example it might have been the model prediction for that image, so I check the proba for that class :
final_layer = my_cnn_model.output[:, 0]

#Then I computed the gradients like that :
grads = keras.backend.gradients( final_layer, layer_conv.output )[0]
print(grads)

最后一个声明(打印)会说(形状是我所使用的cnn的特定形状,但不要紧):

Tensor("gradients/max_pooling2d/MaxPool_grad/MaxPoolGrad:0", shape=(?, 76, 76, 64), dtype=float32)

现在,当我使用tf 2.0时:grads计算部分,所以:

grads = keras.backend.gradients( final_layer, layer_conv.output )[0]

不再工作,出现错误:

RuntimeError: tf.gradients is not supported when eager execution is enabled. Use tf.GradientTape instead.

我已经搜索过,发现了

with tf.GradientTape() as tape:
...

但是同样的我得到了错误,或者我没有得到相同的输出Tensor("gradients/max_pooling2d/MaxPool_grad/MaxPoolGrad:0", shape=(?, 76, 76, 64), dtype=float32),所以我的gradcam功能的其余部分不起作用。

我该如何计算grads,这当然与我的1.14 tf env相似?我会错过一些琐碎的事情吗?

编辑:我使用函数式API,自己的CNN或tf.keras中已在此处使用的“转移学习”模型,顶部是经过修改/添加的层。

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

如果您对急切模式不感兴趣,例如到处使用旧代码,则可以简单地禁用急切执行。

here所述:

import tensorflow as tf
tf.compat.v1.disable_eager_execution()

另一方面,如果您想保持急切模式,或者在另一件事困扰您的代码时,则可以:

#you need a persistent tape if you're calling many gradients instead of just one
with tf.GradientTape(persistent = True) as tape:

    #must "watch" all variables that are not "trainable weights" 
    #if you are using them for gradients
    tape.watch(layer_conv.output)

    #if the input data should be watched (you're getting the gradients related to the inputs)
    input_tensor = tf.constant(input_data)
    tape.watch(input_tensor)

    #must do the entire prediction inside this tape block.
    #it would be better if you could make your model output all tensors of interest
    #not sure if you can do "some_layer.output" in eager mode for this purpose
    model_outputs = model(input_tensor) 

#finally, outside the block you can get the gradients
g1 = tape.gradient(model_outputs, layer_conv.output) 
    #again, maybe you need this layer output to be "actually output" 
    #instead of gotten from the layer like this

g2 = tape.gradient(some_output, input_tensor)

g3...
g4...

#finally delete the persistent tape
del tape