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/