1

I am trying to generate some kind of textual representation for the TensorFlow Computational Graph. I know that Tensorboard can provide me with the visualization. However, I need some kind of representation (adjacency matrix or adjacency list) from where I can parse information associated with graphs.

So far, I have tried the following:

import tensorflow as tf

a = tf.constant(1.3, name = const_a)
b = tf.constant(3.1, name = const_b)
c = tf.add(a,b, name = 'addition')
d = tf.multiply(c,a, name = 'multiplication')
e = tf.add(d,c, name = 'addition_1')

with tf.Session() as sess:
     print(sess.run([c,d,e]))

After this, I decided to keep the graph object in a separate variable and tried to parse information from there:

graph = tf.get_default_graph()

I found out how to get the list of all operations from this documentation.

for op in graph.get_operations():
     print(op.values())

This part actually provides me with the information of the nodes of the computation graph.

(<tf.Tensor 'const_a:0' shape=() dtype=float32>,)
(<tf.Tensor 'const_b:0' shape=() dtype=float32>,)
(<tf.Tensor 'addition:0' shape=() dtype=float32>,)
(<tf.Tensor 'multiplication:0' shape=() dtype=float32>,)
(<tf.Tensor 'addition_1:0' shape=() dtype=float32>,)

However, I cannot seem to find any method that can provide me with information regarding the edges of the computation graph. I cannot find any method that can give me the input tensors associated with each operation. I would like to know that the operation named addition_1 has input tensors produced by the operations addition and multiplication; or something that can be used to derive this information. From the documentation, it seems that the Operation object has a property named inputs which may be the thing I am looking for. Nonetheless, I don't see a method that can be called to return this property.

1 Answers1

0

From your code I think you are using tensorflow v<2. So, not sure if this will solve your problem but I can create adj.list and adj.mat format using v2.2.0

split is used to parse name, following this answer

Adjacency matrix generation,

# adjacency matrix
# if operation input is node1 and output is node2, then mat[node1][node2] = 1
graph_adj_mat = [] 
# name to number mapping to set 1/0 from the node name tensorflow gives
graph_node_name_to_num_map = {}
# node number to name map will be needed later to understand matrix
# as tensorflow identify node using name
graph_node_num_to_name_map = {}


# usage of compat module to use Session in v2.2.0
# if v < 2 use tf.Session() as sess
with tf.compat.v1.Session() as sess:
    # initiating the matrix and necessary map
    for op in sess.graph.get_operations():
        graph_node_num_to_name_map[len(graph_adj_mat)] = op.name
        graph_node_name_to_num_map[op.name] = len(graph_adj_mat)
        graph_adj_mat.append([0]*len(sess.graph.get_operations()))

    # parsing the name and setting adj. mat
    # edge direction input tensor to output tensor
    for op in sess.graph.get_operations():
        dst_node_name  = op.name.split(':')[0]
        for in_tensor in op.inputs:
            src_node_name  = in_tensor.name.split(':')[0]
            graph_adj_mat[graph_node_name_to_num_map[src_node_name]][graph_node_name_to_num_map[dst_node_name]] = 1


print(graph_adj_mat)
print(graph_node_num_to_name_map)

Adjacency list generation (using dict),

# adjacency list is dictionary of tensor name, 
# each input tensor name key holds output tensor name containing list
graph_adj_list = {}
with tf.compat.v1.Session() as sess:
    for op in sess.graph.get_operations():
        graph_adj_list[op.name] = []

    for op in sess.graph.get_operations():
        dst_node_name  = op.name.split(':')[0]
        for in_tensor in op.inputs:
            src_node_name  = in_tensor.name.split(':')[0]
            graph_adj_list[src_node_name].append(dst_node_name)

# graph_adj_list[in_tensor_name] contains list containing tensor names which are produced using in_tensor_name
print(graph_adj_list)

Output tested with modified version of given code,

import tensorflow as tf

print(tf.__version__)

tf.compat.v1.disable_eager_execution()
tf.compat.v1.reset_default_graph()

a = tf.constant(1.3, name = 'const_a')
b = tf.constant(3.1, name = 'const_b')
c = tf.add(a,b, name = 'addition')
d = tf.multiply(c,a, name = 'multiplication')
e = tf.add(d,c, name = 'addition_1')