分享

MLP三大工作超详细解读:why do we need?

 极市平台 2021-05-15

作者|科技猛兽
审稿丨邓富城
编辑丨极市平台

极市导读

 

本文作者详细介绍了最近火爆CV圈三项关于MLP的工作。 >>加入极市CV技术交流群,走在计算机视觉的最前沿

专栏目录https://zhuanlan.zhihu.com/p/348593638

本文目录

1 MLP-Mixer: An all-MLP Architecture for Vision
(来自Google Research, Brain Team,ViT作者团队)
1.1 MLP-Mixer原理分析
1.1.1 仅仅靠着MLP就真的无法解决复杂数据集的分类任务吗?
1.1.2 MLP-Mixer是如何处理输入图片的?
1.1.3 MLP-Mixer与之前Conv1×1的不同之处在哪里?
1.1.4 MLP-Mixer架构
1.1.5 MLP-Mixer实验
1.2 MLP-Mixer代码解读

2 RepMLP:卷积重参数化为全连接层进行图像识别
(来自清华大学,旷视,RepVGG作者团队)
2.1 RepMLP原理分析
2.1.1 深度学习模型的几个性质
2.1.2 RepMLP模块
2.1.3 如何将卷积等效成FC层?

3 ResMLP:ImageNet数据集训练残差MLP网络
(来自Facebook AI,索邦大学)
3.1 ResMLP原理分析
3.2 ResMLP代码解读

作者主页:https://www.zhihu.com/people/wang-jia-hao-53-3

1 MLP-Mixer: An all-MLP Architecture for Vision

论文名称:MLP-Mixer: An all-MLP Architecture for Vision

论文地址:

https:///abs/2105.01601

1.1 MLP-Mixer原理分析

1.1.1 仅仅靠着MLP就真的无法解决复杂数据集的分类任务吗?

神经网络主要有三个基本要素:权重、偏置和激活函数。

权重: 神经元之间的连接强度由权重表示,权重的大小表示可能性的大小

偏置: 偏置的设置是为了正确分类样本,是模型中一个重要的参数,即保证通过输入算出的输出值不能随便激活。

激活函数: 起非线性映射的作用,其可将神经元的输出幅度限制在一定范围内,一般限制在(-1~1) 或 (0~1) 之间。最常用的激活函数是Sigmoid函数,其可将 (-∞,+∞) 的数映射到(0~1) 的范围内。

典型的MLP包括包括三层:输入层、隐层和输出层,MLP神经网络不同层之间是全连接的( 全连接的意思就是:上一层的任何一个神经元与下一层的所有神经元都有连接)。

图1:典型的MLP结构

问:MLP模型能不能进行图像识别的任务呢?

答:当然可以。 MLP的最经典例子就是数字识别,即我们随便给出一张上面写有数字的图片并作为输入,由它最终给出图片上的数字到底是几。

对于一张写有数字的图片,我们可将其分解为由28*28=784个像素点构成,每个像素点的值在 (0~1) 之间,其表示灰度值,值越大该像素点则越亮,越低则越暗,以此表达图片上的数字并将这786个像素点作为神经网络的输入。而输出则由十个神经元构成,分别表示 (0~9) 这十个数字,这十个神经元的值也是在 (0~1) 之间,也表示灰度值,但神经元值越大表示从输入经判断后是该数字的可能性越大。如下面这个视频所示 :

视频来自:3Blue1Brown (from YouTube)

MLP模型识别数字的过程

隐层的层数和神经元的选择需根据具体情况选择,此例选择两层隐层,每层16个神经元。那么根据上面的叙述,根据权重、偏置的个数此神经网络将会有(784×16+16)+(16×16+16)+(16×10+10) = 13002个参数需要去调节。

输入的784个像素点输入模型以后,首先通过第一层的权重,其结果与偏置参数相加以后,通过激活函数,使模型因此有了非线性的性质。第一层的输出再经过地层的权重和偏置,激活函数得到最终的结果,如下面这个视频所示:

MLP模型识别数字的过程

所以,一个MLP模型是可以识别图像,完成图像分类任务的。

但是,上面的2个例子的图像都来自很简单的数据集MNIST,MNIST数据集一共只有10类,所以靠着2层的MLP就能完成分类任务。但是对于ImageNet这种1000类的数据集来讲,MLP模型就显得力不从心了。所以人们后来开发出了借助CNN,Transformer模型 (比如AlexNet,VGG,ResNet,EfficientNet,GhostNet,ViT,DeiT等) 来解决复杂分类数据集的问题。 比如2012年AlexNet赢得了图像分类挑战赛的冠军,代表CNN模型为代表的深度学习方法开始超越传统方法而逐渐流行。VGG-Net使用以3×3卷积为主要结构的深度神经网络达到了当时的SOTA结果。ResNet使用skip-connection与BN操作使得训练特别深的深度神经网络成为可能。后来的Group Convolution以及Depth-wise Convolution使得卷积操作变得更高效。Non-local Network和SE-Net通过即插即用的操作进一步提升了CNN的性能。

但是,不使用CNN和Transformer,仅仅靠着MLP就真的无法解决复杂数据集的分类任务吗?

本文给出的MLP-Mixer就是为了解决这个问题,它仅仅依赖于基础矩阵乘法运算和数据的布局变换 (reshapes and transpositions) ,以及非线性层。结果表明,尽管Mixer仅仅使用了MLP层,但是其结果却是极具竞争力的。作者在大型数据集 (约1亿=100M张图片,对比 ImageNet 是1.28M训练集,5万验证集和10万测试集) 上训练以后可以在ImageNet 的验证集上达到87.94% 的准确率 (对比 EfficientNet-B7是84.7%, ViT-B是77.9% );若在 稍微小一点的数据集 (约1-10M张图片) 上训练,也能达到接近CNN架构的性能。

由此可见,仅仅靠着MLP真的可以解决复杂数据集的分类任务,而且和CNN,Transformer模型的性能相当。

1.1.2 MLP-Mixer是如何处理输入图片的?

一张图片的维度是 的。

之前基于Transformer的ViT模型是怎么处理这个输入image的呢?

答: ViT 模型处理图片的方式是将其分块 (patch) ,每个patch的大小是 ,那样的话一共可以分成 个patch,其中:

接下来我们得到了 个patch,把每一个大小是 的patch给展平 (Flatten),就是展成一维向量,得到一个长度是 的向量。个这样的向量拼在一起就结合成一个维度是 的张量,再把张量通过线性映射将第2维的大小为 ,这样最后我们就得到了一个维度是 的张量。它由 个 的向量组成,每个向量我们把它称为1个 token。这个张量才是后续Transformer模型的真正输入。

现在基于MLP的 MLP-Mixer 是怎么处理这个输入image的呢?

答:和ViT是一样的。

把输入图片分块 (patch),每个patch的大小是 ,一共可以分成 个patch,把每一个大小是 的patch给展平 (Flatten),就是展成一维向量,得到一个长度是 的向量。个这样的向量拼在一起就结合成一个维度是 的张量,再把张量通过线性映射将第2维的大小为 称为hidden dimension。这样最后我们就得到了一个维度是 的张量。它由 个 的向量组成,每个向量我们把它称为1个 token。这个张量 才是后续MLP-MiXer模型的真正输入,如下图1所示。

图1:MLP-Mixer输入

1.1.3 MLP-Mixer与之前Conv1×1的不同之处在哪里?

对于1×1卷积其实相当于是作了矩阵乘法,因为假设对一个 的张量作1×1卷积,卷积核的维度是 ,则输出的张量维度是 。就相当于给它成了一个维度是 的矩阵。所以其实就相当于是在每一个空间位置 (each spatial location) 上的矩阵乘法。但是问题是1×1卷积不能结合不同空间位置的信息

1×1卷积可以结合不同channels的信息,但不能结合不同空间位置的信息。

上节说道MLP-Mixer的输入是维度是 的张量,那么这个Mixer不仅混合各个channels之间的信息,也混合不同空间位置 (tokens/patches) 之间的信息。 所以主要分成了2种层:channel-mixing MLPs 层和 token-mixing MLPs 层。

channel-mixing MLPs层结合不同channels的信息,是一种按位置per-location的操作。

token-mixing MLPs层结合不同tokens的信息,是一种跨位置cross-location的操作。

那么对于一个维度是 的输入矩阵来讲,channel-mixing MLPs层应该是作用于它的每一行,而token-mixing MLPs层作用于它的每一列。

MLP-Mixer即可以靠channel-mixing MLPs层结合不同channels的信息,也可以靠token-mixing MLPs层结合不同空间位置的信息。

1.1.4 MLP-Mixer架构

图2:MLP-Mixer架构

有了上面的铺垫再来理解MLP-Mixer的结构就很简单了。如上图2所示,Mixer 由大小相同的多个层和一个分类头组成。每个层由 2 个 MLP 块组成,其中,第一个块是 token-mixing MLP 块,第二个是 channel-mixing MLP 块。其中分类头就包括Global Average Pooling和一个全连接层。

每个MLP 块如右下角小图所示,包含2个全连接层和中间一个GELU激活函数 ,给模型融入非线性成分,每个MLP 块代码如下图3所示 (这1节的代码是JAX/Flax的,想参考PyTorch代码的读者请看第2节)。

图3:MLP 块

首先看这个 token-mixing MLP 块,取输入的每个channel ,对它依次通过Layer Normalization,和MLP,最后再进行残差连接得到 token-mixing MLP 块输出,如上式1.1 Top所示。token-mixing MLP 块的hidden dimension命名为 .

再看这个 channel-mixing MLP 块,取上一步输出的每个空间位置 ,对它依次通过Layer Normalization,和MLP,最后再进行残差连接得到 channel-mixing MLP 块输出,如上式1.1 Bottom所示。channel-mixing MLP 块的hidden dimension命名为 

经过了 token-mixing MLP 块和channel-mixing MLP 块以后就算是过了一个Block,每个Block的代码如下图4所示。

图4:每个Block的代码

依次通过 个这样的Block和分类头就得到的最终的输出,整体结构的代码如下图5所示:

图5:整体结构的代码

几个值得注意的地方:

因为只有MLP层,所以MLP-Mixer的计算复杂度与序列长度 是线性相关的;而基于Transformer的ViT等模型的计算复杂度与 是平方相关的。

MLP-Mixer没有使用位置编码信息,因为token-mixing MLP把不同空间位置的信息融合起来了,所以对输入的顺序敏感,可以自动地学习到位置信息。token-mixing MLP 对输入 token 的顺序很敏感,因此能够学会表征位置。

MLP-Mixer每一层的输入和输出的维度是一致的,与Transformer保持一致,而不是像CNN那样是pyramidal structure,即越深的层的输入分辨率越低。

1.1.5 MLP-Mixer实验

数据集:

验证集: ImageNet (1.28M training,1k classes),ReaL,CIFAR10/100 (50k examples, 10/100 classes),Oxford-IIIT Pets (3.7k examples, 36 classes), and Oxford Flowers-102 (2k examples, 102 classes),Visual Task Adaptation Benchmark (VTAB-1k)。

训练集: ILSVRC2021 ImageNet,ImageNet-21k (14M training,21k classes),JFT-300M (300M training,18k classes)。

超参数设置:

参数
训练优化器Adam
参数beta1=0.9,beta2=0.999
学习率warm up策略linear
学习率decay策略linear
预训练分辨率224
数据增强策略RandAugment, mixup, dropout, stochastic depth
Fine-tune优化器SGD
batch size512
学习率warm up策略linear

其实写这些超参数也没啥意义,因为我们也没有作者的庞大私有数据集,也没法复现结果orz。

模型设置:

不同大小的模型配置如下图6所示。

图6:不同大小的模型配置

S, B, L, H分别代表:small, base, large, huge。B, L, H都是12层的模型,S是8层模型。
16, 32代表patch的大小。

大型数据集性能比较

在大型数据集JFT-300和ImageNet-21k上的不同类型模型的性能对比如下图7所示。黄色圆点的代表基于ResNet的模型,蓝色圆点的代表基于Transformer的模型,粉色圆点的代表基于MLP的模型。结果显示在ImageNet-21k上MLP-Mixer性能略微逊色于其他模型,但是如果在最大的JFT-300上预训练的话,Mixer在ImageNet上的性能就能够达到87.94%,超过了大多数的其他模型。

图7:在大型数据集JFT-300和ImageNet-21k上的不同类型模型的性能对比

训练时长或者数据集大小的影响

下图8左图所示是模型性能随训练时长或者数据集大小的帕累托曲线,证明pre-training cost 和下游任务的性能有着明显的相关关系。图8右图所示是当分别把JFT-300的数据集取3%训练233 epochs,10%训练70 epochs,30%训练23 epochs和100%训练7 epochs时的不同模型的性能变化。结果表明小数据集时模型都展示出了过拟合现象,BiT模型过拟合程度较低。当数据量持续增长时,Mixer-L/32和Mixer-L/16比BiT模型增长更快。这个现象在ViT模型中也存在,但是Mixer模型的这一特点比ViT更显著。这可能是因为Mixer 架构学习到的一些underlying distribution与self-attention layers机制不匹配。

图8:模型性能随训练时长或者数据及大小的帕累托曲线

模型大小的影响

改变模型大小的方式包含:

改变层数,hidden dimension和MLP的宽度: 影响预训练时间和模型的吞吐率。
Fine-tune数据的分辨率: 只影响模型的吞吐率。

结果如下图9所示,只使用ImageNet作为训练集时,Mixer-B/16达到了76.44%的性能,比ViT-B/16少了3个点。但是当训练数据量增加时,Mixer模型的性能逐步提升,Mixer-H/14在JFT-300的性能仅仅比ViT-H/14低0.3%。

图9:模型大小的影响

权重可视化

首先要明确权重的维度是多大的。

输入的维度是 的张量。所以每个神经元有196个权值。比如Mixer-B/16模型,其 代表它的token-Mixing MLP层的hidden dimension = 384。那么token-Mixing MLP层的第一个全连接层就有384×196 = 75264个参数,看成是384个196维的参数,把每个196维的参数变成14×14的正方形,就得到了384个正方形,如下图10所示。

图10:第1层和第2层在不同数据集的权重可视化

下图11是前3层在JFT-300的权重可视化。作者发现第1层包含了好多local interactions,后2层包含了更多的mixing across larger regions,这个性质与CNN相似。

图11:前3层在JFT-300的权重可视化

1.2 MLP-Mixer代码解读

原论文开源的是JAX/Flax版本的代码,下文解读的这份PyTorch代码来自Phil Wang大佬的实现,链接如下:

https://github.com/lucidrains/mlp-mixer-pytorch

使用这份代码的步骤很简单,只需要2步:

第1步安装依赖库:

$ pip install mlp-mixer-pytorch

第2步测试:

import torchfrom mlp_mixer_pytorch import MLPMixer
model = MLPMixer( image_size = 256, patch_size = 16, dim = 512, depth = 12, num_classes = 1000)
img = torch.randn(1, 3, 256, 256)pred = model(img) # (1, 1000)

MLP-Mixer:

from torch import nnfrom einops.layers.torch import Rearrange

# LayerNorm + Add.class PreNormResidual(nn.Module): def __init__(self, dim, fn): super().__init__() self.fn = fn self.norm = nn.LayerNorm(dim)
def forward(self, x): return self.fn(self.norm(x)) + x
# 一个MLP块:由2个全连接层和中间的激活函数构成.def FeedForward(dim, expansion_factor = 4, dropout = 0.): return nn.Sequential( nn.Linear(dim, dim * expansion_factor), nn.GELU(), nn.Dropout(dropout), nn.Linear(dim * expansion_factor, dim), nn.Dropout(dropout) )
def MLPMixer(*, image_size, patch_size, dim, depth, num_classes, expansion_factor = 4, dropout = 0.): assert (image_size % patch_size) == 0, 'image must be divisible by patch size' num_patches = (image_size // patch_size) ** 2
return nn.Sequential( Rearrange('b c (h p1) (w p2) -> b (h w) (p1 p2 c)', p1 = patch_size, p2 = patch_size), nn.Linear((patch_size ** 2) * 3, dim, 1), *[nn.Sequential( PreNormResidual(dim, nn.Sequential( Rearrange('b n c -> b c n'), FeedForward(num_patches, expansion_factor, dropout), Rearrange('b c n -> b n c'), )), PreNormResidual(dim, FeedForward(dim, expansion_factor, dropout)) ) for _ in range(depth)], nn.LayerNorm(dim), Rearrange('b n c -> b c n'), nn.AdaptiveAvgPool1d(1), Rearrange('b c () -> b c'), nn.Linear(dim, num_classes) )

其中:

Rearrange('b c (h p1) (w p2) -> b (h w) (p1 p2 c)', p1 = patch_size, p2 = patch_size)将图片分patch。
Rearrange('b n c -> b c n')把patch这个维度置换到最后一维,进行MLP,这是token-mixing MLP 块的做法。
Rearrange('b c n -> b n c')把channel这个维度置换到最后一维,进行MLP,这是channel-mixing MLP 块的做法。
在每个Block的开始和最后使用PreNormResidual进行Layer Norm和求和的操作。
Rearrange('b n c -> b c n')和nn.AdaptiveAvgPool1d(1)先把patch这个维度放在最后,再紧接着Global Average Pooling把最后一维归一化。
最后Rearrange('b c () -> b c')和nn.Linear(dim, num_classes)完成分类任务。

小结:

MLP-Mixer即可以靠channel-mixing MLPs层结合不同channels的信息,也可以靠token-mixing MLPs层结合不同空间位置的信息。

CNN的特点是inductive bias,ViT靠大量数据 (JFT-300数据集)使性能战胜了CNN,说明大量的数据是可以战胜inductive bias的,这个MLP-Mixer也是一样。卷积相当于是一种认为设计的学习模式:即局部假设。能够以天然具备学习相邻信息的优势,但长远看来,在数据和算力提升的前提下,相比于attention甚至MLP,可能成为了限制。因为不用滑窗,也不用attention的方法其实是CNN的母集。

早起人们放弃MLP而使用CNN的原因是算力不足,CNN更节省算力,训练好模型更容易。现在算力资源提高了,就有了重新回到MLP的可能。MLP-Mixer说明在分类这种简单的任务上是可以通过算力的堆砌来训练出比CNN更广义的MLP模型 (CNN可以看做是狭义的MLP)。

最后,channel-mixing MLPs层相当于1×1 convolution,而token-mixing MLPs层相当于广义的depth-wise convolution,只是MLP-Mixer让这两种类型的层交替执行了。

2 RepMLP:卷积重参数化为全连接层进行图像识别 (Arxiv)

论文名称:RepMLP: Re-parameterizing Convolutions into Fully-connected Layers for Image Recognition

论文地址:

https:///abs/2105.01883

开源预训练模型和代码 (PyTorch版):

https://github.com/DingXiaoH/RepMLP

2.1 RepMLP原理分析:

本文是MLP-Mixer后一天挂在Arxiv上的工作,也是使用纯MLP模型完成图像分类任务的工作。它借助重参数技术,将卷积与FC巧妙地融合,加强分类网络的性能。在ImageNet分类、人脸识别以及语义分割等任务(无论是否具有平移不变性)上均能涨点。结合FC层的全局表征能力和位置先验性质以及卷积层的局部先验性质,可以在大幅增加参数的同时不会造成推理速度的显著降低。

2.1.1 深度学习模型的几个性质

局部先验性质

卷积的局部先验性质的意思是: 卷积操作默认图片中的某个像素与周围的像素联系更加密切,而与距它较远的像素联系更少。所以卷积操作只处理某个局部邻域的信息。这一性质也称为归纳偏置 (inductive bias) 或者局部先验性质 (local prior)FC层不具备这个能力。

全局建模能力

与其同时,捕获长距离依赖 (long-range dependency) 的能力,这一性质也称为全局建模能力 (global capacity) 。传统卷积拥有长距离依赖的能力的方法是使用更大的感受野,堆叠更多的卷积层。但是这也势必会导致计算十分低效,且造成优化困难。Transformer模型被用来解决这个问题,其中的self-attention层专门用来捕获长距离依赖,但是缺少了局部先验性质。FC层也具备这个能力,这很容易理解,因为FC层的输出与每个输入都有连接。

位置先验性质

位置先验性质的意思是:比如人通过人脸识别来解锁手机,脸部的照片一般情况下都在屏幕的中心,眼睛一般在图像上方,鼻子一般在中部。这一性质就是位置先验,也叫做positional perception,而一层卷积是不具备这个性质的。FC层具备这个能力,因为FC层的参数是位置相关的,而不像卷积操作,不同位置的参数是共享的。

综上,作者看上了全连接层具备的全局建模能力位置先验性质,使用FC层取代卷积操作。此外,FC层的计算更高效,对于应用场景更友好。

但是,FC层却不具备局部先验性质,作者解决这个问题的办法是使用结构重参数技术 (structural reparameterization technique)

2.1.2 RepMLP模块

所谓结构重参数的意思已经在RepVGG里面有讲到,就是:训练时的结构对应一组参数,推理时我们想要的结构对应另一组参数;只要能把前者的参数等价转换为后者,就可以将前者的结构等价转换为后者, 官方描述为:

The meaning of structural reparameterization is that the training-time model has a set of parameters while the inference-time model has another set, and we parameterize the latter with the parameters transformed from the former.

注意结构重参数技术 整个过程只转换模型一次,就是训完以后把训练模型等效为部署模型的那个时候,转换完成后,训练的模型变成了全新的部署模型,训练的模型可以丢弃。

问:RepVGG是怎么使用结构重参数的?

答: 在训练模型时,为每一个3x3卷积层添加平行的1x1卷积分支和恒等映射分支,构成一个RepVGG Block。在部署 (deploy) 时,把1×1卷积分支和恒等映射分等效为3×3分支,权重weights和偏置bias 叠加在之前训练的3×3分支上面。

问:RepMLP是怎么使用结构重参数的?

答:在训练模型时,为每一个MLP层添加平行的卷积+BN分支,构成一个RepMLP Block。在部署(deploy) 时,把平行的卷积分支等效为MLP分支,使deploy模型只有MLP操作。

与RepVGG的一卷到底相比,RepMLP运行速度更快,并且具备全局建模能力和位置先验性质。

在CIFAR数据集上,简简单单的MLP模型即可取得与CNN非常接近的性能。通过将RepMLP插入到现有CNN中,我们在ImageNet数据集上提升ResNets模型精度达1.8%,在人脸识别任务上提升2.9%,在Cityscapes提升2.3%mIoU精度且具有更低的FLOPs。

本文的贡献是使得MLP层同时具备局部先验性质,全局建模能力和位置先验性质,使其适用于图像识别任务且不造成任何推理耗时增加。

图12:RepMLP结构

RepMLP的架构如上图12所示。训练阶段的RepMLP由3部分构成:Global Perceptron、Partition Perceptron、Local Perceptron。

对于卷积层,假设特征图表示为,用字母 和 分别代表卷积和全连接层的权值。本文采用了PyTorch风格的数据排布与伪代码风格,比如卷积处理的数据流表示如下:

其中表示输出特征, 表示输出通道数, 表示pad的像素数量,表示卷积核 (暂时假设groups=1) 。为简单起见,我们还假设

对于全连接层,假设P和Q为输入与输出维度,分别表示输入与输出,表示全连接层核,计算公式如下:

假设FC不会改变输入输出分辨率,即。我们采用RS (reshape)来表示仅仅改变张量形变而不会改变内存数据顺序的操作,它是一种cost-free的操作。输入首先会被展平 (Flatten) 为 个长度为的向量,即,然后乘以核得到输出,最后再RS为。为更好的阅读,在歧义的情况下我们忽略RS而简写为:

这种形式的全连接层无法充分利用图像的局部信息,并忽视了位置信息。

而且这种形式的全连接层所需要的参数也很大,假设,此时FC层的参数量高达10G,这样巨大的参数量是难以接受的,而且如上文所述,无法充分利用图像的局部信息

所以作者提出了3种Global Perceptron 和 Partition Perceptron来节约参数量。

Global Perceptron

Global Perceptron是把特征图分成一样大小的部分来节约参数量,比如,的特征图可以被拆分为,我们将每个视作一个部分。假设表示期望部分的高和宽,则特征图的变化过程如下图13所示:

图13:Global Perceptron特征图的变化过程

我们看到经过了Global Perceptron,维度为 的特征图最终通过PyTorch里面的reshape和permute操作变成了 。通过这种方式,参数量可以从下降到

但是,强行把特征图分成不同的部分会打破不同部分之间的相关性。各个部分会被分开对待而忽视了它们原本的位置上的相关性。为对每个分区添加相关性,Global Perceptron采用了以下几个操作:

  • 对每个分区采用均值池化得到1个像素。
  • 将上述所得送入到BN+1个两层的MLP。
  • 将上述所得进行reshape并与每个部分的特征相加。
  • 得到的结果传入Partition Perceptron 和 Local Perceptron层

则特征图维度的完整的变化过程如下图14所示,具体过程如图12所示。

图14:Global Perceptron特征图维度的完整变化过程

Partition Perceptron

Partition Perceptron 包含FC与BN层,并以每个部分的特征作为输入。Global Perceptron的输出将通过reshape、re-arrange、reshape等操作变为。作者进一步采用组卷及降低FC3的参数量,定义如下:

类似的,组形式的FC核 ,此时参数量可以减少g倍。尽管这种形式的FC不被某些框架(如Pytorch)支持,但我们可以采用卷积代替实现。它的实现包含三个步骤:

  • 将输入特征Reshape 为spatial size = 的特征;
  • 采用groups = g 的卷积;
  • 将上述所得特征 Reshape 为

整个过程定义如下:

则特征图维度的完整的变化过程如下图15所示,具体过程如图12所示。

图15:Partition Perceptron特征图维度的完整变化过程

Local Perceptron

图16:Local Perceptron特征图维度的完整变化过程

Local Perceptron将每个部分的特征经由几个卷积进行处理。所有卷积分支的输出与Partition Perceptron的输出相加作为最终的输出。特征图维度的完整的变化过程如上图16所示,具体过程如图12所示。

2.1.3 如何将卷积等效成FC层?

假设FC核为:,卷积核 ,我们期望构建满足:

注意到:对任意与同形状的核,MMUL的加法特征满足:

因此,只要可以构建与同形状的,我们就可以将F合并到并满足:

很明显,一定存在 (因为卷积可以视为稀疏版FC层)。

所以接下来要做的事情是如何把这个卷积操作 给等效成全连接操作 ,换句话讲,如何找到 这个 的神奇之处就在于:给某一个张量乘以 ,就相当于是给这个张量的Reshape成的四维形式做卷积。

作者给出了一种方法,这也是本文我认为最妙的地方:

现在全连接操作是咋算的呢?计算形式是:

给上式插入一个Identity Matrix ,这个式子就变成了:

因为这里面都是矩阵乘法,多乘一个单位矩阵没啥关系。

前面说过:这个 的神奇之处就在于:给某一个张量乘以 ,就相当于是给这个张量的Reshape成的四维形式做卷积。

那么2.10式是给 这个张量乘以 ,就相当于是给 这个张量的四维形式 做卷积,这里:

所以我们把矩阵乘法变成卷积,就有:

但是有一点不同, 的结果是2维的,而卷积的结果是4维度的 ,所以需要再来个Reshape,所以

结合上式2.12,2.10就变为了:

这个绿到发光的部分正是我们要找的 

所以:

2.14式就是我们要找的等效全连接操作 ,算法就是卷积核的等效FC核可以通过对恒等矩阵进行卷积并添加合适reshape得到。这个转换既便捷又可导。

PyTorch格式的伪代码如下:

Algorithm 1 PyTorch code for converting groupwsie conv into FC.Input: C, h, w, g, O, conv kernel, conv biasI = torch.eye(C * h * w // g).repeat(1, g).reshape(C * h * w // g, C, h, w)fc kernel = F.conv2d(I, conv kernel, padding=conv kernel.size(2)//2, groups=g)fc kernel = fc kernel.reshape(O * h * w // g, C * h * w).t() # Note the transposefc bias = conv bias.repeat interleave(h * w)return: fc kernel, fc bias

下一步,按照上式1.3的做法,把BN的参数合并到卷积中:

这是因为:

式1.3是2D BN的融合方法,那么1D BN也是同理,融合进 里面。所以说按照2.14式的做法我们就可以把所有的卷积操作等效成FC了。

Experiment:

数据集:CIFAR10,ImageNet

超参数:

参数
数据增广策略padding, RandomCrop, RandomFlip
bs128
学习率变化cosine learning rate annealing

CIFAR10实验:

这里作者构建了2个模型,PureMLP和ConvNet,如下图17所示:

图17:PureMLP和ConvNet

PureMLP由FC层 (Conv1×1)和RepMLP构成,图中的16×16,32×32代表分辨率。左右的改变其实就是左边的RepMLP层对标右面的3×3卷积。所有的RepMLP层都使用 。为了使左右2侧的计算量尽量接近,左侧3个stage的channel分别是16,32,64,而左侧3个stage的channel分别是32,64,128。结果如下图18所示:

图18:CIFAR10实验结果

可以看到:

  • 纯MLP模型能够以52.8M FLPs达到91.11%的精度,不过该结果弱于Wide ConvNet;

作者随后进行了一些对照实验,转换前的计算量达到118.9M,高于包含卷积与BN,其计算量非常大,这说明了结构重参数的重要性。

  • 移除Local Perceptron,模型精度下降8.5%,说明了局部先验的重要性。
  • 移除Global Perceptron,模型精度下降1.5%,说明了全局建模的重要性。
  • 替换FC3为卷积 (K=9, p=4),尽管其感受野更大,但仍造成精度下降3.5.%,说明了FC要比卷积更有力。

ImageNet实验:

超参数:

参数
数据增广策略mixup, AutoAugment, Random Crop, RandomFlip
bs256
学习率变化cosine learning rate annealing
weight decaye-4

采用ResNet作为基线模型并用于评估RepMLP作为传统ConvNet构建模型的性能。模块定义如下图19所示。假设ResNet的几个stage的特征依次是 

图19:Sketch of a RepMLP Bottleneck

只对stride=1的层替换了RepMLP,仅仅对 进行替换时,结果如下图20所示。 时RepMLP-Res50具有比ResNet50更少的参数量,更快的推理速度(快10%)。

图20:仅仅对 c4 进行替换时

前两行说明:当前深度学习框架对于组形式卷积支持程度并不够好,参数量提升59%,但推理速度仅下降了0.7%;更进一步的组形式优化有可能使得RepMLP更高效。

下图21是对不同层的特征进行替换时的性能变化,超参数设置为 

图21:对不同层的特征进行替换

采用RepMLP模块替换ResNet中的模块会导致轻微的速度下降,但精度出现了显著提升。比如,仅仅采用RepMLP替换 即可带来0.94%精度提升,参数量仅增加5M; 的替换可以取得最佳的均衡。

下图22为更高输入分辨率下不同模型的性能对比。

图22:更高输入分辨率下不同模型的性能对比

在320×320的高输入分辨率下,超参数设置为 。 意思是对于 使用group=8,而对 使用group=16。

得到的结论是:

相比同参数量的传统ConvNet,RepMLP-Res50的计算量更低、推理速度更快。比如,相比224×224输入的ResNet101,RepMLP-Res50仅需50%FLOPs,更少的参数量,推理速度快50%,也可以取得同等精度;当输入分辨率为320×320时,RepMLP-Res50在精度、速度以及FLOPs方面的优势更大。

提升RepMLP的参数量不会导致推理速度的大幅下降。比如,从RepMLP-Res50-g8/16到RepMLP-Res50-g4/8,参数量提升47%,但FLOPs仅提升3.6%,推理速度仅从311下降到305。这对于高吞吐量的大型服务器推理是非常有用的。

相比于EfficientNet (在端测设备效率较高而在GPU端是低效的),RepMLP-Res50在速度于精度方面表现更优。

除了前述模块改进外,作者还提供了一种更轻量化的高速版本如下图23所示,性能见下图24。

图23:更轻量化的高速版本RepMLP
图24:更轻量化的高速版本RepMLP性能

轻量版RepMLP取得了与原始ResNet50相当的性能(77.14 vs 77.19),但FLOPs降低30%,推理速度快55%,达到1074 examples per second。

小结:

RepMLP借助结构重参数技术,将MLP与卷积巧妙结合,不仅保留了MLP的全局建模能力和位置先验性质,还能融入卷积的局部先验性质。在ImageNet分类、人脸识别以及语义分割等任务(无论是否具有平移不变性)上均能涨点。作为模型压缩的方法,它可以在GPU端实现模型推理速度的提升。

3 ResMLP:ImageNet数据集训练残差MLP网络 (Arxiv)

论文名称:ResMLP: Feedforward networks for image classification with data-efficient training

论文地址:

https:///pdf/2105.03404.pdf

3.1 ResMLP原理分析:

本文第一作者就是 DeiT 一作 Hugo Touvron 博士。他曾经针对视觉 Transformer 模型 ViT 需要大量数据集训练的难题提出了DeiT模型,通过一组优秀的超参数和蒸馏操作实现了仅仅使用 ImageNet 数据集就能达到很强的性能,详见下面链接。现在他又按照这个思路写了一篇,针对视觉 MLP 模型 MLP-Mixer 需要大量数据集训练的难题提出了 ResMLP 模型,通过残差结构和蒸馏操作实现了仅仅使用 ImageNet 数据集就能达到很强的性能。

下面列举几个Hugo Touvron 博士最近的研究和对应的论文以及论文解读,他在视觉Transformer模型上面灌了很多水。

DeiT:

https:///pdf/2012.12877.pdf

搞懂Vision Transformer 原理和代码,看这篇技术综述就够了(三)

CaiT:

https:///pdf/2103.17239.pdf

搞懂 Vision Transformer 原理和代码,看这篇技术综述就够了(八)

本文不使用任何 Self-attention 模块,只有 Linear Layers 和 GELU 激活函数为模型提供非线性。另外一个有意思的是,ResMLP不会使用任何正则化层 (Batch Norm, Group Norm, Layer Norm) 来稳定训练,其训练方式和 DeiT 和 CaiT 保持一致。

图25:ResMLP架构

ResMLP架构如上图25所示,怎么处理输入image的呢?

答:和ViT是一样的。

把输入图片分块 (patch),每个patch的大小是 ,那样的话一共可以分成 个patch,其中:

接下来我们得到了 个patch,把每一个大小是 的patch给展平 (Flatten),就是展成一维向量,得到一个长度是 的向量。个这样的向量拼在一起就结合成一个维度是 的张量,再把张量通过线性映射将第2维的大小为 ,这样最后我们就得到了一个维度是 的张量。它由 个 的向量组成,每个向量我们把它称为1个 token。这个张量才是后续Transformer模型的真正输入。

每一个Block的结构也很简单:sublayer + feedforward sublayer

sublayer 就是图25左边那部分,由一个线性层和残差连接构成,不使用Layer Normalization,但是会使用2个Affine Transformation:

式中的 都是可学习的参数。此操作简单地重新缩放和给输入分量一个偏置,而且不会占用很多推理时间。注意 是对输入的每一个patch单独做的,就是在 这个维度去做,也就是说不会涉及到batch之间和patch之间的信息交流。与CaiT里面的Layer Scale方法很像,相同的是scale值 一开始都会初始化成一个很小的值 (初始化 ),不同的是Affine Transformation还有一个偏置项。

每个sublayer会有2个Affine Transformation,我们注意到一个是在残差前面 (取代pre-normalization操作),一个是在残差内部 (取代post-normalization操作)。

feedforward sublayer 就是图25右边那部分,由两个线性层和残差连接构成,中间使用GELU激活函数,不使用Layer Normalization,但是会使用2个Affine Transformation。

所以每个Block的表达式可以写成:

这里 是每个层的可学习权重参数, 。注意按照这个式子图25貌似有点问题,箭头应该放在A的前面分叉。

问:与Transfomer的Block相比,ResMLP的主要的区别在于,将 Self-attention 层替换为线性层。那么线性层与Self-attention的区别在哪里呢?

答: 个人理解是Self-attention是数据依赖的,即不同的input可以得到不同的attention map,然后这个attention map还会与input计算出的value作用,可以看成是data-dependent的超参数。

而线性层不是数据依赖的,即不同的input都会使用相同的权重参数得到 ,换句话讲,MLP模型没有依赖于输入数据的超参数,这就使模型更加general。

问:为什么sublayer 要做2次转置,不做行不行?

答:不行。 这个做法与MLP-Mixer保持一致。第1次转置把patches这个维度甩到最后一维,目的是融合不同patches之间的信息;第1次转置把channels这个维度甩到最后一维,目的是融合不同channels之间的信息。如果不做就没法融合这2个维度的信息,所以不做不行。

问:需要像Transformer模型一样用class token吗?

答:不需要。 作者也尝试在最后两层使用Transformer,前面的层的attention统一替换成Linear层,做法和CaiT模型一致。发现这样做会进一步涨点。但是参数量和计算量也会上升,这个模型命名为class-MLP。

另外值得注意的是:ResMLP模型不使用位置编码,因为ResMLP把不同空间位置的信息融合起来了,所以对输入的顺序敏感,可以自动地学习到位置信息。ResMLP 对输入 token 的顺序很敏感,因此能够学会表征位置。

Experiments:

数据集: 训练:ImageNet (1.28M 训练集,1000类),测试:ImageNet-real,ImegeNet-v2

超参数:

参数
优化器Lamb
学习率5e-3
weight decay0.2

其他与DeiT一致。

ImageNet实验结果

下图26所示为各种模型在ImageNet的实验结果。就参数量,计算量和准确率的trade-off而言,基于MLP的模型不如基于Transformer的或者CNN的模型,但是却展示出了非常鼓舞人心的结果。作者可能觉得比较尴尬,所以这样解释道:

  • 那些基于卷积和Transformer的模型经过了years of research and careful optimization towards accuracy, parameters and FLOPs,所以结果比MLP好是有情可原的。
  • ResMLP证实了结构并不适限制模型性能的因素,尤其是在训练数据量有限的情况下。
图26:各种模型在ImageNet的实验结果

知识蒸馏结果

仿照DeiT的做法作者也对ResMLP模型进行蒸馏,就是把label替换为教师模型RegNet-16GF的输出结果,结果如下图27所示。

图27:知识蒸馏结果

迁移学习性能

先在ImageNet上预训练,然后在各种小数据集上面Fine-tune得到的结果如下图所示。Fine-tune的小数据集包括CIFAR-10, CIFAR-100, Flowers-1022, Stanford Cars, iNaturalist。迁移学习性能与其他模型相当,说明MLP模型在合适的数据增强策略的加持下减少了过拟合。

图28:迁移学习性能

可视化结果

下图是线性层3.2式的 矩阵权重的可视化结果,可视化的方法是把 的每一行即 个值reshape成正方形排列,所以一共就有 个正方形。浅层的可视化结果展现出卷积的特征,展示出一种attention map的感觉;有趣的是,在许多层中,大的权重沿着两个轴延伸,最突出的是在第7层。网络的最后7层是不同的,比如第20层和第22层:它们包括patch本身的尖峰和其他幅度较大或较小的patch之间的扩散响应。

图29:可视化结果

权重的稀疏度

下图30红色线是线性层3.2式的 矩阵权重的稀疏度的可视化结果。蓝色线是线性层3.2式的 矩阵权重。稀疏权重的标准是这个权值小于最大权值的5%。结果显示不论是 还是 都是极其稀疏的。 矩阵的稀疏度更大,它主要负责patches之间的信息融合,说明不是任意的patches之间的信息都需要融合,在能够预见未来会有MLP稀疏化方面的研究。

图30:权重的稀疏度

过拟合表现

因为MLP模型极易产生过拟合,所以作者在下图31中展示了ResMLP模型的泛化能力。从吐0中可以看出:ResMLP模型的泛化能力与其他基于Transformer相当。

图31:过拟合表现

3.2 ResMLP代码解读

这份PyTorch代码并非来自原作者,而是来自Phil Wang大佬的实现,链接如下:

https://github.com/lucidrains/res-mlp-pytorch

不得不说大哥 code 是真滴快啊!!!ResMLP是21年5月7号上传的arxiv,大哥10号上午就把工作复现出来了。这样的大神我们不夸,我们舔orz。

使用这份代码的步骤很简单,只需要2步:

第1步安装依赖库:

$ pip install res-mlp-pytorch

第2步测试:

import torchfrom res_mlp_pytorch import ResMLP
model = ResMLP( image_size = 256, patch_size = 16, dim = 512, depth = 12, num_classes = 1000)
img = torch.randn(1, 3, 256, 256)pred = model(img) # (1, 1000)

ResMLP:

定义Affine操作:

class Affine(nn.Module): def __init__(self, dim, fn): super().__init__() self.g = nn.Parameter(torch.ones(1, 1, dim)) self.b = nn.Parameter(torch.zeros(1, 1, dim)) self.fn = fn
def forward(self, x): x = x * self.g + self.b return self.fn(x)

注意是在输入的最后一个维度作用的对角矩阵和偏置,因为self.g, self.b初始化在了最后一维 (即channels的维度)。

总架构:

class LayerScaleResidual(nn.Module): # https:///abs/2103.17239 def __init__(self, dim, depth, fn): super().__init__() if depth <= 18: init_eps = 0.1 elif depth > 18 and depth <= 24: init_eps = 1e-5 else: init_eps = 1e-6
scale = torch.zeros(1, 1, dim).fill_(init_eps) self.scale = nn.Parameter(scale) self.fn = fn
def forward(self, x): return self.fn(x) * self.scale + x
def ResMLP(*, image_size, patch_size, dim, depth, num_classes, expansion_factor = 4): assert (image_size % patch_size) == 0, 'image must be divisible by patch size' num_patches = (image_size // patch_size) ** 2 wrapper = lambda i, fn: LayerScaleResidual(dim, i + 1, Affine(dim, fn))
return nn.Sequential( Rearrange('b c (h p1) (w p2) -> b (h w) (p1 p2 c)', p1 = patch_size, p2 = patch_size), nn.Linear((patch_size ** 2) * 3, dim), *[nn.Sequential( wrapper(i, nn.Conv1d(num_patches, num_patches, 1)), wrapper(i, nn.Sequential( nn.Linear(dim, dim * expansion_factor), nn.GELU(), nn.Linear(dim * expansion_factor, dim) )) ) for i in range(depth)], Reduce('b n c -> b c', 'mean'), nn.Linear(dim, num_classes) )

wrapper(i, nn.Conv1d(num_patches, num_patches, 1))代表 linear sublayer,输出通道数为 (num_patches),输入通道数为 (num_patches),使用1×1的1维卷积代表MLP。
这里实现的方式特别巧妙,这样可以使得变量的维度一直是 (bs, N, d),直接使用1维卷积去搞N这个维度,而不用进行转置操作了。如果仍然使用nn.Linear,那就还需要把N这一维度通过转置操作甩在最后才能使用nn.Linear(N,N)。

wrapper(i, nn.Sequential(
nn.Linear(dim, dim * expansion_factor),
nn.GELU(),
nn.Linear(dim * expansion_factor, dim)
))代表feedforward sublayer。

注意wrapper是个lambda函数,真正执行的函数是LayerScaleResidual,为一个残差操作,一路是残差,另一路是Affine操作再乘以scale,这里的scale相当于又进行了一次Affine操作。

小结:

ResMLP是一种完全基于多层感知机(MLP)进行图像分类的体系结构。它是一个简单的残差网络,它交替线性层,其中图像 patches在通道之间独立且相同地交互;以及2层前馈网络,其中通道中的每个 patch独立地相互作用,达到了鼓舞人心的性能。

总结:

本文介绍了目前的3个在分类任务上使用MLP模型的工作。

MLP-Mixer即可以靠channel-mixing MLPs层结合不同channels的信息,也可以靠token-mixing MLPs层结合不同空间位置的信息。卷积相当于是一种认为设计的学习模式:即局部假设。能够以天然具备学习相邻信息的优势,但长远看来,在数据和算力提升的前提下,相比于attention甚至MLP,可能成为了限制。因为不用滑窗,也不用attention的方法其实是CNN的母集。但是channel-mixing MLPs层相当于1×1 convolution,而token-mixing MLPs层相当于广义的depth-wise convolution,只是MLP-Mixer让这两种类型的层交替执行了。

RepMLP将训练时的卷积操作通过结构重参数化技术转化成部署时的MLP,但不是纯MLP模型,也包含卷积的成分,只是靠MLP提升性能。

ResMLP针对视觉 MLP 模型 MLP-Mixer 需要大量数据集训练的难题提出了 ResMLP 模型,通过残差结构和蒸馏操作实现了仅仅使用 ImageNet 数据集就能达到较强的性能。

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多