MindSpore开发之路(十一):构建循环神经网络(RNN):`RNN`, `LSTM`, `Embedding`层

在上一篇文章中,我们探索了卷积神经网络(CNN)如何像"火眼金睛"一样高效地处理图像数据。然而,现实世界中的数据并非都是静态的图片,还有大量按顺序排列的数据,例如一段文字、一首乐曲、或者一段时间内的股票价格。这类数据被称为序列数据

1. RNN是什么

对于序列数据,CNN那种"一视同仁"的局部感知能力就不太够用了,因为序列中的每个元素都可能与它之前的所有元素相关。这时,我们就需要一种新的网络结构------循环神经网络(Recurrent Neural Network, RNN)

RNN就像一个拥有"记忆"的阅读者。当它处理序列中的一个元素时(比如一个单词),它不仅会关注这个单词本身,还会参考它对前面所有单词的"记忆"。这种循环往复、承前启后的机制,使得RNN在自然语言处理(NLP)、时间序列预测等领域取得了巨大成功。

本篇文章将带您走进RNN的世界,重点介绍在MindSpore中构建RNN模型所需的三个核心"零件"。

2. RNN的核心"零件"

处理序列数据,尤其是文本数据时,我们通常需要以下三个关键组件的配合。

2.1 词嵌入层 (nn.Embedding):文字到向量的桥梁

计算机无法直接理解"你好"、"世界"这样的文字。为了让神经网络能够处理文本,我们首先需要将每个字或词转换成一个固定长度的数字向量。这个过程就叫做词嵌入(Word Embedding)

  • 工作原理nn.Embedding层就像一本"密码本"(或字典)。你首先要确定你的词汇表有多大(vocab_size),以及你想用多长的向量来表示一个词(embedding_size)。nn.Embedding层内部会维护一个vocab_size * embedding_size大小的查询表。当你输入一个词的索引(一个整数)时,它就会从表中查出对应的向量作为输出。

  • 关键参数

    • vocab_size (int): 词汇表的大小。例如,如果你的词典里有1000个不同的词,这个值就是1000。
    • embedding_size (int): 用来表示一个词的向量的维度。
  • 代码示例

python 复制代码
import mindspore
from mindspore import nn, Tensor
import numpy as np

# 假设我们的词汇表大小为1000,每个词用100维的向量表示
vocab_size = 1000
embedding_size = 100

# 定义一个Embedding层
embedding_layer = nn.Embedding(vocab_size, embedding_size)

# 假设我们有一句话,它包含4个词,其在词典中的索引分别是 1, 5, 99, 0
# 输入的shape通常是 (batch_size, sequence_length)
input_indices = Tensor([[1, 5, 99, 0]], mindspore.int32)

# 将索引输入Embedding层
output_vectors = embedding_layer(input_indices)

print("输入索引的尺寸:", input_indices.shape)
print("输出词向量的尺寸:", output_vectors.shape) # (1, 4, 100)

2.2 循环神经网络层 (nn.RNN):最初的"记忆"单元

nn.RNN是MindSpore中基础的循环神经网络层。

  • 工作原理 :RNN的核心在于其内部的"循环"。对于一个长度为L的序列,RNN层会按时间步从t=0t=L-1依次处理每个元素的向量。在每个时间步t,它会接收两个输入:

    1. 当前时间步的输入向量 x_t
    2. 上一个时间步的隐藏状态 h_{t-1}(可以理解为"短期记忆")。

    它将这两个输入融合,计算出当前时间步的输出 output_t 和新的隐藏状态 h_t,然后将 h_t 传递给下一个时间步。这个 h_t 就构成了RNN的"记忆"。

  • 关键参数

    • input_size (int): 输入向量的维度(通常等于embedding_size)。
    • hidden_size (int): 隐藏状态向量的维度。
    • batch_first (bool): 如果为True,则输入和输出Tensor的维度顺序为 (batch, seq_len, input_size),这通常更直观。
  • 代码示例

python 复制代码
# 承接上例,词向量维度为100,我们设定RNN的隐藏层维度为32
input_size = 100
hidden_size = 32
seq_len = 4 # 序列长度
batch_size = 1 # 批量大小

# 定义一个RNN层
# batch_first=True 让输入的第一维是batch_size
rnn_layer = nn.RNN(input_size, hidden_size, batch_first=True)

# 将Embedding层的输出作为RNN的输入
# output_vectors 的 shape 是 (1, 4, 100)
output, hidden_state = rnn_layer(output_vectors)

print("RNN输出(所有时间步)的尺寸:", output.shape) # (1, 4, 32)
print("RNN最后一个时间步的隐藏状态尺寸:", hidden_state.shape) # (1, 1, 32)

局限性 :基础的RNN存在一个著名的问题------梯度消失/爆炸。当序列很长时,它很难学习到序列开头的"长期依赖"信息,就像一个人记性不好,读到后面就忘了前面讲了什么。

2.3 长短期记忆网络层 (nn.LSTM):更强大的"记忆"单元

为了解决RNN的"记性差"的问题,研究者们设计了长短期记忆网络(Long Short-Term Memory, LSTM)。LSTM是RNN的一种变体,也是目前应用最广泛的循环神经网络之一。

  • 工作原理 :LSTM的核心在于其内部精巧的"门控机制"。相比于RNN简单的隐藏状态,LSTM引入了一个细胞状态(Cell State),可以看作是"长期记忆"。它还设计了三个"门"来控制信息的流动:

    1. 遗忘门(Forget Gate):决定从长期记忆中丢弃哪些信息。
    2. 输入门(Input Gate):决定将哪些新的信息存入长期记忆。
    3. 输出门(Output Gate):决定从长期记忆中输出哪些信息作为当前时间步的隐藏状态。

    通过这套机制,LSTM能够有选择地记忆和遗忘,从而有效地捕捉长距离依赖关系。

  • 关键参数 :与nn.RNN基本相同。

  • 代码示例

python 复制代码
# 定义一个LSTM层,参数与RNN类似
lstm_layer = nn.LSTM(input_size, hidden_size, batch_first=True)

# 将同样的词向量输入LSTM层
# LSTM的输出包含 output, (h_n, c_n)
output, (h_n, c_n) = lstm_layer(output_vectors)

print("LSTM输出(所有时间步)的尺寸:", output.shape) # (1, 4, 32)
print("LSTM最后一个时间步的隐藏状态尺寸:", h_n.shape) # (1, 1, 32)
print("LSTM最后一个时间步的细胞状态尺寸:", c_n.shape) # (1, 1, 32)

3. 组装一个简单的序列处理模型

现在,我们将这三个"零件"组装起来,构建一个可用于文本分类等任务的基础模型结构。

python 复制代码
import mindspore
from mindspore import nn

class SimpleSentimentClassifier(nn.Cell):
    def __init__(self, vocab_size, embedding_size, hidden_size, num_classes):
        super(SimpleSentimentClassifier, self).__init__()
        # 1. Embedding层
        self.embedding = nn.Embedding(vocab_size, embedding_size)
        
        # 2. LSTM层
        self.lstm = nn.LSTM(embedding_size, hidden_size, batch_first=True)
        
        # 3. 全连接层 (分类器)
        self.fc = nn.Dense(hidden_size, num_classes)

    def construct(self, x):
        # x 的 shape: (batch_size, seq_len)
        
        # 1. 经过Embedding层
        # embedded 的 shape: (batch_size, seq_len, embedding_size)
        embedded = self.embedding(x)
        
        # 2. 经过LSTM层
        # lstm_out shape: (batch_size, seq_len, hidden_size)
        # h_n shape: (1, batch_size, hidden_size)
        lstm_out, (h_n, c_n) = self.lstm(embedded)
        
        # 3. 我们通常取最后一个时间步的输出来代表整句话的语义
        # last_output shape: (batch_size, hidden_size)
        last_output = lstm_out[:, -1, :]
        
        # 4. 经过全连接层得到分类结果
        # logits shape: (batch_size, num_classes)
        logits = self.fc(last_output)
        
        return logits

# 实例化网络
model = SimpleSentimentClassifier(vocab_size=1000, 
                                embedding_size=100, 
                                hidden_size=32, 
                                num_classes=2) # 假设是二分类(如情感积极/消极)
print(model)

4. 总结

在本篇文章中,我们学习了处理序列数据的利器------循环神经网络,并掌握了其在MindSpore中的三个核心组件:

  • nn.Embedding:将离散的词符转换为密集的向量,是处理文本数据的第一步。
  • nn.RNN:基础的循环网络层,通过传递隐藏状态来维持"短期记忆"。
  • nn.LSTM:RNN的强大变体,通过精巧的门控机制实现了"长短期记忆",能更好地捕捉序列中的长距离依赖。

通过组合这三个组件,我们构建了一个简单的序列处理模型,为后续进行文本分类、机器翻译等NLP实战任务奠定了基础。

在下一篇文章中,我们将学习训练过程中的得力助手------回调函数(Callbacks),敬请期待!

相关推荐
机器学习之心4 小时前
科研绘图 | PSO-LSTM粒子群优化长短期记忆神经网络模型结构图
人工智能·神经网络·lstm·pso-lstm
代码洲学长4 小时前
RNN模型01
人工智能·python·rnn·自然语言处理·gru·lstm
机器学习之心1 天前
贝叶斯优化Transformer-LSTM的模型结构图
深度学习·lstm·transformer
木头左1 天前
集成学习方法在LSTM交易预测中的应用多元入参的作用
机器学习·lstm·集成学习
weixin_404679311 天前
VL-JEPA: Joint Embedding Predictive Architecture for Vision-language
embedding
机器学习之心2 天前
一张Transformer-LSTM模型的结构图
深度学习·lstm·transformer
Hcoco_me2 天前
cv::contourArea &&鞋带公式
人工智能·rnn·lstm
Are you manufacturer2 天前
Tetuan的电力消耗数据进行时间序列预测
数据分析·lstm
木头左3 天前
LSTM模型入参有效性验证基于量化交易策略回测的方法学实践
人工智能·rnn·lstm