Recursive AI

Results

All onenlp docs

Measured rows. The tokenizer speed rows below are final: they were taken in one benchmark-queue group per machine, alone on the machine, with bench/scripts/tokenizer-rows.sh. Speed numbers elsewhere on this page are indicative until they are re-measured alone on the machine.

Tokenizer speed against Microsoft.ML.Tokenizers

Both libraries encode the same text to token IDs, count tokens and decode IDs, one thread. Before a row is timed the harness checks that the IDs from both are identical on that input (and that both decode to the same text); a row whose outputs differ is shown as such and not timed. Our correctness reference is Hugging Face tokenizers and tiktoken (see parity.md); where the comparator differs from them that is information, not a failure of ours.

  • Gate: ours at or faster than the managed reference on every timed row. Result: all 47 timed rows on x64 and all 47 on arm64 pass (speedup 1.00x or more). Load time is reported, not gated.
  • Speedup is comparator time divided by ours: the median per operation (5 to 25 samples after a half-second warm-up).
  • Alloc is bytes allocated per operation on the calling thread. Ours writes into a caller's buffer (EncodeToIds(text, ids)); the comparator returns a list (EncodeToIds(string)), which is the call each library offers for the job. Decode allocates the result string in both.
  • Inputs (from the Tatoeba sentence export, fixed by the first run and reused on the second machine): short = one English sentence (59 chars); medium = eight English sentences (513 chars); long = every 600th sentence of the export, 990,287 bytes of UTF-8 across all the languages it holds.
  • Operations: encode-to-ids without special tokens; count = token count; decode of the IDs without special tokens.
  • Families and files: WordPiece = bert-base-uncased (tokenizer.json; the comparator reads vocab.txt with lowercasing and accent stripping on, as the Hugging Face file has them); Unigram = xlm-roberta-base (tokenizer.json; the comparator reads sentencepiece.bpe.model); SentencePiece BPE with byte fallback = TinyLlama (tokenizer.json); byte-level BPE = gpt2 (tokenizer.json); Tiktoken = cl100k_base and o200k_base (.tiktoken files, comparator TiktokenTokenizer.CreateForModel).
  • Peak extra RSS (growth of the resident-set high-water mark during the samples) is in the harness output (rows.md); it follows the garbage collector's timing and is not tabulated here. It is only measured on Linux.

Rows not timed, and why

  • WordPiece, medium decode: the comparator's decoded text differs from ours at character 74 (lengths 525 and 519); it does not apply the Hugging Face cleanup rules to spaces before punctuation and contractions. Ours matches Hugging Face (see parity.md).
  • WordPiece, long (encode, count, decode): the IDs differ from the first difference at token 159 (ours 1456, the comparator 100, its unknown token): the comparator gives the unknown token for text that the Hugging Face tokenizer, and ours, split into pieces. 357,483 tokens (ours) against 356,166.
  • Unigram, long (encode, count, decode): the IDs differ at token 30,076 (ours 49,729, the comparator 1,759); 250,378 tokens against 251,115. On short and medium the IDs are identical once the comparator's numbering is mapped to the Hugging Face file's: the comparator numbers the pieces of sentencepiece.bpe.model, and the Hugging Face file puts four control tokens first, so a piece ID p is token p + 1 (the three control pieces swap places).
  • t5-small is not a Unigram row: the comparator throws IndexOutOfRangeException while building its Unigram model from t5-small's spiece.model.

Machines and pins

  • x64: AMD Ryzen 9 7950X3D (16 cores, 32 threads), Linux 7.0.0-38-generic, .NET SDK 10.0.403, Release, non-concurrent GC, ICU on. Run on 2026-11-05 at 03:27 UTC. Load average before the run 3.6 (1 min), 15.5 (5 min), 17.4 (15 min), the tail of an earlier job; during the run (10 s samples) it fell from 3.6 to about 1.5; the machine was otherwise idle (the queue checked that the CPU was idle before starting).
  • arm64: Apple M2 (8 cores), macOS (Darwin 27.0.0), .NET SDK 10.0.403 (user-local install), Release, non-concurrent GC, ICU on. Run on 2026-11-05 at 04:40 UTC. Load average before the run 2.7 / 3.9 / 12.4; during the run 2.4 to 3.3 (the harness's own thread and the OS).
  • Versions: Microsoft.ML.Tokenizers 2.0.1 with Microsoft.ML.Tokenizers.Data.{Gpt2, Cl100kBase, O200kBase} 2.0.1; OneNLP at the commit of this page; information column: tokenizers 0.22.1 and tiktoken 0.14.0 (Python, one thread, x64 only).
  • Tokenizer files: the Hugging Face model files named in parity.md; the .tiktoken files from the published encodings.
  • Run with bench/scripts/tokenizer-rows.sh MODELS INPUTS OUT; INPUTS is the Tatoeba export or a directory with short.txt, medium.txt and long.txt.

Rows

Times are medians per operation. native is the information column: the Hugging Face tokenizers / tiktoken Python package on the x64 machine, same text.

x64

familyoperationsizeoursMicrosoft.ML.Tokenizersspeedupalloc oursalloc comparatornative (info, x64)
WordPiece (bert-base-uncased)load-31.88 ms19.66 ms0.62x
WordPiece (bert-base-uncased)encode-to-idsshort281 ns873 ns3.10x0 B456 B15.00 µs
WordPiece (bert-base-uncased)countshort283 ns835 ns2.96x0 B240 B14.82 µs
WordPiece (bert-base-uncased)decodeshort70 ns161 ns2.31x144 B176 B5.52 µs
WordPiece (bert-base-uncased)encode-to-idsmedium2.85 µs7.81 µs2.74x0 B2.3 KB108.94 µs
WordPiece (bert-base-uncased)countmedium2.80 µs7.51 µs2.68x0 B1.1 KB108.24 µs
WordPiece (bert-base-uncased)decodemediumnot timednot timed-
WordPiece (bert-base-uncased)encode-to-idslongnot timednot timed-
WordPiece (bert-base-uncased)countlongnot timednot timed-
WordPiece (bert-base-uncased)decodelongnot timednot timed-
Unigram (xlm-roberta-base)load-226.30 ms705.90 ms3.12x
Unigram (xlm-roberta-base)encode-to-idsshort199 ns1.35 µs6.79x0 B216 B12.97 µs
Unigram (xlm-roberta-base)countshort200 ns1.43 µs7.14x0 B0 B13.25 µs
Unigram (xlm-roberta-base)decodeshort69 ns146 ns2.11x144 B176 B1.02 µs
Unigram (xlm-roberta-base)encode-to-idsmedium1.67 µs11.31 µs6.76x0 B2.2 KB106.73 µs
Unigram (xlm-roberta-base)countmedium1.59 µs12.12 µs7.63x0 B0 B104.94 µs
Unigram (xlm-roberta-base)decodemedium651 ns1.38 µs2.13x1.0 KB1.1 KB10.47 µs
Unigram (xlm-roberta-base)encode-to-idslongnot timednot timed-
Unigram (xlm-roberta-base)countlongnot timednot timed-
Unigram (xlm-roberta-base)decodelongnot timednot timed-
SentencePiece BPE, byte fallback (TinyLlama)load-48.44 ms10.91 ms0.23x
SentencePiece BPE, byte fallback (TinyLlama)encode-to-idsshort89 ns4.14 µs46.76x0 B1.6 KB7.37 µs
SentencePiece BPE, byte fallback (TinyLlama)countshort88 ns4.11 µs46.67x0 B1.4 KB7.48 µs
SentencePiece BPE, byte fallback (TinyLlama)decodeshort83 ns148 ns1.78x144 B176 B2.97 µs
SentencePiece BPE, byte fallback (TinyLlama)encode-to-idsmedium12.05 µs42.03 µs3.49x0 B12.3 KB77.08 µs
SentencePiece BPE, byte fallback (TinyLlama)countmedium12.28 µs42.40 µs3.45x0 B11.1 KB78.32 µs
SentencePiece BPE, byte fallback (TinyLlama)decodemedium671 ns1.52 µs2.27x1.0 KB1.1 KB24.45 µs
SentencePiece BPE, byte fallback (TinyLlama)encode-to-idslong86.57 ms243.17 ms2.81x1.8 MB21.5 MB359.33 ms
SentencePiece BPE, byte fallback (TinyLlama)countlong88.74 ms241.62 ms2.72x1.8 MB17.5 MB358.47 ms
SentencePiece BPE, byte fallback (TinyLlama)decodelong4.48 ms6.70 ms1.49x1.6 MB1.6 MB71.05 ms
Byte-level BPE (gpt2)load-20.22 ms26.44 ms1.31x
Byte-level BPE (gpt2)encode-to-idsshort438 ns677 ns1.55x0 B312 B11.05 µs
Byte-level BPE (gpt2)countshort441 ns633 ns1.43x0 B96 B11.08 µs
Byte-level BPE (gpt2)decodeshort67 ns113 ns1.70x144 B176 B1.23 µs
Byte-level BPE (gpt2)encode-to-idsmedium3.99 µs6.21 µs1.56x0 B1.2 KB86.19 µs
Byte-level BPE (gpt2)countmedium3.93 µs5.68 µs1.45x0 B96 B83.95 µs
Byte-level BPE (gpt2)decodemedium450 ns978 ns2.17x1.0 KB1.1 KB9.14 µs
Byte-level BPE (gpt2)encode-to-idslong28.97 ms63.26 ms2.18x0 B14.0 MB382.68 ms
Byte-level BPE (gpt2)countlong28.90 ms61.19 ms2.12x0 B10.0 MB380.77 ms
Byte-level BPE (gpt2)decodelong4.59 ms6.78 ms1.48x1.6 MB1.6 MB43.94 ms
Tiktoken cl100k_baseload-18.31 ms19.22 ms1.05x
Tiktoken cl100k_baseencode-to-idsshort475 ns704 ns1.48x408 B312 B2.07 µs
Tiktoken cl100k_basecountshort520 ns644 ns1.24x408 B96 B2.03 µs
Tiktoken cl100k_basedecodeshort67 ns111 ns1.65x144 B176 B364 ns
Tiktoken cl100k_baseencode-to-idsmedium5.02 µs6.32 µs1.26x1.3 KB1.2 KB16.57 µs
Tiktoken cl100k_basecountmedium5.15 µs6.05 µs1.17x1.3 KB96 B16.66 µs
Tiktoken cl100k_basedecodemedium508 ns1.01 µs1.99x1.0 KB1.1 KB1.49 µs
Tiktoken cl100k_baseencode-to-idslong47.85 ms65.20 ms1.36x8.8 MB12.5 MB51.54 ms
Tiktoken cl100k_basecountlong47.77 ms63.95 ms1.34x8.8 MB8.5 MB52.25 ms
Tiktoken cl100k_basedecodelong4.47 ms6.07 ms1.36x1.6 MB1.6 MB7.22 ms
Tiktoken o200k_baseload-27.60 ms43.85 ms1.59x
Tiktoken o200k_baseencode-to-idsshort564 ns793 ns1.41x408 B312 B1.21 µs
Tiktoken o200k_basecountshort555 ns740 ns1.33x408 B96 B1.22 µs
Tiktoken o200k_basedecodeshort71 ns111 ns1.56x144 B176 B386 ns
Tiktoken o200k_baseencode-to-idsmedium5.25 µs6.83 µs1.30x1.3 KB1.2 KB9.38 µs
Tiktoken o200k_basecountmedium5.26 µs6.48 µs1.23x1.3 KB96 B9.45 µs
Tiktoken o200k_basedecodemedium519 ns943 ns1.82x1.0 KB1.1 KB1.45 µs
Tiktoken o200k_baseencode-to-idslong44.38 ms68.68 ms1.55x8.8 MB10.2 MB37.04 ms
Tiktoken o200k_basecountlong43.92 ms65.53 ms1.49x8.8 MB6.2 MB37.88 ms
Tiktoken o200k_basedecodelong3.99 ms5.38 ms1.35x1.6 MB1.6 MB5.63 ms

arm64

familyoperationsizeoursMicrosoft.ML.Tokenizersspeedupalloc oursalloc comparatornative (info, x64)
WordPiece (bert-base-uncased)load-33.32 ms19.15 ms0.57x
WordPiece (bert-base-uncased)encode-to-idsshort305 ns971 ns3.18x0 B456 B
WordPiece (bert-base-uncased)countshort306 ns955 ns3.12x0 B240 B
WordPiece (bert-base-uncased)decodeshort89 ns165 ns1.85x144 B176 B
WordPiece (bert-base-uncased)encode-to-idsmedium2.77 µs10.49 µs3.79x0 B2.3 KB
WordPiece (bert-base-uncased)countmedium2.77 µs10.42 µs3.77x0 B1.1 KB
WordPiece (bert-base-uncased)decodemediumnot timednot timed-
WordPiece (bert-base-uncased)encode-to-idslongnot timednot timed-
WordPiece (bert-base-uncased)countlongnot timednot timed-
WordPiece (bert-base-uncased)decodelongnot timednot timed-
Unigram (xlm-roberta-base)load-206.07 ms757.73 ms3.68x
Unigram (xlm-roberta-base)encode-to-idsshort171 ns1.45 µs8.51x0 B216 B
Unigram (xlm-roberta-base)countshort168 ns1.57 µs9.38x0 B0 B
Unigram (xlm-roberta-base)decodeshort98 ns148 ns1.51x144 B176 B
Unigram (xlm-roberta-base)encode-to-idsmedium1.32 µs13.04 µs9.90x0 B2.2 KB
Unigram (xlm-roberta-base)countmedium1.30 µs14.68 µs11.25x0 B0 B
Unigram (xlm-roberta-base)decodemedium751 ns1.57 µs2.10x1.0 KB1.1 KB
Unigram (xlm-roberta-base)encode-to-idslongnot timednot timed-
Unigram (xlm-roberta-base)countlongnot timednot timed-
Unigram (xlm-roberta-base)decodelongnot timednot timed-
SentencePiece BPE, byte fallback (TinyLlama)load-48.96 ms11.15 ms0.23x
SentencePiece BPE, byte fallback (TinyLlama)encode-to-idsshort108 ns3.63 µs33.63x0 B1.6 KB
SentencePiece BPE, byte fallback (TinyLlama)countshort116 ns3.65 µs31.42x0 B1.4 KB
SentencePiece BPE, byte fallback (TinyLlama)decodeshort98 ns174 ns1.78x144 B176 B
SentencePiece BPE, byte fallback (TinyLlama)encode-to-idsmedium13.70 µs44.19 µs3.22x0 B12.3 KB
SentencePiece BPE, byte fallback (TinyLlama)countmedium13.64 µs43.78 µs3.21x0 B11.1 KB
SentencePiece BPE, byte fallback (TinyLlama)decodemedium687 ns1.99 µs2.89x1.0 KB1.1 KB
SentencePiece BPE, byte fallback (TinyLlama)encode-to-idslong102.25 ms265.79 ms2.60x1.8 MB21.5 MB
SentencePiece BPE, byte fallback (TinyLlama)countlong102.62 ms263.03 ms2.56x1.8 MB17.5 MB
SentencePiece BPE, byte fallback (TinyLlama)decodelong4.48 ms7.12 ms1.59x1.6 MB1.6 MB
Byte-level BPE (gpt2)load-26.90 ms32.47 ms1.21x
Byte-level BPE (gpt2)encode-to-idsshort396 ns638 ns1.61x0 B312 B
Byte-level BPE (gpt2)countshort392 ns620 ns1.58x0 B96 B
Byte-level BPE (gpt2)decodeshort74 ns120 ns1.63x144 B176 B
Byte-level BPE (gpt2)encode-to-idsmedium3.72 µs5.84 µs1.57x0 B1.2 KB
Byte-level BPE (gpt2)countmedium3.71 µs5.66 µs1.53x0 B96 B
Byte-level BPE (gpt2)decodemedium426 ns1.13 µs2.66x1.0 KB1.1 KB
Byte-level BPE (gpt2)encode-to-idslong24.74 ms66.39 ms2.68x0 B14.0 MB
Byte-level BPE (gpt2)countlong24.92 ms65.01 ms2.61x0 B10.0 MB
Byte-level BPE (gpt2)decodelong4.28 ms7.94 ms1.85x1.6 MB1.6 MB
Tiktoken cl100k_baseload-19.96 ms19.20 ms0.96x
Tiktoken cl100k_baseencode-to-idsshort439 ns675 ns1.54x408 B312 B
Tiktoken cl100k_basecountshort430 ns622 ns1.45x408 B96 B
Tiktoken cl100k_basedecodeshort61 ns116 ns1.92x144 B176 B
Tiktoken cl100k_baseencode-to-idsmedium4.17 µs6.01 µs1.44x1.3 KB1.2 KB
Tiktoken cl100k_basecountmedium4.05 µs5.88 µs1.45x1.3 KB96 B
Tiktoken cl100k_basedecodemedium447 ns1.12 µs2.51x1.0 KB1.1 KB
Tiktoken cl100k_baseencode-to-idslong51.07 ms68.65 ms1.34x8.8 MB12.5 MB
Tiktoken cl100k_basecountlong50.61 ms67.49 ms1.33x8.8 MB8.5 MB
Tiktoken cl100k_basedecodelong3.80 ms6.42 ms1.69x1.6 MB1.6 MB
Tiktoken o200k_baseload-23.05 ms50.26 ms2.18x
Tiktoken o200k_baseencode-to-idsshort501 ns816 ns1.63x408 B312 B
Tiktoken o200k_basecountshort493 ns762 ns1.55x408 B96 B
Tiktoken o200k_basedecodeshort60 ns116 ns1.92x144 B176 B
Tiktoken o200k_baseencode-to-idsmedium4.86 µs7.56 µs1.56x1.3 KB1.2 KB
Tiktoken o200k_basecountmedium4.80 µs7.41 µs1.54x1.3 KB96 B
Tiktoken o200k_basedecodemedium432 ns1.09 µs2.52x1.0 KB1.1 KB
Tiktoken o200k_baseencode-to-idslong45.61 ms70.04 ms1.54x8.8 MB10.2 MB
Tiktoken o200k_basecountlong45.55 ms67.84 ms1.49x8.8 MB6.2 MB
Tiktoken o200k_basedecodelong3.54 ms5.78 ms1.63x1.6 MB1.6 MB

Language-ID and recognizer speed

Single thread, one process per system and input set, after a warm-up over 200 inputs; three timed repetitions, and the table shows the median repetition (the first repetition of every system is slower while the JIT tiers up, and the comparators' first recognizer repetition is slower still). Run with bench/scripts/langid-recognizer-rows.sh; each machine ran alone in the benchmark queue. These are publishable rows for the two components.

  • Speedup is comparator time divided by ours; 1.00x or more passes. Alloc is bytes allocated on the calling thread. Peak RSS is the process's peak resident size (one process per system, so it includes that system's model load).
  • Language ID inputs: every 15th line of the held-out main evaluation set per bucket (tools/bench/make-langid-bench.sh): 4,970 words, 4,872 pairs, 5,000 sentences. Ours: the 75-language model (3.6 MB). Comparator: SearchPioneer.Lingua 2.0.0 built for the same 75 languages with its models preloaded, in high and low accuracy mode. Accuracy rows are in recipes/langid/results/.
  • Recognizers inputs: English text of 11,558 lines, 9,979,226 characters, built from the development split only (tools/recognizers-gold/make_bench_text.py). Row 1 compares the comparator's number, ordinal, percentage, currency, dimension, temperature, age, e-mail, URL, IP, phone, hashtag, mention and GUID models with our rules for the same types (the rule files without date/time). Row 2 adds the date/time model on both sides; because the comparator runs it at about 0.1 M chars/s, that row uses the first quarter of the same text (2,889 lines, 2,492,312 characters) so a benchmark group fits its time limit. Both systems see the same lines; the comparator is Microsoft.Recognizers.Text 1.8.13 (en-US). The two systems return different numbers of results (conventions differ); this table compares cost, and the quality rows compare results.

Machines and pins

x64arm64
CPUAMD Ryzen 9 7950X3D, 16 cores / 32 threads (avx2, avx512f, fma, bmi2)Apple M2, 8 cores
OS, SDKLinux 7.0, .NET SDK 10.0.403, ReleasemacOS, .NET SDK 10.0.403, Release
Load average (1/5/15 min) before1.22 / 2.48 / 6.931.81 / 1.82 / 1.81
1-minute load after the Lingua rows, after the first recognizer row, at the end1.5, 3.1, 4.82.3, 2.2, 2.3
Run2026-11-052026-11-05

OneModel is not used by either component. Language-ID weights: langid.bin, sha256 9d06cc77632083274ae5ca5fbb0f3e676abfc63aa6a2d702cbdf9d558cba9d6d. The runs queue behind other work, then hold the machine alone; the load averages above are the 1-minute values read between rows.

Language ID (median repetition)

bucketsystemx64 µs/textx64 texts/sx64 speeduparm64 µs/textarm64 texts/sarm64 speedupalloc per text
wordsours7.88126,9707.96125,6571.4 KB
wordsLingua high76.2813,1109.7x84.3711,85310.6x79 KB
wordsLingua low68.7914,5368.7x60.7216,4687.6x75 KB
pairsours5.05198,1048.08123,6361.4 KB
pairsLingua high90.8711,00518.0x85.9911,62910.6x84 KB
pairsLingua low64.4215,52412.8x55.6717,9646.9x80 KB
sentencesours9.06110,42210.7593,0581.4 KB
sentencesLingua high375.102,66641.4x294.613,39427.4x126 KB
sentencesLingua low250.143,99827.6x212.594,70419.8x123 KB

Our repetitions of 15 to 50 ms vary more than the comparator's (x64 pairs: 8.3, 5.1 and 3.0 µs/text as the JIT tiers up); the median is shown and the speedup is at least 7.6x on every row either way.

oursLingua highLingua low
Load, x64 / arm6410.7 ms / 8.2 ms3,850 ms / 4,238 ms326 ms / 321 ms
Peak RSS, x64 / arm6495 MB / 65 MB4,791 MB / 2,747 MB367 MB / 253 MB
Model on disk3.6 MBn/a (embedded in the package)

Recognizers (median repetition)

rowsystemx64 timex64 M chars/sx64 speeduparm64 timearm64 M chars/sarm64 speedupallocpeak RSS x64 / arm64load x64 / arm64
number, unit, currency, sequence (10.0 M chars)ours0.497 s20.080.559 s17.86387 MB113 / 84 MB21 / 18 ms
number, unit, currency, sequence (10.0 M chars)Recognizers.Text 1.8.1327.12 s0.3754.6x32.18 s0.3157.6x8,795 MB (x64), 8,827 MB (arm64)345 / 299 MB266 / 259 ms
with date/time (2.5 M chars)ours0.620 s4.020.558 s4.47556 MB101 / 67 MB39 / 31 ms
with date/time (2.5 M chars)Recognizers.Text 1.8.1327.16 s0.0943.8x28.18 s0.0950.5x5,024 MB (x64), 5,026 MB (arm64)334 / 303 MB630 / 424 ms

Pass/fail: every row is at or faster than its managed comparator, on both machines.

German fast tier

UD German-GSD r2.18 test and GermEval 2014 test against spaCy 3.8.18 trained with its default configuration on the same data; the table, the settings and the weights are in recipes/de/fast/PROVENANCE.md. Raw text: every row ahead of spaCy or within noise (tokens 99.91 vs 98.03, UPOS 94.22 vs 90.13, UFeats 85.32 vs 80.11, LAS 76.75 vs 70.77). Gold tokens: UPOS (94.56 vs 94.59), XPOS (95.35 vs 95.21), lemmas (95.95 vs 95.65), UAS, LAS and entities (66.28 vs 65.77) within noise; UFeats (86.25 vs 84.71) and AllTags (82.78 vs 81.29) ahead. The tagging heads sit on an encoder with one bidirectional LSTM layer after one window layer (recipes/de/fast/PROVENANCE.md). The package is 109 MB; the consumer app runs on JIT and NativeAOT.

French fast tier

UD French-GSD r2.18 test and WikiNER French (wp3) test against spaCy 3.8.18 trained with its default configuration on the same data, paired bootstrap 95% CI over sentences (1,000 resamples, seed 1); the table, the settings and the weights are in recipes/fr/PROVENANCE.md. Gold tokens: UPOS (96.77 vs 97.07), UFeats (96.34 vs 96.41), lemmas (97.51 vs 97.49), UAS (90.22 vs 89.10) and LAS (86.69 vs 85.98) within noise. Raw text: every row ahead of spaCy, whose tokenizer keeps du and au as one token where the treebank has two words (tokens 99.88 vs 98.85, words 99.48 vs 94.64, UPOS 96.06 vs 91.80, LAS 85.97 vs 78.10); sentences 94.79 vs 91.82, within noise. Entities, gold tokens: micro F1 82.48 vs 75.50 (+6.97 [6.12, 7.78]) and each of LOC, MISC, ORG, PER ahead. French-GSD has no XPOS. The package is 95 MB.

Portuguese fast tier

UD Portuguese-Bosque r2.18 test and Universal NER Portuguese-Bosque test against spaCy 3.8.18 trained with its default configuration on the same data; the table, the settings and the weights are in recipes/pt/fast/PROVENANCE.md. Bosque has no XPOS, so there is no tagger and no XPOS or AllTags row. Raw text: every row ahead of spaCy except tokens (99.86 vs 99.87, within noise) (words 99.74 vs 88.51, UPOS 95.35 vs 84.15, LAS 82.09 vs 65.85, sentences 92.72 vs 84.48). Gold tokens: UPOS (95.89 vs 95.92), UFeats (94.51 vs 94.11), lemmas (97.30 vs 96.90), UAS (86.93 vs 86.05) and LAS (82.74 vs 81.96) within noise. The tagging heads sit on an encoder with one bidirectional LSTM layer after one window layer (recipes/pt/fast/PROVENANCE.md). Entities 73.13 vs 75.27 (paired difference -2.14 [-4.26, 0.39], within noise).

Fast-tier tagging speed in the other languages (indicative)

The tagging model of each language alone (sentencizer, tagger where present, morphologizer, lemmatizer), raw test text of the language's gating treebank, one thread, one document per call, three runs of four passes; build before the faster kernels and the LSTM-free encoder prediction against the current build, in the same job, x64 worker with load 16 to 25. Predictions of the current build equal the earlier build's on every file (dumps of the tagging, parser and entity files of each language: 0 differing lines, plus the Dutch entity confidence noted under English).

Language, fileBefore, tokens/sNow, tokens/sAllocation nowPeak working set now
German (GSD)13,300 to 15,80016,100 to 17,2003,227 B/token1,150 MB
Portuguese (Bosque)13,500 to 17,40016,000 to 21,5001,893 B/token691 MB
Dutch (Alpino)10,300 to 11,20012,900 to 15,1005,102 B/token1,055 MB
French (GSD)23,900 to 24,00030,500 to 31,1002,238 B/token745 MB
Turkish (BOUN)3,150 to 3,1704,280 to 4,2906,310 B/token1,900 MB

German, Portuguese and Dutch (the recurrent-layer models) gain 15 to 40 percent; the rest of their time is in the three wide heads and the 256-wide encoders, which need the same retraining as English to be faster. Allocation went up for them because the recurrent layers now return one array per call. First-call times of the tagging models: German 1,419 ms, Dutch 1,258 ms, Portuguese 226 ms (load 125 to 171 ms). A French and a Turkish narrow student were trained on web text labelled by the shipped models; their text had not been checked against the evaluation sets, so they are not used.

English fast tier (shipped: self-trained tagging and entity models, earlier parser)

Model english.onenlp in RecursiveAI.OneNlp.Models.English (126.2 MB, sha256 1414ec79...1e48): the tagging model (tagger, morphologizer, lemmatizer; 96-wide encoder with no window layer), the parser model (recipes/en/parser, unchanged) and the entity model (128-wide encoder with no window layer), each with its own encoder, put into one pipeline file by recipes/en/assemble. The tagging and entity models are trained by recipes/en/selftrain: the treebank (or UNER) plus web text labelled by the previous packaged model, after removing every sentence that matches a train, development or test sentence of the evaluation data (recipes/en/selftrain/results/dedup-report.jsonl). Provenance: recipes/en/selftrain/PROVENANCE.md.

UD English-EWT r2.18 test (2,077 sentences, 25,131 tokens) and UNER English-EWT test, each read once for the final configuration; the development sets chose every setting. Paired bootstrap 95% CI over sentences (1,000 resamples, seed 1) from tools/OneNlp.Eval; reference spaCy 3.8.18 trained on the same data with its default configuration, same input mode, with its own interval. "Within noise" means the intervals overlap (docs/measurement.md). The rows are in recipes/en/selftrain/results/.

Quality, gold tokens and sentences

MetricOursspaCyWithin noise
UPOS94.16 [93.79, 94.54]94.29 [93.89, 94.66]yes
XPOS93.21 [92.79, 93.61]93.43 [93.00, 93.82]yes
UFeats95.15 [94.86, 95.47]95.18 [94.88, 95.45]yes
AllTags91.29 [90.83, 91.75]91.53 [91.05, 91.97]yes
Lemmas96.11 [95.77, 96.44]95.80 [95.42, 96.13]yes
UAS85.77 [84.91, 86.55]85.40 [84.50, 86.26]yes
LAS81.68 [80.82, 82.49]81.96 [81.03, 82.83]yes
CLAS76.76 [75.76, 77.75]77.28 [76.18, 78.29]yes

Quality, raw text

Tagging and dependency rows below: ten consecutive sentences per call. The parser file is the one of the earlier model and its heads and relations are identical to that model's, so its whole-document rows are unchanged: Sentences 76.15 [74.25, 78.08] against spaCy 72.66, UAS 81.80, LAS 78.13 [77.18, 79.06] against 78.53, CLAS 73.04 against 74.34 (all within noise or ahead).

MetricOursspaCyWithin noise
Tokens99.00 [98.80, 99.19]95.70 [95.14, 96.21]ahead
UPOS92.90 [92.42, 93.35]92.45 [91.84, 93.06]yes
XPOS91.91 [91.38, 92.38]91.72 [91.09, 92.34]yes
UFeats93.87 [93.48, 94.26]93.37 [92.81, 93.92]yes
AllTags90.04 [89.49, 90.57]89.99 [89.32, 90.62]yes
Lemmas95.03 [94.61, 95.43]93.69 [93.08, 94.29]ahead
UAS81.40 [80.41, 82.30]81.34 [80.25, 82.37]yes
LAS77.76 [76.82, 78.70]78.53 [77.46, 79.55]yes
CLAS72.63 [71.53, 73.75]74.34 [73.14, 75.47]yes

MLAS, information: 65.61 [64.46, 66.72] over ten-sentence calls, against spaCy's 69.05 [67.81, 70.21]; it is outside the interval, as for every earlier English model, and is not one of the gated rows.

Entities (UNER English-EWT test, gold tokens)

RowOursspaCyPaired difference
micro F163.09 [60.01, 65.89]62.32 [59.42, 65.33]0.77 [-1.92, 3.33]
precision70.95 [67.54, 74.27]67.97 [64.80, 71.11]2.98 [-0.18, 6.06]
recall56.80 [53.58, 60.13]57.54 [54.26, 60.91]-0.74 [-3.42, 1.83]
LOC71.56 [67.09, 75.67]71.43 [66.56, 76.16]0.13 [-3.83, 3.97]
ORG43.87 [38.29, 48.99]44.33 [39.12, 49.82]-0.46 [-5.77, 4.70]
PER69.40 [64.96, 73.26]68.05 [63.91, 71.83]1.35 [-2.51, 5.16]

Every row is within noise.

Speed (indicative, not a gate row)

Raw EWT test text (25,131 tokens, repeated four times per pass, 100,524 tokens), one document per call, twelve passes after the process starts, medians of the last ten; Catalyst 26.10.6514 with its English models on the same documents, run back to back in the same job. Machine: x64 worker (Ryzen 9 7950X3D, 32 threads) with other jobs running (load average 22 to 30 before and after, so the numbers are noisy), .NET SDK 10.0.403, OneModel 1.0.0. The gate run is made once, on a quiet machine, at the 1.0 gate.

1 thread, tokens/s (min to max)allocation8 threads, tokens/s
Catalyst, sentences + tokens + POS + lemmas545,000 (409,000 to 733,000)not measured in this job (307 B/token before)not run
Ours, sentences + tokens + UPOS/UFeats + lemmas366,000 (336,000 to 464,000)329 B/token1,460,000
Ours, sentences + entities221,000 (184,000 to 314,000)322 B/token361,000
Ours, parser path (the parser sets sentences)5,200 (4,500 to 5,400)4,940 B/token5,700
Ours, full pipeline5,600 (4,800 to 5,800)5,480 B/token5,600

The ratio on the tagging path is 0.67 in this job (the same model against Catalyst in an earlier job with the same method: 0.94 for a 96-wide variant of the same recipe before the final retraining, 0.06 for the previous packaged model), which meets the 0.5 bar. Peak working set 1,241 MB (1 thread) and 1,360 MB (8 threads) for the full pipeline; model file 126.2 MB; load 416 ms and the first call 365 ms (previous model: 328 ms and 434 ms). Full pipeline in the single-file mode used by Nlp.Analyze (one document per call): 5,100 to 5,500 tokens/s against 3,000 to 3,500 for the previous model. The parser is now the limit of the full pipeline (about 190 us per token, an LSTM over a 192-wide state), and its prediction is serialized per head, so eight threads do not help it; the tagging and entity paths scale (4.0 and 1.6 times at eight threads).

How the speed was reached without changing a row: the encoders are narrower and trained on more text (above); GELU, the dense layers and the parser's LSTM and label scores run on dedicated row kernels (RowKernels, LstmInference) with bit-identical or last-digit-identical results (prediction dumps of every shipped file before and after: 0 differing lines on English, German, Portuguese, Dutch, Turkish and French except one Dutch entity confidence that rounds 0.901 to 0.902); the encoder runs outside the head lock.

English fast tier, option: one shared encoder (not shipped)

A single encoder shared by every head, trained by recipes/en/joint (23.7 MB, sha256 6bb03663...50b9): four times smaller and more than ten times faster on the tagging path, with the rows below. It is not the packaged model because its UFeats, AllTags, entity and raw CLAS and MLAS rows are weaker. Rows measured on the model file english.onenlp of that recipe. UD English-EWT r2.18 test, 2,077 sentences, 25,131 tokens; UNER English-EWT test. Paired bootstrap 95% CI over sentences (1,000 resamples, seed 1); reference spaCy 3.8.18 trained on the same data with its default configuration, same input mode. "Within noise" means the intervals overlap. The development sets chose the configuration; the test files were read once.

Quality, gold tokens and sentences

MetricOursspaCyWithin noise
UPOS93.58 [93.17, 93.99]94.29 [93.91, 94.68]yes
XPOS92.81 [92.36, 93.24]93.43 [93.00, 93.87]yes
UFeats94.40 [94.07, 94.73]95.18 [94.86, 95.48]no
AllTags90.45 [89.98, 90.95]91.53 [91.05, 91.99]no
Lemmas95.84 [95.50, 96.17]95.80 [95.46, 96.13]yes
UAS84.98 [84.12, 85.80]85.40 [84.48, 86.28]yes
LAS81.31 [80.47, 82.16]81.96 [81.00, 82.91]yes

Quality, raw text

MetricOursspaCyWithin noise
Tokens99.00 [98.81, 99.19]95.70 [95.16, 96.17]ahead
Sentences72.76 [70.97, 74.66]72.66 [70.46, 74.70]yes
UPOS92.53 [92.09, 93.01]92.45 [91.83, 93.05]yes
XPOS91.60 [91.11, 92.11]91.72 [91.10, 92.34]yes
UFeats93.39 [92.97, 93.79]93.37 [92.84, 93.91]yes
AllTags89.35 [88.80, 89.89]89.99 [89.34, 90.64]yes
Lemmas94.68 [94.29, 95.07]93.69 [93.07, 94.28]ahead
UAS80.41 [79.47, 81.36]81.34 [80.25, 82.34]yes
LAS76.93 [75.98, 77.92]78.53 [77.49, 79.54]yes
CLAS71.81 [70.67, 72.97]74.34 [73.19, 75.49]no
MLAS65.14 [63.97, 66.36]69.05 [67.85, 70.21]no

Entities (UNER English-EWT test, gold tokens)

RowOursspaCyPaired difference
micro F159.38 [56.06, 62.60]62.32 [59.42, 65.33]-2.93 [-5.81, -0.15]
LOC65.55 [60.45, 70.29]71.43 [66.56, 76.16]-5.88 [-9.82, -1.94]
ORG45.19 [39.35, 50.48]44.33 [39.12, 49.82]0.86 [-3.94, 5.38]
PER64.19 [59.35, 68.55]68.05 [63.91, 71.83]-3.86 [-8.32, 0.72]

The intervals overlap on every entity row; the paired differences for micro F1 and LOC exclude zero.

Speed (indicative, not a gate row)

Raw EWT test text (25,131 tokens, repeated four times per pass), one thread, sentences + tokens + UPOS/UFeats + lemmas; Catalyst 26.10.6514 with its English models on the same documents, run back to back in the same job. Machine: x64 worker (Ryzen 9 7950X3D) while other jobs were running (load 9 to 15), .NET SDK 10.0.403. The gate run is made once, on a quiet machine, at the 1.0 gate.

tokens/sallocationnote
Catalyst530,000 to 590,000307 B/tokenUPOS 80.7, lemmas 83.8 on this text
Ours, one document per call215,000 to 270,000413 B/tokenUPOS 92.5, lemmas 94.7
Ours, ProcessMany batches of 64226,000 to 259,000327 B/token
Ours, entities path209,000 to 257,000393 B/token
Ours, parser path5,300 to 7,900856 B/tokenthe bidirectional LSTM is the cost
Ours, full pipeline5,500 to 7,9001,377 B/token

The ratio on the tagging path is about 0.4 (misses). Peak working set 640 MB for the full pipeline; model file 23.7 MB; first Nlp.Analyze (loads the weights) 325 ms on x64. Where the time goes (microseconds per token, one document per call): tokenizer 0.2, sentencizer 0.05, encoder about 2 (lookups 0.6, window-layer product 1.2), lemmatizer 0.9, morphologizer 1.0. A smaller configuration of the same recipe (48 wide, no window layer) ran the same path at 500,000 to 690,000 tokens/s (about 1.6 to 2.3 times Catalyst in the same conditions) with a development tagging mean 0.6 points lower; it is not the shipped model.

Dutch fast tier

UD Dutch-Alpino r2.18 test and WikiNER Dutch (wp3) test against spaCy 3.8.18 trained with its default configuration on the same data, paired bootstrap 95% CI over sentences (1,000 resamples, seed 1); the table, the settings and the weights are in recipes/nl/fast/PROVENANCE.md. Every row is within noise of spaCy in both modes. Gold tokens (the treebank's own words and sentences): UPOS 93.83 vs 94.42, XPOS 91.52 vs 91.73, UFeats 92.94 vs 93.13, AllTags 90.30 vs 90.51, lemmas 91.61 vs 91.83, UAS 85.18 vs 84.09, LAS 80.28 vs 79.85. Raw text: tokens 99.66 vs 99.82, sentences 91.31 vs 89.60, UPOS 93.09 vs 94.36, XPOS 90.94 vs 91.63, UFeats 92.47 vs 92.97, AllTags 89.52 vs 90.39, lemmas 91.19 vs 91.65, UAS and LAS (79.48 vs 79.57). The tagging heads sit on an encoder with one bidirectional LSTM layer after one window layer (recipes/nl/fast/PROVENANCE.md). Entities (gold tokens): micro F1 87.47 vs 86.21 (difference +1.26 [0.76, 1.72], ahead), every type within noise or ahead.

Turkish fast tier

UD Turkish-BOUN r2.18 test and Turkish-WikiNER test against spaCy 3.8.18 trained with its default configuration on the same data, paired bootstrap 95% CI over sentences (1,000 resamples, seed 1); the table, the settings and the weights are in recipes/tr/fast/PROVENANCE.md. The tokenizer is a trained multiword-token splitter (NeuralMultiwordSplitter, docs/segmentation.md). Gold words: UPOS (88.97 vs 88.04), UFeats (78.15 vs 78.30) and MLAS (40.47 vs 38.85) within noise; XPOS, AllTags and lemmas (85.11 vs 80.24) ahead. Raw text: tokens (99.56 vs 99.42), words (96.55 vs 97.06), UPOS (86.02 vs 86.82), UFeats, UAS (65.73 vs 63.96), LAS (57.53 vs 55.86), CLAS (54.83 vs 53.43), MLAS (38.10 vs 38.02) and BLEX within noise, sentences, XPOS, AllTags and lemmas ahead. The parser was retrained on the tokenizer's words and on 60,239 sentences of web text parsed by earlier parsers where two of them agree (it was CLAS 49.84 and MLAS 34.87 before); gold words: UAS, LAS, CLAS (59.08 vs 55.03) and BLEX ahead. Entities (gold tokens): 67.40 vs 65.82, within noise. The package is about 148 MB; the consumer app runs on JIT and NativeAOT.

Spanish fast tier

UD Spanish-AnCora r2.18 test and WikiNER Spanish (wp3) test against spaCy 3.8.18 trained with its default configuration on the same data, paired bootstrap 95% CI over sentences (1,000 resamples, seed 1); the table, the settings and the weights are in recipes/es/fast/PROVENANCE.md. Gold words and sentences: UPOS (98.11 vs 98.18), UFeats (97.71 vs 97.74) and lemmas (98.84 vs 98.72) within noise; XPOS (86.73 vs 84.97), AllTags (86.09 vs 84.47), UAS (90.05 vs 89.04) and LAS (87.00 vs 85.95) ahead. Raw text: every row within noise or ahead (spaCy's tokenizer keeps del and verlo as one token where the treebank has several words; words 99.83 vs 96.60, UPOS 97.86 vs 94.81, LAS 86.70 vs 81.82); tokens 99.84 vs 99.90 and sentences 98.14 vs 97.70 within noise. Entities, gold tokens: micro F1 82.88 vs 83.35 (difference -0.46 [-1.14, 0.20], within noise); ORG ahead (+4.96), PER behind (-1.96 [-2.83, -1.13]). The entity model reads the tokenizer's pieces of del and al: trained on whole tokens it scored 81.71 (-1.64, outside the interval). Indicative cost on one thread of the shared worker: tagging heads 44 us/token, whole pipeline about 190 us/token. The package is 109 MB; the consumer app runs on JIT and NativeAOT.

Italian fast tier

UD Italian-ParlaMint r2.18 test (gating) and WikiNER Italian (wp3) test against spaCy 3.8.18 trained with its default configuration on the same data, paired bootstrap 95% CI over sentences (1,000 resamples, seed 1); the tables, the settings and the weights are in recipes/it/fast/PROVENANCE.md. The training treebank is small: 897 sentences (ParlaMint and MarkIT; the larger Italian treebanks are non-commercial), so parser rows are low in absolute terms (LAS 72.6) for both systems. Gold words and sentences: UPOS (94.44 vs 94.10), XPOS (93.74 vs 93.59), UAS (78.52 vs 77.08) and LAS (72.57 vs 71.39) within noise; UFeats (89.52 vs 87.42), AllTags (86.31 vs 84.08) and lemmas (95.18 vs 93.13) ahead. Raw text: tokens 99.86 vs 99.75 within noise; every other row ahead (spaCy's tokenizer keeps del and farlo as one token where the treebank has several words; words 99.67 vs 89.73, UPOS 94.01 vs 83.53, LAS 72.77 vs 58.38, sentences 96.00 vs 87.55). Entities, gold tokens: micro F1 86.35 vs 83.54 (+2.80 [2.18, 3.42]); PER, ORG and MISC ahead, LOC within noise. No row misses. Indicative cost on one thread of the shared worker: the whole pipeline 7.2k tokens/s. The package is 103 MB; the consumer app runs on JIT and NativeAOT.

Chinese fast tier

UD Chinese-GSDSimp r2.18 test and UNER Chinese-GSDSIMP test against spaCy 3.8.18 trained with its default configuration on the same data, paired bootstrap 95% CI over sentences (1,000 resamples, seed 1); the settings and weights are in recipes/zh/fast/PROVENANCE.md. spaCy's default Chinese tokenizer cuts single characters, so its raw-text pipeline cannot reach word-level scores (Tokens 39.43); the gold-token reference is the gold_preproc training run described in tools/baselines/spacy/lang/PROVENANCE.md, which trains and scores on gold words. The pipeline cuts words with a trained character tagger (docs/segmentation.md), tags, lemmatizes, parses and finds entities.

Gold words and sentences (spaCy gold_preproc):

MetricOursspaCyWithin noise
UPOS90.41 [89.70, 91.07]90.35 [89.70, 90.99]yes
XPOS91.37 [90.75, 91.98]91.11 [90.45, 91.70]yes
UFeats98.38 [98.13, 98.59]98.43 [98.19, 98.66]yes
AllTags89.49 [88.76, 90.17]89.52 [88.79, 90.20]yes
Lemmas99.87 [99.79, 99.94]99.91 [99.85, 99.96]yes
UAS74.94 [73.46, 76.38]73.11 [71.46, 74.68]yes
LAS68.76 [67.12, 70.32]68.24 [66.47, 69.94]yes
CLAS65.85 [64.15, 67.51]65.49 [63.52, 67.27]yes
MLAS56.94 [55.08, 58.69]58.87 [56.85, 60.72]yes

Raw text (spaCy's default pipeline, character tokens):

MetricOursspaCyWithin noise
Tokens, Words89.62 [88.87, 90.42]39.43 [38.60, 40.23]no (ahead)
Sentences99.40 [98.70, 99.90]46.93 [42.22, 51.79]no (ahead)
UPOS81.90 [80.99, 82.86]34.92 [34.11, 35.68]no (ahead)
XPOS82.73 [81.85, 83.67]35.69 [34.86, 36.47]no (ahead)
UFeats88.24 [87.49, 89.01]38.38 [37.56, 39.16]no (ahead)
AllTags81.00 [80.09, 81.99]34.29 [33.48, 35.06]no (ahead)
Lemmas89.56 [88.82, 90.35]39.43 [38.60, 40.23]no (ahead)
UAS62.50 [60.81, 64.17]9.12 [8.44, 9.79]no (ahead)
LAS57.88 [56.21, 59.63]8.59 [7.94, 9.28]no (ahead)

Entities, UNER Chinese-GSDSIMP test, gold tokens (paired with spaCy gold_preproc): micro F1 62.80 [58.46, 67.23] vs 61.86 [57.66, 66.12] (difference 0.94 [-2.18, 4.40], within noise); precision 62.44 vs 67.08 (-4.64 [-8.52, -0.50], inside the noise rule); recall 63.17 vs 57.40. Per type: LOC 69.86 vs 68.15, ORG 47.91 vs 45.00, PER 57.69 vs 59.08, all within noise. With the shipped entity confidence threshold of 0.6 (recipes/zh/fast/PROVENANCE.md, "Entity confidence threshold"): micro F1 63.79 [59.39, 68.27] (difference +1.93 [-1.48, 5.33]); precision 69.28 vs 67.08 (+2.20 [-2.02, 6.59]); recall 59.11 vs 57.40 (+1.70 [-1.61, 5.12]); LOC 70.38, ORG 51.28, PER 57.95, all within noise. On raw text (our segmenter's words, character-span F1) the micro F1 is 52.88 [48.60, 57.61]; spaCy's default model reaches 13.30 on gold tokens only, and no raw-text spaCy row exists.

For information (docs/references.md): Stanza 1.5.1 raw text UPOS 88.82, LAS 70.65; UDPipe 2 gold tokens UPOS 95.73, LAS 83.60; Trankit base raw UPOS 94.17, LAS 81.96 (an older annotation). Our fast tier is below them, as expected of a fast tier with no pretrained embeddings; the gate is spaCy's.

Misses: none. Everything is within noise or ahead; MLAS (-1.93) is inside the noise rule.

Indicative speed (1 thread, load average 8-13 on the shared worker, raw development text; Catalyst has no Chinese model, so there is no managed row): segmenter alone 22-23k words/s (3.7 kB allocated per word); segmenter and tagging 16-17k words/s; the whole pipeline (segmenter, tagging, parser, entities) 4.5-4.6k words/s.

Parser speed (one LSTM layer, product label features)

Every fast-tier parser was retrained with the setting in docs/parser.md ("Speed configuration"): English english.onenlp is now 117.5 MB (sha256 ac0080ad...ed9b; the tagging and entity models are unchanged, only the parser part differs). Training data, seeds and licences are those of the earlier parsers (UD treebanks, CC BY-SA 4.0 / CC BY 4.0; the models keep share-alike lineage); selection used each language's development file with the earlier early-stopping rule (patience 6), and each test file was read for the final models (see the note below for the two languages where a smaller setting was scored on test before the larger one was chosen on dev).

Speed (indicative: 1 thread, batches of 32 documents, raw test text, x64 worker, load average 14 to 23)

ModelParser head, beforeParser head, afterFull pipeline, beforeFull pipeline, after
English137 to 145 us/token (5.3k tokens/s), 4,974 B/token30 us/token (32.5k tokens/s), 2,563 B/token4.9k to 5.0k tokens/s, 5,516 B/token26.3k tokens/s, 3,105 B/token
Germanabout 150 us/token32 us/token
Dutch15130
Portuguese16929
Spanish15628
French12620
Italian8046
Chinese14248

The English parser alone: 137 us/token by component before (LSTM 81, label scorer 52, projections 9, arcs and tree 8) and 20 us/token after in the per-component profile. Peak working set of the English full pipeline 939 MB (was 1,083 MB). The other languages' rows are the parser file alone (its own encoder 10 to 13 us/token is included in the full-pipeline figure, not in the head column).

English, UD English-EWT r2.18 test (hash fa024f43...c494a), paired bootstrap 95% CI, 1,000 resamples, seed 1, reference spaCy 3.8.18 default configuration on the same data

ModeMetricOursspaCyEarlier parserWithin noise
gold tokensUAS85.26 [84.38, 86.13]85.4085.77yes
LAS81.53 [80.62, 82.43]81.9681.68yes
CLAS76.78 [75.68, 77.86]77.2876.76yes
MLAS69.36 [68.23, 70.47]71.1469.17yes
raw textUAS80.74 [79.78, 81.71]81.3481.80yes
LAS77.26 [76.28, 78.25]78.5378.13yes
CLAS72.19 [71.00, 73.35]74.3473.04yes
MLAS65.30 [64.12, 66.48]69.0565.61no (behind; not a gated row)
raw textSentences71.08 [69.06, 72.98]72.6676.15yes

Tagging rows are those of the unchanged tagging model (gold UPOS 94.16, UFeats 95.15, lemmas 96.11; raw UPOS 92.90).

Other languages, gating treebank test, LAS (UAS, CLAS, MLAS in the committed result files), paired CI against spaCy 3.8.18

LanguageModeOurs (earlier parser)spaCyWithin noise
German GSDgold76.66 [75.63, 77.72] (78.25)77.31yes
raw74.87 [73.79, 75.92] (76.75)70.77ahead
Dutch Alpinogold79.12 [77.87, 80.39] (80.28)79.85yes
raw78.18 [76.87, 79.46] (79.48)79.57yes
Portuguese Bosquegold81.80 [81.10, 82.49] (82.74)81.96yes
raw81.14 [80.44, 81.82] (82.09)65.85ahead
Spanish AnCoragold86.41 [85.90, 86.89] (87.00)85.95yes
raw86.15 [85.61, 86.64] (86.70)81.82ahead
French GSDgold86.96 [85.86, 87.96] (86.62)85.98yes
raw86.07 [84.92, 87.11] (85.92)78.10ahead
Italian ParlaMintgold71.55 [70.26, 72.97] (72.57)71.39yes
raw71.55 [70.27, 72.90] (72.77)58.38ahead
Chinese GSDSimpgold words (spaCy trained with gold_preproc)67.49 [65.94, 69.14] (68.76)68.24yes
raw (our segmenter)56.93 [55.23, 58.73] (57.88)8.59ahead

Every UAS, LAS and CLAS row is within noise or ahead in both modes. MLAS, which also depends on the tagging model, is within noise or ahead in every row of these languages (Chinese gold words: 55.78 [53.92, 57.68] against 58.87). Raw-text rows compare our tokenizer against spaCy's, which is the reason for the large margins.

Note on selection: for Italian and Chinese the 128-unit setting was scored on test before the 192-unit setting was chosen on dev (dev LAS 72.43 and 64.82 against 73.97 and 66.81, and 74.81 and 68.22 for the earlier parsers); the larger setting was chosen because the smaller lost more than 1 point of dev LAS, the rule used for every language.