幽默是一种特殊的语言表达方式,在日常生活中扮演着化解尴尬、活跃气氛、促进交流的重要角色。而幽默计算是近年来自然语言处理领域的新兴热点之一,其主要研究如何基于计算机技术对幽默进行识别、分类与生成,具有重要的理论和应用价值。本文的主要内容为基于预训练模型对幽默的识别与等级分类。
目录
前言
这是一个评测网站上的任务,评测地址为:
http://sa-nsfc.com/evaluation/http://sa-nsfc.com/evaluation/
这里面有6个nlp评测的任务,如图:
所以喜爱nlp的不妨来试一试!
一、任务介绍
本次任务主要分为两个任务:
子任务一:生成幽默识别
幽默生成是幽默计算的重要目标之一,能够赋予计算机人类的沟通技能。该部分工作要求计算机对幽默本质有深入的理解,即理解幽默产生的机制,从而生成具有幽默效果的内容。幽默生成技术的研究将为如聊天机器人等实际应用场景带来更佳的用户体验。因此,本任务旨在通过对幽默产生机制的分析,实现对计算机生成幽默(如例1、例2)的识别,进而作为评估如对话系统、聊天机器人智能性的重要指标。
例1:我想像一个有很多钱的穷人一样生活。
例2:用户友好的计算机首先需要友好的用户。
子任务二:中文幽默等级划分
幽默是日常生活中沟通交流的重要组成部分,也是人类智慧与创造力的结晶。由于幽默特征与主观因素关系密切,“可笑或有趣”对于不同的人多具有不同的诠释,即不同的幽默往往存在着不同的幽默等级。为了研究这一现象,该任务旨在通过分析幽默的内容,探索对幽默等级划分有效的方法,即预测不同幽默的有趣程度。本任务对CCL2018中文幽默等级数据集及分类类别进行了扩展,旨在进一步深入挖掘影响幽默等级划分的重要因素。
例3:弱幽默(label=1):忧虑并不能阻止灾难,它会阻止快乐。
例4:普通幽默(label=3):岁寒三友:火锅、白菜、热被窝。
例5:强幽默(label=5):程序员:一种红眼睛,笨拙的哺乳动物,能够与无生命的物体无障碍的交谈。
评价方式
可以看到,任务一较简单,只是一个二分类的任务,而且得分占比也高。
二、数据集
任务1:
训练集内容:
任务2:
训练集内容:
训练集和测试集的占比:
统计子任务一和子任务二各类别的占比:
# 统计类别大小
def count_label(filename):
df = pd.read_csv(filename)
label_df=df["label"].value_counts()
label_df.plot(kind='bar',figsize=(4,6),color='b',title='label_count')
count_label(train_task1_path)
count_label(train_task2_path)
可以看到训练集中的各类别数据不是很均匀。
数据集下载地址:
注:由于评测网站上的是数据集无法下载,所以我直接去github上下载了(不需要科学上网),下面是数据集下载链接,这里面你也可以看到评测任务更多的详细信息。https://github.com/DUTIR-Emotion-Group/CCL2019-Chinese-Humor-Computationhttps://github.com/DUTIR-Emotion-Group/CCL2019-Chinese-Humor-Computation
三、数据处理
3.1数据合并
由于任务二所使用的训练集、拓展集、测试集都属于幽默文本,所以可以考虑将其加到任务一的训练集中,虽然会进一步加剧样本类别不平衡,但是实验后发现分类结果的f1值有所提升!
将任务二的训练集添加到任务一的训练集中:
def file_and_file(file1,file2,file_file,tag='row'):
"""
tag:string row或rol按行合并或按列合并,默认行合并
"""
f1 = pd.read_csv(file1)
f2 = pd.read_csv(file2)
#将f2文件中的所有label换成1
f2['label']= f2['label'].replace([3,5],1)
file = [f1,f2]
if tag=='row':
train = pd.concat(file)
elif tag=='col':
train = pd.concat(file,axis=1)
else:
print("row或rol按行合并或按列合并!")
return 0
train.to_csv(file_file, index=0)
train_task1_path="C:/Users/86182/Desktop/ECHC/CCL2019-Chinese-Humor-Computation-master/task1/task1_train.csv"
train_task2_path="C:/Users/86182/Desktop/ECHC/CCL2019-Chinese-Humor-Computation-master/task2/task2_train.csv"
tagert_file_path="C:/Users/86182/Desktop/ECHC/result/加工处理/task1_task2_train.csv"
file_and_file(train_task1_path,train_task2_path,tagert_file_path)
将任务二的测试集、拓展集合并,并添加label列:
#合并task2中的develop和test数据集
def develop_test_concat(file1,file2,file_file,tag='row'):
"""
tag:string row或rol按行合并或按列合并,默认行合并
"""
f1 = pd.read_csv(file1)
f2 = pd.read_csv(file2)
#添加一列标签label,设为1
f1_label = [1]*len(f1)
f2_label=[1]*len(f2)
f1.insert(loc=len(f1.columns), column='label', value=f1_label)
f2.insert(loc=len(f2.columns), column='label', value=f2_label)
file = [f1,f2]
if tag=='row':
train = pd.concat(file)
elif tag=='col':
train = pd.concat(file,axis=1)
else:
print("row或rol按行合并或按列合并!")
return 0
train.to_csv(file_file, index=0)
develop_task2_path="C:/Users/86182/Desktop/ECHC/CCL2019-Chinese-Humor-Computation-master/task2/task2_development.csv"
test_task2_path="C:/Users/86182/Desktop/ECHC/CCL2019-Chinese-Humor-Computation-master/task2/task2_test.csv"
develop_test_task2_path="C:/Users/86182/Desktop/ECHC/result/加工处理/task2_dev_test.csv"
develop_test_concat(develop_task2_path,test_task2_path,develop_test_task2_path)
再调用一次file_and_file函数合并就行了
task1_task2_dev_test_big_path="C:/Users/86182/Desktop/ECHC/result/加工处理/task1_task2_dev_test_big.csv"
file_and_file(tagert_file_path,develop_test_task2_path,task1_task2_dev_test_big_path)
统计一下类别分布情况:
这里先给出经过数据合并和未合并的幽默识别结果:
数据合并后的f1值:
未合并的f1值:
3.2数据扩展
既然通过扩展训练集可以提高训练集的f1,那是否可以通过使用其他的幽默数据集加入到模型的训练中,以继续提高f1值呢?为此我找到了一些数据集,用于加入到训练集中。
数据集1https://download.csdn.net/download/qq_53644346/85901755
扩展幽默数据集2https://download.csdn.net/download/qq_53644346/85901751
3.3数据集划分
由于并没有给验证集,所以需要划分训练集和验证集,这一步的工作我放在预训练模型中了。
四、预训练模型
模型我已经训练好了,直接调用即可。
任务一的模型:
基于bert的幽默识别预训练模型:
任务二的模型:
基于bert的幽默等级分类预训练模型:
基于bert的幽默等级分类预训练模型-Python文档类资源-CSDN文库
五、结果
5.1引入库
import pandas as pd
import csv
import time
import numpy as np
5.2加载模型
from transformers import AutoModelForSequenceClassification, AutoTokenizer
# 模型路径
model_path="C:/Users/86182/Desktop/ECHC/result/模型库/bert_task1_big/model"
def get_result(model_path,path,filename):
"""
model_path预训练模型路径
path处理后的测试集路径
filename为生成的结果文件路径
"""
#加载模型
model = AutoModelForSequenceClassification.from_pretrained(model_path, use_auth_token=True)
tokenizer = AutoTokenizer.from_pretrained(model_path, use_auth_token=True)
get_id_label(path=path,filename=filename,model=model,tokenizer=tokenizer)
5.3获得result文件
def get_id_label(path,filename,model,tokenizer):
"""
path处理后的测试集路径
filename为生成的结果文件路径
"""
s_time=time.time()
print("------------------------------------start-----------------------------------")
#读取处理过的测试集
test_sets=pd.read_csv(path)
test_joke=test_sets['joke']
with open(filename, 'w', newline='') as file:
writer = csv.writer(file)
#写入ID和Label属性名
writer.writerow(["id", "label"])
start_time=time.time()
for i in range(len(test_joke)):
#记时器
if i%100==0:
end_time=time.time()
spend_time=np.round(end_time-start_time,2)
print(i,"/",len(test_joke),"finished! ----------->>>----------用时:",spend_time,'s')
start_time=time.time()
inputs = tokenizer(test_joke[i], return_tensors="pt")
outputs = model(**inputs)
#print(outputs.logits)
label=0
if outputs.logits[0][0]>outputs.logits[0][1]:
# print(0)
pass
else:
# print(1)
label=1
writer.writerow([i, label])
print("-------------------------------------end------------------------------------")
e_time=time.time()
print("总耗时:",np.round(e_time-s_time,2),"s")
5.4运行结果
5.5评测结果
其他人的评测信息:
总结
通过做这些评测任务,让我受益良多。同时,希望这篇文章对你也有帮助吧!