情感分析神经网络训练指南:从零到精通

情感分析:从评论中洞察用户情绪

情感分析与文本挖掘和自然语言处理(NLP)紧密相关,旨在从书面评论中提取定性评价。以电影评论为例,许多人会阅读评论来评估一部电影在普通观众中的受欢迎程度。虽然电影的评分或星级评价可能无法完全反映其商业成功或失败,但一系列电影评论却能提供对电影的定性洞察。通过分析电影评论文本,我们可以了解观众认为电影的哪些方面表现出色,哪些方面有待改进。深入审查评论往往能揭示电影是否达到了评论者的期望。情感分析能够有效评估评论者对特定主题或评论的整体情感极性。

进行情感分析时,您可以使用计算程序来识别和分类文本中的观点,例如判断作者(或评论者)对给定主题(在本例中是一部电影)持有积极还是消极的态度。作为意见挖掘的一个子领域,情感分析侧重于从结构化、半结构化或非结构化的文本数据中提取对特定主题的情感和观点。与其他意见挖掘模型类似,情感分析可用于监测品牌和产品观点,并了解客户需求。情感分析不仅关注文本的极性(积极、消极或中性),还能检测评论者的具体情感和情绪(由模型定义的愤怒、快乐、悲伤等)、紧迫性,甚至意图(感兴趣与否)。

在本教程中,您将使用Keras构建一个神经网络,用于预测电影评论的情感。您的模型将使用国际电影数据库(IMDb)的评论数据集,该数据集包含50,000条电影评论,用于将评论分类为积极或消极两类。本教程结束后,您将能够创建一个深度学习模型并训练一个神经网络来进行情感分析。

前提条件

步骤1 – 准备您的Jupyter Notebook环境

Jupyter Notebook提供了一个交互式的计算环境,因此经常用于运行深度学习模型,而不是在命令行终端中使用Python。使用Jupyter Notebook,命令和输出会出现在同一个笔记本中,使您能够在开发分析过程时记录您的思考。

要在您的Jupyter Notebook中按照本教程进行操作,您需要打开一个新的Notebook并安装所需的依赖项,这将在本步骤中完成。

注意:如果您正在使用远程服务器的教程,则可以使用端口转发在本地机器的浏览器中访问您的Jupyter Notebook。

打开一个终端并输入以下命令:

ssh -L 8888:localhost:8888 您的非根用户@您的服务器IP

连接到服务器后,导航到输出中提供的链接以访问您的Jupyter Notebook。在本教程的其余部分中,请保持此终端打开。在前提条件中,您已在服务器上设置了一个Jupyter Notebook环境。一旦您登录到服务器上,激活虚拟环境。

source ~/environments/my_env/bin/activate

然后运行Jupyter Notebook应用程序来启动应用。

jupyter notebook

运行并连接后,您将在浏览器中访问到一个用户界面。从“New”下拉菜单中选择“Python3 (ipykernel)”选项,这将打开一个未命名的Python笔记本的新标签页。将文件命名为neural_network.ipynb,因为您将在此文件中运行代码。

然后,在浏览器的Jupyter Notebook的第一个单元格中,使用pip安装处理数据所需的依赖项。

neural_network.ipynb

!pip install numpy
!pip install tensorflow

numpy依赖于线性代数中的数组操作。在本教程中,您将使用它来通过调用以下函数来操作以数组形式存在的IMDb数据集:

  • 使用concatenate函数将测试数据数组序列连接到训练数据数组中。
  • 使用unique函数在数据集数组中找到独特的元素。
  • 在对数据集进行向量化时,使用zeros函数返回一个由零填充的新数组。

TensorFlow依赖库允许您在Python中训练和部署深度学习模型。安装TensorFlow也会同时安装KerasKeras运行在TensorFlow之上,并为用户和TensorFlow之间引入了一个抽象层,以便快速开发深度学习模型。本教程使用TensorFlowKeras完成整个情感分析的训练和部署过程。

在将这两个命令添加到您的Jupyter Notebook后,点击运行按钮来运行它们。

您的Jupyter Notebook将会提供一个运行输出来指示每个依赖项正在被下载。在这个输出下方会有一个新的输入单元格,您可以在其中运行接下来的代码行。

当依赖项下载完成后,您将导入它们。请将以下代码添加到下一个单元格中,然后按运行按钮。

neural_network.ipynb

import numpy as np
from keras.utils import to_categorical
from keras import models
from keras import layers

注意:当运行这些命令时,您可能会收到有关TensorFlow和TensorRT库的警告。通常,TensorFlow可以与CPU、GPU和TPU一起工作。警告信息说明安装的TensorFlow版本可以使用AVX和AVX2指令集,从而加快处理速度。这个警告不是错误,而是一个提示,表示TensorFlow将利用您的CPU提供额外的速度。

Keras工具的安装包含了内置的IMDb数据库。该数据集有50/50的训练集和测试集划分。为了避免过度训练神经网络,在本教程中,您将设置一个80/20的划分比例。因此,在下载数据后,您将合并数据和目标,以便在教程的后续部分进行80/20的划分。请将以下行添加到一个新的单元格中并点击运行:

neural_network.ipynb

这是文章《如何训练一个用于情感分析的神经网络》的第2部分(共8部分)。

from keras.datasets import imdb
(training_data, training_targets), (testing_data, testing_targets) = imdb.load_data(num_words=10000)
data = np.concatenate((training_data, testing_data), axis=0)
targets = np.concatenate((training_targets, testing_targets), axis=0)

此代码单元导入了IMDb数据集,并将训练数据和测试数据进行连接。默认情况下,数据集被划分为训练数据、训练目标、测试数据和测试目标。

您的Jupyter笔记本将包含一个活动日志,并且需要一些时间来下载数据集。

输出
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb.npz 17464789/17464789 [==============================] - 0s 0us/step

在这一步中,您准备了Jupyter Notebook环境,以便您可以调查此数据集的模式、假设和异常测试。接下来,您将对整个数据集进行探索性数据分析。

第二步——分析数据集

现在您将评估数据集,确定如何使用这些数据来训练您的模型。对数据集进行探索性数据分析将揭示数据集的潜在结构。这个过程可能会发现不容易察觉的趋势、模式和关系。这些信息可以帮助您检测错误、驳斥假设,并理解关键变量之间的关系。这些洞察力最终可能会导致选择一种合适的预测模型。

您在处理这个数据集时的第一个任务是获取输出类型和不重复单词的数量。要获取这些信息,请在一个新的单元格中运行以下代码行:

神经网络.ipynb
print("输出类别为", np.unique(targets))
print("不重复单词的数量为", len(np.unique(np.hstack(data))))

此单元格打印数据集中唯一情感(积极[1]或消极[0])的数量,以及评论中使用的唯一单词数量。

下面的输出将打印:

输出
输出类别为 [0 1] 不重复单词的数量为 9998

这个输出的第一行说明电影被标记为积极(1)或消极(0)。第二行说明数据集中有9998个独特的单词。

接下来,您将确定电影评论的平均词长和词的标准差。为此,请在新单元格中运行以下代码行:

神经网络.ipynb
length = [len(i) for i in data]
print("平均评论长度为", np.mean(length))
print("标准差为", round(np.std(length)))

此单元格将打印数据集的平均评论长度和标准差。

输出

平均评论长度为 234.75892
标准差为 173

这项评估表明,平均评论长度为234个字,标准差为173。

接下来,您可以通过在新单元格中运行以下代码来打印数据集中的一个元素(第一个索引)。

神经网络.ipynb

print("标签:", targets[0])
print(data[0])

数据集中第一个元素的电影评论 – 标签对将输出:

输出

标签: 1 [1, 14, 22, 16, 43, 530, 973, 1622, 1385, 65, 458, 4468, 66, 3941, 4, 173, 36, 256, 5, 25, 100, 43, 838, 112, 50, 670, 2, 9, 35, 480, 284, 5, 150, 4, 172, 112, 167, 2, 336, 385, 39, 4, 172, 4536, 1111, 17, 546, 38, 13, 447, 4, 192, 50, 16, 6, 147, 2025, 19, 14, 22, 4, 1920, 4613, 469, 4, 22, 71, 87, 12, 16, 43, 530, 38, 76, 15, 13, 1247, 4, 22, 17, 515, 17, 12, 16, 626, 18, 2, 5, 62, 386, 12, 8, 316, 8, 106, 5, 4, 2223, 5244, 16, 480, 66, 3785, 33, 4, 130, 12, 16, 38, 619, 5, 25, 124, 51, 36, 135, 48, 25, 1415, 33, 6, 22, 12, 215, 28, 77, 52, 5, 14, 407, 16, 82, 2, 8, 4, 107, 117, 5952, 15, 256, 4, 2, 7, 3766, 5, 723, 36, 71, 43, 530, 476, 26, 400, 317, 46, 7, 4, 2, 1029, 13, 104, 88, 4, 381, 15, 297, 98, 32, 2071, 56, 26, 141, 6, 194, 7486, 18, 4, 226, 22, 21, 134, 476, 26, 480, 5, 144, 30, 5535, 18, 51, 36, 28, 224, 92, 25, 104, 4, 226, 65, 16, 38, 1334, 88, 12, 16, 283, 5, 16, 4472, 113, 103, 32, 15, 16, 5345, 19, 178, 32]

此输出为数据集的第一条评论,标记为正面(1),并以整数索引形式提供了全文。默认情况下,文本评论以数值编码形式给出,作为基于整数的单词索引列表。评论中的单词索引基于它们在整个数据集中的出现频率。例如,数据中出现次数第二多的术语由整数2进行编码。

接下来,您将检索字典,将单词索引映射回原始单词,以便您可以阅读文本评论。请在新单元格中运行这些代码。

神经网络.ipynb

这是文章《如何训练一个用于情感分析的神经网络》的第4部分(共8部分)。

index = imdb.get_word_index()
reverse_index = dict([(value, key) for (key, value) in index.items()])
decoded = " ".join( [reverse_index.get(i - 3, "#") for i in data[0]] )
print(decoded)

这段代码将数字形式解码为可读文本。通过 get_word_index() 函数,您可以检索将单词映射到其在 IMDb 数据集中索引的字典。然后,reverse_index 变量保存将单词索引反转后,把索引映射到单词的字典。dict() 函数创建一个以键值对形式存储数据值的字典。代码的最后两行将解码并打印数据集中的第一个序列。

使用 get_word_index() 函数,您将收到以下输出:

输出
# this film was just brilliant casting location scenery story direction everyone's really suited the part they played and you could just imagine being there robert # is an amazing actor and now the same being director # father came from the same scottish island as myself so i loved the fact there was a real connection with this film the witty remarks throughout the film were great it was just brilliant so much that i bought the film as soon as it was released for # and would recommend it to everyone to watch and the fly fishing was amazing really cried at the end it was so sad and you know what they say if you cry at a film it must have been good and this definitely was also # to the two little boy's that played the # of norman and paul they were just brilliant children are often left out of the # list i think because the stars that play them all grown up are such a big profile for the whole film but these children are amazing and should be praised for what they have done don't you think the whole story was so lovely because it was true and was someone's life after all that was shared with us all

get_word_index() 函数将该评论的数字数据解码为可读的单词,并将每个无法识别的单词替换为“#”。

在这一步中,您已经对数据集进行了评估,审查了每个评论的准备情况。有了这些信息,现在您将准备数据进行训练。

第三步 – 为训练准备数据

在这一步骤中,您将为训练准备数据集。深度学习模型通常是根据它们所训练的数据逐渐发展的。

在准备数据时,您需要以精确的方式对其进行格式化,以产生有价值的洞见,从而得到更准确的模型结果。一些数据准备的技术包括特征选择(选择与模型相关的特征)、特征工程(使用编码方法将数据集中的变量转换为有用的特征)以及将数据集分割为训练集和测试集。

在本教程中,您将把数据分成测试集和训练集,并通过将数据向量化进行特征工程。

在下一个单元格中,运行以下代码以将数据集中的每个评论转化为向量。

神经网络.ipynb

def vectorize(sequences, dimension = 10000):
    results = np.zeros((len(sequences), dimension))
    for i, sequence in enumerate(sequences):
        results[i, sequence] = 1
    return results

data = vectorize(data)
targets = np.array(targets).astype("float32")

首先,您将对每个评论进行向量化和填充,确保每个评论都包含10,000个数字。通过这个过程,您将填充每个短于10,000字的评论,因为数据集中最长的评论大约是这个长度,并且神经网络要求每个输入都具有相同的大小。

vectorize()函数接受两个参数:一个数组和一个预设的维度10000。这个函数调用NumPy库中的zeros()方法,该方法返回一个由零填充的新数组,然后对剩余的数据进行编码。通过最后两行代码,您将在数据集上调用定义的函数,然后将数据集的目标列转换为32位浮点数。32位浮点数是具有大约七位有效数字的浮点数。将目标列转换为32位浮点数将增加列的精确度,并进而提升深度学习模型的性能。

作为准备数据的最后一步,您将把数据分成训练集和测试集。您将把40,000个评论放入训练集中,将10,000个评论放入测试集中,实现之前提到的80/20的分割比例。

在新的单元格中运行这些命令来拆分您的数据集。

神经网络笔记本.ipynb
test_x = data[:10000]
test_y = targets[:10000]
train_x = data[40000:]
train_y = targets[40000:]

数据集已经按照1:4的比例分成测试集和训练集。其中,训练集和测试集的目标变量分别保存为train_ytest_y,训练集和测试集的评论分别保存为train_xtest_x。此外,除了使用新数据测试和评估模型外,数据集的分割还可以防止模型过拟合,即算法过于拟合训练数据。

在这一步中,您准备了数据并将数据集分为训练集和测试集。您将原始数据转换为可用于深度学习模型的特征。准备好训练数据后,您现在将构建并训练神经网络,该神经网络将用于您的深度学习模型。

第四步——构建和训练神经网络

现在您可以构建您的神经网络了。

您将从定义您想要构建的模型类型开始。在Keras中有两种可用的模型类型:顺序模型API和函数式API。在本教程中,您将使用顺序模型API,因为它允许您逐层创建模型。

注意:

对于更复杂的深度学习模型,您应该使用函数式API,因为顺序API不允许您创建共享层或具有多个输入或输出的模型。然而,对于本教程来说,顺序API就足够了。在新的单元格中运行以下命令,将您的模型设置为序列模型。

神经网络笔记本.ipynb
model = models.Sequential()

注意:

在此阶段您可能会遇到另一个TensorFlow错误,提示您使用适当的编译器标签重新构建TensorFlow。这个错误与之前的错误相关,因为TensorFlow 2.x软件包同时支持CPU和GPU,所以TensorFlow正在寻找GPU驱动程序。您可以安全地忽略这个警告,因为它不会影响教程的结果。由于层是深度学习模型的基础,下一步您将添加输入层、隐藏层和输出层。在它们之间,您将在每一层上使用dense,并使用dropout来防止过拟合。

在一个新的单元格中运行这些代码以添加层:

神经网络笔记本.ipynb

这是文章《如何训练一个用于情感分析的神经网络》的第6部分(共8部分)。

# 输入层
model.add(layers.Dense(50, activation = "relu", input_shape=(10000, )))
# 隐藏层
model.add(layers.Dropout(0.3, noise_shape=None, seed=None))
model.add(layers.Dense(50, activation = "relu"))
model.add(layers.Dropout(0.2, noise_shape=None, seed=None))
model.add(layers.Dense(50, activation = "relu"))
# 输出层
model.add(layers.Dense(1, activation = "sigmoid"))
model.summary()

由于它产生了令人满意的结果,你将在隐藏层中使用ReLU函数。ReLU代表修正线性单元(Rectified Linear Unit),该函数在接收到任何负输入时返回0,并在接收到任何正值时返回该值。将此函数添加到你的第一层中,通过返回0去除了负值。在本教程中,ReLU函数确保所有进入输入层的值都是必要的神经输入的正值。

在输出层,你将使用Sigmoid函数,该函数将值映射到0和1之间。由于输出是正数(1)或负数(0),Sigmoid函数将确保输出层产生的输出是0或1。

最后,你将让Keras打印一份你刚刚构建的模型摘要。

你将收到你刚训练的模型的特性摘要。

输出
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 50)                500050    
dropout (Dropout)            (None, 50)                0         
dense_1 (Dense)              (None, 50)                2550      
dropout_1 (Dropout)          (None, 50)                0         
dense_2 (Dense)              (None, 50)                2550      
dense_3 (Dense)              (None, 1)                 51        
=================================================================
Total params: 505,201
Trainable params: 505,201
Non-trainable params: 0
_________________________________________________________________

接下来,你将编译并配置用于训练的模型。你将使用Adam优化器,它是一种在训练过程中改变权重和偏差的算法,并将二元交叉熵(Binary Crossentropy)作为损失函数、准确率(Accuracy)作为评估指标。损失函数将计算模型在训练期间应该寻求最小化的量。在这种情况下,你选择了二元交叉熵,因为真实标签和预测标签之间的交叉熵损失是二元(0或1)分类应用的一个优秀度量指标。

要编译模型,请在下一个单元格中运行以下命令。

神经网络.ipynb

model.compile(
optimizer = "adam",
loss = "binary_crossentropy",
metrics = ["accuracy"]
)

compile()函数定义了模型的架构。在此定义中,您使用Adam算法作为模型的优化器。Adam算法是一种基于近似一阶和二阶矩的梯度下降方法。度量标准(metrics)和损失参数(loss)密切相关。度量标准参数定义了如何评估模型的性能,而损失参数定义了模型在训练过程中需要最小化的量。这里的度量标准是准确率(模型正确预测的比例),损失函数是二元交叉熵(当只有两个标签类别(正类别1和负类别0)时,衡量标签与预测之间差异的标准)。

现在,您将能够训练您的模型。为此,您将使用批量大小为32,并且只进行两个周期(epoch)。批量大小是指每次通过神经网络传播的样本数量,而周期是对整个训练数据的一次迭代。通常,较大的批量大小意味着训练速度更快,但有时收敛较慢。相反,较小的批量大小在训练时较慢,但可以更快地收敛。

您现在将开始训练模型,以获取所有参数的正确值,将输入映射到您的输出。请在下一个单元格中运行这些代码。

神经网络.ipynb
results = model.fit(
train_x, train_y,
epochs= 2,
batch_size = 32,
validation_data = (test_x, test_y)
)

您将使用.fit()函数来训练您的模型。此函数在数据集上对深度学习模型进行固定次数的迭代训练。该函数有两个必需的参数:

  • train_x:指输入数据。
  • train_y:指训练集的标签数据,模型将在此数据上进行训练,并且可以接受其他参数。

其他参数包括:

  • epochs:训练模型的周期数,一个周期是对所提供全部数据的一次迭代。
  • batch_size:每次梯度更新的样本数量。
  • validation_data:模型在每个周期结束时评估损失的数据。

这段代码使用两个周期和批量大小为32来训练模型,这意味着整个数据集将通过神经网络两次,并且每次迭代中使用32个训练样例。验证数据使用test_xtest_y

注意:训练情感分析模型需要大量内存。如果您在一台只有8GB内存的服务器上运行本教程,可能会收到以下警告:分配的x超过了可用系统内存的10%。当出现这个警告时,您可以忽略它并继续进行教程,因为它只是说明训练过程占用了相当数量的空闲系统内存,对教程的其他部分没有影响。在这一步中,您构建了深度学习模型,并在您准备的数据集上进行了训练。接下来,您将使用在这一步中生成的验证数据,评估模型对另一个数据集的性能。

第五步 — 评估模型

在这一步骤中,您将对模型进行评估。模型评估是机器学习改进和发展过程中不可或缺的一部分。该评估有助于找到最能代表您的数据和最适合的模型,并评估所选择模型的表现效果。

机器学习分类模型有四个主要的模型评估指标:准确率、精确度、召回率和F1得分。

准确率是一个常用的性能指标,因为它评估了模型预测正确的比例。准确率通过将正确预测的数量除以总预测数量来确定。在本教程中,您将使用准确率来评估您的模型。

在该模型的背景下,精确度指的是预测准确的正面电影评论与总预测正面电影评论的比例。召回率是正确预测的正面电影评论与数据集中评估的总电影评论数量的比例。精确度回答了这个问题:您的模型标记为正面的所有电影评论中,有多少实际上是正面的?相反,召回率回答了这个问题:所有真正正面的电影评论中,您的模型标记为正面的有多少?F1得分是精确度和召回率结果的加权平均值。因此,它考虑了被错误分类的任何评论。

在这个教程中,您将使用准确率评估模型的性能。在下一个单元格中运行以下代码行。

神经网络.ipynb
scores = model.evaluate(test_x, test_y, verbose=0)
print("Accuracy: %.2f%%" % (scores[1]*100))

这段代码将模型的准确率分数存储在一个名为scores的变量中,并将其打印到屏幕上。.evaluate()函数接受三个参数:

  • x_test:测试数据集的特征列。
  • y_test:测试数据集的目标列。
  • verbose:详细模式。

以下结果将以精确率打印出来。

输出

准确率: 86.59%

这个训练模型的准确率为86.59%。

这个准确度分数表明,该模型在十次中有九次能准确预测出评论是积极还是消极的。您可以继续改进您的代码,尝试提高分类器的准确性。为了使您的模型表现更好并提高准确度,您可以增加模型的迭代次数或批处理大小。

深度学习模型(和机器学习模型)的强大程度取决于所输入的数据。因此,通过增加更多的数据来提高模型的准确性是常见的做法。然而,用于该模型的数据是内置的,无法修改。在这种情况下,您可以通过在第四步中增加更多的层或增加迭代次数(将整个数据集通过神经网络传递的次数)来提高模型的准确性。

为了增加周期数目,在model.fit()的代码块中将周期数从2更改为3(或其他数字),然后重新运行该代码块及其后续代码块。

神经网络.ipynb
results = model.fit(
    train_x, train_y,
    epochs=3,
    batch_size=32,
    validation_data=(test_x, test_y)
)

增加了训练轮次的数量,这意味着训练数据将总共经过神经网络三次,模型将有额外的机会从数据中学习。当您重新运行model.evaluate()函数时,将会得到一个更新的准确率输出。

在这个步骤中,您通过计算准确率评估了您构建的模型。在初始计算之后,您增加了训练轮次的数量来改善模型,并重新评估准确率得分。

总结

在这个教程中,您使用Keras训练了一个神经网络,用于将电影评论的情感分类为积极或消极。您使用了由斯坦福大学研究人员收集的IMDb情感分类数据集。该数据集是Keras预加载的二元情感分类数据集之一。您可以访问这个数据集,其中包含了25,000条高度极化的电影评论用于训练,以及另外25,000条用于测试。您对这个数据集进行了回顾,以开发一个适用于情感分析的大型神经网络模型。

既然您已经构建并训练了一个神经网络,您可以使用自己的数据来尝试这个实现,或者在其他流行的数据集上进行测试。您可以尝试使用其他的Keras数据集,或者尝试不同的算法。

为了加强您在Keras和TensorFlow方面的经验,您可以根据我们的教程,使用Keras和TensorFlow构建深度学习模型来预测员工保留情况。

bannerAds