def train_model(args, dl, vgae):
    optimizer = torch.optim.Adam(vgae.parameters(), lr=args.lr)
    adj_t = dl.adj_train
    norm_w = ((adj_t.shape[0] ** 2) / float((((adj_t.shape[0] ** 2) - adj_t.sum()) * 2)))
    pos_weight = torch.FloatTensor([(float(((adj_t.shape[0] ** 2) - adj_t.sum())) / adj_t.sum())]).to(args.device)
    features = dl.features.to(args.device)
    adj_label = dl.adj_label.to_dense().to(args.device)
    best_vali_criterion = 0.0
    best_state_dict = None
    vgae.train()
    for epoch in range(args.epochs):
        t = time.time()
        A_pred = vgae(features)
        optimizer.zero_grad()
        loss = log_lik = (norm_w * F.binary_cross_entropy_with_logits(A_pred, adj_label, pos_weight=pos_weight))
        if (not args.gae):
            kl_divergence = ((0.5 / A_pred.size(0)) * (((1 + (2 * vgae.logstd)) - (vgae.mean ** 2)) - torch.exp((2 * vgae.logstd))).sum(1).mean())
            loss -= kl_divergence
        A_pred = torch.sigmoid(A_pred).detach().cpu()
        r = get_scores(dl.val_edges, dl.val_edges_false, A_pred, dl.adj_label)
        print('Epoch{:3}: train_loss: {:.4f} recon_acc: {:.4f} val_roc: {:.4f} val_ap: {:.4f} f1: {:.4f} time: {:.4f}'.format((epoch + 1), loss.item(), r['acc'], r['roc'], r['ap'], r['f1'], (time.time() - t)))
        if (r[args.criterion] > best_vali_criterion):
            best_vali_criterion = r[args.criterion]
            best_state_dict = copy.deepcopy(vgae.state_dict())
            r_test = r
            print('          test_roc: {:.4f} test_ap: {:.4f} test_f1: {:.4f} test_recon_acc: {:.4f}'.format(r_test['roc'], r_test['ap'], r_test['f1'], r_test['acc']))
        loss.backward()
        optimizer.step()
    print('Done! final results: test_roc: {:.4f} test_ap: {:.4f} test_f1: {:.4f} test_recon_acc: {:.4f}'.format(r_test['roc'], r_test['ap'], r_test['f1'], r_test['acc']))
    vgae.load_state_dict(best_state_dict)
    return vgae
def train_model(args, dl, vgae):
    optimizer = torch.optim.Adam(vgae.parameters(), lr=args.lr)
    adj_t = dl.adj_train
    norm_w = ((adj_t.shape[0] ** 2) / float((((adj_t.shape[0] ** 2) - adj_t.sum()) * 2)))
    pos_weight = torch.FloatTensor([(float(((adj_t.shape[0] ** 2) - adj_t.sum())) / adj_t.sum())]).to(args.device)
    features = dl.features.to(args.device)
    adj_label = dl.adj_label.to_dense().to(args.device)
    best_vali_criterion = 0.0
    best_state_dict = None
    vgae.train()
    for epoch in range(args.epochs):
        t = time.time()
        A_pred = vgae(features)
        optimizer.zero_grad()
        loss = log_lik = (norm_w * F.binary_cross_entropy_with_logits(A_pred, adj_label, pos_weight=pos_weight))
        if (not args.gae):
            kl_divergence = ((0.5 / A_pred.size(0)) * (((1 + (2 * vgae.logstd)) - (vgae.mean ** 2)) - torch.exp((2 * vgae.logstd))).sum(1).mean())
            loss -= kl_divergence
        A_pred = torch.sigmoid(A_pred).detach().cpu()
        r = get_scores(dl.val_edges, dl.val_edges_false, A_pred, dl.adj_label)
        print('Epoch{:3}: train_loss: {:.4f} recon_acc: {:.4f} val_roc: {:.4f} val_ap: {:.4f} f1: {:.4f} time: {:.4f}'.format((epoch + 1), loss.item(), r['acc'], r['roc'], r['ap'], r['f1'], (time.time() - t)))
        if (r[args.criterion] > best_vali_criterion):
            best_vali_criterion = r[args.criterion]
            best_state_dict = copy.deepcopy(vgae.state_dict())
            r_test = r
            print('          test_roc: {:.4f} test_ap: {:.4f} test_f1: {:.4f} test_recon_acc: {:.4f}'.format(r_test['roc'], r_test['ap'], r_test['f1'], r_test['acc']))
        loss.backward()
        optimizer.step()
    print('Done! final results: test_roc: {:.4f} test_ap: {:.4f} test_f1: {:.4f} test_recon_acc: {:.4f}'.format(r_test['roc'], r_test['ap'], r_test['f1'], r_test['acc']))
    vgae.load_state_dict(best_state_dict)
    return vgae