如何使用BERT和Tensorflow建立一个文本分类模型

675 阅读12分钟

如何使用BERT和Tensorflow构建文本分类模型

文本分类是机器学习的一个子集,它将文本分为预定义的类别。文本分类是自然语言处理(NLP)中的重要任务之一。

文本分类的一些例子是意图检测情感分析话题标签垃圾邮件检测

在本教程中,我们将建立一个垃圾邮件检测模型。垃圾邮件检测模型将把电子邮件分类为垃圾邮件或非垃圾邮件。这将被用于过滤不需要的和未经请求的电子邮件。我们将使用BERT和Tensorflow建立这个模型。

BERT将被用来为所有的电子邮件生成句子编码。最后,我们将使用Tensorflow来构建神经网络。Tensorflow将创建我们机器学习模型的输入和输出层。

前提条件

读者要理解本教程,应该。

  • 知道如何与[深度学习模型]打交道
  • 知道如何在数据分析中使用[Pandas]和[Numpy]。
  • 知道如何使用[TensorFlow]。
  • 拥有[谷歌Colab笔记本]。我们将使用谷歌Colab,因为它更快。

导入重要的包

让我们导入所需的包,如下。

import tensorflow as tf
import tensorflow_hub as hub
import tensorflow_text as text
import pandas as pd

我们已经导入了以下包。

  • tensorflow:它是用于建立神经网络的机器学习包。它将创建我们机器学习模型的输入和输出层。

  • tensorflow_hub:它包含一个预训练的机器模型,用于建立我们的文本分类。我们的预训练模型是BERT。我们将重新使用BERT模型并对其进行微调以满足我们的需求。

  • tensorflow_text:它将使我们能够处理文本。在本教程中,我们要解决的是一个文本分类问题。

  • pandas:我们将使用Pandas来加载我们的数据集。我们还使用Pandas进行数据操作和分析。它让我们对我们的数据集的结构有一个清晰的认识。

现在,让我们加载并探索我们将在本教程中使用的数据集。

我们需要运行这个命令来加载数据集。

df = pd.read_csv("spam.csv")

让我们看看我们的数据集中五个数据样本的结构。

df.head(5)

输出结果如下图所示。

Dataset structure

从上面的图片来看,我们的数据集有两个类别:hamspamham 代表不是垃圾邮件的邮件,这是来自可信来源的邮件。spam 代表来自未知来源的邮件。

该数据集还有Message 列。这一列代表电子邮件的信息。让我们看看spamham 的电子邮件的单个值计数。

df['Category'].value_counts()

输出结果如下所示。

Value count

从上面的图片来看,我们有4825封ham ,747封spamham 邮件的数量明显较多。

这两个类别的比例如下所示。

747/4825
0.15481865284974095

这个结果意味着,大约15%是垃圾邮件,85%是火腿邮件。这表明了一个类的不平衡。我们需要平衡这两个类别,以减少模型训练中的偏差。

平衡数据集

我们有各种技术来平衡数据集。在本教程中,我们将使用最简单的方法。我们将把多数类的4825个减少到747个。这将使两个类得到平衡。

在我们平衡两个班级之前,让我们为各个班级创建数据框架。

spam 类的数据框架

要创建数据框,请运行以下代码。

df_spam = df[df['Category']=='spam']

火腿 "类的数据框架

要创建这个数据框,请运行这段代码。

df_ham = df[df['Category']=='ham']

现在我们已经创建了两个数据框架,我们将减少ham 类的数量,使其与spam 类相等。

df_ham_downsampled = df_ham.sample(df_spam.shape[0])

我们将把新的类保存到一个df_ham_downsampled 变量中。我们需要将这两个平衡的类串联成一个数据框。

df_balanced = pd.concat([df_ham_downsampled, df_spam])

pd.concat 方法将把df_ham_downsampleddf_spam 串联成一个数据框。它将把数据集保存到一个变量df_balanced

现在让我们来检查一下这些类是否平衡。

df_balanced['Category'].value_counts()

输出如下所示。

spam    747
ham     747
Name: Category, dtype: int64

输出显示数据集的类值与747 相同。因此,我们的数据集现在是平衡的。

添加标签

我们需要将我们的数据集标记为101 将代表属于spam 类别的数据样本。0 将代表属于ham 类别的数据样本。

为了打上标签,数据集运行这段代码。

df_balanced['spam']=df_balanced['Category'].apply(lambda x: 1 if x=='spam' else 0)

从上面的代码中,我们用lambda 来编写我们的逻辑。apply 方法将运行写好的逻辑。这将使我们能够标记我们的数据集。

为了看到五个数据样本的输出,运行这段代码。

df_balanced.sample(5)

输出结果如下图所示。

Labeled dataset

从上面的图片中,我们可以看到,数据集被标记成了两个。一些数据样本被标记为1 ,而另一些被标记为0 。我们现在需要分割我们的标签数据集。

分割标记的数据集

我们把数据集分成两组,第一组将用于训练,第二组将用于测试。

我们将使用train_test_split 来分割我们的数据集,我们的导入方式如下。

from sklearn.model_selection import train_test_split

要分割这个数据集,请使用这段代码。

X_train, X_test, y_train, y_test = train_test_split(df_balanced['Message'],df_balanced['spam'], stratify=df_balanced['spam'])

在上面的代码中,我们使用stratify ,以确保训练和测试样本中的类别分布相等。这保证了我们在拆分后有等量的spamham 的邮件。分割完数据集后,我们就可以开始使用BERT了。

开始使用BERT

BERT是Bidirectional Encoder Representations from Transformers的缩写。BERT模型帮助机器理解和解释文本的含义。它使用紧接在前的文本来理解上下文。它还检查句子中的单词关系以给出单词的实际含义。

然后,BERT将把一个给定的句子转换成一个嵌入向量。嵌入向量用于表示给定文件中的独特词汇。BERT确保具有相同含义的单词将有一个类似的表示。

机器学习对文本不起作用,但对数字很有效。这就是为什么BERT将输入文本转换为嵌入向量。嵌入向量是数字,模型可以很容易地工作。

BERT的过程经历了两个阶段。预处理和编码。

预处理

预处理是BERT的第一个阶段。这个阶段涉及到从我们的数据集中去除噪音。在这个阶段,BERT将清理数据集。它还会从数据集中删除重复的记录。

它还将格式化数据集,以便在模型训练期间可以轻松使用。这将提高模型的性能。

编码

由于机器学习不能很好地处理文本,我们需要将文本转换为实数。这个过程被称为编码。BERT将把一个给定的句子转换成一个嵌入向量。

让我们下载BERT模型。

下载BERT模型

BERT模型通常是预先训练过的。它们在TensorFlow Hub中可用。TensorFlow Hub包含所有被下载的预训练的机器学习模型。

我们将下载两个模型,一个用于执行预处理,另一个用于编码。这些模型的链接如下所示。

bert_preprocess = hub.KerasLayer("https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3")
bert_encoder = hub.KerasLayer("https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/4")

下载模型后,让我们开始使用TensorFlow构建我们的模型。

使用TensorFlow建立模型

在TensorFlow中,有两种类型的模型可以建立。顺序模型和功能模型。在顺序模型中,层与层之间是相互建立的。在一个顺序模型中,我们没有多个输入和输出。

功能性模型更加稳健和灵活。它们不按顺序创建层。在功能模型中,我们有多个输入和输出。本教程将使用函数式方法来建立我们的模型。我们将从初始化BERT层开始。

初始化BERT层

text_input = tf.keras.layers.Input(shape=(), dtype=tf.string, name='text')
preprocessed_text = bert_preprocess(text_input)
outputs = bert_encoder(preprocessed_text)

在上面的代码中,我们正在使用tf.keras.layers.Input 方法创建一个输入层。我们将使用preprocessed_text 作为该层的输入。

然后,bert_encoder 函数将把预处理的文本转换成嵌入向量。这将是该层的输出。然后,outputs 将被送入神经网络层。

初始化神经网络层

l = tf.keras.layers.Dropout(0.1, name="dropout")(outputs['pooled_output'])
l = tf.keras.layers.Dense(1, activation='sigmoid', name="output")(l)

神经网络有两个层,Dropout 层,和Dense 层。

辍学 "层

这个层将被用来防止模型的过度拟合。我们将使用0.1% 的神经元来处理过拟合。过度拟合发生在模型从训练数据中完美学习,但在测试中表现不佳的情况下。我们也给它命名为dropout

由于我们使用函数方法来建立模型,我们使用(outputs['pooled_output']) ,将这一层的输入作为一个函数来添加。这个输入是BERT层的输出。

密集'层

它只有一个神经元。我们也将激活函数初始化为sigmoid 。当我们的输出值在01 之间时,就会使用sigmoid 。在我们的案例中,当进行预测时,预测概率将位于01 之间。这就是为什么它是最合适的。

我们也将该层命名为output ,因为这是我们的输出层。现在让我们加入输入和输出层,构建最终的模型,如下图所示。

model = tf.keras.Model(inputs=[text_input], outputs = [l])

该模型将使用text_input 作为输入,并将只有一个单一的输出。我们将显示模型摘要,以便我们可以看到所有使用的输入和输出层。

model.summary()

模型摘要如下图所示。

Model summary

上面的图片显示了我们为模型初始化的所有输入和输出层。输出还显示了总参数、可训练参数和不可训练参数。

  • 总参数。它代表了我们模型中的所有参数。

  • 可训练参数。它代表我们要训练的参数。

  • 不可训练的参数。这些参数是来自BERT模型。它们已经被训练过了。

让我们来编译我们的模型。

模型编译

在这个阶段,我们将为我们的模型设置optimizerloss function ,和metrics ,如下所示。

  • Optimizer 是用来提高模型性能和减少模型训练过程中出现的错误。我们使用adam 优化器。

  • Metrics 将用于检查模型的性能,这样我们就可以知道我们是如何训练我们的模型的。我们设置了 ,它将被用来计算模型的准确性得分。BinaryAccuracy(name='accuracy')

  • Loss function 是用来计算训练阶段的模型误差的。我们使用binary_crossentropy 作为我们的损失函数,因为我们的输出是二进制的。输出可以是0 ,也可以是1

我们现在设置这些参数。

METRICS = [
      tf.keras.metrics.BinaryAccuracy(name='accuracy'),
      tf.keras.metrics.Precision(name='precision'),
      tf.keras.metrics.Recall(name='recall')
]

model.compile(optimizer='adam',
 loss='binary_crossentropy',
 metrics=METRICS)

编译完模型后,我们现在可以将其拟合到我们的数据集中。

拟合模型

在这个阶段,模型从训练数据样本中进行学习。该模型将识别训练数据集中的模式并获得知识。

model.fit(X_train, y_train, epochs=10)

我们将指定 epochs 的数量为 10。该模型将在数据集中迭代10次,并在每次迭代后打印准确率分数。这个过程如下图所示。

Model training

经过十次迭代,模型的准确度得分是0.9179 。这个值代表91.79% 。让我们使用该模型来进行预测。

使用测试数据集评估模型

为了评估该模型,我们将使用该模型对测试数据集中的数据样本进行分类。它们应该被归入hamspam

使用下面的代码。

y_predicted = model.predict(X_test)
y_predicted = y_predicted.flatten()

model.predict 方法将给出二维数组中的预测结果,但我们希望我们的结果是一维数组。为了将结果从2D 转换为1D 数组,我们使用y_predicted.flatten() 函数。

由于我们使用了sigmoid 激活函数,预测概率将位于0.01.0 之间。因此,如果预测结果>0.5,输出应该是1 ,如果预测结果<0.5,输出应该是0

我们将使用NumPy来帮助我们创建这个逻辑。

import numpy as np

y_predicted = np.where(y_predicted > 0.5, 1, 0)
y_predicted

结果如下图所示。

Model prediction

上图显示我们的模型已经将数据样本分类为01 。我们现在可以使用这个模型,使用输入文本进行单一的预测。

进行预测

我们使用下面的文本来进行预测。

sample_dataset = [
 'You can win a lot of money, register in the link below,
 'You have an iPhone 10, spin the image below to claim your prize and it will be delivered in your door step',
 'You have an offer, the company will give you 50% off on every item purchased.',
 'Hey Bravin, don't be late for the meeting tomorrow will start lot exactly 10:30 am,
 "See you monday, we have alot to talk about the future of this company ."
]

上面的文本显示了电子邮件的例子。我们将使用我们的模型将这些电子邮件分类为spamham

要运行预测,请使用此代码。

model.predict(sample_dataset)

预测结果显示如下。

array([[0.8734353 ],
       [0.92858446],
       [0.8960864 ],
       [0.29311982],
       [0.13262196]], dtype=float32)

从上面的输出结果来看,前三封邮件已经被归类为spam 。他们的预测概率大于0.5。最后两封邮件被分类为ham 。它们的预测概率小于0.5。这些都是正确的预测,表明我们已经成功建立了我们的文本分类模型。

总结

在本教程中,我们学习了如何建立一个垃圾邮件检测模型。该模型能够将电子邮件分类为spamham 。我们首先使用BERT将一个给定的句子转换成嵌入向量。这是用预先训练好的BERT模型完成的。

我们使用TensorFlow创建了我们的模型,并初始化了所有的输入和输出层。我们遵循构建神经网络的所有阶段,最终得出了一个垃圾邮件检测模型。最后,我们使用该模型进行预测,该模型能够给出准确的预测结果。