cjdd3b commited on
Commit
7b74a68
·
verified ·
1 Parent(s): c391d36

Add Cite-32M package and model card

Browse files
.gitattributes CHANGED
@@ -1,35 +1,5 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
  *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
  *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
  *.pt filter=lfs diff=lfs merge=lfs -text
23
  *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip 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
 
1
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
 
2
  *.bin filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
3
  *.onnx filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
4
  *.pt filter=lfs diff=lfs merge=lfs -text
5
  *.pth filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
README.md ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ language:
4
+ - en
5
+ library_name: cite
6
+ tags:
7
+ - cite
8
+ - paragraph-citation
9
+ - retrieval
10
+ - question-answering
11
+ - news
12
+ - encoder
13
+ - modernbert
14
+ - on-device
15
+ pipeline_tag: text-ranking
16
+ base_model: jhu-clsp/ettin-encoder-32m
17
+ ---
18
+
19
+ # Cite
20
+
21
+ Which paragraphs answer the question.
22
+
23
+ A small encoder that, given a question and ordered paragraph texts, returns a
24
+ calibrated probability per paragraph and two thresholds (`needed`,
25
+ `contributing`).
26
+
27
+ | | |
28
+ | --- | --- |
29
+ | **Task** | Paragraph citation / needed-blocks |
30
+ | **Size** | ~42 MB weights (trimmed vocab, int8 embeddings, fp16 rest) |
31
+ | **Runtime** | CPU (PyTorch); Mac MPS optional |
32
+ | **Weights** | [v0.1.0](https://huggingface.co/localangle/cite/tree/v0.1.0) |
33
+ | **Demo** | [localangle/cite-demo](https://huggingface.co/spaces/localangle/cite-demo) |
34
+
35
+ Cite does **not** write an answer. It ranks the paragraphs you already have and
36
+ flags which ones are needed to answer the question.
37
+
38
+ > Question: *Who voted against the library renovation?*
39
+ > → Cite highlights the paragraph naming Paulsen and Chen.
40
+
41
+ ## Try it
42
+
43
+ - **Live demo:** [localangle/cite-demo](https://huggingface.co/spaces/localangle/cite-demo) — paste an article, ask a question, see which paragraphs Cite cites.
44
+ - **Local playground:** from the [cite](https://github.com/localangle/cite) repo, `uv run python deploy/cite_playground.py`.
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ pip install "cite @ git+https://github.com/localangle/cite.git"
50
+ # or, from a checkout:
51
+ uv sync
52
+ ```
53
+
54
+ Python ≥ 3.12. Needs `torch`, `transformers`, `safetensors`, `huggingface_hub`.
55
+
56
+ ## Usage
57
+
58
+ ```python
59
+ from cite import CitePackage
60
+
61
+ cite = CitePackage.from_pretrained("localangle/cite")
62
+
63
+ paragraphs = [
64
+ "The council approved a $4.2 million library renovation.",
65
+ "Paulsen and Chen voted against the measure.",
66
+ "Construction starts in March.",
67
+ ]
68
+ scores = cite.predict("Who voted against the renovation?", paragraphs)
69
+
70
+ for score in scores:
71
+ if score.needed:
72
+ print(score.index, score.probability, paragraphs[score.index])
73
+ ```
74
+
75
+ `score.needed` uses the packaged threshold (0.71). `score.contributing` is a
76
+ looser relatedness cut (0.15). Logits are Platt-scaled to probabilities at load
77
+ time; you do not fit thresholds yourself for the published package.
78
+
79
+ Load a local folder the same way:
80
+
81
+ ```python
82
+ cite = CitePackage.load("path/to/package") # or from_pretrained("./path")
83
+ ```
84
+
85
+ ## Files
86
+
87
+ | File | Contents |
88
+ | --- | --- |
89
+ | `cite.json` | Format, Platt scaling, thresholds, source metadata |
90
+ | `weights.safetensors` | Trimmed encoder + head (int8 token embeddings, fp16 elsewhere) |
91
+ | `encoder/` | ModernBERT/Ettin config for the trimmed vocabulary |
92
+ | `tokenizer/` | Tokenizer with `[MASK]` as the block marker |
93
+
94
+ Weights expand to fp32 at load; only storage is compressed.
95
+
96
+ ## Accuracy
97
+
98
+ On a held-out real-news needed-blocks eval (v59, 1,800 questions over local
99
+ news outlets; threshold chosen on a separate calibration split):
100
+
101
+ | Metric | Cite-32M package |
102
+ | --- | --- |
103
+ | Coverage | 0.696 |
104
+ | Exact set match | 0.727 |
105
+ | Empty-set accuracy | 0.895 |
106
+ | Any-extra rate | 0.057 |
107
+
108
+ Same operating point as the fp32 student within the packaging tolerance. See
109
+ the research reports in the [cite](https://github.com/localangle/cite) repository
110
+ (`experiments/105-cite-distill`, `experiments/106-cite-compress`).
111
+
112
+ ## Latency
113
+
114
+ Batch-1, CPU, AMD EPYC (HF `cpu-upgrade`, 8 vCPU) for the related ONNX int8
115
+ form: about 44 ms p50 at 5–12 paragraphs and 268 ms at 33–60. The portable
116
+ PyTorch package this repo ships is the accuracy-matched serving artifact; long
117
+ documents are dominated by attention cost.
118
+
119
+ ## How it works
120
+
121
+ Cite is a fine-tuned [Ettin](https://huggingface.co/jhu-clsp/ettin-encoder-32m)
122
+ encoder (ModernBERT family). The question and each paragraph are packed into
123
+ one sequence with a `[MASK]` marker before every paragraph; the head reads the
124
+ marker states. A 400M teacher labeled real news; the 32M student was distilled
125
+ and then compressed (trimmed vocabulary, int8 embeddings, fp16 weights).
126
+
127
+ ## Limitations
128
+
129
+ - Cite ranks paragraphs; it does not generate answers or quote spans inside a
130
+ paragraph.
131
+ - Eval is English news-style text. Other domains are unmeasured.
132
+ - Empty-set accuracy drops a few points from calibration to eval; treat the
133
+ packaged threshold as a starting point for a new domain.
134
+ - Documents longer than `max_tokens` (7999) drop trailing paragraphs.
135
+ - Training used private teacher labels and news text that is not redistributed
136
+ here.
137
+
138
+ ## Built on
139
+
140
+ - [Ettin encoder 32M](https://huggingface.co/jhu-clsp/ettin-encoder-32m) (MIT)
141
+ by JHU CLSP. Fine-tuned and compressed for Cite; see
142
+ `THIRD_PARTY_NOTICES.md`.
143
+
144
+ ## License
145
+
146
+ MIT for the Cite code and this package's weights, subject to the Ettin MIT
147
+ notice above.
148
+
149
+ ## Citation
150
+
151
+ ```bibtex
152
+ @software{cite_2026,
153
+ title = {Cite: Which paragraphs answer the question},
154
+ author = {Local Angle},
155
+ year = {2026},
156
+ url = {https://huggingface.co/localangle/cite},
157
+ }
158
+ ```
THIRD_PARTY_NOTICES.md ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Third-party notices
2
+
3
+ ## Ettin / ModernBERT backbone
4
+
5
+ This package's encoder is derived from
6
+ [`jhu-clsp/ettin-encoder-32m`](https://huggingface.co/jhu-clsp/ettin-encoder-32m)
7
+ (MIT License). Cite fine-tunes and compresses those weights; the original
8
+ license terms continue to apply to the Ettin contribution.
9
+
10
+ Paper: Weller et al., "Ettin: an Open Suite of Paired Encoders and Decoders"
11
+ (arXiv:2507.11412).
cite.json ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "format": "cite-package-1",
3
+ "kept": 41655,
4
+ "marker": "mask",
5
+ "max_tokens": 7999,
6
+ "platt": {
7
+ "bias": 0.28167128937742075,
8
+ "slope": 0.6159961343551152
9
+ },
10
+ "readout": "mlm_head",
11
+ "source": {
12
+ "base_model": {
13
+ "repo": "jhu-clsp/ettin-encoder-32m",
14
+ "revision": "1b8ba06455dd44f80fc9c1ca9e22806157a57379"
15
+ },
16
+ "experiment": "experiments/106-cite-compress",
17
+ "student": "cjdd3b/angle-core-private-evals/105-clip-32m-distill"
18
+ },
19
+ "storage": "token embeddings int8 per row; other weights fp16; computed in fp32",
20
+ "thresholds": {
21
+ "contributing": 0.15,
22
+ "needed": 0.71,
23
+ "needed_rule": "lowest threshold with graf_calibration empty-set accuracy >= 0.93 (104 amendment), per variant"
24
+ },
25
+ "vocabulary_full": 50368
26
+ }
encoder/config.json ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "ModernBertModel"
4
+ ],
5
+ "attention_bias": false,
6
+ "attention_dropout": 0.0,
7
+ "bos_token_id": 41651,
8
+ "causal_mask": false,
9
+ "classifier_activation": "gelu",
10
+ "classifier_bias": false,
11
+ "classifier_dropout": 0.0,
12
+ "classifier_pooling": "mean",
13
+ "cls_token_id": 41651,
14
+ "decoder_bias": true,
15
+ "deterministic_flash_attn": false,
16
+ "dtype": "float32",
17
+ "embedding_dropout": 0.0,
18
+ "eos_token_id": 41652,
19
+ "global_attn_every_n_layers": 3,
20
+ "gradient_checkpointing": false,
21
+ "hidden_activation": "gelu",
22
+ "hidden_size": 384,
23
+ "initializer_cutoff_factor": 2.0,
24
+ "initializer_range": 0.02,
25
+ "intermediate_size": 576,
26
+ "is_causal": false,
27
+ "layer_norm_eps": 1e-05,
28
+ "layer_types": [
29
+ "full_attention",
30
+ "sliding_attention",
31
+ "sliding_attention",
32
+ "full_attention",
33
+ "sliding_attention",
34
+ "sliding_attention",
35
+ "full_attention",
36
+ "sliding_attention",
37
+ "sliding_attention",
38
+ "full_attention"
39
+ ],
40
+ "local_attention": 128,
41
+ "max_position_embeddings": 7999,
42
+ "mlp_bias": false,
43
+ "mlp_dropout": 0.0,
44
+ "model_type": "modernbert",
45
+ "norm_bias": false,
46
+ "norm_eps": 1e-05,
47
+ "num_attention_heads": 6,
48
+ "num_hidden_layers": 10,
49
+ "pad_token_id": 41653,
50
+ "position_embedding_type": "sans_pos",
51
+ "rope_parameters": {
52
+ "full_attention": {
53
+ "rope_theta": 160000.0,
54
+ "rope_type": "default"
55
+ },
56
+ "sliding_attention": {
57
+ "rope_theta": 160000.0,
58
+ "rope_type": "default"
59
+ }
60
+ },
61
+ "sep_token_id": 41652,
62
+ "sparse_pred_ignore_index": -100,
63
+ "sparse_prediction": false,
64
+ "tie_word_embeddings": true,
65
+ "transformers_version": "5.17.0",
66
+ "vocab_size": 41655
67
+ }
tokenizer/tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer/tokenizer_config.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "clean_up_tokenization_spaces": true,
4
+ "cls_token": "[CLS]",
5
+ "is_local": false,
6
+ "local_files_only": false,
7
+ "mask_token": "[MASK]",
8
+ "model_input_names": [
9
+ "input_ids",
10
+ "attention_mask"
11
+ ],
12
+ "model_max_length": 8192,
13
+ "pad_token": "[PAD]",
14
+ "sep_token": "[SEP]",
15
+ "tokenizer_class": "TokenizersBackend",
16
+ "unk_token": "[UNK]"
17
+ }
weights.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:88110b9fe6cbd84b5534e5957322d8e925bdae8785aefbec3771a8263a639aba
3
+ size 41750550