functionX86 commited on
Commit
d2d3f85
·
verified ·
1 Parent(s): 137ea43

Fine-tuned BANKING77 intent classifier with model card

Browse files
Files changed (5) hide show
  1. README.md +129 -0
  2. config.json +188 -0
  3. model.safetensors +3 -0
  4. tokenizer.json +0 -0
  5. tokenizer_config.json +18 -0
README.md ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ language: en
4
+ library_name: transformers
5
+ pipeline_tag: text-classification
6
+ base_model: BAAI/bge-small-en-v1.5
7
+ tags:
8
+ - intent-classification
9
+ - customer-support
10
+ - banking
11
+ - banking77
12
+ datasets:
13
+ - PolyAI/banking77
14
+ metrics:
15
+ - f1
16
+ - accuracy
17
+ model-index:
18
+ - name: banking77-intent-classifier
19
+ results:
20
+ - task:
21
+ type: text-classification
22
+ name: Intent Classification
23
+ dataset:
24
+ type: banking77
25
+ name: BANKING77
26
+ metrics:
27
+ - type: f1
28
+ name: Macro F1
29
+ value: 0.9245
30
+ - type: accuracy
31
+ name: Accuracy
32
+ value: 0.9247
33
+ ---
34
+
35
+ # banking77-intent-classifier
36
+
37
+ A 77-class banking intent classifier, fine-tuned from
38
+ [`BAAI/bge-small-en-v1.5`](https://huggingface.co/BAAI/bge-small-en-v1.5) on
39
+ [BANKING77](https://github.com/PolyAI-LDN/task-specific-datasets).
40
+
41
+ Given a customer message such as *"my card still hasn't arrived after two weeks"*, it predicts
42
+ the intent (`card_arrival`) so the request can be routed automatically.
43
+
44
+ ## Results
45
+
46
+ | Metric | Value |
47
+ |---|---|
48
+ | Macro F1 | **0.9245** |
49
+ | Accuracy | **0.9247** |
50
+ | Top-3 accuracy | 0.974 |
51
+ | Inference | ~0.34 ms per request |
52
+
53
+ Evaluated on the official BANKING77 test split (3080 requests, 40 per intent), scored
54
+ once, at the end. Model selection used a stratified 10 % validation split carved out of the
55
+ training data.
56
+
57
+ ## An honest note on what this model is for
58
+
59
+ **This model was beaten by a simpler approach, and that is the interesting part.**
60
+
61
+ It was trained as the third rung of a deliberate ladder, to measure what fine-tuning actually
62
+ buys over cheaper alternatives on this dataset:
63
+
64
+ | Approach | Macro F1 | Training cost |
65
+ |---|---|---|
66
+ | TF-IDF (word + char n-grams) → logistic regression | 0.915 | 23 s, CPU |
67
+ | **Frozen `bge-small` embeddings → logistic regression** | **0.935** | 54 s, CPU |
68
+ | This model — `bge-small` fine-tuned end to end | 0.9245 | ~215 s, GPU |
69
+
70
+ Using the *same encoder frozen*, with nothing but a logistic regression on top, scores higher.
71
+ The gap held across five training runs spanning three random seeds, which scored between
72
+ 0.9245 and 0.9307 (mean ≈ 0.927). Runs vary by a few tenths of a point even at a fixed seed,
73
+ because GPU kernel scheduling and multi-worker data loading are not bit-deterministic — so the
74
+ comparison rests on the spread of runs rather than on any single number.
75
+
76
+ Two plausible reasons:
77
+
78
+ 1. `bge-small` is contrastively pre-trained for semantic similarity. Grouping semantically
79
+ similar sentences is more or less what intent classification is, so its embedding space
80
+ already arrives close to the right shape — and fine-tuning distorts a geometry that was
81
+ already good.
82
+ 2. 10 003 examples across 77 intents is roughly 130 per class. That is thin for updating 33 M
83
+ parameters, and the model reaches a memorised training loss before it generalises further.
84
+
85
+ An earlier version of this model, trained without a validation split, drove training loss to
86
+ 0.037 and scored 0.9295 — marginally higher than the properly regularised model published
87
+ here. That version was overfit, and comparing it against a regularised alternative would have
88
+ proved nothing. The lower, honest number is the one reported.
89
+
90
+ **If you want the best model for this task, use frozen embeddings with a linear head.** This
91
+ checkpoint is published for reproducibility and as a documented negative result.
92
+
93
+ ## Usage
94
+
95
+ ```python
96
+ from transformers import pipeline
97
+
98
+ classifier = pipeline("text-classification", model="functionX86/banking77-intent-classifier")
99
+ classifier("my card still hasn't arrived after two weeks")
100
+ # [{'label': 'card_arrival', 'score': 0.98}]
101
+ ```
102
+
103
+ ## Training
104
+
105
+ | Setting | Value |
106
+ |---|---|
107
+ | Base model | `BAAI/bge-small-en-v1.5` (33 M parameters) |
108
+ | Max sequence length | 64 tokens |
109
+ | Epochs | up to 15, early stopping on validation macro-F1 (patience 3) |
110
+ | Batch size | 32 |
111
+ | Learning rate | 5e-5, 10 % warmup, weight decay 0.01 |
112
+ | Precision | fp16 |
113
+ | Hardware | one NVIDIA RTX 3050 Ti (4 GB) |
114
+
115
+ The 64-token cap comes from the data: the 95th percentile of BANKING77 requests is 29 words,
116
+ so it truncates almost nothing while running roughly four times faster than the default 256.
117
+
118
+ ## Limitations
119
+
120
+ - **English only**, and trained on retail banking requests. It will not transfer to another
121
+ domain without retraining.
122
+ - **Several BANKING77 intents genuinely overlap** — `card_arrival` vs `card_delivery_estimate`,
123
+ `top_up_failed` vs `top_up_reverted`, and the whole identity-verification cluster. A share of
124
+ the residual error is label ambiguity that no model can resolve.
125
+ - **Raw softmax scores are not calibrated.** For any use that depends on a confidence
126
+ threshold, fit a temperature on held-out data first — on the frozen-embedding variant this
127
+ reduced expected calibration error from 0.110 to 0.012 without changing a single prediction.
128
+ - Trained on public research data, not on real customer messages, and never evaluated for
129
+ fairness across customer segments. Not suitable for production use as-is.
config.json ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_cross_attention": false,
3
+ "architectures": [
4
+ "BertForSequenceClassification"
5
+ ],
6
+ "attention_probs_dropout_prob": 0.1,
7
+ "bos_token_id": null,
8
+ "classifier_dropout": null,
9
+ "dtype": "float32",
10
+ "eos_token_id": null,
11
+ "hidden_act": "gelu",
12
+ "hidden_dropout_prob": 0.1,
13
+ "hidden_size": 384,
14
+ "id2label": {
15
+ "0": "Refund_not_showing_up",
16
+ "1": "activate_my_card",
17
+ "2": "age_limit",
18
+ "3": "apple_pay_or_google_pay",
19
+ "4": "atm_support",
20
+ "5": "automatic_top_up",
21
+ "6": "balance_not_updated_after_bank_transfer",
22
+ "7": "balance_not_updated_after_cheque_or_cash_deposit",
23
+ "8": "beneficiary_not_allowed",
24
+ "9": "cancel_transfer",
25
+ "10": "card_about_to_expire",
26
+ "11": "card_acceptance",
27
+ "12": "card_arrival",
28
+ "13": "card_delivery_estimate",
29
+ "14": "card_linking",
30
+ "15": "card_not_working",
31
+ "16": "card_payment_fee_charged",
32
+ "17": "card_payment_not_recognised",
33
+ "18": "card_payment_wrong_exchange_rate",
34
+ "19": "card_swallowed",
35
+ "20": "cash_withdrawal_charge",
36
+ "21": "cash_withdrawal_not_recognised",
37
+ "22": "change_pin",
38
+ "23": "compromised_card",
39
+ "24": "contactless_not_working",
40
+ "25": "country_support",
41
+ "26": "declined_card_payment",
42
+ "27": "declined_cash_withdrawal",
43
+ "28": "declined_transfer",
44
+ "29": "direct_debit_payment_not_recognised",
45
+ "30": "disposable_card_limits",
46
+ "31": "edit_personal_details",
47
+ "32": "exchange_charge",
48
+ "33": "exchange_rate",
49
+ "34": "exchange_via_app",
50
+ "35": "extra_charge_on_statement",
51
+ "36": "failed_transfer",
52
+ "37": "fiat_currency_support",
53
+ "38": "get_disposable_virtual_card",
54
+ "39": "get_physical_card",
55
+ "40": "getting_spare_card",
56
+ "41": "getting_virtual_card",
57
+ "42": "lost_or_stolen_card",
58
+ "43": "lost_or_stolen_phone",
59
+ "44": "order_physical_card",
60
+ "45": "passcode_forgotten",
61
+ "46": "pending_card_payment",
62
+ "47": "pending_cash_withdrawal",
63
+ "48": "pending_top_up",
64
+ "49": "pending_transfer",
65
+ "50": "pin_blocked",
66
+ "51": "receiving_money",
67
+ "52": "request_refund",
68
+ "53": "reverted_card_payment?",
69
+ "54": "supported_cards_and_currencies",
70
+ "55": "terminate_account",
71
+ "56": "top_up_by_bank_transfer_charge",
72
+ "57": "top_up_by_card_charge",
73
+ "58": "top_up_by_cash_or_cheque",
74
+ "59": "top_up_failed",
75
+ "60": "top_up_limits",
76
+ "61": "top_up_reverted",
77
+ "62": "topping_up_by_card",
78
+ "63": "transaction_charged_twice",
79
+ "64": "transfer_fee_charged",
80
+ "65": "transfer_into_account",
81
+ "66": "transfer_not_received_by_recipient",
82
+ "67": "transfer_timing",
83
+ "68": "unable_to_verify_identity",
84
+ "69": "verify_my_identity",
85
+ "70": "verify_source_of_funds",
86
+ "71": "verify_top_up",
87
+ "72": "virtual_card_not_working",
88
+ "73": "visa_or_mastercard",
89
+ "74": "why_verify_identity",
90
+ "75": "wrong_amount_of_cash_received",
91
+ "76": "wrong_exchange_rate_for_cash_withdrawal"
92
+ },
93
+ "initializer_range": 0.02,
94
+ "intermediate_size": 1536,
95
+ "is_decoder": false,
96
+ "label2id": {
97
+ "Refund_not_showing_up": 0,
98
+ "activate_my_card": 1,
99
+ "age_limit": 2,
100
+ "apple_pay_or_google_pay": 3,
101
+ "atm_support": 4,
102
+ "automatic_top_up": 5,
103
+ "balance_not_updated_after_bank_transfer": 6,
104
+ "balance_not_updated_after_cheque_or_cash_deposit": 7,
105
+ "beneficiary_not_allowed": 8,
106
+ "cancel_transfer": 9,
107
+ "card_about_to_expire": 10,
108
+ "card_acceptance": 11,
109
+ "card_arrival": 12,
110
+ "card_delivery_estimate": 13,
111
+ "card_linking": 14,
112
+ "card_not_working": 15,
113
+ "card_payment_fee_charged": 16,
114
+ "card_payment_not_recognised": 17,
115
+ "card_payment_wrong_exchange_rate": 18,
116
+ "card_swallowed": 19,
117
+ "cash_withdrawal_charge": 20,
118
+ "cash_withdrawal_not_recognised": 21,
119
+ "change_pin": 22,
120
+ "compromised_card": 23,
121
+ "contactless_not_working": 24,
122
+ "country_support": 25,
123
+ "declined_card_payment": 26,
124
+ "declined_cash_withdrawal": 27,
125
+ "declined_transfer": 28,
126
+ "direct_debit_payment_not_recognised": 29,
127
+ "disposable_card_limits": 30,
128
+ "edit_personal_details": 31,
129
+ "exchange_charge": 32,
130
+ "exchange_rate": 33,
131
+ "exchange_via_app": 34,
132
+ "extra_charge_on_statement": 35,
133
+ "failed_transfer": 36,
134
+ "fiat_currency_support": 37,
135
+ "get_disposable_virtual_card": 38,
136
+ "get_physical_card": 39,
137
+ "getting_spare_card": 40,
138
+ "getting_virtual_card": 41,
139
+ "lost_or_stolen_card": 42,
140
+ "lost_or_stolen_phone": 43,
141
+ "order_physical_card": 44,
142
+ "passcode_forgotten": 45,
143
+ "pending_card_payment": 46,
144
+ "pending_cash_withdrawal": 47,
145
+ "pending_top_up": 48,
146
+ "pending_transfer": 49,
147
+ "pin_blocked": 50,
148
+ "receiving_money": 51,
149
+ "request_refund": 52,
150
+ "reverted_card_payment?": 53,
151
+ "supported_cards_and_currencies": 54,
152
+ "terminate_account": 55,
153
+ "top_up_by_bank_transfer_charge": 56,
154
+ "top_up_by_card_charge": 57,
155
+ "top_up_by_cash_or_cheque": 58,
156
+ "top_up_failed": 59,
157
+ "top_up_limits": 60,
158
+ "top_up_reverted": 61,
159
+ "topping_up_by_card": 62,
160
+ "transaction_charged_twice": 63,
161
+ "transfer_fee_charged": 64,
162
+ "transfer_into_account": 65,
163
+ "transfer_not_received_by_recipient": 66,
164
+ "transfer_timing": 67,
165
+ "unable_to_verify_identity": 68,
166
+ "verify_my_identity": 69,
167
+ "verify_source_of_funds": 70,
168
+ "verify_top_up": 71,
169
+ "virtual_card_not_working": 72,
170
+ "visa_or_mastercard": 73,
171
+ "why_verify_identity": 74,
172
+ "wrong_amount_of_cash_received": 75,
173
+ "wrong_exchange_rate_for_cash_withdrawal": 76
174
+ },
175
+ "layer_norm_eps": 1e-12,
176
+ "max_position_embeddings": 512,
177
+ "model_type": "bert",
178
+ "num_attention_heads": 12,
179
+ "num_hidden_layers": 12,
180
+ "pad_token_id": 0,
181
+ "position_embedding_type": "absolute",
182
+ "problem_type": "single_label_classification",
183
+ "tie_word_embeddings": true,
184
+ "transformers_version": "5.16.1",
185
+ "type_vocab_size": 2,
186
+ "use_cache": false,
187
+ "vocab_size": 30522
188
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8fa858510c522804c299d925f821d4425447e8aaa7f59d68ac5bad03af3d0e91
3
+ size 133581876
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "clean_up_tokenization_spaces": true,
4
+ "cls_token": "[CLS]",
5
+ "do_basic_tokenize": true,
6
+ "do_lower_case": true,
7
+ "is_local": false,
8
+ "local_files_only": false,
9
+ "mask_token": "[MASK]",
10
+ "model_max_length": 512,
11
+ "never_split": null,
12
+ "pad_token": "[PAD]",
13
+ "sep_token": "[SEP]",
14
+ "strip_accents": null,
15
+ "tokenize_chinese_chars": true,
16
+ "tokenizer_class": "BertTokenizer",
17
+ "unk_token": "[UNK]"
18
+ }