Convolutional Constained MOD

This example demonstrates the use of ccmod.ConvCnstrMOD_Consensus for computing a convolutional dictionary update via the convolutional constrained method of optimal directions problem [1] [26]. This problem is mainly useful as a component within convolutional dictionary learning, but its use is demonstrated here since a user may wish to construct such objects as part of a custom convolutional dictionary learning algorithm, using dictlrn.DictLearn.

from __future__ import print_function
from builtins import input

import pyfftw   # See https://github.com/pyFFTW/pyFFTW/issues/40
import numpy as np

from sporco.admm import cbpdn
from sporco.admm import ccmod
from sporco import util
from sporco import signal
from sporco import plot
plot.config_notebook_plotting()

Load training images.

exim = util.ExampleImages(scaled=True, zoom=0.25, gray=True)
S1 = exim.image('barbara.png', idxexp=np.s_[10:522, 100:612])
S2 = exim.image('kodim23.png', idxexp=np.s_[:, 60:572])
S3 = exim.image('monarch.png', idxexp=np.s_[:, 160:672])
S4 = exim.image('sail.png', idxexp=np.s_[:, 210:722])
S5 = exim.image('tulips.png', idxexp=np.s_[:, 30:542])
S = np.dstack((S1, S2, S3, S4, S5))

Highpass filter training images.

npd = 16
fltlmbd = 5
sl, sh = signal.tikhonov_filter(S, fltlmbd, npd)

Load initial dictionary.

D0 = util.convdicts()['G:12x12x36']

Compute sparse representation on current dictionary.

lmbda = 0.1
opt = cbpdn.ConvBPDN.Options({'Verbose': True, 'MaxMainIter': 100,
                     'HighMemSolve': True})
c = cbpdn.ConvBPDN(D0, sh, lmbda, opt)
X = c.solve()
Itn   Fnc       DFid      Regℓ1     r         s         ρ
----------------------------------------------------------------
   0  4.13e+02  2.48e+01  3.88e+03  9.11e-01  1.90e-01  6.00e+00
   1  3.31e+02  7.06e+01  2.60e+03  6.12e-01  2.76e-01  6.00e+00
   2  2.99e+02  7.08e+01  2.28e+03  3.06e-01  2.46e-01  6.00e+00
   3  3.00e+02  6.52e+01  2.35e+03  2.25e-01  1.88e-01  4.73e+00
   4  3.08e+02  5.90e+01  2.49e+03  1.96e-01  1.31e-01  3.66e+00
   5  2.97e+02  5.68e+01  2.40e+03  1.70e-01  9.63e-02  3.17e+00
   6  2.71e+02  5.55e+01  2.15e+03  1.38e-01  7.91e-02  3.17e+00
   7  2.48e+02  5.56e+01  1.92e+03  1.14e-01  6.64e-02  3.17e+00
   8  2.33e+02  5.59e+01  1.77e+03  9.44e-02  5.49e-02  3.17e+00
   9  2.23e+02  5.63e+01  1.67e+03  7.90e-02  4.64e-02  3.17e+00
  10  2.16e+02  5.66e+01  1.60e+03  6.63e-02  4.07e-02  3.17e+00
  11  2.13e+02  5.68e+01  1.56e+03  6.01e-02  3.63e-02  2.86e+00
  12  2.12e+02  5.67e+01  1.55e+03  5.51e-02  3.23e-02  2.60e+00
  13  2.11e+02  5.66e+01  1.54e+03  4.83e-02  2.86e-02  2.60e+00
  14  2.09e+02  5.64e+01  1.52e+03  4.27e-02  2.56e-02  2.60e+00
  15  2.05e+02  5.63e+01  1.49e+03  3.80e-02  2.35e-02  2.60e+00
  16  2.02e+02  5.63e+01  1.46e+03  3.61e-02  2.17e-02  2.34e+00
  17  2.00e+02  5.64e+01  1.44e+03  3.46e-02  1.97e-02  2.14e+00
  18  1.98e+02  5.64e+01  1.42e+03  3.16e-02  1.77e-02  2.14e+00
  19  1.97e+02  5.65e+01  1.40e+03  2.90e-02  1.61e-02  2.14e+00
  20  1.95e+02  5.65e+01  1.39e+03  2.67e-02  1.49e-02  2.14e+00
  21  1.94e+02  5.66e+01  1.37e+03  2.46e-02  1.38e-02  2.14e+00
  22  1.92e+02  5.66e+01  1.36e+03  2.27e-02  1.29e-02  2.14e+00
  23  1.91e+02  5.66e+01  1.34e+03  2.11e-02  1.21e-02  2.14e+00
  24  1.89e+02  5.66e+01  1.33e+03  1.97e-02  1.14e-02  2.14e+00
  25  1.88e+02  5.66e+01  1.31e+03  1.84e-02  1.07e-02  2.14e+00
  26  1.87e+02  5.66e+01  1.30e+03  1.72e-02  1.01e-02  2.14e+00
  27  1.86e+02  5.67e+01  1.29e+03  1.62e-02  9.53e-03  2.14e+00
  28  1.85e+02  5.67e+01  1.28e+03  1.52e-02  9.02e-03  2.14e+00
  29  1.84e+02  5.67e+01  1.27e+03  1.44e-02  8.57e-03  2.14e+00
  30  1.83e+02  5.68e+01  1.26e+03  1.36e-02  8.14e-03  2.14e+00
  31  1.82e+02  5.68e+01  1.26e+03  1.29e-02  7.73e-03  2.14e+00
  32  1.82e+02  5.68e+01  1.25e+03  1.22e-02  7.33e-03  2.14e+00
  33  1.81e+02  5.68e+01  1.25e+03  1.21e-02  6.95e-03  1.95e+00
  34  1.81e+02  5.68e+01  1.24e+03  1.16e-02  6.54e-03  1.95e+00
  35  1.81e+02  5.69e+01  1.24e+03  1.10e-02  6.15e-03  1.95e+00
  36  1.80e+02  5.69e+01  1.23e+03  1.05e-02  5.79e-03  1.95e+00
  37  1.80e+02  5.69e+01  1.23e+03  1.00e-02  5.48e-03  1.95e+00
  38  1.79e+02  5.69e+01  1.22e+03  9.57e-03  5.21e-03  1.95e+00
  39  1.79e+02  5.69e+01  1.22e+03  9.12e-03  4.96e-03  1.95e+00
  40  1.78e+02  5.70e+01  1.21e+03  8.70e-03  4.74e-03  1.95e+00
  41  1.78e+02  5.70e+01  1.21e+03  8.29e-03  4.52e-03  1.95e+00
  42  1.78e+02  5.70e+01  1.21e+03  7.91e-03  4.30e-03  1.95e+00
  43  1.77e+02  5.70e+01  1.20e+03  7.56e-03  4.10e-03  1.95e+00
  44  1.77e+02  5.70e+01  1.20e+03  7.22e-03  3.92e-03  1.95e+00
  45  1.76e+02  5.70e+01  1.19e+03  6.90e-03  3.75e-03  1.95e+00
  46  1.76e+02  5.70e+01  1.19e+03  6.59e-03  3.58e-03  1.95e+00
  47  1.76e+02  5.71e+01  1.19e+03  6.31e-03  3.41e-03  1.95e+00
  48  1.76e+02  5.71e+01  1.19e+03  6.03e-03  3.26e-03  1.95e+00
  49  1.75e+02  5.71e+01  1.18e+03  5.77e-03  3.12e-03  1.95e+00
  50  1.75e+02  5.71e+01  1.18e+03  5.52e-03  2.99e-03  1.95e+00
  51  1.75e+02  5.71e+01  1.18e+03  5.28e-03  2.87e-03  1.95e+00
  52  1.74e+02  5.71e+01  1.17e+03  5.05e-03  2.75e-03  1.95e+00
  53  1.74e+02  5.71e+01  1.17e+03  4.84e-03  2.63e-03  1.95e+00
  54  1.74e+02  5.71e+01  1.17e+03  4.64e-03  2.51e-03  1.95e+00
  55  1.74e+02  5.71e+01  1.17e+03  4.44e-03  2.41e-03  1.95e+00
  56  1.74e+02  5.71e+01  1.16e+03  4.26e-03  2.31e-03  1.95e+00
  57  1.73e+02  5.71e+01  1.16e+03  4.09e-03  2.22e-03  1.95e+00
  58  1.73e+02  5.72e+01  1.16e+03  3.93e-03  2.12e-03  1.95e+00
  59  1.73e+02  5.72e+01  1.16e+03  3.78e-03  2.03e-03  1.95e+00
  60  1.73e+02  5.72e+01  1.16e+03  3.63e-03  1.94e-03  1.95e+00
  61  1.73e+02  5.72e+01  1.16e+03  3.48e-03  1.87e-03  1.95e+00
  62  1.73e+02  5.72e+01  1.15e+03  3.34e-03  1.80e-03  1.95e+00
  63  1.72e+02  5.72e+01  1.15e+03  3.21e-03  1.73e-03  1.95e+00
  64  1.72e+02  5.72e+01  1.15e+03  3.09e-03  1.66e-03  1.95e+00
  65  1.72e+02  5.72e+01  1.15e+03  2.97e-03  1.59e-03  1.95e+00
  66  1.72e+02  5.72e+01  1.15e+03  2.86e-03  1.53e-03  1.95e+00
  67  1.72e+02  5.72e+01  1.15e+03  2.75e-03  1.47e-03  1.95e+00
  68  1.72e+02  5.72e+01  1.15e+03  2.65e-03  1.42e-03  1.95e+00
  69  1.72e+02  5.72e+01  1.14e+03  2.54e-03  1.36e-03  1.95e+00
  70  1.71e+02  5.72e+01  1.14e+03  2.45e-03  1.32e-03  1.95e+00
  71  1.71e+02  5.72e+01  1.14e+03  2.36e-03  1.27e-03  1.95e+00
  72  1.71e+02  5.72e+01  1.14e+03  2.27e-03  1.23e-03  1.95e+00
  73  1.71e+02  5.72e+01  1.14e+03  2.19e-03  1.19e-03  1.95e+00
  74  1.71e+02  5.72e+01  1.14e+03  2.11e-03  1.14e-03  1.95e+00
  75  1.71e+02  5.72e+01  1.14e+03  2.03e-03  1.09e-03  1.95e+00
  76  1.71e+02  5.72e+01  1.14e+03  1.96e-03  1.05e-03  1.95e+00
  77  1.71e+02  5.72e+01  1.14e+03  1.88e-03  1.00e-03  1.95e+00
  78  1.71e+02  5.72e+01  1.14e+03  1.81e-03  9.68e-04  1.95e+00
  79  1.71e+02  5.72e+01  1.13e+03  1.75e-03  9.34e-04  1.95e+00
  80  1.71e+02  5.72e+01  1.13e+03  1.69e-03  9.00e-04  1.95e+00
  81  1.71e+02  5.73e+01  1.13e+03  1.63e-03  8.65e-04  1.95e+00
  82  1.70e+02  5.73e+01  1.13e+03  1.57e-03  8.31e-04  1.95e+00
  83  1.70e+02  5.73e+01  1.13e+03  1.51e-03  7.98e-04  1.95e+00
  84  1.70e+02  5.73e+01  1.13e+03  1.46e-03  7.68e-04  1.95e+00
  85  1.70e+02  5.73e+01  1.13e+03  1.41e-03  7.41e-04  1.95e+00
  86  1.70e+02  5.73e+01  1.13e+03  1.36e-03  7.16e-04  1.95e+00
  87  1.70e+02  5.73e+01  1.13e+03  1.31e-03  6.93e-04  1.95e+00
  88  1.70e+02  5.73e+01  1.13e+03  1.26e-03  6.71e-04  1.95e+00
  89  1.70e+02  5.73e+01  1.13e+03  1.22e-03  6.49e-04  1.95e+00
  90  1.70e+02  5.73e+01  1.13e+03  1.18e-03  6.26e-04  1.95e+00
  91  1.70e+02  5.73e+01  1.13e+03  1.14e-03  6.04e-04  1.95e+00
  92  1.70e+02  5.73e+01  1.13e+03  1.10e-03  5.81e-04  1.95e+00
  93  1.70e+02  5.73e+01  1.13e+03  1.06e-03  5.61e-04  1.95e+00
  94  1.70e+02  5.73e+01  1.13e+03  1.03e-03  5.41e-04  1.95e+00
  95  1.70e+02  5.73e+01  1.13e+03  9.94e-04  5.25e-04  1.95e+00
----------------------------------------------------------------

Update dictionary for training image set.

opt = ccmod.ConvCnstrMOD_Consensus.Options({'Verbose': True,
            'MaxMainIter': 100, 'rho': 1e1})
c = ccmod.ConvCnstrMOD_Consensus(X, sh, D0.shape, opt)
c.solve()
D1 = c.getdict().squeeze()
print("ConvCnstrMOD_Consensus solve time: %.2fs" % c.timer.elapsed('solve'))
Itn   DFid      Cnstr     r         s
--------------------------------------------
   0  5.67e+01  6.45e-07  9.62e-01  1.01e+00
   1  5.52e+01  7.82e-07  4.95e-01  2.47e-02
   2  5.08e+01  9.14e-07  7.64e-01  1.35e-01
   3  5.04e+01  7.54e-07  3.83e-01  2.98e-02
   4  5.00e+01  6.34e-07  4.89e-01  5.99e-02
   5  4.99e+01  7.17e-07  2.84e-01  2.17e-02
   6  4.97e+01  7.80e-07  3.13e-01  3.07e-02
   7  4.97e+01  8.14e-07  2.02e-01  1.59e-02
   8  4.96e+01  6.99e-07  2.00e-01  1.92e-02
   9  4.96e+01  8.25e-07  1.39e-01  1.19e-02
  10  4.96e+01  7.50e-07  1.28e-01  1.24e-02
  11  4.96e+01  9.23e-07  9.34e-02  8.35e-03
  12  4.96e+01  1.15e-06  8.21e-02  7.85e-03
  13  4.96e+01  8.69e-07  6.18e-02  5.69e-03
  14  4.96e+01  8.08e-07  5.25e-02  5.16e-03
  15  4.95e+01  8.00e-07  4.04e-02  4.00e-03
  16  4.95e+01  7.76e-07  3.36e-02  3.58e-03
  17  4.95e+01  8.38e-07  2.62e-02  2.90e-03
  18  4.95e+01  9.58e-07  2.15e-02  2.56e-03
  19  4.95e+01  1.09e-06  1.69e-02  2.12e-03
  20  4.95e+01  8.63e-07  1.38e-02  1.86e-03
  21  4.95e+01  7.54e-07  1.09e-02  1.56e-03
  22  4.95e+01  9.05e-07  8.82e-03  1.36e-03
  23  4.95e+01  8.52e-07  7.01e-03  1.16e-03
  24  4.95e+01  8.09e-07  5.64e-03  1.02e-03
  25  4.95e+01  8.24e-07  4.50e-03  8.90e-04
  26  4.95e+01  9.02e-07  3.61e-03  7.90e-04
  27  4.95e+01  8.33e-07  2.88e-03  6.98e-04
  28  4.95e+01  7.30e-07  2.31e-03  6.27e-04
  29  4.95e+01  7.61e-07  1.85e-03  5.63e-04
  30  4.95e+01  7.25e-07  1.48e-03  5.13e-04
  31  4.95e+01  8.14e-07  1.19e-03  4.69e-04
  32  4.95e+01  7.94e-07  9.52e-04  4.35e-04
--------------------------------------------
ConvCnstrMOD_Consensus solve time: 3.36s

Display initial and final dictionaries.

fig = plot.figure(figsize=(14, 7))
plot.subplot(1, 2, 1)
plot.imview(util.tiledict(D0), title='D0', fig=fig)
plot.subplot(1, 2, 2)
plot.imview(util.tiledict(D1), title='D1', fig=fig)
fig.show()
../../_images/ccmod_cns_gry_13_0.png

Get iterations statistics from CCMOD solver object and plot functional value, ADMM primary and dual residuals, and automatically adjusted ADMM penalty parameter against the iteration number.

its = c.getitstat()
fig = plot.figure(figsize=(20, 5))
plot.subplot(1, 3, 1)
plot.plot(its.DFid, xlbl='Iterations', ylbl='Functional', fig=fig)
plot.subplot(1, 3, 2)
plot.plot(np.vstack((its.PrimalRsdl, its.DualRsdl)).T,
          ptyp='semilogy', xlbl='Iterations', ylbl='Residual',
          lgnd=['Primal', 'Dual'], fig=fig)
plot.subplot(1, 3, 3)
plot.plot(its.Rho, xlbl='Iterations', ylbl='Penalty Parameter', fig=fig)
fig.show()
../../_images/ccmod_cns_gry_15_0.png