mlboydaisuke commited on
Commit
3c378f7
·
verified ·
1 Parent(s): 02a2295

Upload README.md with huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +65 -79
README.md CHANGED
@@ -12,85 +12,71 @@ base_model:
12
  ---
13
  # all-MiniLM-L6-v2 — ExecuTorch
14
 
15
- Sentence embeddings: text in, one vector out. For search, clustering and retrieval that
16
- never leaves the device.
 
17
 
18
- - **Source**: sentence-transformers/all-MiniLM-L6-v2 — 22M parameters, 6 BERT layers, 384-dimensional output
19
- - **License**: Apache-2.0
20
  - **Input**: `input_ids` and `attention_mask`, both `[1, 256]` int64
21
- - **Output**: `[1, 384]`
22
-
23
- ## The pooling is in the graph, on purpose
24
-
25
- sentence-transformers keeps the recipe per model in `1_Pooling/config.json` and
26
- `modules.json`, and the three small models on this shelf do not agree:
27
-
28
- | | pooling | normalised |
29
- |---|---|---|
30
- | all-MiniLM-L6-v2 | mean | yes |
31
- | bge-small-en-v1.5 | **CLS** | yes |
32
- | paraphrase-multilingual-L12 | mean | **no** |
33
-
34
- This one uses mean over the attention mask, then L2 normalise. Getting it wrong does not throw: mean-pooling BGE, or normalising
35
- the multilingual one, gives vectors that look fine and rank wrong. So it is baked in rather
36
- than left to the caller.
37
-
38
- ## Verification (Mac arm64, 2026-08-23)
39
-
40
- | build | size | latency | worst cosine vs eager |
41
- |---|---|---|---|
42
- | XNNPACK fp32 | 90.4 MB | 14.4 ms | 1.000000 |
43
- | XNNPACK fp16 | 45.3 MB | 26.3 ms | 0.999999 |
44
- | Core ML fp32 | 45.4 MB | **2.0 ms** | 0.999984 |
45
-
46
- Eager fp32 on the same input is 8.5 ms. Cosine is against the model run in eager through
47
- its own documented pooling, over eight sentences including one in Japanese — not against
48
- random token ids, which would tell you nothing.
49
-
50
- **And that the vectors are useful**, which agreement alone cannot show:
51
-
52
- ```
53
- 0.588 a paraphrase vs -0.063 an unrelated sentence
54
- ```
55
-
56
- Across languages "機械学習のモデルを端末の上で動かす" against "On-device inference keeps
57
- the data on the phone", with an unrelated sentence about the weather — this model scores
58
- -0.047 against 0.125 — it does not, and should not.
59
-
60
- ## Not shipped
61
-
62
- **int8** converts and holds — worst cosine 0.998018 against eager over the same eight
63
- sentences but it comes out at **58.6 MB against fp16's 45.3 MB**, so nothing would pick
64
- it. The reason is arithmetic rather than a defect: dynamic int8 quantizes the linear
65
- weights and leaves the token embedding table alone, and that table is 46.9 MB of a 90.4 MB
66
- model. Quantizing every linear saves 31.8 MB; fp16 halves the table too. On a model whose
67
- weights are mostly a vocabulary, fp16 is the smaller build.
68
-
69
- An earlier version of this card said int8 *does not export*, with an `IndexError: tensors
70
- used as indices must be long, int, byte or bool tensors`. That was true of the build at the
71
- time and the cause was misread. The error is not in the embedding lookup: XNNPACKQuantizer's
72
- `transform_for_annotation` lifts every scalar argument of `add.Tensor`/`mul.Tensor` into a
73
- buffer and writes it as `torch.tensor(float(arg))` regardless of the node's dtype, so the
74
- `arange(n) + 0` that builds a HuggingFace attention mask comes back float32 and can no
75
- longer index. It is one line in ExecuTorch
76
- (`backends/xnnpack/quantizer/xnnpack_quantizer_utils.py`, still present on main), and it
77
- affects every BERT-family model, not these three.
78
-
79
- ## Worth knowing about the speed
80
-
81
- XNNPACK fp32 is **slower than PyTorch eager** here (14.4 ms against 8.5), and fp16
82
- is slower again while halving the file. Core ML is the one that pays: 2.0 ms, roughly
83
- 4.2x eager, at half the size. If this is going on an Apple device, take the Core ML
84
- build.
85
-
86
- ## Conversion
87
-
88
- ```bash
89
- python convert/export_embed.py all_minilm_l6
90
- python convert/check_embed.py all_minilm_l6
91
- ```
92
-
93
- Sequence length is fixed at 256; the attention mask makes padding harmless for mean pooling,
94
- and chunking anything longer is the caller's job.
95
-
96
  (conversion scripts: [executorch-models](https://github.com/john-rocky/executorch-models))
 
12
  ---
13
  # all-MiniLM-L6-v2 — ExecuTorch
14
 
15
+ Six layers, and the cheapest embedding on this shelf. Text in, one
16
+ 384-dimensional vector out, for search and retrieval that never leaves the
17
+ device.
18
 
19
+ - **Source**: sentence-transformers/all-MiniLM-L6-v2 — 6 layers, 384 dimensions, 30,522 vocabulary
20
+ - **License**: apache-2.0
21
  - **Input**: `input_ids` and `attention_mask`, both `[1, 256]` int64
22
+ - **Output**: `[1, 384]`, mean-pooled and L2-normalised inside the graph
23
+
24
+ ## The recipe is in the graph, and it was read off this repo
25
+
26
+ sentence-transformers stores it per model, and the shelf's seven embedding models do
27
+ not agree. This one pools **mean** and
28
+ **normalises**, read from
29
+ `1_Pooling/config.json` and `modules.json` rather than inferred from the family name.
30
+ Getting it wrong does not throw; it returns vectors that look fine and rank wrong.
31
+
32
+ ## Verification
33
+
34
+ | build | file | size (MB) | Mac ms* | backend takes | worst cosine vs eager | retrieval budget |
35
+ |---|---|---|---|---|---|---|
36
+ | fp32 | `embed_all_minilm_l6_xnnpack_fp32.pte` | 90.4 | 11.1 | 73.4% | 1.000000 | 0% |
37
+ | fp16 | `embed_all_minilm_l6_xnnpack_fp16.pte` | 45.3 | 16.7 | 63.4% | 0.999999 | 4% |
38
+ | Core ML (fp16, iOS) | `embed_all_minilm_l6_coreml_all.pte` | 45.7 | 2.0 | 100.0% | 0.999984 | 19% |
39
+
40
+ \*Mac arm64, median of 10, one 256-token sequence — a reference point for relative
41
+ cost, not a device number. Torch eager fp32 on the same machine is
42
+ 10.5 ms.
43
+
44
+ Cosine is measured against the model run in eager through its own pooling, over eight
45
+ sentences. The last column is the one that decides: rank those eight against each
46
+ other, and ask whether this build's score error is smaller than the gap between the
47
+ document a query retrieves and the runner-up. Every shipped build keeps all eight
48
+ top-1 results.
49
+
50
+ ## The attention is eager, and that is the faster export
51
+
52
+ `F.scaled_dot_product_attention` decomposes in the edge dialect to `_safe_softmax`,
53
+ whose guard against a fully-masked row costs six operations XNNPACK cannot take —
54
+ `scalar_tensor`, `where`, `logical_not`, `eq`, `full_like`, `any.dim` once per
55
+ attention block, and each one cuts the subgraph in two. The guard can only ever fire
56
+ when some query row loses **every** key, which needs left padding or an empty
57
+ sequence. This model is right-padded, so even a row that is all padding still sees the
58
+ real tokens and the guard protects nothing.
59
+
60
+ Exporting with `attn_implementation="eager"` removes it. Measured with 251 of 256
61
+ positions masked — as adversarial as this shape gets — the two graphs agree to 1.4e-07,
62
+ and XNNPACK fp32 goes from **59.7% to 73.4%** delegated.
63
+
64
+ ## Not shipped: int8
65
+
66
+ `embed_all_minilm_l6_xnnpack_int8.pte` is **58.6 MB** against fp16's 45.3 MB. Dynamic int8 quantises the
67
+ linear weights and leaves the token embedding table in fp32, and here that table is
68
+ 47 MB of the 90.4 MB model **52%**. The size a build comes out at is
69
+ `0.5 + 1.5 x (table share)` times the fp16 build; at 52% that is
70
+ 1.28, so there was never a smaller file to be had.
71
+
72
+ It is withheld on the number that decides. Ranking the eight test sentences against
73
+ each other, this build moves a pair score by at most **0.0102** while the
74
+ closest fp32 decision the gap between the document a query retrieves and the
75
+ runner-up is **0.0059**. That is **173%** of
76
+ the room available, against a bar of 50%.
77
+
78
+ Correlation reads 0.998751 for this build, which no correlation gate
79
+ would stop.
80
+
81
+ torch.export -> to_edge_transform_and_lower(partitioner) -> .pte
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  (conversion scripts: [executorch-models](https://github.com/john-rocky/executorch-models))