matulichpt commited on
Commit
5d8f754
·
verified ·
1 Parent(s): 11f2a17

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. LICENSE +190 -0
  2. README.md +261 -202
  3. config.json +2 -2
LICENSE ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to the Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ Copyright 2026 Grai Team
179
+
180
+ Licensed under the Apache License, Version 2.0 (the "License");
181
+ you may not use this file except in compliance with the License.
182
+ You may obtain a copy of the License at
183
+
184
+ http://www.apache.org/licenses/LICENSE-2.0
185
+
186
+ Unless required by applicable law or agreed to in writing, software
187
+ distributed under the License is distributed on an "AS IS" BASIS,
188
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
189
+ See the License for the specific language governing permissions and
190
+ limitations under the License.
README.md CHANGED
@@ -1,111 +1,97 @@
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.698 | baseline |
78
- | + Cross-encoder reranking | 0.782 | +12.0% |
79
- | + BM25 fusion (RadLITE) | **0.829** | **+18.8%** |
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
@@ -113,206 +99,279 @@ pip install sentence-transformers
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
- ## Demo: Cross-Encoder Reranking
167
 
168
  ```python
169
- from sentence_transformers import CrossEncoder
170
  import numpy as np
171
 
172
- model = CrossEncoder('matulichpt/radlit-crossencoder')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
- query = "What causes ring-enhancing brain lesions in AIDS patients?"
175
 
176
- # Candidates from bi-encoder retrieval (simulated)
177
- candidates = [
178
- "In AIDS, toxoplasmosis shows ring-enhancing lesions in basal ganglia. CNS lymphoma is typically periventricular.",
179
- "Brain metastases occur at gray-white junction and may show ring enhancement.",
180
- "Glioblastoma is the most common primary brain malignancy.",
181
- ]
182
 
183
- # Score each candidate
184
- pairs = [[query, doc] for doc in candidates]
185
- scores = model.predict(pairs)
186
 
187
- # Rank by relevance
188
- ranked = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True)
189
- print(f"Top result: {ranked[0][0][:80]}...")
190
- print(f"Score: {ranked[0][1]:.2f}")
191
- # The AIDS-specific answer ranks first despite shorter text
192
- ```
193
 
194
- The cross-encoder correctly prioritizes the clinically relevant answer about AIDS-specific differentials.
195
 
196
- ### Temperature Calibration
 
 
197
 
198
- **Important**: For optimal performance in score fusion, apply temperature scaling:
 
 
 
 
 
 
 
 
 
199
 
200
  ```python
201
- # Raw CE scores have higher variance than bi-encoder scores
202
- raw_scores = crossencoder.predict(pairs)
 
 
 
 
 
 
 
 
 
 
 
 
 
203
 
204
- # Temperature calibration aligns score distributions
205
- # T=1.5 found optimal through grid search
206
- calibrated_scores = raw_scores / 1.5
207
  ```
208
 
209
- This is critical when combining cross-encoder scores with bi-encoder scores.
210
 
211
- ### Full RadLITE Fusion
212
 
213
  ```python
214
- def radlite_score(query, document, biencoder, crossencoder, bm25_score):
215
- """
216
- Full RadLITE scoring with optimal weights.
217
-
218
- Optimal weights (found via grid search on RadLIT-9):
219
- - Bi-encoder: 0.5
220
- - Cross-encoder: 0.2
221
- - BM25: 0.3
222
- """
223
- # Bi-encoder score
224
- q_emb = biencoder.encode(query, convert_to_tensor=True)
225
- d_emb = biencoder.encode(document, convert_to_tensor=True)
226
- biencoder_score = float(util.cos_sim(q_emb, d_emb)[0][0])
227
-
228
- # Cross-encoder score (calibrated)
229
- ce_score = crossencoder.predict([[query, document]])[0] / 1.5
230
-
231
- # Fusion
232
- final_score = (
233
- 0.5 * biencoder_score +
234
- 0.2 * ce_score +
235
- 0.3 * bm25_score # Normalized BM25
236
  )
 
 
 
237
 
238
- return final_score
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  ```
240
 
241
- ## Technical Details
242
 
243
- ### Why Temperature Calibration?
 
 
 
 
 
 
244
 
245
- Cross-encoder scores tend to be more extreme than bi-encoder similarity scores:
246
 
247
- | Score Type | Typical Range | Variance |
248
- |------------|---------------|----------|
249
- | Bi-encoder cosine | [0.3, 0.9] | Low |
250
- | Raw CE score | [-2, 3] | High |
251
- | Calibrated CE (T=1.5) | [-1.3, 2] | Medium |
252
 
253
- Without calibration, the CE dominates the fusion and degrades overall performance. Temperature 1.5 achieves ~0.7 correlation between score distributions.
254
 
255
- ### Latency Considerations
 
 
256
 
257
- | Operation | Latency |
258
- |-----------|---------|
259
- | Single pair scoring | ~4ms |
260
- | 50 pairs (batch) | ~200-300ms |
261
- | Bi-encoder (50 docs) | ~80-120ms |
262
 
263
- For production use, consider:
264
- - Limiting rerank candidates (50 is optimal)
265
- - Batch processing
266
- - GPU acceleration
267
 
268
- ## Intended Use
 
 
269
 
270
- ### Primary Use Cases
 
 
271
 
272
- - Second-stage reranking for radiology retrieval
273
- - Relevance scoring for radiology Q&A
274
- - Fine-grained document ranking
275
 
276
- ### Out-of-Scope Uses
 
 
 
277
 
278
- - First-stage retrieval (too slow for large corpora)
279
- - Non-radiology content
280
- - Clinical diagnosis
281
 
282
- ## Limitations
283
 
284
- 1. **Latency**: ~4ms per pair; not suitable for first-stage retrieval
285
- 2. **Domain**: Optimized for radiology; limited generalization
286
- 3. **Context Length**: 512 tokens max; long documents need truncation
287
- 4. **Score Interpretation**: Requires calibration for fusion
 
 
 
288
 
289
- ## Ethical Considerations
290
 
291
- - Not a diagnostic tool
292
- - Should be used to surface relevant educational content, not replace clinical judgment
293
- - May reflect biases in radiology literature
 
294
 
295
  ## Citation
296
 
 
 
297
  ```bibtex
298
- @software{radlit_crossencoder_2026,
299
- title = {RadLIT-CrossEncoder: Radiology Reranking Model},
300
- author = {Grai Team},
301
- year = {2026},
302
- url = {https://huggingface.co/matulichpt/radlit-crossencoder},
303
- note = {+30% improvement on complex radiology queries}
 
304
  }
305
  ```
306
 
307
  ## Related Models
308
 
309
- - [RadLIT-BiEncoder](https://huggingface.co/matulichpt/radlit-biencoder) - First-stage retrieval
310
- - RadLITE Pipeline - Full retrieval system documentation
311
 
312
  ## License
313
 
314
- Apache 2.0 - Free for research and commercial use.
315
-
316
- ## Contact
317
-
318
- For questions or collaboration: Open an issue on the model repository
 
1
  ---
2
+ license: apache-2.0
3
  language:
4
  - en
 
 
5
  tags:
 
6
  - cross-encoder
7
+ - reranker
8
  - radiology
9
  - medical
10
+ - retrieval
11
+ - sentence-similarity
12
+ - healthcare
13
+ - clinical
14
+ base_model: cross-encoder/ms-marco-MiniLM-L-12-v2
15
+ pipeline_tag: text-classification
16
+ library_name: sentence-transformers
17
  datasets:
18
+ - radiology-education-corpus
19
  metrics:
20
  - mrr
21
+ - ndcg
 
22
  model-index:
23
+ - name: RadLITE-Reranker
24
  results:
25
  - task:
26
  type: reranking
27
+ name: Document Reranking
28
  dataset:
29
+ name: RadLIT-9 (Radiology Retrieval Benchmark)
30
+ type: radiology-retrieval
 
31
  metrics:
32
  - type: mrr
33
  value: 0.829
34
  name: MRR (with bi-encoder)
35
  - type: mrr_improvement
36
+ value: 0.303
37
+ name: MRR Improvement on ACR Core Exam (+30.3%)
38
  ---
39
 
40
+ # RadLITE-Reranker
41
 
42
+ **Radiology Late Interaction Transformer Enhanced - Cross-Encoder Reranker**
43
 
44
+ A domain-specialized cross-encoder for reranking radiology search results. This model takes a query-document pair and predicts a relevance score, providing more accurate ranking than bi-encoder similarity alone.
45
 
46
+ > **Recommended:** Use this reranker together with [RadLITE-Encoder](https://huggingface.co/matulichpt/radlit-biencoder) in a two-stage pipeline for optimal performance. The bi-encoder handles fast retrieval over large corpora, then this cross-encoder reranks the top candidates for precision. This combination achieves **MRR 0.829** on radiology benchmarks (+30% on board exam questions).
47
 
48
+ ## Model Description
49
 
50
+ | Property | Value |
51
+ |----------|-------|
52
+ | **Model Type** | Cross-Encoder (Reranker) |
53
+ | **Base Model** | [ms-marco-MiniLM-L-12-v2](https://huggingface.co/cross-encoder/ms-marco-MiniLM-L-12-v2) |
54
+ | **Domain** | Radiology / Medical Imaging |
55
+ | **Hidden Size** | 384 |
56
+ | **Max Sequence Length** | 512 tokens |
57
+ | **Output** | Single relevance score |
58
+ | **License** | Apache 2.0 |
59
 
60
+ ### Why Use a Reranker?
61
 
62
+ Bi-encoders (like RadLITE-Encoder) are fast but encode query and document independently. Cross-encoders process them together, capturing fine-grained interactions:
63
 
64
+ | Approach | Speed | Accuracy | Use Case |
65
+ |----------|-------|----------|----------|
66
+ | Bi-Encoder | Fast (1000s docs/sec) | Good | First-stage retrieval |
67
+ | Cross-Encoder | Slow (10s docs/sec) | Excellent | Reranking top candidates |
 
 
68
 
69
+ **Two-stage pipeline**: Use bi-encoder to get top 50-100 candidates, then rerank with cross-encoder for best results.
70
 
71
  ## Performance
72
 
73
+ ### Impact on RadLIT-9 Benchmark
 
 
74
 
75
  | Configuration | MRR | Improvement |
76
  |---------------|-----|-------------|
77
+ | Bi-Encoder only | 0.78 | baseline |
78
+ | **Bi-Encoder + Reranker** | **0.829** | **+6.3%** |
 
 
 
 
 
79
 
80
+ ### ACR Core Exam (Board-Style Questions)
 
 
 
 
 
81
 
82
+ | Dataset | With Reranker | Without | Improvement |
83
+ |---------|---------------|---------|-------------|
84
+ | Core Exam Chest | 0.533 | 0.409 | **+30.3%** |
85
+ | Core Exam Combined | 0.466 | 0.381 | **+22.5%** |
86
 
87
+ The reranker is especially valuable for complex, multi-part queries typical of board exam questions.
88
 
89
+ ## Quick Start
 
 
 
 
 
 
 
90
 
91
  ### Installation
92
 
93
  ```bash
94
+ pip install sentence-transformers>=2.2.0
95
  ```
96
 
97
  ### Basic Usage
 
99
  ```python
100
  from sentence_transformers import CrossEncoder
101
 
102
+ # Load the reranker
103
+ reranker = CrossEncoder("matulichpt/radlit-crossencoder", max_length=512)
104
 
105
+ # Query and candidate documents
106
+ query = "What are the imaging features of hepatocellular carcinoma?"
107
+ documents = [
108
+ "HCC typically shows arterial enhancement with portal venous washout on CT.",
109
+ "Fatty liver disease presents as decreased attenuation on non-contrast CT.",
110
+ "Hepatic hemangiomas show peripheral nodular enhancement.",
111
  ]
112
 
113
+ # Create query-document pairs
114
+ pairs = [[query, doc] for doc in documents]
 
115
 
116
+ # Get relevance scores
117
+ scores = reranker.predict(pairs)
118
 
119
+ # Apply temperature calibration (RECOMMENDED)
120
+ calibrated_scores = scores / 1.5
 
121
 
122
+ print("Scores:", calibrated_scores)
123
+ # Document about HCC will have highest score
124
+ ```
125
 
126
+ ### Temperature Calibration
 
 
 
 
127
 
128
+ **Important**: This model outputs scores with high variance. Apply temperature scaling for better fusion with other signals:
 
 
 
129
 
130
+ ```python
131
+ # Raw scores might be: [4.2, -1.5, 0.8]
132
+ # After calibration: [2.8, -1.0, 0.53]
133
 
134
+ TEMPERATURE = 1.5 # Recommended value
 
 
135
 
136
+ def calibrated_predict(reranker, pairs):
137
+ raw_scores = reranker.predict(pairs)
138
+ return raw_scores / TEMPERATURE
 
 
139
  ```
140
 
141
+ ### Full Two-Stage Search Pipeline
142
 
143
  ```python
144
+ from sentence_transformers import SentenceTransformer, CrossEncoder
145
  import numpy as np
146
 
147
+ class RadLITESearch:
148
+ def __init__(self, device="cuda"):
149
+ # Stage 1: Fast bi-encoder
150
+ self.encoder = SentenceTransformer(
151
+ "matulichpt/radlit-biencoder",
152
+ device=device
153
+ )
154
+ # Stage 2: Precise reranker
155
+ self.reranker = CrossEncoder(
156
+ "matulichpt/radlit-crossencoder",
157
+ max_length=512,
158
+ device=device
159
+ )
160
+ self.temperature = 1.5
161
+ self.corpus_embeddings = None
162
+ self.corpus = None
163
+
164
+ def index_corpus(self, documents: list):
165
+ """Pre-compute embeddings for your corpus."""
166
+ self.corpus = documents
167
+ self.corpus_embeddings = self.encoder.encode(
168
+ documents,
169
+ normalize_embeddings=True,
170
+ show_progress_bar=True,
171
+ batch_size=32
172
+ )
173
+
174
+ def search(self, query: str, top_k: int = 10, candidates: int = 50):
175
+ """Two-stage search: retrieve then rerank."""
176
+
177
+ # Stage 1: Bi-encoder retrieval
178
+ query_emb = self.encoder.encode(query, normalize_embeddings=True)
179
+ scores = query_emb @ self.corpus_embeddings.T
180
+ top_indices = np.argsort(scores)[-candidates:][::-1]
181
+
182
+ # Stage 2: Cross-encoder reranking
183
+ candidate_docs = [self.corpus[i] for i in top_indices]
184
+ pairs = [[query, doc] for doc in candidate_docs]
185
+ rerank_scores = self.reranker.predict(pairs) / self.temperature
186
+
187
+ # Sort by reranked scores
188
+ sorted_indices = np.argsort(rerank_scores)[::-1]
189
+
190
+ results = []
191
+ for idx in sorted_indices[:top_k]:
192
+ results.append({
193
+ "document": candidate_docs[idx],
194
+ "corpus_index": int(top_indices[idx]),
195
+ "score": float(rerank_scores[idx]),
196
+ "biencoder_score": float(scores[top_indices[idx]])
197
+ })
198
+ return results
199
+
200
+
201
+ # Usage
202
+ searcher = RadLITESearch()
203
+ searcher.index_corpus(your_radiology_documents)
204
+ results = searcher.search("pneumothorax CT findings")
205
+ ```
206
 
207
+ ## Integration with Any Corpus
208
 
209
+ ### Radiopaedia / Educational Content
 
 
 
 
 
210
 
211
+ ```python
212
+ import json
 
213
 
214
+ # Load your content (e.g., Radiopaedia articles)
215
+ with open("radiopaedia_articles.json") as f:
216
+ articles = json.load(f)
 
 
 
217
 
218
+ corpus = [article["content"] for article in articles]
219
 
220
+ # Initialize search
221
+ searcher = RadLITESearch()
222
+ searcher.index_corpus(corpus)
223
 
224
+ # Search
225
+ results = searcher.search("classic findings of pulmonary embolism on CTPA")
226
+
227
+ for r in results[:5]:
228
+ print(f"Score: {r['score']:.3f}")
229
+ print(f"Content: {r['document'][:200]}...")
230
+ print()
231
+ ```
232
+
233
+ ### Integration with Elasticsearch/OpenSearch
234
 
235
  ```python
236
+ from sentence_transformers import CrossEncoder
237
+
238
+ reranker = CrossEncoder("matulichpt/radlit-crossencoder", max_length=512)
239
+
240
+ def rerank_elasticsearch_results(query: str, es_results: list, top_k: int = 10):
241
+ """Rerank Elasticsearch BM25 results."""
242
+ documents = [hit["_source"]["content"] for hit in es_results]
243
+ pairs = [[query, doc] for doc in documents]
244
+
245
+ scores = reranker.predict(pairs) / 1.5 # Temperature calibration
246
+
247
+ # Combine with ES scores (optional)
248
+ for i, hit in enumerate(es_results):
249
+ hit["rerank_score"] = float(scores[i])
250
+ hit["combined_score"] = 0.3 * hit["_score"] + 0.7 * scores[i]
251
 
252
+ # Sort by combined score
253
+ reranked = sorted(es_results, key=lambda x: x["combined_score"], reverse=True)
254
+ return reranked[:top_k]
255
  ```
256
 
257
+ ## Optimal Fusion Weights
258
 
259
+ When combining multiple signals (bi-encoder, cross-encoder, BM25), use these weights:
260
 
261
  ```python
262
+ # Optimal weights from grid search on RadLIT-9
263
+ FUSION_WEIGHTS = {
264
+ "biencoder": 0.5, # RadLITE-Encoder similarity
265
+ "crossencoder": 0.2, # RadLITE-Reranker (after temp calibration)
266
+ "bm25": 0.3 # Lexical matching (if available)
267
+ }
268
+
269
+ def fused_score(bienc_score, ce_score, bm25_score=0):
270
+ return (
271
+ FUSION_WEIGHTS["biencoder"] * bienc_score +
272
+ FUSION_WEIGHTS["crossencoder"] * ce_score +
273
+ FUSION_WEIGHTS["bm25"] * bm25_score
 
 
 
 
 
 
 
 
 
 
274
  )
275
+ ```
276
+
277
+ ## Architecture
278
 
279
+ ```
280
+ [Query] + [SEP] + [Document]
281
+ |
282
+ v
283
+ [BERT Tokenizer]
284
+ |
285
+ v
286
+ [MiniLM Encoder] (12 layers, 384 hidden)
287
+ |
288
+ v
289
+ [Classification Head]
290
+ |
291
+ v
292
+ Relevance Score (float)
293
  ```
294
 
295
+ ## Training Details
296
 
297
+ - **Base Model**: ms-marco-MiniLM-L-12-v2 (trained on MS MARCO passage ranking)
298
+ - **Fine-tuning**: Radiology query-document relevance pairs
299
+ - **Training Steps**: 5,626
300
+ - **Best Validation Loss**: 0.691
301
+ - **Learning Rate**: 2e-5
302
+ - **Batch Size**: 32
303
+ - **Category Weighting**: Yes (balanced across radiology subspecialties)
304
 
305
+ ## Best Practices
306
 
307
+ ### 1. Always Use Temperature Calibration
 
 
 
 
308
 
309
+ Raw cross-encoder scores can be extreme. Temperature scaling (1.5) produces better fusion:
310
 
311
+ ```python
312
+ calibrated = raw_score / 1.5
313
+ ```
314
 
315
+ ### 2. Limit Candidates for Reranking
 
 
 
 
316
 
317
+ Cross-encoders are slow. Only rerank top 50-100 candidates from bi-encoder:
 
 
 
318
 
319
+ ```python
320
+ # Good: Rerank top 50
321
+ rerank_candidates = 50
322
 
323
+ # Bad: Rerank entire corpus
324
+ rerank_candidates = len(corpus) # Too slow!
325
+ ```
326
 
327
+ ### 3. Batch Predictions
 
 
328
 
329
+ ```python
330
+ # Efficient: Single batch call
331
+ pairs = [[query, doc] for doc in candidates]
332
+ scores = reranker.predict(pairs, batch_size=32)
333
 
334
+ # Inefficient: Individual calls
335
+ scores = [reranker.predict([[query, doc]])[0] for doc in candidates]
336
+ ```
337
 
338
+ ### 4. GPU Acceleration
339
 
340
+ ```python
341
+ reranker = CrossEncoder(
342
+ "matulichpt/radlit-crossencoder",
343
+ max_length=512,
344
+ device="cuda" # Use GPU
345
+ )
346
+ ```
347
 
348
+ ## Limitations
349
 
350
+ - **English only**: Trained on English radiology text
351
+ - **Speed**: ~10-50 pairs/second (use for reranking, not full corpus)
352
+ - **512 token limit**: Long documents are truncated
353
+ - **Domain-specific**: Optimized for radiology, may underperform on general medical content
354
 
355
  ## Citation
356
 
357
+ If you use RadLITE in your work, please cite:
358
+
359
  ```bibtex
360
+ @software{radlite_2026,
361
+ title = {RadLITE: Calibrated Multi-Stage Retrieval for Radiology Education},
362
+ author = {Grai Team},
363
+ year = {2026},
364
+ month = {January},
365
+ url = {https://huggingface.co/matulichpt/radlit-crossencoder},
366
+ note = {+30% MRR improvement on ACR Core Exam questions}
367
  }
368
  ```
369
 
370
  ## Related Models
371
 
372
+ - [RadLITE-Encoder](https://huggingface.co/matulichpt/radlit-biencoder) - Bi-encoder for first-stage retrieval
373
+ - [RadBERT-RoBERTa-4m](https://huggingface.co/zzxslp/RadBERT-RoBERTa-4m) - Base radiology language model
374
 
375
  ## License
376
 
377
+ Apache 2.0 - Free for commercial and research use.
 
 
 
 
config.json CHANGED
@@ -10,12 +10,12 @@
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,
 
10
  "hidden_dropout_prob": 0.1,
11
  "hidden_size": 384,
12
  "id2label": {
13
+ "0": "relevance"
14
  },
15
  "initializer_range": 0.02,
16
  "intermediate_size": 1536,
17
  "label2id": {
18
+ "relevance": 0
19
  },
20
  "layer_norm_eps": 1e-12,
21
  "max_position_embeddings": 512,