【语言与知识主题月】情感分析的多种方法评测
才能我浪费99 发布于2019-12-10 11:05 浏览:455 回复:10
0
收藏
最后编辑于2020-01-03

1. 简介

现在情感分析有很广泛的应用,例如:

评论分析与决策,通过对产品多维度评论观点进行倾向性分析,给用户提供该产品全方位的评价,方便用户进行决策
评论分类,通过对评论进行情感倾向性分析,将不同用户对同一事件或对象的评论内容按情感极性予以分类展示
舆情监控,通过对需要舆情监控的实时文字数据流进行情感倾向性分析,把握用户对热点信息的情感倾向性变化
等等

百度针对情感分析也提供了多种解决方案,包括:

百度情感倾向分析服务:对包含主观信息的文本进行情感倾向性判断,可支持在线训练模型调优效果,为口碑分析、话题监控、舆情分析等应用提供帮助。

ERINE模型:今年百度发布了知识增强的语义表示模型 ERNIE(Enhanced Representation from kNowledge IntEgration),并发布了基于 PaddlePaddle 的开源代码与模型,在语言推断、语义相似度、命名实体识别、情感分析、问答匹配等自然语言处理(NLP)各类中文任务上的验证显示,模型效果全面超越 BERT。

情感倾向分析(Sentiment Classification,简称Senta)针对带有主观描述的中文文本,可自动判断该文本的情感极性类别并给出相应的置信度,能够帮助企业理解用户消费习惯、分析热点话题和危机舆情监控,为企业提供有利的决策支持。PaddleHub现在这方面的模型有:senta_lstm,senta_gru,senta_cnn,senta_bow,senta_bilstm,emotion_detection_textcnn等。这些PaddleHub Module预训练数据集为百度自建数据集,支持预测和Fine-tune。

本文对使用百度情感倾向分析服务进行在线情感分析及使用百度ERINE模型、PaddleHub情感分析模型进行离线情感分析进行评测分析,并提供了详细的使用攻略及代码,方便大家使用。

2 情感倾向分析API调用攻略(Python3)

2.1 认证授权:

在开始调用任何API之前需要先进行认证授权,具体的说明请参考:

http://ai.baidu.com/docs#/Auth/top

具体Python3代码如下:

# -*- coding: utf-8 -*-
#!/usr/bin/env python

import urllib
import json
#client_id 为官网获取的AK, client_secret 为官网获取的SK
client_id =【百度云应用的AK】
client_secret =【百度云应用的SK】

#获取token
def get_token():
    host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=' + client_id + '&client_secret=' + client_secret
    request = urllib.request.Request(host)
    request.add_header('Content-Type', 'application/json; charset=UTF-8')
    response = urllib.request.urlopen(request)
    token_content = response.read()
    if token_content:
        token_info = json.loads(token_content)
        token_key = token_info['access_token']
    return token_key



2.2 情感倾向分析接口调用:
详细说明请参考:http://ai.baidu.com/docs#/NLP-API/57b9b630

接口描述
情感倾向分析接口(通用版):自动对包含主观信息的文本进行情感倾向性判断(积极、消极、中性),并给出相应的置信度。为口碑分析、话题监控、舆情分析等应用提供基础技术支持,同时支持用户自行定制模型效果调优。

请求说明
HTTP方法: POST
请求URL: https://aip.baidubce.com/rpc/2.0/nlp/v1/sentiment_classify

URL参数:
参数 值
access_token 通过API Key和Secret Key获取的access_token,参考“Access Token获取”

Header如下:
参数 值
Content-Type application/json

Body请求示例:
{
"text": "苹果是一家伟大的公司"
}

请求参数
参数 类型 描述 是否必填
text string 文本内容,最大2048字节


返回说明
参数 说明 描述
log_id uint64 请求唯一标识码
sentiment int 表示情感极性分类结果,0:负向,1:中性,2:正向
confidence float 表示分类的置信度,取值范围[0,1]
positive_prob float 表示属于积极类别的概率 ,取值范围[0,1]
negative_prob float 表示属于消极类别的概率,取值范围[0,1]

Python3调用代码如下:

#调用情感分类接口        
def get_classify(content):
    print (content)
    token=get_token()
    url = 'https://aip.baidubce.com/rpc/2.0/nlp/v1/sentiment_classify'
    params = dict()
    params['text'] = content
    params = json.dumps(params).encode('utf-8')
    access_token = token
    url = url + "?access_token=" + access_token
    request = urllib.request.Request(url=url, data=params)
    request.add_header('Content-Type', 'application/json')
    response = urllib.request.urlopen(request)
    content = response.read()
    if content:
        content=content.decode('gb2312')
        #print (content)
        data = json.loads(content)
        data=data['items'][0]
        sentiment=data['sentiment']
        if sentiment==0:
            sentiment='负向'
        elif sentiment==1:
            sentiment='中性'
        else:
            sentiment='正向'
        
        print ('情感分类结果:',sentiment)
        print ('分类的置信度:',data['confidence'])
        print ('积极类别概率:',data['positive_prob'])
        print ('消极类别概率:',data['negative_prob'])
        
test_list = [
    "这个宾馆比较陈旧了,特价的房间也很一般。总体来说一般", 
    "交通方便;环境很好;服务态度很好 房间较小",
    "稍微重了点,可能是硬盘大的原故,还要再轻半斤就好了。" ,
    "服务很不错,下次还会来。" ,
    "前台接待太差,下次不会再选择入住此店啦", 
    "菜做的很好,味道很不错。" ,
    "19天硬盘就罢工了,算上运来的一周都没用上15天,你说这算什么事呀",
    "现在是高峰期,人太多了,我们晚点来吧"
]
        
import datetime
print (datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
for text in test_list:
    get_classify(text)
print (datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))

 

3、ERINE模型

ERNIE 通过建模海量数据中的词、实体及实体关系,学习真实世界的语义知识。相较于 BERT 学习原始语言信号,ERNIE 直接对先验语义知识单元进行建模,增强了模型语义表示能力,以 Transformer 为网络基本组件,以Masked Bi-Language Model和 Next Sentence Prediction 为训练目标,通过预训练得到通用语义表示,再结合简单的输出层,应用到下游的 NLP 任务。我们可以使用ERINE进行情感分类,具体步骤如下:

1,首先我们要在PaddleHub中选择ernie作为预训练模型,进行Fine-tune。ChnSentiCorp数据集是一个中文情感分类数据集。PaddleHub已支持加载该数据集。关于该数据集,详情请查看ChnSentiCorp数据集使用。
https://github.com/PaddlePaddle/PaddleHub/wiki/PaddleHub-API:-Dataset

2,生成Reader:接着生成一个文本分类的reader,reader负责将dataset的数据进行预处理,首先对文本进行切词,接着以特定格式组织并输入给模型进行训练。
ClassifyReader的参数有以下三个:
dataset: 传入PaddleHub Dataset;
vocab_path: 传入ERNIE/BERT模型对应的词表文件路径;
max_seq_len: ERNIE模型的最大序列长度,若序列长度不足,会通过padding方式补到max_seq_len, 若序列长度大于该值,则会以截断方式让序列长度为max_seq_len;

3,选择Fine-Tune优化策略,适用于ERNIE/BERT这类Transformer模型的迁移优化策略为AdamWeightDecayStrategy。详情请查看Strategy。

AdamWeightDecayStrategy的参数有以下三个:
learning_rate: 最大学习率
lr_scheduler: 有linear_decay和noam_decay两种衰减策略可选
warmup_proprotion: 训练预热的比例,若设置为0.1, 则会在前10%的训练step中学习率逐步提升到learning_rate
weight_decay: 权重衰减,类似模型正则项策略,避免模型overfitting
optimizer_name: 优化器名称,使用Adam

4,选择运行时配置
在进行Finetune前,我们可以设置一些运行时的配置,例如如下代码中的配置,表示:
use_cuda:设置为False表示使用CPU进行训练。如果您本机支持GPU,且安装的是GPU版本的PaddlePaddle,我们建议您将这个选项设置为True;
epoch:要求Finetune的任务只遍历1次训练集;
batch_size:每次训练的时候,给模型输入的每批数据大小为32,模型训练时能够并行处理批数据,因此batch_size越大,训练的效率越高,但是同时带来了内存的负荷,过大的batch_size可能导致内存不足而无法训练,因此选择一个合适的batch_size是很重要的一步;
log_interval:每隔10 step打印一次训练日志;
eval_interval:每隔50 step在验证集上进行一次性能评估;
checkpoint_dir:将训练的参数和数据保存到ernie_txt_cls_turtorial_demo目录中;
strategy:使用DefaultFinetuneStrategy策略进行finetune;
更多运行配置,请查看RunConfig

5,组建Finetune Task
有了合适的预训练模型和准备要迁移的数据集后,我们开始组建一个Task。
获取module的上下文环境,包括输入和输出的变量,以及Paddle Program;
从输出变量中找到用于情感分类的文本特征pooled_output;
在pooled_output后面接入一个全连接层,生成Task;

6,开始Finetune
选择finetune_and_eval接口来进行模型训练,这个接口在finetune的过程中,会周期性的进行模型效果的评估,以便我们了解整个训练过程的性能变化。

7,使用模型进行预测
当Finetune完成后,使用模型来进行预测

具体代码如下:

from paddle.fluid.framework import switch_main_program
import paddlehub as hub
import paddle.fluid as fluid
module = hub.Module(name="ernie", version="1.0.1")
dataset = hub.dataset.ChnSentiCorp()
#生成Reader
reader = hub.reader.ClassifyReader(
    dataset=dataset,
    vocab_path=module.get_vocab_path(),
    max_seq_len=128)
#选择Fine-Tune优化策略 
strategy = hub.AdamWeightDecayStrategy(
    weight_decay=0.01,
    warmup_proportion=0.1,
    learning_rate=5e-5,
    lr_scheduler="linear_decay",
    optimizer_name="adam")
#选择运行时配置
config = hub.RunConfig(
    use_cuda=True,
    num_epoch=1,
    checkpoint_dir="ernie_txt_cls_turtorial_demo",
    batch_size=32,
    log_interval=10,
    eval_interval=50,
    strategy=strategy)
    
#组建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)
#开始Finetune 
cls_task.finetune_and_eval()

#使用模型进行预测
# coding: utf-8
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import numpy as np
import os

import paddle
import paddle.fluid as fluid
import paddlehub as hub

# loading Paddlehub ERNIE pretrained model
module = hub.Module(name="ernie")
inputs, outputs, program = module.context(max_seq_len=128)

# Sentence classification  dataset reader
dataset = hub.dataset.ChnSentiCorp()
reader = hub.reader.ClassifyReader(
    dataset=dataset,
    vocab_path=module.get_vocab_path(),
    max_seq_len=128)

# Construct transfer learning network
# Use "pooled_output" for classification tasks on an entire sentence.
# Use "sequence_output" for token-level output.
pooled_output = outputs["pooled_output"]

# Setup feed list for data feeder
# Must feed all the tensor of ERNIE's module need
feed_list = [
    inputs["input_ids"].name,
    inputs["position_ids"].name,
    inputs["segment_ids"].name,
    inputs["input_mask"].name,
]

strategy = hub.AdamWeightDecayStrategy(
    weight_decay=0.01,
    warmup_proportion=0.1,
    learning_rate=5e-5,
    lr_scheduler="linear_decay",
    optimizer_name="adam")

# Setup runing config for PaddleHub Finetune API
config = hub.RunConfig(
    use_data_parallel=False,
    use_pyreader=False,
    use_cuda=True,
    batch_size=32,
    enable_memory_optim=False,
    checkpoint_dir="ernie_txt_cls_turtorial_demo",
    strategy=strategy)

# Define a classfication finetune task by PaddleHub's API
cls_task = hub.TextClassifierTask(
    data_reader=reader,
    feature=pooled_output,
    feed_list=feed_list,
    num_classes=dataset.num_labels,
    config=config)

# Data to be prdicted
data = [
    ["这个宾馆比较陈旧了,特价的房间也很一般。总体来说一般"], 
    ["交通方便;环境很好;服务态度很好 房间较小"],
    ["稍微重了点,可能是硬盘大的原故,还要再轻半斤就好了。" ],
    ["服务很不错,下次还会来。" ],
    ["前台接待太差,下次不会再选择入住此店啦"], 
    ["菜做的很好,味道很不错。" ],
    ["19天硬盘就罢工了,算上运来的一周都没用上15天,你说这算什么事呀"],
    ["现在是高峰期,人太多了,我们晚点来吧"]
]

index = 0
run_states = cls_task.predict(data=data)
results = [run_state.run_results for run_state in run_states]
for batch_result in results:
    # get predict index
    batch_result = np.argmax(batch_result, axis=2)[0]
    for result in batch_result:
        if result==1:
            result='正向'
        else:
            result='负向'
        print(data[index][0], result)
        index += 1

 

4、PaddleHub情感分析模型(以senta_bilstm为例)

模型概述
情感倾向分析(Sentiment Classification,简称Senta)针对带有主观描述的中文文本,可自动判断该文本的情感极性类别并给出相应的置信度,能够帮助企业理解用户消费习惯、分析热点话题和危机舆情监控,为企业提供有利的决策支持。该模型基于一个双向LSTM结构,情感类型分为积极、消极。该PaddleHub Module支持预测和Fine-tune。

参数:

data:dict类型,key为text,str类型;value为待预测文本,list类型。

返回:

results:list类型,每个元素为对应输入文本的预测结果。预测结果为dict类型,有以下字段:

text字段存放原输入待预测文本;
sentiment_label为情感分类结果对应的label;
sentiment_key表示分类结果为positive或是negative;
positive_probs为原输入文本对应positive的概率值;
negative_probs为原输入文本对应negative的概率值;

调用代码:

import paddlehub as hub

senta = hub.Module(name="senta_bilstm")
test_text = [
    "这个宾馆比较陈旧了,特价的房间也很一般。总体来说一般", 
    "交通方便;环境很好;服务态度很好 房间较小",
    "稍微重了点,可能是硬盘大的原故,还要再轻半斤就好了。" ,
    "服务很不错,下次还会来。" ,
    "前台接待太差,下次不会再选择入住此店啦", 
    "菜做的很好,味道很不错。" ,
    "19天硬盘就罢工了,算上运来的一周都没用上15天,你说这算什么事呀",
    "现在是高峰期,人太多了,我们晚点来吧"
]
input_dict = {"text": test_text}
results = senta.sentiment_classify(data=input_dict)

for result in results:
    print(result['text'])
    print(result['sentiment_label'])
    print(result['sentiment_key'])
    print(result['positive_probs'])
    print(result['negative_probs'])


5、功能评测:
选用不同的数据对情感分类的准确性进行测试。具体案例如下:
"这个宾馆比较陈旧了,特价的房间也很一般。总体来说一般",
"交通方便;环境很好;服务态度很好 房间较小",
"稍微重了点,可能是硬盘大的原故,还要再轻半斤就好了。" ,
"服务很不错,下次还会来。" ,
"前台接待太差,下次不会再选择入住此店啦",
"菜做的很好,味道很不错。" ,
"19天硬盘就罢工了,算上运来的一周都没用上15天,你说这算什么事呀",
"现在是高峰期,人太多了,我们晚点来吧"

5.1 情感分析API结果:
这个宾馆比较陈旧了,特价的房间也很一般。总体来说一般
情感分类结果: 负向
分类的置信度: 0.943242
积极类别概率: 0.025541
消极类别概率: 0.974459
交通方便;环境很好;服务态度很好 房间较小
情感分类结果: 正向
分类的置信度: 0.890898
积极类别概率: 0.950904
消极类别概率: 0.049096
稍微重了点,可能是硬盘大的原故,还要再轻半斤就好了。
情感分类结果: 负向
分类的置信度: 0.0922925
积极类别概率: 0.408468
消极类别概率: 0.591532
服务很不错,下次还会来。
情感分类结果: 正向
分类的置信度: 0.990288
积极类别概率: 0.99563
消极类别概率: 0.00437049
前台接待太差,下次不会再选择入住此店啦
情感分类结果: 负向
分类的置信度: 0.980575
积极类别概率: 0.00874128
消极类别概率: 0.991259
菜做的很好,味道很不错。
情感分类结果: 正向
分类的置信度: 0.959412
积极类别概率: 0.981735
消极类别概率: 0.0182646
19天硬盘就罢工了,算上运来的一周都没用上15天,你说这算什么事呀
情感分类结果: 负向
分类的置信度: 0.366781
积极类别概率: 0.284949
消极类别概率: 0.715051
现在是高峰期,人太多了,我们晚点来吧
情感分类结果: 正向
分类的置信度: 0.400084
积极类别概率: 0.730038
消极类别概率: 0.269962


5.2 ERINE的结果:
这个宾馆比较陈旧了,特价的房间也很一般。总体来说一般 负向
交通方便;环境很好;服务态度很好 房间较小 正向
稍微重了点,可能是硬盘大的原故,还要再轻半斤就好了。 负向
服务很不错,下次还会来。 正向
前台接待太差,下次不会再选择入住此店啦 负向
菜做的很好,味道很不错。 正向
19天硬盘就罢工了,算上运来的一周都没用上15天,你说这算什么事呀 负向
现在是高峰期,人太多了,我们晚点来吧 负向

5.3、PaddleHub情感分析模型(以senta_bilstm为例)

这个宾馆比较陈旧了,特价的房间也很一般。总体来说一般
0
negative
0.0103
0.9897
交通方便;环境很好;服务态度很好 房间较小
1
positive
0.9374
0.0626
稍微重了点,可能是硬盘大的原故,还要再轻半斤就好了。
0
negative
0.2237
0.7763
服务很不错,下次还会来。
1
positive
0.9891
0.0109
前台接待太差,下次不会再选择入住此店啦
0
negative
0.0057
0.9943
菜做的很好,味道很不错。
1
positive
0.9714
0.0286
19天硬盘就罢工了,算上运来的一周都没用上15天,你说这算什么事呀
0
negative
0.0266
0.9734
现在是高峰期,人太多了,我们晚点来吧
1
positive
0.7662
0.2338

6、结论及建议

通过测试发现不论直接调用百度情感分析服务还是使用百度ERINE模型,对情感分析都有很好、很准确的结果。百度情感分析服务调用起来更加的方便,不需要使用者掌握太多的深度学习方面的技术,适用于绝大多数的应用场景。

PaddleHub情感分析模型库,是一个针对情感分析的模型库,并且针对情感分析场景进行了预训练,支持FineTune,不过即使没有FineTune也可以直接用于情感分析,调用起来比较方便。不过需要使用者掌握一定的深度学习方面的技术。

ERINE模型是一个通用模型给与用户更大的灵活性,可以根据自己的需要定制化的开发适合自己的引用,不过需要对深度学习及Paddle Paddle有比较深入的了解。大家可以根据自己的实际情况选择适合的技术。

收藏
点赞
0
个赞
共10条回复 最后由才能我浪费99回复于2020-01-03 08:52
#11才能我浪费99回复于2020-01-03 08:52:47
#8 风搅火回复
确实是,而且百度还有很多免费课程教大家

是啊,这些课程都很好

0
#10风搅火回复于2019-12-27 19:17:04
#5 小雨青青润无声回复
这个情感分析只能是进行正向和负向的分析吗

估计以后会有更多样的分析

0
#9风搅火回复于2019-12-27 19:16:25
#7 小雨青青润无声回复
这个可以运用于网评分析上

主要应该是在销售上

0
#8风搅火回复于2019-12-27 19:15:37
#2 才能我浪费99回复
测试后发现百度NLP功能很强大

确实是,而且百度还有很多免费课程教大家

0
#7小雨青青润无声回复于2019-12-20 15:59:25

这个可以运用于网评分析上

0
#6小雨青青润无声回复于2019-12-20 15:58:19
#3 才能我浪费99回复
ERINE的确强大

分析的非常准确

0
#5小雨青青润无声回复于2019-12-20 15:57:53
#2 才能我浪费99回复
测试后发现百度NLP功能很强大

这个情感分析只能是进行正向和负向的分析吗

0
#4才能我浪费99回复于2019-12-10 11:20:39

大家可以一起来测试一下

0
#3才能我浪费99回复于2019-12-10 11:18:03

ERINE的确强大

0
#2才能我浪费99回复于2019-12-10 11:17:04

测试后发现百度NLP功能很强大

0
TOP
切换版块