CJ blog

不知名算法工程师

EVA-02: A Visual Representation for Neon Genesis

EVA02的目标是作为下一代的基于Transformer的视觉表示模型。

文章主要包含两个部分:1、对普通Vit的架构改进,2、MIM的预训练策略

总结

EVA02主要有两个改进,一是,通过实验的方法来观察采用哪些NLP方向关于Vit的改进;二是,增加视觉特征编码的容量以及增加训练的轮数和图像的size;

1 Architecture

image-20230629182751431

ViT主要由 MHSA(用于全局空间信息聚合)和 pointwise的FFNs(特征变换)交错组成。但是NLP方面很多针对ViT的修改没有在视觉上应用。作者做了一个实验来探索不同的修改带来的影响:

image-20230703191529244

Gelu: $GELU(x)=x * \phi(x),x \sim N(0,1)$

img

截图20230914183157

img

2 pre-trainning strategy

image-20230703195140612

MIM teacher model变大,训练的epoch也需要变多;

image-20230703195449659

分辨率的增加以及在imgnet数据上的有监督ft也会增加性能

预训练目标类似于 EVA [44],即仅以可见图像块为条件回归屏蔽图像文本对齐的视觉特征。我们使用 [MASK] 标记破坏输入补丁,并按照 [5, 44] 使用掩码率为 40% 的分块掩码。

MIM 预训练的目标表示来自可公开访问的 EVA-CLIP [44] 视觉塔,具有 10 亿个参数。 EV A-02 的输出特征首先被归一化 [4],然后通过线性层投影到与 EVA-CLIP 的视觉特征相同的维度。我们使用负余弦相似度作为损失函数。

EMA的原理和pytorch实现

EMA 定义

指数移动平均也叫权重移动平均,是一种给予近期数据更高权重的平均方法。

在深度学习的优化中的EMA

在深度学习的优化过程中,$\theta_t$ 是 t 时刻的模型权重 weight, $\upsilon_t$ 是 t 时刻的影子权重。在梯度下降的过程中,会一直维护着这个影子权重,但是这个影子权重不会参与训练。基本的假设是模型权重在最后 n 步内,会在实际的最优点处抖动,所以我们去最后 n 步的平均,能使模型更加的鲁棒。

EMA为何有效

因为在训练的时候,会使用验证集来衡量模型精度,但是验证集和测试集并不完全一致,在训练后期阶段,模型可能已经在测试集最佳精度附近波动,所以使用ema的结果会比使用单一结果更可靠。

image-20230307191607861

image-20230307191620727

Pytorch实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class EMA():
def __init__(self, model, decay):
self.model = model
self.decay = decay
self.shadow = {}
self.backup = {}

def register(self):
for name, param in self.model.named_parameters():
if param.requires_grad:
self.shadow[name] = param.data.clone()

def update(self):
for name, param in self.model.named_parameters():
if param.requires_grad:
assert name in self.shadow
new_average = (1.0 - self.decay) * param.data + self.decay * self.shadow[name]
self.shadow[name] = new_average.clone()

def apply_shadow(self):
for name, param in self.model.named_parameters():
if param.requires_grad:
assert name in self.shadow
self.backup[name] = param.data
param.data = self.shadow[name]

def restore(self):
for name, param in self.model.named_parameters():
if param.requires_grad:
assert name in self.backup
param.data = self.backup[name]
self.backup = {}

# 初始化
ema = EMA(model, 0.999)
ema.register()

# 训练过程中,更新完参数后,同步update shadow weights
def train():
optimizer.step()
ema.update()

# eval前,apply shadow weights;eval之后,恢复原来模型的参数
def evaluate():
ema.apply_shadow()
# evaluate
ema.restore()

LoRA

论文链接:https://arxiv.org/abs/2106.09685
代码链接:https://github.com/microsoft/LoRA

LoRA是一种finetune扩散模型的训练技术。通过对标准的checkpoint模型微小的修改,可以比checkpoint模型小10到100倍。LoRA的原理比较简单,原始全量的finetune其实就是在原始模型参数基础上加入增量$W=W_0+\Delta W$,那么我们可以通过冻结原始参数 $W_0$,并且把增量部分通过低秩分解方式进一步降低参数量级$\Delta W = A*B^T$, 原始参数的维度是 $d*d$, 则低秩分解后的参数量级是 $2*r*d$, 这里 $r<<d$, 因此可以起到大幅降低微调参数量级的效果。

和textula inversion一样,不能直接使用LoRA模型,需要和checkpoint文件一起使用。

How does LoRA work in Stable diffusion?

image

LoRA通过在checkpoint上做小的修改替换风格,具体而言修改的地方是UNet中的cross-attention层。该层是图像和文本prompt交界的层。LORA的作者们发现微调该部分足以实现良好的性能。

cross attention层的权重是一个矩阵,LoRA fine tune这些权重来微调模型。那么LoRA是怎么做到模型文件如此小?LoRA的做法是将一个权重矩阵分解为两个矩阵存储,能起到的作用可以用下图表示,参数量由(1000 2000)减少到(1000 2+2000*2), 大概300多倍!

img

核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
## 初始化低秩矩阵A和B
self.lora_A.update(nn.ModuleDict({adapter_name: nn.Linear(self.in_features, r, bias=False)}))
self.lora_B.update(nn.ModuleDict({adapter_name: nn.Linear(r, self.out_features, bias=False)}))
self.scaling[adapter_name] = lora_alpha / r

## 向前计算
result = F.linear(x, transpose(self.weight, self.fan_in_fan_out), bias=self.bias)
result += (
self.lora_B[self.active_adapter](
self.lora_A[self.active_adapter](self.lora_dropout[self.active_adapter](x))
)
* self.scaling[self.active_adapter]
)

alpha参数:alpha其实是个缩放参数,本质和learning rate相同。

SD微调中,lora作用域Cross attention层

cross attention

cross-attention是扩散模型中关键的技术之一,在LoRA中通过微调该模块,即可微调生成图片的样式,而在Hypernetwork中使用两个带有dropout和激活函数的全链接层,分别修改cross attention中的key和value,也可以定制想要的生成风格。可见cross attention的重要性。

在讲cross-attention之前,先看看经典的transformer中attention的含义,attnetion实际上用了三个QKV矩阵,来计算不同token之间的彼此的依赖关系,Q和K可以用来计算当前token和其他token的相似度,这个相似度作为权值对V进行加权求和,可以作为下一层的token。更通俗点说,Q和k的作用是用来在token之间搬运信息,而value本身就是从当前token当中提取出来的信息. 比较常见的是self-attention,该注意力是一个sequence内部不同token间产生注意力,而cross-attention的区别是在不同的sequence之间产生注意力。

DALI预处理加速

NVIDIA DALI 文档:https://docs.nvidia.com/deeplearning/dali/user-guide/docs/examples/general/data_loading/external_input.html

安装:https://docs.nvidia.com/deeplearning/dali/user-guide/docs/installation.html#pip-official-releases

1、DALI pipeline

DALI可以选择纯CPU加载和预处理或者CPU&GPU混合加载,GPU加载。

在DALI中,任何数据处理任务都有一个称为 Pipeline 的对象, Pipeline 对象是类的实例nvidia.dali.Pipeline或派生类。

可以通过以下方式定义DALI Pipeline

  1. 通过实现内部使用 DALI 运算符的函数并使用pipeline_def()装饰器对其进行装饰。
  2. 通过Pipeline直接实例化对象、构建图形并使用Pipeline.set_outputs().
  3. 通过从Pipeline类继承并覆盖Pipeline.define_graph()(这是定义 DALI Pipelines 的传统方式)

截图20230907195707

2、图像分类的pipeline示例

所有操作均在GPU上,note:使用gpu进行预处理,会占用显存,模型越大占用越多,但是GPU利用率会一直保持在100%。模型较大不推荐使用GPU加载。

使用纯CPU操作,数据处理的速度也比 torchvision快

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class TrainPipeline(Pipeline):
def __init__(self, batch_size, num_threads, device_id, data_root, img_size, n_holes, length, custom_cutout=False):

super(TrainPipeline, self).__init__(batch_size, num_threads, device_id, prefetch_queue_depth=4)
mode = 'gpu'
self.decode = ops.decoders.Image(device='mixed')

self.img_size = img_size

# readers.File类似torchvision.datasets.ImageFolder,dali还有其他高阶API,可自行研究使用
self.input = ops.readers.File(file_root=data_root, random_shuffle=True)
# Resize
self.resize = ops.Resize(device=mode, resize_x=int(img_size*1.2), resize_y=int(img_size*1.2))
# Randomcrop,类似于torchvision.transforms.RandomCrop
self.randomcrop = ops.RandomResizedCrop(device=mode, size=img_size, random_area=[0.3, 1.0])
# CropMirrorNormalize可以实现normalize和随机水平翻转,类似于torchvision.transforms.Normalize & RandomHorizontalFlip
self.normalize = ops.CropMirrorNormalize(device=mode, mean=[0.5*255, 0.5*255, 0.5*255],
std=[0.5*255, 0.5*255, 0.5*255])
# 获取随机数
self.rng1 = ops.random.Uniform()
self.rng2 = ops.random.CoinFlip()
# 实例化改变图片色彩的类,类似于torchvision.transforms.ColorJitter
self.colortwist = ops.ColorTwist(device=mode)
# 实例化旋转图像的类,类似于torchvision.transforms.RandomRotation
self.rotate = ops.Rotate(device=mode, fill_value=0)
# gridmask,类似于cutout这种随机遮挡块操作
self.gridmask = ops.GridMask(device=mode)

如果需要自定义数据处理的函数,可参考一下方式。以cutout为例:cutout使用的是cpu处理了,如果是gpu处理的话,需要将numpy改成cupy,DALI原生支持的操作和数据增强挺丰富的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class CUTOUT(object):

def __init__(self, n_holes, length):
self.n_holes = n_holes
self.length = length

def __call__(self, imgs):
c, h, w = imgs.shape
mask = np.ones((h, w), np.float32)
for n in range(self.n_holes):
y = np.random.randint(h)
x = np.random.randint(w)
y1 = np.clip(y - self.length // 2, 0, h)
y2 = np.clip(y + self.length // 2, 0, h)
x1 = np.clip(x - self.length // 2, 0, w)
x2 = np.clip(x + self.length // 2, 0, w)
mask[y1: y2, x1: x2] = 0.
mask = np.expand_dims(mask, 0).repeat(c, axis=0)
imgs = imgs * mask

return imgs

# 然后在上面的 TrainPipeline上加上下面这行,model 是 “cpu”
self.mask = ops.PythonFunction(device="cpu", function=CUTOUT(n_holes, length), num_outputs=1)

图像分类数据加载的时候的调用方式:其他的Iterator可以参考 https://docs.nvidia.com/deeplearning/dali/user-guide/docs/plugins/pytorch_tutorials.html

1
2
3
4
5
6
7
8
from nvidia.dali.plugin.pytorch import DALIClassificationIterator
from nvidia.dali.plugin.base_iterator import LastBatchPolicy

pipe_train = TrainPipeline(batch_size, num_threads, device_id, data_root, img_size, n_holes, length,custom_cutout=custom_cutout)
pipe_train.build()

# DALIClassificationIterator: 返回pytorch tensor 形式是 (data and label) , 即DataLoader
train_loader = DALIClassificationIterator(pipe_train, size=pipe_train.epoch_size('Reader'),last_batch_policy=LastBatchPolicy.PARTIAL, auto_reset=True)

MAE:Masked Autoencoders

code: https://github.com/facebookresearch/mae

paper: https://arxiv.org/abs/2111.06377

1、概述

image-20240111174241212

以一定比例随机mask掉图片中的一些图像块然后重建这些部分像素值。

主要特点有两个:

  1. 非对称的编、解码器设计
  2. 使用较高(如 75%)的掩码率(mask 比例)

第1点所述的“非对称”主要体现在 输入形式网络结构 上:编码器(Encoder)仅对可见(un-masked)的图像块进行编码,而解码器(Decoder)的输入则是所有的图像块;同时,Decoder 可以是比较轻量的(比如 Encoder 通常是多层堆叠的 Transformer,而 Decoder 仅需较少层甚至1层就 ok)。这也表明 Encoder 与 Decoder 之间是解耦的。

第2点是该工作的一个重要发现:不同于 NLP,在 CV 中可能要配合较高的 mask 比例才能作为“有效”的自监督代理任务。“有效”指的是任务本身足够困难,这样模型才能学到有效的潜在特征表示。

由于 Encoder 仅处理 un-masked 的 patch(占所有输入的少数),因此,尽管其本身网络结构比较重载,但依然能够高效训练,特别是对于大模型,能够加速3倍以上,同时配合较高的掩码率,还能够涨点。

作者从一个问题出来解释选择这样mask策略以及模型设计的理由,“为什么 masked autoencoding 在CV中应用比较少相较于NLP?” 作者提炼了以下三点:

  • 架构差异:之前CNN的架构不适合使用
  • 信息密度不同: 语言的信息密度比较高,将句子中的少量词语抹去再让模型预测被抹去的这些词是比较困难的任务;但对于图像则相反,它在空间中是冗余的,对于图片中的某个部分,模型很容易由其相邻的图像块推断出来,因此在CV中,mask的比例应该更高,才能使任务本身具有足够的挑战性,从而使模型学到良好的潜在特征表示。
  • 解码的目标不一致:CV 和 NLP 在解码器的设计上应该有不一样的考虑:NLP 解码输出的是对应被 mask 掉的词语,本身包含了丰富的语义信息;而 CV 要重建的是被 mask 掉的图像块(像素值),是低语义的。因此,NLP 的解码器可以很简单,比如 BERT,严格来说它并没有解码器,最后用 MLP 也可以搞定。因为来自编码器的特征也是高度语义的,与需要解码的目标之间的 gap 较小;而 CV 的解码器设计则需要“谨慎”考虑了,因为它要将来自编码器的高级语义特征解码至低级语义层级

image-20240111174251713

2、具体方法

MAE的特点主要是:高掩码率随机 mask 策略、非对称的编、解码器设计 以及 重建的目标是像素

2.1 masked 策略

沿袭 ViT 的做法,将图像分成一块块(ViT 中是 16x16 大小)不重叠的 patch,然后使用服从均匀分布(uniform distribution)的采样策略对这些 patches 随机采样一部分,同时 mask 掉余下的另一部分。被 mask 掉的 patches 占所有 patches 的大部分(实验效果发现最好的比例是 75%),它们不会输入到 Encoder。

作者实验发现:无论是finetune,还是 fine-tune 还是 linear-probe(微调方法,将最后一层替换成线性层,微调时冻结其他层,只训练这个线性层),75%都是一个比较好的比例。

image-20240115201547788

2.2 Encoder

Encoder只处理 un-masked 的patches。Encoder可以是Vit或者其他backbone。图像划分成patch采用Vit的做法。

先将图像从 (B,C,H,W) reshape 成 (B,N,PxPxC),其中 N 和 P 分别为 patch 数量 和 patch 大小( $H/P \times W/P$),也就是将3通道的图像转换成 N 个 维度大小为 PxPxC 的向量;然后,通过线性映射(linear projection,可以是全连接层)将其嵌入(embed)到指定的维度空间大小,记为 ‘dim’(从 PxPxC project 到 dim),转换成为 token(B,N,dim);最后再加上位置嵌入(position embedding),从而为各个 patch 添加位置信息。位置嵌入是所有图像共享的、可学习的,shape 与 每张图的 token 相对应,即:(N,dim)。

由于 un-masked patches 占所有 patches 的少数,计算消耗和空间需求都减少了,因此可以训练很大的 Encoder。

2.3 Decoder

Decoder 不仅需要处理经过 Encoder 编码的 un-masked 的 tokens,还需要处理 masked tokens。但请注意,masked token 并非由之前 mask 掉的 patch 经过 embedding 转换而来,而是可学习的、所有 masked patches 都共享的1个向量,对,仅仅就是1个!

通过 position embedding 来区分各个 masked patch 对应的 token。

2.4 loss

MAE 预训练任务的目标是重建像素值,并且仅仅是 masked patches 的像素值,也就是仅对 mask 掉的部分计算 loss,而 loss 就是很大众的 MSE。为何仅计算 mask 部分的 loss?实验结果发现这样做模型的性能会更好,而如果对所有 patches 都计算 loss 的话会掉点。

3. 实验

mask采样策略

作者通过实验比较,最终选择了服从均匀分布的随机采样,以下是详细实验结果:

image-20240116104651814

Decoder设计

作者还研究了Decoder的设计,下图展示了 Decoder 的深度和宽度对于 ft 和 linear probe 的影响。

image-20240116104906404

Decoder 的深度和宽度对于 linear probe 有较为明显的影响,但对于 fine-tune 的影响却不那么突出。究其本质,原因是是预训练任务(图像重建)与下游任务(图像识别)之间存在着 gap

encoder为什么不用 masked tokens

image-20240116105137183

原因是下游任务并不存在这些 masked tokens,上下游任务之间存在gap。如果Encoder 也对 masked tokens 进行编码,会进一步将这种 gap 的影响“扩散”至下游任务中。

各种重建目标的比较

image-20240116105418257

数据增强

image-20240116105510461

360图片搜索—图片美观度模型

code和数据集地址

一、背景

在图片搜索中,用户希望搜索的图片不但和自己的查询相关,并且在视觉感官、图片质量等方面也要比较满意。此时,就需要我们计算图片图片的在美学上的特征分值,加到排序模型中,将高相关性、高美学质量的图像排在检索结果的前面。

但是现有的图片质量模型主要考虑图像的质量,如像素,清晰度、有无噪声,在图像的美学特征,如构图、色彩、内容和谐等考虑的权重偏低。

二、相关研究

大部分的工作将这种美观度评估的任务形式化为回归或者分类问题。开源的数据集有 AVA【1】, AADB【2】等。代表的工作有 NIMA模型【3】和DARN模型【4】。360美观度模型正是在DARN模型的基础上改进得到的。

NIMA模型利用了AVA数据集,AVA数据集包含了约 25w张图像,由业余摄影师根据审美品质进行评分,200人评分的平均分就是该张图像的最终的分数。

NIMA模型目标是预测与人类评分的相关性,而不是将图片分类或者回归到平均分。提出了EMD loss,它显示了有序类分类的性能提升。下面是模型结构。

image-20231026144748579

开源的数据集AVA、AADB图像与图片搜索的图像在种类和美学质量分布上有很大的差异,所以不能再公开的数据集上训练模型。最好的方式使构建自己的数据集,但是像AVA数据集的构建,需要一批具有美学专业知识的标注人员对每张图片进行标注。标注成本和难度都有很大

Microsoft提出了《An Universal Image Attractiveness Ranking Framework》,很好的解决美学数据集构建难的问题,并提出了新的美学模型——DARN模型。下面介绍DARN模型以及360美观度模型在此之上的改进。

三、基于DARN的美观度模型

1、数据集构建

数据集的构建过程如下:

1、在图片搜索中高中低频queey中各选择2000条query。

2、根据query在图片搜索返回结果中,top20里面,top40-60里面各抽取两张图片。

3、根据Swiss-system tournament规则、对这4张图像进行三轮标注。

4、每一轮标注,将同一query下4张图片组成两对,每一对图像由7个人标注人员去进行投票:

左边更好,左边好一点,一样好,右边好一点,右边更好。

具体标注可以参考下图:

image-20231026154542693

这样标注的好处是,标注人员无需掌握专业知识,“比较”相对于给出一个直接的分值更简单,多人投票也降低主观偏好带来的偏差。7个标注人员对image1和image2进行投票的结果中,左边更好,左边好一点,一样好,右边好一点,右边更好的人数分别为0、1、1、4、1,则这对图像的label为:

2、DARN模型

我们的标注数据是pair对,模型结构如下:

image-20231026163835872

左边的网络和右边的网络是参数共享的,图像对输入到网络中,经过 Deep CNN(如resnet50)的特征抽取,再经过三个fc层,然后计算最终输出的方差和均值。

假设每张图像都是由很多的专业的美学专家评分得到的,那么根据中心极限定理,图像美观度分值$X$服从正态分布,AVA数据基本就符合正态分布。所以最终计算得到的均值和方差就可以看作是模型计算的该图像的平均美观度分值和方差

对于一个pair对 $[x_i,x_j]$, 它们的 label 记为${0,1,2,3,4}$ 分别对应着左边更好,左边好一点,一样好,右边好一点,右边更好。对于我们的标注数据有:

直觉上,图像通过模型得到的美观度分值有以下两个特点:

  • 图像越美观,模型得到美观度分数均值越大。
  • 图像对的label应该与美观度分数一致。如,$u_i>>u_j$,那么标注图像 $i$ 好一点或者更好的人数应该更多。如果 $u_i=u_j$,则大部分人标注的 label 是 “一样好”。

上面说到我们假设美观度分值服从正态分布,那么两个美观度分值的差也服从正态分布,记$x_{i}^{left}$,$x_{j}^{right}$分别表示图像对中左边图像美观度和右边图像美观度(左边和右边只是为了对应我们数据的标注label),他们美观度的差值 $\Delta X$ 服从 $N(x,u_i-u_j,\sigma_{1}^{2}+\sigma_{2}^{2})$。

然后我们定义4个可以学习的边界值 ${b_i}_{i=0}^{3}$,这4个boundaries将 x 轴分成5部分,也就将正态分布和x轴围成的区域分成了5个部分,这5个部分就对应了 我们设定的 五个label {左边更好,左边好一点,一样好,右边好一点,右边更好},我们定义 $p_{i}^{j},j={0,1,2,3}$表示第$i$对图像对被标注lable $j$ 的概率。$\Delta u_i $和 $\Delta \sigma_i$ 表示第$i$对图像对美观度分值差的均值和方差。于是我们有:

形象点可以看下图:

image-20231026175218691

上面这张图显示了标签如何随着图像对的分数差值系统的变化。当右侧图像的平均得分远高于左侧图像时,得分差的分布将向右移动,导致标签“右侧更好”的概率更高。当左右之间的分数差异变小时,分布向左移动并导致标签发生变化。因此,当两个图像的分数相等时,中间桶中的面积最大,这意味着这对图像最有可能被标记为“一样好”。

至此我们可以计算出模型对第 $i$ 对图像对的美观度分值的差的分布 $p_i=(p_{i}^{0},p_{i}^{1},p_{i}^{2},p_{i}^{3},p_{i}^{4})$ ,而我们

图像对的真实label 为 $l=(n_{i}^{0},n_{i}^{1},n_{i}^{2},n_{i}^{3},n_{i}^{4})$, 因此我们可以定义一个对数最大似然损失函数:

image-20231026180559585

从上面的过程可以看出,由于预先假设图像的美学评分服从正态分布,而正态分布可以由均值和方差两个参数控制,所以严格的说,DARN模型预测的不是美学评分,而是美学评分分布。在实际应用时,可以直接用均值作为该图像的美学评分

3、实验改进

实验的过程中,根据我们的数据集和训练情况对DARN模型做了一些改进和调整。

1、 原始DARN模型中,deep CNN以及以后所有FC层,激活函数都是 Relu。缺少带有归一化能力的激活函数和norm操作,则很可能随着W方差的增大,出现个别节点数值过大的问题,导致训练时loss很可能出现nan的情况。所以将第一个FC层的激活函数改为 tanh。

2、在计算均值之前加上softplus激活函数。使得最后推理的结果都是正的,且减小方差。模型中计算正态分布在某一个区间的积分,需要保证 $\sigma >0$,才能让正态分布函数有意义,但是原始论文中:

image-20231026182412236

使用的是Relu激活函数,有可能训练得到 $\sigma = 0$。

3、训练中对边界值进行截断,防止训练中部分 $\Delta u$过大,产生nan值。

4、最后一层维度通过实验调整为 16。

5、边界值的初始化值对于模型训练影响很大,我们数据集下初始化值为(-0.75,-0.25, 0.25, 0.75)

6、deep CNN 由 resnet50 调整为 swin transformer。

四、结果展示

image2022-11-3_15-17-31

image2022-11-3_15-21-28

image2022-11-3_15-19-28

该美观度模型计算的特征应用在360图片搜索的排序中,离线ndcg指标和在线Ctr均得到了提升。

参考文献

【1】N. Murray, L. Marchesotti, and F. Perronnin. Ava: A large-scale database for aesthetic visual analysis. In Computer Vision and Pattern Recognition (CVPR), pages 2408–2415,Providence, RI, USA, 2012. IEEE.

【2】S. Kong, X. Shen, Z. Lin, R. Mech, and C. Fowlkes. Photo aesthetics ranking network with attributes and content adapta-tion. In European Conference on Computer Vision (ECCV),
page 662679, Amsterdam, The Netherlands, 2016. Springer.

【3】H. Talebi and P . Milanfar. Nima: Neural image assess-ment. IEEE Transactions on Image Processing, 27:3998–4011, 2017

NIMA:Neural Image Assessment

1、introduction

  1. 基于CNN的方法相比较早期基于手工制作的特征的做法,性能有显著的提升;

  2. AVA 数据集,图片审美视觉分析的标准数据集;

  3. 深度CNN非常适合审美评估任务【1】【2】;他们的双列 CNN 由四个卷积层和两个全连接层组成,其输入是调整大小的图像和大小为 224 × 224 的裁剪窗口;

  4. 之前大多是通过分类或者回归的方法预测人类评估的分数;

  5. kong【3】训练了一个基于 AlexNet 的 CNN 来学习两个输入图像的审美分数差异,从而间接优化排名相关性。

  6. NIMA的目标是预测与人类评分的相关性,而不是将图片分类或者回归到平均分。提出了EMD loss,它显示了有序类分类的性能提升。实验也表明,这种方法也更准确地预测了平均分。

2、proposed method

模型建立在图片分类模型的结构基础上。

image-20231026114849878

在训练阶段,输入图像被重新缩放为256256,然后随机提取 224\224的裁剪,这减少潜在的过度拟合问题。

3、实验

基线CNN权重通过在ImageNet上训练来初始化,最后一个全连接层是随机初始化。权重和偏置动量设置为0.9,基线CNN最后一层dropout应用0.75。基线CNN层和最后一个全连接层的学习率分别设置为310e-7,3\10e-6。在基线CNN层上设置较低的学习率会导致使用sgd时更容易和更快优化。

参考文献

【1】Deep multi-patch aggregation network for image style, aesthetics, and quality estimation

【2】Rating image aesthetics using deep learning

【3】S. Kong, X. Shen, Z. Lin, R. Mech, and C. Fowlkes, “Photo aesthetics ranking network with attributes and content adaptation,” in European Conference on Computer Vision. Springer, 2016, pp. 662–679. 1, 2, 6, 7

ViT(Vision Transformer)

模型介绍

受到NLP领域中Transformer成功应用的启发,Vit算法中尝试将标准的Transformer结构直接应用于图像,并对整个图像分类流程进行最少的修改。

Vit原论文中最核心的结论是,当拥有足够多的数据进行预训练的时候,ViT的表现就会超过CNN,突破Transformer的归纳偏置的限制,可以在下游任务中获得较好的迁移效果。

但是当训练数据集不够大的时候,ViT的表现通常比同等大小的ResNets要差一些,因为Transformer和CNN相比缺少归纳偏置(inductive bias),即一种先验知识,提前做好的假设。CNN具有两种归纳偏置,一种是局部性(locality/two-dimensional neighborhood structure),即图片上相邻的区域具有相似的特征;一种是平移不变形(translation equivariance), $f(g(x)=g(f(x)))$ ,其中g代表卷积操作,f代表平移操作。当CNN具有以上两种归纳偏置,就有了很多先验信息,需要相对少的数据就可以学习一个比较好的模型。

模型结构与实现

图1 ViT算法结构示意图

1.图像分块嵌入

transformer的输入是一个二维矩阵,因此在ViT算法中,首先要做的是如何将一个$H\times W\times C$ 的三维图像转换为$N\times D$ 的二维输入。

iT中的具体实现方式为:将 $H×W×C$ 的图像,变为一个 $N×(P^2\times C)$ 的序列。这个序列可以看作是一系列展平的图像块,也就是将图像切分成小块后,再将其展平。该序列中一共包含了 $N=HW/P^2$ 个图像块,每个图像块的维度则是 $(P^2\times C)$。其中 $P$ 是图像块的大小,$C$ 是通道数量。经过如上变换,就可以将 $N$ 视为sequence的长度了。

但是,此时每个图像块的维度是 $(P2\times C)$,而我们实际需要的向量维度是 $D$,因此我们还需要对图像块进行 Embedding。这里 Embedding 的方式非常简单,只需要对每个 $(P^2\times C)$的图像块做一个线性变换,将维度压缩为 $D$ 即可。

2.多头注意力

将图像转换成序列之后,就可以将其输入到 Transformer 中结构中进行特征提取了。

图4 多头注意力

3.MLP

图7 多层感知机

4.DropPath

除了以上重要模块意外,代码实现过程中还使用了DropPath(Stochastic Depth)来代替传统的Dropout结构,DropPath可以理解为一种特殊的 Dropout。其作用是在训练过程中随机丢弃子图层(randomly drop a subset of layers),而在预测时正常使用完整的 Graph。

参考文献An Image is Worth 16x16 Words:Transformers for Image Recognition at Scale

resnet

1.1 batch normalization原理

提出背景:在训练层数较深的神经网络时,参数的变化导致每一层的输入分布会发生变化,进而上层的网络需要不停地去适应这些分布变化,使得我们的模型训练变得困难——internal Covariate Shift

问题:上层网络需要不停调整来适应输入分布的变化,导致网络学习速度的降低;网络的训练过程容易陷入梯度饱和区,减缓网络收敛速度。

减缓internal covariate shift的方法:

  • 白化:对输入数据分布进行变换,具有相同的均值和方差;
  • batch normalization:由于白化过程计算成本太高,且改变了网络每一层的分布。

image-20220701153501142

image-20220701153552148

1.2 resnet 结构

image-20220701154852179

Stage 0

  • (3,224,224)指输入INPUT的通道数(channel)、高(height)和宽(width),即(C,H,W)。现假设输入的高度和宽度相等,所以用(C,W,W)表示。
  • 该stage中第1层包括3个先后操作
  1. CONV
    CONV是卷积(Convolution)的缩写,7×7指卷积核大小,64卷积核的数量(即该卷积层输出的通道数),/2指卷积核的步长为2。
  2. BN
    BN是Batch Normalization的缩写,即常说的BN层。
  3. RELU
    RELU指ReLU激活函数。
  • 该stage中第2层为MAXPOOL,即最大池化层,其kernel大小为3×3、步长为2

  • (64,56,56)是该stage输出的通道数(channel)、高(height)和宽(width),其中64等于该stage第1层卷积层中卷积核的数量,56等于224/2/2(步长为2会使输入尺寸减半)。

总体来讲,在Stage 0中,形状为(3,224,224)的输入先后经过卷积层、BN层、ReLU激活函数、MaxPooling层得到了形状为(64,56,56)的输出。

Inception

背景

一般来说,提升神经网络性能最直接的办法就是增加网络的尺寸,包括增加网络的深度和宽度两个方面。但这种方式存在一些问题:

  1. 参数太多,如果训练数据集有限,很容易产生过拟合;

  2. 网络越大,参数越多,计算复杂度越高,难以应用;

  3. 网络越深,容易出现梯度弥散问题,难以优化模型;

Inception-v1

深度研究 Inception Net模型之前,必须了解 Inception 网络的一个重要概念:

1×1卷积:1×1 卷积简单地将输入像素及其所有相应通道映射到输出像素。1×1卷积作为降维模块,一定程度上减少的计算量。

  • 例如,在不使用1×1卷积的情况下执行5×5卷积,如下所示:

FLOPs运算次数:(14×14×48)×(5×5×480)= 112.9M

  • 使用 1×1 卷积:

FLOPs运算次数

1×1卷积的操作数= (14×14×16)×(1×1×480)=1.5M
5×5卷积的操作数= (14×14×48)×(5×5×16 ) = 3.8M
相加后,1.5M + 3.8M = 5.3M

因此1×1卷积可以帮助减少模型大小,这可以在某种程度上帮助减少过度拟合问题;

降维初始模型

Inception v2

Inception v1架构的问题

Inception V1有时会使用5×5等卷积,导致输入维度大幅下降。这导致神经网络使用一些精度下降。其背后的原因是,如果输入维度下降得太快,神经网络容易丢失信息。 此外,与3×3相比,
当我们使用更大的卷积(如5×5 )时,复杂度也会降低. 我们可以在因式分解方面走得更远,即我们可以将3×3卷积分成1×3的非对称卷积,然后是3×1卷积。这相当于滑动一个具有与3×3卷积相同感受野但比*3×3便宜33%的两层网络。当输入维度很大但仅当输入大小为mxm时,这种分解不适用于早期层(m 在 12 到 20 之间)。根据 Inception V1 架构,辅助分类器提高了网络的收敛性。他们认为,通过将有用的梯度推到较早的层(以减少损失),它可以帮助减少深层网络中梯度消失问题的影响。但是,这篇论文的作者发现这个分类器在训练的早期并没有很好地提高收敛性。

Batch Normalization

在BN的论文里,作者提出了Internal Covariate Shift这个问题,即在训练神经网络的过程中,因为前一层的参数变化而导致每层的输入分布都在不断变化(the distribution of each layer’s inputs changes during training, as the parameters of the previous layers change)。这使得我们需要更低的学习率和更小心地进行参数初始化,导致我们难以充分构建一个具有饱满地非线性结构的模型,而这个现象就被称作Internal Covariate Shift。为了解决这个问题,Google提出了Batch Normalization(批规范化)。即在每次梯度下降前,对每个mini-batch做归一化操作来降低数据分布的影响。

小卷积和代替大卷积核

灯箱

该架构还将 nXn 分解转换为1xn和 nx1 分解。正如我们上面讨论的,3×3 卷积可以转换为1×3 ,然后是 3×1 卷积,与*3×3相比,计算复杂度降低了 33% 。

灯箱

Inception v3

Inception v3 类似于 Inception v2,并做了以下改动:

  • 使用 RMSprop 优化器;

  • 辅助分类器全连接层的BN;

  • 使用 7×7 分解卷积;

Inception v4

将 Inception 模块和残差连接 结合起来。

EmbOding!9196#CN360

0%