TensorFlow 2之迁移学习进行IMDB评论文本分类
背景
使用迁移学习,来进行IMDB评论文本的二元分类。
简介
数据集
http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
初体验
import numpy as np
import tensorflow as tf
import tensorflow_hub as hub
import tensorflow_datasets as tfds
# 第一步 准备数据集
# IMDB数据集样本,其包含 50,000 条影评文本。
# 从该数据集切割出的 25,000 条评论用作训练,另外 25,000 条用作测试。
# 训练集与测试集是平衡的(balanced),意味着它们包含相等数量的积极和消极评论。
# 将训练集分割成 60% 和 40%,最终有 15,000 个训练样本, 10,000 个验证样本和 25,000 个测试样本。
# 下载数据集时,可以自行配置使用代理:
# export TFDS_HTTP_PROXY="http://127.0.0.1:8118/"
# export TFDS_HTTPS_PROXY="http://127.0.0.1:8118/"
# export HTTP_PROXY="http://127.0.0.1:8118/"
# export HTTPS_PROXY="http://127.0.0.1:8118/"
train_data, validation_data, test_data = tfds.load(
name="imdb_reviews",
split=('train[:60%]', 'train[60%:]', 'test'),
as_supervised=True,
try_gcs=False)
# 预览数据集
# 打印前10个样本
train_examples_batch, train_labels_batch = next(iter(train_data.batch(10)))
# print(train_examples_batch)
# 打印前10个标签
# print(train_labels_batch)
# tf.Tensor([0 0 0 1 1 1 0 0 0 0], shape=(10,), dtype=int64)
# 第二步 搭建模型
# 表示文本的一种方式是将句子转换为嵌入向量(embeddings vectors)。我们可以使用一个预先训练好的文本嵌入(text embedding)作为首层,这将具有三个优点:
# * 我们不必担心文本预处理
# * 我们可以从迁移学习中受益
# * 嵌入具有固定长度,更易于处理
# 针对此示例我们将使用 TensorFlow Hub 中名为 google/tf2-preview/gnews-swivel-20dim/1 的一种预训练文本嵌入(text embedding)模型 。
# embedding = "https://hub.tensorflow.google.cn/google/tf2-preview/gnews-swivel-20dim/1"
embedding = "datasets/gnews-swivel-20dim/"
hub_layer = hub.KerasLayer(embedding, input_shape=[],
dtype=tf.string, trainable=True)
# 预览hub层结构
# print(hub_layer(train_examples_batch[:3]))
# tf.Tensor(
# [[ 1.765786 -3.882232 3.9134233 -1.5557289 -3.3362343 -1.7357955
# -1.9954445 1.2989551 5.081598 -1.1041286 -2.0503852 -0.72675157
# -0.65675956 0.24436149 -3.7208383 2.0954835 2.2969332 -2.0689783
# -2.9489717 -1.1315987 ]
# [ 1.8804485 -2.5852382 3.4066997 1.0982676 -4.056685 -4.891284
# -2.785554 1.3874227 3.8476458 -0.9256538 -1.896706 1.2113281
# 0.11474707 0.76209456 -4.8791065 2.906149 4.7087674 -2.3652055
# -3.5015898 -1.6390051 ]
# [ 0.71152234 -0.6353217 1.7385626 -1.1168286 -0.5451594 -1.1808156
# 0.09504455 1.4653089 0.66059524 0.79308075 -2.2268345 0.07446612
# -1.4075904 -0.70645386 -1.907037 1.4419787 1.9551861 -0.42660055
# -2.8022065 0.43727064]], shape=(3, 20), dtype=float32)
# 完整模型如下
# 1. 第一层是 Tensorflow Hub 层。这一层使用一个预训练的保存好的模型来将句子映射为嵌入向量(embedding vector)。
# 我们所使用的预训练文本嵌入(embedding)模型(google/tf2-preview/gnews-swivel-20dim/1)将句子切割为符号,嵌入(embed)每个符号然后进行合并。
# 最终得到的维度是:(num_examples, embedding_dimension)。
# 2. 该定长输出向量通过一个有 16 个隐层单元的全连接层(Dense)进行管道传输。
# 3. 最后一层与单个输出结点紧密相连。使用 Sigmoid 激活函数,其函数值为介于 0 与 1 之间的浮点数,表示概率或置信水平。
model = tf.keras.Sequential()
model.add(hub_layer)
model.add(tf.keras.layers.Dense(16, activation='relu'))
model.add(tf.keras.layers.Dense(1))
# model.summary()
# Model: "sequential"
# _________________________________________________________________
# Layer (type) Output Shape Param #
# =================================================================
# keras_layer (KerasLayer) (None, 20) 400020
# _________________________________________________________________
# dense (Dense) (None, 16) 336
# _________________________________________________________________
# dense_1 (Dense) (None, 1) 17
# =================================================================
# Total params: 400,373
# Trainable params: 400,373
# Non-trainable params: 0
# _________________________________________________________________
# 第三步 编译模型
# 二分类问题且模型输出概率值(一个使用 sigmoid 激活函数的单一单元层),我们将使用 binary_crossentropy 损失函数。
# 这不是损失函数的唯一选择,例如,您可以选择 mean_squared_error 。
# 但是,一般来说 binary_crossentropy 更适合处理概率——它能够度量概率分布之间的“距离”,或者在我们的示例中,指的是度量 ground-truth 分布与预测值之间的“距离”。
model.compile(optimizer='adam',
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=['accuracy'])
# 第四步 训练模型
history = model.fit(train_data.shuffle(10000).batch(512),
epochs=20,
validation_data=validation_data.batch(512),
verbose=1)
# 第五步 评估准确率
results = model.evaluate(test_data.batch(512), verbose=2)
for name, value in zip(model.metrics_names, results):
print("%s: %.3f" % (name, value))
# 49/49 - 1s - loss: 0.3182 - accuracy: 0.8580
# loss: 0.318
# accuracy: 0.858
# 这种十分朴素的方法得到了约 87% 的准确率(accuracy)。若采用更好的方法,模型的准确率应当接近 95%。