一、提出
递归神经网络(Recurrent Neural Networks,RNNs)的训练是通过权值直接优化来实现的,这种方式容易产生两个问题:收敛速度慢和易陷入局部最优。回声状态网络( echo state network,ESN) 由 Jaeger于2001年提出,在模型构建与学习算法方面较 传统的递归神经网络有较大差别,其相应的学习算法为递归神经网络的研究开启了新纪元。
回声状态网络又称储备池计算,采用由随机稀疏连接的神经元组成的储备池作为隐层,用以输入进行高维、非线性的表示。ESN将神经网络的隐层权值预先生成而非训练生成,与隐层至输出层的权值训练分开进行,其基本思想的前提是生成的储备池具有某种良好的属性,往往能够保证仅采用线性方法训练储备池至输出层的权值即可获得优良的性能。
二、基本原理
2.1 网络结构

ESN拓扑结构图
基本方程:





预先生成Win(输入单元与储备池内部连接权值矩阵)、W(储备池内部连接权值矩阵)、Wback(储备池与输出单元连接权值矩阵),只训练Wout(储备池与输出单元连接权值矩阵)
:储备池单元的激活函数
:输出单元的激活函数
2.2 主要参数
2.2.1 储备池规模N
储备池其中神经元的个数N,N值越大,预测的精度越高,但同时也会导致效率低下,容易过拟合。
2.2.2 储备池谱半径SR
SR是W最大特征值的绝对值,是影响储备池记忆能力的主要因素。一般需要保证SR<1,ESN才有回声状态性质。
2.2.3 储备池稀疏程度SD
SD是内部神经元的连接情况,表示储备池中相互连接的神经元占所有神经元总数的比例,通常为1%~5%。
2.2.4 输入单元尺度IS
IS是输入连接至储备池之前需要相乘的一个尺度因子。相乘使得输入信号变换至神经元激活函数相应的范围内。
2.3 构造方法

ESN的建立流程
(3)其次是输入连接的权值大小以及内部连接矩阵的谱半径,这些关键参数会影响到网络短期记忆时间的长短,输入权值越小而内部矩阵的谱半径越接近1,网络短期记忆时间越长。但是增强记忆能力的同时,这种操作也造成了网络对“快速变化”系统建模能力下降。在实际应用中,要通过分析被建模系统的实际变化特征来选取相应的数值。
训练过程
(1)采样
但是通常情况下选取网络的初始状态为
0
,即
x(
0
)=
0
。
(
u
( n)
n
=
1
2
…
M)
经过输入连接权
W
in
,样本数
据
y(n)
经过反馈连接权
W
back
分别被加到储备池
,按照
系统
(
1
)
,依次完成系统状态的计算和相应输出
y
( n)
的
计算与收集
。
注意每
一
时刻系统状态
x
(n)
的计算
都
需要将样本数据
y
( n)
写入到输出单元
。
为了计算输出
连接权矩阵
需要从某
一
时刻开始收集
(
采样
)
内部状
态变量
。
这里假定从
m
时刻开始收集系统状态,
并以向
量
(x
1
( i)
x
2
( i)
…
x
N
( i))( i
=
mm
+1
…
M)
为行
构成矩阵
B
( M
–
m
+1
N),
同时相应的样本数据
y
(n)
也被收集,
并构成
一
个列向量
T
( M
–
m
+1
1
)。
(2)权值计算
需要根据在采样阶段收集到系统状态矩阵和样本数据,
计算输出连接权
W
out
。
因为状态变量
x
( n)
和系统输出
y
( n)
之间是线性关系
,而
需要实现的目标是利用网络实际输出
y
( n)
逼近期望输
出
y
( n),
即

wout
i
。
满足系统的均方误差最小
即需要求解如下的优
化问题
:

这是一
个线性回归
问题,可
以归结为求矩阵
B
的逆矩阵问题,
实际应用中矩阵
B
,在计算上该问题可以进一
步处理为矩
阵
B
的伪逆问题,
即

至此,训练完成。
三、Python代码实现(简洁版,只适合入门使用)
from numpy import * from matplotlib.pyplot import * import scipy.linalg import matplotlib.pyplot as plt # 加载数据 # 前2000个数据用来训练,2001-4000的数据用来测试。训练数据中,前100项用来初始化储备池,以让储备池中形成良好的回声之后再开始训练。 trainLen = 2000 testLen = 2000 initLen = 100 # 前100项用来初始化储备池 data = loadtxt('MackeyGlass_t17.txt') # 绘制前1000条数据 figure(0).clear() plot(data[0:1000]) title('A sample of data') # 生成ESN储层 inSize = outSize = 1 # inSize 输入维数 K resSize = 1000 # 储备池规模 N a = 0.3 # 可以看作储备池更新的速度,可不加,即设为1. random.seed(42) # 随机初始化 Win 和 W Win = (random.rand(resSize, 1 + inSize) - 0.5) * 1 # 输入矩阵 N * 1+K W = random.rand(resSize, resSize) - 0.5 # 储备池连接矩阵 N * N # 对W进行防缩,以满足稀疏的要求。 # 方案 1 - 直接缩放 (快且有脏数据, 特定储层): W *= 0.135 # 方案 2 - 归一化并设置谱半径 (正确, 慢): print('计算谱半径...') rhoW = max(abs(linalg.eig(W)[0])) # linalg.eig(W)[0]:特征值 linalg.eig(W)[1]:特征向量 W *= 1.25 / rhoW # 为设计(收集状态)矩阵分配内存 X = zeros((1 + inSize + resSize, trainLen - initLen)) # 储备池的状态矩阵x(t):每一列是每个时刻的储备池状态。后面会转置 # 直接设置相应的目标矩阵 Yt = data[None, initLen + 1:trainLen + 1] # 输出矩阵:每一行是一个时刻的输出 # 输入所有的训练数据,然后得到每一时刻的输入值和储备池状态。 x = zeros((resSize, 1)) for t in range(trainLen): u = data[t] x = (1 - a) * x + a * tanh(dot(Win, vstack((1, u))) + dot(W, x)) # vstack((1, u)):将偏置量1加入输入序列 if t >= initLen: # 空转100次后,开始记录储备池状态 X[:, t - initLen] = vstack((1, u, x))[:, 0] # 使用Wout根据输入值和储备池状态去拟合目标值,这是一个简单的线性回归问题,这里使用的是岭回归(Ridge Regression)。 reg = 1e-8 # 正则化系数 X_T = X.T # Wout: 1 * 1+K+N Wout = dot(dot(Yt, X_T), linalg.inv(dot(X, X_T) + \ reg * eye(1 + inSize + resSize))) # linalg.inv矩阵求逆;numpy.eye()生成对角矩阵,规模:1+inSize+resSize,默认对角线全1,其余全0 # Wout = dot( Yt, linalg.pinv(X) ) # 使用训练数据进行前向处理得到结果 # run the trained ESN in a generative mode. no need to initialize here, # because x is initialized with training data and we continue from there. Y = zeros((outSize, testLen)) u = data[trainLen] for t in range(testLen): x = (1 - a) * x + a * tanh(dot(Win, vstack((1, u))) + dot(W, x)) y = dot(Wout, vstack((1, u, x))) # 输出矩阵(1 * 1+K+N)*此刻状态矩阵(1+K+N * 1)=此刻预测值 Y[:, t] = y # t时刻的预测值 Y: 1 * testLen # 生成模型 u = y # 预测模型 # u = data[trainLen+t+1] # 计算第一个errorLen时间步长的MSE errorLen = 500 mse = sum(square(data[trainLen + 1:trainLen + errorLen + 1] - Y[0, 0: errorLen])) / errorLen print('MSE = {0}'.format(str(mse))) # 绘制测试集的真实数据和预测数据 figure(1).clear() plot(data[trainLen + 1:trainLen + testLen + 1], 'g') plot(Y.T, 'b') title('Target and generated signals $y(n)$ starting at $n=0$') legend(['Target signal', 'Free-running predicted signal']) # 绘制储备池中前200个时刻状态(x(t))的前20个储层结点值 figure(2).clear() plot(X[0:20, 0:200].T) title('Some reservoir activations $\mathbf{x}(n)$') # 绘制输出矩阵 figure(3).clear() # bar(np.arange(1 + inSize + resSize), Wout.T, 8) plot(np.arange(1 + inSize + resSize), Wout.T) title('Output weights $\mathbf{W}^{out}$') show()
MackeyGlass_t17.txt – 蓝奏云 ,点击此连接获取数据集




四、改进
基于储备池内部结构的改进、基于拓扑结构的改进、基于回声状态网络参数的改进等方面
五、参考资料
1.罗熊, 黎江, 孙增圻. 回声状态网络的研究进展[J]. 北京科技大学学报, 2012, 34(2): 217-222.
2.张晋雁, 陶宏才. 回声状态网络研究[J]. 成都信息工程学院学报, 2015, 30(6): 546-550.
3.孙晓川, 李莹琦. 小世界递归小波神经网络研究[J]. 南京邮电大学学报: 自然科学版, 2017, 37(4): 97-102.
4.彭宇, 王建民, 彭喜元. 储备池计算概述[J]. 电子学报, 2011, 39(10): 2387-2396.
5.郭嘉. 回声状态网络分类方法及其应用研究[D]. 哈尔滨: 哈尔滨工业大学, 2011.
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/176578.html原文链接:https://javaforall.net
