广告文本多分类——2020腾讯游戏安全技术决赛反思

四月初的天气时常阴晴未定。

由于好兄弟去年参加了这个比赛的缘故(见他的博客),我今年也尝试报名参赛,并也进入决赛,不过可惜只拿到优秀奖。我自己甚是失望,故属文于此,记录下整个答题过程和反思。

1. 数据分析

赛事方提供的游戏部分公开言语数据(中文),每条记录包括了言语内容本身和对应的细分类标签(正常和4种广告细分类,共5个分类)。首先我对数据进行初步分析,得到数据的数量分布以及对应的标签含义如下表:

数据标签 0 1 2 3 4
数量/条 73034 25466 500 1000 2000
标签含义 普通非广告文本 出资源广告 退款广告 社交广告 代练广告

​ 由此可见,各类标签的数据十分不均衡,因此我做了以下两种数据增强操作。

1) 分词数据增强:我首先设定均衡的数据分布比例为4:1:1:1:1,而后我使用jieba分词将文本进行分词操作。分词之后,对于文本的分词进行两种操作,一是随机地进行删除,二是 shuffle, 即打乱词序,得到通过分词进行数据增强之后的训练集;

2) 反向翻译数据增强:反向翻译的主要思想是先将机器翻译成另一种语言,再从另一种语言的文本翻译回原先语言,从而进行数据增强。我按照设定的数据分布比例,使用腾讯AI开放平台提供的文本翻译(翻译君)API进行反向翻译数据增强。

经过数据增强,各标签数据的比例大约在4:1:1:1:1,总的数据量到达了293490条。

2. 模型建立

我实际上实现了两个模型,BERT与TextCNN。

因为Pytorch和Transformers的框架下,就已经有了文本分类的API,用BERT的中文分词器处理完数据之后就可以很简单的直接训练,具体可以参考我滴好兄弟的另一篇博客

而TextCNN则十分常规的embedding+convd+maxpooling+output的网络结构,实现起来也轻而易举,分词则是用jieba这个分词库。

以上就是就是我模型的建立,由于本文重点在反思部分,故此处便不再叨唠。

3. 测试效果

BERT的多分类模型,在我9:1划分的测试集上的结果如下:

Accuracy Precision Recall F1
97.5926% 97.76% 97.80% 97.71%

看着这么高的表现只不过是镜花水月。实际上我得知自己只有优秀奖之后向赛事方寻求了测试集的部分数据,其数据的数量分布如下:

数据标签 0 1 2 3 4
数量/条 12110 2447 287 620 1269

可以发现,测试集的数据分布其实和训练集是十分接近的,而我训练的BERT模型在测试集上的测试效果则不堪入目:

Accuracy Precision Recall F1
87.0805% 27.85% 17.23% 21.78%

而TextCNN的模型在测试集上却有不错的效果:

Accuracy Precision Recall F1
86.85% 88.87% 60.31% 79.46%

认真debug一晚上之后,发现是在BERT模型中做预测时,调用forward的时候少传了一个参数,预测部分的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..........

for step, batch in enumerate(test_dataloader):
if step % 40 == 0 and not step == 0:
print(' Batch {:>5,} of {:>5,}.'.format(step, len(test_dataloader)))
batch = tuple(t.to(device) for t in batch)
# b_input_ids, b_input_mask = batch
b_input_ids, b_input_mask, b_labels = batch
with torch.no_grad():
outputs = model(b_input_ids,
token_type_ids=None,
attention_mask=b_input_mask #在提交答卷时少传了这个attention_mask
)

logits = outputs[0]
logits = logits.detach().cpu().numpy()
label_ids = b_labels.to('cpu').numpy()

.............

attention_mask的作用是用于指示输入的文本,如果是PAD符号则是0,否则就是1。无论在训练还是预测,这都是一个十分重要的参数,我竟然漏了这个参数,实属nt。还有一个很重要的原因是,由于本地GPU不够跑BERT,而我又暂时没有服务器,只能在colab上跑程序,当时做预测时,只用了非常小(10行)的一个测试集,发现都正确之后便没有再检查了。出现如此低级错误,实在是不能接受。

不过现在的懊恼都已经弃我去者,昨日之日不可留了。希望以此为戒,乞求拜托今日之日的烦忧。

debug之后,BERT模型正确的测试代码的测试结果如下:

Accuracy Precision Recall F1
87.08% 88.20% 61.57% 79.60%

相比于TextCNN只有一点点的提升。考虑到测试文本中存在很多的非中文噪声,如:(该例子为我手动杜撰的)

1
4t把恩dsaiuhf223daf2元十万钻

实际上这个广告文本的内容就是

1
2元十万钻

所以我清洗了文本中的非中文字符。注意,可能存在其他正常的文本中本就出现非中文字符,所以这种清洗方式可能并不是最合适的。清洗之后BERT模型的表现略有上升:

Accuracy Precision Recall F1
87.33% 88.61% 62.35% 80.17%

以上,这次大赛的工作就告一段落了。之后,我向主办方了解到广告文本多分类第一名的F1达到了89.3%,确实存在比较大的差距。总结来说我觉得自己的工作可以改进的部分如下:

  1. 对于文本多分类问题,还只是用了最基础的BERT预训练模型加上一层decoder,可能忽略了其他一些重要的信息,decoder可能过于简单,也许可以参考最近的论文做更多设计。
  2. 可能数据的预处理部分存在问题,数据增强部分设定的数据分布比例可能必不合理,相反强行拉成4:1:1:1:1可能造成模型从这个数据分布获取了一些其他并不准确的特征信息。另外,数据清洗部分的做法也有待考虑。
  3. 我以后一定要换一台本地可以跑BERT的代码,或者自己有一张卡,不愿上colab薅资本主义恶臭的的羊毛(其实是因为colab老是断开连接,GPU用久了还给我限额)。

面试

在听 Jony J 的 My Man 时收到了腾讯面试官的来电,便开始了一次忽如而至的面试,听声音面试官是个和蔼的靓仔。

面试的流程大抵寻常,自我介绍、项目介绍、针对项目进行提问。

我介绍完自己用ALBERT做的机器阅读理解的毕业设计之后,他问了我一些问题:

  • 问:ALBERT相较于BERT的改进。

    答:极大程度地减少了参数量;

  • 问:Multi-Head Attention的作用。

    答:让模型去关注不同方面的信息,比如说一些底层的Head去关注一次低层的识别,如关注位置信息、关注语法信息、关注罕见词,而高层的Head去对整个句子做一些高层次的理解;

  • 问:前馈神经网络的作用。

    答:其实就是全连接层的作用,Multi-Head Attention/卷积对数据进行处理后得到了数据的局部特征,而前馈神经网络/全连接层的作用就是把之前的局部特征通过权值矩阵进行整合,方便进行后续下游任务的处理;

  • 问:你为什么认为BERT这些预训练模型不能提取文本信息中的句法和语义信息?

    答:我是从BERT模型的训练方式MLM和Next Sentence Prediction,说明其只能对上下文信息做比较好的提取,而没有显性考虑文本中的语义和句法信息;

  • 问:怎么理解语义?你对语义是怎么处理的?

  • 问:你们又是怎么处理句法的呢?

  • 问:你说用了斯坦福的句法依存分析的API,介绍一下这个句法依存分析的原理:

  • 问:句法和语义信息中的位置信息你们是怎么处理的呢?

接着又让我介绍了一下我的论文工作,针对我的论文问的问题我大多都回答得不错,其中有些印象深刻的问题:

  • 问:对于推荐系统中的冷启动问题,你们是怎么处理的?

    答:(其实没有处理)emmm,确实存在冷启动问题,那我们使用的解决冷启动问题的方法是设定了一个地理位置信息对象的种类熵,也就是把熵的概念应用在店铺的种类分布之下,把这个种类熵作为基于索引的搜索过程中的一种评价指标,熵越大表示当前索引节点下的店铺种类越多,而这样的做法恰恰也是倾向于给用户提供多样性的选择,也就是推荐系统当中一种常用的解决冷启动问题的方法。

  • 问:相对于Baseline,你们的模型取得了怎么样的提升?

    答:从响应时间上对比,100条真实的搜索,我们的平均响应时间为15秒,也就是平均每条0.15秒。另外我们实现了传统的Spatial Keywords Query中的IR树模型作为baseline,而这个模型的响应时间,100条真实的搜索,平均响应时间为30秒,也就是平均每条0.3秒。也就是说我们的模型快乐以北,那作为trade-off,由于我们的模型引入了新的维度的特征,在索引的大小上有了一定度的增大。

最后让我介绍了这次大赛的工作,我主要说了自己做的数据增强工作(说出来其实很水),接着面试官小哥问了一些问题:

  • 问:如何对文本是如何做分词的呢?

    答:我说用BERT原来的中文tokenization,但实际上原来的tokenization并不是传统意义上的分词,而是把文本分成一个个单字,而BERT就是基于单字的表示,也就相当于BERT模型并没有做中文的分词;另一个textcnn的模型倒是用了分词,用jieba分词之后,而后使用随机词向量输入到textcnn模型中。

以上便是对这次面试的大多印象,这个实习岗位是在腾讯深圳总部,工作内容是关于非法信息识别(祖安人亲妈)。希望能顺利拿到offer。