I cannot understand Tensorflow system.
First,I wrote
#coding:UTF-8
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
const1 = tf.constant(2)
const2 = tf.constant(3)
add_op = tf.add(const1,const2)
with tf.Session() as sess:
result = sess.run(add_op)
print(result)
and it print out 5.
Second,I wrote
#coding:UTF-8
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
const1 = tf.constant(2)
const2 = tf.constant(3)
add_op = tf.add(const1,const2)
print(add_op)
and it print out Tensor("Add:0", shape=(), dtype=int32).
I cannot understand this system.
I use Python and other languages, so I think tf.add() method is add method.However,in the case of Tensorflow,it seems different.
why is this part
with tf.Session() as sess:
result = sess.run(add_op)
print(result)
necessary?
What functions does this part have?
I would suggest to read the official Getting Started with TensorFlow guide of TensorFlow to get to know the core concepts of the library, such as the one which seems to be the problem here:
Every TensorFlow program consists of two parts:
Building the computational graph.
Running the computational graph.
Now, what is a "computational graph"? In TensorFlow, you specify a series of operations which are executed on your input. This series of operations is your "computational graph". To understand that, lets look at some examples:
Simple addition: let's look at your example, your code is
const1 = tf.constant(2)
const2 = tf.constant(3)
add_op = tf.add(const1,const2)
This creates two constant nodes in the graph, and creates a second node which adds them. Graphically, this looks like:
To make it a little bit more complex, lets say you have an input x and want to add a constant 3 to it. Then your code would be:
const1 = tf.constant(2)
x = tf.placeholder(tf.float32)
add_op = tf.add(const1,x)
and your graph is
In both examples, this was the first part of the program. So far, we only defined how our computational graph should look, i.e. what inputs we have, what outputs, and all calculations needed.
But: no calculations have been done so far! In the second example, you don't even know what your input x is - only that it will be a float32.
If you have a GPU, you'll notice that TensorFlow hasn't even touched the GPU yet. Even if you have a huge neural network with millions of training images, this step runs in milliseconds, as no "real" work has to be done.
Now comes part two: running the graph we defined above. Here's where the work happens!
We fire up TensorFlow by creating a tf.Session, and then we can run anything by calling sess.run().
with tf.Session() as sess:
result = sess.run(add_op)
print(result)
In the second example, we now have to tell TensorFlow what our value x should be:
with tf.Session() as sess:
result = sess.run(add_op, {x: 5.0})
print(result)
tl;dr: every TensorFlow program has two parts: 1. building a computational graph, and 2. running this graph. With tf.add you only define the graph, but no addition is performed yet. To run this graph, use sess.run() as in your first piece code.
Related
I'm currently running in a problem where tensorflow doesn't produce the results I intended to get. When I tried to debug the problem I noticed that up to a division everything seems to work out fine.
https://imgur.com/a/DT4RWiS
Can someone enlighten me what might be happening here?
There might be some stochasticity involved. Consider the following example:
import tensorflow as tf
a = tf.random_uniform(shape=(4,), minval=1, maxval=2)
b = tf.random_uniform(shape=(4,), minval=1, maxval=2)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(a.eval()/b.eval())
print((a/b).eval())
When a.eval() and (a/b).eval() are called, tf.random_uniform is executed and tensor a is filled with different random numbers.
This is because the / operator in tensorflow follows the Python 2 syntax and performs an integer division (see https://www.tensorflow.org/api_docs/python/tf/div). You should use tf.divide instead. In general for any mathematical operation between tensors you should use tf.operation_name
I'm new at Tensorflow. I am having a litte trouble at understanding its constants. I have this simple code mentioned below:
import tensorflow as tf
vector = tf.constant([[1,2,3,4],[4,5,6,7],[8,9,1,2]],tf.int32,name="vector")
with tf.Session() as sess:
v = sess.run(vector)
argm = tf.argmax(v,1)
print(argm)
I expect this to return something like [4,7,8], as I understood from the documentation. Instead, I get this:
Tensor("ArgMax:0", shape=(3,), dtype=int64).
So, i don't know what am I doing wrong.
Alternatively to the answer of #James, you might want to use tensorflow's eager execution, which behaves more like "standard" python: operations are executed as you type them, no more graphs and Session.
import tensorflow as tf
tf.enable_eager_execution()
vector = tf.constant([[1,2,3,4],[4,5,6,7],[8,9,1,2]],tf.int32,name="vector")
argm = tf.argmax(vector,1)
print(argm)
Tensorflow operations like tf.argmax somewhat unintuitively don't perform the operation that they're stating, but add an operation to a graph that will be performed. When you run argm = tf.argmax(v,1), the return value is tensor that isn't evaluated yet.
If you want the result of the argmax operation, you can run something like this:
import tensorflow as tf
vector = tf.constant([[1,2,3,4],[4,5,6,7],[8,9,1,2]],tf.int32,name="vector")
argm = tf.argmax(vector,1)
with tf.Session() as sess:
a = sess.run(argm)
print(a)
With this code, we're explicitly asking Tensorflow to run the computations to compute the result of the tf.argmax operation. With your previous code, we ran the computation to compute v (which is a constant, so that's pretty quick), then define a new graph operation to compute argmax on that - but never actually do the computation.
Today I noticed some strange behaviour in Tensorflow and thought I'd ask here to understand what's happening. My problem revolves around tf.control_dependencies not making the specified operator being run before the operators I define inside the with block. What I am asking here is not how to compute the performance metrics (I coded that manually), but rather where my misconception lies.
So, to set the scene. Today, I made some code to log performance metrics during training of a CNN, and I was using the tensorflow.metrics module for this. However, the operators in this module cumulate the previous results (so performance metrics can be computed for very large datasets). I want to log how the metrics evolve over time as the network train, so I don't want this behaviour. Therefore, I wrapped the creation of these performance metrics nodes in a tf.control_dependencies, forcing (or so I thought) a tf.local_variables_initialiser to be evaluated before my performance metrics is computed. Thus, my code could look like this
import tensorflow as tf
import numpy as np
labels = tf.convert_to_tensor(np.arange(10))
out = tf.convert_to_tensor(np.random.randn(10, 1))
with tf.control_dependencies([tf.local_variables_initializer()]):
_, precision = tf.metrics.precision(labels, out)
with tf.Session() as sess:
#sess.run(tf.local_variables_initializer())
print(sess.run(precision))
but when I try to run the above code, I get the following error
FailedPreconditionError (see above for traceback): Attempting to use uninitialized value precision_4/true_positives/count
[[Node: precision_4/true_positives/AssignAdd = AssignAdd[T=DT_FLOAT, _class=["loc:#precision_4/true_positives/count"], use_locking=false, _device="/job:localhost/replica:0/task:0/device:CPU:0"](precision_4/true_positives/count, precision_4/true_positives/Sum)]]
now, I have encountered this error many times while I tried to understand the metrics module and the reason for it is that I have not initialised my variables properly. Therefore, I tested this code
import tensorflow as tf
import numpy as np
labels = tf.convert_to_tensor(np.arange(10))
out = tf.convert_to_tensor(np.random.randn(10, 1))
with tf.control_dependencies([tf.local_variables_initializer()]):
_, precision = tf.metrics.precision(labels, out)
with tf.Session() as sess:
sess.run(tf.local_variables_initializer())
print(sess.run(precision))
which does indeed work.
So my question remains. Why is the tf.local_variables_initializer() node not ran before the performance metrics are computed in my first code example?
This is indeed really strange. I guess you need to place
_, precision = tf.metrics.precision(labels, out)
before the control_dependencies like
import tensorflow as tf
import numpy as np
labels = tf.convert_to_tensor(np.arange(10))
out = tf.convert_to_tensor(np.random.randn(10, 1))
_, _precision = tf.metrics.precision(labels, out)
with tf.control_dependencies([tf.local_variables_initializer()]):
# precision = tf.identity(_precision)
precision = 1 * _precision
with tf.Session() as sess:
print(sess.run(precision))
This works like expected as the local variables of tf.metrics.precision do exist before calling tf.local_variables_initializer. In your code, the tf.local_variables_initializer is executed before the node precision. Hence, precision_4/true_positives/count cannot exists and therefore not initialized, simply because the graph is not existing.
To make it even more strange (which seems to be a bug):
Placing precision = 1 * precision in the body of control_dependencies works. But precision = tf.identity(precision) does not.
This is a good candidate for a bug in TensorFlow.
I'm trying to run a neural network multiple times with different parameters in order to calibrate the networks parameters (dropout probabilities, learning rate e.d.). However I am having the problem that running the network while keeping the parameters the same still gives me a different solution when I run the network in a loop as follows:
filename = create_results_file()
for i in range(3):
g = tf.Graph()
with g.as_default():
accuracy_result, average_error = network.train_network(
parameters, inputHeight, inputWidth, inputChannels, outputClasses)
f, w = get_csv_writer(filename)
w.writerow([accuracy_result, "did run %d" % i, average_error])
f.close()
I am using the following code at the start of my train_network function before setting up the layers and error function of my network:
np.random.seed(1)
tf.set_random_seed(1)
I have also tried adding this code before the TensorFlow graph creation, but I keep getting different solutions in my results output.
I am using an AdamOptimizer and am initializing network weights using tf.truncated_normal. Additionally I am using np.random.permutation to shuffle the incoming images for each epoch.
Setting the current TensorFlow random seed affects the current default graph only. Since you are creating a new graph for your training and setting it as default (with g.as_default():), you must set the random seed within the scope of that with block.
For example, your loop should look like the following:
for i in range(3):
g = tf.Graph()
with g.as_default():
tf.set_random_seed(1)
accuracy_result, average_error = network.train_network(
parameters, inputHeight, inputWidth, inputChannels, outputClasses)
Note that this will use the same random seed for each iteration of the outer for loop. If you want to use a different—but still deterministic—seed in each iteration, you can use tf.set_random_seed(i + 1).
Backend Setup: cuda:10.1, cudnn: 7, tensorflow-gpu: 2.1.0, keras: 2.2.4-tf, and vgg19 customized model
After looking into the issue of unstable results for tensorflow backend with GPU training and large neural network models based on keras, I was finally able to get reproducible (stable) results as follows:
Import only those libraries that would be required for setting seed and initialize a seed value
import tensorflow as tf
import os
import numpy as np
import random
SEED = 0
Function to initialize seeds for all libraries which might have stochastic behavior
def set_seeds(seed=SEED):
os.environ['PYTHONHASHSEED'] = str(seed)
random.seed(seed)
tf.random.set_seed(seed)
np.random.seed(seed)
Activate Tensorflow deterministic behavior
def set_global_determinism(seed=SEED):
set_seeds(seed=seed)
os.environ['TF_DETERMINISTIC_OPS'] = '1'
os.environ['TF_CUDNN_DETERMINISTIC'] = '1'
tf.config.threading.set_inter_op_parallelism_threads(1)
tf.config.threading.set_intra_op_parallelism_threads(1)
# Call the above function with seed value
set_global_determinism(seed=SEED)
Important notes:
Please call the above code before executing any other code
Model training might become slower since the code is deterministic, hence there's a tradeoff
I experimented several times with a varying number of epochs and different settings (including model.fit() with shuffle=True) and the above code gives me reproducible results.
References:
https://suneeta-mall.github.io/2019/12/22/Reproducible-ml-tensorflow.html
https://keras.io/getting_started/faq/#how-can-i-obtain-reproducible-results-using-keras-during-development
https://www.tensorflow.org/api_docs/python/tf/config/threading/set_inter_op_parallelism_threads
https://www.tensorflow.org/api_docs/python/tf/random/set_seed?version=nightly
Deterministic behaviour can be obtained either by supplying a graph-level or an operation-level seed. Both worked for me. A graph-level seed can be placed with tf.set_random_seed. An operation-level seed can be placed e.g, in a variable intializer as in:
myvar = tf.Variable(tf.truncated_normal(((10,10)), stddev=0.1, seed=0))
Tensorflow 2.0 Compatible Answer: For Tensorflow version greater than 2.0, if we want to set the Global Random Seed, the Command used is tf.random.set_seed.
If we are migrating from Tensorflow Version 1.x to 2.x, we can use the command,
tf.compat.v2.random.set_seed.
Note that tf.function acts like a re-run of a program in this case.
To set the Operation Level Seed (as answered above), we can use the command, tf.random.uniform([1], seed=1).
For more details, refer this Tensorflow Page.
It seems as if none of these answers will work due to underlying implementation issues in CuDNN.
You can get a bit more determinism by adding an extra flag
os.environ['PYTHONHASHSEED']=str(SEED)
os.environ['TF_CUDNN_DETERMINISTIC'] = '1' # new flag present in tf 2.0+
random.seed(SEED)
np.random.seed(SEED)
tf.set_random_seed(SEED)
But this still won't be entirely deterministic. To get an even more exact solution, you need use the procedure outlined in this nvidia repo.
Please add all random seed functions before your code:
tf.reset_default_graph()
tf.random.set_seed(0)
random.seed(0)
np.random.seed(0)
I think, some models in TensorFlow are using numpy or the python random function.
I'm using TensorFlow 2 (2.2.0) and I'm running code in JupyterLab. I've tested this in macOS Catalina and in Google Colab with same results. I'll add some stuff to Tensorflow Support's answer.
When I do some training using the model.fit() method I do it in a cell. I do some other stuff in other cells. This is the code I run in the mentioned cell:
# To have same results always place this on top of the cell
tf.random.set_seed(1)
(x_train, y_train), (x_test, y_test) = load_data_onehot_grayscale()
model = get_mlp_model_compiled() # Creates the model, compiles it and returns it
history = model.fit(x=x_train, y=y_train,
epochs=30,
callbacks=get_mlp_model_callbacks(),
validation_split=.1,
)
This is what I understand:
TensorFlow has some random processes that happen at different stages (initializing, shuffling, ...), every time those processes happen TensorFlow uses a random function. When you set the seed using tf.random.set_seed(1) you make those processes use it and if the seed is set and the processes don't change the results will be the same.
Now, in the code above, if I change tf.random.set_seed(1) to go below the line model = get_mlp_model_compiled() my results change, I believe it's because get_mlp_model_compiled() uses randomness and isn't using the seed I want.
Caveat about point 2: if I run the cell 3 times in a row I do get same results. I believe this happens because, in run nº1 get_mlp_model_compiled() isn't using TensorFlow's internal counter with my seed. In run nº2 it will be using a seed and all subsequent runs it will be using the seed too so after run nº2 results will be the same.
I might have some information wrong so feel free to correct me.
To understand what's going on you should read the docs, they're not so long and kind of easy to understand.
This answer is an addition to Luke's answer and for TF v2.2.0
import numpy as np
import os
import random
import tensorflow as tf # 2.2.0
SEED = 42
os.environ['PYTHONHASHSEED']=str(SEED)
os.environ['TF_CUDNN_DETERMINISTIC'] = '1' # TF 2.1
random.seed(SEED)
np.random.seed(SEED)
tf.random.set_seed(SEED)
I get different results (test accuracy) every time I run the imdb_lstm.py example from Keras framework (https://github.com/fchollet/keras/blob/master/examples/imdb_lstm.py)
The code contains np.random.seed(1337) in the top, before any keras imports. It should prevent it from generating different numbers for every run. What am I missing?
UPDATE: How to repro:
Install Keras (http://keras.io/)
Execute https://github.com/fchollet/keras/blob/master/examples/imdb_lstm.py a few times. It will train the model and output test accuracy.
Expected result: Test accuracy is the same on every run.
Actual result: Test accuracy is different on every run.
UPDATE2: I'm running it on Windows 8.1 with MinGW/msys, module versions:
theano 0.7.0
numpy 1.8.1
scipy 0.14.0c1
UPDATE3: I narrowed the problem down a bit. If I run the example with GPU (set theano flag device=gpu0) then I get different test accuracy every time, but if I run it on CPU then everything works as expected. My graphics card: NVIDIA GeForce GT 635)
You can find the answer at the Keras docs: https://keras.io/getting-started/faq/#how-can-i-obtain-reproducible-results-using-keras-during-development.
In short, to be absolutely sure that you will get reproducible results with your python script on one computer's/laptop's CPU then you will have to do the following:
Set the PYTHONHASHSEED environment variable at a fixed value
Set the python built-in pseudo-random generator at a fixed value
Set the numpy pseudo-random generator at a fixed value
Set the tensorflow pseudo-random generator at a fixed value
Configure a new global tensorflow session
Following the Keras link at the top, the source code I am using is the following:
# Seed value
# Apparently you may use different seed values at each stage
seed_value= 0
# 1. Set the `PYTHONHASHSEED` environment variable at a fixed value
import os
os.environ['PYTHONHASHSEED']=str(seed_value)
# 2. Set the `python` built-in pseudo-random generator at a fixed value
import random
random.seed(seed_value)
# 3. Set the `numpy` pseudo-random generator at a fixed value
import numpy as np
np.random.seed(seed_value)
# 4. Set the `tensorflow` pseudo-random generator at a fixed value
import tensorflow as tf
tf.random.set_seed(seed_value)
# for later versions:
# tf.compat.v1.set_random_seed(seed_value)
# 5. Configure a new global `tensorflow` session
from keras import backend as K
session_conf = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)
sess = tf.Session(graph=tf.get_default_graph(), config=session_conf)
K.set_session(sess)
# for later versions:
# session_conf = tf.compat.v1.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)
# sess = tf.compat.v1.Session(graph=tf.compat.v1.get_default_graph(), config=session_conf)
# tf.compat.v1.keras.backend.set_session(sess)
It is needless to say that you do not have to to specify any seed or random_state at the numpy, scikit-learn or tensorflow/keras functions that you are using in your python script exactly because with the source code above we set globally their pseudo-random generators at a fixed value.
Theano's documentation talks about the difficulties of seeding random variables and why they seed each graph instance with its own random number generator.
Sharing a random number generator between different {{{RandomOp}}}
instances makes it difficult to producing the same stream regardless
of other ops in graph, and to keep {{{RandomOps}}} isolated.
Therefore, each {{{RandomOp}}} instance in a graph will have its very
own random number generator. That random number generator is an input
to the function. In typical usage, we will use the new features of
function inputs ({{{value}}}, {{{update}}}) to pass and update the rng
for each {{{RandomOp}}}. By passing RNGs as inputs, it is possible to
use the normal methods of accessing function inputs to access each
{{{RandomOp}}}’s rng. In this approach it there is no pre-existing
mechanism to work with the combined random number state of an entire
graph. So the proposal is to provide the missing functionality (the
last three requirements) via auxiliary functions: {{{seed, getstate,
setstate}}}.
They also provide examples on how to seed all the random number generators.
You can also seed all of the random variables allocated by a
RandomStreams object by that object’s seed method. This seed will be
used to seed a temporary random number generator, that will in turn
generate seeds for each of the random variables.
>>> srng.seed(902340) # seeds rv_u and rv_n with different seeds each
I finally got reproducible results with my code. It's a combination of answers I saw around the web. The first thing is doing what #alex says:
Set numpy.random.seed;
Use PYTHONHASHSEED=0 for Python 3.
Then you have to solve the issue noted by #user2805751 regarding cuDNN by calling your Keras code with the following additional THEANO_FLAGS:
dnn.conv.algo_bwd_filter=deterministic,dnn.conv.algo_bwd_data=deterministic
And finally, you have to patch your Theano installation as per this comment, which basically consists in:
replacing all calls to *_dev20 operator by its regular version in theano/sandbox/cuda/opt.py.
This should get you the same results for the same seed.
Note that there might be a slowdown. I saw a running time increase of about 10%.
In Tensorflow 2.0 you can set random seed like this:
import tensorflow as tf
tf.random.set_seed(221)
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential( [
layers.Dense(2,name = 'one'),
layers.Dense(3,activation = 'sigmoid', name = 'two'),
layers.Dense(2,name = 'three')])
x = tf.random.uniform((12,12))
model(x)
The problem is now solved in Tensorflow 2.0 ! I had the same issue with TF 1.x (see If Keras results are not reproducible, what's the best practice for comparing models and choosing hyper parameters? ) but
import os
####*IMPORANT*: Have to do this line *before* importing tensorflow
os.environ['PYTHONHASHSEED']=str(1)
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers
import random
import pandas as pd
import numpy as np
def reset_random_seeds():
os.environ['PYTHONHASHSEED']=str(1)
tf.random.set_seed(1)
np.random.seed(1)
random.seed(1)
#make some random data
reset_random_seeds()
NUM_ROWS = 1000
NUM_FEATURES = 10
random_data = np.random.normal(size=(NUM_ROWS, NUM_FEATURES))
df = pd.DataFrame(data=random_data, columns=['x_' + str(ii) for ii in range(NUM_FEATURES)])
y = df.sum(axis=1) + np.random.normal(size=(NUM_ROWS))
def run(x, y):
reset_random_seeds()
model = keras.Sequential([
keras.layers.Dense(40, input_dim=df.shape[1], activation='relu'),
keras.layers.Dense(20, activation='relu'),
keras.layers.Dense(10, activation='relu'),
keras.layers.Dense(1, activation='linear')
])
NUM_EPOCHS = 500
model.compile(optimizer='adam', loss='mean_squared_error')
model.fit(x, y, epochs=NUM_EPOCHS, verbose=0)
predictions = model.predict(x).flatten()
loss = model.evaluate(x, y) #This prints out the loss by side-effect
#With Tensorflow 2.0 this is now reproducible!
run(df, y)
run(df, y)
run(df, y)
This works for me:
SEED = 123456
import os
import random as rn
import numpy as np
from tensorflow import set_random_seed
os.environ['PYTHONHASHSEED']=str(SEED)
np.random.seed(SEED)
set_random_seed(SEED)
rn.seed(SEED)
It is easier that it seems. Putting only this, it works:
import numpy as np
import tensorflow as tf
import random as python_random
def reset_seeds():
np.random.seed(123)
python_random.seed(123)
tf.random.set_seed(1234)
reset_seeds()
The KEY of the question, VERY IMPORTANT, is to call the function reset_seeds() every time before running the model. Doing that you will obtain reproducible results as I check in the Google Collab.
I would like to add something to the previous answers. If you use python 3 and you want to get reproducible results for every run, you have to
set numpy.random.seed in the beginning of your code
give PYTHONHASHSEED=0 as a parameter to the python interpreter
I have trained and tested Sequential() kind of neural networks using Keras. I performed non linear regression on noisy speech data. I used the following code to generate random seed :
import numpy as np
seed = 7
np.random.seed(seed)
I get the exact same results of val_loss each time I train and test on the same data.
I agree with the previous comment, but reproducible results sometimes needs the same environment(e.g. installed packages, machine characteristics and so on). So that, I recommend to copy your environment to other place in case to have reproducible results. Try to use one of the next technologies:
Docker. If you have a Linux this very easy to move your environment to other place. Also you can try to use DockerHub.
Binder. This is a cloud platform for reproducing scientific experiments.
Everware. This is yet another cloud platform for "reusable science". See the project repository on Github.
Unlike what has been said before, only Tensorflow seed has an effect on random generation of weights (latest version Tensorflow 2.6.0 and Keras 2.6.0)
Here is a small test you can run to check the influence of each seed (with np being numpy, tf being tensorflow and random the Python random library):
# Testing how seeds influence results
# -----------------------------------
print("Seed specification")
my_seed = 36
# To vary python hash, numpy random, python random and tensorflow random seeds
a, b, c, d = 0, 0, 0, 0
os.environ['PYTHONHASHSEED'] = str(my_seed+a) # Has no effect
np.random.seed(my_seed+b) # Has no effect
random.seed(my_seed+c) # Has no effect
tf.random.set_seed(my_seed+d) # Has an effect
print("Making ML model")
keras.mixed_precision.set_global_policy('float64')
model = keras.Sequential([
layers.Dense(2, input_shape=input_shape),#, activation='relu'),
layers.Dense(output_nb, activation=None),
])
#
weights_save = model.get_weights()
print("Some weights:", weights_save[0].flatten())
We notice that variables a, b, c have no effect on the results.
Only d has an effect on the results.
So, in the latest versions of Tensorflow, only tensorflow random seed has an influence on the random choice of weights.