|
1 | 1 | r""" |
2 | | -ISTA, FISTA, and TWIST for Compressive sensing |
3 | | -============================================== |
| 2 | +IHT, ISTA, FISTA, and TWIST for Compressive sensing |
| 3 | +=================================================== |
4 | 4 |
|
5 | | -In this example we want to compare three popular solvers in compressive |
6 | | -sensing problem, namely :py:class:`pylops.optimization.sparsity.ista`, |
7 | | -:py:class:`pylops.optimization.sparsity.fista`, and |
8 | | -:py:class:`pyproximal.optimization.primal.TwIST`. |
| 5 | +In this example we want to compare four popular solvers in compressive |
| 6 | +sensing problem, namely IHT, ISTA, FISTA, and TwIST. The first three can |
| 7 | +be implemented using the same solver, namely the |
| 8 | +:py:class:`pyproximal.optimization.primal.ProximalGradient`, whilst the latter |
| 9 | +is implemented in :py:class:`pyproximal.optimization.primal.TwIST`. |
9 | 10 |
|
10 | | -Whilst all solvers try to solve an unconstrained problem with a L1 |
| 11 | +The IHT solver tries to solve the following unconstrained problem with a L0Ball |
| 12 | +regularization term: |
| 13 | +
|
| 14 | +.. math:: |
| 15 | + J = \|\mathbf{d} - \mathbf{Op} \mathbf{x}\|_2 \; s.t. \; \|\mathbf{x}\|_0 \le K |
| 16 | +
|
| 17 | +The other solvers try instead to solve an unconstrained problem with a L1 |
11 | 18 | regularization term: |
12 | 19 |
|
13 | 20 | .. math:: |
14 | 21 | J = \|\mathbf{d} - \mathbf{Op} \mathbf{x}\|_2 + \epsilon \|\mathbf{x}\|_1 |
15 | 22 |
|
16 | | -their convergence speed is different, which is something we want to focus in |
| 23 | +however their convergence speed is different, which is something we want to focus in |
17 | 24 | this tutorial. |
18 | 25 |
|
19 | 26 | """ |
|
27 | 34 | plt.close('all') |
28 | 35 | np.random.seed(0) |
29 | 36 |
|
| 37 | +def callback(x, pf, pg, eps, cost): |
| 38 | + cost.append(pf(x) + eps * pg(x)) |
| 39 | + |
30 | 40 | ############################################################################### |
31 | 41 | # Let's start by creating a dense mixing matrix and a sparse signal. |
32 | 42 | # Note that the mixing matrix leads to an underdetermined system of equations |
|
45 | 55 | y = Aop * x |
46 | 56 |
|
47 | 57 | ############################################################################### |
48 | | -# We try now to recover the sparse signal with our 3 different solvers |
49 | | -eps = 1e-2 |
| 58 | +# We try now to recover the sparse signal with our 4 different solvers |
| 59 | +L = np.abs((Aop.H * Aop).eigs(1)[0]) |
| 60 | +tau = 0.95 / L |
| 61 | +eps = 5e-3 |
50 | 62 | maxit = 100 |
51 | 63 |
|
| 64 | +# IHT |
| 65 | +l0 = pyproximal.proximal.L0Ball(3) |
| 66 | +l2 = pyproximal.proximal.L2(Op=Aop, b=y) |
| 67 | +costf1 = [] |
| 68 | +x_iht = pyproximal.optimization.primal.ProximalGradient(l2, l0, tau=tau, x0=np.zeros(M), |
| 69 | + epsg=eps, niter=maxit, acceleration='fista', show=False) |
| 70 | + |
52 | 71 | # ISTA |
53 | | -x_ista, niteri, costi = \ |
54 | | - pylops.optimization.sparsity.ista(Aop, y, niter=maxit, eps=eps, tol=1e-10, |
55 | | - show=False) |
| 72 | +l1 = pyproximal.proximal.L1() |
| 73 | +l2 = pyproximal.proximal.L2(Op=Aop, b=y) |
| 74 | +costi = [] |
| 75 | +x_ista = \ |
| 76 | + pyproximal.optimization.primal.ProximalGradient(l2, l1, tau=tau, x0=np.zeros(M), |
| 77 | + epsg=eps, niter=maxit, show=False, |
| 78 | + callback=lambda x: callback(x, l2, l1, eps, costi)) |
| 79 | +niteri = len(costi) |
56 | 80 |
|
57 | 81 | # FISTA |
58 | | -x_fista, niterf, costf = \ |
59 | | - pylops.optimization.sparsity.fista(Aop, y, niter=maxit, eps=eps, |
60 | | - tol=1e-10, show=False) |
| 82 | +l1 = pyproximal.proximal.L1() |
| 83 | +l2 = pyproximal.proximal.L2(Op=Aop, b=y) |
| 84 | +costf = [] |
| 85 | +x_fista = \ |
| 86 | + pyproximal.optimization.primal.ProximalGradient(l2, l1, tau=tau, x0=np.zeros(M), |
| 87 | + epsg=eps, niter=maxit, acceleration='fista', show=False, |
| 88 | + callback=lambda x: callback(x, l2, l1, eps, costf)) |
| 89 | +niterf = len(costf) |
61 | 90 |
|
62 | 91 | # TWIST (Note that since the smallest eigenvalue is zero, we arbitrarily |
63 | 92 | # choose a small value for the solver to converge stably) |
|
73 | 102 | m, s, b = ax.stem(x, linefmt='k', basefmt='k', |
74 | 103 | markerfmt='ko', label='True') |
75 | 104 | plt.setp(m, markersize=10) |
| 105 | +m, s, b = ax.stem(x_iht, linefmt='--c', basefmt='--c', |
| 106 | + markerfmt='co', label='IHT') |
| 107 | +plt.setp(m, markersize=10) |
76 | 108 | m, s, b = ax.stem(x_ista, linefmt='--r', basefmt='--r', |
77 | 109 | markerfmt='ro', label='ISTA') |
78 | 110 | plt.setp(m, markersize=7) |
|
95 | 127 | ax.legend() |
96 | 128 | ax.grid(True, which='both') |
97 | 129 | plt.tight_layout() |
| 130 | + |
| 131 | +############################################################################### |
| 132 | +# To conclude, given the nature of the problem (small number of non-zero coefficients), |
| 133 | +# the IHT solver shows the fastest convergence - note that we do not display the |
| 134 | +# cost function since this is a constrained problem. This is however greatly influenced |
| 135 | +# by the fact that we assume exact knowledge of the number of non-zero coefficients. |
| 136 | +# When this information is not available, IHT may become suboptimal. In this case the |
| 137 | +# FISTA solver should always be preferred (over ISTA) and TwIST represents an |
| 138 | +# alternative worth checking. |
| 139 | + |
0 commit comments