当前位置: 首页 > 科技观察

你还不懂的傅里叶变换,神经网络只需要30多行代码就可以学会

时间:2023-03-14 14:04:43 科技观察

在我们的生活中,从天文观测到MP3播放器上的频谱,都离不开傅里叶变换.通俗地说,离散傅里叶变换(DFT)就是把一系列复杂的波形分成不同的频率分量。比如说声音,如果用声波录音机来显示声音,其实生活中的大部分声音都是非常复杂的,甚至是杂乱无章的。而通过傅里叶变换,可以将这些杂乱的声波转换成正弦波,也就是我们平时在音乐谱图中看到的。但是,在实际计算中,这个过程其实非常复杂。如果把声波看成一个连续函数,它可以唯一表示为一串三角函数的叠加。但是在叠加的过程中,各个三角函数的加权系数是不一样的,有的需要高一些,有的需要低一些,有的甚至不相加。傅里叶变换就是求这些三角函数和它们各自的权值。这不是巧合,这个搜索和搜索的过程非常类似于神经网络。神经网络的本质其实就是逼近一个函数。不是可以用训练神经网络的方式得到傅立叶变换吗?这确实是可行的,最近有人在网上公布了他训练的过程和结果。DFT=NeuralNetwork如何训练神经网络?这位网友给出的思路是这样的:首先,离散傅里叶变换(DFT)应该看成是人工神经网络。这是一个单层网络,没有偏置,没有激活函数,有特定的权重。价值。其输出节点个数等于傅里叶变换计算后的频率个数。具体方法如下:这是一个DFT:k表示每N个样本的循环次数;N代表信号的长度;表示样本n处的信号值。一个信号可以表示为所有正弦信号的总和。yk是一个复数,它给出了信号x中频率为k的正弦曲线的信息;从yk我们可以计算出正弦波的幅度和相位。在矩阵形式中,它变成了:这里给出了特定k值的傅立叶值。但通常情况下,我们要计算全谱,即从[0,1,...N-1]开始计算k的值,可以用一个矩阵来表示(k按列递增,n按行递增):简化后:看到这里应该很眼熟,因为它是一个没有偏置和激活函数的神经网络层。指数矩阵包含权重,可以称为复傅立叶权重。通常我们不知道神经网络的权重,但在这里我们可以。不要使用复数通常我们不会在神经网络中使用复数。为了适应这种情况,我们需要将矩阵的大小加倍,以便左侧部分包含实数,右侧部分包含虚数。带入DFT,可以得到:然后用实部(cos形式)表示矩阵的左半部分,用虚部(sin形式)表示矩阵的右半部分:化简后,可以get:将称为傅立叶权重;注意y^和y实际上包含相同的信息,但是y^没有使用复数,所以它的长度是y的两倍。换句话说,我们可以用或来表示幅度和相位,但我们通常使用。现在,可以将傅里叶层添加到网络中。现在可以使用神经网络实现使用傅立叶权重计算傅立叶变换,并使用快速傅立叶变换(FFT)检查正确性。importmatplotlib.pyplotasplty_real=y[:,:signal_length]y_imag=y[:,signal_length:]tvals=np.arange(signal_length).reshape([-1,1])freqs=np.arange(signal_length).reshape([1,-1])arg_vals=2*np.pi*tvals*freqs/signal_lengthsinusoids=(y_real*np.cos(arg_vals)-y_imag*np.sin(arg_vals))/signal_lengthreconstructed_signal=np.sum(sinusoids,axis=1)print('rmse:',np.sqrt(np.mean((x-reconstructed_signal)**2)))plt.subplot(2,1,1)plt.plot(x[0,:])plt.title('Originalsignal')plt.subplot(2,1,2)plt.plot(reconstructed_signal)plt.title('SignalreconstructedfromsinusoidsafterDFT')plt.tight_layout()plt.show()rmse:2.3243522568191728e-15得到这个小的误差值可以证明计算的结果就是我们想要的。另一种方法是重塑信号:importmatplotlib.pyplotasplty_real=y[:,:signal_length]y_imag=y[:,signal_length:]tvals=np.arange(signal_length).reshape([-1,1])freqs=np。arange(signal_length).reshape([1,-1])arg_vals=2*np.pi*tvals*freqs/signal_length正弦曲线=(y_real*np.cos(arg_vals)-y_imag*np.sin(arg_vals))/signal_lengthreconstructed_signal=np.sum(sinusoids,axis=1)print('rmse:',np.sqrt(np.mean((x-reconstructed_signal)**2)))plt.subplot(2,1,1)plt.plot(x[0,:])plt.title('Originalsignal')plt.subplot(2,1,2)plt.plot(reconstructed_signal)plt.title('SignalreconstructedfromsinusoidsafterDFT')plt.tight_layout()plt.show()rmse:2.3243522568191728e-15最后可以看出,正弦信号经过DFT重构后的信号与原始信号可以很好的重叠。通过梯度下降学习傅里叶变换现在是神经网络实际学习的部分,不需要像以前那样预先计算权重。首先,使用FFT训练神经网络学习离散傅里叶变换:importtensorflowastfsignal_length=32#Initialiseweightvectortotrain:W_learned=tf.Variable(np.random.random([signal_length,2*signal_length])-0.5)#Expectedweights,用于比较:W_expected=create_fourier_weights(signal_length)losses=[]rmses=[]foriinrange(1000):#Generatearandomsignaleachiteration:x=np.random.random([1,signal_length])-0.5#ComputetheexpectedresultusingtheFFT:fft=np.fft.fft(x)y_true=np.hstack([fft.real,fft.imag])withtf.GradientTape()astape:y_pred=tf.matmul(x,W_learned)loss=tf.reduce_sum(tf.square(y_pred-y_true))#Trainweights,通过梯度下降:)**2)))Finallossvalue1.6738563548424711e-09Finalweights'rmsevalue3.1525832404710523e-06结果如上,证实神经网络确实能够学习到离散傅立叶呃变换。除了使用快速傅立叶变换方法训练网络学习DFT,还可以通过网络重构输入信号来学习DFT。(类似于自动编码器)。自编码器(autoencoder,AE)是一类用于半监督学习和无监督学习的人工神经网络(ArtificialNeuralNetworks,ANNs)。它的作用是以输入信息为学习目标,学习输入信息的表示。(表示学习)。W_learned=tf.Variable(np.random.random([signal_length,2*signal_length])-0.5)tvals=np.arange(signal_length).reshape([-1,1])freqs=np.arange(signal_length)。重塑([1,-1])arg_vals=2*np.pi*tvals*freqs/signal_lengthcos_vals=tf.cos(arg_vals)/signal_lengthsin_vals=tf.sin(arg_vals)/signal_lengthlosses=[]rmses=[]foriinrange(10000):x=np.random.random([1,signal_length])-0.5withtf.GradientTape()astape:y_pred=tf.matmul(x,W_learned)y_real=y_pred[:,0:signal_length]y_imag=y_pred[:,signal_length:]sinusoids=y_real*cos_vals-y_imag*sin_valsreconstructed_signal=tf.reduce_sum(sinusoids,axis=1)loss=tf.reduce_sum(tf.square(x-reconstructed_signal))W_gradient=tape.gradient(丢失,W_learned)=tf.Variable(W_learned-0.5*W_gradient)losses.append(loss)rmses.append(np.sqrt(np.mean((W_learned-W_expected)**2)))Finallossvalue4.161919455121241e-22Finalweights'rmsevalue0.2024333926959009后用这个模型做了很多测试,得到的权重并不像上面例子中那样接近傅立叶权重,但是可以看出重构信号是一致的。尝试切换到输入幅度和相位。W_learned=tf.Variable(np.random.random([signal_length,2*signal_length])-0.5)losses=[]rmses=[]foriinrange(10000):x=np.random.random([1,signal_length])-.5withtf.GradientTape()astape:y_pred=tf.matmul(x,W_learned)y_real=y_pred[:,0:signal_length]y_imag=y_pred[:,signal_length:]amplitudes=tf.sqrt(y_real**2+y_imag**2)/signal_lengthphases=tf.atan2(y_imag,y_real)sinusoids=amplitudes*tf.cos(arg_vals+phases)reconstructed_signal=tf.reduce_sum(sinusoids,axis=1)loss=tf.reduce_sum(tf.square(x-reconstructed_signal))W_gradient=tape.gradient(loss,W_learned)W_learned=tf.Variable(W_learned-0.5*W_gradient)losses.append(loss)rmses.append(np.sqrt(np.mean((W_learned-W_expected)**2)))Finallossvalue2.2379359316633115e-21Finalweights'rmsevalue0.2080118219691059可以看出重构信号再次一致;然而,和以前一样,输入幅度和相位的最终权重与傅里叶权重并不完全相同(但非常接近)。由此可以得出结论,虽然最终的权值不是最准确的,但也可以获得局部最优解。这样,神经网络就学会了傅立叶变换!值得一提的是,这种方法仍有疑问:首先,它没有解释计算出的权重与真实的傅立叶权重有多大差异;有什么好处。