gemma4-e2b-exp-quant / test_perplexity.py
toxzak's picture
Initial upload: mixed-budget sub-4-bit artifacts + perplexity result
9c41926 verified
Raw
History Blame Contribute Delete
3.59 kB
"""
Perplexity evaluation for quantized .pt checkpoints.
This runs a real transformer forward pass after applying quantized weights.
For GGUF/GEMV latency checks, use run_gemv_chain.py instead.
"""
import argparse
import gc
from pathlib import Path
import torch
from scripts.eval_quantized import apply_quantized_weights, eval_perplexity
def evaluate_quantized_perplexity(
model_name="models/gemma-4-E2B",
quantized_path="quantized/gemma-4-E2B-sub1bit.pt",
wikitext_path="data/wiki.test.txt",
device=None,
max_length=512,
stride=512,
):
"""Evaluate WikiText perplexity after applying quantized weights."""
if device is None:
device = "cuda" if torch.cuda.is_available() else "cpu"
if not Path(wikitext_path).exists():
raise FileNotFoundError(f"WikiText not found: {wikitext_path}")
print("=" * 60)
print("QUANTIZED MODEL PERPLEXITY EVALUATION")
print("=" * 60)
print(f"Device: {device}")
print(f"Model: {model_name}")
print(f"Quantized: {quantized_path}")
print(f"WikiText: {wikitext_path}")
print("\n[1] Loading quantized checkpoint...")
q_data = torch.load(quantized_path, map_location="cpu", weights_only=True)
quantized = q_data["quantized"]
print(f" {len(quantized)} quantized entries")
print("\n[2] Loading base model...")
from transformers import AutoModelForCausalLM, AutoTokenizer
torch_dtype = torch.float16 if device == "cuda" else torch.float32
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map=device,
torch_dtype=torch_dtype,
trust_remote_code=True,
)
model.eval()
print("\n[3] Applying quantized weights...")
apply_stats = apply_quantized_weights(
model,
quantized,
device=device,
model_dir=model_name if Path(model_name).is_dir() else None,
checkpoint_weight_keys=q_data.get("weight_keys"),
)
print(f" Replaced {apply_stats['replaced']}/{len(quantized)} weights")
if apply_stats["skipped"]:
print(f" Skipped {len(apply_stats['skipped'])} shared-KV checkpoint entries")
print("\n[4] Evaluating perplexity...")
ppl, stats = eval_perplexity(
model,
tokenizer,
wikitext_path,
device,
max_length=max_length,
stride=stride,
)
print()
print("=" * 60)
print("RESULTS")
print("=" * 60)
print(f" Perplexity: {ppl:.4f}")
print(f" Chunks: {stats['n_chunks']}")
print(f" Target: <= 10.5")
print(f" Status: {'PASS' if ppl <= 10.5 else 'FAIL'}")
print("=" * 60)
del model
gc.collect()
if device == "cuda":
torch.cuda.empty_cache()
return ppl, stats
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Evaluate quantized model perplexity")
parser.add_argument("--model", default="models/gemma-4-E2B")
parser.add_argument("--quantized", default="quantized/gemma-4-E2B-sub1bit.pt")
parser.add_argument("--wikitext", default="data/wiki.test.txt")
parser.add_argument("--device", default=None)
parser.add_argument("--max-length", type=int, default=512)
parser.add_argument("--stride", type=int, default=512)
args = parser.parse_args()
evaluate_quantized_perplexity(
model_name=args.model,
quantized_path=args.quantized,
wikitext_path=args.wikitext,
device=args.device,
max_length=args.max_length,
stride=args.stride,
)