Skip to content

Trainable Document Classifier[source]

The eds.doc_classifier component is a trainable document-level classifier. It predicts attributes of the document as a whole (its type, a principal diagnosis, the set of topics it covers) from a single pooled document embedding, and stores each prediction in a Doc._ extension.

The component is configured with one head per predicted attribute, given as a dict of options: a single-label head when a document has exactly one label, a multi-label head (multi_label: true) when it has a variable-length set of them.

Architecture

A document embedding component, such as eds.doc_pooler, turns the document into a single vector, which is fed to each head. A head owns its own MLP and label set, and writes to the Doc._ attribute it is named after. A single-label head is trained with a cross-entropy loss and decoded with an argmax, a multi-label head with a binary cross-entropy loss and decoded by keeping every label whose probability is at least its threshold. At training time the per-head losses are aggregated into a single loss, weighted by each head's loss_weight.

Document classifier architecture

Examples

The pipeline below predicts the principal diagnosis of a hospital stay (exactly one per document, so a single-label head) and its associated diagnoses (a set, so a multi-label head). Each head is keyed by the name of the attribute it fills in.

import edsnlp, edsnlp.pipes as eds

nlp = edsnlp.blank("eds")
nlp.add_pipe(
    eds.doc_classifier(
        embedding=eds.doc_pooler(
            pooling_mode="mean",
            embedding=eds.transformer(
                model="hf-internal-testing/tiny-random-bert",
                window=128,
                stride=96,
            ),
        ),
        heads={
            # the principal diagnosis: exactly one per document
            "dp": {"labels": ["C34", "I21"]},
            # the associated diagnoses: a set, of any size
            "das": {
                "labels": ["E11", "I10", "N18"],
                "multi_label": True,
                "threshold": 0.5,
            },
        },
    ),
    name="doc_classifier",
)

doc = nlp("Compte rendu d'hospitalisation.")
print(doc._.dp in ["C34", "I21"], isinstance(doc._.das, list))
# Out: True True

To predict a single attribute, keep only the corresponding head.

labels may also be the path to a JSON file holding the list of labels, or to a text file with one label per line, which is convenient for large label sets. It can also be left out entirely, in which case the labels are inferred from the gold data during nlp.post_init(...). Once saved, the model no longer depends on these files: the labels are stored with the model.

A document whose gold value is None for a head does not supervise it. A corpus annotated only for the principal diagnosis can therefore be mixed, in the same training run, with one annotated for everything.

To train the model, refer to the Training API documentation and to the document classifier tutorial.

Extensions

The eds.doc_classifier pipeline declares one extension on the Doc object per head, named after the head:

  • doc._.<head>: the label predicted by the head, a string for a single-label head and a list of strings for a multi-label one.

When store_probs is set, it also fills doc._.prob, a dict mapping each head name to a {label: probability} dict.

Parameters

PARAMETER DESCRIPTION
nlp

The pipeline the component belongs to.

TYPE: Optional[PipelineProtocol]

name

Component name.

TYPE: str DEFAULT: "doc_classifier"

embedding

Document embedding component, which returns one embedding per document, such as eds.doc_pooler.

TYPE: DocEmbeddingComponent

heads

The heads of the classifier, keyed by the name of the Doc._ attribute each one fills in. Each head is a dict of options, all optional:

  • labels: the labels of the head, as a list, as the path to a JSON file holding that list, or as the path to a text file with one label per line. Inferred from the gold data during nlp.post_init(...) when left out.
  • multi_label (default False): whether a document carries a set of labels rather than exactly one.
  • threshold (default 0.5): for a multi-label head, the probability above which a label is kept.
  • class_weights: a {label: frequency} mapping, or the path to a JSON file holding it, used to weight the loss by inverse frequency.
  • hidden_size: size of a hidden layer before the classifier, none by default.
  • activation_mode (default "relu", or "gelu", "silu"), dropout_rate (default 0.0) and layer_norm (default False): options of that hidden layer.
  • loss_weight (default 1.0): weight of the head in the training loss.

TYPE: Dict[str, HeadConfig]

store_probs

Whether to store the per-label probabilities of each head in doc._.prob[<head>].

TYPE: bool DEFAULT: False

probs_topk

Only store the probabilities of the probs_topk most probable labels of each head. Useful when a head has thousands of labels.

TYPE: Optional[int] DEFAULT: None

probs_threshold

Only store the probabilities greater than or equal to probs_threshold.

TYPE: Optional[float] DEFAULT: None

Authors and citation

The eds.doc_classifier pipeline was developed by AP-HP's Data Science team.