matulichpt commited on
Commit
28114b3
·
verified ·
1 Parent(s): 6e6863b

Initial model upload with benchmarks

Browse files
Files changed (7) hide show
  1. README.md +288 -0
  2. config.json +32 -0
  3. model.safetensors +3 -0
  4. special_tokens_map.json +37 -0
  5. tokenizer.json +0 -0
  6. tokenizer_config.json +58 -0
  7. vocab.txt +0 -0
README.md ADDED
@@ -0,0 +1,288 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - en
4
+ license: apache-2.0
5
+ library_name: sentence-transformers
6
+ tags:
7
+ - sentence-transformers
8
+ - cross-encoder
9
+ - text-classification
10
+ - radiology
11
+ - medical
12
+ - reranking
13
+ datasets:
14
+ - custom
15
+ metrics:
16
+ - mrr
17
+ - recall
18
+ pipeline_tag: text-classification
19
+ model-index:
20
+ - name: radlit-crossencoder
21
+ results:
22
+ - task:
23
+ type: reranking
24
+ name: Radiology Document Reranking
25
+ dataset:
26
+ type: custom
27
+ name: RadLIT-9
28
+ config: radlit9-v1.1-balanced
29
+ metrics:
30
+ - type: mrr
31
+ value: 0.829
32
+ name: MRR (with bi-encoder)
33
+ - type: mrr_improvement
34
+ value: 0.30
35
+ name: MRR Improvement on Complex Queries
36
+ ---
37
+
38
+ # RadLIT-CrossEncoder: Radiology Reranking Model
39
+
40
+ A cross-encoder model fine-tuned for reranking radiology document retrieval results. Designed to work as the second stage of the RadLITE pipeline, providing significant improvements on complex clinical queries.
41
+
42
+ ## Model Description
43
+
44
+ RadLIT-CrossEncoder takes a query-document pair and outputs a relevance score. Unlike bi-encoders that encode queries and documents separately, cross-encoders process them jointly, enabling more nuanced relevance judgments at the cost of higher latency.
45
+
46
+ ### Architecture
47
+
48
+ - **Base Model**: BERT architecture (medical-initialized)
49
+ - **Hidden Size**: 384
50
+ - **Layers**: 12
51
+ - **Attention Heads**: 12
52
+ - **Parameters**: ~33M (optimized for inference speed)
53
+ - **Max Sequence Length**: 512 tokens
54
+ - **Output**: Single relevance score (regression)
55
+
56
+ ### Training
57
+
58
+ The model was fine-tuned on radiology query-document pairs with relevance labels:
59
+
60
+ - **Training Objective**: Binary Cross-Entropy with soft labels
61
+ - **Training Data**: Expert-labeled query-document pairs from radiology education
62
+ - **Hard Negatives**: Mined from bi-encoder retrieval failures
63
+ - **Batch Size**: 16
64
+ - **Learning Rate**: 2e-5
65
+ - **Epochs**: 3
66
+
67
+ **Note**: Training data sources are not disclosed due to variable licensing. The model is released under Apache 2.0.
68
+
69
+ ## Performance
70
+
71
+ ### Impact on RadLITE Pipeline
72
+
73
+ When combined with RadLIT-BiEncoder:
74
+
75
+ | Configuration | MRR | Improvement |
76
+ |---------------|-----|-------------|
77
+ | Bi-encoder only | 0.703 | baseline |
78
+ | + Cross-encoder reranking | 0.741 | +5.4% |
79
+ | + Calibrated fusion (RadLITE) | **0.829** | **+17.9%** |
80
+
81
+ ### Performance on Complex Queries
82
+
83
+ The cross-encoder shows largest improvements on complex clinical reasoning queries:
84
+
85
+ | Query Type | Improvement |
86
+ |------------|-------------|
87
+ | Board exam questions | **+30.3%** |
88
+ | Differential diagnosis | +22.5% |
89
+ | Staging/classification | +18.0% |
90
+ | Simple factual | +5.0% |
91
+
92
+ ### Subspecialty Impact
93
+
94
+ Greatest improvements on subspecialties requiring clinical reasoning:
95
+
96
+ | Subspecialty | Improvement with CE |
97
+ |--------------|---------------------|
98
+ | Physics | +33.9% |
99
+ | Genitourinary | +20.1% |
100
+ | Neuroradiology | +18.0% |
101
+ | Gastrointestinal | +16.6% |
102
+
103
+ ## Usage
104
+
105
+ ### Installation
106
+
107
+ ```bash
108
+ pip install sentence-transformers
109
+ ```
110
+
111
+ ### Basic Usage
112
+
113
+ ```python
114
+ from sentence_transformers import CrossEncoder
115
+
116
+ # Load model
117
+ model = CrossEncoder('matulichpt/radlit-crossencoder')
118
+
119
+ # Score query-document pairs
120
+ pairs = [
121
+ ["What are the CT findings in pulmonary embolism?",
122
+ "CT pulmonary angiography shows filling defects in the pulmonary arteries..."],
123
+ ["What are the CT findings in pulmonary embolism?",
124
+ "MRI of the knee shows ACL tear with bone bruise pattern..."]
125
+ ]
126
+
127
+ scores = model.predict(pairs)
128
+ print(scores) # [0.92, 0.08] - higher score = more relevant
129
+ ```
130
+
131
+ ### Reranking Pipeline
132
+
133
+ ```python
134
+ from sentence_transformers import SentenceTransformer, CrossEncoder
135
+ import numpy as np
136
+
137
+ # Load models
138
+ biencoder = SentenceTransformer('matulichpt/radlit-biencoder')
139
+ crossencoder = CrossEncoder('matulichpt/radlit-crossencoder')
140
+
141
+ def retrieve_and_rerank(query, corpus, corpus_embeddings, top_k=10, rerank_k=50):
142
+ # Stage 1: Bi-encoder retrieval
143
+ query_embedding = biencoder.encode(query, convert_to_tensor=True)
144
+ cos_scores = util.cos_sim(query_embedding, corpus_embeddings)[0]
145
+ top_indices = torch.topk(cos_scores, k=rerank_k)[1].tolist()
146
+
147
+ # Stage 2: Cross-encoder reranking
148
+ candidates = [corpus[i] for i in top_indices]
149
+ pairs = [[query, doc] for doc in candidates]
150
+ ce_scores = crossencoder.predict(pairs)
151
+
152
+ # Apply temperature calibration (IMPORTANT: use T=1.5)
153
+ calibrated_scores = ce_scores / 1.5
154
+
155
+ # Sort and return top-k
156
+ sorted_indices = np.argsort(calibrated_scores)[::-1][:top_k]
157
+ return [(candidates[i], calibrated_scores[i]) for i in sorted_indices]
158
+
159
+ # Example
160
+ results = retrieve_and_rerank(
161
+ "What are the imaging features of hepatocellular carcinoma?",
162
+ corpus, corpus_embeddings
163
+ )
164
+ ```
165
+
166
+ ### Temperature Calibration
167
+
168
+ **Important**: For optimal performance in score fusion, apply temperature scaling:
169
+
170
+ ```python
171
+ # Raw CE scores have higher variance than bi-encoder scores
172
+ raw_scores = crossencoder.predict(pairs)
173
+
174
+ # Temperature calibration aligns score distributions
175
+ # T=1.5 found optimal through grid search
176
+ calibrated_scores = raw_scores / 1.5
177
+ ```
178
+
179
+ This is critical when combining cross-encoder scores with bi-encoder scores.
180
+
181
+ ### Full RadLITE Fusion
182
+
183
+ ```python
184
+ def radlite_score(query, document, biencoder, crossencoder, bm25_score):
185
+ """
186
+ Full RadLITE scoring with optimal weights.
187
+
188
+ Optimal weights (found via grid search on RadLIT-9):
189
+ - Bi-encoder: 0.5
190
+ - Cross-encoder: 0.2
191
+ - BM25: 0.3
192
+ """
193
+ # Bi-encoder score
194
+ q_emb = biencoder.encode(query, convert_to_tensor=True)
195
+ d_emb = biencoder.encode(document, convert_to_tensor=True)
196
+ biencoder_score = float(util.cos_sim(q_emb, d_emb)[0][0])
197
+
198
+ # Cross-encoder score (calibrated)
199
+ ce_score = crossencoder.predict([[query, document]])[0] / 1.5
200
+
201
+ # Fusion
202
+ final_score = (
203
+ 0.5 * biencoder_score +
204
+ 0.2 * ce_score +
205
+ 0.3 * bm25_score # Normalized BM25
206
+ )
207
+
208
+ return final_score
209
+ ```
210
+
211
+ ## Technical Details
212
+
213
+ ### Why Temperature Calibration?
214
+
215
+ Cross-encoder scores tend to be more extreme than bi-encoder similarity scores:
216
+
217
+ | Score Type | Typical Range | Variance |
218
+ |------------|---------------|----------|
219
+ | Bi-encoder cosine | [0.3, 0.9] | Low |
220
+ | Raw CE score | [-2, 3] | High |
221
+ | Calibrated CE (T=1.5) | [-1.3, 2] | Medium |
222
+
223
+ Without calibration, the CE dominates the fusion and degrades overall performance. Temperature 1.5 achieves ~0.7 correlation between score distributions.
224
+
225
+ ### Latency Considerations
226
+
227
+ | Operation | Latency |
228
+ |-----------|---------|
229
+ | Single pair scoring | ~4ms |
230
+ | 50 pairs (batch) | ~200-300ms |
231
+ | Bi-encoder (50 docs) | ~80-120ms |
232
+
233
+ For production use, consider:
234
+ - Limiting rerank candidates (50 is optimal)
235
+ - Batch processing
236
+ - GPU acceleration
237
+
238
+ ## Intended Use
239
+
240
+ ### Primary Use Cases
241
+
242
+ - Second-stage reranking for radiology retrieval
243
+ - Relevance scoring for radiology Q&A
244
+ - Fine-grained document ranking
245
+
246
+ ### Out-of-Scope Uses
247
+
248
+ - First-stage retrieval (too slow for large corpora)
249
+ - Non-radiology content
250
+ - Clinical diagnosis
251
+
252
+ ## Limitations
253
+
254
+ 1. **Latency**: ~4ms per pair; not suitable for first-stage retrieval
255
+ 2. **Domain**: Optimized for radiology; limited generalization
256
+ 3. **Context Length**: 512 tokens max; long documents need truncation
257
+ 4. **Score Interpretation**: Requires calibration for fusion
258
+
259
+ ## Ethical Considerations
260
+
261
+ - Not a diagnostic tool
262
+ - Should be used to surface relevant educational content, not replace clinical judgment
263
+ - May reflect biases in radiology literature
264
+
265
+ ## Citation
266
+
267
+ ```bibtex
268
+ @software{radlit_crossencoder_2026,
269
+ title = {RadLIT-CrossEncoder: Radiology Reranking Model},
270
+ author = {Grai Team},
271
+ year = {2026},
272
+ url = {https://huggingface.co/matulichpt/radlit-crossencoder},
273
+ note = {+30% improvement on complex radiology queries}
274
+ }
275
+ ```
276
+
277
+ ## Related Models
278
+
279
+ - [RadLIT-BiEncoder](https://huggingface.co/matulichpt/radlit-biencoder) - First-stage retrieval
280
+ - RadLITE Pipeline - Full retrieval system documentation
281
+
282
+ ## License
283
+
284
+ Apache 2.0 - Free for research and commercial use.
285
+
286
+ ## Contact
287
+
288
+ For questions or collaboration: Open an issue on the model repository
config.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "BertForSequenceClassification"
4
+ ],
5
+ "attention_probs_dropout_prob": 0.1,
6
+ "classifier_dropout": null,
7
+ "dtype": "float32",
8
+ "gradient_checkpointing": false,
9
+ "hidden_act": "gelu",
10
+ "hidden_dropout_prob": 0.1,
11
+ "hidden_size": 384,
12
+ "id2label": {
13
+ "0": "LABEL_0"
14
+ },
15
+ "initializer_range": 0.02,
16
+ "intermediate_size": 1536,
17
+ "label2id": {
18
+ "LABEL_0": 0
19
+ },
20
+ "layer_norm_eps": 1e-12,
21
+ "max_position_embeddings": 512,
22
+ "model_type": "bert",
23
+ "num_attention_heads": 12,
24
+ "num_hidden_layers": 12,
25
+ "pad_token_id": 0,
26
+ "position_embedding_type": "absolute",
27
+ "sbert_ce_default_activation_function": "torch.nn.modules.linear.Identity",
28
+ "transformers_version": "4.56.0",
29
+ "type_vocab_size": 2,
30
+ "use_cache": true,
31
+ "vocab_size": 30522
32
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3dfc8832e0d99ed4c39d357bd5be9ea2552eab7107daa09b30db39a43f741a73
3
+ size 133464836
special_tokens_map.json ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cls_token": {
3
+ "content": "[CLS]",
4
+ "lstrip": false,
5
+ "normalized": false,
6
+ "rstrip": false,
7
+ "single_word": false
8
+ },
9
+ "mask_token": {
10
+ "content": "[MASK]",
11
+ "lstrip": false,
12
+ "normalized": false,
13
+ "rstrip": false,
14
+ "single_word": false
15
+ },
16
+ "pad_token": {
17
+ "content": "[PAD]",
18
+ "lstrip": false,
19
+ "normalized": false,
20
+ "rstrip": false,
21
+ "single_word": false
22
+ },
23
+ "sep_token": {
24
+ "content": "[SEP]",
25
+ "lstrip": false,
26
+ "normalized": false,
27
+ "rstrip": false,
28
+ "single_word": false
29
+ },
30
+ "unk_token": {
31
+ "content": "[UNK]",
32
+ "lstrip": false,
33
+ "normalized": false,
34
+ "rstrip": false,
35
+ "single_word": false
36
+ }
37
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "0": {
4
+ "content": "[PAD]",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ },
11
+ "100": {
12
+ "content": "[UNK]",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "101": {
20
+ "content": "[CLS]",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ },
27
+ "102": {
28
+ "content": "[SEP]",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false,
33
+ "special": true
34
+ },
35
+ "103": {
36
+ "content": "[MASK]",
37
+ "lstrip": false,
38
+ "normalized": false,
39
+ "rstrip": false,
40
+ "single_word": false,
41
+ "special": true
42
+ }
43
+ },
44
+ "clean_up_tokenization_spaces": true,
45
+ "cls_token": "[CLS]",
46
+ "do_basic_tokenize": true,
47
+ "do_lower_case": true,
48
+ "extra_special_tokens": {},
49
+ "mask_token": "[MASK]",
50
+ "model_max_length": 512,
51
+ "never_split": null,
52
+ "pad_token": "[PAD]",
53
+ "sep_token": "[SEP]",
54
+ "strip_accents": null,
55
+ "tokenize_chinese_chars": true,
56
+ "tokenizer_class": "BertTokenizer",
57
+ "unk_token": "[UNK]"
58
+ }
vocab.txt ADDED
The diff for this file is too large to render. See raw diff