# Copyright Lightning AI. Licensed under the Apache License 2.0, see LICENSE file. """Pre-flight validation for LitGPT checkpoints. Usage: litgpt validate --checkpoint_dir checkpoints/meta-llama/... """ import sys from pathlib import Path import torch import yaml from litgpt.config import Config from litgpt.utils import ( check_valid_checkpoint_dir, estimate_model_memory, validate_checkpoint, ) def validate_setup( checkpoint_dir: Path, model_filename: str = "lit_model.pth", dtype: str = "float32", training: bool = False, ) -> None: """Run pre-flight validation on a checkpoint directory. This checks everything without actually running training or generation: 1. Checkpoint directory structure (required files exist) 2. Model config loading 3. Tokenizer loading 4. Checkpoint key/shape validation against the model 5. Memory estimation Args: checkpoint_dir: Path to the checkpoint directory. model_filename: Name of the checkpoint file (default: ``lit_model.pth``). dtype: Data type for memory estimation (``float32``, ``float16``, ``bfloat16``). training: If ``True``, estimate memory for training (includes optimizer states). """ checkpoint_dir = Path(checkpoint_dir) print(f"{'=' * 60}") print("LitGPT Pre-flight Validation") print(f"Checkpoint: {checkpoint_dir}") print(f"{'=' * 60}\n") all_passed = True # --- Step 1: Checkpoint directory structure --- print("[1/5] Checking checkpoint directory structure...") try: check_valid_checkpoint_dir( checkpoint_dir, model_filename=model_filename, ) print(" ✓ All required files found.\n") except (FileNotFoundError, SystemExit) as e: print(f" ✗ Directory validation failed: {e}\n", file=sys.stderr) all_passed = False # --- Step 2: Load model config --- print("[2/5] Loading model config...") config = None config_path = checkpoint_dir / "model_config.yaml" try: if config_path.is_file(): with open(config_path, encoding="utf-8") as f: config_dict = yaml.safe_load(f) config = Config(**config_dict) print(f" ✓ Config loaded: {config.name or 'unnamed'}") print( f" n_layer={config.n_layer}, n_embd={config.n_embd}, " f"n_head={config.n_head}, vocab_size={config.vocab_size}\n" ) else: print(f" ✗ Config file not found: {config_path}\n", file=sys.stderr) all_passed = False except Exception as e: print(f" ✗ Failed to load config: {e}\n", file=sys.stderr) all_passed = False # --- Step 3: Tokenizer --- print("[3/5] Checking tokenizer...") try: from litgpt.tokenizer import Tokenizer tokenizer = Tokenizer(checkpoint_dir) # Do a simple encode/decode round-trip test_text = "Hello" tokens = tokenizer.encode(test_text) decoded = tokenizer.decode(tokens) print(f" ✓ Tokenizer loaded (backend={tokenizer.backend})") print(f' Round-trip test: "{test_text}" → {tokens.tolist()} → "{decoded}"\n') except Exception as e: print(f" ✗ Tokenizer failed: {e}\n", file=sys.stderr) all_passed = False # --- Step 4: Checkpoint validation --- print("[4/5] Validating checkpoint against model...") checkpoint_path = checkpoint_dir / model_filename if config is not None and checkpoint_path.is_file(): try: from litgpt import GPT with torch.device("meta"): model = GPT(config) result = validate_checkpoint(checkpoint_path, model, verbose=False) if result.is_valid: print(" ✓ Checkpoint keys and shapes match the model.\n") else: all_passed = False print(f" ✗ {result.summary()}\n", file=sys.stderr) except Exception as e: print(f" ✗ Checkpoint validation error: {e}\n", file=sys.stderr) all_passed = False elif not checkpoint_path.is_file(): print(f" ⊘ Skipped (checkpoint file not found: {checkpoint_path})\n") else: print(" ⊘ Skipped (config not loaded)\n") # --- Step 5: Memory estimation --- print("[5/5] Estimating memory requirements...") if config is not None: mem = estimate_model_memory(config, dtype=dtype, training=training) print(f" Estimated parameters: {mem['param_count']:,}") print(f" Parameter memory: {mem['param_memory_gb']:.2f} GB ({dtype})") mode_str = "training (params + grads + optimizer)" if training else "inference (params only)" print(f" Estimated total ({mode_str}): {mem['estimated_total_gb']:.2f} GB") if mem["available_gpu_memory_gb"] is not None: print(f" Available GPU memory: {mem['available_gpu_memory_gb']:.2f} GB") if mem["fits_in_memory"]: print(" ✓ Model should fit in GPU memory.\n") else: print(" ⚠ WARNING: Model may NOT fit in GPU memory!\n", file=sys.stderr) all_passed = False else: print(" ⊘ No GPU detected, skipping memory fit check.\n") else: print(" ⊘ Skipped (config not loaded)\n") # --- Summary --- print(f"{'=' * 60}") if all_passed: print("✓ All validation checks passed!") else: print("✗ Some validation checks failed. See details above.", file=sys.stderr) print(f"{'=' * 60}") if not all_passed: raise SystemExit(1)