Skip to the content.

Training

Training proceeds in two stages. Stage 1 (retriever) must finish first because its rankings drive hard-negative mining; Stage 2 (reranker) is independent and can run in parallel once the data is prepared.

0. Prepare data

python scripts/download_esci.py --locale us --out data/raw

1. Bi-encoder retriever

bash scripts/train_retriever.sh configs/bi_encoder.yaml

The script runs three steps:

  1. Warm-up pass — train with in-batch negatives only (InfoNCE, temperature 0.05). Every other document in the batch is an implicit negative.
  2. Hard-negative mining — embed the catalogue, retrieve the top-100 products per training query, and keep highly-ranked non-Exact products as hard negatives (necs.data.hard_negatives).
  3. Fine-tune pass — retrain with the mined negatives appended to each batch’s document pool. The loss target for query i stays column i because documents are laid out as [positives | hard-negatives].

Hard negatives are intended to focus training on Substitute/Complement cases: random negatives may be trivially separable, while a non-Exact product that the retriever ranks highly is a more informative error. The size of any improvement must be established by the reproducible ablation plan rather than assumed here.

Key hyper-parameters (configs/bi_encoder.yaml)

Param Default Notes
model_name all-MiniLM-L6-v2 shared query/doc encoder
temperature 0.05 InfoNCE softmax temperature
num_hard_negatives 4 mined negatives appended per query
retrieval_top_k 100 candidates pulled for mining / serving
batch_size 64 larger ⇒ more in-batch negatives

2. Cross-encoder reranker

bash scripts/train_reranker.sh configs/cross_encoder.yaml

Trains deberta-v3-base on labelled (query, product) pairs with class-weighted cross-entropy and gradient accumulation (effective batch 64). Dynamic padding keeps step time down on the long-tailed product passages.

Key hyper-parameters (configs/cross_encoder.yaml)

Param Default Notes
model_name microsoft/deberta-v3-base joint encoder
max_seq_len 192 query + product budget
class_weights [1.0, 2.0, 4.0, 1.5] E, S, C, I — upweight rare ones
lr 1e-5 DeBERTa is lr-sensitive

3. Build the serving index

python scripts/build_index.py \
    --retriever artifacts/bi_encoder \
    --out artifacts/product_index

4. Evaluate

python scripts/run_eval.py --config configs/pipeline.yaml \
    --retriever artifacts/bi_encoder --reranker artifacts/cross_encoder

See docs/experiments.md for results.

Reproducibility

Configs are plain YAML and the training code exposes deterministic seeding for Python, NumPy, and Torch. A seed alone does not make a run reproducible: save the exact config, dependency versions, dataset checksums, model revisions, hardware, logs, and checkpoint hashes described in docs/reproducibility.md. Mixed precision is enabled by configuration on CUDA and can change numeric behavior across hardware.