当前位置: 首页 > ds >正文

TensorFlow深度学习实战——基于循环神经网络的情感分析模型

TensorFlow深度学习实战——基于循环神经网络的情感分析模型

    • 0. 前言
    • 1. 数据处理
    • 2. 模型构建与训练
    • 3. 模型评估
    • 相关链接

0. 前言

情感分析 (Sentiment Analysis) 是自然语言处理中的一项技术,旨在识别和提取文本中的情感信息,通常是分析一段文本中是否存在积极、消极或中立的情绪,广泛应用于社交媒体监控、客户反馈分析、产品评论分析等领域。我们已经学习了使用 TensorFlow 构建简单情感分析模型,在本节中,将实现基于循环神经网络的情感分析模型,进一步提高情感分析性能。

1. 数据处理

本节构建的基于循环神经网络的情感分析模型属于多对一结构,以句子为输入并预测其情感是正面还是负面。数据集是来自 UCI 机器学习库上的 Sentiment-labeled sentences 数据集,包含来自亚马逊、IMDbYelp3,000 条评论句子,句子标记为 0 表示评论表达了负面情感,标记为 1 表示评论表达了正面情感。

(1) 首先,导入所需库:

import numpy as np
import os
import shutil
import tensorflow as tf
from sklearn.metrics import accuracy_score, confusion_matrix

(2) 数据集以压缩文件提供,解压后包含三个文件,每个文件包含一个提供者的标记句子,每行包含一个句子和一个标签,句子和标签之间用制表符分隔。首先下载压缩文件,然后将文件解析为(句子, 标签)对的列表:

def clean_logs(data_dir):logs_dir = os.path.join(data_dir, "logs")shutil.rmtree(logs_dir, ignore_errors=True)return logs_dirdef download_and_read(url):local_file = url.split('/')[-1]local_file = local_file.replace("%20", " ")p = tf.keras.utils.get_file(local_file, url, extract=True, cache_dir=".")local_folder = os.path.join("datasets", local_file.split('.')[0])labeled_sentences = []for labeled_filename in os.listdir(local_folder):if labeled_filename.endswith("_labelled.txt"):with open(os.path.join(local_folder, labeled_filename), "r") as f:for line in f:sentence, label = line.strip().split('\t')labeled_sentences.append((sentence, label))return labeled_sentences# clean up log area
data_dir = "./data"
logs_dir = clean_logs(data_dir)# download and read data into data structures
labeled_sentences = download_and_read("https://archive.ics.uci.edu/ml/machine-learning-databases/00331/sentiment%20labelled%20sentences.zip")
sentences = [s for (s, l) in labeled_sentences]
labels = [int(l) for (s, l) in labeled_sentences]

(3) 模型训练的目标是,使其能够根据输入的句子预测相应的情感标签。每个句子都是一个单词序列。然而,为了将其输入模型,我们必须将其转换为一个整数序列。序列中的每个整数指向一个单词,整数与单词的映射称为词汇表。因此,我们需要对句子进行词元化 (tokenize) 并生成词汇表:

# tokenize sentences
tokenizer = tf.keras.preprocessing.text.Tokenizer()
tokenizer.fit_on_texts(sentences)
vocab_size = len(tokenizer.word_counts)
print("vocabulary size: {:d}".format(vocab_size))word2idx = tokenizer.word_index
idx2word = {v:k for (k, v) in word2idx.items()}

本节的词汇表包含 5,271 个唯一的单词。可以通过丢弃出现次数低于某个阈值的单词来缩小词汇表的大小,该阈值可以通过检查 tokenizer.word_counts 字典确定。在这种情况下,我们需要为词汇表添加一个用于表示未知单词 (UNK) 的项,用以替换所有在词汇表中未找到的单词。
构建查找字典,以便在单词和索引之间进行转换。第一个字典在训练期间用于构建整数序列,以供网络使用。第二个字典用于将单词索引转换回单词,以便在后续的预测代码中使用。

(4) 每个句子的单词数可能不同。我们的模型需要为每个句子提供相同长度的整数序列。为了满足这个要求,通常会选择一个足够大的最大序列长度,以容纳训练集中大多数句子。较短的句子将用零填充,而较长的句子将被截断。选择最大序列长度的一个简单方法是查看不同百分位数位置的句子长度(即单词数):

seq_lengths = np.array([len(s.split()) for s in sentences])
print([(p, np.percentile(seq_lengths, p)) for p in [75, 80, 90, 95, 99, 100]])

输出结果如下所示:

[(75, 16.0), (80, 18.0), (90, 22.0), (95, 26.0), (99, 36.0), (100, 71.0)]

可以看到,最大句子长度为 71 个单词,但 99% 的句子长度都在 36 个单词以下,如果选择 64 作为阈值,大多数情况下不需要截断句子。可以多次交互式地运行以上代码块,以选择合适的词汇表大小和最大序列长度的值。在本节中,我们选择保留所有单词(即 vocab_size = 5271),并将 max_seqlen 设置为 64

(5) 接下来,创建模型可用的数据集。首先使用训练好的词元分析器 (tokenizer),将每个句子从单词序列 (sentences) 转换为整数序列 (sentences_as_ints),其中每个整数对应于词元分析器中单词的索引 (tokenizer.word_index),然后对其进行截断并用 0 进行填充。标签同样转换为 NumPy 数组 labels_as_ints,最后,将张量 sentences_as_intslabels_as_ints 合并为一个 TensorFlow 数据集:

max_seqlen = 64# create dataset
sentences_as_ints = tokenizer.texts_to_sequences(sentences)
sentences_as_ints = tf.keras.preprocessing.sequence.pad_sequences(sentences_as_ints, maxlen=max_seqlen)
labels_as_ints = np.array(labels)
dataset = tf.data.Dataset.from_tensor_slices((sentences_as_ints, labels_as_ints))

(6) 将数据集的三分之一用于模型评估,剩余数据中,使用 10% 作为验证数据集,验证数据集将用于在训练过程中评估模型的进展,剩余部分作为训练数据集。最后,将每个数据集的批大小设为 64

# split into train and test
dataset = dataset.shuffle(10000)
test_size = len(sentences) // 3
val_size = (len(sentences) - test_size) // 10
test_dataset = dataset.take(test_size)
val_dataset = dataset.skip(test_size).take(val_size)
train_dataset = dataset.skip(test_size + val_size)batch_size = 64
train_dataset = train_dataset.batch(batch_size)
val_dataset = val_dataset.batch(batch_size)
test_dataset = test_dataset.batch(batch_size)

2. 模型构建与训练

定义模型。模型的每个输入句子是一个大小为 max_seqlen (64) 的整数序列,该序列输入到嵌入层中,该层将每个单词转换为一个向量,大小为 (vocab_size + 1), 其中 vocab_size 表示词汇表大小。额外的单词用于处理在 pad_sequences() 调用中引入的填充整数 0。每个时间步的 64 个向量送入一个双向长短期记忆 (Long Short Term Memory, LSTM) 层,该层将每个单词转换为大小为 (64,) 的向量。LSTM 在每个时间步的输出送入一个使用 ReLU 激活的全连接层,生成一个大小为 (64, ) 的向量。这个全连接层的输出再送入另一个全连接层,该层通过 sigmoid 激活在每个时间步输出一个大小为 (1, ) 的向量。模型使用二元交叉熵损失函数和 Adam 优化器编译,然后训练 10epochs

class SentimentAnalysisModel(tf.keras.Model):def __init__(self, vocab_size, max_seqlen, **kwargs):super(SentimentAnalysisModel, self).__init__(**kwargs)self.embedding = tf.keras.layers.Embedding(vocab_size, max_seqlen)self.bilstm = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(max_seqlen))self.dense = tf.keras.layers.Dense(64, activation="relu")self.out = tf.keras.layers.Dense(1, activation="sigmoid")def call(self, x):x = self.embedding(x)x = self.bilstm(x)x = self.dense(x)x = self.out(x)return xmodel = SentimentAnalysisModel(vocab_size+1, max_seqlen)
model.build(input_shape=(batch_size, max_seqlen))
model.summary()# compile
model.compile(loss="binary_crossentropy",optimizer="adam", metrics=["accuracy"]
)# train
best_model_file = os.path.join(data_dir, "best_model.h5")
checkpoint = tf.keras.callbacks.ModelCheckpoint(best_model_file,save_weights_only=True,save_best_only=True)
tensorboard = tf.keras.callbacks.TensorBoard(log_dir=logs_dir)
num_epochs = 10
history = model.fit(train_dataset, epochs=num_epochs, validation_data=val_dataset,callbacks=[checkpoint, tensorboard])

可以看到,模型在训练集上的准确率达到了 99.17%,验证集的准确率约为 99.00%。观察训练过程的损失变化情况,以了解模型何时开始在训练集上过拟合。可以看到,训练损失持续下降,但验证损失在经历最初的下降后开始上升。当验证损失开始上升时,模型在训练集上出现过拟合。

训练过程

模型训练过程中在训练集和验证集上的准确率和损失变化情况如下所示:

训练过程监测

3. 模型评估

(1) 检查点回调根据最低验证集损失值保存最佳模型,可以重新加载保存的最佳模型评估保留的测试集:

# evaluate with test set
best_model = SentimentAnalysisModel(vocab_size+1, max_seqlen)
best_model.build(input_shape=(batch_size, max_seqlen))
best_model.load_weights(best_model_file)
best_model.compile(loss="binary_crossentropy",optimizer="adam", metrics=["accuracy"]
)

(2) 对模型进行评估的最简单方法是调用 model.evaluate()

test_loss, test_acc = best_model.evaluate(test_dataset)
print("test loss: {:.3f}, test accuracy: {:.3f}".format(test_loss, test_acc))

输出结果如下所示:

test loss: 0.044, test accuracy: 0.990

(3) 还可以使用 model.predict() 获取预测结果,将它们与标签逐个比较,并使用外部工具(如 scikit-learn )评估模型预测结果:

# predict on batches
labels, predictions = [], []
idx2word[0] = "PAD"
is_first_batch = True
for test_batch in test_dataset:inputs_b, labels_b = test_batchpred_batch = best_model.predict(inputs_b)predictions.extend([(1 if p > 0.5 else 0) for p in pred_batch])labels.extend([l for l in labels_b])if is_first_batch:for rid in range(inputs_b.shape[0]):words = [idx2word[idx] for idx in inputs_b[rid].numpy()]words = [w for w in words if w != "PAD"]sentence = " ".join(words)print("{:d}\t{:d}\t{:s}".format(labels[rid], predictions[rid], sentence))is_first_batch = Falseprint("accuracy score: {:.3f}".format(accuracy_score(labels, predictions)))
print("confusion matrix")
print(confusion_matrix(labels, predictions))

对于测试数据集中第一个批次的 64 个句子,我们重建句子并显示标签(第一列)以及模型的预测(第二列)。可以看到,模型在大多数句子中的预测都正确:

预测结果

评估整个测试数据集的结果。可以看到,测试准确率与调用 evaluate() 方法的结果相同。生成混淆矩阵,在 1000 个测试样本中,情感分析网络正确预测了987次,错误预测了 13 次:

accuracy score: 0.987
confusion matrix
[[497   4][  9 490]]

相关链接

TensorFlow深度学习实战(1)——神经网络与模型训练过程详解
TensorFlow深度学习实战(2)——使用TensorFlow构建神经网络
TensorFlow深度学习实战(3)——深度学习中常用激活函数详解
TensorFlow深度学习实战(4)——正则化技术详解
TensorFlow深度学习实战(5)——神经网络性能优化技术详解
TensorFlow深度学习实战(7)——分类任务详解
TensorFlow深度学习实战(8)——卷积神经网络
TensorFlow深度学习实战(12)——词嵌入技术详解
TensorFlow深度学习实战(13)——神经嵌入详解
TensorFlow深度学习实战(14)——循环神经网络详解
TensorFlow深度学习实战——基于循环神经网络的文本生成模型

http://www.xdnf.cn/news/3538.html

相关文章:

  • 多模态大语言模型arxiv论文略读(五十二)
  • LangChain4j +DeepSeek大模型应用开发——6 提示词
  • Nginx 核心功能02
  • 小米首个推理大模型开源——Xiaomi MiMo,为推理而战!
  • 体系学习1:C语言与指针1——预定义、进制打印、传参为数组
  • python多进程的使用
  • 机器视觉开发-摄像头扫描二维码
  • 2025五一数学建模C题完整分析论文(共36页)(含模型、可运行代码、数据)
  • 嵌入式产品运行中数据丢失怎么办?
  • SpringBoot云端日记本系统开发实现
  • 记录搭建自己的应用中心-需求看板搭建
  • DeepSeek V3 训练策略:FP8混合精度与多Token预测
  • 电子病历高质量语料库构建方法与架构项目(环境聆听与自动化文档生成篇)
  • AD数据库清理
  • Mem0.ai研究团队开发的全新记忆架构系统“Mem0”正式发布
  • TTL、LRU、LFU英文全称及释义
  • 脑机接口技术:开启人类与机器的全新交互时代
  • LabVIEW异步调用VI介绍
  • 【2025年五一数学建模竞赛】A题 解题思路与模型代码
  • 【Unity】MVP框架的使用例子
  • 使用 MCP(模型上下文协议)和 Claude 在 Node.js 中构建聊天应用程序
  • 海量数据存储与分析:HBase vs ClickHouse vs Doris 三大数据库优劣对比指南
  • 理解计算机系统_网络编程(6)_web服务器
  • PDF本地化开源项目推荐
  • AI Agent(2):Agent技术架构
  • terraform output输出实战
  • JVM——Java 虚拟机是如何加载 Java 类的?
  • 【AI提示词】成本效益分析师
  • 2025年人工智能火爆技术总结
  • PS_POR_B复位的重要性