CoolFace
Modelpublic

FlorianTraugott/ms-marco-MiniLM-L6-v2-indian-tax-law

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes14downloads
Model Card

ms-marco-MiniLM-L6-v2 fine-tuned as an Indian tax-law reranker

A cross-encoder reranker, fully fine-tuned from `cross-encoder/ms-marco-MiniLM-L6-v2` for second-stage reranking over Indian tax-law judgments. It reads a (query, passage) pair together and scores how well the passage answers the question.

Used to rerank the top 50 results from `bge-small-en-v1.5-indian-tax-law-lora`, it improves nDCG@10 by +12.4% and Recall@10 by +11.4% over that retriever alone.

The finding you should know before using this

A zero-shot MS-MARCO reranker makes this task worse, not better. On the same shortlists, the un-tuned base model scores nDCG@10 0.4837 — below the 0.5015 you get by not reranking at all. The gain here comes from domain fine-tuning, not from adding a reranker.

A paired bootstrap over the same 256 queries and identical shortlists (10,000 resamples) puts the fine-tuned-versus-zero-shot gap at +0.0798 nDCG@10, 95% CI [+0.0516, +0.1092], p < 0.0001, better on 83 queries and worse on 33. The interval excludes zero.

So: do not substitute the base model here and expect similar behaviour.

Usage

The reranker takes bare query text — unlike the bi-encoder, it needs no prefix.

python
from sentence_transformers import CrossEncoder

model = CrossEncoder("FlorianTraugott/ms-marco-MiniLM-L6-v2-indian-tax-law", max_length=512)

query = "Can a reassessment notice be issued after four years?"
shortlist = ["<passage 1>", "<passage 2>", "..."]   # top-50 from the bi-encoder

scores = model.predict([(query, p) for p in shortlist])
reranked = [p for _, p in sorted(zip(scores, shortlist), key=lambda x: -x[0])]

Scores are raw logits (the model uses an identity activation), so they are unbounded and only meaningful for ordering — not as calibrated probabilities.

Results

256 held-out queries against a 3,868-passage corpus, reranking the top N=50.

metricoff-the-shelf bi-encoderfine-tuned bi-encoder**+ this reranker**+ *zero-shot* reranker
Recall@100.48440.68750.76560.6875
MRR@100.29960.44310.49890.4193
nDCG@100.34440.50150.56350.4837
comparisonRecall@10MRR@10nDCG@10
this reranker vs the retriever alone+11.4%+12.6%+12.4%
full two-stage stack vs the off-the-shelf baseline+58.1%+66.5%+63.6%

Choosing the rerank depth

A reranker permutes a shortlist; it cannot add to it. So post-rerank Recall@10 can never exceed the retriever's Recall@N, and at N=10 it is provably unchanged.

NRecall@10ceiling (retriever Recall@N)MRR@10nDCG@10
100.68750.68750.48750.5365
250.73830.79690.49260.5521
500.76560.86330.49890.5635
1000.75780.91800.49690.5599

N=50 is the operating point: it maximises every metric measured, and N=100 is both slower and worse. At N=10, Recall is frozen by construction while MRR@10 still rises +10.0% and nDCG@10 +7.0% on the identical ten documents — the reranker doing purely its reordering job.

Training

Base modelcross-encoder/ms-marco-MiniLM-L6-v2 (Apache-2.0, 22.7M params, 6 layers)
Methodfull fine-tune — all 105 tensors including the classification head
Losspointwise BinaryCrossEntropyLoss, unweighted
Data6,792 labeled pairs — 1,132 positives + 5,660 mined hard negatives (5:1)
Schedule2 epochs, 382 steps, batch 32, lr 2e-5, 38 warmup
Sequence512 tokens, train and eval — 0 pairs truncated (longest 455)
Precisionfp32 on Apple Silicon MPS — 12.5 minutes

LoRA was tried and rejected: under task_type=SEQ_CLS, PEFT attaches without error but leaves modules_to_save=None, so the classification head stays frozen while the body adapts underneath it. Full fine-tuning was verified live instead.

Training data

Same corpus and split as the companion retriever: 3,868 passages from 400 Indian tax judgments filtered from `opennyaiorg/InJudgements_dataset` (Apache-2.0), with synthetic queries generated by OpenAI gpt-4.1-mini under anti-echo constraints, and 5 hard negatives per query mined with the un-tuned retriever.

The reranker trains on the same hard negatives the retriever saw, so its difficulty is calibrated to the shortlists it actually sits behind. Eval positives are excluded from training in both label slots; all leak checks measure 0.

Full pipeline and provenance: https://github.com/FlorianTraugott/legal-retrieval-finetune

Intended use and limitations

Intended for reranking a retrieval shortlist over Indian tax-law judgments, at N≈50, behind the companion retriever `bge-small-en-v1.5-indian-tax-law-lora`. Neither model is the full story alone: the retriever sets the recall ceiling this model reorders within.

Not intended for other legal domains or jurisdictions, general-purpose reranking, or scoring passages outside a retrieved shortlist. It is a ranking component, not a legal-advice system.

  1. 1.Reranking is net-positive, not uniformly safe. Of 221 queries with a positive in the top 50: 91 improved, 69 unchanged, 61 got worse. One positive fell from rank 1 to 22. Net top-10 swing was +20.
  2. 2.This checkpoint was selected on the evaluation set (by nDCG@10 at N=50), so its figures carry mild selection optimism. The effect is bounded — only three candidates were compared and the two trained ones differ by 0.0008 nDCG@10.
  3. 3.The in-training validation metric was saturated (0.8983 zero-shot on a 1-in-6 ranking proxy), which is why checkpoint selection was redone on the real task.
  4. 4.The eval queries are synthetic, each with a single labelled correct passage, so the attainable ceiling is below 1.0 and unknown.
  5. 5.Latency was never benchmarked. N=50 means 50 cross-encoder forward passes per query, serially, after retrieval. Batched throughput during evaluation was 139–179 pairs/second on an Apple Silicon laptop, which is not a served single-query path.
  6. 6.About 44% of the available headroom is converted: at N=50 the ceiling is Recall@10 0.8633 and this model reaches 0.7656.

Licence

Apache-2.0, inherited from cross-encoder/ms-marco-MiniLM-L6-v2 (Apache-2.0); this is a full fine-tune of those weights, so the derivative carries the same terms and its notice requirements. The training corpus derives from opennyaiorg/InJudgements_dataset (Apache-2.0). Synthetic training queries were generated using OpenAI gpt-4.1-mini; if you redistribute or build on this work, review OpenAI's terms for your own use case.

Author: Ayush Padhy (GitHub/HF: @FlorianTraugott)

Citation

bibtex
@software{legal_retrieval_finetune_2026,
  title  = {Fine-tuning a two-stage retrieval stack for Indian tax law},
  year   = {2026},
  url    = {https://github.com/FlorianTraugott/legal-retrieval-finetune}
}