【发布时间】:2019-11-02 07:44:54
【问题描述】:
我正在尝试基于这篇论文实现local-p attention:https://arxiv.org/pdf/1508.04025.pdf 具体来说,等式(9)基于对一些非线性函数取sigmoid,然后将结果乘以时间步长。由于 sigmoid 返回的值介于 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 attention的实现比这个要复杂一些,我这里简化了。因此,主要挑战是将 24.2 转换为 24 而不会失去可微性,或者使用某种掩码操作通过点积获取索引。遮罩操作是首选,因为我们必须为每个示例批量执行此操作,并且在自定义 Keras 层内有一个循环并不整洁。您对如何完成此任务有任何想法吗?我将不胜感激任何答案和 cmets!
【问题讨论】:
-
请问您为什么不直接使用论文的
equation-10?它会不会解决您的可微性问题,因为这个方程会根据高斯生成aligned_position周围的位置。 -
等式(9)上面的段落表明源隐藏状态被视为集合[p_t - D,p_t + D]。我一直在寻找高斯步骤之前的切片操作。我使用 lambda 函数实现了高斯步骤,现在可以将其应用于 所有 隐藏状态,结果非常好。所以谢谢你的建议!同样,高斯分布解决了可微性问题,但这种方法仍然不等同于论文建议的方法,因为它将高斯步骤应用于源隐藏状态的切片版本。至少在我的理解中......
-
你的切片问题能解决吗?
-
是的,但是是间接的。如果有人试图做类似的事情,我会在下面添加一个答案。
标签: python tensorflow recurrent-neural-network tf.keras