Mova0.5 pre-release⌕
☰
home / docs / tools / hbo

hbo

Mova's own parser for Ancient (Biblical) Hebrew: raw text → words → trees. macula gives trees only for the text MACULA analysed; hbo reads Hebrew that MACULA never saw (quoted in papers, commentaries, other books).

raw text → tokens (spaces, maqaf, sof pasuq) → segmenter (seg.tsv) → gparse (GPU) → CoNLL-U, hbo

Data

macula converts the whole Hebrew Bible (all 39 books of MACULA's WLC lowfat files): 22 945 Hebrew sentences, 468 356 MACULA words. The Aramaic chapters (Daniel 2:4b–7:28, Ezra 4:8–6:18 and 7:12–26, Jeremiah 10:11) go to arc/, 268 sentences and 7 555 words, and are not read here. A sentence goes by the language of most of its words, so Genesis 31:47 (two Aramaic words in a Hebrew verse) stays Hebrew; 2 sentences mix the two.

hbo split holds books out whole (2026-10-18):

partbookssentenceswords
trainthe rest21 437460 531
devRuth, Jonah1333 290
testDeuteronomy, Genesis 19–301 37533 940

The test covers all of PTNK's test split (Genesis 19–30 and its verses of Deuteronomy), so PTNK test can be read through MACULA ids. FORM is normalized to a level of pointing: pointed drops the accents (teʿamim), meteg and rafe and keeps the vowels; unpointed keeps letters only. XPOS is MACULA's Type (the verb form: wayyiqtol, qatal, yiqtol, weqatal, imperative …; the kind of a particle), or the UPOS where it has none.

The segmenter

A written word is cut into MACULA's words: prefixes (ו ה ב כ ל מ ש …), the host, suffixes (pronoun suffixes, the directional and paragogic ה and נ). A split is a list of pieces, each a number of letters (a letter with its marks) or H, the article a preposition swallowed (בָּאָרֶץ = בְּ + ה + אָרֶץ, the ה not written). A suffix can take the vowel of the letter before it: MACULA cuts כֻּלָּם as כֻּלּ + ָם, so a piece marked ^ takes the vowels of the letter before it and leaves the dagesh.

The model is learned from the training trees (seg.tsv, plain TSV):

  1. lex: every written word seen in training, with its splits and their counts. A seen word takes its commonest split.
  2. pre: the first k letters of a word (k = 1 … max_k) → how its prefixes split, counted over the rarer words (seen at most rare times), which behave like unseen ones. An unseen word takes the split of its longest beginning seen at least min times.
  3. rest: what follows the prefixes, as seen in training → its suffixes; if that was never seen, suf: the last k letters of it, as for pre.
  4. chain, sufx, host: the prefix chains (the letters of the prefixes: ו, ו.ב, ב.H …), suffixes and hosts of training, with counts.
  5. ctx: for the written words the lexicon splits more than one way, their splits by the word before and the word after.

From these tables a word gets a list of candidate splits, best first (Model::candidates); the segmenter takes the first. Every candidate must pass the consonant check: its words, the swallowed article left out, spell the written word's letters back (Naaijer 2023); a word no candidate passes stays whole. The switches, written in the header of seg.tsv (with=) or given with --with:

switchwhat it doesused
hostlex:ban unseen word's candidate whose host was never a host in training has its share multiplied by b, and the candidates are ranked by share (Rubinstein 2021); hostlex alone is a hard filterpointed, b = 0.3
partiala pointed word not in the lexicon takes the splits of the lexicon's forms whose points include its own: a missing point is unspecified, not absent (Habash 2016); a word with a bare letter inside that is still unknown goes to the unpointed segmenter (--fallback, or hbo parse with both model dirs)pointed
ctx:Ka word the lexicon splits more than one way: each split's share replaced, first by the word before and then by the word after, with q = (count with that neighbour + K · share) / (neighbour's count + K)unpointed, K = 0.5
chain:Ndrop a candidate whose prefix chain or suffix was seen fewer than N timesoff (no gain)
jointrank an unseen word's candidates by the product of the prefix and suffix shares, not prefixes firstoff
no-checkturn the consonant check off (negative control)off

Every word says why it was cut so, in MISC: Seg=lex:1772/1772 (seen 1 772 times, always so), Seg=pre:וּבְ→1.1:31/33,suf:יו→^2:40/52, Seg=lex:30/41,p:אל:6/6 (the word before decided) and the like.

Parameters chosen on dev and on the two-fold check of train (hbo seg cv, books alternating between the halves), 2026-10-18: pointed max_k 4, min 10, rare 2, with=hostlex:0.3,partial, unpointed max_k 3, min 3, rare 5, with=ctx:0.5. Learning twice gives the same file.

Measured (2026-10-18)

Share of written words split exactly right; «unseen» are the words not in the lexicon.

pointedof it unseenunpointedof it unseen
dev (Ruth + Jonah)97.5887.4394.5677.62
test Deuteronomy98.3388.3095.3767.96
test Genesis 19–3097.8982.3294.8867.20
1–2 Chronicles (unseen by the layers models)98.3795.86
never split (negative control), dev47.2847.28

Word F1 (pieces as spans) on test: pointed 98.33 (DEU) and 97.87 (GEN 19–30); unpointed 95.93 and 95.19. The consonant check fails on no word of dev, test or the two-fold check: it guards cut.

What each switch gives (dev / two-fold check of train, split right):

pointedunpointed
none97.38 / 96.7494.21 / 93.31
partial97.53 / 96.82
hostlex:0.397.43 / 97.0293.71 / 93.65
hostlex (hard)95.77 / 96.74: names cut into known hosts (נָעֳמִי → נָעֳ + מִי)93.25 / 93.32
hostlex:0.794.21 / 93.48 (end to end on dev −0.02 LAS: left off)
partial,hostlex:0.397.58 / 97.08
ctx:0.5no change94.56 / 93.72 (Chronicles 95.15 → 95.86)
chain:1 … 30±0.01±0.01
joint97.38 / 96.7694.26 / 93.33

The errors split two ways (Seker et al. 2020): the gold split not among the candidates at all, or among them but not chosen. On test the second kind is three quarters of the errors (pointed DEU 62 missing / 175 not chosen; unpointed DEU 165 / 494), and the gold split is among the first two candidates for 97.6–98.9% of the words (dev, cv). The commonest errors pointed are a ו or ל taken for a prefix in an unseen word or the reverse; unpointed, the swallowed article (1.H.3 → 1.3): without points the lexicon itself is ambiguous (בבית: בְּ + בַיִת or בַּ + ה + בַּיִת), which ctx addresses.

Partly pointed text (dev with a share of the points dropped, deterministically, seg eval --thin X; scored on the letters cut, as a dropped vowel hides which suffix takes it): points dropped 0 / 25 / 50 / 100%: pointed model alone 97.48 / 81.82 / 69.28 / 48.84; with partial and the unpointed fallback 97.63 / 95.37 / 94.61 / 94.21; the unpointed model 94.21 throughout.

Ablations of the tables on dev (switches off): without rest, pointed 96.93 (−0.45) and unpointed 93.05 (−1.16); without the lexicon (rules only), pointed 87.97 (−9.41) and unpointed 84.29 (−9.92).

Several segmentations (lattice)

hbo lattice writes each sentence in several readings: the segmenter's best, and per written word each other candidate among the first k (3) with at least ratio (0.05) of the best's share. gparse annotate with GP_SCORE=1 adds each reading's tree score (# gp_score: the log-probabilities of head and relation and half those of the two tags). hbo choose gives each word the candidate whose reading gains most, tree gain + λ · log share ratio + μ · words added (--study writes every reading's gains against gold), and the text is parsed again.

It does not pay (2026-10-18, end-to-end LAS): unpointed dev 77.09 → 76.42 … 77.39 over λ, μ; checked on 1–2 Chronicles with the layers models, pointed 85.24 → 85.10 … 85.27 and unpointed 79.73 → 79.58 … 79.99, the setting best on dev −0.10. On dev a gold candidate gains +0.13 tree score on average and a wrong one replacing a gold base −0.41: the parser, trained on gold words only, scores a wrong segmentation nearly as confidently as a right one. The commands stay for study; nothing uses them by default.

The parser

gparse (the GPU parser, gparse — the SLM parser trained by gradient descent on the GPU) is trained on the normalized trees as they are; its predicted XPOS carries the verb form. GP_LEX (the training trees, lex.conllu) gives LEMMA and FEATS for a word whose form and tags were seen, the commonest FEATS of its tags otherwise.

GP_LR=0.002 GP_TOKENS=1000 GP_EPOCHS=30 GP_SEED=42 gparse train pointed/gparse data-pointed/train.conllu -- data-pointed/dev-RUT.conllu data-pointed/dev-JON.conllu

30 epochs of about 100 s each on the shared RTX 4000 (jobs run --mem-gb 8, nice); the best dev epoch was the 29th.

Measured (2026-10-18)

On the test books against MACULA's converted trees. «Gold words»: the parser gets the gold words (LEMMA … DEPREL cleared, hbo blank). «End to end»: the written words cut by our segmenter (hbo resegment), scored as F1 with words aligned within each written word. LAS counts the full relation (with subtypes).

pointed modelwordsgold words UPOSFEATSUASLASend to end words F1UPOSFEATSUASLAS
test Deuteronomy24 39598.7795.0092.6190.1698.0396.9193.4789.8487.53
test Genesis 19–309 54598.3095.2693.0790.8097.3295.8693.0989.3687.35
dev Ruth2 14795.1189.6190.9685.2496.5591.7587.0086.4980.89
dev Jonah1 14396.7693.4490.4688.1097.8594.5191.3587.8385.55

XPOS (with the verb form) is 98.24 on Deuteronomy and 97.19 on Genesis 19–30. gparse eval gives the same UAS and LAS on gold words.

Without points (unpointed, the same settings; best dev epoch 22), LAS:

unpointed modelgold words UASLASFEATSend to end words F1UASLAS
test Deuteronomy90.8287.7692.6293.8982.4879.93
— Deuteronomy 1–31 (prose)91.2788.3992.9193.9482.9080.50
— Deuteronomy 32–33 (archaic poetry)83.7678.0487.8492.9675.5970.63
test Genesis 19–3091.7488.6192.4793.8282.7880.28

What the segmenter's switches give end to end (test read once, 2026-10-18; parsed on the CPU, which gives the same trees as the GPU here), LAS:

DeuteronomyGenesis 19–30dev
pointed, no switches87.0287.0782.14
pointed, hostlex:0.3,partial87.5387.3582.51
unpointed, no switches78.9678.5776.56
unpointed, ctx:0.579.9380.2877.09

On gold words, losing the points costs the parser only 2.2–2.4 LAS; end to end it costs 7.1–7.6, because the segmenter is the weak step without points (words F1 counts here only the written words split wholly right).

PTNK test (UD 2.18, CC BY-NC, read once), through MACULA ids (macula compare, LAS on the relation without its subtype), gold words: UAS 91.53, LAS 87.95 on 13 004 words. The rule-based conversion itself scores UAS 96.51, LAS 93.58 there (macula): the parser loses about 5 points against the trees it learned from.

By layer of the language (2026-10-18)

Biblical Hebrew was written over a thousand years in different grammars, so the scores are given by layer. A second model (layers-pointed, the same settings, its own segmenter) is trained without the archaic poems, without Chronicles (the whole of that late book unseen), without Amos and Micah, and without Genesis 19–30; Ezra–Nehemiah, Esther, the Hebrew of Daniel and Ecclesiastes stay in training. Gold words / end to end, LAS:

layerheld outwordsUASLASe2e LASsegmenter
classical proseGenesis 19–309 54592.7490.3386.8297.72
classical prose (model 1)Deuteronomy 1–3122 59593.0690.7687.60
late prose, unseen book1–2 Chronicles40 65790.1587.7484.9698.22
— 1 Chronicles (genealogies, lists)18 11787.3084.3580.57
— 2 Chronicles22 54092.4490.4688.50
propheticAmos, Micah5 51089.0084.1680.5997.49
archaic poetryExod 15, Judg 5, Deut 32–33, Gen 49, Ps 18, 2 Sam 224 58387.6182.7678.0696.11
— Exodus 1552891.4887.1280.65
— Judges 552880.1173.1169.12
— Deuteronomy 32–331 52185.2780.5477.40
— Genesis 4959487.0481.4876.41
— Psalm 1872392.3988.6682.80
— 2 Samuel 2268991.0086.6580.97
archaic poetry (model 1)Deuteronomy 32–331 52185.6780.7477.53

The segmenter column is the share of written words split right. Reading it:

The layer table is read with the layers model's own segmenter without switches. 1–2 Chronicles also served to check the segmenter's switches and the lattice (2026-10-18), so it is no longer an untouched measure: with hostlex:0.3,partial the pointed segmenter splits 98.37% right there and end to end LAS is 85.24 (from 84.96). A third model, layers-unpointed (the same held-out parts without points; best dev epoch 29), reads Chronicles end to end at LAS 78.43, and 79.73 with ctx:0.5.

Two runs of annotate give the same files. Parsing runs at about 35 000 words/s.

Run

macula <lowfat-dir> $MOVA_DATA/models/hbo/trees
hbo split $MOVA_DATA/models/hbo/trees $MOVA_DATA/models/hbo/data-pointed pointed --dev RUT,JON --test DEU,GEN.19-30
hbo seg learn pointed $MOVA_DATA/models/hbo/pointed/seg.tsv data-pointed/train.conllu --max-k 4 --min 10 --rare 2 --with hostlex:0.3,partial
hbo seg learn unpointed $MOVA_DATA/models/hbo/unpointed/seg.tsv data-unpointed/train.conllu --max-k 3 --min 3 --rare 5 --with ctx:0.5
hbo seg cv unpointed data-unpointed/train.conllu --max-k 3 --min 3 --rare 5 --with ctx:0.5
hbo seg eval pointed/seg.tsv data-pointed/test-DEU.conllu [--without lex,rest] [--with …] [--fallback unpointed/seg.tsv] [--thin 0.5]
HBO_GPARSE=<path to gparse> hbo parse $MOVA_DATA/models/hbo in.txt out.conllu

hbo parse takes one or more sentences a line; a sentence ends at sof pasuq (׃) or «.», «?», «!». A model dir holds seg.tsv, gparse/ and lex.conllu; given the dir above both, it takes pointed/ when the text has vowel points and unpointed/ otherwise. The output keeps the written words as multiword tokens (forms as written, accents included), with Seg= and Swallowed=ה in MISC.

The crate is also a library (hbo::load_seg, hbo::segment_line, hbo::annotate, hbo::lattice, hbo::text, hbo::seg, hbo::conllu): roundtrip mixed parses its Hebrew pieces through it, with the same segmenter switches and fallback as hbo parse.

Other commands: hbo segment (words only), hbo resegment (gold sentences cut by the segmenter; --with, --fallback), hbo lattice and hbo choose (several segmentations, above), hbo blank, hbo merge (a parser's columns back onto a file with multiword tokens and MISC), hbo score, hbo pick (the sentences of some books or chapters).

Models and data live in hbo (trees/, data-*/, pointed/, unpointed/, layers-pointed/, layers-unpointed/, runs/, log/), not in git; the segmenters before the switches are kept beside them as seg.before-2026-10-18.tsv.

Limits

Licence

Elamur Cosmic License (Elamur Cosmic License). MACULA Hebrew: © Biblica, Inc., CC BY 4.0.

This page in Markdown → https://md.mova.elamur.ai/free/en/docs/tools/hbo/