✅博主简介:本人擅长建模仿真、数据分析、论文写作与指导,项目与课题经验交流。项目合作可私信或扫描文章底部二维码。
图像在人类生产生活中具有极大价值,而图像分辨率决定了其中存储的信息量。提高图像分辨率可改善信息量,图像超分辨率重建技术应运而生。近年来,基于深度学习的方法成为主流,但多数方法设计复杂网络结构以追求更好重建效果,这导致网络模型参数量和计算量较大,难以应用于计算资源有限的设备。同时,一些使用像素级损失训练的网络模型,重建图像往往过于平滑,缺乏纹理特征。
二、轻量级图像超分辨率重建网络 LMDFFN
-
核心轻量级特征提取块 LFEB
- 利用通道划分将特征分组,这一方式能显著减少网络的参数量和计算量。通过将分组特征分别经过普通方形卷积和非对称卷积,可以提取不同形状的纹理特征。这样的设计使得网络在不增加过多计算负担的情况下,能够更好地捕捉图像中的各种纹理信息。
-
通道和空间注意力机制
- 设计了一个更适用于图像超分辨率重建的通道和空间注意力机制。通道注意力有助于提取图像的纹理细节,能够让网络更加关注不同通道中对纹理表现重要的信息。空间注意力则可以关注不同特征图的不同空间位置,使得网络能够根据空间位置的重要性进行有针对性的处理。
-
深度可分离卷积在重建阶段的应用
- 在模型的重建阶段,应用深度可分离卷积进一步降低模型的参数量。深度可分离卷积将传统卷积分解为深度卷积和逐点卷积,在保持相似性能的同时大大减少了计算量和参数量,使得模型更加轻量化,适合在资源受限的环境中运行。
实验表明,LMDFFN 网络在具有较低模型参数量和计算量的情况下,在定量评价和视觉质量提升上都取得了优异的效果。它能够在不牺牲重建质量的前提下,降低对计算资源的需求,为图像超分辨率重建在各种设备上的应用提供了可能。
三、基于生成对抗网络的图像超分辨率重建算法 SRPGAN
-
生成模型的改进
- 设计了双分支残差块代替传统的残差块。双分支分别为含有注意力机制的分支和无注意力机制的分支,这样的设计可以实现不同特征的组合。注意力机制分支能够突出重要特征,无注意力机制分支则可以提供更基础的特征信息,两者结合使得生成模型能够更好地捕捉图像的各种特征。
-
归一化方式的探索
- 相对于传统的批量归一化层,使用更适合底层视觉问题的半实例归一化层。半实例归一化层在处理图像超分辨率重建等底层视觉问题时,能够更好地保留图像的细节和纹理信息,避免了批量归一化可能带来的一些问题,如对小批量数据不稳定性的影响。
-
判别模型的改进
- 应用 PatchGAN 代替普通的 GAN。PatchGAN 能够加强对于局部纹理信息的改善,它通过对图像的局部区域进行判别,使得生成模型更加注重局部纹理的真实性和细节,从而提高重建图像的视觉质量。
import torch
import torch.nn as nn
import torch.optim as optim
# 定义轻量级特征提取块
class LFEB(nn.Module):
def __init__(self, in_channels, out_channels):
super(LFEB, self).__init__()
self.channel_split = in_channels // 2
self.square_conv = nn.Conv2d(self.channel_split, out_channels // 2, kernel_size=3, padding=1)
self.asymmetric_conv = nn.Conv2d(self.channel_split, out_channels // 2, kernel_size=(3, 1), padding=(1, 0))
def forward(self, x):
split_x = torch.split(x, self.channel_split, dim=1)
square_out = self.square_conv(split_x[0])
asymmetric_out = self.asymmetric_conv(split_x[1])
return torch.cat([square_out, asymmetric_out], dim=1)
# 定义通道和空间注意力机制
class AttentionModule(nn.Module):
def __init__(self, in_channels):
super(AttentionModule, self).__init__()
self.channel_att = nn.Sequential(
nn.AdaptiveAvgPool2d(1),
nn.Conv2d(in_channels, in_channels // 16, kernel_size=1),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels // 16, in_channels, kernel_size=1)
)
self.spatial_att = nn.Sequential(
nn.Conv2d(in_channels, 1, kernel_size=1),
nn.Sigmoid()
)
def forward(self, x):
channel_att = self.channel_att(x)
x = x * channel_att
spatial_att = self.spatial_att(x)
return x * spatial_att
# 定义轻量级图像超分辨率重建网络
class LMDFFN(nn.Module):
def __init__(self, in_channels, out_channels):
super(LMDFFN, self).__init__()
self.lfeb = LFEB(in_channels, 64)
self.attention = AttentionModule(64)
self.conv1 = nn.Conv2d(64, 64, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(64, out_channels, kernel_size=3, padding=1)
def forward(self, x):
x = self.lfeb(x)
x = self.attention(x)
x = self.conv1(x)
x = self.conv2(x)
return x
# 定义生成模型中的双分支残差块
class DualBranchResidualBlock(nn.Module):
def __init__(self, in_channels):
super(DualBranchResidualBlock, self).__init__()
self.branch1 = nn.Sequential(
nn.Conv2d(in_channels, in_channels, kernel_size=3, padding=1),
AttentionModule(in_channels),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels, in_channels, kernel_size=3, padding=1)
)
self.branch2 = nn.Sequential(
nn.Conv2d(in_channels, in_channels, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels, in_channels, kernel_size=3, padding=1)
)
def forward(self, x):
return x + self.branch1(x) + self.branch2(x)
# 定义生成模型
class Generator(nn.Module):
def __init__(self, in_channels, out_channels):
super(Generator, self).__init__()
self.conv1 = nn.Conv2d(in_channels, 64, kernel_size=9, padding=4)
self.res_blocks = nn.Sequential(
DualBranchResidualBlock(64),
DualBranchResidualBlock(64),
DualBranchResidualBlock(64),
DualBranchResidualBlock(64),
DualBranchResidualBlock(64),
DualBranchResidualBlock(64)
)
self.conv2 = nn.Conv2d(64, out_channels, kernel_size=3, padding=1)
def forward(self, x):
x = self.conv1(x)
x = self.res_blocks(x)
return self.conv2(x)
# 定义判别模型
class Discriminator(nn.Module):
def __init__(self, in_channels):
super(Discriminator, self).__init__()
self.conv1 = nn.Conv2d(in_channels, 64, kernel_size=4, stride=2, padding=1)
self.conv2 = nn.Conv2d(64, 128, kernel_size=4, stride=2, padding=1)
self.conv3 = nn.Conv2d(128, 256, kernel_size=4, stride=2, padding=1)
self.conv4 = nn.Conv2d(256, 512, kernel_size=4, stride=1, padding=1)
self.fc = nn.Linear(512 * 4 * 4, 1)
def forward(self, x):
x = nn.LeakyReLU(0.2)(self.conv1(x))
x = nn.LeakyReLU(0.2)(self.conv2(x))
x = nn.LeakyReLU(0.2)(self.conv3(x))
x = nn.LeakyReLU(0.2)(self.conv4(x))
x = x.view(x.size(0), -1)
return torch.sigmoid(self.fc(x))
# 训练函数
def train(model, generator, discriminator, dataloader, optimizer, criterion):
for epoch in range(num_epochs):
for low_res, high_res in dataloader:
optimizer.zero_grad()
# 训练生成器
generated_high_res = generator(low_res)
g_loss = criterion(generated_high_res, high_res)
g_loss.backward()
optimizer.step()
# 训练判别器
real_labels = torch.ones_like(discriminator(high_res))
fake_labels = torch.zeros_like(discriminator(generated_high_res.detach()))
real_loss = criterion(discriminator(high_res), real_labels)
fake_loss = criterion(discriminator(generated_high_res), fake_labels)
d_loss = (real_loss + fake_loss) / 2
discriminator.zero_grad()
d_loss.backward()
optimizer.step()
# 主函数
if __name__ == "__main__":
in_channels = 3
out_channels = 3
num_epochs = 100
batch_size = 16
learning_rate = 0.0001
model = LMDFFN(in_channels, out_channels)
generator = Generator(in_channels, out_channels)
discriminator = Discriminator(out_channels)
optimizer = optim.Adam(list(model.parameters()) + list(generator.parameters()) + list(discriminator.parameters()), lr=learning_rate)
criterion = nn.MSELoss()
dataloader = # 创建数据加载器
train(model, generator, discriminator, dataloader, optimizer, criterion)