第22天:NLP实战(六)——基于PaddleHub的疫情期间网民情绪识别

时间:2022-07-24
本文章向大家介绍第22天:NLP实战(六)——基于PaddleHub的疫情期间网民情绪识别,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

  首先给大家说一声抱歉,最近一直在准备秋招的事宜,没有很多时间学习NLP相关的知识。前面通过五次的实战,大致的将自然语言处理中经常用到的算法过了一遍,并且循序渐进,由浅入深。由刚开始的教我们如何从零开始获取语料,并且进行常用的数据分析到深度学习中最为简单的DNN网络带大家将环境搭建好,并且初步的介绍一个深度学习模型的流程,接下来就是到了最为核心的CNN模型、RNN中的GRU模型,并且分别用了典型的案例进行了实践。上一次我们通过NLP中典型的词向量对其进行了项目电影评论情感分析。前几次的项目都是利用百度飞桨的AI·Studio的paddle来进行的,因此本次就是利用paddle hub进行的疫情期间网民情绪识别。

背景介绍

  新型冠状病毒(COVID-19)感染的肺炎疫情牵动着全国人民的心,全国同舟共济、众志成城,打响了一场没有硝烟的疫情阻击战。习主席指出:要鼓励运用大数据、人工智能、云计算等数字技术,在疫情监测分析、病毒溯源、防控救治、资源调配等方面更好发挥支撑作用。为助力疫情防控和疫情之后的经济社会恢复工作,推动北京市政府数据开放,吸纳大数据产业顶尖社会资源,充分释放专业人才智慧资源,北京市经济和信息化局、中国计算机学会大数据专家委员会联合主办科技战疫·大数据公益挑战赛。   2019新型冠状病毒(2019-nCoV)感染的肺炎疫情发生对人们生活生产的方方面面产生了重要影响,并引发国内舆论的广泛关注,众多网民参与疫情相关话题的讨论。为了帮助政府掌握真实社会舆论情况,科学高效地做好防控宣传和舆情引导工作,本师资培训项目针对疫情相关话题开展网民情绪识别的任务。

任务描述

  数据给定了微博ID和微博内容,需要同学们设计算法对微博内容进行情绪识别,判断微博内容是积极的、消极的还是中性的。数据集依据与“新冠肺炎”相关的230个主题关键词进行数据采集,抓取了2020年1月1日—2020年2月20日期间共计100万条微博数据,并对其中10万条数据进行人工标注,标注分为三类,分别为:1(积极),0(中性)和-1(消极)。微博内容包括了文本、图片、视频等内容。本项目选用文本内容进行微博内容的情绪识别。采用Macro-F1值进行评分。

数据集介绍

  我们本次项目使用的数据集是微博上在疫情期间的微博上的评论。本数据集可以在疫情期间网民情绪识别上自行下载。本人将数据集下载下来了,为了以防大家因为各种原因下载不下来,将数据集上传到了百度云,大家可以自行下载[验证码:7m38]。我们可以大致查看其数据集的相关内容:   大概的框架如图所示:

  接下来是train_label的相关内容:

  其中的微博ID和结果如下:

  我们看下test_data的数据集内容如下:

  实验环境搭建以及实验平台前几篇文章均介绍过,只要是跑了上一篇文章的这次实验环境不用动,要是没跑的可以去跑一遍上一个项目:NLP实战(五)——词向量Skip-gram实践,当然也可以按照前面介绍搭建好环境可以直接跑本项目。

项目实现

1、数据分析

  首先我们先将挂载的数据集解压出来。具体代码实现如下:

!cd data/data22724 && unzip -o test_dataset.zip
!cd data/data22724 && unzip -o "train_ dataset.zip"

  解压的结果如下:

  由于数据采用GB2312编码,因此先将数据读出,转换为utf8编码再重新写入,方便后续pandas库的使用处理。

# 转换编码
def re_encode(path):
    with open(path, 'r', encoding='GB2312', errors='ignore') as file:
        lines = file.readlines()
    with open(path, 'w', encoding='utf-8') as file:
        file.write(''.join(lines))
        
re_encode('data/data22724/nCov_10k_test.csv') # 这里写你自己数据集的路径
re_encode('data/data22724/nCoV_100k_train.labled.csv') # 写自己文件的路径

2、数据预览

  读取数据,查看数据大小、列名,可以看到:训练集包含十万条数据,测试集包含一万条数据。当然,数据包括了微博id, 微博发布时间, 发布人账号, 微博中文内容, 微博图片, 微博视频, 情感倾向。其中微博中文内容是我们将使用的训练和测试数据,情感倾向为问题标签。

# 读取数据
import pandas as pd
train_labled = pd.read_csv('data/data22724/nCoV_100k_train.labled.csv', engine ='python')
test = pd.read_csv('data/data22724/nCov_10k_test.csv', engine ='python')
print(train_labled.shape)
print(test.shape)
print(train_labled.columns)

  打印的结果如下:

  我们首先查看数据,实现结果如下:

train_labled.head(3)
test.head(3)

  数据表打印如图所示:

3、标签分布

  问题标签分为三类,分别为:1(积极),0(中性)和-1(消极),其分布如下。

%matplotlib inline
train_labled['情感倾向'].value_counts(normalize=True).plot(kind='bar');

  其中的分布图如图所示:

  从图中可以看出,中性数据数量占一半以上,积极次之,消极最少。此外,数据中还包含少量的未知标签,我们将其视为异常数据剔除。我可以清除异常标签数据。

# 清除异常标签数据
train_labled = train_labled[train_labled['情感倾向'].isin(['-1','0','1'])]

4、文本长度

  训练集文本长度最大为 241,平均为 87。我们可以查看其中数据的分布。

train_labled['微博中文内容'].str.len().describe()

5、用PaddleHub快速实现Fine Tune

  如果只考虑微博文本数据,需要解决的问题其实是文本分类问题。随着2018年ELMo、BERT等模型的发布,NLP领域进入了“大力出奇迹”的时代。采用大规模语料上进行无监督预训练的深层模型,在下游任务数据上微调一下,即可达到很好的效果。曾经需要反复调参、精心设计结构的任务,现在只需简单地使用更大的预训练数据、更深层的模型便可解决。因此NLP项目的入手门槛也随之变低。新手只要选择好预训练模型,在自己数据上微调,很多情况下就可以达到很好的效果。本项目将采用百度出品的PaddleHub预训练模型微调工具,快速构建比赛方案。模型方面则选择ERNIE模型。   ERNIE 1.0 通过建模海量数据中的词、实体及实体关系,学习真实世界的语义知识。相较于 BERT 学习原始语言信号,ERNIE 直接对先验语义知识单元进行建模,增强了模型语义表示能力。PaddlePaddle 出品的预训练模型管理和迁移学习工具,便捷地获取PaddlePaddle生态下的预训练模型,完成模型的管理和一键预测。配合使用Fine-tune API,可以基于大规模预训练模型快速完成迁移学习,让预训练模型能更好地服务于用户特定场景的应用。   其中的流程如下:

  • 将数据整理成特定格式
  • 定义Dataset数据类
  • 加载模型
  • 构建reader数据读取接口
  • 确定finetune训练策略
  • 配置finetune参数
  • 确定任务,开始finetune(训练)
  • 预测

  以上流程每个步骤只需一两句代码即可完成,使得我们可以快速得到解决方案。首先,我们应该要更新并且安装PaddleHub.只需要pip安装即可。

!pip install  paddlehub==1.6.0 -i https://pypi.tuna.tsinghua.edu.cn/simple

6、数据整理

  PaddleHub文本任务的输入数据格式为:

  我们将数据划分为训练集和验证集,比例为8:2, 然后保存为文本文件,两列需用tab分隔符隔开。

# 划分验证集,保存格式  text[t]label
from sklearn.model_selection import train_test_split
train_labled = train_labled[['微博中文内容', '情感倾向']]
train, valid = train_test_split(train_labled, test_size=0.2, random_state=2020)
train.to_csv('/home/aistudio/data/data22724/train.txt', index=False, header=False, sep='t')
valid.to_csv('/home/aistudio/data/data22724/valid.txt', index=False, header=False, sep='t')

7、自定义数据加载

  加载文本类自定义数据集,用户仅需要继承基类BaseNLPDatast,修改数据集存放地址以及类别即可。这里我们没有带标签的测试集,所以test_file直接用验证集代替 “valid.txt” 。

# 自定义数据集
import os
import codecs
import csv

from paddlehub.dataset.base_nlp_dataset import BaseNLPDataset

class MyDataset(BaseNLPDataset):
    """DemoDataset"""
    def __init__(self):
        # 数据集存放位置
        self.dataset_dir = "/home/aistudio/data/data22724"
        super(MyDataset, self).__init__(
            base_path=self.dataset_dir,
            train_file="train.txt",
            dev_file="valid.txt",
            test_file="valid.txt",
            train_file_with_header=False,
            dev_file_with_header=False,
            test_file_with_header=False,
            # 数据集类别集合
            label_list=["-1", "0", "1"])

dataset = MyDataset()
for e in dataset.get_train_examples()[:3]:
    print("{}t{}t{}".format(e.guid, e.text_a, e.label))

打印结果如下:

8、加载模型

  这里我们选择ERNIE1.0的中文预训练模型。当然paddlehub也有其他的模型。我们只需修改name=‘xxx’ 就可以切换不同的模型。

# 加载模型
import paddlehub as hub
module = hub.Module(name="ernie")

  加载的结果如下:

9、构建Reader

  构建一个文本分类的reader,reader负责将dataset的数据进行预处理,首先对文本进行切词,接着以特定格式组织并输入给模型进行训练。通过max_seq_len可以修改最大序列长度,若序列长度不足,会通过padding方式补到max_seq_len, 若序列长度大于该值,则会以截断方式让序列长度为max_seq_len, 这里我们设置为128。

# 构建Reader
reader = hub.reader.ClassifyReader(
    dataset=dataset,
    vocab_path=module.get_vocab_path(),
    sp_model_path = module.get_spm_path(),
    word_dict_path = module.get_word_dict_path(),
    max_seq_len=128
)

10、finetune策略

  选择迁移优化策略。此处我们设置最大学习率为 learning_rate=5e-5。权重衰减设置为 weight_decay=0.01,其避免模型overfitting。训练预热的比例设置warmup_proportion=0.1, 这样前10%的训练step中学习率会逐步提升到learning_rate。

# finetune策略1
strategy = hub.L2SPFinetuneStrategy(
    learning_rate=1e-4,
    optimizer_name="adam",
    regularization_coeff=1e-3)

11、运行配置

  设置训练时的epoch,batch_size,模型储存路径等参数。这里我们设置训练轮数 num_epoch = 1,模型保存路径 checkpoint_dir=“model”, 每100轮(eval_interval)对验证集验证一次评分,并保存最优模型。

# 运行配置
config = hub.RunConfig(
    use_cuda=True,
    num_epoch= 10,
    batch_size= 128,
    checkpoint_dir="hub_finetune",
    strategy=strategy
    )

12、组建Finetune Task

  对于文本分类任务,我们需要获取模型的池化层输出,并在后面接上全连接层实现分类。因此,我们先获取module的上下文环境,包括输入和输出的变量,并从中获取池化层输出作为文本特征。再接入一个全连接层,生成Task。评价指标为F1,因此设置metrics_choices=[“f1”]。

# Finetune Task
inputs, outputs, program = module.context(
    trainable=True, max_seq_len= 128)

# Use "pooled_output" for classification tasks on an entire sentence.
pooled_output = outputs["pooled_output"]

feed_list = [
    inputs["input_ids"].name,
    inputs["position_ids"].name,
    inputs["segment_ids"].name,
    inputs["input_mask"].name,
]

cls_task = hub.TextClassifierTask(
        data_reader=reader,
        feature=pooled_output,
        feed_list=feed_list,
        num_classes=dataset.num_labels,
        config=config,
        metrics_choices=["f1"])

13、开始finetune

  我们使用finetune_and_eval接口就可以开始模型训练,finetune过程中,会周期性的进行模型效果的评估。

# finetune
run_states = cls_task.finetune_and_eval()

14、预测

  finetune完成后,调用predict接口即可完成预测,预测数据格式为二维的list:[[‘第一条文本’], [‘第二条文本’], […], …]

# 预测
import numpy as np
    
inv_label_map = {val: key for key, val in reader.label_map.items()}

# Data to be prdicted
data = test[['微博中文内容']].fillna(' ').values.tolist()

run_states = cls_task.predict(data=data)
results = [run_state.run_results for run_state in run_states]

15、生成结果

# 生成预测结果
proba = np.vstack([r[0] for r in results])
prediction = list(np.argmax(proba, axis=1))
prediction = [inv_label_map[p] for p in prediction]
        
submission = pd.DataFrame()
submission['id'] = test['微博id'].values
submission['id'] = submission['id'].astype(str) + ' '
submission['y'] = prediction
np.save('proba.npy', proba)
submission.to_csv('result_ernie.csv', index=False)
submission.head()

  让我们来看看具体预测结果:

submission['text'] = test[['微博中文内容']].fillna(' ').values
submission['label'] = submission['y'].values
display(submission[['text', 'label']][175:180])

总结

  本项目使用了PaddleHub完成了疫情期间网民情绪识别比赛方案的快速构建, 并得到了不错的识别效果。PaddleHub包含了大量的预训练模型。不管是NLP还是CV,我们都可以使用PaddleHub来实现我们的baseline,不需要繁琐的代码,就可以快速切换不同模型来进行实验效果验证。疫情之下,掌握真实社会舆论情况,才能科学地做好防控宣传和舆情引导工作,AI技术可以帮助我们高效地完成识别。这些代码均可运行,希望大家在有时间的情况下,可以动手运行一遍,感受一下paddle hub是如何被应用的,另外就是感受一下一个网络的训练过程和预测过程。当然在文中也多次提到需要大家注意的几个问题,希望大家在练习的时候要特别关注,练习完之后感觉收获满满。加油,希望我们都学有所获,坚持练习,我们未来可期。