Google BERT中文应用之微博情感极性分析——转载

转载自:https://zhuanlan.zhihu.com/p/55856680

Google 前段时间开源了他们的 BERT -- BidirectionalEncoderRepresentations fromTransformers 模型,使用多头注意力和位置嵌入,替换不易并行的循环神经网络,一举打破自然语言处理领域11个不同问题的最好记录。这个模型的开源,直接将自然语言处理推动到了一个新的时代,

google-research/bert​github.com图标

上周末试着用 Google BERT 的阅读理解功能提取了《红楼梦》中对话的人物,

hahakity:BERT 应用之《红楼梦》中对话人物提取​zhuanlan.zhihu.com图标

觉得此预训练模型真是NLP界的屠龙刀倚天剑。不需要结巴分词,不需要自己训练或者下载词向量,不需要Bi-LSTM,就那么粗鲁的把 BERT 的微调任务数据改成我们的数据,就可以得到比条件随机场好得多的结果。最关键的是,很多自然语言处理的判别和序列标注任务都可以用阅读理解来完成。再接再厉,这个周末尝试用BERT做中文文本分类。训练数据是从网上下载的新浪微博情感极性分类数据。此数据的每一条都包含一段新浪微博评论,以及评论的极性 -- 正向 或 负向。本次实验会先构建一个作为对比基准的 LSTM分类器,然后修改 Google BERT 的 run_classfier.py 文件,训练并分析微博情感极性。本次实验的代码和数据集可以开放获取,

https://gitlab.com/snowhitiger/weibo_sentiment_analysis.git​gitlab.com图标

基准模型

先建立基准模型,使用循环神经网络的单层 LSTM 分类器,来自Keras自带的对 IMDB 电影英文评论做极性分析的例子。此模型会作为对比BERT表现的基准模型,

x_train = sequence.pad_sequences(x_train, maxlen=maxlen)
x_test = sequence.pad_sequences(x_test, maxlen=maxlen)

model = Sequential()
model.add(Embedding(max_features, 128))
model.add(LSTM(128, dropout=0.2, recurrent_dropout=0.2))
model.add(Dense(1, activation='sigmoid'))

# try using different optimizers and different optimizer configs
model.compile(loss='binary_crossentropy',
                    optimizer='adam',
                    metrics=['accuracy'])

在单机上训练两个Epoch,得到测试精度为 ~ 95%。训练15个Epoch,测试精度为 ~97%。原则上说,这个精度已经非常之高,但是按20000组测试数据来看,3%的误差也对应着600多组错误分类的数据。改用双向 LSTM 可能会改进预言结果,不过我们现在想尝试的是 Google的预训练微调模型 BERT,所以就先省略其他的尝试。

准备数据

感谢这位昵称为SophonPlus的朋友在Github上共享了很多中文NLP训练语料,

SophonPlus/ChineseNlpCorpus​github.com图标

这次实验使用其中的数据集:weibo_senti_100k

下载数据集后,下面的脚本可以把微博情感极性分类数据拆分成训练,验证,测试集,保证其可以被 BERT 的 runclassifier.py 中的 _read_tsv() 函数正确读入

#!/usr/bin/env python
import os
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.utils import shuffle

def train_valid_test_split(x_data, y_data,
        validation_size=0.1, test_size=0.1, shuffle=True):
    x_, x_test, y_, y_test = train_test_split(x_data, y_data, test_size=test_size, shuffle=shuffle)
    valid_size = validation_size / (1.0 - test_size)
    x_train, x_valid, y_train, y_valid = train_test_split(x_, y_, test_size=valid_size, shuffle=shuffle)
    return x_train, x_valid, x_test, y_train, y_valid, y_test

if __name__ == '__main__':
    path = "weibo_data/"
    pd_all = pd.read_csv(os.path.join(path, "weibo_senti_100k.csv"))
    pd_all = shuffle(pd_all)
    x_data, y_data = pd_all.review, pd_all.label

    x_train, x_valid, x_test, y_train, y_valid, y_test = \
            train_valid_test_split(x_data, y_data, 0.1, 0.1)

    train = pd.DataFrame({'label':y_train, 'x_train': x_train})
    train.to_csv("train.csv", index=False, sep='\t')
    valid = pd.DataFrame({'label':y_valid, 'x_valid': x_valid})
    valid.to_csv("dev.csv", index=False, sep='\t')
    test = pd.DataFrame({'label':y_test, 'x_test': x_test})
    test.to_csv("test.csv", index=False, sep='\t')

 

修改模型

在 runclassifier.py 中有好几个文本分类的模型,我们只需要照葫芦画瓢,写一个自己的微博情感分类模型即可,所做的只不过是按格式读入我们准备的文本与标签数据。将下述代码加入到 run_classfier.py,

class WeiboProcessor(DataProcessor):
  """Processor for the WeiBo data set ."""

  def get_train_examples(self, data_dir):
    """See base class."""
    return self._create_examples(
        self._read_tsv(os.path.join(data_dir, "train.csv")), "train")

  def get_dev_examples(self, data_dir):
    """See base class."""
    return self._create_examples(
        self._read_tsv(os.path.join(data_dir, "dev.csv")), "dev")

  def get_test_examples(self, data_dir):
    """See base class."""
    return self._create_examples(
        self._read_tsv(os.path.join(data_dir, "test.csv")), "test")

  def get_labels(self):
    """See base class."""
    return ["0", "1"]

  def _create_examples(self, lines, set_type):
    """Creates examples for the training and dev sets."""
    examples = []
    for (i, line) in enumerate(lines):
      # All sets have a header
      if i == 0: continue
      guid = "%s-%s" % (set_type, i)
      text_a = tokenization.convert_to_unicode(line[1])
      label = tokenization.convert_to_unicode(line[0])
      examples.append(
          InputExample(guid=guid, text_a=text_a, text_b=None, label=label))
    return examples

 

此外,还要在这个文件的 main 函数中注册我们添加的模型,注意 cola, mnli, mrpc 和 xnli 都是BERT自带的文本分类任务,weibo 那一项是我们新加的,

 processors = {
 "cola": ColaProcessor,
 "mnli": MnliProcessor,
 "mrpc": MrpcProcessor,
 "xnli": XnliProcessor,
 "weibo":WeiboProcessor
 }

至此,模型已修改完毕。

训练 BERT 微调任务

在 test_weibo.sh 中做相应的修改,运行: sh test_weibo.sh 即可开训,预测数据及精度放在weibo_output文件夹。

export BERT_BASE_DIR="path_to/chinese_L-12_H-768_A-12"
export WEIBO_DIR="path_to/weibo_data/"

python path_to/bert/run_classifier.py \
  --task_name=WeiBo \
  --do_train=True \
  --do_eval=True \
  --data_dir=$WEIBO_DIR \
  --vocab_file=$BERT_BASE_DIR/vocab.txt \
  --bert_config_file=$BERT_BASE_DIR/bert_config.json \
  --init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \
  --train_batch_size=32 \
  --learning_rate=5e-5 \
  --num_train_epochs=2.0 \
  --max_seq_length=128 \
  --output_dir=path_to/weibo_output/

 

运行结果

eval_accuracy = 0.97816485
eval_loss = 0.06019879

结果与LSTM相比并没有提高很多,可能是任务太简单了吧。检查预测错误的最后几个案例,发现标签本身也有问题,前面的标签 1 表示 高兴,积极的情绪,0 表示生气,消极的情绪。如下所示是BERT预言错误的例子,很多数据的原始标签是错的,所以此任务的分类精度不能说明太多问题,仅做参考。手动标错的数据会加黑 --

1 各种噩耗,速生鸡、塑化剂...我对洋洋说:"咱吃什么呢?吃草吧!"他回:"有农药!"我又说;...
1 上个月从德国定的eisenmann排气等了一个多月了,还没到货,真起急。今天过来西国贸这边只...
0 回复xxx:这个要吃,有计划[哈哈] //xxx:?得?有好吃的?仁冰[哈哈...
1 我的长假很开心?[嘻嘻]我的长假不尽兴?[抓狂]不管你是哪样,周六来看大本营,让陈奕迅为你的...
1 绝了[哈哈][哈哈] //xxx: [哈哈]笑暴了 //xxx: [哈哈] 玛滴!...
0 回复xxx:惭愧、惭愧,实事求是吧了! //xxx:你倒是会冲些呢嘛 /...
0 可能是拍电视剧吧,爱情雨。//xxx: 呵呵,心跳过快,脑子一片空百//xxxxx...
1 芒果[花心]芒果我爱你[爱你],可惜不能吃掉你~痛苦!想吃不能吃~[馋嘴][泪]
0 //xxx:xxxxx-海上梦 是个跨界作品是个新生儿,编导们还在创新还在提高演员们大进...
0 好不容易有我想看的比赛,晚上守着电视机等看马术盛装舞步个人决赛,结果从快结束处才开始直播,并...
1 疑惑的转~[思考] //xxx:很和谐!// xxx: [晕] // xxx...
1 #单城双恋#超级好看,看完很想去马拉玩????[鼓掌][抓狂]
0 这个我必须给你扎针了. 我可是娘家人//xxx: 分明是婚前最后的微笑[嘻嘻] //@...
1 必须转发[转发]//xxx: [晕]怎么被发出来啦。。同学们低调低调[害羞...
1 回复xxx:别灰心。。多转转哈 还有三次机会呢[嘻嘻] //@那女-ren-小...
1 怕老汉我死了,你成孤儿哈?[酷] //xxx:回复xxx:一派胡言、你个超级大神...
1 左边的你也跑不了//xxx: 右边的真像你![哈哈]//xxx: [笑哈哈]...
1 !!!!!妈呀,不是吧?!!! //xxx:?得胸啊~~~~ //xxx: ...
1 男男女女女好几个,没一个会打架的//xxx: //xxx:好[鼓掌] //xxx:...
1 [哈哈]很有娱乐精神 //xxx:[哇哈哈]卧槽!必须一位!!xxxxxxxxx ...
1 回复xxx:苦甜口吧![晕][晕] //xxx:苞米用火烤糊了是甜的还是苦的? //...
1 干扰的我不能工作。[晕]。公猫没了蛋蛋以后黏力加倍![爱你]
1 回复xxx:说得好,绿色多了,没注意搭配,光想着牙口不好滴小白鲨喜欢吃了,下...
1 人生已多风雨...接受现实吧[偷笑] //xxx: 往事不要再提[悲伤][悲伤]//@D...
0 回复xxx: 哈哈,我想说来着,没敢,还是你有魄力!不过猪同学那么温婉脾气,后果...
1 [哈哈][哈哈][哈哈]//xxx:[怒]
1 [花心][爱你][围观]我今天。。。[泪] //xxx:良师益友![赞]
1 [太阳][愤怒][熊猫][嘻嘻][猪头]
0 家里新房装修,这孩子上蹿下跳的到处玩,开心的不得了~ 两岁了,已经会跟我玩玩对话了。骗他也越...

为了用BERT训练出更好的中文文本情感分类器,可能需要更好的训练数据集了 :)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值