Is this possible with tf.tensor_scatter_nd_add - tensorflow

A simple example of the following use of tf.tensor_scatter_nd_add is giving me problems.
B = tf.tensor_scatter_nd_add(A, indices, updates)
tensor A is (1,4,4)
A = [[[1. 1. 1. 1.],
[1. 1. 1. 1.],
[1. 1. 1. 1.],
[1. 1. 1. 1.]]]
the desired result is tensor B:
B = [[[1. 1. 1. 1.],
[1. 2. 3. 1.],
[1. 4. 5. 1.],
[1. 1. 1. 1.]]]
i.e. I want to add this smaller tensor to just the 4 inner elements of tensor A
updates = [[[1, 2],
[3, 4]]]
Tensorflow 2.1.0. I've tried a number of ways of constructing indices. The call to tensor_scatter_nd_add returns an error saying the inner dimensions don't match.
Do the updates tensor need to be the same shape as A?

Planaria,
Try passing indices and updates the following way: updates with shape (n), indices with shape (n,3) where n is number of changed items.
Indices should point to individual cells that you want to change:
A = tf.ones((1,4,4,), dtype=tf.dtypes.float32)
updates = tf.constant([1., 2., 3., 4])
indices = tf.constant([[0,1,1], [0,1,2], [0,2,1], [0,2,2]])
tf.tensor_scatter_nd_add(A, indices, updates)
<tf.Tensor: shape=(1, 4, 4), dtype=float32, numpy=
array([[[1., 1., 1., 1.],
[1., 2., 3., 1.],
[1., 4., 5., 1.],
[1., 1., 1., 1.]]], dtype=float32)>

Related

Transform sequential 2d array to time-windowed dataset

I have a 2d dataframe:
C1. C2. C3
0. 2. 3. 6
1. 8. 2. 1
2. 8. 6. 2
3. 4. 9. 0
4. 6. 7. 1
5. 2. 3. 0
I want it to be a 3d data with <num_windows, window_size, num_features>
So if window size is 5, the shape of the 3d data will be <2,5,3> and will be:
[[2,3,4],[8,2,1],[8,6,2],[4,9,0],[6,7,1]] , [[8,2,1],[8,6,2],[4,9,0],[6,7,1],[2,3,0]]
What is the best way to do it?
You can use sliding_window_view:
num_windows = 2
window_size = 5
num_features = 3
np.lib.stride_tricks.sliding_window_view(df, (window_size, num_features))[:num_windows,0,:,:]
gives a 3D array of shape (num_windows, window_size, num_features):
array([[[2., 3., 6.],
[8., 2., 1.],
[8., 6., 2.],
[4., 9., 0.],
[6., 7., 1.]],
[[8., 2., 1.],
[8., 6., 2.],
[4., 9., 0.],
[6., 7., 1.],
[2., 3., 0.]]])

What is the simplest way to create an upper triangle tensor with Tensorflow?

Similar to this question, I want to convert this tensor
tensor = tf.ones((5, 5))
tf.Tensor(
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]], shape=(5, 5), dtype=float32)
to an upper triangular tensor with ones and zeros everywhere else:
tf.Tensor(
[[1. 1. 1. 1. 1.]
[0. 1. 1. 1. 1.]
[0. 0. 1. 1. 1.]
[0. 0. 0. 1. 1.]
[0. 0. 0. 0. 1.]], shape=(5, 5), dtype=float32)
any ideas?
You can use tf.linalg.band_part:
>>> tensor = tf.ones((5, 5))
>>> tf.linalg.band_part(tensor, 0, -1)
<tf.Tensor: shape=(5, 5), dtype=float32, numpy=
array([[1., 1., 1., 1., 1.],
[0., 1., 1., 1., 1.],
[0., 0., 1., 1., 1.],
[0., 0., 0., 1., 1.],
[0., 0., 0., 0., 1.]], dtype=float32)>
Note that you can use that function to extract an arbitrary number of diagonals from the tensor. Useful cases include:
tf.linalg.band_part(input, 0, -1) ==> Upper triangular part.
tf.linalg.band_part(input, -1, 0) ==> Lower triangular part.
tf.linalg.band_part(input, 0, 0) ==> Diagonal.

Tensorflow: Reshape a 1-D tensor with given numbers of elements in each row

I want to convert a 1-D tensor to 2-D shape in Tensorflow 2, with the number of elements in each row is given. I found a solution using the RaggedTensor like this
numbers = tf.constant([1,3,2,5,4])
c0 = tf.ones(shape=(15,)) # the tensor need to be reshape
rc0 = tf.RaggedTensor.from_row_lengths(values=c0, row_lengths=numbers)
c1 = rc0.to_tensor()
The final value of c1 should be
<tf.Tensor: shape=(5, 5), dtype=float32, numpy=
array([[1., 0., 0., 0., 0.],
[1., 1., 1., 0., 0.],
[1., 1., 0., 0., 0.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 0.]], dtype=float32)>
I found it refused to work when the size of the input tensor is large, and the performance is not good enough.
Is there any other high performance solution?

Removing certain rows from tensor in tensorflow without using tf.RaggedTensor

Given tensor data
[[[ 0., 0.],
[ 1., 1.],
[-1., -1.]],
[[-1., -1.],
[ 4., 4.],
[ 5., 5.]]]
I want to remove [-1,-1] and get
[[[ 0., 0.],
[ 1., 1.]],
[[ 4., 4.],
[ 5., 5.]]]
How to get the above without using ragged feature in tensorflow?
You can try this:
x = tf.constant(
[[[ 0., 0.],
[ 1., 1.],
[-1., -2.]],
[[-1., -2.],
[ 4., 4.],
[ 5., 5.]]])
mask = tf.math.not_equal(x, np.array([-1, -1]))
result = tf.boolean_mask(x, mask)
shape = tf.shape(x)
result = tf.reshape(result, (shape[0], -1, shape[2]))
You could do it like this:
import tensorflow as tf
import numpy as np
data = [[[ 0., 0.],
[ 1., 1.],
[-1., -1.]],
[[-1., -1.],
[ 4., 4.],
[ 5., 5.]]]
data = tf.constant(data)
indices = tf.math.not_equal(data, tf.constant([-1., -1.]))
res = data[indices]
shape = tf.shape(data)
total = tf.reduce_sum(
tf.cast(tf.math.logical_and(indices[:, :, 0], indices[:, :, 1])[0], tf.int32))
res = tf.reshape(res, (shape[0], total, shape[-1]))
with tf.Session() as sess:
print(sess.run(res))
# [[[0. 0.]
# [1. 1.]]
# [[4. 4.]
# [5. 5.]]]

Using tf.tile to replicate a tensor N times

My current tensor has shape of (3, 2), e.g.,
[[ 1. 2.]
[ 2. 1.]
[-2. -1.]]
I would like to expand to a shape of (1, 3, 2) with each second dimension a replica of the entire tensor, e.g.,
[[[ 1. 2.]
[ 2. 1.]
[ -2. -1.]]
[[ 1. 2.]
[ 2. 1.]
[ -2. -1.]]
[[ 1. 2.]
[ 2. 1.]
[ -2. -1.]]]
I tried the folllowing code but it only replicate each row instead.
tiled_vecs = tf.tile(tf.expand_dims(input_vecs, 1), [1, 3, 1])
Results in
[[[ 1. 2.]
[ 1. 2.]
[ 1. 2.]]
[[ 2. 1.]
[ 2. 1.]
[ 2. 1.]]
[[-2. -1.]
[-2. -1.]
[-2. -1.]]]
This should work,
tf.ones([tf.shape(A)[0], 1, 1]) * A
# Achieved by creating a 3d matrix as shown below
# and multiplying it with A, which is `broadcast` to obtain the desired result.
[[[1.]],
[[1.]], * A
[[1.]]]
Code Sample:
#input
A = tf.constant([[ 1., 2.], [ 2. , 1.],[-2., -1.]])
B = tf.ones([tf.shape(A)[0], 1, 1]) * A
#output
array([[[ 1., 2.],
[ 2., 1.],
[-2., -1.]],
[[ 1., 2.],
[ 2., 1.],
[-2., -1.]],
[[ 1., 2.],
[ 2., 1.],
[-2., -1.]]], dtype=float32)
Also using tf.tile, we can obtain the same:
tf.tile(tf.expand_dims(A,0), [tf.shape(A)[0], 1, 1])