| """Convert the pinned trained System One scorer after the Gemma gate is accepted.""" |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import json |
| import time |
| from pathlib import Path |
|
|
| from assets import LOCK, ROOT, check_base_access, sha256 |
| from native_reference import MAX_LENGTH, encode_options, pad_batch |
|
|
|
|
| def main() -> None: |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument("--output-dir", type=Path, default=ROOT / "build") |
| args = parser.parse_args() |
| check_base_access() |
|
|
| import coremltools as ct |
| import numpy as np |
| import torch |
|
|
| from export_model import export_wrapper, load_trained_scorer |
|
|
| torch.set_num_threads(4) |
| tokenizer, native = load_trained_scorer() |
| source = ROOT / "build" / "source" |
| example = json.loads((source / "demos.json").read_text())[0] |
| sequences = encode_options(tokenizer, example["state"], example["question"], example["options"]) |
| |
| sequences = (sequences * 16)[:16] |
| ids, mask = pad_batch(sequences, tokenizer.pad_token_id, MAX_LENGTH) |
| example_tensors = (torch.tensor(ids, dtype=torch.int32), torch.tensor(mask, dtype=torch.int32)) |
| wrapper = export_wrapper(native) |
| with torch.inference_mode(): |
| original = native(input_ids=example_tensors[0].long(), attention_mask=example_tensors[1].long()).logits |
| wrapped = wrapper(*example_tensors) |
| wrapper_error = float((original - wrapped).abs().max()) |
| if wrapper_error > 1e-5: |
| raise ValueError(f"wrapper changed the trained scorer: {wrapper_error}") |
| traced = torch.jit.trace(wrapper, example_tensors) |
|
|
| started = time.perf_counter() |
| coreml = ct.convert( |
| traced, |
| convert_to="mlprogram", |
| minimum_deployment_target=ct.target.iOS17, |
| compute_precision=ct.precision.FLOAT16, |
| compute_units=ct.ComputeUnit.CPU_ONLY, |
| inputs=[ |
| ct.TensorType(name="input_ids", shape=(16, MAX_LENGTH), dtype=np.int32), |
| ct.TensorType(name="attention_mask", shape=(16, MAX_LENGTH), dtype=np.int32), |
| ], |
| outputs=[ct.TensorType(name="logits", dtype=np.float32)], |
| ) |
| coreml.short_description = "Trained System One Gemma scalar scorer; choice temperature 2.35 in host" |
| coreml.author = "Akash Kamat (trained weights); Fluid Inference (Core ML conversion)" |
| coreml.license = "Gemma Terms of Use; trained scorer noncommercial restriction" |
| coreml.user_defined_metadata.update( |
| { |
| "source_repo": LOCK["source_repo"], |
| "source_revision": LOCK["source_revision"], |
| "base_repo": LOCK["base_repo"], |
| "base_revision": LOCK["base_revision"], |
| "trained_adapter_sha256": LOCK["files"]["pretrained-scorer/adapter_model.safetensors"], |
| "output_contract": "16 scalar logits; apply temperature 2.35 and softmax to real candidates in host", |
| } |
| ) |
| args.output_dir.mkdir(parents=True, exist_ok=True) |
| package = args.output_dir / "system_one_gemma_fp16_L256_K16.mlpackage" |
| coreml.save(str(package)) |
| report = { |
| "package": package.name, |
| "source_revision": LOCK["source_revision"], |
| "base_revision": LOCK["base_revision"], |
| "parameters": sum(p.numel() for p in native.parameters()), |
| "trained_score_head_verified": True, |
| "wrapper_max_logit_error": wrapper_error, |
| "conversion_seconds": time.perf_counter() - started, |
| "package_bytes": sum(path.stat().st_size for path in package.rglob("*") if path.is_file()), |
| "package_files_sha256": { |
| str(path.relative_to(package)): sha256(path) for path in package.rglob("*") if path.is_file() |
| }, |
| "parity_verified": False, |
| } |
| (args.output_dir / "conversion.json").write_text(json.dumps(report, indent=2) + "\n") |
| print(json.dumps(report, indent=2)) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|