You need to agree to share your Hugging Face information to access this model

This repository is publicly accessible, but you have to accept the conditions to access its files and content.

Log in or Sign Up to review the conditions and access this model content.

IndicMT: English ↔ 22 Indian languages · 153.8M parameters

IndicMT

Compact multilingual machine translation for English and the 22 Scheduled Indian languages.



GitHub: indicMT License: Apache-2.0 CTranslate2 4.8.2 OpenNMT-py 3.5.1 Medium Blog Technical Report Trailer
Languages: 23 Directions: 44 Parameters: 153.8M int8 model: 170.6 MB



IN22-Gen en→xx 47.15 chrF++ IN22-Gen xx→en 53.87 chrF++
IN22-Conv en→xx 43.15 chrF++ IN22-Conv xx→en 50.59 chrF++

Usage · Languages · Results · Limitations · Citation


Compact multilingual machine translation between English and the 22 Scheduled Indian languages (44 directions). This repository holds the OpenNMT-py training checkpoint and an int8 CTranslate2 conversion of it for fast CPU inference.

  • Model: Transformer encoder-decoder, 12 encoder and 12 decoder layers, d_model 512, feed-forward 2048, 16 heads, 153,807,872 parameters, one shared 128k SentencePiece (unigram) vocabulary with tied embeddings.
  • Training: from scratch with OpenNMT-py 3.5.1 on AI4Bharat's BPCC. Pre-trained on an 8:2 mix of mined and human-translated data (step 13,600), then fine-tuned on human data only (step 1,800).
  • Code, data pipeline, evaluation and serving: github.com/ujjwalsharmaIITB/indicMT. Technical report: Technical report. Blog: Medium blog. Trailer: watch on Google Drive.

Files

Path Contents Size
indicMT/ CTranslate2 model, int8 weights (recommended for CPU inference) 170.6 MB
indicMT.pt OpenNMT-py 3.5.1 checkpoint, float32, as saved at the end of training 2.4 GB
indicMT.spm.model SentencePiece model (128k unigram), shared by both 3.5 MB
indicmt_config.json Variants, language tags and the source format, machine-readable

indicMT/ holds model.bin, config.json and shared_vocabulary.json. The checkpoint is the unmodified training file: model weights, vocabulary, training options and the Adam optimizer state, so fine-tuning can continue from it.

Usage

CTranslate2 (int8, CPU)

pip install ctranslate2==4.8.2 sentencepiece==0.2.2 huggingface_hub
import ctranslate2
import sentencepiece as spm
from huggingface_hub import snapshot_download

path = snapshot_download("ujjwalsharmaIITB/indicMT", allow_patterns=["indicMT/*", "indicMT.spm.model"])
sp = spm.SentencePieceProcessor(model_file=f"{path}/indicMT.spm.model")
translator = ctranslate2.Translator(f"{path}/indicMT", device="cpu")


def translate(texts, tgt, beam_size=5):
    """texts: raw sentences in one source language; tgt: target tag without brackets, e.g. "hi" or "en"."""
    tag = f"<{tgt}>"
    sources = sp.encode([f"{tag} {t}" for t in texts], out_type=str)  # tag and sentence as one string
    results = translator.translate_batch(sources, beam_size=beam_size)
    return [sp.decode(r.hypotheses[0]) for r in results]


print(translate(["Hello, how are you?"], "hi"))     # English -> Hindi
print(translate(["नमस्ते, आप कैसे हैं?"], "en"))      # Hindi -> English
print(translate(translate(["नमस्ते, आप कैसे हैं?"], "en"), "ta"))  # Hindi -> Tamil, pivoted through English

Encoding the input. Use sp.encode(f"<xx> {text}") on the whole string. Do not use ['<xx>'] + sp.encode(text).

The tag names the target language. The output carries no tag; detokenize it with sp.decode. Translation between two Indian languages goes through English (two calls), as in the last example.

OpenNMT-py checkpoint (GPU or CPU)

pip install torch==2.2.0 OpenNMT-py==3.5.1 sentencepiece==0.2.2 huggingface_hub
import subprocess
import sentencepiece as spm
from huggingface_hub import snapshot_download

path = snapshot_download("ujjwalsharmaIITB/indicMT", allow_patterns=["indicMT.pt", "indicMT.spm.model"])
sp = spm.SentencePieceProcessor(model_file=f"{path}/indicMT.spm.model")

texts, tag = ["Hello, how are you?"], "<hi>"
with open("src.spm", "w", encoding="utf-8") as f:
    for pieces in sp.encode([f"{tag} {t}" for t in texts], out_type=str):  # same source format as above
        f.write(" ".join(pieces) + "\n")

subprocess.run(["onmt_translate", "-model", f"{path}/indicMT.pt", "-src", "src.spm",
                "-output", "hyp.spm", "-beam_size", "5", "-gpu", "0"], check=True)  # drop "-gpu 0" on CPU
with open("hyp.spm", encoding="utf-8") as f:
    print([sp.decode(line.split()) for line in f])

The checkpoint stores its training options as a Python object, so it loads with torch.load(..., weights_only=False). That is the default in torch 2.2.0, which OpenNMT-py 3.5.1 pins. From torch 2.6 the default changed and loading fails. Load only files you trust this way.

Batch inference and serving

The GitHub repository has the code for larger jobs:

Language tags

Language Tag Code Script
English <en> eng_Latn Latin
Assamese <as> asm_Beng Bengali
Bengali <bn> ben_Beng Bengali
Bodo <br> brx_Deva Devanagari
Dogri <doi> doi_Deva Devanagari
Gujarati <gu> guj_Gujr Gujarati
Hindi <hi> hin_Deva Devanagari
Kannada <kn> kan_Knda Kannada
Kashmiri <ks> kas_Arab Perso-Arabic
Konkani <gom> gom_Deva Devanagari
Maithili <mai> mai_Deva Devanagari
Malayalam <ml> mal_Mlym Malayalam
Manipuri <mni> mni_Mtei Meitei (Meetei Mayek)
Marathi <mr> mar_Deva Devanagari
Nepali <ne> npi_Deva Devanagari
Odia <or> ory_Orya Odia
Punjabi <pa> pan_Guru Gurmukhi
Sanskrit <sa> san_Deva Devanagari
Santali <sat> sat_Olck Ol Chiki
Sindhi <sd> snd_Deva Devanagari
Tamil <ta> tam_Taml Tamil
Telugu <te> tel_Telu Telugu
Urdu <ur> urd_Arab Perso-Arabic

The Bodo tag is <br> (ISO 639-3 brx). It is not Breton.

Results

IN22-Gen English to Indic chrF++: IndicMT 47.15 against other systems

Macro chrF++ over the 22 languages, beam 5, corpus-level sacreBLEU (word_order=2). All reported results are from the CTranslate2 float32 model, the checkpoint in this repository converted to CTranslate2 without quantization.

Test set en→xx xx→en
IN22-Gen 47.15 53.87
IN22-Conv 43.15 50.59

Against IndicTrans2 1B run with the same protocol (paired bootstrap, 22 directions pooled), IndicMT is slightly but significantly ahead on en→xx on IN22-Gen (47.31 against 46.53, p = 0.001; 11 directions better and 8 worse at p < 0.05) and on IN22-Conv (43.23 against 42.60, p = 0.001; 8 better, 13 worse). IndicTrans2 is clearly ahead on xx→en (62.48 against 53.87 on IN22-Gen, 55.63 against 50.59 on IN22-Conv) and has 7.2 times more parameters.

An LLM judge (Gemma 4 31B-it) rated every IN22-Gen en→xx translation (22,528 sentences) for fluency, adequacy and overall quality on a 1–5 scale. Shown the human reference, it rates 63.8% of IndicMT translations perfect (5/5/5; mean overall 4.33), against 70.3% (4.48) for IndicTrans2 1B. Without the reference: 66.9% (4.38) against 73.8% (4.52).

Quantization and the files in this repository

This repository ships the OpenNMT-py checkpoint (indicMT.pt) and the int8 CTranslate2 model (indicMT/); the reported results are from the CTranslate2 float32 conversion of the same checkpoint. chrF++, beam 5; latency is the median for one sentence on CPU (8 threads), IN22-Gen.

Model IN22-Gen en→xx IN22-Gen xx→en IN22-Conv en→xx IN22-Conv xx→en p50 latency Size
OpenNMT-py checkpoint (indicMT.pt) 46.95 53.69 42.97 50.38 2.4 GB
CTranslate2 float32 (reported) 47.15 53.87 43.15 50.59 399.2 ms 630.4 MB
CTranslate2 int16 47.15 53.86 43.15 50.59 367.1 ms 323.2 MB
CTranslate2 int8 (indicMT/) 47.16 53.85 43.14 50.59 374.2 ms 170.6 MB

int16 and int8 are not significantly different from float32 on IN22-Gen, and int8 is 3.7 times smaller.

Compared with other systems

IndicMT (CTranslate2 float32), IndicTrans2, Indic Translate and Sarvam Translate are from our own runs (corpus-level chrF++; beam 5 for IndicMT and IndicTrans2, greedy decoding for the two LLMs). All other baselines are taken from the bodhan-ai/indic-translate model page (read on 2026-09-19), which reports sentence-level chrF++ with greedy decoding on IN22-Gen only, so those rows are indicative. A star marks a system that covers only 16 of the 22 languages.

Model Parameters IN22-Gen en→xx IN22-Gen xx→en IN22-Conv en→xx IN22-Conv xx→en Source
IndicMT 0.154B 47.15 53.87 43.15 50.59 our run
IndicTrans2 1B 1.1B 46.39 62.48 42.61 55.63 our run
Indic Translate 7.94B 47.73 60.33 45.04 55.10 our run
Sarvam Translate 4B 48.74 51.82 45.71 49.77 our run
gemini-3.5-flash undisclosed 40.30 66.60 Indic Translate page
gemma-4-31B-it 30.7B 39.20 59.60 Indic Translate page
translategemma-27b-it * 27B 39.60 58.50 Indic Translate page
gemma-4-26B-a4b-it 25.2B 36.20 56.60 Indic Translate page
translategemma-12b-it * 12B 37.10 55.00 Indic Translate page
gemma-3-27b-it 27.43B 31.90 55.50 Indic Translate page
gemma-3-12b-it 12.19B 28.80 53.20 Indic Translate page
translategemma-4b-it * 4B 31.20 49.20 Indic Translate page
gemma-3-4b-it 4.3B 22.90 47.10 Indic Translate page

Under the same scoring, IndicMT is 0.58 chrF++ below Indic Translate and 1.59 below Sarvam Translate on IN22-Gen en→xx (1.89 and 2.56 below on IN22-Conv), and ahead of Sarvam Translate on xx→en on both test sets. BLEU from our runs (IN22-Gen en→xx / xx→en, IN22-Conv en→xx / xx→en): IndicMT 19.19 / 29.19, 15.73 / 28.36; IndicTrans2 17.88 / 39.12, 15.22 / 34.02; Indic Translate 19.37 / 36.43, 17.30 / 33.37; Sarvam Translate 20.67 / 28.32, 17.95 / 27.51.

Per-language chrF++ (CTranslate2 float32, beam 5)
Language IN22-Gen en→xx IN22-Gen xx→en IN22-Conv en→xx IN22-Conv xx→en
Assamese 44.74 56.02 44.58 55.39
Bengali 47.24 54.39 45.01 53.75
Bodo 49.30 52.34 46.39 49.18
Dogri 55.86 61.04 50.64 58.29
Gujarati 50.88 57.92 50.21 56.42
Hindi 53.19 56.99 47.14 55.34
Kannada 49.06 55.31 31.70 43.40
Kashmiri 32.99 50.47 27.55 47.18
Konkani 43.51 49.67 41.41 45.31
Maithili 49.69 56.72 44.08 51.92
Malayalam 44.83 53.35 38.19 48.49
Manipuri 46.26 50.29 41.64 46.54
Marathi 48.63 54.94 46.08 52.94
Nepali 49.68 59.00 49.60 57.08
Odia 46.23 57.14 40.87 54.57
Punjabi 47.12 53.73 52.55 56.25
Sanskrit 37.26 45.86 34.35 41.76
Santali 41.11 43.72 42.99 45.11
Sindhi 39.73 50.54 37.11 46.16
Tamil 47.63 50.60 38.19 41.90
Telugu 49.58 54.03 42.56 47.61
Urdu 62.73 61.04 56.44 58.34

Compute

GPU-hours are GPUs × wall-clock hours, from the cluster's job accounting. Training ran on 4 × A100 80 GB; evaluation and the LLM judge ran on A40 and L40 GPUs.

Release model only. What it takes to reproduce the released model:

Stage GPUs GPU-hours
Pre-training, combined data, to step 13,600 4 × A100 100
Fine-tuning on human data, to step 1,800 4 × A100 11
IN22-Gen and IN22-Conv evaluation of one checkpoint, 88 directions, OpenNMT-py 2 × A40 0.5
chrF++ trajectory: the same evaluation for 63 checkpoints (54 pre-training up to step 13,600, 9 fine-tuning up to step 1,800) 2 × A40 32
IN22-Gen and IN22-Conv evaluation, CTranslate2 float32 (reported scores) CPU, 16 cores 0 (about 1 hour)
LLM judge, English→Indic 2 × A40 7.7
Total (the trajectory includes the single checkpoint) about 150

Whole project. Everything run for IndicMT, including models that were not released:

Work GPU-hours
Pre-training (human, mined and combined data) 1,539
Deeper architectures (12+18 and 18+18 layers) 715
IN22 evaluation of checkpoints 473
Fine-tuning (with and without replay, deeper models) 248
LLM judge 135
Baseline runs (IndicTrans2, Indic Translate, Sarvam Translate) 15
Setup and tests 4
Total 3,129

By GPU type: 2,507 A100, 479 A40, 143 L40.

Limitations

  • Sentence-level. Trained on sentences of at most 200 SentencePiece pieces. Split paragraphs and documents into sentences first.
  • Indic to Indic pivots through English: two passes, so errors compound and latency doubles.
  • One script per language (table above). For example, Sindhi is Devanagari only, Kashmiri Perso-Arabic only, Santali Ol Chiki only and Manipuri Meetei Mayek only. Text in other scripts is out of domain. Characters outside the vocabulary become <unk> (no byte fallback).
  • Uneven quality. The weakest directions are English to Kashmiri (32.99 IN22-Gen) and English to Sanskrit (37.26). Conversational English-to-Kannada (31.70 IN22-Conv) and English-to-Tamil (38.19) are much lower than on IN22-Gen. Indic-to-English trails IndicTrans2 1B by 8.61 chrF++ on average (IN22-Gen).
  • Automatic metrics only. Scores are chrF++ and BLEU; there is no human evaluation.
  • Data. BPCC includes mined web data, and the model can reproduce its errors and biases. This is a research model: outputs may contain errors, so review them before any high-stakes use.

Training data and evaluation

  • Training: AI4Bharat BPCC, human-translated (bpcc-seed-latest, ilci) and mined (comparable, samanantar-filtered, nllb-filtered) configs, with script-consistency filtering and temperature-sampled mixing.
  • Evaluation: IN22-Gen (1,024 sentences per direction) and IN22-Conv (1,503).

Citation

@techreport{sharma2026indicmt,
  author = {Sharma, Ujjwal},
  title  = {{IndicMT}: Compact Multilingual Machine Translation for 22 Indian Languages},
  year   = {2026},
  note   = {Technical report},
  url    = {https://www.cse.iitb.ac.in/~ujjwalsharma/blogs/indicMT/}
}

License

Apache License 2.0. Copyright 2026 Ujjwal Sharma. The training data (BPCC) and test sets (IN22) are AI4Bharat's and have their own terms.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Dataset used to train ujjwalsharmaIITB/indicMT

Evaluation results