<!-- DO NOT EDIT. -->
<!-- THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. -->
<!-- TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: -->
<!-- "auto_examples/plug-and-play/demo_vanilla_PnP.py" -->
<!-- LINE NUMBERS ARE GIVEN BELOW. -->

#### NOTE
New to DeepInverse? Get started with the basics with the
[5 minute quickstart tutorial](https://deepinv.org/auto_examples/basics/demo_quickstart.html.md#sphx-glr-auto-examples-basics-demo-quickstart-py)..

<a id="sphx-glr-auto-examples-plug-and-play-demo-vanilla-pnp-py"></a>

# Vanilla PnP for computed tomography (CT).

This example shows how to use a standard PnP algorithm with DnCNN denoiser for computed tomography.

<!-- GENERATED FROM PYTHON SOURCE LINES 8-20 -->
```Python
import deepinv as dinv
from pathlib import Path
import torch
from deepinv.models import DnCNN
from deepinv.optim.data_fidelity import L2
from deepinv.optim.prior import PnP
from deepinv.optim.optimizers import PGD
from deepinv.utils import load_example
from deepinv.utils.plotting import plot, plot_curves
```

<!-- GENERATED FROM PYTHON SOURCE LINES 22-25 -->

## Setup paths for data loading and results.

<!-- GENERATED FROM PYTHON SOURCE LINES 25-28 -->
```Python
BASE_DIR = Path(".")
RESULTS_DIR = BASE_DIR / "results"
```

<!-- GENERATED FROM PYTHON SOURCE LINES 29-31 -->

## Load image and parameters

<!-- GENERATED FROM PYTHON SOURCE LINES 31-48 -->
```Python
# Set the global random seed from pytorch to ensure reproducibility of the example.
torch.manual_seed(0)
device = dinv.utils.get_device()
# Set up the variable to fetch dataset and operators.
method = "PnP"
img_size = 32
x = load_example(
    "SheppLogan.png",
    img_size=img_size,
    grayscale=True,
    resize_mode="resize",
    device=device,
)
operation = "tomography"
```

```none
Selected GPU 0 with 24371.25 MiB free memory
```

<!-- GENERATED FROM PYTHON SOURCE LINES 49-53 -->

## Set the forward operator

We use the [`deepinv.physics.Tomography`](https://deepinv.org/api/stubs/deepinv.physics.Tomography.html.md#deepinv.physics.Tomography)
class from the physics module to generate a CT measurements.

<!-- GENERATED FROM PYTHON SOURCE LINES 53-73 -->
```Python
noise_level_img = 0.03  # Gaussian Noise standard deviation for the degradation
angles = 50
n_channels = 1  # 3 for color images, 1 for gray-scale images
physics = dinv.physics.Tomography(
    img_width=img_size,
    angles=angles,
    normalize=True,
    device=device,
    noise_model=dinv.physics.GaussianNoise(sigma=noise_level_img),
)

scaling = torch.pi / (2 * angles)  # approximate operator norm of A^T A

# Use parallel dataloader if using a GPU to speed up training,
# otherwise, as all computes are on CPU, use synchronous data loading.
num_workers = 4 if torch.cuda.is_available() else 0
```

<!-- GENERATED FROM PYTHON SOURCE LINES 74-84 -->

## Set up the PnP algorithm to solve the inverse problem.

We use the Proximal Gradient Descent optimization algorithm.
The algorithm alternates between a denoising step and a gradient descent step.
The denoising step is performed by a DNCNN pretrained denoiser [`deepinv.models.DnCNN`](https://deepinv.org/api/stubs/deepinv.models.DnCNN.html.md#deepinv.models.DnCNN).

Set up the PnP algorithm parameters : the `stepsize`, `sigma_denoiser` the noise level of the denoiser.
Attention: The choice of the stepsize is crucial as it also defines the amount of regularization.  Indeed, the regularization parameter `lambda` is implicitly defined by the stepsize.
Both the stepsize and the noise level of the denoiser control the regularization power and should be tuned to the specific problem.
The following parameters have been chosen manually.

<!-- GENERATED FROM PYTHON SOURCE LINES 84-125 -->
```Python
stepsize = 15 * scaling
sigma_denoiser = 0.01
max_iter = 200
early_stop = True

# Select the data fidelity term
data_fidelity = L2()

# Specify the denoising prior
denoiser = DnCNN(
    in_channels=n_channels,
    out_channels=n_channels,
    pretrained="download",  # automatically downloads the pretrained weights, set to a path to use custom weights.
    device=device,
)
prior = PnP(denoiser=denoiser)

# Logging parameters
verbose = True
plot_convergence_metrics = True  # compute performance and convergence metrics along the algorithm, curves saved in RESULTS_DIR

# instantiate the algorithm class to solve the IP problem.
# initialize with the rescaled adjoint such that the initialization lives already at the correct scale
init = lambda y, physics: physics.A_adjoint(y) * scaling

# define the model
model = PGD(
    data_fidelity=data_fidelity,
    prior=prior,
    stepsize=stepsize,
    sigma_denoiser=sigma_denoiser,
    early_stop=early_stop,
    max_iter=max_iter,
    verbose=verbose,
    custom_init=init,
)

# Set the model to evaluation mode. We do not require training here.
model.eval()
```

```none
PGD(
  (fixed_point): FixedPoint(
    (iterator): PGDIteration(
      (f_step): fStepPGD()
      (g_step): gStepPGD()
    )
  )
  (psnr): PSNR()
)
```

<!-- GENERATED FROM PYTHON SOURCE LINES 126-131 -->

## Evaluate the model on the problem and plot the results.

The model returns the output and the metrics computed along the iterations.
For computing PSNR, the ground truth image `x_gt` must be provided.

<!-- GENERATED FROM PYTHON SOURCE LINES 131-159 -->
```Python
y = physics(x)
x_lin = (
    physics.A_adjoint(y) * scaling
)  # rescaled linear reconstruction with the adjoint operator

# run the model on the problem.
with torch.no_grad():
    x_model, metrics = model(
        y, physics, x_gt=x, compute_metrics=True
    )  # reconstruction with PnP algorithm

# compute PSNR
print(f"Linear reconstruction PSNR: {dinv.metric.PSNR()(x, x_lin).item():.2f} dB")
print(f"PnP reconstruction PSNR: {dinv.metric.PSNR()(x, x_model).item():.2f} dB")

# plot images. Images are saved in RESULTS_DIR.
imgs = [y, x, x_lin, x_model]
plot(
    imgs,
    titles=["Input", "GT", "Linear", "Recons."],
    save_dir=RESULTS_DIR / "images",
    show=True,
)

# plot convergence curves. Metrics are saved in RESULTS_DIR.
if plot_convergence_metrics:
    plot_curves(metrics, save_dir=RESULTS_DIR / "curves", show=True)
```

```none
Linear reconstruction PSNR: 14.37 dB
PnP reconstruction PSNR: 28.16 dB
```

**Total running time of the script:** (0 minutes 0.650 seconds)

🏷 Tags: Tomography

<a id="sphx-glr-download-auto-examples-plug-and-play-demo-vanilla-pnp-py"></a>

[`Download Jupyter notebook: demo_vanilla_PnP.ipynb`](https://deepinv.org/auto_examples/plug-and-play/_downloads/375872dc6facb4bd00efc1af2e7f1437/demo_vanilla_PnP.ipynb)

[`Download Python source code: demo_vanilla_PnP.py`](https://deepinv.org/auto_examples/plug-and-play/_downloads/873d523bccb69fb019bf7f5379602f26/demo_vanilla_PnP.py)

[`Download zipped: demo_vanilla_PnP.zip`](https://deepinv.org/auto_examples/plug-and-play/_downloads/1dd64207d1e7a0d33ed1b372efd21e27/demo_vanilla_PnP.zip)

[Gallery generated by Sphinx-Gallery](https://sphinx-gallery.github.io)
