【自然语言处理】基于双向LSTM(Bi-LSTM)文本分类的Tensorflow实现

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/tudaodiaozhale/article/details/86220530

前言

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)

猜你喜欢

转载自blog.csdn.net/tudaodiaozhale/article/details/86220530