Keras TimeDistributed не маскирует модель CNN - PullRequest
0 голосов
/ 30 апреля 2018

Для примера, у меня есть вход, состоящий из 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 должна оставаться обучаемой.

Ответы [ 3 ]

0 голосов
/ 09 мая 2018

Кажется, работает как задумано. Маскировка в Keras не дает нулей, как вы ожидаете, вместо этого она пропускает временные шаги, которые маскируются в верхних слоях, таких как LSTM и расчет потерь. В случае RNN, Keras (по меньшей мере, тензорный поток) реализован так, что переносятся состояния с предыдущего шага, tenorflow_backend.py . Это делается частично для сохранения форм тензоров при задании динамического ввода.

Если вы действительно хотите нули, вам придется реализовать собственный слой с логикой, аналогичной маскированию, и возвращать нули в явном виде. Чтобы решить вашу проблему, вам нужна маска перед финальным слоем LSTM с использованием final_input:

class MyMask(Masking):
   """Layer that adds a mask based on initial input."""
   def compute_mask(self, inputs, mask=None):
      # Might need to adjust shapes
      return K.any(K.not_equal(inputs[0], self.mask_value), axis=-1)

   def call(self, inputs):
      # We just return input back
      return inputs[1]

   def compute_output_shape(self, input_shape):
     return input_shape[1]
final_model = MyMask(mask_value=-2.)([final_input, final_model])

Вероятно, вы можете прикрепить маску более простым способом, но этот пользовательский класс по существу добавляет маску на основе ваших начальных входов и выводит тензор Кераса, который теперь имеет маску.

Ваш LSTM будет игнорировать в вашем примере второе изображение. Для подтверждения вы можете return_sequences=True и проверить, что выходные данные для 2 изображений идентичны.

0 голосов
/ 21 августа 2018

Я пытаюсь реализовать то же самое, я хочу, чтобы мои последовательности LSTM имели переменные размеры. Однако я даже не могу реализовать вашу оригинальную модель. Я получаю следующую ошибку: TypeError: Слой input_1 не поддерживает маскирование, но был передан input_mask: Tensor ("time_distributed_1 / Reshape_1: 0", shape = (?, 100, 100), dtype = bool) Я использую тензор потока 1.10 и керас 2.2.2

Я решил проблему, добавив второй вход, маску, чтобы указать, какие временные шаги следует учитывать для LSTM. Таким образом, последовательность изображений всегда имеет одинаковое количество временных шагов, CNN всегда генерирует выходные данные, но некоторые из них игнорируются для входа LSTM. Однако отсутствующие изображения необходимо тщательно выбирать, чтобы не повлиять на нормализацию партии.

def LSTM_CNN(params):
resnet = ResNet50(include_top=False, weights='imagenet', pooling = 'avg')
input_layer = Input(shape=(params.numFrames, params.height, params.width, 3))
input_mask = Input(shape=(params.numFrames,1))
curr_layer = TimeDistributed(resnet)(input_layer)    
resnetOutput = Dropout(0.5)(curr_layer)
curr_layer = multiply([resnetOutput,input_mask])
cnn_output = curr_layer
curr_layer = Masking(mask_value=0.0)(curr_layer)
lstm_out = LSTM(256, dropout=0.5)(curr_layer)
output = Dense(output_dim=params.numClasses, activation='sigmoid')(lstm_out)
model = Model([input_layer, input_mask], output)
return model
0 голосов
/ 07 мая 2018

Не совсем уверен, что это будет работать, но на основе комментария , сделанного здесь , с более новой версией tenorflow + keras это должно работать:

final_model = TimeDistributed(Flatten())(final_input)
final_model = Masking(mask_value = -2.)(final_model)
final_model = TimeDistributed(Reshape(IMG_SIZE))(final_model)
final_model = TimeDistributed(base_model)(final_model)
final_model = Model(final_input,final_model)

Я взглянул на исходный код маскирования и заметил, что Керас создает тензор маски, который уменьшает только последнюю ось. Пока вы имеете дело с 5D-тензорами, это не вызовет проблем, но когда вы уменьшите размеры для LSTM, этот маскирующий тензор станет несовместимым.

Выполнение первого шага выравнивания перед маскированием гарантирует, что тензор маскирования работает правильно для 3D-тензоров. Затем вы снова расширяете изображение до исходного размера.


Я, вероятно, скоро попытаюсь установить более новые версии, чтобы протестировать его сам, но эти процедуры установки вызвали слишком много проблем, и я сейчас в центре чего-то важного.

На моей машине этот код компилируется, но эта странная ошибка появляется во время предсказания (см. Ссылку в первой строке этого ответа).


Создание модели для прогнозирования промежуточных слоев

По коду, который я видел, я не уверен, что маскирующая функция хранится внутри тензоров. Я не знаю точно, как это работает, но, похоже, это происходит отдельно от построения функций внутри слоев.

Итак, попробуйте использовать стандартную модель keras, чтобы сделать прогнозы:

inp = final_model.input                                           # input placeholder
outputs = [layer.output for layer in final_model.layers]          # all layer outputs

fullModel = Model(inp,outputs)
layerPredictions = fullModel.predict(np.expand_dims(TEST_SAMPLE,0))

print(layerPredictions[-2])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...