How to get log probabilities in TensorFlow? - python

I am trying to convert a pytorch script to tensorflow and I need to get log probabilities from a categorical distribution. But the tensorflow calculated log probabilities is different from pytorch's log prob even after using same seed. This is what I have done so far
import torch
from torch.distributions import Categorical
import tensorflow as tf
import tensorflow_probability as tfp
torch.manual_seed(1)
tf.random.set_seed(1)
probs =[0.4,0.6]
m = Categorical(torch.tensor(probs))
action = m.sample()
n = tfp.distributions.Categorical(probs)
print("pytorch",m.log_prob(action))
print("Tensorflow", tf.math.log(n.prob(action.item())))

tfp.distributions.Categorical(probs)
takes logs as the default argument. They are being normalized and resulting probabilities of built distribution are [.45, .55].
You need to build tfp distribution as:
tfp.distributions.Categorical(probs=probs)

Related

Understanding what fc1000_softmax output from tensorflow CNN classification means

I am using python 3.6.10 and tensorflow 1.5 on a cpu. I have trained a cnn and saved it as a .onnx file. I am now trying to make a binary classification of my images using the code below:
import onnx
import warnings
from onnx_tf.backend import prepare
import numpy as np
from numpy import array
from IPython.display import display
from PIL import Image
warnings.filterwarnings('ignore')
onnx_model = onnx.load("trainednet.onnx") # load onnx model
tf_rep = prepare(onnx_model) # Import the ONNX model to Tensorflow
img = Image.open('Im025.jpg').resize((224, 224))
img = array(img).reshape(1,3, 224,224)
classification = tf_rep.run(img)
print(classification)
The print(classification) gives me an output like this:
Outputs(fc1000_softmax=array([[9.9967182e-01, 3.2823894e-04]], dtype=float32))
What does this output mean and how can I use it to understand what tensorflow classified my image as?
Well, what you have is the array of the output of the softmax layer of your model. This output can be interpreted as a probability assigned to each class ( in your case 2). You can also see it as "how confident the model is for each class".
So to have the final classification you need to take the max value of this array and map it to your label map { 0 -> class_one, 1-> class_two}.
Yes exactly, so after you model is not perfect (ie the model doesn't have 100% of accuracy). You should test on more images of class two and you will see the second number will be higher .
You should run it on a test set or refer to the metrics of the trained model.

How do I get reproducible results with Keras?

I'm trying to get reproducible results with Keras, however every time I run the program I get different results.
I've set the python hash seed, the Numpy random seed, the random seed, the TensorFlow seed, and the kernel_initializer glorot_uniform seed, but I still don't get reproducible results. Are there any other things I can do to get reproducible results?
I expect the predictions to be the same, however they are not. I get different results every single time.
with TENSORFLOW 2
import tensorflow as tf
tf.random.set_seed(33)
os.environ['PYTHONHASHSEED'] = str(33)
np.random.seed(33)
random.seed(33)
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)
Because you're using Keras with Tensorflow as backend, you will find it is pretty hard to get reproducible result especially when GPU is enable. However, there is still a method to achieve this.
First, do not use GPU.
import os
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"] = ""
Second, as you've did in code, set seed for Numpy, Random, TensorFlow and so on.
import tensorflow as tf
import numpy as np
import random as rn
sd = 1 # Here sd means seed.
np.random.seed(sd)
rn.seed(sd)
os.environ['PYTHONHASHSEED']=str(sd)
from keras import backend as K
config = tf.ConfigProto(intra_op_parallelism_threads=1,inter_op_parallelism_threads=1)
tf.set_random_seed(sd)
sess = tf.Session(graph=tf.get_default_graph(), config=config)
K.set_session(sess)
One final word, both two pieces of code should be placed at the begining of your code.
I created a rule to achieve reproducibility:
Works for python 3.6, not 3.7
First install Keras 2.2.4
After install tensorflow 1.9
And finally in the code:
import numpy as np
import random as rn
import tensorflow as tf
import keras
from keras import backend as K
#-----------------------------Keras reproducible------------------#
SEED = 1234
tf.set_random_seed(SEED)
os.environ['PYTHONHASHSEED'] = str(SEED)
np.random.seed(SEED)
rn.seed(SEED)
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)
#-----------------------------------------------------------------#
(Only tested for Tensorflow 2)
Besides setting the random seeds, I found that my RTX 3080 GPU would only give deterministic results if I used tf.float64 instead of the default of tf.float32. This appears to be due to rounding errors on the GPU, which leads to differences in the path taken during gradient descent. Note that this does not guarantee reproducibility across different GPUs. Different GPU architectures are not guaranteed to perform operations in exactly the same way. Such differences in implementation may cause differences in rounding, which can in turn affect the convergence of your model.

Logging long tensor values in tensorflow estimator

I have built a classification model using tensorflow estimator API. I am trying to get tensor outputs from hidden layes printed in logs while prediction using below code.
model = tf.estimator.DNNLinearCombinedClassifier(
model_dir=model_dir,
linear_feature_columns=wide_columns,
dnn_feature_columns=deep_columns,
dnn_hidden_units=hidden_units,
config=run_config)
tensors_to_log = {"DenseOut": "dnn/logits/BiasAdd"}
logging_hook = tf.train.LoggingTensorHook(tensors=tensors_to_log, every_n_iter=1)
predictions = model.predict(train_input_fn, hooks=[logging_hook])
When i run the code I am able to get the tensors logged in output but since the value is very long it is truncated and i can only see few numbers in begining and end.
INFO:tensorflow:DenseOut = [[ 0.61572325 -0.44044942 -0.19232166 ... 0.04 0.605 0.15]]
How can I specify tensorflow to log the complete output?
So interesting, I found that the solution was to set np.set_printoptions.
import numpy as np
np.set_printoptions(threshold=np.nan)
It seems that tensorflow and numpy are closely integrated.
Try this:
import sys
import numpy as np
np.set_printoptions(threshold= sys.maxsize)

Sampling from a truncated normal distribution in TensorFlow

I'm porting a bunch of calculations from Numpy/Scipy to TensorFlow and I need to generate samples from a truncated normal distribution, the equivalent of scipy.stats.truncnorm.rvs().
I think that the two standard ways to generate these samples are by rejection sampling or by feeding truncated uniform distribution samples to the inverse normal cumulative distribution function, but the former seems difficult to implement within a static computation graph (we can't know how many rejection loops to run until we generate the samples) and I don't think there is an inverse normal cumulative distribution function in the standard TensorFlow libraries.
I realize that there is a function in TensorFlow called truncated_normal(), but that simply clips at two standard deviations; you can't specify the lower and upper limits.
Any suggestions?
The simpler might be to embed the functions you're used to in the TensorFlow graph using tf.py_func. And in case you need it, you can just set the seed as usual using the numpy.random module:
import numpy as np
import tensorflow as tf
from scipy.stats import truncnorm
np.random.seed(seed=123)
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
size = tf.placeholder(tf.int32)
f = tf.py_func(lambda x, y, s: truncnorm.rvs(x, y, size=s),
inp=[a, b, size],
Tout=tf.float64)
with tf.Session() as sess:
print(sess.run(f, {a:0, b:1, size:10}))
will print:
[0.63638154 0.24732635 0.19533476 0.49072188 0.66066675 0.37031253
0.9732229 0.62423404 0.42385328 0.34206036]

How to get reproducible results in keras

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.

Categories

Resources