Buckets:

Mercity/policy-classifier / 03-11-progress /reports /policy_classifier_domain_split.md
Rishik001's picture
|
download
raw
5.77 kB
# Policy classifier: ModernBERT-large vs Qwen3-0.6B, in-domain and held-out domains
3 November 2026
## Hypothesis
A message-only policy classifier (followed / violated / not applicable) trained on generated support conversations should still work on business domains it has never seen. We test this by holding out 2 of the 12 domains entirely, and compare two backbones of similar cost: the encoder ModernBERT-large and the decoder Qwen3-0.6B.
## What did we do
Four training runs: each model on two versions of the same 30,000 labelled pairs.
**Data**
| Split version | Train | Validation | Test |
| --- | ---: | ---: | ---: |
| Original (random by case, all 12 domains) | 27,000 | 3,000 | none |
| Domain split (10 training domains, 2 held out) | 22,204 | 2,575 | 5,221 |
- Held-out test domains: insurance claims and travel booking. They were chosen because their label mix (about 38% followed, 25% violated, 37% not applicable) is closest to the whole dataset.
- Training domains: e-commerce returns, healthcare intake, edtech tutoring, recruiting, telecom support, real estate, banking support, HR helpdesk, fitness and nutrition, IT helpdesk.
- Validation in the domain split is one whole case from each training domain (154 to 353 pairs per domain), so no conversation appears in both train and validation.
**Training configuration** (identical for all four runs except where noted)
| Setting | ModernBERT-large | Qwen3-0.6B |
| --- | --- | --- |
| Classification head | mean-pooled head + classifier | score on last non-pad token |
| LoRA target layers | attention QKV, MLP in/out | all attention and MLP projections |
| Max sequence length | 2,400 | 2,352 |
| Adapter | LoRA, rank 32, alpha 64, dropout 0.05 (no DoRA) | same |
| Batch size | 64, no accumulation | same |
| Epochs | 1.5 | same |
| Learning rate | 2e-4, linear decay, 5% warmup | same |
| Weight decay / gradient clip | 0.01 / 1.0 | same |
| Precision | BF16, gradient checkpointing on | same |
| Seed | 7 | same |
| Optimiser steps | 633 (original), 521 (domain split) | same |
| Hardware | 1x H100 NVL (the two domain-split runs shared it) | same |
All numbers below come from the final checkpoint of each run. Training metrics were logged to Weights & Biases in offline mode and have not been synced yet.
## What did we find
**Core findings**
- Both models carry over to unseen domains with a small drop: Qwen loses about 1 accuracy point from validation to the held-out test, ModernBERT about 2.
- Qwen3-0.6B is better than ModernBERT-large on every summary metric, in both split versions. The largest gap is on the held-out test (macro F1 0.829 vs 0.812).
- Violation detection is the weak class for both models: violated recall is 0.69 (ModernBERT) and 0.75 (Qwen) on domain-split validation. Missed violations are mostly predicted as followed.
- On the original split the two models are within 0.5 points of each other, which is within noise for 3,000 validation pairs.
**Domain split: summary**
| Model | Split | Pairs | Accuracy | Macro F1 |
| --- | --- | ---: | ---: | ---: |
| ModernBERT-large | Validation (seen domains) | 2,575 | 0.8392 | 0.8296 |
| ModernBERT-large | Test (unseen domains) | 5,221 | 0.8159 | 0.8116 |
| Qwen3-0.6B | Validation (seen domains) | 2,575 | 0.8439 | 0.8376 |
| Qwen3-0.6B | Test (unseen domains) | 5,221 | 0.8324 | 0.8291 |
**Domain split: per class**
| Model | Split | Class | Precision | Recall | F1 | Support |
| --- | --- | --- | ---: | ---: | ---: | ---: |
| ModernBERT-large | Validation | followed | 0.7788 | 0.8950 | 0.8328 | 952 |
| ModernBERT-large | Validation | violated | 0.8544 | 0.6880 | 0.7622 | 657 |
| ModernBERT-large | Validation | not applicable | 0.9002 | 0.8872 | 0.8936 | 966 |
| ModernBERT-large | Test | followed | 0.8184 | 0.8083 | 0.8133 | 1,946 |
| ModernBERT-large | Test | violated | 0.7668 | 0.7849 | 0.7757 | 1,311 |
| ModernBERT-large | Test | not applicable | 0.8472 | 0.8442 | 0.8457 | 1,964 |
| Qwen3-0.6B | Validation | followed | 0.8031 | 0.8613 | 0.8312 | 952 |
| Qwen3-0.6B | Validation | violated | 0.8419 | 0.7458 | 0.7910 | 657 |
| Qwen3-0.6B | Validation | not applicable | 0.8879 | 0.8934 | 0.8906 | 966 |
| Qwen3-0.6B | Test | followed | 0.8115 | 0.8294 | 0.8203 | 1,946 |
| Qwen3-0.6B | Test | violated | 0.8043 | 0.7994 | 0.8018 | 1,311 |
| Qwen3-0.6B | Test | not applicable | 0.8730 | 0.8574 | 0.8651 | 1,964 |
**Original split (validation only, 3,000 pairs)**
| Model | Class | Precision | Recall | F1 | Support |
| --- | --- | ---: | ---: | ---: | ---: |
| ModernBERT-large | followed | 0.8186 | 0.8215 | 0.8201 | 1,115 |
| ModernBERT-large | violated | 0.8071 | 0.7714 | 0.7888 | 770 |
| ModernBERT-large | not applicable | 0.8524 | 0.8753 | 0.8637 | 1,115 |
| ModernBERT-large | **accuracy / macro F1** | | | **0.8287 / 0.8242** | |
| Qwen3-0.6B | followed | 0.8197 | 0.8152 | 0.8174 | 1,115 |
| Qwen3-0.6B | violated | 0.8359 | 0.7740 | 0.8038 | 770 |
| Qwen3-0.6B | not applicable | 0.8430 | 0.8906 | 0.8661 | 1,115 |
| Qwen3-0.6B | **accuracy / macro F1** | | | **0.8327 / 0.8291** | |
Confusion matrices, original split (rows = true label, columns = predicted followed / violated / not applicable):
| Model | True label | followed | violated | not applicable |
| --- | --- | ---: | ---: | ---: |
| ModernBERT-large | followed | 916 | 84 | 115 |
| ModernBERT-large | violated | 122 | 594 | 54 |
| ModernBERT-large | not applicable | 81 | 58 | 976 |
| Qwen3-0.6B | followed | 909 | 74 | 132 |
| Qwen3-0.6B | violated | 121 | 596 | 53 |
| Qwen3-0.6B | not applicable | 79 | 43 | 993 |
Original-split and domain-split numbers use different validation sets and should not be compared with each other. Each result is a single seed.
## Next steps
To be agreed before writing.

Xet Storage Details

Size:
5.77 kB
·
Xet hash:
f93159aeff6f1315c62e37f2fd907bc21c9efbda18a1849f62872ed21658e4e2

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.