mailroom-modernbert-classifier

Hierarchical document classifier for the LLM-Mailroom intake pipeline: a fine-tuned ModernBERT-base encoder with a doc_type head plus one subclass head per document class. It is the deterministic pre-check in the BERT-coupled intake overhaul (mailroom-issues #85).

Architecture

  • Backbone: answerdotai/ModernBERT-base — 22 layers, 768 hidden, 8,192-token context, bf16.
  • Heads: one head per class — doc_type (6 classes) plus 5 subclass heads (contract, corporate_record, correspondence, insurance_claim, merger_agreement). MLP heads with dropout 0.1.
  • Windowing: token-level, 8,192 tokens with 512-token overlap. doc_type by plurality vote over windows; subclass by plurality over windows whose doc_type vote is the winning class.
  • Calibration: per-head temperature scaling (temperatures.json).

Files

file purpose
model.safetensors ModernBERT backbone weights (bf16, ~298 MB)
heads.pt hierarchical head state dicts
labels.json head vocabularies (labels / label2id / id2label / weights)
temperatures.json per-head calibration temperatures
train_counts.json per-(doc_type, subclass) authentic train-row counts (support gate)
config.json, tokenizer.json, tokenizer_config.json backbone config + tokenizer
summary.json full run summary (hyperparameters, per-epoch metrics, selection, test metrics)

Labels

doc_type (6): contract, merger_agreement, corporate_record, correspondence, insurance_claim, unknown (inference-only abstention — not a trained class)

contract (24): agency, co_branding, collaboration, consulting, development, distributor, endorsement, franchise, hosting, ip, joint_venture, license, maintenance, manufacturing, marketing, other, outsourcing, promotion, reseller, service, sponsorship, strategic_alliance, supply, transportation

corporate_record (10): articles_of_incorporation, board_resolution, bylaws, charter_amendment, indenture, officer_certificate, other, powers_of_attorney, rights_instrument, subsidiary_list

correspondence (7): demand, email, letter, meeting_request, memo, notice, press_release

insurance_claim (6): auto, carrier, inpatient, outpatient, pde, property

merger_agreement (5): all_cash, all_stock, mixed_cash_stock, mixed_cash_stock_election, other

Results

Trained 2 epochs on Lucius-Morningstar/mailroom-modernbert-training @ 5b72a345cd3c057b736bea4910fdbef6509ad1c3 — 4,497 train / 489 validation windows; 323 held-out test documents (never used for training, calibration, or threshold tuning).

Validation

epoch val_loss doc_acc macro-F1 (observed) ECE (calibrated)
1 1.0041 0.8859 0.8524 0.0201
2 0.9121 0.9195 0.9051 0.0205

Selected epoch: 2 — best observed doc_type macro-F1 subject to calibrated ECE ≤ 0.05 (gate_met: true).

Held-out test (323 docs)

metric value
doc_type accuracy 0.9319 (301/323)
subclass accuracy (given correct doc_type) 0.5449 (164/301)

Per-head (epoch 2, validation)

head window acc macro-F1 (observed) ECE (calibrated)
doc_type 0.9141 0.9051 0.0205
insurance_claim 0.8889 0.8085 0.0500
corporate_record 0.5405 0.2218 0.1037
merger_agreement 0.4656 0.1988 0.0350
correspondence 0.5161 0.0980 0.1050
contract 0.1630 0.0899 0.0630

Usage

The backbone is a standard ModernBertModel; the hierarchical heads are a custom bundle. Load it with the mailroom-ml inference layer:

from mailroom_ml.inference import load_bundle, classify_document

bundle = load_bundle("Lucius-Morningstar/mailroom-modernbert-classifier")
result = classify_document(
    title="Notice of Default",
    text=document_text,
    bundle=bundle,
)
# result["doc_type"], result["subclass"], result["confidence"], result["route"]

route == "fast_path" means the calibrated gate passed and the LLM sorter may be skipped (skip mode + allowlist only); otherwise route the document to the LLM sorter with the BERT triage as an advisory prior.

Provenance

  • Training run: 20260920-173810 — 2 epochs, ~3.78 h on a Modal L4.
  • Hyperparameters: batch 4, grad-accum 8, lr 2e-5, seed 42, λ_dt 0.65, label smoothing 0.05, sqrt-inverse class weights (cap 10), MLP heads (dropout 0.1), weight decay 0.01, subclass support floor 12.
  • Dataset revision: 5b72a345cd3c057b736bea4910fdbef6509ad1c3.
  • Calibration temperatures: doc_type 0.484, contract 0.705, corporate_record 0.596, correspondence 0.960, insurance_claim 0.122, merger_agreement 0.679.

Limitations

  • Subclass heads are weak for contract / correspondence / corporate_record / merger_agreement (macro-F1 0.09–0.22). Use the doc_type head for routing; route subclass-ambiguous documents to the LLM sorter (the Tier-1 prior-scoped lane, mailroom-issues #108). Do not trust a skip-mode subclass for these classes yet.
  • Trained on a curated legal-document corpus; not a substitute for legal review.
  • unknown is an inference-only abstention label, not a trained class.
  • Long documents are windowed (8,192 tokens, 512 overlap); the model never truncates silently — oversize documents fall back to the LLM path.

License

Apache-2.0 (inherits answerdotai/ModernBERT-base).

Downloads last month
29
Safetensors
Model size
0.1B params
Tensor type
BF16
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for Lucius-Morningstar/mailroom-modernbert-classifier

Finetuned
(1484)
this model

Dataset used to train Lucius-Morningstar/mailroom-modernbert-classifier

Collection including Lucius-Morningstar/mailroom-modernbert-classifier