Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

2. 1D Poisson problem with TV denoising using MYULA

We consider a Bayesian inverse problem in which we infer a conductivity field σ\sigma from potential uu measurements everywhere in a 1D domain, similar problem in a 2D domain was presented in 2. PDE-based BIP using CUQIpy and CUQIpy-FEniCS plugin. The forward map from the conductivity σ\sigma to the measurements is governed by the 1D Poisson equation with zero Neumann boundary condition at the left and Dirichlet boundary condition at the right, and source term f(x)=10f(x)=10:

(em(x)u(x))=f(x)     in     Ω=(0,1)\nabla \cdot \left( e^{m(x)} \nabla u(x) \right) = f(x) \;\; \text{ in } \;\;\Omega = (0,1)
u(0)n=0     and     u(1)=1\nabla u(0) \cdot n = 0 \;\; \text{ and } \;\; u(1) = 1

where we use a log parameterization, σ=em(x)\sigma = e^{m(x)}, to ensure positivity of the inferred conductivity. We denote by m\mathbf{m} and u\mathbf{u} the discretized versions of the log conductivity field and the potential, respectively, and we denote by F\mathbf{F} the forward map F(m)=y\mathbf{F}(\mathbf{m})=\mathbf{y}, which for a given m\mathbf{m} returns the measurements y\mathbf{y} of the potential u\mathbf{u} everywhere in the domain.

In this section, we present two Bayesian inverse problem setups for this problem. Both setups share the same forward model and likelihood, and differ only in the choice of the prior for the log conductivity field m\mathbf{m}:

  • In the first setup, we use a GMRF prior

  • and in the second setup, we use a TV-type implicit prior

We compare the results obtained from these two setups to illustrate the effect of the choice of the prior on the posterior distribution and the inferred conductivity field.

Table of Contents

  • 2.1. Learning objectives

  • 2.2. Setting up a CUQIpy PDE object and the forward model

  • 2.3. BIP setup with GMRF prior

  • 2.4. BIP setup with TV-type implicit prior

2.1. Learning objectives

  • Describe the MYULA algorithm and how it is different from ULA.

  • Describe how Moreau-Yosida smoothing is used to overcome the non-differentiability of the TV prior in the MYULA algorithm.

  • Write the MYULA step in terms of the proximal operator of the TV prior.

  • Create RestorationPrior and MoreauYoshidaPrior objects in CUQIpy to create a TV-type implicit prior.

  • Sample from the posterior distribution using the MYULA algorithm and analyze the results.

⚠️ Note:
  • This notebook is under the GPLv3.0 license.

  • This notebook was run on a machine locally and not using github actions for this book. To run this notebook on your machine, you need to have CUQIpy-FEniCS installed.

We import the necessary libraries and modules.

from cuqi.distribution import Gaussian, GMRF, JointDistribution
from cuqi.implicitprior import RestorationPrior, MoreauYoshidaPrior
from cuqi.sampler import  ULA
from cuqi.model import PDEModel
from cuqi.array import CUQIarray
from cuqi.geometry import Continuous1D
from cuqipy_fenics.geometry import FEniCSContinuous
from cuqipy_fenics.pde import SteadyStateLinearFEniCSPDE
import numpy as np
import dolfin as dl
import matplotlib.pyplot as plt
from skimage.restoration import denoise_tv_chambolle
import ufl

# Set logging level of dl
dl.set_log_level(dl.LogLevel.ERROR)

2.2. Setting up a CUQIpy PDE object and the forward model

In this section, we set up a CUQIpy PDE object for the 1D Poisson problem described above and define the forward model. We assume the reader is familiar with the basics of FEniCS and finite element methods. However, understanding the details of this section is not required to follow the rest of the notebook, namely, sections 2.3 and 2.4.

First we create a mesh and define a function space for the PDE problem using FEniCS dolfin library.

n = 80 # number of nodes in the mesh
mesh = dl.IntervalMesh(n-1, 0, 1)

# Function space for the solution u
solution_function_space = dl.FunctionSpace(mesh, 'Lagrange', 1)
# Function space for the parameter m
parameter_function_space = dl.FunctionSpace(mesh, 'Lagrange', 1)

We then define the FEniCS variational form for the 1D poission problem.

source_signal = 10 # source term in the PDE
def form(m,u,p):
    return ufl.exp(m)*ufl.inner(ufl.grad(u), ufl.grad(p))*ufl.dx\
          - dl.Constant(source_signal)*p*ufl.dx

We define the Dirichlet boundary condition for the PDE problem as well as the corresponding adjoint Dirichlet boundary condition which is needed for the gradient-based sampling methods ULA and MYULA that we will use later in this notebook.

def u_boundary(x, on_boundary):
    return on_boundary and  ((x[0] > 1-dl.DOLFIN_EPS))

dirichlet_bc_expression = dl.Expression("right_bc*(x[0]>endpoint-eps)",
                                        eps=dl.DOLFIN_EPS, endpoint=1,
                                        right_bc=1, degree=1)

dirichlet_bc = [dl.DirichletBC(
            solution_function_space, dirichlet_bc_expression, u_boundary)]
adjoint_dirichlet_bc = [dl.DirichletBC(
            solution_function_space, dl.Constant(0), u_boundary)]

After that we create CUQIpy-FEniCS PDE object, to which we supply the form, the function spaces, and the boundary conditions.

PDE = SteadyStateLinearFEniCSPDE(
            form, mesh, solution_function_space, parameter_function_space,
            dirichlet_bc, adjoint_dirichlet_bc)

Then we create the CUQIpy forward model to which we supply the PDE object, and the domain and the range geometries.

domain_geometry = FEniCSContinuous(parameter_function_space)
range_geometry = FEniCSContinuous(solution_function_space)
F = PDEModel(PDE,range_geometry,domain_geometry)

This concludes setting up the forward model F.

2.3. BIP setup with a GMRF prior

To infer the log conductivity field, we set up the following Bayesian model

mGMRF(0,25)ymGaussian(F(m),noise2I)\begin{align*} \mathbf{m} &\sim \mathrm{GMRF}(0, 25)\\ \mathbf{y}|\mathbf{m} &\sim \mathrm{Gaussian}(\mathbf{F}(\mathbf{m}), \mathrm{noise}^2\mathbf{I})\\ \end{align*}

where noise2\mathrm{noise}^2 is the variance of the Gaussian noise in the measurements.

GMRF prior

We create a GMRF prior for the log conductivity field m\mathbf{m} as follows

m = GMRF(np.zeros(domain_geometry.par_dim), 25) 

The true signal

We choose a true log conductivity field m\mathbf{m} to be a piecewise constant function given as follows

m_true_array = np.ones(n)*-1
m_true_array[int(n/3):2*int(n/3)] = -0.5
m_true = CUQIarray(m_true_array, geometry=domain_geometry)
m_true.plot()
<Figure size 640x480 with 1 Axes>

The likelihood, the data, and the posterior distribution

We then create the data distribution assuming a noise level noise

noise = 0.02
y = Gaussian(mean=F(m), cov=noise**2*np.eye(range_geometry.par_dim),
             geometry=range_geometry)

And we generate a realization of the data yobs\mathbf{y}^\text{obs} by sampling from the data distribution at the true log conductivity field.

y_obs = y(m=m_true.parameters).sample()

y_obs.plot(label="observation")
F(m_true).plot(label="exact data")
plt.legend()
<Figure size 640x480 with 1 Axes>

The posterior distribution, given the data yobs\mathbf{y}^\text{obs}, is then given by

p(myobs)p(yobsm)p(m),p(\mathbf{m}|\mathbf{y}^\text{obs}) \propto p(\mathbf{y}^\text{obs}|\mathbf{m})p(\mathbf{m}),

where p(yobsm)p(\mathbf{y}^\text{obs}|\mathbf{m}) is the likelihood function, i.e. the data distribution PDF at a fixed y=yobs\mathbf{y}=\mathbf{y}^\text{obs}, and p(m)p(\mathbf{m}) is the prior distribution PDF. The posterior distribution can equivalently be written as

p(myobs)L(myobs)p(m),p(\mathbf{m}|\mathbf{y}^\text{obs}) \propto L(\mathbf{m}|\mathbf{y}^\text{obs})p(\mathbf{m}),

where L(myobs)=p(yobsm)L(\mathbf{m}|\mathbf{y}^\text{obs}) = p(\mathbf{y}^\text{obs}|\mathbf{m}). We create the posterior distribution in CUQIpy as follows

posterior = JointDistribution(m, y)(y=y_obs)

Sampling using ULA

In 1. Sampling with CUQIpy: five little stories, we introduce the Unadjusted Langevin Algorithm (ULA) for sampling from the posterior distribution. We recall the ULA update step for sampling from a posterior distribution with PDF p(myobs)p(\mathbf{m}|\mathbf{y}^\text{obs}) as follows

mk+1=mk+δlogp(mkyobs)+2δξk=mk+δlogL(mkyobs)+δlogp(mk)+2δξk,\begin{align*} \mathbf{m}_{k+1} &= \mathbf{m}_k + \delta \nabla \log p(\mathbf{m}_k|\mathbf{y}^\text{obs}) + \sqrt{2\delta} \mathbf{\xi}_k\\ &= \mathbf{m}_k + \delta \nabla \log L(\mathbf{m}_k|\mathbf{y}^\text{obs}) + \delta \nabla \log p(\mathbf{m}_k) + \sqrt{2\delta} \mathbf{\xi}_k, \end{align*}

where mk\mathbf{m}_k is the current sample and mk+1\mathbf{m}_{k+1} is the next sample, δ\delta is the step size, and ξkGaussian(0,I)\mathbf{\xi}_k \sim \mathrm{Gaussian}(0, \mathbf{I}) is a standard Gaussian multi-variate random variable. We sample from the posterior distribution using the CUQIpy implementation of ULA. First, we set the number of samples and the thinning factor:

Ns = 100000
Nt = 100

Then we create the ULA sampler and sample from the posterior distribution as follows

initial_point_ula = np.ones(n)*-0.75
delta_ula = 2e-6
sampler_ula = ULA(posterior, initial_point=initial_point_ula, scale=delta_ula)

sampler_ula.sample(Ns, Nt)
samples_ula = sampler_ula.get_samples()
Sample: 100%|██████████| 100000/100000 [1:08:23<00:00, 24.37it/s, acc rate: 100.00%]

We plot the credibility interval for the inferred log conductivity field m\mathbf{m}

# Switch samples geometry to Continuous1D for better plotting of the credibility interval
samples_ula.geometry = Continuous1D(np.flip(mesh.coordinates()[:,0]))

samples_ula.plot_ci(95, exact=m_true)
plt.ylim(-1.4, 0)
plt.xlim(0, 1)
(0.0, 1.0)
<Figure size 640x480 with 1 Axes>

We notice that the credibility interval roughly captures the true solution, but both the credibility interval and the mean are highly oscillatory and do not capture the piecewise constant nature of the true solution. In the next section, we impose a TV-type implicit prior through the MYULA framework to capture the piecewise constant nature of the true solution.

2.4. BIP setup with a TV-type implicit prior

Principles behind MYULA sampling method

The Moreau-Yosida Unadjusted Langevin Algorithm (MYULA) was introduced in durmus2018efficient as an extension of the ULA algorithm to allow sampling from posterior distributions with non-differentiable priors, such as TV-type priors. The main idea behind MYULA is to use Moreau-Yosida regularization to create a smoothed version of the original non-differentiable prior, which allows us to compute the gradient needed for the Langevin updates.

To take an ULA step, as described above, we need the gradient of the log-posterior which involves the gradient of the log-prior R(m):=logp(m)-R(\mathbf{m}) :=\log p(\mathbf{m}). In the case in which R(m)R(\mathbf{m}) is non-differentiable, we can consider as a surrogate posterior the density pα(myobs)p(yobsm)pα(m)p_{\alpha} (\mathbf{m}|y^\text{obs}) \propto p(y^\text{obs}|\mathbf{m}) p_{\alpha} (\mathbf{m}) where pα(m)p_{\alpha}(\mathbf{m}) is a smoothed version of the original prior p(m)=eR(m)p(\mathbf{m})=e^{-R(\mathbf{m})}.

In MYULA setting, we obtain the smoothed counterpart Rα(m)R_\alpha(\mathbf{m}) of R(m)R(\mathbf{m}) by applying the Moreau envelope as follows

Rα(m)=infz{12mz22+αR(z)}.\begin{align*} R_\alpha(\mathbf{m}) = \operatorname{inf}_{\mathbf{z}} \left\{\frac{1}{2}\| \mathbf{m}- \mathbf{z} \|_2^2 + \alpha R(\mathbf{z})\right\}. \end{align*}

The smoothing strength α\alpha controls how closely the smoothed prior pα(m)=eRα(m)p_\alpha(\mathbf{m})=e^{-R_\alpha(\mathbf{m})} approximates the original prior p(m)=eR(m)p(\mathbf{m})=e^{-R(\mathbf{m})}, and as it goes to zero, the smoothed prior converges to the original prior. Rα(m)R_\alpha(\mathbf{m}) is continuously differentiable and its gradient can be computed as follows Bauschke2017

Rα(m)=1α(mproxRα(m)),\begin{align*} \nabla R_\alpha(\mathbf{m}) = \frac{1}{\alpha} (\mathbf{m} - \operatorname{prox}_{R}^\alpha (\mathbf{m})), \end{align*}

where the proximal operator of RR, proxRα(m)\operatorname{prox}_{R}^\alpha (\mathbf{m}), is defined as follows

proxRα(m)=argminz{12mz22+αR(z)}.\begin{align*} \operatorname{prox}_{R}^\alpha (\mathbf{m}) = \operatorname{argmin}_{\mathbf{z}} \left\{\frac{1}{2}\| \mathbf{m}- \mathbf{z} \|_2^2 + \alpha R(\mathbf{z})\right\}. \end{align*}

MYULA step for sampling from the surrogate posterior is then given by

mk+1=mk+δlogL(mkyobs)+δlogpα(mk)+2δξk=mk+δlogL(mkyobs)δRα(mk)+2δξk=mk+δlogL(mkyobs)δα(mkproxRα(mk))+2δξk.\begin{align*} \mathbf{m}_{k+1} &= \mathbf{m}_k + \delta \nabla \log L(\mathbf{m}_k|y^\text{obs}) + \delta \nabla \log p_{\alpha}(\mathbf{m}_k) + \sqrt{2\delta} \mathbf{\xi}_k\\ &= \mathbf{m}_k + \delta \nabla \log L(\mathbf{m}_k|y^\text{obs}) - \delta \nabla R_\alpha(\mathbf{m}_k) + \sqrt{2\delta} \mathbf{\xi}_k\\ &= \mathbf{m}_k + \delta \nabla \log L(\mathbf{m}_k|y^\text{obs}) - \frac{\delta}{\alpha} (\mathbf{m}_k - \operatorname{prox}_{R}^\alpha (\mathbf{m}_k)) + \sqrt{2\delta} \mathbf{\xi}_k. \end{align*}

TV-type implicit prior and the Bayesian model setup

We want to impose a TV-type implicit prior on the log conductivity field m\mathbf{m} to capture the piecewise constant nature of the true solution. In this case, the negative log prior is given by the 1D non-differentiable TV function of m\mathbf{m} as follows

RTV,λ(m)=λm1=λRTV(m)\begin{align*} R^{\text{TV}, \lambda}(\mathbf{m}) = \lambda ||\nabla \mathbf{m}||_{1} = \lambda R^{\text{TV}}(\mathbf{m}) \end{align*}

where λ\lambda is a weight parameter for the TV term. To apply MYULA, we only need the proximal operator of RTV(m)R^{\text{TV}}(\mathbf{m}), which is also known as a TV denoising operator. This operator takes a signal as input and returns a more TV-regularized signal and is available in, e.g., scikit-image. In CUQIpy, we use the term “restoration operator” as a general term to refer to denoising operators, as well as other types of operators that can be used to define implicit priors through the MYULA and PnPULA laumont2022bayesian frameworks. For brevity, we focus in this section on the MYULA framework, and the reader can refer to laumont2022bayesian and everink2025computational for the PnPULA framework.

The gradient of the smoothed counterpart RαTV(m)R^{\text{TV}}_\alpha(\mathbf{m}) of RTV(m)R^{\text{TV}}(\mathbf{m}) is then given by

RαTV(m)=1α(mproxRTVα(m)),\begin{align*} \nabla R^{\text{TV}}_\alpha(\mathbf{m}) = \frac{1}{\alpha} (\mathbf{m} - \operatorname{prox}_{R^{\text{TV}}}^\alpha (\mathbf{m})), \end{align*}

and RαTV,λ(m)=λRαTV(m)\nabla R^{\text{TV},\lambda}_\alpha(\mathbf{m}) = \lambda \nabla R^{\text{TV}}_\alpha(\mathbf{m}).

The Bayesian inverse problem setup with the TV-type implicit prior is then given by

m1ZeRαTV,λ(m)ymGaussian(F(m), noise2I),\begin{align*} \mathbf{m} &\sim \frac{1}{Z} e^{-R^{\text{TV},\lambda}_\alpha(\mathbf{m})}\\ \mathbf{y}|\mathbf{m} &\sim \mathrm{Gaussian}(\mathbf{F}(\mathbf{m}), \ \mathrm{noise}^2\mathbf{I}), \end{align*}

where ZZ is the normalization constant of the prior distribution which we do not need to compute for sampling from the posterior distribution using MYULA.

To create a TV-type implicit prior in CUQIpy, we use the RestorationPrior and the MoreauYoshidaPrior classes. The RestorationPrior requires as input a restoration operator, which in our case is the TV denoising operator. This operator is provided in the form of a python function that takes a signal and a parameter controlling the strength of restoration restoration_strength, α\alpha in this case, as input and returns the denoised (restored) signal.

def restore_TV(x, restoration_strength=None):
    # Use scikit-image's TV denoising operator denoise_tv_chambolle
    denoised_image = denoise_tv_chambolle(x,
        weight=restoration_strength,
        max_num_iter=100)
    return  denoised_image, None

We use the restore_TV function to create the CUQIpy RestorationPrior object as follows

restorator = RestorationPrior(
        restore_TV,
        geometry=F.domain_geometry
    )

We then define our smoothed TV prior m_tv as follows

alpha = 0.5*noise**2 
lambda_tv = 200
m_tv = MoreauYoshidaPrior(
    restorator, smoothing_strength=alpha, regularization_strength=lambda_tv)

The MoreauYoshidaPrior object, m_tv, provides the gradient of RαTV,λ(m)R^{\text{TV},\lambda}_\alpha(\mathbf{m}). The parameter regularization_strength, λ\lambda, controls the strength of the TV regularization term relative to the likelihood term in the posterior distribution. The larger the regularization_strength parameter, the stronger the TV regularization term, driving the inferred solution to be closer to a piecewise constant function.

Now we can create the data distribution and the posterior distribution as follows

y_tv = Gaussian(F(m_tv), noise**2, geometry=F.range_geometry)
posterior_tv = JointDistribution(y_tv, m_tv)(y_tv=y_obs)

Sampling using MYULA in CUQIpy

We sample the posterior using the ULA algorithm with the smoothed TV prior, which is in essence the MYULA algorithm, as follows

scale_myula =2e-6
initial_point_myula = np.ones(n)*-0.75
sampler_myula = ULA(
    posterior_tv, scale=scale_myula, initial_point=initial_point_myula)

sampler_myula.sample(Ns, Nt=Nt)
samples_myula = sampler_myula.get_samples()
Sample: 100%|██████████| 100000/100000 [57:21<00:00, 29.06it/s, acc rate: 100.00%] 

And we plot the credibility intervals for the MYULA samples

# Switch samples geometry to Continuous1D for better plotting of the credibility interval
samples_myula.geometry = Continuous1D(np.flip(mesh.coordinates()[:,0]))

samples_myula.plot_ci(95, exact=m_true)
plt.ylim(-1.4,0)
plt.xlim(0,1)
(0.0, 1.0)
<Figure size 640x480 with 1 Axes>

Note that the MYULA samples are much less oscillatory than the ULA samples with GMRF prior, and they capture the piecewise constant nature of the true solution much better.