opensearch-neural-sparse-en-jp-ko

Fine-tuned from opensearch-project/opensearch-neural-sparse-encoding-multilingual-v1 for cross-lingual sparse retrieval across English, Japanese, and Korean.

The training objective pulls non-English queries toward English vocabulary positions in the sparse output โ€” so a Japanese sentence about "้›ปๆฑ ๆŠ•่ณ‡" and its English equivalent about "battery investment" activate similar vocab positions, enabling a single English anchor schema to retrieve across all three scripts.

Domain: automotive, supply-chain, and geopolitics.

This repository includes both the trained weights and the full training harness (training/), so you can reproduce, extend, or retarget the model to your own domain.


Quick usage

from transformers import AutoTokenizer, AutoModelForMaskedLM
import torch

tok = AutoTokenizer.from_pretrained("cp500/opensearch-neural-sparse-en-jp-ko")
model = AutoModelForMaskedLM.from_pretrained("cp500/opensearch-neural-sparse-en-jp-ko")

text = "ใƒˆใƒจใ‚ฟใฏ้›ปๆฑ ๆŠ€่ก“ใซๅคš้กใฎๆŠ•่ณ‡ใ‚’ใ—ใฆใ„ใ‚‹ใ€‚"
enc = tok(text, return_tensors="pt", return_token_type_ids=False)
logits = model(**enc).logits
activated = torch.log1p(torch.relu(logits))
activated = activated * enc["attention_mask"].unsqueeze(-1)
sparse = activated.max(dim=1).values
top = torch.topk(sparse[0], k=15)
for v, i in zip(top.values, top.indices):
    if v > 0:
        print(f"{{tok.convert_ids_to_tokens(int(i)):>20}}  {{float(v):.3f}}")

Loss functions

The training objective is a weighted sum of three terms:

loss = task_loss ร— (1 + (ฮป_xl โˆ’ 1) ร— xl_fraction)
     + ฮป_q ยท FLOPS(query_batch)
     + ฮป_d ยท (FLOPS(positive_batch) + FLOPS(negative_batch))

1. Task loss โ€” InfoNCE with in-batch negatives

The core retrieval signal. For each query in a batch of size B:

  • Compute sparse representations: q_sparse, p_sparse, n_sparse via SPLADE's log(1 + ReLU(logits)) + attention-masked max-pool over token positions.
  • Build scores against every positive in the batch plus one explicit hard negative: scores = concat(q @ p_batch.T, q ยท n) โ€” shape (B, B + 1).
  • Optimise multi-class cross-entropy with the correct label = row index (each query's own positive is the target).

Why cross-entropy and not MarginMSE? During our initial runs, MarginMSE with dot-product scores collapsed to near-empty sparse vectors: the model found it cheaper to shrink all scores toward zero than to learn proper margins. InfoNCE's softmax normalisation makes that strategy lose โ€” the loss is invariant to uniform score scaling, so the only way to improve is to differentiate positives from negatives.

2. Cross-lingual pair up-weighting

The primary goal is cross-lingual alignment โ€” pulling non-English queries onto English vocab positions. We scale the task loss by a per-batch factor proportional to how many cross-lingual pairs it contains:

xl_fraction = count(q_lang โ‰  p_lang) / batch_size
task_weight = 1 + (ฮป_xl โˆ’ 1) ร— xl_fraction            # ฮป_xl = 1.5 default

A batch with 100% cross-lingual pairs contributes 1.5ร— the gradient of a batch with 100% monolingual pairs. The dataset is deliberately skewed toward cross-lingual triplets (see the corpus card for the language-pair distribution).

3. FLOPS regularisation

Without regularisation, a sparse encoder can "cheat" by activating all vocab positions slightly โ€” sparse in name only. FLOPS regularisation (from the SPLADE line of papers) penalises the squared L1 of the mean activation vector across a batch:

FLOPS(batch) = โ€–mean_over_batch(|activations|)โ€–ยฒ_{L1-then-L2}
             = ( ฮฃ_v ( (1/B) ฮฃ_b |a_{b,v}| ) )ยฒ computed per vocab-col then
                                                  .pow(2).sum() across cols

This is asymmetrically applied: queries are pushed sparser (ฮป_q = 3eโˆ’4 by default) than documents (ฮป_d = 1eโˆ’4), consistent with the SPLADE production convention that short queries should activate fewer tokens than long documents.

4. FLOPS lambda warm-up

Applying full FLOPS regularisation from step 0 kills the model โ€” it happily zeroes the output before the task loss has started pulling any signal through the layers. We ramp ฮป_q and ฮป_d quadratically from 0 to their target values over the first flops_warmup_steps steps (default: min(total_steps / 3, 2000)). This lets the model first establish which vocab positions matter for retrieval, then compress.

5. What we did NOT use and why

  • Knowledge distillation from a cross-encoder teacher (MarginMSE canonical recipe): we have no multilingual automotive cross-encoder with trustworthy teacher scores. InfoNCE is the honest fallback when teacher scores aren't available.
  • Hard negative mining from a first-pass encoder: the five hard negatives per concept were generated directly by the data-gen prompt, not mined post hoc. This keeps the pipeline simple and reproducible.
  • Normalisation of sparse vectors before dot product: SPLADE-v3 and prithivida/Splade_PP both use raw dot product. InfoNCE's softmax makes magnitude-robustness moot.

Training configuration

  • Base model: opensearch-project/opensearch-neural-sparse-encoding-multilingual-v1 (XLM-RoBERTa, 160M params, 105,879 vocab)
  • Dataset: cp500/multilingual-automotive-sparse โ€” 67,500 (query, positive, negative) triplets across 9 EN/JA/KO language-pair combinations
  • Hardware: 1ร— NVIDIA L40S (g6e.2xlarge)
  • Epochs: 3
  • Batch size: 16
  • Optimizer: AdamW, lr = 2e-5, weight decay = 0.01
  • LR schedule: Linear with 6% warm-up
  • Temperature: 1.0 (InfoNCE softmax)
  • Cross-lingual weight (ฮป_xl): 1.5
  • FLOPS ฮป_query (target): 3e-4
  • FLOPS ฮป_doc (target): 1e-4
  • FLOPS warm-up: 2000 quadratic steps before reaching target ฮป

Evaluation

Held-out split: 2,241 (query, positive) pairs across 9 language-pair combinations.

Pair n MRR@10 Recall@10
en->en 499 0.7752 0.9940
en->ja 499 0.2844 0.9880
en->ko 499 0.2955 0.9940
ja->en 499 0.4278 0.9800
ja->ja 499 0.6164 0.9960
ja->ko 499 0.3091 0.9820
ko->en 499 0.4345 0.9820
ko->ja 499 0.3253 0.9880
ko->ko 499 0.5826 0.9920
overall 4491 0.4501 0.9884

Mean activations / query: 74 Mean activations / passage: 125

EN-vocab activation ratio by query language (top-50 active dims):

  • en: 0.578
  • ja: 0.555
  • ko: 0.565 Non-EN mean: 0.560

Cross-lingual success metric (the point of this model): the mean fraction of the top-50 active vocab positions on JA/KO queries that correspond to English WordPiece tokens. The base XLM-R sparse encoder sits near 0.05โ€“0.15 on this metric โ€” its sparse output stays in the input language's vocab space. Successful cross-lingual fine-tuning should push this toward 0.30+.


Reproducing from scratch

The full pipeline โ€” from seed concepts to a trained model โ€” is included in the training/ directory. Four steps:

Step 1. Generate the training corpus

pip install boto3                                  # for Bedrock
aws sso login                                      # whatever auth your account uses
python training/generate_corpus.py --target 2500   # ~1 hour, ~$20-25 in Bedrock
python training/flatten_triplets.py                # 2500 concepts โ†’ ~67k triplets

The concept seeds live in training/concept_seeds.py โ€” edit the OEMS/SUPPLIERS/MATERIALS/etc. lists there to retarget the corpus to a different domain.

Step 2. (Optional) Push the corpus to HuggingFace

See cp500/multilingual-automotive-sparse for the reference dataset. If you want to publish your own variant:

huggingface-cli login
python training/push_corpus.py --repo-id <your-user>/<your-dataset>

Step 3. Train on a GPU

huggingface-cli login              # once, caches your write token
pip install -r training/requirements.txt
bash training/run_on_instance.sh   # train + eval + push; ~1 hour on L40S

Or run train.py directly for full control:

python training/train.py \
    --dataset cp500/multilingual-automotive-sparse \
    --base-model opensearch-project/opensearch-neural-sparse-encoding-multilingual-v1 \
    --epochs 3 --batch-size 16 \
    --flops-lambda-q 3e-4 --flops-lambda-d 1e-4 \
    --crosslingual-weight 1.5 \
    --output-dir checkpoints/

Step 4. Evaluate

python training/eval.py --model checkpoints/final --out eval_summary.json

The eval script computes per-language-pair MRR@10 and Recall@10, plus the cross-lingual success metric (English-vocab activation ratio on JA/KO inputs).


License

Apache 2.0. The base model, the training corpus, and this fine-tuned model are all Apache 2.0. The corpus was generated via Anthropic's Claude Haiku through AWS Bedrock โ€” review Anthropic's Acceptable Use Policy for downstream applications.

Downloads last month
25
Safetensors
Model size
0.2B params
Tensor type
F32
ยท
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support

Model tree for cp500/opensearch-neural-sparse-en-jp-ko

Dataset used to train cp500/opensearch-neural-sparse-en-jp-ko