Internship Defense · Master 1 Informatique, Décision, Données (IDD) · Université Paris-Dauphine – PSL
2026-09-02
I. The Internship — Subject & Objectives
II. Technical Context
III. Contributions & Results
IV. Technical Conclusion
V. Personal Assessment
Worked example — declared activity: “Clothing retail in a physical store”
The section letter isn’t written into the numeric code — it’s derived from it (each division belongs to exactly one section).
Python 3.13uvPyTorchPyTorch LightningCaptumKubernetes / Argo WorkflowsQuartoSSP Cloud (Onyxia)S3 / MinIO
torchTextClassifiers — INSEE’s own open-source PyTorch/Lightning package, a unified interface across every architecture comparedRather than start directly on NAF’s ~700 classes, the whole pipeline — training, prediction analysis, explainability — was built and validated on two public benchmarks first, in increasing order of difficulty.
960 runs on Amazon, swept across architecture and embedding dimension.
Each word’s background is shaded by its attribution score for the selected class — green = pushes toward it, red = pushes away. For Label Attention’s own weights (third row), blue intensity = share of attention received — unsigned, since attention weights can’t push away from a class, only toward it.
A clear gap: label attention consistently hurts here, unlike on Amazon. Suspected cause — not enough data per class: 150 classes for 15,000 examples here, vs. 5 classes for 200k on Amazon, so building a good class representation is much harder. We’ll confirm this later.
Amazon and CLINC150 were the testbed. NAF is the target application — automatic coding of business-creation declarations, at production scale.
| Training examples | FastText | + Label Attn. |
|---|---|---|
| 163,615 | ≈0.63 | ≈0.76 |
| 314,230 | ≈0.57 | ≈0.63 |
| 628,461 | ≈0.51 | ≈0.53 |
| 1,208,579 | ≈0.48 | ≈0.47 |
This confirms the hypothesis from CLINC150: label attention needs enough data per class to learn useful queries, and only pays off once that data is available — exactly what happens here, at full NAF scale.
Only ≈7–8% of errors stay within the right class — the largest bucket by far, ≈47–48%, is “No match”: missing even the section.
Progressively delete the most-attributed words and track how fast the model’s own confidence collapses, against a random-deletion control.
Label attention’s own weights are the most faithful guide of the three — a free, more trustworthy explanation at this scale.
With a single predicted class, an error is an error.
One model, one flat 679-way sub-class prediction — no notion of section, division, group or class along the way. As just seen: a wrong prediction is roughly as likely to be completely off as it is to be a near-miss, and it’s structural — not fixed by picking a better architecture.
The goal isn’t fewer errors — it’s smarter ones.
L = L_sec + L_div + L_grp + L_cls + L_sub — unweighted sum, backpropagated jointly through the shared trunkClass counts (20 / 84 / 274 / 586 / 679) reflect codes observed in the training split (train_fraction = 0.13 of the full corpus). Full NAF 2025: 21 / 87 / 287 / 651 / 747.
We reason directly with each head’s own prediction, independently — not by truncating the sub-class guess.
The heads are independent: a fine level can land right while a coarser one misses — impossible before. But the 5 heads are trained jointly and never compared to each other at inference — they can produce mutually inconsistent codes.
Intuition: add a sixth loss term that directly penalizes disagreement between adjacent levels.
Four adjacent-pair checks, one example
Predicted codes shown below each level — the model's five heads, not the ground truth
Intuition: chain the levels instead of feeding them all in parallel — each head's embedding feeds the next, section first, mirroring a human coding officer.
Cascade — same SentenceEmbedder → Linear → ŷ per level, chained instead of forked
⊕ = concatenation. Every column keeps the exact same SentenceEmbedder → Linear → ŷk → ℒk shape — the only change is what feeds each SentenceEmbedder: the shared trunk T alone for Section, T concatenated with the previous level's own embedding for every level after it.
Intuition: keep all 5 heads in parallel, but let their embeddings communicate before classification — mixed by a single function (mean, attention…)
Five per-level embeddings, averaged into one before classification
Same efused feeds all five heads — only their own weights (Wsec…Wsub) can still make them disagree.
1. Accuracy vs. cost — Lightweight architectures are competitive, and label attention’s extra expressiveness is real — but it only pays off once there is enough data per class. Confirmed twice: CLINC150 vs. Amazon, then again on NAF at 1.2M-example scale.
2. Trustworthy explanations — Through extensive testing and illustration, we succeeded in identifying what drove the model to give a given answer.
3. Hierarchy — Dedicated per-level heads cut the “completely wrong” rate from ~47% to 29–34%, and clearly beat truncating a flat prediction — but introduce a head-disagreement problem that this internship identifies without yet solving.
Questions?
Full report, code, and figures on my GitHub: github.com/julber95/interpretable-text-classification