【发布时间】:2019-11-12 22:18:43
【问题描述】:
我最近实现了一个“从头开始”生成名称的 RNN,它运行良好,但远非完美。所以我想用 pytorch 的 LSTM 类试试运气,看看它是否有所作为。确实如此,并且前 7 ~ 8 个字符的输出看起来要好得多。但随后网络陷入循环并输出诸如“laulaulaulau”或“rourourourou”之类的内容(它应该生成法语名称)。
这是一个经常发生的问题吗?如果是这样,您知道解决方法吗?我担心网络不产生 EOS 代币的事实...... 这是一个已经在这里问过的问题Why does my keras LSTM model get stuck in an infinite loop? 但没有真正回答,因此我的帖子。
这是模型:
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
输入和目标是两个one-hot编码向量序列,分别在开始和结束处有一个序列的开始和序列的结束向量。它们代表取自名称列表(数据库)的名称中的字符。 我在数据库中的每个名称上使用一个和标记。这是我使用的功能
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)
训练循环:
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()
采样函数:
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
典型的采样输出看起来像这样:
Laurayeerauerararauo
Leayealouododauodouo
Courouauurourourodau
你知道我该如何改进吗?
【问题讨论】:
-
我很难理解您的
sample函数。它应该做什么?创建名字?你能给出一些示例输出吗?它在哪里使用,在您的训练循环中/创建数据集/其他配置时? -
sample函数将 one-hot 编码的“序列开始”标记输入网络并要求输出,这是一个概率分布,从中抽取下一个字母。然后这个字母被馈送到网络,你重复这个过程,直到生成“序列结束”令牌。它在网络经过训练后用于生成名称。
标签: python-3.x neural-network pytorch lstm