IMDB 文本分类

TF2.0 TensorFlow 2 / 2.0 中文文档 - 文本分类 Classify text

主要内容:使用迁移学习算法解决一个典型的二分分类(Binary Classification)问题——电影正向评论和负向评论分类。

这篇文档使用包含有50,000条电影评论的 IMDB 数据集,25,000用于训练,25,000用于测试。而且训练集和测试集是均衡的,即其中包含同等数量的正向评论和负向评论。

代码使用tf.kerasTensorFlow Hub,TensorFlow Hub 是一个用于迁移学习的平台/库。

  1. import numpy as np
  2. import tensorflow as tf # 2.0.0-beta1
  3. import tensorflow_hub as hub # 0.5.0
  4. import tensorflow_datasets as tfds

下载 IMDB 数据集

IMDB datasets

IMDB 数据集在tfds中是可以直接获取的,调用时会自动下载到你的机器上。

  1. # 进一步划分训练集。
  2. # 60%(15,000)用于训练,40%(10,000)用于验证(validation)。
  3. train_validation_split = tfds.Split.TRAIN.subsplit([6, 4])
  4. (train_data, validation_data), test_data = tfds.load(
  5. name="imdb_reviews",
  6. split=(train_validation_split, tfds.Split.TEST),
  7. as_supervised=True)

数据格式

每个例子包含一句电影评论和对应的标签,0或1。0代表负向评论,1代表正向评论。

看一下前十条数据。

  1. train_examples_batch, train_labels_batch = next(iter(train_data.batch(10)))
  2. train_examples_batch
  1. <tf.Tensor: id=220, shape=(10,), dtype=string, numpy=
  2. array([b"As a lifelong fan of Dickens, I have ...",
  3. b"Oh yeah! Jenna Jameson did it again! ...",
  4. b"I saw this film on True Movies (which ...",
  5. b'This was a wonderfully clever and ...',
  6. b'I have no idea what the other reviewer ...',
  7. b"This was soul-provoking! I am an ...",
  8. b'Just because someone is under ...',
  9. b'A very close and sharp discription ...',
  10. b"This is the most depressing film ..."],
  11. dtype=object)>

前十个标签。

  1. train_labels_batch
  2. # <tf.Tensor: id=221, shape=(10,), dtype=int64, numpy=array([1, 1, 1, 1, 1, 1, 0, 1, 1, 0])>

搭建模型

神经网络需要堆叠多层,架构上需要考虑三点。

  • 文本怎么表示?
  • 模型需要多少层?
  • 每一层多少个隐藏节点

一种表示文本的方式是将句子映射为向量(embeddings vectors),或者称为文本嵌入(text embedding)。嵌入方法很多,比如我们可以采用最简单的独热编码,假设常用单词总共1000个,给每一个单词一个独热编码。假设每句话由10个单词构成,那么每句话均可以映射到10x1000的二维空间中。那么某句话就可以表示为:

  1. # 10x1000的二维向量表示一句话
  2. [[0, 0, 0, 1, 0, ... 0],
  3. [0, 0, ..., 0, 1,... 0],
  4. [0, 0, 0, 0, 0, ... 1],
  5. ...
  6. [0, 0, 0, 0, 0, ... 1]]

文本嵌入的方法很多,要考虑的因素也很多,比如同义词如何处理,维度过高怎么办?知乎上有比较详细的回答:word embedding的解释

我们可以使用一个预训练(pre-trained)好的文本嵌入模型作为第一层,有3个好处。

  • 不用担心文本处理。
  • 能从迁移学习中受益。
  • 嵌入后size固定,处理起来简单。

接下来从 TensorFlow Hub 中选用的pre-trained 文本嵌入模型称为google/tf2-preview/gnews-swivel-20dim/1

接下来创建一个 Keras Layer 使用这个模型将句子转为向量。取前三条评论试一试。注意无论句子的长度如何,最终的嵌入结果均为长度20的一维向量。

  1. embedding = "https://tfhub.dev/google/tf2-preview/gnews-swivel-20dim/1"
  2. hub_layer = hub.KerasLayer(embedding, input_shape=[],
  3. dtype=tf.string, trainable=True)
  4. hub_layer(train_examples_batch[:3])
  1. <tf.Tensor: id=402, shape=(3, 20), dtype=float32, numpy=
  2. array([[ 3.9819887, -4.4838037 , 5.177359, ... ],
  3. [ 3.4232912, -4.230874 , 4.1488533, ... ],
  4. [ 3.8508697, -5.003031 , 4.8700504, ... ]],
  5. dtype=float32)>

接下来,搭建完整的神经网络模型。

  1. model = tf.keras.Sequential()
  2. model.add(hub_layer)
  3. model.add(tf.keras.layers.Dense(16, activation='relu'))
  4. model.add(tf.keras.layers.Dense(1, activation='sigmoid'))
  5. model.summary()
  1. Model: "sequential"
  2. _________________________________________________________________
  3. Layer (type) Output Shape Param
  4. =================================================================
  5. keras_layer (KerasLayer) (None, 20) 400020
  6. _________________________________________________________________
  7. dense (Dense) (None, 16) 336
  8. _________________________________________________________________
  9. dense_1 (Dense) (None, 1) 17
  10. =================================================================
  11. Total params: 400,373
  12. Trainable params: 400,373
  13. Non-trainable params: 0
  14. _________________________________________________________________
  1. 第一层是 TensorFlow Hub 层,将句子转换为 tokens,然后映射每个 token,并组合成最终的向量。输出的维度是:句子个数 * 嵌入维度(20)。
  2. 接下来是全连接层(Full-connected, FC),即Dense层,16个节点。
  3. 最后一层,也是全连接层,只有一个节点。使用sigmoid激活函数,输出值是float,范围0-1,代表可能性/置信度。

损失函数和优化器

binary_crossentropy更适合处理概率问题,mean_squared_error适合处理回归(Regression)问题。

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

训练模型

共 20 epochs,每个batch 512个数据。即对所有训练数据进行20轮迭代。在训练过程中,将监视模型在包含10,000条数据的验证集上的损失(loss)和正确率(accuracy)。

  1. history = model.fit(train_data.shuffle(10000).batch(512),
  2. epochs=20,
  3. validation_data=validation_data.batch(512),
  4. verbose=1)
  1. Epoch 1/20
  2. 30/30 [========] - 6s 190ms/step - loss: 1.0201 - accuracy: 0.4331 - val_loss: 0.0000e+00 - val_accuracy: 0.0000e+00
  3. Epoch 2/20
  4. 30/30 [========] - 5s 159ms/step - loss: 0.7801 - accuracy: 0.4677 - val_loss: 0.7407 - val_accuracy: 0.5009
  5. ......
  6. Epoch 20/20
  7. 30/30 [========] - 5s 152ms/step - loss: 0.1917 - accuracy: 0.9348 - val_loss: 0.2930 - val_accuracy: 0.8784

评估模型

evaluate返回2个值,Loss(误差,越小越好) 和 accuracy。

  1. results = model.evaluate(test_data.batch(512), verbose=0)
  2. for name, value in zip(model.metrics_names, results):
  3. print("%s: %.3f" % (name, value))
  4. # loss: 0.314
  5. # accuracy: 0.866

这个非常基础的模型达到了87%的正确率,复杂一点的模型可以达到95%。

返回文档首页

参考地址:Text classification of movie reviews with Keras and TensorFlow Hub

附 推荐