PyTorch RNN-BiLSTM 情感分析准确率低

Posted

技术标签:

【中文标题】PyTorch RNN-BiLSTM 情感分析准确率低【英文标题】:PyTorch RNN-BiLSTM sentiment analysis low accuracy 【发布时间】:2020-02-12 17:45:15 【问题描述】:

我将 PyTorch 与一组电影评论一起使用,每个评论都标记为正面或负面。每条评论都被截断或填充为 60 个单词,我的批量大小为 32。这个 60x32 的张量被馈送到一个嵌入层为 100 的嵌入层,从而产生一个 60x32x100 的张量。然后我使用每个评论的未填充长度来打包嵌入输出,并将其提供给带有hidden dim = 256 的 BiLSTM 层。

然后我将其填充回来,应用一个变换(试图获得前向和后向方向的最后一个隐藏状态)并将变换馈送到一个 512x1 的线性层。这是我的模块,我通过此处未显示的 sigmoid 传递最终输出

class RNN(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim, output_dim, n_layers, 
                 bidirectional, dropout, pad_idx):
        
        super().__init__()
        self.el = nn.Embedding(vocab_size, embedding_dim)
        print('vocab size is ', vocab_size)
        print('embedding dim is ', embedding_dim)
        self.hidden_dim = hidden_dim
        self.num_layers = n_layers # 2
        self.lstm = nn.LSTM(input_size=embedding_dim, hidden_size=hidden_dim, num_layers=n_layers, dropout=dropout, bidirectional=bidirectional)
        # Have an output layer for outputting a single output value
        self.linear = nn.Linear(2*hidden_dim, output_dim)

    def init_hidden(self):
        return (torch.zeros(self.n_layers*2, 32, self.hidden_dim).to(device), 
                torch.zeros(self.n_layers*2, 32, self.hidden_dim).to(device))
        
    def forward(self, text, text_lengths):
        print('input text size ', text.size())
        embedded = self.el(text)
        print('embedded size ', embedded.size())
        packed_seq = torch.nn.utils.rnn.pack_padded_sequence(embedded, lengths=text_lengths, enforce_sorted=False)
        packed_out, (ht, ct) = self.lstm(packed_seq, None)
        out_rnn, out_lengths = torch.nn.utils.rnn.pad_packed_sequence(packed_out)
        print('padded lstm out ', out_rnn.size())        
        #out_rnn = out_rnn[-1] #this works
        #out_rnn = torch.cat((out_rnn[-1, :, :self.hidden_dim], out_rnn[0, :, self.hidden_dim:]), dim=1) # this works
        out_rnn = torch.cat((ht[-1], ht[0]), dim=1) #this works
        #out_rnn = out_rnn[:, -1, :] #doesn't work maybe should
        print('attempt to get last hidden ', out_rnn.size())
        linear_out = self.linear(out_rnn)
        print('after linear ', linear_out.size())
        return linear_out

我尝试了 3 种不同的变换来获得线性层的正确尺寸

out_rnn = out_rnn[-1] #this works
out_rnn = torch.cat((out_rnn[-1, :, :self.hidden_dim], out_rnn[0, :, self.hidden_dim:]), dim=1) # this works
out_rnn = torch.cat((ht[-1], ht[0]), dim=1) #this works

这些都会产生这样的输出

输入文字大小 torch.Size([60, 32])

嵌入式尺寸 torch.Size([60,32, 100])

用 lstm 填充 torch.Size([36, 32, 512])

尝试获取最后一个隐藏的 torch.Size([32, 512])

在线性torch.Size([32, 1])之后

我希望填充后的 lstm 输出为 [60, 32, 512],但它在第一维中始终小于 60。

我正在使用 optim.SGDnn.BCEWithLogitsLoss() 训练 10 个 epoch。我的训练准确率始终在 52% 左右,测试准确率始终在 50% 左右,因此模型的表现并不比随机猜测好。我确信我的数据在我的tochtext.data.Dataset 中得到了正确处理。我是否错误地转发了我的张量?

我尝试在我的 lstm、packed_seq 函数和 pad_packed_seq 函数中使用 batch_first=True,这会在馈送到线性层之前破坏我的转换。

更新 我添加了 init_hidden 方法并尝试不使用 pack/pad 序列方法,但仍然得到相同的结果

【问题讨论】:

这里不清楚,但您是否在每次迭代中将隐藏状态清零?导致您的模型类缺少 LSTM 网络的典型 init_hidden() 方法。另一个罪魁祸首可能是 pack-pad 功能?我会先尝试不使用它们,以确保一切正常。 我添加了 init_hidden 并尝试不使用 pack/pad 功能,但仍然得到相同的结果。是否有正确的方法可以从我在 lstm 和线性层之间进行的 3 种可能的转换中获取最后一个隐藏状态?所有 3 个都给出大致相同的结果 根据pad_packed_sequence的文档,返回的张量是“T x B x *,其中T是最长序列的长度”。我的解释是 T 是批次中最长的长度。这可以解释为什么它总是 total_length 将其填充到固定长度。 pad_packed_sequence 的 PyTorch 文档说输出张量“批量元素将按其长度递减排序。”那么在计算loss的时候,有没有恢复batch的原始顺序呢? 谢谢,我没有恢复原来的顺序。目前我在不使用 pack/pad 功能的情况下运行它并获得 50% 的准确度。我正在尝试先在没有这些功能的情况下提高准确性,然后再将它们添加回来 【参考方案1】:

我将优化器从 SGD 更改为 Adam,并将层从 2 更改为 1,我的模型开始学习,准确率 > 75%

【讨论】:

以上是关于PyTorch RNN-BiLSTM 情感分析准确率低的主要内容,如果未能解决你的问题,请参考以下文章

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

Pytorch实战笔记——CNN实现情感分析

自然语言处理-Pytorch情感分析简介

R实战——贝叶斯分类器-文本情感分析

情感分析语料资源(免费)

NLP文本情感分析