|
import torch |
|
import torch.nn as nn |
|
import torch.nn.functional as F |
|
import pickle |
|
from safetensors.torch import load_file |
|
import logging |
|
import argparse |
|
|
|
|
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') |
|
|
|
|
|
embedding_dim = 128 |
|
hidden_dim = 256 |
|
num_layers = 2 |
|
sequence_length = 10 |
|
|
|
|
|
class LSTMModel(nn.Module): |
|
def __init__(self, vocab_size, embedding_dim, hidden_dim, num_layers): |
|
super(LSTMModel, self).__init__() |
|
self.embedding = nn.Embedding(vocab_size, embedding_dim) |
|
self.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers, batch_first=True) |
|
self.fc = nn.Linear(hidden_dim, vocab_size) |
|
|
|
def forward(self, x): |
|
embeds = self.embedding(x) |
|
lstm_out, _ = self.lstm(embeds) |
|
logits = self.fc(lstm_out[:, -1, :]) |
|
return logits |
|
|
|
|
|
def predict_next_word(model, word2idx, idx2word, sequence, sequence_length, temp, top_k): |
|
model.eval() |
|
with torch.no_grad(): |
|
seq_idx = [word2idx.get(word, word2idx['<UNK>']) for word in sequence.split()] |
|
seq_idx = seq_idx[-sequence_length:] |
|
seq_tensor = torch.tensor(seq_idx, dtype=torch.long).unsqueeze(0) |
|
outputs = model(seq_tensor) |
|
outputs = outputs / temp |
|
probs = F.softmax(outputs, dim=1).squeeze() |
|
top_k_probs, top_k_idx = torch.topk(probs, top_k) |
|
predicted_idx = torch.multinomial(top_k_probs, 1).item() |
|
predicted_word = idx2word[top_k_idx[predicted_idx].item()] |
|
return predicted_word |
|
|
|
|
|
def generate_sentence(model, word2idx, idx2word, start_sequence, sequence_length, temp, top_k, max_length): |
|
sentence = start_sequence |
|
for _ in range(max_length): |
|
next_word = predict_next_word(model, word2idx, idx2word, sentence, sequence_length, temp, top_k) |
|
sentence += ' ' + next_word |
|
if next_word == '<pad>': |
|
break |
|
return sentence |
|
|
|
|
|
def parse_args(): |
|
parser = argparse.ArgumentParser(description='LSTM Next Word Prediction Chatbot') |
|
parser.add_argument('--temp', type=float, default=1.0, help='Temperature parameter') |
|
parser.add_argument('--top_k', type=int, default=10, help='Top-k sampling parameter') |
|
parser.add_argument('--model_file', type=str, default='lstm_model.safetensors', help='Path to the safetensors model file') |
|
parser.add_argument('--start_sequence', type=str, default='Once upon a time', help='Starting sequence for sentence generation') |
|
parser.add_argument('--max_length', type=int, default=50, help='Maximum number of words to generate') |
|
return parser.parse_args() |
|
|
|
|
|
def main(): |
|
args = parse_args() |
|
temp = args.temp |
|
top_k = args.top_k |
|
model_file = args.model_file |
|
start_sequence = args.start_sequence |
|
max_length = args.max_length |
|
|
|
logging.info(f'Loading the model and vocabulary from {model_file}...') |
|
model_state_dict = load_file(model_file) |
|
with open('word2idx.pkl', 'rb') as f: |
|
word2idx = pickle.load(f) |
|
|
|
|
|
idx2word = {idx: word for word, idx in word2idx.items()} |
|
|
|
vocab_size = len(word2idx) |
|
model = LSTMModel(vocab_size, embedding_dim, hidden_dim, num_layers) |
|
model.load_state_dict(model_state_dict) |
|
model.eval() |
|
|
|
logging.info('Model and vocabulary loaded successfully.') |
|
logging.info(f'Starting sequence: {start_sequence}') |
|
logging.info(f'Temperature: {temp}, Top-k: {top_k}, Max Length: {max_length}') |
|
generated_sentence = generate_sentence(model, word2idx, idx2word, start_sequence, sequence_length, temp, top_k, max_length) |
|
logging.info(f'Generated sentence: {generated_sentence}') |
|
|
|
if __name__ == '__main__': |
|
main() |