使⽤PaddleNLP识别垃圾邮件(⼆):⽤BERT做中⽂邮件内容分类
本⽂是《使⽤PaddleNLP识别垃圾邮件》系列第⼆篇,该系列持续更新中……
系列背景介绍:系列项⽬,针对当前企业⾯临的垃圾邮件问题,尝试使⽤深度学习的⽅法,探索多语⾔垃圾邮件的内容、标题提取与分类识别。
该系列还有⼀个姊妹篇,,欢迎感兴趣的读者点进来交流评论
系列⽬录
使⽤PaddleNLP的⽂本分类LSTM模型,提取中⽂邮件内容判断邮件是否为垃圾邮件。
使⽤PaddleNLP的BERT预训练模型,根据提取的中⽂邮件内容判断邮件是否为垃圾邮件。
介绍在Python中解析eml邮件内容的办法:email模块和mmpi库
使⽤PaddleNLP的ELECTRA预训练模型,根据提取的英⽂邮件标题判断邮件是否为垃圾邮件。
升级到最新⾃定义数据集⽅法;
使⽤PaddleNLP模型库,⼤幅简化开发流程;
使⽤PaddleNLP的RoBERTa预训练模型,根据提取的中⽂邮件标题判断邮件是否为垃圾邮件;
完成完整的批量邮件分类部署流程。
项⽬思路
在项⽬对中⽂邮件内容提取的基础上,使⽤BERT进⾏finetune,⼒争在LSTM的98.5%的基线上进⼀步提升。
关于BERT模型的详细介绍与PaddleNLP对BERT模型的应⽤,在项⽬中进⾏了详细总结,欢迎感兴趣的读者交流指导。
本项⽬参考了陆平⽼师的项⽬,但是由于PaddleNLP版本迭代的原因,个别地⽅需要修改,在本项⽬中,进⾏了调整和说明。
数据集介绍
是⼀个公开的垃圾邮件语料库,由国际⽂本检索会议提供,分为英⽂数据集(trec06p)和中⽂数据集(trec06c),其中所含的邮件均来源于真实邮件保留了邮件的原有格式和内容。
除TREC 2006外,还有TREC 2005和TREC 2007的英⽂垃圾邮件数据集(对,没有中⽂),本项⽬中,仅使⽤TREC 200提供的中⽂数据集进⾏演⽰。TREC 2005-2007的垃圾邮件数据集,均已整理在项⽬挂载的数据集中,感兴趣的读者可以⾃⾏fork。
⽂件⽬录形式:delay和full分别是⼀种垃圾邮件过滤器的过滤机制,full⽬录下,是理想的邮件分类结果,我们可以视为研究的标签。
trec06c
└───data
││  000
││  001
││  ...
│└───215
└───delay
││  index
└───full
││  index
邮件内容样本⽰例:
负责⼈您好我是深圳⾦海实业有限公司⼴州东莞等省市有分公司我司有良好的社会关系和实⼒因每⽉进项多出项少现有⼀部分发票可优惠对外代开税率较低增值税发票为其它国税地税运输⼴告等普通发票为的税点还可以根据数⽬⼤⼩来衡量优惠的多少希望贵公司商家等来电商谈欢迎合作本公司郑重承诺所⽤票据可到税务局验证或抵扣欢迎来电进⼀步商谈电话⼩时服务信箱联系⼈张海南顺祝商祺深圳市⾦海实业有限公司
GG⾮常好的朋友H在计划马上的西藏⾃助游(完全靠搭车的那种),我和H也是很早认识的朋友,他有⼥朋友,在⼀起10年了,感情很好。
GG对旅游兴趣不⼤。⽽且喜欢跟着旅⾏社的那种。所以肯定不去。
我在没有认识GG前,时常独⾃去⼀些地⽅,从南到北,觉得旅⾏不应该⽬的那么强。
⼀、环境配置
本项⽬基于Paddle 2.0 编写,如果你的环境不是本版本,请先参考官⽹ Paddle 2.0 。
# 导⼊相关的模块
import re
import jieba
import os
import random
import paddle
import paddlenlp as ppnlp
from paddlenlp.data import Stack, Pad, Tuple
functional as F
as nn
from visualdl import LogWriter
import numpy as np
from functools import partial #partial()函数可以⽤来固定某些参数值,并返回⼀个新的callable对象
print(paddle.__version__)
2.0.2
⼆、数据加载
2.1 数据集准备
# 解压数据集
!tar xvf data/
2.2 提取邮件内容,划分训练集、验证集、测试集
本项⽬中,截取中⽂邮件提取内容的最后200个字符作为⽂本分类任务的输⼊,但是这⾥需要特别注意的是,个别邮件提取结果为null,在BERT预训练模型的finetune任务中,如果输⼊为空会产⽣报错。
因此,在⽣成训练集、验证集、测试集前,要进⾏数据清洗。
# 去掉⾮中⽂字符
def clean_str(string):
string = re.sub(r"[^\u4e00-\u9fff]"," ", string)
string = re.sub(r"\s{2,}"," ", string)
return string.strip()
# 从指定路径读取邮件⽂件内容信息
def get_data_in_a_file(original_path, save_path=''):
email =''
f =open(original_path,'r', encoding='gb2312', errors='ignore')
# lines = f.readlines()
for line in f:
# 去掉换⾏符
line = line.strip().strip('\n')
# 去掉⾮中⽂字符
line = clean_str(line)
email += line
f.close()
# 只保留末尾200个字符
return email[-200:]
# 读取标签⽂件信息
f =open('trec06c/full/index','r')
for line in f:
str_list = line.split(" ")
# 设置垃圾邮件的标签为0
if str_list[0]=='spam':
label ='0'
# 设置正常邮件标签为1
elif str_list[0]=='ham':
label ='1'
text = get_data_in_a_file('trec06c/full/'+str(str_list[1].split("\n")[0])) with open("","a+")as f:
f.write(text +'\t'+ label +'\n')
data_list_path="./"
with open(os.path.join(data_list_path,''),'w', encoding='utf-8')as f_eval:
f_eval.seek(0)
uncate()
with open(os.path.join(data_list_path,''),'w', encoding='utf-8')as f_train:
f_train.seek(0)
uncate()
with open(os.path.join(data_list_path,''),'w', encoding='utf-8')as f_test:
f_test.seek(0)
uncate()
with open(os.path.join(data_list_path,''),'r', encoding='utf-8')as f_data:
lines = adlines()
i =0
with open(os.path.join(data_list_path,''),'a', encoding='utf-8')as f_eval,open(os.path.join(data_list_path,''),'a', encoding='utf-8')as f _test,open(os.path.join(data_list_path,''),'a', encoding='utf-8')as f_train:
for line in lines:
# 提取label信息
label = line.split('\t')[-1].replace('\n','')
# 提取输⼊⽂本信息
words = line.split('\t')[0]
# 邮件⽂本提取结果中有⼤量空格,这⾥统⼀⽤逗号替换
words = place(' ',',')
labs =""
# 数据清洗,如果输⼊⽂本内容为空,则视为脏数据予以提出,避免在BERT模型finetune时报错
if len(words)>0:
# 划分验证集
if i %10==1:
labs = words +'\t'+ label +'\n'
f_eval.write(labs)
# 划分测试集
elif i %10==2:
labs = words +'\t'+ label +'\n'
f_test.write(labs)
# 划分训练集
else:
labs = words +'\t'+ label +'\n'
f_train.write(labs)
i +=1
else:
pass
print("数据列表⽣成完成!")
数据列表⽣成完成!
2.3 ⾃定义数据集
在⽰例项⽬中,BERT模型finetune的数据集为公开中⽂情感分析数据集ChnSenticorp。使⽤PaddleNLP
的._datasets⽅法即可以加载该数据集。
在本项⽬中,我们需要⾃定义数据集,并使⾃定义数据集后的数据格式与使
⽤ppnlp._datasets(['train','dev','test'])加载后完全⼀致。
class SelfDefinedDataset(paddle.io.Dataset):
def__init__(self, data):
super(SelfDefinedDataset, self).__init__()
self.data = data
def__getitem__(self, idx):
return self.data[idx]
def__len__(self):
return len(self.data)
def get_labels(self):
return["0","1"]
def txt_to_list(file_name):
res_list =[]
for line in open(file_name):
res_list.append(line.strip().split('\t'))
return res_list
trainlst = txt_to_list('')
devlst = txt_to_list('')
testlst = txt_to_list('')
train_ds, dev_ds, test_ds = _datasets([trainlst, devlst, testlst]) #获得标签列表
label_list = _labels()
#获得标签列表
label_list = _labels()
#看看数据长什么样⼦,分别打印训练集、验证集、测试集的前3条数据。
print("训练集数据:{}\n".format(train_ds[0:3]))
print("验证集数据:{}\n".format(dev_ds[0:3]))
print("测试集数据:{}\n".format(test_ds[0:3]))
print("训练集样本个数:{}".format(len(train_ds)))
eval是做什么的print("验证集样本个数:{}".format(len(dev_ds)))
print("测试集样本个数:{}".format(len(test_ds)))
2.4 数据预处理

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。