TensorFlow, batchwise indexing (first dimension) and sorting - python

I've got a params tensor with shape (?,368,5), as well as a query tensor with shape (?,368). The query tensor stores indices for sorting the first tensor.
The required output has shape: (?,368,5). Since I need it for a loss function in a neural network, the used operations should stay differentiable. Also, at runtime the size of the first axis ? corresponds to the batchsize.
So far I experimented with tf.gather and tf.gather_nd, however
tf.gather(params,query) results in a tensor with shape (?,368,368,5).
The query tensor is achieved by performing:
query = tf.nn.top_k(params[:, :, 0], k=params.shape[1], sorted=True).indices
Overall, I try to sort the params tensor by the first element on the third axis (for kind of a chamfer distance). At last to mention is, that I work with the Keras framework.

You need to add the indices of the first dimension to query in order to use it with tf.gather_nd. Here is a way to do it:
import tensorflow as tf
import numpy as np
np.random.seed(100)
with tf.Graph().as_default(), tf.Session() as sess:
params = tf.placeholder(tf.float32, [None, 368, 5])
query = tf.nn.top_k(params[:, :, 0], k=params.shape[1], sorted=True).indices
n = tf.shape(params)[0]
# Make tensor of indices for the first dimension
ii = tf.tile(tf.range(n)[:, tf.newaxis], (1, params.shape[1]))
# Stack indices
idx = tf.stack([ii, query], axis=-1)
# Gather reordered tensor
result = tf.gather_nd(params, idx)
# Test
out = sess.run(result, feed_dict={params: np.random.rand(10, 368, 5)})
# Check the order is correct
print(np.all(np.diff(out[:, :, 0], axis=1) <= 0))
# True

Related

One Hot Encoding in Tensorflow

I've been following the tensorflow walkthrough here to create my own categorical OHE layer. The layer suggested is below and I've followed the preceding steps to the guide very closely:
def get_category_encoding_layer(name, dataset, dtype, max_tokens=None):
# Create a StringLookup layer which will turn strings into integer indices
if dtype == 'string':
index = preprocessing.StringLookup(max_tokens=max_tokens)
else:
index = preprocessing.IntegerLookup(max_tokens=max_tokens)
# Prepare a Dataset that only yields our feature
feature_ds = dataset.map(lambda x, y: x[name])
# Learn the set of possible values and assign them a fixed integer index.
index.adapt(feature_ds)
# Create a Discretization for our integer indices.
encoder = preprocessing.CategoryEncoding(num_tokens=index.vocabulary_size())
# Apply one-hot encoding to our indices. The lambda function captures the
# layer so we can use them, or include them in the functional model later.
return lambda feature: encoder(index(feature))
However the output isn't aligned with the guide. When my input to the layer is a list of n strings, instead of the output being shape (n, vocabulary size), I am receiving an output of shape (1, vocabulary size), with multiple categories incorrectly marked '1'.
e.g. using n=2 and vocabulary size=3
Instead of getting an OHE of [[1, 0, 0], [0, 1, 0]], I am getting [1, 1, 0].
My code is exactly the same as the guide, but it looks like the layer is "merging" the encoding of each element of my input. Is there something wrong with the layer they provided or could someone give pointer on what I could test?
By default, CategoryEncoding uses output_mode="multi_hot". That's why you're getting output of size (1, vocab_size). To get OHE of size (n, vocab_size), make this change in your code
encoder = preprocessing.CategoryEncoding(num_tokens=index.vocabulary_size(), output_mode='one_hot')

How to loop through an unknown sized tensor and do tensor operations on its elements?

I am currently working on a neural network that takes some inputs and returns 2 outputs. I used 2 outputs in a regression problem where they both are 2 coordinates, X and Y.
My problem doesn't need X and Y values but angle it is facing which is atan2(y,x).
I am trying to to create a custom keras metric and a loss function that does a atan2 operation between the elements of the predicted tensor and true tensor so as to better train the network on my task.
The shape of the output tensor in metric is [?, 2] and I want to do a function where I can loop through the tensor and apply atan2(tensor[itr, 1], tensor[itr, 0]) on it to get an array of another tensors.
I have tried using tf.slit and tf.slice
I don't want to convert it into a numpy array and back to tensorflow due to performance reasons.
I have tried to get the shape of tensors using tensor.get_shape().as_list() and iterate through it.
self.model.compile(loss="mean_absolute_error",
optimizer=tf.keras.optimizers.Adam(lr=0.01),
metrics=[vect2d_to_angle_metric])
# This is the function i want to work on
def vect2d_to_angle_metric(y_true, y_predicted):
print("y_true = ", y_true)
print("y_predicted = ", y_predicted)
print("y_true shape = ", y_true.shape())
print("y_predicted shape = ", y_predicted.shape())
The print out of the above function being
y_true = Tensor("dense_2_target:0", shape=(?, ?), dtype=float32)
y_predicted = Tensor("dense_2/BiasAdd:0", shape=(?, 2), dtype=float32)
y_true shape = Tensor("metrics/vect2d_to_angle_metric/Shape:0", shape=(2,), dtype=int32)
y_predicted shape = Tensor("metrics/vect2d_to_angle_metric/Shape_1:0", shape=(2,), dtype=int32)
Python pseudo-code of the functionality I want to apply to the tensorflow function
def evaluate(self):
mean_array = []
for i in range(len(x_test)):
inputs = x_test[i]
prediction = self.model.getprediction(i)
predicted_angle = np.arctan2(result[i][1], result[i][0])
real_angle = np.arctan2(float(self.y_test[i][1]), float(self.y_test[i][0]))
mean_array.append(([abs(predicted_angle - real_angle)]/real_angle) * 100)
i += 1
I expect to slide the 2 sides of the tensor [i][0] and [i][1] and to a tf.atan2() function on both of them and finally make another tensor out of them so as to follow with other calculations and pass the custom loss.

Using an array for indexing for training network (tensorflow)

I am relatively new to tensorflow and am running into problems trying to index tensors properly. Towards the bottom of the shown, I am trying to use x (which itself is a tensor containing an array form such as [[0,1], [2,3]]) in order to index the y_rt tensor (one can think it as slicing the y_rt tensor). However, I am having troubles converting the tensor into an array or list. I am aware that there is the .eval() function, however I cannot use it here since the shown code happens before the .run() call. Any help would be much appreciated.
with tf.name_scope('placeholders'):
x_true = tf.placeholder(tf.float32, shape=[None, size, size, 1], name="x_true")
y_rt = tf.placeholder(tf.float32, shape=[None, operator.range.shape[0], operator.range.shape[1], 1], name="y_rt")
is_training = tf.placeholder(tf.bool, shape=(), name='is_training')
angle = tf.placeholder(tf.float32, shape=[n_batches, number], name="projection_order")
ordersel = tf.placeholder(tf.int32, shape=[n_batches, number], name='order_selection')
selection = tf.placeholder(tf.float32, shape=[number], name='iteration_selection')
dual = tf.placeholder(tf.float32, shape=[None, number, 183, 1], name='dual')
y_par = tf.placeholder(tf.float32, shape=[None, number, 183, 1], name='y_partial')
for i in range(n_batches): #iterations, the amount of projection batches we have
with tf.variable_scope('my_iterate{}'.format(i)):
value = layer_sub(primal[..., 1:2], epoch_angle[i])
x = (selection[i])
y_partial = y_rt[:, selection, :, :] #y_rt is of form (?,total, 183, 1)
As of version 1.9 TensorFlow doesn't support indexing by arrays using slice notation. From the tf.Tensor documentation for __getitem__:
This operation extracts the specified region from the tensor. The notation is similar to NumPy with the restriction that currently only support basic indexing. That means that using a non-scalar tensor as input is not currently allowed.
If you want more advanced indexing than simple scalars, tf.boolean_mask can help you select tensor elements using a boolean array and tf.gather_nd can help you select elements using an integer array.
Note in your example, the index specified by x would be a scalar with your 1-d selection tensor, and would work for slice notation if you used it:
x = selection[i]
y_partial = y_rt[:, x, :, :]
but indexing into selection for each of your training batches probably isn't what you want here.

Tensorflow gather_nd over input with varied shape

I need to extract the the sub tensors along axis=1 based on the value from another tensor.
state = tf.placeholder(shape=[None, None, 10], dtype=tf.float32)
length = tf.placeholder(shape=[None], dtype=tf.int32)
# this won't work, just be put here to demonstrate what I need
next_init_state = state[:, length - 1, :]
if state and length have deterministic shape, then next_init_state can be derived through gather_nd
state = tf.placeholder(shape=[10, 10, 10], dtype=tf.float32)
length = tf.placeholder(shape=[10], dtype=tf.int32)
index = tf.stack([tf.range(0, 10), length])
next_init_state = tf.gather_nd(state, index)
However since state and length all have nondeterministic shape None in the problem I have, the gather_nd approach won't work. At least I cannot think of a way to make it work. Is there any way to address it ?
I realized this is actually solved by Tensorflow's higher order function.
tf.map_fn(lambda x: x[0][x[1], :], (state, length), dtype=tf.float32)

how to apply a transformation to a single neuron?

Usually, an activation function is applied to all neurons of a given layer as in
layer = tf.nn.relu(layer)
How can I apply an activation function to say the second neuron only?
How can I apply a specific transformation (say tf.exp()) to a specific neuron only?
Slicing a column cannot apply here since to slice a column I need to know the number of rows and it is unknown at construction time.
You can do slicing of dynamically-shaped tensors, just like static ones. Here I stripped everything down to a [?, 2] tensor and it's 0-slice:
import numpy as np
import tensorflow as tf
x = tf.placeholder(dtype=tf.float32, shape=[None, 2], name='x')
layer = tf.nn.relu(x)
slice = layer[:, 0]
activation = tf.log(1 + tf.exp(slice))
with tf.Session() as session:
session.run(tf.global_variables_initializer())
layer_val, slice_val, activ_val = session.run([layer, slice, activation],
feed_dict={x: np.random.randn(10, 2)})
print layer_val[:, 0]
print slice_val
print activ_val
You should see that layer_val[:, 0] is the same as slice_val, and activ_val is its transformation.

Categories