propertypilot/property-pilot-tickets
Viewer • Updated • 13.7k • 469
DistilBERT finetuned on 10,980 synthetic property maintenance tickets with two classification heads:
Part of the PropertyPilot project — an AI-powered property maintenance triage system.
| Task | Zero-shot F1 | Finetuned F1 | Improvement |
|---|---|---|---|
| Category (macro) | 0.032 | 0.972 | +0.939 |
| Urgency (macro) | 0.062 | 0.761 | +0.700 |
Urgency labels are derived from ticket text content (keyword-based rule classifier), making them strongly correlated with the actual maintenance scenario described.
Trained on propertypilot/property-pilot-tickets:
DistilBertModel (distilbert-base-uncased)
-> CLS token -> Dropout(0.1)
-> Linear(768, 10) # category head
-> Linear(768, 4) # urgency head
| File | Description |
|---|---|
model.pt |
PyTorch state dict (best checkpoint by combined val F1) |
label_map.json |
id2label / label2id for both heads |
tokenizer_config.json |
Tokenizer config (distilbert-base-uncased fast tokenizer) |
tokenizer.json |
Fast tokenizer file |
distilbert_config.json |
Base DistilBERT config |
eval_results.json |
Full training history + test metrics |
confusion_cat.png |
Category confusion matrix |
confusion_urg.png |
Urgency confusion matrix |
import torch, json
from transformers import DistilBertModel, DistilBertTokenizerFast
import torch.nn as nn
class TriageClassifier(nn.Module):
def __init__(self, n_cat, n_urg):
super().__init__()
self.bert = DistilBertModel.from_pretrained("distilbert-base-uncased")
self.dropout = nn.Dropout(0.1)
self.cat_head = nn.Linear(768, n_cat)
self.urg_head = nn.Linear(768, n_urg)
def forward(self, input_ids, attention_mask):
out = self.bert(input_ids=input_ids, attention_mask=attention_mask)
cls = self.dropout(out.last_hidden_state[:, 0])
return self.cat_head(cls), self.urg_head(cls)
# Load
label_map = json.load(open("label_map.json"))
tokenizer = DistilBertTokenizerFast.from_pretrained("distilbert-base-uncased")
model = TriageClassifier(n_cat=10, n_urg=4)
model.load_state_dict(torch.load("model.pt", map_location="cpu"))
model.eval()
# Predict
text = "gas leak in kitchen, can smell it strongly"
enc = tokenizer(text, return_tensors="pt", max_length=128, truncation=True, padding="max_length")
with torch.no_grad():
cat_logits, urg_logits = model(enc["input_ids"], enc["attention_mask"])
cat = label_map["category_id2label"][str(cat_logits.argmax(-1).item())]
urg = label_map["urgency_id2label"][str(urg_logits.argmax(-1).item())]
print(f"Category: {cat} | Urgency: {urg}")