Joh*_*owk 3 neural-network python-3.x lstm pytorch
我最近实现了一个“从头开始”生成 RNN 的名称,它运行良好,但远非完美。所以我想在 pytorch 的 LSTM 类上碰碰运气,看看它是否有所作为。确实如此,并且前 7 到 8 个字符的输出看起来更好。但是随后网络陷入循环并输出诸如“laulaulaulau”或“rourourourou”之类的东西(应该是生成法语名称)。
这是一个经常发生的问题吗?如果是这样,您知道解决方法吗?我担心网络不产生 EOS 令牌的事实......这是一个已经在这里问过的问题为什么我的 keras LSTM 模型陷入无限循环? 但没有真正回答所以我的帖子。
这是模型:
class pytorchLSTM(nn.Module):
def __init__(self,input_size,hidden_size):
super(pytorchLSTM,self).__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.lstm = nn.LSTM(input_size, hidden_size)
self.output_layer = nn.Linear(hidden_size,input_size)
self.tanh = nn.Tanh()
self.softmax = nn.LogSoftmax(dim = 2)
def forward(self, input, hidden)
out, hidden = self.lstm(input,hidden)
out = self.tanh(out)
out = self.output_layer(out)
out = self.softmax(out)
return out, hidden
Run Code Online (Sandbox Code Playgroud)
输入和目标分别是两个单热编码向量序列,在开始和结束处分别有序列的开始和序列的结束向量。它们代表取自姓名列表(数据库)的姓名中的字符。我在数据库中的每个名称上使用 和 标记。这是我使用的功能
def inputTensor(line):
#tensor starts with <start of sequence> token.
tensor = torch.zeros(len(line)+1, 1, n_letters)
tensor[0][0][n_letters - 2] = 1
for li in range(len(line)):
letter = line[li]
tensor[li+1][0][all_letters.find(letter)] = 1
return tensor
# LongTensor of second letter to end (EOS) for target
def targetTensor(line):
letter_indexes = [all_letters.find(line[li]) for li in range(len(line))]
letter_indexes.append(n_letters - 1) # EOS
return torch.LongTensor(letter_indexes)
Run Code Online (Sandbox Code Playgroud)
训练循环:
def train_lstm(model):
start = time.time()
criterion = nn.NLLLoss()
optimizer = torch.optim.Adam(model.parameters())
n_iters = 20000
print_every = 1000
plot_every = 500
all_losses = []
total_loss = 0
for iter in range(1,n_iters+1):
line = randomChoice(category_line)
input_line_tensor = inputTensor(line)
target_line_tensor = targetTensor(line).unsqueeze(-1)
optimizer.zero_grad()
loss = 0
output, hidden = model(input_line_tensor)
for i in range(input_line_tensor.size(0)):
l = criterion(output[i], target_line_tensor[i])
loss += l
loss.backward()
optimizer.step()
Run Code Online (Sandbox Code Playgroud)
采样函数:
def sample():
max_length = 20
input = torch.zeros(1,1,n_letters)
input[0][0][n_letters - 2] = 1
output_name = ""
hidden = (torch.zeros(2,1,lstm.hidden_size),torch.zeros(2,1,lstm.hidden_size))
for i in range(max_length):
output, hidden = lstm(input)
output = output[-1][:][:]
l = torch.multinomial(torch.exp(output[0]),num_samples = 1).item()
if l == n_letters - 1:
break
else:
letter = all_letters[l]
output_name += letter
input = inputTensor(letter)
return output_name
Run Code Online (Sandbox Code Playgroud)
典型的采样输出看起来像这样:
Laurayeerauerararauo
Leayealouododauodouo
Courouauurourourodau
Run Code Online (Sandbox Code Playgroud)
你知道我该如何改进吗?
我找到了解释:
当使用LSTM
类的实例作为 RNN 的一部分时,默认输入维度是(seq_length,batch_dim,input_size)
. 为了能够将 lstm 的输出解释为概率(在输入集上),我需要Linear
在Softmax
调用之前将它传递给一个层,这就是问题发生的地方:Linear
实例期望输入的格式为(batch_dim,seq_length,input_size)
.
为了解决这个问题,我们需要在创建时batch_first = True
将参数作为参数传递LSTM
给 RNN,然后向 RNN 提供形式为 的输入(batch_dim, seq_length, input_size)
。
归档时间: |
|
查看次数: |
685 次 |
最近记录: |