最简单的方法是使用支持 autodiff 的运算符来获取 STFT,例如通过 PyTorch。然后只需将窗口设置为可更新参数,初始化为 Hanning 等:
import torch.nn as nn
from scipy.signal import windows
win = torch.from_numpy(windows.hann(128))
win_t = nn.Parameter(win, requires_grad=True)
然后我们会做例如
def forward(self, x):
x = STFT(x, win_t)
x = self.conv(x)
...
通过例如将窗口的权重定义为初始窗口的一半,但使用使用更新的权重的完整窗口进行操作,这可能有助于应用对称约束。
例如,请参阅这篇文章,将完全可微分 CWT 应用于反演。该网络可以嵌入到一个卷积网络中,如果我们用nn.Parameter
.
优化宽度
如果目标是优化预定义窗口函数的参数,则通过可微参数生成窗口:
def gauss(N, sigma):
t = torch.linspace(-.5, .5, N)
return torch.exp(-(t / sigma)**2)
N = x.shape[-1]
sigma = nn.Parameter(torch.tensor(0.1))
win_t = gauss(N, sigma)
优化长度
为了优化窗口的样本数量,我们必须确保采样是可微的。
- Hann 可以
arange(N) / N
,但N
必须是连续的,这需要四舍五入。torch.round
不可微分,但torch.clamp
可以。
- 为确保该过程有效,我们通过归一化互相关 (NCC) 定义优化目标:最佳窗口长度将与参考匹配。我们通过
conv1d
.
- 通过普通梯度下降进行优化,确保每一步后梯度为零,以避免梯度下降
假设我们从 开始,N=129
最优是N_ref=160
。结果:
Github上的代码。