NER, POS Tagging and Coreference
BIO tags, CRF and HMM taggers, Viterbi, dependency parses, coreference clusters and entity linking to a KB.
- Concepts and terms
- Tasks and commands
- Annotated code
- Diagrams
- Defaults and numbers
- Troubleshooting
- Questions and tips
Extraction pipeline#
From Lesson 05.24, Lesson 05.25, Lesson 05.06
Core ideas#
- BIO
B-Xbegins,I-Xcontinues,Ois outside.New B-GPE,York I-GPE.- BILOU
- adds
L-X(last) andU-X(unit) for cleaner boundaries. - HMM
- P = \prod_i P(t_i \mid t_{i-1}) \, P(w_i \mid t_i). Transition times emission.
- CRF
- discriminative. Mixes word shape, case and neighbor features. Enforces valid tag sequences.
- Viterbi
- dynamic programming for the best tag sequence over the tag lattice.
- Dependency parse
- each word has one head and a relation label.
- Mention types
- named entity, nominal, pronominal, appositive.
- Prior + context
P(entity | mention) × context-similarity(entity, text).
Rule-based pronoun resolver#
Tasks in code#
| Task | Code |
|---|---|
| Spans to BIO labels | spans_to_bio(tokens, |
| BIO labels back to spans | bio_to_spans(tokens, |
| Capitalization shape | word_shape(word) |
| Gazetteer baseline | rule_based_ner(tokens) |
| Most-frequent-tag baseline | predict_mft(tokens, |
| Train the bigram HMM | train_hmm(examples, |
| Decode tags | viterbi(tokens, |
| Link a mention | disambiguate(mention, |
From 05.06 code/main.py, 05.07 code/main.py, 05.25 code/main.py
CRF and transformer NER#
crf = sklearn_crfsuite.CRF(algorithm="lbfgs", c1=0.1, c2=0.1,L1 and L2 regularization max_iterations=100, all_possible_transitions=True)learns I-ORG after O is unlikelyX_train = [to_features(s) for s in sentences_tokenized]crf.fit(X_train, bio_labels_train)~84 F1 on CoNLL-2003ner = pipeline("ner", model="dslim/bert-base-NER", aggregation_strategy="simple")merges B-X, I-X into spansprint(ner("Apple sued Google over its iPhone in the US."))From Lesson 05.06
spaCy: tags, parse, entities, clusters#
nlp = spacy.load("en_core_web_sm")doc = nlp("The cats were running at 3pm.")for token in doc: print(token.tag_, token.pos_, token.dep_, token.head.text)Penn, UD, relationfor ent in doc.ents: print(f"{ent.text:20s} {ent.label_}")iPhone comes out ORG in smnlp = spacy.load("en_coreference_web_trf")experimental modeldoc = nlp("<text>")rerun with the coref modelfor cluster in doc._.coref_clusters: print(cluster, "->", [m.text for m in cluster])From Lesson 05.07, Lesson 05.06, Lesson 05.24
Numbers to expect#
| Setting | Default | Note |
|---|---|---|
| Most-frequent-tag on Brown | ~85% | The floor for any tagger |
| Bigram HMM on Brown | ~93% | Gain comes from transitions |
| CRF with features | ~97% | BiLSTM-CRF or transformer ~98%+ |
| Annotator agreement, PTB | 97% | Past 98% is likely overfitting |
| Tagsets | 36 | PTB has 36 tags. UD has 17 |
| Coref SOTA, CoNLL-2012 | ~83 F1 | Mean of MUC, B³, CEAF |
| Candidates per mention | 10-30 | From the alias index |
| Classical NER latency | 50ms | Under it, classical NER wins |
Troubleshooting#
| Symptom | Cause | Fix |
|---|---|---|
| CoNLL model fails on contracts | Domain shift | Fine-tune on your domain |
| ORG and FACILITY overlap | BIO cannot nest spans | Span-based or multi-pass NER |
| Long entity split in two | Token-level labels | aggregation_strategy or post-process |
| F1 looks too high | Token-level F1 | Entity-level F1 with seqeval |
| Every mention its own cluster | Singleton explosion | Check MUC, B³ and CEAF together |
| Coref drops on long docs | ~15 F1 loss over 2,000 tokens | Sliding window plus merge |
| Wrong famous entity picked | Popularity bias | Domain fine-tune, check NIL |
| EL recall drops | NER cut the span short | Fix mention boundaries upstream |
Use X when#
- Classical NER or an LLM?
- Classical under 50ms, at 98%+ F1, or on-prem. Else start with an LLM zero-shot baseline.
- PTB or UD?
- PTB for English-only legacy pipelines. UD for multilingual work.
- Which parser?
- spaCy for most production, stanza for multilingual, trankit for top UD accuracy.
- Which EL method?
- BLINK or REL for English Wikipedia. Exact-match prior for the lowest latency.
- LLM coref?
- Easy cases only. It over-merges and drops mentions in long docs.
Abbreviations#
- NER
- named entity recognition. Label token spans with types.
- CRF
- Conditional Random Field. Models label transitions.
- PTB / UD
- Penn Treebank and Universal Dependencies tagsets.
- EL
- entity linking. Map a mention to one KB entry.
- NIL
- no KB entry matches the mention.
- CoNLL F1
- mean of MUC, B³ and CEAF-φ4 F1.
- Cataphora
- the pronoun comes before its referent.
Tips#
- Report mention recall and disambiguation accuracy. 99% on 80% recall is an 80% pipeline.
- Merge coref clusters into NER entities. Emit one KB id per entity, not per mention.
- Constrain LLM entity linking to valid KB ids.
- Test noun-verb ambiguity (
saw,book,can) on 20 sampled outputs.
From Lesson 05.25, Lesson 05.24, Lesson 05.07