Tensorflow: create vector based on input - python

I am not really experienced in Tensorflow and I am doing one of those things that would apparently be very easy, but getting stuck at it.
I need to create a matrix given an input using a tensorflow layer.
Here is what I've gotten:
def createTransformationMatrix(args):
scale = args[0]
M = tf.Variable([scale[0], 0, 0, 0, scale[1], 0, 0, 0], dtype=tf.float32)
return M
scaleValue = Input(shape=(2,));
createTransfMatrix = Lambda(createTransformationMatrix)(scaleValue)
transformImage = Model([scaleValue], createTransfMatrix, name='transformImage');
scaleValueInput = np.array([1.0,1.0])
output = transformImage.predict(scaleValueInput[None,:])
This gives the error:
InvalidArgumentError (see above for traceback): You must feed a value for placeholder tensor 'lambda_1/Placeholder' with dtype float and shape [?,2]
[[Node: lambda_1/Placeholder = Placeholder[dtype=DT_FLOAT, shape=[?,2], _device="/job:localhost/replica:0/task:0/device:CPU:0"]()]]

You can do it using tensorflow
scaleValue = tf.placeholder("float32", 2)
b = tf.expand_dims(scaleValue, axis=1)
c = tf.constant([[1,0,0,0]], 'float32')
d = tf.matmul(b,c)
res = tf.reshape(d, shape=[-1])
with tf.Session() as sess:
print (sess.run([res], feed_dict={scaleValue: np.array([1,3])}))
Output
[array([1., 0., 0., 0., 3., 0., 0., 0.], dtype=float32)]
Solution using padding
scaleValue = tf.placeholder("float32", 2)
a = tf.expand_dims(scaleValue, axis=1)
paddings = tf.constant([[0, 0,], [0, 3]])
b = tf.pad(a, paddings, "CONSTANT")
res = tf.reshape(b, shape=[-1])
with tf.Session() as sess:
print (sess.run([res], feed_dict={scaleValue: np.array([1,3])}))
Set the padding to constant to the shape you want
Where in paddings = tf.constant([[top, bottom,], [left, right]]), top, bottom, left, right represents No:of zeros in the corresponding position.

Related

Tensorflow & keras: how to use constant, cond and switch_case to conditionally select the output of a layer?

I need to create a network using the keras API where the output of some layers conditionally depend on the output of some other layers. In the minimal example below, I want to do the following:
if a is equal to 0, then the output must be 0.0;
if a is equal to 1, then the output must be 1.0;
if a is equal to 2, then the output must be equal to b;
I don't know how to implement such a logic using tf.constant, tf.cond or even better tf.switch_case.
Whatever I try, I face the same problem: I can't manage to have the shape of the returned tensor as (None, b_size). The code below works, but it is not ideal.
How can I use the elegant tf.switch_case?
In my network I can assume a is already of type int32, so the cast is here for illustration purposes only.
I added a dummy layer at the end just to show I can continue adding more layers afterwards.
import tensorflow as tf
from keras import layers, models, Input, backend, initializers
b_size = 3
input_tensor = Input(shape=(1 + b_size,))
# split input into a and b (a scalar, b vectorial)
a, b = tf.split(input_tensor, [1, b_size], 1)
def get_0():
return tf.multiply(0.0, b) # How can I get a tensor of zeros with the right shape?
def get_1():
return tf.add(1.0, tf.multiply(0.0, b)) # How can I get a tensor of ones with the right shape?
def get_b():
return b
a_equal_0 = tf.equal(tf.cast(a, dtype='int32'), 0)
a_equal_1 = tf.equal(tf.cast(a, dtype='int32'), 1)
# How can I use tf.switch_case instead of backend.switch?
select_output = backend.switch(a_equal_0, get_0, backend.switch(a_equal_1, get_1, get_b))
# This final layer is used to test if a layer can correctly take select_output as its input
do_nothing_layer = layers.Dense(
units=b_size,
kernel_initializer=initializers.Identity(1),
use_bias=False)
output_tensor = do_nothing_layer(select_output)
m = models.Model(inputs=[input_tensor], outputs=[output_tensor])
m.predict([[0, 3, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]])
Output is correctly
array([[0., 0., 0.],
[1., 1., 1.],
[3., 4., 5.]], dtype=float32)

How to use 'Keras symbolic inputs' with 'tf.while_loop'?

I'm trying to create N x N tensor using tf.while_loop in my custom Keras layer. Here, N (timesteps in code) is a Keras symbolic tensor (integer scalar). The below code is __call__ method of my custom Keras layer in Functional Model.
import tensorflow as tf
from keras import backend as K
# timesteps = tf.constant(7) ## This makes this code work!!
timesteps = K.shape(inputs)[1] ## Or equivalently provided by timesteps = keras.layers.Input(shape= (), batch_size= 1, name= "timesteps")
# timesteps = tf.convert_to_tensor(timesteps) ## Does not work.
idx_outer = tf.constant(0)
timesteps_mixed_outer = tf.reshape(tf.Variable([]), (0, timesteps))
# timesteps_mixed_outer = Lambda(lambda timesteps : tf.reshape(tf.Variable([]), (0, timesteps)))(timesteps) ## Does not work
def body_inner(idx_inner, idx_outer, timesteps_mixed_inner):
timesteps_mixed_inner = tf.concat([timesteps_mixed_inner, [tf.cond(idx_inner == idx_outer, lambda : True, lambda : False)]], axis = 0)
return idx_inner + 1, idx_outer, timesteps_mixed_inner
def body_outer(idx_outer, timesteps_mixed_outer):
timesteps_mixed_inner = tf.Variable([])
idx_inner = tf.constant(0)
idx_inner, idx_outer, timesteps_mixed_inner = tf.while_loop(lambda idx_inner, idx_outer, timesteps_mixed_inner: K.less(idx_inner, timesteps), body_inner, [idx_inner, idx_outer, timesteps_mixed_inner], shape_invariants= [idx_inner.get_shape(), idx_outer.get_shape(), tf.TensorShape([None])])
timesteps_mixed_outer = tf.concat([timesteps_mixed_outer, [timesteps_mixed_inner]], axis = 0)
return idx_outer + 1, timesteps_mixed_outer
idx_outer, timesteps_mixed_outer = tf.while_loop(lambda idx_outer, timesteps_mixed_outer: K.less(idx_outer, timesteps), body_outer, [idx_outer, timesteps_mixed_outer], shape_invariants= [idx_outer.get_shape(), tf.TensorShape([None, None])]) ## Here raises error
The last line of above code raises the following error:
Exception has occurred: TypeError
Could not build a TypeSpec for <KerasTensor: shape=(0, None) dtype=float32 (created by layer 'tf.reshape')> with type KerasTensor
What I have tried:
I suspected the problem is came from Keras symbolic tensor input 'timesteps', so I have changed to timesteps = tf.constant(7) for experimental purpose. Then the code works and 'timesteps_mixed_outer' has the desired values:
<tf.Tensor: shape=(7, 7), dtype=float32, numpy=
array([[1., 0., 0., 0., 0., 0., 0.],
[0., 1., 0., 0., 0., 0., 0.],
[0., 0., 1., 0., 0., 0., 0.],
[0., 0., 0., 1., 0., 0., 0.],
[0., 0., 0., 0., 1., 0., 0.],
[0., 0., 0., 0., 0., 1., 0.],
[0., 0., 0., 0., 0., 0., 1.]], dtype=float32)>
I suspected the problem comes the use of from Keras symbolic tensor timesteps in tf.reshape function, so I have initialized timesteps_mixed_outer = tf.reshape(tf.Variable([]), (0, 7)) and leave timesteps = K.shape(inputs)[1]. Then new error occurs:
Exception has occurred: TypeError
Keras symbolic inputs/outputs do not implement `__len__`. You may be trying to pass Keras symbolic inputs/outputs to a TF API that does not register dispatching, preventing Keras from automatically converting the API call to a lambda layer in the Functional Model. This error will also get raised if you try asserting a symbolic input/output directly.
I have also tried to wrap tf.reshape following two solutions suggested in TypeError: Could not build a TypeSpec for <KerasTensor when using tf.map_fn and keras functional model, but both raise the same error.
My environments is as follows:
MacOS 12.0.1
Python 3.7.3
keras-preprocessing [installed: 1.1.2]
keras.__version__ == 2.4.3
tensorflow [installed: 2.4.1]
tensorflow-estimator [installed: 2.4.0]
EDIT
This error is raised when I build Keras model, before feeding actual Numpy values. timesteps = K.shape(inputs)[1] is varying across inputs, so it is set to None as like a batch dimension.
timesteps = K.shape(inputs)[1]
==
<KerasTensor: shape=() dtype=int32 inferred_value=[None] (created by layer 'tf.__operators__.getitem_6')>
==
dtype:tf.int32
is_tensor_like:True
name:'tf.__operators__.getitem_6/strided_slice:0'
op:'Traceback (most recent call last):\n File "/Users/imgspoints/.vscode/extensions/ms-python.python-2022.2.1924087327/pythonFiles/lib/python/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_resolver.py", line 193, in _get_py_dictionary\n attr = getattr(var, name)\n File "/Users/imgspoints/.local/share/virtualenvs/experiments-m6CLaaa4/lib/python3.7/site-packages/tensorflow/python/keras/engine/keras_tensor.py", line 251, in op\n raise TypeError(\'Keras symbolic inputs/outputs do not \'\nTypeError: Keras symbolic inputs/outputs do not implement `op`. You may be trying to pass Keras symbolic inputs/outputs to a TF API that does not register dispatching, preventing Keras from automatically converting the API call to a lambda layer in the Functional Model.\n'
shape:TensorShape([])
type_spec:TensorSpec(shape=(), dtype=tf.int32, name=None)
_inferred_value:[None]
_keras_history:KerasHistory(layer=<tensorflow.python.keras.layers.core.SlicingOpLambda object at 0x1774fac88>, node_index=0, tensor_index=0)
_name:'tf.__operators__.getitem_6/strided_slice:0'
_overload_all_operators:<bound method KerasTensor._overload_all_operators of <class 'tensorflow.python.keras.engine.keras_tensor.KerasTensor'>>
_overload_operator:<bound method KerasTensor._overload_operator of <class 'tensorflow.python.keras.engine.keras_tensor.KerasTensor'>>
_to_placeholder:<bound method KerasTensor._to_placeholder of <KerasTensor: shape=() dtype=int32 inferred_value=[None] (created by layer 'tf.__operators__.getitem_6')>>
_type_spec:TensorSpec(shape=(), dtype=tf.int32, name=None)
When the error is raised, K.less(idx_outer, timesteps) can be evaluated succesfully:
timesteps == <KerasTensor: shape=() dtype=bool (created by layer 'tf.math.less')>
So I believe the error comes from tf.concat and I'm now trying to replace tf.concat to another operation (e.g. Keras Concatenate layer).
Simpler Example
The following codes work when end = tf.constant(7) but raises
Keras symbolic inputs/outputs do not implement `__len__`. You may be trying to pass Keras symbolic inputs/outputs to a TF API that does not register dispatching, preventing Keras from automatically converting the API call to a lambda layer in the Functional Model. This error will also get raised if you try asserting a symbolic input/output directly.
error at _, final_output = tf.while_loop(cond, body, loop_vars=[step, output]) when end = Input(shape= (), batch_size= 1, name= "timesteps", dtype= tf.int32).
mport tensorflow as tf
from keras.layers import Input
# end = Input(shape= (), batch_size= 1, name= "timesteps", dtype= tf.int32) ## not works :(
end = tf.constant(7) ## works :)
array = tf.Variable([1., 1., 1., 1., 1., 1., 1.])
step = tf.constant(0)
output = tf.TensorArray(dtype=tf.float32, size=0, dynamic_size=True)
def cond(step, output):
return step < end
def body(step, output):
output = output.write(step, tf.gather(array, step))
return step + 1, output
_, final_output = tf.while_loop(cond, body, loop_vars=[step, output])
Try wrapping your logic in a custom layer and using tf operations:
import tensorflow as tf
class CustomLayer(tf.keras.layers.Layer):
def __init__(self):
super(CustomLayer, self).__init__()
def call(self, inputs):
input_shape = tf.shape(inputs)
end = input_shape[-1]
array = tf.ones((input_shape[-1],))
step = tf.constant(0)
output = tf.TensorArray(dtype=tf.float32, size=0, dynamic_size=True)
def cond(step, output):
return step < end
def body(step, output):
output = output.write(step, tf.gather(array, step))
return step + 1, output
_, final_output = tf.while_loop(cond, body, loop_vars=[step, output])
return tf.reshape(final_output.stack(), (input_shape))
inputs = tf.keras.layers.Input(shape= (None, ), batch_size= 1, name= "timesteps", dtype= tf.int32)
cl = CustomLayer()
outputs = cl(inputs)
model = tf.keras.Model(inputs, outputs)
random_data = tf.random.uniform((1, 7), dtype=tf.int32, maxval=50)
print(model(random_data))
tf.Tensor([1. 1. 1. 1. 1. 1. 1.], shape=(7,), dtype=float32)
timesteps_mixed_outer = tf.concat([timesteps_mixed_outer, [timesteps_mixed_inner]], axis = 0)
You have to check the shape of timesteps_mixed_outer and timesteps_mixed_inner. try to change the axis value.
or try this.
timesteps_mixed_outer = tf.concat([timesteps_mixed_outer.numpy(), timesteps_mixed_inner.numpy()], axis = 0)

Pytorch Autograd gives different gradients when using .clamp instead of torch.relu

I'm still working on my understanding of the PyTorch autograd system. One thing I'm struggling at is to understand why .clamp(min=0) and nn.functional.relu() seem to have different backward passes.
It's especially confusing as .clamp is used equivalently to relu in PyTorch tutorials, such as https://pytorch.org/tutorials/beginner/pytorch_with_examples.html#pytorch-nn.
I found this when analysing the gradients of a simple fully connected net with one hidden layer and a relu activation (linear in the outputlayer).
to my understanding the output of the following code should be just zeros. I hope someone can show me what I am missing.
import torch
dtype = torch.float
x = torch.tensor([[3,2,1],
[1,0,2],
[4,1,2],
[0,0,1]], dtype=dtype)
y = torch.ones(4,4)
w1_a = torch.tensor([[1,2],
[0,1],
[4,0]], dtype=dtype, requires_grad=True)
w1_b = w1_a.clone().detach()
w1_b.requires_grad = True
w2_a = torch.tensor([[-1, 1],
[-2, 3]], dtype=dtype, requires_grad=True)
w2_b = w2_a.clone().detach()
w2_b.requires_grad = True
y_hat_a = torch.nn.functional.relu(x.mm(w1_a)).mm(w2_a)
y_a = torch.ones_like(y_hat_a)
y_hat_b = x.mm(w1_b).clamp(min=0).mm(w2_b)
y_b = torch.ones_like(y_hat_b)
loss_a = (y_hat_a - y_a).pow(2).sum()
loss_b = (y_hat_b - y_b).pow(2).sum()
loss_a.backward()
loss_b.backward()
print(w1_a.grad - w1_b.grad)
print(w2_a.grad - w2_b.grad)
# OUT:
# tensor([[ 0., 0.],
# [ 0., 0.],
# [ 0., -38.]])
# tensor([[0., 0.],
# [0., 0.]])
#
The reason is that clamp and relu produce different gradients at 0. Checking with a scalar tensor x = 0 the two versions: (x.clamp(min=0) - 1.0).pow(2).backward() versus (relu(x) - 1.0).pow(2).backward(). The resulting x.grad is 0 for the relu version but it is -2 for the clamp version. That means relu chooses x == 0 --> grad = 0 while clamp chooses x == 0 --> grad = 1.

Input an integer with placeholder in tensorflow?

I want to feed a batch_size integer as a placeholder in Tensorflow. But it does not act as an integer. Consider the following example:
import tensorflow as tf
max_length = 5
batch_size = 3
batch_size_placeholder = tf.placeholder(dtype=tf.int32)
mask_0 = tf.one_hot(indices=[0]*batch_size_placeholder, depth=max_length, on_value=0., off_value=1.)
mask_1 = tf.one_hot(indices=[0]*batch_size, depth=max_length, on_value=0., off_value=1.)
# new session
with tf.Session() as sess:
feed = {batch_size_placeholder : 3}
batch, mask0, mask1 = sess.run([
batch_size_placeholder, mask_0, mask_1
], feed_dict=feed)
When I print the values of batch, mask0 and mask1 I have the following:
print(batch)
>>> array(3, dtype=int32)
print(mask0)
>>> array([[0., 1., 1., 1., 1.]], dtype=float32)
print(mask1)
>>> array([[0., 1., 1., 1., 1.],
[0., 1., 1., 1., 1.],
[0., 1., 1., 1., 1.]], dtype=float32)
Indeed I thought mask0 and mask1 must be the same, but it seems that Tensorflow does not treat batch_size_placeholder as an integer. I believe it would be a tensor, but is there anyway that I can use it as an integer in my computations?
Is there anyway I can fix this problem? Just FYI, I used tf.one_hot as just an example, I want to run train/validation during training in my code where I will need a lot of other computations with different values for batch_size in training and in validation steps.
Any help would be appreciated.
In pure python usage, [0]*3 will be [0,0,0]. However, batch_size_placeholder is a placeholder, during the graph execution, it will be a tensor. [0]*tensor will be regarded as tensor multiplication. In your case, it will be a 1-d tensor which has 0 value. To correctly use batch_size_placeholder, you should create a tensor which has the same length as batch_size_placeholder.
mask_0 = tf.one_hot(tf.zeros(batch_size_placeholder, dtype=tf.int32), depth=max_length, on_value=0., off_value=1.)
It will have the same result as mask_1.
A simple example to show the difference.
batch_size_placeholder = tf.placeholder(dtype=tf.int32)
a = [0]*batch_size_placeholder
b = tf.zeros(batch_size_placeholder, dtype=tf.int32)
with tf.Session() as sess:
print(sess.run([a, b], feed_dict={batch_size_placeholder : 3}))
# [array([0], dtype=int32), array([0, 0, 0], dtype=int32)]

How to get the value from a tensor

Here's my setup:
indices = tf.placeholder(tf.int32, shape=[2])
weights = tf.Variable(tf.random_normal([100000, 3], stddev=0.35))
def objective(indices, weights):
idx1 = indices[0]; idx2 = indices[1] #extract two indices
mask = np.zeros(weights.shape.as_list()[0]) #builds a mask for some tensor "weights"
mask[idx1] = 1 # don't ask why I want to do this. I just do.
mask[idx2] = 1
obj = tf.reduce_sum(tf.multiply(weights[idx1], weights[idx2]))
return obj
optimizer = tf.train.GradientDescentOptimizer(0.01)
obj = objective(indices, weights)
trainer = optimizer.minimize(obj)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
sess.run([trainer, obj], feed_dict={indices=[100, 1000]})
So the point is that I have some tensor, and I take a slice of it which corresponds to an index in my mask. This index is a tf.strided_slice. I want to index my mask with idx1 and idx2, as both evaluate to be ints.
But idx1 and idx2 are not ints but tensors, so the obj = objective(indices, weights) call leads to an error.
How can I get the code to work?
You can make use of a combination of tf.SparseTensor and tf.sparse_tensor_to_dense to achieve what you want:
import numpy as np
import tensorflow as tf
indices = tf.placeholder(tf.int64, shape=[2])
weights = tf.Variable(tf.random_normal([5, 3], stddev=0.35))
def objective(indices, weights):
idx1 = indices[0]; idx2 = indices[1] #extract two indices
mask = np.zeros(weights.shape.as_list()[0]) #builds a mask for some tensor "weights"
mask_ones = tf.SparseTensor(tf.reshape(indices, [-1,1]), [1, 1], mask.shape) # Stores the 1s used in the mask
mask = mask + tf.sparse_tensor_to_dense(mask_ones) # Set the mask
obj = tf.reduce_sum(tf.multiply(weights[idx1], weights[idx2]))
return obj, mask
obj, mask = objective(indices, weights)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run([weights, obj, mask], feed_dict={indices:[0, 4]}))
[array([[...]], dtype=float32), 0.0068909675, array([1., 0., 0., 0., 1.], dtype=int32)]

Categories

Resources