自然语言处理(nlp)基于gru实现情感分类(代码片段)

灵彧universe 灵彧universe     2022-12-01     346

关键词:

【自然语言处理(NLP)】基于GRU实现情感分类


@TOC


前言

任务描述

任务描述:

本示例教程演示如何在IMDB数据集上用GRU网络完成文本分类的任务。

IMDB数据集是一个对电影评论标注为正向评论与负向评论的数据集,共有25000条文本数据作为训练集,25000条文本数据作为测试集。
该数据集的官方地址为: http://ai.stanford.edu/~amaas/data/sentiment/


一、环境设置

import paddle
import numpy as np
import matplotlib.pyplot as plt
import paddle.nn as nn

print(paddle.__version__)  # 查看当前版本

# cpu/gpu环境选择,在 paddle.set_device() 输入对应运行设备。
device = paddle.set_device(gpu)

二、数据准备

  1. 由于IMDB是NLP领域中常见的数据集,飞桨框架将其内置,路径为 paddle.text.datasets.Imdb。通过 mode 参数可以控制训练集与测试集。
print(loading dataset...)
train_dataset = paddle.text.datasets.Imdb(mode=train)
test_dataset = paddle.text.datasets.Imdb(mode=test)
print(loading finished)
  1. 构建了训练集与测试集后,可以通过 word_idx 获取数据集的词表。在飞桨框架2.0版本中,推荐使用padding的方式来对同一个batch中长度不一的数据进行补齐,所以在字典中,我们还会添加一个特殊的词,用来在后续对batch中较短的句子进行填充。
word_dict = train_dataset.word_idx  # 获取数据集的词表

# add a pad token to the dict for later padding the sequence
word_dict[<pad>] = len(word_dict)

for k in list(word_dict)[:5]:
    print(":".format(k.decode(ASCII), word_dict[k]))

print("...")

for k in list(word_dict)[-5:]:
    print(":".format(k if isinstance(k, str) else k.decode(ASCII), word_dict[k]))

print("totally  words".format(len(word_dict)))

输出结果如下图1所示:


(一)、参数设置

  1. 在这里我们设置一下词表大小,embedding的大小,batch_size,等等
vocab_size = len(word_dict) + 1
print(vocab_size)
emb_size = 256
seq_len = 200
batch_size = 32
epochs = 10
pad_id = word_dict[<pad>]

classes = [negative, positive]

# 生成句子列表
def ids_to_str(ids):
    # print(ids)
    words = []
    for k in ids:
        w = list(word_dict)[k]
        words.append(w if isinstance(w, str) else w.decode(ASCII))
    return " ".join(words)
  1. 在这里,取出一条数据打印出来看看,可以用 docs 获取数据的list,用 labels 获取数据的label值,打印出来对数据有一个初步的印象。
# 取出来第一条数据看看样子。
sent = train_dataset.docs[0]
label = train_dataset.labels[1]
print(sentence list id is:, sent)
print(sentence label id is:, label)
print(--------------------------)
print(sentence list is: , ids_to_str(sent))
print(sentence label is: , classes[label])

输出结果如图2所示:

(二)、用padding的方式对齐数据

  1. 文本数据中,每一句话的长度都是不一样的,为了方便后续的神经网络的计算,常见的处理方式是把数据集中的数据都统一成同样长度的数据。这包括:对于较长的数据进行截断处理,对于较短的数据用特殊的词<pad>进行填充。接下来的代码会对数据集中的数据进行这样的处理。
# 读取数据归一化处理
def create_padded_dataset(dataset):
    padded_sents = []
    labels = []
    for batch_id, data in enumerate(dataset):
        sent, label = data[0], data[1]
        padded_sent = np.concatenate([sent[:seq_len], [pad_id] * (seq_len - len(sent))]).astype(int32)
        padded_sents.append(padded_sent)
        labels.append(label)
    return np.array(padded_sents), np.array(labels)

# 对train、test数据进行实例化
train_sents, train_labels = create_padded_dataset(train_dataset)
test_sents, test_labels = create_padded_dataset(test_dataset)

# 查看数据大小及举例内容
print(train_sents.shape)
print(train_labels.shape)
print(test_sents.shape)
print(test_labels.shape)

for sent in train_sents[:3]:
    print(ids_to_str(sent))

输出结果如下图3所示:


(三)、用Dataset 与 DataLoader 加载

将前面准备好的训练集与测试集用Dataset 与 DataLoader封装后,完成数据的加载。

class IMDBDataset(paddle.io.Dataset):
    
    继承paddle.io.Dataset类进行封装数据
    
    def __init__(self, sents, labels):
        self.sents = sents
        self.labels = labels

    def __getitem__(self, index):
        data = self.sents[index]
        label = self.labels[index]

        return data, label

    def __len__(self):
        return len(self.sents)

train_dataset = IMDBDataset(train_sents, train_labels)
test_dataset = IMDBDataset(test_sents, test_labels)

train_loader = paddle.io.DataLoader(train_dataset, return_list=True,
                                    shuffle=True, batch_size=batch_size, drop_last=True)
test_loader = paddle.io.DataLoader(test_dataset, return_list=True,
                                    shuffle=True, batch_size=batch_size, drop_last=True)

三、模型配置

本示例中,我们将会使用一个不考虑词的顺序的GRU的网络,在查找到每个词对应的embedding后,简单的取平均,作为一个句子的表示。然后用Linear进行线性变换。为了防止过拟合,我们还使用了Dropout。

GRU是LSTM网络的一种效果很好的变体,它较LSTM网络的结构更加简单,而且效果也很。
因此也是当前非常流形的一种网络。GRU既然是LSTM的变体,因此也是可以解决RNN网络中的长依赖问题。

图中的zt和rt分别表示更新门和重置门。
更新门用于控制前一时刻的状态信息被带入到当前状态中的程度,更新门的值越大说明前一时刻的状态信息带入越多。
重置门控制前一状态有多少信息被写入到当前的候选集 h~t 上,重置门越小,前一状态的信息被写入的越少。

import paddle.nn as nn
import paddle

# 定义GRU网络
class MyGRU(paddle.nn.Layer):
    def __init__(self):
        super(MyGRU, self).__init__()
        self.embedding = nn.Embedding(vocab_size, 256)
        self.gru = nn.GRU(256, 256, num_layers=2, direction=bidirectional,dropout=0.5)
        self.linear = nn.Linear(in_features=256*2, out_features=2)
        self.dropout = nn.Dropout(0.5)

    def forward(self, inputs):
        emb = self.dropout(self.embedding(inputs))
        #output形状大小为[batch_size,seq_len,num_directions * hidden_size]
        #hidden形状大小为[num_layers * num_directions, batch_size, hidden_size]
        #把前向的hidden与后向的hidden合并在一起
        output, hidden = self.gru(emb)
        hidden = paddle.concat((hidden[-2,:,:], hidden[-1,:,:]), axis = 1)
        #hidden形状大小为[batch_size, hidden_size * num_directions]
        hidden = self.dropout(hidden)
        return self.linear(hidden) 

四、模型训练

(一)、可视化定义

def draw_process(title,color,iters,data,label):
    plt.title(title, fontsize=24)
    plt.xlabel("iter", fontsize=20)
    plt.ylabel(label, fontsize=20)
    plt.plot(iters, data,color=color,label=label) 
    plt.legend()
    plt.grid()
    plt.show()

(二)、对模型进行封装

def train(model):
    model.train()
    opt = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters())
    steps = 0
    Iters, total_loss, total_acc = [], [], []

    for epoch in range(epochs):
        for batch_id, data in enumerate(train_loader):
            steps += 1
            sent = data[0]
            label = data[1]

            logits = model(sent)
            loss = paddle.nn.functional.cross_entropy(logits, label)
            acc = paddle.metric.accuracy(logits, label)

            if batch_id % 500 == 0:  # 500个epoch输出一次结果
                Iters.append(steps)
                total_loss.append(loss.numpy()[0])
                total_acc.append(acc.numpy()[0])

                print("epoch: , batch_id: , loss is: ".format(epoch, batch_id, loss.numpy()))

            loss.backward()
            opt.step()
            opt.clear_grad()

        # evaluate model after one epoch
        model.eval()
        accuracies = []
        losses = []

        for batch_id, data in enumerate(test_loader):

            sent = data[0]
            label = data[1]

            logits = model(sent)
            loss = paddle.nn.functional.cross_entropy(logits, label)
            acc = paddle.metric.accuracy(logits, label)

            accuracies.append(acc.numpy())
            losses.append(loss.numpy())

        avg_acc, avg_loss = np.mean(accuracies), np.mean(losses)

        print("[validation] accuracy: , loss: ".format(avg_acc, avg_loss))

        model.train()

        # 保存模型
        paddle.save(model.state_dict(),str(epoch)+"_model_final.pdparams")

    # 可视化查看
    draw_process("trainning loss","red",Iters,total_loss,"trainning loss")
    draw_process("trainning acc","green",Iters,total_acc,"trainning acc")

model = MyGRU()
train(model)

输出结果分别如图4、5、6所示:


五、模型评估


模型评估

model_state_dict = paddle.load(6_model_final.pdparams)  # 导入模型
model = MyGRU()
model.set_state_dict(model_state_dict) 
model.eval()
accuracies = []
losses = []

for batch_id, data in enumerate(test_loader):

    sent = data[0]
    label = data[1]

    logits = model(sent)
    loss = paddle.nn.functional.cross_entropy(logits, label)
    acc = paddle.metric.accuracy(logits, label)

    accuracies.append(acc.numpy())
    losses.append(loss.numpy())

avg_acc, avg_loss = np.mean(accuracies), np.mean(losses)
print("[validation] accuracy: , loss: ".format(avg_acc, avg_loss))

输出结果如下图7所示:

六、模型预测

def ids_to_str(ids):
    words = []
    for k in ids:
        w = list(word_dict)[k]
        words.append(w if isinstance(w, str) else w.decode(ASCII))
    return " ".join(words)

label_map = 0:"negative", 1:"positive"

# 导入模型
model_state_dict = paddle.load(6_model_final.pdparams)
model = MyGRU()
model.set_state_dict(model_state_dict) 
model.eval()

for batch_id, data in enumerate(test_loader):

    sent = data[0]
    results = model(sent)

    predictions = []
    for probs in results:
        # 映射分类label
        idx = np.argmax(probs)
        labels = label_map[idx]
        predictions.append(labels)

    for i,pre in enumerate(predictions):
        print( 数据:  \\n 情感: .format(ids_to_str(sent[0]), pre))
        break
    break

输出结果如下图8所示:


总结

本系列文章内容为根据清华社出版的《机器学习实践》所作的相关笔记和感悟,其中代码均为基于百度飞桨开发,若有任何侵权和不妥之处,请私信于我,定积极配合处理,看到必回!!!

最后,引用本次活动的一句话,来作为文章的结语~( ̄▽ ̄~)~:

学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。

自然语言处理(nlp)基于循环神经网络实现情感分类(代码片段)

【自然语言处理(NLP)】基于循环神经网络实现情感分类活动地址:[CSDN21天学习挑战赛](https://marketing.csdn.net/p/bdabfb52c5d56532133df2adc1a728fd)作者简介:在校大学生一枚,华为云享专家,阿里云星级博主,... 查看详情

nlp循环神经网络实现情感分类(代码片段)

循环神经网络实现文本情感分类1.Pytorch中LSTM和GRU模块使用1.1LSTM介绍1.2LSTM使用示例1.3GRU的使用示例1.4双向LSTM1.5LSTM和GRU的使用注意点2.使用LSTM完成文本情感分类2.1修改模型2.2完成训练和测试代码2.3模型训练的最终输出2.4添加进度... 查看详情

基于机器学习和tfidf的情感分类算法,详解自然语言处理(代码片段)

摘要:这篇文章将详细讲解自然语言处理过程,基于机器学习和TFIDF的情感分类算法,并进行了各种分类算法(SVM、RF、LR、Boosting)对比本文分享自华为云社区《[Python人工智能]二十三.基于机器学习和TFIDF的情... 查看详情

自然语言处理(nlp)基于fnn网络的电影评论情感分析(代码片段)

【自然语言处理(NLP)】基于FNN网络的电影评论情感分析作者简介:在校大学生一枚,华为云享专家,阿里云专家博主,腾云先锋(TDP)成员,云曦智划项目总负责人,全国高等学校计算机... 查看详情

自然语言处理(nlp)基于bilstm+crf的事件抽取(代码片段)

【自然语言处理(NLP)】基于BiLSTM+CRF的事件抽取(文章目录)前言(一)、任务描述事件抽取技术是从非结构化信息中抽取出用户感兴趣的事件,并以结构化呈现给用户。事件抽取任务可分解为4个子任务:触发词识别、事件类型分类... 查看详情

pt之transformer:基于pytorch框架利用transformer算法针对imdb数据集实现情感分类的应用案例代码解析(代码片段)

...对IMDB数据集实现情感分类的应用案例情感分析是指通过自然语言处理技术对文本进行分析,确定文本所表达的情感倾向。Transformer模型是一种基于注意力机制的神经网络模型,可以有效地处理自然语言处理任务。这个代... 查看详情

自然语言处理(nlp)基于lstm的命名实体识别(代码片段)

【自然语言处理(NLP)】基于LSTM的命名实体识别(文章目录)前言(一)、任务描述命名实体识别任务主要识别文本中的实体,并且给识别出的实体进行分类,比如人名、地名、机构名或其它类型。本质上,对于给定的文本,只需要... 查看详情

nlp文本情感分析(代码片段)

...度的计算研究。文本情感分析(SentimentAnalysis)是自然语言处理(NLP)方法中常见的应用,也是一个有趣的基本任务,尤其是以提炼文本情绪内容为目的的分类。它是对带有情感色彩的主观性文本进行分析... 查看详情

从整体视角了解情感分析文本分类!(代码片段)

...a;太子长琴,算法工程师,Datawhale成员文本分类是自然语言处理(NLP)最基础核心的任务,或者换句话说,几乎所有NLP任务都是「分类」任务,或者涉及到「分类」概念。比如分词、词性标注、命名实... 查看详情

自然语言处理(nlp):24基于文本语义的智能问答系统

...https://edu.51cto.com/course/25919.html​​0开篇介绍问答系统是自然语言处理领域一个很经典的问题,它用于回答人们以自然语言形式提出的问题,有着广泛的应用。经典应用场景包括:智能语音交互、在线客服、知识获取、情感类聊... 查看详情

自然语言处理(nlp)基于bilstm的关系抽取(代码片段)

【自然语言处理(NLP)】基于BiLSTM的关系抽取(文章目录)前言(一)、任务描述关系抽取是信息抽取的重要子任务,其主要目的是将非结构化获半结构化描述的自然语言文本转化成结构化数据,关系抽取主要负责对文本中抽取出的... 查看详情

学习nlp:《精通python自然语言处理》中文pdf+英文pdf+代码

自然语言处理是计算语言学和人工智能之中与人机交互相关的领域之一。推荐学习自然语言处理的一本综合学习指南《精通Python自然语言处理》,介绍了如何用Python实现各种NLP任务,以帮助读者创建基于真实生活应用的项目。全... 查看详情

自然语言处理(nlp)基于lstm实现文字检测(代码片段)

【自然语言处理(NLP)】基基于LSTM实现文字检测作者简介:在校大学生一枚,华为云享专家,阿里云星级博主,腾云先锋(TDP)成员,云曦智划项目总负责人,全国高等学校计算机教学与产... 查看详情

pytorch自然语言处理传统nlp快速回顾(计算语言学)(代码片段)

PyTorch自然语言处理传统NLP快速回顾语料库,标记和类型一元组,二元组,三元组,...,N元组词形和词干分类句子和文档分类单词:词性标注分类短语:分块和命名实体识别句子结构单词意义和情感总... 查看详情

pytorch自然语言处理传统nlp快速回顾(计算语言学)(代码片段)

PyTorch自然语言处理传统NLP快速回顾语料库,标记和类型一元组,二元组,三元组,...,N元组词形和词干分类句子和文档分类单词:词性标注分类短语:分块和命名实体识别句子结构单词意义和情感总... 查看详情

nlp文本情感分类(代码片段)

文本情感分类1.案例介绍2.思路分析3.准备数据集3.1基础Dataset的准备3.2文本序列化4.构建模型5.模型的训练和评估1.案例介绍为了对前面的wordembedding这种常用的文本向量化的方法进行巩固,这里我们会完成一个文本情感分类的... 查看详情

做项目一定用得到的nlp资源分类版

...翻译数字转换指代消解文本聚类文本分类知识推理可解释自然语言处理文本对抗攻击文本可视化文本标注工具语言检测综合工具有趣搞笑工具课程报告面试等比赛金融自然语言处理医疗自然语言处理法律自然语言处理其他备注原... 查看详情

自然语言处理(nlp)基于transformer的英文自动文摘(代码片段)

【自然语言处理(NLP)】基于Transformer的英文自动文摘(文章目录)前言(一)、任务描述本示例教程介绍如何使用飞桨完成一个机器翻译任务。我们将会使用飞桨提供的开源框架完成基于Transformer的英文文本自动文摘模型。飞桨框架... 查看详情