Esempio n. 1
0
 def __call__(self, Z):
     if Z.ndim == 1:
         return normalize(Z)
     elif Z.ndim == 2:
         # e.g a 2D patch in a feature_map
         shape = Z.shape
         return normalize(Z.flatten()).reshape(shape)
Esempio n. 2
0
 def __call__(self, Z):
     if Z.ndim == 1:
         return normalize(Z)
     elif Z.ndim == 2:
         # e.g a 2D patch in a feature_map
         shape = Z.shape
         return normalize(Z.flatten()).reshape(shape)
Esempio n. 3
0
def replace_coherent_atoms(X, y, D, n_class_atoms, thresh=None, kappa=None, unused_data=None):
    # replace the coherent atoms of the sub-dictionaries in D
    n_classes = len(n_class_atoms)
    Xc = []
    for c in range(n_classes):
        x_c = y == c
        # extract the datapoints for
        # this class
        Xc.append(X[:, x_c])

    dicts = []
    for c in range(n_classes):
        dicts.append(D[:, get_class_atoms(c, n_class_atoms)])
    for c in range(n_classes):
        Dc = dicts[c]
        for j in range(c + 1, n_classes):
            Dj = dicts[j]
            c_atom_pairs = find_coherent_atoms(Dc, Dj, thresh=thresh, kappa=kappa)

            if unused_data is None:
                # we remove the coherent atoms from both Dc and Dj
                for c_atoms in c_atom_pairs:
                    Dc = np.delete(Dc, c_atoms[0], 1)
                    Dj = np.delete(Dj, c_atoms[1], 1)
                    n_class_atoms[c] = n_class_atoms[c] - 1
                    n_class_atoms[j] = n_class_atoms[j] - 1
            else:

                # replace them with one datapoint that
                # hasn't been used
                for c_atoms in c_atom_pairs:
                    # there are datapoints available
                    # to be used as atoms
                    if len(unused_data[c]) != 0:
                        _idx = np.random.choice(unused_data[c], size=1)
                        idx = _idx[0]
                        Dc[:, c_atoms[0]] = Xc[c][:, idx]
                        Dc[:, c_atoms[0]] = normalize(Dc[:, c_atoms[0]])
                        unused_data[c].remove(idx)

                    if len(unused_data[j]) != 0:
                        _idx = np.random.choice(unused_data[j], size=1)
                        idx = _idx[0]
                        Dj[:, c_atoms[1]] = Xc[j][:, idx]
                        Dj[:, c_atoms[1]] = normalize(Dj[:, c_atoms[1]])
                        unused_data[j].remove(idx)

                    dicts[c], dicts[j] = Dc, Dj

    # merge the sub-dictionaries
    D = dicts[0]
    for c in range(1, n_classes):
        D = np.hstack((D, dicts[c]))

    return D, n_class_atoms
Esempio n. 4
0
def force_mi(D, X, Z, unused_data, eta, max_tries=100):
    # force mutual incoherence within a dictionary
    n_atoms = D.shape[1]
    G = np.abs(np.dot(D.T, D))
    np.fill_diagonal(G, 0)

    for atom_idx1 in range(n_atoms):

        atom_idx2 = np.argmax(G[atom_idx1, :])
        # the maximum coherence
        mcoh = G[atom_idx1, atom_idx2]
        if mcoh < eta:
            print "less than the eta"
            continue
        # choose one of the two to replace
        # should we choose the one least used?
        if norm(Z[atom_idx1, :]) > norm(Z[atom_idx2, :]):
            c_atom = atom_idx1
        else:
            c_atom = atom_idx2

        # new_atom = None
        cnt = 0
        available_data = unused_data[:]
        min_idx = None
        min_coh = mcoh

        while mcoh > eta:
            # replace the coherent atom
            if cnt > max_tries:
                break
            # no datapoint available to be used as atom
            if len(available_data) == 0:
                return D
            _idx = np.random.choice(available_data, size=1)
            if len(_idx) == 0:
                return D, unused_data
            idx = _idx[0]
            new_atom = X[:, idx]
            new_atom = normalize(new_atom)
            available_data.remove(idx)
            g = np.abs(np.dot(D.T, new_atom))
            mcoh = np.max(g)
            if mcoh < min_coh or min_coh is None:
                min_coh = mcoh
                min_idx = idx
            cnt += 1

        D[:, c_atom] = X[:, min_idx]
        D[:, c_atom] = normalize(D[:, c_atom])
        unused_data.remove(min_idx)

    return D, unused_data
Esempio n. 5
0
def force_mi(D, X, Z, unused_data, eta, max_tries=100):
    # force mutual incoherence within a dictionary
    n_atoms = D.shape[1]
    G = np.abs(np.dot(D.T, D))
    np.fill_diagonal(G, 0)

    for atom_idx1 in range(n_atoms):

        atom_idx2 = np.argmax(G[atom_idx1, :])
        # the maximum coherence
        mcoh = G[atom_idx1, atom_idx2]
        if mcoh < eta:
            print "less than the eta"
            continue
        # choose one of the two to replace
        # should we choose the one least used?
        if norm(Z[atom_idx1, :]) > norm(Z[atom_idx2, :]):
            c_atom = atom_idx1
        else:
            c_atom = atom_idx2

        # new_atom = None
        cnt = 0
        available_data = unused_data[:]
        min_idx = None
        min_coh = mcoh

        while mcoh > eta:
            # replace the coherent atom
            if cnt > max_tries:
                break
            # no datapoint available to be used as atom
            if len(available_data) == 0:
                return D
            _idx = np.random.choice(available_data, size=1)
            if len(_idx) == 0:
                return D, unused_data
            idx = _idx[0]
            new_atom = X[:, idx]
            new_atom = normalize(new_atom)
            available_data.remove(idx)
            g = np.abs(np.dot(D.T, new_atom))
            mcoh = np.max(g)
            if mcoh < min_coh or min_coh is None:
                min_coh = mcoh
                min_idx = idx
            cnt += 1

        D[:, c_atom] = X[:, min_idx]
        D[:, c_atom] = normalize(D[:, c_atom])
        unused_data.remove(min_idx)

    return D, unused_data
Esempio n. 6
0
def approx_ksvd(Y, D, X, n_cycles=1, verbose=True):
    # the approximate KSVD algorithm
    n_atoms = D.shape[1]
    n_features, n_samples = Y.shape
    unused_atoms = []
    R = Y - fast_dot(D, X)

    for c in range(n_cycles):
        for k in range(n_atoms):
            if verbose:
                sys.stdout.write("\r" + "k-svd..." + ":%3.2f%%" % ((k / float(n_atoms)) * 100))
                sys.stdout.flush()
            # find all the datapoints that use the kth atom
            omega_k = X[k, :] != 0
            if not np.any(omega_k):
                # print "this atom is not used"
                unused_atoms.append(k)
                continue
            Rk = R[:, omega_k] + np.outer(D[:, k], X[k, omega_k])
            # update of D[:,k]
            D[:, k] = np.dot(Rk, X[k, omega_k])
            D[:, k] = normalize(D[:, k])
            # update of X[:,k]
            X[k, omega_k] = np.dot(Rk.T, D[:, k])
            # update the residual
            R[:, omega_k] = Rk - np.outer(D[:, k], X[k, omega_k])
        print ""

    return D, X, unused_atoms
Esempio n. 7
0
def approx_ksvd(Y, D, X, n_cycles=1, verbose=True):
    # the approximate KSVD algorithm
    n_atoms = D.shape[1]
    n_features, n_samples = Y.shape
    unused_atoms = []
    R = Y - fast_dot(D, X)

    for c in range(n_cycles):
        for k in range(n_atoms):
            if verbose:
                sys.stdout.write("\r" + "k-svd..." + ":%3.2f%%" % ((k / float(n_atoms)) * 100))
                sys.stdout.flush()
            # find all the datapoints that use the kth atom
            omega_k = X[k, :] != 0
            if not np.any(omega_k):
                # print "this atom is not used"
                unused_atoms.append(k)
                continue
            Rk = R[:, omega_k] + np.outer(D[:, k], X[k, omega_k])
            # update of D[:,k]
            D[:, k] = np.dot(Rk, X[k, omega_k])
            D[:, k] = normalize(D[:, k])
            # update of X[:,k]
            X[k, omega_k] = np.dot(Rk.T, D[:, k])
            # update the residual
            R[:, omega_k] = Rk - np.outer(D[:, k], X[k, omega_k])
        print ""

    return D, X, unused_atoms
Esempio n. 8
0
def ksvd_dict_learn(X, n_atoms, init_dict='data', sparse_coder=None,
                    max_iter=20, non_neg=False, approx=False, eta=None,
                    n_cycles=1, n_jobs=1, mmap=False, verbose=True):
    """
    The K-SVD algorithm

    X: the data matrix of shape (n_features,n_samples)
    n_atoms: the number of atoms in the dictionary
    sparse_coder: must be an instance of the sparse_coding.sparse_encoder class
    approx: if true, invokes the approximate KSVD algorithm
    max_iter: the maximum number of iterations
    non_neg: if set to True, it uses non-negativity constraints
    n_cycles: the number of updates per atom (Dictionary Update Cycles)
    n_jobs: the number of CPU threads
    mmap: if set to True, the algorithm applies memory mapping to save memory
    """
    n_features, n_samples = X.shape
    shape = (n_atoms, n_samples)
    Z = np.zeros(shape)
    # dictionary initialization
    # track the datapoints that are not used as atoms
    unused_data = []
    if init_dict == 'data':
        from .utils import init_dictionary
        D, unused_data = init_dictionary(X, n_atoms, method=init_dict, return_unused_data=True)
    else:
        D = np.copy(init_dict)

    if mmap:
        D = get_mmap(D)
        sparse_coder.mmap = True

    print "dictionary initialized"
    max_patience = 10
    error_curr = 0
    error_prev = 0
    it = 0
    patience = 0
    approx_errors = []

    while it < max_iter and patience < max_patience:
        print "----------------------------"
        print "iteration", it
        print ""
        it_start = time.time()
        if verbose:
            t_sparse_start = time.time()
        # sparse coding
        Z = sparse_coder(X, D)
        if verbose:
            t_sparse_duration = time.time() - t_sparse_start
            print "sparse coding took", t_sparse_duration, "seconds"
            t_dict_start = time.time()

        # ksvd to learn the dictionary
        set_openblas_threads(n_jobs)
        if approx:
            D, _, unused_atoms = approx_ksvd(X, D, Z, n_cycles=n_cycles)
        elif non_neg:
            D, _, unused_atoms = nn_ksvd(X, D, Z, n_cycles=it)
        else:
            D, _, unused_atoms = ksvd(X, D, Z, n_cycles=n_cycles)
        set_openblas_threads(1)
        if verbose:
            t_dict_duration = time.time() - t_dict_start
            print "K-SVD took", t_dict_duration, "seconds"
            print ""
        if verbose:
            print "number of unused atoms:", len(unused_atoms)
        # replace the unused atoms in the dictionary
        for j in range(len(unused_atoms)):
            # no datapoint available to be used as atom
            if len(unused_data) == 0:
                break
            _idx = np.random.choice(unused_data, size=1)
            idx = _idx[0]
            D[:, unused_atoms[j]] = X[:, idx]
            D[:, unused_atoms[j]] = normalize(D[:, unused_atoms[j]])
            unused_data.remove(idx)

        if eta is not None:
            # do not force incoherence in the last iteration
            if it < max_iter - 1:
                # force Mutual Incoherence
                D, unused_data = force_mi(D, X, Z, unused_data, eta)
        if verbose:
            amc = average_mutual_coherence(D)
            print "average mutual coherence:", amc

        it_duration = time.time() - it_start
        # calculate the approximation error
        error_curr = approx_error(D, Z, X, n_jobs=2)
        approx_errors.append(error_curr)
        if verbose:
            print "error:", error_curr
            print "error difference:", (error_curr - error_prev)
            error_prev = error_curr
        print "duration:", it_duration, "seconds"
        if (it > 0) and (error_curr > 0.9 * error_prev or error_curr > error_prev):
            patience += 1
        it += 1
    print ""
    return D, Z
Esempio n. 9
0
def ksvd_dict_learn(X, n_atoms, init_dict='data', sparse_coder=None,
                    max_iter=20, non_neg=False, approx=False, eta=None,
                    n_cycles=1, n_jobs=1, mmap=False, verbose=True):
    """
    The K-SVD algorithm

    X: the data matrix of shape (n_features,n_samples)
    n_atoms: the number of atoms in the dictionary
    sparse_coder: must be an instance of the sparse_coding.sparse_encoder class
    approx: if true, invokes the approximate KSVD algorithm
    max_iter: the maximum number of iterations
    non_neg: if set to True, it uses non-negativity constraints
    n_cycles: the number of updates per atom (Dictionary Update Cycles)
    n_jobs: the number of CPU threads
    mmap: if set to True, the algorithm applies memory mapping to save memory
    """
    n_features, n_samples = X.shape
    shape = (n_atoms, n_samples)
    Z = np.zeros(shape)
    # dictionary initialization
    # track the datapoints that are not used as atoms
    unused_data = []
    if init_dict == 'data':
        from .utils import init_dictionary
        D, unused_data = init_dictionary(X, n_atoms, method=init_dict, return_unused_data=True)
    else:
        D = np.copy(init_dict)

    if mmap:
        D = get_mmap(D)
        sparse_coder.mmap = True

    print "dictionary initialized"
    max_patience = 10
    error_curr = 0
    error_prev = 0
    it = 0
    patience = 0
    approx_errors = []

    while it < max_iter and patience < max_patience:
        print "----------------------------"
        print "iteration", it
        print ""
        it_start = time.time()
        if verbose:
            t_sparse_start = time.time()
        # sparse coding
        Z = sparse_coder(X, D)
        if verbose:
            t_sparse_duration = time.time() - t_sparse_start
            print "sparse coding took", t_sparse_duration, "seconds"
            t_dict_start = time.time()

        # ksvd to learn the dictionary
        set_openblas_threads(n_jobs)
        if approx:
            D, _, unused_atoms = approx_ksvd(X, D, Z, n_cycles=n_cycles)
        elif non_neg:
            D, _, unused_atoms = nn_ksvd(X, D, Z, n_cycles=it)
        else:
            D, _, unused_atoms = ksvd(X, D, Z, n_cycles=n_cycles)
        set_openblas_threads(1)
        if verbose:
            t_dict_duration = time.time() - t_dict_start
            print "K-SVD took", t_dict_duration, "seconds"
            print ""
        if verbose:
            print "number of unused atoms:", len(unused_atoms)
        # replace the unused atoms in the dictionary
        for j in range(len(unused_atoms)):
            # no datapoint available to be used as atom
            if len(unused_data) == 0:
                break
            _idx = np.random.choice(unused_data, size=1)
            idx = _idx[0]
            D[:, unused_atoms[j]] = X[:, idx]
            D[:, unused_atoms[j]] = normalize(D[:, unused_atoms[j]])
            unused_data.remove(idx)

        if eta is not None:
            # do not force incoherence in the last iteration
            if it < max_iter - 1:
                # force Mutual Incoherence
                D, unused_data = force_mi(D, X, Z, unused_data, eta)
        if verbose:
            amc = average_mutual_coherence(D)
            print "average mutual coherence:", amc

        it_duration = time.time() - it_start
        # calculate the approximation error
        error_curr = approx_error(D, Z, X, n_jobs=2)
        approx_errors.append(error_curr)
        if verbose:
            print "error:", error_curr
            print "error difference:", (error_curr - error_prev)
            error_prev = error_curr
        print "duration:", it_duration, "seconds"
        if (it > 0) and (error_curr > 0.9 * error_prev or error_curr > error_prev):
            patience += 1
        it += 1
    print ""
    return D, Z
Esempio n. 10
0
def replace_coherent_atoms(X,
                           y,
                           D,
                           n_class_atoms,
                           thresh=None,
                           kappa=None,
                           unused_data=None):
    # replace the coherent atoms of the sub-dictionaries in D
    n_classes = len(n_class_atoms)
    Xc = []
    for c in range(n_classes):
        x_c = y == c
        # extract the datapoints for
        # this class
        Xc.append(X[:, x_c])

    dicts = []
    for c in range(n_classes):
        dicts.append(D[:, get_class_atoms(c, n_class_atoms)])
    for c in range(n_classes):
        Dc = dicts[c]
        for j in range(c + 1, n_classes):
            Dj = dicts[j]
            c_atom_pairs = find_coherent_atoms(Dc,
                                               Dj,
                                               thresh=thresh,
                                               kappa=kappa)

            if unused_data is None:
                # we remove the coherent atoms from both Dc and Dj
                for c_atoms in c_atom_pairs:
                    Dc = np.delete(Dc, c_atoms[0], 1)
                    Dj = np.delete(Dj, c_atoms[1], 1)
                    n_class_atoms[c] = n_class_atoms[c] - 1
                    n_class_atoms[j] = n_class_atoms[j] - 1
            else:

                # replace them with one datapoint that
                # hasn't been used
                for c_atoms in c_atom_pairs:
                    # there are datapoints available
                    # to be used as atoms
                    if len(unused_data[c]) != 0:
                        _idx = np.random.choice(unused_data[c], size=1)
                        idx = _idx[0]
                        Dc[:, c_atoms[0]] = Xc[c][:, idx]
                        Dc[:, c_atoms[0]] = normalize(Dc[:, c_atoms[0]])
                        unused_data[c].remove(idx)

                    if len(unused_data[j]) != 0:
                        _idx = np.random.choice(unused_data[j], size=1)
                        idx = _idx[0]
                        Dj[:, c_atoms[1]] = Xc[j][:, idx]
                        Dj[:, c_atoms[1]] = normalize(Dj[:, c_atoms[1]])
                        unused_data[j].remove(idx)

                    dicts[c], dicts[j] = Dc, Dj

    # merge the sub-dictionaries
    D = dicts[0]
    for c in range(1, n_classes):
        D = np.hstack((D, dicts[c]))

    return D, n_class_atoms