简体   繁体   English

如何在 TF2.0 中用 GradientTape 替换 Keras 的 gradients() function?

[英]How to replace Keras' gradients() function with GradientTape in TF2.0?

With the "old" Keras library I created heatmaps for my CNNs using the keras.backend.gradients() function, like this:使用“旧”Keras 库,我使用keras.backend.gradients() function 为我的 CNN 创建了热图,如下所示:

# load model and image, then predict the class this image belongs to
model = load_model(os.path.join(model_folder, "custom_model.h5"))
image = image.load_img(image_path)
img_tensor = image.img_to_array(image)
img_tensor = np.expand_dims(img_tensor, axis=0)
img_tensor = preprocess_input(img_tensor)

preds = model.predict(img_tensor)
model_prediction = model.output[:, np.argmax(preds[0])]

# Calculate pooled grads for heatmap
conv_layer = model.get_layer("block5_conv3")  # last conv. layer
grads = K.gradients(model_prediction, conv_layer.output)[0]
pooled_grads = K.mean(grads, axis=(0, 1, 2))

# Get values of pooled grads and model conv. layer output as Numpy arrays
input_layer = model.get_layer("model_input")
iterate = K.function([input_layer], [pooled_grads, conv_layer.output[0]])
pooled_grads_value, conv_layer_output_value = iterate([img_tensor])

# Continue with heatmap generation ...

Now I switched to TF2.0 and it's built-in Keras implementation.现在我切换到 TF2.0,它内置了 Keras 实现。 Everything works fine, however, using that code I get the following error when calling K.gradients() :一切正常,但是,使用该代码调用K.gradients()时出现以下错误:

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

I did some research and tried to understand how I can make use of GradientTape , but unfortunately I don't know much about TF nor TF2.0 - I always worked with Keras.我做了一些研究并试图了解如何使用GradientTape ,但不幸的是,我对 TF 和 TF2.0 了解不多 - 我一直使用 Keras。 Can you guys guide me how I can make this gradient calculation work again with my setup?你们能指导我如何通过我的设置使这个梯度计算再次工作吗?

Here is a solution to your problem.这是您的问题的解决方案。 It implies creating a model that outputs both conv_output and predictions, so we can apply the GradientTape properly.这意味着创建一个同时输出 conv_output 和预测的 model,因此我们可以正确应用GradientTape

Didn't have your model/data so I took a ResNet50 and random values.没有你的模型/数据,所以我拿了一个 ResNet50 和随机值。

import numpy as np
import tensorflow as tf

model = tf.keras.applications.resnet50.ResNet50()
img_tensor = np.random.random((1, 224, 224, 3))

conv_layer = model.get_layer('conv5_block3_1_conv')

heatmap_model = tf.keras.models.Model(
    [model.inputs], [model.get_layer('conv5_block3_1_conv').output, model.output]
)

with tf.GradientTape() as tape:
    conv_output, predictions = heatmap_model(img_tensor)
    loss = predictions[:, np.argmax(predictions[0])]

grads = tape.gradient(loss, conv_output)

You cannot use K.function as it won't work when eager execution is enabled, which is done by default.您不能使用 K.function,因为它在启用急切执行时不起作用,这是默认完成的。 K.function from my limited understanding, can be used on a static graph, which occurs when eager execution is disabled.从我有限的理解来看,K.function 可用于 static 图,该图在禁用急切执行时发生。

tensorflow.compat.v1.disable_eager_execution()

Above block can alleviate some issues but create new ones.上面的块可以缓解一些问题,但会产生新的问题。 Better workaround is to use a guided gradients approach, where you only consider positive gradients and positive convolution outputs to obtain guided gradients.更好的解决方法是使用引导梯度方法,您只考虑正梯度和正卷积输出来获得引导梯度。

castConvOutputs = tensorflow.cast(conv_output > 0, "float32")
castGrads = tensorflow.cast(grads > 0, "float32")
guidedGrads = castConvOutputs * castGrads * grads

# My goal was to create the class activation map for single image, so we are skipping axis=0 which is meant to have the batch_size of images at axis=0
convOutputs = conv_output[0]
guidedGrads = guidedGrads[0]

Finally I took the mean along the width and height of the image (pooled guided gradients) and summed the mathematically weighted activations across all channels (depth layer) to create the class activation map.最后,我沿图像的宽度和高度取平均值(合并引导梯度),并对所有通道(深度层)的数学加权激活求和,以创建 class 激活 map。

weights = tensorflow.reduce_mean(guidedGrads, axis=(0, 1))
cam = tensorflow.reduce_sum(tensorflow.multiply(weights, convOutputs), axis=-1)

This can later be modified with a colormap of choice with a cv2.applycolormap after normalizing and scaling to 0-255 integer range.在标准化和缩放到 0-255 integer 范围后,稍后可以使用 cv2.applycolormap 选择颜色图来修改它。

Credits: Adrian Rosebrock blog致谢:Adrian Rosebrock 博客

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM