Download finalize_bundle.py from maxffarrell/d3-lite-CoreAI: direct link, hf CLI and curl.
- Browser
- Download file 7.41 kB
-
https://huggingface.co/maxffarrell/d3-lite-CoreAI/resolve/main/finalize_bundle.py
- Command line
-
hf download hf://maxffarrell/d3-lite-CoreAI/finalize_bundle.py
-
curl -L -o finalize_bundle.py https://huggingface.co/maxffarrell/d3-lite-CoreAI/resolve/main/finalize_bundle.py
7.41 kB
| """Write the published model card and checksums only after completed validation.""" | |
| import argparse | |
| import hashlib | |
| import json | |
| import shutil | |
| from pathlib import Path | |
| p = argparse.ArgumentParser() | |
| p.add_argument("name") | |
| a = p.parse_args() | |
| b = Path("bundles") / (a.name + "-CoreAI") | |
| m = json.loads((b / "manifest.json").read_text()) | |
| rows = json.loads((b / "validation.json").read_text()) | |
| if len(rows) != 10 or any(r["coreai_choice"] != r["upstream_choice"] for r in rows): | |
| raise ValueError("Incomplete or mismatching smoke suite") | |
| for name in ["validate.py", "text.aimodel"]: | |
| f = b / name | |
| if f.is_dir(): | |
| shutil.rmtree(f) | |
| elif f.exists(): | |
| f.unlink() | |
| max_error = max(r["max_probability_error"] for r in rows) | |
| m.update( | |
| experimental=True, | |
| validation={ | |
| "selected_answer_matches": len(rows), | |
| "cases": len(rows), | |
| "max_probability_error": max_error, | |
| "strict_probability_parity": max_error <= 0.02, | |
| }, | |
| platform={ | |
| "os": "macOS 27.0.1", | |
| "runtime": "coreai-core 1.0.0b3", | |
| "specialization": "default", | |
| "accelerator_placement_verified": False, | |
| }, | |
| ) | |
| (b / "manifest.json").write_text(json.dumps(m, indent=2) + "\n") | |
| summary = "\n".join( | |
| f"| {r['modality']} / {r['type']} | {r['tokens']} | {r['options']} | Yes | {r['max_probability_error']:.6f} |" | |
| for r in rows | |
| ) | |
| card = f"""--- | |
| license: apache-2.0 | |
| base_model: {m["source"]} | |
| pipeline_tag: zero-shot-classification | |
| tags: | |
| - coreai | |
| - apple | |
| - decision-model | |
| - multimodal | |
| - experimental | |
| - vision | |
| - video | |
| --- | |
| # {a.name} — experimental Apple Core AI conversion | |
| Community conversion of [{m["source"]}](https://huggingface.co/{m["source"]}) at revision `{m["revision"]}`. Converted by Max Farrell. This is an Apple **Core AI `.aimodel`** bundle for macOS 27, with its text backbone, original 255-way answer readout, and vision encoder. Choice, yes/no (noul), and score questions run through Core AI; tokenization, media decoding, and result formatting run on the host. No text is generated. | |
| **Experimental, with measured numerical drift.** All 10 smoke cases selected the same answer as the official BF16 PyTorch runtime on identical resized inputs. The largest absolute probability difference was **{max_error:.6f}**. These are small conversion smoke tests, not a quality benchmark, calibration result, or evidence of equivalence on arbitrary inputs. Fixed-capacity padding and Core AI's BF16 execution can change probabilities and may change decisions on other inputs. The initial 0.02 probability-parity target was not met by every model; the full values are reported rather than claimed as strict numerical parity. | |
| ## Capacity and changes from upstream | |
| - One question per forward pass; `system_one` processes several questions sequentially. | |
| - **512 combined tokens**, including visual tokens and all prompt text. Oversized requests raise an error; nothing is truncated. | |
| - Images and sampled video frames are resized to **224×224**, including aspect-ratio changes. Each image or two-frame video patch group occupies 49 visual tokens. This is much smaller than upstream's default image/video resolution. | |
| - Multiple images/videos work only when their complete prompt fits. Video decoding retains upstream's 2-fps sampling, at least 4 and at most 32 frames; long sampled clips may exceed the 512-token limit and are rejected. | |
| - Up to 255 answer codes are retained; the prompt capacity generally limits practical option count well before 255. | |
| - The original **BF16 backbone weights** and **FP32 decision head** are retained. Linear attention stays causal; full attention remains noncausal as upstream specifies. | |
| - Default specialization was tested on this Mac. Forced CPU-only specialization crashed inside Apple's compiler during development. **No verified Neural Engine/GPU placement, iPhone compatibility, speedup, or power-efficiency claim.** | |
| ## Use | |
| ```bash | |
| hf download maxffarrell/{a.name}-CoreAI --local-dir {a.name}-CoreAI | |
| cd {a.name}-CoreAI | |
| python -m venv .venv | |
| source .venv/bin/activate | |
| pip install -r requirements.txt | |
| ``` | |
| ```python | |
| import asyncio | |
| from coreai_d3 import D3CoreAI | |
| async def main(): | |
| model = await D3CoreAI.load(".") | |
| result = await model.system_one( | |
| state="The customer was charged twice.", | |
| questions={{"route": {{ | |
| "type": "choice", | |
| "instructions": "Which team should handle this?", | |
| "criteria": {{"billing": "Payments", "shipping": "Delivery"}} | |
| }}}}, | |
| # images=["receipt.png"], | |
| # videos=["clip.mp4"], | |
| ) | |
| print(result) | |
| asyncio.run(main()) | |
| ``` | |
| All neural inference in this adapter uses `decision.aimodel` and `vision.aimodel`. PyTorch/Transformers are dependencies for conversion and host preprocessing; source PyTorch weights are not included or needed for inference. Core AI may write a local specialization cache on first load. The adapter uses the upstream prompt formatter and typed response shapes. | |
| ## Validation | |
| macOS 27.0.1, `coreai-core==1.0.0b3`, default specialization. The BF16 reference uses Transformers 5.17.0 and the pinned upstream checkpoint. Images and video are compared using the same 224×224 input pixels, not against upstream's original full-resolution run. Text includes choice, noul, score, Spanish, 10 options, and a 433-token case. Additional checks cover one image, two images, video, and rejecting oversized text. End-to-end `system_one` is separately smoke-tested without loading source weights. | |
| | Case | Tokens | Options | Selected answer matches | Max probability difference | | |
| | --- | ---: | ---: | --- | ---: | | |
| {summary} | |
| See `validation.json` for per-case records. Its elapsed times include reference work and are **not inference benchmarks**. | |
| ## Reproduce | |
| Download the exact source revision, convert, and reassemble into a fresh output directory: | |
| ```bash | |
| hf download {m["source"]} --revision {m["revision"]} --local-dir upstream/{a.name} | |
| python convert.py --source upstream/{a.name} --output bundles/{a.name}-CoreAI --length 512 --precision bfloat16 | |
| python package.py {a.name} | |
| python validate_mm.py {a.name} | |
| ``` | |
| `coreai-torch==0.4.3` warns that PyTorch 2.14.0 is newer than its validated range; the supplied environment is the version used for these exports and smoke tests. `UPSTREAM_MANIFEST.json` describes original source files; `SHA256SUMS` verifies this converted bundle. | |
| ## Attribution and license | |
| Original model: vLLM Semantic Router Team, based on the Qwen model identified in `UPSTREAM_NOTICE`. Original model and this conversion are Apache-2.0; see `LICENSE` and `NOTICE`. The prompt contract and host decision formatting/media loader are included from the pinned upstream source. The upstream runtime contains an Apache-2.0 noncausal attention hook adapted from Perplexity AI and retains its original attribution. This is an independent community conversion, not an official Apple or vLLM release. | |
| """ | |
| (b / "README.md").write_text(card) | |
| lines = [] | |
| for f in sorted(b.rglob("*")): | |
| if not f.is_file() or f.name == "SHA256SUMS" or "__pycache__" in f.parts: | |
| continue | |
| h = hashlib.sha256() | |
| with f.open("rb") as s: | |
| for block in iter(lambda: s.read(8 * 1024 * 1024), b""): | |
| h.update(block) | |
| lines.append(h.hexdigest() + " " + str(f.relative_to(b))) | |
| (b / "SHA256SUMS").write_text("\n".join(lines) + "\n") | |
| print(a.name, len(lines), "files", max_error) | |