alexwengg commited on
Commit
d00480b
·
verified ·
1 Parent(s): 8775a37

Add verified Jeff W8 classification size option

Browse files
JeffDecision-L128-W8.mlpackage/Data/com.apple.CoreML/model.mlmodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7f6c1c290d3723229bf5e6c22f9fa9db187957f33ed72b3063ebbf88c8073e6f
3
+ size 443616
JeffDecision-L128-W8.mlpackage/Data/com.apple.CoreML/weights/weight.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:10bd21357d7313872abd964923b2483c817dddc66e0ea667d10c262dcc834aae
3
+ size 487930560
JeffDecision-L128-W8.mlpackage/Manifest.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "fileFormatVersion": "1.0.0",
3
+ "itemInfoEntries": {
4
+ "415259F0-F9D2-4CC8-9488-BF11BF376148": {
5
+ "author": "com.apple.CoreML",
6
+ "description": "CoreML Model Weights",
7
+ "name": "weights",
8
+ "path": "com.apple.CoreML/weights"
9
+ },
10
+ "41CD2FD7-844B-4EEC-A662-26FFDB616B0A": {
11
+ "author": "com.apple.CoreML",
12
+ "description": "CoreML Model Specification",
13
+ "name": "model.mlmodel",
14
+ "path": "com.apple.CoreML/model.mlmodel"
15
+ }
16
+ },
17
+ "rootModelIdentifier": "41CD2FD7-844B-4EEC-A662-26FFDB616B0A"
18
+ }
README.md CHANGED
@@ -41,4 +41,8 @@ PY
41
 
42
  Four real source-checkpoint fixtures cover billing, technical support, a three-label intent choice and yes/no classification. The mathematical decision wrapper matched native logits within **3.82e-6**. Tracing-only patches matched native logits exactly on those fixtures. The exported FP16 Core ML model preserved all four chosen labels with maximum absolute logit error **0.1139**. FP32 Core ML is a diagnostic control with four-of-four agreement and maximum logit error **3.44e-5**; the FP32 package is not included because it is much larger. Full Decision Index quality, additional input lengths, other task heads and broad latency/ANE performance have not been evaluated. See `native-parity.json` and `coreml-parity-fp16.json`.
43
 
 
 
 
 
44
  This conversion is derived from the Apache-2.0 GLiFormer weights and [Transformers](https://github.com/huggingface/transformers) DeBERTa implementation. Jeff's decision adapter code is MIT licensed; the helper source here retains attribution. The model card makes no claim that this conversion is faster or more accurate than another model on a benchmark.
 
41
 
42
  Four real source-checkpoint fixtures cover billing, technical support, a three-label intent choice and yes/no classification. The mathematical decision wrapper matched native logits within **3.82e-6**. Tracing-only patches matched native logits exactly on those fixtures. The exported FP16 Core ML model preserved all four chosen labels with maximum absolute logit error **0.1139**. FP32 Core ML is a diagnostic control with four-of-four agreement and maximum logit error **3.44e-5**; the FP32 package is not included because it is much larger. Full Decision Index quality, additional input lengths, other task heads and broad latency/ANE performance have not been evaluated. See `native-parity.json` and `coreml-parity-fp16.json`.
43
 
44
+ An optional `JeffDecision-L128-W8.mlpackage` compresses the FP16 package's trained embedding and linear constants using per-channel symmetric int8. Its 488,374,793-byte package (versus 922,812,014 bytes FP16) retained the chosen label on all four source-checkpoint fixtures with maximum absolute logit error **0.129469**, below the predeclared 0.25 gate. Choose it by passing that package path to `JeffCoreML`. On a small battery-powered Apple M5 Pro probe, W8 had no demonstrated full-request speed advantage: All-compute p50 was 10.07 ms for W8 and 10.12 ms for FP16, with an outlier in W8's eight-call p95. Forcing CPU plus Neural Engine was about 19 ms for both. This is a size option with four-fixture validation, not a broad quality benchmark. Exact artifact hashes are in `reports/w8-validation.json`; see `tools/decision-coreml-profile/RESULTS.md` in the repository for timing scope and placement details.
45
+
46
+ When using `huggingface_hub.snapshot_download`, pass `local_dir="./jeff-coreml"` and point `JeffCoreML` there. Core ML compilation on the tested macOS release rejected a symlinked Hub-cache weight file; a materialized local directory avoids that path issue.
47
+
48
  This conversion is derived from the Apache-2.0 GLiFormer weights and [Transformers](https://github.com/huggingface/transformers) DeBERTa implementation. Jeff's decision adapter code is MIT licensed; the helper source here retains attribution. The model card makes no claim that this conversion is faster or more accurate than another model on a benchmark.
publish.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Publish the locally validated Jeff Core ML artifact to its own HF repo."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import json
7
+ import shutil
8
+ from pathlib import Path
9
+
10
+ from huggingface_hub import HfApi, snapshot_download
11
+
12
+ from export import REVISION, SOURCE
13
+
14
+ REPO_ID = "FluidInference/jeff-coreml"
15
+ W8_PACKAGE = "JeffDecision-L128-W8.mlpackage"
16
+ REQUIRED = (
17
+ "README.md",
18
+ "LICENSE",
19
+ "assets.lock.json",
20
+ "jeff_decision.py",
21
+ "trace_compat.py",
22
+ "export.py",
23
+ "verify.py",
24
+ "runtime.py",
25
+ "quantize.py",
26
+ "probe-native.py",
27
+ "pyproject.toml",
28
+ "uv.lock",
29
+ )
30
+ TOKENIZER = ("gliner_config.json", "tokenizer.json", "tokenizer_config.json")
31
+
32
+
33
+ def package_file_hashes(package: Path) -> dict[str, str]:
34
+ hashes = {}
35
+ for file in sorted(package.rglob("*")):
36
+ if not file.is_file():
37
+ continue
38
+ sha = hashlib.sha256()
39
+ with file.open("rb") as stream:
40
+ for block in iter(lambda: stream.read(1024 * 1024), b""):
41
+ sha.update(block)
42
+ hashes[file.relative_to(package).as_posix()] = sha.hexdigest()
43
+ return hashes
44
+
45
+
46
+ def validate_w8_report(report: dict) -> None:
47
+ if report.get("source_revision") != REVISION or report.get("package") != W8_PACKAGE:
48
+ raise ValueError("W8 report does not identify the pinned checkpoint and package")
49
+ if report.get("native_fixture_count") != 4 or report.get("native_choice_agreement") != 4:
50
+ raise ValueError("W8 report does not preserve all four native decisions")
51
+ if report.get("max_logit_error", float("inf")) > 0.25:
52
+ raise ValueError("W8 report exceeds the 0.25 logit-error gate")
53
+ if len(report.get("package_files_sha256", {})) != 3:
54
+ raise ValueError("W8 report lacks the complete package file hashes")
55
+
56
+
57
+ def stage() -> Path:
58
+ source = Path(snapshot_download(SOURCE, revision=REVISION, local_files_only=True))
59
+ root = Path(__file__).parent
60
+ stage_dir = root / "build" / "hub-stage"
61
+ if stage_dir.exists():
62
+ shutil.rmtree(stage_dir)
63
+ stage_dir.mkdir(parents=True)
64
+ for name in REQUIRED:
65
+ shutil.copy2(root / name, stage_dir / name)
66
+ for name in TOKENIZER:
67
+ shutil.copy2(source / name, stage_dir / name)
68
+ shutil.copy2(root / "build/native-parity.json", stage_dir / "native-parity.json")
69
+ shutil.copy2(root / "build/coreml-parity-fp16.json", stage_dir / "coreml-parity-fp16.json")
70
+ shutil.copytree(root / "reports", stage_dir / "reports")
71
+ package = root / "build/JeffDecision-L128-FP16.mlpackage"
72
+ shutil.copytree(package, stage_dir / package.name)
73
+ w8_package = root / "build" / W8_PACKAGE
74
+ report = json.loads((root / "reports/w8-validation.json").read_text())
75
+ validate_w8_report(report)
76
+ if package_file_hashes(w8_package) != report["package_files_sha256"]:
77
+ raise ValueError("W8 package does not match the verified release report")
78
+ shutil.copytree(w8_package, stage_dir / W8_PACKAGE)
79
+ return stage_dir
80
+
81
+
82
+ def main() -> None:
83
+ native = json.loads(Path("build/native-parity.json").read_text())
84
+ coreml = json.loads(Path("build/coreml-parity-fp16.json").read_text())
85
+ if len(native) != 4 or len(coreml) != 4 or not all(row["top_label_agreement"] for row in coreml):
86
+ raise RuntimeError("the four-case trained-model/Core ML parity evidence is incomplete")
87
+ if max(row["max_logit_error"] for row in coreml) > 0.25:
88
+ raise RuntimeError("Core ML parity exceeds the published tolerance")
89
+ stage_dir = stage()
90
+ api = HfApi()
91
+ api.create_repo(REPO_ID, repo_type="model", private=False, exist_ok=True)
92
+ result = api.upload_folder(
93
+ repo_id=REPO_ID,
94
+ repo_type="model",
95
+ folder_path=str(stage_dir),
96
+ commit_message="Publish validated Jeff GLiFormer Large L128 FP16 Core ML classifier",
97
+ )
98
+ print(result, flush=True)
99
+ print(json.dumps(api.list_repo_files(REPO_ID), indent=2), flush=True)
100
+
101
+
102
+ if __name__ == "__main__":
103
+ main()
quantize.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Create targeted int8 Jeff Core ML variants without modifying the FP16 source."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ from pathlib import Path
8
+
9
+ import coremltools as ct
10
+ import coremltools.optimize.coreml as cto
11
+
12
+
13
+ def package_bytes(path: Path) -> int:
14
+ return sum(file.stat().st_size for file in path.rglob("*") if file.is_file())
15
+
16
+
17
+ def selected_constants(model, scheme: str) -> list[str]:
18
+ metadata = cto.get_weights_metadata(model, weight_threshold=2048)
19
+ selected = []
20
+ for name, weight in metadata.items():
21
+ if not weight.child_ops:
22
+ continue
23
+ consumer = weight.child_ops[0].op_type
24
+ embedding = consumer == "gather" and len(weight.val.shape) == 2
25
+ linear = consumer == "linear" and len(weight.val.shape) == 2
26
+ if (scheme == "e8" and embedding) or (scheme == "w8" and (embedding or linear)):
27
+ selected.append(name)
28
+ if not selected:
29
+ raise ValueError(f"no eligible constants found for {scheme}")
30
+ return selected
31
+
32
+
33
+ def main() -> None:
34
+ parser = argparse.ArgumentParser(description=__doc__)
35
+ parser.add_argument("--source", type=Path, default=Path("build/JeffDecision-L128-FP16.mlpackage"))
36
+ parser.add_argument("--scheme", choices=("e8", "w8"), required=True)
37
+ parser.add_argument("--output", type=Path)
38
+ args = parser.parse_args()
39
+ output = args.output or Path(f"build/JeffDecision-L128-{args.scheme.upper()}.mlpackage")
40
+ if output.exists():
41
+ parser.error(f"output already exists: {output}")
42
+ model = ct.models.MLModel(str(args.source), compute_units=ct.ComputeUnit.CPU_ONLY)
43
+ names = selected_constants(model, args.scheme)
44
+ config = cto.OpLinearQuantizerConfig(mode="linear_symmetric", dtype="int8", granularity="per_channel")
45
+ compressed = cto.linear_quantize_weights(
46
+ model, cto.OptimizationConfig(op_name_configs={name: config for name in names})
47
+ )
48
+ compressed.user_defined_metadata["precision"] = args.scheme
49
+ compressed.save(str(output))
50
+ report = {
51
+ "source": str(args.source.resolve()),
52
+ "source_bytes": package_bytes(args.source),
53
+ "output": str(output.resolve()),
54
+ "output_bytes": package_bytes(output),
55
+ "compressed_constants": len(names),
56
+ "scheme": args.scheme,
57
+ }
58
+ Path(f"build/quantize-{args.scheme}.json").write_text(json.dumps(report, indent=2) + "\n")
59
+ print(json.dumps(report, indent=2), flush=True)
60
+
61
+
62
+ if __name__ == "__main__":
63
+ main()
reports/w8-native.json ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "name": "billing",
4
+ "labels": [
5
+ "billing: invoice or payment issue",
6
+ "support: technical product issue"
7
+ ],
8
+ "native_logits": [
9
+ 10.187458038330078,
10
+ -6.71131706237793
11
+ ],
12
+ "coreml_logits": [
13
+ 10.1640625,
14
+ -6.76953125
15
+ ],
16
+ "max_logit_error": 0.05821418762207031,
17
+ "top_label_agreement": true,
18
+ "coreml_wall_ms": 591.8338329647668
19
+ },
20
+ {
21
+ "name": "technical",
22
+ "labels": [
23
+ "billing: invoice or payment issue",
24
+ "support: technical product issue"
25
+ ],
26
+ "native_logits": [
27
+ -12.322779655456543,
28
+ 13.379047393798828
29
+ ],
30
+ "coreml_logits": [
31
+ -12.34375,
32
+ 13.3125
33
+ ],
34
+ "max_logit_error": 0.06654739379882812,
35
+ "top_label_agreement": true,
36
+ "coreml_wall_ms": 18.682791967876256
37
+ },
38
+ {
39
+ "name": "three_way",
40
+ "labels": [
41
+ "schedule: appointment request",
42
+ "billing: payment issue",
43
+ "support: technical issue"
44
+ ],
45
+ "native_logits": [
46
+ 5.41853141784668,
47
+ -12.076669692993164,
48
+ -9.080745697021484
49
+ ],
50
+ "coreml_logits": [
51
+ 5.2890625,
52
+ -12.0,
53
+ -9.0234375
54
+ ],
55
+ "max_logit_error": 0.1294689178466797,
56
+ "top_label_agreement": true,
57
+ "coreml_wall_ms": 18.921707989647985
58
+ },
59
+ {
60
+ "name": "boolean",
61
+ "labels": [
62
+ "yes",
63
+ "no"
64
+ ],
65
+ "native_logits": [
66
+ 1.0098832845687866,
67
+ -1.0589547157287598
68
+ ],
69
+ "coreml_logits": [
70
+ 1.0498046875,
71
+ -1.123046875
72
+ ],
73
+ "max_logit_error": 0.06409215927124023,
74
+ "top_label_agreement": true,
75
+ "coreml_wall_ms": 9.147749980911613
76
+ }
77
+ ]
reports/w8-validation.json ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "source_revision": "d0a4e53d09cebe6bc963dd9be319d4279084bb2d",
3
+ "package": "JeffDecision-L128-W8.mlpackage",
4
+ "package_bytes": 488374793,
5
+ "fp16_package_bytes": 922812014,
6
+ "package_files_sha256": {
7
+ "Data/com.apple.CoreML/model.mlmodel": "7f6c1c290d3723229bf5e6c22f9fa9db187957f33ed72b3063ebbf88c8073e6f",
8
+ "Data/com.apple.CoreML/weights/weight.bin": "10bd21357d7313872abd964923b2483c817dddc66e0ea667d10c262dcc834aae",
9
+ "Manifest.json": "1744498652aebc3ab6068de32aefcf32bc46c4ab1faaba1bdd1a479c8ed94049"
10
+ },
11
+ "compressed_constants": 146,
12
+ "native_fixture_count": 4,
13
+ "native_choice_agreement": 4,
14
+ "max_logit_error": 0.1294689178466797,
15
+ "release_logit_error_gate": 0.25,
16
+ "automatic_full_request_p50_ms": 10.0669375,
17
+ "fp16_automatic_full_request_p50_ms": 10.119333,
18
+ "forced_cpu_ane_full_request_p50_ms": 19.097396,
19
+ "timing_scope": "exploratory local battery-powered real-request smoke test",
20
+ "scope": "Optional W8 size artifact verified on four native classification fixtures; no Decision Index or 2048 claim and no measured speed advantage."
21
+ }