开始的话:
从基础做起,不断学习,坚持不懈,加油。
一位爱生活爱技术来自火星的程序汪
RNN系列
说到RNN,我们就不得不说attention在RNN中的运用了。为啥使用attention我也就不多说了。
话不多说,直接上图(没水印且居中的图片,终于舒服了)。
看过前面几个章节的,图中
m
a
t
c
h
match
match以下的部分就不需要过多解释了。
h
t
h_t
ht 就是每个时间步的输出
C
0
C_0
C0 就是最后的
s
t
a
t
e
state
state输出
在
B
a
h
d
a
n
a
u
A
t
t
e
n
t
i
o
n
BahdanauAttention
BahdanauAttention中:
u
t
=
v
T
t
a
n
h
(
W
1
h
+
W
2
d
t
)
u^t=v^Ttanh(W_1h + W_2d_t)
ut=vTtanh(W1h+W2dt)
a
t
=
s
o
f
t
m
a
x
(
u
t
)
a^t=softmax(u^t)
at=softmax(ut)
c
t
=
∑
t
L
a
t
h
l
c^t = \sum_t^{L}a^th_l
ct=∑tLathl
h
h
h 表示每个时间步的输出
d
t
d_t
dt 表示
d
e
c
o
d
e
r
decoder
decoder时候的状态
v
T
v^T
vT 表示
w
e
i
g
h
t
s
weights
weights,需要去学习的
剩下的就比较好理解了。
在分类的 t a s k task task中,是没有 d e c o d e r decoder decoder的
接下来会结合着 d e m o demo demo和上面的图片来详细说明下过程。
def attention(inputs, hidden_size, dropout, attention_size):
"""
:param inputs: [B, T, D] -> [batch_size, sequence_length, embedding_size]
:param hidden_size: RNN output size
:param dropout: dropout rate
:param attention_size: attention output size
:return:
"""
fw = tf.nn.rnn_cell.GRUCell(hidden_size, name='fw')
bw = tf.nn.rnn_cell.GRUCell(hidden_size, name='bw')
if dropout:
fw = tf.nn.rnn_cell.DropoutWrapper(fw, output_keep_prob=dropout)
bw = tf.nn.rnn_cell.DropoutWrapper(bw, output_keep_prob=dropout)
output, _ = tf.nn.bidirectional_dynamic_rnn(
fw,
bw,
inputs=inputs,
dtype=tf.float32
)
# [batch_size, sequence_length, 2 * hidden_size]
output = tf.concat(output, axis=2)
# W * X + B
# [batch_size, sequence_length, 2 * hidden_size] -> [batch_size, sequence_length, attention_size]
I = tf.layers.dense(inputs=output, units=attention_size, activation=tf.tanh)
V = tf.get_variable(name='v_omega', shape=[attention_size], dtype=tf.float32)
# [batch_size, sequence_length, attention_size]
U = tf.multiply(I, V)
# [batch_size, sequence_length]
U = tf.reduce_sum(U, axis=2)
# [batch_size, sequence_length]
A = tf.nn.softmax(U, axis=1)
# multiply is [batch_size, sequence_length, 2 * hidden_size] * [batch_size, sequence_length, 1]
# multiply = [batch_size, sequence_length, 2 * hidden_size]
# reduce_sum = [batch_size, 2 * hidden_size]
C = tf.reduce_sum(tf.multiply(output, tf.expand_dims(A, -1)), axis=1)
return C, A
在拿到 r n n rnn rnn的输出结果 o u t p u t output output之后,我们就拿到了在上面公式中的 h h h
I = tf.layers.dense(inputs=output, units=attention_size, activation=tf.tanh)
上面这行代码,就是公式中的
t
a
n
h
(
W
1
h
+
W
2
d
t
)
tanh(W_1h + W_2d_t)
tanh(W1h+W2dt)
只不过没有了
d
t
d_t
dt,可以改为:
t
a
n
h
(
W
1
h
+
b
)
tanh(W_1h + b)
tanh(W1h+b)
V = tf.get_variable(name='v_omega', shape=[attention_size], dtype=tf.float32)
# [batch_size, sequence_length, attention_size]
U = tf.multiply(I, V)
经过上面的两行代码,就得到了
u
t
u^t
ut,而这也是我们在图片中
m
a
t
c
h
match
match后的结果。
u
t
=
v
T
t
a
n
h
(
W
1
h
+
b
)
u^t=v^Ttanh(W_1h + b)
ut=vTtanh(W1h+b)
# [batch_size, sequence_length]
U = tf.reduce_sum(U, axis=2)
# [batch_size, sequence_length]
A = tf.nn.softmax(U, axis=1)
经过
s
o
f
t
m
a
x
softmax
softmax之后,就拿到了我们的attention结果,也就是图片中的
S
t
S_t
St,对应着公式中的:
a
t
=
s
o
f
t
m
a
x
(
u
t
)
a^t=softmax(u^t)
at=softmax(ut)
最后将
a
t
t
e
n
t
i
o
n
attention
attention和
h
h
h做加权并求和。
# multiply is [batch_size, sequence_length, 2 * hidden_size] * [batch_size, sequence_length, 1]
# multiply = [batch_size, sequence_length, 2 * hidden_size]
# reduce_sum = [batch_size, 2 * hidden_size]
C = tf.reduce_sum(tf.multiply(output, tf.expand_dims(A, -1)),
# C = tf.reduce_mean(tf.multiply(output, tf.expand_dims(A, -1)), axis=1)axis=1)
对应公式中的:
c
t
=
∑
t
L
a
t
h
l
c^t = \sum_t^{L}a^th_l
ct=∑tLathl
最后的
C
C
C,就是我们对一个输入的
v
e
c
t
o
r
vector
vector表示,不同的输入
x
t
x_t
xt贡献着不一样的权重。
上面的就是
a
t
t
e
n
t
i
o
n
attention
attention在分类中的
d
e
m
o
demo
demo展示。
最后再提一句,在
e
n
c
o
d
e
r
encoder
encoder-
d
e
c
o
d
e
r
decoder
decoder中,我们可以拿到
r
n
n
rnn
rnn的输出也就是图片中的
h
t
h_t
ht和
c
0
c_0
c0,通过
h
t
h_t
ht和
c
0
c_0
c0(
c
0
c_0
c0也就是
d
e
c
o
d
e
r
decoder
decoder的初始状态)计算
a
t
t
e
n
t
i
o
n
attention
attention之后,我们能拿到
C
C
C(也就是下面图片中的
X
d
−
1
X_{d-1}
Xd−1),在
d
e
c
o
d
e
r
decoder
decoder的时候,会把
X
d
−
1
X_{d-1}
Xd−1和
c
0
c_0
c0作为解码中的第一次输出,从而得到
c
1
c_1
c1,然后通过
c
1
c_1
c1以及
h
t
h_t
ht得到下一步的输入,以此迭代到输出结束为止。
看图加深下理解:
这时候的 a t t e n t i o n attention attention就和 B a h d a n a u A t t e n t i o n BahdanauAttention BahdanauAttention中的差不多啦。
当然
a
t
t
e
n
t
i
o
n
attention
attention还是有很多变体的,主要是在
m
a
t
c
h
match
match的过程中有不同。
在 LuongAttention 中,
m
a
t
c
h
match
match操作是这样的:
u
t
=
d
t
W
h
u^t=d_tWh
ut=dtWh
a
t
=
s
o
f
t
m
a
x
(
u
t
)
a^t=softmax(u^t)
at=softmax(ut)
c
t
=
∑
t
L
a
t
h
l
c^t = \sum_t^{L}a^th_l
ct=∑tLathl
这两类 a t t e n t i o n attention attention也就是我们经常说的加法 a t t e n t i o n attention attention和乘法 a t t e n t i o n attention attention了。
这个实例中我们用的是
g
l
o
b
a
l
global
global
a
t
t
e
n
t
i
o
n
attention
attention,也就是对所有的输入
X
t
X_t
Xt进行了
a
t
t
e
n
t
i
o
n
attention
attention的操作。还有一种
l
o
c
a
l
local
local
a
t
t
e
n
t
i
o
n
attention
attention的操作,是在随机窗口内做
a
t
t
e
n
t
i
o
n
attention
attention操作,减少了计算量,区别在于关注的是所有
e
n
c
o
d
e
r
encoder
encoder状态还是部分
e
n
c
o
d
e
r
encoder
encoder状态。
具体请看
L
u
o
n
g
A
t
t
e
n
t
i
o
n
LuongAttention
LuongAttention中的详细介绍。
随着 g o o g l e google google大佬提出了 t r a n s f o r m e r transformer transformer之后,一种更为一般化的 a t t e n t i o n attention attention就出来了:
A t t e n t i o n ( Q , V , K ) = s o f t m a x ( Q K T d k ) V Attention(Q,V, K)= softmax(\frac{QK^T}{\sqrt{d^k}} ) V Attention(Q,V,K)=softmax(dkQKT)V
对应上面公式中:
Q
Q
Q ->
C
0
C_0
C0
K
K
K ->
h
t
h_t
ht
V
V
V ->
h
t
h_t
ht
如果 Q Q Q、 K K K、 V V V 都是一个值得话,那就是我们的 s e l f self self- a t t e n t i o n attention attention了。
谢谢