Update README.md
Browse files
README.md
CHANGED
|
@@ -1,5 +1,146 @@
|
|
| 1 |
---
|
| 2 |
-
license:
|
| 3 |
-
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
library_name: onnx
|
| 4 |
+
pipeline_tag: feature-extraction
|
| 5 |
+
base_model: sentence-transformers/all-MiniLM-L12-v2
|
| 6 |
+
tags:
|
| 7 |
+
- onnx
|
| 8 |
+
- sentence-similarity
|
| 9 |
+
- feature-extraction
|
| 10 |
+
- retrieval
|
| 11 |
+
- knowledge-distillation
|
| 12 |
---
|
| 13 |
+
|
| 14 |
+
# flowgraph-a2-student-l12
|
| 15 |
+
|
| 16 |
+
The embedding model used by [FlowGraph](https://github.com/tokenfactory-jobtoken/FlowGraph) β a
|
| 17 |
+
local-first desktop app that gives AI tools persistent, graph-shaped memory stored on the user's own
|
| 18 |
+
machine.
|
| 19 |
+
|
| 20 |
+
These are **FlowGraph's own trained weights**: a MiniLM-L12 student **distilled** from a
|
| 21 |
+
permissively-licensed offline teacher. No third-party model is redistributed here. The model runs
|
| 22 |
+
**locally and in-process** via ONNX Runtime β no API key, no network call at inference time.
|
| 23 |
+
|
| 24 |
+
## What's in this repo
|
| 25 |
+
|
| 26 |
+
A single packaged bundle, `embedder-onnx-bundle-a2-student-l12.tar.gz` (~124 MB), which FlowGraph's
|
| 27 |
+
installer downloads by pinned digest. Inside, at the archive root:
|
| 28 |
+
|
| 29 |
+
| file | sha256 |
|
| 30 |
+
|---|---|
|
| 31 |
+
| `model.onnx` | `d99dbe939d43fd691d8ad36665f5f74592930d9d41ec00c47f44e32f0899bb27` |
|
| 32 |
+
| `vocab.txt` | `26e5c70d53771ba1a86b01f21baed1bf6f401236bcc15fd2cb73f0a0ea5aba66` |
|
| 33 |
+
| `config.json` | `be86edead4f536af99471225bfb498006c897aa2db9c754cc36a97d9c7d43783` |
|
| 34 |
+
| `tokenizer.json`, `tokenizer_config.json` | (HuggingFace tokenizer artifacts; unused by FlowGraph's in-tree WordPiece tokenizer, which reads `vocab.txt`) |
|
| 35 |
+
|
| 36 |
+
Bundle identity (`specVersion`, a merkle-sha256 over `model.onnx` + `vocab.txt` + `config.json`):
|
| 37 |
+
|
| 38 |
+
```
|
| 39 |
+
96e68b60d45a33a2f3c5a53d37b01f17c36b1378819cd8f3a9f6ad5d8ebee195
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
Archive sha256: `0946c46dba4c5682e5567b53563a5f4f493abc2199677482ac80090720afd11d`
|
| 43 |
+
|
| 44 |
+
## Architecture
|
| 45 |
+
|
| 46 |
+
MiniLM-L12 (12 layers, hidden 384, 12 heads, ~34M params) β mean pooling β `Dense(384 β 768, no bias,
|
| 47 |
+
identity activation)` β L2 normalize. The exported ONNX bakes the whole pipeline in: it takes
|
| 48 |
+
`input_ids` + `attention_mask` and emits a single **L2-normalized 768-d `sentence_embedding`** per row.
|
| 49 |
+
There is no `token_type_ids` input.
|
| 50 |
+
|
| 51 |
+
- dimensions: **768**
|
| 52 |
+
- max sequence length: **256**
|
| 53 |
+
- text prefix: **`search_document: `** β prepended to *both* passages and queries (see below)
|
| 54 |
+
- tokenizer: BERT WordPiece, uncased, accent-stripping
|
| 55 |
+
|
| 56 |
+
## Usage
|
| 57 |
+
|
| 58 |
+
```python
|
| 59 |
+
import numpy as np, onnxruntime as ort
|
| 60 |
+
from tokenizers import Tokenizer
|
| 61 |
+
|
| 62 |
+
tok = Tokenizer.from_file("tokenizer.json"); tok.enable_truncation(max_length=256)
|
| 63 |
+
sess = ort.InferenceSession("model.onnx", providers=["CPUExecutionProvider"])
|
| 64 |
+
|
| 65 |
+
def embed(texts):
|
| 66 |
+
enc = [tok.encode("search_document: " + t).ids for t in texts] # NOTE: same prefix for queries
|
| 67 |
+
L = max(len(e) for e in enc)
|
| 68 |
+
ids = np.zeros((len(enc), L), dtype=np.int64)
|
| 69 |
+
mask = np.zeros((len(enc), L), dtype=np.int64)
|
| 70 |
+
for i, e in enumerate(enc):
|
| 71 |
+
ids[i, :len(e)] = e; mask[i, :len(e)] = 1
|
| 72 |
+
return sess.run(None, {"input_ids": ids, "attention_mask": mask})[0] # already unit-normalized
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
**The prefix is symmetric.** Unlike nomic-class models, this student was distilled on a single
|
| 76 |
+
`search_document: ` regime, so queries take the *same* prefix as passages. Using `search_query: ` puts
|
| 77 |
+
the input out of distribution.
|
| 78 |
+
|
| 79 |
+
## Training
|
| 80 |
+
|
| 81 |
+
Distilled from **`nomic-ai/nomic-embed-text-v1.5`** at revision
|
| 82 |
+
`e9b6763023c676ca8431644204f50c2b100d9aab` (Apache-2.0), used strictly as an **offline teacher** β its
|
| 83 |
+
weights are not redistributed.
|
| 84 |
+
|
| 85 |
+
| | |
|
| 86 |
+
|---|---|
|
| 87 |
+
| loss | pointwise MSE to the teacher's L2-normalized embedding **+ relational** in-batch pairwise-similarity MSE (match the teacher's *rankings*, not just its coordinates) |
|
| 88 |
+
| corpus | `wikimedia/wikipedia`, config `20231101.simple`, split `train`; texts with `len > 100`, truncated to the first 512 chars, first **150,000** in dataset order |
|
| 89 |
+
| epochs / batch / lr / warmup | 4 / 128 / 2e-4 / 100 |
|
| 90 |
+
| precision | AMP (fp16), single GPU |
|
| 91 |
+
| max seq length | 256 |
|
| 92 |
+
| student init | `sentence-transformers/all-MiniLM-L12-v2` + the Dense projection head + Normalize |
|
| 93 |
+
|
| 94 |
+
The relational term is what made this work: plain MSE-to-embedding plateaued around 59% on an internal
|
| 95 |
+
doc-level proxy regardless of student size (23M / 34M / 110M all landed in the same band), while adding
|
| 96 |
+
the in-batch pairwise-similarity term lifted the 34M student to ~71% β about 95% of the teacher at
|
| 97 |
+
roughly a quarter of the parameters.
|
| 98 |
+
|
| 99 |
+
**Reproducibility.** No RNG seed was set during training, so bit-identical retraining is not possible
|
| 100 |
+
by construction. The contract is: the **released checkpoint is pinned by hash** (above) and the
|
| 101 |
+
procedure is documented; reproduction means *equivalent under this procedure*, not bit-identical.
|
| 102 |
+
|
| 103 |
+
## Export
|
| 104 |
+
|
| 105 |
+
`torch.onnx.export` (legacy exporter, `dynamo=False`), opset **17**, `do_constant_folding=True`, dynamic
|
| 106 |
+
axes `{0: batch, 1: seq}` on the inputs. Attention is forced to **eager** at export time. (For the
|
| 107 |
+
record: an earlier SDPA-traced export produces numerically *identical* vectors β cosine 1.00000 and 100%
|
| 108 |
+
top-10 neighbour overlap across a probe set β so the attention implementation is pinned for procedure
|
| 109 |
+
fidelity, not because it changes the vector space.)
|
| 110 |
+
|
| 111 |
+
Faithfulness was verified against the PyTorch reference on 200 real corpus texts (including 73 short,
|
| 112 |
+
label-like strings): **min cosine 1.00000, mean 1.00000, top-10 neighbour overlap 100.0%**.
|
| 113 |
+
|
| 114 |
+
## Evaluation
|
| 115 |
+
|
| 116 |
+
Measured inside FlowGraph's retrieval benchmark at node level, with the **graph held constant** and only
|
| 117 |
+
the embedder swapped (so the numbers isolate the embedder rather than the ingest), 200 labeled queries
|
| 118 |
+
per dataset, `k=10`:
|
| 119 |
+
|
| 120 |
+
| | ArguAna (1000 distractors) | HotpotQA |
|
| 121 |
+
|---|--:|--:|
|
| 122 |
+
| this model β vector recall@10 | **38.5%** | **60.5%** |
|
| 123 |
+
| FlowGraph's previous static embedder | 30.5% | 31.0% |
|
| 124 |
+
| teacher (nomic-embed-text-v1.5) | 48.5% | 65.3% |
|
| 125 |
+
| this model β hybrid nDCG@10 | **0.330** | **0.611** |
|
| 126 |
+
| teacher β hybrid nDCG@10 | 0.340 | 0.612 |
|
| 127 |
+
|
| 128 |
+
On raw vector recall the student reaches 79β93% of its teacher. On the **fused hybrid channel** the app
|
| 129 |
+
actually serves (reciprocal-rank fusion of vector + BM25 + graph walk) it reaches **97β100%** of the
|
| 130 |
+
teacher, and slightly *exceeds* it on HotpotQA MRR. Note that these are node-level scores over an
|
| 131 |
+
LLM-extracted knowledge graph, not standard BEIR document retrieval numbers, so they are not comparable
|
| 132 |
+
to published BEIR leaderboards.
|
| 133 |
+
|
| 134 |
+
Inference is CPU-cheap: roughly **25 ms/text** single-threaded on a 2-core container for short inputs.
|
| 135 |
+
|
| 136 |
+
## Intended use & limitations
|
| 137 |
+
|
| 138 |
+
Built for retrieval over a personal knowledge graph: short node labels and document chunks, English,
|
| 139 |
+
β€256 tokens. It is a distilled student β on raw semantic recall the teacher is still better, and it
|
| 140 |
+
inherits the teacher's and the Simple-English-Wikipedia corpus's biases. Not evaluated for
|
| 141 |
+
classification, clustering, or non-English text.
|
| 142 |
+
|
| 143 |
+
## License
|
| 144 |
+
|
| 145 |
+
Apache-2.0. The weights are FlowGraph's own; the teacher was used offline under its own Apache-2.0
|
| 146 |
+
terms and is not redistributed here.
|