|
Download README.md from faxenoff/code-daemon-ner-v1: direct link, hf CLI and curl.
- Browser
- Download file 7.89 kB
-
https://huggingface.co/faxenoff/code-daemon-ner-v1/resolve/main/README.md
- Command line
-
hf download hf://faxenoff/code-daemon-ner-v1/README.md
-
curl -L -o README.md https://huggingface.co/faxenoff/code-daemon-ner-v1/resolve/main/README.md
7.89 kB
| license: mit | |
| language: | |
| - code | |
| - en | |
| - ru | |
| tags: | |
| - code | |
| - token-classification | |
| - named-entity-recognition | |
| - ner | |
| - xlm-roberta | |
| - weak-supervision | |
| - software-engineering | |
| pipeline_tag: token-classification | |
| base_model: | |
| - nreimers/mMiniLMv2-L12-H384-distilled-from-XLMR-Large | |
| # code-daemon-ner-v1 | |
| A small **NER model that finds software-engineering entities in prose** β the sentences of a | |
| README, a design doc, an issue thread, a commit message. In | |
| [Code-Daemon](https://code-daemon.dev) the spans it emits become the concept nodes | |
| that link a paragraph of documentation to the code it talks about. | |
| **What makes it different:** this is prose NER, not code parsing. A parser already extracts every | |
| identifier in a source file, exactly. What it cannot do is read *"the IVF rescoring path in | |
| `faiss_index.zig` regressed nDCG@10 by 4 points"* and tell you that `IVF` is an algorithm, | |
| `faiss_index.zig` a file and `nDCG@10` a metric. No public model exists for these labels, and the | |
| zero-shot ones miss the conventions that matter here β so this one was trained for them, and it | |
| runs faster on a CPU than they do on a GPU. | |
| - **~117M parameters** β XLM-RoBERTa, 12 layers Γ 384 hidden, multilingual vocabulary. | |
| - **English and Russian** prose; **128 tokens** β one or two sentences per call. | |
| - **2-input ONNX** (`input_ids`, `attention_mask`) β `logits [batch, seq, 17]` (8 types in BIO). | |
| ## Labels | |
| | tier | type | what | examples | | |
| |---|---|---|---| | |
| | Core | `component` | a named part of a system, **including model names** | `DocStore`, `mMiniLMv2` | | |
| | Core | `api_endpoint` | a callable surface: function, method, route, **agent tool name** | `semantic_search`, `POST /v1/messages` | | |
| | Core | `file_path` | a path or file name | `src/semantic/faiss_index.zig` | | |
| | Core | `tool` | something you invoke: executable, runtime, service, language, hardware | `TensorRT`, `rclone`, `SQL` | | |
| | Soft | `algorithm` | a named method | `BM25`, `Louvain` | | |
| | Soft | `data_structure` | a named container or layout | `CSR`, `Prolly tree` | | |
| | Soft | `config` | a knob, flag, env var | `journal_mode=MEMORY`, `--epochs` | | |
| | Soft | `metric` | a measurement or unit | `nDCG@10`, `p95 latency` | | |
| Core types are what a knowledge graph links on; Soft types are tolerated at lower precision. | |
| ## Numbers | |
| 1 500 hand-reviewed sentences, entity level (exact span **and** type). The honest alternative for a | |
| private label set is a zero-shot model you hand the label names to β GLiNER, each run at its best | |
| of four prompt/threshold settings: | |
| | model | params | Core macro-F1 | P / R | chunks/s | | |
| |---|--:|--:|--:|--:| | |
| | **this model** | **117M** | **0.426** | 0.38 / 0.55 | **68 on a CPU** | | |
| | gliner-multitask-v1.0 | 909M | 0.284 | 0.23 / 0.41 | 10 on a GPU | | |
| | gliner_multi-v2.1 | 289M | 0.155 | 0.17 / 0.23 | 39 on a GPU | | |
| Per Core type, F1: | |
| | type | this model | gliner-multitask | gliner_multi | | |
| |---|--:|--:|--:| | |
| | `api_endpoint` | **0.521** | 0.382 | 0.006 | | |
| | `file_path` | **0.497** | 0.300 | 0.248 | | |
| | `tool` | **0.425** | 0.312 | 0.286 | | |
| | `component` | **0.263** | 0.143 | 0.080 | | |
| - **Fine-tuning buys the label convention.** Where a label name explains itself (`file_path`, | |
| `tool`), zero-shot gets within ~1.5Γ; where it is a project rule (`api_endpoint` includes agent | |
| tool names), it collapses. If your types are ordinary ones, a zero-shot model may serve you better. | |
| - **The trade: recall over precision.** On the strongest types it over-predicts (P 0.39β0.41, | |
| R 0.68β0.72). Use it as a **candidate generator behind a filter**, not as a labeller you trust | |
| unattended. | |
| - **Soft types are weak** (macro-F1 0.21; `config` 0.12), and multi-word spans mostly come back | |
| as single tokens. | |
| Inside the daemon on TensorRT, a 32-sentence batch takes 3 ms of GPU and 15 ms of tokenisation β | |
| parallelise the tokenizer before looking for a faster engine. | |
| ## How to use it | |
| - **Pre-split identifiers** (`camelCase` / `snake_case` β words) before tokenizing and keep | |
| **seq 128**: that is how it was trained, and scoring it any other way gives lower numbers. | |
| - **Calibrated probabilities:** divide the logits by `T` from `temperature.json` (0.665) before | |
| the softmax; `argmax` alone does not need it. | |
| - **Shapes:** TensorRT INT8 single profile seq 128; OpenVINO CPU / iGPU INT8 at batch 32, NPU INT4 | |
| at batch 8; Core ML `b32 s128`. | |
| ```python | |
| import onnxruntime as ort, numpy as np, json | |
| from transformers import AutoTokenizer | |
| tok = AutoTokenizer.from_pretrained(".") # bundled XLM-R SentencePiece | |
| labels = json.load(open("code-daemon-ner-v1_label_map.json"))["id2label"] | |
| T = json.load(open("temperature.json"))["T"] | |
| sess = ort.InferenceSession("model.onnx", providers=["CPUExecutionProvider"]) | |
| def tag(text, max_len=128): | |
| enc = tok(text, return_tensors="np", truncation=True, max_length=max_len, | |
| return_offsets_mapping=True, return_token_type_ids=False) | |
| logits = sess.run(None, {"input_ids": enc["input_ids"].astype(np.int64), | |
| "attention_mask": enc["attention_mask"].astype(np.int64)})[0][0] | |
| probs = np.exp(logits / T) / np.exp(logits / T).sum(-1, keepdims=True) # calibrated | |
| for (a, b), row in zip(enc["offset_mapping"][0], probs): | |
| lab = labels[str(int(row.argmax()))] | |
| if lab != "O" and b > a: | |
| yield text[a:b], lab, float(row.max()) | |
| for span, label, p in tag("The IVF rescoring path in src/semantic/faiss_index.zig cost 4 nDCG@10 points."): | |
| print(f"{span!r:40} {label:18} {p:.2f}") | |
| ``` | |
| **Out of scope:** symbols in source code (use a parser), general-domain NER, any high-stakes | |
| automatic decision. | |
| ## How it was made | |
| - **Backbone:** `mMiniLMv2-L12-H384`, a multilingual MiniLM distilled from XLM-RoBERTa-Large. | |
| - **Labels by weak supervision:** with no corpus for this label set, several independent labellers | |
| voted on each chunk and the votes were reconciled into one BIO sequence; the backbone was then | |
| fine-tuned on them and its output temperature-calibrated. | |
| - **Evaluation is human-labelled** and disjoint from the training labels. | |
| ## Files | |
| | file | what it is | | |
| |---|---| | |
| | `model.onnx` | FP32, dynamic shape β the standalone path | | |
| | `model_static.onnx`, `model_int8qdt.onnx` | seq pinned to 128 / INT8 Q/DQ β engine-build inputs | | |
| | `model.safetensors`, `config.json` | the weights as `XLMRobertaForTokenClassification`; `AutoModelForTokenClassification` loads them as-is; the Apple (MLX) build is prepared from this pair | | |
| | `sentencepiece.bpe.model`, `tokenizer_config.json`, `code-daemon-ner-v1_tokenizer.json` | the tokenizer (SentencePiece + fast tokenizer) | | |
| | `code-daemon-ner-v1_label_map.json` | the 17 BIO classes | | |
| | `temperature.json` | the calibration scalar `T` | | |
| | `eval_metrics.json`, `manifest.json` | per-type scores; build metadata | | |
| | `code-daemon-ner-v1_{win_x64,linux_x64}_trt11.0_sm_{75,80,86,89,120}.engine` | TensorRT INT8 per OS Γ GPU; `sm_90` (H100/H200) Linux only | | |
| | `code-daemon-ner-v1_ov2026.4_{cpu,igpu_lnl}_int8_b32_s128.{xml,bin}`, `β¦_npu_int4_b8_s128.*` | OpenVINO 2026.4 for Intel CPU, iGPU, NPU | | |
| | `coreml_ane/embed.mlpackage/` | Core ML for the Apple Neural Engine, function `b32 s128`; load with `cpuAndNeuralEngine` | | |
| A TensorRT engine loads only on the GPU architecture and TensorRT version that built it; any | |
| other machine uses OpenVINO or the ONNX. | |
| ## License | |
| Released under the **MIT license**. The backbone is a re-upload of Microsoft's mMiniLMv2 | |
| ([microsoft/unilm](https://github.com/microsoft/unilm/tree/master/minilm), MIT); the re-upload | |
| repository itself declares no license. Neither the training corpus nor the evaluation set ships | |
| here. Not legal advice. | |
| ## Attribution | |
| Backbone: **[nreimers/mMiniLMv2-L12-H384-distilled-from-XLMR-Large](https://huggingface.co/nreimers/mMiniLMv2-L12-H384-distilled-from-XLMR-Large)** | |
| (itself distilled from XLM-RoBERTa-Large). | |