Text Ranking
Transformers
Safetensors
qwen3
text-classification
reranker
sequence-classification
multilingual
bfloat16
32k
Instructions to use sigridjineth/ctxl-rerank-v2-1b-seq-cls with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use sigridjineth/ctxl-rerank-v2-1b-seq-cls with Transformers:
# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForSequenceClassification tokenizer = AutoTokenizer.from_pretrained("sigridjineth/ctxl-rerank-v2-1b-seq-cls") model = AutoModelForSequenceClassification.from_pretrained("sigridjineth/ctxl-rerank-v2-1b-seq-cls", device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 8,956 Bytes
c773995 3acb305 c773995 4b65b64 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 470db40 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 470db40 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 c773995 3acb305 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | ---
library_name: transformers
license: cc-by-nc-sa-4.0
pipeline_tag: text-ranking
tags:
- reranker
- sequence-classification
- qwen3
- multilingual
- bfloat16
- 32k
base_model: ContextualAI/ctxl-rerank-v2-instruct-multilingual-1b
model_type: qwen3
---
# Contextual AI Reranker v2 1B — **SequenceClassification (single-logit) Converted Model**
This repository contains a **drop-in SequenceClassification** version of the original **ContextualAI/ctxl-rerank-v2-instruct-multilingual-1b**.
It exposes a **single logit per input** (one score) that is **numerically equivalent** to the original model’s last-token **`vocab_id=0`** logit (`next_logits[:, 0]`). That means you can use standard **text-classification/CrossEncoder** tooling for fast, simple reranking—without custom logits processors—while preserving the original scores and ranking order.
> **What changed?** We copy the LM head’s **row 0** vector into a 1-logit classification head (`score.weight ← lm_head.weight[0]`), set bias to 0 (or the matching bias row if present), and keep tokenizer/padding behavior aligned with the original. Result: `SequenceClassification` output ≡ original `next_logits[:, 0]`.
---
## Highlights
* **Parity with the original**: The score from this model equals the original **ID=0** logit at the very last token position (use the same prompt template and left-padding).
* **Frictionless integration**: Works out-of-the-box with **Sentence-Transformers CrossEncoder** and standard **Transformers** classification interfaces.
* **Fast & memory-light**: Computes a single logit (`hidden_size × 1`) instead of a full vocabulary projection.
* **Multilingual** and long-context (inherits capabilities from the base reranker).
---
## Model Overview
* **Type**: Text Reranking (single-logit SequenceClassification)
* **Base**: `ContextualAI/ctxl-rerank-v2-instruct-multilingual-1b` (Qwen3 CausalLM)
* **Languages**: 100+ (inherited)
* **Params**: \~1B (inherited)
* **Context Length**: up to 32K (inherited)
* **Scoring definition**: single logit ≡ original `next_logits[:, 0]`
---
## Input Formatting (keep this template)
```text
Check whether a given document contains information helpful to answer the query.
<Document> {document}
<Query> {query}{optional_instruction} ??
```
* Use **left padding** so the **last token** aligns across a batch.
* If the tokenizer has no `pad_token`, set `pad_token = eos_token`.
---
## Updated Usage
Below are **drop-in** examples for the converted model. These mirror the original card’s behavior but through **SequenceClassification**.
### Updated Sentence Transformers Usage (CrossEncoder)
```python
from sentence_transformers import CrossEncoder
MODEL_ID = "sigridjineth/ctxl-rerank-v2-1b-seq-cls" # or local folder
def format_prompts(query: str, instruction: str, docs: list[str]) -> list[str]:
inst = f" {instruction}" if instruction else ""
return [
"Check whether a given document contains information helpful to answer the query.\n"
f"<Document> {d}\n"
f"<Query> {query}{inst} ??"
for d in docs
]
query = "Which is a domestic animal?"
docs = ["Cats are pets.", "The moon is made of cheese.", "Dogs are loyal companions."]
ce = CrossEncoder(MODEL_ID, max_length=8192)
# Ensure original padding behavior
if ce.tokenizer.pad_token is None:
ce.tokenizer.pad_token = ce.tokenizer.eos_token
ce.tokenizer.padding_side = "left"
prompts = format_prompts(query, "", docs)
scores = ce.predict(prompts) # one logit per doc (higher = more relevant)
ranked = sorted(zip(scores, docs), key=lambda x: x[0], reverse=True)
for s, d in ranked:
print(f"{s:.4f} | {d}")
```
### Updated Transformers Usage (SequenceClassification)
```python
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification
MODEL_ID = "sigridjineth/ctxl-rerank-v2-1b-seq-cls" # or local folder
device = "cuda" if torch.cuda.is_available() else "cpu"
dtype = torch.bfloat16 if torch.cuda.is_available() else torch.float32
def format_prompts(query: str, instruction: str, docs: list[str]) -> list[str]:
inst = f" {instruction}" if instruction else ""
return [
"Check whether a given document contains information helpful to answer the query.\n"
f"<Document> {d}\n"
f"<Query> {query}{inst} ??"
for d in docs
]
tok = AutoTokenizer.from_pretrained(MODEL_ID, use_fast=True)
if tok.pad_token is None:
tok.pad_token = tok.eos_token
tok.padding_side = "left"
model = AutoModelForSequenceClassification.from_pretrained(MODEL_ID, torch_dtype=dtype).to(device).eval()
query = "Which is a domestic animal?"
docs = ["Cats are pets.", "The moon is made of cheese."]
prompts = format_prompts(query, "", docs)
enc = tok(prompts, return_tensors="pt", padding=True, truncation=True).to(device)
with torch.no_grad():
logits = model(**enc).logits.squeeze(-1) # [batch]
# Optional: exact parity rounding with original BF16 readout
scores = logits.to(torch.bfloat16).float().cpu().tolist()
ranked = sorted(zip(scores, docs), key=lambda x: x[0], reverse=True)
for s, d in ranked:
print(f"{s:.4f} | {d}")
```
> **Note on parity**: Casting the output logit to **bf16 then back to float** matches the original card’s BF16 rounding step.
---
## (Reference) Original Transformers Usage (CausalLM)
If you prefer to call the original model directly, compute `next_logits[:, -1, 0]` as specified in the base card.
```python
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
BASE_ID = "ContextualAI/ctxl-rerank-v2-instruct-multilingual-1b"
device = "cuda" if torch.cuda.is_available() else "cpu"
dtype = torch.bfloat16 if torch.cuda.is_available() else torch.float32
def format_prompts(q: str, inst: str, docs: list[str]) -> list[str]:
inst = f" {inst}" if inst else ""
return [
"Check whether a given document contains information helpful to answer the query.\n"
f"<Document> {d}\n"
f"<Query> {q}{inst} ??"
for d in docs
]
tok = AutoTokenizer.from_pretrained(BASE_ID, use_fast=True)
if tok.pad_token is None:
tok.pad_token = tok.eos_token
tok.padding_side = "left"
lm = AutoModelForCausalLM.from_pretrained(BASE_ID, torch_dtype=dtype).to(device).eval()
docs = ["Cats are pets.", "The moon is made of cheese."]
prompts = format_prompts("Which is a domestic animal?", "", docs)
enc = tok(prompts, return_tensors="pt", padding=True, truncation=True).to(device)
with torch.no_grad():
out = lm(**enc).logits[:, -1, :] # [batch, vocab]
scores = out[:, 0].to(torch.bfloat16).float().cpu().tolist()
for s, d in sorted(zip(scores, docs), key=lambda x: x[0], reverse=True):
print(f"{s:.4f} | {d}")
```
---
## Conversion Details
* **Architecture**: `Qwen3ForSequenceClassification(num_labels=1)`
* **Head initialization**:
* `score.weight ← lm_head.weight[0]` (row for `vocab_id=0`)
* `score.bias ← 0` (or the corresponding bias term if present in LM head)
* **Tokenizer/Config**:
* Ensure `pad_token` exists (`pad_token = eos_token` if missing)
* Set `padding_side="left"`
* Propagate `pad/eos/bos` IDs into the model `config` for correct batching
* **Parity check**:
* Verified that `SequenceClassification` logit ≡ original `next_logits[:, 0]`
* Optional BF16 round-trip on the score for exact rounding parity
---
## Intended Use & Limitations
* **Use**: Document reranking for search/QA/multilingual scenarios; batch scoring of `(query, document)` prompts.
* **Not for**: Open-ended generation; the model emits a **single score** per input.
* **License constraints**: Non-commercial & Share-Alike. If you redistribute derivatives, include attribution and the same license.
* **Bias & safety**: Inherits all limitations and potential biases of the base model; evaluate before deployment.
---
## Requirements
* **Transformers** ≥ 4.51.0
* **PyTorch** with BF16 support recommended on GPU
* Long inputs: set `max_length` accordingly (up to the inherited context window)
---
## Citation
If you use this converted model, please cite the original work:
```bibtex
@misc{ctxl_rerank_v2_instruct_multilingual,
title = {Contextual AI Reranker v2},
author = {George Halal and Sheshansh Agrawal and Bo Han and Arnav Palkhiwala},
year = {2025},
url = {https://contextual.ai/blog/rerank-v2}
}
```
---
## License
This repository follows the original **Creative Commons Attribution Non Commercial Share Alike 4.0 (CC-BY-NC-SA-4.0)** license.
You **must** provide attribution, **may not** use it commercially, and **must** distribute derivatives under the same license.
---
## Acknowledgements
All modeling, training, and evaluation credit goes to **Contextual AI** for the original `ctxl-rerank-v2` family.
This repository provides a **compatibility conversion** to a single-logit `SequenceClassification` interface for easier integration and deployment.
|