当前位置:   article > 正文

情感分类问题IMDB实战(SimpleRNN,LSTM,GRU)_imdb情感分类

imdb情感分类

使用经典的 IMDB 影评数据集来完成情感分类任务。 IMDB 影评数据集包含了50000 条用户评价,评价的标签分为消极和积极, 其中 IMDB 评级<5 的用户评价标注为0,即消极; IMDB 评价>=7 的用户评价标注为 1,即积极。 25000 条影评用于训练集,25,000 条用于测试集
 

一、数据集加载以及数据集预处理

  1. # 加载IMDB数据集,数据采用数字编码,一个数字代表一个单词
  2. (x_train, y_train), (x_test, y_test) = keras.datasets.imdb.load_data(num_words=total_words)
  3. print(x_train.shape, len(x_train[0]), y_train.shape) # (25000,) 218 (25000,)
  4. print(x_test.shape, len(x_test[0]), y_test.shape) # (25000,) 68 (25000,)
  5. # 截断和填充句子,使得等长为max_review_len,此处长句子保留后面部分,短句子在前面填充
  6. x_train = keras.preprocessing.sequence.pad_sequences(x_train, maxlen=max_review_len)
  7. x_test = keras.preprocessing.sequence.pad_sequences(x_test, maxlen=max_review_len)
  8. # 构建数据集,打散,批量,并丢掉最后一个不够batches的batch
  9. db_train = tf.data.Dataset.from_tensor_slices((x_train, y_train))
  10. db_train = db_train.shuffle(1000).batch(batches, drop_remainder=True)
  11. db_test = tf.data.Dataset.from_tensor_slices((x_test, y_test))
  12. db_test = db_test.batch(batches, drop_remainder=True)
  13. print('db_train:', db_train) # db_train: <BatchDataset shapes: ((128, 80), (128,)), types: (tf.int32, tf.int64)>

通过Keras提供的数据集datasets可以从网上加载IMDB数据集,该数据集一共50000条用户评价,一半用于训练,另一半用于测试。x_train 和 x_test 是长度为 25,000 的一维数组,数组的每个元素是不定长 List,保存了数字编码的每个句子,例如训练集的第一个句子共有 218 个单词,测试集的第一个句子共有 68 个单词,每个句子都包含了句子起始标志 ID。

对于长度参差不齐的句子,设置一个阈值,对大于此长度的句子,选择截断部分单词,可以选择截去句首单词,也可以截去句末单词;对于小于此长度的句子,可以选择在句首或句尾填充,句子截断功能可以通过 keras.preprocessing.sequence.pad_sequences()函数实现

截断或填充为相同长度后通过 Dataset 类包裹成数据集对象,并添加常用的数据集处理流程,比如数据集批量化,打散,当最后一批数据集不满足一个batch将其丢弃。

二、网络模型构建
 

 自定义网络模型类MyRNN: Embedding层-->两个RNN层-->分类层网络

  1. class MyRNN(keras.Model):
  2. def __init__(self, units):
  3. super(MyRNN, self).__init__()
  4. # 词向量编码 [b,80] ==> [b,80,100]
  5. # embedding_len:单词向量的长度,total_words:词汇的数量 max_review_len:输入句子长度
  6. self.embedding = layers.Embedding(total_words, embedding_len, input_length=max_review_len)
  7. # 构建2个Cell [b,80,100] => [b,64]
  8. self.rnn = Sequential([
  9. layers.SimpleRNN(units, dropout=0.5, return_sequences=True),
  10. layers.SimpleRNN(units, dropout=0.5)
  11. ])
  12. # 构建分类网络,用于将Cell的输出特征进行分类,2分类
  13. # [b,64]=> [b,1]
  14. self.outlayer = Sequential([
  15. layers.Dense(units),
  16. layers.Dropout(rate=0.5),
  17. layers.ReLU(),
  18. layers.Dense(1)
  19. ])
  20. # 向前计算
  21. def call(self, inputs, training=None):
  22. x = inputs # [b,80]
  23. # embedding: [b,80] ==> [b,80, 100]
  24. x = self.embedding(x)
  25. # rnn cell compute: [b, 80,100] => [b,64]
  26. out1 = self.rnn(x)
  27. # 末层最后一个输出作为分类网络的输入: [b, 64] => [b, 1]
  28. x = self.outlayer(out1, training)
  29. # p(y is pos|x)
  30. prob = tf.sigmoid(x)
  31. return prob

Embedding层作用:把单词编码为某个词向量,它接受采用数字编码的单词编号,是可训练的

 RNN层:每层都需要上一层在每个时间戳上面的状态输出,因此除了最末层以外,所有的 RNN 层都需要返回每个时间戳上面的状态输出,通过设置 return_sequences=True 来实现,用做下一层的输入,dropout用于优化网络性能:减少层与层之间的连接

分类网络完成 2 分类任务,故输出节点设置为 1。输入序列通过 Embedding 层完成词向量编码循环通过两个 RNN层,提取语义特征取最后一层的最后时间戳的状态向量输出送入分类网络,经过Sigmoid 激活函数后得到输出概率
通过Cell方式:

  1. class MyRNN(keras.Model):
  2. def __init__(self, units):
  3. super(MyRNN, self).__init__()
  4. # [b, 64],构建Cell初始化状态向量,重复使用
  5. self.state0 = [tf.zeros([batches, units])]
  6. self.state1 = [tf.zeros([batches, units])]
  7. # 词向量编码 [b,80] ==> [b,80,100]
  8. self.embedding = layers.Embedding(total_words, embedding_len, input_length=max_review_len)
  9. # 构建2个Cell
  10. self.rnn_cell0 = layers.SimpleRNNCell(units, dropout=0.5) # dropout 减少连接
  11. self.rnn_cell1 = layers.SimpleRNNCell(units, dropout=0.5)
  12. # 构建分类网络,用于将Cell的输出特征进行分类,2分类
  13. # [b,80,100] => [b,64]=> [b,1]
  14. self.outlayer = Sequential([
  15. layers.Dense(units),
  16. layers.Dropout(rate=0.5),
  17. layers.ReLU(),
  18. layers.Dense(1)
  19. ])
  20. # 向前计算
  21. def call(self, inputs, training=None):
  22. x = inputs # [b,80]
  23. # embedding: [b,80] ==> [b,80, 100]
  24. x = self.embedding(x)
  25. # rnn cell compute: [b, 80,100] => [b,64]
  26. state0 = self.state0
  27. state1 = self.state1
  28. for word in tf.unstack(x, axis=1): # word: [b,100] 从时间维度展开
  29. out0, state0 = self.rnn_cell0(word, state0, training)
  30. out1, state1 = self.rnn_cell1(out0, state1, training)
  31. # 末层最后一个输出作为分类网络的输入: [b, 64] => [b, 1]
  32. x = self.outlayer(out1, training)
  33. # p(y is pos|x)
  34. prob = tf.sigmoid(x)
  35. return prob

需要自己实现向前计算,并且维护各个RNN层的初始状态向量,其他都是一样的 

 

三、网络装配

  1. model = MyRNN(units)
  2. # 装配优化器,学习率,测量器
  3. model.compile(optimizer=optimizers.Adam(1e-3),
  4. loss=losses.BinaryCrossentropy(),
  5. metrics=['accuracy'])

在完成网络模型的搭建后,需要指定网络使用的优化器对象、 损失函数类型, 评价指标等设定,这一步称为装配 为了简便, 这里使用 Keras 的 Compile&Fit 方式训练网络,设置优化器为 Adam 优

四、训练与验证

  1. # 训练 与 验证 validation_data:验证数据
  2. model.fit(db_train, epochs=epochs, validation_data=db_test)
  3. # 测试
  4. model.evaluate(db_test)

这里使用 Keras 的 Compile&Fit 方式训练网络,设置好优化器,学习率,误差函数测试指标(采用准确率),之间利用fit()喂入数据集和测试集即可训练

结果: 训练了近30个epoch

五、LSTM模型

只需要修改网络模型一处即可:修改网络层类型即可

  1. # 构建rnn
  2. self.rnn = Sequential([
  3. layers.LSTM(units, dropout=0.5, return_sequences=True),
  4. layers.LSTM(units, dropout=0.5)
  5. ])

结果:LSTM明显效果比RNN好一点

 

六、GRU模型

只需要修改网络模型一处即可:修改网络层类型即可

  1. # 构建rnn
  2. self.rnn = Sequential([
  3. layers.GRU(units, dropout=0.5, return_sequences=True),
  4. layers.GRU(units, dropout=0.5)
  5. ])

 结果:也稍微比SampleRNN好:

 

七、完整程序

  1. # -*- codeing = utf-8 -*-
  2. # @Time : 10:20
  3. # @Author:Paranipd
  4. # @File : imdb_rnn_cell.py
  5. # @Software:PyCharm
  6. import os
  7. import tensorflow as tf
  8. import numpy as np
  9. from tensorflow import keras
  10. from tensorflow.keras import Sequential, Model, layers, metrics, optimizers, losses
  11. tf.random.set_seed(22)
  12. np.random.seed(22)
  13. os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
  14. assert tf.__version__.startswith('2')
  15. batches = 128 # 批量大小
  16. total_words = 10000 # 词汇表大小N_vocad
  17. max_review_len = 80 # 句子的最大长度s,大于的部分将截断,小于的将填充
  18. embedding_len = 100 # 词向量特征长度
  19. # 加载IMDB数据集,数据采用数字编码,一个数字代表一个单词
  20. (x_train, y_train), (x_test, y_test) = keras.datasets.imdb.load_data(num_words=total_words)
  21. print(x_train.shape, len(x_train[0]), y_train.shape) # (25000,) 218 (25000,)
  22. print(x_test.shape, len(x_test[0]), y_test.shape) # (25000,) 68 (25000,)
  23. # 截断和填充句子,使得等长为max_review_len,此处长句子保留后面部分,短句子在前面填充
  24. x_train = keras.preprocessing.sequence.pad_sequences(x_train, maxlen=max_review_len)
  25. x_test = keras.preprocessing.sequence.pad_sequences(x_test, maxlen=max_review_len)
  26. # 构建数据集,打散,批量,并丢掉最后一个不够batches的batch
  27. db_train = tf.data.Dataset.from_tensor_slices((x_train, y_train))
  28. db_train = db_train.shuffle(1000).batch(batches, drop_remainder=True)
  29. db_test = tf.data.Dataset.from_tensor_slices((x_test, y_test))
  30. db_test = db_test.batch(batches, drop_remainder=True)
  31. print('db_train:', db_train) # db_train: <BatchDataset shapes: ((128, 80), (128,)), types: (tf.int32, tf.int64)>
  32. class MyRNN(keras.Model):
  33. def __init__(self, units):
  34. super(MyRNN, self).__init__()
  35. # 词向量编码 [b,80] ==> [b,80,100]
  36. # embedding_len:单词向量的长度,total_words:词汇的数量 max_review_len:输入句子长度
  37. self.embedding = layers.Embedding(total_words, embedding_len, input_length=max_review_len)
  38. # 构建2个Cell [b,80,100] => [b,64]
  39. self.rnn = Sequential([
  40. layers.SimpleRNN(units, dropout=0.5, return_sequences=True),
  41. layers.SimpleRNN(units, dropout=0.5)
  42. ])
  43. # 构建分类网络,用于将Cell的输出特征进行分类,2分类
  44. # [b,64]=> [b,1]
  45. self.outlayer = Sequential([
  46. layers.Dense(units),
  47. layers.Dropout(rate=0.5),
  48. layers.ReLU(),
  49. layers.Dense(1)
  50. ])
  51. # 向前计算
  52. def call(self, inputs, training=None):
  53. x = inputs # [b,80]
  54. # embedding: [b,80] ==> [b,80, 100]
  55. x = self.embedding(x)
  56. # rnn cell compute: [b, 80,100] => [b,64]
  57. out1 = self.rnn(x)
  58. # 末层最后一个输出作为分类网络的输入: [b, 64] => [b, 1]
  59. x = self.outlayer(out1, training)
  60. # p(y is pos|x)
  61. prob = tf.sigmoid(x)
  62. return prob
  63. def main():
  64. units = 64 # rnn状态向量长度
  65. epochs = 50
  66. model = MyRNN(units)
  67. # 装配优化器,学习率,测量器
  68. model.compile(optimizer=optimizers.Adam(1e-3),
  69. loss=losses.BinaryCrossentropy(),
  70. metrics=['accuracy'])
  71. # 训练 与 验证 validation_data:验证数据
  72. model.fit(db_train, epochs=epochs, validation_data=db_test)
  73. # 测试
  74. model.evaluate(db_test)
  75. if __name__ == '__main__':
  76. main()

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/人工智能uu/article/detail/993007
推荐阅读
相关标签
  

闽ICP备14008679号