def multi_hg_weighting_trans_infer(hg_list, y, lbd, mu, max_iter, log=True): """ multi-hypergraph weighting from the "3-D Object Retrieval and Recognition With Hypergraph Analysis" :param hg_list: list, list of HyperG instance :param y: numpy array, shape = (n_nodes,) :param lbd: float, the positive tradeoff parameter of empirical loss :param mu: float, the positive tradeoff parameter of the l2 norm on hypergraph weights :param max_iter: int, maximum iteration times of alternative optimization. :param log: bool :return: numpy array, shape = (n_test, ), predicted labels of test instances """ assert max_iter > 0 loss = [] prev_F = None Y = init_label_matrix(y) n_hg = len(hg_list) n_nodes = len(y) omega = np.zeros(n_hg) hg_weights = np.ones(n_hg)/n_hg for i_iter in range(max_iter): print_log("hypergraph weights: {}".format(str(hg_weights))) # update F THETA = None for idx in range(len(hg_list)): if THETA is None: THETA = hg_weights[idx] * hg_list[idx].theta_matrix() else: THETA += hg_weights[idx] * hg_list[idx].theta_matrix() L2 = sparse.eye(n_nodes) - (1 / (1 + lbd)) * THETA F = ((lbd + 1) / lbd) * inv(L2.toarray()).dot(Y) # update hg_weight for idx in range(n_hg): omega[idx] = np.trace(F.T.dot(np.eye(n_nodes) + hg_list[idx].theta_matrix()).dot(F)) # TODO for idx in range(n_hg): hg_weights[idx] = 1. / n_hg + np.sum(omega) / (2 * mu * n_hg) - omega[idx] / (2 * mu) # loss i_loss = np.sum(omega * hg_weights) + lbd * np.linalg.norm(F - Y) loss.append(i_loss) if log: print_log("Iter: {}; loss:{:.5f}".format(i_iter, i_loss)) if i_iter > 0 and (i_loss - loss[-2]) > 0.: print_log("Iteration stops after {} round.".format(i_iter)) F = prev_F break prev_F = F predict_y = F.argmax(axis=1).reshape(-1)[y == -1] return predict_y
def main(): print_log("loading data") X_train, X_test, y_train, y_test = load_modelnet(selected_mod=(0, 1)) X = [np.vstack((X_train[imod], X_test[imod])) for imod in range(len(X_train))] y = np.concatenate((y_train, -1 * np.ones_like(y_test))) print_log("generating hypergraph") hg_list = [ gen_knn_hg(X[imod], n_neighbors=10) for imod in range(len(X_train)) ] print_log("learning on hypergraph") y_predict = multi_hg_trans_infer(hg_list, y, lbd=100) print_log("accuracy: {}".format(accuracy_score(y_test, y_predict)))
def main(): print_log("loading data") X_train, X_test, y_train, y_test = load_myocardium([3]) X = np.concatenate([X_train, X_test], axis=0) y = np.concatenate( [y_train.reshape(-1), -1 * np.ones_like(y_test).reshape(-1)]) print_log("generating hypergraph") # grid hg grid_hg_s = [gen_grid_neigh_hg(X[i].shape) for i in range(X.shape[0])] grid_hg = fuse_mutli_sub_hg(grid_hg_s) # knn hg X_patch_ft = np.stack([ gather_patch_ft(X[i][:, :, np.newaxis], (5, 5)) for i in range(X.shape[0]) ]) knn_hg = gen_knn_hg(X_patch_ft.reshape(-1, X_patch_ft.shape[-1]), n_neighbors=7) # concatfeat hg concat_hg = concat_multi_hg([grid_hg, knn_hg]) print_log("learning on hypergraph") y_predict = trans_infer(concat_hg, y, 100) print_log("iou: {}".format(iou_socre(y_predict, y_test.reshape(-1)))) print_log("postprocessing") y_postpro = postprocess(y_predict.reshape(y_test.shape)) print_log("iou(postprocess): {}".format( iou_socre(y_postpro.reshape(-1), y_test.reshape(-1)))) # visualize print_log("visualizing") fig = plt.figure() ax1 = fig.add_subplot(2, 2, 1) ax1.imshow(X_test.squeeze()) ax1.title.set_text('X_test') ax1.axis('off') ax2 = fig.add_subplot(2, 2, 2) ax2.imshow(y_test.squeeze()) ax2.title.set_text('y_test') ax2.axis('off') ax3 = fig.add_subplot(2, 2, 3) ax3.imshow(y_predict.reshape(y_test.squeeze().shape)) ax3.title.set_text('y_predict') ax3.axis('off') ax4 = fig.add_subplot(2, 2, 4) ax4.imshow(y_postpro.reshape(y_test.squeeze().shape)) ax4.title.set_text('y_postpro') ax4.axis('off') plt.show()
def hyedge_weighting_trans_infer(hg, y, lbd, mu, max_iter=15, log=True): """ hyperedge weighting from the "Visual-Textual Joint Relevance Learning for Tag-Based Social Image Search" paper :param hg: instance of HyperG :param y: numpy array, shape = (n_nodes,) :param lbd: float, the positive tradeoff parameter of empirical loss :param mu: float, the positive tradeoff parameter of hyperedge weights :param max_iter: int, maximum iteration times of alternative optimization :param log: bool :return: numpy array, shape = (n_test, ), predicted labels of test instances """ assert max_iter > 0 loss = [] prev_F = None Y = init_label_matrix(y) for i_iter in range(max_iter): # update F if i_iter > 0: prev_F = F F = _transductive_one_step(hg, Y, lbd) # update w n_edges = hg.num_edges() H = hg.incident_matrix() DV = hg.node_degrees() DV2 = hg.inv_square_node_degrees() invde = hg.inv_edge_degrees().data.reshape(-1) dv = DV.data.reshape(-1) Tau = DV2.dot(H).toarray() C = np.zeros((n_edges, 1)) for i in range(n_edges): C[i, 0] = -invde[i] * np.trace( np.sum(np.power(F.T.dot(Tau[:, i].reshape(-1, 1)), 2.), axis=0, keepdims=True) ) # update w --- optimization Dense_H = H.toarray() w = cp.Variable(n_edges, nonneg=True) objective = cp.Minimize((1 / 2) * cp.quad_form(w, 2 * mu * np.eye(n_edges)) + C.T @ w) constraints = [Dense_H @ w == dv, w >= np.zeros(n_edges)] prob = cp.Problem(objective, constraints) prob.solve() hg.update_hyedge_weights(w.value) # loss hg_reg_loss = np.trace(F.T.dot(hg.laplacian().dot(F))) emp_loss = np.linalg.norm(F - Y) w_loss = np.sum(np.power(w.value, 2.)) i_loss = hg_reg_loss + lbd * emp_loss + w_loss loss.append(i_loss) # log if log: print_log("Iter: {}; loss:{:.5f}".format(i_iter, i_loss)) if i_iter > 0 and (i_loss - loss[-2]) > 0.: print_log("Iteration stops after {} round.".format(i_iter)) F = prev_F break predict_y = F.argmax(axis=1).reshape(-1)[y == -1] return predict_y
def tensor_hg_trans_infer(X, y, lbd, alpha, mu, stepsize, max_iter=50, hsl_iter=10, log=True, stop=True): """ tensor-based (dynamic) hypergraph learning :param X: numpy array, shape = (n_nodes, n_features) :param y: numpy array, shape = (n_nodes,) -1 for the unlabeled data, 0,1,2.. for the labeled data :param lbd: float, the positive tradeoff parameter of empirical loss :param alpha: float, :param mu: float, :param stepsize: float :param max_iter: int, maximum iteration times of alternative optimization :param hsl_iter: int, the number of iterations in the process of updating hypergraph tensor :param log: bool :param stop: boolean, :return: numpy array, shape = (n_test, ), predicted labels of test instances """ if log: print_log("parameters: lambda:{}\talpha:{}\tmu:{}\tstepsize:{}".format(lbd, alpha, mu, stepsize)) n_nodes = X.shape[0] # init Y Y = init_label_matrix(y) ceil_logn = np.ceil(np.log(n_nodes)).astype('int') # init tensor hypergraph T = np.ones((1, n_nodes * ceil_logn)) mED = pairwise_distances(X) neighbors = np.asarray(np.argsort(mED, axis=1, kind='stable')) neighbors = neighbors[:, 1:(ceil_logn + 1)] # calculate S S = np.zeros((n_nodes, n_nodes)) delta_omega = np.arange(2, ceil_logn + 2) delta_omega = np.tile(delta_omega, (n_nodes, 1)) delta_omega = delta_omega.reshape((1, -1), order='F') t_iter = 0 for i in range(ceil_logn): for j in range(n_nodes): if T[0, t_iter] == 0: continue clique = [j] + neighbors[j, 0:i + 1].tolist() indexs = np.array(list(combinations(clique, 2))) S[indexs[:, 0], indexs[:, 1]] = S[indexs[:, 0], indexs[:, 1]] + T[0, t_iter] / delta_omega[0, t_iter] t_iter = t_iter + 1 S = S + S.T c = 1 / (1 + alpha) F = np.linalg.inv(np.eye(n_nodes) + (2 * c / lbd) * (np.diag(np.sum(S, axis=0)) - S)) @ Y T0 = T fH_value = [] loss = [] prev_F = None for i_iter in range(max_iter): FED = pairwise_distances(F) f = np.zeros((1, T.shape[1])) f_iter = 0 for i in range(ceil_logn): for j in range(n_nodes): clique = [j] + neighbors[j, 0:i + 1].tolist() indexs = np.array(list(combinations(clique, 2))) tmp1 = np.sum(FED[indexs[:, 0], indexs[:, 1]], axis=0) tmp2 = np.sum(mED[indexs[:, 0], indexs[:, 1]], axis=0) f[0, f_iter] = (tmp1 + alpha * tmp2) / ((1 + alpha) * delta_omega[0, f_iter]) f_iter = f_iter + 1 for iter2 in range(hsl_iter): dfT = f + 2 * mu * (T - T0) T = T - stepsize * dfT T[T < 0] = 0 T[T > 1] = 1 fH_value.append( (f @ T.T).reshape(-1)[0] + lbd * np.power(np.linalg.norm(F - Y, ord='fro'), 2.) + mu * np.power( np.linalg.norm(T - T0, ord='fro'), 2)) S = np.zeros((n_nodes, n_nodes)) t_iter = 0 for i in range(ceil_logn): for j in range(n_nodes): if T[0, t_iter] != 0: clique = [j] + neighbors[j, 0:i + 1].tolist() indexs = np.array(list(combinations(clique, 2))) S[indexs[:, 0], indexs[:, 1]] = S[indexs[:, 0], indexs[:, 1]] + T[0, t_iter] / delta_omega[0, t_iter] t_iter = t_iter + 1 S = S + S.T c = 1 / (1 + alpha) F = np.linalg.inv(np.eye(n_nodes) + (2 * c / lbd) * (np.diag(np.sum(S, 0)) - S)) @ Y fh = (f @ T.T).reshape(-1)[0] + lbd * np.power(np.linalg.norm(F - Y, ord='fro'), 2.) + mu * np.power( np.linalg.norm(T - T0, ord='fro'), 2) if log: loss.append(fh) print_log("Iter: {}; loss:{:.5f}".format(i_iter, fh)) fH_value.append(fh) if stop: if len(loss) >= 2 and loss[-1] > loss[-2]: print_log("Stop at iteration :{}".format(i_iter)) F = prev_F break prev_F = F predict_y = np.argmax(F, axis=1).reshape(-1)[y == -1] return predict_y
def dyna_hg_trans_infer(hg, y, lbd, stepsize, beta, max_iter, hsl_iter, log=True): """dynamic hypergraph structure learning from the "Dynamic Hypergraph Structure Learning" paper. :param hg: instance of HyperG :param y: numpy array, shape = (n_nodes,) :param lbd: float, the positive tradeoff parameter of empirical loss :param stepsize: float :param beta: float, the positive tradeoff parameter of regularizer on H in the feature space loss :param max_iter: int, maximum iteration times of alternative optimization. :param hsl_iter: int, the number of iterations in the process of updating hypergraph incident matrix :param log: bool :return: numpy array, shape = (n_test, ), predicted labels of test instances """ if log: print_log("alpha:{}\tbeta:{}".format(stepsize, beta)) n_nodes = hg.num_nodes() Y = init_label_matrix(y) a = np.ones(n_nodes) a[y != -1] = 1e-4 A = sparse.diags(a) X = hg.node_features() assert X is not None, "hg instance should be constructed with the parameter of 'with_feature=True'" F = _dhsl_update_f(hg, Y, A, lbd) for i_iter in range(max_iter): # update H C = (1 - beta) * F.dot(F.T) + beta * X.dot(X.T) for i_hsl in range(hsl_iter): # sparse DV2 = hg.inv_square_node_degrees() INVDE = hg.inv_edge_degrees() W = sparse.diags(hg.hyperedge_weights()) # dense H = hg.incident_matrix() WDHD = W.dot(INVDE).dot(H.T).dot(DV2).todense() H = H.todense() DCD = sparse.dia_matrix.dot(DV2.dot(C), DV2) term3 = 2 * sparse.coo_matrix.dot(DCD.dot(H), W.dot(INVDE)) tmp = np.diag(H.T.dot(DCD).dot(H)).reshape(1, -1) term2 = - np.tile(sparse.csr_matrix.dot(tmp, W.dot(INVDE).dot(INVDE)), (n_nodes, 1)) term1 = - DV2.dot(DV2).dot(DV2).dot(np.diag(H.dot(WDHD).dot(C)).reshape(-1, 1)).dot( hg.hyperedge_weights().reshape(1, -1) ) dfH = term1 + term2 + term3 H = H + stepsize * dfH H[H < 0] = 0 H[H > 1] = 1 H = sparse.coo_matrix(H) hg.update_incident_matrix(H) # update F F = _dhsl_update_f(hg, Y, A, lbd) if log: print_log("Iter: {}".format(i_iter)) predict_y = F.argmax(axis=1).reshape(-1)[y == -1] return predict_y
def inductive_fit(hg, y, lbd, mu, eta, max_iter, log=True): """ inductive multi-hypergraph learning from the "Inductive Multi-Hypergraph Learning and Its Application on View-Based 3D Object Classification" (you should call the inductive_fit first and then call the inductive_predict to predict unlabeled instances) :param hg: instance of HyperG or list :param y: numpy array, shape = (n_nodes,) :param lbd: float, the positive tradeoff parameter of empirical loss. :param mu: float, the positive tradeoff parameter of the regularizer on projection matrix. :param eta: float, the positive tradeoff parameter of the l2 norm on hypergraph weights :param max_iter: int, maximum iteration times of alternative optimization. :param log: bool :return: instance of IMHL """ assert isinstance(hg, (HyperG, list)) assert isinstance(y, (np.ndarray, list)) if isinstance(hg, HyperG): hg_list = [hg] else: hg_list = hg n_hg = len(hg_list) Y = init_label_matrix(y) M = [None for _ in range(n_hg)] omega = np.zeros(n_hg) loss = np.zeros(n_hg) for hg_idx in range(n_hg): if log: print_log("processing I_HG :{}".format(hg_idx)) X = hg_list[hg_idx].node_features() L = hg_list[hg_idx].laplacian() _, n_features = X.shape INVU = np.eye(n_features) for i_iter in range(max_iter): # fix U, update M A = sparse.csr_matrix.dot(X.T, L).dot(X) + lbd * X.T.dot(X) TMP = np.linalg.inv(A.dot(INVU) + mu * np.eye(n_features)) M[hg_idx] = lbd * INVU.dot(TMP).dot(X.T).dot(Y) # fix M, update U invu = np.sqrt(np.sum(np.power(M[hg_idx], 2.), axis=1)).reshape(-1) INVU = 2 * np.diag(invu) g_reg_term = np.trace(M[hg_idx].T.dot(X.T).dot( L.dot(X).dot(M[hg_idx]))) emp_loss_term = np.power(np.linalg.norm(X.dot(M[hg_idx]) - Y), 2) m_reg_term = np.sum( [np.linalg.norm(M[hg_idx][i, :]) for i in range(n_features)]) i_loss = g_reg_term + lbd * emp_loss_term + mu * m_reg_term if log: print_log("I_HG: {}; loss:{:.5f}".format(hg_idx, i_loss)) loss[hg_idx] = i_loss for hg_idx in range(n_hg): omega[hg_idx] = 1. / n_hg + np.sum(loss) / ( 2 * n_hg * eta) - loss[hg_idx] / (2 * eta) if log: print("hypergraph weights:{}".format(omega)) return IMHL(M, omega)
def gen_l1_hg(X, gamma, n_neighbors, log=False, with_feature=False): """ :param X: numpy array, shape = (n_samples, n_features) :param gamma: float, the tradeoff parameter of the l1 norm on representation coefficients :param n_neighbors: int, :param log: bool :param with_feature: bool, optional(default=False) :return: instance of HyperG """ assert n_neighbors >= 1. assert isinstance(X, np.ndarray) assert X.ndim == 2 n_nodes = X.shape[0] n_edges = n_nodes m_dist = pairwise_distances(X) m_neighbors = np.argsort(m_dist)[:, 0:n_neighbors + 1] edge_idx = np.tile( np.arange(n_edges).reshape(-1, 1), (1, n_neighbors + 1)).reshape(-1) node_idx = [] values = [] for i_edge in range(n_edges): if log: print_log("processing edge {} ".format(i_edge)) neighbors = m_neighbors[i_edge].tolist() if i_edge in neighbors: neighbors.remove(i_edge) else: neighbors = neighbors[:-1] P = X[neighbors, :] v = X[i_edge, :] # cvxpy x = cp.Variable(P.shape[0], nonneg=True) objective = cp.Minimize( cp.norm((P.T @ x).T - v, 2) + gamma * cp.norm(x, 1)) # objective = cp.Minimize(cp.norm(x@P-v, 2) + gamma * cp.norm(x, 1)) prob = cp.Problem(objective) try: prob.solve() except SolverError: prob.solve(solver='SCS', verbose=False) node_idx.extend([i_edge] + neighbors) values.extend([1.] + x.value.tolist()) node_idx = np.array(node_idx) values = np.array(values) H = sparse.coo_matrix((values, (node_idx, edge_idx)), shape=(n_nodes, n_edges)) if with_feature: return HyperG(H, X=X) return HyperG(H)