I have trained a model with fine-tuning pre-trained model ssd_mobilenet_v2_coco_2018
. Here, I have used the exact same pipeline.config file for training which is available inside ssd_mobilenet_v2_coco_2018
pre-trained folder.
I have only removed the batch_norm_trainable: true
flag and changed the number of classes (4).
After training the model with my custom datasets with 4 classes, I found concat
and concat_1
nodes get exchange with each other.
Pre-trained model has
| concat | 1x1917x1x4 |
after-training it becomes
| concat | 1x1917x5 |
I have attached both tensorboard graph visualisation images. First image is pre-trained graph ssd_mobilenet_v2_coco_2018
.
The node exchanges can be seen on the rightmost corner of the image. As in the pre-trained graph, Postprocess layer
connect with concat_1
and Squeeeze
connect with concat
. But after the training, the graph shows completely reverse. Like Prosprocess layer
connect with concat
and Squeeeze
connect with concat_1
.
Further, I also found in the pre-trained model graph that the Preprocessor
takes input ToFloat
while after training the graph shows Cast as an input to Preprocessor
.
I have fed the input to the model as tfrecords
.
Each node takes zero or more tensors as inputs and produces a tensor as an output. One type of node is a constant. Like all TensorFlow constants, it takes no inputs, and it outputs a value it stores internally.
Graphs are data structures that contain a set of tf. Operation objects, which represent units of computation; and tf. Tensor objects, which represent the units of data that flow between operations. They are defined in a tf. Graph context.
The TensorFlow Python library has a default graph to which ops constructors add nodes. The default graph is sufficient for many applications. See the Graph class documentation for how to explicitly manage multiple graphs.
What Are Computational Graphs? In TensorFlow, machine learning algorithms are represented as computational graphs. A computational graph is a type of directed graph where nodes describe operations, while edges represent the data (tensor) flowing between those operations.
You create and run a graph in TensorFlow by using tf.function, either as a direct call or as a decorator. tf.function takes a regular function as input and returns a Function. A Function is a Python callable that builds TensorFlow graphs from the Python function. You use a Function in the same way as its Python equivalent. import tensorflow as tf
A Function is a Python callable that builds TensorFlow graphs from the Python function. You use a Function in the same way as its Python equivalent.
Grappler is the default graph optimization system in the TensorFlow runtime. Grappler applies optimizations in graph mode (within tf.function) to improve the performance of your TensorFlow computations through graph simplifications and other high-level optimizations such as inlining function bodies to enable inter-procedural optimizations.
To explain, the print statement is executed when Function runs the original code in order to create the graph in a process known as "tracing". Tracing captures the TensorFlow operations into a graph, and print is not captured in the graph. That graph is then executed for all three calls without ever running the Python code again.
Most probably, the difference is not in the graph, but simply in the names of the nodes, i.e. nodes concat
and concat_1
on the left are the same nodes as resp. concat_1
and concat
on the right.
The thing is, when you don't provide an explicit name to a node, tensorflow needs to come up with one, and it's naming convention is rather uninventive. The first time it needs to name a node, it does so with its type. When it encounter the situation again, it simply add _
+ an increasing number to the name.
Take this example:
import tensorflow as tf
x = tf.placeholder(tf.float32, (1,), name='x')
y = tf.placeholder(tf.float32, (1,), name='y')
z = tf.placeholder(tf.float32, (1,), name='z')
xy = tf.concat([x, y], axis=0) # named 'concat'
xz = tf.concat([x, z], axis=0) # named 'concat_1'
The graph looks like this:
Now if we construct the same graph, but this time creating xz
before xy
, we get the following graph:
So the graph did not really change -- only the names did. This is probably what happened in your case: the same operations were created but not in the same order.
The fact that names changed for stateless nodes like concat
is unimportant, because no weights will be misrouted when loading a saved model for example. Nonetheless, if naming stability is important for you, you could either give explicit names to your operations or place them in distinct scopes:
xy = tf.concat([x, y], axis=0, name='xy')
xz = tf.concat([x, z], axis=0, name='xz')
It is much more problematic if variables switch name. This is one of the reason why tf.get_variable
-- which forces variables to have a name and raises an error when a name conflict occurs -- was the preferred way of dealing with variables in the pre-TF2 era.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With