The problem in brief
This is named-entity recognition (NER) with almost no labels. You must tag every word of 4 000 news sentences as part of a person, organisation, location, creative work, event, or nothing. Only 50 sentences are fully tagged. For 8 000 more you only know how many names of each type they contain, not where they are. The real names were replaced by invented words ("zhiggerry", "sovietnama") that never appear in two sentences, so memorising names is useless. The only pretrained model allowed is google/electra-base-discriminator.
The data are the official Kaggle files. The test labels are private and we did not submit anything: our scores come from our own validation on the 50 tagged sentences (2-fold) and on 500 held-out count sentences.
How you are scored
A name is a maximal run of consecutive words with the same non-O label. A predicted name counts as correct only if its start, end and type all match a true name exactly. Over all sentences and types:
What to aim for. The Evaluation page gives a baseline at 0.66 (ELECTRA fine-tuned on the 50 tagged sentences) and a reference solution at 0.83. On the public leaderboard the "reference" entry has 0.833 and the best contestant 0.812.
First look at the data
- The 8 000 count sentences hold 5 387 persons, 5 170 organisations, 5 672 locations, but only 464 creative works and 390 events: two types are rare. Sentences have 1 to 11 names, 2.1 on average.
- In the 50 tagged sentences, 117 of the 206 name words are rare (they appear in a single sentence of the whole corpus), and only 22 rare words are not inside a name. Invented words are a strong clue, but 89 name words are ordinary ("city", "court", "festival", "u.s."), so a rare-word rule alone is not enough: "the u.s. food and drug administration" is one organisation of five words, four of them common.
- The statement gives hard rules. Names never overlap, two names of the same type are always separated, and a name never starts with "the", "a", "an" or punctuation, and never ends with punctuation or "'s".
A first baseline
Fine-tune ELECTRA on the tagged sentences and take the arg-max label of each word. In our 2-fold check (train on 25 tagged sentences, score on the other 25, then swap), this gives entity of 0.659 and 0.496, mean 0.577. With all 50 sentences, the organisers' baseline reaches 0.66 on the leaderboard. The model sees far too few examples, especially of creative works and events.
The key idea
The counts are a constraint, and a constraint can turn weak labels into strong ones. Take a sentence where the clerk wrote "1 person, 1 location". A model trained on 25 sentences outputs, for every word, a probability for each of the 6 labels. Its arg-max might find two persons, or miss the location. But among all taggings that contain exactly one person and exactly one location and that respect the stated rules, the most probable one is usually right. That gives us a reliable full tagging of the sentence, a pseudo-label, that we can train on.
Finding that best constrained tagging is a small dynamic programme, a Viterbi decoder with an extra counter in its state. Let be the model's log-probability of label for word . We maximise
over label sequences . The state after word is the pair (current label, vector of names started so far per type). Moving to a type different from the previous label opens a new name and increments . That move is allowed only if word may start a name, the previous name may end at word , and stays at most the target count . At the end we require . The number of states is , a few hundred at most, so all 7 500 sentences decode in seconds.
Then we iterate, a classic self-training (EM-like) loop:
- train on the gold sentences;
- pseudo-label the count sentences with the constrained decoder;
- retrain from the pretrained weights on pseudo-labels plus gold (gold repeated 10 times);
- go back to 2 with the better model.
Why does this work? The constraint removes most of the model's mistakes before they are trained on. A wrong boundary or a missing name usually breaks the counts, so the decoder is forced to pick another tagging, and the next best is often the correct one. The model then learns from 7 500 mostly correct sentences instead of 25. It is the same reason that a crossword gets easier once you know the length of each word.
At test time there are no counts, so we use the same decoder without the counter. The structural rules still repair impossible outputs, such as a name starting with "the".
The full solution
- Freeze the bottom 10 layers of ELECTRA and cache their outputs (float16 on disk, read back with
pread). Only the top 2 transformer layers and a linear layer are trained. This was a necessity, not a choice: fine-tuning the whole model used too much memory on our shared machine. It also makes each training round take about 2 minutes on 2 CPU threads. - Round 0: 150 steps on the gold sentences.
- Rounds 1 and 2: constrained decoding of the 7 500 count sentences, then retraining (about 1.5 epochs, batch 32, AdamW, learning rate , warm-up then linear decay).
- Test: unconstrained structural decoding of the 4 000 sentences.
The heart of the decoder (start of a new name of type t):
valid = used[:, t - 1] >= 1 # states where one more name of type t fits
src = np.where(valid, np.arange(S) - strides[t - 1], 0) # state before opening that name
other = ended.copy(); other[t] = NEG # same type must be separated by a word
sv = other[other[:, src].argmax(0), src] + lp[i, t]
We kept 500 count sentences out of every pseudo-labelling step and used them as a second, larger check: the share of sentences for which the predicted tagging has exactly the right counts.
Results
Entity micro- on the tagged sentences, 2-fold (25 train / 25 scored, then swapped; about 50 names per fold). The official test labels are private.
| approach | fold A | fold B | mean | exact counts (500 held out) |
|---|---|---|---|---|
| gold only (baseline idea) | 0.659 | 0.496 | 0.577 | 0.43 |
| 1 round, pseudo-labels ignore the counts | 0.683 | 0.48 | ||
| 1 round, count-constrained pseudo-labels | 0.775 | 0.624 | 0.700 | 0.56 to 0.59 |
| 2 rounds, count-constrained (final recipe) | 0.732 | 0.667 | 0.699 | 0.59 to 0.63 |
| final model, all 50 gold sentences, 2 rounds | 0.648 |

What the table shows:
- The counts are what makes self-training work. Pseudo-labelling with the plain arg-max (red) gains 2.4 points; the same round with count-constrained pseudo-labels gains 11.7 points on the same fold.
- A second round helps the count accuracy on both folds (0.56 to 0.59, 0.59 to 0.63) and the of fold B, while fold A's drops. With only about 50 names per fold, one point is half a name, so the gold scores are noisy. The 500-sentence count check, which moves steadily, is the more stable signal.
- More gold sentences help. The final model, trained with all 50, gets the counts exactly right on 64.8 % of held-out sentences against 59 to 63 % for the half-gold folds, so its test should be somewhat above our 2-fold estimate of 0.70.
Our estimate, about 0.70 entity , clearly beats the gold-only approach in the same setting (0.58) but stays below the organisers' reference (0.83). Two things we would try next with more compute: fine-tuning more layers (we fine-tuned only the top 2 out of 12 because of the memory limit), and keeping only the pseudo-labels the decoder is confident about (the margin between the best and second-best constrained tagging).
What to remember
- Weak labels are often constraints in disguise. Counts, totals, "at least one", bag-level labels: whenever you know a property of the answer, decode the most probable output that satisfies it and train on that.
- Viterbi with a counter in the state is the standard tool for "most probable sequence with exactly of something". The state space is the product of the counters, small here.
- Self-training needs a filter. Training on your own arg-max predictions mostly confirms your own mistakes (+2 points); training on constrained predictions corrects them (+12 points).
- Validate on more than one signal when the gold set is tiny. About 50 names per fold makes jump by several points at random; a large proxy such as exact-count accuracy is less noisy.
- Freeze and cache when compute is short. Caching the frozen bottom of a transformer turns every training round from many minutes into two, which is what makes an iterative method affordable.