自监督高效图像去噪

发布于:2024-12-06 ⋅ 阅读:(28) ⋅ 点赞:(0)

🏡作者主页:点击! 

🤖编程探索专栏:点击!

⏰️创作时间:2024年12月3日21点02分


神秘男子影,
  秘而不宣藏。
泣意深不见,
男子自持重,
   子夜独自沉。

论文链接

点击开启你的论文编程之旅icon-default.png?t=O83Ahttps://www.aspiringcode.com/content?id=17116443769287&uid=56797c41200543f98e5e37f3525f2b40

概述

本文复现论文 Zero-Shot Noise2Noise: Efficient Image Denoising without any Data[1] 提出的图像去噪方法。

随着深度学习的发展,各种图像去噪方法的性能不断提升。然而,目前的工作大多需要高昂的计算成本或对噪声模型的假设。为解决这个问题,该论文提出了一种自监督学习方法。该方法使用一个简单的两层卷积神经网络和噪声到噪声损失(Noise to Noise Loss),在只使用一张测试图像作为训练样本的情况下,实现了低成本高质量的图像去噪。

算法原理

论文提出的方法主要包含三个部分:成对下采样、残差损失、一致性损失。

成对下采样

该成对下采样器将原始图像下采样为长宽只有原先一半的子图。具体地,其通过将图像分割为大小为 2 × 2 的非重叠补丁,并将每个补丁的对角线像素取平均值并分配给第一个子图,然后将反对角线像素取平均值并分配给第二个子图像。该成对下采样器的示意图如下所示:

残差损失

在非自监督的情况下,损失函数一般采用噪声图像与干净图像之间平方差的形式:

在自监督的情况下,没有干净图像作为训练目标,则可以将两张噪声图像子图互为训练目标,即噪声到噪声损失:

基于噪声独立性假设,可以证明这两种损失的期望值相同。

一致性损失

考虑到残差损失只使用了噪声图像子图训练模型,而测试时需要整张噪声图像作为输入,为了使网络对子图的噪声估计与对原图的噪声估计保持一致,作者还引入了一个一致性损失函数:

总的损失如下所示:

核心逻辑

上述方法的核心逻辑如下所示:

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np

def diag_sample(image):
    '''下采样函数,输入图像,输出两张长宽只有原先一半的子图'''
    # 分割成2x2的补丁
    height = int(image.shape[2] / 2)
    width = int(image.shape[3] / 2)
    image_patch = image[:, :, 0: height * 2, 0: width * 2].view(image.shape[0], image.shape[1], height, 2, width, 2).permute(0, 1, 2, 4, 3, 5)
    # 对角线元素取平均作为第一个子图
    image_sub1 = (image_patch[:, :, :, :, 0, 0] +image_patch[:, :, :, :, 1, 1]) / 2
    # 反对角线元素取平均作为第二个子图
    image_sub2 = (image_patch[:, :, :, :, 0, 1] +image_patch[:, :, :, :, 1, 0]) / 2
    return image_sub1, image_sub2

class NoisePredictor(nn.Module):
    '''噪声估计网络,输入图像,输出估计的图像噪声'''
    def __init__(self, channels=3):
        super(NoisePredictor, self).__init__()
        self.net = nn.Sequential(
            nn.Conv2d(channels, 52, 3, padding=1),
            nn.LeakyReLU(negative_slope=0.2, inplace=True),
            nn.Conv2d(52, 52, 3, padding = 1),
            nn.LeakyReLU(negative_slope=0.2, inplace=True),
            nn.Conv2d(52, channels, 1)
        )
    
    def forward(self, x):
        return self.net(x)

def train_once(image_noise, model, optimizer):
    '''对模型进行一轮训练'''
    # 用于计算差方和
    mse_loss = nn.MSELoss(reduction='sum')
    
    model.train()
    optimizer.zero_grad()
    # 生成噪声的子图
    image_noise_s1, image_noise_s2 = diag_sample(image_noise)
    # 估计噪声图像子图的干净图像
    image_s1_clean = image_noise_s1 - model(image_noise_s1)
    image_s2_clean = image_noise_s2 - model(image_noise_s2)
    # 估计噪声图像的干净图像
    image_clean = image_noise - model(image_noise)
    # 生成噪声图像的干净图像的子图
    image_clean_s1, image_clean_s2 = diag_sample(image_clean)
    # 残差损失
    loss_res = (mse_loss(image_s1_clean, image_noise_s2) + mse_loss(image_s2_clean, image_noise_s1)) / 2
    # 一致性损失
    loss_con = (mse_loss(image_s1_clean, image_clean_s1) + mse_loss(image_s2_clean, image_clean_s2)) / 2
    # 总损失
    loss = loss_res + loss_con
    # 梯度反向传播
    loss.backward()
    # 更新模型参数
    optimizer.step()

def add_noise(image, degree):
    '''输入图像和噪声程度(0~1),输出加入噪声的图像'''
    noise = np.random.normal(0, degree, image.shape)
    noisy_image = np.clip(image + noise, 0, 1)
    return noisy_image

以上代码仅作展示,更详细的代码文件请参见附件。

效果演示

配置环境并运行main.py脚本,效果如下:

使用方式

  • 解压附件压缩包并进入工作目录。如果是Linux系统,请使用如下命令:
unzip Image_Denoising.zip
cd Image_Denoising
  • 代码的运行环境可通过如下命令进行配置:
pip install -r requirements.txt
  • 如果希望在本地运行程序,请运行如下命令:
python main.py
  • 如果希望在线部署,请运行如下命令:
python main-flask.py
  • 如果希望使用自己的文件路径或改动其他实验设置,请在文件config.json中修改对应参数。以下是参数含义对照表:

参数名

含义

image

输入的原始图像路径,默认为"dog.jpg",即我提供的样例

learning_rate

学习率

epoch_count

训练轮数

step_size

学习率衰减周期

gamma

学习率衰减比

degree

噪声程度,默认为0.2,范围是0~1

max_bytes

输入文件大小限制,默认为10240,即10KB,仅用于在线部署限制输入

(以上内容皆为原创,请勿转载)

参考文献

[1] Mansour Y, Heckel R. Zero-shot noise2noise: Efficient image denoising without any data[C]//Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition. 2023: 14018-14027.

成功的路上没有捷径,只有不断的努力与坚持。如果你和我一样,坚信努力会带来回报,请关注我,点个赞,一起迎接更加美好的明天!你的支持是我继续前行的动力!"

"每一次创作都是一次学习的过程,文章中若有不足之处,还请大家多多包容。你的关注和点赞是对我最大的支持,也欢迎大家提出宝贵的意见和建议,让我不断进步。"

神秘泣男子


网站公告

今日签到

点亮在社区的每一天
去签到