File size: 4,240 Bytes
29f25be | 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 | """Prepare V2 resources and native fixtures, leaving existing V1 releases intact."""
import argparse
import shutil
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT / "src"))
import torch
from vimeml.deployment import v2
from vimeml.deployment.bundle import fresh_directory, read_json, write_json
from vimeml.training.data import file_sha
from vimeml.training.evaluate_ime import score_candidates
from vimeml.tools.phrase_demo import PhraseDemo
def package(bundle, source, compiled, template, output):
if output.exists():
raise ValueError("Resource output exists.")
source_manifest = v2.verify_package(source)
if source_manifest["kind"] != "linear8_fp32_compute" or source_manifest["minimum_ios"] != 18:
raise ValueError("Expected V2 INT8 FP32-compute iOS18 experiment.")
if not (compiled / "coremldata.bin").is_file():
raise ValueError("Missing iOS compiled model.")
lm = v2.CoreMLLM(bundle, source)
old = read_json(template)
fixtures = {"format": "vime_client_fixtures_v2", "model": lm.metadata,
"tokenization": [], "scoring": [], "phrases": []}
for item in old["tokenization"]:
ids = lm.processor.encode(item["text"], out_type=int)
fixtures["tokenization"].append({"text": item["text"], "ids": ids,
"decoded": lm.processor.decode(ids)})
for item in old["scoring"]:
scored = score_candidates(lm, item["context"], item["candidates"])
fixtures["scoring"].append({"context": item["context"], "candidates": item["candidates"],
"sums": [candidate["log_probability_sum"] for candidate in scored["candidates"]]})
demo = PhraseDemo(lm, [])
for index, item in enumerate(old["phrases"]):
result = demo.suggest({"prompt": item["prompt"], "mode": "beam", "count": 5, "max_tokens": 8})
first = result["suggestions"][0]
fixtures["phrases"].append({"prompt": item["prompt"], "firstText": first["text"],
"firstIDs": first["new_token_ids"], "firstSum": first["log_probability_sum"]})
print(f"Native phrase fixture {index+1}/{len(old['phrases'])}", flush=True)
fresh_directory(output)
resources = output / "Resources"
resources.mkdir()
shutil.copytree(compiled, resources / "TinyJapaneseV21INT8.mlmodelc")
shutil.copyfile(bundle / "tokenizer.model", resources / "VimeJapaneseTokenizerV2.model")
manifest = {"format": "vime_ios_lm_v2", "architecture": v2.ARCHITECTURE,
"model_version": "2.1-extend5-step40000-int8-b32-v1", "minimum_ios": 18,
"vocab_size": 16384, "context_length": 128, "compute_units": "CPU_ONLY",
"special_ids": lm.special, "tokenizer_sha256": lm.metadata["tokenizer_sha256"],
"compiled_files_sha256": {name: item["sha256"] for name, item in v2.inventory(compiled, hashes=True).items()},
"source_manifest_sha256": lm.metadata["coreml_manifest_sha256"],
"bundle_manifest_sha256": lm.metadata["bundle_manifest_sha256"],
"checkpoint_sha256": lm.metadata["checkpoint_sha256"],
"kind": source_manifest["kind"], "quantization": "weight-only symmetric INT8 block32; FP32 computation",
"strict_fp32_logits_alignment_passed": False,
"quality_review": "Candidate for V2 integration; see VimeML dated quality/device reports. Device acceptance is separate."}
write_json(resources / "VimeLMManifestV21.json", manifest)
write_json(output / "VimeLMFixturesV21.json", fixtures)
write_json(output / "manifest.json", {"format": "vimeml_v2_ios_resources_v1", "model": lm.metadata,
"files": v2.inventory(output), "note": "Resources/ is installed by the Vime client resource installer. No client source snapshot included."})
def main():
parser = argparse.ArgumentParser(description=__doc__)
for name in ("bundle", "source", "compiled", "template", "output"):
parser.add_argument("--" + name, type=Path, required=True)
args = parser.parse_args()
torch.set_num_threads(2)
package(args.bundle, args.source, args.compiled, args.template, args.output)
if __name__ == "__main__":
main()
|