一、什么是RNN
循环神经网络(Recurrent Neural Network,RNN)是一种用于处理序列数据的神经网络结构。与传统的前馈神经网络不同,RNN具有循环连接,可以使信息在网络中持续传递。这种结构使得RNN非常适合处理具有时间相关性的序列数据,如语言、时间序列等。
RNN的主要特点是它们可以接受任意长度的输入序列,并且能够记忆序列中之前的信息,这使得它们在处理序列数据时非常有用。在RNN中,每个时间步都有一个输入和一个隐藏状态,隐藏状态包含了该时间步之前的信息,并且会传递到下一个时间步中,从而影响后续的输出。
RNN在处理自然语言等序列式的问题中较为实用,因为RNN模型的输入和输出的长度都不需要固定。所以RNN很适合文本、语音持续序列等数据。
对于文本问题,输入和输出的长度并不固定,一句话可长可短。所以,输入的长度并不固定 输出的长度也不固定,比如把英语翻译成汉语。一句英语有十个单词,翻译成汉语,可能有十个字,可能有八个字,甚至可能是四个字的成语,输出的汉语的字数并不固定。所以这可能是一个多对多的模型。
二、RNN前向公式
上图二中输入是Xt,隐藏层是ht,输出层是Yt。
我们设
其中Zt为隐藏层的净输入值,激活函数sigmoid函数为ht,U和·W分别为隐藏状态下和输入状态下的权重,b为偏置,在这里为0。所以也可以写成
以下举个例子,如果我们看一段话,我们会是一个字一个字的看来累积到一去形成一段话,而我们使用RNN模型,RNN也会和我们一样将一个一个看懂的字给记录下来把所记下来的都会更新到yt里面。我们每次把一个词向量输入RNN。然后RNN就会更新状态y 把新的输入积累到状态y里面,y0里面包含了第一个词t的信息,而y1里面包含了x0和x1两个输入的词语。
由上面公式可推出最后的yt中包含了每个输入的x的值。
三、实例代码重点讲解
先确定要找的数据集
如果有的话就不用下载,我下载的数据集地址是:
https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb.npz
设置max_features是10000,意思是词典里有10000个词汇,
embedding_dim=32,意思是词向量x的维度是32。
maxlen=500,意思是每个电影评论有500个单词,如果超过了500个单词就会被截掉,只保留500个,如果不到500就用zero padding补成长度等于500。
state_dim=32,意思是RNN隐层状态的维度等于32
首先建了一个Sequential模型model然后往model里面加层。
首先是Embedding层用于将整数索引的单词映射到密集向量的嵌入空间中。参数max_features指定了词汇表的大小,embedding_dim指定了嵌入向量的维度,input_length指定了输入序列的长度。
然后是Simple RNN layer,需要指定状态向量yt的维度State dimension(state_dim)
最后是Dense全连接层, 输入RNN的最后一个状态yt,输出一个0-1之间的数,输出维度是1,这里我们设置RNN层的,意思是RNN只输出最后一个状态向量,把之前的状态向量全都扔掉。
这个train函数用于训练模型: train_data:训练数据,是一个Numpy数组,包含输入样本,
train_labels:训练标签,是一个Numpy数组,包含对应的目标标签,
epochs:训练的轮数,即遍历整个训练数据集的次数,默认为10轮,
batch_size:每个批次中的样本数,默认为128,
validation_split:用于验证集划分的比例,默认为0.2,表示将训练数据的20%用作验证集。该函数的功能是使用给定的训练数据和标签来训练模型,并返回一个History对象,其中包含了训练过程中的损失值和指标值的记录。在训练过程中,模型将根据给定的损失函数和优化器对训练数据进行反向传播和参数更新。
def train(self, train_data, train_labels, epochs=10, batch_size=128, validation_split=0.2):
return self.model.fit(train_data, train_labels, epochs=epochs, batch_size=batch_size,
validation_split=validation_split)
Embedding层的输出是一个500×32的矩阵,500的意思是每个电影评论有500个单词,32的意思是每个单词用32维的词向量表示。
Simple RNN的输出是一个32维的向量,它是RNN的最后一个状态向量yt,前面所有的状态向量都已经被扔掉了
Dense层的输出已经定位输出一维。
最后训练模型epochs= 10遍历整个训练数据集十次,batch_size=128,默认每个批次的样本数为128个,validation_split=0.2划分验证集的比例。
history = rnn_classifier.train(train_data, train_labels, epochs=10, batch_size=128, validation_split=0.2)
四、完整代码
# -*- coding: utf-8 -*-
import os
from tensorflow.keras.datasets import imdb
from tensorflow.keras.preprocessing import sequence
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, SimpleRNN, Dense
from urllib.request import urlretrieve
class RNNClassifier:
def __init__(self, max_features=10000, maxlen=500, embedding_dim=32, state_dim=32):
self.max_features = max_features
self.maxlen = maxlen
self.embedding_dim = embedding_dim
self.state_dim = state_dim
# 创建模型
self.model = Sequential()
self.model.add(Embedding(max_features, embedding_dim, input_length=maxlen))
self.model.add(SimpleRNN(state_dim))
self.model.add(Dense(1, activation='sigmoid'))
# 编译模型
self.model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
def train(self, train_data, train_labels, epochs=10, batch_size=128, validation_split=0.2):
return self.model.fit(train_data, train_labels, epochs=epochs, batch_size=batch_size, validation_split=validation_split)
def evaluate(self, test_data, test_labels):
return self.model.evaluate(test_data, test_labels)
def summary(self):
self.model.summary()
# 设置参数
max_features = 10000 # 词汇量
maxlen = 500 # 截断长度
# 检查并下载数据集
imdb_path = "imdb.npz"
if not os.path.exists(imdb_path):
url = "https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb.npz"
print("正在下载 IMDB 数据集...")
urlretrieve(url, imdb_path)
print("下载完成.")
# 加载并预处理数据集
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(path=imdb_path, num_words=max_features)
train_data = sequence.pad_sequences(train_data, maxlen=maxlen)
test_data = sequence.pad_sequences(test_data, maxlen=maxlen)
# 创建 RNN 分类器实例
rnn_classifier = RNNClassifier(max_features, maxlen)
# 训练模型
history = rnn_classifier.train(train_data, train_labels, epochs=10, batch_size=128, validation_split=0.2)
# 打印模型摘要
rnn_classifier.summary()
# 评估模型性能
loss, accuracy = rnn_classifier.evaluate(test_data, test_labels)
print('测试集损失:', loss)
print('测试集准确率:', accuracy)