在深度學習方面,圖像識別、語音識別主要運用卷積神經網絡(CNN),而文字語言處理主要運用循環神經網絡(RNN)python
循環神經網絡的應用場景比較多,好比暫時能寫論文,寫程序,寫詩,可是,(老是會有可是的),可是他們如今還不能正常使用,學習出來的東西沒有邏輯,因此要想真正讓它更有用,路還很遠。 ###普通神經元 ###全鏈接深度神經網絡
###循環神經元
###循環神經網絡解析數組
###例如: """網絡
我是中國人 你在作什麼 是嗎<eco><eco><eco>session
是一個batch內的佯本,進行rnn訓練.app
假設隱藏層神經元數量爲k,一次處理3句話,每句話序列長度爲5(即時間維度),字向量是n維則(即n個輸入節點):[batch ,n_steps ,word_embeding]=[3,5,n] 過程: 一、分別將batch的一個字輸入網絡(我、你、是),根據網絡權重w0/b0(nk個)計算 和 初始狀態(s0一、s0二、h03),分別產生狀態s十一、s十二、s13; 二、分別將batch的第二個字輸入網絡(是、在、嗎),根據網絡權重w0/b0(nk個)計算 和 狀態(s十一、s十二、s13),分別產生狀態s2一、s2二、s23; . . . 三、計算完最後一個字後,將batch個佯本產生的結果總和來進行權重w0/b0調整爲-->w1/b1,一個batch結束 四、進行下一個batch佯本集計算,循環步驟1 注意:batch中3句話分別進行計算相互不干擾,但共享權重。(也能夠理解爲分別單獨計算第一句話進入網絡,計算第二句話也進入網絡,計算第三句話進入網絡,只是用矩陣形式方便一塊兒計算。 且進行計算完3句話後,用總的偏差來梯度調整權重,而不是分別每句話計算完就調整權重。這是用batch所在) batch做用參考https://www.jianshu.com/p/037d3b305ef3 """函數
-----------------------------------------------------------程序分析---------------------------------------------------------------- import tensorflow as tf import numpy as np學習
""" 我是中國人 你在作什麼 是嗎<eco><eco><eco>測試
假設隱藏層LSTM神經元數量爲k,一次處理3句話,每句話序列長度爲5(即時間維度),字向量是n維則(即n個輸入節點):[batch ,n_steps ,word_embeding]=[3,5,n] 過程:(其中步驟1叫單步執行,至關於call方法,步驟1到3是多步執行,dynamic_rnn函數來實現) 一、分別將batch的一個字輸入網絡(我、你、是),根據網絡權重w0/b0(nk個)計算 和 初始狀態(h0一、h0二、h03),分別產生狀態h十一、h十二、h13; 二、分別將batch的第二個字輸入網絡(是、在、嗎),根據網絡權重w0/b0(nk個)計算 和 狀態(h十一、h十二、h13),分別產生狀態h2一、h2二、h23; . . . 三、計算完最後一個字後,將batch個佯本產生的結果總和來進行權重w0/b0調整爲-->w1/b1,一個batch結束 四、進行下一個batch佯本集計算,循環步驟1 注意:batch中3句話分別進行計算相互不干擾,但共享權重。(也能夠理解爲分別單獨計算第一句話進入網絡,計算第二句話也進入網絡,計算第三句話進入網絡,只是用矩陣形式方便一塊兒計算。 且進行計算完3句話後,用總的偏差來梯度調整權重,而不是分別每句話計算完就調整權重。這是batch用處所在)ui
"""code
cell = tf.nn.rnn_cell.BasicRNNCell(num_units=128) # state_size = 128 print(cell.state_size) # 128
inputs = tf.placeholder(np.float32, shape=(32, 100)) # 32 是 batch_size h0 = cell.zero_state(32, np.float32) # 經過zero_state獲得一個全0的初始狀態,形狀爲(batch_size, state_size) output, h1 = cell.call(inputs, h0) #調用call函數 print(h1.shape) # (32, 128) --#--------------------lstm狀態有h和c------------------ lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=128) inputs = tf.placeholder(np.float32, shape=(32, 100)) # 32 是 batch_size h0 = lstm_cell.zero_state(32, np.float32) # 經過zero_state獲得一個全0的初始狀態 output, h1 = lstm_cell.call(inputs, h0) # call方法inputs必須是[batch_size,輸入節點數](即單步執行)
print(h1.h) # shape=(32, 128) print(h1.c) # shape=(32, 128)
inputs2 = tf.placeholder(np.float32, shape=(32, 20, 100)) # 32 是 batch_size 20是序列長度,100是輸入節點維數。shape = (batch_size, time_steps, input_size) # initial_state: shape = (batch_size, cell.state_size)。初始狀態。通常能夠取零矩陣 initial_state = lstm_cell.zero_state(32, np.float32) # 經過zero_state獲得一個全0的初始狀態 outputs, state = tf.nn.dynamic_rnn(lstm_cell, inputs2, initial_state=initial_state) # state爲最後一步的狀態,outputs爲每一步的輸出數組(但最後的state 並不等於outpus的最後一行,這裏有待研究) print(state.h) # shape=(32, 128)
''' 不少時候,單層RNN的能力有限,咱們須要多層的RNN。將x輸入第一層RNN的後獲得隱層狀態h,這個隱層狀態就至關於第二層RNN的輸入,第二層RNN的隱層狀態又至關於第三層RNN的輸入, 以此類推。在TensorFlow中,可使用tf.nn.rnn_cell.MultiRNNCell函數對RNNCell進行堆疊 '''
def get_a_cell(): return tf.nn.rnn_cell.BasicRNNCell(num_units=128) # 每調用一次這個函數就返回一個BasicRNNCell
cell = tf.nn.rnn_cell.MultiRNNCell([get_a_cell() for _ in range(3)]) # 用tf.nn.rnn_cell MultiRNNCell建立3層RNN 獲得的cell實際也是RNNCell的子類 它的state_size是(128, 128, 128) (128, 128, 128)並非128x128x128的意思 而是表示共有3個隱層狀態,每一個隱層狀態的大小爲128 print(cell.state_size) # (128, 128, 128) 使用對應的call函數 inputs = tf.placeholder(np.float32, shape=(32, 100)) # 32 是 batch_size h0 = cell.zero_state(32, np.float32) # 經過zero_state獲得一個全0的初始狀態 output1, h1 = cell.call(inputs, h0) print(h1) # tuple中含有3個32x128的向量 經過MultiRNNCell獲得的cell並非什麼新鮮事物,它實際也是RNNCell的子類,所以也有call方法、state_size和output_size屬性。一樣能夠經過tf.nn.dynamic_rnn來一次運行多步。
''' BasicRNNCell對照來看。h就對應了BasicRNNCell的state。那麼,y是否是就對應了BasicRNNCell的output呢?答案是否認的
def call(self, inputs, state): """Most basic RNN: output = new_state = act(W * input + U * state + B).""" output = self._activation(_linear([inputs, state], self._num_units, True)) return output, output # call 源碼,output和state是同樣的。所以,咱們還須要額外對輸出定義新的變換,才能獲得圖中真正的輸出y
再來看一下BasicLSTMCell的call函數定義(函數的最後幾行):
new_c = ( c * sigmoid(f + self._forget_bias) + sigmoid(i) * self._activation(j)) new_h = self._activation(new_c) * sigmoid(o)
if self._state_is_tuple: new_state = LSTMStateTuple(new_c, new_h) else: new_state = array_ops.concat([new_c, new_h], 1) return new_h, new_state
只須要關注self._state_is_tuple == True的狀況,由於self._state_is_tuple == False的狀況將在將來被棄用。返回的隱狀態是new_c和new_h的組合,而output就是單獨的new_h。若是咱們處理的是分類問題,那麼咱們還須要對new_h添加單獨的Softmax層才能獲得最後的分類機率輸出。 '''
看以下代碼:
def build_lstm(self): def get_a_cell(lstm_size, keep_prob): # 建立單個lstm,並增長drop層 lstm = tf.nn.rnn_cell.BasicLSTMCell(lstm_size) drop = tf.nn.rnn_cell.DropoutWrapper(lstm, output_keep_prob=keep_prob) return drop with tf.name_scope('lstm'): # 堆疊多層lstm cell = tf.nn.rnn_cell.MultiRNNCell( [get_a_cell(self.lstm_size, self.keep_prob) for _ in range(self.num_layers)] ) self.initial_state = cell.zero_state(self.batch_size, tf.float32) # 經過dynamic_rnn對cell展開時間維度 self.lstm_outputs, self.final_state = tf.nn.dynamic_rnn(cell, self.lstm_inputs, initial_state=self.initial_state) def train(self, batch_generator, max_steps, save_path, save_every_n, log_every_n): self.session = tf.Session() with self.session as sess: sess.run(tf.global_variables_initializer()) # Train network step = 0 new_state = sess.run(self.initial_state) for x, y in batch_generator: step += 1 start = time.time() feed = {self.inputs: x, self.targets: y, self.keep_prob: self.train_keep_prob, self.initial_state: new_state} # batch_loss, new_state, _ = sess.run([self.loss, self.final_state, self.optimizer], feed_dict=feed)
該程序將運行完一個batch後的狀態做爲下一個batch的初始狀態,這樣是有問題的。由於每一個batch佯本並不受上一個batch佯本的影響(在一個batch裏面,序列之間是受影響的,dynamic_rnn函數已經自動將序列間的狀態進行傳遞,最終輸出的是序列最後一個字的狀態)。因此每次訓練完一個batch佯本,initial_state應該被置爲0。 feed 部分不須要傳入self.initial_state,每一個batch的初始狀態都是:self.initial_state = cell.zero_state(self.batch_size, tf.float32)。程序修改以下:
def train(self, batch_generator, max_steps, save_path, save_every_n, log_every_n): self.session = tf.Session() with self.session as sess: sess.run(tf.global_variables_initializer()) # Train network step = 0 # new_state = sess.run(self.initial_state) for x, y in batch_generator: step += 1 start = time.time() feed = {self.inputs: x, self.targets: y, self.keep_prob: self.train_keep_prob,} # self.initial_state: new_state} # batch_loss, new_state, _ = sess.run([self.loss, self.final_state, self.optimizer], feed_dict=feed)
另外,在測試階段,由於輸入的是第一個字,因此須要將輸出的狀態傳入到下一個字,這點是須要注意的。