def test_08(self): N = 32 M = 16 L = 8 dsz = (L, L, M) S = np.random.randn(N, N) cri = cnvrep.CDU_ConvRepIndexing(dsz, 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.mskWshape(W, cri) == (N, N, 1, 1, 1)
def init_vars(self, S, dimK): """Initalise variables required for sparse coding and dictionary update for training data `S`.""" Nv = S.shape[0:self.dimN] if self.cri is None or Nv != self.cri.Nv: self.cri = cr.CDU_ConvRepIndexing(self.dsz, S, dimK, self.dimN) if self.opt['CUDA_CBPDN']: if self.cri.Cd > 1 or self.cri.Cx > 1: raise ValueError('CUDA CBPDN solver can only be used for ' 'single channel problems') # self.Df = sl.pyfftw_byte_aligned(sl.rfftn(self.D, self.cri.Nv, # self.cri.axisN)) self.Df = pyfftw.byte_align(sl.rfftn(self.D, self.cri.Nv, self.cri.axisN)) self.Gf = sl.pyfftw_empty_aligned(self.Df.shape, self.Df.dtype) self.Z = sl.pyfftw_empty_aligned(self.cri.shpX, self.dtype) else: self.Df[:] = sl.rfftn(self.D, self.cri.Nv, self.cri.axisN)
def __init__(self, Z, S, dsz, opt=None, dimK=1, dimN=2): """ | **Call graph** .. image:: ../_static/jonga/ccmodcnsns_init.svg :width: 20% :target: ../_static/jonga/ccmodcnsns_init.svg """ # Set default options if none specified if opt is None: opt = ConvCnstrMOD_Consensus.Options() # Infer problem dimensions and set relevant attributes of self self.cri = cr.CDU_ConvRepIndexing(dsz, S, dimK=dimK, dimN=dimN) # Handle possible reshape of channel axis onto multiple image axis # (see comment below) Nb = self.cri.K if self.cri.C == self.cri.Cd else \ self.cri.C * self.cri.K admm.ADMMConsensus.__init__(self, Nb, self.cri.shpD, S.dtype, opt) # Set penalty parameter self.set_attr('rho', opt['rho'], dval=self.cri.K, dtype=self.dtype) # Reshape S to standard layout (Z, i.e. X in cbpdn, is assumed # to be taken from cbpdn, and therefore already in standard # form). If the dictionary has a single channel but the input # (and therefore also the coefficient map array) has multiple # channels, the channel index and multiple image index have # the same behaviour in the dictionary update equation: the # simplest way to handle this is to just reshape so that the # channels also appear on the multiple image index. if self.cri.Cd == 1 and self.cri.C > 1: self.S = S.reshape(self.cri.Nv + (1, ) + (self.cri.C * self.cri.K, ) + (1, )) else: self.S = S.reshape(self.cri.shpS) self.S = np.asarray(self.S, dtype=self.dtype) # Compute signal S in DFT domain self.Sf = sl.rfftn(self.S, None, self.cri.axisN) # Create constraint set projection function self.Pcn = cr.getPcn(dsz, self.cri.Nv, self.cri.dimN, self.cri.dimCd, zm=opt['ZeroMean']) if Z is not None: self.setcoef(Z) self.X = sl.pyfftw_empty_aligned(self.xshape, dtype=self.dtype) # See comment on corresponding test in xstep method if self.cri.Cd > 1: self.YU = sl.pyfftw_empty_aligned(self.yshape, dtype=self.dtype) else: self.YU = sl.pyfftw_empty_aligned(self.xshape, dtype=self.dtype) self.Xf = sl.pyfftw_rfftn_empty_aligned(self.xshape, self.cri.axisN, self.dtype)
def __init__(self, Z, S, dsz, opt=None, dimK=1, dimN=2): """ This class supports an arbitrary number of spatial dimensions, `dimN`, with a default of 2. The input coefficient map array `Z` (usually labelled X, but renamed here to avoid confusion with the X and Y variables in the ADMM base class) is expected to be in standard form as computed by the ConvBPDN class. 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). Parameter `dimK`, with a default value of 1, indicates the number of multiple-signal dimensions in `S`: :: Default dimK = 1, i.e. assume input S is of form S(N0, N1, C, K) or S(N0, N1, K) If dimK = 0 then input S is of form S(N0, N1, C, K) or S(N0, N1, C) The internal data layout for S, D (X here), and X (Z here) is: :: dim<0> - dim<Nds-1> : Spatial dimensions, product of N0,N1,... is N dim<Nds> : C number of channels in S and D dim<Nds+1> : K number of signals in S dim<Nds+2> : M number of filters in D sptl. chn sig flt S(N0, N1, C, K, 1) D(N0, N1, C, 1, M) (X here) X(N0, N1, 1, K, M) (Z here) The `dsz` parameter indicates the desired filter supports in the output dictionary, since this cannot be inferred from the input variables. The format is the same as the `dsz` parameter of :func:`.cnvrep.bcrop`. Parameters ---------- Z : array_like Coefficient map array S : array_like Signal array dsz : tuple Filter support size(s) opt : ccmod.Options object Algorithm options dimK : int, optional (default 1) Number of dimensions for multiple signals in input S dimN : int, optional (default 2) Number of spatial dimensions """ # Set default options if none specified if opt is None: opt = ConvCnstrMODBase.Options() # Infer problem dimensions and set relevant attributes of self self.cri = cr.CDU_ConvRepIndexing(dsz, S, dimK=dimK, dimN=dimN) # Call parent class __init__ super(ConvCnstrMODBase, self).__init__(self.cri.shpD, S.dtype, opt) # Set penalty parameter self.set_attr('rho', opt['rho'], dval=self.cri.K, dtype=self.dtype) # Reshape S to standard layout (Z, i.e. X in cbpdn, is assumed # to be taken from cbpdn, and therefore already in standard # form). If the dictionary has a single channel but the input # (and therefore also the coefficient map array) has multiple # channels, the channel index and multiple image index have # the same behaviour in the dictionary update equation: the # simplest way to handle this is to just reshape so that the # channels also appear on the multiple image index. if self.cri.Cd == 1 and self.cri.C > 1: self.S = S.reshape(self.cri.Nv + (1, ) + (self.cri.C * self.cri.K, ) + (1, )) else: self.S = S.reshape(self.cri.shpS) self.S = np.asarray(self.S, dtype=self.dtype) # Compute signal S in DFT domain self.Sf = sl.rfftn(self.S, None, self.cri.axisN) # Create constraint set projection function self.Pcn = cr.getPcn(dsz, self.cri.Nv, self.cri.dimN, self.cri.dimCd, zm=opt['ZeroMean']) # Create byte aligned arrays for FFT calls self.YU = sl.pyfftw_empty_aligned(self.Y.shape, dtype=self.dtype) self.Xf = sl.pyfftw_rfftn_empty_aligned(self.Y.shape, self.cri.axisN, self.dtype) if Z is not None: self.setcoef(Z)
sl, sh = signal.tikhonov_filter(S, fltlmbd, npd) """ Construct initial dictionary. """ np.random.seed(12345) D0 = np.random.randn(8, 8, 64) """ Construct object representing problem dimensions. """ cri = cnvrep.CDU_ConvRepIndexing(D0.shape, sh) """ Define X and D update options. """ lmbda = 0.2 mu = 0.1 optx = cbpdn.ConvBPDNJoint.Options({'Verbose': False, 'MaxMainIter': 1, 'rho': 50.0*lmbda + 0.5, 'AutoRho': {'Period': 10, 'AutoScaling': False, 'RsdlRatio': 10.0, 'Scaling': 2.0, 'RsdlTarget': 1.0}}) optd = ccmod.ConvCnstrMODOptions({'Verbose': False, 'MaxMainIter': 1, 'rho': 10.0*cri.K, 'AutoRho': {'Period': 10, 'AutoScaling': False, 'RsdlRatio': 10.0, 'Scaling': 2.0, 'RsdlTarget': 1.0}},
def __init__(self, Z, S, W, dsz, opt=None, dimK=None, dimN=2): """ Initialise a ConvCnstrMODMaskDcplBase object with problem size and options. Parameters ---------- Z : array_like Coefficient map array S : array_like Signal array 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). dsz : tuple Filter support size(s) opt : :class:`ConvCnstrMODMaskDcplBase.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 """ # Set default options if none specified if opt is None: opt = ConvCnstrMODMaskDcplBase.Options() # Infer problem dimensions and set relevant attributes of self self.cri = cr.CDU_ConvRepIndexing(dsz, S, dimK=dimK, dimN=dimN) # Convert W to internal shape W = np.asarray(W.reshape(cr.mskWshape(W, self.cri)), dtype=S.dtype) # Reshape W if necessary (see discussion of reshape of S below) if self.cri.Cd == 1 and self.cri.C > 1: # In most cases broadcasting rules make it possible for W # to have a singleton dimension corresponding to a non-singleton # dimension in S. However, when S is reshaped to interleave axisC # and axisK on the same axis, broadcasting is no longer sufficient # unless axisC and axisK of W are either both singleton or both # of the same size as the corresponding axes of S. If neither of # these cases holds, it is necessary to replicate the axis of W # (axisC or axisK) that does not have the same size as the # corresponding axis of S. shpw = list(W.shape) swck = shpw[self.cri.axisC] * shpw[self.cri.axisK] if swck > 1 and swck < self.cri.C * self.cri.K: if W.shape[self.cri.axisK] == 1 and self.cri.K > 1: shpw[self.cri.axisK] = self.cri.K else: shpw[self.cri.axisC] = self.cri.C W = np.broadcast_to(W, shpw) self.W = W.reshape(W.shape[0:self.cri.dimN] + (1, W.shape[self.cri.axisC] * W.shape[self.cri.axisK], 1)) else: self.W = W # Call parent class __init__ Nx = self.cri.N * self.cri.Cd * self.cri.M CK = (self.cri.C if self.cri.Cd == 1 else 1) * self.cri.K shpY = list(self.cri.shpX) shpY[self.cri.axisC] = self.cri.Cd shpY[self.cri.axisK] = 1 shpY[self.cri.axisM] += CK super(ConvCnstrMODMaskDcplBase, self).__init__(Nx, shpY, self.cri.axisM, CK, S.dtype, opt) # Reshape S to standard layout (Z, i.e. X in cbpdn, is assumed # to be taken from cbpdn, and therefore already in standard # form). If the dictionary has a single channel but the input # (and therefore also the coefficient map array) has multiple # channels, the channel index and multiple image index have # the same behaviour in the dictionary update equation: the # simplest way to handle this is to just reshape so that the # channels also appear on the multiple image index. if self.cri.Cd == 1 and self.cri.C > 1: self.S = S.reshape(self.cri.Nv + (1, self.cri.C * self.cri.K, 1)) else: self.S = S.reshape(self.cri.shpS) self.S = np.asarray(self.S, dtype=self.dtype) # Create constraint set projection function self.Pcn = cr.getPcn(dsz, self.cri.Nv, self.cri.dimN, self.cri.dimCd, zm=opt['ZeroMean']) # Initialise byte-aligned arrays for pyfftw self.YU = sl.pyfftw_empty_aligned(self.Y.shape, dtype=self.dtype) xfshp = list(self.cri.Nv + (self.cri.Cd, 1, self.cri.M)) xfshp[dimN - 1] = xfshp[dimN - 1] // 2 + 1 self.Xf = sl.pyfftw_empty_aligned(xfshp, dtype=sl.complex_dtype(self.dtype)) if Z is not None: self.setcoef(Z)
def __init__(self, D0, S, lmbda, W, opt=None, xmethod=None, dmethod=None, dimK=1, dimN=2): """ | **Call graph** .. image:: ../_static/jonga/cbpdnmddl_init.svg :width: 20% :target: ../_static/jonga/cbpdnmddl_init.svg | Parameters ---------- D0 : array_like Initial dictionary array S : array_like Signal array lmbda : float Regularisation parameter W : array_like Mask array. The array shape must be such that the array is compatible for multiplication with the *internal* shape of input array S (see :class:`.cnvrep.CDU_ConvRepIndexing` for a discussion of the distinction between *external* and *internal* data layouts) after reshaping to the shape determined by :func:`.cnvrep.mskWshape`. opt : :class:`ConvBPDNMaskDictLearn.Options` object Algorithm options xmethod : string, optional (default 'admm') String selecting sparse coding solver. Valid values are documented in function :func:`.ConvBPDNMask`. dmethod : string, optional (default 'pgm') String selecting dictionary update solver. Valid values are documented in function :func:`.ConvCnstrMODMask`. dimK : int, optional (default 1) Number of signal dimensions. If there is only a single input signal (e.g. if `S` is a 2D array representing a single image) `dimK` must be set to 0. dimN : int, optional (default 2) Number of spatial/temporal dimensions """ if opt is None: opt = ConvBPDNMaskDictLearn.Options(xmethod=xmethod, dmethod=dmethod) if xmethod is None: xmethod = opt.xmethod if dmethod is None: dmethod = opt.dmethod if opt.xmethod != xmethod or opt.dmethod != dmethod: raise ValueError('Parameters xmethod and dmethod must have the ' 'same values used to initialise the Options ' 'object') self.opt = opt self.xmethod = xmethod self.dmethod = dmethod # Get dictionary size if self.opt['DictSize'] is None: dsz = D0.shape else: dsz = self.opt['DictSize'] # Construct object representing problem dimensions cri = cr.CDU_ConvRepIndexing(dsz, S, dimK, dimN) # Normalise dictionary D0 = cr.Pcn(D0, dsz, cri.Nv, dimN, cri.dimCd, crp=True, zm=opt['CCMOD', 'ZeroMean']) # Modify D update options to include initial values for Y if cri.C == cri.Cd: Y0b0 = np.zeros(cri.Nv + (cri.C, 1, cri.K)) else: Y0b0 = np.zeros(cri.Nv + (1, 1, cri.C * cri.K)) Y0b1 = cr.zpad(cr.stdformD(D0, cri.Cd, cri.M, dimN), cri.Nv) if dmethod == 'pgm': opt['CCMOD'].update({'X0': Y0b1}) else: if dmethod == 'cns': Y0 = Y0b1 else: Y0 = np.concatenate((Y0b0, Y0b1), axis=cri.axisM) opt['CCMOD'].update({'Y0': Y0}) # Create X update object xstep = ConvBPDNMask(D0, S, lmbda, W, opt['CBPDN'], method=xmethod, dimK=dimK, dimN=dimN) # Create D update object dstep = ConvCnstrMODMask(None, S, W, dsz, opt['CCMOD'], method=dmethod, dimK=dimK, dimN=dimN) # Configure iteration statistics reporting isc = dictlrn.IterStatsConfig(isfld=dc.isfld(xmethod, dmethod, opt), isxmap=dc.isxmap(xmethod, opt), isdmap=dc.isdmap(dmethod), evlmap=dc.evlmap(opt['AccurateDFid']), hdrtxt=dc.hdrtxt(xmethod, dmethod, opt), hdrmap=dc.hdrmap(xmethod, dmethod, opt), fmtmap={ 'It_X': '%4d', 'It_D': '%4d' }) # Call parent constructor super(ConvBPDNMaskDictLearn, self).__init__(xstep, dstep, opt, isc)
def __init__(self, D0, S, lmbda=None, opt=None, xmethod=None, dmethod=None, dimK=1, dimN=2): """ | **Call graph** .. image:: ../_static/jonga/cbpdndl_init.svg :width: 20% :target: ../_static/jonga/cbpdndl_init.svg | Parameters ---------- D0 : array_like Initial dictionary array S : array_like Signal array lmbda : float Regularisation parameter opt : :class:`ConvBPDNDictLearn.Options` object Algorithm options xmethod : string, optional (default 'admm') String selecting sparse coding solver. Valid values are documented in function :func:`.ConvBPDN`. dmethod : string, optional (default 'fista') String selecting dictionary update solver. Valid values are documented in function :func:`.ConvCnstrMOD`. dimK : int, optional (default 1) Number of signal dimensions. If there is only a single input signal (e.g. if `S` is a 2D array representing a single image) `dimK` must be set to 0. dimN : int, optional (default 2) Number of spatial/temporal dimensions """ if opt is None: opt = ConvBPDNDictLearn.Options(xmethod=xmethod, dmethod=dmethod) if xmethod is None: xmethod = opt.xmethod if dmethod is None: dmethod = opt.dmethod if opt.xmethod != xmethod or opt.dmethod != dmethod: raise ValueError('Parameters xmethod and dmethod must have the ' 'same values used to initialise the Options ' 'object') self.opt = opt self.xmethod = xmethod self.dmethod = dmethod # Get dictionary size if self.opt['DictSize'] is None: dsz = D0.shape else: dsz = self.opt['DictSize'] # Construct object representing problem dimensions cri = cr.CDU_ConvRepIndexing(dsz, S, dimK, dimN) # Normalise dictionary D0 = cr.Pcn(D0, dsz, cri.Nv, dimN, cri.dimCd, crp=True, zm=opt['CCMOD', 'ZeroMean']) # Modify D update options to include initial value for Y optname = 'X0' if dmethod == 'fista' else 'Y0' opt['CCMOD'].update( {optname: cr.zpad(cr.stdformD(D0, cri.Cd, cri.M, dimN), cri.Nv)}) # Create X update object xstep = ConvBPDN(D0, S, lmbda, opt['CBPDN'], method=xmethod, dimK=dimK, dimN=dimN) # Create D update object dstep = ConvCnstrMOD(None, S, dsz, opt['CCMOD'], method=dmethod, dimK=dimK, dimN=dimN) # Configure iteration statistics reporting isc = dictlrn.IterStatsConfig(isfld=dc.isfld(xmethod, dmethod, opt), isxmap=dc.isxmap(xmethod, opt), isdmap=dc.isdmap(dmethod), evlmap=dc.evlmap(opt['AccurateDFid']), hdrtxt=dc.hdrtxt(xmethod, dmethod, opt), hdrmap=dc.hdrmap(xmethod, dmethod, opt), fmtmap={ 'It_X': '%4d', 'It_D': '%4d' }) # Call parent constructor super(ConvBPDNDictLearn, self).__init__(xstep, dstep, opt, isc)
def __init__(self, Z, S, W, dsz, opt=None, dimK=None, dimN=2): """ | **Call graph** .. image:: ../_static/jonga/ccmodmdfista_init.svg :width: 20% :target: ../_static/jonga/ccmodmdfista_init.svg | Parameters ---------- Z : array_like Coefficient map array S : array_like Signal array W : array_like Mask array. The array shape must be such that the array is compatible for multiplication with the *internal* shape of input array S (see :class:`.cnvrep.CDU_ConvRepIndexing` for a discussion of the distinction between *external* and *internal* data layouts). dsz : tuple Filter support size(s) opt : :class:`ConvCnstrMODMasked.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 """ # Set default options if none specified if opt is None: opt = ConvCnstrMODMask.Options() # Infer problem dimensions and set relevant attributes of self self.cri = cr.CDU_ConvRepIndexing(dsz, S, dimK=dimK, dimN=dimN) # Append singleton dimensions to W if necessary if hasattr(W, 'ndim'): W = sl.atleast_nd(self.cri.dimN + 3, W) # Reshape W if necessary (see discussion of reshape of S in # ccmod base class) if self.cri.Cd == 1 and self.cri.C > 1 and hasattr(W, 'ndim'): # In most cases broadcasting rules make it possible for W # to have a singleton dimension corresponding to a # non-singleton dimension in S. However, when S is # reshaped to interleave axisC and axisK on the same axis, # broadcasting is no longer sufficient unless axisC and # axisK of W are either both singleton or both of the same # size as the corresponding axes of S. If neither of these # cases holds, it is necessary to replicate the axis of W # (axisC or axisK) that does not have the same size as the # corresponding axis of S. shpw = list(W.shape) swck = shpw[self.cri.axisC] * shpw[self.cri.axisK] if swck > 1 and swck < self.cri.C * self.cri.K: if W.shape[self.cri.axisK] == 1 and self.cri.K > 1: shpw[self.cri.axisK] = self.cri.K else: shpw[self.cri.axisC] = self.cri.C W = np.broadcast_to(W, shpw) self.W = W.reshape(W.shape[0:self.cri.dimN] + (1, W.shape[self.cri.axisC] * W.shape[self.cri.axisK], 1)) else: self.W = W super(ConvCnstrMODMask, self).__init__(Z, S, dsz, opt, dimK, dimN) # Create byte aligned arrays for FFT calls self.WRy = sl.pyfftw_empty_aligned(self.S.shape, dtype=self.dtype) self.Ryf = sl.pyfftw_rfftn_empty_aligned(self.S.shape, self.cri.axisN, self.dtype)
def __init__(self, D0, S, lmbda, W, opt=None, dimK=1, dimN=2): """ Initialise a MixConvBPDNMaskDcplDictLearn object with problem size and options. Parameters ---------- D0 : array_like Initial dictionary array S : array_like Signal array lmbda : float Regularisation parameter W : array_like Mask array. The array shape must be such that the array is compatible for multiplication with the *internal* shape of input array S (see :class:`.cnvrep.CDU_ConvRepIndexing` for a discussion of the distinction between *external* and *internal* data layouts). opt : :class:`MixConvBPDNMaskDcplDictLearn.Options` object Algorithm options dimK : int, optional (default 1) Number of signal dimensions. If there is only a single input signal (e.g. if `S` is a 2D array representing a single image) `dimK` must be set to 0. dimN : int, optional (default 2) Number of spatial/temporal dimensions """ if opt is None: opt = MixConvBPDNMaskDcplDictLearn.Options() self.opt = opt # Get dictionary size if self.opt['DictSize'] is None: dsz = D0.shape else: dsz = self.opt['DictSize'] # Construct object representing problem dimensions cri = cr.CDU_ConvRepIndexing(dsz, S, dimK, dimN) # Normalise dictionary D0 = cr.Pcn(D0, dsz, cri.Nv, dimN, cri.dimCd, crp=True, zm=opt['CCMOD', 'ZeroMean']) # Modify D update options to include initial values for X X0 = cr.zpad(cr.stdformD(D0, cri.Cd, cri.M, dimN), cri.Nv) opt['CCMOD'].update({'X0': X0}) # Create X update object xstep = Acbpdn.ConvBPDNMaskDcpl(D0, S, lmbda, W, opt['CBPDN'], dimK=dimK, dimN=dimN) # Create D update object dstep = ccmod.ConvCnstrMODMask(None, S, W, dsz, opt['CCMOD'], dimK=dimK, dimN=dimN) # Configure iteration statistics reporting if self.opt['AccurateDFid']: isxmap = { 'XPrRsdl': 'PrimalRsdl', 'XDlRsdl': 'DualRsdl', 'XRho': 'Rho' } evlmap = {'ObjFun': 'ObjFun', 'DFid': 'DFid', 'RegL1': 'RegL1'} else: isxmap = { 'ObjFun': 'ObjFun', 'DFid': 'DFid', 'RegL1': 'RegL1', 'XPrRsdl': 'PrimalRsdl', 'XDlRsdl': 'DualRsdl', 'XRho': 'Rho' } evlmap = {} if dstep.opt['BackTrack', 'Enabled']: isfld = [ 'Iter', 'ObjFun', 'DFid', 'RegL1', 'Cnstr', 'XPrRsdl', 'XDlRsdl', 'XRho', 'D_F_Btrack', 'D_Q_Btrack', 'D_ItBt', 'D_L', 'Time' ] isdmap = { 'Cnstr': 'Cnstr', 'D_F_Btrack': 'F_Btrack', 'D_Q_Btrack': 'Q_Btrack', 'D_ItBt': 'IterBTrack', 'D_L': 'L' } hdrtxt = [ 'Itn', 'Fnc', 'DFid', u('ℓ1'), 'Cnstr', 'r_X', 's_X', u('ρ_X'), 'F_D', 'Q_D', 'It_D', 'L_D' ] hdrmap = { 'Itn': 'Iter', 'Fnc': 'ObjFun', 'DFid': 'DFid', u('ℓ1'): 'RegL1', 'Cnstr': 'Cnstr', 'r_X': 'XPrRsdl', 's_X': 'XDlRsdl', u('ρ_X'): 'XRho', 'F_D': 'D_F_Btrack', 'Q_D': 'D_Q_Btrack', 'It_D': 'D_ItBt', 'L_D': 'D_L' } else: isfld = [ 'Iter', 'ObjFun', 'DFid', 'RegL1', 'Cnstr', 'XPrRsdl', 'XDlRsdl', 'XRho', 'D_L', 'Time' ] isdmap = {'Cnstr': 'Cnstr', 'D_L': 'L'} hdrtxt = [ 'Itn', 'Fnc', 'DFid', u('ℓ1'), 'Cnstr', 'r_X', 's_X', u('ρ_X'), 'L_D' ] hdrmap = { 'Itn': 'Iter', 'Fnc': 'ObjFun', 'DFid': 'DFid', u('ℓ1'): 'RegL1', 'Cnstr': 'Cnstr', 'r_X': 'XPrRsdl', 's_X': 'XDlRsdl', u('ρ_X'): 'XRho', 'L_D': 'D_L' } isc = dictlrn.IterStatsConfig(isfld=isfld, isxmap=isxmap, isdmap=isdmap, evlmap=evlmap, hdrtxt=hdrtxt, hdrmap=hdrmap) # Call parent constructor super(MixConvBPDNMaskDcplDictLearn, self).__init__(xstep, dstep, opt, isc)
def __init__(self, D0, S, lmbda=None, opt=None, dimK=1, dimN=2): """ Initialise a ConvBPDNDictLearn object with problem size and options. Parameters ---------- D0 : array_like Initial dictionary array S : array_like Signal array lmbda : float Regularisation parameter opt : :class:`ConvBPDNDictLearn.Options` object Algorithm options dimK : int, optional (default 1) Number of signal dimensions. If there is only a single input signal (e.g. if `S` is a 2D array representing a single image) `dimK` must be set to 0. dimN : int, optional (default 2) Number of spatial/temporal dimensions """ if opt is None: opt = ConvBPDNDictLearn.Options() self.opt = opt # Get dictionary size if self.opt['DictSize'] is None: dsz = D0.shape else: dsz = self.opt['DictSize'] # Construct object representing problem dimensions cri = cr.CDU_ConvRepIndexing(dsz, S, dimK, dimN) # Normalise dictionary D0 = cr.Pcn(D0, dsz, cri.Nv, dimN, cri.dimCd, crp=True, zm=opt['CCMOD', 'ZeroMean']) # Modify D update options to include initial values for X opt['CCMOD'].update( {'X0': cr.zpad(cr.stdformD(D0, cri.C, cri.M, dimN), cri.Nv)}) # Create X update object xstep = Fcbpdn.ConvBPDN(D0, S, lmbda, opt['CBPDN'], dimK=dimK, dimN=dimN) # Create D update object dstep = ccmod.ConvCnstrMOD(None, S, dsz, opt['CCMOD'], dimK=dimK, dimN=dimN) print("L xstep in cbpdndl: ", xstep.L) print("L dstep in cbpdndl: ", dstep.L) # Configure iteration statistics reporting isfld = ['Iter', 'ObjFun', 'DFid', 'RegL1', 'Cnstr'] hdrtxt = ['Itn', 'Fnc', 'DFid', u('ℓ1'), 'Cnstr'] hdrmap = { 'Itn': 'Iter', 'Fnc': 'ObjFun', 'DFid': 'DFid', u('ℓ1'): 'RegL1', 'Cnstr': 'Cnstr' } if self.opt['AccurateDFid']: isxmap = { 'X_F_Btrack': 'F_Btrack', 'X_Q_Btrack': 'Q_Btrack', 'X_ItBt': 'IterBTrack', 'X_L': 'L', 'X_Rsdl': 'Rsdl' } evlmap = {'ObjFun': 'ObjFun', 'DFid': 'DFid', 'RegL1': 'RegL1'} else: isxmap = { 'ObjFun': 'ObjFun', 'DFid': 'DFid', 'RegL1': 'RegL1', 'X_F_Btrack': 'F_Btrack', 'X_Q_Btrack': 'Q_Btrack', 'X_ItBt': 'IterBTrack', 'X_L': 'L', 'X_Rsdl': 'Rsdl' } evlmap = {} # If Backtracking enabled in xstep display the BT variables also if xstep.opt['BackTrack', 'Enabled']: isfld.extend( ['X_F_Btrack', 'X_Q_Btrack', 'X_ItBt', 'X_L', 'X_Rsdl']) hdrtxt.extend(['F_X', 'Q_X', 'It_X', 'L_X']) hdrmap.update({ 'F_X': 'X_F_Btrack', 'Q_X': 'X_Q_Btrack', 'It_X': 'X_ItBt', 'L_X': 'X_L' }) else: # Add just L value to xstep display isfld.extend(['X_L', 'X_Rsdl']) hdrtxt.append('L_X') hdrmap.update({'L_X': 'X_L'}) isdmap = { 'Cnstr': 'Cnstr', 'D_F_Btrack': 'F_Btrack', 'D_Q_Btrack': 'Q_Btrack', 'D_ItBt': 'IterBTrack', 'D_L': 'L', 'D_Rsdl': 'Rsdl' } # If Backtracking enabled in dstep display the BT variables also if dstep.opt['BackTrack', 'Enabled']: isfld.extend([ 'D_F_Btrack', 'D_Q_Btrack', 'D_ItBt', 'D_L', 'D_Rsdl', 'Time' ]) hdrtxt.extend(['F_D', 'Q_D', 'It_D', 'L_D']) hdrmap.update({ 'F_D': 'D_F_Btrack', 'Q_D': 'D_Q_Btrack', 'It_D': 'D_ItBt', 'L_D': 'D_L' }) else: # Add just L value to dstep display isfld.extend(['D_L', 'D_Rsdl', 'Time']) hdrtxt.append('L_D') hdrmap.update({'L_D': 'D_L'}) isc = dictlrn.IterStatsConfig(isfld=isfld, isxmap=isxmap, isdmap=isdmap, evlmap=evlmap, hdrtxt=hdrtxt, hdrmap=hdrmap) # Call parent constructor super(ConvBPDNDictLearn, self).__init__(xstep, dstep, opt, isc)
def __init__(self, D0, S, lmbda, W, opt=None, method='cns', dimK=1, dimN=2): """ Initialise a ConvBPDNMaskDcplDictLearn object with problem size and options. | **Call graph** .. image:: _static/jonga/cbpdnmddl_init.svg :width: 20% :target: _static/jonga/cbpdnmddl_init.svg | Parameters ---------- D0 : array_like Initial dictionary array S : array_like Signal array lmbda : float Regularisation parameter W : array_like Mask array. The array shape must be such that the array is compatible for multiplication with the *internal* shape of input array S (see :class:`.cnvrep.CDU_ConvRepIndexing` for a discussion of the distinction between *external* and *internal* data layouts). opt : :class:`ConvBPDNMaskDcplDictLearn.Options` object Algorithm options method : string, optional (default 'cns') String selecting dictionary update solver. Valid values are documented in function :func:`.ConvCnstrMODMaskDcpl`. dimK : int, optional (default 1) Number of signal dimensions. If there is only a single input signal (e.g. if `S` is a 2D array representing a single image) `dimK` must be set to 0. dimN : int, optional (default 2) Number of spatial/temporal dimensions """ if opt is None: opt = ConvBPDNMaskDcplDictLearn.Options(method=method) self.opt = opt # Get dictionary size if self.opt['DictSize'] is None: dsz = D0.shape else: dsz = self.opt['DictSize'] # Construct object representing problem dimensions cri = cr.CDU_ConvRepIndexing(dsz, S, dimK, dimN) # Normalise dictionary D0 = cr.Pcn(D0, dsz, cri.Nv, dimN, cri.dimCd, crp=True, zm=opt['CCMOD', 'ZeroMean']) # Modify D update options to include initial values for Y and U if cri.C == cri.Cd: Y0b0 = np.zeros(cri.Nv + (cri.C, 1, cri.K)) else: Y0b0 = np.zeros(cri.Nv + (1, 1, cri.C * cri.K)) Y0b1 = cr.zpad(cr.stdformD(D0, cri.Cd, cri.M, dimN), cri.Nv) if method == 'cns': Y0 = Y0b1 else: Y0 = np.concatenate((Y0b0, Y0b1), axis=cri.axisM) opt['CCMOD'].update({'Y0': Y0}) # Create X update object xstep = cbpdn.ConvBPDNMaskDcpl(D0, S, lmbda, W, opt['CBPDN'], dimK=dimK, dimN=dimN) # Create D update object dstep = ccmodmd.ConvCnstrMODMaskDcpl(None, S, W, dsz, opt['CCMOD'], method=method, dimK=dimK, dimN=dimN) # Configure iteration statistics reporting if self.opt['AccurateDFid']: isxmap = { 'XPrRsdl': 'PrimalRsdl', 'XDlRsdl': 'DualRsdl', 'XRho': 'Rho' } evlmap = {'ObjFun': 'ObjFun', 'DFid': 'DFid', 'RegL1': 'RegL1'} else: isxmap = { 'ObjFun': 'ObjFun', 'DFid': 'DFid', 'RegL1': 'RegL1', 'XPrRsdl': 'PrimalRsdl', 'XDlRsdl': 'DualRsdl', 'XRho': 'Rho' } evlmap = {} isc = dictlrn.IterStatsConfig(isfld=[ 'Iter', 'ObjFun', 'DFid', 'RegL1', 'Cnstr', 'XPrRsdl', 'XDlRsdl', 'XRho', 'DPrRsdl', 'DDlRsdl', 'DRho', 'Time' ], isxmap=isxmap, isdmap={ 'Cnstr': 'Cnstr', 'DPrRsdl': 'PrimalRsdl', 'DDlRsdl': 'DualRsdl', 'DRho': 'Rho' }, evlmap=evlmap, hdrtxt=[ 'Itn', 'Fnc', 'DFid', u('ℓ1'), 'Cnstr', 'r_X', 's_X', u('ρ_X'), 'r_D', 's_D', u('ρ_D') ], hdrmap={ 'Itn': 'Iter', 'Fnc': 'ObjFun', 'DFid': 'DFid', u('ℓ1'): 'RegL1', 'Cnstr': 'Cnstr', 'r_X': 'XPrRsdl', 's_X': 'XDlRsdl', u('ρ_X'): 'XRho', 'r_D': 'DPrRsdl', 's_D': 'DDlRsdl', u('ρ_D'): 'DRho' }) # Call parent constructor super(ConvBPDNMaskDcplDictLearn, self).__init__(xstep, dstep, opt, isc)
def __init__(self, D0, S, lmbda=None, opt=None, method='cns', dimK=1, dimN=2, stopping_pobj=None): """ Initialise a ConvBPDNDictLearn object with problem size and options. | **Call graph** .. image:: _static/jonga/cbpdndl_init.svg :width: 20% :target: _static/jonga/cbpdndl_init.svg | Parameters ---------- D0 : array_like Initial dictionary array S : array_like Signal array lmbda : float Regularisation parameter opt : :class:`ConvBPDNDictLearn.Options` object Algorithm options method : string, optional (default 'cns') String selecting dictionary update solver. Valid values are documented in function :func:`.ConvCnstrMOD`. dimK : int, optional (default 1) Number of signal dimensions. If there is only a single input signal (e.g. if `S` is a 2D array representing a single image) `dimK` must be set to 0. dimN : int, optional (default 2) Number of spatial/temporal dimensions """ if opt is None: opt = ConvBPDNDictLearn.Options(method=method) self.opt = opt self.stopping_pobj = stopping_pobj # Get dictionary size if self.opt['DictSize'] is None: dsz = D0.shape else: dsz = self.opt['DictSize'] # Construct object representing problem dimensions cri = cr.CDU_ConvRepIndexing(dsz, S, dimK, dimN) # Normalise dictionary D0 = cr.Pcn(D0, dsz, cri.Nv, dimN, cri.dimCd, crp=True, zm=opt['CCMOD', 'ZeroMean']) # Modify D update options to include initial values for Y and U opt['CCMOD'].update( {'Y0': cr.zpad(cr.stdformD(D0, cri.C, cri.M, dimN), cri.Nv)}) # Create X update object xstep = cbpdn.ConvBPDN(D0, S, lmbda, opt['CBPDN'], dimK=dimK, dimN=dimN) # Create D update object dstep = ccmod.ConvCnstrMOD(None, S, dsz, opt['CCMOD'], method=method, dimK=dimK, dimN=dimN) # Configure iteration statistics reporting if self.opt['AccurateDFid']: isxmap = { 'XPrRsdl': 'PrimalRsdl', 'XDlRsdl': 'DualRsdl', 'XRho': 'Rho' } evlmap = {'ObjFun': 'ObjFun', 'DFid': 'DFid', 'RegL1': 'RegL1'} else: isxmap = { 'ObjFun': 'ObjFun', 'DFid': 'DFid', 'RegL1': 'RegL1', 'XPrRsdl': 'PrimalRsdl', 'XDlRsdl': 'DualRsdl', 'XRho': 'Rho' } evlmap = {} isc = dictlrn.IterStatsConfig(isfld=[ 'Iter', 'ObjFun', 'DFid', 'RegL1', 'Cnstr', 'XPrRsdl', 'XDlRsdl', 'XRho', 'DPrRsdl', 'DDlRsdl', 'DRho', 'Time' ], isxmap=isxmap, isdmap={ 'Cnstr': 'Cnstr', 'DPrRsdl': 'PrimalRsdl', 'DDlRsdl': 'DualRsdl', 'DRho': 'Rho' }, evlmap=evlmap, hdrtxt=[ 'Itn', 'Fnc', 'DFid', u('ℓ1'), 'Cnstr', 'r_X', 's_X', u('ρ_X'), 'r_D', 's_D', u('ρ_D') ], hdrmap={ 'Itn': 'Iter', 'Fnc': 'ObjFun', 'DFid': 'DFid', u('ℓ1'): 'RegL1', 'Cnstr': 'Cnstr', 'r_X': 'XPrRsdl', 's_X': 'XDlRsdl', u('ρ_X'): 'XRho', 'r_D': 'DPrRsdl', 's_D': 'DDlRsdl', u('ρ_D'): 'DRho' }) # Call parent constructor super(ConvBPDNDictLearn, self).__init__(xstep, dstep, opt, isc)
def solve(self, S): """Solve for given signal S.""" self.timer.start(['solve', 'solve_wo_eval']) cri = cr.CDU_ConvRepIndexing(self.dsz, S) S = np.asarray(S.reshape(cri.shpS), dtype=self.dtype) X = self.xinit(S) Y = X.copy() G = self.D.copy() D = self.D.copy() S = S.squeeze(-1).transpose(3, 2, 0, 1) tx = td = 1. # MaxMainIter gives no of iterations for each sample. for self.j in range(self.j, self.j + self.opt['MaxMainIter']): Xprev, Dprev = X.copy(), D.copy() Y, X, G, D, tx, td = self.step(S, Y, X, G, D, tx, td, self.opt['FISTA', 'L'], self.opt['CCMOD', 'L']) tx = (1 + np.sqrt(1 + 4 * tx**2)) / 2. td = (1 + np.sqrt(1 + 4 * td**2)) / 2. self.timer.stop('solve_wo_eval') X_Rsdl = linalg.norm(Y - Xprev) D_Rsdl = linalg.norm(G - Dprev) recon = self.slices2im(np.matmul(G, Y)) dfd = linalg.norm(recon - S)**2 / 2. reg = linalg.norm(Y.ravel(), 1) obj = dfd + self.lmbda * reg cnstr = linalg.norm(self.dprox(G) - G) dtx = { 'L': self.opt['FISTA', 'L'], 'Rsdl': X_Rsdl, 'F_Btrack': None, 'Q_Btrack': None, 'IterBTrack': None } dtd = { 'L': self.opt['CCMOD', 'L'], 'Rsdl': D_Rsdl, 'Cnstr': cnstr, 'F_Btrack': None, 'IterBTrack': None, 'Q_Btrack': None } evl = {'ObjFun': obj, 'DFid': dfd, 'RegL1': reg} if not self.opt['AccurateDFid']: dtx.update(evl) evl = None self.timer.start('solve_wo_eval') self.D = G self.X = Y t = self.timer.elapsed(self.opt['IterTimer']) itst = self.isc.iterstats(self.j, t, dtx, dtd, evl) if self.opt['Verbose']: self.isc.printiterstats(itst) if self.opt['Callback'] is not None: if self.opt['Callback'](self): break if 0: import matplotlib.pyplot as plt plt.imshow(su.tiledict(self.getdict().squeeze())) plt.show() self.j += 1 self.timer.stop(['solve', 'solve_wo_eval']) if self.opt['Verbose'] and self.opt['StatusHeader']: self.isc.printseparator() return self.getdict()