def __init__(self, D0, lmbda=None, opt=None, dimK=None, dimN=2): """ Parameters ---------- D0 : array_like Initial dictionary array lmbda : float Regularisation parameter opt : :class:`OnlineConvBPDNDictLearn.Options` object Algorithm options dimK : 0, 1, or None, optional (default None) Number of signal dimensions in signal array passed to :meth:`solve`. If there will only be 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 = OnlineConvBPDNDictLearn.Options() if not isinstance(opt, OnlineConvBPDNDictLearn.Options): raise TypeError('Parameter opt must be an instance of ' 'OnlineConvBPDNDictLearn.Options') self.opt = opt if dimN != 2 and opt['CUDA_CBPDN']: raise ValueError('CUDA CBPDN solver can only be used when dimN=2') if opt['CUDA_CBPDN'] and cuda.device_count() == 0: raise ValueError('SPORCO-CUDA not installed or no GPU available') self.dimK = dimK self.dimN = dimN # DataType option overrides data type inferred from __init__ # parameters of derived class self.set_dtype(opt, D0.dtype) # Initialise attributes representing algorithm parameter self.lmbda = lmbda self.eta_a = opt['eta_a'] self.eta_b = opt['eta_b'] self.set_attr('eta', opt['eta_a'] / opt['eta_b'], dval=2.0, dtype=self.dtype) # Get dictionary size if self.opt['DictSize'] is None: self.dsz = D0.shape else: self.dsz = self.opt['DictSize'] # Construct object representing problem dimensions self.cri = None # Normalise dictionary ds = cr.DictionarySize(self.dsz, dimN) dimCd = ds.ndim - dimN - 1 D0 = cr.stdformD(D0, ds.nchn, ds.nflt, dimN).astype(self.dtype) self.D = cr.Pcn(D0, self.dsz, (), dimN, dimCd, crp=True, zm=opt['ZeroMean']) self.Dprv = self.D.copy() # Create constraint set projection function self.Pcn = cr.getPcn(self.dsz, (), dimN, dimCd, crp=True, zm=opt['ZeroMean']) # Initalise iterations stats list and iteration index self.itstat = [] self.j = 0 # Configure status display self.display_config()
def __init__(self, dsz, S, dimK=None, dimN=2): """Initialise a ConvRepIndexing object. Initialise a ConvRepIndexing object representing dimensions of S (input signal), D (dictionary), and X (coefficient array) in a convolutional representation. These dimensions are inferred from the input `dsz` and `S` as well as from parameters `dimN` and `dimK`. Management and inferrence of these problem dimensions is not entirely straightforward because :class:`.ConvCnstrMODBase` and related classes make use *internally* of S, D, and X arrays with a standard layout (described below), but *input* `S` and `dsz` are allowed to deviate from this layout for the convenience of the user. Note that S, D, and X refers to the names of signal, dictionary, and coefficient map arrays in :class:`.admm.cbpdn.ConvBPDN`; the corresponding variable names in :class:`.ConvCnstrMODBase` are S, X, and Z. The most fundamental parameter is `dimN`, which specifies the dimensionality of the spatial/temporal samples being represented (e.g. `dimN` = 2 for representations of 2D images). This should be common to *input* `S` and `dsz`, and is also common to *internal* S, D, and X. The remaining dimensions of input `S` can correspond to multiple channels (e.g. for RGB images) and/or multiple signals (e.g. the array contains multiple independent images). If input `S` contains two additional dimensions (in addition to the `dimN` spatial dimensions), then those are considered to correspond, in order, to channel and signal indices. If there is only a single additional dimension, then determination whether it represents a channel or signal index is more complicated. The rule for making this determination is as follows: * if `dimK` is set to 0 or 1 instead of the default ``None``, then that value is taken as the number of signal indices in input `S` and any remaining indices are taken as channel indices (i.e. if `dimK` = 0 then dimC = 1 and if `dimK` = 1 then dimC = 0). * if `dimK` is ``None`` then the number of channel dimensions is determined from the number of dimensions specified in the input dictionary size `dsz`. Input `dsz` should specify at least `dimN` + 1 dimensions, with the final dimension indexing dictionary filters. If it has exactly `dimN` + 1 dimensions then it is a single-channel dictionary, and input `S` is also assumed to be single-channel, with the additional index in `S` assigned as a signal index (i.e. `dimK` = 1). Conversely, if input `dsz` specified `dimN` + 2 dimensions it is a multi-channel dictionary, and the additional index in `S` is assigned as a channel index (i.e. dimC = 1). Note that it is an error to specify `dimK` = 1 if input `S` has `dimN` + 1 dimensions and input `dsz` specified `dimN` + 2 dimensions since a multi-channel dictionary requires a multi-channel signal. (The converse is not true: a multi-channel signal can be decomposed using a single-channel dictionary.) The *internal* data layout for S (signal), D (dictionary), and X (coefficient array) is (multi-channel dictionary) :: sptl. chn sig flt S(N0, N1, ..., C, K, 1) D(N0, N1, ..., C, 1, M) X(N0, N1, ..., C, K, M) or (single-channel dictionary) :: sptl. chn sig flt S(N0, N1, ..., C, K, 1) D(N0, N1, ..., 1, 1, M) X(N0, N1, ..., C, K, M) where * Nv = [N0, N1, ...] and N = N0 x N1 x ... are the vector of sizes of the spatial/temporal indices and the total number of spatial/temporal samples respectively * C is the number of channels in S * K is the number of signals in S * M is the number of filters in D It should be emphasised that dimC and dimK may take on values 0 or 1, and represent the number of channel and signal dimensions respectively *in input S*. In the internal layout of S there is always a dimension allocated for channels and signals. The number of channel dimensions in input `D` and the corresponding size of that index are represented by dimCd and Cd respectively. Parameters ---------- dsz : tuple Dictionary size specification (using the same format as the `dsz` argument of :func:`bcrop`) S : array_like Input signal 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 of signal samples """ # Extract properties of dictionary size specification tuple ds = cr.DictionarySize(dsz, dimN) self.dimCd = ds.ndim - dimN - 1 self.Cd = ds.nchn self.M = ds.nflt self.dsz = dsz # Numbers of spatial, channel, and signal dimensions in # external S are dimN, dimC, and dimK respectively. These need # to be calculated since inputs D and S do not already have # the standard data layout above, i.e. singleton dimensions # will not be present if dimK is None: rdim = S.ndim - dimN if rdim == 0: (dimC, dimK) = (0, 0) elif rdim == 1: dimC = self.dimCd # Assume S has same number of channels as D dimK = S.ndim - dimN - dimC # Assign remaining channels to K else: (dimC, dimK) = (1, 1) else: dimC = S.ndim - dimN - dimK # Assign remaining channels to C self.dimN = dimN # Number of spatial dimensions self.dimC = dimC # Number of channel dimensions in S self.dimK = dimK # Number of signal dimensions in S # Number of channels in S if self.dimC == 1: self.C = S.shape[dimN] else: self.C = 1 self.Cx = self.C # Ensure that multi-channel dictionaries used with a signal with a # matching number of channels if self.Cd > 1 and self.C != self.Cd: raise ValueError("Multi-channel dictionary with signal with " "mismatched number of channels (Cd=%d, C=%d)" % (self.Cd, self.C)) # Number of signals in S if self.dimK == 1: self.K = S.shape[self.dimN + self.dimC] else: self.K = 1 # Shape of spatial indices and number of spatial samples self.Nv = S.shape[0:dimN] self.N = np.prod(np.array(self.Nv)) # Axis indices for each component of X and internal S and D self.axisN = tuple(range(0, dimN)) self.axisC = dimN self.axisK = dimN + 1 self.axisM = dimN + 2 # Shapes of internal S, D, and X self.shpD = self.Nv + (self.Cd, ) + (1, ) + (self.M, ) self.shpS = self.Nv + (self.C, ) + (self.K, ) + (1, ) self.shpX = self.Nv + (self.Cx, ) + (self.K, ) + (self.M, )
def test_06(self): dsz = ((8, 8, 3, 16), (12, 12, 3, 32)) ds = cnvrep.DictionarySize(dsz) assert ds.nchn == 3 assert ds.nflt == 48
def test_07(self): dsz = (((5, 5, 2, 8), (7, 7, 1, 8)), ((9, 9, 2, 16), (10, 10, 1, 16))) ds = cnvrep.DictionarySize(dsz) assert ds.nchn == 3 assert ds.nflt == 24
def test_04(self): dsz = (8, 8, 32) ds = cnvrep.DictionarySize(dsz) assert ds.nchn == 1 assert ds.nflt == 32 assert str(ds) != ''