Pytorch RNN 模型没有学习任何东西
Pytorch RNN model not learning anything
任务:预测提供的灾难推文是否真实。已经将我的文本数据转换为张量,然后转换为 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")
总损失值几乎相同,测试数据集中所有结果概率完全相同。我对此很陌生,所以超参数调整,我有点用蛮力,但似乎没有任何效果,我认为我的问题不在于架构,而在于训练部分,因为所有预测都完全相同。
这里的好消息是:“总损失值几乎相同”,这意味着它们并不总是相同,因此,我认为您的网络不会输出常数概率!我可以看到许多可能的原因导致您的培训无法按计划进行。不幸的是,如果不调试自己,我将无法确定会发生什么。所以这是我的假设:
- 首先,伤人的是:也许这个任务对于神经网络来说太难了。您是否尝试过手动对它们进行分类,您觉得这很容易做到吗?除了接受机器学习不是魔杖并且不能解决所有问题之外,没有简单的解决方案。
- 也许你的学习率太高(或太低)尝试启动训练值范围从 10^-5 到 100,每次乘以 10。不需要让训练 运行 太久,只需检查你的损失从一个迭代到另一个迭代有多少变化。
- 也许你的训练集是不平衡的:如果你有 95% 的
True
输入和 5% 的 False
输入,那么你的网络自然会开始预测每个 True
时间(logits 对应于 ~95% 的概率)。在这种情况下,尝试人为地平衡它(至少暂时):您可以通过复制 False
示例(最好不在内存中,而是直接在代码中)或删除一些 True
示例(理想情况下也只在代码中,而不是在数据库中。
- 也许您的架构太小(或太大)尝试添加(或删除)层。我将从删除层开始,因为较小的网络往往学得更快。
虽然测试所有这些假设可能对您有所帮助,但我首先鼓励您了解网络的输出,打印 softmax 层的输出:它输出的概率是多少,您能猜出原因吗? (有时你不能,但很多时候,这是可能的,就像我之前在这个答案中谈到的 95/5 概率的情况)检查损失是否是你期望给出这个输出的(手动计算)如果需要的话),一般来说,好奇地找出你的代码是如何表现的,并检查它是否在你可以解释你的变量的任何地方都按预期工作。
它是机器学习的难点之一,驾驭它并不容易;)祝你好运!
据我所知,您正在每次前向传递中初始化 hidden1=self.init_hidden(batch)。那不应该是正确的。在每个正向传递中初始化一个层解释了您描述的行为。
任务:预测提供的灾难推文是否真实。已经将我的文本数据转换为张量,然后转换为 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")
总损失值几乎相同,测试数据集中所有结果概率完全相同。我对此很陌生,所以超参数调整,我有点用蛮力,但似乎没有任何效果,我认为我的问题不在于架构,而在于训练部分,因为所有预测都完全相同。
这里的好消息是:“总损失值几乎相同”,这意味着它们并不总是相同,因此,我认为您的网络不会输出常数概率!我可以看到许多可能的原因导致您的培训无法按计划进行。不幸的是,如果不调试自己,我将无法确定会发生什么。所以这是我的假设:
- 首先,伤人的是:也许这个任务对于神经网络来说太难了。您是否尝试过手动对它们进行分类,您觉得这很容易做到吗?除了接受机器学习不是魔杖并且不能解决所有问题之外,没有简单的解决方案。
- 也许你的学习率太高(或太低)尝试启动训练值范围从 10^-5 到 100,每次乘以 10。不需要让训练 运行 太久,只需检查你的损失从一个迭代到另一个迭代有多少变化。
- 也许你的训练集是不平衡的:如果你有 95% 的
True
输入和 5% 的False
输入,那么你的网络自然会开始预测每个True
时间(logits 对应于 ~95% 的概率)。在这种情况下,尝试人为地平衡它(至少暂时):您可以通过复制False
示例(最好不在内存中,而是直接在代码中)或删除一些True
示例(理想情况下也只在代码中,而不是在数据库中。 - 也许您的架构太小(或太大)尝试添加(或删除)层。我将从删除层开始,因为较小的网络往往学得更快。
虽然测试所有这些假设可能对您有所帮助,但我首先鼓励您了解网络的输出,打印 softmax 层的输出:它输出的概率是多少,您能猜出原因吗? (有时你不能,但很多时候,这是可能的,就像我之前在这个答案中谈到的 95/5 概率的情况)检查损失是否是你期望给出这个输出的(手动计算)如果需要的话),一般来说,好奇地找出你的代码是如何表现的,并检查它是否在你可以解释你的变量的任何地方都按预期工作。
它是机器学习的难点之一,驾驭它并不容易;)祝你好运!
据我所知,您正在每次前向传递中初始化 hidden1=self.init_hidden(batch)。那不应该是正确的。在每个正向传递中初始化一个层解释了您描述的行为。