RNN求解过程推导与实现



RNN展开网络如下图

enter description here

RNN展开结构.jpg

enter description here

RNN节点结构.jpg

现令第t时刻的输入表示为,隐层节点的输出为,输出层的预测值,输入到隐层的权重矩阵,隐层自循环的权重矩阵,隐层到输出层的权重矩阵,对应的偏执向量分别表示为,输入层的某一个节点使用i标识,如,类似的隐层和输出层某一节点表示为。这里我们仅以三层网络为例。

那么首先正向计算

其中分别表示激活前对应的加权和,表示激活函数。

然后看看误差如何传递。

假设真实的输出应该是,那么误差可以定义为,是训练样本的index。整个网络的误差

我们将RNN再放大一些,看看细节

enter description here

RNN节点内部连接.jpg

矩阵向量化表示

所以梯度为:

其中是点乘符号,即对应元素乘。

代码实现:
我们可以注意到在计算梯度时需要用到的之前计算过的量,即需要保存的量包括,前向计算时隐层节点和输出节点的输出值,以及由时刻累积的

这篇文章里使用python实现了基本的RNN过程。代码功能是模拟二进制相加过程中的依次进位过程,代码很容易明白。
这里改写成matlab代码

  1. functionerror =binaryRNN( ) 
  2. largestNumber=256
  3. T=8
  4. dic=dec2bin(0:largestNumber-1)-'0';% 将uint8表示成二进制数组,这是一个查找表 
  5. %% 初始化参数 
  6. eta=0.1;% 学习步长 
  7. inputDim=2;% 输入维度 
  8. hiddenDim=16; %隐层节点个数 
  9. outputDim=1; % 输出层节点个数 
  10.  
  11. W=rand(hiddenDim,outputDim)*2-1;% (-1,1)参数矩阵 
  12. U=rand(hiddenDim,hiddenDim)*2-1;% (-1,1)参数矩阵 
  13. V=rand(inputDim,hiddenDim)*2-1;% (-1,1)参数矩阵 
  14.  
  15. delta_W=zeros(hiddenDim,outputDim);% 时刻间中间变量 
  16. delta_U=zeros(hiddenDim,hiddenDim); 
  17. delta_V=zeros(inputDim,hiddenDim); 
  18. error=0
  19. for p=1:10000 
  20. aInt=randi(largestNumber/2); 
  21. bInt=randi(largestNumber/2); 
  22. a=dic(aInt+1,:); 
  23. b=dic(bInt+1,:); 
  24. cInt=aInt+bInt; 
  25. c=dic(cInt+1,:); 
  26. y=zeros(1,T); 
  27.  
  28. preh=zeros(1,hiddenDim); 
  29. hDic=zeros(T,hiddenDim); 
  30. %% 前向计算 
  31. for t=T:-1:1% 注意应该从最低位计算,也就是二进制数组最右端开始计算 
  32. x=[a(t),b(t)];  
  33. h=sigmoid(x*V+preh*U); 
  34. y(t)=sigmoid(h*W);  
  35. hDic(t,:)=h; 
  36. preh=h; 
  37. end 
  38.  
  39. err=y-c; 
  40. error=error+norm(err,2)/2
  41. next_delta_h=zeros(1,hiddenDim); 
  42. %% 反馈 
  43. for t=1:T 
  44. delta_y = err(t).*sigmoidOutput2d(y(t)); 
  45. delta_h=(delta_y*W'+next_delta_h*U').*sigmoidOutput2d(hDic(t,:)); 
  46.  
  47. delta_W=delta_W+hDic(t,:)'*delta_y; 
  48. if t<T 
  49. delta_U=delta_U+hDic(t+1,:)'*delta_h; 
  50. end 
  51. delta_V=delta_V+[a(t),b(t)]'*delta_h; 
  52. next_delta_h=delta_h;  
  53. end 
  54. % 梯度下降 
  55. W=W-eta*delta_W; 
  56. U=U-eta*delta_U; 
  57. V=V-eta*delta_V; 
  58.  
  59. delta_W=zeros(hiddenDim,outputDim); 
  60. delta_U=zeros(hiddenDim,hiddenDim); 
  61. delta_V=zeros(inputDim,hiddenDim); 
  62.  
  63. ifmod(p,1000)==0 
  64. fprintf('Samples:%d\n',p); 
  65. fprintf('True:%d\n',cInt); 
  66. fprintf('Predict:%d\n',bin2dec(int2str(round(y)))); 
  67. fprintf('Error:%f\n',norm(err,2)/2); 
  68. end 
  69. end 
  70. end 
  71.  
  72. functionsx=sigmoid(x) 
  73. sx=1./(1+exp(-x)); 
  74. end 
  75.  
  76. functiondx=sigmoidOutput2d(output) 
  77. dx=output.*(1-output); 
  78. end 
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
RNN(循环神经网络)是一种能够处理序列数据的神经网络模型。它通过自循环的方式将前一时刻的隐藏状态信息传递给下一时刻,以此来建模序列中的时序关系。 RNN的反向传播算法主要包含以下几个步骤: 1. 初始化:首先,我们需要初始化模型的参数,包括权重和偏置。这些参数会在反向传播过程中根据损失函数来进行调整。 2. 前向传播:在反向传播之前,我们需要先进行一次前向传播。假设我们有一个包含T个时刻的序列数据,每个时刻的输入是一个D维的向量,隐藏状态的维度为H。对于每个时刻t,我们先计算当前时刻的隐藏状态,根据当前时刻的输入数据和前一时刻的隐藏状态: ht = activation(Wx * Xt + Wh * ht-1 + b) 其中,Wx和Wh分别是输入与隐藏状态之间的权重矩阵,b是偏置项,activation是激活函数。 3. 计算损失函数:根据预测结果和真实结果计算损失函数,常见的损失函数包括均方差误差和交叉熵等。损失函数衡量了模型的预测与真实结果之间的差距。 4. 反向传播:在RNN中,由于隐藏状态之间存在时序关系,我们需要考虑到每个时刻的梯度对前一时刻的梯度的影响。首先,我们计算当前时刻的梯度: dht = dout + dht+1 其中,dout是损失函数对当前时刻的输出的导数。然后,我们利用当前时刻的梯度来计算当前时刻的权重矩阵和偏置项的梯度: dWx += Xt * dht dWh += ht-1 * dht db += dht 接下来,我们计算对前一时刻隐藏状态的梯度: dht-1 = Wh * dht 最后,我们利用当前时刻的梯度和前一时刻的梯度来计算损失函数对输入的导数: dXt = Wx * dht + dXt+1 这样就完成了一个时刻的反向传播。重复以上步骤,可以依次计算每个时刻的梯度,从而完成整个反向传播的过程。 5. 更新参数:最后,利用计算得到的梯度信息更新模型的参数。采用梯度下降法,通过调整参数,使得损失函数尽可能地减小。 总结起来,RNN的反向传播算法通过自循环的方式将梯度从当前时刻传递到前一时刻,并利用当前时刻和前一时刻的梯度来计算参数的梯度,然后通过梯度下降法来更新参数,从而优化模型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值