LUNA / Base /scripts /validate_model.py
ASTERIZER
LUNA 100M: cloud-ready training pipeline
ad68b7f
Raw
History Blame
4.33 kB
"""
Post-training validation script.
Tests the trained model by generating text from prompts.
Usage:
python Base/scripts/validate_model.py --checkpoint_dir Base/out/pretrain/custom-100m-10m-test/final
python Base/scripts/validate_model.py --checkpoint_dir Base/out/pretrain/custom-100m-3b/final
"""
import argparse
from pathlib import Path
import torch
from litgpt import Tokenizer
from litgpt.config import Config
from litgpt.model import GPT
def load_model(checkpoint_dir: str):
"""Load a pretrained model from a litgpt checkpoint directory."""
checkpoint_dir = Path(checkpoint_dir)
if not checkpoint_dir.exists():
raise FileNotFoundError(f"Checkpoint directory not found: {checkpoint_dir}")
config = Config.from_checkpoint(checkpoint_dir)
model_path = checkpoint_dir / "lit_model.pth"
if not model_path.exists():
raise FileNotFoundError(f"Model file not found: {model_path}")
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")
with torch.device("meta"):
model = GPT(config)
checkpoint = torch.load(str(model_path), map_location="cpu", weights_only=False)
# Handle both direct state_dict and wrapped checkpoint formats
if "model" in checkpoint:
state_dict = checkpoint["model"]
else:
state_dict = checkpoint
model.load_state_dict(state_dict, assign=True)
model = model.to(device)
model.eval()
return model, config, device
def generate_text(model, tokenizer, device, prompt, max_new_tokens=200, temperature=0.8, top_k=50):
"""Generate text from a prompt."""
input_ids = tokenizer.encode(prompt, device=device).unsqueeze(0)
with torch.no_grad():
for _ in range(max_new_tokens):
# Crop to block_size if needed
idx_cond = input_ids[:, -model.max_seq_length:]
logits = model(idx_cond)
logits = logits[:, -1, :] / temperature
# Top-k filtering
if top_k is not None:
v, _ = torch.topk(logits, min(top_k, logits.size(-1)))
logits[logits < v[:, [-1]]] = float("-inf")
probs = torch.softmax(logits, dim=-1)
next_id = torch.multinomial(probs, num_samples=1)
input_ids = torch.cat([input_ids, next_id], dim=1)
# Stop on EOS
if next_id.item() == tokenizer.eos_id:
break
return tokenizer.decode(input_ids[0])
def main():
parser = argparse.ArgumentParser(description="Validate a pretrained LitGPT model")
parser.add_argument(
"--checkpoint_dir",
type=str,
required=True,
help="Path to the checkpoint directory (e.g., Base/out/pretrain/custom-100m-10m-test/final)",
)
parser.add_argument(
"--tokenizer_dir",
type=str,
default="Base/checkpoints/EleutherAI/pythia-160m",
help="Path to the tokenizer directory",
)
parser.add_argument(
"--max_new_tokens",
type=int,
default=200,
help="Maximum tokens to generate",
)
args = parser.parse_args()
print(f"Loading model from: {args.checkpoint_dir}")
model, config, device = load_model(args.checkpoint_dir)
print(f"\nModel config: {config.name}")
print(f"Parameters: {sum(p.numel() for p in model.parameters()):,}")
print(f"Block size: {config.block_size}")
tokenizer = Tokenizer(Path(args.tokenizer_dir))
test_prompts = [
"The future of artificial intelligence",
"In a groundbreaking study, researchers found that",
"The most important thing about education is",
"Once upon a time, in a land far away,",
]
print(f"\n{'='*60}")
print("GENERATION TESTS")
print(f"{'='*60}")
for i, prompt in enumerate(test_prompts, 1):
print(f"\n--- Prompt {i}: \"{prompt}\" ---")
output = generate_text(
model, tokenizer, device, prompt,
max_new_tokens=args.max_new_tokens,
)
print(f"Generated:\n{output}\n")
print(f"{'='*60}")
print("Validation complete!")
print("Note: A freshly pretrained model will produce semi-coherent text.")
print("Quality improves with more training data and compute.")
if __name__ == "__main__":
main()