Insert data processing between network and loss

Hi

I tried to find a similar topic, but did not find any. My problem is the following: try to approximate the inverse of a set of filters using a neural network. I’m using pytorch and I have 1D data.

The approach is as follows: The network is defined and I do the usual forward / backward steps. The forward pass is done as:

# Zero the gradients
optimizer.zero_grad()
# Perform forward pass
outputs = mlp(inputs)

Then I insert my filters:

outputs = myFilters(outputs)

And compute the loss, trying to fit the output with the input:

# Compute loss
loss = loss_function(outputs, inputs)
loss.backward()
optimizer.step()

But I get an error in the loss.backward() step:

RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

As I understand it, it says that Pytorch cannot backpropagate the error through the filter before passing through the network. How can I do that ?

Thanks for your help.

Could you post the definition of myFilters as it seems this method detaches the tensor from the computation graph and is thus raising the error.

Thanks for your answer
currently, the filter is done as follows. First, some parameters are defined in advance (before the training phase):

    # Sigmoid parameter
    sig = 5
    
    # Filter parameters
    cutoff = 500
    ftype = 'cheby2'
    btype = 'low'
    order = 5
    att = 30 # dB
    nyq = 22050
    b, a = signal.iirfilter(order, cutoff / nyq, rs=att,
                                    btype=btype, ftype=ftype)

and during training:

            # Perform forward pass
            outputs = mlp(inputs)
            
            # Filter
            tmp = 1 + np.exp(-outputs.detach().numpy() * sig)
            dat = 2 / tmp - 1
            outputData = signal.lfilter(b, a, dat)
            outputs = torch.from_numpy(outputData)
            
            # Compute loss
            loss = loss_function(outputs, inputs)
            loss.backward()

You are explicitly detaching the model output ans use numpy which Autograd won’t be able to track. You could either use pure PyTorch methods or create a custom autograd.Function including the backward method.

When you say ’ You could either use pure PyTorch methods’, do you mean for the #Filter block, instead of using numpy?
I guess I can do that for the 2 first lines, but how can I do that for the signal.lfilter function? Is there any equivalent in pytorch?

Edit:
I replaced the lines:

            tmp = 1 + np.exp(-outputs.detach().numpy() * sig)
            dat = 2 / tmp - 1

by

            tmp = 1 + torch.exp(torch.mul(outputs, -sig))
            dat = torch.div(2, tmp) - 1

So I guess that now, the autograd will automatically take care of them. I still need to find how to compute the low pass filter.

I see here that there exists a torchaudio.functional.lfilter function:

torchaudio.functional.lfilter(waveform: Tensor, 
a_coeffs: Tensor, 
b_coeffs: Tensor, 
clamp: bool = True, 
batching: bool = True) → Tensor

If I use it, will it be automatically managed by the autograd?

Edit2:
So I changed the filter block with:

            # Filter
            tmp = 1 + torch.exp(torch.mul(outputs, -sig))
            dat = torch.div(2, tmp) - 1
            outputs = functional.lfilter(dat, a_tensor, b_tensor)

where:

    b, a = signal.iirfilter(order, cutoff / nyq, rs=att,
                                    btype=btype, ftype=ftype)
    a_tensor = torch.from_numpy(a).to(torch.float32)
    b_tensor = torch.from_numpy(b).to(torch.float32)

Now I get a new error message:

outputs = functional.lfilter(dat, a_tensor, b_tensor)

File “C:\Users\me\AppData\Local\Programs\Spyder\pkgs\torchaudio\functional.py”, line 594, in lfilter
o0.addmv_(windowed_output_signal, a_coeffs_flipped, alpha=-1)

RuntimeError: Output 0 of UnbindBackward is a view and is being modified inplace. This view is the output of a function that returns multiple views. Such functions do not allow the output views to be modified inplace. You should replace the inplace operation by an out-of-place one.

What does this mean?

Edit3:
As I want this processing block to remain unchanged during the training process, I tried to add a no_grad() instruction:

            # Filter
            with torch.no_grad():
                tmp = 1 + torch.exp(torch.mul(outputs, -sig))
                dat = torch.div(2, tmp) - 1
                outputs = functional.lfilter(dat, a_tensor, b_tensor)

but this leads to the following error:

    loss.backward()

  File "C:\Users\me\AppData\Local\Programs\Spyder\pkgs\torch\tensor.py", line 221, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph)

  File "C:\Users\me\AppData\Local\Programs\Spyder\pkgs\torch\autograd\__init__.py", line 132, in backward
    allow_unreachable=True)  # allow_unreachable flag

RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

I’m back to the beginning…

Your approach looks correct. Could you try to .clone() the input to the function to check if this would get rid of the inplace error?

Thanks
When I do this:

            inp = torch.clone(outputs)
            tmp = 1 + torch.exp(torch.mul(inp, -sig))
            dat = torch.div(2, tmp) - 1
            outputs = functional.lfilter(dat, a_tensor, b_tensor)

I still get the inplace error message:

outputs = functional.lfilter(dat, a_tensor, b_tensor)

File “C:\Users\me\AppData\Local\Programs\Spyder\pkgs\torchaudio\functional.py”, line 594, in lfilter
o0.addmv_(windowed_output_signal, a_coeffs_flipped, alpha=-1)

RuntimeError: Output 0 of UnbindBackward is a view and is being modified inplace. This view is the output of a function that returns multiple views. Such functions do not allow the output views to be modified inplace. You should replace the inplace operation by an out-of-place one.

and if I try to clone the input data of the filter (dat), it doesn’t change.

But adding no_grad before the filters, like this:

            # Filter
            with torch.no_grad():
                inp = torch.clone(outputs)
                tmp = 1 + torch.exp(torch.mul(inp, -sig))
                dat = torch.div(2, tmp) - 1
                outputs = functional.lfilter(dat, a_tensor, b_tensor)

leads to the following error:

loss.backward()

File “C:\Users\me\AppData\Local\Programs\Spyder\pkgs\torch\tensor.py”, line 221, in backward
torch.autograd.backward(self, gradient, retain_graph, create_graph)

File “C:\Users\me\AppData\Local\Programs\Spyder\pkgs\torch\autograd_init_.py”, line 132, in backward
allow_unreachable=True) # allow_unreachable flag

RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

The inplace operation should have been removed in this PR two years ago so you might need to update torchaudio to a newer version.

I upgraded torchaudio, as well as torch (my python setup is a mess, so it took some time), and removed the with torch.no_grad(): and now it works.

Training…

Loss after epoch 0: train 0.012097, valid 0.047847 ** Saving **
Loss after epoch 1: train 0.009809, valid 0.046365 ** Saving **
Loss after epoch 2: train 0.009157, valid 0.046639 ** Saving ** .
Loss after epoch 3: train 0.009253, valid 0.048142
Loss after epoch 4: train 0.009138, valid 0.048630 ** Saving **
Loss after epoch 5: train 0.008838, valid 0.048512 ** Saving ** .
Loss after epoch 6: train 0.008995, valid 0.047558
Loss after epoch 7: train 0.008856, valid 0.048354
Loss after epoch 8: train 0.008831, valid 0.050807 ** Saving ** .
Loss after epoch 9: train 0.008876, valid 0.046235
Loss after epoch 10: train 0.008922, valid 0.048804

Thanks a lot for your help!
Have a good day