alexwengg's picture
Publish validated LFM2.5-350M-RLCD FP16 Core ML conversion
616b1e2 verified
Raw
History Blame Contribute Delete
2.52 kB
"""Standalone Core ML RLCD inference with the pinned tokenizer and schema contract."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
import coremltools as ct
import numpy as np
from transformers import AutoTokenizer
from preprocessing import Shape, batch_arrays, prepare_candidates, select_values
class RLCDCoreML:
def __init__(self, package: Path, tokenizer_dir: Path, shape: Shape = Shape()):
self.shape = shape
self.tokenizer = AutoTokenizer.from_pretrained(tokenizer_dir)
self.model = ct.models.MLModel(str(package), compute_units=ct.ComputeUnit.ALL)
def constrained(self, context: str, schema: dict) -> dict:
candidates = prepare_candidates(self.tokenizer, context, schema, self.shape)
scores = []
model_calls = 0
for offset in range(0, len(candidates), self.shape.candidates):
group = candidates[offset : offset + self.shape.candidates]
arrays = batch_arrays(self.tokenizer, group, self.shape)
output = self.model.predict(arrays)
scores.extend(np.asarray(output["scores"]).reshape(-1).tolist()[: len(group)])
model_calls += 1
selected = select_values(candidates, scores)
telemetry: dict[str, list[dict]] = {}
for candidate, score in zip(candidates, scores):
telemetry.setdefault(candidate.field, []).append({"value": candidate.value, "log_likelihood": score})
return {
"text": json.dumps(selected, ensure_ascii=False, allow_nan=False),
"scores": telemetry,
"branches": len(candidates),
"model_calls": model_calls,
}
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("package", type=Path)
parser.add_argument("--tokenizer-dir", type=Path, default=Path("."))
parser.add_argument("--length", type=int, default=256)
parser.add_argument("--batch", type=int, default=8)
parser.add_argument("--max-value-tokens", type=int, default=16)
parser.add_argument("--context", required=True)
parser.add_argument("--schema", type=Path, required=True)
args = parser.parse_args()
schema = json.loads(args.schema.read_text())
runtime = RLCDCoreML(args.package, args.tokenizer_dir, Shape(args.length, args.batch, args.max_value_tokens))
print(json.dumps(runtime.constrained(args.context, schema), indent=2, ensure_ascii=False))
if __name__ == "__main__":
main()