Download export/_llm.py from executorch-community/Llama-3.2-1B-Instruct-ExecuTorch-WebGPU: direct link, hf CLI and curl.
- Browser
- Download file 6.04 kB
-
https://huggingface.co/executorch-community/Llama-3.2-1B-Instruct-ExecuTorch-WebGPU/resolve/main/export/_llm.py
- Command line
-
hf download hf://executorch-community/Llama-3.2-1B-Instruct-ExecuTorch-WebGPU/export/_llm.py
-
curl -L -o _llm.py https://huggingface.co/executorch-community/Llama-3.2-1B-Instruct-ExecuTorch-WebGPU/resolve/main/export/_llm.py
6.04 kB
| """Shared export path for the Qwen LLM recipes: pinned HF snapshot -> ExecuTorch checkpoint | |
| -> export_llm (Vulkan partitioner, which WebGPUPartitioner wraps unchanged) -> .pte. | |
| Graph contract (matches the internal WebGPU LLM artifacts): forward(tokens[1, <=prefill_max] | |
| int64, input_pos[1] int64) -> logits[1, vocab] float32 for the last position, KV cache inside the | |
| program (fp32 buffers, max_context_length positions), 4-bit groupwise weight-only linears | |
| (et_vk.linear_q4gsw) and 4-bit groupwise embedding (et_vk.embedding_q4gsw). | |
| """ | |
| import importlib | |
| import json | |
| import os | |
| import shlex | |
| import shutil | |
| import subprocess | |
| import sys | |
| from pathlib import Path | |
| import _common | |
| SHIMS = Path(__file__).resolve().parent / "_shims" | |
| TOKENIZER_FILES = [ | |
| "tokenizer.json", | |
| "tokenizer_config.json", | |
| "vocab.json", | |
| "merges.txt", | |
| "generation_config.json", | |
| "config.json", | |
| "LICENSE", | |
| ] | |
| def export( | |
| *, name, upstream_repo, revision, model_class, params, converter, max_context, args | |
| ): | |
| from huggingface_hub import snapshot_download | |
| out = Path(args.out).resolve() | |
| work = out / "_work" | |
| work.mkdir(parents=True, exist_ok=True) | |
| snap = Path( | |
| snapshot_download( | |
| upstream_repo, | |
| revision=revision, | |
| allow_patterns=["*.safetensors", "*.json", "merges.txt", "LICENSE"], | |
| ) | |
| ) | |
| sys.path.insert(0, str(SHIMS)) | |
| env = {**os.environ, "PYTHONPATH": os.pathsep.join(filter(None, [str(SHIMS), os.environ.get("PYTHONPATH")]))} | |
| ckpt = work / "checkpoint.pth" | |
| if not ckpt.exists(): | |
| importlib.import_module(converter).convert_weights(str(snap), str(ckpt)) | |
| params_path = work / "params.json" | |
| params_path.write_text(json.dumps(params, indent=2) + "\n") | |
| output_name = f"{name}.pte" | |
| overrides = [ | |
| f"base.model_class={model_class}", | |
| f"base.checkpoint={ckpt}", | |
| f"base.params={params_path}", | |
| "model.use_kv_cache=true", | |
| "model.use_sdpa_with_kv_cache=true", | |
| "model.enable_dynamic_shape=true", | |
| "model.dtype_override=fp32", | |
| f"export.max_seq_length={args.prefill_max + 1}", | |
| f"export.max_context_length={max_context}", | |
| f"export.output_dir={out}", | |
| f"export.output_name={out / output_name}", | |
| "quantization.qmode=4w", | |
| f"quantization.group_size={args.group_size}", | |
| f"quantization.embedding_quantize='4,{args.group_size}'", | |
| "backend.vulkan.enabled=true", | |
| ] | |
| cmd = [ | |
| sys.executable, | |
| "-m", | |
| "executorch.extension.llm.export.export_llm", | |
| *overrides, | |
| ] | |
| print("+", " ".join(shlex.quote(c) for c in cmd), flush=True) | |
| subprocess.run(cmd, check=True, env=env) | |
| pte = out / output_name | |
| tok_dir = out / "tokenizer" | |
| tok_dir.mkdir(exist_ok=True) | |
| tokenizer_files = {} | |
| for f in TOKENIZER_FILES: | |
| if (snap / f).exists(): | |
| shutil.copyfile(snap / f, tok_dir / f) | |
| tokenizer_files[f] = _common.sha256_file(tok_dir / f) | |
| shutil.rmtree(work) | |
| data = pte.read_bytes() | |
| recipe = { | |
| "model": name, | |
| "upstream": { | |
| "model": upstream_repo, | |
| "revision": revision, | |
| "official": True, | |
| "safetensors_sha256": { | |
| p.name: _common.sha256_file(p) | |
| for p in sorted(snap.glob("*.safetensors")) | |
| }, | |
| }, | |
| "versions": _common.versions(), | |
| "export": { | |
| "api": "python -m executorch.extension.llm.export.export_llm (hydra overrides below)", | |
| "overrides": [_common.scrub(o, out).replace(str(work.resolve()), "<work>") for o in overrides], | |
| "checkpoint_conversion": f"{converter}.convert_weights(<snapshot>, checkpoint.pth)", | |
| "import_shim": "recipes/_shims/torchtune (re-exports executorch.examples.models.checkpoint.get_mapped_key; torchtune itself is not installed)", | |
| "params": params, | |
| "partitioner": "VulkanPartitioner via backend.vulkan.enabled (WebGPUPartitioner is a pass-through wrapper of it; delegate id VulkanBackend)", | |
| "inputs": [ | |
| { | |
| "name": "tokens", | |
| "shape": [1, f"1..{args.prefill_max}"], | |
| "dtype": "int64", | |
| }, | |
| {"name": "input_pos", "shape": [1], "dtype": "int64"}, | |
| ], | |
| "outputs": [ | |
| { | |
| "name": "logits", | |
| "shape": [1, params["vocab_size"]], | |
| "dtype": "float32", | |
| "note": "last position only", | |
| } | |
| ], | |
| "prefill_max": args.prefill_max, | |
| "max_seq_len_metadata": args.prefill_max + 1, | |
| "max_context_length": max_context, | |
| "dtype": "float32 activations", | |
| "quantization": f"4-bit groupwise weight-only linears (torchao IntxWeightOnlyConfig int4, group {args.group_size}) and 4-bit groupwise embedding (group {args.group_size}); output head quantized too", | |
| "kv_cache": "fp32 buffers in the program; fp16 KV is a runtime option of the WebGPU runtime (et_set_kv_f16), not an export flag", | |
| }, | |
| "files": { | |
| pte.name: {"bytes": len(data), "sha256": _common.sha256_file(pte)}, | |
| **{f"tokenizer/{k}": {"sha256": v} for k, v in tokenizer_files.items()}, | |
| }, | |
| "graph": _common.delegate_summary(data), | |
| "command": _common.command_line(out), | |
| } | |
| (out / "recipe.json").write_text(json.dumps(recipe, indent=2) + "\n") | |
| print(json.dumps({"files": recipe["files"], "graph": recipe["graph"]}, indent=2)) | |
| def add_args(ap, max_context): | |
| ap.add_argument("--out", required=True, help="output directory") | |
| ap.add_argument( | |
| "--prefill-max", type=int, default=512, help="max tokens per forward call" | |
| ) | |
| ap.add_argument( | |
| "--max-context", type=int, default=max_context, help="KV cache length" | |
| ) | |
| ap.add_argument("--group-size", type=int, default=64) | |