5

I am trying to implement Graph Convolution Layer using Keras custom layer that is mentioned in the following paper: GCNN.

When I am trying to train my model, It gives me the following error:

Traceback (most recent call last):
File "main.py", line 35, in <module>
model.fit(train_images, train_labels, validation_data=(test_images, test_labels), epochs=50, batch_size=32)
File "/usr/local/lib/python2.7/dist-packages/keras/engine/training.py", line 1010, in fit
self._make_train_function()
File "/usr/local/lib/python2.7/dist-packages/keras/engine/training.py", line 509, in _make_train_function
loss=self.total_loss)
File "/usr/local/lib/python2.7/dist-packages/keras/legacy/interfaces.py", line 91, in wrapper
return func(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/keras/optimizers.py", line 256, in get_updates
grads = self.get_gradients(loss, params)
File "/usr/local/lib/python2.7/dist-packages/keras/optimizers.py", line 91, in get_gradients
raise ValueError('An operation has `None` for gradient. '
ValueError: An operation has `None` for gradient. Please make sure that all of your ops have a gradient defined (i.e. are differentiable). Common ops without gradient: K.argmax, K.round, K.eval.

I don't know how to get rid of this problem.

Can someone explain me briefly what should I do?

I have gone through Keras official documentation about writing custom layer but it didn't specify about it. Link

Following is the code for my custom layer.

class GraphConvolutionalLayer(Layer):

def __init__(self, A, num_input_features, num_output_features, **kwargs):
    self.A = A
    self.num_input_features = num_input_features
    self.num_output_features = num_output_features

    self.num_vertices = A.get_shape().as_list()[0]
    self.input_spec = (self.num_vertices, num_input_features)

    super(GraphConvolutionalLayer, self).__init__(**kwargs)

def build(self, input_shape):
    self.k0 = self.add_weight(name='k0', 
                                  shape=(self.num_output_features, self.num_input_features),
                                  initializer='uniform',
                                  trainable=True)
    self.k1 = self.add_weight(name='k1', 
                          shape=(self.num_output_features, self.num_input_features),
                          initializer='uniform',
                          trainable=True)

    self.H = tf.einsum('ab,cd->abcd', tf.convert_to_tensor(self.k0, dtype=tf.float32), tf.eye(self.num_vertices)) 
    self.built = True

def call(self, Vin):

    Vin2 = tf.reshape(tf.transpose(Vin, [0, 2, 1]), [Vin.get_shape().as_list()[1] * Vin.get_shape().as_list()[2], -1])

    H_tmp = tf.reshape(tf.transpose(self.H, [0, 2, 1, 3]), [ self.num_output_features, self.num_vertices, self.num_vertices * self.num_input_features])

    Vout = tf.transpose(K.dot(H_tmp, Vin2), [2, 1, 0])

    return Vout

def compute_output_shape(self, input_shape):
    return (self.num_vertices, self.num_output_features)

Following is the code for the main file.

main_input = Input(shape=train_images[0].shape)
Vout1 = GraphConvolutionalLayer(A, 1, 4)(main_input)
Vout2 = GraphConvolutionalLayer(A, 4, 8)(Vout1)
Vout3 = Flatten()(Vout2)
Vout4 = Dense(10, activation='sigmoid')(Vout3)
print(train_images.shape, train_labels.shape)

model = Model(inputs=main_input, outputs=Vout4)
print(model.summary())
model.compile(optimizer='rmsprop', loss='binary_crossentropy')
model.fit(train_images, train_labels, validation_data=(test_images, test_labels), epochs=50, batch_size=32)
4
  • Please add full code and line in which error occurs Commented Mar 15, 2019 at 15:41
  • I have added full code. Please help me. Commented Mar 16, 2019 at 3:13
  • What does A stands for? Commented Mar 16, 2019 at 10:26
  • A is the adjacency matrix of the graph. Commented Mar 16, 2019 at 11:13

2 Answers 2

1

Here, I take uniform as an initializer. When I changed it, I didn't get any error. I don't know why this happened but I could be able to solve my error just changing that line.

Sign up to request clarification or add additional context in comments.

Comments

0

As error states, some of your function is non-differentiable. It' not easy to say why exactly it happens. For example, take a look

List of Differentiable Ops in Tensorflow

How to make sure your computation graph is differentiable

Edit: Consider example, where I use standard cifar10 data.

class GraphConvolutionalLayer(layers.Layer):
    def __init__(self, A, num_input_features, num_output_features, **kwargs):
        #self.A = A
        self.num_input_features = num_input_features
        self.num_output_features = num_output_features

        self.num_vertices = A
        self.input_spec = (self.num_vertices, num_input_features)

        super(GraphConvolutionalLayer, self).__init__(**kwargs)

    def build(self, input_shape):
        self.k0 = self.add_weight(name='k0',
                                  shape=(self.num_output_features, self.num_input_features),
                                  initializer='uniform',
                                  trainable=True)

        self.H = tf.einsum('ab,cd->abcd', tf.convert_to_tensor(self.k0, dtype=tf.float32), tf.eye(self.num_vertices))
        self.H = tf.reshape(self.H, [32*32, 3])
        self.built = True

    def call(self, Vin):

        Vin2 = tf.reshape(Vin, [Vin.get_shape().as_list()[1] * Vin.get_shape().as_list()[1],Vin.get_shape().as_list()[-1]])
        Vin2 = tf.transpose(Vin2)
        Vout = tf.matmul(self.H, Vin2)
        return Vout

def input_fn():
    train, test = tf.keras.datasets.cifar10.load_data()
    dataset = tf.data.Dataset.from_tensor_slices((train[0], train[1]))
    dataset = dataset.batch(1)
    return dataset

main_input = layers.Input(shape=[32, 32, 3])
Vout1 = GraphConvolutionalLayer(32, 3, 1)(main_input)    
Vout3 = layers.Flatten()(Vout1)
Vout4 = layers.Dense(10, activation='sigmoid')(Vout3)
model = Model(inputs=main_input, outputs=Vout4)
model.compile(optimizer='rmsprop', loss='binary_crossentropy')
model.fit(input_fn(), epochs=50, steps_per_epoch=10)

In this case gradients are computed. So the problem clearly is not in how you construct GraphConvolutionalLayer but in some internal operation, which depends on data. You need to check every op one by one with your data shapes.

P.S. You can try substituting einsum with matmul, cause the former is simply a syntactic wrap for the latter.

3 Comments

Still, this code gave me an error because tf.eigsum function is non-differentiable. I tried a lot to convert my code such that I can use tf.matmul but I couldn't get anything. Can you please tell any alternative of tf.eigsum which is differentiable.
Updated answer.
I want to train my mnist or cifar10 with more than one Graph CNN layer. Can you please share the code that runs perfectly. That helps me to understand the problem. I ran your code and it showed me this error: AttributeError: 'NoneType' object has no attribute '_inbound_nodes'

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.