Skip to content

Commit 3ba050e

Browse files
committed
remove the last softmax activation
1 parent 0977e37 commit 3ba050e

26 files changed

+230
-177
lines changed

graphgallery/nn/layers/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111
from graphgallery.nn.layers.edgeconv import GraphEdgeConvolution
1212
from graphgallery.nn.layers.mediansage import MedianAggregator, MedianGCNAggregator
1313
from graphgallery.nn.layers.gcnf import GraphConvFeature
14-
from graphgallery.nn.layers.misc import SparseConversion, Scale, Sample
14+
from graphgallery.nn.layers.misc import SparseConversion, Scale, Sample, Gather

graphgallery/nn/layers/misc.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,24 @@ def get_config(self):
5757

5858
def compute_output_shape(self, input_shapes):
5959
return tf.TensorShape(input_shapes[0])
60+
61+
62+
class Gather(Layer):
63+
def __init__(self, axis=0, *args, **kwargs):
64+
super().__init__(*args, **kwargs)
65+
self.axis = axis
66+
67+
def call(self, inputs):
68+
params, indices = inputs
69+
output = tf.gather(params, indices, axis=self.axis)
70+
return output
71+
72+
def get_config(self):
73+
base_config = super().get_config()
74+
return base_config
75+
76+
def compute_output_shape(self, input_shapes):
77+
axis = self.axis
78+
params_shape, indices_shape = input_shapes
79+
output_shape = params_shape[:axis] + indices_shape + params_shape[axis + 1:]
80+
return tf.TensorShape(output_shape)

graphgallery/nn/models/__init__.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# (semi-)supervised model
55
from graphgallery.nn.models.semisupervised.semi_supervised_model import SemiSupervisedModel
66
from graphgallery.nn.models.semisupervised.gcn import GCN
7-
from graphgallery.nn.models.semisupervised.gcn_mix import GCN_MIX
87
from graphgallery.nn.models.semisupervised.sgc import SGC
98
from graphgallery.nn.models.semisupervised.gat import GAT
109
from graphgallery.nn.models.semisupervised.clustergcn import ClusterGCN
@@ -17,11 +16,14 @@
1716
from graphgallery.nn.models.semisupervised.lgcn import LGCN
1817
from graphgallery.nn.models.semisupervised.obvat import OBVAT
1918
from graphgallery.nn.models.semisupervised.sbvat import SBVAT
20-
from graphgallery.nn.models.semisupervised.s_obvat import SimplifiedOBVAT
2119
from graphgallery.nn.models.semisupervised.gmnn import GMNN
22-
from graphgallery.nn.models.semisupervised.edgeconv import EdgeGCN
23-
from graphgallery.nn.models.semisupervised.mediansage import MedianSAGE
24-
from graphgallery.nn.models.semisupervised.gcnf import GCNF
20+
21+
# experimental
22+
from graphgallery.nn.models.semisupervised.experimental.gcnf import GCNF
23+
from graphgallery.nn.models.semisupervised.experimental.gcn_mix import GCN_MIX
24+
from graphgallery.nn.models.semisupervised.experimental.s_obvat import SimplifiedOBVAT
25+
from graphgallery.nn.models.semisupervised.experimental.edgeconv import EdgeGCN
26+
from graphgallery.nn.models.semisupervised.experimental.mediansage import MedianSAGE
2527

2628

2729
# unsupervised model

graphgallery/nn/models/semisupervised/chebynet.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import tensorflow as tf
22
from tensorflow.keras import Model, Input
3-
from tensorflow.keras.layers import Dropout, Softmax
3+
from tensorflow.keras.layers import Dropout
44
from tensorflow.keras.optimizers import Adam
55
from tensorflow.keras import regularizers
6+
from tensorflow.keras.losses import SparseCategoricalCrossentropy
67

7-
from graphgallery.nn.layers import ChebyConvolution
8+
from graphgallery.nn.layers import ChebyConvolution, Gather
89
from graphgallery.sequence import FullBatchNodeSequence
910
from graphgallery.nn.models import SemiSupervisedModel
1011
from graphgallery.utils.misc import chebyshev_polynomials
@@ -37,7 +38,7 @@ class ChebyNet(SemiSupervisedModel):
3738
i.e., math:: \hat{A} = D^{-\frac{1}{2}} A D^{-\frac{1}{2}})
3839
norm_x (String, optional):
3940
How to normalize the node feature matrix. See `graphgallery.normalize_x`
40-
(default :str: `l1`)
41+
(default :obj: `None`)
4142
device (String, optional):
4243
The device where the model is running on. You can specified `CPU` or `GPU`
4344
for the model. (default: :str: `CPU:0`, i.e., running on the 0-th `CPU`)
@@ -51,7 +52,7 @@ class ChebyNet(SemiSupervisedModel):
5152
"""
5253

5354
def __init__(self, adj, x, labels, order=2, norm_adj=-0.5,
54-
norm_x='l1', device='CPU:0', seed=None, name=None, **kwargs):
55+
norm_x=None, device='CPU:0', seed=None, name=None, **kwargs):
5556

5657
super().__init__(adj, x, labels,
5758
device=device, seed=seed, name=name, **kwargs)
@@ -103,11 +104,11 @@ def build(self, hiddens=[16], activations=['relu'], dropouts=[0.5], l2_norms=[5e
103104
h = Dropout(rate=dropout)(h)
104105

105106
h = ChebyConvolution(self.n_classes, order=self.order, use_bias=use_bias)([h, adj])
106-
h = tf.gather(h, index)
107-
output = Softmax()(h)
107+
h = Gather()([h, index])
108108

109-
model = Model(inputs=[x, *adj, index], outputs=output)
110-
model.compile(loss='sparse_categorical_crossentropy', optimizer=Adam(lr=lr), metrics=['accuracy'])
109+
model = Model(inputs=[x, *adj, index], outputs=h)
110+
model.compile(loss=SparseCategoricalCrossentropy(from_logits=True),
111+
optimizer=Adam(lr=lr), metrics=['accuracy'])
111112
self.model = model
112113

113114
def train_sequence(self, index):

graphgallery/nn/models/semisupervised/clustergcn.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
import networkx as nx
33
import tensorflow as tf
44
from tensorflow.keras import Model, Input
5-
from tensorflow.keras.layers import Dropout, Softmax
5+
from tensorflow.keras.layers import Dropout
66
from tensorflow.keras.optimizers import Adam
77
from tensorflow.keras import regularizers
8+
from tensorflow.keras.losses import SparseCategoricalCrossentropy
89

910
from graphgallery.nn.layers import GraphConvolution, SparseConversion
1011
from graphgallery.nn.models import SemiSupervisedModel
@@ -46,7 +47,7 @@ class ClusterGCN(SemiSupervisedModel):
4647
i.e., math:: \hat{A} = D^{-\frac{1}{2}} A D^{-\frac{1}{2}})
4748
norm_x (String, optional):
4849
How to normalize the node feature matrix. See `graphgallery.normalize_x`
49-
(default :str: `l1`)
50+
(default :obj: `None`)
5051
device (String, optional):
5152
The device where the model is running on. You can specified `CPU` or `GPU`
5253
for the model. (default: :str: `CPU:0`, i.e., running on the 0-th `CPU`)
@@ -60,7 +61,7 @@ class ClusterGCN(SemiSupervisedModel):
6061
"""
6162

6263
def __init__(self, adj, x, labels, graph=None, n_clusters=None,
63-
norm_adj=-0.5, norm_x='l1', device='CPU:0', seed=None, name=None, **kwargs):
64+
norm_adj=-0.5, norm_x=None, device='CPU:0', seed=None, name=None, **kwargs):
6465

6566
super().__init__(adj, x, labels=labels, device=device, seed=seed, name=name, **kwargs)
6667

@@ -118,7 +119,7 @@ def build(self, hiddens=[32], activations=['relu'], dropouts=[0.5], l2_norms=[1e
118119
mask = Input(batch_shape=[None], dtype=tf.bool, name='mask')
119120

120121
adj = SparseConversion()([edge_index, edge_weight])
121-
122+
122123
h = x
123124
for hid, activation, dropout, l2_norm in zip(hiddens, activations, dropouts, l2_norms):
124125
h = Dropout(rate=dropout)(h)
@@ -128,12 +129,10 @@ def build(self, hiddens=[32], activations=['relu'], dropouts=[0.5], l2_norms=[1e
128129
h = Dropout(rate=dropout)(h)
129130
h = GraphConvolution(self.n_classes, use_bias=use_bias)([h, adj])
130131
h = tf.boolean_mask(h, mask)
131-
output = Softmax()(h)
132-
133-
model = Model(inputs=[x, edge_index, edge_weight, mask], outputs=output)
134132

135-
model.compile(loss='sparse_categorical_crossentropy', optimizer=Adam(lr=lr),
136-
metrics=['accuracy'])
133+
model = Model(inputs=[x, edge_index, edge_weight, mask], outputs=h)
134+
model.compile(loss=SparseCategoricalCrossentropy(from_logits=True),
135+
optimizer=Adam(lr=lr), metrics=['accuracy'])
137136

138137
self.model = model
139138

graphgallery/nn/models/semisupervised/densegcn.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
from tensorflow.keras.layers import Dropout, Softmax
66
from tensorflow.keras.optimizers import Adam
77
from tensorflow.keras import regularizers
8+
from tensorflow.keras.losses import SparseCategoricalCrossentropy
89

9-
from graphgallery.nn.layers import DenseGraphConv
10+
from graphgallery.nn.layers import DenseGraphConv, Gather
1011
from graphgallery.nn.models import SemiSupervisedModel
1112
from graphgallery.sequence import FullBatchNodeSequence
1213
from graphgallery.utils.shape_utils import set_equal_in_length
@@ -42,7 +43,7 @@ class DenseGCN(SemiSupervisedModel):
4243
i.e., math:: \hat{A} = D^{-\frac{1}{2}} A D^{-\frac{1}{2}})
4344
norm_x (String, optional):
4445
How to normalize the node feature matrix. See `graphgallery.normalize_x`
45-
(default :str: `l1`)
46+
(default :obj: `None`)
4647
device (String, optional):
4748
The device where the model is running on. You can specified `CPU` or `GPU`
4849
for the model. (default: :str: `CPU:0`, i.e., running on the 0-th `CPU`)
@@ -56,7 +57,7 @@ class DenseGCN(SemiSupervisedModel):
5657
5758
"""
5859

59-
def __init__(self, adj, x, labels, norm_adj=-0.5, norm_x='l1',
60+
def __init__(self, adj, x, labels, norm_adj=-0.5, norm_x=None,
6061
device='CPU:0', seed=None, name=None, **kwargs):
6162

6263
super().__init__(adj, x, labels, device=device, seed=seed, name=name, **kwargs)
@@ -112,11 +113,11 @@ def build(self, hiddens=[16], activations=['relu'], dropouts=[0.5], l2_norms=[5e
112113
h = Dropout(rate=dropout)(h)
113114

114115
h = DenseGraphConv(self.n_classes, use_bias=use_bias)([h, adj])
115-
h = tf.gather(h, index)
116-
output = Softmax()(h)
116+
h = Gather()([h, index])
117117

118-
model = Model(inputs=[x, adj, index], outputs=output)
119-
model.compile(loss='sparse_categorical_crossentropy', optimizer=Adam(lr=lr), metrics=['accuracy'])
118+
model = Model(inputs=[x, adj, index], outputs=h)
119+
model.compile(loss=SparseCategoricalCrossentropy(from_logits=True),
120+
optimizer=Adam(lr=lr), metrics=['accuracy'])
120121
self.model = model
121122

122123
def train_sequence(self, index):

graphgallery/nn/models/semisupervised/edgeconv.py renamed to graphgallery/nn/models/semisupervised/experimental/edgeconv.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import numpy as np
22
import tensorflow as tf
33
from tensorflow.keras import Model, Input
4-
from tensorflow.keras.layers import Dropout, Softmax
4+
from tensorflow.keras.layers import Dropout
55
from tensorflow.keras.optimizers import Adam
66
from tensorflow.keras import regularizers
7+
from tensorflow.keras.losses import SparseCategoricalCrossentropy
78

8-
from graphgallery.nn.layers import GraphEdgeConvolution
9+
from graphgallery.nn.layers import GraphEdgeConvolution, Gather
910
from graphgallery.nn.models import SemiSupervisedModel
1011
from graphgallery.sequence import FullBatchNodeSequence
1112
from graphgallery.utils.shape_utils import set_equal_in_length
@@ -44,7 +45,7 @@ class EdgeGCN(SemiSupervisedModel):
4445
i.e., math:: \hat{A} = D^{-\frac{1}{2}} A D^{-\frac{1}{2}})
4546
norm_x (String, optional):
4647
How to normalize the node feature matrix. See `graphgallery.normalize_x`
47-
(default :str: `l1`)
48+
(default :obj: `None`)
4849
device (String, optional):
4950
The device where the model is running on. You can specified `CPU` or `GPU`
5051
for the model. (default: :str: `CPU:0`, i.e., running on the 0-th `CPU`)
@@ -57,7 +58,7 @@ class EdgeGCN(SemiSupervisedModel):
5758
5859
"""
5960

60-
def __init__(self, adj, x, labels, norm_adj=-0.5, norm_x='l1',
61+
def __init__(self, adj, x, labels, norm_adj=-0.5, norm_x=None,
6162
device='CPU:0', seed=None, name=None, **kwargs):
6263

6364
super().__init__(adj, x, labels, device=device, seed=seed, name=name, **kwargs)
@@ -109,11 +110,11 @@ def build(self, hiddens=[16], activations=['relu'], dropouts=[0.5], l2_norms=[5e
109110
h = Dropout(rate=dropout)(h)
110111

111112
h = GraphEdgeConvolution(self.n_classes, use_bias=use_bias)([h, edge_index, edge_weight])
112-
h = tf.gather(h, index)
113-
output = Softmax()(h)
114-
115-
model = Model(inputs=[x, edge_index, edge_weight, index], outputs=output)
116-
model.compile(loss='sparse_categorical_crossentropy', optimizer=Adam(lr=lr), metrics=['accuracy'])
113+
h = Gather()([h, index])
114+
115+
model = Model(inputs=[x, edge_index, edge_weight, index], outputs=h)
116+
model.compile(loss=SparseCategoricalCrossentropy(from_logits=True),
117+
optimizer=Adam(lr=lr), metrics=['accuracy'])
117118
self.model = model
118119

119120
def train_sequence(self, index):

graphgallery/nn/models/semisupervised/gcn_mix.py renamed to graphgallery/nn/models/semisupervised/experimental/gcn_mix.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class GCN_MIX(SemiSupervisedModel):
3636
i.e., math:: \hat{A} = D^{-\frac{1}{2}} A D^{-\frac{1}{2}})
3737
norm_x (String, optional):
3838
How to normalize the node feature matrix. See `graphgallery.normalize_x`
39-
(default :str: `l1`)
39+
(default :obj: `None`)
4040
device (String, optional):
4141
The device where the model is running on. You can specified `CPU` or `GPU`
4242
for the model. (default: :str: `CPU:0`, i.e., running on the 0-th `CPU`)
@@ -49,7 +49,7 @@ class GCN_MIX(SemiSupervisedModel):
4949
5050
"""
5151

52-
def __init__(self, adj, x, labels, norm_adj=-0.5, norm_x='l1',
52+
def __init__(self, adj, x, labels, norm_adj=-0.5, norm_x=None,
5353
device='CPU:0', seed=None, name=None, **kwargs):
5454

5555
super().__init__(adj, x, labels, device=device, seed=seed, name=name, **kwargs)

graphgallery/nn/models/semisupervised/gcnf.py renamed to graphgallery/nn/models/semisupervised/experimental/gcnf.py

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import tensorflow as tf
22
from tensorflow.keras import Model, Input
3-
from tensorflow.keras.layers import Dropout, Softmax
3+
from tensorflow.keras.layers import Dropout
44
from tensorflow.keras.optimizers import Adam
55
from tensorflow.keras import regularizers
6+
from tensorflow.keras.losses import SparseCategoricalCrossentropy
67

7-
from graphgallery.nn.layers import GraphConvFeature
8+
from graphgallery.nn.layers import GraphConvFeature, Gather
89
from graphgallery.nn.models import SemiSupervisedModel
910
from graphgallery.sequence import FullBatchNodeSequence
1011
from graphgallery.utils.shape_utils import set_equal_in_length
@@ -17,34 +18,34 @@ class GCNF(SemiSupervisedModel):
1718
1819
Arguments:
1920
----------
20-
adj: shape (N, N), Scipy sparse matrix if `is_adj_sparse=True`,
21+
adj: shape (N, N), Scipy sparse matrix if `is_adj_sparse=True`,
2122
Numpy array-like (or matrix) if `is_adj_sparse=False`.
22-
The input `symmetric` adjacency matrix, where `N` is the number
23+
The input `symmetric` adjacency matrix, where `N` is the number
2324
of nodes in graph.
24-
x: shape (N, F), Scipy sparse matrix if `is_x_sparse=True`,
25+
x: shape (N, F), Scipy sparse matrix if `is_x_sparse=True`,
2526
Numpy array-like (or matrix) if `is_x_sparse=False`.
2627
The input node feature matrix, where `F` is the dimension of features.
2728
labels: Numpy array-like with shape (N,)
2829
The ground-truth labels for all nodes in graph.
29-
norm_adj (Float scalar, optional):
30-
The normalize rate for adjacency matrix `adj`. (default: :obj:`-0.5`,
31-
i.e., math:: \hat{A} = D^{-\frac{1}{2}} A D^{-\frac{1}{2}})
32-
norm_x (Boolean, optional):
33-
Whether to use row-wise normalization for node feature matrix.
34-
(default :bool: `True`)
35-
device (String, optional):
36-
The device where the model is running on. You can specified `CPU` or `GPU`
30+
norm_adj (Float scalar, optional):
31+
The normalize rate for adjacency matrix `adj`. (default: :obj:`-0.5`,
32+
i.e., math:: \hat{A} = D^{-\frac{1}{2}} A D^{-\frac{1}{2}})
33+
norm_x (String, optional):
34+
How to normalize the node feature matrix. See `graphgallery.normalize_x`
35+
(default :obj: `None`)
36+
device (String, optional):
37+
The device where the model is running on. You can specified `CPU` or `GPU`
3738
for the model. (default: :str: `CPU:0`, i.e., running on the 0-th `CPU`)
38-
seed (Positive integer, optional):
39-
Used in combination with `tf.random.set_seed` & `np.random.seed` & `random.seed`
40-
to create a reproducible sequence of tensors across multiple calls.
39+
seed (Positive integer, optional):
40+
Used in combination with `tf.random.set_seed` & `np.random.seed` & `random.seed`
41+
to create a reproducible sequence of tensors across multiple calls.
4142
(default :obj: `None`, i.e., using random seed)
42-
name (String, optional):
43+
name (String, optional):
4344
Specified name for the model. (default: :str: `class.__name__`)
4445
4546
"""
4647

47-
def __init__(self, adj, x, labels, norm_adj=-0.5, norm_x='l1',
48+
def __init__(self, adj, x, labels, norm_adj=-0.5, norm_x=None,
4849
device='CPU:0', seed=None, name=None, **kwargs):
4950

5051
super().__init__(adj, x, labels, device=device, seed=seed, name=name, **kwargs)
@@ -100,11 +101,11 @@ def build(self, hiddens=[16], activations=['relu'], dropouts=[0.5], l2_norms=[5e
100101
# of the input data to remain the same
101102
# if ensure_shape:
102103
# h = tf.ensure_shape(h, [self.n_nodes, self.n_classes])
103-
h = tf.gather(h, index)
104-
output = Softmax()(h)
104+
h = Gather()([h, index])
105105

106-
model = Model(inputs=[x, adj, index], outputs=output)
107-
model.compile(loss='sparse_categorical_crossentropy', optimizer=Adam(lr=lr), metrics=['accuracy'])
106+
model = Model(inputs=[x, adj, index], outputs=h)
107+
model.compile(loss=SparseCategoricalCrossentropy(from_logits=True),
108+
optimizer=Adam(lr=lr), metrics=['accuracy'])
108109

109110
self.model = model
110111

graphgallery/nn/models/semisupervised/mediansage.py renamed to graphgallery/nn/models/semisupervised/experimental/mediansage.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import numpy as np
22
import tensorflow as tf
33
from tensorflow.keras import Model, Input
4-
from tensorflow.keras.layers import Dropout, Softmax
4+
from tensorflow.keras.layers import Dropout
55
from tensorflow.keras.optimizers import Adam
66
from tensorflow.keras import regularizers
7+
from tensorflow.keras.losses import SparseCategoricalCrossentropy
78

89
from graphgallery.nn.layers import MedianAggregator, MedianGCNAggregator
910
from graphgallery.nn.models import SemiSupervisedModel
@@ -34,7 +35,7 @@ class MedianSAGE(SemiSupervisedModel):
3435
`5` sencond-order neighbors, and the radius for `GraphSAGE` is `2`)
3536
norm_x (String, optional):
3637
How to normalize the node feature matrix. See `graphgallery.normalize_x`
37-
(default :str: `l1`)
38+
(default :obj: `None`)
3839
device (String, optional):
3940
The device where the model is running on. You can specified `CPU` or `GPU`
4041
for the model. (default: :str: `CPU:0`, i.e., running on the 0-th `CPU`)
@@ -48,7 +49,7 @@ class MedianSAGE(SemiSupervisedModel):
4849
4950
"""
5051

51-
def __init__(self, adj, x, labels, n_samples=[15, 3], norm_x='l1',
52+
def __init__(self, adj, x, labels, n_samples=[15, 3], norm_x=None,
5253
device='CPU:0', seed=None, name=None, **kwargs):
5354

5455
super().__init__(adj, x, labels, device=device, seed=seed, name=name, **kwargs)
@@ -124,10 +125,10 @@ def build(self, hiddens=[32], activations=['relu'], dropouts=[0.5], l2_norms=[5e
124125
h = h[0]
125126
if output_normalize:
126127
h = tf.nn.l2_normalize(h, axis=1)
127-
output = Softmax()(h)
128128

129-
model = Model(inputs=[x, nodes, *neighbors], outputs=output)
130-
model.compile(loss='sparse_categorical_crossentropy', optimizer=Adam(lr=lr), metrics=['accuracy'])
129+
model = Model(inputs=[x, nodes, *neighbors], outputs=h)
130+
model.compile(loss=SparseCategoricalCrossentropy(from_logits=True),
131+
optimizer=Adam(lr=lr), metrics=['accuracy'])
131132

132133
self.model = model
133134

0 commit comments

Comments
 (0)