Given a tensor t=[[1,2], [3,4]], I need to produce ts=[[1,2,1,2], [1,2,3,4], [3,4,1,2], [3,4,3,4]]. That is, I need to stack together all row pairs.
Important: the tensor has dimension [None, 2], ie. the first dimension is variable.
I have tried:
Using a tf.while_loop to generate a list of indices idx=[[0, 0], [0, 1], [1, 0], [1, 1]], then tf.gather(ts, idx). This works but is messy and I don't know what to do about gradients.
2 for loops iterating over tf.unstack(t), adding stacked rows to a buffer, then tf.stack(buffer). This does not work if the first dimension is variable.
To look for inspiration in broadcasting. For instance, given x=t.expand_dims(t, 0), y=t.expand_dims(t, 1), s=tf.reshape(tf.add(x, y), [-1, 2]) s will be [[2, 4], [4, 6], [4, 6], [6, 8]], ie. the sum of every row combination. But how can I do stacking instead of sum? I've been failing for 2 days :)
Solution with tf.meshgrid() and some reshaping:
import tensorflow as tf
import numpy as np
t = tf.placeholder(tf.int32, [None, 2])
num_rows, size_row = tf.shape(t)[0], tf.shape(t)[1] # actual dynamic dimensions
# Getting pair indices using tf.meshgrid:
idx_range = tf.range(num_rows)
pair_indices = tf.stack(tf.meshgrid(*[idx_range, idx_range]))
pair_indices = tf.transpose(pair_indices, perm=[1, 2, 0])
# Finally gathering the rows accordingly:
res = tf.reshape(tf.gather(t, pair_indices), (-1, size_row * 2))
with tf.Session() as sess:
print(sess.run(res, feed_dict={t: np.array([[1,2], [3,4], [5,6]])}))
# [[1 2 1 2]
# [3 4 1 2]
# [5 6 1 2]
# [1 2 3 4]
# [3 4 3 4]
# [5 6 3 4]
# [1 2 5 6]
# [3 4 5 6]
# [5 6 5 6]]
Solution using cartesian product:
import tensorflow as tf
import numpy as np
t = tf.placeholder(tf.int32, [None, 2])
num_rows, size_row = tf.shape(t)[0], tf.shape(t)[1] # actual dynamic dimensions
# Getting pair indices by computing the indices cartesian product:
row_idx = tf.range(num_rows)
row_idx_a = tf.expand_dims(tf.tile(tf.expand_dims(row_idx, 1), [1, num_rows]), 2)
row_idx_b = tf.expand_dims(tf.tile(tf.expand_dims(row_idx, 0), [num_rows, 1]), 2)
pair_indices = tf.concat([row_idx_a, row_idx_b], axis=2)
# Finally gathering the rows accordingly:
res = tf.reshape(tf.gather(t, pair_indices), (-1, size_row * 2))
with tf.Session() as sess:
print(sess.run(res, feed_dict={t: np.array([[1,2], [3,4], [5,6]])}))
# [[1 2 1 2]
# [1 2 3 4]
# [1 2 5 6]
# [3 4 1 2]
# [3 4 3 4]
# [3 4 5 6]
# [5 6 1 2]
# [5 6 3 4]
# [5 6 5 6]]
Can be achieved by:
tf.concat([tf.tile(tf.expand_dims(t,1), [1, tf.shape(t)[0], 1]), tf.tile(tf.expand_dims(t,0), [tf.shape(t)[0], 1, 1])], axis=2)
Detailed steps:
t = tf.placeholder(tf.int32, shape=[None, 2])
#repeat each row of t
d = tf.tile(tf.expand_dims(t,1), [1, tf.shape(t)[0], 1])
#Output:
#[[[1 2] [1 2]]
# [[3 4] [3 4]]]
#repeat the entire input t
e = tf.tile(tf.expand_dims(t,0), [tf.shape(t)[0], 1, 1])
#Output:
#[[[1 2] [3 4]]
# [[1 2] [3 4]]]
#concat
f = tf.concat([d, e], axis=2)
with tf.Session() as sess:
print(sess.run(f, {t:np.asarray([[1,2],[3,4]])}))
#Output
#[[[1 2 1 2]
#[1 2 3 4]]
#[[3 4 1 2]
#[3 4 3 4]]]
Related
This question is similar to this question:
pad last dimension of tensor
with the exception that I would like to pre-pad this tensor with the beginning values. Given the ragged tensor:
[[1],
[4, 2],
[1, 2, 3]]
I would expect the output to be:
[[1 1 1],
[4 4 2],
[1 2 3]]
I would like to be able to apply the solution to a larger ragged tensor.
Just use the properties of a ragged tensor:
import tensorflow as tf
x = tf.ragged.constant([[1],
[4, 2],
[1, 2, 3]])
rows_to_pad = tf.abs(x.row_lengths() - tf.reduce_max(x.row_lengths()))
padded_x = tf.concat([tf.RaggedTensor.from_row_lengths(
values=tf.repeat(tf.gather(x.merge_dims(0, -1), x.row_starts()), rows_to_pad, axis=0),
row_lengths=rows_to_pad), x], axis=-1).to_tensor()
[[1 1 1]
[4 4 2]
[1 2 3]]
A different ragged tensor:
x = tf.ragged.constant([[1, 4, 5, 6, 7, 8, 3],
[4, 2],
[1, 2, 3],
[1, 2, 3, 4, 5],
[1]])
Pre-padded:
[[1 4 5 6 7 8 3]
[4 4 4 4 4 4 2]
[1 1 1 1 1 2 3]
[1 1 1 2 3 4 5]
[1 1 1 1 1 1 1]]
I have an array of points, and I want to split these into two arrays by the second dimension:
points_right = points[points[:, 0] > p0[0]]
points_left = points[points[:, 0] < p0[0]]
how can I split these points in one loop?
I think np.split is what you're looking for, just use axis=1.
Example splitting a 2x4 matrix:
import numpy as np
pts = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
left_pts, right_pts = np.split(pts, indices_or_sections=2, axis=1)
The original matrix (pts):
[[1 2 3 4]
[5 6 7 8]]
left_pts:
[[1 2]
[5 6]]
right_pts:
[[3 4]
[7 8]]
https://numpy.org/doc/stable/reference/generated/numpy.split.html
I have a tensor array a and a tensor matrix m. Now I want to insert a into m after every second position started at index 0 ending with len(m)-2. Let's make an equivalent example using numpy and plain python:
# define m
m = np.array([[3,7,6],[4,3,1],[8,4,2],[2,8,7]])
print(m)
#[[3 7 6]
# [4 3 1]
# [8 4 2]
# [2 8 7]]
# define a
a = np.array([1,2,3])
#[1 2 3]
# insert a into m
result = []
for i in range(len(m)):
result.append(a)
result.append(m[i])
print(np.array(result))
#[[1 2 3]
# [3 7 6]
# [1 2 3]
# [4 3 1]
# [1 2 3]
# [8 4 2]
# [1 2 3]
# [2 8 7]]
I am looking for a solution in tensorflow. I am convinced that there is a solution that doesn't need a loop but I am not able to find one. I hope someone can help me out with this!
You can concatenate your target vector at the beginning of each line of your matrix, and then reshape it.
import tensorflow as tf
initial_array = tf.constant([
[3, 7, 6],
[4, 3, 1],
[8, 4, 2],
[2, 8, 7],
])
vector_to_add = [1, 2, 3]
concat = tf.concat([[vector_to_add] * initial_array.shape[0], initial_array], axis=1) # Concatenate vector_to_add to each vector of initial_array
output = tf.reshape(concat, (2 * initial_array.shape[0], initial_array.shape[1])) # Reshape
This should work,
np.ravel(np.column_stack((m, np.tile(a, (4, 1))))).reshape(8, 3)
For idea, please refer to Interweaving two numpy arrays. Apply any solution described there, and reshape.
I am trying to extract all slices of length 4 along 0th axis of a 2-dim tensor. So far I can do it mixing pure Python with tensorflow.
r = test.shape[0] # test should be a tensor
n = 4
a_list = list(range(r))
the_list = np.array([a_list[slice(i, i+n)] for i in range(r - n+1)])
test_stacked = tf.stack(tf.gather(test, the_list))
What would be an efficient way of doing that without using pure Python? Note that the "test" array is actually supposed to be a tensor, thus its shape isn't known before I execute the first part of the graph.
A full vanilla example:
array = np.array([[0, 1],[1, 2],[2, 3],[3, 4],[4, 5],[5, 6]])
array.shape # (6,2)
r = array.shape[0]
n = 4
a_list = list(range(r))
the_list = np.array([a_list[slice(i, i+n)] for i in range(r - n+1)])
result = array[the_list] # all possible slices of length 4 of the array along 0th axis
result.shape # (3, 4, 2)
result:
[[[0 1]
[1 2]
[2 3]
[3 4]]
[[1 2]
[2 3]
[3 4]
[4 5]]
[[2 3]
[3 4]
[4 5]
[5 6]]]
You may want to try the more general tf.extract_image_patches.
import tensorflow as tf
a = tf.constant([[0, 1],[1, 2],[2, 3],[3, 4],[4, 5],[5, 6]])
# tf.extract_image_patches requires a [batch, in_rows, in_cols, depth] tensor
a = a[None, :, :, None]
b = tf.extract_image_patches(a,
ksizes=[1, 4, 2, 1],
strides=[1, 1, 1, 1],
rates=[1, 1, 1, 1],
padding='VALID')
b = tf.reshape(tf.squeeze(b), [-1, 4, 2])
sess = tf.InteractiveSession()
print(b.eval())
I believe gather_nd is what you are looking for.
# a is a tensor of size (6, 2)
def get_indices(l, d):
return [[[j] for j in range(i, i + d)] for i in range(l - d + 1)]
b = tf.gather_nd(a, get_indices(6, 4))
# b is a tensor of shape (3, 4, 2)
Actually, I'm doing the homework "Art Generation with Neural Style Transfer" of deeplearning.ai on coursera. In the function compute_layer_style_cost(a_S, a_G):
a_S = tf.reshape(a_S, [n_H*n_W, n_C])
a_G = tf.reshape(a_G, [n_H*n_W, n_C])
GS = gram_matrix(tf.transpose(a_S))
GG = gram_matrix(tf.transpose(a_G))
Why does this code give the right answer, however, the following doesn't:
a_S = tf.reshape(a_S, [n_C, n_H*n_W])
a_G = tf.reshape(a_G, [n_C, n_H*n_W])
GS = gram_matrix(a_S)
GG = gram_matrix(a_G)
Here's a trivial example that shows the difference between these two expressions:
import tensorflow as tf
tf.InteractiveSession()
x = tf.range(0, 6)
a = tf.reshape(x, [3, 2])
b = tf.transpose(tf.reshape(x, [2, 3]))
print(x.eval())
print(a.eval())
print(b.eval())
The result:
[0 1 2 3 4 5]
[[0 1]
[2 3]
[4 5]]
[[0 3]
[1 4]
[2 5]]
As you can notice, a and b are different, though have the same shape. That's because the first reshaping "splits" x into [0 1], [2 3] and [4 5], while the second reshaping into [0 1 2] and [3 4 5].