本笔记是将评论文本将影评分为积极(positive)或消极(nagetive)两类。这是一个二元(binary)或者二分类问题,一种重要且应用广泛的机器学习问题。 本笔记使用了 TensorFlow Hub 和 Keras 进行迁移学习的基本应用。
我们将使用包含 Internet Movie Database 中的 50,000 条电影评论文本的 IMDB 数据集。先将这些评论分为两组,其中 25,000 条用于训练,另外 25,000 条用于测试。训练组和测试组是均衡的,也就是说其中包含相等数量的正面评价和负面评价。
此笔记本使用 tf.keras
(一个在 TensorFlow 中用于构建和训练模型的高级 API)和 tensorflow_hub
(一个用于在一行代码中从 TFHub 加载训练模型的库)。有关使用 tf.keras
的更高级文本分类教程,请参阅 MLCC 文本分类指南。
终端:conda install tensorflow-hub
和conda install tensorflow-datasets
import numpy as np
import tensorflow as tf
!pip install tensorflow-hub
!pip install tfds-nightly # 无法下载
import tensorflow_hub as hub
import tensorflow_datasets as tfds
print("Version: ", tf.__version__)
print("Eager mode: ", tf.executing_eagerly())
print("Hub version: ", hub.__version__)
print("GPU is", "available" if tf.config.experimental.list_physical_devices("GPU") else "NOT AVAILABLE")
1. 下载 IMDB 数据集
train_data,validation_data,test_data = tfds.load(
name = 'imdb_reviews',
split= ('train[:60%]', 'train[60%:]' ,'test'),
as_supervised = True)
2. 探索数据
我们花一点时间来了解数据的格式。每个样本都是一个代表电影评论的句子和一个相应的标签。句子未经过任何预处理。标签是一个整数值(0 或 1),其中 0 表示负面评价,而 1 表示正面评价。
我们来打印下前十个样本。
train_examples_batch,train_labels_batch = next(iter(train_data.batch(10)))
train_examples_batch
打印前十个标签
train_labels_batch
3. 构建模型
神经网络由堆叠的层来构建,这需要从三个主要方面来进行体系结构决策:
- 如何表示文本?
- 模型里有多少层?
- 每个层里有多少隐层单元(hidden units) ?
本示例中,输入数据由句子组成。预测的标签为 0 或 1。
表示文本的一种方式是将句子转换为嵌入向量。使用一个预训练文本嵌入向量作为首层,这将具有三个优点:
- 不必担心文本预处理
- 可以从迁移学习中受益
- 嵌入具有固定长度,更易于处理
在本示例中,您使用来自 TensorFlow Hub 的 预训练文本嵌入向量模型,名称为 google/nnlm-en-dim50/2。
本教程中还可以使用来自 TFHub 的许多其他预训练文本嵌入向量:
- google/nnlm-en-dim128/2 - 基于与 google/nnlm-en-dim50/2 相同的数据并使用相同的 NNLM 架构进行训练,但具有更大的嵌入向量维度。更大维度的嵌入向量可以改进您的任务,但可能需要更长的时间来训练您的模型。
- google/nnlm-en-dim128-with-normalization/2 - 与 google/nnlm-en-dim128/2 相同,但具有额外的文本归一化,例如移除标点符号。如果您的任务中的文本包含附加字符或标点符号,这会有所帮助。
- google/universal-sentence-encoder/4 - 一个可产生 512 维嵌入向量的更大模型,使用深度平均网络 (DAN) 编码器训练。
还有很多!在 TFHub 上查找更多文本嵌入向量模型。
让我们首先创建一个使用 Tensorflow Hub 模型嵌入(embed)语句的Keras层,并在几个输入样本中进行尝试。请注意无论输入文本的长度如何,嵌入(embeddings)输出的形状都是:(num_examples, embedding_dimension)
。
embedding = "https://hub.tensorflow.google.cn/google/nnlm-en-dim50/2"
hub_layer = hub.KerasLayer(embedding, input_shape=[],
dtype=tf.string, trainable=True)
hub_layer(train_examples_batch[:3])
构建完整模型
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()
层按顺序堆叠以构建分类器:
- 第一层是 TensorFlow Hub 层。此层使用预训练的 SaveModel 将句子映射到其嵌入向量。您使用的预训练文本嵌入向量模型 (google/nnlm-en-dim50/2) 可将句子拆分为词例,嵌入每个词例,然后组合嵌入向量。生成的维度是:
(num_examples, embedding_dimension)
。对于此 NNLM 模型,embedding_dimension
是 50。 - 该定长输出向量通过一个有 16 个隐层单元的全连接层(
Dense
)进行管道传输。 - 最后一层与单个输出结点紧密相连。使用
Sigmoid
激活函数,其函数值为介于 0 与 1 之间的浮点数,表示概率或置信水平。
3.1 损失函数和优化器
一个模型需要一个损失函数和一个优化器来训练。由于这是一个二元分类问题,并且模型输出 logit(具有线性激活的单一单元层),因此,我们将使用 binary_crossentropy
损失函数。
这并非损失函数的唯一选择,例如,您还可以选择 mean_squared_error
。但是,一般来说,binary_crossentropy
更适合处理概率问题,它可以测量概率分布之间的“距离”,或者在我们的用例中,是指真实分布与预测值之间的差距。
稍后,当您探索回归问题(例如,预测房屋价格)时,您将看到如何使用另一个称为均方误差的损失函数。
现在,配置模型来使用优化器和损失函数:
model.compile(optimizer='adam',
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=['accuracy'])
4. 训练模型
使用包含 512 个样本的 mini-batch 对模型进行 10 个周期的训练,也就是在 x_train
和 y_train
张量中对所有样本进行 10 次迭代。在训练时,监测模型在验证集的 10,000 个样本上的损失和准确率:
history = model.fit(train_data.shuffle(10000).batch(512),
epochs=10,
validation_data=validation_data.batch(512),
verbose=1)
5. 评估模型
results = model.evaluate(test_data.batch(512), verbose=2)
for name, value in zip(model.metrics_names, results):
print("%s: %.3f" % (name, value))
6. 进一步阅读
- 有关处理字符串输入的更通用方式以及对训练过程中准确率和损失进度的更详细分析,请参阅使用预处理文本的文本分类教程。
- 尝试更多使用来自 TFHub 的训练模型的文本相关教程。