Проблема Grad-CAM с Keras на VGG16 с тонкой настройкой
В настоящее время я изучаю книгу Франсуа Шоле "Deep Learning with Python" и обучаю ConvNet тонкой настройке для классификации кошек и собак. И это нормально, все отлично работает.
А несколькими главами позже представлен алгоритм Grad-CAM для предварительного просмотра того, на что "смотрит" ConvNet. И снова мой код работает отлично, и результат отличный (с неизмененным набором данных VGG16).
Поэтому я решил попробовать алгоритм Grad-CAM в сети, которую я ранее обучал распознавать собак и кошек (тонко настроенный VGG16). И, увы, я не могу заставить это работать...
Вызов функции градиента всегда возвращает None
,
Я пробовал разные входные изображения, и, поскольку проблема продолжала показывать, я решил перенастроить свою ConvNet, чтобы она была более идентичной исходному VGG16.
Я изменил свою конфигурацию ConvNet для вывода категориального результата (с 2 категориями вместо 1000) из softmax вместо уникального значения из сигмоида, и затем я попытался снова, но проблема остается той же, и градиент возвращается None
не важно что.
Есть еще 2 различия между моей моделью и VGG16:
- мой вход (150, 150), тогда как вход VGG (224, 224). Но я не понимаю, почему это может быть источником проблемы.
- моя модель построена на VGG без верхних слоев, и, таким образом, первый "слой" моей модели также является моделью (последний сверточный слой должен быть доступен через
model.get_layer('vgg16').get_layer('block5_conv3')
) тогда как когда я использую VGG16, слои доступны напрямую (последний сверточный слой может быть доступен с помощьюmodel.get_layer('block5_conv3')
).
Вот мой код:
from keras import models, layers, optimizers
##model = VGG16(weights='imagenet') # it works with this one
model = models.load_model('DL_CONVNET_05.h5') # but not with my own model
model.compile(optimizer=optimizers.RMSprop(lr=1e-5), loss='categorical_crossentropy', metrics=['acc']) # also tried with a binary_crossentropy
# Preprocess an input image for VGG16
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input, decode_predictions
import numpy as np
img_path = 'datasets/test/dogs/dog.1700.jpg'
img = image.load_img(img_path, target_size=(150,150)) # (224,224) in the original VGG16 input but (150,150) in my own fined-tuned ConvNet
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
preds = model.predict(x)
print("Predicted values:", preds)
print("Predicted class:", np.argmax(preds[0]))
# Setting up the Grad-CAM algorithm
import keras.backend as K
test_output = model.output[:,np.argmax(pred[0])] # test against the predicted class (can be changed to 0 for Cat or 1 for Dog)
# with the original Grad-CAM with the original VGG16,
# the following line directly get the 'block5_conv3' layer,
# but as my own model is built from a VGG16 without the top layers
# on which I added some tuned layer I can't access it directly
last_conv_layer = model.get_layer('vgg16').get_layer('block5_conv3')
ЗДЕСЬ ПРОБЛЕМА... грады возвращаются None
grads = K.gradients( test_output, last_conv_layer.output)[0]
print("grads:",grads)
pooled_grads = K.mean(grads, axis=(0,1,2))
iterate = K.function([model.input], [pooled_grads, last_conv_layer.output[0]])
pooled_grads_value, conv_layer_output_value = iterate([x])
for i in range(512): # 512 is the number of channels in block5_conv3
conv_layer_output_value[:,:,i] *= pooled_grads_value[i]
heatmap = np.mean(conv_layer_output_value, axis=-1)
# etc. etc... but as the problem is here I guess the rest of the code is useless.
Я склонен думать, что это может быть потому, что я ловлю вывод, используя last_conv_layer = model.get_layer('vgg16').get_layer('block5_conv3')
(который является вложенным слоем внутри модели vgg16, который, в свою очередь, находится внутри моей модели) вместо last_conv_layer = model.get_layer('block5_conv3')
(когда vgg16 - непосредственно используемая модель), но я не уверен, и я не знаю, как это исправить.
Кроме того, это может быть связано с сообщенной проблемой тензорного потока ( https://github.com/tensorflow/tensorflow/issues/783), но я не уверен, и подтверждение от кого-то с более глубоким пониманием проблемы будет более чем приветствуется
У вас есть идея или предложение?
Спасибо за помощь.