微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Keras AdditiveAttention 层的输出形状

如何解决Keras AdditiveAttention 层的输出形状

尝试使用 AdditiveAttention 中的 Keras 层。关于 tensorflow 教程中层的手动实现 https://www.tensorflow.org/tutorials/text/nmt_with_attention

import tensorflow as tf 

class BahdanauAttention(tf.keras.layers.Layer):
  def __init__(self,units):
    super(BahdanauAttention,self).__init__()
    self.W1 = tf.keras.layers.Dense(units)
    self.W2 = tf.keras.layers.Dense(units)
    self.V = tf.keras.layers.Dense(1)

  def call(self,query,values):
    query_with_time_axis = tf.expand_dims(query,1)
    score = self.V(tf.nn.tanh(
        self.W1(query_with_time_axis) + self.W2(values)))
    attention_weights = tf.nn.softmax(score,axis=1)

    # context_vector shape after sum == (batch_size,hidden_size)
    context_vector = attention_weights * values
    context_vector = tf.reduce_sum(context_vector,axis=1)
    return context_vector,attention_weights

context_vector 的形状是 (batch_size,units)

而使用与 AdditiveAttention 相同的 keras built-in

from tensorflow.keras.layers import AdditiveAttention

shapecontext_vector = [batch_size,Tq,dim]

任何有关造成这种 OP shape 差异的原因的建议都会有所帮助。

解决方法

除了一些变化外,两种实现方式都非常相似。该教程中 BahdanauAttention 的实现是一种简化和改编的版本,并使用了一些线性变换。您想知道的 context_vector 的返回形状只不过是输入数据形状的问题。下面是一些演示,让我们看看教程实现:

class BahdanauAttention(tf.keras.layers.Layer):
  def __init__(self,units):
    super(BahdanauAttention,self).__init__()
    self.W1 = tf.keras.layers.Dense(units)
    self.W2 = tf.keras.layers.Dense(units)
    self.V  = tf.keras.layers.Dense(1)

  def call(self,query,values):
    query_with_time_axis = tf.expand_dims(query,1)
    score = self.V(tf.nn.tanh(self.W1(query_with_time_axis) + self.W2(values)))
    attention_weights = tf.nn.softmax(score,axis=1)
    context_vector = attention_weights * values
    context_vector = tf.reduce_sum(context_vector,axis=1)
    return context_vector,attention_weights

现在,我们向它传递一些输入,3D2D

attention_layer = BahdanauAttention(10)

y = tf.random.uniform((2,60,512))  
out,attn = attention_layer(y,y)
out.shape,attn.shape
(TensorShape([2,512]),TensorShape([2,2,1]))

y = tf.random.uniform((2,1]))

现在,将相同的输入传递给内置的 AdditiveAttention,看看我们会得到什么

buit_attn = tf.keras.layers.AdditiveAttention()

y = tf.random.uniform((2,attn = buit_attn([y,y],return_attention_scores=True)
out.shape,60]))

y = tf.random.uniform((2,2]))

因此,context_vector 的形状在此处具有可比性,但与 attention_weights 的形状不同。原因是,正如我们所提到的,我相信该教程的实现有点修改和采用。如果我们查看 BahdanauAttentionAdditiveAttention 的计算,我们会得到:

  1. queryvalue 分别重塑为形状 [batch_size,Tq,1,dim][batch_size,Tv,dim]
  2. 将形状为 [batch_size,Tv] 的分数计算为非线性和:scores = tf.reduce_sum(tf.tanh(query + value),axis=-1)
  3. 使用分数计算形状为 [batch_size,Tv]: distribution = tf.nn.softmax(scores) 的分布。
  4. 使用分布创建形状为 batch_size,dim]: return tf.matmul(distribution,value) 的值的线性组合。

而且我认为该教程中的实现与计算注意力权重特征有点不同。如果我们遵循上述方法(1 到 4),我们也将获得与 attention_weights 相同的输出形状。这是方法,(但不是这里只是一个演示目的,不是一般性的。)

class BahdanauAttention(tf.keras.layers.Layer):
  def __init__(self,self).__init__()
    self.W1 = tf.keras.layers.Dense(units)
    self.W2 = tf.keras.layers.Dense(units)
    self.V = tf.keras.layers.Dense(1)

  def call(self,2)  # [batch_size,dim]
    value_with_time_axis = tf.expand_dims(values,1) # [batch_size,dim]
    scores = tf.reduce_sum(tf.tanh(query_with_time_axis + 
                                   value_with_time_axis),axis=-1)
    distribution = tf.nn.softmax(scores)
    return tf.matmul(distribution,values),distribution

现在,如果我们传递相同的输入,我们将从两个实现中获得相同的输出形状。但是,一般来说,用例应该选择内置实现。

attention_layer = BahdanauAttention(10)

y = tf.random.uniform((2,60]))

buit_attn = tf.keras.layers.AdditiveAttention()
y = tf.random.uniform((2,60]))

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。