Add two tensors with different dimensions in tensorflow - python

I am basically trying to add two tensors in tensorflow, the crux is that they are of different lengths
a = [1, 2, 3, 4, 5] and b = [1, 2, 3] and am looking for a function that I am calling tf.myadd in the following
tf.myadd(a, b) = [2, 4, 6, 4, 5]
I have been looking into broadcasting, yet this has not the expected behavior.

Broadcasting is the default for all tensor operations in tf. In this case, you are trying to avoid broadcasting since the 2 tensors ((5,) and (3,)) are NOT broadcastable along the axis=0 by the standard broadcasting rules. So what you need is an element-wise addition without broadcasting.
What you can do as in this case is use post-padding on the smaller array such that the two 1D tensors have the same shape and then add them elementwise over axis=0.
Like this -
import numpy as np
import tensorflow as tf
a = [1, 2, 3, 4, 5]
b = [1, 2, 3]
b_pad = np.pad(b, (0,len(a)-len(b)))
tf.add(a,b_pad).numpy()
array([2, 4, 6, 4, 5], dtype=int32)

Related

Python - How to remove some terms of a numpy array in specific intervals

Suppose I have the following array:
import numpy as np
x = np.array([1,2,3,4,5,
1,2,3,4,5,
1,2,3,4,5])
How can I manipulate it to remove the term in equally spaced intervals and adapt the new length for it? For example, I'd like to have:
x = [1,2,3,4,
1,2,3,4,
1,2,3,4]
Where the terms from positions 4, 9, and 14 were excluded (so every 5 terms, one gets excluded). If possible, I'd like to have a code that I could use for an array with length N. Thank you in advance!
In your case, you can simply run code below after initializing the x array(as you did your question):
x.reshape(3,5)[:,:4]
Output
array([[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]])
If you are interested in getting a vector and not a matrix(such as the output above), you can call the flatten function on the code above:
x.reshape(3,5)[:,:4].flatten()
Output
array([1, 2, 3, 4,
1, 2, 3, 4,
1, 2, 3, 4])
Explanation
Since x is a numpy array, we can use NumPy in-built functions such as reshape. This function, which has a self-explanatory name, shapes the array into the desired format. x was a vector of 15 elements. Therefore, running x.reshape(3,5) gives us a matrix with 3 rows and five columns. [:, :4] is to reselect the first four columns. flatten function changes a matrix into a vector.
IIUC, you can use a boolean mask generated with the modulo (%) operator:
N = 5
mask = np.arange(len(x))%N != N-1
x[mask]
output: array([1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4])
This works even if your array has not a size that is a multiple of N

PyTorch slice matrix with vector

Say I have one matrix and one vector as follows:
import torch
x = torch.tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
y = torch.tensor([0, 2, 1])
is there a way to slice it x[y] so the result is:
res = [1, 6, 8]
So basically I take the first element of y and take the element in x that corresponds to the first row and the elements' column.
You can specify the corresponding row index as:
import torch
x = torch.tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
y = torch.tensor([0, 2, 1])
x[range(x.shape[0]), y]
tensor([1, 6, 8])
Advanced indexing in pytorch works just as NumPy's, i.e the indexing arrays are broadcast together across the axes. So you could do as in FBruzzesi's answer.
Though similarly to np.take_along_axis, in pytorch you also have torch.gather, to take values along a specific axis:
x.gather(1, y.view(-1,1)).view(-1)
# tensor([1, 6, 8])

Zipping and reshaping in Tensorflow

Problem:
Let's say I have two tensors, a and b. Both have the same shape: [?, 10, 4096].
How do I zip the two in a manner that the resulting tensor has a shape of [?, 20, 4096], but also such that the ith element of a comes right before the ith element of b.
Example with lists:
a = [1, 3, 5]
b = [2, 4, 6]
and now I want a tensor that looks like [1, 2, 3, 4, 5, 6] and not [1, 3, 5, 2, 4, 6], which is what would happen if I were to tf.stack the two and then use tf.reshape, right?.
Or perhaps a more general question would be, how do you know in what order tf.reshape reshapes a tensor?
First it looks like, stacking and then reshaping does the job:
import tensorflow as tf
a = tf.constant([1, 3, 5])
b = tf.constant([2, 4, 6])
c = tf.stack([a, b], axis = 1)
d = tf.reshape(c, (-1,))
with tf.Session() as sess:
print(sess.run(c)) # [[1 2],[3 4],[5 6]]
print(sess.run(d)) # [1 2 3 4 5 6]
To answer your second question, TensorFlow reshape operation use the same order than numpy default order, a.k.a C order, quoting from here:
Read the elements of a using this index order, and place the elements into the reshaped array using this index order. ā€˜Cā€™ means to read / write the elements using C-like index order, with the last axis index changing fastest, back to the first axis index changing slowest.
import numpy as np
a = np.array([1, 3, 5])
b = np.array([2, 4, 6])
c = np.stack([a, b], axis=1)
c.reshape((-1,), order='C') # array([1, 2, 3, 4, 5, 6])

Concatenate two NumPy arrays vertically

I tried the following:
>>> a = np.array([1,2,3])
>>> b = np.array([4,5,6])
>>> np.concatenate((a,b), axis=0)
array([1, 2, 3, 4, 5, 6])
>>> np.concatenate((a,b), axis=1)
array([1, 2, 3, 4, 5, 6])
However, I'd expect at least that one result looks like this
array([[1, 2, 3],
[4, 5, 6]])
Why is it not concatenated vertically?
Because both a and b have only one axis, as their shape is (3), and the axis parameter specifically refers to the axis of the elements to concatenate.
this example should clarify what concatenate is doing with axis. Take two vectors with two axis, with shape (2,3):
a = np.array([[1,5,9], [2,6,10]])
b = np.array([[3,7,11], [4,8,12]])
concatenates along the 1st axis (rows of the 1st, then rows of the 2nd):
np.concatenate((a,b), axis=0)
array([[ 1, 5, 9],
[ 2, 6, 10],
[ 3, 7, 11],
[ 4, 8, 12]])
concatenates along the 2nd axis (columns of the 1st, then columns of the 2nd):
np.concatenate((a, b), axis=1)
array([[ 1, 5, 9, 3, 7, 11],
[ 2, 6, 10, 4, 8, 12]])
to obtain the output you presented, you can use vstack
a = np.array([1,2,3])
b = np.array([4,5,6])
np.vstack((a, b))
array([[1, 2, 3],
[4, 5, 6]])
You can still do it with concatenate, but you need to reshape them first:
np.concatenate((a.reshape(1,3), b.reshape(1,3)))
array([[1, 2, 3],
[4, 5, 6]])
Finally, as proposed in the comments, one way to reshape them is to use newaxis:
np.concatenate((a[np.newaxis,:], b[np.newaxis,:]))
If the actual problem at hand is to concatenate two 1-D arrays vertically, and we are not fixated on using concatenate to perform this operation, I would suggest the use of np.column_stack:
In []: a = np.array([1,2,3])
In []: b = np.array([4,5,6])
In []: np.column_stack((a, b))
array([[1, 4],
[2, 5],
[3, 6]])
A not well known feature of numpy is to use r_. This is a simple way to build up arrays quickly:
import numpy as np
a = np.array([1,2,3])
b = np.array([4,5,6])
c = np.r_[a[None,:],b[None,:]]
print(c)
#[[1 2 3]
# [4 5 6]]
The purpose of a[None,:] is to add an axis to array a.
a = np.array([1,2,3])
b = np.array([4,5,6])
np.array((a,b))
works just as well as
np.array([[1,2,3], [4,5,6]])
Regardless of whether it is a list of lists or a list of 1d arrays, np.array tries to create a 2d array.
But it's also a good idea to understand how np.concatenate and its family of stack functions work. In this context concatenate needs a list of 2d arrays (or any anything that np.array will turn into a 2d array) as inputs.
np.vstack first loops though the inputs making sure they are at least 2d, then does concatenate. Functionally it's the same as expanding the dimensions of the arrays yourself.
np.stack is a new function that joins the arrays on a new dimension. Default behaves just like np.array.
Look at the code for these functions. If written in Python you can learn quite a bit. For vstack:
return _nx.concatenate([atleast_2d(_m) for _m in tup], 0)
Suppose you have 3 NumPy arrays (A, B, C). You can contact these arrays vertically like this:
import numpy as np
np.concatenate((A, B, C), axis=1)
np.shape

Flattening an array only one layer?

Is there any built-in numpy function that would get:
a=np.asarray([[[1,2],[3,4]],[[1,2],[3,4]]])
And would return:
b=[[1,2],[3,4],[1,2],[3,4]]
? Something like like one layer flattening.
P.S. I am looking for a vectorized option otherwise this dumb code is available:
flat1D(a):
b=np.array([])
for item in a:
b=np.append(b,item)
return b
You can simply reshape the array.
>>> a.reshape(-1,a.shape[-1])
array([[1, 2],
[3, 4],
[1, 2],
[3, 4]])
The shown code returns a 1D array, to do this:
>>> a.ravel()
array([1, 2, 3, 4, 1, 2, 3, 4])
Or, if you are sure you want to copy the array:
>>> a.flatten()
array([1, 2, 3, 4, 1, 2, 3, 4])
The difference between ravel and flatten primarily comes from the fact that flatten will always return a copy and ravel will return a view if possible and a copy if not.
if you know the dimensions of the new array you can specify these as a tuple (4,2) and use .reshape()
a.reshape((4,2))

Categories

Resources