"docs/references/multi_node_deployment/multi_node.md" did not exist on "9af0e21ef5f2b61c64ca53237642aa2ac6da4fe3"
train.py 5.2 KB
Newer Older
1
2
import argparse
import time
3

4
5
6
7
import numpy as np
import tensorflow as tf
from gcn import GCN

8
9
10
import dgl
from dgl.data import CiteseerGraphDataset, CoraGraphDataset, PubmedGraphDataset

11
12
13
14
15
16
17
18
19
20
21
22

def evaluate(model, features, labels, mask):
    logits = model(features, training=False)
    logits = logits[mask]
    labels = labels[mask]
    indices = tf.math.argmax(logits, axis=1)
    acc = tf.reduce_mean(tf.cast(indices == labels, dtype=tf.float32))
    return acc.numpy().item()


def main(args):
    # load and preprocess dataset
23
    if args.dataset == "cora":
24
        data = CoraGraphDataset()
25
    elif args.dataset == "citeseer":
26
        data = CiteseerGraphDataset()
27
    elif args.dataset == "pubmed":
28
29
        data = PubmedGraphDataset()
    else:
30
        raise ValueError("Unknown dataset: {}".format(args.dataset))
31

32
    g = data[0]
33
34
35
36
    if args.gpu < 0:
        device = "/cpu:0"
    else:
        device = "/gpu:{}".format(args.gpu)
37
        g = g.to(device)
38
39

    with tf.device(device):
40
41
42
43
44
        features = g.ndata["feat"]
        labels = g.ndata["label"]
        train_mask = g.ndata["train_mask"]
        val_mask = g.ndata["val_mask"]
        test_mask = g.ndata["test_mask"]
45
46
47
        in_feats = features.shape[1]
        n_classes = data.num_labels
        n_edges = data.graph.number_of_edges()
48
49
        print(
            """----Data statistics------'
50
51
52
53
        #Edges %d
        #Classes %d
        #Train samples %d
        #Val samples %d
54
55
56
57
58
59
60
61
62
        #Test samples %d"""
            % (
                n_edges,
                n_classes,
                train_mask.numpy().sum(),
                val_mask.numpy().sum(),
                test_mask.numpy().sum(),
            )
        )
63

64
        # add self loop
65
        if args.self_loop:
66
67
            g = dgl.remove_self_loop(g)
            g = dgl.add_self_loop(g)
68
69
70
71
72
73
        n_edges = g.number_of_edges()
        # normalization
        degs = tf.cast(tf.identity(g.in_degrees()), dtype=tf.float32)
        norm = tf.math.pow(degs, -0.5)
        norm = tf.where(tf.math.is_inf(norm), tf.zeros_like(norm), norm)

74
        g.ndata["norm"] = tf.expand_dims(norm, -1)
75
76

        # create GCN model
77
78
79
80
81
82
83
84
85
        model = GCN(
            g,
            in_feats,
            args.n_hidden,
            n_classes,
            args.n_layers,
            tf.nn.relu,
            args.dropout,
        )
86
87

        loss_fcn = tf.keras.losses.SparseCategoricalCrossentropy(
88
89
            from_logits=True
        )
90
91
        # use optimizer
        optimizer = tf.keras.optimizers.Adam(
92
93
            learning_rate=args.lr, epsilon=1e-8
        )
94
95
96
97
98
99
100
101
102
103
104

        # initialize graph
        dur = []
        for epoch in range(args.n_epochs):
            if epoch >= 3:
                t0 = time.time()
            # forward
            with tf.GradientTape() as tape:
                logits = model(features)
                loss_value = loss_fcn(labels[train_mask], logits[train_mask])
                # Manually Weight Decay
105
                # We found Tensorflow has a different implementation on weight decay
106
107
108
                # of Adam(W) optimizer with PyTorch. And this results in worse results.
                # Manually adding weights to the loss to do weight decay solves this problem.
                for weight in model.trainable_weights:
109
110
111
                    loss_value = loss_value + args.weight_decay * tf.nn.l2_loss(
                        weight
                    )
112
113
114
115
116
117
118

                grads = tape.gradient(loss_value, model.trainable_weights)
                optimizer.apply_gradients(zip(grads, model.trainable_weights))
            if epoch >= 3:
                dur.append(time.time() - t0)

            acc = evaluate(model, features, labels, val_mask)
119
120
121
122
123
124
125
126
127
128
            print(
                "Epoch {:05d} | Time(s) {:.4f} | Loss {:.4f} | Accuracy {:.4f} | "
                "ETputs(KTEPS) {:.2f}".format(
                    epoch,
                    np.mean(dur),
                    loss_value.numpy().item(),
                    acc,
                    n_edges / np.mean(dur) / 1000,
                )
            )
129
130
131
132
133

        acc = evaluate(model, features, labels, test_mask)
        print("Test Accuracy {:.4f}".format(acc))


134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="GCN")
    parser.add_argument(
        "--dataset",
        type=str,
        default="cora",
        help="Dataset name ('cora', 'citeseer', 'pubmed').",
    )
    parser.add_argument(
        "--dropout", type=float, default=0.5, help="dropout probability"
    )
    parser.add_argument("--gpu", type=int, default=-1, help="gpu")
    parser.add_argument("--lr", type=float, default=1e-2, help="learning rate")
    parser.add_argument(
        "--n-epochs", type=int, default=200, help="number of training epochs"
    )
    parser.add_argument(
        "--n-hidden", type=int, default=16, help="number of hidden gcn units"
    )
    parser.add_argument(
        "--n-layers", type=int, default=1, help="number of hidden gcn layers"
    )
    parser.add_argument(
        "--weight-decay", type=float, default=5e-4, help="Weight for L2 loss"
    )
    parser.add_argument(
        "--self-loop",
        action="store_true",
        help="graph self-loop (default=False)",
    )
164
165
166
167
168
    parser.set_defaults(self_loop=False)
    args = parser.parse_args()
    print(args)

    main(args)