多层 RNN原理以及实现

数学原理


多层 RNN 的核心思想是堆叠多个 RNN 层,每一层的输出作为下一层的输入,从而逐层提取更高层次的抽象特征。


1. 单层 RNN 的数学表示

首先,单层 RNN 的计算过程如下。对于一个时间步 t t t,单层 RNN 的隐藏状态 h t h_t ht 和输出 y t y_t yt 可以表示为:

h t = activation ( W i h x t + b i h + W h h h t − 1 + b h h ) h_t = \text{activation}(W_{ih} x_t + b_{ih} + W_{hh} h_{t-1} + b_{hh}) ht=activation(Wihxt+bih+Whhht1+bhh)
y t = W h o h t + b h o y_t = W_{ho} h_t + b_{ho} yt=Whoht+bho

其中:

  • x t x_t xt 是时间步 t t t 的输入。
  • h t h_t ht 是时间步 t t t 的隐藏状态。
  • h t − 1 h_{t-1} ht1 是时间步 t − 1 t-1 t1 的隐藏状态。
  • W i h W_{ih} Wih W h h W_{hh} Whh W h o W_{ho} Who 是权重矩阵。
  • b i h b_{ih} bih b h h b_{hh} bhh b h o b_{ho} bho 是偏置项。
  • activation \text{activation} activation 是激活函数(如 tanh ⁡ \tanh tanh ReLU \text{ReLU} ReLU)。

2. 多层 RNN 的数学表示

假设我们有一个 L L L 层的 RNN,每一层的隐藏状态为 h t ( l ) h_t^{(l)} ht(l),其中 l l l 表示第 l l l 层, t t t 表示时间步。多层 RNN 的计算过程如下:

(1) 第一层( l = 1 l = 1 l=1

第一层的输入是原始输入序列 x t x_t xt,隐藏状态 h t ( 1 ) h_t^{(1)} ht(1) 的计算公式为:

h t ( 1 ) = activation ( W i h ( 1 ) x t + b i h ( 1 ) + W h h ( 1 ) h t − 1 ( 1 ) + b h h ( 1 ) ) h_t^{(1)} = \text{activation}(W_{ih}^{(1)} x_t + b_{ih}^{(1)} + W_{hh}^{(1)} h_{t-1}^{(1)} + b_{hh}^{(1)}) ht(1)=activation(Wih(1)xt+bih(1)+Whh(1)ht1(1)+bhh(1))

其中:

  • W i h ( 1 ) W_{ih}^{(1)} Wih(1) W h h ( 1 ) W_{hh}^{(1)} Whh(1) 是第一层的权重矩阵。
  • b i h ( 1 ) b_{ih}^{(1)} bih(1) b h h ( 1 ) b_{hh}^{(1)} bhh(1) 是第一层的偏置项。
(2) 第 l l l 层( l > 1 l > 1 l>1

l l l 层的输入是第 l − 1 l-1 l1 层的输出 h t ( l − 1 ) h_t^{(l-1)} ht(l1),隐藏状态 h t ( l ) h_t^{(l)} ht(l) 的计算公式为:

h t ( l ) = activation ( W i h ( l ) h t ( l − 1 ) + b i h ( l ) + W h h ( l ) h t − 1 ( l ) + b h h ( l ) ) h_t^{(l)} = \text{activation}(W_{ih}^{(l)} h_t^{(l-1)} + b_{ih}^{(l)} + W_{hh}^{(l)} h_{t-1}^{(l)} + b_{hh}^{(l)}) ht(l)=activation(Wih(l)ht(l1)+bih(l)+Whh(l)ht1(l)+bhh(l))

其中:

  • W i h ( l ) W_{ih}^{(l)} Wih(l) W h h ( l ) W_{hh}^{(l)} Whh(l) 是第 l l l 层的权重矩阵。
  • b i h ( l ) b_{ih}^{(l)} bih(l) b h h ( l ) b_{hh}^{(l)} bhh(l) 是第 l l l 层的偏置项。
(3) 输出层

最后一层(第 L L L 层)的输出 h t ( L ) h_t^{(L)} ht(L) 作为整个网络的输出 y t y_t yt

y t = W h o h t ( L ) + b h o y_t = W_{ho} h_t^{(L)} + b_{ho} yt=Whoht(L)+bho

其中:

  • W h o W_{ho} Who b h o b_{ho} bho 是输出层的权重矩阵和偏置项。

3. 多层 RNN 的数据流向

以下是一个 L L L 层 RNN 的数据流向的数学描述:

(1) 输入序列

输入序列为 x 1 , x 2 , … , x T x_1, x_2, \dots, x_T x1,x2,,xT,其中 T T T 是序列长度。

(2) 初始化隐藏状态

每一层的初始隐藏状态 h 0 ( l ) h_0^{(l)} h0(l) 通常初始化为零或随机值:

h 0 ( l ) = 0 或 h 0 ( l ) ∼ N ( 0 , σ 2 ) h_0^{(l)} = \mathbf{0} \quad \text{或} \quad h_0^{(l)} \sim \mathcal{N}(0, \sigma^2) h0(l)=0h0(l)N(0,σ2)

(3) 时间步 t t t 的计算

对于每个时间步 t t t,从第一层到第 L L L 层依次计算隐藏状态:

  1. 第一层
    h t ( 1 ) = activation ( W i h ( 1 ) x t + b i h ( 1 ) + W h h ( 1 ) h t − 1 ( 1 ) + b h h ( 1 ) ) h_t^{(1)} = \text{activation}(W_{ih}^{(1)} x_t + b_{ih}^{(1)} + W_{hh}^{(1)} h_{t-1}^{(1)} + b_{hh}^{(1)}) ht(1)=activation(Wih(1)xt+bih(1)+Whh(1)ht1(1)+bhh(1))

  2. l l l 层( l > 1 l > 1 l>1
    h t ( l ) = activation ( W i h ( l ) h t ( l − 1 ) + b i h ( l ) + W h h ( l ) h t − 1 ( l ) + b h h ( l ) ) h_t^{(l)} = \text{activation}(W_{ih}^{(l)} h_t^{(l-1)} + b_{ih}^{(l)} + W_{hh}^{(l)} h_{t-1}^{(l)} + b_{hh}^{(l)}) ht(l)=activation(Wih(l)ht(l1)+bih(l)+Whh(l)ht1(l)+bhh(l))

  3. 输出
    y t = W h o h t ( L ) + b h o y_t = W_{ho} h_t^{(L)} + b_{ho} yt=Whoht(L)+bho

(4) 序列输出

最终,整个序列的输出为 y 1 , y 2 , … , y T y_1, y_2, \dots, y_T y1,y2,,yT


4. 多层 RNN 的特点

(1) 逐层抽象
  • 每一层 RNN 可以看作是对输入序列的不同层次的抽象。
  • 较低层捕捉局部和细节信息,较高层捕捉全局和语义信息。
(2) 参数共享
  • 每一层的参数(权重矩阵和偏置项)在时间步之间共享。
  • 不同层的参数是独立的。
(3) 梯度传播
  • 在反向传播时,梯度会通过时间步和层数传播。
  • 由于梯度消失或爆炸问题,训练深层 RNN 可能会比较困难。

可视化原理

下面是一个可视化的结构显示图:其中每一层神经元都要有两个方向的输出,一个是向本时间步的下一层传送,另一个是向下一个时间步的本层传送。而且,每一个神经元都有两个权重矩阵。注意:下方右图仅仅是逻辑上展开的数据流,其中不同世间步上的同一层,用的是同一个权重矩阵。

在这里插入图片描述

代码实现


1. 示例任务

假设有一个简单的任务:

  • 处理一个长度为 4 的序列
  • 批次大小为 2
  • 每个时间步的输入特征维度为 3
  • 希望使用一个 2 层的单向 RNN
  • 隐藏状态维度为 5。

2. 输入数据

输入句子
  • 句子 1: “I love PyTorch”
  • 句子 2: “RNN is fun”
输入数据的形状
  • 序列长度 (seq_len): 4(假设每个单词是一个时间步)
  • 批次大小 (batch_size): 2
  • 输入特征维度 (input_size): 3(假设每个单词用一个 3 维向量表示)
具体输入数据
import torch# 输入数据形状: (seq_len, batch_size, input_size)
input_data = torch.tensor([# 时间步 1[[0.1, 0.2, 0.3],  # 句子 1 的第一个单词[0.4, 0.5, 0.6]], # 句子 2 的第一个单词# 时间步 2[[0.7, 0.8, 0.9],  # 句子 1 的第二个单词[1.0, 1.1, 1.2]], # 句子 2 的第二个单词# 时间步 3[[1.3, 1.4, 1.5],  # 句子 1 的第三个单词[1.6, 1.7, 1.8]], # 句子 2 的第三个单词# 时间步 4[[1.9, 2.0, 2.1],  # 句子 1 的第四个单词[2.2, 2.3, 2.4]]  # 句子 2 的第四个单词
])
print("Input shape:", input_data.shape)  # 输出: torch.Size([4, 2, 3])

3. 初始隐藏状态

初始隐藏状态的形状
  • RNN 层数 (num_layers): 2
  • 方向数 (num_directions): 1(单向 RNN)
  • 批次大小 (batch_size): 2
  • 隐藏状态维度 (hidden_size): 5
具体初始隐藏状态
# 初始隐藏状态形状: (num_layers * num_directions, batch_size, hidden_size)
h0 = torch.zeros(2, 2, 5)  # 2层RNN,批次大小为2,隐藏状态维度为5
print("h0 shape:", h0.shape)  # 输出: torch.Size([2, 2, 5])

4. 定义 RNN 模型

import torch.nn as nn# 定义 RNN
rnn = nn.RNN(input_size=3,  # 输入特征维度hidden_size=5, # 隐藏状态维度num_layers=2,  # RNN 层数batch_first=False  # 输入形状为 (seq_len, batch_size, input_size)
)

5. 前向传播

计算输出
# 前向传播
output, hn = rnn(input_data, h0)print("Output shape:", output.shape)  # 输出: torch.Size([4, 2, 5])
print("hn shape:", hn.shape)          # 输出: torch.Size([2, 2, 5])
输出解析
  1. output:

    • 形状为 (seq_len, batch_size, hidden_size),即 (4, 2, 5)
    • 包含了每个时间步的隐藏状态。
    • 例如,output[0] 是第一个时间步的隐藏状态,output[-1] 是最后一个时间步的隐藏状态。
  2. hn:

    • 形状为 (num_layers, batch_size, hidden_size),即 (2, 2, 5)
    • 包含了最后一个时间步的隐藏状态。
    • 例如,hn[0] 是第一层的最终隐藏状态,hn[1] 是第二层的最终隐藏状态。

6. 具体输出值

output 的值
print("Output (所有时间步的隐藏状态):")
print(output)

输出示例:

tensor([[[ 0.1234,  0.5678,  0.9101,  0.1121,  0.3141],[ 0.4151,  0.6171,  0.8191,  0.0212,  0.2232]],[[ 0.4252,  0.6272,  0.8292,  0.0313,  0.2333],[ 0.4353,  0.6373,  0.8393,  0.0414,  0.2434]],[[ 0.4454,  0.6474,  0.8494,  0.0515,  0.2535],[ 0.4555,  0.6575,  0.8595,  0.0616,  0.2636]],[[ 0.4656,  0.6676,  0.8696,  0.0717,  0.2737],[ 0.4757,  0.6777,  0.8797,  0.0818,  0.2838]]],grad_fn=<StackBackward>)
hn 的值
print("hn (最后一个时间步的隐藏状态):")
print(hn)

输出示例:

tensor([[[ 0.4656,  0.6676,  0.8696,  0.0717,  0.2737],[ 0.4757,  0.6777,  0.8797,  0.0818,  0.2838]],[[ 0.4858,  0.6878,  0.8898,  0.0919,  0.2939],[ 0.4959,  0.6979,  0.8999,  0.1020,  0.3040]]],grad_fn=<StackBackward>)

batch_first=True时

以下是一个具体的例子,展示当 batch_first=True 时,PyTorch 中 torch.nn.RNN 的输入、输出以及参数的作用。


任务

假设有一个简单的任务:

  • 处理一个长度为 4 的序列
  • 批次大小为 2
  • 每个时间步的输入特征维度为 3
  • 希望使用一个 2 层的单向 RNN
  • 隐藏状态维度为 5
  • 并且设置 batch_first=True

2. 输入数据

输入句子
  • 句子 1: “I love PyTorch”
  • 句子 2: “RNN is fun”
输入数据的形状
  • 批次大小 (batch_size): 2
  • 序列长度 (seq_len): 4(假设每个单词是一个时间步)
  • 输入特征维度 (input_size): 3(假设每个单词用一个 3 维向量表示)
具体输入数据
import torch# 输入数据形状: (batch_size, seq_len, input_size)
input_data = torch.tensor([# 句子 1[[0.1, 0.2, 0.3],  # 第一个单词[0.7, 0.8, 0.9],  # 第二个单词[1.3, 1.4, 1.5],  # 第三个单词[1.9, 2.0, 2.1]], # 第四个单词# 句子 2[[0.4, 0.5, 0.6],  # 第一个单词[1.0, 1.1, 1.2],  # 第二个单词[1.6, 1.7, 1.8],  # 第三个单词[2.2, 2.3, 2.4]]  # 第四个单词
])
print("Input shape:", input_data.shape)  # 输出: torch.Size([2, 4, 3])

3. 初始隐藏状态

初始隐藏状态的形状
  • RNN 层数 (num_layers): 2
  • 方向数 (num_directions): 1(单向 RNN)
  • 批次大小 (batch_size): 2
  • 隐藏状态维度 (hidden_size): 5
具体初始隐藏状态
# 初始隐藏状态形状: (num_layers * num_directions, batch_size, hidden_size)
h0 = torch.zeros(2, 2, 5)  # 2层RNN,批次大小为2,隐藏状态维度为5
print("h0 shape:", h0.shape)  # 输出: torch.Size([2, 2, 5])

4. 定义 RNN 模型

import torch.nn as nn# 定义 RNN
rnn = nn.RNN(input_size=3,  # 输入特征维度hidden_size=5, # 隐藏状态维度num_layers=2,  # RNN 层数batch_first=True  # 输入形状为 (batch_size, seq_len, input_size)
)

5. 前向传播

计算输出
# 前向传播
output, hn = rnn(input_data, h0)print("Output shape:", output.shape)  # 输出: torch.Size([2, 4, 5])
print("hn shape:", hn.shape)          # 输出: torch.Size([2, 2, 5])
输出解析
  1. output:

    • 形状为 (batch_size, seq_len, hidden_size),即 (2, 4, 5)
    • 包含了每个时间步的隐藏状态。
    • 例如,output[0] 是第一个句子的所有时间步的隐藏状态,output[1] 是第二个句子的所有时间步的隐藏状态。
  2. hn:

    • 形状为 (num_layers, batch_size, hidden_size),即 (2, 2, 5)
    • 包含了最后一个时间步的隐藏状态。
    • 例如,hn[0] 是第一层的最终隐藏状态,hn[1] 是第二层的最终隐藏状态。

6. 具体输出值

output 的值
print("Output (所有时间步的隐藏状态):")
print(output)

输出示例:

tensor([[[ 0.1234,  0.5678,  0.9101,  0.1121,  0.3141],[ 0.4252,  0.6272,  0.8292,  0.0313,  0.2333],[ 0.4454,  0.6474,  0.8494,  0.0515,  0.2535],[ 0.4656,  0.6676,  0.8696,  0.0717,  0.2737]],[[ 0.4151,  0.6171,  0.8191,  0.0212,  0.2232],[ 0.4353,  0.6373,  0.8393,  0.0414,  0.2434],[ 0.4555,  0.6575,  0.8595,  0.0616,  0.2636],[ 0.4757,  0.6777,  0.8797,  0.0818,  0.2838]]],grad_fn=<TransposeBackward0>)
hn 的值
print("hn (最后一个时间步的隐藏状态):")
print(hn)

输出示例:

tensor([[[ 0.4656,  0.6676,  0.8696,  0.0717,  0.2737],[ 0.4757,  0.6777,  0.8797,  0.0818,  0.2838]],[[ 0.4858,  0.6878,  0.8898,  0.0919,  0.2939],[ 0.4959,  0.6979,  0.8999,  0.1020,  0.3040]]],grad_fn=<StackBackward>)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/66952.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RNA 测序技术概览(RNA-seq)

前言 转录组测序&#xff08;RNA-seq&#xff09;是当下最流行的二代测序&#xff08;NGS&#xff09;方法之一&#xff0c;使科研工作者实现在转录水平上定量、定性的研究&#xff0c;它的出现已经革命性地改变了人们研究基因表达调控的方式。然而&#xff0c;转录组测序&…

C语言练习(16)

猴子吃桃问题。猴子第一天摘下若干个桃子&#xff0c;当即吃了一半&#xff0c;还不过瘾&#xff0c;又多吃了一个。第二天早上又将剩下的桃子吃掉一半&#xff0c;又多吃了一个。以后每天早上都吃了前一天剩下的一半加一个。到第10天早上想再吃时&#xff0c;见只剩一个桃子了…

【机器学习】自定义数据集使用框架的线性回归方法对其进行拟合

一、使用框架的线性回归方法 1. 基础原理 在自求导线性回归中&#xff0c;我们需要先自定义参数&#xff0c;并且需要通过数学公式来对w和b进行求导&#xff0c;然后在反向传播过程中通过梯度下降的方式来更新参数&#xff0c;从而降低损失值。 2. 实现步骤 ① 散点输入 有一…

pytest执行报错:found no collectors

今天在尝试使用pytest运行用例的时候出现报错&#xff1a;found no collectors&#xff1b;从两个方向进行排查&#xff0c;一是看文件名和函数名是不是符合规范&#xff0c;命名要是"test_*"格式&#xff1b;二是是否存在修改文件名的情况&#xff0c;如果修改过文件…

mysql-06.JDBC

目录 什么是JDBC: 为啥存在JDBC: JDBC工作原理&#xff1a; JDBC的优势&#xff1a; 下载mysql驱动包&#xff1a; 用java程序操作数据库 1.创建dataSource: 2.与服务端建立连接 3.构造sql语句 4.执行sql 5.关闭连接&#xff0c;释放资源 参考代码&#xff1a; 插…

微信小程序wxs实现UTC转北京时间

微信小程序实现UTC转北京时间 打脸一刻&#xff1a;最近在迭代原生微信小程序&#xff0c;好一段时间没写原生的&#xff0c;有点不习惯&#xff1b; 咦&#xff0c;更新数据咋不生效呢&#xff1f;原来还停留在 this.xxx&#xff1b; 哟&#xff0c;事件又没反应了&#xff1f…

机器学习-线性回归(对于f(x;w)=w^Tx+b理解)

一、&#x1d453;(&#x1d499;;&#x1d498;) &#x1d498;T&#x1d499;的推导 学习线性回归&#xff0c;我们那先要对于线性回归的表达公示&#xff0c;有所认识。 我们先假设空间是一组参数化的线性函数&#xff1a; 其中权重向量&#x1d498; ∈ R&#x1d437; …

R语言学习笔记之语言入门基础

一、R语言基础 快速熟悉R语言中的基本概念&#xff0c;先入个门。 1、运算符 运算符含义例子加1 1-减3 - 2*乘3 * 2/除9 / 3^(**)乘方2 ^ 3 2 ** 3%%取余5 %% 2%/%取整5 %/% 2 2、赋值符号 等号a 1三者等价&#xff1a;把1赋值给变量a左箭头<−a <- 1右箭头−&g…

计算机网络三张表(ARP表、MAC表、路由表)总结

参考&#xff1a; 网络三张表&#xff1a;ARP表, MAC表, 路由表&#xff0c;实现你的网络自由&#xff01;&#xff01;_mac表、arp表、路由表-CSDN博客 网络中的三张表&#xff1a;ARP表、MAC表、路由表 首先要明确一件事&#xff0c;如果一个主机要发送数据&#xff0c;那么必…

【Nomoto 船舶模型】

【Nomoto 船舶模型】 1. Nomoto 船舶模型简介2. 来源及发展历程3. 构建 一阶模型Nomoto 船舶模型3.1 C 实现3.2 Python 实现3.3 说明 5. 参数辨识方法5.1 基于最小二乘法的参数辨识5.2 数学推导5.3 Python 实现5.4 说明 4. 结论参考文献 1. Nomoto 船舶模型简介 Nomoto 模型是…

差分进化算法 (Differential Evolution) 算法详解及案例分析

差分进化算法 (Differential Evolution) 算法详解及案例分析 目录 差分进化算法 (Differential Evolution) 算法详解及案例分析1. 引言2. 差分进化算法 (DE) 算法原理2.1 基本概念2.2 算法步骤3. 差分进化算法的优势与局限性3.1 优势3.2 局限性4. 案例分析4.1 案例1: 单目标优化…

深入理解GPT底层原理--从n-gram到RNN到LSTM/GRU到Transformer/GPT的进化

从简单的RNN到复杂的LSTM/GRU,再到引入注意力机制,研究者们一直在努力解决序列建模的核心问题。每一步的进展都为下一步的突破奠定了基础,最终孕育出了革命性的Transformer架构和GPT大模型。 1. 从n-gram到循环神经网络(RNN)的诞生 1.1 N-gram 模型 在深度学习兴起之前,处理…

【JWT】jwt实现HS、RS、ES、ED签名与验签

JWT 实现 HS、RS、ES 和 ED 签名与验签 签名方式算法密钥类型签名要点验签要点HSHMAC-SHA256对称密钥- 使用 crypto/hmac 和对称密钥生成 HMAC 签名- 将 header.payload 作为数据输入- 使用同一密钥重新计算 HMAC 签名- 比较计算结果与接收到的签名是否一致RSRSA-SHA256公钥 …

地址栏信息location

获取信息 页面跳转 location.href当前地址栏信息 location.assign()设置跳转新的页面 location.replace() location.reload()刷新页面

程序员转型测试:解锁漏洞挖掘新旅程

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 程序…

StarRocks常用命令

目录 1、StarRocks 集群管理&配置命令 2、StarRocks 常用操作命令 3、StarRocks 数据导入和导出 1、StarRocks 集群管理&配置命令 查询 FE 节点信息 SHOW frontends; SHOW PROC /frontends; mysql -h192.168.1.250 -P9030 -uroot -p -e "SHOW PROC /dbs;"…

08-ArcGIS For JavaScript-通过Mesh绘制几何体(Cylinder,Circle,Box,Pyramid)

目录 概述代码实现1、Mesh.createBox2、createPyramid3、Mesh.createSphere4、Mesh.createCylinder 完整代码 概述 对于三维场景而言&#xff0c;二位的点、线、面&#xff0c;三维的圆、立方体、圆柱等都是比较常见的三维对象&#xff0c;在ArcGIS For JavaScript中我们知道点…

Linux中page、buffer_head、bio的关系

在Linux中&#xff0c;page、buffer_head、bio这三个概念紧密相关&#xff0c;共同构成了块设备I/O和内存管理的重要部分&#xff0c;它们的联系主要体现在以下方面&#xff1a; page与buffer_head 基于page构建&#xff1a;buffer_head通常是基于page来构建的&#xff0c;一…

直线拟合例子 ,岭回归拟合直线

目录 直线拟合,算出离群点 岭回归拟合直线&#xff1a; 直线拟合,算出离群点 import cv2 import numpy as np# 输入的点 points np.array([[51, 149],[122, 374],[225, 376],[340, 382],[463, 391],[535, 298],[596, 400],[689, 406],[821, 407] ], dtypenp.float32)# 使用…

SpringCloud两种注册中心

SpringCloud 基本概念 系统架构 我们之前做的所有的项目都属于单体架构&#xff0c;下面我们将要学习更适合大型项目的分布式架构 单体架构&#xff1a; 将业务的所有功能几种在一个项目中开发&#xff0c;打成一个包部署。 优点&#xff1a;架构简单、部署成本低 缺点&am…