文本分类中的一些经验和 tricks
最近在总结之前做的文本分类实验的一些经验和 tricks,同时也参考了网上的一些相关资料(见文末),其中有些 tricks 没尝试过,先在这里记下,或者日后能用上。
这里的经验和 tricks 大概可分为两部分:预处理部分和模型部分,下面分别介绍
预处理
-
文本更正,一些基本的操作包括:繁体转简体,全角转半角,拼音纠错等
-
文本泛化,如一个手机号码,因为有几千万的手机号码,不可能为每个手机号码设一个特征,所以最好将手机号码转化为同一个特征;另外表情符号、人名、地址、网址、命名实体等也要考虑这种泛化,泛化的程度这个视具体的任务,比如说地址可以以国家为粒度,也可以以省份为粒度
-
规范文本为统一长度时,取所有长度的均值或者中位数,但是别取最大值;截断时根据具体任务考虑从前面阶段或从后面截断
-
构建数据集的 vocabulary 时,需要考虑以下几个方面
- 取前N个高频词或者过滤掉出现次数小于某个阈值的词
- 根据具体任务确定是否需要去掉 stop words
- 假如采用了预训练的词向量,要尽可能让 vocabulary 中的词语能找到对应的词向量(这个问题也涉及到预训练的词向量和分词器的选择)
-
词向量的选择,当数据集较小时,直接使用预训练好的词向量(如google、facebook开源的),且不用微调;当训练集比较大的时候,可随机初始化进行训练,也可以对预训练的词向量进行微调(微调收敛得更快,但是结果差异不大)
-
分词时考虑以下几个方面
- 是否需要分词,使用 char-level 的方法时不需要分词,但是在很多场景下 word-level 的效果都要比 char-level 的要好
- 分词时可以只保留长度大于1的词(会去除很多停止词),对结果精度没什么影响,但是可以有效降低特征维度
- 采用预训练的词向量时,要保证分词后的大部分词语能够出现在预训练的词向量表中,否则这个词语的 embedding 就相当于是随机初始化,预训练的词向量没有提供任何信息;具体方法可参考 这里
- 文本数据增强的方法有
- drop: 随机删掉文本
- shuffle: 随机改变文本顺序
- replace: 用近义词进行替换
- ….
模型
-
规则有时能解决大部分的问题,不一定要用到模型,使用时要权衡模型带来的收益和复杂性
-
传统的机器学习方法根据其特征工程的不同可分为三大类
- 词袋模型:将出现的词记为1,否则记为 0,问题是维度高且稀疏性严重
- 向量空间模型:根据文档频率、互信息、信息增益、χ²统计量等进行了特征(词语)的选择,同时通过 tfidf 值为每个词赋权重;一定程度上缓解了上面提到的词袋模型维度高且稀疏性严重的问题
- 主题模型:pLSA/LDA/HDP 等主题模型将文本表示低维实数向量,类似于深度学习中的 embedding,但是比 embedding 有更好的解释性
-
fasttext 简单、速度快,是一个非常不错的 baseline;随着问题复杂性增加可依次尝试 CNN -> RNN -> BERT
-
对于深度学习模型,把模型变得更深更宽更复杂往往能够提升效果;但是当模型复杂到一定程度的时候,提升的效果微乎其微甚至没提升
-
rnn 类模型用双向一般会比单向要好
-
使用 dropout(一般设为 0.5) 基本都能提升效果,使用的地方包括:embedding 层后、FC层后
-
训练震荡问题:增加随机采样因素尽可能使得数据分布 iid,默认 shuffle 机制能使得训练结果更稳定。如果训练模型仍然很震荡,可以考虑调整学习率 或
mini_batch_size
-
学习率一般设置衰减,如在N个 epoch 之后将学习率乘上 0.1,从而不断降低学习率
-
模型融合时,差异性越大,融合效果越好,具体可参 这里
参考