Pytorch RNN 模型没有学到任何东西

Posted

技术标签:

【中文标题】Pytorch RNN 模型没有学到任何东西【英文标题】:Pytorch RNN model not learning anything 【发布时间】:2021-03-28 02:48:44 【问题描述】:

任务:预测提供的灾难推文是否真实。已经将我的文本数据转换为张量,然后转换为 train_loader。下面提到了所有必需的代码。

我的模型架构

class RealOrFakeLSTM(nn.Module):
    
    def __init__(self, input_size, output_size, embedding_dim, hidden_dim, n_layers, bidirec, drop_prob):
        super().__init__()
        self.output_size=output_size
        self.n_layers=n_layers
        self.hidden_dim=hidden_dim
        self.bidirec=True;
        self.embedding=nn.Embedding(vocab_size, embedding_dim)
        self.lstm1=nn.LSTM(embedding_dim, hidden_dim, n_layers, dropout=drop_prob, batch_first=True, bidirectional=bidirec)
        #self.lstm2=nn.LSTM(hidden_dim, hidden_dim, n_layers, dropout=drop_prob, batch_first=True)
        self.dropout=nn.Dropout(drop_prob)
        self.fc=nn.Linear(hidden_dim, output_size)
        self.sigmoid=nn.Sigmoid()
        
    def forward(self, x):
        batch=len(x)
        hidden1=self.init_hidden(batch)
        #hidden2=self.init_hidden(batch)
        embedd=self.embedding(x)
        lstm_out1, hidden1=self.lstm1(embedd, hidden1)
        #lstm_out2, hidden2=self.lstm2(lstm_out1, hidden2)
        lstm_out1=lstm_out1.contiguous().view(-1, self.hidden_dim) # make it lstm_out2, if you un comment the other lstm cell.
        out=self.dropout(lstm_out1)
        out=self.fc(out)
        sig_out=self.sigmoid(out)
        sig_out=sig_out.view(batch, -1)
        sig_out=sig_out[:, -1] 
        return sig_out
    
    def init_hidden(self, batch):
        if (train_on_gpu):
          if self.bidirec==True:
            hidden=(torch.zeros(self.n_layers*2, batch, self.hidden_dim).cuda(),torch.zeros(self.n_layers*2, batch, self.hidden_dim).cuda())
          else:
            hidden=(torch.zeros(self.n_layers, batch, self.hidden_dim).cuda(),torch.zeros(self.n_layers, batch, self.hidden_dim).cuda())
        else:
          if self.bidirec==True:
            hidden=(torch.zeros(self.n_layers*2, batch, self.hidden_dim),torch.zeros(self.n_layers*2, batch, self.hidden_dim))
          else:
            hidden=(torch.zeros(self.n_layers, batch, self.hidden_dim),torch.zeros(self.n_layers, batch, self.hidden_dim))
        return hidden

超参数和训练

learning_rate=0.005
epochs=50
vocab_size = len(vocab_to_int)+1 # +1 for the 0 padding
output_size = 2
embedding_dim = 300
hidden_dim = 256
n_layers = 2
batch_size=23
net=RealOrFakeLSTM(vocab_size, output_size, embedding_dim, hidden_dim, n_layers, True, 0.3)
net.to(device)
criterion=nn.BCELoss()
optimizer=torch.optim.Adam(net.parameters(),lr=learning_rate)
net.train()
loss_arr=np.array([])
lossPerEpoch=np.array([])
for i in range(epochs):
  total_loss=0;
  for input,label in train_loader:
    if train_on_gpu:
      input=input.to(device)
      label=label.to(device)
    optimizer.zero_grad()
    input=input.clone().detach().long()
    out=net(input)
    loss=criterion(out.squeeze(),label.float())
    loss_arr=np.append(loss_arr,loss.cpu().detach().numpy())
    loss.backward()
    optimizer.step()
    total_loss+=loss
  total_loss=total_loss/len(train_loader)
  lossPerEpoch=np.append(lossPerEpoch,total_loss.cpu().detach().numpy())
  print("Epoch ",i,": ",total_loss)
  torch.save(net.state_dict(), Path+"/RealOrFakeLSTM.pt")
  torch.save(net, Path+"/RealOrFakeLSTM.pth")
current_time=str(time.time())
torch.save(net.state_dict(), Path+"/pt/RealOrFakeLSTM"+'_pt_'+current_time+".pt")
torch.save(net, Path+"/pth/RealOrFakeLSTM"+'_pth_'+current_time+".pth")

总损失值几乎相同,测试数据集中所有结果概率完全相同。我对此很陌生,所以超参数调整,我有点用蛮力,但似乎没有任何效果,我认为我的问题不在于架构,而在于训练部分,因为所有预测都是完全相同的。

【问题讨论】:

如果你在粘贴这些大块代码之前用 2-3 行描述你想要解决的任务,我想你会得到更多的答案 :) @JosephBudin 谢谢,我是新手,任何帮助都是好的。我尝试添加任务,如果您能提供任何其他建议,那就太好了。 没问题,别担心;)我试着回答你。我不能比假设做得更好,但希望它会有所帮助。如果确实如此,我会很高兴您投票并接受我的回答,如果没有,请随意不要这样做。我不会把它当成个人;) 最重要的是,欢迎来到 ***! @JosephBudin 你肯定帮了忙,谢谢。 【参考方案1】:

据我所知,在每次前向传递中都会初始化 hidden1=self.init_hidden(batch)。那不应该是正确的。在每个前向传递中初始化一个层解释了您描述的行为。

【讨论】:

就这么简单,谢谢。我不敢相信它超出了我的眼睛。【参考方案2】:

这里的好消息是:“总损失值几乎相同”,这意味着它们并不总是相同,因此,我认为您的网络不会输出恒定概率!我可以看到您的培训未按计划进行的许多可能原因。不幸的是,如果不调试自己,我将无法确定会发生什么。所以这是我的假设:

首先,伤人的是:对于神经网络来说,这项任务可能太难了。您是否尝试过手动对它们进行分类,并且发现它很容易做到?对此没有简单的解决方案,除非接受机器学习不是魔杖,不能解决所有问题。 可能您的学习率太高(或太低),请尝试针对从 10^-5 到 100 的值启动训练,每次将它们乘以 10。无需让训练运行太久,只需检查您的损失从一次迭代到另一次的变化。 也许你的训练集是不平衡的:如果你有 95% 的 True 输入和 5% 的 False 输入,那么你的网络自然会从每次预测 True 开始(logits 对应一个概率)约 95%)。在这种情况下,尝试人为地平衡它(至少暂时):您可以通过复制False 示例(最好不在内存中而是直接在代码中)或删除一些True 示例(理想情况下仅在代码,不在数据库中)。 可能您的架构太小(或太大),请尝试添加(或删除)层。我会先移除层,因为较小的网络往往学得更快。

虽然测试所有这些假设可能会对您有所帮助,但我首先鼓励您了解网络的输出,打印 softmax 层的输出:它输出的概率是多少,您能猜出原因吗? (有时你不能,但通常情况下,这是可能的,就像我在这个答案前面谈到的 95/5 概率情况一样)检查损失是否是你期望得到的输出(手动计算如果需要),一般来说,好奇地想知道你的代码是如何表现的,并检查它在你可以解释变量的任何地方是否按预期工作。

这是机器学习中最难的部分之一,通过它并不容易;)祝你好运!

【讨论】:

您的回复对优化我的模型很有帮助。谢谢。

以上是关于Pytorch RNN 模型没有学到任何东西的主要内容,如果未能解决你的问题,请参考以下文章

pytorch LSTM模型不学习

PyTorch建立RNN相关模型

小白学习PyTorch教程九基于Pytorch训练第一个RNN模型

最简单的RNN回归模型入门(PyTorch)

在 pytorch 中通过具有线性输出层的 RNN 发送的填充批次的掩码和计算损失

Pytorch基础——使用 RNN 生成简单序列