How to multiply a tensor with a vector? - python

I have 2 tensors
a = torch.tensor([1,2])
b = torch.tensor([[[10,20],
[30,40]],
[[1,2],
[3,4]]])
and I would like to combine them in such a way that
a ? b = tensor([[[10,20],
[30,40]],
[[ 2, 4],
[ 6, 8]]])
(and then sum over the 0th dimension, in the end I want to do a weighted sum)
I've tried:
""" no idea how to interpret that """
a # b
tensor([[ 70, 100],
[ 7, 10]])
b # a
tensor([[ 50, 110],
[ 5, 11]])
for i in range(b.size()[0]): # works but I don't think this will work with autograd
b[i] *= a[i]
a * b # multiplies right side by 2
tensor([[[10, 40],
[30, 80]],
[[ 1, 4],
[ 3, 8]]])
a.unsqueeze(1) # multiplies bottom side by 2
tensor([[[10, 20],
[60, 80]],
[[ 1, 2],
[ 6, 8]]])
a.unsqueeze(2) * b # dimension out of range

This should workc = a.unsqueeze(1).unsqueeze(1) * b

You can also try below code:
a = torch.tensor([1,2])
b = torch.tensor([[[10,20],
[30,40]],
[[1,2],
[3,4]]])
print((a.view(-1, 1)*torch.flatten(b, 1)).view(b.shape))
output:
tensor([[[10, 20],
[30, 40]],
[[ 2, 4],
[ 6, 8]]])
Here, we are basically carrying out below steps:
Reshaping a to a 2d tensor of size [a.shape[0],1], i.e. [2, 1] in above case.
Then, we are using torch.flatten() to flatten tensor b starting from the first dimension(i.e. start_dim=1). Here, end_dim=-1 by default. Resultant size is [2, 4].
Performing element-wise multiplication.
Finally, reshaping the result to shape same as original tensor b, i.e [2, 2, 2].

Interesting -- I tried a few different broadcasting tricks and didn't see any obvious wins, so the simple version:
b[0] *= a[0]
b[1] *= a[1]
c = b

Related

Numpy: Replacing part of array by another entire array based on selected index

I have two np array A and B and one index list, where:
A = np.arange(12).reshape(3,2,2)
>>> A
array([[[ 0, 1],
[ 2, 3]],
[[ 4, 5],
[ 6, 7]],
[[ 8, 9],
[10, 11]]])
>>> B:
array([[[10, 10],
[10, 10]],
[[20, 20],
[20, 20]]])
index_list = [0,2]
I would like to replace array A by entire array B based on index the index_list gives, which is 0 and 2 (corresponding to A's index at axis=0):
# desired output:
array([[[ 10, 10],
[ 10, 10]],
[[ 4, 5],
[ 6, 7]],
[[ 20, 20],
[20, 20]]])
I have been thinking about implementing this process in a more efficient way, but only come up with two loops:
row_count = 0
for i,e in enumerate(A):
for idx in index_list:
if i == idx:
A[i,:,:] = B[row_count,:,:]
row_count += 1
which is computational expensive because I have two huge np arrays to process... it would be very appreciated if anyone have any idea of how to implement this process in vectorization way or in a more efficient way. Thanks!
Have you tried just assigning like this:
A[index_list[0]] = B[0]
A[index_list[1]] = B[1]
I guess if you had a bigger number of indexes in the index_list, and more to replace, you could then make a loop.

view_as_windows on 4d array

Given an ndarray of shape (batch_size, w, h, c), and a patch size (p, p), I want to extract patches from each 3D matrix (i.e. shape (p, p, c). No patches will overlap, so the stride can be thought of as p.
This should return an array with (batch_size * p * p, p, p, c)
Using skimage.view_as_windows here is a minimal example
import numpy as np
import skimage
a = np.arange(8*8*2).reshape((8, 8, 2))
b = a * 2
c = np.concatenate((a[np.newaxis, :, :, :], b[np.newaxis, :, :, :]), axis = 0)
d = skimage.util.view_as_windows(c, 2, step = 2).reshape((8*2*2, 2, 2, 2))
However, only the alternate values are what I expect:
d[0]
Out[183]:
array([[[ 0, 1],
[ 2, 3]],
[[16, 17],
[18, 19]]])
d[1]
Out[184]:
array([[[ 0, 2],
[ 4, 6]],
[[32, 34],
[36, 38]]])
d[2]
Out[185]:
array([[[ 4, 5],
[ 6, 7]],
[[20, 21],
[22, 23]]])
d[3]
Out[186]:
array([[[ 8, 10],
[12, 14]],
[[40, 42],
[44, 46]]])
d[4]
Out[187]:
array([[[ 8, 9],
[10, 11]],
[[24, 25],
[26, 27]]])
Thus, d[::2] is close to my solution but half the values are lost
I am not sure if the problem is the window size or the step, or even if my problem is possible using view_as_windows, so I am open to any efficient suggestion.
First, I think you mean to return a volume of shape (batch_size * w/p * h/p, p, p, c)? i.e., if the patches are non-overlapping, then the product of the dimensions should be the same pre- and post-patching.
Having gotten that out of the way, here's my attempt. I'm changing the batch size and channel dimensions to make it clearer which is which.
import numpy as np
from skimage import util
batch = np.arange(4*8*8*3).reshape((4, 8, 8, 3))
blocked = util.view_as_blocks((1, 2, 2, 3))
patches = blocked.reshape((64, 2, 2, 3))
print(patches[0].transpose((2, 0, 1)))
print(patches[1].transpose((2, 0, 1)))
which gives:
[[[0 1]
[8 9]]
[[0 1]
[8 9]]
[[0 1]
[8 9]]]
and
[[[ 2 3]
[10 11]]
[[ 2 3]
[10 11]]
[[ 2 3]
[10 11]]]
Unfortunately, the reshape triggers a copy. I'm not sure whether there is a way to avoid it, but hopefully this is not your main computational/memory concern.

How to add a dimension to a numpy array in Python

I have an array that is size (214, 144). I need it to be (214,144,1) is there a way to do this easily in Python? Basically the dimensions are supposed to be (Days, Times, Stations). Since I only have 1 station's data that dimension would be a 1. However if I could also make the code flexible enough work for say 2 stations that would be great (e.g. changing the dimension size from (428,288) to (214,144,2)) that would be great!
You could use reshape:
>>> a = numpy.array([[1,2,3,4,5,6],[7,8,9,10,11,12]])
>>> a.shape
(2, 6)
>>> a.reshape((2, 6, 1))
array([[[ 1],
[ 2],
[ 3],
[ 4],
[ 5],
[ 6]],
[[ 7],
[ 8],
[ 9],
[10],
[11],
[12]]])
>>> _.shape
(2, 6, 1)
Besides changing the shape from (x, y) to (x, y, 1), you could use (x, y/n, n) as well, but you may want to specify the column order depending on the input:
>>> a.reshape((2, 3, 2))
array([[[ 1, 2],
[ 3, 4],
[ 5, 6]],
[[ 7, 8],
[ 9, 10],
[11, 12]]])
>>> a.reshape((2, 3, 2), order='F')
array([[[ 1, 4],
[ 2, 5],
[ 3, 6]],
[[ 7, 10],
[ 8, 11],
[ 9, 12]]])
1) To add a dimension to an array a of arbitrary dimensionality:
b = numpy.reshape (a, list (numpy.shape (a)) + [1])
Explanation:
You get the shape of a, turn it into a list, concatenate 1 to that list, and use that list as the new shape in a reshape operation.
2) To specify subdivisions of the dimensions, and have the size of the last dimension calculated automatically, use -1 for the size of the last dimension. e.g.:
b = numpy.reshape(a, [numpy.size(a,0)/2, numpy.size(a,1)/2, -1])
The shape of b in this case will be [214,144,4].
(obviously you could combine the two approaches if necessary):
b = numpy.reshape (a, numpy.append (numpy.array (numpy.shape (a))/2, -1))

Multiplying NumPy arrays by scalars

I have a NumPy array of shape (2,76020,2). Basically it is made of two columns containing 76020 rows each, and each row has two entries.
I want to multiply each column by a different weight, say column 1 by 3 and column 2 by 5. For example:
m =
[3,4][5,8]
[1,2][2,2]
a = [3,5]
I want:
[9,12][25,40]
[3,6][10,10]
I thought I could just multiply m*a, but that gives me instead:
[9,20][15,40]
[3,10][6,10]
How can I write this multiplication?
It's a problem of broadcasting: you must align the dimensions to multiply, here the second:
m = array(
[[[3,4],[5,8]],
[[1,2],[2,2]]])
a = array([3,5])
print(a[None,:,None].shape, m*a[None,:,None])
"""
(1, 2, 1)
[[[ 9 12]
[25 40]]
[[ 3 6]
[10 10]]]
"""
As #B.M. says, this is a 'array broadcasting' issue. (The idea behind his answer is correct, but I think his and the OP's dimensions aren't matching up correctly.)
>>> m = np.array([[[3,4],[5,8]],[[1,2],[2,2]]])
>>> print(m)
[[[3 4]
[5 8]]
[[1 2]
[2 2]]]
>>> print(m.shape)
(2, 2, 2)
>>> a = np.array([3,5])
>>> print(a.shape)
(2,)
We need the shapes of m and a to match, so we have to 'broadcast' a to the correct shape:
>>> print(a[:, np.newaxis, np.newaxis].shape)
(2, 1, 1)
>>> b = a[:, np.newaxis, np.newaxis] * m
>>> print(b)
[[[ 9 12]
[15 24]]
[[ 5 10]
[10 10]]]
In this way the first dimension of a is preserved, and maps to each element of the first dimension of m. But there are also two new dimensions ('axes') created to 'broadcast' into the other two dimensions of m.
Note: np.newaxis is (literally) None, they have the same effect. The former is more readable to understand what's happening. Additionally, just in terms of standard terminology, the first dimension (axis) is generally referred to as the 'rows', and the second axis the 'columns'.
Your description is ambiguous
Basically it is made of two columns containing 76020 rows each, and each row has two entries.
In (2,76020,2), which 2 is columns, and which is entries?
I believe your m is (that display is also ambiguous)
In [8]: m
Out[8]:
array([[[3, 4],
[5, 8]],
[[1, 2],
[2, 2]]])
In [9]: m*a
Out[9]:
array([[[ 9, 20],
[15, 40]],
[[ 3, 10],
[ 6, 10]]])
That's the same as m*a[None,None,:]. When broadcasting, numpy automatically adds dimensions at the beginning as needed. Or iteratively:
In [6]: m[:,:,0]*3
Out[6]:
array([[ 9, 15],
[ 3, 6]])
In [7]: m[:,:,1]*5
Out[7]:
array([[20, 40],
[10, 10]])
Since m is (2,2,2) shape, we can't off hand tell which axis a is supposed to multiply.
According to the accepted answer, you want to multiply along the middle axis
In [16]: m*a[None,:,None]
Out[16]:
array([[[ 9, 12],
[25, 40]],
[[ 3, 6],
[10, 10]]])
But what if m was (2,3,2) in shape? a would then have to have 3 values
In [17]: m=np.array([[[3,4],[5,8],[0,0]],[[1,2],[2,2],[1,1]]])
In [18]: m*a[None,:,None]
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-18-f631c33646b7> in <module>()
----> 1 m*a[None,:,None]
ValueError: operands could not be broadcast together with shapes (2,3,2) (1,2,1)
The alternative broadcastings work
In [19]: m*a[:,None,None]
Out[19]:
array([[[ 9, 12],
[15, 24],
[ 0, 0]],
[[ 5, 10],
[10, 10],
[ 5, 5]]])
In [20]: m*a[None,None,:]
Out[20]:
array([[[ 9, 20],
[15, 40],
[ 0, 0]],
[[ 3, 10],
[ 6, 10],
[ 3, 5]]])
Now if m had distinct dimensions, e.g. (3,1000,2), we could tell at a glance with axis a 2 element weight array would work with.

Create array of outer products in numpy

I have an array of n vectors of length m. For example, with n = 3, m = 2:
x = array([[1, 2], [3, 4], [5,6]])
I want to take the outer product of each vector with itself, then concatenate them into an array of square matrices of shape (n, m, m). So for the x above I would get
array([[[ 1, 2],
[ 2, 4]],
[[ 9, 12],
[12, 16]],
[[25, 30],
[30, 36]]])
I can do this with a for loop like so
np.concatenate([np.outer(v, v) for v in x]).reshape(3, 2, 2)
Is there a numpy expression that does this without the Python for loop?
Bonus question: since the outer products are symmetric, I don't need to m x m multiplication operations to calculate them. Can I get this symmetry optimization from numpy?
Maybe use einsum?
>>> x = np.array([[1, 2], [3, 4], [5,6]])
>>> np.einsum('ij...,i...->ij...',x,x)
array([[[ 1, 2],
[ 2, 4]],
[[ 9, 12],
[12, 16]],
[[25, 30],
[30, 36]]])
I used the following snippet when I was trying to do the same in Theano:
def multiouter(A,B):
'''Provided NxK (Theano) matrices A and B it returns a NxKxK tensor C with C[i,:,:]=A[i,:]*B[i,:].T'''
return A.dimshuffle(0,1,'x')*B.dimshuffle(0,'x',1)
Doing a straighforward conversion to Numpy yields
def multiouter(A,B):
'''Provided NxK (Numpy) arrays A and B it returns a NxKxK tensor C with C[i,:,:]=A[i,:]*B[i,:].T'''
return A[:,:,None]*B[:,None,:]
I think I got the inspiration for it from another StackOverflow posting, so I am not sure I can take all the credit.
Note: indexing with None is equivalent to indexing with np.newaxis and instantiates a new axis with dimension 1.

Categories