danielegrattarola / spektral

Graph Neural Networks with Keras and Tensorflow 2.
https://graphneural.network
MIT License
2.37k stars 334 forks source link

GNNExplainer: tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes #253

Closed antonioaa1979 closed 3 years ago

antonioaa1979 commented 3 years ago

Hi Daniele and all,

thanks for creating and maintaining this great library!

I have been trying to use GNNExplainer, but I keep seeing the below error message. Still don't know if it's a bug or something i am doing wrong on my side, but there is no much documentation or examples around it.

I am able to run smoothly the sample code at https://github.com/danielegrattarola/spektral/blob/master/examples/other/explain_node_predictions.py.

But when applying to my dataset (where I can run successfully a GCN model), i get the below:

dataset
Out[66]: SADataset(n_graphs=1)

dataset[0]
Out[67]: Graph(n_nodes=1653, n_node_features=42, n_edge_features=None, n_labels=10)

x_exp, a_exp = dataset[0].x, dataset[0].a

x_exp.shape
Out[69]: (1653, 42)

a_exp.shape
Out[70]: TensorShape([1653, 1653])

explainer = GNNExplainer(model, preprocess=gcn_filter, verbose=True)
n_hops was automatically inferred to be 2

node_idx = 0

adj_mask, feat_mask = explainer.explain_node(x=x_exp, a=a_exp, node_idx=node_idx)

pred_loss: 1.097847819328308, a_size_loss: 0.5874298214912415, a_entropy_loss: 0.0692998617887497, smoothness_loss: [[0.]], x_size_loss: 2.0829315185546875, x_entropy_loss: 0.06919442862272263
pred_loss: 1.0877137184143066, a_size_loss: 0.5852940678596497, a_entropy_loss: 0.06929884105920792, smoothness_loss: [[0.]], x_size_loss: 2.075951099395752, x_entropy_loss: 0.06918510049581528
[... output removed]
pred_loss: 0.6421844959259033, a_size_loss: 0.3796449303627014, a_entropy_loss: 0.05964722856879234, smoothness_loss: [[0.]], x_size_loss: 1.379091501235962, x_entropy_loss: 0.05970795825123787
pred_loss: 0.6415124535560608, a_size_loss: 0.37782761454582214, a_entropy_loss: 0.05948375537991524, smoothness_loss: [[0.]], x_size_loss: 1.372214436531067, x_entropy_loss: 0.059564121067523956

adj_mask.shape
Out[75]: TensorShape([2349])

adj_mask
Out[76]: 
<tf.Variable 'Variable:0' shape=(2349,) dtype=float32, numpy=
array([ 0.8150444 ,  0.77765435, -0.9916512 , ..., -1.0242233 ,
       -0.9629407 , -0.9988212 ], dtype=float32)>

feat_mask.shape
Out[77]: TensorShape([1, 42])

feat_mask
Out[78]: 
<tf.Variable 'Variable:0' shape=(1, 42) dtype=float32, numpy=
array([[ 0.58385307, -1.3217939 , -1.0627872 , -0.00148061, -1.0020486 ,
        -0.9942789 , -0.97092587, -0.9922697 ,  0.3853194 , -0.83190703,
        -1.1318972 , -0.99104863, -1.0001428 , -0.9827519 , -0.9750702 ,
        -0.96384555, -0.890569  , -1.0193573 ,  0.4747884 , -0.91873515,
         0.7341433 , -0.97718424, -0.86869913, -0.9699511 ,  0.37709397,
        -1.0660834 , -0.92709947, -0.89111555, -1.0546191 , -1.0837208 ,
        -1.0699799 , -1.0806109 ,  0.61809593, -0.9817147 , -1.0526807 ,
        -0.95195514, -1.0162035 , -1.181156  , -1.0657567 , -1.0472083 ,
        -0.85559815, -1.0388821 ]], dtype=float32)>

G = explainer.plot_subgraph(adj_mask, feat_mask, node_idx)
Traceback (most recent call last):
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3331, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-74-182e1ffafc94>", line 1, in <module>
    G = explainer.plot_subgraph(adj_mask, feat_mask, node_idx)
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/spektral/models/gnn_explainer.py", line 276, in plot_subgraph
    adj_mtx, top_ftrs = self._explainer_cleaning(a_mask, x_mask, node_idx, a_thresh)
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/spektral/models/gnn_explainer.py", line 243, in _explainer_cleaning
    tf.multiply, self.comp_graph, selected_adj_mask
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/tensorflow/python/util/dispatch.py", line 206, in wrapper
    return target(*args, **kwargs)
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/tensorflow/python/ops/sparse_ops.py", line 2931, in map_values
    op(*inner_args, **inner_kwargs),
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/tensorflow/python/util/dispatch.py", line 206, in wrapper
    return target(*args, **kwargs)
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/tensorflow/python/ops/math_ops.py", line 530, in multiply
    return gen_math_ops.mul(x, y, name)
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/tensorflow/python/ops/gen_math_ops.py", line 6240, in mul
    _ops.raise_from_not_ok_status(e, name)
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/tensorflow/python/framework/ops.py", line 6897, in raise_from_not_ok_status
    six.raise_from(core._status_to_exception(e.code, message), None)
  File "<string>", line 3, in raise_from
tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [2349] vs. [2589] [Op:Mul]
danielegrattarola commented 3 years ago

@AlexandrMelnic can you take a look at this error thrown by plot_subgraph? I feel it would be easier since you know the code better :D

Thanks

AlexandrMelnic commented 3 years ago

Hi! sure I will take a look, @antonioaa1979 if you don't mind can you send me your code? So I can understand better the problem.

antonioaa1979 commented 3 years ago

thanks both! @AlexandrMelnic, reg the code: I build a dataset and a model pretty much following the citation_gcn example script with some customization of the Dataset class, and after that i run the GNNExplainer lines that you see above. I could send the code if you want, but not the data (it's company dataset I am not authorized to export), so not sure that will help. But i can reproduce the issue any time locally and can run commands for you and export the output, if that works.

antonioaa1979 commented 3 years ago

hi @AlexandrMelnic doing some debugging, if this can help, the issue happens within _explainer_cleaning function, specifically at those lines:

selected_subgraph shape: (1653, 1653) selected_adj_mask shape: (2349,)

        # remove the edges which value is < a_thresh
        selected_adj_mask = tf.where(
            selected_subgraph.values >= a_thresh, selected_subgraph.values, 0
        )

selected_subgraph shape: (1653, 1653) selected_adj_mask shape: (2589,)

Specifically, selected_adj_mask shape is changing after the above line, and it's making following line to fail:

        selected_subgraph = tf.sparse.map_values(
            tf.multiply, self.comp_graph, selected_adj_mask
        )

since comp_graph has a shape of (2349,)

-> tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [2349] vs. [2589] [Op:Mul]

AlexandrMelnic commented 3 years ago

Hi, sorry for the delay, in the incoming week I will have more time and I can try to solve this issue. It won't have any sense for the sake of the model but can you try to use it by giving in input the adjacency matrix and not passing the gcn_filter? Furthermore, did you try for other values of a_thresh? Another thing: when you use the correct model with gcn_filter, as you printed the shapes above, can you print the shapes at also the previous steps of _explainer_cleaning of selected_subgraph and selected_subgraph.values.

antonioaa1979 commented 3 years ago

Thanks @AlexandrMelnic ! Tried with different a_thresh and get same error message (with unchanging "incompatible shapes" values):

explainer = GNNExplainer(model, preprocess=gcn_filter, verbose=True)
adj_mask, feat_mask = explainer.explain_node(x=x_exp, a=a_exp, node_idx=node_idx)
G = explainer.plot_subgraph(adj_mask, feat_mask, node_idx)
-> tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [2739] vs. [2955] [Op:Mul]

G = explainer.plot_subgraph(adj_mask, feat_mask, node_idx, a_thresh=0.001)
-> tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [2739] vs. [2955] [Op:Mul]

G = explainer.plot_subgraph(adj_mask, feat_mask, node_idx, a_thresh=0.5)
-> tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [2739] vs. [2955] [Op:Mul]

Also tried without gcn_filter preprocessing, and got same error message (but with changing "incompatible shapes" values):

explainer = GNNExplainer(model, verbose=True)
adj_mask, feat_mask = explainer.explain_node(x=x_exp, a=a_exp, node_idx=node_idx)
G = explainer.plot_subgraph(adj_mask, feat_mask, node_idx)
-> tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [1088] vs. [1304] [Op:Mul]

Hope this helps, Antonio

AlexandrMelnic commented 3 years ago

I see.....

Can you try this, so I can understand at which point is the problem:

def explainer_cleaning(adj_mask, a_thresh):
    selected_adj_mask = tf.nn.sigmoid(adj_mask)

    # convert into a binary matrix
    comp_graph_values = tf.ones_like(exp.comp_graph.values)

    comp_graph = tf.sparse.SparseTensor(
        exp.comp_graph.indices, comp_graph_values, exp.comp_graph.shape
    )

    print(comp_graph.shape, comp_graph.values.shape, selected_adj_mask.shape)
    #get the final masked adj matrix
    selected_subgraph = tf.sparse.map_values(
        tf.multiply, comp_graph, selected_adj_mask
    )

    print(comp_graph.shape, comp_graph.values.shape, selected_adj_mask.shape)
    # impose the symmetry of the adj matrix
    selected_subgraph = (
        tf.sparse.add(selected_subgraph, tf.sparse.transpose(selected_subgraph)) / 2
    )

    print(comp_graph.shape, comp_graph.values.shape, selected_adj_mask.shape)
    # remove the edges which value is < a_thresh
    selected_adj_mask = tf.where(
        selected_subgraph.values >= a_thresh, selected_subgraph.values, 0
    )

    print(comp_graph.shape, comp_graph.values.shape, selected_adj_mask.shape)
    selected_subgraph = tf.sparse.map_values(
        tf.multiply, comp_graph, selected_adj_mask
    )

    print(comp_graph.shape, comp_graph.values.shape, selected_adj_mask.shape)
explainer_cleaning(adj_mask, 0.1)

It should take in input the masked adjacency matrix that is returned from the explain_node method.

antonioaa1979 commented 3 years ago

here we go..

exp = explainer
explainer_cleaning(adj_mask, 0.1)

(1653, 1653) (2739,) (2739,)
(1653, 1653) (2739,) (2739,)
(1653, 1653) (2739,) (2739,)
(1653, 1653) (2739,) (2955,)
Traceback (most recent call last):
  File "<ipython-input-47-f9dee555135b>", line 1, in <module>
    explainer_cleaning(adj_mask, 0.1)
  File "<ipython-input-35-75bc29f78de7>", line 31, in explainer_cleaning
    tf.multiply, comp_graph, selected_adj_mask
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/tensorflow/python/util/dispatch.py", line 206, in wrapper
    return target(*args, **kwargs)
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/tensorflow/python/ops/sparse_ops.py", line 2931, in map_values
    op(*inner_args, **inner_kwargs),
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/tensorflow/python/util/dispatch.py", line 206, in wrapper
    return target(*args, **kwargs)
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/tensorflow/python/ops/math_ops.py", line 530, in multiply
    return gen_math_ops.mul(x, y, name)
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/tensorflow/python/ops/gen_math_ops.py", line 6240, in mul
    _ops.raise_from_not_ok_status(e, name)
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/tensorflow/python/framework/ops.py", line 6897, in raise_from_not_ok_status
    six.raise_from(core._status_to_exception(e.code, message), None)
  File "<string>", line 3, in raise_from
tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [2739] vs. [2955] [Op:Mul]
antonioaa1979 commented 3 years ago

extra elements:

selected_adj_mask = tf.nn.sigmoid(adj_mask)
# convert into a binary matrix
comp_graph_values = tf.ones_like(exp.comp_graph.values)
comp_graph = tf.sparse.SparseTensor(
    exp.comp_graph.indices, comp_graph_values, exp.comp_graph.shape
)
print(comp_graph.shape, comp_graph.values.shape, selected_adj_mask.shape)
# get the final masked adj matrix
selected_subgraph = tf.sparse.map_values(
    tf.multiply, comp_graph, selected_adj_mask
)
print(comp_graph.shape, comp_graph.values.shape, selected_adj_mask.shape)
# impose the symmetry of the adj matrix
selected_subgraph = (
        tf.sparse.add(selected_subgraph, tf.sparse.transpose(selected_subgraph)) / 2
)
print(comp_graph.shape, comp_graph.values.shape, selected_adj_mask.shape, selected_subgraph.shape,
      selected_subgraph.values.shape)

(1653, 1653) (2739,) (2739,) (1653, 1653) (2739,) (2739,) (1653, 1653) (2739,) (2739,) (1653, 1653) (2955,)

# remove the edges which value is < a_thresh
selected_adj_mask = tf.where(
    selected_subgraph.values >= a_thresh, selected_subgraph.values, 0
)
print(comp_graph.shape, comp_graph.values.shape, selected_adj_mask.shape, selected_subgraph.shape,
      selected_subgraph.values.shape)

(1653, 1653) (2739,) (2955,) (1653, 1653) (2955,)

selected_subgraph = tf.sparse.map_values(
    tf.multiply, comp_graph, selected_adj_mask
)

tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [2739] vs. [2955] [Op:Mul]

AlexandrMelnic commented 3 years ago

Can you try again with this:

def explainer_cleaning(adj_mask, explainer, a_thresh):
    selected_adj_mask = tf.nn.sigmoid(adj_mask)

    # convert into a binary matrix
    comp_graph_values = tf.ones_like(explainer.comp_graph.values)
    comp_graph = tf.sparse.SparseTensor(
        explainer.comp_graph.indices, comp_graph_values, explainer.comp_graph.shape
    )

    print('1 comp_graph shape:', comp_graph.shape)
    print('1 comp_graph values shape: ', comp_graph.values.shape)
    print('1 selected_adj_mask shape: ', selected_adj_mask.shape)

    #get the final masked adj matrix
    selected_subgraph = tf.sparse.map_values(
        tf.multiply, comp_graph, selected_adj_mask
    )
    print('2 selected_subgraph shape: ', selected_subgraph.shape)
    print('2 selected_subgraph values shape: ', selected_subgraph.values.shape)
    is_nonzero = tf.not_equal(selected_subgraph.values, 0)
    selected_subgraph = tf.sparse.retain(selected_subgraph, is_nonzero)

    print('2 selected_subgraph shape after retain: ', selected_subgraph.shape)
    print('2 selected_subgraph values shape after retain: ', selected_subgraph.values.shape)

    # impose the symmetry of the adj matrix
    selected_subgraph = (
        tf.sparse.add(selected_subgraph, tf.sparse.transpose(selected_subgraph)) / 2
    )

    print('3 selected_subgraph shape: ', selected_subgraph.shape)
    print('3 selected_subgraph values shape: ', selected_subgraph.values.shape)

    is_nonzero = tf.not_equal(selected_subgraph.values, 0)
    selected_subgraph = tf.sparse.retain(selected_subgraph, is_nonzero)

    print('3 selected_subgraph shape after retain: ', selected_subgraph.shape)
    print('3 selected_subgraph values shape after retain: ', selected_subgraph.values.shape)

    # remove the edges which value is < a_thresh
    selected_adj_mask = tf.where(
        selected_subgraph.values >= a_thresh, selected_subgraph.values, 0
    )

    print('4 selected_adj_mask shape: ', selected_adj_mask.shape)

    selected_subgraph = tf.sparse.map_values(
        tf.multiply, comp_graph, selected_adj_mask
    )
    print('5 selected_subgraph shape: ', selected_subgraph.shape)
    print('5 selected_subgraph values shape: ', selected_subgraph.values.shape)

    is_nonzero = tf.not_equal(selected_subgraph.values, 0)
    selected_subgraph = tf.sparse.retain(selected_subgraph, is_nonzero)

It can happen that some values of the sparse matrices are not zero, in this way we could solve.

Otherwise I am thinking the elements on the diagonal of the a matrix can be a problem, for this reason can you convert your a matrix into a binary adjacency one with this function:

def binary_adj_converter(a_in):
    """
    Transforms a graph matrix into the binary adjacency matrix.
    **Arguments**
    - `a_in`: sparse `(n_nodes, n_nodes)` graph tensor;
    """
    a_idx = a_in.indices
    off_diag_idx = tf.not_equal(a_idx[:, 0], a_idx[:, 1])
    a_idx = a_idx[off_diag_idx]

    a = tf.sparse.SparseTensor(
        a_idx, tf.ones(a_idx.shape[0], dtype=tf.float32), a_in.shape
    )
    return a

After you converted the a matrix feed it into the explainer method without the gcn_filter. You can also run again the function above so we can see the shapes. Thanks

antonioaa1979 commented 3 years ago

the first test leads to this:

explainer_cleaning(adj_mask, explainer, a_thresh=0.1)
1 comp_graph shape: (1653, 1653)
1 comp_graph values shape:  (2739,)
1 selected_adj_mask shape:  (2739,)
2 selected_subgraph shape:  (1653, 1653)
2 selected_subgraph values shape:  (2739,)
2 selected_subgraph shape after retain:  (1653, 1653)
2 selected_subgraph values shape after retain:  (2739,)
3 selected_subgraph shape:  (1653, 1653)
3 selected_subgraph values shape:  (2955,)
3 selected_subgraph shape after retain:  (1653, 1653)
3 selected_subgraph values shape after retain:  (2955,)
4 selected_adj_mask shape:  (2955,)
Traceback (most recent call last):
...
tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [2739] vs. [2955] [Op:Mul]
antonioaa1979 commented 3 years ago

the second test doesn't run for me. I build the adjacency matrix as a a COO sparse matrix:

a = sp.coo_matrix((weights[:, 2], (weights[:, 0], weights[:, 1])), shape=shape, dtype=weights.dtype)

when i run the binary converter i get this error in the first line of the function:

a = binary_adj_converter(a)

 File "<ipython-input-33-39e085bf0893>", line 104, in binary_adj_converter
    a_idx = a_in.indices
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/scipy/sparse/base.py", line 687, in __getattr__
    raise AttributeError(attr + " not found")
AttributeError: indices not found

But if i convert with my own procedure the adjacency matrix to binary, i still see the issue:

a = sp.coo_matrix((np.ones(len(weights)), (weights[:, 0], weights[:, 1])), shape=shape, dtype=weights.dtype) # Binary
...
G = explainer.plot_subgraph(adj_mask, feat_mask, node_idx)
tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [2739] vs. [2955] [Op:Mul]
AlexandrMelnic commented 3 years ago

Ok the problem is in the transpose operation I guess. I will try to fix it. Thank you for the collaboration!

antonioaa1979 commented 3 years ago

thank you.. feel free to ping me for testing the fix

danielegrattarola commented 3 years ago

Thanks for working on this @AlexandrMelnic, let me know if I can speed up testing/pushing the fix.

Cheers

AlexandrMelnic commented 3 years ago

Let's see if this works. I did rewrite the function a little bit, there was no a real reason to have that transposition at that point. Can you try this function just as before:

def explainer_cleaning(explainer, adj_mask, a_thresh):

    selected_adj_mask = tf.nn.sigmoid(adj_mask)

    print('1 selected_adj_mask ',  selected_adj_mask.shape)
    comp_graph_values = tf.ones_like(explainer.comp_graph.values)
    comp_graph = tf.sparse.SparseTensor(
        explainer.comp_graph.indices, comp_graph_values, explainer.comp_graph.shape
    )
    print('2 comp_graph.values ',  comp_graph.values.shape)

    selected_adj_mask = tf.where(
        selected_adj_mask >= a_thresh, selected_adj_mask, 0
    )

    print('3 selected_adj_mask ', selected_adj_mask.shape)

    selected_subgraph = tf.sparse.map_values(
        tf.multiply, comp_graph, selected_adj_mask
    )
    print('4 selected_subgraph ', selected_subgraph.values.shape)

    is_nonzero = tf.not_equal(selected_subgraph.values, 0)
    selected_subgraph = tf.sparse.retain(selected_subgraph, is_nonzero)

    print('5 selected_subgraph ', selected_subgraph.values.shape)

    selected_subgraph = (
        tf.sparse.add(selected_subgraph, tf.sparse.transpose(selected_subgraph)) / 2
    )

    print('6 selected_subgraph ', selected_subgraph.values.shape)
    return selected_subgraph
antonioaa1979 commented 3 years ago

Hi @AlexandrMelnic the function doesn't produce errors:

explainer_cleaning(explainer, adj_mask, a_thresh=0.1)
1 selected_adj_mask  (2739,)
2 comp_graph.values  (2739,)
3 selected_adj_mask  (2739,)
4 selected_subgraph  (2739,)
5 selected_subgraph  (2739,)
6 selected_subgraph  (2955,)
Out[22]: <tensorflow.python.framework.sparse_tensor.SparseTensor at 0x15a138f90>

Pls let me know once the fix is committed and available, if you dont mind ;)

danielegrattarola commented 3 years ago

Hi @antonioaa1979 ,

I've merged @AlexandrMelnic's change into the develop branch, can you verify that it solves your issue by installing the latest version from source?

git clone https://github.com/danielegrattarola/spektral.git
cd spektral
git checkout develop
pip install -U .

Thanks

antonioaa1979 commented 3 years ago

Thanks both! Hi @danielegrattarola I have followed above procedure, but got following error when training the model now:

history = model.fit(loader_tr.load(), steps_per_epoch=loader_tr.steps_per_epoch, validation_data=loader_va.load(),
              validation_steps=loader_va.steps_per_epoch, epochs=epochs,
              callbacks=[EarlyStopping(patience=patience, restore_best_weights=True),])

Traceback (most recent call last):
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3331, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-14-39d8faee841b>", line 4, in <module>
    history = model.fit(loader_tr.load(), steps_per_epoch=loader_tr.steps_per_epoch, validation_data=loader_va.load(),
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/spektral/data/loaders.py", line 240, in load
    output = self.collate(self.dataset)
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/spektral/data/loaders.py", line 221, in collate
    output = to_disjoint(**packed)
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/spektral/data/utils.py", line 52, in to_disjoint
    a_out = sp.block_diag(a_list)
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/scipy/sparse/construct.py", line 688, in block_diag
    data.append(a.ravel())
AttributeError: 'SparseTensor' object has no attribute 'ravel'

Not sure if this is due to the develop branch? How can i verify i have installed the latest develop branch correctly? This is what i got from above pip install command:

spektral %  pip install -U .
...
Building wheels for collected packages: spektral
  Building wheel for spektral (setup.py) ... done
  Created wheel for spektral: filename=spektral-1.0.6-py3-none-any.whl size=123388 sha256=1240b7b30ad0b0252736dc3b830279cfc5a6b2e22f5a98dc80db97570e006c13
  Stored in directory: /private/var/folders/g9/yz6yp_5n1l3cs72t4_1bsl_w0000gn/T/pip-ephem-wheel-cache-hq4fzoi8/wheels/77/05/37/6661e4114ebe416489cd00534974ec6bdc81c919032683bd41
Successfully built spektral
Installing collected packages: spektral
  Attempting uninstall: spektral
    Found existing installation: spektral 1.0.7
    Uninstalling spektral-1.0.7:
      Successfully uninstalled spektral-1.0.7
Successfully installed spektral-1.0.6

Thanks

PS: how do i go back to master version?

danielegrattarola commented 3 years ago

Yes, that is due to some new changes in develop. When creating the dataset, before you had to convert the adjacency matrix from Scipy sparse to SparseTensor. Now the Loader expects a Scipy sparse matrix. So, if you have the AdjToSpTensor transform used anywhere, you should remove it and let the adjacent matrix be a scipy sparse or numpy array.

PS: how do i go back to master version?

cd spektral 
git checkout master
antonioaa1979 commented 3 years ago

ok, removed the AdjToSpTensor transform and the model now does fit. But got this error in running explain_node:

adj_mask, feat_mask = explainer.explain_node(x=x_exp, a=a_exp, node_idx=node_idx)
Out[29]: 
Traceback (most recent call last):
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3331, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-28-0f5c5af0c10f>", line 1, in <module>
    adj_mask, feat_mask = explainer.explain_node(x=x_exp, a=a_exp, node_idx=node_idx)
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/spektral/models/gnn_explainer.py", line 107, in explain_node
    a, node_idx, self.n_hops, self.preprocess
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/spektral/models/gnn_explainer.py", line 314, in k_hop_sparse_subgraph
    if a.dtype != tf.float32:
TypeError: Cannot interpret 'tf.float32' as a data type

a_exp.dtype
Out[30]: dtype('float32')

tf.float32
Out[31]: tf.float32

a_exp.dtype != tf.float32
Out[32]: 
Traceback (most recent call last):
  File ".pyenv/versions/3.7.6/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3331, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-32-ce553183aea3>", line 1, in <module>
    a_exp.dtype != tf.float32
TypeError: Cannot interpret 'tf.float32' as a data type

type(tf.float32)
Out[33]: tensorflow.python.framework.dtypes.DType

tf.__version__
Out[34]: '2.5.0'

it seems like fit method expects an adjacency matrix in scipy sparse format, while explainer still expects it as tensorflow sparcetensor?

AlexandrMelnic commented 3 years ago

when you give in input a_exp in the explain_node can you convert it into a sparse tensor? So we can understand if everything else works. Then I can rewrite the function such that it takes in input a scipy sparse matrix.

antonioaa1979 commented 3 years ago

good one... here we go...

adj_mask, feat_mask = explainer.explain_node(x=x_exp, a=spektral.utils.sparse.sp_matrix_to_sp_tensor(a_exp), node_idx=node_idx)
...

G = explainer.plot_subgraph(adj_mask, feat_mask, node_idx)

plt.show()

all runs smoothly and produces a nice chart! Thanks, i can confirm the bugfix works!

danielegrattarola commented 3 years ago

Thanks to both of you for working through this issue. I will merge the fix into master as soon as possible.

Cheers