[Python] How predict next word using LSTM model?

Discussão em 'Python' iniciado por Stack, Julho 8, 2025.

  1. Stack

    Stack Membro Participativo

    I am currently building an LSTM model in Pytorch to predict the next word of a given input.

    My model:

    class LSTM(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim, num_layers, dropout_rate, tie_weights):
    super().__init__()

    self.num_layers = num_layers
    self.hidden_dim = hidden_dim
    self.embedding_dim = embedding_dim

    self.embedding = nn.Embedding(vocab_size, embedding_dim)
    self.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers=num_layers,
    dropout=dropout_rate, batch_first=True)
    self.dropout = nn.Dropout(dropout_rate)
    self.linear = nn.Linear(hidden_dim, vocab_size)

    if tie_weights:
    #Embedding and hidden layer need to be same size for weight tieing
    assert embedding_dim == hidden_dim, 'cannot tie, check dims'
    self.linear.weight = self.embedding.weight
    self.init_weights()

    def forward(self, x):
    # x is a batch of input sequences
    x = self.embedding(x)
    x, _ = self.lstm(x)
    x = self.linear(x)
    return x

    def init_weights(self):
    init_range_emb = 0.1
    init_range_other = 1/math.sqrt(self.hidden_dim)
    self.embedding.weight.data.uniform_(-init_range_emb, init_range_emb)
    self.linear.weight.data.uniform_(-init_range_other, init_range_other)
    self.linear.bias.data.zero_()
    for i in range(self.num_layers):
    self.lstm.all_weights[0] = torch.FloatTensor(self.embedding_dim,
    self.hidden_dim).uniform_(-init_range_other, init_range_other)
    self.lstm.all_weights[1] = torch.FloatTensor(self.hidden_dim,
    self.hidden_dim).uniform_(-init_range_other, init_range_other)



    vocab_size = len(vocab)
    embedding_dim = 100
    hidden_dim = 100
    num_layers = 2
    dropout_rate = 0.4
    tie_weights = True
    model = LSTM(vocab_size, embedding_dim, hidden_dim, num_layers, dropout_rate, tie_weights)
    model.to(device)


    Training and evaluation funciton:

    import copy
    import time

    criterion = nn.CrossEntropyLoss()
    lr = 20.0 # learning rate
    optimizer = torch.optim.SGD(model.parameters(), lr=lr)
    scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 1.0, gamma=0.95)

    def train(model: nn.Module) -> None:
    model.train() # turn on train mode
    total_loss = 0.
    log_interval = 200
    start_time = time.time()

    num_batches = len(train_data) // bptt
    for batch, i in enumerate(range(0, train_data.size(0) - 1, bptt)):
    data, targets = get_batch(train_data, i)
    seq_len = data.size(0)
    output = model(data)
    loss = criterion(output.view(-1, vocab_size), targets)

    optimizer.zero_grad()
    loss.backward()
    torch.nn.utils.clip_grad_norm_(model.parameters(), 0.5)
    optimizer.step()

    total_loss += loss.item()

    if batch % log_interval == 0 and batch > 0:
    lr = scheduler.get_last_lr()[0]
    ms_per_batch = (time.time() - start_time) * 1000 / log_interval
    cur_loss = total_loss / log_interval
    ppl = math.exp(cur_loss)
    print(f'| epoch {epoch:3d} | {batch:5d}/{num_batches:5d} batches | '
    f'lr {lr:02.2f} | ms/batch {ms_per_batch:5.2f} | '
    f'loss {cur_loss:5.2f} | ppl {ppl:8.2f}')
    total_loss = 0
    start_time = time.time()


    def evaluate(model: nn.Module, eval_data: Tensor) -> float:
    model.eval() # turn on evaluation mode
    total_loss = 0.
    with torch.no_grad():
    for i in range(0, eval_data.size(0) - 1, bptt):
    data, targets = get_batch(eval_data, i)
    seq_len = data.size(0)
    output = model(data)
    output_flat = output.view(-1, vocab_size)
    total_loss += seq_len * criterion(output_flat, targets).item()
    return total_loss / (len(eval_data) - 1)


    Training loop

    best_val_loss = float('inf')
    epochs = 50
    best_model = None

    for epoch in range(1, epochs + 1):
    epoch_start_time = time.time()
    train(model)
    val_loss = evaluate(model, val_data)
    val_ppl = math.exp(val_loss)
    elapsed = time.time() - epoch_start_time
    print('-' * 89)
    print(f'| end of epoch {epoch:3d} | time: {elapsed:5.2f}s | '
    f'valid loss {val_loss:5.2f} | valid ppl {val_ppl:8.2f}')
    print('-' * 89)

    if val_loss < best_val_loss:
    best_val_loss = val_loss
    best_model = copy.deepcopy(model)

    scheduler.step()


    My problem is I have no idea how to go about this. I've seen some implementations of character based LSTM text generators but I'm looking for it to be word based. For example I want to pass an input like "How are you" and the output will included the next predicted word, like for example "How are you today"

    Any help appreciated.

    Continue reading...

Compartilhe esta Página