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 cross_diffusion_infer(hg_list, y, iter, log=True): """ cross diffusion from the "Cross Diffusion on Multi-hypergraph for Multi-modal 3D Object Recognition" paper. :param hg_list: list, list of HyperG instance :param y: numpy array, shape = (n_nodes,) :param iter: int, iteration times of diffusion :param log: bool :return: """ assert isinstance(hg_list, list) n_hg = len(hg_list) assert n_hg >= 2 Y = init_label_matrix(y) P = [None for _ in range(n_hg)] F1 = [np.copy(Y) for _ in range(n_hg)] F2 = [np.copy(Y) for _ in range(n_hg)] # calculate transition matrix P for hg_idx in range(n_hg): H = hg_list[hg_idx].incident_matrix() w = hg_list[hg_idx].hyperedge_weights() INVDE = hg_list[hg_idx].inv_edge_degrees() S = H.dot(sparse.diags(w)).dot(INVDE).dot(H.T) INVS_S = sparse.diags(1 / S.sum(axis=1).A.reshape(-1)) P[hg_idx] = INVS_S.dot(S) for i_iter in range(iter): for hg_idx in range(n_hg): F2[hg_idx] = P[hg_idx].dot(F1[(hg_idx + 1) % n_hg]) F2[hg_idx][y != -1] = Y[y != -1] for hg_idx in range(n_hg): F1[hg_idx] = F2[hg_idx] if log: print_log("Iter: {}".format(i_iter)) F = np.zeros_like(Y) for hg_idx in range(n_hg): F += F1[hg_idx] F = F / n_hg predict_y = np.argmax(F, axis=1).reshape(-1) return predict_y[y == -1]
def multi_hg_trans_infer(hg_list, y, lbd): """ multi-hypergraph transtductive infer :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 :return: numpy array, shape = (n_test, ), predicted labels of test instances """ assert isinstance(hg_list, list) Y = init_label_matrix(y) n_nodes = Y.shape[0] THETA = np.zeros((n_nodes, n_nodes)) for i in range(len(hg_list)): THETA += hg_list[i].theta_matrix() L2 = sparse.eye(n_nodes) - (1 / (1 + lbd)) * THETA F = (((lbd + 1) / lbd) * inv(L2.A)).dot(Y) predict_y = F.argmax(axis=1).reshape(-1)[y == -1] return predict_y
def trans_infer(hg, y, lbd): """transductive inference from the "Learning with Hypergraphs: Clustering, Classification, and Embedding" paper :param hg: instance of HyperG :param y: numpy array, shape = (n_nodes,) :param lbd: float, the positive tradeoff parameter of empirical loss :return: numpy array, shape = (n_test, ), predicted labels of test instances """ assert isinstance(hg, HyperG) Y = init_label_matrix(y) n_nodes = Y.shape[0] THETA = hg.theta_matrix() L2 = sparse.eye(n_nodes) - (1 / (1 + lbd)) * THETA F = ((lbd + 1) / lbd) * inv(L2.toarray()).dot(Y) predict_y = F.argmax(axis=1).reshape(-1)[y == -1] return predict_y
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)