【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层本身;通过随时间反向传播过程中误差的聚合将这种关系编码进了网络中,并将其表示为"思想向量"本身。我们基于思想向量做出的决策,通过分类器,就特定的分类问题向顺序向量的"质量"提供反馈。

相关推荐
全能全知者2 分钟前
不废话简单易懂的Selenium 页面操作与切换
python·selenium·测试工具·网络爬虫
你可以自己看2 小时前
python的基础语法
开发语言·python
FL16238631293 小时前
[技术杂谈]暗影精灵8plus电竞版台式机安装和使用注意
深度学习
夜清寒风3 小时前
opencv学习:图像掩码处理和直方图分析及完整代码
人工智能·opencv·学习·算法·机器学习·计算机视觉
akhfuiigabv3 小时前
使用Neo4j-Cypher-FT实现自然语言查询图数据库
数据库·python·oracle·neo4j
lizi888883 小时前
足球大小球及亚盘数据分析与机器学习实战详解:从数据清洗到模型优化
java·人工智能·机器学习·数据挖掘·数据分析
繁依Fanyi4 小时前
828华为云征文|华为Flexus云服务器搭建OnlyOffice私有化在线办公套件
服务器·开发语言·前端·python·算法·华为·华为云
zhangfeng11334 小时前
在 PyTorch 中,除了 pad_sequence 还有哪些其他处理序列数据的函数?时间序列数据 预处理
人工智能·pytorch·python·深度学习
python1564 小时前
Python Numpy布尔数组在数据分析中的应用
python·数据分析·numpy
AIAdvocate4 小时前
力扣-96.不同的二叉搜索树 题目详解
python·算法·动态规划