import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
from tensorflow.keras.applications import VGG16
from tensorflow.keras import backend as K
import numpy as np
import matplotlib.pyplot as plt
model = VGG16(weights='imagenet',include_top=False)
layer_name = 'block3_conv1'
filter_index = 0
layer_output = model.get_layer(layer_name).output
loss = K.mean(layer_output[:, :, :, filter_index])
# The call to `gradients` returns a list of tensors (of size 1 in this case)
# hence we only keep the first element -- which is a tensor.
grads = K.gradients(loss, model.input)[0]
# with tensorflow.GradientTape() as gtape:
# print(type(gtape))
# grads = gtape.gradient(loss, model.input)
# print(type(grads))
# We add 1e-5 before dividing so as to avoid accidentally dividing by 0.
grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)
iterate = K.function([model.input], [loss, grads])
# Let's test it:
loss_value, grads_value = iterate([np.zeros((1, 150, 150, 3))])
# We start from a gray image with some noise
input_img_data = np.random.random((1, 150, 150, 3)) * 20 + 128.
# Run gradient ascent for 40 steps
step = 1. # this is the magnitude of each gradient update
for i in range(40):
# Compute the loss value and gradient value
loss_value, grads_value = iterate([input_img_data])
# Here we adjust the input image in the direction that maximizes the loss
input_img_data += grads_value * step
def deprocess_image(x):
# normalize tensor: center on 0., ensure std is 0.1
x -= x.mean()
x /= (x.std() + 1e-5)
x *= 0.1
# clip to [0, 1]
x += 0.5
x = np.clip(x, 0, 1)
# convert to RGB array
x *= 255
x = np.clip(x, 0, 255).astype('uint8')
return x
def generate_pattern(layer_name, filter_index, size=150):
# Build a loss function that maximizes the activation
# of the nth filter of the layer considered.
layer_output = model.get_layer(layer_name).output
loss = K.mean(layer_output[:, :, :, filter_index])
# Compute the gradient of the input picture wrt this loss
grads = K.gradients(loss, model.input)[0]
# Normalization trick: we normalize the gradient
grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)
# This function returns the loss and grads given the input picture
iterate = K.function([model.input], [loss, grads])
# We start from a gray image with some noise
input_img_data = np.random.random((1, size, size, 3)) * 20 + 128.
# Run gradient ascent for 40 steps
step = 1.
for i in range(40):
loss_value, grads_value = iterate([input_img_data])
input_img_data += grads_value * step
img = input_img_data[0]
return deprocess_image(img)
plt.imshow(generate_pattern('block3_conv1', 0))
plt.show()
for layer_name in ['block1_conv1', 'block2_conv1', 'block3_conv1', 'block4_conv1']:
size = 64
margin = 5
# This a empty (black) image where we will store our results.
results = np.zeros((8 * size + 7 * margin, 8 * size + 7 * margin, 3))
for i in range(8): # iterate over the rows of our results grid
for j in range(8): # iterate over the columns of our results grid
# Generate the pattern for filter `i + (j * 8)` in `layer_name`
filter_img = generate_pattern(layer_name, i + (j * 8), size=size)
# Put the result in the square `(i, j)` of the results grid
horizontal_start = i * size + i * margin
horizontal_end = horizontal_start + size
vertical_start = j * size + j * margin
vertical_end = vertical_start + size
results[horizontal_start: horizontal_end, vertical_start: vertical_end, :] = filter_img
# Display the results grid
plt.figure(figsize=(20, 20))
plt.imshow(results.astype(np.uint8))
plt.show()
在这个实验中遇到的问题主要有下面几个:
(1)grads = K.gradients(loss, model.input)[0]报错显示RuntimeError: tf.gradients is not supported when eager execution is enabled. Use tf.GradientTape instead.。然后修改为
with tensorflow.GradientTape() as gtape:
grads = gtape.gradient(loss, model.input)
又报错说ValueError: Attempt to convert a value (None) with an unsupported type (<class 'NoneType'>) to a Tensor.产生这个问题的代码是grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)虽然我没看出来哪错了。
在百般折腾没折腾好之后我选择了将tensorflow2.x的代码和tensorflow1.x的代码做一下兼容,
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
没错,代码可以跑了,但是,又出现了第二个问题:
(2)出来的滤波器可视化跟书上的完全不一样
竟然是长这个样子的。
现在我还没有看出来问题在哪,要是明白的欢迎给我讲讲,谢谢~
经过大佬的讲解,发现是在显示的时候,result是numpy,numpy是float格式的,必须转成uint8格式才能显示出来,
所以倒数第二句改成 plt.imshow(results.astype(np.uint8))就可以来,结果是这样子的