我正在尝试训练LSTM模型,以使用Pytorch中的单词级关联来预测歌曲根据其歌词写的年份。有51种潜在的类/标签(1965-2015)-但是我正在研究使用二进制分类器解决另一个问题的模板。我一直在尝试找出如何更改模型以预测多个类别(1965、1966等)。
我知道您应该提供一个大小为C = num_classes的张量作为输出。但是,我通过使output_size = 51做到了这一点,但是却出现了一个错误,这使我认为存在与定义或在我定义的标准类上进行操作有关的某些事情。
这是模型:
class LyricLSTM(nn.Module):
def __init__(self, vocab_size, output_size, embedding_dim, hidden_dim, n_layers, drop_prob=0.5):
super().__init__()
self.output_size = output_size
self.n_layers = n_layers
self.hidden_dim = hidden_dim
# embedding and LSTM layers
self.embedding = nn.Embedding(vocab_size, embedding_dim)
self.lstm = nn.LSTM(embedding_dim, hidden_dim, n_layers,
dropout=drop_prob, batch_first=True)
# dropout layer
self.dropout = nn.Dropout(0.3)
# linear and sigmoid layers
self.fc = nn.Linear(hidden_dim, output_size)
self.sig = nn.Sigmoid()
#self.softmax = nn.LogSoftmax(dim=1)
def forward(self, x, hidden):
batch_size = x.size(0)
# embeddings and lstm_out
embeds = self.embedding(x)
lstm_out, hidden = self.lstm(embeds, hidden)
# stack up lstm outputs
lstm_out = lstm_out.contiguous().view(-1, self.hidden_dim)
# dropout and fully-connected layer
out = self.dropout(lstm_out)
out = self.fc(out)
# sigmoid function
sig_out = self.sig(out)
#sig_out = self.softmax(out)
# reshape to be batch_size first
sig_out = sig_out.view(batch_size, -1)
sig_out = sig_out[:, -1] # get last batch of labels
# return last sigmoid output and hidden state
return sig_out, hidden
def init_hidden(self, batch_size):
''' Initializes hidden state '''
# Create two new tensors with sizes n_layers x batch_size x hidden_dim,
# initialized to zero, for hidden state and cell state of LSTM
weight = next(self.parameters()).data
hidden = (weight.new(self.n_layers, batch_size, self.hidden_dim).zero_(),
weight.new(self.n_layers, batch_size, self.hidden_dim).zero_())
return hidden
以及训练循环:
n_epochs = 10
batch_size = 16 #100 # 11 batches of size 337 so iters = 11 (11 * 337 = 3707)
# Split into training, validation, testing - train= 80% | valid = 10% | test = 10%
split_frac = 0.8
train_x = encoded_lyrics[0:int(split_frac * len(encoded_lyrics))] # 3707 training samples
train_y = encoded_years[0:int(split_frac * len(encoded_lyrics))] # 3707 training samples
# Dataloaders and batching
# create Tensor datasets
train_data = TensorDataset(torch.from_numpy(train_x), torch.from_numpy(train_y))
# make sure to SHUFFLE your data
train_loader = DataLoader(train_data, shuffle=True, batch_size=batch_size, drop_last=True)
output_size = 51
embedding_dim = 400
hidden_dim = 128 #256
n_layers = 2
lstmc = lstm.LyricLSTM(vocab_len, output_size, embedding_dim, hidden_dim, n_layers)
# Loss function + accuracy reporting
current_loss = 0
losses = np.zeros(n_epochs) # For plotting
accuracy = np.zeros(n_epochs)
lr = 0.001
criterion = nn.CrossEntropyLoss() #nn.BCELoss()
optimizer = torch.optim.Adam(lstmc.parameters(), lr=lr)
counter = 0
print_every = 1
clip = 5 # gradient clipping
# Main training loop
start = time.time()
lstmc.train()
for epoch in range(0, n_epochs):
# initialize hidden state
h = lstmc.init_hidden(batch_size)
# batch loop
for inputs, labels in train_loader:
counter += 1
# Creating new variables for the hidden state, otherwise
# we'd backprop through the entire training history
h = tuple([each.data for each in h])
# zero accumulated gradients
lstmc.zero_grad()
# get the output from the model
inputs = inputs.type(torch.LongTensor)
output, h = lstmc(inputs, h)
# calculate the loss and perform backprop
loss = criterion(output.squeeze(), labels.float())
loss.backward()
nn.utils.clip_grad_norm_(lstmc.parameters(), clip)
optimizer.step()
运行代码时出现此错误
File "main.py", line 182, in main
loss = criterion(output.squeeze(), labels.float())
/venv/lib/python3.7/site-packages/torch/nn/modules/module.py", line 489, in __call__
result = self.forward(*input, **kwargs)
/venv/lib/python3.7/site-packages/torch/nn/modules/loss.py", line 904, in forward
ignore_index=self.ignore_index, reduction=self.reduction)
/venv/lib/python3.7/site-packages/torch/nn/functional.py", line 1970, in cross_entropy
return nll_loss(log_softmax(input, 1), target, weight, None, ignore_index, None, reduction)
/venv/lib/python3.7/site-packages/torch/nn/functional.py", line 1295, in log_softmax
ret = input.log_softmax(dim)
RuntimeError: Dimension out of range (expected to be in range of [-1, 0], but got 1)
这是我得到的输出和标签(批次大小为16):
Output: tensor([0.4962, 0.5025, 0.4963, 0.4936, 0.5058, 0.4872, 0.4995, 0.4852, 0.4840,
0.4791, 0.4984, 0.5034, 0.4796, 0.4826, 0.4811, 0.4859],
grad_fn=<SqueezeBackward0>)
Labels: tensor([1994., 1965., 1981., 1986., 1973., 1981., 1975., 1968., 1981., 1968.,
1989., 1981., 1988., 1991., 1983., 1982.])
我期望输出是长度为51的张量,其中每个元素都包含该年是正确答案的可能性(例如:output [0] =第一年/ 1965,output [1] = 1966,依此类推) )。
答案 0 :(得分:1)
您必须为CrossEntropyLoss提供(N,C)作为输入,并将(N)作为目标。我怀疑在您模型的foward()
方法中,以下代码段是错误的。
sig_out = self.sig(out) # shape: batch_size*seq_len x output_size
# reshape to be batch_size first
sig_out = sig_out.view(batch_size, -1) # shape: batch_size x seq_len*output_size
sig_out = sig_out[:, -1] # shape: batch_size
您要如何处理上一条语句?另外,您想对LSTM输出的seq_len
维度做什么?
尝试考虑您在这里做什么。
尽管我认为output
张量的形状是错误的,但请确保output
是形状为(N,C)的2d张量,labels
是形状为1d的1d张量( N)。
此外,我在您的代码中看到了一些问题。
# zero accumulated gradients
lstmc.zero_grad()
相反,请执行:optimizer.zero_grad()
view()
和fc
层之前不需要进行softmax
操作。self.fc = nn.Linear(hidden_dim, output_size)
self.softmax = nn.LogSoftmax(dim=-1) # use -1 to apply in the last axis
...
out = self.dropout(lstm_out)
out = self.softmax(self.fc(out))
因此,请勿使用以下代码段。
# stack up lstm outputs
lstm_out = lstm_out.contiguous().view(-1, self.hidden_dim) # DON'T DO THIS