Sanity Check on Numpy Dimensions? - python

Just wanted to make sure I'm seeing what I'm seeing in numpy.
In english terms, I want to create an array with a height of 2, width of 3, and a depth of four.
I would assume that the shape would be (2,3,4) following logical order, but when I create the array, the shape turns out to be (4,2,3).
some = np.array([[[1,2,3],[4,5,6]], [[5,6,7],[8,9,10]],[[5,6,7],[8,9,10]],[[5,6,7],[8,9,10]]])
# some.shape = (4,2,3), not what I expect (2,3,4)
Can someone explain how the dimensions are ordered in python?

Related

How to concatenate tensor to another list of tensor in pytorch?

I have a tensor of shape "torch.Size([2, 2, 3])" and another tensor of shape "torch.Size([2, 1, 3])". I want a concatenated tensor of shape "torch.Size([2, 2, 6])".
For example :
a=torch.tensor([[[2,3,5],[12,13,15]],[[20,30,50],[120,130,150]]])
b=torch.tensor([[[99,99,99]],[[999,999,999]]])
I want the output as : [[[99,99,99,2,3,5],[99,99,99,12,13,15]],[[999,999,999,20,30,50],[999,999,999,120,130,150]]]
I have written a O(n2) solution using two for loops but,
This is taking a lot of time with millions of calculation, Does anyone help me in doing this efficiently ?? May be some matrix calculation trick for tensors ??
To exactly match the example you have provided:
c = torch.cat([b.repeat([1,a.shape[1]//b.shape[1],1]),a],2)
The reasoning behind this is that the concatenate operation in pytorch (and numpy and other libraries) will complain if the dimensions of the two tensors in the non-specified axes (in this case 0 and 1) do not match. Therefore, you have to repeat the tensor along the non-matching axis (the first axis, therefore the second element of the repeat list) in order to make the dimensions align. Note that the solution here will only work if the middle dimension of a is evenly divisible by the middle dimension of b.
In newer versions of pytorch, this can also be done using the torch.tile() function.

Slicing a mesh of unknown dimensions

I'm trying to do a grid search over a model I've trained. So, producing a mesh, then predicting that mesh with the model to find a maximum.
I'm producing the mesh with:
def generate_random_grid(n_scanning_parameters,n_points_each_dimension):
points=np.linspace(1,0,num=n_points_each_dimension,endpoint=False)
x_points=[points for dimension in range(n_scanning_parameters)]
mesh=np.array(np.meshgrid(*x_points))
return mesh
As you can see, I don't know the dimensions in advance. So later when I want to index the mesh to predict different points, I don't know how to index.
E.g, if I have 4 dimensions and 10 points along each dimension, the mesh has the shape (4,10,10,10,10). And I need to access points like e.g. [:,0,0,0,0] or [:,1,2,3,4]. Which would give me a 1-D vector with 4 elements.
Now I can produce the 4 last indices using
for index in np.ndindex(*mesh.shape[1:]):
, but then indexing my mesh like mesh[:,index] doesn't result in a 1-D vector with 4 elements as I expect it to.
How can I index the mesh?
Since you're working with tuples, and numpy supports tuple indexing, let's start with that.
Effectively, you want to do your slicing like a[:, 0, 0, 0, 0]. But your index is a tuple, and you're attempting something like a[:, (0,0,0,0)] - this gives you four hyperplanes along the second dimension instead. Your indexing should be more like a[(:,0,0,0,0)] - but this gives a syntax error.
So the solution would be to use the slice built-in.
a[(slice(None),0,0,0,0)]
This would give you your one dimensional vector.
In terms of your code, you can simply add the tuples to make this work.
for index in np.ndindex(*mesh.shape[1:]):
vector = mesh[(slice(None), ) + index]
An alternative approach would be to simply use a transposed array and reversed indices. The first dimension is at the end, removing the need for :.
for index in np.ndindex(*mesh.shape[1:]):
vector = mesh.T[index[::-1]]

Matrix multiplication over specific dimensions in tensorflow (or numpy)

I hope I'm not missing anything obvious here, but I've scoured the inter-webs to no avail, and finally come to ask here...
Here's a really dry and simple description of what I'd like to do:
Say I've got a tensor of shape (20, 40, 3, 5), and another tensor of shape (20, 40, 5, 7). The first two dimension sizes are to be kept as are, and are purposely identical for the two tensors. The last two dimensions on the other hand, are to be (matrix-)multiplied, matmul style. Meaning my resulting tensor would be of shape (20, 40, 3, 7). How can that be done??
I realize I can theoretically just loop over the first two dimensions and use tf.matmul() directly, but that's an absolute no-go due to runtime, efficiency, model-trainer and GPU world-wide protests, and my conscience if that's of any weight :-).
I've unfortunately disregarded as "not what I need" the following options:
tf.tensordot would give me an output of shape (20, 40, 3, 20, 40, 7). No good.
tf.scan is only good for the first dimension if I'm reading it correctly (suitable for RNNs maybe? Not my case anyhow).
tf.matmul works for tensors of rank >= 2, but works like # over the last and first dimensions respectively. Again, not my case.
So again - how can this be done?
A numpy answer that helps me get in the right direction would also be very helpful, but I'll need a tf implementation at the end of the day.
Thanks in advance, and sorry if I'm missing something dumb.
The following is closer to what I need, but less clear and so is being written separately:
The first two dimensions are spatial dimensions of an image. The last two are actually square matrices, obtained via tf.contrib.distributions.fill_triangular, and are being multiplied (along with an appropriate transpose on one of them) to obtain covariance matrices associated to each spatial coordinate. I don't know if that helps in any way, but it gives some context at the very least. Also, there might or might not be a batch dimension as well, but I'm assuming that solving the 4-D tensor case would be generalizable enough.
Posting this for future reference:
From numpy matmul doc:
If either argument is N-D, N > 2, it is treated as a stack of matrices
residing in the last two indexes and broadcast accordingly.
For dimensions >2 it will treat it as a stack of matrices, attempting to matmul the last 2 dimensions, resulting with a np array as the OP required.
For example:
import numpy as np
A = np.ones((1,2,1,2))
B = np.ones((1,2,2,1))
print(A.shape)
print(B.shape)
print(np.matmul(A,B).shape)
with result:
(1, 2, 1, 2)
(1, 2, 2, 1)
(1, 2, 1, 1)

adding new axes to facilitate broadcast, a better way?

I am looking for a nice way to "clean up" the dimensions of two arrays which I would like to combine together using broadcasting.In particular I would like to broadcast a one dimensional array up to the shape of a multidimensional array and then add the two arrays. My understanding of the broadcasting rules tells me that this should work find if the last dimension of the multidimensional array matches that of the one dimensional array. For example, arrays with shapes (,3) and (10,3) would add fine
My problem is, given how the array I have is built the matching dimension happens to be the first dimension of the array so the broadcasting rules are not met. For reference my one d array has shape (,3) and the multi-dimensional array is (3,10,10,50).
I could correct this by reshaping the multi-dimensional array so that the compatible dimension is the last dimension but I'd like to avoid this as I find the logic of reshaping tricky to follow when the different dimensions have specific meaning.
I can also add empty dimensions to the one dimensional array as in the code below until the one dimensional array has as many dimensions as the high dimensional array as in the code snippet below.
>>> import numpy as np
>>> a = np.array([[1,2],
>>> [3,4],
>>> [5,6]])
>>> b = np.array([10,20,30])
>>> a+b[:,None]
array([[11, 12],
[23, 24],
[35, 36]])
This gives me my desired output however in my case my high dimensional array has 4 different axes so I would need to add in multiple empty dimensions which starts to feel inelegant. I can do something like
b = b[[slice(None)] + 3*[np.newaxis]]
and then proceed but that doesn't seem great. More generally one could imagine needing an arbitrary number of new axes on both sides of the original one dimension and writing a helper function to generalize the above logic. Is there a nicer/clearer way to achieve this?

How to assign values of a 2d array to 3d array in NumPy

I'm currently working on a 3d array called X of size (100,5,1). I want to assign the randomly created 2d arrays called s, dimension of (5,1) to X. My code is like below.
for i in range(100):
s = np.random.uniform(-1, 2, 5)
for j in range(5):
X[:,j,:] = s[j]
I got 100 (5,1) arrays and they're all the same. I can see why I have this result, but I can't find the solution for this.
I need to have 100 unique (5,1) arrays in X.
You are indexing the entire first dimension and thus broadcasting a single 5 x 1 array. This is why you are seeing copies and it only remembers the last randomly generated 5 x 1 array you've created in the loop seen over the entire first dimension. To fix this, simply change the indexing from : to i.
X[i,j,:] = s[j]
However, this seems like a bad code smell. I would recommend allocating the exact size you need in one go by overriding the size input parameter into numpy.random.uniform.
s = np.random.uniform(low=-1, high=2, size=(100, 5, 1))
Therefore, do not loop and just use the above statement once. This makes sense as each 5 x 1 array you are creating is sampled from the same probability distribution. It would make more sense in an efficiency viewpoint to just allocate the desired size once.

Categories

Resources