def orig(X, U, V, error, gamma=gamma): global ndim, size, C ndim = len(X[0]) size = len(X) C = len(V) S = np.ones((size, C)) t = 1 while True: print('--- ORIG ---') print('== t = ', t) new_U = solve_U(S, X, V, gamma) delta = l21_norm(U - new_U) U = new_U old_V = V V = update_V(S, U, X) print('DELTA V', l21_norm(V - old_V)) S = update_S(X, V, epsilon, True) # print('NMI', NMI(U)) print('DELTA', delta) if delta < error and t != 1: print('Converged at step', t) break t += 1 return U, V
def origin_update_V(x, u, v): V = np.zeros((C, ndim)) for k in range(C): A = 0 vk = v[k, :].reshape((1, ndim)) for i in range(N): xi = x[i, :].reshape((1, ndim)) V[k, :] = V[k, :] + 1 / (2 * l21_norm(xi - vk)) * u[i, k] * xi A = A + 1 / (2 * l21_norm(xi - vk)) * u[i, k] V[k, :] = V[k, :] / A return V
def solve_U(x, v, old_v, gamma): U = pymp.shared.array((N, C)) with pymp.Parallel(min(mp.cpu_count(), 4)) as p: for i in p.range(N): xi = np.repeat(x[i, :].reshape((1, ndim)), C, axis=0) norm_v = l21_norm(xi - v, axis=1) norm_v_old = l21_norm(xi - old_v, axis=1) W = welsch_func(norm_v_old) h = W + (norm_v - norm_v_old) * (1 - epsilon * W) # h = welsch_func(l21_norm(xi - v, axis=1)) h = (-h) / (2 * gamma) U[i, :] = solve_huang_eq_13(h) # U[i, :] = solve_huang_eq_13_new(h) return U
def origin_solve_U(x, v, gamma): U = np.zeros((N, C)) for i in range(N): xi = np.repeat(x[i, :].reshape((1, ndim)), C, axis=0) h = l21_norm(xi - v, axis=1) h = (-h) / (4 * gamma * epsilon**0.5 / 0.63817562) U[i, :] = solve_huang_eq_13(h) return U
def solve_U(x, v, gamma): U = np.zeros((N, C)) for i in range(N): xi = np.repeat(x[i, :].reshape((1, ndim)), C, axis=0) h = welsch_func(l21_norm(xi - v, axis=1)) h = (-h) / (2 * gamma) U[i, :] = solve_huang_eq_13(h) return U
def update_S(x, v, epsilon, capped): s = np.ones((size, C)) for i in range(len(x)): for k in range(C): norm_ = l21_norm(x[i, :] - v[k, :]) if norm_ < epsilon: s[i, k] = 1 / (2 * norm_) else: s[i, k] = 0 return s
def solve_U(s, x, v, gamma): n = s.shape[0] U = np.zeros((n, C)) for i in range(n): xi = np.repeat(x[i, :].reshape((1, ndim)), C, axis=0) h = s[i, :] * l21_norm(xi - v, axis=1)**2 h = (-h) / (2 * gamma) U[i, :] = solve_huang_eq_13(h) return U
def solve_U(x, v, gamma): N, C, ndim = len(x), len(v), len(x[0]) U = pymp.shared.array((N, C)) with pymp.Parallel(mp.cpu_count()) as p: for i in p.range(N): xi = np.repeat(x[i, :].reshape((1, ndim)), C, axis=0) h = welsch_func(l21_norm(xi - v, axis=1)) h = (-h) / (2 * gamma) U[i, :] = solve_huang_eq_13(h) return U
def run(X, C, labels, *, logger=None, init=None, multi_V=False): assert isinstance(multi_V, bool) log = logger.print if logger else __builtins__.print U, V = init_uv(X, C, method=init) t = 0 while True: log('t =', t) delta_V = 100 while delta_V > 1e-1: new_V = update_V(V, U, X) delta_V = l21_norm(new_V - V) V = new_V log('DELTA V', delta_V) if not multi_V: break new_U = solve_U(X, V, gamma) delta_U = l21_norm(U - new_U) U = new_U log('DELTA U', delta_U) log('NMI', NMI(U, labels)) if delta_U < 1e-1: log('Converged at step', t) log('NMI', NMI(U, labels)) break t += 1 return t, NMI(U, labels)
def update_V(v, u, x): W = np.zeros((N, C)) for i in range(N): for k in range(C): W[i, k] = u[i, k] * np.exp(-epsilon * l21_norm(x[i, :] - v[k, :])**2) new_v = np.zeros(v.shape) for k in range(C): denominator = W[:, k].sum() new_v[k, :] = W[:, k].reshape((1, N)) @ x / denominator return new_v
def init_uv(X, C, *, method): N, ndim = len(X), len(X[0]) assert isinstance(method, str) if method == 'random': V = np.random.random((C, ndim)) elif method == 'orig': return origin_init(X, C) else: V = _init_centroids(X, C, method) U = np.ones((N, C)) * .1 / (C - 1) for i in range(N): xi = np.repeat(X[i, :].reshape((1, ndim)), C, axis=0) U[i, np.argmin(l21_norm(xi - V, axis=1))] = .9 return U, V
def E(U, V, X, gamma, epsilon, capped): N, C, ndim = len(X), len(V), len(X[0]) # noqa term1 = 0. if capped: for i in range(N): xi = X[i, :] for k in range(C): term1 += U[i, k] * min(epsilon, distance(xi, V[k, :])) else: for i in range(N): xi = X[i, :] for k in range(C): term1 += U[i, k] * distance(xi, V[k, :]) return term1 + gamma * l21_norm(U)**2
def origin_init(X, C): N, ndim = len(X), len(X[0]) size = N def origin_solve_U(x, v, gamma): U = np.zeros((N, C)) for i in range(N): xi = np.repeat(x[i, :].reshape((1, ndim)), C, axis=0) h = l21_norm(xi - v, axis=1) h = (-h) / (4 * gamma * epsilon**0.5 / 0.63817562) U[i, :] = solve_huang_eq_13(h) return U def origin_update_V(x, u, v): V = np.zeros((C, ndim)) for k in range(C): A = 0 vk = v[k, :].reshape((1, ndim)) for i in range(N): xi = x[i, :].reshape((1, ndim)) V[k, :] = V[k, :] + 1 / (2 * l21_norm(xi - vk)) * u[i, k] * xi A = A + 1 / (2 * l21_norm(xi - vk)) * u[i, k] V[k, :] = V[k, :] / A return V V = np.random.random((C, ndim)) U = np.zeros((size, C)) while True: U = origin_solve_U(X, V, gamma) new_V = origin_update_V(X, U, V) delta = l21_norm(new_V - V) V = new_V print(delta) if delta < 1e-1: break return U, V
def U_converged(old, new, tol=5e-1): delta = l21_norm(old - new) return delta, delta < tol
if __name__ == '__main__': images, labels = mndata.load_testing() ndim = 784 size = len(labels) C = 10 X = np.array(images).reshape((size, ndim)) / 255 print(np.linalg.norm(X, axis=1)) t = 0 V = np.random.random((C, ndim)) U = np.zeros((size, C)) for i in range(size): xi = np.repeat(X[i, :].reshape((1, ndim)), C, axis=0) U[i, np.argmax(l21_norm(xi - V, axis=1))] = 1 S = np.ones((size, C)) while True: print('-------------') print('== t = ', t) new_U = solve_U(S, X, V, gamma) delta = l21_norm(U - new_U) print('DELTA U', delta) U = new_U old_V = V V = update_V(S, U, X) print('DELTA V', l21_norm(V - old_V)) old_S = S
if __name__ == '__main__': images, labels = mndata.load_testing() ndim = 784 N = size = len(labels) C = 10 X = np.array(images).reshape((size, ndim)) / 255 t = 0 V = np.random.random((C, ndim)) U = np.ones((size, C)) * .1 / (C - 1) for i in range(size): xi = np.repeat(X[i, :].reshape((1, ndim)), C, axis=0) U[i, np.argmin(l21_norm(xi - V, axis=1))] = .9 S = np.ones((size, C)) delta_U = 10 while delta_U > 0.1: print('-------------') print('== t = ', t) delta_U = 100 old_V = V.copy() new_V = update_V(old_V, U, X, epsilon) delta_V = l21_norm(new_V - V) V = new_V