Change values of a tensorflow tensor based on condition - python

I'm trying to recreate a numpy code snippet I wrote in tensorflow, but I'm struggling to find the correct/best tensorflow operations.
Consider the following numpy solution:
import numpy as np
# Initialize a random numpy array:
my_dummy = np.random.random((6, 2, 2, 10))
print(my_dummy)
> [[[[0.6715164 0.58915908 0.36607568 0.73404715 0.69455375 0.52177771
0.91810873 0.85010461 0.37485212 0.35634401]
[0.55885052 0.13041019 0.89774818 0.3363019 0.66634638 0.32054576
0.46174629 0.59975141 0.02283781 0.02997967]]
....
]]]]
# Create random floats, based on channel 0 of my dummy:
random_floats = np.random.random(my_dummy.shape[0])
print(random_floats)
> [0.89351759 0.76734892 0.36810602 0.08513434 0.65511941 0.61297472]
# Create a mask with ones and a shape based on my_dummy:
my_mask = np.ones((my_dummy.shape[0], 1, 1, my_dummy.shape[-1]))
print(my_mask)
> [[[[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]]]
[[[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]]]
[[[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]]]
[[[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]]]
[[[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]]]
[[[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]]]]
# Initialize a rate parameter:
my_rate = 0.5
# Based on my_rate, change the array accordingly:
my_mask[my_rate > random_floats] = [1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
print(my_mask)
[[[[1. 0. 1. 0. 1. 0. 1. 0. 1. 0.]]]
[[[1. 0. 1. 0. 1. 0. 1. 0. 1. 0.]]]
[[[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]]]
[[[1. 0. 1. 0. 1. 0. 1. 0. 1. 0.]]]
[[[1. 0. 1. 0. 1. 0. 1. 0. 1. 0.]]]
[[[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]]]]
# Multiply my_dummy with the new mask:
np.multiply(my_dummy, my_mask)
array([[[[0.6715164 , 0.58915908, 0.36607568, 0.73404715, 0.69455375,
0.52177771, 0.91810873, 0.85010461, 0.37485212, 0.35634401],
[0.55885052, 0.13041019, 0.89774818, 0.3363019 , 0.66634638,
0.32054576, 0.46174629, 0.59975141, 0.02283781, 0.02997967]],
[[0.22358676, 0.74959561, 0.11109368, 0.56021714, 0.2767754 ,
0.55156506, 0.15488703, 0.25738564, 0.18588607, 0.57593545],
[0.15804289, 0.87858207, 0.12890992, 0.78828551, 0.52467083,
0.45117698, 0.2605117 , 0.46659721, 0.855278 , 0.29630581]]],
[[[0.381445 , 0. , 0.48308211, 0. , 0.5136352 ,
0. , 0.84428703, 0. , 0.20532641, 0. ],
[0.696645 , 0. , 0.84184568, 0. , 0.01369105,
0. , 0.27683334, 0. , 0.59356542, 0. ]],
[[0.5281193 , 0. , 0.82336821, 0. , 0.63435181,
0. , 0.12824084, 0. , 0.35045286, 0. ],
[0.02205884, 0. , 0.22927706, 0. , 0.45538199,
0. , 0.81220918, 0. , 0.46427429, 0. ]]],
.....
]]]])
In tensorflow, I did this (warning, many imports, I tried a lot of things and no longer sure whether all of them are necessary, just want to ensure you can reproduce immediately):
from keras.engine.base_layer import InputSpec
from tensorflow.python.util import deprecation
from tensorflow.python.framework import ops
from tensorflow.python.eager import context
from tensorflow.python.framework import tensor_shape
from tensorflow.python.framework import tensor_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import random_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.platform import tf_logging as logging
import numbers
import numpy as np
import tensorflow as tf
from tensorflow.python.framework import ops
from tensorflow.python.ops import random_ops
from tensorflow.python.ops import math_ops
from keras import backend as K
# Create my_dummy and convert to tensor object:
my_dummy = np.random.random((6, 2, 2, 4))
my_dummy = ops.convert_to_tensor(my_dummy)
my_dummy.get_shape()
> TensorShape([Dimension(6), Dimension(2), Dimension(2), Dimension(4)])
# Create random floats, like before and inspect tensor with Keras (instead of running a tf session):
random_floats = random_ops.random_uniform([my_dummy.get_shape().as_list()[0]], dtype=my_dummy.dtype)
K.eval(random_floats)
> array([0.74018297, 0.76996447, 0.52047441, 0.28215968, 0.91457724,
0.64637448])
# Like before, create a mask with ones, like before shape (almost completely) based on my_dummy:
my_mask = tf.ones([my_dummy.get_shape()[0], 1, 1, my_dummy.get_shape()[-1]], dtype=x.dtype)
K.eval(my_mask)
> array([[[[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]]],
[[[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]]],
[[[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]]],
[[[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]]],
[[[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]]],
[[[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]]]])
Unfortunately, this where I'm stuck. I did not find a way to alter the entries in the my_mask Tensor object, based on a rate value. One thing I tried was tf.where:
tf.where(rate > random_floats, my_mask, tf.constant([1, 0, 1, 0, 1, 0, 1, 0, 1, 0], dtype = my_dummy.dtype))
but get the error:
ValueError: Shapes must be equal rank, but are 4 and 1 for 'Select_1' (op: 'Select') with input shapes: [6], [6,1,1,10], [10].
Thankful for any advice/help :)

It is basically more or less the same in tensorflow. Showing with smaller shaped data for convenience:
import tensorflow as tf
value_to_assign = tf.constant([[1., 0., 1., 0., 1.]])
rate = tf.constant(.5)
dummy = tf.random_normal(shape=(4, 1, 1, 5))
# random_floats = tf.random_normal(shape=(tf.shape(dummy)[0], ))
random_floats = tf.constant([0.4, 0.6, .7, .2]) # <--using const values to illustrate
init_val = tf.ones((tf.shape(dummy)[0], 1, 1, tf.shape(dummy)[-1]))
mask = tf.Variable(init_val,
trainable=False)
indices = tf.where(tf.equal(True, rate > random_floats))
tiled = tf.tile(value_to_assign,
multiples=[tf.shape(indices)[0], 1])[:, tf.newaxis, tf.newaxis, :]
mask = tf.scatter_nd_update(mask,
indices=indices,
updates=tiled)
res = mask * dummy
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print('MASK')
print(sess.run(mask))
print('DUMMY')
print(sess.run(dummy))
print('RESULT')
print(sess.run(res))
MASK
[[[[1. 0. 1. 0. 1.]]]
[[[1. 1. 1. 1. 1.]]]
[[[1. 1. 1. 1. 1.]]]
[[[1. 0. 1. 0. 1.]]]]
DUMMY
[[[[-1.2031308 -1.6657363 -1.5552464 0.8540495 0.37618718]]]
[[[-0.4468031 0.46417323 -0.3764856 1.1906835 -1.4670093 ]]]
[[[ 1.2066191 -1.4767337 -0.9487017 -0.49180242 -0.33098853]]]
[[[-0.1621628 0.61168176 0.10006899 0.7585997 -0.23903783]]]]
RESULT
[[[[ 1.7753109 0. -0.5451439 -0. -0.53782284]]]
[[[ 0.08024058 -1.8178499 1.183356 1.0895957 -0.9272436 ]]]
[[[-0.5266396 -2.0316153 -1.0043124 -1.1657876 0.6106227 ]]]
[[[-0.46503183 0. 0.01983969 -0. 0.58563703]]]]

Related

Inserting complex functions in a python code

I have been trying to insert $e^ix$ as matrix element.
The main aim is to find the eigenvalue of a matrix which has many complex functions as elements. Can anyone help me how to insert it? My failed attempt is below:
for i in range(0,size):
H[i,i]=-2*(cmath.exp((i+1)*aj))
H[i,i+1]=1.0
H[i,i-1]=1.0
'a' is defined earlier in the program. The error flagged shows that aj is not defined. Using cmath I thought a complex number can be expontiated as (x+yj). Unfortunately, I couldn't figure out the right way to use it. Any help would be appreciated
Define a small float array:
In [214]: H = np.eye(3)
In [215]: H
Out[215]:
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
Create a complex number:
In [216]: 1+3j
Out[216]: (1+3j)
In [217]: np.exp(1+3j)
Out[217]: (-2.6910786138197937+0.383603953541131j)
Trying to assign it to H:
In [218]: H[1,1]=np.exp(1+3j)
<ipython-input-218-6c0b228d2833>:1: ComplexWarning: Casting complex values to real discards the imaginary part
H[1,1]=np.exp(1+3j)
In [219]: H
Out[219]:
array([[ 1. , 0. , 0. ],
[ 0. , -2.69107861, 0. ],
[ 0. , 0. , 1. ]])
Now make an complex dtype array:
In [221]: H = np.eye(3).astype( complex)
In [222]: H[1,1]=np.exp(1+3j)
In [223]: H
Out[223]:
array([[ 1. +0.j , 0. +0.j ,
0. +0.j ],
[ 0. +0.j , -2.69107861+0.38360395j,
0. +0.j ],
[ 0. +0.j , 0. +0.j ,
1. +0.j ]])
edit
For an array of values:
In [225]: a = np.array([1,2,3])
In [226]: np.exp(a+1j*a)
Out[226]:
array([ 1.46869394+2.28735529j, -3.07493232+6.7188497j ,
-19.88453084+2.83447113j])
In [228]: H[:,0]=np.exp(a+1j*a)
In [229]: H
Out[229]:
array([[ 1.46869394+2.28735529j, 0. +0.j ,
0. +0.j ],
[ -3.07493232+6.7188497j , -2.69107861+0.38360395j,
0. +0.j ],
[-19.88453084+2.83447113j, 0. +0.j ,
1. +0.j ]])

how to put Multiple Matrices Together into a Single Matrix?

I need to put multiple matrices together into a single matrix, like so:
I have the values for the matrix, but I can't get it to appear like how it does in the image- instead, my values end up stacked on top of each other in an array. How can I go about getting my matrices to look like the image above?
My code:
import numpy as np
w_estimate = [0.656540, 7.192304, 2.749036]
F = [np.identity(3) * -w_estimate[1:4], -np.identity(3)], [np.identity(3)*0, np.identity(3)*0]
It's supposed to look like:
F = [[np.identity(3) * -w_estimate[1:4], -np.identity(3)]
[np.identity(3) * 0, np.identity(3) * 0]]
but instead it looks like:
[[np.identity(3) * -w_estimate[1:4]],
[-np.identity(3)],
[np.identity(3) * 0],
[np.identity(3) * 0]]
Help is very much appreciated.
The first correction to your code pertains to -w_estimate[1:4].
Since w_estimate is a plain pythonic list, you can not apply
minus operator to it.
You can however apply minus operator to a Numpy array.
Another correction is to avoid -0 in the result.
To get an array with diagonal elements filled from some other array,
and all other zeroes, you can use np.diagonal_fill, which fills
in-place diagonal elements of some (earlier) created array
(using np.zeros).
So to construct 2 "upper" blocks of your result, you can write:
a1 = np.zeros((3,3))
a2 = a1.copy()
np.fill_diagonal(a1, -np.array(w_estimate)[1:4])
np.fill_diagonal(a2, -1)
Note that -np.array(w_estimate)[1:4] returns last 2 elements of
w_estimate them, i.e. [7.192304, 2.749036]. Since the target array
is "3 by 3", the source sequence is repeated (in this case, for the
last diagonal element only).
If your intention is different, change -np.array(w_estimate)[1:4]
accordingly.
And to construct the whole intended array, run:
F = np.vstack((np.hstack((a1, a2)), np.zeros((3,6))))
The result is:
array([[-7.192304, 0. , 0. , -1. , 0. , 0. ],
[ 0. , -2.749036, 0. , 0. , -1. , 0. ],
[ 0. , 0. , -7.192304, 0. , 0. , -1. ],
[ 0. , 0. , 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0. , 0. ]])
You shoud definitely take a look at numpy.block method.
>>> A = np.eye(2) * 2
>>> B = np.eye(3) * 3
>>> np.block([
... [A, np.zeros((2, 3))],
... [np.ones((3, 2)), B ]
... ])
array([[2., 0., 0., 0., 0.],
[0., 2., 0., 0., 0.],
[1., 1., 3., 0., 0.],
[1., 1., 0., 3., 0.],
[1., 1., 0., 0., 3.]])

How do I compute one hot encoding using tf.one_hot?

I'm trying to build a one hot encoding of y_train of mnist data-set using tensorflow. I couldn't understand how to do it?
# unique values 0 - 9
y_train = array([5, 0, 4, ..., 5, 6, 8], dtype=uint8)
In keras we'll do something like
# this converts it into one hot encoding
one hot_encoding = tf.keras.utils.to_categorical(y_train)
Where as in tf.one_hot what should be my input to indices & depth parameters? After doing one hot encoding how can I convert it back to numpy array from 2d-tensor?
I'm not familiar with Tensorflow but after some tests, this is what I've found:
tf.one_hot() takes an indices and a depth. The indices are the values to actually convert to a one-hot encoding. depth refers to the maximum value to utilize.
For example, take the following code:
y = [1, 2, 3, 2, 1]
tf.keras.utils.to_categorical(y)
sess = tf.Session();
with sess.as_default():
print(tf.one_hot(y, 2).eval())
print(tf.one_hot(y, 4).eval())
print(tf.one_hot(y, 6).eval())
tf.keras.utils.to_categorical(y) Returns the following:
array([[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.],
[0., 0., 1., 0.],
[0., 1., 0., 0.]], dtype=float32)
In contrast, the tf.one_hot() options (2, 4, and 6) do the following:
[[0. 1.]
[0. 0.]
[0. 0.]
[0. 0.]
[0. 1.]]
[[0. 1. 0. 0.]
[0. 0. 1. 0.]
[0. 0. 0. 1.]
[0. 0. 1. 0.]
[0. 1. 0. 0.]]
[[0. 1. 0. 0. 0. 0.]
[0. 0. 1. 0. 0. 0.]
[0. 0. 0. 1. 0. 0.]
[0. 0. 1. 0. 0. 0.]
[0. 1. 0. 0. 0. 0.]]
As can be seen here, to mimic tf.keras.utils.to_categorical() using tf.one_hot(), the depth parameter should be equivalent to the maximum value present in the array, +1 for 0. In this case, the maximum value is 3, so there are four possible values in the encoding - 0, 1, 2, and 3. As such, a depth of 4 is required to represent all of these values in the one-hot encoding.
As for conversion to numpy, as shown above, using a Tensorflow session, running eval() on a tensor converts it to a numpy array. For methods on doing this, refer to How can I convert a tensor into a numpy array in TensorFlow?.
I'm not familiar with Tensorflow but I hope this helps.
Note: for the purposes of MNIST, a depth of 10 should be sufficient.
I'd like to counter what #Andrew Fan has said. First, the above y label list does not start at index 0, which is what is required. Just look at the first column (i.e. index 0) in all of those examples: they're all empty. This will create a redundant class in the learning and may cause problems. One hot creates a simple list with 1 for that index position and zeros elsewhere. Therefore, your depth has to be the same as the number of classes, but you also have to start at index 0.

specific kind of slicing over tensor object in tensorflow

Summary of the question, Is this kind of slicing and then assignment supported in tensorflow?
out[tf_a2[y],x[:,None]] = tf_a1[tf_a2[y],x[:,None]]
final = out[:-1]
Lets give the example, I have a tensor like this:
tf_a1 = tf.Variable([ [9.968594, 8.655439, 0., 0. ],
[0., 8.3356, 0., 8.8974 ],
[0., 0., 6.103182, 7.330564 ],
[6.609862, 0., 3.0614321, 0. ],
[9.497023, 0., 3.8914037, 0. ],
[0., 8.457685, 8.602337, 0. ],
[0., 0., 5.826657, 8.283971 ],
[0., 0., 0., 0. ]])
and I have this one:
tf_a2 = tf.constant([[1, 2, 5],
[1, 4, 6],
[0, 7, 7],
[2, 3, 6],
[2, 4, 7]])
Now I want to keep the elements in tf_a1 in which the combination of n (here n is 2) of them (index of them) is in the value of tf_a2. What does it mean?
For example, in tf_a1, in the first column, indexes which has value are: (0,3,4). Is there any row in tf_a2 which contains any combination of these two indexes: (0,3), (0,4) or (3,4). Actually, there is no such row. So all the elements in that column became zero.
Indexes for the second column in tf_a1 is (0,1) (0,5) (1,5). As you see the record (1,5) is available in the tf_a2 in the first row. That's why we keep those in the tf_a1.
This is the correct numpy code:
y,x = np.where(np.count_nonzero(a1p[a2], axis=1) >= n)
out = np.zeros_like(tf_a1)
out[tf_a2[y],x[:,None]] = tf_a1[tf_a2[y],x[:,None]]
final = out[:-1]
This is the expected output of this numpy code (but I need this in tensorflow):
[[0. 0. 0. 0. ]
[0. 8.3356 0. 8.8974 ]
[0. 0. 6.103182 7.330564 ]
[0. 0. 3.0614321 0. ]
[0. 0. 3.8914037 0. ]
[0. 8.457685 8.602337 0. ]
[0. 0. 5.826657 8.283971 ]]
The tensorflow code should be something like this:
y, x = tf.where(tf.count_nonzero(tf.gather(tf_a1, tf_a2, axis=0), axis=1) >= n)
out = tf.zeros_like(tf_a1)
out[tf_a2[y],x[:,None]] = tf_a1[tf_a2[y],x[:,None]]
final = out[:-1]
This part of the code tf.gather(tf_a1, tf_a2, axis=0), axis=1) is doing the numpy like slicing tf_a1[tf_a2]
Update 1
The only line which does not work its:
out[tf_a2[y],x[:,None]] = tf_a1[tf_a2[y],x[:,None]]
final = out[:-1]
Any idea how can I accomplish this in tensorflow, is this kind of slicing is supported in tensor object at all?
Any help is appreciated:)

Why can't I change numpy's array?

My array is from a image whick like below:
[[[ 66.17041352 32.64576397 20.96214396]
[ 66.17041352 32.64576397 20.96214396]
[ 65.96318838 32.36065031 16.13857633]
...,
[ 69.04849876 28.06324166 26.57747623]
[ 63.7269604 32.96378326 25.94336956]
[ 53.96807994 39.33219382 23.9025511 ]]
...,
[[ 18.55833403 34.4104455 -9.75497344]
[ 18.55833403 34.4104455 -9.75497344]
[ 21.45103128 32.77919479 -3.84284208]
...,
[ 44.64859327 41.89617915 14.25196745]
[ 43.40291913 43.25109885 17.43372679]
[ 43.30009306 47.94315449 15.59464532]]
[[ 18.64249436 31.63054472 -7.56023249]
[ 18.64249436 31.63054472 -7.56023249]
[ 23.23099091 32.284216 -3.86411699]
...,
[ 44.98536772 45.0246078 17.92556564]
[ 45.53417128 45.42120428 17.50264622]
[ 46.7226915 45.42428651 19.21054283]]]
I want to change the array to zero like this:
[[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]
...,
[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
...,
[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]
...,
[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]
...,
[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]]
I know how to make it happen, but I just wonder why my origin code doesn't work.The print shows that nothing changed.
for row in image_arr:
for col in row:
col = [0,0,0]
print image_arr
In your loop, you are just reassigning the name col to the list [0,0,0], over and over and over again. Not at all what you want! To change your 3d array to all zeros, you simply do this.:
arr[:, :, :,] = 0
Bing bang boom, you're done.
This is because col is a copy not a reference. This is true for all of python:
CODE Example:
simple = [1,2,3,4,5,6]
print simple
for elem in simple:
elem = 0
print simple
OUTPUT:
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6]
Try this instead:
rows,cols,lens = arr.shape
for r in range(rows):
for c in range(cols):
arr[r][c] = [0,0,0]
You change the value col in the loop but it's not related to the original variable image_arr.
You can use enumerate to access the index and modify image_arr variable directly. As in the following example:
import numpy as np
image_arr = np.arange(30).reshape(3, 5, 2)
print(image_arr)
for i,row in enumerate(image_arr):
for j,col in enumerate(row):
image_arr[i][j]=0
print(image_arr)
You are changing col to a new list, but col is not a reference to a sublist of row. Instead, if you change the elements of col, then you will get the result you want:
for row in image_arr:
for col in row:
for i in range(len(col))
col[i] = 0
Is because col is a value not a reference , see Python objects confusion: a=b, modify b and a changes!
try instead :
a=0
b=0
for row in image_arr:
for col in row:
image_arr[a][b] = [0,0,0]
a=a+1
b=b+1
print image_arr
col is a 1d array, a view of arr. To change its values you need to use slicing notation. col=[0,0,0] reassigns the variable without mutating the iteration variable. Mutability is a key concept here (and applicable to lists and dictionaries as well).
In [254]: arr = np.ones((2,3,4))
In [255]: for row in arr:
...: for col in row:
...: col[:] = 0 # or = [1,2,3,5]
...:
In [256]: arr
Out[256]:
array([[[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.]],
[[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.]]])
And since you want to change all the values, col[:]=0 works just as well as col[:]=[0,0,0,0] (in my shape).
But while we are at it, any of these also work
In [257]: for row in arr:
...: row[:,:] = 1
...:
In [258]: arr
Out[258]:
array([[[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.],
...]]])
In [259]: arr[:,:,:]=2 # one : per dimension
In [260]: arr[...] = 3 # ... shorthand for multiple :
But why reset arr? Why not make a new array with the same shape (and throw away the 'original')?
arr1 = np.zeros_like(arr)

Categories