hariharasudhan/en-indic-translate-26b
En-Indic Translate 26B
English to 11 Indic language translation model. Translates English text to Assamese, Bengali, Gujarati, Hindi, Kannada, Malayalam, Marathi, Odia, Punjabi, Tamil, and Telugu while preserving LaTeX formulas, code blocks, and document structure.
Base Model
Fine-tuned from google/gemma-4-26B-A4B-it (a Mixture-of-Experts model with 26B total parameters, 4B active).
Baseline: Sarvam-Translate
The comparison baseline is `sarvamai/sarvam-translate`, a strong open En→Indic translation model. Translating complex scientific documents is hard in a way that ordinary sentence translation is not: the inputs are long, densely structured, and formula-heavy, so a model has to translate the prose while leaving LaTeX math, section headings, and fenced code untouched — and stay coherent over thousands of tokens without collapsing into a repetition loop. The evaluation below measures whether the document survived the translation, not just whether the sentences read well.
Evaluation and metrics
The model is evaluated on a held-out set of 500 complex English documents (~45 per language, across all 11 Indic languages), scored reference-free — each translation is judged against its own source document for whether the math, structure, and layout survived, so no human gold translation is required. The table below places this model in context alongside its two siblings and the Sarvam-Translate baseline.
Higher is better on every row except degeneracy rate and loop period (lower is better). Values are means / pass-rates over the 500 documents.
Supporting math detail
On average Sarvam drops ~34 inline math elements per document; our models drop ~1–4. Code-fence match is the closest column (100% vs 92%) — a clear but modest win.
How to read these metrics
All metrics are reference-free (no gold translation needed). Higher is better on everything except degeneracy rate and loop period, where lower is better.
- Degeneracy (loop) rate — the share of documents where the model falls into a repetition loop, repeating the same span over and over until it runs out of budget, producing unusable output for that document.
- Loop period — when a model does loop, how long the repeated chunk is: a 5-character stutter is recoverable, a 1,500-character block repeated over and over is catastrophic.
- Math preservation — the fraction of the source document's math (LaTeX equations and symbols) that survives intact in the translation.
- Structure integrity — how much of the document's skeleton (section headings and fenced code blocks) is reproduced in the right shape in the translation.
- Renderable — whether the translated document actually displays correctly, with its math and markup rendering with no errors.
- Heading match — whether the translation keeps exactly the same set of section-heading levels as the source: no headings dropped, merged, or invented.
- Code-fence match — whether every fenced code block is copied through byte-for-byte, exactly as in the source.
Sample translations
Side-by-side examples on short, math-rich excerpts. The first set shows the source next to this model's output; the second set adds the Sarvam-Translate baseline for contrast on languages where the baseline visibly breaks down.
Source | this model
Bengali (bn)
Marathi (mr)
Telugu (te)
Punjabi (pa)
Source | this model | Sarvam-Translate
Hindi (hi)
Kannada (kn)
Tamil (ta)
Malayalam (ml)
Supported Languages
Usage with HuggingFace Transformers
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id = "sulabhkatiyar/en-indic-translate-26b"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", torch_dtype="bfloat16")
text = "Your English text here"
target_lang = "Hindi" # or any supported language
prompt = f"Translate English to {target_lang}:\n{text}"
messages = [{"role": "user", "content": prompt}]
inputs = tokenizer.apply_chat_template(messages, return_tensors="pt", add_generation_prompt=True).to(model.device)
outputs = model.generate(inputs, max_new_tokens=4096, do_sample=False)
result = tokenizer.decode(outputs[0][inputs.shape[-1]:], skip_special_tokens=True)
print(result)Usage with vLLM
from vllm import LLM, SamplingParams
from transformers import AutoTokenizer
model_id = "sulabhkatiyar/en-indic-translate-26b"
tokenizer = AutoTokenizer.from_pretrained(model_id)
llm = LLM(model=model_id, max_model_len=32768)
text = "Your English text here"
target_lang = "Hindi"
prompt = f"Translate English to {target_lang}:\n{text}"
messages = [{"role": "user", "content": prompt}]
prompt_text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
outputs = llm.generate([prompt_text], SamplingParams(temperature=0, max_tokens=4096))
print(outputs[0].outputs[0].text)Example
Input (English):
Gradient descent is the workhorse of modern machine learning. Given a loss function $L(\theta)$, the parameters are updated iteratively using the rule $\theta_{t+1} = \theta_t - \eta \nabla L(\theta_t)$, where $\eta$ is the learning rate. For a neural network with $N$ layers, the gradient is computed via backpropagation:
$$\frac{\partial L}{\partial W^{(l)}} = \delta^{(l)} \cdot (a^{(l-1)})^\top$$
where $\delta^{(l)}$ denotes the error signal at layer $l$. A minimal training loop in Python looks like this:
for epoch in range(numepochs): loss = model(xtrain, ytrain) loss.backward() optimizer.step() optimizer.zerograd()
When $\eta$ is too large, the loss oscillates; when too small, convergence stalls. Adaptive methods like Adam adjust $\eta$ per-parameter using running estimates of $\mathbb{E}[g^2]$.Output (Hindi):
ग्रेडिएंट डिसेंट आधुनिक मशीन लर्निंग का वर्कहॉर्स है। एक हानि फ़ंक्शन $L(\theta)$ दिए जाने पर, मापदंडों को नियम $\theta_{t+1} = \theta_t - \eta \nabla L(\theta_t)$ का उपयोग करके पुनरावृत्ति से अपडेट किया जाता है, जहाँ $\eta$ सीखने की दर है। $N$ परतों वाले एक न्यूरल नेटवर्क के लिए, ग्रेडिएंट की गणना बैकप्रोपैगेशन के माध्यम से की जाती है:
$$\frac{\partial L}{\partial W^{(l)}} = \delta^{(l)} \cdot (a^{(l-1)})^\top$$
जहाँ $\delta^{(l)}$ परत $l$ पर त्रुटि संकेत को दर्शाता है। पायथन में एक न्यूनतम प्रशिक्षण लूप इस प्रकार दिखता है:
for epoch in range(numepochs): loss = model(xtrain, ytrain) loss.backward() optimizer.step() optimizer.zerograd()
जब $\eta$ बहुत बड़ा होता है, तो हानि दोलन करती है; जब बहुत छोटा होता है, तो अभिसरण रुक जाता है। एडम जैसे अनुकूली तरीके $\mathbb{E}[g^2]$ के रनिंग अनुमानों का उपयोग करके प्रति-पैरामीटर $\eta$ को समायोजित करते हैं।Caveats
This model was developed and tested on AMD MI300X GPUs (ROCm). Some package versions may need adjustment for NVIDIA CUDA environments.
License
This model inherits the Gemma license from its base model.
