用RNN & CNN进行情感分析 - PyTorch

一、情感分析及数据集

情感分析研究人们在文本中(如产品评论、博客评论和论坛讨论等)“隐藏”的情绪。

这里使用斯坦福大学的大型电影评论数据集(large movie review dataset)进行情感分析。它由一个训练集和一个测试集组成,其中包含从IMDb下载的25000个电影评论。在这两个数据集中,“积极”和“消极”标签的数量相同,表示不同的情感极性。

1.读取数据集

import os
import torch
from torch import nn
from d2l import torch as d2l

d2l.DATA_HUB['aclImdb'] = (
    'http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz',
    '01ada507287d82875905620988597833ad4e0903')

data_dir = d2l.download_extract('aclImdb', 'aclImdb')

def read_imdb(data_dir, is_train):
    """读取IMDb评论数据集文本序列和标签(1:积极,0:消极)"""
    data, labels = [], []
    for label in ('pos', 'neg'):
        folder_name = os.path.join(data_dir, 'train' if is_train else 'test', label)
        for file in os.listdir(folder_name):
            with open(os.path.join(folder_name, file), 'rb') as f:
                review = f.read().decode('utf-8').replace('\n', '')
                data.append(review)
                labels.append(1 if label == 'pos' else 0)
    return data, labels

2.预处理数据集

将每个单词作为一个词元,过滤掉出现不到5次的单词,从训练数据集中创建一个词表。

train_data = read_imdb(data_dir, is_train=True)
train_tokens = d2l.tokenize(train_data[0], token='word')
vocab = d2l.Vocab(train_tokens, min_freq=5, reserved_tokens=['<pad>'])

在词元化之后,绘制评论词元长度的直方图。

d2l.set_figsize()
d2l.plt.xlabel('# tokens per review')
d2l.plt.ylabel('count')
d2l.plt.hist([len(line) for line in train_tokens], bins=range(0, 1000, 50));

请添加图片描述

从上图可以看出评论的长度各不相同,为了每次处理一小批量这样的评论,通过截断和填充将每个评论的长度设置为500。类似于基于Seq2Seq的机器翻译-PyTorch中对机器翻译数据集的预处理步骤。

def load_data_imdb(batch_size, num_steps=500):
    """返回数据迭代器和IMDb评论数据集的词表"""
    data_dir = d2l.download_extract('aclImdb', 'aclImdb')
    train_data = read_imdb(data_dir, True)
    test_data = read_imdb(data_dir, False)
    train_tokens = d2l.tokenize(train_data[0], token='word')
    test_tokens = d2l.tokenize(test_data[0], token='word')
    vocab = d2l.Vocab(train_tokens, min_freq=5)
    train_features = torch.tensor([d2l.truncate_pad(
        vocab[line], num_steps, vocab['<pad>']) for line in train_tokens])
    test_features = torch.tensor([d2l.truncate_pad(
        vocab[line], num_steps, vocab['<pad>']) for line in test_tokens])
    train_iter = d2l.load_array((train_features, torch.tensor(train_data[1])),
                                batch_size)
    test_iter = d2l.load_array((test_features, torch.tensor(test_data[1])),
                               batch_size,
                               is_train=False)
    return train_iter, test_iter, vocab

二、利用RNN进行情感分析

由于IMDb评论数据集不是很大,使用在大规模语料库上预训练的文本表示可以减少模型的过拟合。使用预训练的GloVe模型来表示每个词元,并将这些词元表示送入多层双向RNN以获得文本序列表示,该文本序列表示将被转换为情感分析输出。

1.使用RNN表示单个文本

在文本分类任务(如情感分析)中,可变长度的文本序列将被转换为固定长度的类别。

在下面的BiRNN类中,虽然文本序列的每个词元经由嵌入层(self.embedding)获得其单独的预训练GloVe表示,但是整个序列由Bi-LSTM(self.encoder)编码。Bi-LSTM在初始和最终时间步的隐状态(在最后一层)被连结起来作为文本序列的表示。

batch_size = 64
train_iter, test_iter, vocab = load_data_imdb(batch_size)

class BiRNN(nn.Module):
    def __init__(self, vocab_size, embed_size, num_hiddens, num_layers, **kwargs):
        super(BiRNN, self).__init__(**kwargs)
        self.embedding = nn.Embedding(vocab_size, embed_size)
        self.encoder = nn.LSTM(embed_size, num_hiddens, num_layers=num_layers,
                                bidirectional=True)
        self.decoder = nn.Linear(4 * num_hiddens, 2)

    def forward(self, inputs):
        # inputs的形状是(批量大小,时间步数)
        # LSTM要求输入的第一个维度是时间维,所以在获得词元表示之前,输入会被转置。
        # 输出形状为(时间步数,批量大小,词向量维度)
        embeddings = self.embedding(inputs.T)
        self.encoder.flatten_parameters()
        # 返回上一个隐藏层在不同时间步的隐状态,
        # outputs的形状是(时间步数,批量大小,2*隐藏单元数)
        outputs, _ = self.encoder(embeddings)
        # 连结初始和最终时间步的隐状态,作为全连接层的输入,
        # 其形状为(批量大小,4*隐藏单元数)
        encoding = torch.cat((outputs[0], outputs[-1]), dim=1)
        outs = self.decoder(encoding)
        return outs

构造一个具有两个隐藏层的双向LSTM来表示单个文本以进行情感分析。

embed_size, num_hiddens, num_layers = 100, 100, 2
devices = d2l.try_all_gpus()
net = BiRNN(len(vocab), embed_size, num_hiddens, num_layers)
def init_weights(m):
    if type(m) == nn.Linear:
        nn.init.xavier_uniform_(m.weight)
    if type(m) == nn.LSTM:
        for param in m._flat_weights_names:
            if "weight" in param:
                nn.init.xavier_uniform_(m._parameters[param])
net.apply(init_weights)
'''
BiRNN(
  (embedding): Embedding(49345, 100)
  (encoder): LSTM(100, 100, num_layers=2, bidirectional=True)
  (decoder): Linear(in_features=400, out_features=2, bias=True)
)
'''

2.加载预训练的词向量

为词表中的单词加载预训练的100维(需要与embed_size一致)的GloVe嵌入。

glove_embedding = d2l.TokenEmbedding('glove.6b.100d')
# 打印词表中所有词元向量的形状
embeds = glove_embedding[vocab.idx_to_token]
embeds.shape

使用预训练的词向量表示评论中的词元,并且在训练期间不更新这些向量。

net.embedding.weight.data.copy_(embeds)
net.embedding.weight.requires_grad = False

3.训练和评估模型

现在我们可以训练双向循环神经网络进行情感分析。(CPU跑不动,5个epochGPU跑了10分钟)

lr, num_epochs = 0.01, 5
trainer = torch.optim.Adam(net.parameters(), lr=lr)
loss = nn.CrossEntropyLoss(reduction="none")
d2l.train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs, devices)

请添加图片描述

4.预测

来使用训练好的模型net预测文本序列的情感。

def predict_sentiment(net, vocab, sequence):
    """预测文本序列的情感"""
    sequence = torch.tensor(vocab[sequence.split()], device=d2l.try_gpu())
    label = torch.argmax(net(sequence.reshape(1, -1)), dim=1)
    return 'positive' if label == 1 else 'negative'
  
print(predict_sentiment(net, vocab, 'this movie is so great'))
print(predict_sentiment(net, vocab, 'this movie is so bad'))

三、利用CNN进行情感分析

通过将文本序列想象成一维图像,一维卷积神经网络可以处理文本中的局部特征,例如n元语法。

使用 t e x t C N N textCNN textCNN 模型演示如何设计一个表示单个文本的卷积神经网络架构。

1.一维卷积

请添加图片描述

一维互相关运算

在一维情况下,卷积窗口在输入张量上从左向右滑动。

def corr1d(X, K):
    """一维互相关运算"""
    w = K.shape[0]
    Y = torch.zeros((X.shape[0] - w + 1))
    for i in range(Y.shape[0]):
        Y[i] = (X[i: i + w] * K).sum()
    return Y

对于任何具有多个通道的一维输入,卷积核需要具有相同数量的输入通道。然后,对于每个通道,对输入的一维张量和卷积核的一维张量执行互相关运算,将所有通道上的结果相加以产生一维输出张量。

请添加图片描述

具有3个输入通道的一维互相关运算
def corr1d_multi_in(X, K):
    # 首先,遍历'X'和'K'的第0维(通道维),然后,把它们加在一起。
    return sum(corr1d(x, k) for x, k in zip(X, K))

请添加图片描述

具有单个输入通道的二维互相关操作

注意,多输入通道的一维互相关等同于单输入通道的二维互相关。多输入通道一维互相关的等价形式是单输入通道二维互相关,其中卷积核的高度必须与输入张量的高度相同。

2.textCNN模型

使用一维卷积和最大时间汇聚,textCNN模型将单个预训练的词元表示作为输入,然后获得并转换用于下游应用的序列表示。

对于具有由 d d d 维向量表示的 n n n 个词元的单个文本序列,输入张量的宽度、高度和通道数分别为 n n n 1 1 1 d d d。textCNN模型将输入转换为输出,如下所示:

  1. 定义多个一维卷积核,并分别对输入执行卷积运算。具有不同宽度的卷积核可以捕获不同数目的相邻词元之间的局部特征。

  2. 在所有输出通道上执行最大时间汇聚层,然后将所有标量汇聚输出连结为向量。

  3. 使用全连接层将连结后的向量转换为输出类别。Dropout可以用来减少过拟合。

请添加图片描述

输入是具有11个词元的句子,其中每个词元由6维向量表示。因此,有一个宽度为11的6通道输入。定义两个宽度为2和4的一维卷积核,分别具有4个和5个输出通道。它们产生4个宽度为 11 − 2 + 1 = 10 11-2+1=10 112+1=10的输出通道和5个宽度为 11 − 4 + 1 = 8 11-4+1=8 114+1=8的输出通道。尽管这9个通道的宽度不同,但最大时间汇聚层给出了一个连结的9维向量,该向量最终被转换为用于二元情感预测的2维输出向量。

  • 定义模型

与上文的双向LSTM模型相比,除了用卷积层代替循环神经网络层外,还使用了两个嵌入层:一个是可训练权重,另一个是固定权重。

class TextCNN(nn.Module):
    def __init__(self, vocab_size, embed_size, kernel_sizes, num_channels, **kwargs):
        super(TextCNN, self).__init__(**kwargs)
        self.embedding = nn.Embedding(vocab_size, embed_size)
        # 这个嵌入层不需要训练
        self.constant_embedding = nn.Embedding(vocab_size, embed_size)
        self.dropout = nn.Dropout(0.5)
        self.decoder = nn.Linear(sum(num_channels), 2)
        self.pool = nn.AdaptiveAvgPool1d(1)
        self.relu = nn.ReLU()
        # 创建多个一维卷积层
        self.convs = nn.ModuleList()
        for c, k in zip(num_channels, kernel_sizes):
            self.convs.append(nn.Conv1d(2 * embed_size, c, k))

    def forward(self, inputs):
        # 沿着向量维度将两个嵌入层连结起来,
        # 每个嵌入层的输出形状都是(批量大小,词元数量,词元向量维度)连结起来
        embeddings = torch.cat((
            self.embedding(inputs), self.constant_embedding(inputs)), dim=2)
        # 根据一维卷积层的输入格式,重新排列张量,以便通道作为第2维
        embeddings = embeddings.permute(0, 2, 1)
        # 每个一维卷积层在最大时间汇聚层合并后,获得的张量形状是(批量大小,通道数,1)
        # 删除最后一个维度并沿通道维度连结
        encoding = torch.cat([
            torch.squeeze(self.relu(self.pool(conv(embeddings))), dim=-1)
            for conv in self.convs], dim=1)
        outputs = self.decoder(self.dropout(encoding))
        return outputs

创建一个textCNN实例。它有3个卷积层,卷积核宽度分别为3、4和5,均有100个输出通道。

embed_size, kernel_sizes, nums_channels = 100, [3, 4, 5], [100, 100, 100]
devices = d2l.try_all_gpus()
net = TextCNN(len(vocab), embed_size, kernel_sizes, nums_channels)

def init_weights(m):
    if type(m) in (nn.Linear, nn.Conv1d):
        nn.init.xavier_uniform_(m.weight)

net.apply(init_weights)
'''
TextCNN(
  (embedding): Embedding(49345, 100)
  (constant_embedding): Embedding(49345, 100)
  (dropout): Dropout(p=0.5, inplace=False)
  (decoder): Linear(in_features=300, out_features=2, bias=True)
  (pool): AdaptiveAvgPool1d(output_size=1)
  (relu): ReLU()
  (convs): ModuleList(
    (0): Conv1d(200, 100, kernel_size=(3,), stride=(1,))
    (1): Conv1d(200, 100, kernel_size=(4,), stride=(1,))
    (2): Conv1d(200, 100, kernel_size=(5,), stride=(1,))
  )
)
'''

3.加载预训练词向量

加载预训练的100维GloVe嵌入作为初始化的词元表示。这些词元表示(嵌入权重)在embedding中将被训练,在constant_embedding中将被固定。

glove_embedding = d2l.TokenEmbedding('glove.6b.100d')
embeds = glove_embedding[vocab.idx_to_token]
net.embedding.weight.data.copy_(embeds)
net.constant_embedding.weight.data.copy_(embeds)
net.constant_embedding.weight.requires_grad = False

4.训练和评估模型

训练textCNN模型进行情感分析。(GPU约三分钟)

lr, num_epochs = 0.001, 5
trainer = torch.optim.Adam(net.parameters(), lr=lr)
loss = nn.CrossEntropyLoss(reduction="none")
d2l.train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs, devices)

请添加图片描述

5.预测

print(predict_sentiment(net, vocab, 'this movie is so great'))
print(predict_sentiment(net, vocab, 'this movie is so bad'))
  • 8
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
### 回答1: songyouwei/absa-pytorch是一个基于PyTorch框架开发的方面级情感分析工具包。方面级情感分析是一种将文本中的情感信息按照不同的方面进行分类的任务,比如针对一篇饭店评论,可以将评论中关于服务、环境、食物等方面的情感进行细粒度的分类和分析。 这个工具包提供了一套完整的方面级情感分析解决方案,包括数据预处理、模训练和推理三个主要模块。首先,它包含了数据预处理模块,可帮助用户将原始的文本数据转化为模可接受的向量表示,并提供了对数据集的划分和批处理等功能。其次,该工具包提供了多种模的训练模块,包括LSTM、GRU、BERT等。用户可以根据自己的需求选择合适的模,并使用提供的接口进行训练和调优。同时,工具包还提供了一些常用的评估指标来评估模的性能表现。最后,在模训练完成后,工具包还提供了一系列的推理函数,可以对新的文本数据进行情感分析,并输出分类结果。 songyouwei/absa-pytorch还具有多个特点和优势。首先,它的代码简洁、易读,提供了丰富的注释和文档,方便用户习和使用。其次,该工具包的模训练速度较快,能够有效地处理大规模的文本数据集。此外,它还支持多种不同的情感分类任务,如情感倾向性分析、情感强度分析等,可以满足不同场景下的需求。最后,songyouwei/absa-pytorch还与其他常用的Python库和工具整合,提供了便捷的数据处理和可视化功能。 综上所述,songyouwei/absa-pytorch是一个基于PyTorch框架开发的方面级情感分析工具包,具有简洁易读的代码、高效的模训练速度以及多种不同的情感分类任务支持等特点。通过使用这个工具包,用户可以轻松地进行方面级情感分析,并获得准确的情感分类结果。 ### 回答2: songyouwei/absa-pytorch是一个使用PyTorch实现的方面情感分析工具包。该工具包是针对方面级情感分析任务而设计的,可以帮助研究人员、开发人员和数据科家在产品评论、社交媒体数据和其他文本数据上进行情感分析研究。 absa-pytorch提供了一套完整的方面级情感分析的实现。它包含了预处理模块、情感分类模和评估模块。预处理模块用于对文本数据进行分词、向量化和嵌入处理。情感分类模基于PyTorch构建,使用卷积神经网络(CNN)和循环神经网络(RNN)等深度习模进行情感分类。评估模块则用于评估模在训练集和测试集上的性能,并提供了准确度、精确度、召回率和F1值等评估指标。 除了提供模实现外,absa-pytorch还提供了丰富的功能和选项,以帮助用户进行自定义和实验。用户可以选择不同的预训练词嵌入模(如GloVe、Word2Vec等),并通过修改配置文件进行超参数调整。此外,absa-pytorch还支持对模进行可解释性分析,以帮助用户理解模情感分析的决策过程。 总的来说,songyouwei/absa-pytorch是一个功能强大的方面情感分析工具包,使用PyTorch实现。它提供了方面级情感分析的实现,并提供了预处理、模训练和评估等功能。它的灵活性和可扩展性使得用户可以进行自定义和实验,以满足不同的研究和应用需求。 ### 回答3: songyouwei/absa-pytorch是一个用于方面级情感分析(Aspect-based Sentiment Analysis,ABSA)的开源PyTorch库。ABSA是一种文本分析任务,旨在识别和分析文本中关于特定方面的情感倾向。 该库提供了用于训练和评估ABSA模的各种工具和功能。它包含了预处理数据的方法,如词嵌入、标签编码等。另外,它还提供了各种模架构的实现,比如LSTM、BERT等,这些模可以用于训练和预测。 使用该库进行ABSA任务时,用户可以根据自己的需求进行配置。例如,用户可以选择使用哪种预训练模作为词嵌入,或者自定义模架构来适应特定的任务。该库还支持多种评估指标,如准确率、F1分数等,以便用户评估模的性能。 此外,songyouwei/absa-pytorch还提供了一些例子和教程,帮助用户更好地理解和使用该库。这些示例可以帮助用户快速上手,并为用户提供参考,以便根据自己的实际情况进行修改和定制。 综上所述,songyouwei/absa-pytorch是一个功能强大且易于使用的库,可以帮助用户进行方面级情感分析任务。它提供了丰富的工具和功能,使用户能够轻松地构建、训练和评估ABSA模,从而提高情感分析的准确性和效率。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

葫芦娃啊啊啊啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值