fastest way to stack ndarrays - python

Gist
Basically I want to perform an increase in dimension of two axes on a n-dimensonal tensor.
For some reason this operation seems very slow on bigger tensors.
If someone can give me a reason or better method I'd be very happy.
Goal
Going from (4, 8, 8, 4, 4, 4, 4, 4, 16, 8, 4, 4, 1) to (4, 32, 8, 4, 4, 4, 4, 4, 4, 8, 4, 4, 1) takes roughly 170 second. I'd like to improve on that. Below is an example, finding the correct indices is not necessary here.
Example Code
Increase dimension (0,2) of tensor
tensor = np.arange(16).reshape(2,2,4,1)
I = np.identity(4)
I tried 3 different methods:
np.kron
indices = [1,3,0,2]
result = np.kron(
I, tensor.transpose(indices)
).transpose(np.argsort(indices))
print(result.shape) # should be (8,2,16,1)
manual stacking
col = []
for i in range(4):
row = [np.zeros_like(tensor)]*4
row[i]=tensor
col.append(a)
result = np.array(col).transpose(0,2,3,1,4,5).reshape(8,2,16,1)
print(result.shape) # should be (8,2,16,1)
np.einsum
result =np.einsum("ij, abcd -> iabjcd", I, tensor).reshape(8,2,16,1)
print(result.shape) # should be (8,2,16,1)
Results
On my machine they performed the following (on the big example with complex entries):
np.einsum ~ 170s
manual stacking ~ 185s
np.kron ~ 580s

As Jérôme pointed out:
all your operations seems to involve a transposition which is known to be very expensive on modern hardware.
I reworked my algorithm to not rely on the dimensional increase by doing certain preprocessing steps. This indeed speeds up the overall process substantially.

Related

Taking away from numpy ndarray from another

I have two numpy.ndarrays which one is a random sample from the other. I wish to take the smaller one (random sample) and remove those data points from the larger one.
What is the code to do so?
delete and remove do not work on ndarrays
Thank you
Maybe this can help:
a = np.array([1, 2, 3, 2, 4, 1])
b = np.array([3, 4, 5, 6])
np.setdiff1d(a, b) # array([1, 2])
From here.

Perform tf.signal.fft2d in the middle of the tensor

I have a tf.Tensor of, for example, shape (31, 6, 6, 3).
I want to perform tf.signal.fft2d on the shapes 6, 6 so, in other words, in the middle. However, the description says:
Computes the 2-dimensional discrete Fourier transform over the inner-most 2 dimensions of input
I could do it with a for loop but I fear it might be very ineffective. Is there a fastest way?
The result must have the same output shape of course.
Thanks to this I implemented this solution using tf.transpose:
in_pad = tf.transpose(in_pad, perm=[0, 3, 1, 2])
out = tf.signal.fft2d(tf.cast(in_pad, tf.complex64))
out = tf.transpose(out, perm=[0, 2, 3, 1])

Quickify splitting of Data into rows via Numpy: Pieces of Data based on the row index

I'm working with wav files at the moment and want to split up the data array with all channels into a matrix, where every row is the specific channel data.
I have the data array like so, and wish the following matrix format:
data = [channel1_frame1, channel2_frame1, ..., channeln_frame1, channel1_frame2, ...] # integers
matrix = [[channel1_frame1, channel1_frame2, channel1_frame3,...],
[channel2_frame1, channel2_frame2, channel2_frame3,...]
...
[channeln_frame1, channeln_frame2, channeln_frame3,...]]
So while it is possible to use np.zeros to create the fitting matrix form and then use a python loop to basically say:
matrix = np.zeros(#channels, len(data)/#channels)
for index in range(#channels):
matrix[i] = data[i::#channels]
Can't I somehow do that with numpy alone? The performance gain might not be so high, especially because the amount of channels will be very low in most cases, but it kind of pisses me off that I've not been able to find a more "elegant" solution to this.
Thanks in advance if you have an idea,
have a nice weekend!
You could use numpy.reshape:
data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
matrix = np.reshape(2, 5) # Assume 2 channels and 5 frames
print(matrix)
This code outputs
array([[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10]])
In your case you would use reshape(len(data)/#channels, #channels) on your data.

Smooth aggressive values in the list

I think it's kind of new question, where we didn't have solution. I need to implement some kind of smothering for a very big values in a list of numbers. For ex.
list = np.array([3, 3, 3, 15, 3, 3, 3])
I have made very simple implementation, with smothering such values. What I have tried so far.
def smooth(x, window, threshold):
for idx, val in enumerate(x):
if idx < window:
continue
avr = np.mean(
x[idx-window:idx])
if abs(avr - val) > threshold:
x[idx] = avr + threshold
print(smooth(list1, 3, 1))
# [3, 3, 3, 4, 3, 3, 3]
In this case, everything works Ok, but taking another example, I need to smooth data in a another way(gaussian smooth for ex).
list = np.array([3, 3, 3, 15, 15, 15])
print(smooth(list, 3, 1))
# [3, 3, 3, 4, 4, 3]
Because window moving from the left to right, I don't know norm of next value. Of course I can evaluate window for this numbers from both directions, but just wondering about right ways of doing that, or common technique.
I would advise against implementing 1D filtering yourself, since
you are likely to introduce artifacts into your data when taking a naive approach (as using a rectangular filter shape like you did in your code snippet).
you are unlikely to come up with a implementation remotely as fast as existing implementations, which have been optimized for decades
unless you are doing it for autodidactic reasons, it is a classic example of wasting your time by reinventing the wheel
Instead make use of the rich variety of existing implementations, available e.g. in the scipy package. You can find a nicely illustrated usage example here: Smoothing of a 1D signal (Scipy Cookbook)

Extract patches similar to that of max pooling or separable convolution

I am trying to create a custom layer that is similar to Max Pooling or the first step of a separable convolution.
For example with a 2-Tensor in which I want to extract the non-overlapping 2x2 patches:
if I have the [4,4] tensor
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9,10,11],
[12,13,14,15]]
I want to end up with the following [2,2,4] Tensor
[[[ 0, 1, 4, 5],[ 2, 3, 6, 7]],
[[ 8, 9,12,13],[10,11,14,15]]]
For a 3-Tensor, I want something similar but to also separate out the 3rd dimension. tf.extract_image_patches almost does what I want, but it folds the "depth" dimension into each patch.
Ideally if I had a tensor of shape [32,64,7] and wanted to extract all the [2,2] patches out of it: I would end up with a shape of [16,32,7,4]
To be clear, I just want to extract the patches, not to actually do max pooling nor separable convolution.
Since I am not actually augmenting the data, I suspect that you can do it with some tf.reshape trickery... Is there any nice way to achieve this in tensorflow without resorting to slicing+stitching/for loops?
Also, what is the correct terminology for this operation? Windowing? Tiling?
Turns out this is really easy to do with tf.transpose. The solution that ended up working for me is:
#Assume x is in BHWC form
def pool(x,size=2):
channels = x.get_shape()[-1]
x = tf.extract_image_patches(
x,
ksizes=[1,size,size,1],
strides=[1,size,size,1],
rates=[1,1,1,1],
padding="SAME"
)
x = tf.reshape(x,[-1],x.get_shape()[1:3]+[size**2,channels])
x = tf.transpose(x,[0,1,2,4,3])
return x

Categories