循环神经网络
循环神经网
循环神经网络处理变长的序列,在这点上不同于普通神经网是。在时间序列定义一种递归关系来实现循环的。
- 表示在 k 时刻的状态(记忆)
- 表示在 k 时刻神经元的输入
- 和 是类似普通前馈神经网络的权重参数
循环神经网的隐含状态(记忆单元)会在整个时间序列上不断地被更新。在神经网隐藏层输出会作为被状态被记忆,在下一次作为输入一部分参与计算。我们可以认为循环神经网络是带有反馈回路(feedback loop),这里反馈回路意思没出计算输出作为状态存储 k 时刻,这个存储 k 时刻状态参与到下一次 k+1 时刻的计算。通过状态可以将信息在时间上序列进行传递。
rnn_simple_01.jpg
所以最终输出包含之前 之前的状态。循环网络与前馈网络没有太大的区别,但是在训练集,我们训练是在早期是一个比较困难事情,因为损失函数很不稳定。这个随后会介绍一下。
自己手写一个简单的循环神经网,该循环神经网经过训练,可以计算在二进制(0 或 1)输入序列上计算出现 1 的个数,并在序列结束时输出总计数。如下图循环卷积有一个状态,在每一个时刻输入一个序列中的元素,计算输出后更新状态,最后输出 y
rnn_simple_02.png下图左边为循环神经元的示例图,而右侧为其在时间序列上展开的效果。我们可将这个神经元进行展开,类似有共享参数和的 n+1 层。
%matplotlib notebook
import sys
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import LogNorm
import seaborn as sns
sns.set_style('darkgrid')
np.random.seed(seed=1)
定义数据集
20 样本,每一个样本序列包含 10 二进制作为二进制。
# 创建数据集
nb_of_samples = 20
sequence_len = 10
# 创建序列
X = np.zeros((nb_of_samples, sequence_len))
# print(X)
for row_idx in range(nb_of_samples):
X[row_idx,:] = np.around(np.random.rand(sequence_len)).astype(int)
t = np.sum(X, axis=1)
t
array([6., 3., 7., 4., 3., 4., 6., 7., 8., 4., 3., 4., 7., 7., 5., 5., 5.,
4., 6., 4.])
在时间序列上训练方法
训练循环神经网络中训练算法是基于时间维度上的反向传播算法。循环神经网反向传播是基于我们在前馈网络的反向传播算法。只要掌握了神经网络的反向传播算法,基于时间的反向传播也不太难理解了。主要区别是,在一定的时间序列的循环网络需要按时间进行展开。在展开网络之后,就看到了我们熟悉的类似于普通的多层前馈网络的模型。区别是每个层有多个输入。
def update_state(xk, sk, wx, wRec):
"""
更新当前状态,当前状态当前 k 状态
"""
return xk * wx + sk * wRec
print(X.shape[0],X.shape[1])
20 10
S = np.zeros((X.shape[0],X.shape[1]+1))
print(S.shape)
(20, 11)
for k in range(0,X.shape[1]):
S[:,k+1] = update_state(X[:,k],S[:,k],1.2,1.2)
print(S)
[[ 0. 1.2 2.64 3.168 3.8016 4.56192
6.674304 9.2091648 12.25099776 14.70119731 18.84143677]
[ 0. 0. 1.2 2.64 3.168 3.8016
5.76192 6.914304 8.2971648 9.95659776 11.94791731]
[ 0. 0. 1.2 1.44 2.928 4.7136
5.65632 7.987584 10.7851008 14.14212096 18.17054515]
[ 0. 0. 1.2 2.64 3.168 5.0016
6.00192 8.402304 10.0827648 12.09931776 14.51918131]
[ 0. 0. 1.2 1.44 2.928 3.5136
4.21632 5.059584 6.0715008 8.48580096 10.18296115]
[ 0. 0. 0. 1.2 1.44 2.928
3.5136 5.41632 6.499584 8.9995008 10.79940096]
[ 0. 1.2 2.64 3.168 5.0016 6.00192
8.402304 11.2827648 13.53931776 17.44718131 20.93661757]
[ 0. 1.2 2.64 3.168 5.0016 7.20192
9.842304 11.8107648 14.17291776 18.20750131 23.04900157]
[ 0. 1.2 2.64 4.368 6.4416 7.72992
10.475904 13.7710848 17.72530176 21.27036211 26.72443453]
[ 0. 0. 1.2 2.64 3.168 3.8016
4.56192 5.474304 7.7691648 10.52299776 12.62759731]
[ 0. 0. 0. 1.2 1.44 1.728
2.0736 3.68832 4.425984 5.3111808 7.57341696]
[ 0. 0. 0. 0. 1.2 2.64
3.168 5.0016 6.00192 8.402304 10.0827648 ]
[ 0. 0. 1.2 2.64 4.368 6.4416
7.72992 10.475904 12.5710848 16.28530176 20.74236211]
[ 0. 1.2 1.44 2.928 3.5136 5.41632
7.699584 10.4395008 13.72740096 17.67288115 21.20745738]
[ 0. 1.2 1.44 1.728 3.2736 3.92832
5.913984 8.2967808 9.95613696 11.94736435 15.53683722]
[ 0. 0. 0. 1.2 2.64 3.168
5.0016 6.00192 8.402304 10.0827648 13.29931776]
[ 0. 0. 1.2 1.44 1.728 2.0736
2.48832 4.185984 6.2231808 8.66781696 11.60138035]
[ 0. 1.2 2.64 4.368 5.2416 7.48992
8.987904 10.7854848 12.94258176 15.53109811 18.63731773]
[ 0. 0. 1.2 1.44 2.928 4.7136
5.65632 7.987584 10.7851008 12.94212096 16.73054515]
[ 0. 0. 0. 0. 1.2 1.44
2.928 3.5136 5.41632 6.499584 8.9995008 ]]
def forward_states(X, wx, wRec):
"""
"""
# 初始化一个持有所有序列的状态的矩阵,初始化值为 0
S = np.zeros((X.shape[0], X.shape[1]+1))
# 使用上面定义 update_state 方法时间序列上状态
for k in range(0, X.shape[1]):
# S[k] = S[k-1] * wRec + X[k] * wx
S[:,k+1] = update_state(X[:,k], S[:,k], wx, wRec)
return S
最后希望大家关注我们微信公众号
wechat.jpeg
网友评论