Skip to content Skip to sidebar Skip to footer

Tensorflow Getting Elements Of Every Row For Specific Columns

If A is a TensorFlow variable like so A = tf.Variable([[1, 2], [3, 4]]) and index is another variable index = tf.Variable([0, 1]) I want to use this index to select columns in

Solution 1:

You can extend your column indices with row indices and then use gather_nd:

import tensorflow as tf

A = tf.constant([[1, 2], [3, 4]])
indices = tf.constant([1, 0])

# prepare row indices
row_indices = tf.range(tf.shape(indices)[0])

# zip row indices with column indices
full_indices = tf.stack([row_indices, indices], axis=1)

# retrieve values by indices
S = tf.gather_nd(A, full_indices)

session = tf.InteractiveSession()
session.run(S)

Solution 2:

You can use one hot method to create a one_hot array and use it as a boolean mask to select the indices you'd like.

A = tf.Variable([[1, 2], [3, 4]])
index = tf.Variable([0, 1])

one_hot_mask = tf.one_hot(index, A.shape[1], on_value = True, off_value = False, dtype = tf.bool)
output = tf.boolean_mask(A, one_hot_mask)

Solution 3:

After dabbling around for quite a while. I found two functions that could be useful.

One is tf.gather_nd() which might be useful if you can produce a tensor of the form [[0, 0], [1, 1]] and thereby you could do

index = tf.constant([[0, 0], [1, 1]])

tf.gather_nd(A, index)

If you are unable to produce a vector of the form [[0, 0], [1, 1]](I couldn't produce this as the number of rows in my case was dependent on a placeholder) for some reason then the work around I found is to use the tf.py_func(). Here is an example code on how this can be done

import tensorflow as tf 
import numpy as np 

def index_along_every_row(array, index):
    N, _ = array.shape 
    return array[np.arange(N), index]

a = tf.Variable([[1, 2], [3, 4]], dtype=tf.int32)
index = tf.Variable([0, 1], dtype=tf.int32)
a_slice_op = tf.py_func(index_along_every_row, [a, index], [tf.int32])[0]
session = tf.InteractiveSession()

a.initializer.run()
index.initializer.run()
a_slice = a_slice_op.eval() 

a_slice will be a numpy array [1, 4]

Solution 4:

We can do the same using this combination of map_fn and gather_nd.

defget_element(a, indices):
    """
    Outputs (ith element of indices) from (ith row of a)
    """return tf.map_fn(lambda x: tf.gather_nd(x[0], x[1]), 
                                  (a, indices),
                                  dtype = tf.float32)

Here's an example usage.

A = tf.constant(np.array([[1,2,3],
                          [4,5,6],
                          [7,8,9]], dtype = np.float32))

idx = tf.constant(np.array([[2],[1],[0]]))
elems = get_element(A, idx)

with tf.Session() as sess:
    e = sess.run(elems)

print(e)

I don't know if this will be much slower than other answers.

It has the advantage that you don't need to specify the number of rows of A in advance, as long as a and indices have the same number of rows at runtime.

Note the output of the above will be rank 1. If you'd prefer it to have rank 2, replace gather_nd by gather

Solution 5:

I couldn't get the accepted answer to work in Tensorflow 2 when I incorporated it into a loss function. Something about GradientTape didn't like it. My solution is an altered version of the accepted answer:

def get_rows(arr):
  N, _ = arr.shape 
  return N

num_rows= tf.py_function(get_rows, [arr], [tf.int32])[0]
rng = tf.range(0,num_rows)
ind = tf.stack([rng, ind], axis=1)
tf.gather_nd(arr, ind)

Post a Comment for "Tensorflow Getting Elements Of Every Row For Specific Columns"