From 7527f4ea23cccbefac4a9c4f281ab964f83288a5 Mon Sep 17 00:00:00 2001 From: nducros Date: Tue, 21 May 2024 11:49:08 +0200 Subject: [PATCH 1/3] manual merge of dcnet adn drunet tutorial without the automatically generated documentation files --- .gitignore | 1 + spyrit/external/drunet.py | 57 +++ tutorial/tuto_06_dcnet_split_measurements.py | 237 +++++++------ tutorial/tuto_07_drunet_split_measurements.py | 333 ++++++++++++++++++ 4 files changed, 511 insertions(+), 117 deletions(-) create mode 100644 tutorial/tuto_07_drunet_split_measurements.py diff --git a/.gitignore b/.gitignore index 6b0eac38..0579fc6f 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ spyrit/drunet/ !spyrit/images/tuto/*.png docs/source/html docs/source/_autosummary +docs/source/_templates docs/source/_static docs/source/api docs/source/gallery diff --git a/spyrit/external/drunet.py b/spyrit/external/drunet.py index 7a69b1f3..3612f60e 100644 --- a/spyrit/external/drunet.py +++ b/spyrit/external/drunet.py @@ -116,6 +116,63 @@ def forward(self, x0): return x +class DRUNet(UNetRes): + def __init__( + self, + noise_level=5, + n_channels=1, + nc=[64, 128, 256, 512], + nb=4, + act_mode="R", + downsample_mode="strideconv", + upsample_mode="convtranspose", + ): + super(DRUNet, self).__init__( + n_channels + 1, n_channels, nc, nb, act_mode, downsample_mode, upsample_mode + ) + self.register_buffer("noise_level", torch.FloatTensor([noise_level / 255.0])) + + def forward(self, x): + # Image domain denoising + x = self.concat_noise_map(x) + + # Pass input images through the network + x = super(DRUNet, self).forward(x) + return x + + def concat_noise_map(self, x): + r"""Concatenation of noise level map to reconstructed images + + Args: + :attr:`x`: reconstructed images from the reconstruction layer + + Shape: + :attr:`x`: reconstructed images with shape :math:`(BC,1,H,W)` + + :attr:`output`: reconstructed images with concatenated noise level map with shape :math:`(BC,2,H,W)` + """ + + b, c, h, w = x.shape + x = 0.5 * (x + 1) + x = torch.cat((x, self.noise_level.expand(b, 1, h, w)), dim=1) + return x + + def set_noise_level(self, noise_level): + r"""Reset noise level value + + Args: + :attr:`noise_level`: noise level value in the range [0, 255] + + Shape: + :attr:`noise_level`: float value noise level :math:`(1)` + + :attr:`output`: noise level tensor with shape :math:`(1)` + """ + self.noise_level = torch.FloatTensor([noise_level / 255.0]).to( + self.noise_level.device + ) + + # ---------------------------------------------- # Functions taken from basicblock.py # https://github.com/cszn/DPIR/tree/master/models diff --git a/tutorial/tuto_06_dcnet_split_measurements.py b/tutorial/tuto_06_dcnet_split_measurements.py index 16f8dc06..d47ddd3a 100644 --- a/tutorial/tuto_06_dcnet_split_measurements.py +++ b/tutorial/tuto_06_dcnet_split_measurements.py @@ -1,83 +1,80 @@ #!/usr/bin/env python3 r""" -06. DCNet solution for split measurements +========================================= +06. Denoised Completion Network (DCNet) ========================================= .. _tuto_dcnet_split_measurements: -This tutorial shows how to perform image reconstruction using DCNet (denoised -completion network) with -and without a trainable image denoiser. In the previous tutorial -:ref:`Acquisition - split measurements ` -we showed how to handle split measurements for a Hadamard operator -and how to perform a pseudo-inverse reconstruction with PinvNet. +This tutorial shows how to perform image reconstruction using the denoised completion network (DCNet) with a trainable image denoiser. In the next tutorial, we will plug a denoiser into a DCNet, which requires no training. -.. image:: ../fig/tuto6.png +.. figure:: ../fig/tuto6.png :width: 600 :align: center :alt: Reconstruction and neural network denoising architecture sketch using split measurements -These tutorials load image samples from `/images/`. """ +###################################################################### +# .. note:: +# +# As in the previous tutorials, we consider a split Hadamard operator and measurements corrupted by Poisson noise (see :ref:`Tutorial 5 `). + # %% # Load a batch of images -# ----------------------------------------------------------------------------- +# ========================================= -############################################################################### -# Images :math:`x` for training neural networks expect values in [-1,1]. The images are normalized -# using the :func:`transform_gray_norm` function. - -import os - -import torch -import torchvision -import numpy as np -import matplotlib.pyplot as plt - -from spyrit.misc.disp import imagesc -from spyrit.misc.statistics import transform_gray_norm +###################################################################### +# Update search path # sphinx_gallery_thumbnail_path = 'fig/tuto6.png' - -h = 64 # image size hxh -i = 1 # Image index (modify to change the image) +import os spyritPath = os.getcwd() imgs_path = os.path.join(spyritPath, "images/") +###################################################################### +# Images :math:`x` for training neural networks expect values in [-1,1]. The images are normalized and resized using the :func:`transform_gray_norm` function. +from spyrit.misc.statistics import transform_gray_norm -# Create a transform for natural images to normalized grayscale image tensors +h = 64 # image is resized to h x h transform = transform_gray_norm(img_size=h) -# Create dataset and loader (expects class folder 'images/test/') +###################################################################### +# Create a data loader from some dataset (images must be in the folder `images/test/`) +import torch +import torchvision + dataset = torchvision.datasets.ImageFolder(root=imgs_path, transform=transform) dataloader = torch.utils.data.DataLoader(dataset, batch_size=7) x, _ = next(iter(dataloader)) print(f"Shape of input images: {x.shape}") -# Select image +###################################################################### +# Select the `i`-th image in the batch +i = 1 # Image index (modify to change the image) x = x[i : i + 1, :, :, :] x = x.detach().clone() b, c, h, w = x.shape -# plot +###################################################################### +# Plot the selected image +from spyrit.misc.disp import imagesc + x_plot = x.view(-1, h, h).cpu().numpy() imagesc(x_plot[0, :, :], r"$x$ in [-1, 1]") # %% # Forward operators for split measurements -# ----------------------------------------------------------------------------- +# ========================================= -############################################################################### -# We consider noisy split measurements for a Hadamard operator and a -# "variance subsampling" strategy that preserves the coefficients with the largest variance, -# obtained from a previously estimated covariance matrix (for more details, -# refer to :ref:`Acquisition - split measurements `). +###################################################################### +# We consider noisy measurements obtained from a split Hadamard operator, and a subsampling strategy that retaines the coefficients with the largest variance (for more details, refer to :ref:`Tutorial 5 `). -############################################################################### -# First, we download the covariance matrix and load it. +###################################################################### +# First, we download the covariance matrix from our warehouse. import girder_client +import numpy as np # api Rest url of the warehouse url = "https://pilot-warehouse.creatis.insa-lyon.fr/api/v1" @@ -109,11 +106,8 @@ Cov = np.eye(h * h) print(f"Cov matrix {cov_name} not found! Set to the identity") -############################################################################### -# We define the measurement, noise and preprocessing operators and then -# simulate a noiseless measurement vector :math:`y`. As in the previous tutorial, -# we simulate an accelerated acquisition by subsampling the measurement matrix -# by retaining only the first :math:`M` rows of a Hadamard matrix :math:`\textrm{Perm} H`. +###################################################################### +# We define the measurement, noise and preprocessing operators and then simulate a measurement vector corrupted by Poisson noise. As in the previous tutorials, we simulate an accelerated acquisition by subsampling the measurement matrix by retaining only the first rows of a Hadamard matrix that is permuted looking at the diagonal of the covariance matrix. from spyrit.core.meas import HadamSplit from spyrit.core.noise import Poisson @@ -125,11 +119,9 @@ M = 64 * 64 // 4 # Number of measurements (here, 1/4 of the pixels) alpha = 100.0 # number of photons -# Ordering matrix -Ord = Cov2Var(Cov) - # Measurement and noise operators -meas_op = HadamSplit(M, h, torch.from_numpy(Ord)) +Ord = Cov2Var(Cov) +meas_op = HadamSplit(M, h, Ord) noise_op = Poisson(meas_op, alpha) prep_op = SplitPoisson(alpha, meas_op) @@ -146,88 +138,97 @@ imagesc(m_plot, r"Measurements $m$") # %% -# PinvNet network -# ----------------------------------------------------------------------------- +# Pseudo inverse solution +# ========================================= -############################################################################### -# We reconstruct with the pseudo inverse using :class:`spyrit.core.recon.PinvNet` class -# as in the previous tutorial. For this, we define the neural network and then perform the reconstruction. -from spyrit.core.recon import PinvNet -from spyrit.misc.disp import add_colorbar, noaxis +###################################################################### +# We compute the pseudo inverse solution using :class:`spyrit.core.recon.PinvNet` class as in the previous tutorial. -# Reconstruction with for Core module (linear net) +# Instantiate a PinvNet (with no denoising by default) +from spyrit.core.recon import PinvNet pinvnet = PinvNet(noise_op, prep_op) -# use GPU, if available +# Use GPU, if available device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - -# Pseudo-inverse net pinvnet = pinvnet.to(device) +y = y.to(device) # Reconstruction with torch.no_grad(): - z_invnet = pinvnet.reconstruct(y.to(device)) # reconstruct from raw measurements + z_invnet = pinvnet.reconstruct(y) # %% -# DCNet network -# ----------------------------------------------------------------------------- +# Denoised completion network (DCNet) +# ========================================= + +###################################################################### +# .. image:: ../fig/dcnet.png +# :width: 400 +# :align: center +# :alt: Sketch of the DCNet architecture -############################################################################### -# We can improve PinvNet results by using the *denoised* completion network DCNet with the -# :class:`spyrit.core.recon.DCNet` class. It has four sequential steps: +###################################################################### +# The DCNet is based on four sequential steps: # -# i) denoising of the acquired measurements, +# i) Denoising in the measurement domain. # -# ii) estimation of the missing measurements from the denoised ones, +# ii) Estimation of the missing measurements from the denoised ones. # -# iii) mapping them to the image domain, and +# iii) Image-domain mapping. # -# iv) denoising in the image-domain. +# iv) (Learned) Denoising in the image domain. # -# Only the last step involves learnable parameters. +# Typically, only the last step involves learnable parameters. -############################################################################### -# .. image:: ../fig/dcnet.png -# :width: 400 -# :align: center -# :alt: Sketch of the DCNet architecture -############################################################################### -# For the denoiser, we compare the default unit matrix (no denoising) with the UNet denoiser -# with the :class:`spyrit.core.nnet.Unet` class. For the latter, we load the pretrained model -# weights. +# %% +# Denoised completion +# ========================================= -############################################################################### -# Without *learnable image-domain* denoising +###################################################################### +# The first three steps implement denoised completion, which corresponds to Tikhonov regularization. Considering linear measurements :math:`y = Hx`, where :math:`H` is the measurement matrix and :math:`x` is the unknown image, it estimates :math:`x` from :math:`y` by minimizing +# +# .. math:: +# \| y - Hx \|^2_{\Sigma^{-1}_\alpha} + \|x\|^2_{\Sigma^{-1}}, +# +# where :math:`\Sigma` is a covariance prior and :math:`\Sigma_\alpha` is the noise covariance. Denoised completation can be performed using the :class:`~spyrit.core.recon.TikhonovMeasurementPriorDiag` class (see documentation for more details). + +###################################################################### +# In practice, it is more convenient to use the :class:`spyrit.core.recon.DCNet` class, which relies on a forward operator, a preprocessing operator, and a covariance prior. from spyrit.core.recon import DCNet -from spyrit.core.nnet import Unet -from torch import nn +dcnet = DCNet(noise_op, prep_op, torch.from_numpy(Cov)) -# Reconstruction with for DCNet (linear net) -dcnet = DCNet(noise_op, prep_op, torch.from_numpy(Cov), denoi=nn.Identity()) +# Use GPU, if available dcnet = dcnet.to(device) +y = y.to(device) -# Reconstruction with torch.no_grad(): - z_dcnet = dcnet.reconstruct(y.to(device)) # reconstruct from raw measurements + z_dcnet = dcnet.reconstruct(y) -############################################################################### -# With a UNet denoising layer, we define the denoising network and -# then load the pretrained weights. +###################################################################### +# .. note:: +# In this tutorial, the covariance matrix used to define subsampling is also used as prior knowledge during reconstruction. -from spyrit.core.train import load_net -import matplotlib.pyplot as plt -from spyrit.misc.disp import add_colorbar, noaxis -# Define UNet denoiser -denoi = Unet() +# %% +# (Learned) Denoising in the image domain +# ========================================= + +###################################################################### +# To implement denoising in the image domain, we provide a :class:`spyrit.core.nnet.Unet` denoiser to a :class:`spyrit.core.recon.DCNet`. + +from spyrit.core.nnet import Unet -# Define DCNet (with UNet denoising) +denoi = Unet() dcnet_unet = DCNet(noise_op, prep_op, torch.from_numpy(Cov), denoi) -dcnet_unet = dcnet_unet.to(device) +dcnet_unet = dcnet_unet.to(device) # Use GPU, if available + +######################################################################## +# We load pretrained weights for the UNet + +from spyrit.core.train import load_net -# Load previously trained model # Download weights url_unet = "https://drive.google.com/file/d/15PRRZj5OxKpn1iJw78lGwUUBtTbFco1l/view?usp=drive_link" model_path = "./model" @@ -254,52 +255,54 @@ load_net(model_unet_path, dcnet_unet, device, False) # print(f"Model {model_unet_path} loaded.") - -# Reconstruction +###################################################################### +# We reconstruct the image with torch.no_grad(): - z_dcnet_unet = dcnet_unet.reconstruct( - y.to(device) - ) # reconstruct from raw measurements + z_dcnet_unet = dcnet_unet.reconstruct(y) -############################################################################### -# We plot all results +#%% +# Results +# ========================================= + +import matplotlib.pyplot as plt +from spyrit.misc.disp import add_colorbar, noaxis -# plot reconstruction side by side x_plot = x.view(-1, h, h).cpu().numpy() x_plot2 = z_invnet.view(-1, h, h).cpu().numpy() x_plot3 = z_dcnet.view(-1, h, h).cpu().numpy() x_plot4 = z_dcnet_unet.view(-1, h, h).cpu().numpy() f, axs = plt.subplots(2, 2, figsize=(10, 10)) + +# Plot the ground-truth image im1 = axs[0, 0].imshow(x_plot[0, :, :], cmap="gray") axs[0, 0].set_title("Ground-truth image", fontsize=16) noaxis(axs[0, 0]) add_colorbar(im1, "bottom") +# Plot the pseudo inverse solution im2 = axs[0, 1].imshow(x_plot2[0, :, :], cmap="gray") -axs[0, 1].set_title("PinvNet", fontsize=16) +axs[0, 1].set_title("Pseudo inverse", fontsize=16) noaxis(axs[0, 1]) add_colorbar(im2, "bottom") +# Plot the solution obtained from denoised completion im3 = axs[1, 0].imshow(x_plot3[0, :, :], cmap="gray") -axs[1, 0].set_title(f"DCNet (without denoising)", fontsize=16) +axs[1, 0].set_title(f"Denoised completion", fontsize=16) noaxis(axs[1, 0]) add_colorbar(im3, "bottom") +# Plot the solution obtained from denoised completion with UNet denoising im4 = axs[1, 1].imshow(x_plot4[0, :, :], cmap="gray") -axs[1, 1].set_title(f"DCNet (UNet denoising)", fontsize=16) +axs[1, 1].set_title(f"Denoised completion with UNet denoising", fontsize=16) noaxis(axs[1, 1]) add_colorbar(im4, "bottom") plt.show() -############################################################################### -# Comparing results, PinvNet provides pixelized reconstruction, DCNet with no denoising -# leads to a smoother reconstruction, as expected by a Tikonov regularization, and -# DCNet with UNet denoising provides the best reconstruction. +###################################################################### +# .. note:: +# While the pseudo inverse reconstrcution is pixelized, the solution obtained by denoised completion is smoother. DCNet with UNet denoising in the image domain provides the best reconstruction. -############################################################################### +###################################################################### # .. note:: -# -# In this tutorial, we have used DCNet with a UNet denoising layer for split measurements. -# We refer to `spyrit-examples tutorials `_ -# for a comparison of different solutions for split measurements (pinvNet, DCNet and DRUNet). +# We refer to `spyrit-examples tutorials `_ for a comparison of different solutions (pinvNet, DCNet and DRUNet) that can be run in colab. diff --git a/tutorial/tuto_07_drunet_split_measurements.py b/tutorial/tuto_07_drunet_split_measurements.py new file mode 100644 index 00000000..566bd412 --- /dev/null +++ b/tutorial/tuto_07_drunet_split_measurements.py @@ -0,0 +1,333 @@ +r""" +====================================================================== +07. DCNet with plug-and-play DRUNet denoising +====================================================================== +.. _tuto_dcdrunet_split_measurements: + +This tutorial shows how to perform image reconstruction using a DCNet (data completion network) that includes a `DRUNet denoiser `_. DRUNet is a pretrained plug-and-play denoising network that has been pretrained for a wide range of noise levels. DRUNet admits the noise level as an input. Contratry to the DCNet described in :ref:`Tutorial 6 `, it requires no training. +""" +###################################################################### +# .. figure:: ../fig/drunet.png +# :width: 600 +# :align: center +# :alt: DCNet with DRUNet denoising in the image domain + +###################################################################### +# .. note:: +# +# As in the previous tutorials, we consider a split Hadamard operator and measurements corrupted by Poisson noise (see :ref:`Tutorial 5 `). + +import numpy as np +import os +from spyrit.misc.disp import imagesc +import matplotlib.pyplot as plt + + +# %% +# Load a batch of images +# ==================================================================== + +###################################################################### +# Images :math:`x` for training neural networks expect values in [-1,1]. The images are normalized using the :func:`transform_gray_norm` function. + +# sphinx_gallery_thumbnail_path = 'fig/drunet.png' + +from spyrit.misc.statistics import transform_gray_norm +import torchvision +import torch + +h = 64 # image size hxh +i = 1 # Image index (modify to change the image) +spyritPath = os.getcwd() +imgs_path = os.path.join(spyritPath, "images") + + +# Create a transform for natural images to normalized grayscale image tensors +transform = transform_gray_norm(img_size=h) + +# Create dataset and loader (expects class folder 'images/test/') +dataset = torchvision.datasets.ImageFolder(root=imgs_path, transform=transform) +dataloader = torch.utils.data.DataLoader(dataset, batch_size=7) + +x, _ = next(iter(dataloader)) +print(f"Shape of input images: {x.shape}") + +# Select image +x = x[i : i + 1, :, :, :] +x = x.detach().clone() +b, c, h, w = x.shape + +# plot +x_plot = x.view(-1, h, h).cpu().numpy() +imagesc(x_plot[0, :, :], r"$x$ in [-1, 1]") + +# %% +# Operators for split measurements +# ==================================================================== + +###################################################################### +# We consider noisy measurements obtained from a split Hadamard operator, and a subsampling strategy that retaines the coefficients with the largest variance (for more details, refer to :ref:`Tutorial 5 `). + +###################################################################### +# First, we download the covariance matrix from our warehouse. + +import girder_client + +# api Rest url of the warehouse +url = "https://pilot-warehouse.creatis.insa-lyon.fr/api/v1" + +# Generate the warehouse client +gc = girder_client.GirderClient(apiUrl=url) + +# Download the covariance matrix and mean image +data_folder = "./stat/" +dataId_list = [ + "63935b624d15dd536f0484a5", # for reconstruction (imageNet, 64) + "63935a224d15dd536f048496", # for reconstruction (imageNet, 64) +] +cov_name = "./stat/Cov_64x64.npy" + +try: + for dataId in dataId_list: + myfile = gc.getFile(dataId) + gc.downloadFile(dataId, data_folder + myfile["name"]) + + print(f"Created {data_folder}") + + Cov = np.load(cov_name) + print(f"Cov matrix {cov_name} loaded") +except: + Cov = np.eye(h * h) + print(f"Cov matrix {cov_name} not found! Set to the identity") + +###################################################################### +# We define the measurement, noise and preprocessing operators and then simulate a measurement vector corrupted by Poisson noise. As in the previous tutorials, we simulate an accelerated acquisition by subsampling the measurement matrix by retaining only the first rows of a Hadamard matrix that is permuted looking at the diagonal of the covariance matrix. + + +from spyrit.core.meas import HadamSplit +from spyrit.core.noise import Poisson +from spyrit.misc.sampling import meas2img2 +from spyrit.misc.statistics import Cov2Var +from spyrit.core.prep import SplitPoisson + +# Measurement parameters +M = 64 * 64 // 4 # Number of measurements (here, 1/4 of the pixels) +alpha = 100.0 # number of photons + +# Measurement and noise operators +Ord = Cov2Var(Cov) +meas_op = HadamSplit(M, h, Ord) +noise_op = Poisson(meas_op, alpha) +prep_op = SplitPoisson(alpha, meas_op) + +# Vectorize image +x = x.view(b * c, h * w) +print(f"Shape of vectorized image: {x.shape}") + +# Measurements +y = noise_op(x) # a noisy measurement vector +m = prep_op(y) # preprocessed measurement vector + +m_plot = m.detach().numpy() +m_plot = meas2img2(m_plot.T, Ord) +imagesc(m_plot, r"Measurements $m$") + +# %% +# DRUNet denoising +# ==================================================================== + +###################################################################### +# DRUNet is defined by the :class:`spyrit.external.drunet.DRUNet` class. This class inherits from the original :class:`spyrit.external.drunet.UNetRes` class introduced in [ZhLZ21]_, with some modifications to handle different noise levels. + +############################################################################### +# We instantiate the DRUNet by providing the noise level, which is expected to be in [0, 255], and the number of channels. The larger the noise level, the higher the denoising. + +from spyrit.external.drunet import DRUNet + +noise_level = 7 +denoi_drunet = DRUNet(noise_level=noise_level, n_channels=1) + +# Use GPU, if available +device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") +denoi_drunet = denoi_drunet.to(device) + +############################################################################### +# We download the pretrained weights of the DRUNet and load them. + +try: + import gdown + + # Download pretrained weights + model_drunet_path = "./model" + url_drunet = "https://drive.google.com/file/d/1fhnIDJAbh7IRSZ9tgk4JPtfGra4O1ghk/view?usp=drive_link" + + if os.path.exists(model_drunet_path) is False: + os.mkdir(model_drunet_path) + print(f"Created {model_drunet_path}") + + model_drunet_path = os.path.join(model_drunet_path, "drunet_gray.pth") + gdown.download(url_drunet, model_drunet_path, quiet=False, fuzzy=True) + + # Load pretrained weights + denoi_drunet.load_state_dict(torch.load(model_drunet_path), strict=False) + print(f"Model {denoi_drunet} loaded.") +except: + print(f"Model {model_drunet_path} not found!") + +# %% +# Pluggind the DRUnet in a DCNet +# ==================================================================== + +###################################################################### +# We define the DCNet network by providing the forward operator, preprocessing operator, covariance prior and denoising prior. The DCNet class :class:`spyrit.core.recon.DCNet` is discussed in :ref:`Tutorial 06 `. + +from spyrit.core.recon import DCNet + +dcnet_drunet = DCNet(noise_op, prep_op, torch.from_numpy(Cov), denoi=denoi_drunet) +dcnet_drunet = dcnet_drunet.to(device) # Use GPU, if available + +###################################################################### +# Then, we reconstruct the image from the noisy measurements. + +with torch.no_grad(): + z_dcnet_drunet = dcnet_drunet.reconstruct(y.to(device)) + +# %% +# Tunning of the denoising +# ==================================================================== + +###################################################################### +# We reconstruct the images for another two different noise levels of DRUnet + +noise_level_2 = 1 +noise_level_3 = 20 + +with torch.no_grad(): + + denoi_drunet.set_noise_level(noise_level_2) + z_dcnet_drunet_2 = dcnet_drunet.reconstruct(y.to(device)) + + denoi_drunet.set_noise_level(noise_level_3) + z_dcnet_drunet_3 = dcnet_drunet.reconstruct(y.to(device)) + +###################################################################### +# Plot all reconstructions +from spyrit.misc.disp import add_colorbar, noaxis + +x_plot = z_dcnet_drunet.view(-1, h, h).cpu().numpy() +x_plot2 = z_dcnet_drunet_2.view(-1, h, h).cpu().numpy() +x_plot3 = z_dcnet_drunet_3.view(-1, h, h).cpu().numpy() + +f, axs = plt.subplots(1, 3, figsize=(10, 5)) +im1 = axs[0].imshow(x_plot2[0, :, :], cmap="gray") +axs[0].set_title(f"DRUNet\n (n map={noise_level_2})", fontsize=16) +noaxis(axs[0]) +add_colorbar(im1, "bottom") + +im2 = axs[1].imshow(x_plot[0, :, :], cmap="gray") +axs[1].set_title(f"DRUNet\n (n map={noise_level})", fontsize=16) +noaxis(axs[1]) +add_colorbar(im2, "bottom") + +im3 = axs[2].imshow(x_plot3[0, :, :], cmap="gray") +axs[2].set_title(f"DRUNet\n (n map={noise_level_3})", fontsize=16) +noaxis(axs[2]) +add_colorbar(im3, "bottom") + +# %% +# Alternative implementation showing the advantage of the :class:`~spyrit.external.drunet.DRUNet` class +# ==================================================================== + +############################################################################## +# First, we consider DCNet without denoising in the image domain (default behaviour) + +dcnet = DCNet(noise_op, prep_op, torch.from_numpy(Cov)) +dcnet = dcnet.to(device) + +with torch.no_grad(): + z_dcnet = dcnet.reconstruct(y.to(device)) + +###################################################################### +# Then, we instantiate DRUNet using the original class :class:`spyrit.external.drunet.UNetRes`. + +from spyrit.external.drunet import UNetRes as drunet + +# Define denoising network +n_channels = 1 # 1 for grayscale image +drunet_den = drunet(in_nc=n_channels + 1, out_nc=n_channels) + +# Load pretrained model +try: + drunet_den.load_state_dict(torch.load(model_drunet_path), strict=True) + print(f"Model {model_drunet_path} loaded.") +except: + print(f"Model {model_drunet_path} not found!") + load_drunet = False +drunet_den = drunet_den.to(device) + +###################################################################### +# To denoise the output of DCNet, we create noise-level map that we concatenate to the output of DCNet that we normalize in [0,1] + +x_sample = 0.5 * (z_dcnet + 1).cpu() + +# +x_sample = torch.cat( + (x_sample,torch.FloatTensor([noise_level / 255.0]).repeat( + 1, 1, x_sample.shape[2], x_sample.shape[3] + ), + ), + dim=1, +) +x_sample = x_sample.to(device) + +with torch.no_grad(): + z_dcnet_den = drunet_den(x_sample) + +############################################################################## +# We plot all results + +x_plot = x.view(-1, h, h).cpu().numpy() +x_plot2 = z_dcnet.view(-1, h, h).cpu().numpy() +x_plot3 = z_dcnet_drunet.view(-1, h, h).cpu().numpy() +x_plot4 = z_dcnet_den.view(-1, h, h).cpu().numpy() + +f, axs = plt.subplots(2, 2, figsize=(10, 10)) +im1 = axs[0, 0].imshow(x_plot[0, :, :], cmap="gray") +axs[0, 0].set_title("Ground-truth image", fontsize=16) +noaxis(axs[0, 0]) +add_colorbar(im1, "bottom") + +im2 = axs[0, 1].imshow(x_plot2[0, :, :], cmap="gray") +axs[0, 1].set_title("No denoising", fontsize=16) +noaxis(axs[0, 1]) +add_colorbar(im2, "bottom") + +im3 = axs[1, 0].imshow(x_plot3[0, :, :], cmap="gray") +axs[1, 1].set_title(f"Using DRUNet with n map={noise_level}", fontsize=16) +noaxis(axs[1, 0]) +add_colorbar(im3, "bottom") + +im4 = axs[1, 1].imshow(x_plot4[0, :, :], cmap="gray") +axs[1, 0].set_title(f"Using UNetRes with n map={noise_level}", fontsize=16) +noaxis(axs[1, 1]) +add_colorbar(im4, "bottom") + +plt.show() + +############################################################################### The results are identical to those obtained using :class:`~spyrit.external.drunet.DRUNet`. + +############################################################################### +# .. note:: +# +# In this tutorial, we have used DRUNet with a DCNet but it can be used any other network, such as pinvNet. In addition, we have considered pretrained weights, leading to a plug-and-play strategy that does not require training. However, the DCNet-DRUNet network can be trained end-to-end to improve the reconstruction performance in a specific setting (where training is done for all noise levels at once). For more details, refer to the paper [ZhLZ21]_. + +############################################################################### +# .. note:: +# +# We refer to `spyrit-examples tutorials `_ for a comparison of different solutions (pinvNet, DCNet and DRUNet) that can be run in colab. + +###################################################################### +# .. rubric:: References for DRUNet +# +# .. [ZhLZ21] Zhang, K.; Li, Y.; Zuo, W.; Zhang, L.; Van Gool, L.; Timofte, R..: Plug-and-Play Image Restoration with Deep Denoiser Prior. In: IEEE Transactions on Pattern Analysis and Machine Intelligence, 44(10), 6360-6376, 2021. +# .. [ZhZG17] Zhang, K.; Zuo, W.; Gu, S.; Zhang, L..: Learning Deep CNN Denoiser Prior for Image Restoration. In: IEEE Conference on Computer Vision and Pattern Recognition, 3929-3938, 2017. From fab21214d4a07d36c654c7d1efc7651fe02a4db0 Mon Sep 17 00:00:00 2001 From: nducros Date: Tue, 21 May 2024 12:02:05 +0200 Subject: [PATCH 2/3] add figure tuto 7 --- docs/source/fig/drunet.png | Bin 0 -> 94775 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/source/fig/drunet.png diff --git a/docs/source/fig/drunet.png b/docs/source/fig/drunet.png new file mode 100644 index 0000000000000000000000000000000000000000..903521a4268c3ffb421278e147dc6873a6becf1b GIT binary patch literal 94775 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�|GRJ7-9>N| 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 OI;yU%mVL-F=)VB#vUqy{ literal 0 HcmV?d00001 From 59bb535ac40c037e0360e010eaaa2258ca762246 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 21 May 2024 10:13:22 +0000 Subject: [PATCH 3/3] [pre-commit.ci] Automatic python formatting --- tutorial/tuto_06_dcnet_split_measurements.py | 11 +++++++---- tutorial/tuto_07_drunet_split_measurements.py | 17 ++++++++++------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/tutorial/tuto_06_dcnet_split_measurements.py b/tutorial/tuto_06_dcnet_split_measurements.py index d47ddd3a..a4e874d2 100644 --- a/tutorial/tuto_06_dcnet_split_measurements.py +++ b/tutorial/tuto_06_dcnet_split_measurements.py @@ -28,6 +28,7 @@ # sphinx_gallery_thumbnail_path = 'fig/tuto6.png' import os + spyritPath = os.getcwd() imgs_path = os.path.join(spyritPath, "images/") @@ -146,6 +147,7 @@ # Instantiate a PinvNet (with no denoising by default) from spyrit.core.recon import PinvNet + pinvnet = PinvNet(noise_op, prep_op) # Use GPU, if available @@ -155,7 +157,7 @@ # Reconstruction with torch.no_grad(): - z_invnet = pinvnet.reconstruct(y) + z_invnet = pinvnet.reconstruct(y) # %% # Denoised completion network (DCNet) @@ -194,9 +196,10 @@ # where :math:`\Sigma` is a covariance prior and :math:`\Sigma_\alpha` is the noise covariance. Denoised completation can be performed using the :class:`~spyrit.core.recon.TikhonovMeasurementPriorDiag` class (see documentation for more details). ###################################################################### -# In practice, it is more convenient to use the :class:`spyrit.core.recon.DCNet` class, which relies on a forward operator, a preprocessing operator, and a covariance prior. +# In practice, it is more convenient to use the :class:`spyrit.core.recon.DCNet` class, which relies on a forward operator, a preprocessing operator, and a covariance prior. from spyrit.core.recon import DCNet + dcnet = DCNet(noise_op, prep_op, torch.from_numpy(Cov)) # Use GPU, if available @@ -258,9 +261,9 @@ ###################################################################### # We reconstruct the image with torch.no_grad(): - z_dcnet_unet = dcnet_unet.reconstruct(y) + z_dcnet_unet = dcnet_unet.reconstruct(y) -#%% +# %% # Results # ========================================= diff --git a/tutorial/tuto_07_drunet_split_measurements.py b/tutorial/tuto_07_drunet_split_measurements.py index 566bd412..744b30cf 100644 --- a/tutorial/tuto_07_drunet_split_measurements.py +++ b/tutorial/tuto_07_drunet_split_measurements.py @@ -6,6 +6,7 @@ This tutorial shows how to perform image reconstruction using a DCNet (data completion network) that includes a `DRUNet denoiser `_. DRUNet is a pretrained plug-and-play denoising network that has been pretrained for a wide range of noise levels. DRUNet admits the noise level as an input. Contratry to the DCNet described in :ref:`Tutorial 6 `, it requires no training. """ + ###################################################################### # .. figure:: ../fig/drunet.png # :width: 600 @@ -137,7 +138,7 @@ # ==================================================================== ###################################################################### -# DRUNet is defined by the :class:`spyrit.external.drunet.DRUNet` class. This class inherits from the original :class:`spyrit.external.drunet.UNetRes` class introduced in [ZhLZ21]_, with some modifications to handle different noise levels. +# DRUNet is defined by the :class:`spyrit.external.drunet.DRUNet` class. This class inherits from the original :class:`spyrit.external.drunet.UNetRes` class introduced in [ZhLZ21]_, with some modifications to handle different noise levels. ############################################################################### # We instantiate the DRUNet by providing the noise level, which is expected to be in [0, 255], and the number of channels. The larger the noise level, the higher the denoising. @@ -184,7 +185,7 @@ from spyrit.core.recon import DCNet dcnet_drunet = DCNet(noise_op, prep_op, torch.from_numpy(Cov), denoi=denoi_drunet) -dcnet_drunet = dcnet_drunet.to(device) # Use GPU, if available +dcnet_drunet = dcnet_drunet.to(device) # Use GPU, if available ###################################################################### # Then, we reconstruct the image from the noisy measurements. @@ -193,7 +194,7 @@ z_dcnet_drunet = dcnet_drunet.reconstruct(y.to(device)) # %% -# Tunning of the denoising +# Tunning of the denoising # ==================================================================== ###################################################################### @@ -203,7 +204,7 @@ noise_level_3 = 20 with torch.no_grad(): - + denoi_drunet.set_noise_level(noise_level_2) z_dcnet_drunet_2 = dcnet_drunet.reconstruct(y.to(device)) @@ -239,13 +240,13 @@ # ==================================================================== ############################################################################## -# First, we consider DCNet without denoising in the image domain (default behaviour) +# First, we consider DCNet without denoising in the image domain (default behaviour) dcnet = DCNet(noise_op, prep_op, torch.from_numpy(Cov)) dcnet = dcnet.to(device) with torch.no_grad(): - z_dcnet = dcnet.reconstruct(y.to(device)) + z_dcnet = dcnet.reconstruct(y.to(device)) ###################################################################### # Then, we instantiate DRUNet using the original class :class:`spyrit.external.drunet.UNetRes`. @@ -272,7 +273,9 @@ # x_sample = torch.cat( - (x_sample,torch.FloatTensor([noise_level / 255.0]).repeat( + ( + x_sample, + torch.FloatTensor([noise_level / 255.0]).repeat( 1, 1, x_sample.shape[2], x_sample.shape[3] ), ),