File size: 3,031 Bytes
000c57b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/usr/bin/env python3
"""
scripts/run_onnx_edge.py

Standalone Edge Embedded Deployment Runner for Q-TensorFormer.
Executes token generation via ONNX Runtime with zero PyTorch runtime dependency:
- Runs dynamic batch and sequence axes on edge CPUs/SoCs (ARM Cortex, Jetson, Raspberry Pi).
- Profiles Inter-Token Latency (ITL) and memory footprints.
"""

import sys
import time
from pathlib import Path
import numpy as np

ROOT_DIR = Path(__file__).resolve().parent.parent
if str(ROOT_DIR) not in sys.path:
    sys.path.insert(0, str(ROOT_DIR))

try:
    import onnxruntime as ort
    HAS_ORT = True
except ImportError:
    HAS_ORT = False

from src.tokenizer import QTensorFormerTokenizer


def run_onnx_inference(onnx_model_path: Path, max_new_tokens: int = 16):
    print("=" * 70)
    print("Q-TensorFormer: Standalone Edge ONNX Runtime Deployment")
    print(f"Target Model: {onnx_model_path}")
    print("=" * 70)

    if not HAS_ORT:
        print("[Error] onnxruntime is not installed. Run: pip install onnxruntime")
        return

    tokenizer = QTensorFormerTokenizer(vocab_size=256)
    prompt = "Edge computing requires adaptive computation"
    token_ids = tokenizer.encode(prompt, add_bos=True)
    print(f"Input Prompt: '{prompt}' ({len(token_ids)} tokens)")

    # Initialize ONNX Runtime Session with optimization
    opts = ort.SessionOptions()
    opts.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
    opts.intra_op_num_threads = 4

    session = ort.InferenceSession(str(onnx_model_path), sess_options=opts, providers=["CPUExecutionProvider"])
    input_name = session.get_inputs()[0].name
    output_name = session.get_outputs()[0].name

    print("\n[+] Starting Autoregressive Generation on Edge ONNX Engine...")
    curr_ids = list(token_ids)
    latencies = []

    for step in range(max_new_tokens):
        t0 = time.perf_counter()
        inp = np.array([curr_ids], dtype=np.int64)
        outputs = session.run([output_name], {input_name: inp})
        logits = outputs[0]  # [1, seq_len, vocab_size]
        next_token = int(np.argmax(logits[0, -1, :]))
        curr_ids.append(next_token)
        lat = (time.perf_counter() - t0) * 1000.0
        latencies.append(lat)

    gen_ids = curr_ids[len(token_ids):]
    generated_text = tokenizer.decode(gen_ids)

    print(f"\n[Generated Output]: {generated_text}")
    print(f"Mean Per-Token Latency: {np.mean(latencies):.2f} ms")
    print(f"P99 Per-Token Latency:  {np.percentile(latencies, 99):.2f} ms")
    print(f"Edge Token Throughput:  {1000.0 / np.mean(latencies):.2f} tokens/second")
    print("=" * 70)


def main():
    onnx_file = ROOT_DIR / "qtensorformer.onnx"
    if not onnx_file.exists():
        print(f"[*] ONNX model not found at {onnx_file}. Triggering automated export...")
        from export_onnx import export_to_onnx
        export_to_onnx(model_path=str(ROOT_DIR), output_path=str(onnx_file), verify=False)

    run_onnx_inference(onnx_file, max_new_tokens=12)


if __name__ == "__main__":
    main()