| from __future__ import annotations |
|
|
| import argparse |
| import sys |
| from pathlib import Path |
| import torch |
|
|
| ROOT = Path(__file__).resolve().parents[1] |
| if str(ROOT) not in sys.path: |
| sys.path.insert(0, str(ROOT)) |
|
|
| from src.model import LLM, ModelConfig |
| from src.tokenizer import BPETokenizer |
| from src.tokenizer.io_utils import load_tokenizer |
|
|
| def generate(model: LLM, input_ids: torch.Tensor, max_new_tokens: int, temperature: float = 1.0) -> torch.Tensor: |
| model.eval() |
| device = input_ids.device |
| |
| current_ids = input_ids |
| |
| b, seq_len = current_ids.shape |
| _, caches = model(current_ids, use_cache=True) |
| |
| generated = [] |
| |
| with torch.no_grad(): |
| for _ in range(max_new_tokens): |
| |
| next_token_id = current_ids[:, -1:] |
| logits, caches = model(next_token_id, use_cache=True, caches=caches) |
| |
| |
| next_token_logits = logits[:, -1, :] / temperature |
| probs = torch.nn.functional.softmax(next_token_logits, dim=-1) |
| next_token = torch.multinomial(probs, num_samples=1) |
| |
| generated.append(next_token) |
| current_ids = torch.cat([current_ids, next_token], dim=1) |
| |
| return torch.cat(generated, dim=1) |
|
|
|
|
| def main(): |
| parser = argparse.ArgumentParser(description="Test model inference with text payload.") |
| parser.add_argument("--text", type=str, required=True, help="Input text payload") |
| parser.add_argument("--max_new_tokens", type=int, default=20, help="Number of tokens to generate") |
| parser.add_argument("--temperature", type=float, default=0.8, help="Sampling temperature") |
| parser.add_argument("--model_path", type=str, default="final_model.pt", help="Path to checkpoint") |
| parser.add_argument("--tokenizer_path", type=str, default="tokenizer_vocab.json", help="Path to tokenizer") |
| parser.add_argument("--d_model", type=int, default=512) |
| parser.add_argument("--n_layers", type=int, default=6) |
| parser.add_argument("--n_heads", type=int, default=8) |
| parser.add_argument("--max_seq_len", type=int, default=256) |
| parser.add_argument("--n_experts", type=int, default=8) |
| parser.add_argument("--d_c", type=int, default=64) |
| parser.add_argument("--d_rope", type=int, default=16) |
| args = parser.parse_args() |
|
|
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") |
| print(f"Using device: {device}") |
|
|
| |
| print(f"Loading tokenizer from {args.tokenizer_path}...") |
| if not Path(args.tokenizer_path).exists(): |
| print("Tokenizer file not found!") |
| return |
| |
| merges, vocab = load_tokenizer(args.tokenizer_path) |
| tokenizer = BPETokenizer() |
| tokenizer.merges = merges |
| tokenizer.vocab = vocab |
| vocab_size = len(tokenizer.vocab) |
| print(f"Tokenizer vocab size: {vocab_size}") |
|
|
| |
| print("Initializing model architecture...") |
| model = LLM( |
| vocab_size=vocab_size, |
| d_model=args.d_model, |
| n_layers=args.n_layers, |
| n_heads=args.n_heads, |
| d_c=args.d_c, |
| n_experts=args.n_experts, |
| max_seq_len=args.max_seq_len, |
| d_rope=args.d_rope, |
| ).to(device) |
| |
| if Path(args.model_path).exists(): |
| print(f"Loading trained weights from {args.model_path}...") |
| model.load_state_dict(torch.load(args.model_path, map_location=device)) |
| else: |
| print(f"Warning: {args.model_path} not found. Using untrained random weights.") |
| |
| |
| tokens = tokenizer.encode(args.text) |
| token_ids = [tokenizer.vocab[t] for t in tokens if t in tokenizer.vocab] |
| |
| if not token_ids: |
| print("Empty input after tokenization.") |
| return |
| |
| input_tensor = torch.tensor([token_ids], dtype=torch.long, device=device) |
| |
| print("\n--- Input payload ---") |
| print(args.text) |
| print(f"Tokens: {input_tensor.tolist()[0]}") |
| |
| |
| print("\n--- Generating ---") |
| out_tensor = generate(model, input_tensor, max_new_tokens=args.max_new_tokens, temperature=args.temperature) |
| out_ids = out_tensor[0].tolist() |
| |
| |
| out_tokens = [list(tokenizer.vocab.keys())[list(tokenizer.vocab.values()).index(idx)] for idx in out_ids] |
| decoded_text = tokenizer.decode(out_tokens) |
| |
| print(decoded_text) |
| |
| if not Path(args.model_path).exists(): |
| print("\n(Note: The model is not trained yet, so the output is random text)") |
|
|
| if __name__ == "__main__": |
| main() |
|
|