Модель титров изображения Keras не компилируется из-за сцепленного слоя, когда mask_zero = True в предыдущем слое - PullRequest
0 голосов
/ 10 мая 2018

Я новичок в Keras и пытаюсь реализовать модель для проекта с субтитрами.

Я пытаюсь воспроизвести модель из Архитектура предварительного ввода субтитров изображения (Изображение взято из этой статьи: Где поместить изображение в генератор субтитров изображения ) (но с небольшим отличием: генерирование слова на каждом временном шаге вместо генерации одного слова в конце), в котором входные данные для LSTM на первом временном шаге являются встроенными функциями CNN.LSTM должен поддерживать переменную входную длину, и для этого я дополнил все последовательности нулями, чтобы у всех из них были максимальные временные шаги.

Код для модели, которую я сейчас имею, следующий:

def get_model(model_name, batch_size, maxlen, voc_size, embed_size, 
        cnn_feats_size, dropout_rate):

    # create input layer for the cnn features
    cnn_feats_input = Input(shape=(cnn_feats_size,))

    # normalize CNN features 
    normalized_cnn_feats = BatchNormalization(axis=-1)(cnn_feats_input)

    # embed CNN features to have same dimension with word embeddings
    embedded_cnn_feats = Dense(embed_size)(normalized_cnn_feats)

    # add time dimension so that this layer output shape is (None, 1, embed_size)
    final_cnn_feats = RepeatVector(1)(embedded_cnn_feats)

    # create input layer for the captions (each caption has max maxlen words)
    caption_input = Input(shape=(maxlen,))

    # embed the captions
    embedded_caption = Embedding(input_dim=voc_size,
                                 output_dim=embed_size,
                                 input_length=maxlen)(caption_input)

    # concatenate CNN features and the captions.
    # Ouput shape should be (None, maxlen + 1, embed_size)
    img_caption_concat = concatenate([final_cnn_feats, embedded_caption], axis=1)

    # now feed the concatenation into a LSTM layer (many-to-many)
    lstm_layer = LSTM(units=embed_size,
                      input_shape=(maxlen + 1, embed_size),   # one additional time step for the image features
                      return_sequences=True,
                      dropout=dropout_rate)(img_caption_concat)

    # create a fully connected layer to make the predictions
    pred_layer = TimeDistributed(Dense(units=voc_size))(lstm_layer)

    # build the model with CNN features and captions as input and 
    # predictions output
    model = Model(inputs=[cnn_feats_input, caption_input], 
                  outputs=pred_layer)

    optimizer = Adam(lr=0.0001, 
                     beta_1=0.9, 
                     beta_2=0.999, 
                     epsilon=1e-8)

    model.compile(loss='categorical_crossentropy',optimizer=optimizer)
    model.summary()

    return model

Модель (как указано выше) компилируется без каких-либо ошибок (см. сводка модели ), и мне удалось обучить ее, используя мои данные.Однако, это не принимает во внимание тот факт, что мои последовательности заполнены нулями, и результаты не будут точными из-за этого.Когда я пытаюсь изменить слой Embedding для поддержки маскирования (также убедившись, что я использую voc_size + 1 вместо voc_size, как это упомянуто в документации) следующим образом:

embedded_caption = Embedding(input_dim=voc_size + 1,
                             output_dim=embed_size,
                             input_length=maxlen, mask_zero=True)(caption_input)

я получаю следующееошибка:

Traceback (most recent call last):
  File "/export/home/.../py3_env/lib/python3.5/site-packages/tensorflow/python/framework/ops.py", line 1567, in _create_c_op
    c_op = c_api.TF_FinishOperation(op_desc)
tensorflow.python.framework.errors_impl.InvalidArgumentError: Dimension 0 in both shapes must be equal, but are 200 and 1. Shapes are [200] and [1]. for 'concatenate_1/concat_1' (op: 'ConcatV2') with input shapes: [?,1,200], [?,25,1], [] and with computed input tensors: input[2] = <1>

Я не знаю, почему он говорит, что форма второго массива - [?, 25, 1], так как я печатаю его форму перед объединением, и это [?, 25,200] (так и должно быть).Я не понимаю, почему возникла проблема с моделью, которая компилируется и работает без этого параметра, но я предполагаю, что мне чего-то не хватает.

Я также подумывал об использовании маскирующего слоя вместо этого.of mask_zero = True, но это должно быть до внедрения, а в документации сказано, что слой внедрения должен быть первым слоем в модели (после ввода).

Могу ли я что-то изменить, чтобы это исправить, или есть обходной путь?

1 Ответ

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

Неравномерная ошибка формы относится к маске, а не к тензорам / входам. С concatenate поддержкой маскирования необходимо обрабатывать распространение маски . У вашего final_cnn_feats нет маски (None), в то время как у вашего embedded_caption есть маска формы (?, 25). Вы можете узнать это, выполнив:

print(embedded_caption._keras_history[0].compute_mask(caption_input))

Поскольку final_cnn_feats не имеет маски, concatenate будет присвоить ей ненулевую маску для правильного распространения маски. Хотя это и правильно, форма маски, однако, имеет ту же форму, что и final_cnn_feats, то есть (?, 1, 200), а не (?, 1), т.е. маскирует все элементы на всех временных шагах, а не только на всех временных шагах. Вот откуда возникает неравная ошибка формы ((?, 1, 200) против (?, 25)).

Чтобы исправить это, вам нужно дать final_cnn_feats правильную / подходящую маску. Сейчас я не знаком с вашим проектом здесь. Один из вариантов - применить Masking слой к final_cnn_feats, поскольку он предназначен для маскирования временного шага (ов) .

final_cnn_feats = Masking()(RepeatVector(1)(embedded_cnn_feats))

Это может быть корректно, только если не все 200 объектов в final_cnn_feats равны нулю, т. Е. Всегда есть хотя бы одно ненулевое значение в final_cnn_feats. С этим условием слой Masking даст маску (?, 1) и не замаскирует ни одного временного шага в final_cnn_feats.

...