深度学习处理文本(5)

导出能够处理原始字符串的模型

在前面的例子中,我们将文本标准化、拆分和建立索引 都作为tf.data管道的一部分。但如果想导出一个独立于这个管道的模型,我们应该确保模型包含文本预处理(否则需要在生产环境中重新实现,这可能很困难,或者可能导致训练数据与生产数据之间的微妙差异)​。幸运的是,这很简单。我们只需创建一个新的模型,复用TextVectorization层,并将其添加到刚刚训练好的模型中。

python 复制代码
inputs = keras.Input(shape=(1,), dtype="string")  ←----每个输入样本都是一个字符串
processed_inputs = text_vectorization(inputs)  ←----应用文本预处理
outputs = model(processed_inputs)  ←----应用前面训练好的模型
inference_model = keras.Model(inputs, outputs)  ←----将端到端的模型实例化

我们得到的模型可以处理原始字符串组成的批量,如下所示。

python 复制代码
import tensorflow as tf
raw_text_data = tf.convert_to_tensor([
    ["That was an excellent movie, I loved it."],
])
predictions = inference_model(raw_text_data)
print(f"{float(predictions[0] * 100):.2f} percent positive")

将单词作为序列处理:序列模型方法

前面几个例子清楚地表明,词序 很重要。基于顺序的手动特征工程(比如二元语法)可以很好地提高精度。现在请记住:深度学习的历史就是逐渐摆脱手动特征工程 ,让模型仅通过观察数据来自己学习特征。如果不手动寻找基于顺序的特征,而是让模型直接观察原始单词序列并自己找出这样的特征,那会怎么样呢?这就是序列模型(sequence model)的意义所在。要实现序列模型,首先需要将输入样本表示为整数索引序列(每个整数代表一个单词)​。然后,将每个整数映射为一个向量,得到向量序列。最后,将这些向量序列输入层的堆叠,这些层可以将相邻向量的特征交叉关联,它可以是一维卷积神经网络、RNN或Transformer。

2016年~2017年,双向RNN(特别是双向LSTM)被认为是最先进的序列模型。你已经熟悉了这种架构,所以第一个序列模型示例将用到它。然而,如今的序列模型几乎都是用Transformer实现的,我们稍后会介绍。奇怪的是,一维卷积神经网络在NLP中一直没有很流行,尽管根据我自己的经验,一维深度可分离卷积的残差堆叠通常可以实现与双向LSTM相当的性能,而且计算成本大大降低。

第一个实例

我们来看一下第一个序列模型实例。首先,准备可以返回整数序列的数据集,如代码清单11-12所示。

代码清单11-12 准备整数序列数据集

python 复制代码
from tensorflow.keras import layers

max_length = 600
max_tokens = 20000
text_vectorization = layers.TextVectorization(
    max_tokens=max_tokens,
    output_mode="int",
    output_sequence_length=max_length,  ←----为保持输入大小可控,我们在前600个单词处截断输入。这是一个合理的选择,因为评论的平均长度是233个单词,只有5%的评论超过600个单词
)
text_vectorization.adapt(text_only_train_ds)

int_train_ds = train_ds.map(
    lambda x, y: (text_vectorization(x), y),
    num_parallel_calls=4)
int_val_ds = val_ds.map(
    lambda x, y: (text_vectorization(x), y),
    num_parallel_calls=4)
int_test_ds = test_ds.map(
    lambda x, y: (text_vectorization(x), y),
    num_parallel_calls=4)

下面来创建模型。要将整数序列转换为向量序列,最简单的方法是对整数进行one-hot编码(每个维度代表词表中的一个单词)​。在这些one-hot向量之上,我们再添加一个简单的双向LSTM,如代码清单11-13所示。

代码清单11-13 构建于one-hot编码的向量序列之上的序列模型

python 复制代码
import tensorflow as tf
inputs = keras.Input(shape=(None,), dtype="int64")  ←----每个输入是一个整数序列
embedded = tf.one_hot(inputs, depth=max_tokens)  ←----将整数编码为20 000维的二进制向量
x = layers.Bidirectional(layers.LSTM(32))(embedded)  ←----添加一个双向LSTM
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(1, activation="sigmoid")(x)  ←----最后添加一个分类层
model = keras.Model(inputs, outputs)
model.compile(optimizer="rmsprop",
              loss="binary_crossentropy",
              metrics=["accuracy"])
model.summary()

下面我们来训练模型,如代码清单11-14所示。

代码清单11-14 训练第一个简单的序列模型

python 复制代码
callbacks = [
    keras.callbacks.ModelCheckpoint("one_hot_bidir_lstm.keras",
                                    save_best_only=True)
]
model.fit(int_train_ds, validation_data=int_val_ds, epochs=10,
          callbacks=callbacks)
model = keras.models.load_model("one_hot_bidir_lstm.keras")
print(f"Test acc: {model.evaluate(int_test_ds)[1]:.3f}")

我们得到两个观察结果。第一,这个模型的训练速度非常慢,尤其是与轻量级模型相比。这是因为输入很大:每个输入样本被编码成尺寸为(600, 20000)的矩阵(每个样本包含600个单词,共有20 000个可能的单词)​。一条影评就有12 000 000个浮点数。双向LSTM需要做很多工作。第二,这个模型的测试精度只有87%,性能还不如一元语法二进制模型,后者的速度还很快。显然,使用one-hot编码将单词转换为向量,这是我们能做的最简单的事情,但这并不是一个好主意。有一种更好的方法:词嵌入(word embedding)​。

相关推荐
代码洲学长1 分钟前
卷积神经网络CNN
人工智能·神经网络·cnn
Wpa.wk2 分钟前
自动化测试 - 文件上传 和 弹窗处理
开发语言·javascript·自动化测试·经验分享·爬虫·python·selenium
_OP_CHEN3 分钟前
【Python基础】(二)从 0 到 1 入门 Python 语法基础:从表达式到运算符的全面指南
开发语言·python
l1t4 分钟前
利用小米mimo为精确覆盖矩形问题C程序添加打乱函数求出更大的解
c语言·开发语言·javascript·人工智能·算法
weixin_398187755 分钟前
YOLOv11 轻量级移动端网络ShuffleNetV2集成指南(详注)
人工智能·yolo
_Li.8 分钟前
机器学习-贝叶斯公式
人工智能·机器学习·概率论
luoganttcc10 分钟前
详细分析一下 国富论里里面 十一章 关于白银价格的 论述
人工智能
我命由我1234513 分钟前
Python Flask 开发:在 Flask 中返回字符串时,浏览器将其作为 HTML 解析
服务器·开发语言·后端·python·flask·html·学习方法
拾忆,想起15 分钟前
设计模式:软件开发的可复用武功秘籍
开发语言·python·算法·微服务·设计模式·性能优化·服务发现
哥布林学者19 分钟前
吴恩达深度学习课程四:计算机视觉 第二周:经典网络结构 课后习题和代码实践
深度学习·ai