import json
import platform
import sys
from pathlib import Path
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
MODEL_REPO = "microsoft/Phi-3.5-mini-instruct"
TEST_PROMPTS = [
"The capital of France is",
"Two plus two equals",
"Once upon a time, there was a",
]
TOP_K = 10
def main() -> None:
torch.manual_seed(0)
import transformers as hf_transformers
device_map = "auto" if torch.cuda.is_available() else "cpu"
print(f"Phi-3.5 longrope forward-pass reference for {MODEL_REPO} (F32, device_map={device_map})")
print(f" torch {torch.__version__}, transformers {hf_transformers.__version__}")
tokenizer = AutoTokenizer.from_pretrained(MODEL_REPO)
model = AutoModelForCausalLM.from_pretrained(
MODEL_REPO, device_map=device_map, dtype=torch.float32
)
model.eval()
input_device = model.get_input_embeddings().weight.device
cfg = model.config
head_dim = getattr(cfg, "head_dim", None) or cfg.hidden_size // cfg.num_attention_heads
re = model.model.rotary_emb
attention_scaling = float(re.attention_scaling)
inv_freq = [float(x) for x in re.inv_freq.flatten().tolist()]
print(f" attention_scaling={attention_scaling}, inv_freq len={len(inv_freq)}")
print(
f" hidden_size={cfg.hidden_size}, num_layers={cfg.num_hidden_layers}, "
f"vocab_size={cfg.vocab_size}, head_dim={head_dim}"
)
results: dict = {
"model_repo": MODEL_REPO,
"methodology": "Phi-3.5 longrope forward-pass oracle (transformers, non-quantized, F32); "
"validates candle-mi longrope RoPE (short + long regimes) against the original checkpoint",
"torch_version": torch.__version__,
"transformers_version": hf_transformers.__version__,
"platform": platform.platform(),
"model_type": cfg.model_type,
"hidden_size": cfg.hidden_size,
"num_layers": cfg.num_hidden_layers,
"vocab_size": cfg.vocab_size,
"head_dim": head_dim,
"rope_theta": getattr(cfg, "rope_theta", None),
"original_max_position_embeddings": getattr(cfg, "original_max_position_embeddings", None),
"attention_scaling": attention_scaling,
"inv_freq": inv_freq,
"test_cases": [],
}
orig_max = getattr(cfg, "original_max_position_embeddings", 4096)
passage = (
"In a distant land beyond the mountains, the seasons turned slowly and "
"the rivers carried stories from one village to the next, year after year. "
)
long_ids = tokenizer(passage * 400, return_tensors="pt").input_ids[0].tolist()
target_len = orig_max + 64 long_ids = long_ids[:target_len]
cases = [(p, None) for p in TEST_PROMPTS] + [("<long-context>", long_ids)]
with torch.no_grad():
for prompt, preset_ids in cases:
if preset_ids is None:
inputs = tokenizer(prompt, return_tensors="pt").to(input_device)
input_ids = inputs.input_ids
else:
input_ids = torch.tensor([preset_ids], device=input_device)
tokens = input_ids[0].tolist()
outputs = model(input_ids=input_ids, use_cache=False, return_dict=True)
last_logits = outputs.logits[0, -1, :].float().cpu()
top_vals, top_idx = last_logits.topk(TOP_K)
regime = "long" if len(tokens) > orig_max else "short"
print(
f" prompt={prompt!r}: {len(tokens)} tokens [{regime}], "
f"top1=({int(top_idx[0])}, {tokenizer.decode([int(top_idx[0])])!r}, {float(top_vals[0]):.4f})"
)
results["test_cases"].append(
{
"prompt": prompt,
"tokens": tokens,
"regime": regime,
"top_10": [
{"index": int(idx), "logit": float(val)}
for idx, val in zip(top_idx, top_vals, strict=False)
],
}
)
out_path = Path(__file__).parent / "phi35_longrope_forward_reference.json"
with open(out_path, "w") as f:
json.dump(results, f, indent=2)
print(f"\nSaved {len(results['test_cases'])} test cases to {out_path}")
if __name__ == "__main__":
main()