目录
Bert的输入最多为512字,如果待处理的文本超过512字呢?
主要做法:
- 数据层面
- 截断法:粗暴前或后截断
- 分段法:分为多个512字的段
- 压缩法:裁剪无意义的句子
- 模型层面
- Transformer-XL、Reformer、Longformer、BigBird等
截断法最容易想到,主要包含:
- 头截断,只保留最前面N(如512)个字;
- 尾截断,只保留最后面N个字;
- 头+尾截断,开头结尾各保留一部分;
注意:
- 虽然是512,去除
[CLS]
和[SEP]
,实际是510字; - 选择头截断、还是尾截断、还是两者结合,主要看数据的关键信息分布。比如:文本里关键信息主要在头部,那采用头截断可能会比较好;
- 截断法适合大量几百字的文本,如果文本几千字,粗暴截断会丢失重要信息;
做法:
- 将长文本依次划分为n个不超过512字的段(最好考虑断句);
- 针对n个段分别过bert编码;
- 将n段经过bert后的
[CLS]
向量进行max-pooling或mean-pooling;- Max-Pooling会保留突出的特征,Mean-Pooling会将特征打平。这和TextCNN后接Max-Pooing是一个道理。
- 然后再接一个全连接层做分类;
特点:
- 考虑到全局信息,相比截断法,对几千字的长文本效果较好;
- 性能较差,每个段都要encode一次,文本越长,速度越慢;
- 段落之间联系会丢失,易出现badcase;
压缩法的核心是裁减掉一些无意义的句子,
- 一些文章开头或结尾有一些无用“套路话术”,这些可以删除掉;
- 去除url,因为它占了很多个字符;
- 句子筛选,只保留最重要的N个句子,如:计算句子和标题的相似度;
- ……
分段法做文本生成的问题:
- 训练阶段,分块,块之间没有信息交互;
- 预测阶段(文本生成),以固定size滑动窗口,效率很低;
如下图所示:
为了解决前面问题,transformer-xl提出了一个 状态复用的块级别循环,原理如下图:
训练阶段:
预测阶段:
- 按块产生输出;
- 因为块级别循环,实际使用的输入不仅是当前块输入,而是更长的扩展上下文;
有个问题,所有块的位置信息都一样(比如都是0~512),合理么?
Transformer-XL引入了相对位置编码(区别于transfomer的绝对位置编码),被添加到self-attention上。
这里不再扩展,需要了解更多参考: Transformer-XL: Attentive Language Models Beyond a Fixed-Length Context
Longformer致力于减少自注意力计算量,即稀疏注意力,将文本处理长度扩充到4096
。
主要提出了三种注意力:滑动窗口注意力、扩张滑动窗口注意力、全局+滑动窗口,如下图:
- 滑动窗口注意力:
- 如图b,引入固定长度的滑动窗口,即当前词只与相邻的k个词关联;
- 注意力复杂度从
O(n^2)
降到O(nk)
; - 类似于卷积,尽管单层感受野是
k
,但是堆L
层,感受野能达到L*k
;
- 扩张滑动窗口注意力:
- 如图c,在滑动窗口注意力基础上引入膨胀,类似IDCNN,跳过一些位置,扩充单层感受野;
- 全局注意力:
- 如图d,我们需要全局注意力来关注一些预先设置的位置;
- 对分类问题,
[CLS]
须设置为全局注意力,确保其能Attention到整个序列;
可用的中文预训练模型:longformer-chinese-base-4096
longformer模型的使用,和之前介绍过的各种bert变体模型的使用没有太大差别,这里注意:
- 模型的加载请使用
transformers.LongformerModel
类; - 上述预训练模型的prefix为
bert
,需要你手动改回来,即LongformerModel.base_model_prefix = 'bert'
; - 分类时,Longformer的
[cls]
位置需设置全局Attention,值为2
; - 当前transformers版本的longformer直接
output_attentions
会报错;
完整代码请参考以下源代码:
- easy_bert/bert4classification/classification_model.py
- easy_bert/bert4sequence_labeling/sequence_labeling_model.py
BigBird也基于稀疏注意力,额外增加了随机注意力,如下图a: