About this project
A domain-adaptation practical: train a headline topic classifier on general AG News titles, evaluate on a frozen UK BBC test set, then fine-tune on UK data and measure the lift — all on a Mac Studio with Apple Silicon MPS.
What we’re asking
Can a classifier trained on broad, mostly US-centric news titles transfer to UK BBC headlines — and does continued fine-tuning on UK text close the gap?
We compare five systems on the same frozen UK test set: Naive Bayes @ AG, DistilBERT @ AG, Naive Bayes @ UK, DistilBERT UK-only (no AG), and DistilBERT AG→UK continued fine-tuning. Charts live on the classification page.
Hardware: Mac Studio
Training and inference ran locally on Apple Silicon — not a cloud GPU box. DistilBERT is small enough that this machine is more than enough; the practical constraint was getting PyTorch’s MPS backend working cleanly.
- Machine
- Mac StudioApple M3 Ultra
- Memory
- 96 GB unifiedCPU + GPU share the same pool
- Compute path
- PyTorch MPS
torch.backends.mpswhen available
- Why not MLX-LM?
- Classifier, not LLMHugging Face Transformers + Torch
MPS notes: we avoid fp16 mixed-precision quirks on MPS,
keep batches modest (32 / 16), and set dataloader_pin_memory=False.
Stage 1 is typically under 1–2 hours; Stage 2 is minutes; Naive Bayes is seconds.
Model: DistilBERT
Backbone: distilbert-base-uncased
with a fresh 4-way sequence-classification head
(AutoModelForSequenceClassification).
- ~66M parameters — about 40% of BERT-base, trained by knowledge distillation.
- Uncased WordPiece tokenizer; max sequence length capped at 64 tokens (headlines / short prefixes).
- 4 labels:
business,sport,tech,politics. - Classical baseline: Multinomial Naive Bayes + bag-of-words unigrams (
CountVectorizer,min_df=2).
Lower-level architecture
DistilBERT is a compressed Transformer encoder. It keeps the BERT-style stack but drops the next-sentence prediction objective and halves the depth, then trains the student to match a BERT teacher.
Encoder stack
What “fine-tuning” updates
We do full continued fine-tuning: every DistilBERT weight plus the classification head receive gradients. LoRA / adapters were not needed — the model is small, the UK set is small, and full updates finish quickly on MPS.
- Forward: tokenize → pad/truncate to ≤64 → encoder → logits.
- Loss: cross-entropy over the four labels.
- Optimizer path: Hugging Face
Trainer(AdamW-style), lr2e-5, weight decay0.01, seed42. - Selection: best checkpoint by validation macro-F1.
Why DistilBERT (not a generative LLM)
This is single-label topic classification. An encoder with a linear head is the right inductive bias: cheap, stable, and easy to compare against a Naive Bayes bag-of-words baseline. We deliberately do not train a large generative model from scratch.
Fine-tuning techniques
The core method is two-stage domain adaptation (continued fine-tuning), with an ablated UK-only run to separate “UK data helps” from “AG pre-training still helps.”
Stage 1 — AG News titles (“before”)
Init from distilbert-base-uncased. Train on stratified AG titles
(~28.5k train / 1.5k val). 2 epochs, batch 32. Save
artifacts/model_ag_headlines/. Evaluate on frozen UK test.
Stage 2 — continue on UK (“after”)
Load the Stage-1 checkpoint (do not re-init from base). Train on
UK train; early-stop on UK val (patience 1, up to 3 epochs), batch 16.
Save artifacts/model_uk_finetuned/. Re-evaluate on the same UK test.
Ablation — UK only (no AG)
Fresh distilbert-base-uncased fine-tuned only on UK train/val
with the same Stage-2 recipe. Isolates whether gains come from UK data
alone vs AG→UK continued training.
Baselines — Multinomial Naive Bayes
Bag-of-words NB trained on AG titles, then separately on UK train; both scored on the same UK test. A cheap ceiling/floor check for the neural models.
| Knob | Stage 1 (AG) | Stage 2 / UK-only |
|---|---|---|
| Init | Hub base model | Stage-1 ckpt / Hub base |
| Learning rate | 2e-5 | 2e-5 |
| Batch size | 32 | 16 |
| Epochs | 2 | ≤3 + early stop |
| Max length | 64 | 64 |
| Best model metric | macro-F1 | macro-F1 |
Not used: LoRA, QLoRA, prefix-tuning, or frozen-encoder linear probes. Full updates are appropriate here; parameter-efficient methods would mostly add complexity without a clear win on this size of model and data.
Data & label mapping
| Source | Role | Notes |
|---|---|---|
| fancyzhx/ag_news | Stage 1 train/val | Title / short prefix only; stratified ~30k subset |
| SetFit/bbc-news | UK fine-tune + frozen test | 70 / 15 / 15 train/val/test, seed 42; drop entertainment |
Unified 4-way labels
| Unified | AG News | BBC |
|---|---|---|
| business | Business | business |
| sport | Sports | sport |
| tech | Sci/Tech | tech |
| politics | World | politics |
AG World → BBC politics is an imperfect bridge on purpose —
that mismatch is part of what UK fine-tuning has to fix. BBC rows often lack
a clean title field; we use title/headline when present,
else the first sentence or first ~16 tokens as a headline proxy.
Software pipeline
Scripts are meant to be run in order after source .venv/bin/activate.
Prepared CSVs already live in data/; model weights stay gitignored
while metrics and charts are committed for GitHub Pages.
prepare_data.py— optional regenerate of splitstrain_nb.py— Naive Bayes @ AG and @ UKtrain_stage1.py→evaluate.py(before metrics)train_stage2.py→evaluate.py(after metrics)train_uk_only.py→evaluate.py(UK-only metrics)assemble_results.py,embed_similarity.py,novel_words.py
Stack: PyTorch, Hugging Face Transformers / Datasets / Accelerate,
scikit-learn, pandas, matplotlib. See requirements.txt and
AGENT_PLAN.html for the locked brief.
Evaluation design
- Frozen UK test — never used for training or early stopping.
- Metrics: accuracy, macro-F1, micro-F1, per-class F1, confusion matrices.
- Micro-F1 = accuracy here (single-label multi-class); both reported for lecture-style comparison.
- Headline results: AG→UK fine-tuned reaches ~0.96 accuracy / macro-F1 on UK test; largest class gain vs AG-only is politics. Details on Classification and in RESULTS.md.
Side analyses dig into why transfer is hard: embedding centroid similarity, headline length distributions, and UK words missing from AG train.
Caveats & design risks
- Label bridge
World↔politicsis noisy by construction. - BBC “headlines” are sometimes truncated article leads, not newsstand titles.
- UK data is small — Stage 2 early-stops on val; over-training would memorize fast.
- AG-only DistilBERT already beats NB @ AG; most of the big jump to ~0.95 comes from UK data itself, with AG→UK still edging UK-only.