SR中的常见的损失函数

文章目录

  • Pixel Loss
  • Content Loss
  • Texture Loss
  • Adversarial Loss
  • Cycle Consistency Loss
  • Total Variation Loss
  • Prior-Based Loss

Pixel Loss

Pixel Loss是指两幅图像像素级的差异,主要包括L1 Loss (即mean absolute error)L2 Loss(即mean square error)
L pixel_11  ( I ^ , I ) = 1 h w c ∑ i , j , k ∣ I ^ i , j , k − I i , j , k ∣ , L pixel_12  ( I ^ , I ) = 1 h w c ∑ i , j , k ( I ^ i , j , k − I i , j , k ) 2 , \begin{aligned} & \mathcal{L}_{\text {pixel\_11 }}(\hat{I}, I)=\frac{1}{h w c} \sum_{i, j, k}\left|\hat{I}_{i, j, k}-I_{i, j, k}\right|, \\ & \mathcal{L}_{\text {pixel\_12 }}(\hat{I}, I)=\frac{1}{h w c} \sum_{i, j, k}\left(\hat{I}_{i, j, k}-I_{i, j, k}\right)^2, \end{aligned} Lpixel_11 (I^,I)=hwc1i,j,k I^i,j,kIi,j,k ,Lpixel_12 (I^,I)=hwc1i,j,k(I^i,j,kIi,j,k)2,
其中h、w、c分别为待评估图像的高度、宽度和通道数。

此外,还有一种像素L1 Loss的变体Charbonnier loss
L pixel_Cha  ( I ^ , I ) = 1 h w c ∑ i , j , k ( I ^ i , j , k − I i , j , k ) 2 + ϵ 2 \mathcal{L}_{\text {pixel\_Cha }}(\hat{I}, I)=\frac{1}{h w c} \sum_{i, j, k} \sqrt{\left(\hat{I}_{i, j, k}-I_{i, j, k}\right)^2+\epsilon^2} Lpixel_Cha (I^,I)=hwc1i,j,k(I^i,j,kIi,j,k)2+ϵ2
其中 ϵ \epsilon ϵ是数值稳定性的常数(例如, 1 0 − 3 10^{−3} 103)。

像素损失约束生成的HR图像 I ^ \hat I I^在像素值上足够接近ground truth I I I。与L1 Loss相比,L2 Loss惩罚大误差,但对小误差更宽容,因此往往导致结果过于平滑。在实践中,L1损耗比L2损耗上有更优的性能和收敛性。
由于PSNR的定义与像素级差异高度相关,最小化像素损耗直接最大化PSNR,所以像素损耗逐渐成为使用最广泛的损耗函数。
然而,由于像素损失实际上并没有考虑到图像质量(如感知质量,纹理),结果往往缺乏高频细节,对于超平滑纹理,在感知上不令人满意。


代码实现

  • Charbonnier Loss (L1)
class CharbonnierLoss(nn.Module):
    """Charbonnier Loss (L1)"""

    def __init__(self, eps=1e-6):
        super(CharbonnierLoss, self).__init__()
        self.eps = eps

    def forward(self, x, y):
        diff = x - y
        loss = torch.sum(torch.sqrt(diff * diff + self.eps)) # 求和
        return loss
        
class CharbonnierLoss2(nn.Module):
    """Charbonnier Loss (L1)"""

    def __init__(self, eps=1e-6):
        super(CharbonnierLoss2, self).__init__()
        self.eps = eps

    def forward(self, x, y):
        diff = x - y
        loss = torch.mean(torch.sqrt(diff * diff + self.eps)) # 求平均
        return loss

Content Loss

为了评价图像的perceptual quality,《Perceptual losses for real time style transfer and super-resolution》 和 《GeneratingImageswithPerceptualSimilarityMetricsbasedonDeepNetworks》将content loss引入到SR中。

Content Loss利用预先训练的图像分类网络来度量图像之间的语义差异。将该网络表示为 φ φ φ,提取的第 l l l层high-level representation为 φ ( l ) ( I ) φ^{(l)}(I) φ(l)(I),Content Loss表示为两幅图像high-level representation之间的欧氏距离,如下:
L content  ( I ^ , I ; ϕ , l ) = 1 h l w l c l ∑ i , j , k ( ϕ i , j , k ( l ) ( I ^ ) − ϕ i , j , k ( l ) ( I ) ) 2 , \mathcal{L}_{\text {content }}(\hat{I}, I ; \phi, l)=\frac{1}{h_l w_l c_l} \sqrt{\sum_{i, j, k}\left(\phi_{i, j, k}^{(l)}(\hat{I})-\phi_{i, j, k}^{(l)}(I)\right)^2}, Lcontent (I^,I;ϕ,l)=hlwlcl1i,j,k(ϕi,j,k(l)(I^)ϕi,j,k(l)(I))2 ,
其中 h l h_l hl w l w_l wl c l c_l cl分别为 l l l层上表示的高度、宽度和通道数。
Content Loss 本质上是将learned knowledge of hierarchical image features从分类网络 φ φ φ转移到SR网络中。
与像素损失相比,内容损失促使输出图像 I ^ \hat I I^在感知上与目标图像 I I I相似,而不是强迫它们精确匹配像素。因此,它产生的结果在视觉上更加直观,其中VGG[128]和ResNet[96]是最常用的预训练CNN。


代码实现
详细讲解见: 《代码详解 —— VGG Loss》

class VGG19(torch.nn.Module): # VGG19的网络
    def __init__(self, requires_grad=False):
        super().__init__()
        vgg_pretrained_features = torchvision.models.vgg19(pretrained=True).features
        self.slice1 = torch.nn.Sequential()
        self.slice2 = torch.nn.Sequential()
        self.slice3 = torch.nn.Sequential()
        self.slice4 = torch.nn.Sequential()
        self.slice5 = torch.nn.Sequential()
        for x in range(2):
            self.slice1.add_module(str(x), vgg_pretrained_features[x])
        for x in range(2, 7):
            self.slice2.add_module(str(x), vgg_pretrained_features[x])
        for x in range(7, 12):
            self.slice3.add_module(str(x), vgg_pretrained_features[x])
        for x in range(12, 21):
            self.slice4.add_module(str(x), vgg_pretrained_features[x])
        for x in range(21, 30):
            self.slice5.add_module(str(x), vgg_pretrained_features[x])
        if not requires_grad:
            for param in self.parameters():
                param.requires_grad = False

    def forward(self, X):
        h_relu1 = self.slice1(X)
        h_relu2 = self.slice2(h_relu1)
        h_relu3 = self.slice3(h_relu2)
        h_relu4 = self.slice4(h_relu3)
        h_relu5 = self.slice5(h_relu4)
        out = [h_relu1, h_relu2, h_relu3, h_relu4, h_relu5]
        return out

# VGG 特征距离损失
class VGGLoss(nn.Module):
    def __init__(self):
        super(VGGLoss, self).__init__()
        self.vgg = VGG19().cuda()
        # self.criterion = nn.L1Loss()
        self.criterion = nn.L1Loss(reduction='sum')
        self.criterion2 = nn.L1Loss()
        self.weights = [1.0 / 32, 1.0 / 16, 1.0 / 8, 1.0 / 4, 1.0]

    def forward(self, x, y):
        x_vgg, y_vgg = self.vgg(x), self.vgg(y)
        loss = 0
        for i in range(len(x_vgg)):
            # print(x_vgg[i].shape, y_vgg[i].shape)
            loss += self.weights[i] * self.criterion(x_vgg[i], y_vgg[i].detach())
        return loss

    def forward2(self, x, y):
        x_vgg, y_vgg = self.vgg(x), self.vgg(y)
        loss = 0
        for i in range(len(x_vgg)):
            # print(x_vgg[i].shape, y_vgg[i].shape)
            loss += self.weights[i] * self.criterion2(x_vgg[i], y_vgg[i].detach())
        return loss

Texture Loss

由于重建图像应该具有与目标图像相同的风格(如颜色、纹理、对比度),并且受Gatys等人《Texture synthesis using convolutional neural networks》、"《Image style transfer using convolutional neural networks》"的style representation的启发,Texture Loss (又称style reconstruction loss)被引入SR中。将image texture 视为不同特征通道之间的相关性,并定义为Gram矩阵 G ( l ) ∈ R c l × c l G^{(l)} \in \mathbb{R}^{c_l \times c_l} G(l)Rcl×cl, 其中 G i j ( l ) G_{ij}^{(l)} Gij(l) 为向量化后的feature map i i i j j j在层 l l l上的 Inner product :
G i j ( l ) ( I ) = vec ⁡ ( ϕ i ( l ) ( I ) ) ⋅ vec ⁡ ( ϕ j ( l ) ( I ) ) G_{i j}^{(l)}(I)=\operatorname{vec}\left(\phi_i^{(l)}(I)\right) \cdot \operatorname{vec}\left(\phi_j^{(l)}(I)\right) Gij(l)(I)=vec(ϕi(l)(I))vec(ϕj(l)(I))
其中 v e c ( ⋅ ) vec(·) vec()表示向量化运算, φ i ( l ) ( I ) φ^{(l)}_i (I) φi(l)(I)表示图像 I I I l l l层特征映射的第 i i i个通道,则纹理损失为:
L texture  ( I ^ , I ; ϕ , l ) = 1 c l 2 ∑ i , j ( G i , j ( l ) ( I ^ ) − G i , j ( l ) ( I ) ) 2 \mathcal{L}_{\text {texture }}(\hat{I}, I ; \phi, l)=\frac{1}{c_l^2} \sqrt{\sum_{i, j}\left(G_{i, j}^{(l)}(\hat{I})-G_{i, j}^{(l)}(I)\right)^2} Ltexture (I^,I;ϕ,l)=cl21i,j(Gi,j(l)(I^)Gi,j(l)(I))2
Sajjadi等人提出的EnhanceNet[8]通过使用纹理损失,可以创造出更逼真的纹理,并产生视觉上更令人满意的结果。尽管如此,决定patch size 的大小以匹配纹理仍然是通过经验估计的。过小的patch 会导致纹理区域出现伪迹,而过大的patch会导致整个图像出现伪迹,因为纹理统计数据是在不同纹理区域上平均的。

Adversarial Loss

近年来,由于其强大的学习能力,GANs[24]受到越来越多的关注,并被引入到各种视觉任务中。具体来说,GAN由一个执行生成(例如,文本生成,图像变换)的生成器和一个识别器组成,识别器将生成的结果和从目标分布中采样的实例作为输入,并区分每个输入是否来自于目标分布。在训练过程中,交替执行两个步骤:
(a)固定生成器并训练识别器,使其更好地进行判别;
(b)固定识别器并训练生成器,使其欺骗判别器。
通过充分的迭代对抗训练,生成的生成器可以产生与真实数据分布一致的输出,而鉴别器不能区分生成的数据与真实数据。

在超分辨率方面,采用对抗学习是很简单的,这种情况下,我们只需要将SR模型作为一个生成器,并定义一个额外的鉴别器来判断输入图像是否生成。因此,Ledig等人[25]首先提出了基于交叉熵的对抗损失的SRGAN,如下所示:
L gan_ce_g  ( I ^ ; D ) = − log ⁡ D ( I ^ ) L gan_ce_d  ( I ^ , I s ; D ) = − log ⁡ D ( I s ) − log ⁡ ( 1 − D ( I ^ ) ) , \begin{aligned} \mathcal{L}_{\text {gan\_ce\_g }}(\hat{I} ; D) & =-\log D(\hat{I}) \\ \mathcal{L}_{\text {gan\_ce\_d }}\left(\hat{I}, I_s ; D\right) & =-\log D\left(I_s\right)-\log (1-D(\hat{I})), \end{aligned} Lgan_ce_g (I^;D)Lgan_ce_d (I^,Is;D)=logD(I^)=logD(Is)log(1D(I^)),
其中 L g a n _ c e _ g L_{gan\_ce\_g} Lgan_ce_g L g a n _ c e _ d L_{gan\_ce\_d} Lgan_ce_d分别表示生成器(即SR模型)和判别器D(即二分类器)的对抗损失, I s I_s Is表示从ground truth中随机采样的图像。此外,Enhancenet[8]也采用了类似的对抗损失。
此外,Wang et al.[32]和Yuan et al.[131]采用基于最小二乘误差的对抗损失,使训练过程更加稳定,获得更高质量的结果,给出:
L gan_ls_g  ( I ^ ; D ) = ( D ( I ^ ) − 1 ) 2 , L gan_ls_d  ( I ^ , I s ; D ) = ( D ( I ^ ) ) 2 + ( D ( I s ) − 1 ) 2 . \begin{aligned} \mathcal{L}_{\text {gan\_ls\_g }}(\hat{I} ; D) & =(D(\hat{I})-1)^2, \\ \mathcal{L}_{\text {gan\_ls\_d }}\left(\hat{I}, I_s ; D\right) & =(D(\hat{I}))^2+\left(D\left(I_s\right)-1\right)^2 . \end{aligned} Lgan_ls_g (I^;D)Lgan_ls_d (I^,Is;D)=(D(I^)1)2,=(D(I^))2+(D(Is)1)2.
与上述研究关注对抗损失的具体形式不同,Park等人[133]认为像素级鉴别器导致产生无意义的高频噪声,并附加另一个特征级鉴别器对经过预处理的CNN提取的高级表示进行操作,该CNN能够捕获真实HR图像中更有意义的属性。Xu等人[63]将一个由生成器和多个特定类别鉴别器组成的多类GAN融合在一起。ESRGAN[103]采用相对论GAN[134]来预测真实图像比假图像相对真实的概率,而不是输入图像真实或假的概率,从而指导恢复更详细的纹理。

广泛的MOS测试(第2.3.3节)表明,尽管使用对抗损失和内容损失训练的SR模型比使用像素损失训练的SR模型获得更低的PSNR,但它们在感知质量[8],[25]上有显著的提高。实际上,该鉴别器提取了真实HR图像中一些难以学习的潜在模式,并推动生成的HR图像符合,从而有助于生成更真实的图像。但目前GAN的训练过程仍然困难且不稳定。虽然已有一些关于如何稳定GAN训练的研究[135]、[136]、[137],但如何确保整合到SR模型中的GAN被正确训练并发挥积极作用仍然是一个问题。

Cycle Consistency Loss

Cycle Consistency Loss。受Zhu等人[138]提出的CycleGAN的启发,Yuan等人[131]提出了一种用于超分辨率的cyclin -cycle方法。具体来说,他们不仅超解析LR图像 I I I到HR图像 I ^ \hat I I^,而且还将采样 I ^ \hat I I^返回到另一个LR图像 I I I通过另一个CNN。要求再生后的 I ^ \hat I I^与输入 I I I相同,因此引入循环一致性损失来约束其像素级一致性:
L cycle  ( I ′ , I ) = 1 h w c ∑ i , j , k ( I i , j , k ′ − I i , j , k ) 2 . \mathcal{L}_{\text {cycle }}\left(I^{\prime}, I\right)=\frac{1}{h w c} \sqrt{\sum_{i, j, k}\left(I_{i, j, k}^{\prime}-I_{i, j, k}\right)^2} . Lcycle (I,I)=hwc1i,j,k(Ii,j,kIi,j,k)2 .

Total Variation Loss

为了抑制生成图像中的噪声,Aly等人[140]在SR中引入了Total Variation Loss(TV)[139]。定义为相邻像素之间的绝对差之和,度量图像中噪声的大小,如下所示:
L T V ( I ^ ) = 1 h w c ∑ i , j , k ( I ^ i , j + 1 , k − I ^ i , j , k ) 2 + ( I ^ i + 1 , j , k − I ^ i , j , k ) 2 \mathcal{L}_{\mathrm{TV}}(\hat{I})=\frac{1}{h w c} \sum_{i, j, k} \sqrt{\left(\hat{I}_{i, j+1, k}-\hat{I}_{i, j, k}\right)^2+\left(\hat{I}_{i+1, j, k}-\hat{I}_{i, j, k}\right)^2} LTV(I^)=hwc1i,j,k(I^i,j+1,kI^i,j,k)2+(I^i+1,j,kI^i,j,k)2
Lai et al.[25]和Yuan et al.[131]也采用了TV loss来增加空间平滑度。

Prior-Based Loss

除上述损失函数外,Prior-Based Loss还引入了外部先验知识来约束损失函数的生成。具体来说,Bulat等人的[30]关注于人脸图像SR,并引入了人脸对齐网络(FAN)来约束人脸地标的一致性。在此基础上,本文提出的Super-FAN算法既提高了LR人脸对齐的性能,又提高了人脸图像识别的性能。
实际上,引入分类网络的内容损失和纹理损失本质上为SR提供了层次图像特征的先验知识,通过引入更多的先验知识,SR的性能可以进一步提高。

参考:《Deep Learning for Image Super-resolution: A Survey》

你可能感兴趣的:(SR,损失函数)