简介
使用Tensorflow Hub和Keras进行迁移学习的基本应用
使用来源于网络电影数据库的IMDB数据集,其中包含50,000条影评文本。从该数据集切割出的25,000条评论用作训练,另外25,000条用作测试。训练集和测试集是平衡的,意味着它们包含相等数量的积极和消极评论
本次使用tf.keras,是一个Tensorflow中用于构建和训练模型的高级API,此外还是用了Tensorflow Hub,一个用于迁移学习的库和平台。
import numpy as np
import tensorflow as tf
import tensorflow_hub as hub
import tensorflow_datasets as tfds
print("Version: ", tf.__version__) # 查看tensorflow版本
print("Eager mode: ", tf.executing_eagerly()) # 查看是否支持动态图模式
print("Hub version: ", hub.__version__) # 查看tensorflow_hub版本
print("GPU is", 'available' if tf.config.experimental.list_physical_devices("GPU") else "NOT AVAILABLE") # 查看设备是否支持GPU
数据准备
IMDB数据可以在Tensorflow数据集处获取。使用以下代码进行IMDB数据集下载
# 将训练集分割成 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代表积极评价
打印一下前十个样本
train_examples_batch, train_lab;es_bath = next(iter(train_data.batch(10)))
train_examples_batch
打印下前十个标签
train_labels_batch
构建模型
神经网络由堆叠的层来构建,这需要从三个主要方面来进行体系结构决策:
- 如何表示文本?
- 模型里有多少层?
- 每个层里又多少隐藏单元(hindeen units)?
本示例中,输入数据由句子组成。预测的标签为0或1.
表示文本的一种方式是将句子转换为嵌入向量。我们可以使用一个预先训练好的文本嵌入作为首层。这将具有三个优点:
- 不必担心文本预处理
- 可以从迁移学习中受益
- 嵌入具有固定长度,更易于处理
针对此示例我们将使用Tensorflow Hub中名为google/tf2-preview/gnews-swivel-20dim/1的一种预训练文本嵌入模型
首先创建一个使用Tensorflow Hub模型嵌入语句的Keras层,并在几个输入样本中进行尝试。注意无论长度如何,嵌入输出的形状都是:(num_examples, embedding_dimension)
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])
构建完整模型
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层。这一层使用一个预训练的保存好的模型来将句子映射为一个嵌入向量。我们所使用的预训练文本嵌入模型将句子切割为符号。嵌入每个符号然后进行合并。最终的得到的维度是:
(num_wxamples, embedding_dimension)
- 该定长输出向量通过一个又16个隐藏单元的全连接层(
Dense
)进行管道传输。 - 最后一层与单个输出节点紧密相连。使用
Sigmoid
激活函数,其函数值为介于0与1之间的浮点数,表示概率或置信水平
损失函数与优化器
一个模型需要损失函数和优化器来进行训练,由于这是一个二分类问题且模型输出概率值9一个使用sigmoid激活函数的单—单元层),我们将使用binary_crossentropy
损失函数
这不是损失函数的唯一选择,例如,您可以选择 mean_squared_error
。但是,一般来说 binary_crossentropy
更适合处理概率——它能够度量概率分布之间的“距离”,或者在我们的示例中,指的是度量 ground-truth 分布与预测值之间的“距离”。
稍后,当我们研究回归问题(例如,预测房价)时,我们将介绍如何使用另一种叫做均方误差的损失函数。
现在,配置模型来使用优化器和损失函数:
model.compile(optimizer='adam',
loss=tf.keras.loeese.BinaryCrossentropy(from_logits=True),
metrics=['accuracy']
)
训练模型
以为512个样本的mini-batch大小迭代20个epoch来训练模型。这指对x_train
和y_train
张量中所有样本的20次迭代。在训练过程中,监测来自验证集的 10,000 个样本上的损失值(loss)和准确率(accuracy):
history = model.fit(train_data.shuffle(10000).batch(512),
epochs=20,
validation_data=validtation_data.batch(512),
verbose=1)
评估模型
我们来看下模型的表现如何。将返回两个值。损失值(loss)(一个表示误差的数字,值越低越好)与准确率(accuracy)。
results = model.evaluate(test_data.batch(512), verbose=2)
for name, value in zip(model.metrics_names, results):
print("%s:%.3f" % (name, value))
这种十分朴素的方法得到了约 85% 的准确率(accuracy)。若采用更好的方法,模型的准确率应当接近 95%。
完整代码
# 导入函数库并进行验证
import numpy as np
import tensorflow as tf
import tensorflow_hub as hub
import tensorflow_datasets as tfds
print("Version: ", tf.__version__) # 查看tensorflow版本
print("Eager mode: ", tf.executing_eagerly()) # 查看是否支持动态图模式
print("Hub version: ", hub.__version__) # 查看tensorflow_hub版本
print("GPU is", 'available' if tf.config.experimental.list_physical_devices("GPU") else "NOT AVAILABLE") # 查看设备是否支持GPU
# 数据准备
# 将训练集分割成 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
)
# 数据分析
train_examples_batch, train_lab;es_bath = next(iter(train_data.batch(10)))
train_examples_batch
train_labels_batch
# 构建模型
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])
# 完整模型
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.compile(optimizer='adam',
loss=tf.keras.loeese.BinaryCrossentropy(from_logits=True),
metrics=['accuracy']
)
# 训练模型
history = model.fit(train_data.shuffle(10000).batch(512),
epochs=20,
validation_data=validtation_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))