美文网首页深度学习自然语言理解机器学习
深度学习--RNN+Attention 文本分类

深度学习--RNN+Attention 文本分类

作者: Nlp_小菜 | 来源:发表于2019-02-05 15:59 被阅读6次

    之前介绍过RNN的分类,本文介绍一下使用预训练词向量进行RNN+Attention的分类模型。

    RNN-Attention文本分类 本文使用双向LSTM加上Attention,模型结构如图所示。从下往上看,w这一层表示一个时间序列(在文本分类指一个句子的长度,seq_length),里面的元素是一个个词汇,我们将词汇经过LSTM网络,使不具备重要性,也就是与分类无关的词语的语义给过滤掉或者保留较小的数值,从而留下较为重要的语义。使用双向LSTM,不仅要考虑句子的正向序列,还有反向序列,获得更完整的语义,将获得的结果经过拼接然后再输送到Attention层。Attention简单来说,就是赋予权重,给不同的词汇根据重要性赋值。最后将权重与LSTM层的结果进行线性求和,所得结果输出到全连接层,经过softmax得到分类结果。 Attention

    下面来正式开始,RNN+Attention在tensorflow中的实现。

    运行环境

    python 3.6
    tensorflow 1.2
    本文GITHUB

    正文

    1.数据预处理
    2.模型构建
    3.模型训练与测试
    4.模型验证
    5.总结

    1 数据预处理

    本实验是使用THUCNews的一个子集进行训练与测试,文本类别涉及10个类别:categories = ['体育', '财经', '房产', '家居', '教育', '科技', '时尚', '时政', '游戏', '娱乐']。这一步的主要作用是将标签与文本分开,然后将文本与标签分别转化为模型所需要的数据格式。例如:文本:[我 爱 体育],标签:体育。转换成:文本[3 4 20],标签[1 0 0 0 0 0 0 0 0 0]。
    然后是padding,按照动态RNN的做法应该是根据不同batch里面句子的长度对不同batch进行padding,但本实验所用素材来自新闻,每个句子其实就是一篇报道,特别的长,故分配指定长度,长度为250,故按照这个长度来padding。最后是生成batch的过程。

    2 模型构建

    模型采用的是动态双向LSTM,对于输出结果,采用拼接的方式,输入词向量的shape是[batch_size,seq_length,embedding_dim],输出为[batch_size,seq_length,2*hidden_dim]。

           with tf.name_scope('Cell'):
                cell_fw = tf.contrib.rnn.BasicLSTMCell(pm.hidden_dim)
                Cell_fw = tf.contrib.rnn.DropoutWrapper(cell_fw, self.keep_pro)
    
                cell_bw = tf.contrib.rnn.BasicLSTMCell(pm.hidden_dim)
                Cell_bw = tf.contrib.rnn.DropoutWrapper(cell_bw, self.keep_pro)
    
            with tf.device('/cpu:0'), tf.name_scope('embedding'):
                self.embedding = tf.get_variable('embedding', shape=[pm.vocab_size, pm.embedding_dim],
                                                 initializer=tf.constant_initializer(pm.pre_trianing))
                self.embedding_input = tf.nn.embedding_lookup(self.embedding, self.input_x)
    
            with tf.name_scope('biRNN'):
    
                output, _ = tf.nn.bidirectional_dynamic_rnn(cell_fw=Cell_fw, cell_bw=Cell_bw, inputs=self.embedding_input,
                                                            sequence_length=self.seq_length, dtype=tf.float32)
                output = tf.concat(output, 2) #[batch_size, seq_length, 2*hidden_dim]
    
    接下来,就是Attention层。 Attention过程

    我们设置三个变量,分别是w,b,u,下标分别是小写的w,公式2是一个softmax过程,公式3是线性加权求和。在实际模型中,是需要对参数进行很多变型的,我们结合代码看一下。

            with tf.name_scope('attention'):
                u_list = []
                seq_size = output.shape[1].value
                hidden_size = output.shape[2].value #[2*hidden_dim]
                attention_w = tf.Variable(tf.truncated_normal([hidden_size, pm.attention_size], stddev=0.1), name='attention_w')
                attention_u = tf.Variable(tf.truncated_normal([pm.attention_size, 1], stddev=0.1), name='attention_u')
                attention_b = tf.Variable(tf.constant(0.1, shape=[pm.attention_size]), name='attention_b')
                for t in range(seq_size):
                    #u_t:[batch,attention]
                    u_t = tf.tanh(tf.matmul(output[:, t, :], attention_w) + tf.reshape(attention_b, [1, -1]))
                    u = tf.matmul(u_t, attention_u)
                    u_list.append(u)
                logit = tf.concat(u_list, axis=1)
                #[batch:seq_size]
                weights = tf.nn.softmax(logit, name='attention_weights')
                #weight:[batch:seq_size]
                out_final = tf.reduce_sum(output * tf.reshape(weights, [-1, seq_size, 1]), 1)
                #out_final:[batch,hidden_size]   
    

    为了给每个词赋予权重,那么权重的shape应该是[batch,seq_length]。
    为了得到每个词的权重,在程序中,对句子序列做了一个for循环,一个循环,得到的是同一个batch中不同序列同一步词的语义。
    例如:batch=64,t=1,也就是64个句子,每个句子第一个词的语义。所以每一步取出的output形状是[batch,hidden_size]。
    那么u_t输出为[batch,attention];
    下一步,u输出得到的结果是[batch,1];
    u_list是将seq_length个u的结果存入列表中;
    将列表按照第一维进行拼接,得到结果logit的形状[batch,seq_length]--以上是公式一的步骤;
    经过softmax,得到weights,shape依旧为[batch,seq_length]--公式二步骤;
    将weigths经过变形,[bacth,seq_length,1],然后使用点乘“*”,表示对应数值相乘;然后将第一维的值进行相加,也就是seq_length这一维度。这个步骤的意思:对于每一个句子,该句词汇与对应权重相乘,然后得到的和再相加,最后输出的形状[batch,hidden_size]。

    模型的最后,是全连+softmax层。这一步相对来说比较简单。

            with tf.name_scope('dropout'):
                self.out_drop = tf.nn.dropout(out_final, keep_prob=self.keep_pro)
    
            with tf.name_scope('output'):
                w = tf.Variable(tf.truncated_normal([hidden_size, pm.num_classes], stddev=0.1), name='w')
                b = tf.Variable(tf.zeros([pm.num_classes]), name='b')
                self.logits = tf.matmul(self.out_drop, w) + b
                self.predict = tf.argmax(tf.nn.softmax(self.logits), 1, name='predict')
    

    3 模型训练与测试

    训练时,每迭代一次,将训练得到的结果,保存到checkpoints;
    loss,accuracy的情况,保留到tensorboard中;
    每100个batch,输出此时的训练结果与测试结果。

       for epoch in range(pm.num_epochs):
           print('Epoch:', epoch+1)
           num_batchs = int((len(x_train) - 1) / pm.batch_size) + 1
           batch_train = batch_iter(x_train, y_train, batch_size=pm.batch_size)
           for x_batch, y_batch in batch_train:
               seq_len = sequence(x_batch)
               feed_dict = model.feed_data(x_batch, y_batch, seq_len, pm.keep_prob)
               _, global_step, _summary, train_loss, train_accuracy = session.run([model.optimizer, model.global_step, merged_summary,
                                                                                   model.loss, model.accuracy],feed_dict=feed_dict)
               if global_step % 100 == 0:
                   test_loss, test_accuracy = model.evaluate(session, x_test, y_test)
                   print('global_step:', global_step, 'train_loss:', train_loss, 'train_accuracy:', train_accuracy,
                         'test_loss:', test_loss, 'test_accuracy:', test_accuracy)
    
               if global_step % num_batchs == 0:
                   print('Saving Model...')
                   saver.save(session, save_path, global_step=global_step)
    
    训练与测试的情况如图所示,训练结果表明,模型收敛情况良好,准确度也较为理想。 训练与测试

    4 模型验证

    验证集数据量是500*10,使用最后保存的模型对验证集进行预测,并计算准确率。 模型验证

    从验证的情况来看,准确率达到了96.5%,从预测的前10项情况来看,模型较为理想。

    5 总结

    相对与之前的两层LSTM模型对文本进行分类,本文采用的双向LSTM+Attention模型。都进行了3次迭代,从结果上看,两层LSTM模型,准确率略高一点;但本文并没有用两层LSTM+Attention模型,所以对于这两次的结果不好做比较,有兴趣的可以下载github代码,把代码改成两层的结构。但从训练时间上来说,RNN网络越深,时间耗费的越久。
    加上之前,共介绍了4种文本分类的深度学习模型,基本可以满足一般的情况,这几种模型不仅可以用来进行文本分类,对于其他分类情况,稍微变动下,也是适应的,比如情感分类。
    对于深度学习分类的介绍,到此为止。以后会介绍深度学习、传统机器学习在中文分词,词性标注等应用的模型。

    参考

    https://blog.csdn.net/thriving_fcl/article/details/73381217
    https://zhuanlan.zhihu.com/p/46313756

    相关文章

      网友评论

        本文标题:深度学习--RNN+Attention 文本分类

        本文链接:https://www.haomeiwen.com/subject/xklcjqtx.html