In [ ]:
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

In [ ]:
#@title MIT License
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

使用 Keras 和 Tensorflow Hub 对电影评论进行文本分类

Note: 我们的 TensorFlow 社区翻译了这些文档。因为社区翻译是尽力而为, 所以无法保证它们是最准确的,并且反映了最新的 官方英文文档。如果您有改进此翻译的建议, 请提交 pull request 到 tensorflow/docs GitHub 仓库。要志愿地撰写或者审核译文,请加入 docs-zh-cn@tensorflow.org Google Group

此笔记本(notebook)使用评论文本将影评分为积极(positive)消极(nagetive)两类。这是一个二元(binary)或者二分类问题,一种重要且应用广泛的机器学习问题。

本教程演示了使用 Tensorflow Hub 和 Keras 进行迁移学习的基本应用。

我们将使用来源于网络电影数据库(Internet Movie Database)IMDB 数据集(IMDB dataset),其包含 50,000 条影评文本。从该数据集切割出的 25,000 条评论用作训练,另外 25,000 条用作测试。训练集与测试集是平衡的(balanced),意味着它们包含相等数量的积极和消极评论。

此笔记本(notebook)使用了 tf.keras,它是一个 Tensorflow 中用于构建和训练模型的高级API,此外还使用了 TensorFlow Hub,一个用于迁移学习的库和平台。有关使用 tf.keras 进行文本分类的更高级教程,请参阅 MLCC文本分类指南(MLCC Text Classification Guide)


In [ ]:
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")

下载 IMDB 数据集

IMDB数据集可以在 Tensorflow 数据集处获取。以下代码将 IMDB 数据集下载至您的机器(或 colab 运行时环境)中:


In [ ]:
# 将训练集分割成 60% 和 40%,从而最终我们将得到 15,000 个训练样本
# 10,000 个验证样本以及 25,000 个测试样本。
train_data, validation_data, test_data = tfds.load(
    name="imdb_reviews", 
    split=('train[:60%]', 'train[60%:]', 'test'),
    as_supervised=True)

探索数据

让我们花一点时间来了解数据的格式。每一个样本都是一个表示电影评论和相应标签的句子。该句子不以任何方式进行预处理。标签是一个值为 0 或 1 的整数,其中 0 代表消极评论,1 代表积极评论。

我们来打印下前十个样本。


In [ ]:
train_examples_batch, train_labels_batch = next(iter(train_data.batch(10)))
train_examples_batch

我们再打印下前十个标签。


In [ ]:
train_labels_batch

构建模型

神经网络由堆叠的层来构建,这需要从三个主要方面来进行体系结构决策:

  • 如何表示文本?
  • 模型里有多少层?
  • 每个层里有多少隐层单元(hidden units)

本示例中,输入数据由句子组成。预测的标签为 0 或 1。

表示文本的一种方式是将句子转换为嵌入向量(embeddings vectors)。我们可以使用一个预先训练好的文本嵌入(text embedding)作为首层,这将具有三个优点:

  • 我们不必担心文本预处理
  • 我们可以从迁移学习中受益
  • 嵌入具有固定长度,更易于处理

针对此示例我们将使用 TensorFlow Hub 中名为 google/tf2-preview/gnews-swivel-20dim/1 的一种预训练文本嵌入(text embedding)模型

为了达到本教程的目的还有其他三种预训练模型可供测试:

让我们首先创建一个使用 Tensorflow Hub 模型嵌入(embed)语句的Keras层,并在几个输入样本中进行尝试。请注意无论输入文本的长度如何,嵌入(embeddings)输出的形状都是:(num_examples, embedding_dimension)


In [ ]:
embedding = "https://tfhub.dev/google/tf2-preview/gnews-swivel-20dim/1"
hub_layer = hub.KerasLayer(embedding, input_shape=[], 
                           dtype=tf.string, trainable=True)
hub_layer(train_examples_batch[:3])

现在让我们构建完整模型:


In [ ]:
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()

层按顺序堆叠以构建分类器:

  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 之间的浮点数,表示概率或置信水平。

让我们编译模型。

损失函数与优化器

一个模型需要损失函数和优化器来进行训练。由于这是一个二分类问题且模型输出概率值(一个使用 sigmoid 激活函数的单一单元层),我们将使用 binary_crossentropy 损失函数。

这不是损失函数的唯一选择,例如,您可以选择 mean_squared_error 。但是,一般来说 binary_crossentropy 更适合处理概率——它能够度量概率分布之间的“距离”,或者在我们的示例中,指的是度量 ground-truth 分布与预测值之间的“距离”。

稍后,当我们研究回归问题(例如,预测房价)时,我们将介绍如何使用另一种叫做均方误差的损失函数。

现在,配置模型来使用优化器和损失函数:


In [ ]:
model.compile(optimizer='adam',
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])

训练模型

以 512 个样本的 mini-batch 大小迭代 20 个 epoch 来训练模型。 这是指对 x_trainy_train 张量中所有样本的的 20 次迭代。在训练过程中,监测来自验证集的 10,000 个样本上的损失值(loss)和准确率(accuracy):


In [ ]:
history = model.fit(train_data.shuffle(10000).batch(512),
                    epochs=20,
                    validation_data=validation_data.batch(512),
                    verbose=1)

评估模型

我们来看下模型的表现如何。将返回两个值。损失值(loss)(一个表示误差的数字,值越低越好)与准确率(accuracy)。


In [ ]:
results = model.evaluate(test_data.batch(512), verbose=2)

for name, value in zip(model.metrics_names, results):
  print("%s: %.3f" % (name, value))

这种十分朴素的方法得到了约 87% 的准确率(accuracy)。若采用更好的方法,模型的准确率应当接近 95%。

进一步阅读

有关使用字符串输入的更一般方法,以及对训练期间准确率(accuracy)和损失值(loss)更详细的分析,请参阅此处