敢不敢跟我一起,15分钟预训练数据到模型训练全流程跑通!概念看了万万千,一到动手就蒙圈!看完这个流程绝对懂了!学AI怎么能错过?

文摘   2024-08-20 22:55   浙江  


点击箭头处“蓝色字”,关注更多及时AI资讯!!



小纸条之前给大家分享过结合RAG构建企业知识数据库的流程,对于数据集的构建的几种方式之前也有展开探讨,那今天就从实打实的代码的角度,来看下不论是对模型训练还是微调都至关重要的一环-文本预处理,以及接着处理好的数据,如何建立和训练一个自己的模型的最小MVP流程示范!

不会写代码的同学也不用担心!我们只要跟着代码过一下这个数据处理的流程,就能加深不少理解!我也不是非常熟悉python,但是跟着看下来,也的的确确对于之前提到的一些概念和参数用在哪里有了更好的认识!


然后看下来之后可以再去colab的官网上跟着做一遍,体感会更强哦,传送门:

https://www.tensorflow.org/tutorials/keras/text_classification?hl=zh-cn#%E8%AE%AD%E7%BB%83%E6%A8%A1%E5%9E%8B

接下来的内容会结合对 BERT 进行微调的完整代码,主要是对 IMDB 电影评论纯文本数据集进行情感分析。主要环节为:

  • 加载 IMDB 数据集

  • 从 TensorFlow Hub 加载 BERT 模型 将 BERT 与分类器相结合

  • 建立咱自己的模型

  • 训练咱自己的模型,将 BERT 作为其中的一部分进行微调

  • 保存咱的模型,并用它对句子进行分类


IMDB数据集构建


我们将训练一个二元分类器对 IMDB 数据集执行情感分析。主要方式就是利用收集到的评论文本将电影评论分类为正面或负面评价。这是一个典型的二元(或二类)分类示例,也是一个重要且应用广泛的机器学习问题。

我们使用 Large Movie Review Dataset

(https://ai.stanford.edu/%7Eamaas/data/sentiment/),其中包含 Internet Movie Database (https://www.imdb.com/)中的 50,000 条电影评论文本 。我们将这些评论分为两组,其中 25,000 条用于训练,另外 25,000 条用于测试。训练集和测试集是均衡的,也就是说其中包含相等数量的正面评价和负面评价。

(下面我们专注流程的梳理,一些中间的输出用截图表示,代码在流程讲解完的下面)


基本的环境准备



下载并IMDB 数据集


我们下载并提取数据集,然后浏览一下目录结构

url:指定了数据集的链接

tf.keras.utils.get_file(...):这是 TensorFlow 中的一个工具函数,用于下载文件。它的参数包括:

  • aclImdb_v1: 下载后的文件名

  • url: 从中下载的文件的链接

  • untar=True: 指定下载的文件是否需要解压。这里设置为 `True`,意味着下载的文件是一个 tar.gz 格式的压缩文件,会在下载完成后被自动解压

  • cache_dir='.': 下载的文件将会保存在当前工作目录(`.`)下

  • cache_subdir='': 指定在缓存目录中的子文件夹为空,这样文件将直接下载到 `cache_dir` 目录。

os.path.dirname(dataset)`来获取下载文件的目录并连接上 'aclImdb' 子目录。`dataset` 是下载后解压的目录


列出了解压后的数据集目录中包含的文件和文件夹

第一行代码构建了训练数据的路径,连接上 'train' 子目录,指向训练集的文件夹。

第二行代码列出训练数据目录中的文件和文件夹,通常包括样本的情感分类(积极/消极的文本文件)。

这其中的pos 和 neg 目录包含许多文本文件,每个文件都是一条电影评论。我们来看看其中的一条评论。


加载数据集


接下来,我们来将从磁盘加载数据并将其准备为适合训练的格式。为此,我们需要使用

text_dataset_from_directory 实用工具,它期望的目录结构如下所示

要准备用于二元分类的数据集,磁盘上需要有两个文件夹,分别对应于 class_a 和 class_b。这些将是正面和负面的电影评论,可以在上面我们加载到的aclImdb/train/pos 和 aclImdb/train/neg 中找到。因为IMDB 数据集包含其他文件夹,所以我们要在使用此实用工具之前将其移除。

remove_dir = os.path.join(train_dir, 'unsup')

shutil.rmtree(remove_dir)

接下来,我们来使用 text_dataset_from_directory 实用工具创建带标签的 tf.data.Dataset。tf.data 是一组强大的数据处理工具。

运行机器学习实验时,最佳做法是将数据集拆成三份:训练、验证测试

IMDB 数据集已经分成训练集和测试集,但缺少验证集。我们来通过下面的 validation_split= 0.2来设置80:20的比例来拆分训练数据,创建验证集。

如上所示,训练文件夹中有 25,000 个样本,我们将使用其中的 80%(或 20,000 个)进行训练。我们可以遍历数据集并打印出一些样本

label表示标签为 0 或 1,下面的Label 0/1 corresponds to表示内容与正面和负面电影评论的对应关系,来自于数据集上的哪个class_names 属性

接下来我们来创建验证数据集和测试数据集。我们来使用训练集中剩余的 5,000 条评论进行验证。

注:使用 validation_split 和 subset 参数时,确保要么指定随机种子,要么传递 shuffle=False,这样验证拆分和训练拆分就不会重叠


准备用于训练的数据集


接下来,我们来使用

tf.keras.layers.TextVectorization 层对数据进行标准化、词例化和向量化。

标准化是指对文本进行预处理,通常是移除标点符号或 HTML 元素以简化数据集。词例化是指将字符串分割成词例(例如,通过空格将句子分割成单个单词)。向量化是指将词例转换为数字,以便将它们输入神经网络。所有这些任务都可以通过这个层完成。

我们上面也看到了,评论包含各种 HTML代码,例如
。TextVectorization 层(默认情况下会将文本转换为小写并去除标点符号,但不会去除 HTML)中的默认标准化程序不会移除这些代码。我们编写一个自定义标准化函数来移除 HTML。

注:为了防止训练-测试偏差(也称为训练-应用偏差),在训练和测试时间对数据进行相同的预处理非常重要。为此,可以将 TextVectorization 层直接包含在模型中。

接下来,我们创建一个 TextVectorization 层,使用该层对我们的数据进行标准化、词例化和向量化。我们要将 output_mode 设置为 int 以便为每个词例创建唯一的整数索引。

我们使用的是默认拆分函数,以及我们在上面定义的自定义标准化函数。我们还可以为模型定义一些常量,例如显式的最大 sequence_length,来将序列填充或截断为精确的 sequence_length 值。

接下来,我们调用 adapt 以使预处理层的状态适合数据集,让过模型构建字符串到整数的索引。

注:在调用时请务必仅使用我们自己的训练数据(使用测试集会泄漏信息)

我们来创建一个函数来查看使用该层预处理一些数据的结果(精彩!)

正如我们在上面看到的,每个词例都被一个整数替换了。我们可以通过在该层上调用 .get_vocabulary() 来查找每个整数对应的词例(字符串),如下图

最后的预处理步骤,将我们之前创建的 TextVectorization 层分别应用于训练数据集、验证数据集和测试数据集。

到此,我们就可以开始训练我们的模型了!


配置数据集到内存


以下是加载数据时应该使用的两种重要方法,以确保 I/O 不会阻塞。

从磁盘加载后,.cache() 会将数据保存在内存中。这将确保数据集在训练模型时不会成为瓶颈。如果您的数据集太大而无法放入内存,也可以使用此方法创建高性能的磁盘缓存,这比许多小文件的读取效率更高。

prefetch() 会在训练时将数据预处理和模型执行重叠。


创建模型


我们开始创建我们的神经网络



tf.keras.Sequential定义了一个顺序模型(Sequential Model),它是 Keras 中的一种模型类型,适合于层按顺序堆叠的情况layers层按需要顺序堆叠,以构建分类器:

嵌入层 (Embedding Layer) :

layers.Embedding(max_features+1,embedding_dim)

max_features + 1:表示词汇表的大小,加一是因为通常需要包含一个用于填充的索引(padding index)。

embedding_dim:表示嵌入向量的维度(每个词或词索引的表示维度)。嵌入层将词索引映射到其相应的嵌入向量。

丢弃层 (Dropout Layer) :layers.Dropout(0.2)

是一个丢弃层,执行随机丢弃输入的一部分。这里 0.2 表示有 20% 的概率将输入的一部分置为零,旨在防止过拟合。

全局平均池化层 (GlobalAveragePooling1D Layer):layers.GlobalAveragePooling1D()

这个层对输入的每个特征的平均值进行池化操作,减少数据的维度,使得后面的全连接层将处理更小的输入。

全连接层 (Dense Layer):layers.Dense(1)

最后一层是一个全连接层,输出一个单一的值。常用于二分类任务,代表模型用于预测某种标签的概率或评分。


损失函数与优化器


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

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


训练模型


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


评估模型


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

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


导出模型


在上面的代码中,我们在向模型馈送文本之前对数据集应用了 TextVectorization。如果我们想让模型能够处理原始字符串(例如,为了简化部署),可以在模型中包含 TextVectorization 层。为此,我们可以使用刚刚训练的权重创建一个新模型。


使用新数据进行推断


要获得对新样本的预测,只需调用 model.predict() 即可。

将文本预处理逻辑包含在模型中后,我们就可以导出用于生产的模型,从而简化部署并降低训练/测试偏差的可能性。

在选择应用 TextVectorization 层的位置时,需要注意性能差异。在模型之外使用它可以让我们在 GPU 上训练时进行异步 CPU 处理和数据缓冲。所以如果要在 GPU 上训练模型,我们应该在开发模型时使用此选项来提高性能,然后在准备好部署时进行切换,在模型中包含 TextVectorization 层。

参考:

https://www.tensorflow.org/tutorials/keras/text_classification?hl=zh-cn#%E8%AE%AD%E7%BB%83%E6%A8%A1%E5%9E%8B

扫码关注更多AI资讯

我们一起学AI!



同桌的AI小纸条
一个专注于将先进的AI人工智能技术融入日常生活的频道。关注让AI为我们所用,探索人工智能领域的无限可能,并征服他们,让AI赋能生活快乐每一天!
 最新文章