一、论文
《Densely Connected Hierarchical Network for Image Denoising》
近年来,深度卷积神经网络已应用于众多图像处理研究中,并且表现出了显着改善的性能。 在这项研究中,我们引入了密集连接的分层图像去噪网络(DHDN),它超越了最新的图像去噪解决方案的性能。我们提出的网络通过应用改进的U-Net的层次结构来提高图像降噪性能。 这使我们的网络可以使用比其他方法更多的参数。 此外,我们通过对我们的卷积块和网络应用密集的连通性和残差学习来诱导特征重用并解决消失的梯度问题。 最后,我们成功地应用了模型集成和自集成方法。 这使我们能够改善提议的网络的性能。 拟议网络的性能通过赢得NTRIE 2019真实图像去噪挑战sRGB轨道的第二名和raw-RGB轨道的第三名而得到验证。 关于加性高斯白噪声去除的其他实验结果也证明,所提出的网络优于传统方法。 尽管有这样一个事实,即所提出的网络仅用一组经过训练的参数即可处理各种噪声水平。
我们的主要贡献概括如下:
- 我们应用了经过修改的U-Net的层次结构,使我们的网络能够有效地使用有限的内存。 因此,与常规网络相比,我们的模型可以使用更多的参数。
- 我们对新颖的卷积块和网络体系结构进行密集的连通性和残差学习,以准确消除输入图像的噪点并解决消失梯度问题。
- 我们采用自集成和模型集成的方法; 这使我们提出的网络能够改善输出图像的客观和主观质量。
- 我们通过一套训练参数来训练模型以处理各种噪声水平。 由于我们的网络不需要输入噪声电平的信息,因此我们完全克服了传统方法的局限性。
二、网络结构
三、代码
下载:https://github.com/BumjunPark/DHDN
import torch
import torch.nn as nn
class _DCR_block(nn.Module):
def __init__(self, channel_in):
super(_DCR_block, self).__init__()
self.conv_1 = nn.Conv2d(in_channels=channel_in, out_channels=int(channel_in/2.), kernel_size=3, stride=1, padding=1)
self.relu1 = nn.PReLU()
self.conv_2 = nn.Conv2d(in_channels=int(channel_in*3/2.), out_channels=int(channel_in/2.), kernel_size=3, stride=1, padding=1)
self.relu2 = nn.PReLU()
self.conv_3 = nn.Conv2d(in_channels=channel_in*2, out_channels=channel_in, kernel_size=3, stride=1, padding=1)
self.relu3 = nn.PReLU()
def forward(self, x):
residual = x
out = self.relu1(self.conv_1(x))
conc = torch.cat([x, out], 1)
out = self.relu2(self.conv_2(conc))
conc = torch.cat([conc, out], 1)
out = self.relu3(self.conv_3(conc))
out = torch.add(out, residual)
return out
class _down(nn.Module):
def __init__(self, channel_in):
super(_down, self).__init__()
self.relu = nn.PReLU()
self.maxpool = nn.MaxPool2d(2)
self.conv = nn.Conv2d(in_channels=channel_in, out_channels=2*channel_in, kernel_size=1, stride=1, padding=0)
def forward(self, x):
out = self.maxpool(x)
out = self.relu(self.conv(out))
return out
class _up(nn.Module):
def __init__(self, channel_in):
super(_up, self).__init__()
self.relu = nn.PReLU()
self.subpixel = nn.PixelShuffle(2)
self.conv = nn.Conv2d(in_channels=channel_in, out_channels=channel_in, kernel_size=1, stride=1, padding=0)
def forward(self, x):
out = self.relu(self.conv(x))
out = self.subpixel(out)
return out
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv_i = nn.Conv2d(in_channels=1, out_channels=128, kernel_size=1, stride=1, padding=0)
self.relu1 = nn.PReLU()
self.DCR_block11 = self.make_layer(_DCR_block, 128)
self.DCR_block12 = self.make_layer(_DCR_block, 128)
self.down1 = self.make_layer(_down, 128)
self.DCR_block21 = self.make_layer(_DCR_block, 256)
self.DCR_block22 = self.make_layer(_DCR_block, 256)
self.down2 = self.make_layer(_down, 256)
self.DCR_block31 = self.make_layer(_DCR_block, 512)
self.DCR_block32 = self.make_layer(_DCR_block, 512)
self.down3 = self.make_layer(_down, 512)
self.DCR_block41 = self.make_layer(_DCR_block, 1024)
self.DCR_block42 = self.make_layer(_DCR_block, 1024)
self.up3 = self.make_layer(_up, 2048)
self.DCR_block33 = self.make_layer(_DCR_block, 1024)
self.DCR_block34 = self.make_layer(_DCR_block, 1024)
self.up2 = self.make_layer(_up, 1024)
self.DCR_block23 = self.make_layer(_DCR_block, 512)
self.DCR_block24 = self.make_layer(_DCR_block, 512)
self.up1 = self.make_layer(_up, 512)
self.DCR_block13 = self.make_layer(_DCR_block, 256)
self.DCR_block14 = self.make_layer(_DCR_block, 256)
self.conv_f = nn.Conv2d(in_channels=256, out_channels=1, kernel_size=1, stride=1, padding=0)
self.relu2 = nn.PReLU()
def make_layer(self, block, channel_in):
layers = []
layers.append(block(channel_in))
return nn.Sequential(*layers)
def forward(self, x):
residual = x
out = self.relu1(self.conv_i(x))
out = self.DCR_block11(out)
conc1 = self.DCR_block12(out)
out = self.down1(conc1)
out = self.DCR_block21(out)
conc2 = self.DCR_block22(out)
out = self.down2(conc2)
out = self.DCR_block31(out)
conc3 = self.DCR_block32(out)
conc4 = self.down3(conc3)
out = self.DCR_block41(conc4)
out = self.DCR_block42(out)
out = torch.cat([conc4, out], 1)
out = self.up3(out)
out = torch.cat([conc3, out], 1)
out = self.DCR_block33(out)
out = self.DCR_block34(out)
out = self.up2(out)
out = torch.cat([conc2, out], 1)
out = self.DCR_block23(out)
out = self.DCR_block24(out)
out = self.up1(out)
out = torch.cat([conc1, out], 1)
out = self.DCR_block13(out)
out = self.DCR_block14(out)
out = self.relu2(self.conv_f(out))
out = torch.add(residual, out)
return out
四、相关资料
真实噪声:Densely Connected Hierarchical Network for Image Denoising(CVPRW2019) 阅读理解
DHDN (a Densely connected Hierarchical image Denoising Network)