Equivalent function like `numpy.diff` in pytorch?

Greetings, I am relatively new to pytorch (also not very familiar with manipulating tensors) and I am trying to implement a function with the same behavior as numpy.diff (https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.diff.html). I would like that this function works only with torch Tensors. After looking at the documentation, it doesn’t seems like pytorch as a function that have the same behavior… Is there an equivalent function that I missed ? if None exist, how would your implement such function ?

Ultimately, I am trying to implement a loss function weighted by Mean Directional Accuracy (MDA)(https://en.wikipedia.org/wiki/Mean_Directional_Accuracy).

For example, the numpy version of it is as follows:

def diff(a, n=1, axis=-1):
    if n == 0:
        return a
    if n < 0:
        raise ValueError(
            "order must be non-negative but got " + repr(n))

    a = asanyarray(a)
    nd = a.ndim
    axis = normalize_axis_index(axis, nd)

    slice1 = [slice(None)] * nd
    slice2 = [slice(None)] * nd
    slice1[axis] = slice(1, None)
    slice2[axis] = slice(None, -1)
    slice1 = tuple(slice1)
    slice2 = tuple(slice2)

    op = not_equal if a.dtype == np.bool_ else subtract
    for _ in range(n):
        a = op(a[slice1], a[slice2])

    return a

>>> x = np.array([1, 2, 4, 7, 0])
>>> np.diff(x)
#array([ 1,  2,  3, -7])

I think indexing should just work:

x = torch.tensor([1, 2, 4, 7, 0])
x_diff = x[1:] - x[:-1]
print(x_diff)
> tensor([ 1,  2,  3, -7])
3 Likes

How to get the same shape output?

Below a solution to keep the same shape when computing first differences across the last dimension by padding zeros at the front.

import torch.nn.functional as F
t = torch.rand((10, 10, 10))
diff = t - F.pad(t, (1, 0))[:, :, :-1]

Note 1: you can also create a Conv layer with a 2 sized kernel with fixed weights [-1, 1], but that comes down to the same thing.
Note 2: Don’t know if this is optimal in terms of speed, I know it’s faster than using a concatenation. Happy to learn when someone has a faster option :slight_smile:

1 Like

Hi Ptrblck

Sorry to take your time. I am using Matlab to find the coordinate so f specific value in 3 Diment by "
[XX,YY,ZZ]=ind2sub(size(SWITHresholedOutPut),find(SWITHresholedOutPut==1));

I want to do same thing in pytorch, means find the coordinate of specific value in 3 dimension.

What is the best option?

Would this work for you?

x = torch.arange(4*5*6).view(4, 5, 6)
idx = (x == 82).nonzero()
1 Like

Hi Ptrblck

I want to compute instantaneous frequency (IF) from hilbert transform using pytorch.
Currently, I am using Matlab for this task.

Matlab script:

[x,fs]=audioread('waveform');

for i = 1:length(sinc_filter)
    C(i,:) = conv(x,sinc{i},'same');
    HT(i,:)=(hilbert(C(i,:)));
    instfreq (i,:)= abs(fs/(2*pi)*diff(unwrap(angle(HT(i,:)))));
end

I want to do the same thing in pytorch.

I didn’t find hilbert and unwrape function in pytorch.

I tried using numpy but that’s taking lot of time for computing instantaneous frequency for each mini-batch.

python script using numpy:

#no. of sinc filters=21
#filter_length=128
#mini-batch size=8
#self.filters size is [1,no. of sinc filters, filter_length]
# Filter is sinc filters with size [batch_size, no. of sinc filter, audio samples(64000 samples)]. 

Filter=F.conv1d(waveforms, self.filters, stride=self.stride,
                        padding=self.padding, dilation=self.dilation,
                         bias=None, groups=1) 

self.Filter=Filter

fs=16000

FILTER_1=self.Filter.cpu().detach().numpy()  

inst_freq=np.zeros((self.Filter.shape[0],self.Filter.shape[1],Filter.shape[2]-1))  # intialized inst_freq matrix

# 1st for loop to compute IF for each filter and 2nd for loop is for each audio wave in mini-batch.
# j range from 0 to 20.
# i range from 0 to 7.


for j in range(self.Filter.shape[1]):
    for i in range(self.Filter.shape[0]):
        z= hilbert(FILTER_1[i,j,:])
        inst_phase = np.unwrap(np.angle(z))
        inst_freq[i,j,:] = np.diff(inst_phase)/(2*np.pi)*fs 
                
  
Main_filt=torch.from_numpy(inst_freq).type(torch.float).to(self.device)

But its taking lot of time for IF computation.

Is there any way to do this things in pytorch.

Please let me know what is the best option to do this operations for IF computation in pytorch.
your suggestions would be really useful for me.

Thanks in advance.

Based on the code it seems you would need to port the hilbert transformation and unwrap to PyTorch to avoid using scipy and numpy on the CPU.
I had a quick look at the source code for hilbert and unwrap and I think all needed operations are implemented in PyTorch, so that you could try to port these methods directly.