深入 RNN(GRU)模型:输入输出维度变化全解析
各位观众老爷, 我是诗人啊_
最近在整理RNN
的相关知识点, 发现输入输出维度,特别容易混淆, 所以想着发一篇文章, 进行梳理, 希望能帮助到大家~
各位观众老爷可以点点关注
不咯~ (简单实用, 注释清晰, 看了包会的)
前言
在循环神经网络(RNN)的学习与实践中,理解数据在模型各层的维度变化是关键环节
本文将围绕基于 GRU(Gated Recurrent Unit )的编码器,详细拆解从输入数据到模型输出过程中每一步的维度流转逻辑,结合实际代码示例,带你清晰掌握 RNN 模型中维度变化的底层规律
一、模型整体架构与核心组件
我们以一个基础的编码器(Encoder)为例,它主要包含词嵌入层(Embedding Layer)和 GRU 层,用于处理序列数据(如文本序列),代码如下:
import torch.nn as nn
# 定义编码器Encoder
class Encoder(nn.Module):
# 1. 初始化
def __init__(self, input_size, hidden_size):
super().__init__()
self.input_size = input_size
self.hidden_size = hidden_size
# 定义词嵌入层
self.embedding = nn.Embedding(input_size, hidden_size)
# 定义gru层
self.gru = nn.GRU(hidden_size, hidden_size, batch_first=True) # 加batch_first的目的是
# 规范forward 过程中接收的输入数据,以及它返回的输出数据(output 和 hidden)的维度顺序
# 2. 前向传播
def forward(self, input, hidden):
# 100, 5 100, 5, 128
# 2.1 接收的数据经过词嵌入层 原本维度(batch_size, seq_len) ----> (batch_size, seq_len, hidden_size )
output = self.embedding(input)
# 2.2 数据经过gru层 # gru接收的是经过词嵌入层self.embedding后的数据维度, 所以用out,
# 这也是为什么定义时nn.GRU(hidden_size, hidden_size, batch_first=True)的原因
output, hidden = self.gru(output, hidden)
# 总结:
'''
输入: input.shape --> (batch_size, seq_len) = (100,5) --经过词嵌入层后,会在最后加上hidden_size维度--> (100,5,128)
输出output: output.shape --> (batch_size, seq_len, hidden_size) --> (100,5,128)
输出hidden: hidden.shape --> (gru层数 * 方向数 , batch_size, hidden_size) --> (1,100,128)
'''
# 2.3 返回值
return output, hidden
# 总结:
'''
输入: input.shape --> (batch_size, seq_len) = (100,5) --经过词嵌入层后,会在最后加上hidden_size维度--> (100,5,128)
输出output: output.shape --> (batch_size, seq_len, hidden_size) --> (100,5,128)
输出hidden: hidden.shape --> (gru层数 * 方向数 , batch_size, hidden_size) --> (1,100,128)
'''
二、各层维度变化详解
(一)输入数据初始形态
在处理序列任务(如文本)时,输入数据 input
通常是经过预处理的整数序列,其维度为 (batch_size, seq_len)
,含义如下:
batch_size
:表示一次训练或推理时处理的样本数量,例如一次处理 100 条文本,batch_size
就是 100 。seq_len
:表示每条样本(如文本句子)的序列长度,假设每条文本固定为 5 个单词,seq_len
就是 5 ,即input.shape = (100, 5)
。
(二)词嵌入层(Embedding Layer)
词嵌入层的作用是将整数序列(单词索引)转换为低维稠密向量,代码中 self.embedding = nn.Embedding(input_size, hidden_size)
,它会把 (batch_size, seq_len)
维度的输入,变换为 (batch_size, seq_len, hidden_size)
维度的输出 。
- 变换逻辑:为序列中的每个位置(单词索引)分配一个
hidden_size
维度的向量表示,比如hidden_size = 128
时,经过词嵌入层后,数据维度就从(100, 5)
变为(100, 5, 128)
,这样就把离散的单词索引转化为了连续的向量,便于模型学习语义信息。
(三)GRU 层(Gated Recurrent Unit)
GRU 层接收词嵌入层输出的数据,其定义 self.gru = nn.GRU(hidden_size, hidden_size, batch_first=True)
中:
batch_first=True
:设置批量维度在前,让输入输出数据的维度顺序更符合我们组织数据的习惯,即输入输出的第一维度是batch_size
。- 输入维度要求:与词嵌入层输出维度匹配,为
(batch_size, seq_len, hidden_size)
,也就是前面得到的(100, 5, 128)
形态的数据。 - 输出维度:
output
:维度保持(batch_size, seq_len, hidden_size)
,它包含了 GRU 层在序列每个时间步(每个单词位置)的输出特征,比如还是(100, 5, 128)
,这些特征可用于后续的序列分类、解码等操作。hidden
:维度为(gru层数 * 方向数, batch_size, hidden_size)
,由于这里是单层单向 GRU(默认配置),所以维度是(1, batch_size, hidden_size)
,即(1, 100, 128)
,它代表 GRU 层最后一个时间步的隐藏状态,蕴含了整个序列的关键信息 。
三、维度变化总结
为了更直观呈现,用表格梳理各环节维度变化:
处理环节 | 输入维度 | 输出维度 | 关键说明 |
---|---|---|---|
原始输入 | (batch_size, seq_len) | - | 离散单词索引序列 |
词嵌入层 | (batch_size, seq_len) | (batch_size, seq_len, hidden_size) | 转换为稠密向量表示 |
GRU 层 | (batch_size, seq_len, hidden_size) | output: (batch_size, seq_len, hidden_size) hidden: (1, batch_size, hidden_size) |
输出序列特征和最终隐藏状态 |
通过这样一步步的维度拆解,就能清晰理解 RNN(GRU)模型中数据是如何在各层流转、变换的,这对于调试模型、设计网络结构都有着重要意义,帮助我们更精准地把控模型输入输出,避免因维度不匹配引发错误,也能让我们更深入理解模型对序列数据的处理逻辑 。
作者有话:
感谢您观看到这里, AI、人工智能
系列文章(基础向)稳定更新中, 如果您感兴趣, 欢迎一键三连~
我是**诗人啊_程序员
**, 我致力于编写出让小白也能轻松上文的技术博客~ 求个关注呗~