How do we index a tensor in python? - python

I'm trying to understand the following code.
content_array[:, :, :, 0] -= 103.939
content_array[:, :, :, 1] -= 116.779
content_array[:, :, :, 2] -= 123.68
content_array = content_array[:, :, :, ::-1]
style_array[:, :, :, 0] -= 103.939
style_array[:, :, :, 1] -= 116.779
style_array[:, :, :, 2] -= 123.68
style_array = style_array[:, :, :, ::-1]
content_array and style_array are arrays with dimensions of
(1, 512, 512, 3) respectively.
What i don't really understand is the indexing([:, :, :, 0], [:, :, :, 1], [:, :, :, 2]). Does this means we are indexing each dimension? and why do we use ':'?

One of numpy's most interesting indexing features, is the ability to index slices. Slices are subarrays in a given dimensions, they are written in the form of i:j:k where i is the starting index, j the ending (not included), and k the step. Specifying all 3 parameters would be tedious most of the time, that's why they all have default values. i=0, j=n where n is the length of the array, k=1. Therefore selecting all the elements along a dimension would come down to writting array[::] for which a syntactic sugar is array[:].
Therefore content_array[:, :, :, 0] is an array of dimension (1, 512, 512). And writing content_array[:, :, :, 0] -= 103.939 means set all the values of the array taken by selecting all the elements such that they have index 0 on last dimension, and decrement all these elements by 103.939.
I would recommend that you read https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html.

Related

Fancy indexing for numpy arrary

I want to sample len(valid_frame_id_ls) frame from data by fancy indexing for numpy arrary. But I received an error message when i run code1. I don't know why the shape of data[n, :, valid_frame_id_ls, :, :] is not equal to the shape of new_data[n, :, :len(valid_frame_id_ls), :, :].Can anyone help me solve this bug. help...
I modify my code and write in code2 block. I did't receive any error message when i run code2. I don't know why code2 is correct.
code1:
data = np.random.random((2, 3, 50, 25, 1))
N, C, T, V, M = data.shape
new_data = np.zeros((N, C, T, V, M))
valid_frame_id_ls = [2, 3, 4, 5, 6]
for n in range(N):
new_data[n, :, :len(valid_frame_id_ls), :, :] = data[n, :, valid_frame_id_ls, :, :]
# code1 error message:
new_data[n, :, :len(valid_frame_id_ls), :, :] = data[n, :, valid_frame_id_ls, :, :]
ValueError: could not broadcast input array from shape (5,3,25,1) into shape (3,5,25,1)
code2:
data = np.random.random((2, 3, 50, 25, 1))
N, C, T, V, M = data.shape
new_data = np.zeros((N, C, T, V, M))
valid_frame_id_ls = [2, 3, 4, 5, 11]
for n in range(N):
new_data[n][:, :len(valid_frame_id_ls), :, :] = data[n][ :, valid_frame_id_ls, :, :]
https://numpy.org/doc/stable/reference/arrays.indexing.html#combining-advanced-and-basic-indexing
As described in this section of the docs, putting a slice in the middle of 'advanced' indexing results in an unexpected rearrangement of dimensions. Your size 5 dimension has been placed first, and the other dimensions after.
This has come up occasionally on SO as well. With a scalar n this really shouldn't be happening, but apparently the issue occurs deep in the indexing, and isn't easily corrected.
data[n][ :, valid_frame_id_ls, :, :]
breaks up the indexing, so the first ':' is no longer in the middle.
Another fix is to replace the slice with an equivalent array. Now both sides will have the same dimensions.
new_data[n, :, np.arange(len(valid_frame_id_ls)), :, :] = data[n, :, valid_frame_id_ls, :, :]
Though in this case I don't think you need to iterate on N at all:
new_data[:,:,:len(valid_frame_id_ls),:,:] = data[:,:, valid_frame_id_ls, :,:]

Numpy Slicing - Calculate Matrix PseudoInverses without Iteration from 3x3 array

I have N, 2x4 arrays stored in a (2x4xN) array J. I am trying to calculate the pseudoinverse for each of the N, 2x4 arrays, and save the pseudoinverses to a (N x 4 x 2) array J_pinv.
What I'm currently doing:
J_pinvs = np.zeros((N, 4, 2))
for i in range(N):
J_pinvs[i, :, :] = np.transpose(J[:, :, i]) # np.linalg.inv(J[:, :, i] # J[:, :, i].transpose())
This works but I would like to speed up the compute time as this will be running in a layer of a neural network so I would like to make it as fast as possible.
What I've tried:
J_pinvs = np.zeros((N, 4, 2))
J_pinvs2[:, :, :] = np.transpose(J[:, :, :]) # np.linalg.inv(J[:, :, :] # J[:, :, :].transpose())
Generates the error:
<ipython-input-87-d8ee1ba2ae5e> in <module>
1 J_pinvs2 = np.zeros((4, 2, 3))
----> 2 J_pinvs2[:, :, :] = np.transpose(J[:, :, :]) # np.linalg.inv(J[:, :, :] # J[:, :, :].transpose())
ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 4 is different from 3)
Is there a way to do this with slicing so that I don't need to use an iterator? I'm having trouble finding anything online. Any help/suggestions would be appretiated!
Thanks,
JM
I think you need to specify how to transpose a 3-D array:
np.linalg.inv(a # a.transpose(0,2,1))
will work. As oppose to
# sample data
a = np.arange(24).reshape(-1,2,4)
a.shape
# (3, 2, 4)
a.transpose().shape
# (4, 2, 3)
and
a # a.transpose()
will not work.
Finally, the whole script should be:
a.transpose(0,2,1) # np.linalg.inv(a # a.transpose(0,2,1))

How to create a Numpy Index with colons everywhere except at one variable coordinate?

I would like to create an index in the form of
[:, :, :, 0, :, :, :, :]
where the position of 0 is determined by a variable, say axis to slice a NumPy array. Obviously there are two special cases that are easy to treat:
axis = 0 would be equivalent to [0, ...]
axis = -1 would be equivalent to [..., 0]
But I wonder how this can be done for any axis value?
You can create a tuple and use slice(None) in place of ::
def custom_index(arr, position, index):
idx = [slice(None)] * len(arr.shape)
idx[position] = index
return arr[tuple(idx)]
Quick test:
mat = np.random.random((5, 3))
assert np.all(mat[2, :] == custom_index(mat, 0, 2)) # mat[(2, slice(None))]
assert np.all(mat[:, 2] == custom_index(mat, 1, 2)) # mat[(slice(None), 2))]
EDIT: as pointed out in the comment, the proper way is np.take

Array Operations to augment image Python cv2 using numpy

Given X is a Numpy Array X.shape =(1, 96, 96, 3), Basically an Image read from CV2 . I am looking for simpler articulation of a augment operation.
Could you please explain what the following lines of code does
b=X[:, ::-1, :, :]
c=X[:, ::-1, ::-1, :]
d=X[:, :, ::-1, :]
X[::-1] indexing applies: indices of X from first to last in steps of -1.
b=X[:, ::-1, :, :] - Reverse image up/down.
c=X[:, ::-1, ::-1, :] - Reverse image up/down and left/right.
d=X[:, :, ::-1, :] - Reverse image left/right.
Remark:
:: is not an operator, it's actually two : operators one after the other.
X[::-1] is the same as X[ : : -1].
Refer to Indexing documentation.
The basic slice syntax is i:j:k where i is the starting index, j is the stopping index, and k is the step.
If i is not given it defaults to 0
If j is not given it defaults to n
Writing [: : -1], omits i and j, and sets k to -1.
The syntax means: "from index 0, take all elements, with step -1", that gives all elements in reverse order (all elements along this axis).
Example:
import cv2
import numpy as np
# Build input:
im = cv2.imread('chelsea.png')
im = cv2.resize(im, (96, 96))
X = np.empty((1, im.shape[0], im.shape[1], im.shape[2])).astype(np.uint8)
X[0, :, :, :] = im
b = X[:, ::-1, :, :]
c = X[:, ::-1, ::-1, :]
d = X[:, :, ::-1, :]
Result:
im:
b:
c:
d:
Note:
I kind of ignored the fist index because the dimension is 1.
In case of multiple frames, it's common for the fist index to apply the number of frames.

How to replace certain values in Tensorflow tensor with the values of the other tensor?

I have a Tensorflow tensor A of size (64, 2, 82, 1), and I want to replace its (:, :, 80:82, :) part with the corresponding part of the tensor B (also (64, 2, 82, 1) size).
How would I do that?
P.S.: To be precise, I mean the operation that would look like this in the numpy:
A[:, :, 80:82, :] = B[:, :, 80:82, :]
the following code might help you to get some idea,
a = tf.constant([[11,0,13,14],
[21,22,23,0]])
condition = tf.equal(a, 0)
case_true = tf.reshape(tf.multiply(tf.ones([8], tf.int32), -9999), [2, 4])
case_false = a
a_m = tf.where(condition, case_true, case_false)
sess = tf.Session()
sess.run(a_m)
here i am accessing individual element of a tensor!
tf.assign should work: (not tested)
tf.assign(A[:, :, 80:82, :], B[:, :, 80:82, :])

Categories