GAN论文研究之注意力生成器
文章目录
前言
对于NICE-GAN模型中用到的组件,部分只是进行原理上的简单介绍,至于为什么使用这些组件,它是怎么起作用的,还需要起源追朔,比如SN-GAN中首次提出spectral normalization这种新的权重归一化方法来稳定判别器的训练,还有U-GAT-IT模型中如何通过CAM(Class Activation Map)实现注意力机制,(GAP → \rightarrow → CAM → \rightarrow → Attentional Net)
一、Class Activation Mapping
首次提出CAM(Class Activation Mapping)这个概念是在论文《Learning Deep Features for Discriminative Localization 》(2016CVPR)中。
简单来说,这篇文章主要介绍了两个核心技术:
GAP(Global Average Pooling Layer) 和 CAM(Class Activation Mapping)
1. GAP
池化层的本质是一个下采样,因为数据经过卷积之后维度越来越高,而且特征图没有多大改变,在连续多个卷积之后,会产生一个很大的参数量,不仅会大大的增加网络训练的难度,还容易造成过拟合的现象,所以通常会在卷积层之后放一个池化层对数据进行压缩,降低维度,减少参数量。池化操作能够对上一层的特征图进行融合,因为相邻区域的参数具有较强的关联性,还能够防止发生过拟合现象。
pooling的结果是使得特征减少,参数减少,但pooling的目的并不仅在于此。
pooling目的是为了保持某种不变性(旋转、平移、伸缩等)
根据相关理论,特征提取的误差主要来自两个方面:
(1)邻域大小受限造成的估计值方差增大;
(2)卷积层参数误差造成估计均值的偏移。
一般来说
average-pooling能减小第一种误差(邻域大小受限造成的估计值方差增大),更多的保留图像的背景信息。
max-pooling能减小第二种误差(卷积层参数误差造成估计均值的偏移),更多的保留纹理信息。
第一个提出GAP这个想法的,是一篇叫做《Network in Network》的论文。这篇论文发现用GAP代替全连接层,不仅可以降低维度,防止过拟合,减少大量参数,网络的性能也很不错。
作者在卷积层后使用GAP模块:
we directly output the spatial average of the feature maps from the last mlpconv layer as the confidence of categories via a global average pooling layer
后续在论文《Learning Deep Features for Discriminative Localization 》中,他们发现了GAP的一个作用,能保留空间信息并且定位(localization)
2. CAM
使用全局均值池化生成CAM的步骤:网络主要由卷积层组成,并且在最后的输出层之前, 在卷积特征图上进行全局平均池化,用于全连接层。可以通过将输出层的权重投影到卷积特征图上来识别图像区域的重要性,该技术称为类激活映射(class, activation mapping)。
W
1
W_{1}
W1 到
W
n
W_{n}
Wn 为GAP到输出层全连接到目标类别(上图目标类别为狗)的权重,由于GAP特征向量是直接来自于特征图(线性关系),因此该权重可视为特征图对目标类别score的贡献程度,进行加权求和既可以获取CAM。
M c ( x , y ) = ∑ k w k c f k ( x , y ) M_{c}(x,y) = \sum_{k}w_{k}^{c}f_{k}(x,y) Mc(x,y)=k∑wkcfk(x,y)
其中 f k ( x , y ) f_{k}(x,y) fk(x,y) 为最后一层特征图位置 ( x , y ) (x,y) (x,y) 的值, w k c w_{k}^{c} wkc 为类别c的全连接权重
- 核心代码
代码实现并不复杂, 提取到特征图和目标类别全连接的权重,直接加权求和,再经过relu操作去除负值,最后归一化获取CAM# 获取全连接层的权重 self._fc_weights = self.model._modules.get(fc_layer).weight.data # 获取目标类别的权重作为特征权重 weights=self._fc_weights[class_idx, :] # 这里self.hook_a为最后一层特征图的输出 batch_cams = (weights.unsqueeze(-1).unsqueeze(-1) * self.hook_a.squeeze(0)).sum(dim=0) # relu操作,去除负值 batch_cams = F.relu(batch_cams, inplace=True) # 归一化操作 batch_cams = self._normalize(batch_cams)
3. Attentional network
U-GAT-IT中的注意力网络只是对CAM进行了一个小改进,结合GAP,GMP训练学习源域的特征权重
w
k
w_{k}
wk,得到注意力向量
ω
\omega
ω。
- 对应源码中的生成器传播过程
def forward(self, input):
x = self.DownBlock(input) #得到编码器的输出,对应途中encoder feature map
gap = torch.nn.functional.adaptive_avg_pool2d(x, 1) #全局平均池化
gap_logit = self.gap_fc(gap.view(x.shape[0], -1)) #gap的预测
gap_weight = list(self.gap_fc.parameters())[0] #self.gap_fc的权重参数
gap = x * gap_weight.unsqueeze(2).unsqueeze(3) #得到全局平均池化加持权重的特征图
gmp = torch.nn.functional.adaptive_max_pool2d(x, 1) #全局最大池化
gmp_logit = self.gmp_fc(gmp.view(x.shape[0], -1)) #gmp的预测
gmp_weight = list(self.gmp_fc.parameters())[0] #self.gmp_fc的权重参数
gmp = x * gmp_weight.unsqueeze(2).unsqueeze(3) #得到全局最大池化加持权重的特征图
cam_logit = torch.cat([gap_logit, gmp_logit], 1) #结合gap和gmp的cam_logit预测
x = torch.cat([gap, gmp], 1) #结合两种池化后的特征图,通道数512
x = self.relu(self.conv1x1(x)) #接入一个卷积层,通道数512转换为256
heatmap = torch.sum(x, dim=1, keepdim=True) #得到注意力热力图
if self.light:
x_ = torch.nn.functional.adaptive_avg_pool2d(x, 1) #轻量级则先经过一个gap
x_ = self.FC(x_.view(x_.shape[0], -1))
else:
x_ = self.FC(x.view(x.shape[0], -1))
gamma, beta = self.gamma(x_), self.beta(x_) #得到自适应gamma和beta
for i in range(self.n_blocks):
#将自适应gamma和beta送入到AdaILN
x = getattr(self, 'UpBlock1_' + str(i+1))(x, gamma, beta)
out = self.UpBlock2(x) #通过上采样后的模块,得到生成结果
return out, cam_logit, heatmap #模型输出为生成结果,cam预测以及热力图
二、spectral normalization
原生 GAN 的目标函数等价于优化生成数据的分布 p g p_{g} pg 和真实数据的分布 p r p_{r} pr 之间的 J-S 散度 (Jensen–Shannon Divergence)。在但存在的问题是判别器训练越好,生成器梯度消失越严重。
WGAN使用性质优良的 Wasserstein distance 代替原生 GAN 中的 J-S 散度。 然后利用KR对偶原理将 Wasserstein distance的求解问题转换为求解最优的利普希茨连续函数的问题。 为了使得判别器 D 满足利普希茨连续性,作者使用“梯度裁剪”将过大的参数直接裁剪到一个阈值以下。
我们可以这样理解:局部最小点附近如果是平坦(flatness)的话(斜率有约束),那么其泛化的性能将较好,反之,若是不平坦(sharpness)的话,稍微一点变动,将产生较大变化,则其泛化性能就不好,也就不稳定。
Spectral normalization for generative adversarial network” (以下简称 Spectral Norm) 使用一种更优雅的方式使得判别器 D 满足利普希茨连续性,限制了函数变化的剧烈程度,从而使模型更稳定。
1. Lipschitz 连续性
Lipschitz 条件限制了函数变化的剧烈程度,即函数的梯度。在一维空间中,很容易看出 y=sin(x) 是 1-Lipschitz的,它的最大斜率是 1
在 GAN 中,假设我们有一个判别器
D
:
I
→
R
D: I \rightarrow R
D:I→R ,其中
I
I
I 是图像空间。如果判别器是 K-Lipschitz continuous 的,那么对图像空间中的任意 x 和 y,有:
∥
D
(
x
)
−
D
(
y
)
∥
<
=
K
∥
x
−
y
∥
\lVert D(x) - D(y)\rVert <= K\lVert x - y \rVert
∥D(x)−D(y)∥<=K∥x−y∥
如果 K 取到最小值,那么 K 被称为 Lipschitz constant
2. SVD分解
Spectral Normalization的做法其实很简单: 将神经网络的每一层的参数 W W W 作 SVD 分解,然后将其最大的奇异值限定为1,满足1-Lipschitz条件, 具体地,在每一次更新 W W W 之后都除以 W W W 最大的奇异值。 这样,每一层对输入 x x x 最大的拉伸系数不会超过 1。
经过 Spectral Norm 之后,神经网络的每一层 g l ( x ) g_{l}(x) gl(x) 权重,都满足
g
l
(
x
)
−
g
l
(
x
)
x
−
y
<
=
1
\frac{g_{l}(x) - g_{l}(x)}{x - y} <= 1
x−ygl(x)−gl(x)<=1
对于整个神经网络 自然也就满足利普希茨连续性。
而在图像上每个位置的卷积操作,正好可以看成是一个矩阵乘法。因此,我们只需要约束各层卷积核的参数 ,使它是 1-Lipschitz continuous 的,就可以满足整个神经网络的 1-Lipschitz continuity。而我们已经知道,想让矩阵满足 1-Lipschitz continuous,只需要让它所有元素同时除以它的最大奇异值,或者说是它的 spectural norm。
总结
- 个人对于注意力机制的理解
对于不同的物体,网络不同通道的响应图程度是不一样的,可能对于某一个特定物体,这个通道有一大块区域相应,那个通道没有相应。这个时候用GAP我们可以把每个通道压缩,这样就得到了一个通道对于物体注意力的向量 ω \omega ω 。再用这个向量 ω \omega ω 对feature map进行加权。从而得到类别激活图,实现注意力机制。而NICE-GAN只是在此基础上加了个残差连接形成残差注意力机制
参考论文
Learning Deep Features for Discriminative Localizatiion
paper / blog
Unsupervised Generative Attentional Networks with Adaptive Layer-Instance Normalization for Image-to-Image Translation (U-GAT-IT)
paper / note