TensorFlow2.0(十二)--实现简单RNN与LSTM网络

前言

上篇博文TensorFlow2.0(十一)–理解LSTM网络我们详细解释了LSTM的工作原理与结构,这篇博文我们通过IMDB数据集来实现简单的RNN与LSTM网络对文本进行分类。

1. 导入相应的库

首先我们需要导入相应的python库

# matplotlib 用于绘图
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline
# 处理数据的库
import numpy as np
import sklearn
import pandas as pd
# 系统库
import os
import sys
import time
# TensorFlow的库
import tensorflow as tf
from tensorflow import keras

2. 加载与构建数据集

2.1 加载数据集

本次加载的数据集为IMDB,是一个电影评分数据集,标签有两种,positive和negative

# IMDB:一个电影评分数据集,有两类,positive与negative
imdb = keras.datasets.imdb
vocab_size = 10000
index_from = 3
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(
                                                       num_words = vocab_size,  # 数据中词表的个数,根据词出现的频次,前10000个会被保留,其余当做特殊字符处理
                                                       index_from = index_from) # 词表的下标从3开始计算

我们来看一下数据是什么样的:

print(train_data[0],train_labels[0])
print(train_data.shape, train_labels.shape)   # 每个训练样本都是变长的
print(len(train_data[0]), len(train_data[1])) # 比如第一个样本的长度是218,第二个样本的长度就是189
print(test_data.shape, test_labels.shape) 

在这里插入图片描述

2.2 构建词表

首先我们要获取词表:

word_index = imdb.get_word_index() # 获取词表
print(len(word_index)) # 打印词表长度
print(list(word_index.items())[:50])  # 打印词表的前50个 key:value形式

输出结果为:
在这里插入图片描述
可以看到我们的词表是字典形式的,key为单词,value是对应的ID。下面我们生成id到word的映射:

"""
更改词表ID
因为我们读取词表的时候是从下标为3的时候开始计算的,所以此时要加3
使词表坐标偏移的目的是为了增加一些特殊字符
"""
word_index = {k:(v+3) for k, v in word_index.items()} 

word_index['<PAD>'] = 0      # padding时用来填充的字符
word_index['<START>'] = 1    # 每个句子开始之前的字符
word_index['<UNK>'] = 2      # 无法识别的字符
word_index['<END>'] = 3      # 每个句子结束时的字符

# id->word的索引
reverse_word_index = dict(
    [(value, key) for key, value in word_index.items()])

def decode_review(text_ids):
    return ' '.join(
        [reverse_word_index.get(word_id, "<UNK>") for word_id in text_ids]) # 没有找到的id默认用<UNK>代替
# 打印train_data[0]中ID对应的语句
decode_review(train_data[0])

我们来看一下转化之后的样本是怎么样的:
在这里插入图片描述

2.3 处理数据

因为我们的样本是不等长的,每个评论的长度都不一样,所以我们需要对数据进行处理,规定一个样本长度,对于长度不足的样本进行补齐,对于长度超出的样本进行截断。

max_length = 500 # 句子的长度,长度低于500的句子会被padding补齐,长度低于500的句子会被截断

"""
利用keras.preprocessing.sequence.pad_sequences对训练集与测试集数据进行补齐和截断
"""
# 处理训练集数据
train_data = keras.preprocessing.sequence.pad_sequences(
    train_data,                   # 要处理的数据
    value = word_index['<PAD>'],  # 要填充的值
    padding = 'post',             # padding的顺序:post指将padding放到句子的后面, pre指将padding放到句子的前面
    maxlen = max_length)          # 最大的长度

# 处理测试集数据
test_data = keras.preprocessing.sequence.pad_sequences(
    test_data,                    # 要处理的数据
    value = word_index['<PAD>'],  # 要填充的值
    padding = 'post',             # padding的顺序:post指将padding放到句子的后面, pre指将padding放到句子的前面
    maxlen = max_length)          # 最大的长度

print(train_data[0])

输出结果为:
在这里插入图片描述

3. 构建简单的RNN模型

3.1 单向RNN模型

首先我们构建一个单向的RNN模型:

embedding_dim = 16  # 每个word embedding成一个长度为16的向量
batch_size = 512    # 每个batch的长度

"""
单层单向的RNN
"""
model = keras.models.Sequential([
    """
    embedding层的作用
    1. 定义一个矩阵 matrix: [vocab_size, embedding_dim] ([10000, 16])
    2. 对于每一个样本[1,2,3,4..],将其变为 max_length * embedding_dim维度的数据,即每一个词都变为长度为16的向量
    3. 最后的数据为三维矩阵:batch_size * max_length * embedding_dim
    """
    keras.layers.Embedding(vocab_size,                  # 词表的长度
                           embedding_dim,               # embedding的长度
                           input_length = max_length),  # 输入的长度
    # units:输出空间维度
    # return_sequences: 布尔值。是返回输出序列中的最后一个输出,还是全部序列。
    keras.layers.SimpleRNN(units = 64, return_sequences = False),
    # 全连接层
    keras.layers.Dense(64, activation = 'relu'),
    keras.layers.Dense(1, activation='sigmoid'),
])
model.summary()

我们来看一下单向SimpleRNN的结构:
在这里插入图片描述

3.2 双向RNN模型

如果单向的RNN模型效果不好的话,可以将单向的RNN模型变为双向的,利用keras.layers.Bidirectional()模块即可:

embedding_dim = 16
batch_size = 512

model = keras.models.Sequential([
    # 1. define matrix: [vocab_size, embedding_dim]
    # 2. [1,2,3,4..], max_length * embedding_dim
    # 3. batch_size * max_length * embedding_dim
    keras.layers.Embedding(vocab_size, embedding_dim,
                           input_length = max_length),
    keras.layers.Bidirectional(
        keras.layers.SimpleRNN(
            units = 64, return_sequences = True)),
    keras.layers.Dense(64, activation = 'relu'),
    keras.layers.Dense(1, activation='sigmoid'),
])

model.summary()
model.compile(optimizer = 'adam',
              loss = 'binary_crossentropy',
              metrics = ['accuracy'])

4. 构建LSTM模型

4.1 单向LSTM模型

与构建RNN一样,构建LSTM的步骤几乎一致,只需要将keras.layers.SimpleRNN()层更改为keras.layers.LSTM()即可:

embedding_dim = 16  # 每个word embedding成一个长度为16的向量
batch_size = 512    # 每个batch的长度

"""
单层单向的LSTM
"""
model = keras.models.Sequential([
    """
    embedding层的作用
    1. 定义一个矩阵 matrix: [vocab_size, embedding_dim] ([10000, 16])
    2. 对于每一个样本[1,2,3,4..],将其变为 max_length * embedding_dim维度的数据,即每一个词都变为长度为16的向量
    3. 最后的数据为三维矩阵:batch_size * max_length * embedding_dim
    """
    keras.layers.Embedding(vocab_size,                  # 词表的长度
                           embedding_dim,               # embedding的长度
                           input_length = max_length),  # 输入的长度
    # units:输出空间维度
    # return_sequences: 布尔值。是返回输出序列中的最后一个输出,还是全部序列。
    keras.layers.LSTM(units = 64, return_sequences = False),
    keras.layers.Dense(64, activation = 'relu'),
    keras.layers.Dense(1, activation='sigmoid'),
])

model.summary()
model.compile(optimizer = 'adam',
                         loss = 'binary_crossentropy',
                         metrics = ['accuracy'])
4.1 双向LSTM模型

双向LSTM模型与双向RNN模型几乎一致,只需要将keras.layers.SimpleRNN()层更改为keras.layers.LSTM()即可:

embedding_dim = 16
batch_size = 512
"""
双向双层的LSTM
"""
model = keras.models.Sequential([
    # 1. define matrix: [vocab_size, embedding_dim]
    # 2. [1,2,3,4..], max_length * embedding_dim
    # 3. batch_size * max_length * embedding_dim
    keras.layers.Embedding(vocab_size, embedding_dim,
                           input_length = max_length),
    keras.layers.Bidirectional(
        keras.layers.LSTM(
            units = 64, return_sequences = True)),
    keras.layers.Dense(64, activation = 'relu'),
    keras.layers.Dense(1, activation='sigmoid'),
])

model.summary()
model.compile(optimizer = 'adam',
              loss = 'binary_crossentropy',
              metrics = ['accuracy'])

5. 模型编译与训练

对于构建好的model,我们就可以进行编译和训练了:

single_rnn_model.compile(optimizer = 'adam',
                         loss = 'binary_crossentropy',
                         metrics = ['accuracy'])
history_single_rnn = single_rnn_model.fit(
    train_data, train_labels,
    epochs = 30,
    batch_size = batch_size,
    validation_split = 0.2)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃骨头的猫、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值