Instructions to use FluidInference/gliner2-5-multi-coreml with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- GLiNER2
How to use FluidInference/gliner2-5-multi-coreml with GLiNER2:
from gliner2 import GLiNER2 model = GLiNER2.from_pretrained("FluidInference/gliner2-5-multi-coreml") # Extract entities text = "Apple CEO Tim Cook announced iPhone 15 in Cupertino yesterday." result = extractor.extract_entities(text, ["company", "person", "product", "location"]) print(result) - Notebooks
- Google Colab
- Kaggle
File size: 6,069 Bytes
b172fa5 | 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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | """Compare two GLiNER2 Core ML packages on selected real classification requests."""
from __future__ import annotations
import argparse
import json
import math
import platform
import statistics
import subprocess
import time
from pathlib import Path
import coremltools as ct
import numpy as np
from preprocessing import load_processor, prepare_with_processor
def percentile(values: list[float], p: float) -> float | None:
if not values:
return None
return sorted(values)[max(0, min(len(values) - 1, math.ceil(p * len(values)) - 1))]
def median(cases: list[dict], field: str) -> float | None:
return statistics.median(row[field] for row in cases) if cases else None
def run() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--reference", type=Path, required=True)
parser.add_argument("--candidate", type=Path, required=True)
parser.add_argument("--tokenizer", type=Path, required=True)
parser.add_argument("--manifest", type=Path, required=True)
parser.add_argument("--out", type=Path, required=True)
parser.add_argument("--compute-units", choices=["all", "cpu-ane"], default="all")
parser.add_argument("--length", type=int, default=128)
parser.add_argument("--max-options", type=int, default=8)
parser.add_argument("--limit", type=int, default=None, help="stop after this many eligible requests")
parser.add_argument("--max-probability-error", type=float, default=0.02)
args = parser.parse_args()
units = ct.ComputeUnit.ALL if args.compute_units == "all" else ct.ComputeUnit.CPU_AND_NE
processor = load_processor(str(args.tokenizer))
load_start = time.perf_counter()
reference = ct.models.MLModel(str(args.reference), compute_units=units)
reference_load_ms = (time.perf_counter() - load_start) * 1000
load_start = time.perf_counter()
candidate = ct.models.MLModel(str(args.candidate), compute_units=units)
candidate_load_ms = (time.perf_counter() - load_start) * 1000
rows = [json.loads(line) for line in args.manifest.read_text().splitlines() if line]
prepared = []
skipped = []
for row in rows:
if args.limit is not None and len(prepared) >= args.limit:
break
labels = [(description or key).strip() for key, description in row["options"]]
prepare_start = time.perf_counter()
try:
arrays = prepare_with_processor(processor, row["state"], "decision", labels, args.length, args.max_options)
except ValueError as error:
skipped.append({"suite": row["suite"], "index": row["index"], "reason": str(error)})
continue
prepare_ms = (time.perf_counter() - prepare_start) * 1000
prepared.append((row, labels, arrays, prepare_ms))
if prepared:
for model in (reference, candidate):
model.predict(prepared[0][2])
checked = []
for index, (row, labels, arrays, prepare_ms) in enumerate(prepared):
outputs = {}
order = (("reference", reference), ("candidate", candidate))
if index % 2:
order = tuple(reversed(order))
for name, model in order:
start = time.perf_counter()
probabilities = np.asarray(model.predict(arrays)["probabilities"])[0, : len(labels)]
outputs[name] = (probabilities, (time.perf_counter() - start) * 1000)
expected, reference_ms = outputs["reference"]
actual, candidate_ms = outputs["candidate"]
checked.append({
"suite": row["suite"],
"index": row["index"],
"choice_agrees": int(expected.argmax()) == int(actual.argmax()),
"max_probability_error": float(np.max(np.abs(expected - actual))),
"prepare_ms": prepare_ms,
"reference_ms": reference_ms,
"candidate_ms": candidate_ms,
"reference_total_ms": prepare_ms + reference_ms,
"candidate_total_ms": prepare_ms + candidate_ms,
})
report = {
"reference": str(args.reference),
"candidate": str(args.candidate),
"manifest": str(args.manifest),
"compute_units": args.compute_units,
"processor": platform.processor(),
"machine": platform.machine(),
"macos": platform.mac_ver()[0],
"power_audit_after_run": subprocess.run(["pmset", "-g", "batt"], capture_output=True, text=True).stdout.strip(),
"reference_load_ms": reference_load_ms,
"candidate_load_ms": candidate_load_ms,
"warmup_calls_per_model": 1 if prepared else 0,
"timed_order": "alternating reference-first/candidate-first by request",
"checked": len(checked),
"skipped": skipped,
"choice_agreement": sum(row["choice_agrees"] for row in checked),
"max_probability_error": max((row["max_probability_error"] for row in checked), default=None),
"probability_error_limit": args.max_probability_error,
"reference_p50_ms": median(checked, "reference_ms"),
"candidate_p50_ms": median(checked, "candidate_ms"),
"reference_p95_ms": percentile([row["reference_ms"] for row in checked], 0.95),
"candidate_p95_ms": percentile([row["candidate_ms"] for row in checked], 0.95),
"reference_total_p50_ms": median(checked, "reference_total_ms"),
"candidate_total_p50_ms": median(checked, "candidate_total_ms"),
"cases": checked,
}
args.out.parent.mkdir(parents=True, exist_ok=True)
args.out.write_text(json.dumps(report, indent=2) + "\n")
summary = {key: value for key, value in report.items() if key not in ("cases", "skipped")}
summary["skipped_count"] = len(skipped)
print(json.dumps(summary, indent=2))
if not checked or report["choice_agreement"] != len(checked):
raise SystemExit("candidate changed a checked decision")
if report["max_probability_error"] > args.max_probability_error:
raise SystemExit("candidate exceeded the selected-request probability error limit")
if __name__ == "__main__":
run()
|