欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > 深度学习处理文本(3)

深度学习处理文本(3)

2025/4/3 23:10:51 来源:https://blog.csdn.net/weixin_52370850/article/details/146770965  浏览:    关键词:深度学习处理文本(3)

表示单词组的两种方法:集合和序列

机器学习模型如何表示单个单词,这是一个相对没有争议的问题:它是分类特征(来自预定义集合的值)​,我们知道如何处理。它应该被编码为特征空间中的维度,或者类别向量(本例中为词向量)​。然而,一个更难回答的问题是,如何对单词组成句子的方式进行编码,即如何对词序进行编码。自然语言中的顺序问题很有趣:与时间序列的时间步不同,句子中的单词没有一个自然、标准的顺序。不同语言对单词的排列方式非常不同,比如英语的句子结构与日语就有很大不同。即使在同一门语言中,通常也可以略微重新排列单词来表达同样的含义。更进一步,如果将一个短句中的单词完全随机打乱,你仍然可以大致读懂它的含义——尽管在许多情况下可能会出现明显的歧义。顺序当然很重要,但它与意义之间的关系并不简单。

如何表示词序是一个关键问题,不同类型的NLP架构正是源自于此。最简单的做法是舍弃顺序,将文本看作一组无序的单词,这就是词袋模型(bag-of-words model)​。你也可以严格按照单词出现顺序进行处理,一次处理一个,就像处理时间序列的时间步一样,这样你就可以利用循环模型。最后,你也可以采用混合方法:Transformer架构在技术上是不考虑顺序的,但它将单词位置信息注入数据表示中,从而能够同时查看一个句子的不同部分(这与RNN不同)​,并且仍然是顺序感知的。RNN和Transformer都考虑了词序,所以它们都被称为序列模型(sequence model)​。从历史上看,机器学习在NLP领域的早期应用大多只涉及词袋模型。随着RNN的重生,人们对序列模型的兴趣从2015年开始才逐渐增加。今天,这两种方法仍然都是有价值的。我们来看看二者的工作原理,以及何时使用哪种方法。

我们将在一个著名的文本分类基准上介绍两种方法,这个基准就是IMDB影评情感分类数据集。现在我们来处理IMDB的原始文本数据,就如同在现实世界中处理一个新的文本分类问题。

准备IMDB影评数据

首先,我们从斯坦福大学Andrew Maas的页面下载数据集并解压。你会得到一个名为aclImdb的目录,其结构如下

aclImdb/
...train/
......pos/
......neg/
...test/
......pos/
......neg/

例如,train/pos/目录包含12 500个文本文件,每个文件都包含一个正面情绪的影评文本,用作训练数据。负面情绪的影评在neg目录下。共有25 000个文本文件用于训练,另有25 000个用于测试。还有一个train/unsup子目录,我们不需要它,将其删除。

!rm -r aclImdb/train/unsup

我们来查看其中几个文本文件的内容。请记住,无论是处理文本数据还是图像数据,在开始建模之前,一定都要查看数据是什么样子。这会让你建立直觉,了解模型在做什么。

!cat aclImdb/train/pos/4077_10.txt

接下来,我们准备一个验证集,将20%的训练文本文件放入一个新目录中,即aclImdb/val目录。

import os, pathlib, shutil, randombase_dir = pathlib.Path("aclImdb")
val_dir = base_dir / "val"
train_dir = base_dir / "train"
for category in ("neg", "pos"):os.makedirs(val_dir / category)files = os.listdir(train_dir / category)random.Random(1337).shuffle(files)----使用种子随机打乱训练文件列表,以确保每次运行代码都会得到相同的验证集num_val_samples = int(0.2 * len(files))---- (本行及以下1)20%的训练文件用于验证val_files = files[-num_val_samples:]for fname in val_files:shutil.move(train_dir / category / fname,---- (本行及以下1)将文件移动到aclImdb/val/neg目录和aclImdb/val/pos目录val_dir / category / fname)

你可以使用text_dataset_from_directory()函数对文本文件做相同的操作。我们为训练、验证和测试创建3个Dataset对象。

from tensorflow import keras
batch_size = 32train_ds = keras.utils.text_dataset_from_directory(----运行这行代码的输出应该是“Found 20000 files belonging to 2 classes.”(找到属于2个类别的20 000个文件);如果你的输出是“Found 70000 files belonging to 3 classes.”(找到属于3个类别的70 000个文件),那么这说明你忘记删除aclImdb/train/unsup目录"aclImdb/train", batch_size=batch_size
)
val_ds = keras.utils.text_dataset_from_directory("aclImdb/val", batch_size=batch_size
)
test_ds = keras.utils.text_dataset_from_directory("aclImdb/test", batch_size=batch_size
)

这些数据集生成的输入是TensorFlow tf.string张量,生成的目标是int32格式的张量,取值为0或1,如代码清单11-2所示。

代码清单11-2 显示第一个批量的形状和数据类型

>>> for inputs, targets in train_ds:
>>>     print("inputs.shape:", inputs.shape)
>>>     print("inputs.dtype:", inputs.dtype)
>>>     print("targets.shape:", targets.shape)
>>>     print("targets.dtype:", targets.dtype)
>>>     print("inputs[0]:", inputs[0])
>>>     print("targets[0]:", targets[0])
>>>     break
inputs.shape: (32,)
inputs.dtype: <dtype: "string">
targets.shape: (32,)
targets.dtype: <dtype: "int32">
inputs[0]: tf.Tensor(b"This string contains the movie review.", shape=(),dtype=string)
targets[0]: tf.Tensor(1, shape=(), dtype=int32)

一切准备就绪。下面我们开始从这些数据中进行学习。

将单词作为集合处理:词袋方法

要对一段文本进行编码,使其可以被机器学习模型所处理,最简单的方法是舍弃顺序,将文本看作一组(一袋)词元。你既可以查看单个单词(一元语法)​,也可以通过查看连续的一组词元(N元语法)来尝试恢复一些局部顺序信息。单个单词(一元语法)的二进制编码如果使用单个单词的词袋,那么“the cat sat on the mat”​(猫坐在垫子上)这个句子就会变成{“cat”, “mat”, “on”, “sat”, “the”}。这种编码方式的主要优点是,你可以将整个文本表示为单一向量,其中每个元素表示某个单词是否存在。举个例子,利用二进制编码(multi-hot)​,你可以将一个文本编码为一个向量,向量维数等于词表中的单词个数。这个向量的几乎所有元素都是0,只有文本中的单词所对应的元素为1。我们在本项任务中试试这种方法。首先,我们用TextVectorization层来处理原始文本数据集,生成multi-hot编码的二进制词向量,如代码清单11-3所示。该层只会查看单个单词,即一元语法(unigram)​。

代码清单11-3 用TextVectorization层预处理数据集

text_vectorization = TextVectorization(----将词表限制为前20 000个最常出现的单词。否则,我们需要对训练数据中的每一个单词建立索引——可能会有上万个单词只出现一两次,因此没有信息量。一般来说,20 000是用于文本分类的合适的词表大小max_tokens=20000,output_mode="multi_hot",----将输出词元编码为multi-hot二进制向量
)text_only_train_ds = train_ds.map(lambda x, y: x)----准备一个数据集,只包含原始文本输入(不包含标签)
text_vectorization.adapt(text_only_train_ds)----利用adapt()方法对数据集词表建立索引binary_1gram_train_ds = train_ds.map(---- (本行及以下8)分别对训练、验证和测试数据集进行处理。一定要指定num_parallel_calls,以便利用多个CPU内核lambda x, y: (text_vectorization(x), y),num_parallel_calls=4)
binary_1gram_val_ds = val_ds.map(lambda x, y: (text_vectorization(x), y),num_parallel_calls=4)
binary_1gram_test_ds = test_ds.map(lambda x, y: (text_vectorization(x), y),num_parallel_calls=4)

你可以查看其中一个数据集的输出,如代码清单11-4所示。

代码清单11-4 查看一元语法二进制数据集的输出

>>> for inputs, targets in binary_1gram_train_ds:
>>>     print("inputs.shape:", inputs.shape)
>>>     print("inputs.dtype:", inputs.dtype)
>>>     print("targets.shape:", targets.shape)
>>>     print("targets.dtype:", targets.dtype)
>>>     print("inputs[0]:", inputs[0])
>>>     print("targets[0]:", targets[0])
>>>     break
inputs.shape: (32, 20000)----输入是由20 000维向量组成的批量
inputs.dtype: <dtype: "float32">
targets.shape: (32,)
targets.dtype: <dtype: "int32">
inputs[0]: tf.Tensor([1. 1. 1. ... 0. 0. 0.], shape=(20000,), dtype=float32)----这些向量由01组成
targets[0]: tf.Tensor(1, shape=(), dtype=int32)

接下来,我们编写一个可复用的模型构建函数,如代码清单11-5所示。本节的所有实验都会用到它。

代码清单11-5 模型构建函数

from tensorflow import keras
from tensorflow.keras import layersdef get_model(max_tokens=20000, hidden_dim=16):inputs = keras.Input(shape=(max_tokens,))x = layers.Dense(hidden_dim, activation="relu")(inputs)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"])return model

最后,我们对模型进行训练和测试,如代码清单11-6所示。

代码清单11-6 对一元语法二进制模型进行训练和测试

model = get_model()
model.summary()
callbacks = [keras.callbacks.ModelCheckpoint("binary_1gram.keras",save_best_only=True)
]
model.fit(binary_1gram_train_ds.cache(),---- (本行及以下1)对数据集调用cache(),将其缓存在内存中:利用这种方法,我们只需在第一轮做一次预处理,在后续轮次可以复用预处理的文本。只有在数据足够小、可以装入内存的情况下,才可以这样做validation_data=binary_1gram_val_ds.cache(),epochs=10,callbacks=callbacks)
model = keras.models.load_model("binary_1gram.keras")
print(f"Test acc: {model.evaluate(binary_1gram_test_ds)[1]:.3f}")

模型的测试精度为89.2%,还不错!请注意,本例的数据集是一个平衡的二分类数据集(正面样本和负面样本数量相同)​,所以无须训练模型就能实现的“简单基准”的精度只有50%。与此相对,在不使用外部数据的情况下,在这个数据集上能达到的最佳测试精度为95%左右

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词