多年前做传统的机器学习,主要用的是LR、SVM、bayes、浅层nerual network、decision tree、random forest、GBDT等,这些分类或回归模型要想AUC、ROC等指标高,最核心的就是构造特征了!为此还专门诞生了一个细分领域:feather enginering,专门研究怎么构造好的feather!就实战情况而言,换模型不换数据/特征,准确率、覆盖率等指标最多提升几个百分点,但是如果构造了好特征,准确率能提升20~30个百分点,所以要想模型效果好,feather才是最重要的,model反而不如feather重要!DNN的效果为什么好?用tylor公式把激活函数展开,就能看到特征x1、x2....xn之间的N阶组合,大量构造、产生新特征,让特征多样性!
2017年的一篇开山之作:attention is all you need,拉开了本轮AI热潮的序幕!从论文的名字就能看出来,attention是最核心的模块!attention的作用还是生成特征:Q和K相乘,得到权重weight;如果两个token A和B的weight大,说明语义接近,那么A token就会使用weight从B token的value尽可能多取值来改善A token自己的value embeddings,value embedding就是token最好的feather representation! 顺着这个思路,还有没有其他变体来构造更符合某些业务场景的value embedding了?
1、仔细想想,attention机制的核心就是Q和K相乘得到权重weight,那么还有其他方法得到权重weight吗?这里以CV为例,暂时把每个pixel当成token处理,H*W就是pixel的position,channel就是pixel的embedding!一旦得到了优质的pixel embedding,后续的sematic segmentation、object detection等CV常见的application都会很容易!所以现在的思路变成了:怎么让每个pixel都得到高质量的 sematic channel值了? 继续推进思路:每个pixel都有原始的channel,一般都是RGB,只有3维,维度之间的权重是一样的,完全没区分,所以很明显这些原始的channel值是不足以体现sematic语义的,现在只能考虑nerual network了:普通的NN,输入是原始的特征向量,经过多层layer转换后,得到高质量的feather,具体这些feather的每个维度代表什么,就看下游的应用怎么使用了!这个思路完全可以用来处理每个pixel的原始channel:经过多层的神经网络,最终得到一个vector,vector的每个维度都是weight权重,然后用weight vector和原始的channel相乘,就得到了pixel的sematic channel!这就是SEnet的思路,整个流程如下:
- H*W*C的图片,先用max pooling或avg polling,把H*W压缩,得到 1*1*C的vector
- 1*1*C 经过NN后得到weight vector,size还是 1*1*C,但此时的vector每个维度都是weight值了
- 1*1*C和原始的H * W* C相乘,相当于把每个 pixel的channel的每个维度都乘以合适的weight,得到sematic channel
怎么样?让每个维度乘以不同weight来改变值的思路是不是和attention的思路完全一样啊!只不过weight求解的方式不一样罢了!SEnet为了得到最终的1*1*C的weight向量,用了FC->ReLU->FC->Sigmoid4层,这4者的组合就是最优的嘛?还有改进空间嘛?这里提供一个变种的思路:
- squeeze部分:SE是在spatial用的pooling方式,还有其他方式
- squeeze:既然能用pooling做squeeze,为啥不试试conv、聚类、linear projection了?
- spatial:既然能压缩H*W,为啥不试试只压缩H、W、C了?
- Excitation部分:
- 局部:channel方向做conv,提取局部特征
- 全局:channel做attention,找到全局依赖特征
- 多尺度:多个不同size的conv kernel组合,提取多个不同颗粒度的channel特征
2、顺着上述的思路,诞生了Selective Kernel Networks:这里使用多个size的kernel提取image特征,不同特征相加,再做squeeze,然后生成两个weight vector,再分别和以前的卷积结果相乘,最后相加,流程图示如下:
和SE对比如下:最明显的区别就是split了,这里使用了两个kernel,提取不同颗粒度的特征;后期还有softmax,为合适的channel赋予更高的weight值!
3、继续顺上述思路:SENet和SKNets都是在channel上生成weight,但是H*W还没动静了,是不是也能想办法提取一些特征了?毕竟image种position也很重要啊,比如image的上方一般都是sky、background等,下方一般都是地面,不同的position有不同的object,所以上述网络并未充分使用position信息哦!既然如此,完全可以依葫芦画瓢,提取H * W的feather啊!CBAM:Convolutional Block Attention Module就是这么干的!
先按照1和2的思路,提取channel的特征信息,网络结构如下:这里选择Max和Avg两种类型的pool,避免单一pool导致有用的信息丢失;
接着就是提取position related feather了,这次是压缩channel通道,同样使用Max或Avg pool,保留H * W信息,也就是每个pixel的channel取max或Avg;
上述方法同时在channel方向、H*W方向做squeeze后生成weight,然后根据weight更改原始image对应维度的特征值,那这两种特征值该怎么融合了?这里用的就是串联方式了:
4、Coordinate Attention for Effcient Mobile Network Design 第3种网络结构分别在position和channel两个维度做squeeze,这还没完了,还有H * C和 W* C方向做squeeze了!做完squeeze后提取初步的feather后,再模仿2、3的方式用NN、conv等方式融合特征,整个流程如下图所示:
这么来看更易懂:分别沿着H和W方向squeeze,这是融合了channel和spatial的信息,或者说将position信息嵌入了channel通道,H或W方向的长程依赖位置信息因此被保存在所生成的注意力图中。
5、接着4的基础上继续扩展,这次 H*W*C增加H*W的交互,这就是Rotate to Attend: Convolutional Triplet Attention Module,网络结构如下:
6、以上所有的网络架构都没有综合考虑image每个position的联系及相关性,无法自适应地整合局部特征及其全局依赖关系,于是乎又诞生了Dual Attention Network for Scene Segmentation:分别在spatial和channel两个方向分别计算sematic的依赖性,然后加权和选择性地聚合每个 position feather!废话少说,直接上图:
spatial attention网络结构:这图看着是不是很眼熟了?怎么这么像transformer的Q*K矩阵了?conv提取局部特征,MauMul得到HW*HW,这不就是position之间的依赖么?matrix中的值如果大,说明这两个position之间的关联/依赖强;HW*HW是由HW*C * C*HW得到了,本质还是pixel之间使用各自的channel计算相似度:比如两个pixel都是天空,那这两个pixel的channel肯定接近;但如果一个pixel是草地,另一个是天空,两个channel的距离肯定远一些!
上述网络架构成功地找到了image中position之间的关联关系,用学术一点的词语表述就是位置注意力模块。同样的思路换个维度,是不是还可以计算channel 注意力了?如下:
这次轮到使用HW作为"桥梁中介"了,计算channel之间的距离/依赖关系;新的问题来了,两种不同方式得到的C*H*W怎么融合了?原论文作者选择了并行,两种方式分别设置了alpha和beta系数,来调整两种方式的权重,图示如下:
7、第6种网络结构已经有NLP中QKV的”那味“了,这么做计算量可不小,比如256*256的image,HW*HW = 65536*65536的矩阵大小是多少?直接在整个完整的image上做attention的计算量是很大的,怎么适当减少计算量了?
- 原始image的H*W不变,把channel看成是每个pixel的embedding,这里分别乘以Q K V三个矩阵,得到H*W*Cq、H*W*Ck和H*W*Cv
- 上路 detail enhancement kernel:
- 先做concat拼接,还原成image原始的形状;
- 然后经过 3*3 conv,提取局部细节纹理特征;上路叫detail enhaucement,可能就是因为用了3*3这个小kernel
- 最后再经过Relu、1*1 conv 最终得到H*W每个pixel中channel每个维度的weight
- 下路 squeeze axial attention
- 分别沿着H和W方向做squeeze,把压缩得到的二维矩阵分别做multi-head attention,这里极大减小了计算量,同时也能根据垂直方向的QK结果更新Cv的值!
参考:
1、https://cloud.tencent.com/developer/article/2398307 11种开源即插即用模块汇总
https://blog.csdn.net/weixin_42645636/article/details/134250476 13种即插即用的模块
2、https://github.com/northBeggar/Plug-and-Play attention-set
3、https://www.bilibili.com/video/BV1wz421S7Ec?spm_id_from=333.788.player.switch&vd_source=241a5bcb1c13e6828e519dd1f78f35b2