Для примера, у меня есть вход, состоящий из 2 изображений, общей формы (2 299 299,3). Я пытаюсь применить inceptionv3 к каждому изображению, а затем обработать вывод с помощью LSTM. Я использую маскирующий слой, чтобы исключить обработку пустого изображения (указано ниже).
Код:
import numpy as np
from keras import backend as K
from keras.models import Sequential,Model
from keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D, BatchNormalization, \
Input, GlobalAveragePooling2D, Masking,TimeDistributed, LSTM,Dense,Flatten,Reshape,Lambda, Concatenate
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.applications import inception_v3
IMG_SIZE=(299,299,3)
def create_base():
base_model = inception_v3.InceptionV3(weights='imagenet', include_top=False)
x = GlobalAveragePooling2D()(base_model.output)
base_model=Model(base_model.input,x)
return base_model
base_model=create_base()
#Image mask to ignore images with pixel values of -1
IMAGE_MASK = -2*np.expand_dims(np.ones(IMG_SIZE),0)
final_input=Input((2,IMG_SIZE[0],IMG_SIZE[1],IMG_SIZE[2]))
final_model = Masking(mask_value = -2.)(final_input)
final_model = TimeDistributed(base_model)(final_model)
final_model = Lambda(lambda x: x, output_shape=lambda s:s)(final_model)
#final_model = Reshape(target_shape=(2, 2048))(final_model)
#final_model = Masking(mask_value = 0.)(final_model)
final_model = LSTM(5,return_sequences=False)(final_model)
final_model = Model(final_input,final_model)
#Create a sample test image
TEST_IMAGE = np.ones(IMG_SIZE)
#Create a test sample input, consisting of a normal image and a masked image
TEST_SAMPLE = np.concatenate((np.expand_dims(TEST_IMAGE,axis=0),IMAGE_MASK))
inp = final_model.input # input placeholder
outputs = [layer.output for layer in final_model.layers] # all layer outputs
functors = [K.function([inp]+ [K.learning_phase()], [out]) for out in outputs]
layer_outs = [func([np.expand_dims(TEST_SAMPLE,0), 1.]) for func in functors]
Это не работает правильно. В частности, модель должна маскировать часть ввода IMAGE_MASK, но вместо этого она обрабатывает ее с самого начала (давая ненулевой вывод). вот подробности:
layer_out [-1], вывод LSTM в порядке:
[array([[-0.15324114, -0.09620268, -0.01668587, 0.07938149, -0.00757846]], dtype=float32)]
layer_out [-2] и layer_out [-3], ввод LSTM неправильный , он должен иметь все нули во втором массиве:
[array([[[ 0.37713543, 0.36381325, 0.36197218, ..., 0.23298527,
0.43247852, 0.34844452],
[ 0.24972123, 0.2378867 , 0.11810347, ..., 0.51930511,
0.33289322, 0.33403745]]], dtype=float32)]
layer_out [-4], вход в CNN правильно маскируется:
[[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.],
...,
[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]]],
[[[-0., -0., -0.],
[-0., -0., -0.],
[-0., -0., -0.],
...,
[-0., -0., -0.],
[-0., -0., -0.],
[-0., -0., -0.]],
Обратите внимание, что код, кажется, работает правильно с более простой base_model, такой как:
def create_base():
input_layer=Input(IMG_SIZE)
base_model=Flatten()(input_layer)
base_model=Dense(2048)(base_model)
base_model=Model(input_layer,base_model)
return base_model
Я исчерпал большинство онлайн-ресурсов по этому вопросу. Перестановки этого вопроса задавались на github Кераса, такие как здесь , здесь и здесь , но я не могу найти никакого конкретного решения.
Ссылки показывают, что проблемы, по-видимому, связаны с сочетанием TimeDistributed, применяемого к BatchNormalization, и хакерские исправления либо слоя идентификации Lambda, либо слоев Reshape устраняют ошибки, но, похоже, не выводят правильную модель.
Я пытался заставить базовую модель поддерживать маскирование с помощью:
base_model.__setattr__('supports_masking',True)
и я также попытался применить слой идентификации с помощью:
TimeDistributed(Lambda(lambda x: base_model(x), output_shape=lambda s:s))(final_model)
но, похоже, ничего из этого не работает. Отметьте, что я хотел бы, чтобы окончательная модель была обучаемой, в частности, ее часть CNN должна оставаться обучаемой.