kurtvalcorza/qwen3-reranker-pipeline

Qwen3 Reranker Pipeline

Python

0

33 commits

updated Oct 17, 2026

See the code

README

Qwen3 Reranker Pipeline

DIMER-oriented inference wrapper for Qwen3-Reranker-0.6B, pinned to an immutable Hugging Face revision. The repository exposes pointwise query-document relevance scoring with the upstream README's exact prompt and yes/no logit-softmax contract, a supply-chain check of the local weight snapshot, and machine-readable provenance.

Upstream alignment

  • Model: Qwen/Qwen3-Reranker-0.6B
  • Revision: e61197ed45024b0ed8a2d74b80b4d909f1255473
  • Upstream weight license: Apache-2.0
  • Upstream task: text reranking (second-stage relevance scoring of retrieved candidates)
  • Repository adaptation: bounded listwise fine-tuning of the last decoder layers on {id, query, positive, negatives} records (adapt), measured by held-out ranking recall@k and MRR (evaluate, lexical_baseline, random_floor); the base weights are never redistributed and the adapter is a tutorial output

Quick start

from qwen3_reranker_pipeline import Qwen3RerankerPipeline

pipe = Qwen3RerankerPipeline.from_pretrained()          # verifies weights/qwen3-reranker-0.6b first
pairs = [
    ("What is the capital of China?", "The capital of China is Beijing."),
    ("What is the capital of China?", "Gravity is a force that attracts two bodies."),
]
result = pipe.rerank(pairs)
print(result["scores"], result["ranking"])   # [~0.9995, ~0.0], [0, 1]

# adaptation: the pinned Banking77 shortlists (fetched and digest-checked at run time), ranking metrics, fine-tuning
from qwen3_reranker_pipeline import TASK_INSTRUCTION, fetch_sample_dataset

splits = fetch_sample_dataset()                            # 231 / 77 / 154 {id, query, positive, negatives} records
print(pipe.lexical_baseline(splits["test"])["recall@1"])   # the no-model floor
print(pipe.evaluate(splits["test"], instruction=TASK_INSTRUCTION)["recall@1"])   # 924 forward passes
pipe.adapt(splits["train"], splits["validation"], instruction=TASK_INSTRUCTION)    # last two layers, 2 epochs
print(pipe.evaluate(splits["test"], instruction=TASK_INSTRUCTION)["recall@1"])
pipe.save_artifact("outputs/qwen3_reranker_adapter")      # adapter.safetensors + manifest.json
reloaded = Qwen3RerankerPipeline.from_artifact("outputs/qwen3_reranker_adapter")

rerank() takes 1..32 (query, document) pairs (MAX_PAIRS) and an optional instruction (default from the upstream README). Each pair is wrapped in the fixed system/user/assistant prompt; the score is the softmax share of the yes logit against the no logit at the last position — a relevance score, not a calibrated probability, and no threshold is applied. Prompts beyond 8,192 tokens (MAX_TEXT_TOKENS) are truncated longest-first and flagged per pair in truncated; texts above 100,000 characters (MAX_TEXT_CHARS) are rejected. Every result carries ranking, score_kind, n_tokens, model_id and model_revision.

Weights layout

weights/qwen3-reranker-0.6b/
  config.json  1_LogitScore/config.json  chat_template.jinja  model.safetensors  tokenizer.json
  tokenizer_config.json  vocab.json  merges.txt  generation_config.json  modules.json
  sentence_bert_config.json  config_sentence_transformers.json  README.md  dimer-base-manifest.json
weights/banking77/           # git-ignored run-time cache of the two pinned Banking77 CSV files (1.1 MB)

from_pretrained() calls stage_missing_files() (fetches absent manifest entries at the pinned revision, only with allow_download=True) then verify_snapshot() (size + SHA-256 of every entry), loads with local_files_only=True, and raises if the tokenizer's yes/no ids differ from the pinned 9693/2152. Without a manifest it raises unless allow_download=True. See docs/WEIGHTS.md.

Tests

pip install -e . --no-deps
pytest -q -o addopts= tests

Tests are offline: they use an injected fake runner and temporary manifests, never the weights.

Tutorial

Open In Colab

tutorials/qwen3_reranker_colab.ipynb is declared E2E (mode GUIDED) under DIMER Notebook Specification 2.2 and is standalone (§4): generated by tools/build_notebook.py, it carries the three pipeline modules (pipeline.py, metrics.py, samples.py), the model identity, manifest digests and runtime pins, so the exported notebook runs without this repository (parity enforced by tests/test_notebook_parity.py; see tutorials/README.md). Its default path stages the missing model.safetensors with stage_missing_files(..., allow_download=True) and digest-verifies the snapshot, fetches the two digest-pinned Banking77 CSV files and draws 231 / 77 / 154 message → intent-phrase shortlists (the gold phrase plus three hard and two random other phrases per query) balanced over the 77 intents with validate_dataset and check_split_disjoint, reranks one test shortlist through the inference contract, reads the frozen reranker's recall@1 / recall@3 / recall@5 and MRR beside the random floor and a lexical baseline, fine-tunes the last two decoder layers for two epochs with a listwise loss and validation-MRR epoch selection, scores the held-out split again (recall@1 73.4 % → 77.9 % in the CPU float32 build record, 73.4 % → 76.6 % on the 2026-09-19 Kaggle T4 run; lexical 26.6 %), prints the adapted model's ordering of three shortlists beside the frozen one, and exports the adapter as safetensors with a manifest that reloads to identical scores. Six outputs/ artifacts are written. BYOD ({id, query, positive, negatives} records as CSV / JSON / JSONL plus your own INSTRUCTION) is optional and gated off by default. A cross-encoder scores one pair per forward pass, so the path takes about fifteen minutes of model time on CPU.

Release status

Candidate — the E2E notebook was regenerated on 2026-10-09 for the Notebook Review Framework v1 findings RR-M1..M4 and RR-m1..m6 (uv isolated environment with a hash lock, no restart; re-runs start from the pinned base; BYOD 12..10,002 distinct queries; guided layer and activity; NOTEBOOK_SPEC 2.2), so its blob changed; the review-fix blob 93f1a9d5 (commit d064746) completed one pass with no restart and 0 errors on a fresh Colab Tesla T4 on 2026-10-09 (Colab CLI sequential execution, 12/12 code cells, 513.7 s; held-out recall@1 0.7338 → 0.7662, MRR 0.8429 → 0.8634; reload parity exact); BYOD on a hosted runtime (REL12) is still open; see docs/release-verification.md and STATUS.md. The 2026-09-19 Kaggle Tesla T4 record of blob 99efdc6a needed one manual restart after the install cell and is history only. Static and unit checks — including the standalone generator parity checks — are necessary but are not the evidence; the hosted run is.

Licensing

This repository's code is Apache-2.0 (LICENSE). The packaged upstream weights are Apache-2.0; see docs/WEIGHTS.md and MODEL_CARD.md.

AI Assistance Disclosure

This repository’s code and accompanying documentation were developed with generative AI assistance for code development and technical writing under maintainer direction. The maintainer remains responsible for reviewing the implementation, validating results, and making release decisions. AI assistance does not constitute independent verification, provider endorsement, or release approval.

kurtvalcorza/qwen3-reranker-pipeline

Qwen3 Reranker Pipeline

Python

0

33 commits

updated Oct 17, 2026

See the code

README

Qwen3 Reranker Pipeline

DIMER-oriented inference wrapper for Qwen3-Reranker-0.6B, pinned to an immutable Hugging Face revision. The repository exposes pointwise query-document relevance scoring with the upstream README's exact prompt and yes/no logit-softmax contract, a supply-chain check of the local weight snapshot, and machine-readable provenance.

Upstream alignment

  • Model: Qwen/Qwen3-Reranker-0.6B
  • Revision: e61197ed45024b0ed8a2d74b80b4d909f1255473
  • Upstream weight license: Apache-2.0
  • Upstream task: text reranking (second-stage relevance scoring of retrieved candidates)
  • Repository adaptation: bounded listwise fine-tuning of the last decoder layers on {id, query, positive, negatives} records (adapt), measured by held-out ranking recall@k and MRR (evaluate, lexical_baseline, random_floor); the base weights are never redistributed and the adapter is a tutorial output

Quick start

from qwen3_reranker_pipeline import Qwen3RerankerPipeline

pipe = Qwen3RerankerPipeline.from_pretrained()          # verifies weights/qwen3-reranker-0.6b first
pairs = [
    ("What is the capital of China?", "The capital of China is Beijing."),
    ("What is the capital of China?", "Gravity is a force that attracts two bodies."),
]
result = pipe.rerank(pairs)
print(result["scores"], result["ranking"])   # [~0.9995, ~0.0], [0, 1]

# adaptation: the pinned Banking77 shortlists (fetched and digest-checked at run time), ranking metrics, fine-tuning
from qwen3_reranker_pipeline import TASK_INSTRUCTION, fetch_sample_dataset

splits = fetch_sample_dataset()                            # 231 / 77 / 154 {id, query, positive, negatives} records
print(pipe.lexical_baseline(splits["test"])["recall@1"])   # the no-model floor
print(pipe.evaluate(splits["test"], instruction=TASK_INSTRUCTION)["recall@1"])   # 924 forward passes
pipe.adapt(splits["train"], splits["validation"], instruction=TASK_INSTRUCTION)    # last two layers, 2 epochs
print(pipe.evaluate(splits["test"], instruction=TASK_INSTRUCTION)["recall@1"])
pipe.save_artifact("outputs/qwen3_reranker_adapter")      # adapter.safetensors + manifest.json
reloaded = Qwen3RerankerPipeline.from_artifact("outputs/qwen3_reranker_adapter")

rerank() takes 1..32 (query, document) pairs (MAX_PAIRS) and an optional instruction (default from the upstream README). Each pair is wrapped in the fixed system/user/assistant prompt; the score is the softmax share of the yes logit against the no logit at the last position — a relevance score, not a calibrated probability, and no threshold is applied. Prompts beyond 8,192 tokens (MAX_TEXT_TOKENS) are truncated longest-first and flagged per pair in truncated; texts above 100,000 characters (MAX_TEXT_CHARS) are rejected. Every result carries ranking, score_kind, n_tokens, model_id and model_revision.

Weights layout

weights/qwen3-reranker-0.6b/
  config.json  1_LogitScore/config.json  chat_template.jinja  model.safetensors  tokenizer.json
  tokenizer_config.json  vocab.json  merges.txt  generation_config.json  modules.json
  sentence_bert_config.json  config_sentence_transformers.json  README.md  dimer-base-manifest.json
weights/banking77/           # git-ignored run-time cache of the two pinned Banking77 CSV files (1.1 MB)

from_pretrained() calls stage_missing_files() (fetches absent manifest entries at the pinned revision, only with allow_download=True) then verify_snapshot() (size + SHA-256 of every entry), loads with local_files_only=True, and raises if the tokenizer's yes/no ids differ from the pinned 9693/2152. Without a manifest it raises unless allow_download=True. See docs/WEIGHTS.md.

Tests

pip install -e . --no-deps
pytest -q -o addopts= tests

Tests are offline: they use an injected fake runner and temporary manifests, never the weights.

Tutorial

Open In Colab

tutorials/qwen3_reranker_colab.ipynb is declared E2E (mode GUIDED) under DIMER Notebook Specification 2.2 and is standalone (§4): generated by tools/build_notebook.py, it carries the three pipeline modules (pipeline.py, metrics.py, samples.py), the model identity, manifest digests and runtime pins, so the exported notebook runs without this repository (parity enforced by tests/test_notebook_parity.py; see tutorials/README.md). Its default path stages the missing model.safetensors with stage_missing_files(..., allow_download=True) and digest-verifies the snapshot, fetches the two digest-pinned Banking77 CSV files and draws 231 / 77 / 154 message → intent-phrase shortlists (the gold phrase plus three hard and two random other phrases per query) balanced over the 77 intents with validate_dataset and check_split_disjoint, reranks one test shortlist through the inference contract, reads the frozen reranker's recall@1 / recall@3 / recall@5 and MRR beside the random floor and a lexical baseline, fine-tunes the last two decoder layers for two epochs with a listwise loss and validation-MRR epoch selection, scores the held-out split again (recall@1 73.4 % → 77.9 % in the CPU float32 build record, 73.4 % → 76.6 % on the 2026-09-19 Kaggle T4 run; lexical 26.6 %), prints the adapted model's ordering of three shortlists beside the frozen one, and exports the adapter as safetensors with a manifest that reloads to identical scores. Six outputs/ artifacts are written. BYOD ({id, query, positive, negatives} records as CSV / JSON / JSONL plus your own INSTRUCTION) is optional and gated off by default. A cross-encoder scores one pair per forward pass, so the path takes about fifteen minutes of model time on CPU.

Release status

Candidate — the E2E notebook was regenerated on 2026-10-09 for the Notebook Review Framework v1 findings RR-M1..M4 and RR-m1..m6 (uv isolated environment with a hash lock, no restart; re-runs start from the pinned base; BYOD 12..10,002 distinct queries; guided layer and activity; NOTEBOOK_SPEC 2.2), so its blob changed; the review-fix blob 93f1a9d5 (commit d064746) completed one pass with no restart and 0 errors on a fresh Colab Tesla T4 on 2026-10-09 (Colab CLI sequential execution, 12/12 code cells, 513.7 s; held-out recall@1 0.7338 → 0.7662, MRR 0.8429 → 0.8634; reload parity exact); BYOD on a hosted runtime (REL12) is still open; see docs/release-verification.md and STATUS.md. The 2026-09-19 Kaggle Tesla T4 record of blob 99efdc6a needed one manual restart after the install cell and is history only. Static and unit checks — including the standalone generator parity checks — are necessary but are not the evidence; the hosted run is.

Licensing

This repository's code is Apache-2.0 (LICENSE). The packaged upstream weights are Apache-2.0; see docs/WEIGHTS.md and MODEL_CARD.md.

AI Assistance Disclosure

This repository’s code and accompanying documentation were developed with generative AI assistance for code development and technical writing under maintainer direction. The maintainer remains responsible for reviewing the implementation, validating results, and making release decisions. AI assistance does not constitute independent verification, provider endorsement, or release approval.