def test_01(self): N = 32 M = 16 L = 8 D = np.random.randn(L, L, M) S = np.random.randn(N, N) cri = cnvrep.CSC_ConvRepIndexing(D, S, dimK=0) assert cri.M == M assert cri.K == 1 assert cri.Nv == (N, N) assert str(cri) != '' W = np.random.randn(N, N) assert cnvrep.l1Wshape(W, cri) == (N, N, 1, 1, 1) W = np.random.randn(N, N, M) assert cnvrep.l1Wshape(W, cri) == (N, N, 1, 1, M) W = np.random.randn(N, N, 1, 1, M) assert cnvrep.l1Wshape(W, cri) == (N, N, 1, 1, M)
def __init__(self, D, S, lmbda=None, W=None, opt=None, nproc=None, ngrp=None, dimK=None, dimN=2): """ Parameters ---------- D : array_like Dictionary matrix S : array_like Signal vector or matrix lmbda : float Regularisation parameter W : array_like Mask array. The array shape must be such that the array is compatible for multiplication with input array S (see :func:`.cnvrep.mskWshape` for more details). opt : :class:`ParConvBPDN.Options` object Algorithm options nproc : int Number of processes ngrp : int Number of groups in partition of filter indices dimK : 0, 1, or None, optional (default None) Number of dimensions in input signal corresponding to multiple independent signals dimN : int, optional (default 2) Number of spatial dimensions """ self.pool = None # Set default options if none specified if opt is None: opt = ParConvBPDN.Options() # Set dtype attribute based on S.dtype and opt['DataType'] self.set_dtype(opt, S.dtype) # Set default lambda value if not specified if lmbda is None: cri = cr.CSC_ConvRepIndexing(D, S, dimK=dimK, dimN=dimN) Df = sl.rfftn(D.reshape(cri.shpD), cri.Nv, axes=cri.axisN) Sf = sl.rfftn(S.reshape(cri.shpS), axes=cri.axisN) b = np.conj(Df) * Sf lmbda = 0.1*abs(b).max() # Set l1 term scaling and weight array self.lmbda = self.dtype.type(lmbda) # Set penalty parameter self.set_attr('rho', opt['rho'], dval=(50.0*self.lmbda + 1.0), dtype=self.dtype) self.set_attr('alpha', opt['alpha'], dval=1.0, dtype=self.dtype) # Set rho_xi attribute (see Sec. VI.C of wohlberg-2015-adaptive) # if self.lmbda != 0.0: # rho_xi = (1.0 + (18.3)**(np.log10(self.lmbda) + 1.0)) # else: # rho_xi = 1.0 # self.set_attr('rho_xi', opt['AutoRho', 'RsdlTarget'], dval=rho_xi, # dtype=self.dtype) # Call parent class __init__ super(ParConvBPDN, self).__init__(D, S, opt, dimK, dimN) if nproc is None: if ngrp is None: self.nproc = min(mp.cpu_count(), self.cri.M) self.ngrp = self.nproc else: self.nproc = min(mp.cpu_count(), ngrp, self.cri.M) self.ngrp = ngrp else: if ngrp is None: self.ngrp = nproc self.nproc = nproc else: self.ngrp = ngrp self.nproc = nproc if W is None: W = np.array([1.0], dtype=self.dtype) self.W = np.asarray(W.reshape(cr.mskWshape(W, self.cri)), dtype=self.dtype) self.wl1 = np.asarray(opt['L1Weight'], dtype=self.dtype) self.wl1 = self.wl1.reshape(cr.l1Wshape(self.wl1, self.cri)) self.xrrs = None # Initialise global variables # Conv Rep Indexing and parameter values for multiprocessing global mp_nproc mp_nproc = self.nproc global mp_ngrp mp_ngrp = self.ngrp global mp_Nv mp_Nv = self.cri.Nv global mp_axisN mp_axisN = tuple(i+1 for i in self.cri.axisN) global mp_C mp_C = self.cri.C global mp_Cd mp_Cd = self.cri.Cd global mp_axisC mp_axisC = self.cri.axisC+1 global mp_axisM mp_axisM = 0 global mp_NonNegCoef mp_NonNegCoef = self.opt['NonNegCoef'] global mp_NoBndryCross mp_NoBndryCross = self.opt['NoBndryCross'] global mp_Dshp mp_Dshp = self.D.shape # Parameters for optimization global mp_lmbda mp_lmbda = self.lmbda global mp_rho mp_rho = self.rho global mp_alpha mp_alpha = self.alpha global mp_rlx mp_rlx = self.rlx global mp_wl1 init_mpraw('mp_wl1', np.moveaxis(self.wl1, self.cri.axisM, mp_axisM)) # Matrices used in optimization global mp_S init_mpraw('mp_S', np.moveaxis(self.S*self.W**2, self.cri.axisM, mp_axisM)) global mp_Df init_mpraw('mp_Df', np.moveaxis(self.Df, self.cri.axisM, mp_axisM)) global mp_X init_mpraw('mp_X', np.moveaxis(self.Y, self.cri.axisM, mp_axisM)) shp_X = list(mp_X.shape) global mp_Xnr mp_Xnr = mpraw_as_np(mp_X.shape, mp_X.dtype) global mp_Y0 shp_Y0 = shp_X[:] shp_Y0[0] = self.ngrp shp_Y0[mp_axisC] = mp_C if self.opt['Y0'] is not None: init_mpraw('Y0', np.moveaxis( self.opt['Y0'].astype(self.dtype, copy=True), self.cri.axisM, mp_axisM)) else: mp_Y0 = mpraw_as_np(shp_Y0, mp_X.dtype) global mp_Y0old mp_Y0old = mpraw_as_np(shp_Y0, mp_X.dtype) global mp_Y1 if self.opt['Y1'] is not None: init_mpraw('Y1', np.moveaxis( self.opt['Y1'].astype(self.dtype, copy=True), self.cri.axisM, mp_axisM)) else: mp_Y1 = mpraw_as_np(shp_X, mp_X.dtype) global mp_Y1old mp_Y1old = mpraw_as_np(shp_X, mp_X.dtype) global mp_U0 if self.opt['U0'] is not None: init_mpraw('U0', np.moveaxis( self.opt['U0'].astype(self.dtype, copy=True), self.cri.axisM, mp_axisM)) else: mp_U0 = mpraw_as_np(shp_Y0, mp_X.dtype) global mp_U1 if self.opt['U1'] is not None: init_mpraw('U1', np.moveaxis( self.opt['U1'].astype(self.dtype, copy=True), self.cri.axisM, mp_axisM)) else: mp_U1 = mpraw_as_np(shp_X, mp_X.dtype) global mp_DX mp_DX = mpraw_as_np(shp_Y0, mp_X.dtype) global mp_DXnr mp_DXnr = mpraw_as_np(shp_Y0, mp_X.dtype) # Variables used to solve the optimization efficiently global mp_inv_off_diag if self.W.ndim is self.cri.axisM+1: init_mpraw('mp_inv_off_diag', np.moveaxis( -self.W**2/(mp_rho*(mp_rho+self.W**2*mp_ngrp)), self.cri.axisM, mp_axisM)) else: init_mpraw('mp_inv_off_diag', -self.W**2/(mp_rho*(mp_rho+self.W**2*mp_ngrp))) global mp_grp mp_grp = [np.min(i) for i in np.array_split(np.array(range(self.cri.M)), mp_ngrp)] + [self.cri.M, ] global mp_cache if self.opt['HighMemSolve'] and self.cri.Cd == 1: mp_cache = [sl.solvedbi_sm_c(mp_Df[k], np.conj(mp_Df[k]), mp_alpha**2, mp_axisM) for k in np.array_split(np.array(range(self.cri.M)), self.ngrp)] else: mp_cache = [None for k in mp_grp] global mp_b shp_b = shp_Y0[:] shp_b[0] = 1 mp_b = mpraw_as_np(shp_b, mp_X.dtype) # Residual and stopping criteria variables global mp_ry0 mp_ry0 = mpraw_as_np((self.ngrp,), mp_X.dtype) global mp_ry1 mp_ry1 = mpraw_as_np((self.ngrp,), mp_X.dtype) global mp_sy0 mp_sy0 = mpraw_as_np((self.ngrp,), mp_X.dtype) global mp_sy1 mp_sy1 = mpraw_as_np((self.ngrp,), mp_X.dtype) global mp_nrmAx mp_nrmAx = mpraw_as_np((self.ngrp,), mp_X.dtype) global mp_nrmBy mp_nrmBy = mpraw_as_np((self.ngrp,), mp_X.dtype) global mp_nrmu mp_nrmu = mpraw_as_np((self.ngrp,), mp_X.dtype)
def __init__(self, D, S, lmbda=None, opt=None, dimK=None, dimN=2): """ This class supports an arbitrary number of spatial dimensions, `dimN`, with a default of 2. The input dictionary `D` is either `dimN` + 1 dimensional, in which case each spatial component (image in the default case) is assumed to consist of a single channel, or `dimN` + 2 dimensional, in which case the final dimension is assumed to contain the channels (e.g. colour channels in the case of images). The input signal set `S` is either `dimN` dimensional (no channels, only one signal), `dimN` + 1 dimensional (either multiple channels or multiple signals), or `dimN` + 2 dimensional (multiple channels and multiple signals). Determination of problem dimensions is handled by :class:`.cnvrep.CSC_ConvRepIndexing`. | **Call graph** .. image:: ../_static/jonga/cbpdn_init.svg :width: 20% :target: ../_static/jonga/cbpdn_init.svg | Parameters ---------- D : array_like Dictionary array S : array_like Signal array lmbda : float Regularisation parameter opt : :class:`ConvBPDN.Options` object Algorithm options dimK : 0, 1, or None, optional (default None) Number of dimensions in input signal corresponding to multiple independent signals dimN : int, optional (default 2) Number of spatial/temporal dimensions """ # Set default options if none specified if opt is None: opt = ComplexConvBPDN.Options() # Set dtype attribute based on S.dtype and opt['DataType'] self.set_dtype(opt, S.dtype) # Set default lambda value if not specified if lmbda is None: cri = cr.CSC_ConvRepIndexing(D, S, dimK=dimK, dimN=dimN) Df = fftn(D.reshape(cri.shpD), cri.Nv, axes=cri.axisN) Sf = fftn(S.reshape(cri.shpS), axes=cri.axisN) b = np.conj(Df) * Sf lmbda = 0.1 * abs(b).max() # Set l1 term scaling self.lmbda = self.dtype.type(lmbda) # Set penalty parameter self.set_attr('rho', opt['rho'], dval=(50.0 * self.lmbda + 1.0), dtype=self.dtype) # Set rho_xi attribute (see Sec. VI.C of wohlberg-2015-adaptive) if self.lmbda != 0.0: # rho_xi = float((1.0 + (18.3)**(np.log10(self.lmbda) + 1.0))) rho_xi = (1.0 + (18.3) ** (np.log10(self.lmbda) + 1.0)) else: rho_xi = 1.0 self.set_attr('rho_xi', opt['AutoRho', 'RsdlTarget'], dval=rho_xi, dtype=self.dtype) # Call parent class __init__ super(ComplexConvBPDN, self).__init__(D, S, opt, dimK, dimN) # Set l1 term weight array self.wl1 = np.asarray(opt['L1Weight'], dtype=self.dtype) self.wl1 = self.wl1.reshape(cr.l1Wshape(self.wl1, self.cri))
def __init__(self, D, S, lmbda, mu=0.0, opt=None, dimK=None, dimN=2): """ | **Call graph** .. image:: ../_static/jonga/cbpdnrtv_init.svg :width: 20% :target: ../_static/jonga/cbpdnrtv_init.svg | Parameters ---------- D : array_like Dictionary matrix S : array_like Signal vector or matrix lmbda : float Regularisation parameter (l1) mu : float Regularisation parameter (gradient) opt : :class:`ConvBPDNRecTV.Options` object Algorithm options dimK : 0, 1, or None, optional (default None) Number of dimensions in input signal corresponding to multiple independent signals dimN : int, optional (default 2) Number of spatial dimensions """ if opt is None: opt = ConvBPDNRecTV.Options() # Infer problem dimensions and set relevant attributes of self self.cri = cr.CSC_ConvRepIndexing(D, S, dimK=dimK, dimN=dimN) # Call parent class __init__ Nx = np.product(np.array(self.cri.shpX)) yshape = list(self.cri.shpX) yshape[self.cri.axisM] += len(self.cri.axisN) * self.cri.Cd super(ConvBPDNRecTV, self).__init__(Nx, yshape, yshape, S.dtype, opt) # Set l1 term scaling and weight array self.lmbda = self.dtype.type(lmbda) self.Wl1 = np.asarray(opt['L1Weight'], dtype=self.dtype) self.Wl1 = self.Wl1.reshape(cr.l1Wshape(self.Wl1, self.cri)) self.mu = self.dtype.type(mu) if hasattr(opt['TVWeight'], 'ndim') and opt['TVWeight'].ndim > 0: self.Wtv = np.asarray( opt['TVWeight'].reshape((1, ) * (dimN + 2) + opt['TVWeight'].shape), dtype=self.dtype) else: # Wtv is a scalar: no need to change shape self.Wtv = self.dtype.type(opt['TVWeight']) # Set penalty parameter self.set_attr('rho', opt['rho'], dval=(50.0 * self.lmbda + 1.0), dtype=self.dtype) # Set rho_xi attribute self.set_attr('rho_xi', opt['AutoRho', 'RsdlTarget'], dval=1.0, dtype=self.dtype) # Reshape D and S to standard layout self.D = np.asarray(D.reshape(self.cri.shpD), dtype=self.dtype) self.S = np.asarray(S.reshape(self.cri.shpS), dtype=self.dtype) # Compute signal in DFT domain self.Sf = sl.rfftn(self.S, None, self.cri.axisN) self.Gf, GHGf = sl.gradient_filters(self.cri.dimN + 3, self.cri.axisN, self.cri.Nv, dtype=self.dtype) # Initialise byte-aligned arrays for pyfftw self.YU = sl.pyfftw_empty_aligned(self.Y.shape, dtype=self.dtype) self.Xf = sl.pyfftw_rfftn_empty_aligned(self.cri.shpX, self.cri.axisN, self.dtype) self.setdict()
def __init__(self, D, S, lmbda, mu=0.0, opt=None, dimK=None, dimN=2): """ | **Call graph** .. image:: ../_static/jonga/cbpdnrtv_init.svg :width: 20% :target: ../_static/jonga/cbpdnrtv_init.svg | Parameters ---------- D : array_like Dictionary matrix S : array_like Signal vector or matrix lmbda : float Regularisation parameter (l1) mu : float Regularisation parameter (gradient) opt : :class:`ConvBPDNRecTV.Options` object Algorithm options dimK : 0, 1, or None, optional (default None) Number of dimensions in input signal corresponding to multiple independent signals dimN : int, optional (default 2) Number of spatial dimensions """ if opt is None: opt = ConvBPDNRecTV.Options() # Infer problem dimensions and set relevant attributes of self self.cri = cr.CSC_ConvRepIndexing(D, S, dimK=dimK, dimN=dimN) # Call parent class __init__ Nx = np.product(np.array(self.cri.shpX)) yshape = list(self.cri.shpX) yshape[self.cri.axisM] += len(self.cri.axisN) * self.cri.Cd super(ConvBPDNRecTV, self).__init__(Nx, yshape, yshape, S.dtype, opt) # Set l1 term scaling and weight array self.lmbda = self.dtype.type(lmbda) self.Wl1 = np.asarray(opt['L1Weight'], dtype=self.dtype) self.Wl1 = self.Wl1.reshape(cr.l1Wshape(self.Wl1, self.cri)) self.mu = self.dtype.type(mu) if hasattr(opt['TVWeight'], 'ndim') and opt['TVWeight'].ndim > 0: self.Wtv = np.asarray(opt['TVWeight'].reshape( (1,)*(dimN + 2) + opt['TVWeight'].shape), dtype=self.dtype) else: # Wtv is a scalar: no need to change shape self.Wtv = self.dtype.type(opt['TVWeight']) # Set penalty parameter self.set_attr('rho', opt['rho'], dval=(50.0*self.lmbda + 1.0), dtype=self.dtype) # Set rho_xi attribute self.set_attr('rho_xi', opt['AutoRho', 'RsdlTarget'], dval=1.0, dtype=self.dtype) # Reshape D and S to standard layout self.D = np.asarray(D.reshape(self.cri.shpD), dtype=self.dtype) self.S = np.asarray(S.reshape(self.cri.shpS), dtype=self.dtype) # Compute signal in DFT domain self.Sf = sl.rfftn(self.S, None, self.cri.axisN) self.Gf, GHGf = sl.GradientFilters(self.cri.dimN+3, self.cri.axisN, self.cri.Nv, dtype=self.dtype) # Initialise byte-aligned arrays for pyfftw self.YU = sl.pyfftw_empty_aligned(self.Y.shape, dtype=self.dtype) self.Xf = sl.pyfftw_rfftn_empty_aligned(self.cri.shpX, self.cri.axisN, self.dtype) self.setdict()