Flexible Transmitter Network
原文附录A里,使用了FTNet模型对sin信号模拟。网上也没找到相关的代码,于是就自己尝试做一下,可能会有些错误,希望给位能够批评指正一下。下面是原文的图片。
问题
我们要拟合的函数是周期为3的sin函数,x轴的范围为0到300的整数。首先给出产生数据的python代码。
# 生成数据
import numpy as np
a=np.array(range(300))
# x
y=np.sin(a*2/3*np.pi)
# y
import matplotlib.pyplot as plt
plt.plot(a[:60],y[:60]) # 画出这条线段
plt.show()
数据图像如下:
根据论文,我们将论文中的模型带入,进行前向传播算法,得出预测数值。
以下为前向传播的公式,在这里可以把每一个字母当成标量。
st是输出信号,mt是t时刻的记忆强度,w和v是参数,xt是输入信号。
这边alpha和beta我都设置为1,原文中也没提到怎么设置这两个常数。
然后这个
σ
\sigma
σ 是激活函数,原文建议用 tanh 所以我们用tanh,然后原文介绍一个自然的想法就是将激活函数分别作用于复数的实部和虚部。
接着我们就写python代码,由于原文没有细说输入xt是什么,这里我们用 y t − 1 y_{t-1} yt−1作为xt。mt是一个随时间更新的一个量。
x=y[:-1]
y=y[1:]
x.shape,y.shape
接着我们需要对这些数据矩阵化,然后初始化一些参数。
# 矩阵化
x=x.reshape(1,len(x))
y=y.reshape(1,len(y))
# 记录 x 和 y 的长度
lx,ly=x.shape[1],y.shape[1]
# 初始化所有参数
np.random.seed(1)
real=np.zeros(ly).reshape(1,ly)
image=np.zeros(ly).reshape(1,ly)
pre=np.zeros(ly).reshape(1,ly)
m=np.ones(ly).reshape(1,ly)*-0.24
w=np.array(np.random.randn(1)).reshape(1,1)
v=np.array(np.random.randn(1)).reshape(1,1)
real.shape,image.shape,pre.shape,m.shape,w,v
接着介绍前向传播和反向传播,同时计算损失函数。
# 前向传播
pre=np.tanh(np.matmul(w,x)-np.matmul(v,m))
real=np.matmul(w,x)-np.matmul(v,m)
image=np.matmul(w,x)+np.matmul(v,m)
# 计算损失
loss = np.sum(np.square(y-pre))/2
loss
下面进行反向传播
# 第一次迭代
dw=np.zeros(1).reshape(1,1)
dv=np.zeros(1).reshape(1,1)
dmw=np.zeros(ly).reshape(1,ly)
dmv=np.zeros(ly).reshape(1,ly)
for i in range(ly):
dw+=(y[0,i]-pre[0,i])*(1-np.square(np.tanh(real[0,i])))*(x[0,i]-v*dmw[0,i])
dmw[0,i]=(1-np.square(np.tanh(image[0,i])))*(x[0,i]+v*dmw[0,i])
for i in range(ly):
dv+=(y[0,i]-pre[0,i])*(1-np.square(np.tanh(real[0,i])))*-(m[0,i]+v*dmv[0,i])
dmv[0,i]=(1-np.square(np.tanh(image[0,i])))*(m[0,i]+v*dmv[0,i])
# 更新参数,学习率0.01
w=w+0.01*dw
v=v+0.01*dv
m=np.tanh(np.matmul(w,x)+np.matmul(v,m))
# 第2次迭代前向传播
pre=np.tanh(np.matmul(w,x)-np.matmul(v,m))
real=np.matmul(w,x)-np.matmul(v,m)
image=np.matmul(w,x)+np.matmul(v,m)
# 计算损失
loss = np.sum(np.square(y-pre))/2
loss
设置最大迭代次数为1000,如果loss小于60则保存参数停止迭代
j=1
while j<1000:
dw=np.zeros(1).reshape(1,1)
dv=np.zeros(1).reshape(1,1)
for i in range(ly):
dw+=(y[0,i]-pre[0,i])*(1-np.square(np.tanh(real[0,i])))*(x[0,i]-v*dmw[0,i])
dmw[0,i]=(1-np.square(np.tanh(image[0,i])))*(x[0,i]+v*dmw[0,i])
for i in range(ly):
dv+=(y[0,i]-pre[0,i])*(1-np.square(np.tanh(real[0,i])))*-(m[0,i]+v*dmv[0,i])
dmv[0,i]=(1-np.square(np.tanh(image[0,i])))*(m[0,i]+v*dmv[0,i])
# 更新参数,学习率0.01
w=w+0.01*dw
v=v+0.01*dv
m=np.tanh(np.matmul(w,x)+np.matmul(v,m))
# 第六次迭代
pre=np.tanh(np.matmul(w,x)-np.matmul(v,m))
real=np.matmul(w,x)-np.matmul(v,m)
image=np.matmul(w,x)+np.matmul(v,m)
# 计算损失
loss = np.sum(np.square(y-pre))/2
j=j+1
if loss<60 or j%50==0:
print(w,v)
print(m)
print(loss)
break
最后我们得出loss为57。下面我们绘制拟合效果图,以及记忆变量mt与信号yt的关系。
plt.plot(a[:60],y[0,:60])
plt.plot(a[:60],pre[0,:60])
plt.show()
plt.plot(a[:60],y[0,:60])
plt.plot(a[:60],m[0,:60])
plt.show()
两张图片看似一样,其实mt和pre的数值是不一样的,但是差距比较小。
接着我们使用传统的MP(多层感知器模型),同样采用tanh作为激活函数,隐藏层神经元设置为1,2,3,4,5。
from sklearn.neural_network import MLPRegressor
mlp = MLPRegressor(hidden_layer_sizes=(1),activation='tanh',max_iter=1000)
mlp.fit(x1,y1)
p2=mlp.predict(x1)
np.sum(np.square(p2-y1))
隐藏层神经元个数 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
loss | 137 | 71 | 57 | 38 | 3 |
未解决的问题
1、原文的sin信号怎么生成的?
2、Mt如何更新?
文中的Mt是随时间变化的,那么对于时间序列问题来说预测一个值Mt就更新一次,但是在论文中反向传播时需要用到所有时间的数据,且Mt是在W和V更新之后,利用新的参数进行估计的,所以这边就比较困惑。
文章链接如下
[1]: https://arxiv.org/pdf/2004.03839.pdf