Fill a tensor with a value that is not a scalar - tensorflow

I am trying to move a list of points to the origin using tensorflow the best way to do it mathematically is to find the centroid of the list of points then subtract the list of points by that centroid.
The problems: The number of rows contained in the point list is unknown until runtime.
Code so far:
import tensorflow as tf
example_point_list = tf.constant([[3., 3.], [.2, .2], [.1, .1]]) // but with any number of points
centroid = tf.reduce_mean(example_point_list, 0)
// subtract???
origin_point_list = tf.sub(example_point_list, centroid)
The problem is that subtract works on an element by element basis so I have to create a centroid tensor with the same number of rows as the point list but there are no methods that do that.
(to put it in math terms)
A = [[1, 1],
[2, 2]
[3, 3]]
B = avg(A) // [2, 2]
// step I need to do but do not know how to do it
B -> B1 // [[2, 2], [2, 2], [2, 2]]
Result = A - B1
Any help is appreciated!

Because of broadcasting, you don't need to tile the rows. In fact, it's more efficient to not tile them and subtract vector from matrix directly. In your case it would look like this
tf.reset_default_graph()
example_points = np.array([[1, 1], [2, 2], [3, 3]], dtype=np.float32)
example_point_list = tf.placeholder(tf.float32)
centroid = tf.reduce_mean(example_point_list, 0)
result = example_point_list - centroid
sess = tf.InteractiveSession()
sess.run(result, feed_dict={example_point_list: example_points})
result
array([[-1., -1.],
[ 0., 0.],
[ 1., 1.]], dtype=float32)
If you really want to tile the centroid vector explicitly, you could do it using shape operator which can get shape during runtime
tf.reset_default_graph()
example_point_list0 = np.array([[1, 1], [2, 2], [3, 3]], dtype=np.float32)
example_point_list = tf.placeholder(tf.float32)
# get number of examples from the array: [3]
num_examples = tf.slice(tf.shape(example_points), [0], [1])
# reshape [3] into 3
num_examples_flat = tf.reshape(num_examples, ())
centroid = tf.reduce_mean(example_point_list, 0)
# reshape centroid vector [2, 2] into matrix [[2, 2]]
centroid_matrix = tf.reshape(centroid, [1, -1])
# assemble 3 into vector of dimensions to tile: [3, 1]
tile_shape = tf.pack([num_examples_flat, 1])
# tile [[2, 2]] into [[2, 2], [2, 2], [2, 2]]
centroid_tiled = tf.tile(centroid_matrix, tile_shape)
sess = tf.InteractiveSession()
sess.run(centroid_tiled, feed_dict={example_point_list: example_point_list0})
result
array([[ 2., 2.],
[ 2., 2.],
[ 2., 2.]], dtype=float32)

Related

How to make mask for variable length sequences, which are then padded, in tensorflow2 for RNN

Trying implement a mask for a sequence of timeperiods, with zero-padding, to an LSTM network.
Each sequence of timeperiods is of varying length, hence requiring padding & masking.
I am trying to model sequences of length 96(timeperiods), and features=33. Simplified data (7 timeperiods and 3 features) are shown:
example state at a timeperiod = [4, 2, 9] at time0(t0)
example sequence = [[2, 3, 6], [1, 6, 8], [2, 9, 4], [2, 7, 3]] at t(0), t(1), t(2), t(3)
example_padded1 = [[2, 3, 6], [1, 6, 8], [2, 9, 4], [2, 7, 3], 0, 0, 0] at t(0) to t(6)
example_padded2 = [[2, 6, 0], [1, 6, 3], [2, 9, 7], [2, 7, 3], 0., 0., 0.]
example_padded3 = [[2, 6, 0], [5, 8, 3], [9, 4, 7], [2, 5, 3], [0., 0., 0.], [0., 0., 0.], [0., 0., 0.]]
Submitting each example sequence to:
seq = example_padded1
masking = layers.Masking(mask_value=0)
masked_output = masking(seq)
print(masked_output._keras_mask)
Gives Errors:
padded1 error: InvalidArgumentError: cannot compute Pack as input #2(zero-based) was expected to be a
float tensor but is a int32 tensor [Op:Pack] name: packed
padded2 error: InvalidArgumentError: Shapes of all inputs must match:
values[0].shape = [3] != values[2].shape = [] [Op:Pack] name: packed
padded3 error: Error: 'list' object has no attribute 'dtype' when
when checking for mask_value = 0
I then added an input layer to define shape of a sequence:
seq_len, n_features = 7, 3
inp = Input(shape=(seq_len, n_features))
masking = layers.Masking(mask_value=0, input_shape=inp)
masked_output2 = masking(seq)
print(masked_output2._keras_mask)
But got error:
TypeError: Cannot iterate over a tensor with unknown first dimension.
(Python 3.8, TF2)
Have also been trying Embedding, but that seems even more problematical
How to implement a mask for variable length sequences, which are then padded?
Have possibly resolved this. Problem lies in how I am building the array of sequences.
Each of my sequences consists of:
[array([1,2,3]),array([2,3,4]), array([4,5,6]), array([0,0,0]), , array([0,0,0]), , array([0,0,0]),, array([0,0,0])]
a list of arrays...
when it should be a single array, like:
array([[1,2,3], [2,3,4], [4,5,6], [0,0,0], [0,0,0], [0,0,0], [0,0,0]])

tensorflow count number of 0 at index 2 in a flatten-batch

Sorry for the inaccurate title. Here is the detail description of the problem: assume a tensor of shape (?, 2), e.g., a tensor T [[0,1], [0,2], [0,0], [1, 4], [1, 3], [2,0], [2,0], [2,0],[2,0]]. How to count how many zero showing up for every T[:, 0]. For the example above, because there is [0,0] and [2,0], the answer is 2.
More examples:
[[0,1], [0,2], [0,1], [1, 4], [1, 3], [2,0], [2,0], [2,0],[2,0]] (Answer: 1, because of [2,0])
[[0,1], [0,2], [0,1], [1, 4], [1, 3], [2,0], [2,0], [2,0],[2,0],[3,0]] (Answer: 2, because of [2, 0] and [3,0])
If I got what you are looking for, the question is how many unique "[X, 0]-pairs" you have in the data. If so, this should do it:
import tensorflow as tf
x = tf.placeholder(shape=(None, 2), dtype=tf.int32)
indices = tf.where(tf.equal(x[:,1], tf.constant(0, dtype=tf.int32)))
unique_values, _ = tf.unique(tf.squeeze(tf.gather(x[:, 0], indices)))
no_unique_values = tf.shape(unique_values, out_type=tf.int32)
data = [ .... ]
with tf.Session() as sess:
no_unique = sess.run(fetches=[no_unique_values], feed_dict={x: data})
Here is a solution I got myself
def get_unique(ts):
ts_part = ts[:, 1]
where = tf.where(tf.equal(0, ts_part))
gather_nd = tf.gather_nd(ts, where)
gather_plus = gather_nd[:, 0] + gather_nd[:, 1]
unique_values, _ = tf.unique(gather_plus)
return tf.shape(unique_values)[0]

How to enlarge a tensor(duplicate value) in tensorflow?

I am new in TensorFlow. I am trying to implement the global_context extraction in this paper https://arxiv.org/abs/1506.04579, which is actually an average pooling over the whole feature map, then duplicate the 1x1 feature map back to the original size. The illustration is as below
Specifically, the expected operation is following.
input: [N, 1, 1, C] tensor, where N is the batch size and C is the number of channel
output: [N, H, W, C] tensor, where H, W is the hight and width of original feature map, and all the H * W values of output are the same as the 1x1 input.
For example,
[[1, 1, 1]
1 -> [1, 1, 1]
[1, 1, 1]]
I have no idea how to do this using TensorFlow. tf.image.resize_images requires 3 channels, and tf.pad cannot pad constant value other than zero.
tf.tile may help you
x = tf.constant([[1, 2, 3]]) # shape (1, 3)
y = tf.tile(x, [3, 1]) # shape (3, 3)
y_ = tf.tile(x, [3, 2]) # shape (3, 6)
with tf.Session() as sess:
a, b, c = sess.run([x, y, y_])
>>>a
array([[1, 2, 3]], dtype=int32)
>>>b
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]], dtype=int32)
>>>c
array([[1, 2, 3, 1, 2, 3],
[1, 2, 3, 1, 2, 3],
[1, 2, 3, 1, 2, 3]], dtype=int32)
tf.tile(input, multiples, name=None)
multiples means how many times you want to repeat in this axis
in y repeat axis0 3 times
in y_ repeat axis0 3 times, and axis1 2 times
you may need to use tf.expand_dim first
yes it accept dynamic shape
x = tf.placeholder(dtype=tf.float32, shape=[None, 4])
x_shape = tf.shape(x)
y = tf.tile(x, [3 * x_shape[0], 1])
with tf.Session() as sess:
x_ = np.array([[1, 2, 3, 4]])
a = sess.run(y, feed_dict={x:x_})
>>>a
array([[ 1., 2., 3., 4.],
[ 1., 2., 3., 4.],
[ 1., 2., 3., 4.]], dtype=float32)

Set k-largest elements of a tensor to zero in TensorFlow

I want to find k largest elements of each row of h and set zero value to those maximum elements.
I could be able to select the indexes of top most value of each row by using top_k function like:
top_k = tf.nn.top_k(h, 1)
But I could not use the indexes returned by top_k to update tensor.
How can I do that? Thanks in advance...
This is a bit tricky, maybe there is a better solution. tf.scatter_update() doesn't work here because it can only modify parts of tensor along the first dimension (not an element in first row and second column for instance).
You have to get the values and indices from tf.nn.top_k() to create a sparse Tensor and subtract it to the initial Tensor x:
x = tf.constant([[6., 2., 0.], [0., 4., 5.]]) # of type tf.float32
k = 2
values, indices = tf.nn.top_k(x, k, sorted=False) # indices will be [[0, 1], [1, 2]], values will be [[6., 2.], [4., 5.]]
# We need to create full indices like [[0, 0], [0, 1], [1, 2], [1, 1]]
my_range = tf.expand_dims(tf.range(0, indices.get_shape()[0]), 1) # will be [[0], [1]]
my_range_repeated = tf.tile(my_range, [1, k]) # will be [[0, 0], [1, 1]]
# change shapes to [N, k, 1] and [N, k, 1], to concatenate into [N, k, 2]
full_indices = tf.concat([tf.expand_dims(my_range_repeated, 2), tf.expand_dims(indices, 2)], axis=2)
full_indices = tf.reshape(full_indices, [-1, 2])
to_substract = tf.sparse_to_dense(full_indices, x.get_shape(), tf.reshape(values, [-1]), default_value=0.)
res = x - to_substract # res should be all 0.
I was facing the opposite problem and wanted a operation which supported gradients. top_k does not support gradient propagation and hence a good way will be to implement the function in c++.
top_k c++ code is found here.
Your operation's kernel will look look like this:
template <typename T>
class MakeSparseOp : public OpKernel {
public:
explicit MakeSparseOp(OpKernelConstruction *context) : OpKernel(context) {}
void Compute(OpKernelContext *context) override {
// Grab the input tensors
const auto &k_in = context->input(1);
OP_REQUIRES(context, TensorShapeUtils::IsScalar(k_in.shape()),
errors::InvalidArgument("k must be scalar, got shape ",
k_in.shape().DebugString()));
int k = k_in.scalar<int32>()();
OP_REQUIRES(context, k >= 0,
errors::InvalidArgument("Need k >= 0, got ", k));
const Tensor &x_in = context->input(0);
OP_REQUIRES(context, x_in.dims() >= 1,
errors::InvalidArgument("input must be >= 1-D, got shape ",
x_in.shape().DebugString()));
OP_REQUIRES(
context, x_in.dim_size(x_in.dims() - 1) >= k,
errors::InvalidArgument("input must have at least k columns"));
// Flattening the input tensor
const auto &x = x_in.flat_inner_dims<T>();
const auto num_rows = x.dimension(0);
const auto num_cols = x.dimension(1);
TensorShape output_shape = x_in.shape();
// Create an output tensor
Tensor *x_out = nullptr;
OP_REQUIRES_OK(context,
context->allocate_output(0, output_shape, &x_out));
/*
* Get the top k values along the first dimension for input
*/
auto x_sparse = x_out->flat_inner_dims<T>();
if (k == 0) return; // Nothing to do
// Using TopN to get the k max element
gtl::TopN<std::pair<T, int32>> filter(k);
x_sparse = x; // Copy all elements
for (int r = 0; r < num_rows; r++) {
// Processing a row at a time
for (int32 c = 0; c < num_cols; c++) {
// The second element is the negated index, so that lower-index
// elements
// are considered larger than higher-index elements in case of
// ties.
filter.push(std::make_pair(x(r, c), -c));
}
for (auto top_k_it = filter.unsorted_begin();
top_k_it != filter.unsorted_end(); ++top_k_it) {
x_sparse(r, -top_k_it->second) = 0; // Set max k to zero
}
filter.Reset();
}
}
};
My implementation for a related problem is here.
With recent availability of scatter_nd_update function in tensorflow, here is a modified version of the answer from Oliver.
k = 2
val_to_replace_with = -333
x = tf.Variable([[6., 2., 0.], [0., 4., 5.]]) # of type tf.float32
values, indices = tf.nn.top_k(x, k, sorted=False) # indices will be [[0, 1], [1, 2]], values will be [[6., 2.], [4., 5.]]
# We need to create full indices like [[0, 0], [0, 1], [1, 2], [1, 1]]
my_range = tf.expand_dims(tf.range(0, tf.shape(indices)[0]), 1) # will be [[0], [1]]
my_range_repeated = tf.tile(my_range, [1, k]) # will be [[0, 0], [1, 1]]
# change shapes to [N, k, 1] and [N, k, 1], to concatenate into [N, k, 2]
full_indices = tf.concat([tf.expand_dims(my_range_repeated, -1), tf.expand_dims(indices, -1)], axis=2)
full_indices = tf.reshape(full_indices, [-1, 2])
# only significant modification -----------------------------------------------------------------
updates = val_to_replace_with + tf.zeros([tf.size(indices)], dtype=tf.float32)
c = tf.scatter_nd_update(x, full_indices, updates)
# only significant modification -----------------------------------------------------------------
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(c))
follow the Olivier Moindrot's idea, but implemented by tf's API.
x = tf.constant([[6., 2., 0.], [0., 4., 5.]]) # of type tf.float32
k = 2
values, indices = tf.nn.top_k(x, k, sorted=False) # indices will be [[0, 1], [1, 2]], values will be [[6., 2.], [4., 5.]]
# We need to create full indices like [[0, 0], [0, 1], [1, 2], [1, 1]]
ii, _ = tf.meshgrid(tf.range(2), tf.range(k), indexing='ij')
full_indices = tf.reshape(tf.stack([ii, indices], axis=-1), [-1, len(x.shape)])
tf.tensor_scatter_nd_sub(x, full_indices, tf.reshape(values, -1))
"""
In [249]: tf.tensor_scatter_nd_sub(x, full_indices, tf.reshape(values, -1))
Out[249]:
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[0., 0., 0.],
[0., 0., 0.]], dtype=float32)>
"""

Fastest method to create 2D numpy array whose elements are in range

I want to create a 2D numpy array where I want to store the coordinates of the pixels such that numpy array looks like this
[(0, 0), (0, 1), (0, 2), ...., (0, 510), (0, 511)
(1, 0), (1, 1), (1, 2), ...., (1, 510), (1, 511)
..
..
..
(511, 0), (511, 1), (511, 2), ...., (511, 510), (511, 511)]
This is a ridiculous question but I couldn't find anything yet.
Can use np.indices or np.meshgrid for more advanced indexing:
>>> data=np.indices((512,512)).swapaxes(0,2).swapaxes(0,1)
>>> data.shape
(512, 512, 2)
>>> data[5,0]
array([5, 0])
>>> data[5,25]
array([ 5, 25])
This may look odd because its really made to do something like this:
>>> a=np.ones((3,3))
>>> ind=np.indices((2,1))
>>> a[ind[0],ind[1]]=0
>>> a
array([[ 0., 1., 1.],
[ 0., 1., 1.],
[ 1., 1., 1.]])
A mgrid example:
np.mgrid[0:512,0:512].swapaxes(0,2).swapaxes(0,1)
A meshgrid example:
>>> a=np.arange(0,512)
>>> x,y=np.meshgrid(a,a)
>>> ind=np.dstack((y,x))
>>> ind.shape
(512, 512, 2)
>>> ind[5,0]
array([5, 0])
All are equivalent ways of doing this; however, meshgrid can be used to create non-uniform grids.
If you do not mind switching row/column indices you can drop the final swapaxes(0,1).
You can use np.ogrid here. Instead of storing a tuple, store it in a 3D array.
>>> t_row, t_col = np.ogrid[0:512, 0:512]
>>> a = np.zeros((512, 512, 2), dtype=np.uint8)
>>> t_row, t_col = np.ogrid[0:512, 0:512]
>>> a[t_row, t_col, 0] = t_row
>>> a[t_row, t_col, 1] = t_col
This should do the trick. Hopefully you can use this, instead of the tuple.
Chintak
The example in the question is not completely clear - either extra commas are missing or extra brakets.
This one - example ranges 3, 4 for clarity - provides the solution for the first variant and produces a 2D array in effect (as the question title suggests) - "listing" all coordinates:
>>> np.indices((3,4)).reshape(2,-1).T
array([[0, 0],
[0, 1],
[0, 2],
[0, 3],
[1, 0],
[1, 1],
[1, 2],
[1, 3],
[2, 0],
[2, 1],
[2, 2],
[2, 3]])
The other variant was already shown in another answer by using 2x .swapaxes() - but it could also be done with one np.rollaxis() (or the new np.moveaxis()) :
>>> np.rollaxis(np.indices((3,4)), 0, 2+1)
array([[[0, 0],
[0, 1],
[0, 2],
[0, 3]],
[[1, 0],
[1, 1],
[1, 2],
[1, 3]],
[[2, 0],
[2, 1],
[2, 2],
[2, 3]]])
>>> _[0,1]
array([0, 1])
This method also works the same for N-dimensional indices, e.g.:
>>> np.rollaxis(np.indices((5,6,7)), 0, 3+1)
Note: The function np.indices works indeed (C-speed) fast for big ranges.