Recursive AI

Moving from Catalyst

All onenlp docs

Catalyst is a managed spaCy-style pipeline for .NET. This page maps its calls to OneNLP's. It is written from Catalyst's published README and from running its released packages as a black box (versions 26.10.6514 and English models 26.9.5316); nothing here comes from its source. There are no compatibility shims: the calls differ, and the table says how.

At a glance

CatalystOneNLP
ModelsCatalyst.Models.English.Register() and a storage folder; model packages per languagereference the model package (RecursiveAI.OneNlp.Models.English, ...); nothing to register, nothing downloaded
PipelinePipeline.ForAsync(Language.English)Nlp.Analyze(text), or Pipeline.Blank(language).Add(...), or PipelineFile.Load(path)
Text objectnew Document(text, Language.English)Doc made by the pipeline; it keeps your string
Processingnlp.ProcessSingle(doc)nlp.Process(text); nlp.ProcessMany(texts) for batches
Sentencesdoc.Spansdoc.Sentences (Span values)
Tokensspan.Tokensforeach (Token t in doc)
Token texttoken.Value (may be normalized: 've as have)token.Text (a string cut from your input; token.TextSpan is the copy-free view); token.Norm for a normalized form
Offsetstoken.Begin, token.End (the end is inclusive)token.Idx, token.EndIdx (the end is exclusive); UTF-16 units into the string you passed
Part of speechtoken.POS (an enum)token.Pos (a Universal Dependencies tag string such as PROPN) and token.Tag (the treebank's own tag)
Lemmatoken.Lemmatoken.Lemma
Entitiesan extra model (AveragePerceptronEntityRecognizer) and token.EntityTypesdoc.Ents or Nlp.Entities(text); span.Label is PER, ORG, LOC or MISC
Dependency parsenonetoken.Dep, token.Head
Morphologynonetoken.Morph

Before and after

Catalyst, as its README shows it:

C#
Catalyst.Models.English.Register();
Storage.Current = new DiskStorage("catalyst-models");
var nlp = await Pipeline.ForAsync(Language.English);
 
var doc = new Document("Marie Curie won the Nobel Prize in Paris.", Language.English);
nlp.ProcessSingle(doc);
 
foreach (var span in doc.Spans)
{
    foreach (var token in span.Tokens)
    {
        Console.WriteLine($"{token.Begin}..{token.End} {token.Value} {token.POS} {token.Lemma}");
    }
}

OneNLP (samples/OneNlp.Samples/MigrationSamples.cs, which builds and runs):

C#
// Reference the model package, then call the verb. Nothing is registered by hand and nothing is downloaded.
Doc doc = Nlp.Analyze("Marie Curie won the Nobel Prize in Paris.");
foreach (Token token in doc)
{
    Console.WriteLine($"{token.Idx} {token} {token.Pos} {token.Lemma}");
}
 
foreach (Span entity in doc.Ents)
{
    Console.WriteLine($"{entity.Label} {entity}");
}

Differences that matter when you port

  • Tokenization follows Universal Dependencies and UAX #29: contractions are split as treebanks split them (don't becomes do and n't), and in French, Spanish, Portuguese, Italian, German, Dutch and Turkish the contractions that are multiword tokens in the treebanks are cut into pieces the model tags. Expect different token counts than Catalyst's.
  • Sentence splitting is set by the parser when the model has one, otherwise by the rule sentencizer.
  • Languages. The Catalyst English models are the only managed comparison for English; the other eight fast-tier languages have no Catalyst counterpart here.
  • Entity labels are the UNER scheme (PER, ORG, LOC), plus MISC where the training data has it, not Catalyst's WikiNER types. The recognizers add CARDINAL, ORDINAL, PERCENT, MONEY and QUANTITY through Nlp.Quantities (recognizers).
  • Training. Catalyst trains averaged perceptrons; OneNLP trains neural heads with Train (training.md). A model trained for Catalyst does not load here; retrain on the same data.
  • Threading. A Pipeline may be shared between threads for Process; documents are independent.

How the two compare on accuracy and speed is in results.md and results-table.md: the English UPOS and lemma rows (on raw text, 92.90 and 95.03 against Catalyst's 80.70 and 83.84 in its black-box run, tools/oracles/Catalyst/README.md) and the speed run, which is repeated at the release gate.