rnn的的公式很简单:
对于每个时刻,输入上一个时刻的隐层s和这个时刻的文本x,然后输出这个时刻的隐层s。对于输出的隐层s 做个ws+b就是这个时刻的输出y。
tf.scan(fn, elems, initializer) # scan operation
def fn(st_1, xt): # recurrent function
st = f(st_1, xt)
return st
rnn的实现:
def step(hprev, x): # initializer xav_init = tf.contrib.layers.xavier_initializer # params W = tf.get_variable('W', shape=[state_size, state_size], initializer=xav_init()) U = tf.get_variable('U', shape=[state_size, state_size], initializer=xav_init()) b = tf.get_variable('b', shape=[state_size], initializer=tf.constant_initializer(0.)) # current hidden state h = tf.tanh(tf.matmul(hprev, W) + tf.matmul(x,U) + b) return h states = tf.scan(step, tf.transpose(rnn_inputs, [1,0,2]), initializer=init_state)
lstm只是网络结构上个对rnn进行改进,它同时增加一个单元叫做state状态,每个lstm有个hidden和一个state。
下面图中h就是隐层,下面图中的c就是状态。首先根据这个时刻的输入x和上个时刻的隐层算出三个门,f(forget),i(input),o(ouput)
激活函数是sigmoid函数,输出0或者1。算出来的f门是来控制上个状态多少被忘记。算出来的i门来控制这个时刻状态的多少被输入。
本时刻的状态由这个时刻的输入x和上个时刻的隐层算出然后用tan函数激活(对应第四行公式)。
本时刻隐层的输出h是由本时刻的状态用tan来激活,然后乘以输出门
看看lstm的实现:
def step(prev, x): # gather previous internal state and output state st_1, ct_1 = tf.unpack(prev) #### # GATES # # input gate i = tf.sigmoid(tf.matmul(x,U[0]) + tf.matmul(st_1,W[0])) # forget gate f = tf.sigmoid(tf.matmul(x,U[1]) + tf.matmul(st_1,W[1])) # output gate o = tf.sigmoid(tf.matmul(x,U[2]) + tf.matmul(st_1,W[2])) # gate weights g = tf.tanh(tf.matmul(x,U[3]) + tf.matmul(st_1,W[3])) ### # new internal cell state ct = ct_1*f + g*i # output state st = tf.tanh(ct)*o return tf.pack([st, ct]) ### # here comes the scan operation; wake up! # tf.scan(fn, elems, initializer) states = tf.scan(step, tf.transpose(rnn_inputs, [1,0,2]), initializer=init_state)
在来看下gru
gru里面没有state这个东西,它有两个门,一个是z,遗忘门,一个是r,就是reset门
跟lstm。算出遗忘门,来控制上个时刻的多少隐层被遗忘,另一半(1-z)就是本时刻多少隐层被输入。
本时刻多少隐层,跟lstm也很相似,只是在上个时刻的h上加了个reset门,就是:根据上个时刻的h加上reset门,和本时刻的输入x,通过tan来激活
看看gru的实现:
def step(st_1, x): #### # GATES # # update gate z = tf.sigmoid(tf.matmul(x,U[0]) + tf.matmul(st_1,W[0])) # reset gate r = tf.sigmoid(tf.matmul(x,U[1]) + tf.matmul(st_1,W[1])) # intermediate h = tf.tanh(tf.matmul(x,U[2]) + tf.matmul( (r*st_1),W[2])) ### # new state st = (1-z)*h + (z*st_1) return st ### # here comes the scan operation; wake up! # tf.scan(fn, elems, initializer) states = tf.scan(step, tf.transpose(rnn_inputs, [1,0,2]), initializer=init_state)
参考文章:
http://colah.github.io/posts/2015-08-Understanding-LSTMs/
http://suriyadeepan.github.io/2017-02-13-unfolding-rnn-2/
https://github.com/suriyadeepan/rnn-from-scratch
http://karpathy.github.io/2015/05/21/rnn-effectiveness/