Tag: Nigerian languages

  • PurpleMIST: decision models that speak eight African languages

    PurpleMIST: decision models that speak eight African languages

    Meet PurpleMIST-Flash: a 7.9B decision model that matches DeepSeek-V4-Pro, a model about 200 times its size,
    across eight African languages. Its probabilities are about five times closer to the truth.

    A decision model doesn’t write text. You give it a piece of state (a WhatsApp message, a support ticket, a
    call transcript, a form record) and a set of typed questions: which team should handle this?, is the customer
    asking for a refund?
    , how urgent is it? For every question it returns a probability for each option, in one
    forward pass, in milliseconds. It is the fastest way to triage, route, moderate and automate at scale. With
    TypeSafe’s Jev, more than a hundred open reproductions, and Ollama’s new /v1/systemone endpoint, it has become
    one of the most active corners of open AI.

    Until now, almost all of it worked only in English. Today we’re changing that with three releases:

    •PurpleMIST-Flash-1.0 (7.9B): our flagship decision model, for English and eight African languages.

    •PurpleMIST-Mini-1.0 (1.9B): the same interface in a model small enough for almost any GPU.

    •African Typed Decisions: to our knowledge, the first decision benchmark for African languages. It has 3,739 cases and 16,881 decisions in Amharic, Hausa, Igbo, Nigerian Pidgin, Somali, Swahili, Yorùbá and isiZulu, and an open leaderboard.

    Frontier accuracy at a fraction of the size

    On African Typed Decisions, PurpleMIST-Flash scores 0.668 accuracy, level with DeepSeek-V4-Pro (0.669), a
    1.6-trillion-parameter model. Where it pulls ahead is the part that matters for a decision model: how much you
    can trust each probability
    .

    ModelSizeEnglish8 African languagesKL ↓Brier ↓
    PurpleMIST-Flash-1.07.9B0.7200.6680.2140.115
    DeepSeek-V4-Pro (prompted)1.6T0.7200.6691.1250.199
    Qwen3.8-Flash (prompted)undisclosed0.7120.6430.8620.216
    OpenDecider-small4B0.6480.4770.3650.199
    laya-multilingual0.32B0.3480.3225.0530.545

    Other open decision models collapse outside English: OpenDecider-small loses 0.171 accuracy. PurpleMIST-Flash
    loses just 0.053.
     It leads every open decision model in every one of the eight languages.

    Strong in English too

    •LocalLLaMA/typed-decisions: 0.720 accuracy, zero-shot. Its probability quality, KL 0.189 and Brier 0.098, ranks 2nd among the published zero-shot models, ahead of Liquid AI d1 and TypeSafe Jev.

    •Jev Decision Index (37 public benchmarks, run with the maintainers’ own kit): ahead of 8 of the 13 models of its size. It is 4.8 points above their median, and above the median in language understanding (+6.4), knowledge and reasoning (+4.3), tools (+3.8) and retrieval (+1.4). We’ve submitted it for the index’s private evaluation.

    Probabilities you can act on

    A decision model is only as useful as its confidence. When it says 90%, it should be right about 90% of the time.
    Every PurpleMIST model is calibrated across domains: one temperature per question type, fitted on thousands of
    states it never saw in training, drawn evenly from eight different sources. The result is an expected
    calibration error of 0.049 across the eight African languages and 0.056 in English. So you can set a
    threshold once and trust it: auto-approve above 0.9, send to a human below.

    Fast at any length

    •Speed: a median of 63 ms per request on a single GPU, over 140,000 benchmark requests of every size.

    •Long inputs: up to 65,536 tokens per pass. Long contracts, transcripts and documents are read whole, never truncated.

    •Many questions: any number of them about a state share one pass, and any number of options per question works, because the model reads each option’s text rather than memorising labels.

    How it works

    PurpleMIST-Flash is built on the text model of Qwen3.5-9B with a purpose-built pointer head. The whole state
    and all its questions go in together, and each option is scored directly against the question it belongs to. It was trained on 300,000 real and synthetic decision states, including 86,134 decisions written natively in, or translated into, the eight African languages.

    Start in minutes

    import os, sys
    from huggingface_hub import hf_hub_download
    
    repo = "olaverse/PurpleMIST-Flash-1.0"
    sys.path.insert(0, os.path.dirname(hf_hub_download(repo, "purplemist.py")))
    from purplemist import Decider
    
    d = Decider.from_pretrained(repo, device="cuda")
    d.decide({"message": "Ẹ jọ̀ọ́, wọ́n ti yọ owó lẹ́ẹ̀mejì lórí káàdì mi. Mo fẹ́ kí ẹ dá owó mi padà."},
             {"team":   {"type": "choice", "instructions": "Which team should handle this?",
                         "criteria": {"billing": "payments and refunds", "delivery": "orders in transit"}},
              "refund": {"type": "noul", "instructions": "The customer is asking for money back."}})

    Or run it as a server. serve.py ships in each model repo and uses the same POST /v1/systemone request and answer format as Ollama’s decision endpoint, so code written for that API reads PurpleMIST’s answers the same way:

    hf download olaverse/PurpleMIST-Flash-1.0 serve.py purplemist.py --local-dir purplemist
    python purplemist/serve.py --model olaverse/PurpleMIST-Flash-1.0 --port 8000

    Flash runs on a single 24 GB GPU. PurpleMIST-Mini brings the same interface to 1.9B parameters. In English it beats models up to four times its size, including Bongard-mini (7.5B) and Jeff-Gemma4-E2B (4.6B), with a median latency of 46 ms. Both are open weights under Apache-2.0.

    Benchmark your model

    African Typed Decisions is open. Score your model on the all config, one request per case, and open a discussion with your numbers. We’ll add you to the leaderboard. If you build for Hausa, Yorùbá, Swahili or any of the other languages and want decision models that understand your users, we’d love to hear from you at olaverse.co.uk.

    Links: PurpleMIST-Flash-1.0 ·
    PurpleMIST-Mini-1.0 ·
    African Typed Decisions

    About the benchmark: references come from LLM teachers, and the African cases are machine-written and machine-checked. PurpleMIST was trained on separate data from the same pipeline. Full methodology is on the
    dataset card.

  • 608 languages in 37 MB: building African-first language identification

    608 languages in 37 MB: building African-first language identification

    Language identification sounds solved. It is the first step of almost every multilingual pipeline: before you
    can translate, filter a web crawl, route a support ticket or pick a speech model, you need to know what language
    the text is in. Open models like GlotLID and Meta’s fastText LID cover hundreds of languages, and on long,
    clean paragraphs they are very good.

    Real input is not long and clean. It is “Ẹ kú àárọ̀”, “how far”, a product review with an emoji, a WhatsApp
    message with no tone marks, a URL. And for African languages, the gaps are wide: Kinyarwanda, Xhosa, Wolof and
    Lingala are routinely confused with their neighbours, and Nigerian Pidgin is often read as English.

    So we built two models for 608 languages, African-first, designed for the input people actually type:

    •lid-lite-608: a 37 MB fastText model, about 6,800 texts per second on one CPU thread.

    •lid-neural-608: a 140M-parameter ModernBERT classifier fine-tuned from mmBERT-small, the most accurate model we tested on short and conversational text.

    Both are Apache-2.0 and trained only on data that allows commercial use.

    The results

    We scored every model on the same data, mapping each model’s language codes to ours so that naming
    differences never count as errors.

    lid-neural-608 vs lid-lite-608, GlotLID and Meta
    lid-neural-608lid-lite-608GlotLID v3Meta fastText LID-218
    Size140M params37 MB1,687 MB1,176 MB
    Held-out test, accuracy (240k samples, 608 languages)0.8670.8580.7830.280
    Short input (1-5 words), web-weighted, traffic mode0.9060.8290.8080.764
    Everyday phrases (“good morning”, “sign in”, …)0.9430.8380.8570.867
    Tatoeba (conversational, 34k)0.9300.9220.8680.557
    UDHR-LID (291 languages)0.9140.9100.9080.567
    FLORES+ devtest (202 languages)0.9420.9340.9570.874

    On the 20 major African languages we track, lid-lite-608 averages 0.839 F1 against GlotLID’s 0.757, with
    the biggest gains where it matters most: Kinyarwanda (0.758 vs 0.371), Xhosa (0.840 vs 0.602), Wolof (0.809 vs
    0.600) and Lingala (0.814 vs 0.642).

    African languages F1

    FLORES+ is the one benchmark where GlotLID leads. Its sentences are long, carefully translated news and wiki
    text, the kind of input every model handles well. The gap opens on short and conversational text: on the
    first 1-5 words of the same FLORES+ sentences, both of our models are ahead.

    One model, two ways to read it

    The most useful thing we added is not a bigger model but a second way of reading the one we have.

    A language identifier trained on balanced data treats all 608 languages as equally likely. That is exactly
    right when you are mining a web crawl for low-resource text: you want every Lingala sentence, and you want it
    labelled Lingala even when it is short. But it is wrong for a chat box. If a user types “Bonjour mon ami”,
    the overwhelmingly likely answer is French, not one of the dozens of small languages that share the same
    words.

    So both models ship with two modes:

    •coverage (default): every language equally likely. Best per-language accuracy, for corpus building.

    •traffic: each language’s score is shifted by how common it is in real text. Formally, we add 0.2 × log(real-world share / training share) to each language’s log-probability, using frequencies we measured on the web. Short and ambiguous input then leans towards the languages that actually dominate traffic.

    from olaverse import LIDLite608
    
    LIDLite608().predict("Bonjour mon ami")                  # 'dhv_Latn'  (coverage)
    LIDLite608(mode="traffic").predict("Bonjour mon ami")    # 'fra_Latn'  (traffic)

    Traffic mode adds 6.6 points of accuracy on 1-5 word input for lid-lite-608 and 5.5 for lid-neural-608, and it
    costs nothing: the same weights, one extra vector.

    The bug that taught us the most: “Good morning” was not English

    An early version of lid-lite scored well on every benchmark we had, and then we typed “Good morning” into it.
    It did not come back as English, and neither did most other everyday English phrases: precision for English on
    short phrases was 0.19.

    The cause was in the data, not the model. Web text in small languages is full of English: menus, cookie
    banners, “Read more”, “Sign in”, quoted headlines. Each of those English fragments was labelled with the
    language of the page it came from, so the model learned that short English phrases are evidence for hundreds
    of other languages.

    The fix had four parts:

    1.A foreign-text filter that removes boilerplate and lines in a different language from their page label before training.

    2.Rebalancing the major languages, so English, French, Spanish and the other high-traffic languages were not drowned out by the long tail.

    3.Tatoeba sentences, about 1.6M samples of short, conversational, human-written text in hundreds of languages.

    4.A probe test of 107 everyday phrases in 11 common languages (greetings, “sign in”, “add to cart”), removed from the training data and checked on every build.

    The probe test now sits next to the benchmarks in every evaluation: lid-neural-608 gets 0.943 of the phrases
    right in traffic mode, the best of all the models we tested. The lesson generalises: aggregate benchmarks
    can hide a failure that every user hits in their first minute.
     Build a small test of the obvious cases and
    never ship without it.

    Built for messy input

    Both models were trained on input that looks like real input:

    •Typos, missing diacritics, case changes and emoji were added to a share of the training samples, so “se daadaa ni” is recognised as Yorùbá as reliably as “ṣé dáadáa ni”.

    •Four length buckets per language, from 1-5 words to full paragraphs, because a model trained only on paragraphs fails on queries.

    •A noise class (zxx_Zxxx) for numbers, URLs, code and other non-language text, so a stray order number is not reported as a language. lid-lite-608 reaches 0.961 F1 on it, against 0.620 for GlotLID.

    •Data hygiene: we removed religious text (which dominates many low-resource corpora and skews the vocabulary), text in the wrong script for its label, and mislabelled documents.

    The held-out test was built from websites never seen in training, 100 samples per length bucket per
    language, so the scores reflect new sources rather than memorised ones.

    Which one to use

    lid-lite-608lid-neural-608
    Size37 MB140M parameters (~560 MB)
    Speed~6,800 texts/s on one CPU thread~1,100 texts/s on an A100
    Best forbulk filtering, CPU and edge deploymentuser input, short text, highest accuracy

    Or use both: run lid-lite-608 as a fast first pass over everything, and send only short or low-confidence
    inputs to lid-neural-608.

    Try it

    pip install "olaverse[lid]"            # lid-lite-608
    pip install "olaverse[deeplearning]"   # lid-neural-608
    from olaverse import LIDLite608, LIDNeural608
    
    LIDLite608().predict("Ẹ kú àárọ̀, ṣé dáadáa ni?")     # 'yor_Latn'
    
    lid = LIDNeural608(mode="traffic")
    lid.predict_batch(["Good morning", "Mo fẹ́ lọ sí ọjà", "Habari za asubuhi"])
    # ['eng_Latn', 'yor_Latn', 'swh_Latn']

    Both models also work with plain fasttext and transformers; the model cards have the code. Labels are ISO
    639-3 plus script (yor_Latn, srp_Cyrl), so the same language in two scripts is never confused.

    •Models: olaverse/lid-lite-608, olaverse/lid-neural-608

    •Library: olaverse on PyPI · docs

    If you work with a language we get wrong, we would like to hear about it: open a discussion on either model
    page with a few example sentences.

  • Pretrained From Scratch for Naija: Introducing mist-encoder-base-ng

    Pretrained From Scratch for Naija: Introducing mist-encoder-base-ng

    A 30.9M-parameter encoder built from the ground up for Hausa, Yoruba, Igbo, and Nigerian Pidgin — with a tokenizer that beats GPT-4o’s on all four.


    Most “African language support” in NLP is an afterthought: a massive multilingual model where Yoruba got a sliver of the training budget and the tokenizer shreds every word into fragments. Today we’re releasing something different — mist-encoder-base-ng, a compact encoder pretrained entirely from scratch on Nigerian text, open-sourced on Hugging Face under Apache 2.0.

    It covers the four major languages of Nigeria — Hausa, Yoruba, Igbo, and Nigerian Pidgin — and it’s built to be a workhorse base: load the encoder body, attach a head, and fine-tune for classification, sentiment, language ID, or sentence embeddings.

    from transformers import AutoModel, AutoTokenizer
    tok = AutoTokenizer.from_pretrained("olaverse/mist-encoder-base-ng")
    enc = AutoModel.from_pretrained("olaverse/mist-encoder-base-ng")
    

    Why from scratch?

    Fine-tuning an existing multilingual model inherits that model’s tokenizer — and for Nigerian languages, general-purpose tokenizers are quietly terrible. Every extra subword a tokenizer needs per word means less real signal fits in a fixed context window, slower inference, and weaker per-token representations.

    So before training the model, we built the tokenizer: otk-bpe-50k, a unified byte-level BPE for Naija text with a ~50k vocabulary, NFC diacritic preservation, code-mixed English support, and 0% unknown tokens. The fertility numbers (tokens per word — lower is better) speak for themselves:

    TokenizerHausaYorubaIgboPidgin
    otk-bpe-50k (ours)1.2311.2961.4161.249
    GPT-4o (o200k)1.5891.6871.8071.304
    AfroXLMR1.6042.2772.5701.401

    Our tokenizer is more efficient on Nigerian text than the tokenizer behind GPT-4o — on all four languages. On Igbo, AfroXLMR needs over 2.5 tokens per word; ours needs 1.4.

    The model

    On top of that tokenizer sits a ModernBERT architecture — 6 layers, hidden size 384, 1024 max positions — pretrained with masked language modeling on ~480k carefully prepared chunks. The corpus combines FineWeb-2, the audited WURA corpus, and a fresh Nigerian Pidgin dataset, all cross-deduplicated (FineWeb-2 and WURA both descend from Common Crawl, so overlap was real), language-balanced so abundant Hausa didn’t drown out scarce Igbo and Pidgin, and chunked into windows so no text was wasted on truncation. Every source is attribution-only licensed, which is what makes the clean Apache 2.0 release possible.

    The result is 30.9M parameters — and since the embedding table is about two-thirds of that, the transformer itself is only ~11M. For comparison: AfriBERTa is 126M, mBERT is 178M, XLM-R is 270M.

    What a 30.9M specialist can do

    On MasakhaNEWS topic classification (macro-F1), the model is genuinely competitive at a quarter of the baselines’ size:

    ModelParamsHausaYorubaIgboPidgin
    mist-encoder-base-ng30.9M0.8780.8590.8030.898
    AfriBERTa126M0.9240.9210.9140.991
    mBERT178M0.8060.8860.8050.967

    It beats mBERT on Hausa and ties it on Igbo — with under a fifth of the parameters. That efficiency is the point: this is a model you can fine-tune on a laptop and deploy on-device or in low-resource environments where 126M+ models are impractical.

    What it can’t do (yet) — and exactly why

    We publish our weaknesses with the same rigor as our wins. Named-entity recognition is this model’s honest weak spot: it trails AfriBERTa and mBERT by roughly 10–20 entity-F1 on MasakhaNER 2.0, with Hausa NER lowest at 0.656.

    And we didn’t just report the gap — we diagnosed it. The deficit is structural, not a tuning artifact: it persists across random seeds and labeling schemes. Two causes: the unified 50k tokenizer fragments entity words (person and place names) more than language-specific tokenizers — on Hausa NER text, ~61% of entity words split into multiple subwords versus ~21% for AfriBERTa — and at 30.9M parameters the model has less capacity to reassemble meaning from those fragments. If NER accuracy is critical to your application, use a larger model. If sentence-level understanding at minimal cost is what you need, this is your base.

    The model card also lays out an evidence-backed v2 roadmap: more capacity (~50–80M), a less-fragmenting tokenizer for token-level tasks, and more Pidgin and Hausa data. Notably, longer pretraining isn’t on the list — eval loss plateaued by epoch 11, so we know that lever is spent.

    Part of a bigger picture

    mist-encoder-base-ng joins the Mist Embedder collection and sits alongside our LID models (which are fine-tuned classifiers) as complementary infrastructure: a from-scratch, Nigerian-first foundation others can build on. Two fine-tunes of it already exist on the Hub, and there’s a demo Space to try it.

    • Model: https://huggingface.co/olaverse/mist-encoder-base-ng
    • Tokenizer: https://huggingface.co/olaverse/otk-bpe-50k
    • Collection: https://huggingface.co/collections/olaverse/mist-embedder

    Apache 2.0, free for commercial use. If you fine-tune it for a Nigerian-language task — sentiment, topic tagging, embeddings, anything — open a discussion on the model page and show us. That’s the whole point of releasing the base.


    Olaverse Lab builds open-source AI with first-class support for underserved languages. Explore all our models at huggingface.co/olaverse.