Repository navigation
LLM Experiments
SILNLP can translate with large language models (LLMs) as well as with the NLLB/MADLAD sequence-to-sequence models. There are two kinds of LLM experiment, selected by model_type at the top level of config.yml:
model_type |
Page | What it does |
|---|---|---|
local_llm (alias llm) |
Local LLM fine-tuning | Downloads an open-weight decoder-only model (Gemma, TranslateGemma, Hunyuan-MT, ...) and fine-tunes it on your corpus with full fine-tuning, LoRA, QLoRA, DoRA or QDoRA. Runs on your own GPU or a ClearML GPU worker. |
remote_llm |
Remote LLM in-context learning | Does not train. Calls a hosted model (Claude, GPT, Gemini, OpenRouter, ...) through LiteLLM and shows it example translations from your training corpus in the prompt ("in-context learning"). |
"Remote" here means a hosted model behind an API. It has nothing to do with running a job remotely on a ClearML queue (--clearml-queue). In fact, run remote LLM experiments on your own machine, not on a ClearML queue. The work happens on the provider's servers, so a GPU worker adds nothing.
If model_type is absent, the experiment is treated as a local LLM only when model starts with google/gemma, google/translate-gemma, google/translategemma, tencent/Hunyuan or Hunyuan-MT. Otherwise it is a sequence-to-sequence (NLLB/MADLAD) experiment. A remote LLM experiment always needs model_type: remote_llm.
Both kinds are driven with the same tools as any other experiment (silnlp.nmt.experiment, preprocess, train, test, translate; see NMT: Usage), and use the same data configuration (see Configure a model).
The LLM libraries are an optional "extra":
poetry install -E llm
It installs bitsandbytes (4-bit quantization), sentence-transformers (embedding retrieval), litellm (hosted models) and rank-bm25 (BM25 retrieval). The VS Code dev container installs it automatically.
- One language pair. An LLM experiment supports exactly one source language and one target language. More than one raises an error.
-
No SentencePiece vocabulary. The defaults are
data.tokenize: false, no vocabulary building,data.mirror: false,data.terms.train: falseanddata.aligner: fast_align. The model sees the raw detokenized parallel text written by preprocessing. -
Language names in prompts. The
{src_lang}and{trg_lang}placeholders in prompts are filled fromdata.lang_codes, which maps an ISO code to the name shown to the model. A code with no entry is used as the name itself:Unlike NLLB, these are not tokenizer language codes; write whatever the model will understand best.data: lang_codes: eng: English spa: Spanish -
Prompts are configured the same way (below), in
infer.promptfor both kinds and alsotrain.promptfor local models. -
Evaluation (
test) and translation (translate) work as for other models:testwrites the usual scores andtranslatewrites drafts. - Validation split. If the experiment has no validation split, evaluation during training is switched off automatically.
-
Multiple drafts.
--multiple-translationsworks, butmultiple_translations_methoddoes not apply (see Producing multiple drafts). Each kind of LLM experiment has its ownnum_draftsdefault (1) and rules. -
Confidence scores (
--save-confidences) are the mean token log probability of each translation. Each kind has its own restrictions.
The prompt section is infer.prompt (used when translating and testing). A local model also has train.prompt (used to build training examples).
infer:
prompt:
system_message: "You are a Bible translator working from {src_lang} into {trg_lang}."
instruction_template: |
Translate the following text from {src_lang} to {trg_lang}.
{examples} Now translate this text:
{source}
example_format: text
num_examples: 5
example_selection:
method: bm25
| Setting | Description |
|---|---|
system_message |
Optional system message. May use {src_lang} and {trg_lang}. |
instruction_template |
The user message. May use {src_lang}, {trg_lang}, {source} (the text to translate) and {examples} (the rendered examples). |
example_format |
How each example is rendered into {examples}; see below. |
num_examples |
How many examples to put in each prompt. 0 means no examples (zero-shot). The default is 0 for local models and 100 for remote models. |
example_selection.method |
How the examples are chosen: tfidf, bm25, embedding or coverage. The default is tfidf for local models and coverage for remote models. |
example_selection.model |
Only for embedding: the sentence-transformers model. Default sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2. |
Notes:
- Templates are filled with Python's
str.format, so a literal{or}in a template must be written{{or}}. - Any setting left unset gets a default for that kind of experiment. If you do not set
instruction_template, you get a zero-shot template whennum_examplesis 0 and a few-shot template (with an{examples}section) when it is greater than 0. If you do set it, it is used as written. - A warning is logged if
num_examplesis greater than 0 but the template has no{examples}(the examples would be silently dropped), or ifnum_examplesis 0 but the template contains{examples}(it would render as nothing). -
params.promptis no longer read. It logs a warning and is ignored; move its settings toinfer.prompt(andtrain.prompt). -
num_examplesmust not be negative.
example_format is either a string (the type) or a mapping with type and, for text, the options template, separator and escape.
| Type | Output |
|---|---|
text |
One block per example, built from template, which may use {src_lang}, {trg_lang}, {source} and {target}. Blocks are joined with separator (default empty). If escape is true, &, < and > in the examples and in the text to translate are XML-escaped; quotes are left alone, because an apostrophe is a letter in some orthographies. The default is template: "Source ({src_lang}): {source}\nTranslation ({trg_lang}): {target}\n\n", with no separator and no escaping (remote models default to something different; see Remote LLM in-context learning). |
json |
A JSON list of {"source": ..., "target": ...} objects. |
xml |
One <example><source>...</source><target>...</target></example> element per example, XML-escaped. |
example_format:
type: text
template: "{src_lang}: {source}\n{trg_lang}: {target}"
separator: "\n\n"
escape: true
The examples come from the experiment's training data (never the validation or test split), as written by preprocessing. The source side of the training corpus is indexed, and for each text to translate the num_examples training verses with the most similar source are chosen.
-
tfidfandbm25are lexical. Text is lowercased and split into words with the sil-machine Latin word tokenizer, and punctuation is ignored. The index is rebuilt in seconds whenever it is needed. -
coverageaims for examples that between them show how each part of the text to translate is rendered, rather than just the closest few. It scores sources by character n-grams (2 to 5 characters), so it does not need word boundaries and suits scripts written without spaces. It takes the most similar examples outright (up to 20, or half ofnum_examplesif that is fewer), then repeatedly adds the example that balances similarity against showing n-grams of the text that the chosen examples do not yet cover. Duplicate examples are dropped, and ties are broken by position, so the same corpus always gives the same prompt. Its index is rebuilt in seconds, like the lexical ones. -
embeddingranks by cosine similarity of sentence embeddings. Computing the embeddings of a large corpus is slow, so a remote LLM experiment saves them (example_retrieval_embeddings.npyandexample_retrieval_meta.json) in the checkpoint folder and reuses them if the method, model and number of training examples are unchanged. - When fewer examples are requested than the corpus holds, they are ordered from least to most similar, so the most relevant example is the one closest to the text to translate. When
num_examplesis at least the corpus size, every example is used in corpus order and no index is built. - While training a local model, the verse being trained on is excluded from its own examples (leave-one-out).
- If
num_examplesis greater than 0 and the training files do not exist, the experiment stops with an error asking you to run preprocessing first. Withnum_examples: 0the corpus is never read.