前言
Github:Github下載地址
RNN在自然語言處理的文本處理上取得了很大的成功。
雙向LSTM可以捕獲上下文的內容,從而使得分類效果更佳。
在本文的這次分類中,本文使用了IMDB電影評價的數據集,最終的模型可以將正面情感和負面情感通過雙向LSTM給分類出來。
實現
這次的主要的類是我們的Detection。
這裏只貼部分代碼進行詮釋,更多代碼請訪問Github
首先定義超參數大小,比如有詞典大小,批次的大小,詞向量的維度,隱層點,最大句子長度(我們的數據集小於最大長度的進行補0),輸出類別數(正面負面),保存節點數(dropout,防止節點太多過擬合)
self.num_emb = vocab_size # vocab size
self.batch_size = batch_size # batch size
self.emb_dim = emb_dim # dimision of embedding
self.hidden_dim = hidden_dim # hidden size
self.sequence_length = sequence_length # sequence length
self.output_dim = 2
self.output_keep_prob = output_keep_prob #to prevent overfit
定義佔用符,其中self.x是句子,self.targets是類別標籤,兩個維度,[0, 1]代表是正類,[1, 0]代表是負類。
並且定義詞向量。
with tf.variable_scope("placeholder"):
self.x = tf.placeholder(shape=[self.batch_size, self.sequence_length], dtype=tf.int32)
self.targets = tf.placeholder(shape=[self.batch_size, self.output_dim], dtype=tf.int64)
with tf.variable_scope("embedding"):
self.g_embeddings = tf.Variable(tf.random_uniform([self.num_emb, self.emb_dim], -1.0, 1.0), name="W_text")
self.inputs= tf.nn.embedding_lookup(self.g_embeddings, self.x) # seq_length x batch_size x emb_dim
定義兩個lstm,一個是輸入的是句子(A, B, C),一個把輸入的顛倒的句子(C, B, A)。
with tf.variable_scope("rnn"):
cell_bw = tf.contrib.rnn.BasicLSTMCell(self.hidden_dim, state_is_tuple=False) # single lstm unit
cell_bw = tf.contrib.rnn.DropoutWrapper(cell_bw, output_keep_prob=self.output_keep_prob)
cell_fw = tf.contrib.rnn.BasicLSTMCell(self.hidden_dim, state_is_tuple=False) # single lstm unit
cell_fw = tf.contrib.rnn.DropoutWrapper(cell_fw, output_keep_prob=self.output_keep_prob)
使用bidirectional_dynamic_rnn將會返回兩個lstm的結果,並用一個元組保存([batch_size, seq_length, cell_fw.output_size],[batch_size, seq_length, cell_bw.output_size]),從上可以看出總共有[2, batch_size, seq_length, output_size]的大小,在此先轉成[2 * batch_size, seq_length, output_size]大小。
接下來在此我將各個step(step就是句子在生成每個詞時算一步)的隱含層輸出進行求和取平均得到[batch_size,output_size]的矩陣,並且最後使用全連接層在經過softmax輸出結果。
with tf.variable_scope("output"):
self.outputs, self.states = tf.nn.bidirectional_dynamic_rnn(cell_bw, cell_fw, self.inputs, dtype=tf.float32) #[2, batch_size, seq_length, output_size]
self.outputs = tf.reshape(self.outputs, shape=[-1, seq_length, output_size]) #[2 * batch_size, seq_length, cell.output_size]
self.outputs = tf.transpose(self.outputs, perm=[1, 0, 2]) # [seq_length, batch_size,output_size]
self.outputs = tf.reduce_mean(self.outputs, 0) # [batch_size,output_size]
self.outputs = self.outputs[:self.batch_size] + self.outputs[self.batch_size:]
self.logits = tf.layers.dense(self.outputs, self.output_dim, name="logits")
self.prob = tf.nn.softmax(self.logits, name="softmax_output")
最後部分我們採用了交叉熵作爲損失函數,並使用Adam優化器進行訓練。
with tf.variable_scope("train"):
self.loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=self.targets, logits=self.logits))
tvars = tf.trainable_variables()
max_grad_norm = 5
# We clip the gradients to prevent explosion
grads, _ = tf.clip_by_global_norm(tf.gradients(self.loss, tvars), max_grad_norm)
gradients = list(zip(grads, tvars))
self.train_op = tf.train.AdamOptimizer(0.005).apply_gradients(gradients)