I need to permute elements of a tensor in TF according to a given indexing. From 2 arrays a and b(indices), I need to compute a new array that permutes the elements in a according to the indices in b. For indices that are empty, it should fill with NA (or equivalent).
For example,
a = [10, 20, 30]
b = [-1, 0, 3]
output = [ 10, 20, NA, NA, 30]
I need to code the equivalent of what happens to the following numpy arrays but for TF tensors.
a = np.array([10,20,30])
b = np.array([-1,0,3])
mini = abs(np.min(b))
maxi = abs(np.max(b))
output = np.zeros(maxi+mini+1)
for ai,bi in zip(a,b):
output[bi+mini]= ai
How do I do this with TensorFlow tensors?
African or European?
If you know that the indices are strictly increasing, tf.sparse_to_dense does what you want.
If the indices are distinct but in increasing order, you can use tf.sparse_reorder to fix the order and then use tf.sparse_tensor_to_dense.
If there are duplicates and you want matching values to add, use tf.unsorted_segment_sum.
If there are duplicates and you want the last entry to win (corresponding exactly to your Python loop), use tf.dynamic_stitch.
Apologies for the zoo of options. The ops were all added for different reasons, so the overall design is not particularly clean.
I found a way of achieving this, I'm posting my answer here in case it helps anyone else.
The scatter_nd function in TensorFlow is very handy in this situation.
The following code permutes elements in the input tensor I according to the transformation given in tensor T. scatter_nd is used to create the new tensor according to this permutation.
sess = tf.InteractiveSession()
I = tf.constant([10,20,30])
T = tf.constant([-1,0,3])
T = T - tf.reduce_min(T)
T_shape = int(T.get_shape()[0])
T = tf.reshape(T, [T_shape,1])
O_shape = tf.reduce_max(T)+1
O = tf.scatter_nd(T, I, [O_shape])
print(sess.run([I,T,O]))
sess.close()
This code performs the following task:
Given
Input = [10, 20, 30]
Transformation = [-1, 0, 3]
Computes
Output = [10, 20, 0, 0, 30]
Related
In PyTorch, we can use standard Pythonic indexing to apply advanced indexing across n-dimensions.
preds is a Tensor of shape [1, 3, 64, 64, 12].
a, b, c, d are 1-dimensional Tensors of the same length. In this instance that length is 9, but this is not always the case.
PyTorch example achieving the desired result:
result = preds[a, b, c, d]
result.shape
>>> [9, 12]
How can this be reproduced in TensorFlow, starting from the same 5 Tensors and creating the same output?
I have tried tf.gather whichs seem to be able to produce the same behaviour in a single dimension:
tf.shape(tf.gather(preds, a))
>>> [9, 3, 64, 64, 12]
Is it possible to extend this to eventually reach the desired output of shape [9, 12]?
I have also noted the presence of tf.gather_nd which seems like it may be relevant here but I cannot determine how I would employ it from the documentation.
Yes, gather_nd can do that
t = tf.random.uniform(shape=(1,3,64,64,12))
# i_n = indices along n-th dim
i_1 = tf.constant([0,0,0,0,0,0,0,0,0])
i_2 = tf.constant([0,1,2,1,2,2,1,0,0])
i_3 = tf.constant([0,21,15,63,22,17,21,54,39])
i_4 = tf.constant([0,16,26,51,33,45,48,29,1])
i = tf.stack([i_1, i_2, i_3, i_4], axis=1) # i.shape == (9,4)
tf.gather_nd(t, i).shape # (9,12)
Supposed I have a list of tensorflow tensor, I want to dynamicaly append extra tensor to this list under certain condition. e.g., if the maximum dot product between each tensor in the list and this extra tensor is larger than 0, than this extra tensor is appended to the list. Here is the code:
lists = []
for i in xrange(10):
a = tf.get_variable(name=str(i), shape=[3], dtype=tf.float32)
lists.append(a)
so right now we have a list of 10 tensors, each tensor has shape [3].
for j in xrange(11, 30):
b = tf.get_variable(name=str(j), shape=[3, 1], dtype=tf.float32)
c = tf.stack(lists)
e = tf.cond(tf.reduce_max(tf.reshape(lists, shape=[-1]), axis=0)>0.00, lambda: tf.stack(lists.append(tf.reshape(b, [-1]))), lambda: c)
lists = tf.unstack(e)
However this code has several problems, first of all,
TypeError: 'NoneType' object has no attribute '__getitem__'
This is because tf.stack(lists.append(tf.reshape(b, [-1]))), lists.append(tf.reshape(b, [-1])) is a 'NoneType'.
Second problem is that even if this part is working, then lists = tf.unstack(e) has a bug because ValueError: Cannot infer num from shape (?, 3) because tf.unstack() can not work on non-inferrable dimensions.
Would you guys please teach me how to implement this function? Thanks
So, you have at least two different problems here.
First problem: I don't understand what kind of reshape you aree doing. I would use tensordot instead. And I would not convert the tensor back into a list, if not needed.
For example:
c = tf.stack(lists) # shape [10,3]
for j in range(11, 30):
b = tf.get_variable(name=str(j), shape=[1, 3], dtype=tf.float32)
d = tf.tensordot(b, c, axes=[1,1]) # shape [1,10]
c = tf.cond(tf.reduce_max(d) > 0.00, lambda: tf.concat([c, b], 0), lambda: c) # shape [?,3]
Second problem: convert a tensor with non-inferrable dimensions into a list. There are lots of questions and answers about this topics:
http://www.google.com/search?q=tensorflow+unstack+can+not+work+on+non-inferrable+dimensions
Hope that helps.
I'm working on masking r-cnn and I have a problem with indexing the masks according to labels.
Here's what I want to achieve: I have a tensor (?,28,28,c), where ? is unknown batch_size, "28x28" are 2d coordinates and c stands for different labels, then I have a list of indices (basically my label predictions) (?,) of int32. Now I want to extract the masks for a given label according to batch index -> make it a (?,28,28,1) tensor.
I tried self.masks_sigmoids = tf.gather(self.final_conv, self.label_predictions, axis=3), but the shape remained the same.
I also looked at tf.gather_nd here http://www.riptutorial.com/tensorflow/example/29069/how-to-use-tf-gather-nd, and I guess this is the right path, but I don't know how to incorporate that I want the indices according to batch index (in numpy (b_i,:,:,c_i))
I also get a feeling that my question is somewhat similar to Batched 4D tensor Tensorflow indexing, though my problem seems less complicated. However, that question is old in terms of the quick development of tensorflow, so I'm asking for a possibly better, more clear solution. EDIT: Even a dirty solution might beneficial as I didn't get the question in the linked SO (already wrote a comment asking to clarify the question), thus I don't get much from the only answer. It might be beneficial for the community as well, because this question is simpler, which means it would demonstrate the solution more clearly.
Solution 1: more generic
You can look at the answer here, it's basically the same problem as yours, with different dimensions.
The solution described there is to create a [?, 28, 28, 4]-shaped tensor indices where indices[i, x, y, :] = [i, x, y, self.label_predictions[i]], and then use tf.gather_nd:
self.masks_sigmoids = tf.gather_nd(self.final_conv, indices=indices)
Building the indices is not very elegant, as shown in this answer (with one more dimension for you), but easy in itself.
Solution 2: A bit more elegant and adapted to your problem
This solution is very similar to the first one, but avoids creating the [x, y] part of indices. The idea is to use the slicing capabilities of gather_nd to avoid writing [x, y] in indices for each (i, x, y), by transposing the data before gathering it. I'll put the whole code here, including how to create indices and how to test:
import numpy as np
import tensorflow as tf
N_CHANNELS = 5
pl=tf.placeholder(dtype=tf.int32, shape=(None, 28, 28, N_CHANNELS))
# Indices we'll use. batch_size = 4 here.
label_predictions = tf.constant([0, 2, 0, 3])
# Indices of shape [?, 2], with indices[i] = [i, self.label_predictions[i]],
# which is easy to do with tf.range() and tf.stack()
indices = tf.stack([tf.range(tf.size(label_predictions)), label_predictions], axis=-1)
# [[0, 0], [1, 2], [2, 0], [3, 3]]
transposed = tf.transpose(pl, perm=[0, 3, 1, 2])
gathered = tf.gather_nd(transposed, indices) # Should be of shape (4, 2, 3)
result = tf.expand_dims(gathered, -1)
initial_value = np.arange(4*28*28*N_CHANNELS).reshape((4, 28, 28, N_CHANNELS))
sess = tf.InteractiveSession()
res = sess.run(result, feed_dict={pl: initial_value})
# print(res)
print("checking validity")
for i in range(4):
for x in range(28):
print(x)
for y in range(28):
assert res[i, x, y, 0] == initial_value[i, x, y, indices[i, 1].eval()]
print("All assertions passed")
I'm trying to efficiently replicate numpy's ndarray.choose() method.
Here's a numpy example of what I'm looking for:
b = np.arange(15).reshape(3, 5)
c = np.array([1,0,4])
c.choose(b.T) # trying to replicate in tensorflow
-> array([ 1, 5, 14])
The best I've been able to do with this is generate a batch_size square matrix (which is huge if batch size is huge) and take the diagonal of it:
tf_b = tf.constant(b)
tf_c = tf.constant(c)
sess.run(tf.diag_part(tf.gather(tf.transpose(tf_b), tf_c)))
-> array([ 1, 5, 14])
Is there a way to do this that is just linear in the first dimension (instead of squared)?
Yeah, there's an easier way to do this. Flatten your b array to 1-d, so it's [0, 1, 2, ..., 13, 14]. Take an array of indices that are in the range of the number of 'choices' you are taking (3 in your case). That will be [0, 1, 2]. Multiply this range by the second dimension of your original shape, which is the number of options for each choice (5 in your case). That gives you [0, 5, 10]. Then add your indices to this to obtain [1, 5, 14]. Now you're good to call tf.gather().
Here is some code that I've taken from here that does a similar thing for RNN outputs. Yours will be slightly different, but the idea is the same.
index = tf.range(0, batch_size) * max_length + (length - 1)
flat = tf.reshape(output, [-1, out_size])
relevant = tf.gather(flat, index)
return relevant
In a big picture, the operation is pretty straightforward. You use the range operation to get the index of the beginning of each row, then add the index of where you are in each row. I think doing it in 1D is easiest, so that's why we flatten it.
I'm learning tensorflow right now, and I have a question that I couldn't find via google. I find it easier to work on a problem and look up documentation as I stumble on issues, so if this is somewhere in the documentation and I haven't applied, I apologize.
I have a tensor. Let's say it's 100 x 1. Let's call it t1. I also have a list of integers, ranging in [0, 99], of size 5000, call it l. I want to transform t1 into a 5000 x 1 tensor, call it t2.
The relationship is as follows: suppose the i^th entry of l is j. Then, I want the i^th entry of t2 to be equal to the j^th entry of t1.
Now, if these were numpy arrays, I would simply do:
t2 = t1[l]
But I don't think this is an efficient way of doing it in tensorflow, and it doesn't even seem to work anyways.
Suggestions?
What you are looking for is tf.gather:
https://www.tensorflow.org/api_docs/python/tf/gather
import tensorflow as tf
tf.InteractiveSession()
t1 = tf.random_normal((100, 1))
l = tf.random_uniform((5000, ), minval=0, maxval=99, dtype=tf.int32)
t2 = tf.gather(t1, l)