源代码
TensorFlow函数:tf.layers.Layer
Luong-style 注意力机制有两种类型:
①standard Luong attention
Effective Approaches to Attention-based Neural Machine Translation 2015
②scaled form inspired partly by the normalized form of Bahdanau attention
1.
基
类
A
t
t
e
n
t
i
o
n
M
e
c
h
a
n
i
s
m
(
o
b
j
e
c
t
)
:
\color{purple}基类 AttentionMechanism(object):
基类AttentionMechanism(object):
存在两个函数
@
p
r
o
p
e
r
t
y
d
e
f
      
a
l
i
g
n
m
e
n
t
s
_
s
i
z
e
(
s
e
l
f
)
:
\color{green}\begin{array}l@property&\\ def \,\,\,\,\,\,alignments\_size(self):\end{array}
@propertydefalignments_size(self):
@
p
r
o
p
e
r
t
y
d
e
f
      
s
t
a
t
e
_
s
i
z
e
(
s
e
l
f
)
:
\color{green}\begin{array}l@property&\\ def \,\,\,\,\,\,state\_size(self):\end{array}
@propertydefstate_size(self):
2.
_
p
r
e
p
a
r
e
_
m
e
m
o
r
y
函
数
:
\color{purple} \_prepare\_memory函数:
_prepare_memory函数:
转换成张量,并将memory(encoder输出)中超过序列长度的屏蔽,将memory转你换成恰当的格式。(
C
o
n
v
e
r
t
 
t
o
 
t
e
n
s
o
r
 
a
n
d
 
p
o
s
s
i
b
l
y
 
m
a
s
k
 
m
e
m
o
r
y
.
\color{pink}Convert\, to\, tensor\, and \,possibly\, mask \,memory.
Converttotensorandpossiblymaskmemory.)
def _prepare_memory(memory, memory_sequence_length, check_inner_dims_defined):
参数介绍:
memory
: 张量, 形状为 [batch_size, max_time, ...]
memory_sequence_length
: int32
类型张量,形状为[batch_size]
。与输入memory对应,每行的值,代表着对应memory行中序列的长度
check_inner_dims_defined
: 布尔值。 如果为真,检查上面memory参数的形状,确保除两个最外层维度外(batch_size,max_time)的所有维度都已明确定义。
Returns:
A (possibly masked), checked, new memory
.
Raises:
ValueError: If check_inner_dims_defined
is True
and not memory.shape[2:].is_fully_defined()
.
此函数包含一个子函数,
_
m
a
y
b
e
_
m
a
s
k
(
m
,
s
e
q
_
l
e
n
_
m
a
s
k
)
\color{green}\_maybe\_mask(m, seq\_len\_mask)
_maybe_mask(m,seq_len_mask)
memory = nest.map_structure(lambda m: ops.convert_to_tensor(m, name="memory"), memory)
上述代码行的含义是,将memory中的所有元素都转换成张量
①nest.map_structure()函数:
tf.contrib.framework.nest.map_structure(func, *structure, **check_types_dict)
作用:对一个可循环结构的元素一次应用函数。返回一个与参数structure有相同参数数量的新结构。
②ops.convert_to_tensor()函数:
作用:将不同数据变成张量:比如可以让数组变成张量、也可以让列表变成张量
if memory_sequence_length is not None:
memory_sequence_length = ops.convert_to_tensor(memory_sequence_length, name="memory_sequence_length")
上述代码将memory_sequence_lenght转换成张量
if check_inner_dims_defined:
def _check_dims(m):
if not m.get_shape()[2:].is_fully_defined():
raise ValueError("Expected memory %s to have fully defined inner dims, "
"but saw shape: %s" % (m.name, m.get_shape()))
nest.map_structure(_check_dims, memory)
如果check_inner_dims_defined为True,检查memory形状,如果任一元素没有被彻底定义,报错
if memory_sequence_length is None:
seq_len_mask = None
else:
seq_len_mask = array_ops.sequence_mask(
memory_sequence_length,
maxlen=array_ops.shape(nest.flatten(memory)[0])[1],
dtype=nest.flatten(memory)[0].dtype)
seq_len_batch_size = (
memory_sequence_length.shape[0].value
or array_ops.shape(memory_sequence_length)[0])
上述代码,else部分,seq_len_mask是一个seq_len_batch_size
×
\times
×array_ops.shape(nest.flatten(memory)[0])[1]大小的张量
①sequence_mask(lenghts, maxlen=None,dtype=tf.bool,name=None)
参数:
lengths:整数张量,其所有值小于等于maxlen。
maxlen:标量整数张量,返回张量的最后维度的大小;默认值是lengths中的最大值。
dtype:结果张量的输出类型。
name:操作的名字
作用:将[batch_size]转换成[batch_size, seq_length]
def _maybe_mask(m, seq_len_mask):
rank = m.get_shape().ndims
rank = rank if rank is not None else array_ops.rank(m)
extra_ones = array_ops.ones(rank - 2, dtype=dtypes.int32)
m_batch_size = m.shape[0].value or array_ops.shape(m)[0]
if memory_sequence_length is not None:
message = ("memory_sequence_length and memory tensor batch sizes do not "
"match.")
with ops.control_dependencies([
check_ops.assert_equal(
seq_len_batch_size, m_batch_size, message=message)]):
seq_len_mask = array_ops.reshape(
seq_len_mask,
array_ops.concat((array_ops.shape(seq_len_mask), extra_ones), 0))
return m * seq_len_mask
else:
return m
判断上一步生成的seq_len_mask中的seq_len_batch_size与memory的m_batch_size是否相等。
3.定义了一个_maybe_mask_score函数,
_
m
a
y
b
e
_
m
a
s
k
_
s
c
o
r
e
(
s
c
o
r
e
,
m
e
m
o
r
y
_
s
e
q
u
e
n
c
e
_
l
e
n
g
t
h
,
s
c
o
r
e
_
m
a
s
k
_
v
a
l
u
e
)
\color{green}\_maybe\_mask\_score(score, memory\_sequence\_length, score\_mask\_value)
_maybe_mask_score(score,memory_sequence_length,score_mask_value)
4.
类
_
B
a
s
e
A
t
t
e
n
t
i
o
n
M
e
c
h
a
n
i
s
m
继
承
了
类
A
t
t
e
n
t
i
o
n
M
e
c
h
a
n
i
s
m
\color{red}{类\_BaseAttentionMechanism继承了类AttentionMechanism}
类_BaseAttentionMechanism继承了类AttentionMechanism
提供公共功能的一个AttentionMechanism基类。
通用的功能包括:
- 存储查询和内存层(query layers and memory layers)。
- 预处理和存储memory。
def __init__(self,
query_layer,
memory,
probability_fn,
memory_sequence_length=None,
memory_layer=None,
check_inner_dims_defined=True,
score_mask_value=None,
name=None):
参数:
q
u
e
r
y
_
l
a
y
e
r
\color{green}query\_layer
query_layer: Callable. tf.layers.Layers
的实例。层深必须和memory_layer
的深度一样。如果没有提供query_layer
,query
的形状必须和memory_layers
一致。这是因为对于公式
s
c
o
r
e
(
s
t
,
h
i
)
=
 
v
a
T
t
a
n
h
(
W
a
[
s
t
;
h
i
]
)
score(s_t, h_i)=\,v_a^Ttanh(W_a[s_t;h_i])
score(st,hi)=vaTtanh(Wa[st;hi])中的
W
a
[
s
t
;
h
i
]
)
W_a[s_t;h_i])
Wa[st;hi])部分,代码是通过两部分实现的,即query_layer层实现
s
t
s_t
st部分,memory_layer层实现
h
i
h_i
hi部分,所以需要两层的深度一致,可以在后面的代码中看到,两层是通过相加结合在一起的。
m
e
m
o
r
y
\color{green}memory
memory:要查询的memory(这里的memory是RNN encoder的输出);尺寸[batch_size, max_time,...]
这
里
的
m
a
x
_
t
i
m
e
代
表
的
是
什
么
呢
?
是
代
表
e
n
c
o
d
e
r
的
步
数
吗
\color{red}这里的max\_time代表的是什么呢?是代表encoder的步数吗
这里的max_time代表的是什么呢?是代表encoder的步数吗
p
r
o
b
a
b
i
l
i
t
y
_
f
n
\color{green}probability\_fn
probability_fn: callable
.将score和previous alignment转换为概率(
这
里
的
s
o
r
e
应
该
是
e
n
c
o
d
e
r
输
出
和
d
e
c
o
d
e
r
输
出
的
对
齐
程
度
\color{red}{这里的sore应该是encoder输出和decoder输出的对齐程度}
这里的sore应该是encoder输出和decoder输出的对齐程度),公式如下:probabilities = probability_fn(score, state)
,state代表所有的score。
m
e
m
o
r
y
s
e
q
u
e
n
c
e
l
e
n
g
t
h
(
o
p
t
i
o
n
a
l
)
\color{green}memory_sequence_length(optional)
memorysequencelength(optional): memory(Encoder输出)中每条(batch entries)序列长度。如果提供,encoder输出张量行中超过各自序列长度的值,用0进行屏蔽。
m
e
m
o
r
y
_
l
a
y
e
r
\color{green}memory\_layer
memory_layer:tf.layers.Layer
的实例(也可能为None)。
m
e
m
o
r
y
_
l
a
y
e
r
和
q
u
e
r
y
_
l
a
y
e
r
的
关
系
是
什
么
?
\color{red}memory\_layer和query\_layer的关系是什么?
memory_layer和query_layer的关系是什么?memory_layer层的深度必须和query_layer
的深度一致。If memory_layer
is not provided, the shape of memory
must match that of query_layer
.
c
h
e
c
k
_
i
n
n
e
r
_
d
i
m
s
_
d
e
f
i
n
e
d
\color{green}check\_inner\_dims\_defined
check_inner_dims_defined:布尔值。如果为真,则核查memory
参数形状,用以确保处最外面两个维度(batch_size, max_time)外其余所有维度已被完全定义。
s
c
o
r
e
_
m
a
s
k
_
v
a
l
u
e
\color{green}score\_mask\_value
score_mask_value:(可选)The mask value for score before passing into
probability_fn
. The default is -inf. Only used if
memory_sequence_length
is not None.
n
a
m
e
\color{green}name
name:操作的名称
def initial_alignments(self,batch_size,dtype)
def initial_alignments(self, batch_size, dtype):
max_time = self._alignments_size
return _zero_state_tensors(max_time, batch_size, dtype)
为“AttentionWrapper”类创建初始对齐值(权重)。这对于使用前面的对齐来计算下一个时间步(例如monotonic attention)的对齐的注意力机制很重要。默认返回一个全零张量。
参数介绍:
batch_size: int32
标量, the batch_size.
dtype: The dtype
.
Returns:
A dtype
tensor shaped [batch_size, alignments_size]
(alignments_size
is the values’ max_time
).
def initial_state(self, batch_size, dtype)
为“AttentionWrapper”类创建初始状态值。这对于使用前面对齐的注意力机制计算下一个时间步的对齐(例如单调注意)非常重要。默认行为是返回与initial_alignments相同的输出。
def initial_state(self, batch_size, dtype):
return self.initial_alignments(batch_size, dtype)
参数介绍:
batch_size: int32
scalar, the batch_size.
dtype: The dtype
.
Returns:
A structure of all-zero tensors with shapes as described by state_size
.
5. 类 L u o n g A t t e n t i o n \color{red}类LuongAttention 类LuongAttention
6.
类
B
a
h
d
a
n
a
u
A
t
t
e
n
t
i
o
n
\color{red}类BahdanauAttention
类BahdanauAttention
继承基类:_BaseAttentionMechanism
Bahdanau注意力机制共有两种形式:
①Bahdanau attention: Neural Machine Traslation by Jointly Learning to Align and Translate 2015
②normalized form: Weight Normalization: A Simple Reparameterization to Accelerate Training of Deep Neural Networks.
在这个类之前定义了一个
_
b
a
h
d
a
n
a
u
_
s
c
o
r
e
(
p
r
o
c
e
s
s
e
d
_
q
u
e
r
y
,
k
e
y
s
,
n
o
r
m
a
l
i
z
e
)
:
\color{purple}\_bahdanau\_score(processed\_query, keys, normalize):
_bahdanau_score(processed_query,keys,normalize):函数。如果normilize为False,此函数处理如下公式:
s
c
o
r
e
(
s
t
,
h
i
)
=
 
v
a
T
t
a
n
h
(
W
a
[
s
t
;
h
i
]
)
score(s_t, h_i)=\,v_a^Ttanh(W_a[s_t;h_i])
score(st,hi)=vaTtanh(Wa[st;hi])
return math_ops.reduce_sum(v * math_ops.tanh(keys + processed_query), [2])
其中,keys对应
h
i
h_i
hi(memory)encoder的输出,形状为[batch_size, max_time, num_units]
;
processed_query对应
s
t
s_t
stdecoder的隐藏状态,形状为[batch_size, num_units]
返回值的形状为[batch_size, max_time]
,即分数
Bahdanau注意力机制的初始化函数:
def __init__(self,
num_units,
memory,
memory_sequence_length=None,
normalize=False,
probability_fn=None,
score_mask_value=None,
dtype=None,
name="BahdanauAttention"):
参数介绍:
num_units
:
q
u
e
r
y
  
m
e
c
h
a
n
i
s
m
\color{green}query\,\, mechanism
querymechanism(注意力机制)的深度
memory
:注意力机制的输入;通常是RNN编码器的输出。此张量的形状为:[batch_size, max_time, ...]
memory_sequence_lenght(可选)
:注意力输入(memory)中批处理条目的序列长度。如果给定,则对注意力输入(memory)这个张量的行进行如下处理,对于超过相应序列长度的值,行用0进行屏蔽。
normalize
:布尔值。如果normalize=True,那么选择第二种形式的注意力机制
probability_fn
:(可选)A callable
。将分数转换成概率。对应于论文中下面的这个公式,
α
t
,
i
  
=
a
l
i
g
n
(
y
t
,
x
i
)
表示
y
t
与
x
i
的对齐程度
              
=
e
x
p
(
s
c
o
r
e
(
s
t
−
1
,
h
i
)
)
∑
i
′
=
1
n
e
x
p
(
s
c
o
r
e
(
s
t
−
1
,
h
i
′
)
)
表示一些预定义对齐得分的Softmax
\alpha_{t, i}\;= align(y_t, x_i)\text{表示${y_t}$与$x_i$的对齐程度} \\\;\;\;\;\;\; \,\,= \frac{exp(score(s_{t-1}, h_i))}{\sum_{i^{'} =1}^nexp(score(s_{t-1}, h_{i^{'}}))}\text{表示一些预定义对齐得分的Softmax}
αt,i=align(yt,xi)表示yt与xi的对齐程度=∑i′=1nexp(score(st−1,hi′))exp(score(st−1,hi))表示一些预定义对齐得分的Softmax默认形式为tf.nn.softmax
,其他选项包括:tf.contrib.seq2seq.hardmax
和tf.contrib.sparsemax.sparsemax
。应用如下, probabilities = probability_fn(score)
,其中,probabilities代表了权重向量
α
t
\alpha_t
αt
score_mask_value
:(可选)在传递到probability_fn
之前的分数掩码值。默认值是-inf。仅在memory_sequence_length
不是None的情况下使用。
dtype
:注意机制的查询层(query)和内存层(memory)的数据类型。默认为float32。
name
:创建操作时使用的名称。
函
数
体
部
分
:
\color{green}函数体部分:
函数体部分:
if probability_fn is None:
probability_fn = nn_ops.softmax
if dtype is None:
dtype = dtypes.float32
wrapped_probability_fn = lambda score, _: probability_fn(score)
super(BahdanauAttention, self).__init__(
query_layer=layers_core.Dense(
num_units, name="query_layer", use_bias=False, dtype=dtype),
memory_layer=layers_core.Dense(
num_units, name="memory_layer", use_bias=False, dtype=dtype),
memory=memory,
probability_fn=wrapped_probability_fn,
memory_sequence_length=memory_sequence_length,
score_mask_value=score_mask_value,
name=name)
self._num_units = num_units
self._normalize = normalize
self._name = name
d e f     _ _ c a l l _ _ def\,\,\, \_\_call\_\_ def__call__函数实现了权重 α t \alpha_t αt的求取
def __call__(self, query, state):
with variable_scope.variable_scope(None, "bahdanau_attention", [query]):
processed_query = self.query_layer(query) if self.query_layer else query
score = _bahdanau_score(processed_query, self._keys, self._normalize)
alignments = self._probability_fn(score, state)
next_state = alignments
return alignments, next_state
参数介绍:
query
:张量类型与 self.values
匹配,形状为[batch_size, query_depth]
。
state
:张量类型与self.values
匹配,形状为[batch_size, alignments_size]
(alignments_size
就是输入(memory)的 max_time
)
返回值:
alignments
:张量类型与self.values
匹配,形状为[batch_size, alignments_size]
(alignments_size
就是输入(memory)的 max_time
)
7.
A
t
t
e
n
t
i
o
n
W
r
a
p
p
e
r
S
t
a
t
e
\color{red}7.AttentionWrapperState
7.AttentionWrapperState:
AttentionWrapperState