当前位置:   article > 正文

基于BERT做中文文本分类(情感分析)_基于bert模型实现文本情感分类python

基于bert模型实现文本情感分类python

Bert

BERT是一种预训练语言表示的方法,这意味着我们在大型文本语料库(例如Wikipedia)上训练通用的“语言理解”模型,然后将该模型用于我们关心的下游NLP任务,BERT优于之前的方法,因为它是第一个用于预训练NLP的无监督,深度双向系统。

相关论文:

《Attention Is All You Need》

《BERT:Pre-training of Deep Bidirectional Transformers for Language Understanding》

之后可能会出一篇详解bert原理的文章。

一、环境搭建:

Tensorflow>=1.11.0 我使用的1.12.0

Python 3.6.8

使用GPU训练(官网说显存要求大于12g)

服务器:1080Ti 32G

二、下载模型:

下载bert:https://github.com/google-research/bert
下载bert预训练模型:https://storage.googleapis.com/bert_models/2018_11_03/chinese_L-12_H-768_A-12.zip

三、数据准备:

将你的语料分成3个文件,分别为train.csv,test.csv,dev.csv三个(我使用的是csv文件,它与tsv区别就是分隔符号的不同,我直接将csv的分隔符‘,’转成‘\t’),放入新建data文件夹下。

具体操作:

我的语料来自于情感分析比赛的,是判断新闻标题情感积极消极还是中性,首先使用pandas对语料进行处理,最终处理成“label+content”的格式。如图所示:

 

将语料分割成三个文件:我分割的比例是8:1:1,可以按照自己的比例进行分割。

  1. #!/usr/bin/env python
  2. import os
  3. import pandas as pd
  4. from sklearn.model_selection import train_test_split
  5. from sklearn.utils import shuffle
  6. def train_valid_test_split(x_data, y_data,
  7. validation_size=0.1, test_size=0.1, shuffle=True):
  8. x_, x_test, y_, y_test = train_test_split(x_data, y_data, test_size=test_size, shuffle=shuffle)
  9. valid_size = validation_size / (1.0 - test_size)
  10. x_train, x_valid, y_train, y_valid = train_test_split(x_, y_, test_size=valid_size, shuffle=shuffle)
  11. return x_train, x_valid, x_test, y_train, y_valid, y_test
  12. if __name__ == '__main__':
  13. path = "data/"
  14. pd_all = pd.read_csv(os.path.join(path, "outcleanfile.csv"))
  15. pd_all = shuffle(pd_all)
  16. x_data, y_data = pd_all.title, pd_all.label
  17. x_train, x_valid, x_test, y_train, y_valid, y_test = \
  18. train_valid_test_split(x_data, y_data, 0.1, 0.1)
  19. train = pd.DataFrame({'label': y_train, 'x_train': x_train})
  20. train.to_csv("data/train.csv", index=False, encoding='utf-8',sep='\t')
  21. valid = pd.DataFrame({'label': y_valid, 'x_valid': x_valid})
  22. valid.to_csv("data/dev.csv", index=False, encoding='utf-8',sep='\t')
  23. test = pd.DataFrame({'label': y_test, 'x_test': x_test})
  24. test.to_csv("data/test.csv", index=False, encoding='utf-8',sep='\t')

最终文件结构如图:

四、修改代码:

1.新定义处理类:

  1. class NewsProcessor(DataProcessor):
  2. """Processor for the WeiBo data set ."""
  3. def get_train_examples(self, data_dir):
  4. """See base class."""
  5. return self._create_examples(
  6. self._read_tsv(os.path.join(data_dir, "train.csv")), "train")
  7. def get_dev_examples(self, data_dir):
  8. """See base class."""
  9. return self._create_examples(
  10. self._read_tsv(os.path.join(data_dir, "dev.csv")), "dev")
  11. def get_test_examples(self, data_dir):
  12. """See base class."""
  13. return self._create_examples(
  14. self._read_tsv(os.path.join(data_dir, "test.csv")), "test")
  15. def get_labels(self):
  16. """See base class."""
  17. return ["0", "1", "2"]
  18. def _create_examples(self, lines, set_type):
  19. """Creates examples for the training and dev sets."""
  20. examples = []
  21. for (i, line) in enumerate(lines):
  22. # All sets have a header
  23. if i == 0: continue
  24. guid = "%s-%s" % (set_type, i)
  25. text_a = tokenization.convert_to_unicode(line[1])
  26. label = tokenization.convert_to_unicode(line[0])
  27. examples.append(
  28. InputExample(guid=guid, text_a=text_a, text_b=None, label=label))
  29. return examples

2.处理类注册:

在bert文件夹下的run_classifier.py中的def main(_):函数中将processors的内容增加为:

  1. processors = {
  2. "cola": ColaProcessor,
  3. "mnli": MnliProcessor,
  4. "mrpc": MrpcProcessor,
  5. "xnli": XnliProcessor,
  6. "news": NewsProcessor
  7. }

五、训练模型:

网上很多使用shell脚本运行,但是我试了n次总是传不进去参数,直接修改了python文件里的参数,不过还是把脚本放在这了,知道问题的小伙伴可以告知一声。执行脚本或python文件前新建output文件用于训练输出。

  1. export DATA_DIR=数据所在的路径
  2. export BERT_BASE_DIR=预训练模型所在的路径
  3. python run_classifier.py \
  4.  --task_name=news \
  5.  --do_train=true \
  6.  --do_eval=true \
  7.  --data_dir=$DATA_DIR/ \
  8.  --vocab_file=$BERT_BASE_DIR/vocab.txt \
  9.  --bert_config_file=$BERT_BASE_DIR/bert_config.json \
  10.  --init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \
  11.  --max_seq_length=128 \
  12.  --train_batch_size=32 \
  13.  --learning_rate=2e-5 \
  14.  --num_train_epochs=3.0 \
  15.  --output_dir=/output

内存不足调整这两个参数:

max_seq_length:发布的模型经过训练,序列长度最大为512,但是您可以使用更短的最大序列长度进行微调,以节省大量内存。train_batch_size:内存使用也与批处理大小成正比。

训练时长根据配置及数据情况而定,我的应该几个小时就跑完了。训练结果保存在output的eval_results.txt。如下:

六、分类预测

将刚才的脚本文件修改为如下:

  1. python run_classifier.py
  2. --task_name=news
  3. --do_predict=true
  4. --data_dir=./glue
  5. --vocab_file=./uncased/uncased_L-12_H-768_A-12/vocab.txt
  6. --bert_config_file=./uncased/uncased_L-12_H-768_A-12/bert_config.json
  7. --init_checkpoint=./tmp/emotion/bert_model.ckpt
  8. --max_seq_length=128
  9. --output_dir=./output/emotion_out/

或者直接更改run_classifier.py中的参数,将do_predict改为True,do_train和do_eval改为False。

最终得到一个tsv文件,文件中每一条是预测各个类(0、1、2)的概率,如下图所示:

显然,概率并不是我们想要的,我们需要将概率最终转换成类别:

  1. import os
  2. import pandas as pd
  3. if __name__ == '__main__':
  4. path = "output/emotion_out/"
  5. pd_all = pd.read_csv(os.path.join(path, "test_results.tsv") ,sep='\t',header=None)
  6. data = pd.DataFrame(columns=['polarity'])
  7. print(pd_all.shape)
  8. for index in pd_all.index:
  9. neutral_score = pd_all.loc[index].values[0]
  10. positive_score = pd_all.loc[index].values[1]
  11. negative_score = pd_all.loc[index].values[2]
  12. if max(neutral_score, positive_score, negative_score) == neutral_score:
  13. # data.append(pd.DataFrame([index, "neutral"],columns=['id','polarity']),ignore_index=True)
  14. data.loc[index+1] = ["neutral"]
  15. elif max(neutral_score, positive_score, negative_score) == positive_score:
  16. #data.append(pd.DataFrame([index, "positive"],columns=['id','polarity']),ignore_index=True)
  17. data.loc[index+1] = [ "positive"]
  18. else:
  19. #data.append(pd.DataFrame([index, "negative"],columns=['id','polarity']),ignore_index=True)
  20. data.loc[index+1] = [ "negative"]
  21. #print(negative_score, positive_score, negative_score)
  22. data.to_csv(os.path.join(path, "pre_sample.tsv"),sep = '\t')
  23. #print(data)

最终得到预测结果:

最后数据可能因为不是均匀分布,导致结果有些不准确,接下来从数据入手,整理下数据集。

参考链接:

https://github.com/google-research/bert

https://blog.csdn.net/qq874455953/article/details/90276116

 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号