psiddh commited on
Commit
f2b116f
·
verified ·
1 Parent(s): 60688da

Re-export with public ExecuTorch 1.5.1 (recipe in export/)

Browse files
.gitattributes CHANGED
@@ -34,3 +34,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  model_ctx8960_m512.pte filter=lfs diff=lfs merge=lfs -text
 
 
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  model_ctx8960_m512.pte filter=lfs diff=lfs merge=lfs -text
37
+ llama3_2_1b_instruct_q4gsw.pte filter=lfs diff=lfs merge=lfs -text
LICENSE CHANGED
@@ -1,70 +1,111 @@
1
  LLAMA 3.2 COMMUNITY LICENSE AGREEMENT
2
-
3
  Llama 3.2 Version Release Date: September 25, 2024
4
 
5
- “Agreement” means the terms and conditions for use, reproduction, distribution and modification of the Llama Materials set forth herein.
6
-
7
-
8
- “Documentation” means the specifications, manuals and documentation accompanying Llama 3.2 distributed by Meta at https://www.llama.com/docs/overview.
9
-
10
 
11
- “Licensee” or “you” means you, or your employer or any other person or entity (if you are entering into this Agreement on such person or entity’s behalf), of the age required under applicable laws, rules or regulations to provide legal consent and that has legal authority to bind your employer or such other person or entity if you are entering in this Agreement on their behalf.
 
12
 
 
 
 
 
 
13
 
14
- “Llama 3.2” means the foundational large language models and software and algorithms, including machine-learning model code, trained model weights, inference-enabling code, training-enabling code, fine-tuning enabling code and other elements of the foregoing distributed by Meta at https://www.llama.com/llama-downloads.
 
 
 
15
 
 
 
16
 
17
- “Llama Materials” means, collectively, Meta’s proprietary Llama 3.2 and Documentation (and any portion thereof) made available under this Agreement.
 
 
18
 
19
 
20
- “Meta” or “we” means Meta Platforms Ireland Limited (if you are located in or, if you are an entity, your principal place of business is in the EEA or Switzerland) and Meta Platforms, Inc. (if you are located outside of the EEA or Switzerland).
21
-
22
-
23
- By clicking “I Accept” below or by using or distributing any portion or element of the Llama Materials, you agree to be bound by this Agreement.
24
 
25
 
26
  1. License Rights and Redistribution.
27
 
28
-
29
- a. Grant of Rights. You are granted a non-exclusive, worldwide, non-transferable and royalty-free limited license under Meta’s intellectual property or other rights owned by Meta embodied in the Llama Materials to use, reproduce, distribute, copy, create derivative works of, and make modifications to the Llama Materials.
30
-
31
-
32
- b. Redistribution and Use.
33
-
34
-
35
- i. If you distribute or make available the Llama Materials (or any derivative works thereof), or a product or service (including another AI model) that contains any of them, you shall (A) provide a copy of this Agreement with any such Llama Materials; and (B) prominently display “Built with Llama” on a related website, user interface, blogpost, about page, or product documentation. If you use the Llama Materials or any outputs or results of the Llama Materials to create, train, fine tune, or otherwise improve an AI model, which is distributed or made available, you shall also include “Llama” at the beginning of any such AI model name.
36
-
37
-
38
- ii. If you receive Llama Materials, or any derivative works thereof, from a Licensee as part of an integrated end user product, then Section 2 of this Agreement will not apply to you.
39
-
40
-
41
- iii. You must retain in all copies of the Llama Materials that you distribute the following attribution notice within a “Notice” text file distributed as a part of such copies: “Llama 3.2 is licensed under the Llama 3.2 Community License, Copyright © Meta Platforms, Inc. All Rights Reserved.”
42
-
43
-
44
- iv. Your use of the Llama Materials must comply with applicable laws and regulations (including trade compliance laws and regulations) and adhere to the Acceptable Use Policy for the Llama Materials (available at https://www.llama.com/llama3_2/use-policy), which is hereby incorporated by reference into this Agreement.
45
-
46
- 2. Additional Commercial Terms. If, on the Llama 3.2 version release date, the monthly active users of the products or services made available by or for Licensee, or Licensee’s affiliates, is greater than 700 million monthly active users in the preceding calendar month, you must request a license from Meta, which Meta may grant to you in its sole discretion, and you are not authorized to exercise any of the rights under this Agreement unless or until Meta otherwise expressly grants you such rights.
47
-
48
-
49
- 3. Disclaimer of Warranty. UNLESS REQUIRED BY APPLICABLE LAW, THE LLAMA MATERIALS AND ANY OUTPUT AND RESULTS THEREFROM ARE PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OF ANY KIND, AND META DISCLAIMS ALL WARRANTIES OF ANY KIND, BOTH EXPRESS AND IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. YOU ARE SOLELY RESPONSIBLE FOR DETERMINING THE APPROPRIATENESS OF USING OR REDISTRIBUTING THE LLAMA MATERIALS AND ASSUME ANY RISKS ASSOCIATED WITH YOUR USE OF THE LLAMA MATERIALS AND ANY OUTPUT AND RESULTS.
50
-
51
-
52
- 4. Limitation of Liability. IN NO EVENT WILL META OR ITS AFFILIATES BE LIABLE UNDER ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, TORT, NEGLIGENCE, PRODUCTS LIABILITY, OR OTHERWISE, ARISING OUT OF THIS AGREEMENT, FOR ANY LOST PROFITS OR ANY INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL, EXEMPLARY OR PUNITIVE DAMAGES, EVEN IF META OR ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF ANY OF THE FOREGOING.
53
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
  5. Intellectual Property.
56
 
57
-
58
- a. No trademark licenses are granted under this Agreement, and in connection with the Llama Materials, neither Meta nor Licensee may use any name or mark owned by or associated with the other or any of its affiliates, except as required for reasonable and customary use in describing and redistributing the Llama Materials or as set forth in this Section 5(a). Meta hereby grants you a license to use “Llama” (the “Mark”) solely as required to comply with the last sentence of Section 1.b.i. You will comply with Meta’s brand guidelines (currently accessible at https://about.meta.com/brand/resources/meta/company-brand/). All goodwill arising out of your use of the Mark will inure to the benefit of Meta.
59
-
60
-
61
- b. Subject to Meta’s ownership of Llama Materials and derivatives made by or for Meta, with respect to any derivative works and modifications of the Llama Materials that are made by you, as between you and Meta, you are and will be the owner of such derivative works and modifications.
62
-
63
-
64
- c. If you institute litigation or other proceedings against Meta or any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Llama Materials or Llama 3.2 outputs or results, or any portion of any of the foregoing, constitutes infringement of intellectual property or other rights owned or licensable by you, then any licenses granted to you under this Agreement shall terminate as of the date such litigation or claim is filed or instituted. You will indemnify and hold harmless Meta from and against any claim by any third party arising out of or related to your use or distribution of the Llama Materials.
65
-
66
-
67
- 6. Term and Termination. The term of this Agreement will commence upon your acceptance of this Agreement or access to the Llama Materials and will continue in full force and effect until terminated in accordance with the terms and conditions herein. Meta may terminate this Agreement if you are in breach of any term or condition of this Agreement. Upon termination of this Agreement, you shall delete and cease use of the Llama Materials. Sections 3, 4 and 7 shall survive the termination of this Agreement.
68
-
69
-
70
- 7. Governing Law and Jurisdiction. This Agreement will be governed and construed under the laws of the State of California without regard to choice of law principles, and the UN Convention on Contracts for the International Sale of Goods does not apply to this Agreement. The courts of California shall have exclusive jurisdiction of any dispute arising out of this Agreement.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  LLAMA 3.2 COMMUNITY LICENSE AGREEMENT
 
2
  Llama 3.2 Version Release Date: September 25, 2024
3
 
4
+ “Agreement” means the terms and conditions for use, reproduction, distribution
5
+ and modification of the Llama Materials set forth herein.
 
 
 
6
 
7
+ “Documentation” means the specifications, manuals and documentation accompanying Llama 3.2
8
+ distributed by Meta at https://llama.meta.com/doc/overview.
9
 
10
+ “Licensee” or “you” means you, or your employer or any other person or entity (if you are
11
+ entering into this Agreement on such person or entity’s behalf), of the age required under
12
+ applicable laws, rules or regulations to provide legal consent and that has legal authority
13
+ to bind your employer or such other person or entity if you are entering in this Agreement
14
+ on their behalf.
15
 
16
+ “Llama 3.2” means the foundational large language models and software and algorithms, including
17
+ machine-learning model code, trained model weights, inference-enabling code, training-enabling code,
18
+ fine-tuning enabling code and other elements of the foregoing distributed by Meta at
19
+ https://www.llama.com/llama-downloads.
20
 
21
+ “Llama Materials” means, collectively, Meta’s proprietary Llama 3.2 and Documentation (and
22
+ any portion thereof) made available under this Agreement.
23
 
24
+ “Meta” or “we” means Meta Platforms Ireland Limited (if you are located in or,
25
+ if you are an entity, your principal place of business is in the EEA or Switzerland)
26
+ and Meta Platforms, Inc. (if you are located outside of the EEA or Switzerland).
27
 
28
 
29
+ By clicking “I Accept” below or by using or distributing any portion or element of the Llama Materials,
30
+ you agree to be bound by this Agreement.
 
 
31
 
32
 
33
  1. License Rights and Redistribution.
34
 
35
+ a. Grant of Rights. You are granted a non-exclusive, worldwide,
36
+ non-transferable and royalty-free limited license under Meta’s intellectual property or other rights
37
+ owned by Meta embodied in the Llama Materials to use, reproduce, distribute, copy, create derivative works
38
+ of, and make modifications to the Llama Materials.
39
+
40
+ b. Redistribution and Use.
41
+
42
+ i. If you distribute or make available the Llama Materials (or any derivative works thereof),
43
+ or a product or service (including another AI model) that contains any of them, you shall (A) provide
44
+ a copy of this Agreement with any such Llama Materials; and (B) prominently display “Built with Llama”
45
+ on a related website, user interface, blogpost, about page, or product documentation. If you use the
46
+ Llama Materials or any outputs or results of the Llama Materials to create, train, fine tune, or
47
+ otherwise improve an AI model, which is distributed or made available, you shall also include “Llama”
48
+ at the beginning of any such AI model name.
49
+
50
+ ii. If you receive Llama Materials, or any derivative works thereof, from a Licensee as part
51
+ of an integrated end user product, then Section 2 of this Agreement will not apply to you.
52
+
53
+ iii. You must retain in all copies of the Llama Materials that you distribute the
54
+ following attribution notice within a “Notice” text file distributed as a part of such copies:
55
+ “Llama 3.2 is licensed under the Llama 3.2 Community License, Copyright © Meta Platforms,
56
+ Inc. All Rights Reserved.”
57
+
58
+ iv. Your use of the Llama Materials must comply with applicable laws and regulations
59
+ (including trade compliance laws and regulations) and adhere to the Acceptable Use Policy for
60
+ the Llama Materials (available at https://www.llama.com/llama3_2/use-policy), which is hereby
61
+ incorporated by reference into this Agreement.
62
+
63
+ 2. Additional Commercial Terms. If, on the Llama 3.2 version release date, the monthly active users
64
+ of the products or services made available by or for Licensee, or Licensee’s affiliates,
65
+ is greater than 700 million monthly active users in the preceding calendar month, you must request
66
+ a license from Meta, which Meta may grant to you in its sole discretion, and you are not authorized to
67
+ exercise any of the rights under this Agreement unless or until Meta otherwise expressly grants you such rights.
68
+
69
+ 3. Disclaimer of Warranty. UNLESS REQUIRED BY APPLICABLE LAW, THE LLAMA MATERIALS AND ANY OUTPUT AND
70
+ RESULTS THEREFROM ARE PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OF ANY KIND, AND META DISCLAIMS
71
+ ALL WARRANTIES OF ANY KIND, BOTH EXPRESS AND IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES
72
+ OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. YOU ARE SOLELY RESPONSIBLE
73
+ FOR DETERMINING THE APPROPRIATENESS OF USING OR REDISTRIBUTING THE LLAMA MATERIALS AND ASSUME ANY RISKS ASSOCIATED
74
+ WITH YOUR USE OF THE LLAMA MATERIALS AND ANY OUTPUT AND RESULTS.
75
+
76
+ 4. Limitation of Liability. IN NO EVENT WILL META OR ITS AFFILIATES BE LIABLE UNDER ANY THEORY OF LIABILITY,
77
+ WHETHER IN CONTRACT, TORT, NEGLIGENCE, PRODUCTS LIABILITY, OR OTHERWISE, ARISING OUT OF THIS AGREEMENT,
78
+ FOR ANY LOST PROFITS OR ANY INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL, EXEMPLARY OR PUNITIVE DAMAGES, EVEN
79
+ IF META OR ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF ANY OF THE FOREGOING.
80
 
81
  5. Intellectual Property.
82
 
83
+ a. No trademark licenses are granted under this Agreement, and in connection with the Llama Materials,
84
+ neither Meta nor Licensee may use any name or mark owned by or associated with the other or any of its affiliates,
85
+ except as required for reasonable and customary use in describing and redistributing the Llama Materials or as
86
+ set forth in this Section 5(a). Meta hereby grants you a license to use “Llama” (the “Mark”) solely as required
87
+ to comply with the last sentence of Section 1.b.i. You will comply with Meta’s brand guidelines (currently accessible
88
+ at https://about.meta.com/brand/resources/meta/company-brand/). All goodwill arising out of your use of the Mark
89
+ will inure to the benefit of Meta.
90
+
91
+ b. Subject to Meta’s ownership of Llama Materials and derivatives made by or for Meta, with respect to any
92
+ derivative works and modifications of the Llama Materials that are made by you, as between you and Meta,
93
+ you are and will be the owner of such derivative works and modifications.
94
+
95
+ c. If you institute litigation or other proceedings against Meta or any entity (including a cross-claim or
96
+ counterclaim in a lawsuit) alleging that the Llama Materials or Llama 3.2 outputs or results, or any portion
97
+ of any of the foregoing, constitutes infringement of intellectual property or other rights owned or licensable
98
+ by you, then any licenses granted to you under this Agreement shall terminate as of the date such litigation or
99
+ claim is filed or instituted. You will indemnify and hold harmless Meta from and against any claim by any third
100
+ party arising out of or related to your use or distribution of the Llama Materials.
101
+
102
+ 6. Term and Termination. The term of this Agreement will commence upon your acceptance of this Agreement or access
103
+ to the Llama Materials and will continue in full force and effect until terminated in accordance with the terms
104
+ and conditions herein. Meta may terminate this Agreement if you are in breach of any term or condition of this
105
+ Agreement. Upon termination of this Agreement, you shall delete and cease use of the Llama Materials. Sections 3,
106
+ 4 and 7 shall survive the termination of this Agreement.
107
+
108
+ 7. Governing Law and Jurisdiction. This Agreement will be governed and construed under the laws of the State of
109
+ California without regard to choice of law principles, and the UN Convention on Contracts for the International
110
+ Sale of Goods does not apply to this Agreement. The courts of California shall have exclusive jurisdiction of
111
+ any dispute arising out of this Agreement.
README.md CHANGED
@@ -24,8 +24,8 @@ the visitor's GPU. It powers the corresponding demo in the ExecuTorch WebGPU Pla
24
 
25
  - **Base model:** [meta-llama/Llama-3.2-1B-Instruct](https://huggingface.co/meta-llama/Llama-3.2-1B-Instruct)
26
  - **Format:** ExecuTorch `.pte` programs delegated to the WebGPU backend
27
- - **Quantization:** 4-bit groupwise weights (q4gsw), fp16 KV cache
28
- - **Total size:** 850.4 MB
29
 
30
  ## About the original model
31
 
@@ -47,19 +47,23 @@ Out of scope: any use that violates applicable laws or the Acceptable Use Policy
47
 
48
  ## What changed in this conversion
49
 
50
- - Weights quantized to 4-bit groupwise (q4gsw); the KV cache is fp16
51
- - Context capped at 8,960 tokens (upstream: 128K)
 
 
 
52
 
53
  ## Inputs and outputs
54
 
55
- - Token IDs in, last-position logits out (vocabulary 128,256); the KV cache lives inside the program; up to 512 new tokens per call
56
- - Tokenize with the files in `tokenizer/` (the upstream Llama 3.2 tokenizer and chat template)
 
57
 
58
  ## Files
59
 
60
  | File | Size | SHA-256 |
61
  |---|---|---|
62
- | `model_ctx8960_m512.pte` | 841.7 MB | `66c9d2934daf17fb…` |
63
  | `tokenizer/config.json` | 877 B | `2febf68cea25bf46…` |
64
  | `tokenizer/generation_config.json` | 189 B | `88effbb63300dbbc…` |
65
  | `tokenizer/special_tokens_map.json` | 296 B | `6f38c73729248f6c…` |
@@ -71,8 +75,8 @@ Full checksums are in `manifest.json`. The playground verifies them after downlo
71
  ## Running it
72
 
73
  These programs were exported with the ExecuTorch WebGPU backend
74
- ([backends/webgpu](https://github.com/pytorch/executorch/tree/main/backends/webgpu)) and validated with the
75
- WebAssembly runtime build used by the ExecuTorch WebGPU Playground (launching soon on [executorch.ai](https://executorch.ai)). That runtime build is not published yet; until it is,
76
  the playground is the supported way to run them. It downloads these files once, caches them in the browser,
77
  and runs everything locally.
78
 
@@ -80,8 +84,11 @@ Requirements: a browser with WebGPU enabled. The language models use the `shader
80
 
81
  ## Provenance
82
 
83
- - Converted from the upstream checkpoint by the ExecuTorch team with the WebGPU export path.
84
- - A reproducible export recipe will be published alongside the open-source ExecuTorch WebGPU runtime.
 
 
 
85
 
86
  ## Citation
87
 
 
24
 
25
  - **Base model:** [meta-llama/Llama-3.2-1B-Instruct](https://huggingface.co/meta-llama/Llama-3.2-1B-Instruct)
26
  - **Format:** ExecuTorch `.pte` programs delegated to the WebGPU backend
27
+ - **Quantization:** 4-bit groupwise weights (q4gsw, group size 64) for all linear layers and the tied token-embedding/output head; fp32 activations and KV cache
28
+ - **Total size:** 709.5 MB
29
 
30
  ## About the original model
31
 
 
47
 
48
  ## What changed in this conversion
49
 
50
+ - Exported with ExecuTorch's `export_llm` (`model_class=llama3_2`) from the original Meta-format checkpoint (`original/consolidated.00.pth`, bf16), with Llama 3 scaled RoPE (factor 32)
51
+ - All linear layers quantized to 4-bit groupwise weights (q4gsw, group size 64, round to nearest); the token embedding is quantized the same way. Llama 3.2 ties the embedding and the output head, so they quantize to the same bytes and the program stores them once
52
+ - Activations and the KV cache buffers in the program are fp32
53
+ - Context capped at 8,960 tokens (upstream: 128K); at most 512 tokens per forward call
54
+ - 4-bit quantization changes the outputs: on 3 test prompts, greedy text from this program agreed with the fp32 model for the first 6, 8 (the whole answer) and 0 tokens, and gave fluent, on-topic answers in all three
55
 
56
  ## Inputs and outputs
57
 
58
+ - `forward(tokens int64 [1, 1..512], input_pos int64 [1]) -> logits float32 [1, 128256]` (last position only)
59
+ - The KV cache lives inside the program; call it with up to 512 new tokens at a time, then one token per step. Metadata methods: `get_max_seq_len` 513, `get_max_context_len` 8960, `get_n_layers` 16, `get_vocab_size` 128256
60
+ - Tokenize with the files in `tokenizer/` (the upstream Llama 3.2 tokenizer and chat template); stop on token 128001, 128008 or 128009
61
 
62
  ## Files
63
 
64
  | File | Size | SHA-256 |
65
  |---|---|---|
66
+ | `llama3_2_1b_instruct_q4gsw.pte` | 700.8 MB | `49de6eec3a54f1f4…` |
67
  | `tokenizer/config.json` | 877 B | `2febf68cea25bf46…` |
68
  | `tokenizer/generation_config.json` | 189 B | `88effbb63300dbbc…` |
69
  | `tokenizer/special_tokens_map.json` | 296 B | `6f38c73729248f6c…` |
 
75
  ## Running it
76
 
77
  These programs were exported with the ExecuTorch WebGPU backend
78
+ ([backends/webgpu](https://github.com/pytorch/executorch/tree/main/backends/webgpu)) and run in a browser (headless Chromium, WebGPU on SwiftShader) with a development build of the ExecuTorch
79
+ WebGPU WebAssembly runtime, where its greedy output matched the CPU reference token for token on 3 test prompts. That runtime build is not published yet; until it is,
80
  the playground is the supported way to run them. It downloads these files once, caches them in the browser,
81
  and runs everything locally.
82
 
 
84
 
85
  ## Provenance
86
 
87
+ - **Upstream:** `meta-llama/Llama-3.2-1B-Instruct` at revision `9213176726f574b556790deb65791e0c5aa438b6` (official)
88
+ - **Weights source:** downloaded from the public mirror `LIF1014/ptdbench-Llama-3.2-1B-Instruct` @ `828e5f37c833a02415416260d5a93780fd41d10e`; the gated official repo was not downloaded. Each of the 9 files taken from the mirror (checkpoint `original/consolidated.00.pth`, `original/params.json`, the 5 tokenizer/config files, `LICENSE.txt`, `USE_POLICY.md`) was verified against the hash the official repo publishes for it at the pinned revision (LFS sha256 for the checkpoint, `fc17d497df5e4175b3a8acb4f5865b26f7fc1b009b25bef814b95fde10e8a1f3`; git blob SHA-1 for the small files), so the bytes used are the official ones. `export/llama-3.2-1b-instruct.py` repeats this check on every run
89
+ - **Exported with:** executorch 1.5.1+cpu, torch 2.14.1+cpu, torchao 0.18.0+cpu, transformers 5.19.0 (executorch git `3b6068392324`)
90
+ - **Reproduce:** `python recipes/llama-3.2-1b-instruct.py --out out/llama-3.2-1b-instruct` (recipe in `export/`)
91
+ - Re-running the recipe produces byte-identical files.
92
 
93
  ## Citation
94
 
export/_common.py ADDED
@@ -0,0 +1,330 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Shared helpers for the ExecuTorch WebGPU export recipes in this directory.
2
+
3
+ Each recipe builds an eager model from a pinned upstream revision and calls
4
+ `export_vision` (or its own LLM path), which writes:
5
+
6
+ <out>/<name>_webgpu.pte program lowered with WebGPUPartitioner (delegate id "VulkanBackend")
7
+ <out>/<name>_portable.pte same exported graph without a delegate, for CPU validation only
8
+ <out>/recipe.json upstream id + revision, versions, shapes, dtype, command line
9
+ <out>/validation.json eager vs exported-program vs portable .pte (and goldens, if given)
10
+ """
11
+
12
+ import hashlib
13
+ import io
14
+ import json
15
+ import platform
16
+ import shlex
17
+ import sys
18
+ import urllib.request
19
+ import zipfile
20
+ from pathlib import Path
21
+
22
+ import numpy as np
23
+ import torch
24
+
25
+ PROXY_HINT = (
26
+ "set https_proxy if the machine needs a proxy for huggingface.co / pypi.org"
27
+ )
28
+
29
+
30
+ def versions():
31
+ import executorch
32
+ import torchao
33
+ from executorch.version import git_version
34
+
35
+ out = {
36
+ "python": platform.python_version(),
37
+ "torch": torch.__version__,
38
+ "torchao": torchao.__version__,
39
+ "executorch": getattr(executorch, "__version__", None)
40
+ or __import__("executorch.version").version.__version__,
41
+ "executorch_git": git_version,
42
+ }
43
+ try:
44
+ import transformers
45
+
46
+ out["transformers"] = transformers.__version__
47
+ except ImportError:
48
+ pass
49
+ try:
50
+ import huggingface_hub
51
+
52
+ out["huggingface_hub"] = huggingface_hub.__version__
53
+ except ImportError:
54
+ pass
55
+ return out
56
+
57
+
58
+ def sha256_file(path):
59
+ h = hashlib.sha256()
60
+ with open(path, "rb") as fh:
61
+ for chunk in iter(lambda: fh.read(1 << 20), b""):
62
+ h.update(chunk)
63
+ return h.hexdigest()
64
+
65
+
66
+ def hf_file(repo_id, filename, revision, expected_sha256=None, cache_dir=None):
67
+ from huggingface_hub import hf_hub_download
68
+
69
+ path = hf_hub_download(
70
+ repo_id=repo_id, filename=filename, revision=revision, cache_dir=cache_dir
71
+ )
72
+ digest = sha256_file(path)
73
+ if expected_sha256 and digest != expected_sha256:
74
+ sys.exit(
75
+ f"{repo_id}@{revision}:{filename} sha256 {digest} != {expected_sha256}"
76
+ )
77
+ return Path(path), digest
78
+
79
+
80
+ def pypi_wheel_member(url, expected_sha256, member):
81
+ """Read one file out of a PyPI wheel, verifying the wheel's sha256."""
82
+ with urllib.request.urlopen(url, timeout=120) as resp:
83
+ blob = resp.read()
84
+ digest = hashlib.sha256(blob).hexdigest()
85
+ if digest != expected_sha256:
86
+ sys.exit(f"{url}: sha256 {digest} != {expected_sha256} ({PROXY_HINT})")
87
+ with zipfile.ZipFile(io.BytesIO(blob)) as zf:
88
+ return zf.read(member).decode()
89
+
90
+
91
+ def scrub(text, out_dir):
92
+ """Replace machine-specific paths so recipe.json can ship with the model."""
93
+ text = text.replace(str(Path(out_dir).resolve()), "<out>")
94
+ text = text.replace(str(Path(__file__).resolve().parent), "recipes")
95
+ return text.replace(str(Path.home()), "~")
96
+
97
+
98
+ def command_line(out_dir):
99
+ argv = [f"recipes/{Path(sys.argv[0]).name}", *sys.argv[1:]]
100
+ args = []
101
+ for a in argv:
102
+ if a.startswith("/") or a.startswith("."):
103
+ a = scrub(str(Path(a).resolve()), out_dir)
104
+ args.append(a)
105
+ return scrub(" ".join(["python", *(shlex.quote(a) for a in args)]), out_dir)
106
+
107
+
108
+ def lower_webgpu(ep):
109
+ from executorch.backends.webgpu.partitioner import WebGPUPartitioner
110
+ from executorch.exir import to_edge_transform_and_lower
111
+
112
+ return to_edge_transform_and_lower(
113
+ ep, partitioner=[WebGPUPartitioner()]
114
+ ).to_executorch()
115
+
116
+
117
+ def lower_portable(ep):
118
+ from executorch.exir import to_edge_transform_and_lower
119
+
120
+ return to_edge_transform_and_lower(ep).to_executorch()
121
+
122
+
123
+ def delegate_summary(pte_bytes):
124
+ """Non-delegated kernels and per-delegate op histograms of a serialized program."""
125
+ import collections
126
+
127
+ from executorch.backends.vulkan.serialization.vulkan_graph_serialize import (
128
+ extract_vk_flatbuffer,
129
+ flatbuffer_to_vk_graph,
130
+ )
131
+ from executorch.exir._serialize._program import deserialize_pte_binary
132
+
133
+ pte = deserialize_pte_binary(pte_bytes)
134
+ prog = pte.program if hasattr(pte, "program") else pte
135
+ seg_base = int.from_bytes(pte_bytes[24:32], "little")
136
+ plan = prog.execution_plan[0]
137
+ ops = [f"{o.name}.{o.overload}" for o in plan.operators]
138
+ kernels = collections.Counter()
139
+ for chain in plan.chains:
140
+ for ins in chain.instructions:
141
+ if type(ins.instr_args).__name__ == "KernelCall":
142
+ kernels[ops[ins.instr_args.op_index]] += 1
143
+ delegates = []
144
+ for d in plan.delegates:
145
+ proc = d.processed
146
+ if proc.location.name == "INLINE":
147
+ blob = prog.backend_delegate_data[proc.index].data
148
+ else:
149
+ seg = prog.segments[proc.index]
150
+ blob = pte_bytes[seg_base + seg.offset : seg_base + seg.offset + seg.size]
151
+ g = flatbuffer_to_vk_graph(extract_vk_flatbuffer(blob))
152
+ delegates.append(
153
+ {
154
+ "id": d.id,
155
+ "ops": dict(collections.Counter(c.name for c in g.chain)),
156
+ "inputs": len(g.input_ids),
157
+ "outputs": len(g.output_ids),
158
+ }
159
+ )
160
+ return {"non_delegated_kernels": dict(kernels), "delegates": delegates}
161
+
162
+
163
+ def compare(a, b):
164
+ a = np.asarray(a, dtype=np.float64).ravel()
165
+ b = np.asarray(b, dtype=np.float64).ravel()
166
+ n = min(a.size, b.size)
167
+ a, b = a[:n], b[:n]
168
+ cos = float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b) + 1e-30))
169
+ return {
170
+ "max_abs": float(np.max(np.abs(a - b))),
171
+ "mean_abs": float(np.mean(np.abs(a - b))),
172
+ "cosine": cos,
173
+ }
174
+
175
+
176
+ def run_pte(pte_bytes, inputs):
177
+ from executorch.extension.pybindings.portable_lib import (
178
+ _load_for_executorch_from_buffer,
179
+ )
180
+
181
+ m = _load_for_executorch_from_buffer(pte_bytes)
182
+ return [
183
+ o.detach().numpy() if isinstance(o, torch.Tensor) else o
184
+ for o in m.forward(inputs)
185
+ ]
186
+
187
+
188
+ def try_run_webgpu_pte_on_cpu(pte_bytes, inputs):
189
+ try:
190
+ return run_pte(pte_bytes, inputs), None
191
+ except Exception as e: # noqa: BLE001 - the error text is the result
192
+ return None, f"{type(e).__name__}: {str(e).splitlines()[0][:300]}"
193
+
194
+
195
+ def export_vision(
196
+ *,
197
+ name,
198
+ model,
199
+ example_input,
200
+ out_dir,
201
+ upstream,
202
+ extra_recipe,
203
+ golden=None,
204
+ output_index=None,
205
+ ):
206
+ """Export, lower, write both .pte files, recipe.json, and validation.json.
207
+
208
+ `golden` is an optional (input ndarray, output ndarray) pair; when its input
209
+ shape matches `example_input`, all paths are also compared against it.
210
+ `output_index` picks one tensor when the eager model returns a tuple.
211
+ """
212
+ out_dir = Path(out_dir)
213
+ out_dir.mkdir(parents=True, exist_ok=True)
214
+ torch.manual_seed(0)
215
+ model = model.eval()
216
+
217
+ class Wrapped(torch.nn.Module):
218
+ def __init__(self, m):
219
+ super().__init__()
220
+ self.m = m
221
+
222
+ def forward(self, x):
223
+ y = self.m(x)
224
+ return y[output_index] if output_index is not None else y
225
+
226
+ wrapped = Wrapped(model).eval()
227
+ with torch.no_grad():
228
+ ep = torch.export.export(wrapped, (example_input,), strict=False)
229
+ webgpu = lower_webgpu(ep)
230
+ portable = lower_portable(ep)
231
+
232
+ webgpu_path = out_dir / f"{name}_webgpu.pte"
233
+ portable_path = out_dir / f"{name}_portable.pte"
234
+ webgpu_path.write_bytes(webgpu.buffer)
235
+ portable_path.write_bytes(portable.buffer)
236
+
237
+ summary = delegate_summary(webgpu.buffer)
238
+ out_shape = list(ep.module()(example_input).shape)
239
+ recipe = {
240
+ "model": name,
241
+ "upstream": upstream,
242
+ "versions": versions(),
243
+ "export": {
244
+ "api": "torch.export.export(strict=False) -> to_edge_transform_and_lower(partitioner=[WebGPUPartitioner()]) -> to_executorch()",
245
+ "partitioner": "executorch.backends.webgpu.partitioner.WebGPUPartitioner() (default compile options; wraps VulkanPartitioner)",
246
+ "inputs": [
247
+ {
248
+ "shape": list(example_input.shape),
249
+ "dtype": "float32",
250
+ "layout": "NCHW",
251
+ }
252
+ ],
253
+ "outputs": [{"shape": out_shape, "dtype": "float32"}],
254
+ "dtype": "float32",
255
+ "quantization": "none (fp32)",
256
+ **extra_recipe,
257
+ },
258
+ "files": {
259
+ webgpu_path.name: {
260
+ "bytes": webgpu_path.stat().st_size,
261
+ "sha256": sha256_file(webgpu_path),
262
+ },
263
+ portable_path.name: {
264
+ "bytes": portable_path.stat().st_size,
265
+ "sha256": sha256_file(portable_path),
266
+ "note": "CPU-only validation artifact (portable kernels, no delegate); not for release",
267
+ },
268
+ },
269
+ "graph": summary,
270
+ "command": command_line(out_dir),
271
+ }
272
+ (out_dir / "recipe.json").write_text(json.dumps(recipe, indent=2) + "\n")
273
+
274
+ # Validation on CPU.
275
+ gen = torch.Generator().manual_seed(1234)
276
+ rand_input = torch.rand(example_input.shape, generator=gen)
277
+ cases = {"random": rand_input}
278
+ if golden is not None and tuple(golden[0].shape) == tuple(example_input.shape):
279
+ cases["golden"] = torch.from_numpy(golden[0].copy())
280
+ report = {
281
+ "cpu_runtime": "executorch pybindings (portable_lib) from the pip wheel",
282
+ "cases": {},
283
+ }
284
+ webgpu_cpu_error = None
285
+ for label, x in cases.items():
286
+ with torch.no_grad():
287
+ eager = wrapped(x).numpy()
288
+ exported = ep.module()(x).numpy()
289
+ port = run_pte(portable.buffer, (x,))[0]
290
+ res = {
291
+ "exported_vs_eager": compare(exported, eager),
292
+ "portable_pte_vs_eager": compare(port, eager),
293
+ }
294
+ wg, err = try_run_webgpu_pte_on_cpu(webgpu.buffer, (x,))
295
+ if wg is not None:
296
+ res["webgpu_pte_vs_eager"] = compare(wg[0], eager)
297
+ else:
298
+ webgpu_cpu_error = err
299
+ if label == "golden":
300
+ ref = golden[1]
301
+ res["internal_golden_vs_eager"] = compare(eager, ref)
302
+ res["internal_golden_vs_portable_pte"] = compare(port, ref)
303
+ res["golden_note"] = (
304
+ "reference output from the internal goldens.manifest.json"
305
+ )
306
+ report["cases"][label] = res
307
+ report["webgpu_pte_on_cpu"] = (
308
+ "ran"
309
+ if webgpu_cpu_error is None
310
+ else f"not runnable on CPU pybindings: {webgpu_cpu_error}"
311
+ )
312
+ (out_dir / "validation.json").write_text(json.dumps(report, indent=2) + "\n")
313
+ print(
314
+ json.dumps(
315
+ {"recipe": recipe["files"], "graph": summary, "validation": report},
316
+ indent=2,
317
+ )
318
+ )
319
+ return ep, webgpu, portable
320
+
321
+
322
+ def load_golden(manifest_path, key):
323
+ man = json.loads(Path(manifest_path).read_text())[key]["tensors"]
324
+ base = Path(manifest_path).parent
325
+
326
+ def ld(t):
327
+ return np.fromfile(base / t["file"], dtype=np.float32).reshape(t["shape"])
328
+
329
+ inp = man.get("input")
330
+ return ld(inp), ld(man["output"])
export/_llm.py ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Shared export path for the Qwen LLM recipes: pinned HF snapshot -> ExecuTorch checkpoint
2
+ -> export_llm (Vulkan partitioner, which WebGPUPartitioner wraps unchanged) -> .pte.
3
+
4
+ Graph contract (matches the internal WebGPU LLM artifacts): forward(tokens[1, <=prefill_max]
5
+ int64, input_pos[1] int64) -> logits[1, vocab] float32 for the last position, KV cache inside the
6
+ program (fp32 buffers, max_context_length positions), 4-bit groupwise weight-only linears
7
+ (et_vk.linear_q4gsw) and 4-bit groupwise embedding (et_vk.embedding_q4gsw).
8
+ """
9
+
10
+ import importlib
11
+ import json
12
+ import os
13
+ import shlex
14
+ import shutil
15
+ import subprocess
16
+ import sys
17
+ from pathlib import Path
18
+
19
+ import _common
20
+
21
+ SHIMS = Path(__file__).resolve().parent / "_shims"
22
+
23
+ TOKENIZER_FILES = [
24
+ "tokenizer.json",
25
+ "tokenizer_config.json",
26
+ "vocab.json",
27
+ "merges.txt",
28
+ "generation_config.json",
29
+ "config.json",
30
+ "LICENSE",
31
+ ]
32
+
33
+
34
+ def export(
35
+ *, name, upstream_repo, revision, model_class, params, converter, max_context, args
36
+ ):
37
+ from huggingface_hub import snapshot_download
38
+
39
+ out = Path(args.out).resolve()
40
+ work = out / "_work"
41
+ work.mkdir(parents=True, exist_ok=True)
42
+ snap = Path(
43
+ snapshot_download(
44
+ upstream_repo,
45
+ revision=revision,
46
+ allow_patterns=["*.safetensors", "*.json", "merges.txt", "LICENSE"],
47
+ )
48
+ )
49
+
50
+ sys.path.insert(0, str(SHIMS))
51
+ env = {**os.environ, "PYTHONPATH": os.pathsep.join(filter(None, [str(SHIMS), os.environ.get("PYTHONPATH")]))}
52
+ ckpt = work / "checkpoint.pth"
53
+ if not ckpt.exists():
54
+ importlib.import_module(converter).convert_weights(str(snap), str(ckpt))
55
+ params_path = work / "params.json"
56
+ params_path.write_text(json.dumps(params, indent=2) + "\n")
57
+
58
+ output_name = f"{name}.pte"
59
+ overrides = [
60
+ f"base.model_class={model_class}",
61
+ f"base.checkpoint={ckpt}",
62
+ f"base.params={params_path}",
63
+ "model.use_kv_cache=true",
64
+ "model.use_sdpa_with_kv_cache=true",
65
+ "model.enable_dynamic_shape=true",
66
+ "model.dtype_override=fp32",
67
+ f"export.max_seq_length={args.prefill_max + 1}",
68
+ f"export.max_context_length={max_context}",
69
+ f"export.output_dir={out}",
70
+ f"export.output_name={out / output_name}",
71
+ "quantization.qmode=4w",
72
+ f"quantization.group_size={args.group_size}",
73
+ f"quantization.embedding_quantize='4,{args.group_size}'",
74
+ "backend.vulkan.enabled=true",
75
+ ]
76
+ cmd = [
77
+ sys.executable,
78
+ "-m",
79
+ "executorch.extension.llm.export.export_llm",
80
+ *overrides,
81
+ ]
82
+ print("+", " ".join(shlex.quote(c) for c in cmd), flush=True)
83
+ subprocess.run(cmd, check=True, env=env)
84
+
85
+ pte = out / output_name
86
+ tok_dir = out / "tokenizer"
87
+ tok_dir.mkdir(exist_ok=True)
88
+ tokenizer_files = {}
89
+ for f in TOKENIZER_FILES:
90
+ if (snap / f).exists():
91
+ shutil.copyfile(snap / f, tok_dir / f)
92
+ tokenizer_files[f] = _common.sha256_file(tok_dir / f)
93
+ shutil.rmtree(work)
94
+
95
+ data = pte.read_bytes()
96
+ recipe = {
97
+ "model": name,
98
+ "upstream": {
99
+ "model": upstream_repo,
100
+ "revision": revision,
101
+ "official": True,
102
+ "safetensors_sha256": {
103
+ p.name: _common.sha256_file(p)
104
+ for p in sorted(snap.glob("*.safetensors"))
105
+ },
106
+ },
107
+ "versions": _common.versions(),
108
+ "export": {
109
+ "api": "python -m executorch.extension.llm.export.export_llm (hydra overrides below)",
110
+ "overrides": [_common.scrub(o, out).replace(str(work.resolve()), "<work>") for o in overrides],
111
+ "checkpoint_conversion": f"{converter}.convert_weights(<snapshot>, checkpoint.pth)",
112
+ "import_shim": "recipes/_shims/torchtune (re-exports executorch.examples.models.checkpoint.get_mapped_key; torchtune itself is not installed)",
113
+ "params": params,
114
+ "partitioner": "VulkanPartitioner via backend.vulkan.enabled (WebGPUPartitioner is a pass-through wrapper of it; delegate id VulkanBackend)",
115
+ "inputs": [
116
+ {
117
+ "name": "tokens",
118
+ "shape": [1, f"1..{args.prefill_max}"],
119
+ "dtype": "int64",
120
+ },
121
+ {"name": "input_pos", "shape": [1], "dtype": "int64"},
122
+ ],
123
+ "outputs": [
124
+ {
125
+ "name": "logits",
126
+ "shape": [1, params["vocab_size"]],
127
+ "dtype": "float32",
128
+ "note": "last position only",
129
+ }
130
+ ],
131
+ "prefill_max": args.prefill_max,
132
+ "max_seq_len_metadata": args.prefill_max + 1,
133
+ "max_context_length": max_context,
134
+ "dtype": "float32 activations",
135
+ "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",
136
+ "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",
137
+ },
138
+ "files": {
139
+ pte.name: {"bytes": len(data), "sha256": _common.sha256_file(pte)},
140
+ **{f"tokenizer/{k}": {"sha256": v} for k, v in tokenizer_files.items()},
141
+ },
142
+ "graph": _common.delegate_summary(data),
143
+ "command": _common.command_line(out),
144
+ }
145
+ (out / "recipe.json").write_text(json.dumps(recipe, indent=2) + "\n")
146
+ print(json.dumps({"files": recipe["files"], "graph": recipe["graph"]}, indent=2))
147
+
148
+
149
+ def add_args(ap, max_context):
150
+ ap.add_argument("--out", required=True, help="output directory")
151
+ ap.add_argument(
152
+ "--prefill-max", type=int, default=512, help="max tokens per forward call"
153
+ )
154
+ ap.add_argument(
155
+ "--max-context", type=int, default=max_context, help="KV cache length"
156
+ )
157
+ ap.add_argument("--group-size", type=int, default=64)
export/_shims/torchtune/__init__.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ """Import shim for `torchtune.models.convert_weights.get_mapped_key`.
2
+
3
+ executorch 1.5.1's examples/models/qwen2_5 imports that single helper from torchtune, which
4
+ ExecuTorch pins to a GitHub commit (unreachable from the export host); the PyPI and nightly
5
+ torchtune builds do not import against torchao 0.18. ExecuTorch ships an equivalent helper in
6
+ executorch.examples.models.checkpoint (already used by its qwen3 converter); this shim
7
+ re-exports it. Only on PYTHONPATH while the Qwen2.5 recipe runs.
8
+ """
export/_shims/torchtune/models/__init__.py ADDED
File without changes
export/_shims/torchtune/models/convert_weights.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from executorch.examples.models.checkpoint import get_mapped_key # noqa: F401
export/llama-3.2-1b-instruct.py ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Llama 3.2 1B Instruct -> ExecuTorch WebGPU (4-bit groupwise weights, KV cache in program).
3
+
4
+ Same export path as the Qwen recipes (_llm.py): export_llm with the Vulkan partitioner (which
5
+ WebGPUPartitioner wraps unchanged), qmode=4w group 64, 4-bit embedding, fp32 activations and fp32
6
+ KV buffers, prefill up to 512 tokens, 8960-token context. Program contract (same as the previous
7
+ artifact): forward(tokens[1, 1..512] int64, input_pos[1] int64) -> logits[1, 128256] float32 for
8
+ the last position.
9
+
10
+ Weights: the Meta-format checkpoint `original/consolidated.00.pth` + `original/params.json` of
11
+ meta-llama/Llama-3.2-1B-Instruct at a pinned revision (Llama 3.2 Community License). The upstream
12
+ repo is gated. `--source auto` (default) downloads from it when the token has access, otherwise
13
+ from a public mirror. Either way every file is checked against the hashes Hugging Face publishes
14
+ for the *official* repo at the pinned revision (LFS sha256 for large files, git blob sha1 for small
15
+ ones; both are visible without access), so the bytes used are the official bytes.
16
+ """
17
+
18
+ import argparse
19
+ import hashlib
20
+ import json
21
+ import os
22
+ import shlex
23
+ import shutil
24
+ import subprocess
25
+ import sys
26
+ from pathlib import Path
27
+
28
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
29
+ import _common # noqa: E402
30
+ import _llm # noqa: E402
31
+
32
+ OFFICIAL = {
33
+ "repo": "meta-llama/Llama-3.2-1B-Instruct",
34
+ "revision": "9213176726f574b556790deb65791e0c5aa438b6",
35
+ }
36
+ # Public mirror whose files are byte-identical to OFFICIAL at the pinned revision (checked below).
37
+ MIRROR = {
38
+ "repo": "LIF1014/ptdbench-Llama-3.2-1B-Instruct",
39
+ "revision": "828e5f37c833a02415416260d5a93780fd41d10e",
40
+ }
41
+ # Hashes Hugging Face reports for OFFICIAL@revision (HfApi.model_info(files_metadata=True)).
42
+ # lfs: sha256 of the file; blob: git blob sha1 (sha1(b"blob <len>\0" + content)).
43
+ FILES = {
44
+ "original/consolidated.00.pth": {
45
+ "lfs": "fc17d497df5e4175b3a8acb4f5865b26f7fc1b009b25bef814b95fde10e8a1f3"
46
+ },
47
+ "original/params.json": {"blob": "9cd8dbdf2dc6f4d8abb60bdb5ce64f4bec2fdfd9"},
48
+ "tokenizer.json": {"blob": "5cc5f00a5b203e90a27a3bd60d1ec393b07971e8"},
49
+ "tokenizer_config.json": {"blob": "4ff488a165e900e5129cda7c20ab32d568d2a475"},
50
+ "special_tokens_map.json": {"blob": "02ee80b6196926a5ad790a004d9efd6ab1ba6542"},
51
+ "config.json": {"blob": "3e3aaf51a035cb5092d9f6827a0dc074657ba88c"},
52
+ "generation_config.json": {"blob": "75ae08310d6d23df373ee2644b497192b3cce6d8"},
53
+ "LICENSE.txt": {"blob": "085b47c1575cb889b7024030e60b78f54f0b8c9e"},
54
+ "USE_POLICY.md": {"blob": "ac3c5f21b9779e3da0677d6d3c587778fe3a331e"},
55
+ }
56
+ # Shipped next to the .pte for the playground's tokenizer (transformers.js) and license notice.
57
+ TOKENIZER_FILES = [
58
+ "tokenizer.json",
59
+ "tokenizer_config.json",
60
+ "special_tokens_map.json",
61
+ "config.json",
62
+ "generation_config.json",
63
+ "LICENSE.txt",
64
+ "USE_POLICY.md",
65
+ ]
66
+ NAME = "llama3_2_1b_instruct_q4gsw"
67
+ MODEL_CLASS = "llama3_2"
68
+
69
+
70
+ def git_blob_sha1(path):
71
+ data = Path(path).read_bytes()
72
+ return hashlib.sha1(b"blob %d\0" % len(data) + data).hexdigest()
73
+
74
+
75
+ def check(path, want):
76
+ if "lfs" in want:
77
+ got = _common.sha256_file(path)
78
+ return got == want["lfs"], {"sha256": got}
79
+ got = git_blob_sha1(path)
80
+ return got == want["blob"], {"git_blob_sha1": got}
81
+
82
+
83
+ def official_metadata():
84
+ """Cross-check the pinned hashes against what the Hub reports now (no access needed)."""
85
+ from huggingface_hub import HfApi
86
+
87
+ info = HfApi().model_info(
88
+ OFFICIAL["repo"], revision=OFFICIAL["revision"], files_metadata=True
89
+ )
90
+ live = {s.rfilename: s for s in info.siblings}
91
+ for f, want in FILES.items():
92
+ s = live[f]
93
+ if "lfs" in want and (s.lfs is None or s.lfs.sha256 != want["lfs"]):
94
+ sys.exit(f"official {f}: Hub reports {s.lfs} != pinned {want}")
95
+ if "blob" in want and s.blob_id != want["blob"]:
96
+ sys.exit(f"official {f}: Hub reports blob {s.blob_id} != pinned {want}")
97
+ return info.sha
98
+
99
+
100
+ def fetch(source):
101
+ from huggingface_hub import hf_hub_download
102
+ from huggingface_hub.errors import GatedRepoError
103
+
104
+ def get(repo):
105
+ return {
106
+ f: Path(hf_hub_download(repo["repo"], f, revision=repo["revision"]))
107
+ for f in FILES
108
+ }
109
+
110
+ used = None
111
+ if source in ("auto", "official"):
112
+ try:
113
+ paths, used = get(OFFICIAL), OFFICIAL
114
+ except GatedRepoError as e:
115
+ if source == "official":
116
+ raise
117
+ print(
118
+ f"official repo not accessible ({str(e).splitlines()[-1][:120]}); using mirror",
119
+ flush=True,
120
+ )
121
+ if used is None:
122
+ paths, used = get(MIRROR), MIRROR
123
+ verified = {}
124
+ for f, p in paths.items():
125
+ ok, got = check(p, FILES[f])
126
+ if not ok:
127
+ sys.exit(
128
+ f"{used['repo']}@{used['revision']}:{f} {got} does not match official {FILES[f]}"
129
+ )
130
+ verified[f] = got
131
+ return paths, used, verified
132
+
133
+
134
+ def main():
135
+ ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
136
+ _llm.add_args(ap, max_context=8960)
137
+ ap.add_argument(
138
+ "--embedding-group-size",
139
+ type=int,
140
+ default=None,
141
+ help="group size of the 4-bit embedding (default: --group-size; the previous artifact used 32)",
142
+ )
143
+ ap.add_argument("--source", choices=["auto", "official", "mirror"], default="auto")
144
+ args = ap.parse_args()
145
+
146
+ out = Path(args.out).resolve()
147
+ work = out / "_work"
148
+ work.mkdir(parents=True, exist_ok=True)
149
+ official_sha = official_metadata()
150
+ paths, used, verified = fetch(args.source)
151
+ params = json.loads(paths["original/params.json"].read_text())
152
+
153
+ sys.path.insert(0, str(_llm.SHIMS))
154
+ env = {
155
+ **os.environ,
156
+ "PYTHONPATH": os.pathsep.join(
157
+ filter(None, [str(_llm.SHIMS), os.environ.get("PYTHONPATH")])
158
+ ),
159
+ }
160
+ ckpt = work / "checkpoint.pth"
161
+ if ckpt.is_symlink() or ckpt.exists():
162
+ ckpt.unlink()
163
+ ckpt.symlink_to(paths["original/consolidated.00.pth"])
164
+ params_path = work / "params.json"
165
+ shutil.copyfile(paths["original/params.json"], params_path)
166
+
167
+ emb_group = args.embedding_group_size or args.group_size
168
+ output_name = f"{NAME}.pte"
169
+ overrides = [
170
+ f"base.model_class={MODEL_CLASS}",
171
+ f"base.checkpoint={ckpt}",
172
+ f"base.params={params_path}",
173
+ "model.use_kv_cache=true",
174
+ "model.use_sdpa_with_kv_cache=true",
175
+ "model.enable_dynamic_shape=true",
176
+ "model.dtype_override=fp32",
177
+ f"export.max_seq_length={args.prefill_max + 1}",
178
+ f"export.max_context_length={args.max_context}",
179
+ f"export.output_dir={out}",
180
+ f"export.output_name={out / output_name}",
181
+ "quantization.qmode=4w",
182
+ f"quantization.group_size={args.group_size}",
183
+ f"quantization.embedding_quantize='4,{emb_group}'",
184
+ "backend.vulkan.enabled=true",
185
+ ]
186
+ cmd = [
187
+ sys.executable,
188
+ "-m",
189
+ "executorch.extension.llm.export.export_llm",
190
+ *overrides,
191
+ ]
192
+ print("+", " ".join(shlex.quote(c) for c in cmd), flush=True)
193
+ subprocess.run(cmd, check=True, env=env)
194
+
195
+ pte = out / output_name
196
+ tok_dir = out / "tokenizer"
197
+ tok_dir.mkdir(exist_ok=True)
198
+ tokenizer_files = {}
199
+ for f in TOKENIZER_FILES:
200
+ shutil.copyfile(paths[f], tok_dir / f)
201
+ tokenizer_files[f] = _common.sha256_file(tok_dir / f)
202
+ shutil.rmtree(work)
203
+
204
+ data = pte.read_bytes()
205
+ recipe = {
206
+ "model": NAME,
207
+ "upstream": {
208
+ "model": OFFICIAL["repo"],
209
+ "revision": OFFICIAL["revision"],
210
+ "official": True,
211
+ "license": "Llama 3.2 Community License (tokenizer/LICENSE.txt, tokenizer/USE_POLICY.md); Built with Llama",
212
+ "files": {f: {**FILES[f], **verified[f]} for f in FILES},
213
+ "hub_revision_checked": official_sha,
214
+ "downloaded_from": {
215
+ **used,
216
+ "note": "all files verified byte-identical to the official hashes above",
217
+ },
218
+ },
219
+ "versions": _common.versions(),
220
+ "export": {
221
+ "api": "python -m executorch.extension.llm.export.export_llm (hydra overrides below)",
222
+ "overrides": [
223
+ _common.scrub(o, out).replace(str(work.resolve()), "<work>")
224
+ for o in overrides
225
+ ],
226
+ "checkpoint": "original/consolidated.00.pth (Meta format, bf16; no conversion), params = original/params.json",
227
+ "params": params,
228
+ "rope": "llama3 scaled RoPE, rope_scale_factor=32 (set by ExecuTorch for model_class llama3_2 when use_scaled_rope)",
229
+ "partitioner": "VulkanPartitioner via backend.vulkan.enabled (WebGPUPartitioner is a pass-through wrapper of it; delegate id VulkanBackend)",
230
+ "inputs": [
231
+ {
232
+ "name": "tokens",
233
+ "shape": [1, f"1..{args.prefill_max}"],
234
+ "dtype": "int64",
235
+ },
236
+ {"name": "input_pos", "shape": [1], "dtype": "int64"},
237
+ ],
238
+ "outputs": [
239
+ {
240
+ "name": "logits",
241
+ "shape": [1, params["vocab_size"]],
242
+ "dtype": "float32",
243
+ "note": "last position only",
244
+ }
245
+ ],
246
+ "prefill_max": args.prefill_max,
247
+ "max_seq_len_metadata": args.prefill_max + 1,
248
+ "max_context_length": args.max_context,
249
+ "dtype": "float32 activations",
250
+ "quantization": f"4-bit groupwise weight-only linears (torchao IntxWeightOnlyConfig int4, group {args.group_size}) and 4-bit groupwise embedding (group {emb_group}); output head quantized too",
251
+ "kv_cache": "fp32 buffers in the program; fp16 KV is a runtime option of the WebGPU runtime (enable_f16_kv_cache / et_set_kv_f16), not an export flag",
252
+ },
253
+ "files": {
254
+ pte.name: {"bytes": len(data), "sha256": _common.sha256_file(pte)},
255
+ **{f"tokenizer/{k}": {"sha256": v} for k, v in tokenizer_files.items()},
256
+ },
257
+ "graph": _common.delegate_summary(data),
258
+ "command": _common.command_line(out),
259
+ }
260
+ (out / "recipe.json").write_text(json.dumps(recipe, indent=2) + "\n")
261
+ print(json.dumps({"files": recipe["files"], "graph": recipe["graph"]}, indent=2))
262
+
263
+
264
+ if __name__ == "__main__":
265
+ main()
export/recipe.json ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "llama3_2_1b_instruct_q4gsw",
3
+ "upstream": {
4
+ "model": "meta-llama/Llama-3.2-1B-Instruct",
5
+ "revision": "9213176726f574b556790deb65791e0c5aa438b6",
6
+ "official": true,
7
+ "license": "Llama 3.2 Community License (tokenizer/LICENSE.txt, tokenizer/USE_POLICY.md); Built with Llama",
8
+ "files": {
9
+ "original/consolidated.00.pth": {
10
+ "lfs": "fc17d497df5e4175b3a8acb4f5865b26f7fc1b009b25bef814b95fde10e8a1f3",
11
+ "sha256": "fc17d497df5e4175b3a8acb4f5865b26f7fc1b009b25bef814b95fde10e8a1f3"
12
+ },
13
+ "original/params.json": {
14
+ "blob": "9cd8dbdf2dc6f4d8abb60bdb5ce64f4bec2fdfd9",
15
+ "git_blob_sha1": "9cd8dbdf2dc6f4d8abb60bdb5ce64f4bec2fdfd9"
16
+ },
17
+ "tokenizer.json": {
18
+ "blob": "5cc5f00a5b203e90a27a3bd60d1ec393b07971e8",
19
+ "git_blob_sha1": "5cc5f00a5b203e90a27a3bd60d1ec393b07971e8"
20
+ },
21
+ "tokenizer_config.json": {
22
+ "blob": "4ff488a165e900e5129cda7c20ab32d568d2a475",
23
+ "git_blob_sha1": "4ff488a165e900e5129cda7c20ab32d568d2a475"
24
+ },
25
+ "special_tokens_map.json": {
26
+ "blob": "02ee80b6196926a5ad790a004d9efd6ab1ba6542",
27
+ "git_blob_sha1": "02ee80b6196926a5ad790a004d9efd6ab1ba6542"
28
+ },
29
+ "config.json": {
30
+ "blob": "3e3aaf51a035cb5092d9f6827a0dc074657ba88c",
31
+ "git_blob_sha1": "3e3aaf51a035cb5092d9f6827a0dc074657ba88c"
32
+ },
33
+ "generation_config.json": {
34
+ "blob": "75ae08310d6d23df373ee2644b497192b3cce6d8",
35
+ "git_blob_sha1": "75ae08310d6d23df373ee2644b497192b3cce6d8"
36
+ },
37
+ "LICENSE.txt": {
38
+ "blob": "085b47c1575cb889b7024030e60b78f54f0b8c9e",
39
+ "git_blob_sha1": "085b47c1575cb889b7024030e60b78f54f0b8c9e"
40
+ },
41
+ "USE_POLICY.md": {
42
+ "blob": "ac3c5f21b9779e3da0677d6d3c587778fe3a331e",
43
+ "git_blob_sha1": "ac3c5f21b9779e3da0677d6d3c587778fe3a331e"
44
+ }
45
+ },
46
+ "hub_revision_checked": "9213176726f574b556790deb65791e0c5aa438b6",
47
+ "downloaded_from": {
48
+ "repo": "LIF1014/ptdbench-Llama-3.2-1B-Instruct",
49
+ "revision": "828e5f37c833a02415416260d5a93780fd41d10e",
50
+ "note": "all files verified byte-identical to the official hashes above"
51
+ }
52
+ },
53
+ "versions": {
54
+ "python": "3.12.15+meta",
55
+ "torch": "2.14.1+cpu",
56
+ "torchao": "0.18.0+cpu",
57
+ "executorch": "1.5.1+cpu",
58
+ "executorch_git": "3b60683923245cf472b7323426920e15623ba361",
59
+ "transformers": "5.19.0",
60
+ "huggingface_hub": "2.2.0"
61
+ },
62
+ "export": {
63
+ "api": "python -m executorch.extension.llm.export.export_llm (hydra overrides below)",
64
+ "overrides": [
65
+ "base.model_class=llama3_2",
66
+ "base.checkpoint=<out>/_work/checkpoint.pth",
67
+ "base.params=<out>/_work/params.json",
68
+ "model.use_kv_cache=true",
69
+ "model.use_sdpa_with_kv_cache=true",
70
+ "model.enable_dynamic_shape=true",
71
+ "model.dtype_override=fp32",
72
+ "export.max_seq_length=513",
73
+ "export.max_context_length=8960",
74
+ "export.output_dir=<out>",
75
+ "export.output_name=<out>/llama3_2_1b_instruct_q4gsw.pte",
76
+ "quantization.qmode=4w",
77
+ "quantization.group_size=64",
78
+ "quantization.embedding_quantize='4,64'",
79
+ "backend.vulkan.enabled=true"
80
+ ],
81
+ "checkpoint": "original/consolidated.00.pth (Meta format, bf16; no conversion), params = original/params.json",
82
+ "params": {
83
+ "dim": 2048,
84
+ "n_layers": 16,
85
+ "n_heads": 32,
86
+ "n_kv_heads": 8,
87
+ "vocab_size": 128256,
88
+ "ffn_dim_multiplier": 1.5,
89
+ "multiple_of": 256,
90
+ "norm_eps": 1e-05,
91
+ "rope_theta": 500000.0,
92
+ "use_scaled_rope": true
93
+ },
94
+ "rope": "llama3 scaled RoPE, rope_scale_factor=32 (set by ExecuTorch for model_class llama3_2 when use_scaled_rope)",
95
+ "partitioner": "VulkanPartitioner via backend.vulkan.enabled (WebGPUPartitioner is a pass-through wrapper of it; delegate id VulkanBackend)",
96
+ "inputs": [
97
+ {
98
+ "name": "tokens",
99
+ "shape": [
100
+ 1,
101
+ "1..512"
102
+ ],
103
+ "dtype": "int64"
104
+ },
105
+ {
106
+ "name": "input_pos",
107
+ "shape": [
108
+ 1
109
+ ],
110
+ "dtype": "int64"
111
+ }
112
+ ],
113
+ "outputs": [
114
+ {
115
+ "name": "logits",
116
+ "shape": [
117
+ 1,
118
+ 128256
119
+ ],
120
+ "dtype": "float32",
121
+ "note": "last position only"
122
+ }
123
+ ],
124
+ "prefill_max": 512,
125
+ "max_seq_len_metadata": 513,
126
+ "max_context_length": 8960,
127
+ "dtype": "float32 activations",
128
+ "quantization": "4-bit groupwise weight-only linears (torchao IntxWeightOnlyConfig int4, group 64) and 4-bit groupwise embedding (group 64); output head quantized too",
129
+ "kv_cache": "fp32 buffers in the program; fp16 KV is a runtime option of the WebGPU runtime (enable_f16_kv_cache / et_set_kv_f16), not an export flag"
130
+ },
131
+ "files": {
132
+ "llama3_2_1b_instruct_q4gsw.pte": {
133
+ "bytes": 734868736,
134
+ "sha256": "49de6eec3a54f1f45a785152375edafec07cb0fd879a142100340fd2765c40a7"
135
+ },
136
+ "tokenizer/tokenizer.json": {
137
+ "sha256": "79e3e522635f3171300913bb421464a87de6222182a0570b9b2ccba2a964b2b4"
138
+ },
139
+ "tokenizer/tokenizer_config.json": {
140
+ "sha256": "9823dcfdc1121869029da45192238e85cf44f0b232a6d9dc20e4fe6f4242a14e"
141
+ },
142
+ "tokenizer/special_tokens_map.json": {
143
+ "sha256": "6f38c73729248f6c127296386e3cdde96e254636cc58b4169d3fd32328d9a8ec"
144
+ },
145
+ "tokenizer/config.json": {
146
+ "sha256": "2febf68cea25bf4611be02b7536f2488a5ba523bb1134986e3610152abe74fdb"
147
+ },
148
+ "tokenizer/generation_config.json": {
149
+ "sha256": "88effbb63300dbbc7390143fbbdd9d9fa50587b37e8bfd16c8c90d4970a74a36"
150
+ },
151
+ "tokenizer/LICENSE.txt": {
152
+ "sha256": "0b4284c1f87029e67654c7953afa16279961632cf73dcfe33374c4c2f298fa35"
153
+ },
154
+ "tokenizer/USE_POLICY.md": {
155
+ "sha256": "40e2777d7faa6beaf98400654170f414d8ab29b921b5163ad4ea0a1d39894201"
156
+ }
157
+ },
158
+ "graph": {
159
+ "non_delegated_kernels": {},
160
+ "delegates": [
161
+ {
162
+ "id": "VulkanBackend",
163
+ "ops": {
164
+ "et_vk.prepack.default": 2,
165
+ "sym_size.int": 1,
166
+ "et_vk.embedding_q4gsw.default": 1,
167
+ "et_vk.select_as_symint.default": 2,
168
+ "add": 1,
169
+ "aten.slice_copy.Tensor": 2,
170
+ "et_vk.rms_norm.default": 33,
171
+ "et_vk.linear_q4gsw.default": 113,
172
+ "aten.view_copy.default": 128,
173
+ "et_vk.apply_rotary_emb.default": 16,
174
+ "sdpa_with_kv_cache.default": 16,
175
+ "aten.add.Tensor": 32,
176
+ "aten.sigmoid.default": 16,
177
+ "aten.mul.Tensor": 32,
178
+ "aten.select_copy.int": 1
179
+ },
180
+ "inputs": 2,
181
+ "outputs": 1
182
+ }
183
+ ]
184
+ },
185
+ "command": "python recipes/llama-3.2-1b-instruct.py --out out/llama-3.2-1b-instruct"
186
+ }
export/requirements.txt ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Environment the re-exports in REEXPORT.md were produced with (Python 3.12, Linux x86_64, CPU only).
2
+ # python -m venv venv
3
+ # venv/bin/pip install -r recipes/requirements.txt --extra-index-url https://download.pytorch.org/whl/cpu
4
+ # executorch 1.5.1 = pytorch/executorch git 3b60683923245cf472b7323426920e15623ba361; its wheel ships
5
+ # backends/webgpu (WebGPUPartitioner) and examples/models/llama (export_llm).
6
+ executorch==1.5.1
7
+ torch==2.14.1+cpu
8
+ torchvision==0.29.1+cpu
9
+ torchao==0.18.0+cpu
10
+ transformers==5.19.0
11
+ huggingface_hub==2.2.0
12
+ safetensors==0.8.0
13
+ tokenizers==0.23.3
14
+ numpy==2.5.4
15
+ pillow==12.3.0
model_ctx8960_m512.pte → llama3_2_1b_instruct_q4gsw.pte RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:66c9d2934daf17fb25fe52a7c2f01616142eef48532c88c2f97aa710817176ea
3
- size 882609536
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:49de6eec3a54f1f45a785152375edafec07cb0fd879a142100340fd2765c40a7
3
+ size 734868736
manifest.json CHANGED
@@ -3,9 +3,9 @@
3
  "repo": "executorch-community/Llama-3.2-1B-Instruct-ExecuTorch-WebGPU",
4
  "files": [
5
  {
6
- "path": "model_ctx8960_m512.pte",
7
- "bytes": 882609536,
8
- "sha256": "66c9d2934daf17fb25fe52a7c2f01616142eef48532c88c2f97aa710817176ea"
9
  },
10
  {
11
  "path": "tokenizer/config.json",
 
3
  "repo": "executorch-community/Llama-3.2-1B-Instruct-ExecuTorch-WebGPU",
4
  "files": [
5
  {
6
+ "path": "llama3_2_1b_instruct_q4gsw.pte",
7
+ "bytes": 734868736,
8
+ "sha256": "49de6eec3a54f1f45a785152375edafec07cb0fd879a142100340fd2765c40a7"
9
  },
10
  {
11
  "path": "tokenizer/config.json",