生成对抗网络的学习记录

440 阅读5分钟

本文首发于个人博客:xerrors.fun/week-post-2…

欢迎访问更多文章:xerrors.fun


深度可分离卷积

参考:【CNN结构设计】深入理解深度可分离卷积

我的理解是将原本复杂的计算给简化了,原本的卷积计算给拆成了两个部分,第一部分是 depthwise 卷积,提取的是每一个通道的信息,不同的通道之间的联系并没有提取出来;第二部分是 pointwise 卷积,使用的是 1x1 的卷积,主要是提取不同通道的信息,这样既简化了计算,也可以获取不同维度的信息。我记得李宏毅老师的视频里面讲如何将模型参数变小的时候讲到过这个部分,图示也很容易理解。

# from: https://github.com/softmurata/AnimeGAN/blob/master/subnetwork.py#L156

class DepthWiseConv(nn.Module):

    def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=0, dilation=1, bias=False):
        super().__init__()
        self.depthwise = nn.Conv2d(in_channels, in_channels, kernel_size, stride, padding, dilation, groups=in_channels, bias=bias)
        self.pointwise = nn.Conv2d(in_channels, out_channels, 1, 1, 0, 1, 1, bias=bias)

    def forward(self, x):

        x = self.depthwise(x)
        x = self.pointwise(x)

        return x

转置卷积

以下内容摘自 雷课,在 PyTorch 中,可以使用 torch.nn.ConvTranspose2d 来实现。

对于很多网络架构的很多应用而言,我们往往需要进行与普通卷积方向相反的转换,即我们希望执行上采样。例子包括生成高分辨率图像以及将低维特征图映射到高维空间,比如在自动编码器或形义分割中。(在后者的例子中,形义分割首先会提取编码器中的特征图,然后在解码器中恢复原来的图像大小,使其可以分类原始图像中的每个像素。)

实现上采样的传统方法是应用插值方案或人工创建规则。而神经网络等现代架构则倾向于让网络自己自动学习合适的变换,无需人类干预。为了做到这一点,我们可以使用转置卷积。

转置卷积在文献中也被称为去卷积或 fractionally strided convolution。但是,需要指出「去卷积(deconvolution)」这个名称并不是很合适,因为转置卷积并非信号/图像处理领域定义的那种真正的去卷积。从技术上讲,信号处理中的去卷积是卷积运算的逆运算。但这里却不是这种运算。因此,某些作者强烈反对将转置卷积称为去卷积。人们称之为去卷积主要是因为这样说很简单。后面我们会介绍为什么将这种运算称为转置卷积更自然且更合适。

我们一直都可以使用直接的卷积实现转置卷积。对于下图的例子,我们在一个 2×2 的输入(周围加了 2×2 的单位步长的零填充)上应用一个 3×3 核的转置卷积。上采样输出的大小是 4×4。

将 2×2 的输入上采样成 4×4 的输出

有趣的是,通过应用各种填充和步长,我们可以将同样的 2×2 输入图像映射到不同的图像尺寸。下面,转置卷积被用在了同一张 2×2 输入上(输入之间插入了一个零,并且周围加了 2×2 的单位步长的零填充),所得输出的大小是 5×5。

将 2×2 的输入上采样成 5×5 的输出

观察上述例子中的转置卷积能帮助我们构建起一些直观认识。但为了泛化其应用,了解其可以如何通过计算机的矩阵乘法实现是有益的。从这一点上我们也可以看到为何「转置卷积」才是合适的名称。

在卷积中,我们定义 C 为卷积核,Large 为输入图像,Small 为输出图像。经过卷积(矩阵乘法)后,我们将大图像下采样为小图像。这种矩阵乘法的卷积的实现遵照:C x Large = Small。

下面的例子展示了这种运算的工作方式。它将输入平展为 16×1 的矩阵,并将卷积核转换为一个稀疏矩阵(4×16)。然后,在稀疏矩阵和平展的输入之间使用矩阵乘法。之后,再将所得到的矩阵(4×1)转换为 2×2 的输出。

卷积的矩阵乘法:将 Large 输入图像(4×4)转换为 Small 输出图像(2×2)

现在,如果我们在等式的两边都乘上矩阵的转置 CT,并借助「一个矩阵与其转置矩阵的乘法得到一个单位矩阵」这一性质,那么我们就能得到公式 CT x Small = Large,如下图所示。

卷积的矩阵乘法:将 Small 输入图像(2×2)转换为 Large 输出图像(4×4)

这里可以看到,我们执行了从小图像到大图像的上采样。这正是我们想要实现的目标。现在。你就知道「转置卷积」这个名字的由来了。转置矩阵的算术解释可参阅:arxiv.org/abs/1603.07…

Huber Loss

参考:机器学习常用损失函数小结 - 知乎

MSE 损失收敛快但容易受 outlier 影响,MAE 对 outlier 更加健壮但是收敛慢,Huber Loss 则是一种将 MSE 与 MAE 结合起来,取两者优点的损失函数,也被称作 Smooth Mean Absolute Error Loss 。其原理很简单,就是在误差接近 0 时使用 MSE,误差较大时使用 MAE,公式为图片

Jhuber=1Ni=1NIyiy^iδ(yiy^i)22+Iyiy^i>δ(δyiy^i12δ2)J_{h u b e r}=\frac{1}{N} \sum_{i=1}^{N} \mathbb{I}_{\left|y_{i}-\hat{y}_{i}\right| \leq \delta} \frac{\left(y_{i}-\hat{y}_{i}\right)^{2}}{2}+\mathbb{I}_{\left|y_{i}-\hat{y}_{i}\right|>\delta}\left(\delta\left|y_{i}-\hat{y}_{i}\right|-\frac{1}{2} \delta^{2}\right)

公式中 δ 是 Huber Loss 的一个超参数,δ 的值是 MSE 和 MAE 两个损失连接的位置。上式等号右边第一项是 MSE 的部分,第二项是 MAE 部分,在 MAE 的部分公式为 δyiy^i12δ2\delta\left|y_{i}-\hat{y}_{i}\right|-\frac{1}{2} \delta^{2} 是为了保证误差 yy^=±δ|y-\hat{y}|=\pm \delta 时 MAE 和 MSE 的取值一致,进而保证 Huber Loss 损失连续可导。

下图是 δ=1.0 时的 Huber Loss,可以看到在 [-δ, δ] 的区间内实际上就是 MSE 损失,在 (-∞, -δ) 和 (δ, ∞) 区间内为 MAE损失。

Huber Loss 的特点

Huber Loss 结合了 MSE 和 MAE 损失,在误差接近 0 时使用 MSE,使损失函数可导并且梯度更加稳定;在误差较大时使用 MAE 可以降低 outlier 的影响,使训练对 outlier 更加健壮。缺点是需要额外地设置一个 δ 超参数。

参考资料

1. 一文读懂 12种卷积方法(含1x1卷积、转置卷积和深度可分离卷积等) 2. 机器学习常用损失函数小结 - 知乎