Esempio n. 1
0
def remove_self_loop_edges(graph: DGLGraph):
    g_src, g_dest = graph.all_edges()
    s2d_loop = g_src - g_dest
    src, dest = g_src[s2d_loop != 0], g_dest[s2d_loop != 0]
    graph_with_out_loop = DGLGraph()
    graph_with_out_loop.add_nodes(graph.number_of_nodes())
    graph_with_out_loop.add_edges(src, dest)
    for key, value in graph.ndata.items():
        graph_with_out_loop.ndata[key] = value
    return graph_with_out_loop
Esempio n. 2
0
def reorginize_self_loop_edges(graph: DGLGraph):
    g_src, g_dest = graph.all_edges()
    s2d_loop = g_src - g_dest
    src, dest = g_src[s2d_loop != 0], g_dest[s2d_loop != 0]
    graph_reorg = DGLGraph()
    graph_reorg.add_nodes(graph.number_of_nodes())
    graph_reorg.add_edges(src, dest)
    self_loop_edge_number = (s2d_loop ==0).sum().item()
    if self_loop_edge_number > 0:
        self_src, self_dest = g_src[s2d_loop == 0], g_dest[s2d_loop == 0]
        graph_reorg.add_edges(self_src, self_dest)
    for key, value in graph.ndata.items():
        graph_reorg.ndata[key] = value
    return graph_reorg, self_loop_edge_number
Esempio n. 3
0
def graph_to_undirected(graph: DGLGraph):
    g_src, g_dest = graph.all_edges()
    s2d_loop = g_src - g_dest
    src, dest = g_src[s2d_loop != 0], g_dest[s2d_loop != 0]
    self_loop_edge_number = s2d_loop == 0
    undirected_graph = DGLGraph()
    undirected_graph.add_nodes(graph.number_of_nodes())
    undirected_graph.add_edges(src, dest)
    undirected_graph.add_edges(dest, src)
    if self_loop_edge_number.sum() > 0:
        self_src, self_dest = g_src[s2d_loop == 0], g_dest[s2d_loop == 0]
        undirected_graph.add_edges(self_src, self_dest)
    for key, value in graph.ndata.items():
        undirected_graph.ndata[key] = value
    return undirected_graph
Esempio n. 4
0
def edge_sparsemax(graph: dgl.DGLGraph, logits, eids=ALL, norm_by="dst"):
    r"""
    Description
    -----------
    Compute edge sparsemax. For a node :math:`i`, edge sparsemax is an operation that computes 

    .. math::
      a_{ij} = \text{ReLU}(z_{ij} - \tau(\z_{i,:}))
    
    where :math:`z_{ij}` is a signal of edge :math:`j\rightarrow i`, also
    called logits in the context of sparsemax. :math:`\tau` is a function
    that can be found at the `From Softmax to Sparsemax <https://arxiv.org/pdf/1602.02068.pdf>`
    paper.

    NOTE: currently only homogeneous graphs are supported.

    Parameters
    ----------
    graph : DGLGraph
        The graph to perform edge sparsemax on.
    logits : torch.Tensor
        The input edge feature.
    eids : torch.Tensor or ALL, optional
        A tensor of edge index on which to apply edge sparsemax. If ALL, apply edge
        sparsemax on all edges in the graph. Default: ALL.
    norm_by : str, could be 'src' or 'dst'
        Normalized by source nodes of destination nodes. Default: `dst`.

    Returns
    -------
    Tensor
        Sparsemax value.
    """
    # we get edge index tensors here since it is
    # hard to get edge index with HeteroGraphIndex
    # object without other information like edge_type.
    row, col = graph.all_edges(order="eid")
    assert norm_by in ["dst", "src"]
    end_n_ids = col if norm_by == "dst" else row
    if not is_all(eids):
        eids = astype(eids, graph.idtype)
        end_n_ids = end_n_ids[eids]
    return EdgeSparsemaxFunction.apply(graph._graph, logits, eids, end_n_ids,
                                       norm_by)
Esempio n. 5
0
def load_cora_data():
    data = citegrh.load_cora()
    features = th.FloatTensor(data.features)
    labels = th.LongTensor(data.labels)
    mask = th.ByteTensor(data.train_mask)
    g = DGLGraph(data.graph)
    print("g: ")
    print(g.all_edges())
    print(g.edata)
    print("features: ")
    print(features.size())
    print(features)
    print("labels: ")
    print(labels.size())
    print(labels)
    print("mask: ")
    print(mask.size())
    print(mask)
    return g, features, labels, mask
Esempio n. 6
0
def main(args):
    # graph
    coo_adj = sp.load_npz("reddit_self_loop/reddit_self_loop_graph.npz")
    graph = DGLGraph(coo_adj, readonly=True)
    # features and labels
    reddit_data = np.load("reddit_self_loop/reddit_data.npz")
    features = reddit_data["feature"]
    labels = reddit_data["label"]
    num_labels = 41
    # tarin/val/test indices
    node_ids = reddit_data["node_ids"]
    node_types = reddit_data["node_types"]
    train_mask = (node_types == 1)
    val_mask = (node_types == 2)
    test_mask = (node_types == 3)
    graph.ndata['train_mask'] = train_mask
    graph.ndata['val_mask'] = val_mask
    graph.ndata['test_mask'] = test_mask
    graph.ndata['feat'] = features
    graph.ndata['label'] = labels
    features = torch.Tensor(features)
    in_feats = features.shape[1]
    labels = torch.LongTensor(labels)
    train_nid = torch.LongTensor(np.where(train_mask == True)[0])
    train_mask = torch.BoolTensor(train_mask)
    val_nid = torch.LongTensor(np.where(val_mask == True)[0])
    val_mask = torch.BoolTensor(val_mask)
    test_nid = torch.LongTensor(np.where(test_mask == True)[0])
    test_mask = torch.BoolTensor(test_mask)

    g = dgl.graph(graph.all_edges())  # 转为HetroGraph
    g.ndata['features'] = features

    gpu = args.gpu
    use_cuda = gpu >= 0 and torch.cuda.is_available()
    if use_cuda:
        torch.cuda.set_device(gpu)
        g.to(torch.device('cuda:{}'.format(gpu)))
        labels = labels.cuda()

    fanouts = list(map(int, args.fan_out.split(',')))
    sampler = Sample(g, fanouts, args.num_neg)
    # 将数据集打乱顺序,分多个batch,每个batch采样两个B
    batch_size = args.batch_size
    num_workers = args.num_workers
    train_ids = torch.LongTensor(np.arange(g.number_of_edges()))
    dataloader = DataLoader(dataset=train_ids,
                            batch_size=batch_size,
                            collate_fn=sampler.obtain_Bs,
                            shuffle=True,
                            drop_last=False,
                            num_workers=num_workers,
                            pin_memory=True)

    # 设定模型
    num_hid = args.num_hidden
    ks = args.num_layers
    dropout_r = args.dropout
    agg = args.agg
    bias = args.bias
    norm = args.norm
    model = GraphSAGE(in_feats,
                      num_hid,
                      num_labels,
                      ks,
                      bias=bias,
                      aggregator=agg,
                      activation=F.relu,
                      norm=norm,
                      dropout=dropout_r,
                      use_cuda=use_cuda)
    if use_cuda:
        model.cuda()
    loss_fcn = Unsuper_Cross_Entropy()
    # use optimizer
    optimizer = torch.optim.Adam(model.parameters(), lr=args.lr)

    # acc
    def compute_acc(logits, labels, train_nids, val_nids, test_nids,
                    num_labels):
        # 输出标准化
        print('Computing accuracy...')
        logits = (logits - logits.mean(0)) / logits.std(
            0, unbiased=False)  # unbiased=False结果与numpy相同

        clf = LR_classification(num_labels, num_labels)
        if use_cuda:
            clf.cuda()
        criterion = nn.NLLLoss()
        optimizer = torch.optim.Adam(clf.parameters(),
                                     lr=0.003,
                                     weight_decay=1e-4)

        for epoch in range(10000):
            y_pred = clf(logits[train_nids])
            loss = criterion(y_pred, labels[train_nids])
            #if epoch % 500 == 0:
            #print('epoch: {} | loss: {}'.format(epoch, loss.item()))
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
        #print('epoch: {} | loss: {}'.format(epoch, loss.item()))

        clf.eval()
        with torch.no_grad():
            pred = clf.forward(logits)

        f1_micro_eval = (torch.argmax(pred[val_nids], dim=1)
                         == labels[val_nids]).float().sum() / val_nids.shape[0]
        f1_micro_test = (torch.argmax(
            pred[test_nids],
            dim=1) == labels[test_nids]).float().sum() / test_nids.shape[0]
        return f1_micro_eval, f1_micro_test

    # eval
    def evaluation(model, g, labels, train_nids, val_nids, test_nids,
                   batch_size, num_labels):
        model.eval()
        with torch.no_grad():
            logits = model.infer(g, batch_size)
        model.train()
        return compute_acc(logits, labels, train_nids, val_nids, test_nids,
                           num_labels)

    # link-prediction
    def link_prediction(model, g, batch_size):
        model.eval()
        with torch.no_grad():
            logits = model.infer(g, batch_size)
        model.train()

        # 计算精度...
        precise = 0
        for start in tqdm.trange(0, g.number_of_edges(), batch_size):
            end = start + batch_size
            if end > g.number_of_edges():
                end = g.number_of_edges()
            ed_ids = torch.LongTensor(np.arange(start, end))
            heads, tails = g.find_edges(ed_ids)
            src = g.ndata['z'][heads, :]
            dst = g.ndata['z'][tails, :]
            y_pred = nn.Sigmoid()((src * dst).sum(dim=1))
            prec = (y_pred >= 0.5).float().sum()
            precise = precise + prec
        precision = precise / g.number_of_edges()
        return precision

    # 训练、验证与测试
    n_epochs = args.num_epochs
    log_every = args.log_every
    eval_every = args.eval_every
    iter_pos = []
    iter_neg = []
    iter_d = []
    iter_t = []
    best_eval_acc = 0
    best_test_acc = 0
    best_precision = 0
    for epoch in range(n_epochs):
        time_epoch_0 = time.time()
        time_step = time.time()
        for step, (pos_graph, neg_graph, blocks) in enumerate(dataloader):
            input_nodes = blocks[0].srcdata[dgl.NID]
            batch_inputs = g.ndata['features'][input_nodes]
            if use_cuda:
                batch_inputs = batch_inputs.cuda()
            time_load = time.time()

            batch_pred = model(batch_inputs, blocks)
            loss = loss_fcn(batch_pred, pos_graph, neg_graph, use_cuda)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            time_train = time.time()

            edge_pos = pos_graph.number_of_edges()
            edge_neg = neg_graph.number_of_edges()
            iter_pos.append(edge_pos / (time_train - time_step))
            iter_neg.append(edge_neg / (time_train - time_step))
            iter_d.append(time_load - time_step)
            iter_t.append(time_train - time_load)
            if step % log_every == 0:
                if step == 0:
                    print(
                        'Epoch {:05d} | Step {:05d} | Loss {:.4f} | '
                        'Speed (samples/sec) {:.4f} & {:.4f} | Load Time(sec) {:.4f} | Train Time(sec) {:.4f}'
                        .format(epoch, step, loss.item(), np.mean(iter_pos),
                                np.mean(iter_neg), np.mean(iter_d),
                                np.mean(iter_t)))
                else:
                    print(
                        'Epoch {:05d} | Step {:05d} | Loss {:.4f} | '
                        'Speed (samples/sec) {:.4f} & {:.4f} | Load Time(sec) {:.4f} | Train Time(sec) {:.4f}'
                        .format(epoch, step, loss.item(),
                                np.mean(iter_pos[3:]), np.mean(iter_neg[3:]),
                                np.mean(iter_d[3:]), np.mean(iter_t[3:])))
            time_step = time.time()
            if step % eval_every == 0:
                print('\n')
                print('Eval-ing...')
                time_ev_0 = time.time()
                if args.link:
                    precision = link_prediction(model, g, batch_size)
                    if precision > best_precision:
                        best_precision = precision
                    time_ev_1 = time.time()
                    print('Precision {:.4f} | Eval Time(s): {:.4f}'.format(
                        precision, time_ev_1 - time_ev_0))
                    print('Best Precision {:.4f}'.format(best_precision))
                else:
                    eval_acc, test_acc = evaluation(model, g, labels,
                                                    train_nid, val_nid,
                                                    test_nid, batch_size,
                                                    num_labels)
                    if eval_acc > best_eval_acc:
                        best_eval_acc = eval_acc
                        best_test_acc = test_acc
                    time_ev_1 = time.time()
                    print('Eval Acc {:.4f} | Eval Time(s): {:.4f}'.format(
                        eval_acc, time_ev_1 - time_ev_0))
                    print('Best Eval Acc {:.4f} | Best Test Acc {:.4f}'.format(
                        best_eval_acc, best_test_acc))
                time_step = time.time()
            #if step == 2:
            #break

        time_epoch_1 = time.time()
        print('Epoch Time(s): {:.4f}'.format(time_epoch_1 - time_epoch_0))
        #if epoch == 1:
        #break

    print('\n')
    print('Finish!')
def main(args):
    # graph
    coo_adj = sp.load_npz("reddit_self_loop/reddit_self_loop_graph.npz")
    graph = DGLGraph(coo_adj, readonly=True)
    # features and labels
    reddit_data = np.load("reddit_self_loop/reddit_data.npz")
    features = reddit_data["feature"]
    labels = reddit_data["label"]
    num_labels = 41
    # tarin/val/test indices
    node_ids = reddit_data["node_ids"]
    node_types = reddit_data["node_types"]
    train_mask = (node_types == 1)
    val_mask = (node_types == 2)
    test_mask = (node_types == 3)
    graph.ndata['train_mask'] = train_mask
    graph.ndata['val_mask'] = val_mask
    graph.ndata['test_mask'] = test_mask
    graph.ndata['feat'] = features
    graph.ndata['label'] = labels
    features = torch.Tensor(features)
    in_feats = features.shape[1]
    labels = torch.LongTensor(labels)
    train_nid = torch.LongTensor(np.where(train_mask == True)[0])
    train_mask = torch.BoolTensor(train_mask)
    val_nid = torch.LongTensor(np.where(val_mask == True)[0])
    val_mask = torch.BoolTensor(val_mask)
    test_nid = torch.LongTensor(np.where(test_mask == True)[0])
    test_mask = torch.BoolTensor(test_mask)

    g = dgl.graph(graph.all_edges())  # 转为HetroGraph
    g.ndata['features'] = features

    gpu = args.gpu
    use_cuda = gpu >= 0 and torch.cuda.is_available()
    if use_cuda:
        torch.cuda.set_device(gpu)
        g.to(torch.device('cuda:{}'.format(gpu)))
        labels = labels.cuda()

    fanouts = list(map(int, args.fan_out.split(',')))
    sampler = Sample(g, fanouts)
    # 将数据集打乱顺序,分多个batch,每个batch采样两个B
    batch_size = args.batch_size
    num_workers = args.num_workers
    dataloader = DataLoader(dataset=train_nid.numpy(),
                            batch_size=batch_size,
                            collate_fn=sampler.obtain_Bs,
                            shuffle=True,
                            drop_last=False,
                            num_workers=num_workers)

    # 设定模型
    num_hid = args.num_hidden
    ks = args.num_layers
    dropout_r = args.dropout
    agg = args.agg
    bias = args.bias
    norm = args.norm
    model = GraphSAGE(in_feats,
                      num_hid,
                      num_labels,
                      ks,
                      bias=bias,
                      aggregator=agg,
                      activation=F.relu,
                      norm=norm,
                      dropout=dropout_r,
                      use_cuda=use_cuda)
    if use_cuda:
        model.cuda()
    loss_fcn = torch.nn.CrossEntropyLoss()
    # use optimizer
    l_r = args.lr
    optimizer = torch.optim.Adam(model.parameters(), lr=l_r)

    # acc
    def compute_acc(pred, labels):
        acc = (torch.argmax(pred, dim=1) == labels).float().sum() / len(pred)
        return acc

    # eval
    def evaluation(model, g, labels, id, batch_size):
        model.eval()
        with torch.no_grad():
            logits = model.infer(g, batch_size)
            pred = logits[id]
            label = labels[id]
        model.train()
        return compute_acc(pred, label)

    # 训练、验证与测试
    n_epochs = args.num_epochs
    log_every = args.log_every
    eval_every = args.eval_every
    avg = 0
    iter_tput = []
    for epoch in range(n_epochs):
        time_epoch_0 = time.time()
        for step, blocks in enumerate(dataloader):
            time_step = time.time()

            input_nodes = blocks[0].srcdata[dgl.NID]
            seeds = blocks[-1].dstdata[dgl.NID]  # 最后一个block的dst为batch中的节点

            batch_inputs = g.ndata['features'][input_nodes]
            batch_labels = labels[seeds]
            if use_cuda:
                batch_inputs = batch_inputs.cuda()
                batch_labels = batch_labels.cuda()

            batch_pred = model(batch_inputs, blocks)
            loss = loss_fcn(batch_pred, batch_labels)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            iter_tput.append(len(seeds) / (time.time() - time_step))
            if step % log_every == 0:
                acc = compute_acc(batch_pred, batch_labels)
                print(
                    'Epoch {:05d} | Step {:05d} | Loss {:.4f} | Train Acc {:.4f} | Speed (samples/sec) {:.4f}'
                    .format(epoch, step, loss.item(), acc.item(),
                            np.mean(iter_tput[3:])))

        time_epoch_1 = time.time()
        print('Epoch Time(s): {:.4f}'.format(time_epoch_1 - time_epoch_0))
        if epoch >= 5:
            avg += time_epoch_1 - time_epoch_0
        if epoch % eval_every == 0 and epoch != 0:
            print('\n')
            print('Eval-ing...')
            time_ev_0 = time.time()
            eval_acc = evaluation(model, g, labels, val_mask, batch_size)
            time_ev_1 = time.time()
            print('Eval Acc {:.4f} | Eval Time(s): {:.4f}'.format(
                eval_acc, time_ev_1 - time_ev_0))
    print('\n')
    print('Eval-ing...')
    time_ev_0 = time.time()
    eval_acc = evaluation(model, g, labels, val_mask, batch_size)
    time_ev_1 = time.time()
    print('Eval Acc {:.4f} | Eval Time(s): {:.4f}'.format(
        eval_acc, time_ev_1 - time_ev_0))
    print('\n')
    print('Testing...')
    time_ev_0 = time.time()
    test_acc = evaluation(model, g, labels, test_mask, batch_size)
    time_ev_1 = time.time()
    print('Test Acc {:.4f} | Eval Time(s): {:.4f}'.format(
        test_acc, time_ev_1 - time_ev_0))
    print('Finish!')
Esempio n. 8
0
    def forward(self, graph: DGLGraph, feat: Tensor, e_feat=None):
        # top-k pool first
        if e_feat is None:
            e_feat = torch.ones((graph.number_of_edges(), ),
                                dtype=feat.dtype,
                                device=feat.device)
        batch_num_nodes = graph.batch_num_nodes()
        x_score = self.calc_info_score(graph, feat, e_feat)
        perm, next_batch_num_nodes = topk(x_score, self.ratio,
                                          get_batch_id(batch_num_nodes),
                                          batch_num_nodes)
        feat = feat[perm]
        pool_graph = None
        if not self.sample or not self.sl:
            # pool graph
            graph.edata["e"] = e_feat
            pool_graph = dgl.node_subgraph(graph, perm)
            e_feat = pool_graph.edata.pop("e")
            pool_graph.set_batch_num_nodes(next_batch_num_nodes)

        # no structure learning layer, directly return.
        if not self.sl:
            return pool_graph, feat, e_feat, perm

        # Structure Learning
        if self.sample:
            # A fast mode for large graphs.
            # In large graphs, learning the possible edge weights between each
            # pair of nodes is time consuming. To accelerate this process,
            # we sample it's K-Hop neighbors for each node and then learn the
            # edge weights between them.

            # first build multi-hop graph
            row, col = graph.all_edges()
            num_nodes = graph.num_nodes()

            scipy_adj = scipy.sparse.coo_matrix(
                (e_feat.detach().cpu(),
                 (row.detach().cpu(), col.detach().cpu())),
                shape=(num_nodes, num_nodes))
            for _ in range(self.k_hop):
                two_hop = scipy_adj**2
                two_hop = two_hop * (1e-5 / two_hop.max())
                scipy_adj = two_hop + scipy_adj
            row, col = scipy_adj.nonzero()
            row = torch.tensor(row, dtype=torch.long, device=graph.device)
            col = torch.tensor(col, dtype=torch.long, device=graph.device)
            e_feat = torch.tensor(scipy_adj.data,
                                  dtype=torch.float,
                                  device=feat.device)

            # perform pooling on multi-hop graph
            mask = perm.new_full((num_nodes, ), -1)
            i = torch.arange(perm.size(0),
                             dtype=torch.long,
                             device=perm.device)
            mask[perm] = i
            row, col = mask[row], mask[col]
            mask = (row >= 0) & (col >= 0)
            row, col = row[mask], col[mask]
            e_feat = e_feat[mask]

            # add remaining self loops
            mask = row != col
            num_nodes = perm.size(0)  # num nodes after pool
            loop_index = torch.arange(0,
                                      num_nodes,
                                      dtype=row.dtype,
                                      device=row.device)
            inv_mask = ~mask
            loop_weight = torch.full((num_nodes, ),
                                     0,
                                     dtype=e_feat.dtype,
                                     device=e_feat.device)
            remaining_e_feat = e_feat[inv_mask]
            if remaining_e_feat.numel() > 0:
                loop_weight[row[inv_mask]] = remaining_e_feat
            e_feat = torch.cat([e_feat[mask], loop_weight], dim=0)
            row, col = row[mask], col[mask]
            row = torch.cat([row, loop_index], dim=0)
            col = torch.cat([col, loop_index], dim=0)

            # attention scores
            weights = (torch.cat([feat[row], feat[col]], dim=1) *
                       self.att).sum(dim=-1)
            weights = F.leaky_relu(weights,
                                   self.negative_slop) + e_feat * self.lamb

            # sl and normalization
            sl_graph = dgl.graph((row, col))
            if self.sparse:
                weights = edge_sparsemax(sl_graph, weights)
            else:
                weights = edge_softmax(sl_graph, weights)

            # get final graph
            mask = torch.abs(weights) > 0
            row, col, weights = row[mask], col[mask], weights[mask]
            pool_graph = dgl.graph((row, col))
            pool_graph.set_batch_num_nodes(next_batch_num_nodes)
            e_feat = weights

        else:
            # Learning the possible edge weights between each pair of
            # nodes in the pooled subgraph, relative slower.

            # construct complete graphs for all graph in the batch
            # use dense to build, then transform to sparse.
            # maybe there's more efficient way?
            batch_num_nodes = next_batch_num_nodes
            block_begin_idx = torch.cat([
                batch_num_nodes.new_zeros(1),
                batch_num_nodes.cumsum(dim=0)[:-1]
            ],
                                        dim=0)
            block_end_idx = batch_num_nodes.cumsum(dim=0)
            dense_adj = torch.zeros(
                (pool_graph.num_nodes(), pool_graph.num_nodes()),
                dtype=torch.float,
                device=feat.device)
            for idx_b, idx_e in zip(block_begin_idx, block_end_idx):
                dense_adj[idx_b:idx_e, idx_b:idx_e] = 1.
            row, col = torch.nonzero(dense_adj).t().contiguous()

            # compute weights for node-pairs
            weights = (torch.cat([feat[row], feat[col]], dim=1) *
                       self.att).sum(dim=-1)
            weights = F.leaky_relu(weights, self.negative_slop)
            dense_adj[row, col] = weights

            # add pooled graph structure to weight matrix
            pool_row, pool_col = pool_graph.all_edges()
            dense_adj[pool_row, pool_col] += self.lamb * e_feat
            weights = dense_adj[row, col]
            del dense_adj
            torch.cuda.empty_cache()

            # edge softmax/sparsemax
            complete_graph = dgl.graph((row, col))
            if self.sparse:
                weights = edge_sparsemax(complete_graph, weights)
            else:
                weights = edge_softmax(complete_graph, weights)

            # get new e_feat and graph structure, clean up.
            mask = torch.abs(weights) > 1e-9
            row, col, weights = row[mask], col[mask], weights[mask]
            e_feat = weights
            pool_graph = dgl.graph((row, col))
            pool_graph.set_batch_num_nodes(next_batch_num_nodes)

        return pool_graph, feat, e_feat, perm
Esempio n. 9
0
def main(args):
    # graph
    coo_adj = sp.load_npz("reddit_self_loop/reddit_self_loop_graph.npz")
    graph = DGLGraph(coo_adj, readonly=True)
    # features and labels
    reddit_data = np.load("reddit_self_loop/reddit_data.npz")
    features = reddit_data["feature"]
    labels = reddit_data["label"]
    num_labels = 41
    # tarin/val/test indices
    node_ids = reddit_data["node_ids"]
    node_types = reddit_data["node_types"]
    train_mask = (node_types == 1)
    val_mask = (node_types == 2)
    test_mask = (node_types == 3)
    graph.ndata['train_mask'] = train_mask
    graph.ndata['val_mask'] = val_mask
    graph.ndata['test_mask'] = test_mask
    graph.ndata['feat'] = features
    graph.ndata['label'] = labels
    features = torch.Tensor(features)
    in_feats = features.shape[1]
    labels = torch.LongTensor(labels)
    train_nid = torch.LongTensor(np.where(train_mask == True)[0])
    train_mask = torch.BoolTensor(train_mask)
    val_nid = torch.LongTensor(np.where(val_mask == True)[0])
    val_mask = torch.BoolTensor(val_mask)
    test_nid = torch.LongTensor(np.where(test_mask == True)[0])
    test_mask = torch.BoolTensor(test_mask)

    g = dgl.graph(graph.all_edges())  # 转为HetroGraph
    g.ndata['features'] = features

    gpu = args.gpu
    use_cuda = gpu >= 0 and torch.cuda.is_available()
    if use_cuda:
        torch.cuda.set_device(gpu)
        g.to(torch.device('cuda:{}'.format(gpu)))
        labels = labels.cuda()

    fanouts = list(map(int, args.fan_out.split(',')))
    sampler = Sample(g, fanouts, args.num_neg)
    # 将数据集打乱顺序,分多个batch,每个batch采样两个B
    batch_size = args.batch_size
    num_workers = args.num_workers
    # train_ids = torch.LongTensor(np.arange(g.number_of_edges()))
    dataloader = DataLoader(dataset=train_nid.numpy(),
                            batch_size=batch_size,
                            collate_fn=sampler.obtain_Bs,
                            shuffle=True,
                            drop_last=False,
                            num_workers=num_workers)
    #print('Loading...')
    #t0 = time.time()
    #DLoaders = []
    #for step, (pos_graph, neg_graph, blocks) in enumerate(dataloader):
    #DLoaders.append((step, (pos_graph, neg_graph, blocks)))
    #t1 = time.time()
    #print('Step {} | {} s'.format(step, t1-t0))
    #t0 = time.time()

    # 设定模型
    num_hid = args.num_hidden
    ks = args.num_layers
    dropout_r = args.dropout
    agg = args.agg
    bias = args.bias
    norm = args.norm
    model = GraphSAGE(in_feats,
                      num_hid,
                      num_labels,
                      ks,
                      bias=bias,
                      aggregator=agg,
                      activation=F.relu,
                      norm=norm,
                      dropout=dropout_r,
                      use_cuda=use_cuda)
    if use_cuda:
        model.cuda()
    loss_fcn = Unsuper_Cross_Entropy()
    # use optimizer
    optimizer = torch.optim.Adam(model.parameters(), lr=args.lr)

    # acc
    def compute_acc(logits, labels, train_nids, val_nids, test_nids):
        logits = logits.cpu().numpy()
        labels = labels.cpu().numpy()
        train_nids = train_nids.cpu().numpy()
        val_nids = val_nids.cpu().numpy()
        test_nids = test_nids.cpu().numpy()

        # 输出标准化
        logits = (logits - logits.mean(0)) / logits.std(0)

        clf = LogisticRegression(multi_class='multinomial', max_iter=10000)
        clf.fit(logits[train_nids], labels[train_nid])

        pred = clf.predict(logits)
        '''
        pred = torch.argmax(logits, dim=1)
        f1_micro_eval = ((pred[val_nids] == labels[val_nids]).float().sum() / pred[val_nids].shape[0]).item()
        f1_micro_test = ((pred[test_nids] == labels[test_nids]).float().sum() / pred[test_nids].shape[0]).item()
        '''
        f1_micro_eval = metrics.f1_score(labels[val_nids],
                                         pred[val_nids],
                                         average='micro')
        f1_micro_test = metrics.f1_score(labels[test_nids],
                                         pred[test_nids],
                                         average='micro')
        return f1_micro_eval, f1_micro_test

    # eval
    def evaluation(model, g, labels, train_nids, val_nids, test_nids,
                   batch_size):
        model.eval()
        with torch.no_grad():
            logits = model.infer(g, batch_size)
        model.train()
        return compute_acc(logits, labels, train_nids, val_nids, test_nids)

    # 训练、验证与测试
    n_epochs = args.num_epochs
    log_every = args.log_every
    eval_every = args.eval_every
    iter_pos = []
    iter_neg = []
    iter_d = []
    iter_t = []
    best_eval_acc = 0
    best_test_acc = 0
    for epoch in range(n_epochs):
        time_epoch_0 = time.time()
        time_step = time.time()
        for step, (pos_graph, neg_graph, blocks) in enumerate(dataloader):
            #for (step, (pos_graph, neg_graph, blocks)) in DLoaders:
            input_nodes = blocks[0].srcdata[dgl.NID]
            batch_inputs = g.ndata['features'][input_nodes]
            if use_cuda:
                batch_inputs = batch_inputs.cuda()
            time_load = time.time()

            batch_pred = model(batch_inputs, blocks)
            loss = loss_fcn(batch_pred, pos_graph, neg_graph, use_cuda)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            time_train = time.time()

            edge_pos = pos_graph.number_of_edges()
            edge_neg = neg_graph.number_of_edges()
            iter_pos.append(edge_pos / (time_train - time_step))
            iter_neg.append(edge_neg / (time_train - time_step))
            iter_d.append(time_load - time_step)
            iter_t.append(time_train - time_load)

            if step % log_every == 0:
                if step == 0:
                    print(
                        'Epoch {:05d} | Step {:05d} | Loss {:.4f} | '
                        'Speed (samples/sec) {:.4f} & {:.4f} | Load Time(sec) {:.4f} | Train Time(sec) {:.4f}'
                        .format(epoch, step, loss.item(), np.mean(iter_pos),
                                np.mean(iter_neg), np.mean(iter_d),
                                np.mean(iter_t)))
                else:
                    print(
                        'Epoch {:05d} | Step {:05d} | Loss {:.4f} | '
                        'Speed (samples/sec) {:.4f} & {:.4f} | Load Time(sec) {:.4f} | Train Time(sec) {:.4f}'
                        .format(epoch, step, loss.item(),
                                np.mean(iter_pos[3:]), np.mean(iter_neg[3:]),
                                np.mean(iter_d[3:]), np.mean(iter_t[3:])))

            time_step = time.time()
            #if step == 2:
            #break

        if epoch % eval_every == 0:
            print('\n')
            print('Eval-ing...')
            time_ev_0 = time.time()
            eval_acc, test_acc = evaluation(model, g, labels, train_nid,
                                            val_nid, test_nid, batch_size)
            if eval_acc > best_eval_acc:
                best_eval_acc = eval_acc
                best_test_acc = test_acc
            time_ev_1 = time.time()
            print('Eval Acc {:.4f} | Eval Time(s): {:.4f}'.format(
                eval_acc, time_ev_1 - time_ev_0))
            print('Best Eval Acc {:.4f} | Best Test Acc {:.4f}'.format(
                best_eval_acc, best_test_acc))
            time_step = time.time()
            #if epoch == 1:
            #break

        time_epoch_1 = time.time()
        print('Epoch Time(s): {:.4f}'.format(time_epoch_1 - time_epoch_0))
    if eval_every != 1:
        print('\n')
        print('Eval-ing...')
        time_ev_0 = time.time()
        eval_acc, test_acc = evaluation(model, g, labels, train_nid, val_nid,
                                        test_nid, batch_size)
        if eval_acc > best_eval_acc:
            best_eval_acc = eval_acc
            best_test_acc = test_acc
        time_ev_1 = time.time()
        print('Eval Acc {:.4f} | Eval Time(s): {:.4f}'.format(
            eval_acc, time_ev_1 - time_ev_0))
        print('Best Eval Acc {:.4f} | Best Test Acc {:.4f}'.format(
            best_eval_acc, best_test_acc))
    print('\n')
    print('Finish!')