Я пытаюсь реализовать внимание local-p на основе этой статьи: https://arxiv.org/pdf/1508.04025.pdf В частности, уравнение (9) получает позицию выравнивания, основанную на взятии сигмоиды некоторых нелинейных функций, а затем умножении полученного значения с количеством временных шагов. Поскольку сигмоид возвращает значения от 0 до 1, это умножение дает действительный индекс от 0 до количества временных шагов. Я могу мягко обойти это, чтобы вывести прогнозируемую позицию, однако я не смог найти способ преобразовать это в целое число для использования в операциях среза / индексации, поскольку tf.cast () не дифференцируем. Другая проблема заключается в том, что производные позиции имеют форму (B, 1) и, следовательно, одну выровненную позицию для каждого примера в партии. См. Ниже, чтобы понять эти операции:
"""B = batch size, S = sequence length (num. timesteps), V = vocabulary size, H = number of hidden dimensions"""
class LocalAttention(Layer):
def __init__(self, size, window_width=None, **kwargs):
super(LocalAttention, self).__init__(**kwargs)
self.size = size
self.window_width = window_width # 2*D
def build(self, input_shape):
self.W_p = Dense(units=input_shape[2], use_bias=False)
self.W_p.build(input_shape=(None, None, input_shape[2])) # (B, 1, H)
self._trainable_weights += self.W_p.trainable_weights
self.v_p = Dense(units=1, use_bias=False)
self.v_p.build(input_shape=(None, None, input_shape[2])) # (B, 1, H)
self._trainable_weights += self.v_p.trainable_weights
super(Attention, self).build(input_shape)
def call(self, inputs):
sequence_length = inputs.shape[1]
## Get h_t, the current (target) hidden state ##
target_hidden_state = Lambda(function=lambda x: x[:, -1, :])(inputs) # (B, H)
## Get h_s, source hidden states ##
aligned_position = self.W_p(target_hidden_state) # (B, H)
aligned_position = Activation('tanh')(aligned_position) # (B, H)
aligned_position = self.v_p(aligned_position) # (B, 1)
aligned_position = Activation('sigmoid')(aligned_position) # (B, 1)
aligned_position = aligned_position * sequence_length # (B, 1)
Допустим, тензор aligned_position
имеет элементы [24.2, 15.1, 12.3] для размера партии = B = 3 для упрощения. Затем исходные скрытые состояния выводятся из входных скрытых состояний (B = 3, S, H), так что для первого примера мы берем временные шаги, начиная с 24, следовательно, что-то вроде first_batch_states = Lambda(function=lambda x: x[:, 24:, :])(inputs)
и так далее. Обратите внимание, что реализация local-p более сложная, чем эта, но я упростил ее здесь. Следовательно, основной проблемой является преобразование 24,2 в 24 без потери дифференцируемости или использование какой-либо маскирующей операции для получения индексов через скалярное произведение. Операция маски предпочтительна, так как нам придется делать это для каждого примера в пакетном режиме, и наличие цикла внутри пользовательского слоя Keras не является аккуратным. У вас есть идеи, как решить эту задачу? Буду благодарен за любые ответы и комментарии!