【Python机器学习】循环神经网络(RNN)——利用Keras实现循环神经网络

首先,加载数据集,获取标签并随机打乱样本,然后对文档分词并使用Word2vec模型使其向量化,接下来,获取标签,最后按照80/20的比例将原始数据分成训练集和测试集。

首先,导入数据处理和循环神经网络训练所需的所有模块:

python 复制代码
import glob
import os
from random import shuffle
from nltk.tokenize import TreebankWordTokenizer
from nlpia.loaders import get_data
from gensim.models.keyedvectors import KeyedVectors

word_vectors=KeyedVectors.load_word2vec_format('GoogleNews-vectors-negative300.bin',binary=True,limit=2000)

然后,我们可以构建数据预处理模块,它能对数据进行训练前的处理:

python 复制代码
def pre_process_data(filepath):
    positive_path=os.path.join(filepath,'pos')
    negative_path=os.path.join(filepath,'neg')
    pos_label=1
    neg_label=0
    dataset=[]
    for filename in glob.glob(os.path.join(positive_path,'*.txt')):
        with open(filename,'r') as f:
            dataset.append((pos_label,f.read()))
    for filename in glob.glob(os.path.join(negative_path,'*.txt')):
        with open(filename,'r') as f:
            dataset.append((neg_label,f.read()))
    shuffle(dataset)
    return dataset

将数据分词和向量化的方法写在一个函数中:

python 复制代码
def tokenize_and_vectorize(dataset):
    tokenizer=TreebankWordTokenizer()
    vectorized_data=[]
    for sample in dataset:
        tokens=tokenizer.tokenize(sample[1])
        sample_vecs=[]
        for token in tokens:
            try:
                sample_vecs.append(word_vectors[token])
            except:
                pass
        vectorized_data.append(sample_vecs)
    return vectorized_data

将目标变量提取(解压)到单独的(但对应的)样本中:

python 复制代码
def collect_excepted(dataset):
    excepted=[]
    for sample in dataset:
        excepted.append(sample[0])
    return excepted

在数据上运行:

python 复制代码
dataset=pre_process_data('C:\\Users\\86185\\PycharmProjects\\pythonProject\\NLP\\aclImdb\\train')
vectorized_data=tokenize_and_vectorize(dataset)
excepted=collect_excepted(dataset)
split_point=int(len(vectorized_data)*0.8)
X_train=vectorized_data[:split_point]
y_train=excepted[:split_point]
X_test=vectorized_data[split_point:]
y_test=excepted[split_point:]

下面将为这个模型使用相同的超参数:每个样本使用400个词条,批大小为32。词向量是300维,我们将让它运行2个周期:

python 复制代码
maxlen=400
batch_size=32
embedding_dims=300
epochs=2

接下来,再次填充和截断样本。通常我们不需要对循环神经网络使用填充或截断,因为它们可以处理任意长度的输入序列。但是,在接下来的几个步骤中,我们将看到所使用的模型要求输入指定长度的序列:

python 复制代码
def pad_turnc(data,maxlen):
    new_data=[]
    zero_vector=[]
    for _ in range(len(data[0][0])):
        zero_vector.append(0.0)
    for sample in data:
        if len(sample)>maxlen:
            temp=sample[:maxlen]
        elif len(sample)<maxlen:
            temp=sample
            additional_elems=maxlen-len(sample)
            for _ in range(additional_elems):
                temp.append(zero_vector)
        else:
            temp=sample
        new_data.append(temp)
    return new_data

import numpy as np

X_train=pad_turnc(X_train,maxlen)
X_test=pad_turnc(X_test,maxlen)

X_train=np.reshape(X_train,(len(X_train),maxlen,embedding_dims))
y_train=np.array(y_train)

X_test=np.reshape(X_test,(len(X_test),maxlen,embedding_dims))
y_test=np.array(y_test)

现在已经有了数据,是时候构建模型了。我们将再次从Keras的一个标准的分层模型Sequential()(分层的)模型开始:

python 复制代码
from keras.api.models import Sequential
from keras.api.layers import Dense,Dropout,Flatten,SimpleRNN
num_neurons=50
model=Sequential()

然后,Keras处理了组装神经网络的各个复杂环节:我们只需要将想要的循环层添加到网络中:

python 复制代码
model.add(SimpleRNN(
    num_neurons,return_sequences=True,
    input_shape=(maxlen,embedding_dims)
))

现在,基础模块已经搭建完毕,可以接收各个输入并将其传递到一个简单的循环神经网络中,对于每个词条,将它们的输出集合到一个向量中。因为序列有400个词条长,并且使用了50个隐藏层神经元,所以这一层的输出将是一个400个元素的向量,其中每个元素都是一个50个元素的向量,每个神经元对应着一个输出。

关键词采纳数return_sequences会告诉网络每个时刻都要返回网络输出,因此有400个向量,每个向量为50维。如果return_sequences被设置为False,那么只会返回最后一个时刻的50维向量。

在本例中,50个神经元的选择是任意的,主要是为了减少计算时间。

使用循环神经网络时,通常不需要使用截断和填充。我们可以提供不同长度的训练数据,并展开网络直到输入结束,Keras对此会自动处理。问题是循环层的输出长度会随着输入时刻的变化而变化。4个词条的输入将输出4个元素长的序列。100个词条的输入将输出100个元素长的序列。如果我们需要把它传递到另一个层,即一个期望输入的维度统一的层,那么上述不等长的结果就会出现问题。但在某些情况下,这种不等长的序列输入也是可以接受的,甚至本来就期望如此。

python 复制代码
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(1,activation='sigmoid'))

我们要求上述简单的RNN返回完整的序列,但是为了防止过拟合,我们添加了一个Dropout层,在每个输入样本上随机选择输入,使这些输入有20%的概率为零,最后再添加一个分类器。在这种情况下,我们只有一个类:"Yes-Positive Sentiemnt-1"或"No-Negative Sentiment-0",所以我们选择只有单个神经元(Dense(1))的层并使用Sigmoid激活函数。但是该稠密层需要输入一个由n个元素组成的扁平的训练(每个元素都是一个浮点数)。SimpleRNN输出的是一个400个元素长的张量,张量中的每个元素都是50个元素长。但是前馈网络并不关心元素的顺序而只关心输入是否符合网络的需要,所以我们使用Keras提供 的一个非常方便的网络层Flatten()将输入从400*50的张量扁平化为一个长度为20000个元素的向量。这就是我们要传递到最后一次用来做分类的向量。实际上,Flatten是一个映射,这意味着误差将从最后一层反向传播回RNN层的输出,这些反向传播的误差之后将在输出的合适点随时间反向传播。

将循环神经网络层生成的"思想向量"传递到前馈网络中,将不再保留我们努力试图想要包含的输入顺序的关系。但重要的是,与词条的序列相关的"学习"发生在RNN层本身;通过随时间反向传播过程中误差的聚合将这种关系编码进了网络中,并将其表示为"思想向量"本身。我们基于思想向量做出的决策,通过分类器,就特定的分类问题向顺序向量的"质量"提供反馈。

相关推荐
网易独家音乐人Mike Zhou26 分钟前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
安静读书28 分钟前
Python解析视频FPS(帧率)、分辨率信息
python·opencv·音视频
Guofu_Liao2 小时前
大语言模型---LoRA简介;LoRA的优势;LoRA训练步骤;总结
人工智能·语言模型·自然语言处理·矩阵·llama
小二·2 小时前
java基础面试题笔记(基础篇)
java·笔记·python
小喵要摸鱼3 小时前
Python 神经网络项目常用语法
python
秀儿还能再秀4 小时前
神经网络(系统性学习三):多层感知机(MLP)
神经网络·学习笔记·mlp·多层感知机
一念之坤5 小时前
零基础学Python之数据结构 -- 01篇
数据结构·python
wxl7812275 小时前
如何使用本地大模型做数据分析
python·数据挖掘·数据分析·代码解释器
NoneCoder5 小时前
Python入门(12)--数据处理
开发语言·python
老艾的AI世界6 小时前
AI翻唱神器,一键用你喜欢的歌手翻唱他人的曲目(附下载链接)
人工智能·深度学习·神经网络·机器学习·ai·ai翻唱·ai唱歌·ai歌曲