Adedayo2000 commited on
Commit
60d1e62
·
verified ·
1 Parent(s): c773f1d

Delete train.py

Browse files
Files changed (1) hide show
  1. train.py +0 -176
train.py DELETED
@@ -1,176 +0,0 @@
1
- """
2
- Support Ticket Classifier
3
- Author: Adedayo Adebayo
4
- Date: 2026-03-14
5
- Description: Multi-class text classification for customer support tickets using BERTweet
6
- """
7
-
8
- import logging
9
- from typing import Dict, List, Tuple, Any
10
- import pandas as pd
11
- import numpy as np
12
- import torch
13
- from sklearn.model_selection import train_test_split
14
- from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
15
- from transformers import AutoTokenizer, AutoModelForSequenceClassification, TrainingArguments, Trainer
16
- from huggingface_hub import HfApi, login
17
-
18
- CONFIG = {
19
- "model_name": "vinai/bertweet-base",
20
- "test_size": 0.2,
21
- "random_state": 99,
22
- "batch_size": 8,
23
- "epochs": 4,
24
- "max_length": 128,
25
- }
26
-
27
- def setup_logging() -> logging.Logger:
28
- logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
29
- return logging.getLogger(__name__)
30
-
31
- logger = setup_logging()
32
-
33
- def load_dataset(filepath: str) -> Tuple[pd.DataFrame, List[str]]:
34
- logger.info(f"Loading dataset from {filepath}")
35
- ticket_dataframe = pd.read_csv(filepath)
36
- ticket_dataframe = clean_dataset(ticket_dataframe)
37
- categories = sorted(ticket_dataframe['category'].unique().tolist())
38
- logger.info(f"Loaded {len(ticket_dataframe)} samples with {len(categories)} categories")
39
- return ticket_dataframe, categories
40
-
41
- def clean_dataset(ticket_dataframe: pd.DataFrame) -> pd.DataFrame:
42
- ticket_dataframe['ticket_text'] = ticket_dataframe['ticket_text'].fillna('').astype(str)
43
- ticket_dataframe['category'] = ticket_dataframe['category'].fillna('General Inquiry')
44
- ticket_dataframe = ticket_dataframe[ticket_dataframe['ticket_text'].str.strip() != '']
45
- return ticket_dataframe
46
-
47
- def create_labels(ticket_dataframe: pd.DataFrame, categories: List[str]) -> Tuple[pd.DataFrame, Dict[str, int], Dict[int, str]]:
48
- label2id = {label: idx for idx, label in enumerate(categories)}
49
- id2label = {idx: label for label, idx in label2id.items()}
50
- ticket_dataframe['label'] = ticket_dataframe['category'].map(label2id)
51
- return ticket_dataframe, label2id, id2label
52
-
53
- def split_dataset(ticket_dataframe: pd.DataFrame) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
54
- ticket = ticket_dataframe['ticket_text'].values
55
- category = ticket_dataframe['label'].values
56
- ticket_train, ticket_test, category_train, category_test = train_test_split(ticket, category, test_size=CONFIG['test_size'], random_state=CONFIG['random_state'], stratify=category)
57
- logger.info(f"Train: {len(ticket_train)}, Test: {len(ticket_test)}")
58
- return ticket_train, ticket_test, category_train, category_test
59
-
60
- class TicketDataset(torch.utils.data.Dataset):
61
- def __init__(self, texts: np.ndarray, labels: np.ndarray, tokenizer: AutoTokenizer, max_length: int):
62
- self.texts = texts
63
- self.labels = labels
64
- self.tokenizer = tokenizer
65
- self.max_length = max_length
66
-
67
- def __len__(self) -> int:
68
- return len(self.texts)
69
-
70
- def __getitem__(self, idx: int) -> Dict[str, torch.Tensor]:
71
- encoding = self.tokenizer(str(self.texts[idx]), add_special_tokens=True, max_length=self.max_length, padding='max_length', truncation=True, return_tensors='pt')
72
- return {
73
- 'input_ids': encoding['input_ids'].squeeze(0),
74
- 'attention_mask': encoding['attention_mask'].squeeze(0),
75
- 'labels': torch.tensor(int(self.labels[idx]), dtype=torch.long)
76
- }
77
-
78
- def create_datasets(ticket_train: np.ndarray, ticket_test: np.ndarray, category_train: np.ndarray, category_test: np.ndarray, tokenizer: AutoTokenizer):
79
- return TicketDataset(ticket_train, category_train, tokenizer, CONFIG['max_length']), TicketDataset(ticket_test, category_test, tokenizer, CONFIG['max_length'])
80
-
81
- def load_model_and_tokenizer(num_labels: int, label2id: Dict[str, int], id2label: Dict[int, str]):
82
- logger.info(f"Loading model: {CONFIG['model_name']}")
83
- tokenizer = AutoTokenizer.from_pretrained(CONFIG['model_name'])
84
- model = AutoModelForSequenceClassification.from_pretrained(CONFIG['model_name'], num_labels=num_labels, id2label=id2label, label2id=label2id)
85
- return model, tokenizer
86
-
87
- def train_model(model, train_dataset, test_dataset) -> Trainer:
88
- logger.info("Training started")
89
- training_args = TrainingArguments(
90
- output_dir='./results',
91
- num_train_epochs=CONFIG['epochs'],
92
- per_device_train_batch_size=CONFIG['batch_size'],
93
- per_device_eval_batch_size=CONFIG['batch_size'],
94
- warmup_steps=50,
95
- weight_decay=0.01,
96
- logging_steps=50,
97
- eval_strategy="epoch",
98
- save_strategy="epoch",
99
- load_best_model_at_end=True,
100
- )
101
- trainer = Trainer(model=model, args=training_args, train_dataset=train_dataset, eval_dataset=test_dataset)
102
- trainer.train()
103
- logger.info("Training complete")
104
- return trainer
105
-
106
- def evaluate_model(trainer, test_dataset, category_test: np.ndarray, categories: List[str]) -> float:
107
- predictions = trainer.predict(test_dataset)
108
- preds = np.argmax(predictions.predictions, axis=-1)
109
- accuracy = accuracy_score(category_test, preds)
110
- logger.info(f"Accuracy: {accuracy*100:.2f}%")
111
- print("CLASSIFICATION REPORT")
112
- print(classification_report(category_test, preds, target_names=categories))
113
- print(confusion_matrix(category_test, preds))
114
- return accuracy
115
-
116
- def push_to_huggingface(model, tokenizer, repo_name: str = "BERTweet-Support-Ticket-Classifier") -> str:
117
- logger.info("Pushing to HuggingFace Hub...")
118
-
119
- try:
120
- from kaggle_secrets import UserSecretsClient
121
- user_secrets = UserSecretsClient()
122
- hf_token = user_secrets.get_secret("HF_TOKEN")
123
- logger.info("Logging in to HuggingFace hub...")
124
- login(token=hf_token)
125
- logger.info("Logged in to HuggingFace")
126
-
127
- api = HfApi()
128
- user_info = api.whoami(token=hf_token)
129
- username = user_info['name']
130
- full_repo_name = f"{username}/{repo_name}"
131
-
132
- logger.info(f"Uploading to: {full_repo_name}")
133
-
134
- model.push_to_hub(repo_name, token=hf_token)
135
- tokenizer.push_to_hub(repo_name, token=hf_token)
136
-
137
- model_url = f"https://huggingface.co/{full_repo_name}"
138
-
139
- logger.info("Model Uploaded Successfully!")
140
- logger.info(f"URL: {model_url}")
141
-
142
- return model_url
143
-
144
- except Exception as e:
145
- logger.error(f"Failed to push due to the following error: {e}")
146
- raise
147
-
148
- def predict_single(text: str, model, tokenizer, id2label: Dict[int, str]) -> Dict[str, Any]:
149
- inputs = tokenizer(text, return_tensors='pt', truncation=True, max_length=CONFIG['max_length'], padding=True)
150
- with torch.no_grad():
151
- outputs = model(**inputs)
152
- probs = torch.nn.functional.softmax(outputs.logits, dim=-1)
153
- pred_idx = torch.argmax(probs).item()
154
- return {'category': id2label[pred_idx], 'confidence': probs[0][pred_idx].item()}
155
-
156
- def run_test_predictions(model, tokenizer, id2label: Dict[int, str]) -> None:
157
- test_samples = [""]
158
- print("TEST PREDICTIONS")
159
- for sample in test_samples:
160
- result = predict_single(sample, model, tokenizer, id2label)
161
- print(f"\n{sample} → {result['category']} ({result['confidence']*100:.1f}%)")
162
-
163
- def main() -> None:
164
- logger.info("Loading pipeline...")
165
- ticket_dataframe, categories = load_dataset('/kaggle/input/datasets/adedayoadebayo23/support-ticket/support_tickets_realistic.csv')
166
- ticket_dataframe, label2id, id2label = create_labels(ticket_dataframe, categories)
167
- ticket_train, ticket_test, category_train, category_test = split_dataset(ticket_dataframe)
168
- model, tokenizer = load_model_and_tokenizer(len(categories), label2id, id2label)
169
- train_dataset, test_dataset = create_datasets(ticket_train, ticket_test, category_train, category_test, tokenizer)
170
- trainer = train_model(model, train_dataset, test_dataset)
171
- accuracy = evaluate_model(trainer, test_dataset, category_test, categories)
172
- push_to_huggingface(model, tokenizer, repo_name="BERTweet-Support-Ticket-Classifier")
173
- run_test_predictions(model, tokenizer, id2label)
174
- logger.info(f"COMPLETED | Accuracy: {accuracy*100:.2f}%")
175
- if __name__ == "__main__":
176
- main()