google-deepmind / graph_nets

Build Graph Nets in Tensorflow
https://arxiv.org/abs/1806.01261
Apache License 2.0
5.34k stars 783 forks source link

"exclude_self_edges" in "broadcast_sender_nodes_to_edges" and "SentEdgesToNodesAggregator" etc #132

Closed Pol-Zeimet closed 3 years ago

Pol-Zeimet commented 3 years ago

Hello, I am currently working on a model to process Documents as graphs. The idea is to use the resulting node embeddings from the graph convolution as a sequence on wich I can perform sequence labeling to extract certain labels. Maybe I have an overcomplicated approach, so feel free to question it :) But since I want to use end-to-end learning for the embedding-calculation and the sequence labeling aswell as be able to process batches of graphs, my input looks as follows:

nodes_input = keras.Input(shape=(512, node_shape), name = 'nodes_input')
edges_input = keras.Input(shape=(60000, edge_shape), name = 'edges_input')
senders_input = keras.Input(shape=(60000), dtype='int32', name = 'senders_input')
receivers_input = keras.Input(shape=(60000), dtype='int32', name = 'receivers_input')

output = some_output(...)

model = keras.Model([nodes_input, edges_input, senders_input, receivers_input], output)

I split the graphs into their components, since tensorflow wants specific shapes which a single graph cannot provide. Rebuilding the batched graph from these is no probem either. The issue that arises however is the following: I need to pad my graphs to a fixed length of nodes, edges, senders and receivers. (in my example 512 nodes, 60000 edges) For nodes and edges, that is no problem, I can fill them with 0-vectors. The problem are senders and receivers, since they need to be filled with an int and will therefore always link edges to nodes.

Padding senders and receivers with 0 will, for example, result in all of the added padding-edges becoming self edges for node 0. This is unfortunate for methods like broadcast_sender_nodes_to_edges and SentEdgesToNodesAggregator Having an argument like exclude_self_edges=True from utils_tf.fully_connect_graph_static would help immensly in this case.

Is there some other way to pad my graphs or ignore the added edges in senders/receivers? Thank you in advance!

Pol-Zeimet commented 3 years ago

After some experimentation I figure that padding with -1 for receivers and senders would work. So I will stick with that for now. That is, of course, if there ain't a more suitable solution.

alvarosg commented 3 years ago

Thanks for bringing this up. Padding GraphsTuples is indeed challenging I would recommend using utils_tf.pad_graphs_tuple available here. The docs also describe the padding strategy we use and possible caveats. The main strategy is to pad with a "Graph" rather than padding tensors in isolation.

There are also methods for getting padding masks and removing the padding that you may find useful: get_graphs_tuple_size (which you can call before adding the padding for use with the following method) remove_graphs_tuple_padding, get_mask. Hopefully that is helpful!

Note this method is not yet on the latest library release from pypi, so you may have to install it directly from github if you want to get it.

Pol-Zeimet commented 3 years ago

Thank you, that is very helpful! I somehow didn't notice those function in the documentation. I feel pretty stupid now haha

alvarosg commented 3 years ago

Oh, no worries, this was only open sourced 12 days ago, and it does not have a demo yet. Glad this helped!

I will close this for now, but please feel free to re-open if necessary :)