RowRed commited on
Commit
23f8b10
·
verified ·
1 Parent(s): bc33fcc

Create README.md

Browse files
Files changed (1) hide show
  1. README.md +245 -0
README.md ADDED
@@ -0,0 +1,245 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ language:
4
+ - en
5
+ tags:
6
+ - prompt-routing
7
+ - category-classifier
8
+ - deberta-v3
9
+ - llm-router
10
+ - cost-optimization
11
+ datasets:
12
+ - RowRed/ComplexityRouter
13
+ - OpenAssistant/oasst2
14
+ base_model:
15
+ - microsoft/deberta-v3-base
16
+ ---
17
+
18
+ # CategoryRouter: A Category‑based LLM Router
19
+
20
+ **CategoryRouter** is a lightweight prompt category classifier finetuned from **microsoft/deberta-v3-base**. It assigns prompts to one of **6 categories**, making it useful for routing queries to the appropriate specialist LLM or service.
21
+
22
+ ## Model Details
23
+
24
+ ### Model Description
25
+
26
+ - **Model type:** Text Classification (multi‑class, 6 classes)
27
+ - **Language:** English
28
+ - **Backbone:** microsoft/deberta-v3-base
29
+ - **License:** Apache‑2.0
30
+ - **Finetuned from model:** microsoft/deberta-v3-base
31
+ - **Training data:** OASST2 + synthetic augmentations + manually created prompts
32
+ Labels generated by **Qwen3.5‑4B** (non‑thinking mode).
33
+
34
+ ### Model Sources
35
+
36
+ - **Dataset repository:** https://huggingface.co/datasets/RowRed/ComplexityRouter
37
+
38
+ ## Categories
39
+
40
+ | Label | Category | Example Prompt |
41
+ |-------|----------|----------------|
42
+ | 0 | Coding | “Write a Python function to merge two sorted lists.” |
43
+ | 1 | Information | “What is the normal force? Explain with an example.” |
44
+ | 2 | Guidance | “How do I change a car tire?” |
45
+ | 3 | Media Generation | “Generate an image prompt for a sunset.” |
46
+ | 4 | Writing | “Write a short story about a robot learning to paint.” |
47
+ | 5 | Other | “Invent a new holiday.” |
48
+
49
+ > **Note:** The original ComplexityRouter dataset had 7 categories; “Math” prompts were merged into “Coding” to retain only 6 distinct categories.
50
+
51
+ ## Uses
52
+
53
+ ### Direct Use
54
+
55
+ Route prompts to the appropriate LLM backend:
56
+
57
+ | Category | Suggested Backend |
58
+ |----------|-------------------|
59
+ | Coding | Code‑specialized model |
60
+ | Information | General‑knowledge model |
61
+ | Guidance | Instruction‑tuned model |
62
+ | Media Generation | Multimodal / image‑generation model |
63
+ | Writing | Creative writing model |
64
+ | Other | Catch‑all (generic model) |
65
+
66
+ ### Out‑of‑Scope Use
67
+
68
+ - Multi‑turn conversations (single prompts only).
69
+ - Non‑English prompts.
70
+ - Prompts requiring image or multimodal understanding.
71
+
72
+ ## Bias, Risks, and Limitations
73
+
74
+ - Training data is synthetic and may not represent all real‑world prompt distributions.
75
+ - Categories with low support (Media Generation, Writing) have lower per‑class F1 scores – boundary cases are inherently ambiguous.
76
+ - The model may struggle with very domain‑specific technical jargon.
77
+ - The “Other” category is a catch‑all; many “Information” prompts leak into it and vice‑versa.
78
+ - Performance may degrade on prompts very different from the training distribution.
79
+
80
+ ## Notice
81
+ This is my first attempt making a widespread finetune. There are probably lots of issues, but thought the idea was sound. I might make a second (hopefully better) version eventually, but am not sure where to get lots of high-quality open source data.
82
+
83
+ ## Training Details
84
+
85
+ ### Training Data
86
+
87
+ | Split | Samples | Source File | Notes |
88
+ |-------------|---------|----------------------|-------|
89
+ | Training | 2,800 | TRAINING.jsonl | Used for model training |
90
+ | Validation | 600 | TRAINING.jsonl | Used for early stopping / hyperparameter tuning |
91
+ | Test (internal) | 600 | TRAINING.jsonl | Used for in‑distribution evaluation |
92
+ | Test (held‑out) | 400 | TEST.jsonl | Fully independent test set (reported results) |
93
+
94
+ **Total unique prompts:** 4,400
95
+
96
+ Class distribution (training):
97
+ Coding: 508 (18.1%) • Information: 937 (33.5%) • Guidance: 609 (21.8%) • Media Generation: 111 (4.0%) • Writing: 88 (3.1%) • Other: 547 (19.6%)
98
+
99
+ ### Training Procedure
100
+
101
+ - Hardware: NVIDIA T4 (16 GB VRAM, Google Colab)
102
+ - Framework: PyTorch 2.11 + Hugging Face Transformers
103
+ - Optimizer: AdamW (lr=2e-5, weight_decay=0.01)
104
+ - Scheduler: Linear warmup (10% of steps) → linear decay
105
+ - Loss: Weighted Cross‑Entropy (sqrt‑scaled class weights) + label smoothing (0.15)
106
+ - Batch size: 16 (effective 32 with gradient accumulation)
107
+ - Epochs: 7 (early stopping patience = 3, best epoch = 7)
108
+ - Training time: ~16 minutes
109
+ - Class balancing: sqrt‑scaled class weights + weighted random sampler
110
+
111
+ ## Evaluation Results
112
+
113
+ ### Internal Test (600 held‑out samples from training split)
114
+
115
+ | Metric | Value |
116
+ |--------|-------|
117
+ | Exact Match Accuracy | 67.0% |
118
+ | Macro F1 | 0.617 |
119
+ | Weighted F1 | 0.665 |
120
+
121
+ **Per‑Class Performance (internal test, 600 samples)**
122
+
123
+ | Category | Precision | Recall | F1 | Support |
124
+ |----------|-----------|--------|----|---------|
125
+ | Coding | 0.714 | 0.688 | 0.701 | 109 |
126
+ | Information | 0.740 | 0.766 | 0.753 | 201 |
127
+ | Guidance | 0.707 | 0.800 | 0.751 | 130 |
128
+ | Media Generation | 0.619 | 0.542 | 0.578 | 24 |
129
+ | Writing | 0.571 | 0.421 | 0.485 | 19 |
130
+ | Other | 0.457 | 0.410 | 0.432 | 117 |
131
+
132
+ **Confusion Matrix (internal test)**
133
+
134
+ ```
135
+ Pred Pred Pred Pred Pred Pred
136
+ Cod Inf Gui Med Wri Oth
137
+ True Cod 75 8 12 1 1 12
138
+ True Inf 5 154 13 0 1 28
139
+ True Gui 9 6 104 0 1 10
140
+ True Med 3 2 0 13 2 4
141
+ True Wri 0 0 3 5 8 3
142
+ True Oth 13 38 15 2 1 48
143
+ ```
144
+
145
+ ### Held‑Out Test (400 independent samples)
146
+
147
+ | Metric | Value |
148
+ |--------|-------|
149
+ | Exact Match Accuracy | 76.5% |
150
+ | Macro F1 | – (per‑category below) |
151
+
152
+ **Per‑Category Breakdown**
153
+
154
+ | Category | Exact Count | Exact Accuracy |
155
+ |----------|-------------|----------------|
156
+ | Coding | 35/44 | 79.5% |
157
+ | Information | 184/229 | 80.3% |
158
+ | Guidance | 55/63 | 87.3% |
159
+ | Media Generation | 8/14 | 57.1% |
160
+ | Writing | 9/20 | 45.0% |
161
+ | Other | 15/30 | 50.0% |
162
+
163
+ ## How to Get Started with the Model
164
+
165
+ ```python
166
+ from transformers import AutoTokenizer, AutoModel
167
+ import torch
168
+ import torch.nn as nn
169
+
170
+ class CategoryRouter(nn.Module):
171
+ def __init__(self, backbone="microsoft/deberta-v3-base", num_labels=6):
172
+ super().__init__()
173
+ self.backbone = AutoModel.from_pretrained(backbone)
174
+ hidden_size = self.backbone.config.hidden_size
175
+ self.classifier = nn.Sequential(
176
+ nn.Dropout(0.1),
177
+ nn.Linear(hidden_size, 256),
178
+ nn.GELU(),
179
+ nn.Dropout(0.1),
180
+ nn.Linear(256, num_labels),
181
+ )
182
+
183
+ def forward(self, input_ids, attention_mask):
184
+ outputs = self.backbone(input_ids=input_ids, attention_mask=attention_mask)
185
+ cls_output = outputs.last_hidden_state[:, 0, :]
186
+ return self.classifier(cls_output)
187
+
188
+ # Load
189
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
190
+ tokenizer = AutoTokenizer.from_pretrained("~~~ME~~~/CategoryRouter")
191
+ model = CategoryRouter()
192
+ model.load_state_dict(
193
+ torch.load("pytorch_model.bin", map_location=device),
194
+ strict=False
195
+ )
196
+ model.to(device)
197
+ model.eval()
198
+
199
+ # Predict
200
+ prompts = ["Write a Python function", "What is the normal force?"]
201
+ encoded = tokenizer(prompts, padding=True, truncation=True, return_tensors="pt").to(device)
202
+ with torch.no_grad():
203
+ logits = model(encoded["input_ids"], encoded["attention_mask"])
204
+ probs = torch.softmax(logits, dim=-1)
205
+ predictions = torch.argmax(probs, dim=-1)
206
+
207
+ category_map = ["Coding", "Information", "Guidance", "Media Generation", "Writing", "Other"]
208
+ for prompt, idx in zip(prompts, predictions):
209
+ print(f"Category: {category_map[idx.item()]} – {prompt}")
210
+ ```
211
+
212
+ ## Citation
213
+ If you use this model, please cite:
214
+
215
+ ```bibtex
216
+ @software{CategoryRouter,
217
+ author = {RowRed},
218
+ title = {CategoryRouter},
219
+ year = {2026},
220
+ url = {https://huggingface.co/RowRed/CategoryRouter}
221
+ }
222
+ ```
223
+
224
+ Additionally, acknowledge the base dataset and labeling model:
225
+
226
+ ```bibtex
227
+ @dataset{oasst2,
228
+ author = {OpenAssistant Contributors},
229
+ title = {Open Assistant Conversations Dataset Release 2},
230
+ year = {2023},
231
+ url = {https://huggingface.co/datasets/OpenAssistant/oasst2}
232
+ }
233
+
234
+ @software{qwen3.5-4b,
235
+ author = {Qwen Team},
236
+ title = {Qwen3.5-4B},
237
+ year = {2026},
238
+ url = {https://huggingface.co/Qwen/Qwen3.5-4B}
239
+ }
240
+ ```
241
+
242
+ ## License
243
+ This model is released under Apache‑2.0.
244
+ The backbone (microsoft/deberta-v3-base) is MIT‑licensed.
245
+ The training dataset is derived from OASST2 (Apache‑2.0) and Qwen3.5‑4B outputs (Apache‑2.0).