【文章閱讀】【超解像】--Residual Dense Network for Image Super-Resolution

【文章閱讀】【超解像】–Residual Dense Network for Image Super-Resolution

論文鏈接:https://arxiv.org/pdf/1802.08797.pdf

code:https://github.com/yulunzhang/RDN

1.主要貢獻

​ 本文作者結合Residual Black和Dense Black提出了RDN(Residual Dense Network)網絡結構,網絡主要由RDB(Residual Dense block)網絡組成,網絡的結構圖如下:
在這裏插入圖片描述

2.論文分析

如上圖,網絡主要由四部分構成:

(1) SFFNet(shallow feature extraction net)

​ 上圖中的前兩個卷基層組成了SFFNet,上圖中的F0=HSFE2(F1)F _ { 0 } = H _ { S F E 2 } \left( F _ { - 1 } \right),F1=HSFE1(ILR)F _ { - 1 } = H _ { S F E 1 } \left( I _ { L R } \right) F0F_0爲SFFNet輸出.

(2) RDBs(redidual dense blocks)

​ 上圖中F1,FdF_1,Fd表示該模塊的中間模塊輸出,根據之前的輸入獲得:
Fd=HRDB,d(Fd1)=HRDB,d(HRDB,d1((HRDB,1(F0)) )) \begin{aligned} F _ { d } & = H _ { R D B , d } \left( F _ { d - 1 } \right) \\ & = H _ { R D B , d } \left( H _ { R D B , d - 1 } \left( \cdots \left( H _ { R D B , 1 } \left( F _ { 0 } \right) \right) \cdots \right) \right) \end{aligned}
​ 該模塊的結構圖爲:
在這裏插入圖片描述
​ 該模塊將殘差模塊Residual block和dense block模塊進行了整合,三個模塊的區別如下:
在這裏插入圖片描述
​ RDB模塊的輸入是Fd1F_{d-1},輸出FdF_d, G0G_0表示Fd1F_{d-1}FdF_{d}的特徵向量數,RDB中間某層輸出爲:
Fd,c=σ(Wd,c[Fd1,Fd,1, ,Fd,c1]) F _ { d , c } = \sigma \left( W _ { d , c } \left[ F _ { d - 1 } , F _ { d , 1 } , \cdots , F _ { d , c - 1 } \right] \right)
假設Fd,cF_{d,c}包含GG個特徵圖(GG也被稱爲增長率);

RDB模塊中主要包含3個部分內容:

  • Contiguous memory

    該模塊將Fd1,Fd,1,Fd,c,FdCF_{d-1},F_{d,1},F_{d,c},F_{dC}的特徵都結合起來;

  • Local feature fusion

    該模塊是concat之後的111*1卷積操作,該操作的作用是CM後非常多的feature map不易於模型訓練,利用該模塊對輸出的維度進行了壓縮.

  • Local residual learning

    該模塊表示將Fd1F_{d-1}Fd,LFF_{d,LF}的特徵進行融合,該操作有助於提升模型的表達能力;
    Fd=Fd1+Fd,LF F _ { d } = F _ { d - 1 } + F _ { d , L F }

(3) DFF(Dense feature fusion)

​ 該模塊主要包含兩個模塊,Global feature fusion和Global Residual learning,其中Global feature fusion模塊的作用是將F1,F2,......FDF_1,F_2,......FD聯合起來FGF=HGFF([F1, ,FD])F _ { G F } = H _ { G F F } \left( \left[ F _ { 1 } , \cdots , F _ { D } \right] \right),Global Residual learning表示將F1F_{-1}FGFF_{GF}相加得到FDFF_{DF}輸出,FDF=F1+FGFF _ { D F } = F _ { - 1 } + F _ { G F }.該操作和RDB操作一樣.

(4) UPNet(Up-sampleing net)

​ 該模塊在網絡的最後利用上採樣和卷積實現圖像的放大.

RDN與DenseNet區別:

  • RDN中去掉了DenseNet中的BN和pooling模塊;
  • DenseNet中只有每一個dense block的輸出是concat起來的,而RDB中的利用局部特徵融合將RDB中的各層信息都進行了融合;
  • RDN利用全局特徵融合將各個RDB模塊中的信息都concat起來,並利用了最開始的特徵;

RDN與SRDenseNet的區別:

  • RDN加入了contiguous memory,使得先前的RDB模塊和當前的模塊信息直接融合,利用LFF,RDB模塊可以利用更大的增長率;RDB中的LRF的應用增加了信息和梯度的流動;
  • RDB內部沒有密集連接.
  • RDB使用了L1 loss,而SRDenseNet使用了L2 loss;

RDN與MemNet區別:

  • MemNet需要對原圖使用Bicubic插值方式對低分辨率圖像進行上採樣,RDN直接使用低分辨率圖像進行處理,減少了計算量和提高效率;
  • Memnet中包含逆向和門限單元模塊,不接受先前模塊的輸入,而RDB的各個模塊之間是有信息交流的;
  • MemNet沒有全部利用中間的特徵信息,而RDN利用GRL將所有的信息都利用起來;

3.結果分析

訓練數據集:利用DIV2K進行訓練,進行如下3種處理:

(1) BI方式:通過Bicubic對圖像進行下采樣,縮小比例爲x2,x3,x4;

(2)BD方式:先對原圖進行(777*7卷積,方差爲1.6)的高斯濾波,再對濾波後的圖像進行下采樣;

(3)DN方法:先做Bicubic下采樣,再加上30%的高斯噪聲;
在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

4.參考

1.https://blog.csdn.net/qq_14845119/article/details/81459859

5.附錄

RDB的Pytorch代碼實現如下:

class RDB_Conv(nn.Module):
    def __init__(self, inChannels, growRate, kSize=3):
        super(RDB_Conv, self).__init__()
        Cin = inChannels
        G  = growRate
        self.conv = nn.Sequential(*[
            nn.Conv2d(Cin, G, kSize, padding=(kSize-1)//2, stride=1),
            nn.ReLU()
        ])

    def forward(self, x):
        out = self.conv(x)
        return torch.cat((x, out), 1) 

class RDB(nn.Module):
    def __init__(self, growRate0, growRate, nConvLayers, kSize=3):
        super(RDB, self).__init__()
        G0 = growRate0
        G  = growRate
        C  = nConvLayers
        
        convs = []
        for c in range(C):
            convs.append(RDB_Conv(G0 + c*G, G))
        self.convs = nn.Sequential(*convs)
        
        # Local Feature Fusion
        self.LFF = nn.Conv2d(G0 + C*G, G0, 1, padding=0, stride=1)

    def forward(self, x):
        return self.LFF(self.convs(x)) + x

RDN的Pytorch代碼如下:

class RDN(nn.Module):
    def __init__(self, args):
        super(RDN, self).__init__()
        r = args.scale[0]
        G0 = args.G0
        kSize = args.RDNkSize

        # number of RDB blocks, conv layers, out channels
        self.D, C, G = {
            'A': (20, 6, 32),
            'B': (16, 8, 64),
        }[args.RDNconfig]

        # Shallow feature extraction net
        self.SFENet1 = nn.Conv2d(args.n_colors, G0, kSize, padding=(kSize-1)//2, stride=1)
        self.SFENet2 = nn.Conv2d(G0, G0, kSize, padding=(kSize-1)//2, stride=1)

        # Redidual dense blocks and dense feature fusion
        self.RDBs = nn.ModuleList()
        for i in range(self.D):
            self.RDBs.append(
                RDB(growRate0 = G0, growRate = G, nConvLayers = C)
            )

        # Global Feature Fusion
        self.GFF = nn.Sequential(*[
            nn.Conv2d(self.D * G0, G0, 1, padding=0, stride=1),
            nn.Conv2d(G0, G0, kSize, padding=(kSize-1)//2, stride=1)
        ])

        # Up-sampling net
        if r == 2 or r == 3:
            self.UPNet = nn.Sequential(*[
                nn.Conv2d(G0, G * r * r, kSize, padding=(kSize-1)//2, stride=1),
                nn.PixelShuffle(r),
                nn.Conv2d(G, args.n_colors, kSize, padding=(kSize-1)//2, stride=1)
            ])
        elif r == 4:
            self.UPNet = nn.Sequential(*[
                nn.Conv2d(G0, G * 4, kSize, padding=(kSize-1)//2, stride=1),
                nn.PixelShuffle(2),
                nn.Conv2d(G, G * 4, kSize, padding=(kSize-1)//2, stride=1),
                nn.PixelShuffle(2),
                nn.Conv2d(G, args.n_colors, kSize, padding=(kSize-1)//2, stride=1)
            ])
        else:
            raise ValueError("scale must be 2 or 3 or 4.")

    def forward(self, x):
        f__1 = self.SFENet1(x)
        x  = self.SFENet2(f__1)

        RDBs_out = []
        for i in range(self.D):
            x = self.RDBs[i](x)
            RDBs_out.append(x)

        x = self.GFF(torch.cat(RDBs_out,1))
        x += f__1

        return self.UPNet(x)

論文個人理解,如有問題,煩請指正,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章