mlboydaisuke's picture
GLiNER2.5-Decide LiteRT: fp16-weight graphs s128/s256/s512 (+fp32 references), fp16/fp32 embedding tables, host contract, Python runtime, conversion scripts, Android sample, card
d9af00e verified
Raw History Blame Contribute Delete
3.88 kB
"""Round 2 step 3: fp32 export at any contract shape (export_s128.py with the shape as an argument).
Usage: export_shape.py --seq 256 (artifact exports/gliner25_decide_s{N}_fp32.tflite; an existing
artifact is never overwritten). Sample inputs = the first oracle fixture that fits s{N}.
Writes results/opscan_s{N}.json (op histogram, ranks, BATCH_MATMUL shapes, forbidden check) and
results/export_s{N}.json (bytes, sha256, export seconds, op/forbidden summary). The forbidden check
is round 1's `forbidden_check`, imported unchanged.
"""
import argparse
import hashlib
import json
import time
import traceback
import torch
from common import ROOT, dump_json, load_model
from decide_graph import DecideClassifier, Shape, fixed_inputs
from export_s128 import forbidden_check
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--seq", type=int, required=True)
args = parser.parse_args()
seq = args.seq
artifact = ROOT / "exports" / f"gliner25_decide_s{seq}_fp32.tflite"
assert not artifact.exists(), "Never overwrite an exported artifact"
for relative in (f"results/export_s{seq}.json", f"results/opscan_s{seq}.json"):
assert not (ROOT / relative).exists(), f"Refusing to overwrite {relative}"
shape = Shape(seq)
oracle = json.loads((ROOT / "fixtures/oracle_fp32.json").read_text())
sample = next(f for f in oracle["fixtures"] if f["fits"][f"s{seq}"])
model = load_model()
graph = DecideClassifier(model, shape).eval().requires_grad_(False)
captured = torch.load(ROOT / f"fixtures/captured/{sample['id']}.pt", weights_only=False)
inputs = fixed_inputs(model, captured, shape)
entry = {"artifact": str(artifact.relative_to(ROOT)), "sample_fixture": sample["id"],
"contract": shape.contract(), "status": "RUNNING",
"converter": "litert-torch (venv lock) + converter_layout.register_rank4_matmul"}
started = time.perf_counter()
try:
import litert_torch
from converter_layout import register_rank4_matmul
from litert_cpu import scan
register_rank4_matmul()
litert_torch.convert(graph, inputs).export(str(artifact))
elapsed = time.perf_counter() - started
digest = hashlib.sha256(artifact.read_bytes()).hexdigest()
opscan = scan(artifact)
opscan.update(forbidden_check(artifact))
dump_json(f"results/opscan_s{seq}.json", opscan)
shapes = {}
for item in opscan["batch_matmuls"]:
key = " x ".join(str(s) for s in item["input_shapes"])
shapes[key] = shapes.get(key, 0) + 1
entry.update(status="PASS", bytes=artifact.stat().st_size, sha256=digest, export_seconds=elapsed,
operator_count=opscan["operator_count"], op_histogram=opscan["op_histogram"],
max_tensor_rank=opscan["max_tensor_rank"], tensor_dtype_histogram=opscan["tensor_dtype_histogram"],
all_batch_matmul_inputs_rank4=opscan["all_batch_matmul_inputs_rank4"],
batch_matmul_input_shapes=shapes, forbidden_checked=opscan["checked"],
forbidden_count=opscan["forbidden_count"], forbidden_found=opscan["forbidden_found"],
signatures=opscan["signatures"], opscan=f"results/opscan_s{seq}.json")
dump_json(f"results/export_s{seq}.json", entry)
print(json.dumps({k: v for k, v in entry.items() if k not in ("contract", "signatures")}, indent=1), flush=True)
except BaseException:
log = ROOT / f"logs/export_{artifact.stem}.traceback.txt"
log.write_text(traceback.format_exc())
entry.update(status="FAIL", export_seconds=time.perf_counter() - started, traceback=str(log.relative_to(ROOT)))
dump_json(f"results/export_attempt_{artifact.stem}.json", entry)
raise
if __name__ == "__main__":
main()