kucukkanat commited on
Commit
768e6d6
·
verified ·
1 Parent(s): 77c7280

Add ONNX export for transformers.js

Browse files
README.md ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: other
3
+ license_name: lfm1.0
4
+ license_link: https://huggingface.co/LiquidAI/LFM2.5-Encoder-350M-Prompt-Router/blob/main/LICENSE
5
+ base_model: LiquidAI/LFM2.5-Encoder-350M-Prompt-Router
6
+ base_model_relation: quantized
7
+ library_name: transformers.js
8
+ pipeline_tag: zero-shot-classification
9
+ tags:
10
+ - onnx
11
+ - transformers.js
12
+ - lfm2
13
+ - quantized
14
+ language:
15
+ - en
16
+ - de
17
+ - es
18
+ - fr
19
+ - it
20
+ - nl
21
+ - pl
22
+ - pt
23
+ - ar
24
+ - hi
25
+ - ja
26
+ - ru
27
+ - tr
28
+ - vi
29
+ - zh
30
+ ---
31
+
32
+ # LFM2.5-Encoder-350M-Prompt-Router-ONNX
33
+
34
+ ONNX export of [`LiquidAI/LFM2.5-Encoder-350M-Prompt-Router`](https://huggingface.co/LiquidAI/LFM2.5-Encoder-350M-Prompt-Router), quantized to run **fully in the browser** through
35
+ [transformers.js](https://github.com/huggingface/transformers.js). No inference server: the weights are
36
+ fetched once, cached, and every forward pass happens in the tab.
37
+
38
+ A zero-shot prompt router. Categories are ordinary prose supplied at call time — nothing is
39
+ trained or cached per label set. One bidirectional pass over the category list *and* the text
40
+ scores every category at once.
41
+
42
+ All credit for the model itself goes to [Liquid AI](https://huggingface.co/LiquidAI). This repository
43
+ contains only a re-export; the weights are unchanged apart from quantization, and the original
44
+ [LFM Open License v1.0](https://huggingface.co/LiquidAI/LFM2.5-Encoder-350M-Prompt-Router/blob/main/LICENSE) applies.
45
+
46
+ Tooling, demo and the export pipeline: <https://github.com/kucukkanat/lfm-encoders>
47
+
48
+ ## Files
49
+
50
+ | dtype | File | Size |
51
+ | --- | --- | --: |
52
+ | `q8` | `onnx/model_quantized.onnx` | 357 MB |
53
+ | `q4` | `onnx/model_q4.onnx` | 449 MB |
54
+
55
+ The graph takes `input_ids` + `attention_mask`, is dynamic in batch and sequence, and returns
56
+ `token_proj` and `rule_proj`.
57
+
58
+ ## Usage
59
+
60
+ ```js
61
+ import { AutoTokenizer, PreTrainedModel, Tensor } from "@huggingface/transformers";
62
+
63
+ const id = "kucukkanat/LFM2.5-Encoder-350M-Prompt-Router-ONNX";
64
+ const tokenizer = await AutoTokenizer.from_pretrained(id);
65
+ const model = await PreTrainedModel.from_pretrained(id, { dtype: "q8" });
66
+
67
+ const { input_ids } = tokenizer("some text");
68
+ const out = await model({
69
+ input_ids,
70
+ attention_mask: new Tensor("int64", new BigInt64Array(input_ids.dims[1]).fill(1n), input_ids.dims),
71
+ });
72
+ ```
73
+
74
+ `PreTrainedModel` rather than `AutoModel` is deliberate: this is a plain "feed the named inputs, read the
75
+ named outputs" session, not one of transformers.js's built-in architectures.
76
+
77
+ ### Prompt format
78
+
79
+ Both projection towers expect one string laid out exactly like this — the model was trained on it and the
80
+ character arithmetic that locates each label depends on it byte for byte:
81
+
82
+ ```
83
+ Categories:
84
+ - label one
85
+ - label two
86
+
87
+ Text:
88
+ <the text>
89
+ ```
90
+
91
+ `token_proj` is the query tower and `rule_proj` the key tower, both 256-d and emitted **per token**. Pool
92
+ the tokens covering each label to get its vector. Pooling after projecting is exact rather than an
93
+ approximation: both towers are affine, and an affine map commutes with a mean — which is what keeps one
94
+ static graph usable for any number of labels.
95
+
96
+ Scoring is `cosine between the L2-normalised pooled towers, scaled by a learned temperature, then a softmax across labels`.
97
+
98
+ [`@lfm-encoder/tasks`](https://github.com/kucukkanat/lfm-encoders) implements all of this, including the
99
+ character-offset reconstruction transformers.js does not provide.
100
+
101
+
102
+ ## Accuracy
103
+
104
+ Measured from JavaScript against the fp32 PyTorch reference. Δ is the largest absolute difference in a
105
+ final probability.
106
+
107
+ | dtype | max Δ | mean Δ | top-1 flips (4 cases) |
108
+ | --- | --: | --: | --: |
109
+ | `fp32` | 6.4e-5 | 1.6e-5 | 0 |
110
+ | `q8` | 0.0910 | 0.0230 | 0 |
111
+ | `q4` | 0.1221 | 0.0309 | 0 |
112
+
113
+ ## Notes
114
+
115
+ - `q8` is smaller on disk but uses **more** browser RAM than fp32 and runs slower: onnxruntime's WASM
116
+ kernels compute in float, so quantized weights are unpacked at session load. Quantization here buys
117
+ download size, not speed or memory.
118
+ - Budget roughly 1.5 GB of RAM per resident model, and expect a tab to hold its high-water mark until
119
+ reloaded.
120
+ - `fp16` / `q4f16` are deliberately absent: RMSNorm's variance overflows fp16 on this architecture and
121
+ every hidden state collapses to zeros.
config.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model_type": "lfm2-bidirectional",
3
+ "architectures": [
4
+ "TwoTowerGraph"
5
+ ],
6
+ "task": "zero-shot-routing",
7
+ "source_model": "LiquidAI/LFM2.5-Encoder-350M-Prompt-Router",
8
+ "hidden_size": 1024,
9
+ "vocab_size": 65536,
10
+ "real_vocab_size": 64402,
11
+ "num_hidden_layers": 16,
12
+ "layer_types": [
13
+ "conv",
14
+ "conv",
15
+ "full_attention",
16
+ "conv",
17
+ "conv",
18
+ "full_attention",
19
+ "conv",
20
+ "conv",
21
+ "full_attention",
22
+ "conv",
23
+ "full_attention",
24
+ "conv",
25
+ "full_attention",
26
+ "conv",
27
+ "full_attention",
28
+ "conv"
29
+ ],
30
+ "max_position_embeddings": 128000,
31
+ "transformers.js_config": {
32
+ "kv_cache_dtype": null,
33
+ "use_external_data_format": false
34
+ },
35
+ "onnx": {
36
+ "inputs": [
37
+ "input_ids",
38
+ "attention_mask"
39
+ ],
40
+ "outputs": [
41
+ "token_proj",
42
+ "rule_proj"
43
+ ]
44
+ },
45
+ "head": {
46
+ "kind": "cosine",
47
+ "normalize": true,
48
+ "scale": 1.3714938163757324,
49
+ "bias": -0.2723352313041687,
50
+ "activation": "softmax",
51
+ "prefix_heading": "Categories",
52
+ "proj_dim": 256
53
+ }
54
+ }
onnx/model_q4.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ac624f7a15ee59888603170573aa39f16268ccdd7d86117f60737f45cc86840a
3
+ size 448954295
onnx/model_quantized.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:353b79e0052f80bd4049542f55a487c6d418a79bc1a2e02f28e6c22f432afdc3
3
+ size 356839915
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "bos_token": "<|startoftext|>",
4
+ "clean_up_tokenization_spaces": false,
5
+ "eos_token": "<|im_end|>",
6
+ "is_local": false,
7
+ "mask_token": "<|mask|>",
8
+ "model_max_length": 1000000000000000019884624838656,
9
+ "pad_token": "<|pad|>",
10
+ "tokenizer_class": "TokenizersBackend"
11
+ }