0

I am using gcn_conv.GCNConv to perform a GraphUpdate with the following code:

g = graphs[0]
hidden_size = 32
context_features = g.context.get_features_dict()
label = context_features.pop('label')
new_graph = g.replace_features(context=context_features)

def set_initial_node_state(node_set, node_set_name):
          features = [
              tf.keras.layers.Dense(hidden_size, activation="relu")(node_set['x_dim']),
              tf.keras.layers.Dense(hidden_size, activation="relu")(node_set['y_dim']),
              tf.keras.layers.Dense(hidden_size, activation="relu")(node_set['z_dim'])
          ]
          return tf.keras.layers.Concatenate()(features)

new_graph = tfgnn.keras.layers.MapFeatures(
          node_sets_fn=set_initial_node_state)(new_graph)


result_gcn = tfgnn.keras.layers.GraphUpdate(
        node_sets = {
            'body': tfgnn.keras.layers.NodeSetUpdate({
                'bones': gcn_conv.GCNConv(
                    units = hidden_size)},
                tfgnn.keras.layers.NextStateFromConcat(
                    tf.keras.layers.Dense(hidden_size)))})(new_graph)

However, the GraphUpdate returns a tensor that is full of nan only for certain rows of the original tensor (of shape 1875x96). This happens specifically with this kind of GraphUpdate, as using a SimpleConv does not generate this issue.

'GraphTensorSpec({'context': ContextSpec({'features': {'label': TensorSpec(shape=(1, 10), dtype=tf.float32, name=None)}, 'sizes': TensorSpec(shape=(1,), dtype=tf.int32, name=None)}, TensorShape([]), tf.int32, None), 'node_sets': {'body': NodeSetSpec({'features': {'x_dim': TensorSpec(shape=(None, 1), dtype=tf.float32, name=None), 'y_dim': TensorSpec(shape=(None, 1), dtype=tf.float32, name=None), 'z_dim': TensorSpec(shape=(None, 1), dtype=tf.float32, name=None)}, 'sizes': TensorSpec(shape=(1,), dtype=tf.int32, name=None)}, TensorShape([]), tf.int32, None)}, 'edge_sets': {'bones': EdgeSetSpec({'features': {}, 'sizes': TensorSpec(shape=(1,), dtype=tf.int32, name=None), 'adjacency': AdjacencySpec({'#index.0': TensorSpec(shape=(None,), dtype=tf.int32, name=None), '#index.1': TensorSpec(shape=(None,), dtype=tf.int32, name=None)}, TensorShape([]), tf.int32, {'#index.0': 'body', '#index.1': 'body'})}, TensorShape([]), tf.int32, None), 'temporal': EdgeSetSpec({'features': {}, 'sizes': TensorSpec(shape=(1,), dtype=tf.int32, name=None), 'adjacency': AdjacencySpec({'#index.0': TensorSpec(shape=(None,), dtype=tf.int32, name=None), '#index.1': TensorSpec(shape=(None,), dtype=tf.int32, name=None)}, TensorShape([]), tf.int32, {'#index.0': 'body', '#index.1': 'body'})}, TensorShape([]), tf.int32, None)}}, TensorShape([]), tf.int32, None)'

Is there any particular operation in the function that may cause nan?

I tried with another set of data with the same structure and range of values and the issue is not there. The tensor does not have any nan values, but float32 ranging between -1 and +1.

Marianna
  • 13
  • 2

1 Answers1

1

GCNConv does normalization by node degree, so nodes with no edges may encounter division by zero. To avoid this you can use GCNConv(units=hidden_size, add_self_loops=True) to prevent this (ensuring that all nodes have at least one edge).