【自然語言處理】基於雙向LSTM(Bi-LSTM)文本分類的Tensorflow實現

前言

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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章