def dictionary_learning_by_L1(X, S, dsz, G1, H1, G0, H0, parameter_rho_dic, iteration, thr, cri): Xf = con.convert_to_Xf(X, S, cri) bar_D = tqdm(total=iteration, desc='D', leave=False) for i in range(iteration): D, G0, H0, XD = dictionary_learning_by_L1_Dstep( Xf, S, G1, H1, G0, H0, parameter_rho_dic, i, cri, dsz) Dr = np.asarray(D.reshape(cri.shpD), dtype=S.dtype) H1r = np.asarray(H1.reshape(cri.shpD), dtype=S.dtype) Pcn = cr.getPcn(dsz, cri.Nv, cri.dimN, cri.dimCd) G1r = Pcn(Dr + H1r) G1 = cr.bcrop(G1r, dsz, cri.dimN).squeeze() H1 = H1 + D - G1 Est = sp.norm_l1(XD - S) if (i == 0): pre_Est = 1.1 * Est if ((pre_Est - Est) / pre_Est <= thr): bar_D.update(iteration - i) break pre_Est = Est bar_D.update(1) bar_D.close() return D, G0, G1, H0, H1
def test_16(self): dsz = (3, 3, 1) Nv = (6, 6) x = np.ones((6, 6, 1)) fn = cnvrep.getPcn(dsz, Nv, crp=True) y = fn(x) assert np.sum(y) == 3.0 assert y.shape == (3, 3, 1)
def test_15(self): dsz = (3, 3, 1) Nv = (6, 6) x = np.ones((6, 6, 1)) fn = cnvrep.getPcn(dsz, Nv) y = fn(x) assert np.sum(y) == 3.0 y[0:3, 0:3] = 0 assert np.sum(y) == 0.0
def test_18(self): dsz = (3, 3, 1) Nv = (6, 6) x = np.ones((6, 6, 1)) x[0] = 2 fn = cnvrep.getPcn(dsz, Nv, crp=True, zm=True) y = fn(x) assert np.all(y != 0.0) assert np.abs(np.sum(y)) < 1e-14 assert y.shape == (3, 3, 1)
def test_17(self): dsz = (3, 3, 1) Nv = (6, 6) x = np.ones((6, 6, 1)) x[0] = 2 fn = cnvrep.getPcn(dsz, Nv, zm=True) y = fn(x) assert np.all(y[0:3, 0:3] != 0.0) assert np.abs(np.sum(y)) < 1e-14 y[0:3, 0:3] = 0 assert np.sum(np.abs(y)) == 0.0
def dictionary_learning_by_L2(X, S, dsz, G, H, parameter_rho_dic, iteration, thr, cri): Xf = con.convert_to_Xf(X, S, cri) bar_D = tqdm(total=iteration, desc='D', leave=False) for i in range(iteration): Gf = con.convert_to_Df(G, S, cri) Hf = con.convert_to_Df(H, S, cri) GH = Gf - Hf Sf = con.convert_to_Sf(S, cri) b = parameter_rho_dic * GH + sl.inner(np.conj(Xf), Sf, cri.axisK) Df = sl.solvemdbi_ism(Xf, parameter_rho_dic, b, cri.axisM, cri.axisK) D = con.convert_to_D(Df, dsz, cri) XfDf = np.sum(Xf * Df, axis=cri.axisM) XD = con.convert_to_S(XfDf, cri) Dr = np.asarray(D.reshape(cri.shpD), dtype=S.dtype) Hr = np.asarray(H.reshape(cri.shpD), dtype=S.dtype) Pcn = cr.getPcn(dsz, cri.Nv, cri.dimN, cri.dimCd) Gr = Pcn(Dr + Hr) G = cr.bcrop(Gr, dsz, cri.dimN).squeeze() H = H + D - G Est = sp.norm_2l2(XD - S) if (i == 0): pre_Est = 1.1 * Est if ((pre_Est - Est) / pre_Est <= thr): bar_D.update(iteration - i) break pre_Est = Est bar_D.update(1) bar_D.close() return D, G, H
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)
Sh = S*2 - Smean # TODO: explicitly zero-padding (for me, foolish) D = np.random.randn(12, 12, 256) # D = np.random.rand(12, 12, 64)*2 - 1 cri = cnvrep.CSC_ConvRepIndexing(D, S) Dr0 = np.asarray(D.reshape(cri.shpD), dtype=S.dtype) Slr = np.asarray(Sl.reshape(cri.shpS), dtype=S.dtype) Shr = np.asarray(Sh.reshape(cri.shpS), dtype=S.dtype) Shf = sl.rfftn(Shr, s=cri.Nv, axes=cri.axisN) # implicitly zero-padding crop_op = [] for l in Dr0.shape: crop_op.append(slice(0, l)) crop_op = tuple(crop_op) Dr0 = cnvrep.getPcn(Dr0.shape, cri.Nv, cri.dimN, cri.dimCd, zm=False)(cnvrep.zpad(Dr0, cri.Nv))[crop_op] # Dr = normalize(Dr, axis=cri.axisM) # Xr = l2norm_minimize(cri, Dr0, Shr) # Dr = mysolve(cri, Dr0, Xr, Shr, 1e-4, maxitr=50, debug_dir='./debug') # # Dr = nakashizuka_solve(cri, Dr0, Xr, Shr, debug_dir='./debug') # # Dr = sporcosolve(cri, Dr, Shr) # # fig = plot.figure(figsize=(7, 7)) # # plot.imview(util.tiledict(Dr.squeeze()), fig=fig) # # fig.savefig('dict.png') # # # evaluate_result(cri, Dr0, Dr, Shr, Sr_add=Slr) exim1 = util.ExampleImages(scaled=True, zoom=0.5, pth='./') S1_test = exim1.image('couple.tiff') exim2 = util.ExampleImages(scaled=True, zoom=1, pth='./')
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)
def mysolve(cri, Dr0, Xr, Sr, final_sigma, maxitr=40, param_mu=1, debug_dir=None): Dr = Dr0.copy() Xr = Xr.copy() Sr = Sr.copy() #離散フーリエ変換 Df = sl.rfftn(Dr, s=cri.Nv, axes=cri.axisN) Sf = sl.rfftn(Sr, s=cri.Nv, axes=cri.axisN) Xf = sl.rfftn(Xr, s=cri.Nv, axes=cri.axisN) alpha = 1e0 # sigma set first_sigma = Xr.max() * 4 # σ←cσ(c < 1)のcの決定 c = (final_sigma / first_sigma)**(1 / (maxitr - 1)) print("c = %.8f" % c) sigma_list = [] sigma_list.append(first_sigma) for i in range(maxitr - 1): sigma_list.append(sigma_list[i] * c) print(sigma_list[-1]) # 辞書のクロップする領域を添え字で指定 crop_op = [] for l in Dr.shape: crop_op.append(slice(0, l)) crop_op = tuple(crop_op) print(crop_op) updcnt = 0 for sigma in sigma_list: print("sigma = %.8f" % sigma) # print("l0norm: %f" % l0norm(Xr, sigma_list[-1])) # print('error1: ', l2norm(Sr - reconstruct(cri, Dr, Xr))) delta = Xr * np.exp(-(Xr * Xr) / (2 * sigma * sigma)) # print("l2(Xr): %.6f, l2(delta): %.6f" % (l2norm(Xr), l2norm(delta))) Xr = Xr - param_mu * delta # + np.random.randn(*Xr.shape)*sigma*1e-1 Xf = sl.rfftn(Xr, cri.Nv, cri.axisN) # saveXhist(Xr, "./hist/%db.png" % reccnt) # print('error2: ', l2norm(Sr - reconstruct(cri, Dr, Xr))) # if debug_dir is not None: # save_reconstructed(cri, Dr, Xr, Sr, debug_dir + '/%drecA.png' % updcnt) # DXf = sl.inner(Df, Xf, axis=cri.axisM) # gamma = (np.sum(np.conj(DXf) * Sf, axis=cri.axisN, keepdims=True) + np.sum(DXf * np.conj(Sf), axis=cri.axisN, keepdims=True)) / 2 / np.sum(np.conj(DXf) * DXf, axis=cri.axisN, keepdims=True) # print(gamma) # print(gamma.shape, ' * ', Xr.shape) # gamma = np.real(gamma) # Xr = Xr * gamma # Xf = to_frequency(cri, Xr) # if debug_dir is not None: # save_reconstructed(cri, Dr, Xr, Sr, debug_dir + '/%drecB.png' % updcnt) # print('error3: ', l2norm(Sr - reconstruct(cri, Dr, Xr))) # print("max: ", np.max(Xr)) # 辞書の勾配降下 B = sl.inner(Xf, Df, axis=cri.axisM) - Sf derivDf = sl.inner(np.conj(Xf), B, axis=cri.axisK) # 目的関数(信号との二乗近似誤差)の勾配 # derivDr = sl.irfftn(derivDf, s=cri.Nv, axes=cri.axisN)[crop_op] def func(alpha): Df_ = Df - alpha * derivDf Dr_ = sl.irfftn(Df_, s=cri.Nv, axes=cri.axisN)[crop_op] Df_ = sl.rfftn(Dr_, s=cri.Nv, axes=cri.axisN) Sf_ = sl.inner(Df_, Xf, axis=cri.axisM) return l2norm(Sr - sl.irfftn(Sf_, s=cri.Nv, axes=cri.axisN)) choice = np.array([func(alpha / 2), func(alpha), func(alpha * 2)]).argmin() alpha *= [0.5, 1, 2][choice] print("alpha: ", alpha) Df = Df - alpha * derivDf # 辞書の射影 Dr = sl.irfftn(Df, s=cri.Nv, axes=cri.axisN) Pcn = cnvrep.getPcn(Dr.shape, cri.Nv, cri.dimN, cri.dimCd, zm=False) # 射影関数のインスタンス化 Dr = Pcn(Dr) Dr = Dr[crop_op] print(l2norm(Dr.T[0])) Df = sl.rfftn(Dr, s=cri.Nv, axes=cri.axisN) b = sl.inner(Df, Xf, axis=cri.axisM) - Sf c = sl.inner(Df, np.conj(Df), axis=cri.axisM) Xf = Xf - np.conj(Df) / c * b Xr = sl.irfftn(Xf, s=cri.Nv, axes=cri.axisN) # save_reconstructed(cri, Dr, Xr, Sr, debug_dir + "rec/%dd.png" % updcnt) # saveXhist(Xr, debug_dir + "hist/%db.png" % updcnt) updcnt += 1 # print("l0 norm of final X: %d" % smoothedl0norm(Xr, 0.00001)) plot.close() mplot.close() return Dr
def __init__(self, Z, S, W, dsz, opt=None, dimK=None, dimN=2): """ 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)) self.Xf = sl.pyfftw_rfftn_empty_aligned(xfshp, self.cri.axisN, self.dtype) if Z is not None: self.setcoef(Z)
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)
def nakashizuka_solve( cri, Dr0, Xr, Sr, final_sigma, maxitr = 40, param_mu = 1, param_lambda = 1e-2, debug_dir = None ): param_rho = 0.5 Xr = Xr.copy() Sr = Sr.copy() Dr = Dr0.copy() Hr = np.zeros_like(cnvrep.zpad(Dr, cri.Nv)) Sf = to_frequency(cri, Sr) # sigma set # sigma_list = [] # sigma_list.append(Xr.max()*4) # for i in range(7): # sigma_list.append(sigma_list[i]*0.5) first_sigma = Xr.max()*4 c = (final_sigma / first_sigma) ** (1/(maxitr - 1)) print("c = %.8f" % c) sigma_list = [] sigma_list.append(first_sigma) for i in range(maxitr - 1): sigma_list.append(sigma_list[i]*c) crop_op = [] for l in Dr.shape: crop_op.append(slice(0, l)) crop_op = tuple(crop_op) Pcn = cnvrep.getPcn(Dr.shape, cri.Nv, cri.dimN, cri.dimCd, zm=False) updcnt = 0 dictcnt = 0 for sigma in sigma_list: print("sigma = %.8f" % sigma) # Xf_old = sl.rfftn(Xr, cri.Nv, cri.axisN) for l in range(1): # print("l0norm: %f" % l0norm(Xr, sigma_list[-1])) # print('error1: ', l2norm(Sr - reconstruct(cri, Dr, Xr))) # print("l2(Xr): %.6f, l2(delta): %.6f" % (l2norm(Xr), l2norm(delta))) delta = Xr * np.exp(-(Xr*Xr) / (2*sigma*sigma)) Xr = Xr - param_mu*delta# + np.random.randn(*Xr.shape)*sigma*1e-1 Xf = to_frequency(cri, Xr) # print('error2: ', l2norm(Sr - reconstruct(cri, Dr, Xr))) Df = to_frequency(cri, Dr) b = Xf / param_lambda + np.conj(Df) * Sf Xf = sl.solvedbi_sm(Df, 1/param_lambda, b, axis=cri.axisM) Xr = to_spatial(cri, Xf).astype(np.float32) # print('error3: ', l2norm(Sr - reconstruct(cri, Dr, Xr))) # save_reconstructed(cri, Dr, Xr, Sr, "./rec/%da.png" % reccnt) # saveXhist(Xr, "./hist/%da.png" % reccnt) Dr, Hr = update_dict(cri, Pcn, crop_op, Xr, Dr, Hr, Sf, param_rho) Df = to_frequency(cri, Dr) # print('error4: ', l2norm(Sr - reconstruct(cri, Dr, Xr))) # # project X to solution space # b = sl.inner(Df, Xf, axis=cri.axisM) - Sf # c = sl.inner(Df, np.conj(Df), axis=cri.axisM) # Xf = Xf - np.conj(Df) / c * b # Xr = sl.irfftn(Xf, s=cri.Nv, axes=cri.axisN) # print('error5: ', l2norm(Sr - reconstruct(cri, Dr, Xr))) if debug_dir is not None: saveimg(util.tiledict(Dr.squeeze()), debug_dir + "/dict/%d.png" % updcnt) updcnt += 1 # saveXhist(Xr, "Xhist_sigma=" + str(sigma) + ".png") # print("l0 norm of final X: %d" % smoothedl0norm(Xr, 0.00001)) plot.close() mplot.close() return Dr
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 convDictLearn(cri, Dr0, dsz, Sr, final_sigma, maxitr, non_nega, param_mu=1, debug_dir=None): Dr = Dr0.copy() Sr = Sr.copy() # 係数をl2ノルム最小解で初期化 Xr = l2norm_minimize(cri, Dr, Sr) # 2次元離散フーリエ変換 Df = sl.rfftn(Dr, s=cri.Nv, axes=cri.axisN) Sf = sl.rfftn(Sr, s=cri.Nv, axes=cri.axisN) Xf = sl.rfftn(Xr, s=cri.Nv, axes=cri.axisN) alpha = 1e0 # sigma set first_sigma = Xr.max() * 4 # σを更新する定数c(c<1)の決定 c = (final_sigma / first_sigma)**(1 / (maxitr - 1)) print("c = %.8f" % c) sigma_list = [] sigma_list.append(first_sigma) for i in range(maxitr - 1): sigma_list.append(sigma_list[i] * c) # 辞書のクロップする領域を添え字で指定 crop_op = [] for l in Dr.shape: crop_op.append(slice(0, l)) crop_op = tuple(crop_op) # 射影関数のインスタンス化 Pcn = cnvrep.getPcn(dsz, cri.Nv, cri.dimN, cri.dimCd, zm=False) updcnt = 0 for sigma in sigma_list: print("sigma = %.8f" % sigma, end=" ") # 係数の勾配降下 delta = Xr * np.exp(-(Xr * Xr) / (2 * sigma * sigma)) Xr = Xr - param_mu * delta Xf = sl.rfftn(Xr, cri.Nv, cri.axisN) print("l0norm = %i" % np.where( abs(Xr.transpose(3, 4, 2, 0, 1).squeeze()[0]) < final_sigma, 0, 1).sum(), end=" ") # 辞書の勾配降下 B = sl.inner(Xf, Df, axis=cri.axisM) - Sf derivDf = sl.inner(np.conj(Xf), B, axis=cri.axisK) def func(alpha): Df_ = Df - alpha * derivDf Dr_ = sl.irfftn(Df_, s=cri.Nv, axes=cri.axisN)[crop_op] Df_ = sl.rfftn(Dr_, s=cri.Nv, axes=cri.axisN) Sf_ = sl.inner(Df_, Xf, axis=cri.axisM) return myutil.l2norm(Sr - sl.irfftn(Sf_, s=cri.Nv, axes=cri.axisN)) error_list = np.array([func(alpha / 2), func(alpha), func(alpha * 2)]) choice = error_list.argmin() alpha *= [0.5, 1, 2][choice] print("alpha = %.8f" % alpha, end=" ") print("error = %5.5f" % error_list[choice], end=" ") Df = Df - alpha * derivDf # 辞書の射影 Dr = Pcn(sl.irfftn(Df, s=cri.Nv, axes=cri.axisN))[crop_op] # 正規化とゼロパディングを同時に行う # print(myutil.l2norm(Dr.T[0])) # 係数の射影 Df = sl.rfftn(Dr, s=cri.Nv, axes=cri.axisN) b = sl.inner(Df, Xf, axis=cri.axisM) - Sf c = sl.inner(Df, np.conj(Df), axis=cri.axisM) Xf = Xf - np.conj(Df) / c * b Xr = sl.irfftn(Xf, s=cri.Nv, axes=cri.axisN) if (non_nega): Xr = np.where(Xr < 0, 0, Xr) # 非負制約 # Xr = np.where(Xr < 1e-6, 0, Xr) print("l0norm_projected = %i" % np.where( abs(Xr.transpose(3, 4, 2, 0, 1).squeeze()[0]) < final_sigma, 0, 1).sum()) updcnt += 1 return Dr, Xr