我是新来PyTorch和LSTMs,我想训练一个分类模型,需要每个字通过word2vec(预训练矢量)编码的句子和输出后一类是看到了完整的句子。我有四个不同的等级。该判决具有可变长度。
我的代码运行没有错误,但它总是预测相同的类,不管我有多少纪元训练我的模型。所以我觉得梯度不正确backpropagated。这里是我的代码:
class LSTM(nn.Module):
def __init__(self, embedding_dim, hidden_dim, tagset_size):
super(LSTM, self).__init__()
self.hidden_dim = hidden_dim
self.lstm = nn.LSTM(embedding_dim, hidden_dim)
self.hidden2tag = nn.Linear(hidden_dim, tagset_size)
self.hidden = self.init_hidden()
def init_hidden(self):
# The axes semantics are (num_layers, minibatch_size, hidden_dim)
return (torch.zeros(1, 1, self.hidden_dim).to(device),
torch.zeros(1, 1, self.hidden_dim).to(device))
def forward(self, sentence):
lstm_out, self.hidden = self.lstm(sentence.view(len(sentence), 1, -1), self.hidden)
tag_space = self.hidden2tag(lstm_out.view(len(sentence), -1))
tag_scores = F.log_softmax(tag_space, dim=1)
return tag_scores
EMBEDDING_DIM = len(training_data[0][0][0])
HIDDEN_DIM = 256
model = LSTM(EMBEDDING_DIM, HIDDEN_DIM, 4)
model.to(device)
loss_function = nn.NLLLoss()
optimizer = optim.SGD(model.parameters(), lr=0.1)
for epoch in tqdm(range(n_epochs)):
for sentence, tag in tqdm(training_data):
model.zero_grad()
model.hidden = model.init_hidden()
sentence_in = torch.tensor(sentence, dtype=torch.float).to(device)
targets = torch.tensor([label_to_idx[tag]], dtype=torch.long).to(device)
tag_scores = model(sentence_in)
res = torch.tensor(tag_scores[-1], dtype=torch.float).view(1,-1).to(device)
# I THINK THIS IS WRONG???
print(res) # tensor([[-10.6328, -10.6783, -10.6667, -0.0001]], device='cuda:0', grad_fn=<CopyBackwards>)
print(targets) # tensor([3], device='cuda:0')
loss = loss_function(res, targets)
loss.backward()
optimizer.step()
该代码主要是由https://pytorch.org/tutorials/beginner/nlp/sequence_models_tutorial.html不同的是,他们有一个序列到序列模型,我有一个序列到一个模型的启发。
我不知道是什么问题,但我想,该模式返回的分数包含得分为每个标签和我的地面实况只包含正确的类的指数?这将如何正确处理?
或者是损失函数也许不是一个正确的我的使用情况?另外,我不知道这是正确完成:
res = torch.tensor(tag_scores[-1], dtype=torch.float).view(1,-1).to(device)
通过采取tag_scores[-1]
我想最后一句话已经给网络后,因为tag_scores包含分数在每个步骤之后,如果我理解正确的话,以获得分数。
这就是我如何评价:
with torch.no_grad():
preds = []
gts = []
for sentence, tag in tqdm(test_data):
inputs = torch.tensor(sentence, dtype=torch.float).to(device)
tag_scores = model(inputs)
# find index with max value (this is the class to be predicted)
pred = [j for j,v in enumerate(tag_scores[-1]) if v == max(tag_scores[-1])][0]
print(pred, idx_to_label[pred], tag)
preds.append(pred)
gts.append(label_to_idx[tag])
print(f1_score(gts, preds, average='micro'))
print(classification_report(gts, preds))
编辑:
当训练前洗牌的数据似乎工作。但为什么?
编辑2:
我想,为什么需要洗牌的原因是,我的训练数据中包含样本组中的每个类。所以其他训练后,当他们每个人,该模型将只能看到在过去的N次迭代的同一类,因此它只会预测这个类。另一个原因也可能是我目前使用的只有一个样本的小批量,因为我还没有想出如何使用其他尺寸。
因为你试图用一个完整的句子进行分类,所以下面一行:
self.hidden2tag(lstm_out.view(len(sentence), -1))
应改为,所以它需要的最终功能分类。
self.hidden2tag(lstm_out.view(sentence[-1], -1))
但我也不太清楚,因为我不熟悉LSTM。