Esempio n. 1
0
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
Esempio n. 2
0
 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)
Esempio n. 3
0
 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)
Esempio n. 4
0
 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
Esempio n. 5
0
 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
Esempio n. 6
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)
Esempio n. 7
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)
Esempio n. 8
0
 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
Esempio n. 9
0
 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
Esempio n. 10
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
Esempio n. 11
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)
Esempio n. 12
0
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='./')
Esempio n. 13
0
    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)
Esempio n. 14
0
    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
Esempio n. 16
0
    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)
Esempio n. 17
0
    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)
Esempio n. 18
0
    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)
Esempio n. 19
0
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
Esempio n. 20
0
    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()
Esempio n. 21
0
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