From 34ddedd68cc6322e0da78481d159d1c03f3fef81 Mon Sep 17 00:00:00 2001 From: ByUnal Date: Thu, 11 Jan 2024 00:20:46 +0300 Subject: [PATCH] Notebooks and results have been added. --- README.md | 7 +- notebooks/hyperoptbert_training.py | 406 +++++++++++++++++++++++++++++ results/acc-f1_scores.png | Bin 0 -> 26358 bytes results/params.txt | 63 +++++ 4 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 notebooks/hyperoptbert_training.py create mode 100644 results/acc-f1_scores.png create mode 100644 results/params.txt diff --git a/README.md b/README.md index 5fb66b6..c01401b 100755 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Overall, since data and targets are unique, the presented model in this study is ## Setup -Install the requirements. I've added torch to requirements.txt but you can prefer to install by yourself according to different cuda version and resources. +Install the requirements. I've added torch to requirements.txt, but you can prefer to install by yourself according to different cuda version and resources. ```commandline pip install -r requirements.txt ``` @@ -19,6 +19,11 @@ pip install -r requirements.txt ## Run the Code I've concluded hyperparameter tuning by using optuna, and therefore main.py fixed accordingly. Also, you can train standalone model by using *train_loop()* +## Results +The results that we obtained our experiments as below: +![plot](./results/acc-f1_scores.png) + +You can also see the best parameters for the models after hyperparameter optimization in *results/params.txt* ## Acknowledgement Currently, I've prepared the paper of this project besides including data collection steps. However, we're doing an additional novel experiments on this topic. So, paper link/details will be shared as soon as the paper is published. diff --git a/notebooks/hyperoptbert_training.py b/notebooks/hyperoptbert_training.py new file mode 100644 index 0000000..41a9e6e --- /dev/null +++ b/notebooks/hyperoptbert_training.py @@ -0,0 +1,406 @@ +# -*- coding: utf-8 -*- +"""hyperoptbert-newer-training.ipynb + +Automatically generated by Colaboratory. + +Original file is located at + https://colab.research.google.com/drive/1P4RT9W1rjk6qtuwCnV4aH9nWpieyHEeN +""" + +# !pip install transformers optuna nltk scikit-learn pandas + +import re +import string +import numpy as np +import pandas as pd +from tqdm import tqdm + +import nltk +nltk.download('stopwords') +nltk.download('wordnet') +nltk.download('omw-1.4') + +from nltk.corpus import stopwords +from nltk.stem import WordNetLemmatizer + +stop_words = set(stopwords.words('english')) +stop_words.add('subject') +stop_words.add('http') + +def remove_stopwords(text): + return " ".join([word for word in str(text).split() if word not in stop_words]) + +lemmatizer = WordNetLemmatizer() +def lemmatize_words(text): + return " ".join([lemmatizer.lemmatize(word) for word in text.split()]) + + +import torch +from torch.utils.data import TensorDataset +from torch.utils.data import DataLoader, RandomSampler, SequentialSampler +from torch.optim import AdamW, SGD, RMSprop + +from transformers import AutoModelForSequenceClassification, AutoTokenizer, get_linear_schedule_with_warmup +import optuna + + +from sklearn.metrics import f1_score, accuracy_score + +import warnings +warnings.filterwarnings("ignore") + +import gc + +gc.collect() +torch.cuda.empty_cache() + +import random, os + +rs = 2 +seed_val = rs +random.seed(seed_val) +np.random.seed(seed_val) +os.environ['PYTHONHASHSEED'] = str(seed_val) +torch.manual_seed(seed_val) +torch.cuda.manual_seed_all(seed_val) +torch.backends.cudnn.deterministic = True +torch.backends.cudnn.benchmark = False + +device = torch.device("cuda" if torch.cuda.is_available() else "cpu") +device + +df = pd.read_csv("cmp711_5class.csv") +df = df.reset_index(drop=True) +df.head() + +df.shape + +# Check how many labels are there in the dataset +unique_labels = df.label.unique().tolist() + +# Map each label into its id representation and vice versa +labels_to_ids = {k: v for v, k in enumerate(sorted(unique_labels))} +ids_to_labels = {v: k for v, k in enumerate(sorted(unique_labels))} + +labels_to_ids + +def preprocessing(text): + text = re.sub('[%s]' % re.escape(string.punctuation), '' , text) + text = re.sub('[^A-Za-z0-9]+',' ', text) + text = text.replace("\t", " ") + text = text.replace("\n", " ") + text = re.sub(' +', ' ', text) # remove extra whitespaces + text = remove_stopwords(text) + text = text.lower() + text = lemmatize_words(text) + + return text + +df["text"] = df["text"].apply(preprocessing) +df["label"] = df["label"].apply(lambda x: labels_to_ids[x]) +df.head() + +def createBertDataset(df, tokenizer, max_length=256): + encoded_data_train = tokenizer.batch_encode_plus( + df.text.values.tolist(), + add_special_tokens=True, + return_attention_mask=True, + truncation=True, + pad_to_max_length=True, + max_length=max_length, + return_tensors='pt' + ) + + input_ids_train = encoded_data_train['input_ids'] + attention_masks_train = encoded_data_train['attention_mask'] + labels_train = torch.tensor(df.label.values) + + return TensorDataset(input_ids_train, attention_masks_train, labels_train) + +df_train, df_val, df_test = np.split(df.sample(frac=1, random_state=rs), [int(.70 * len(df)), int(.80 * len(df))]) +df_train.shape, df_val.shape, df_test.shape + +# Function to calculate the accuracy of our predictions vs labels +def flat_accuracy(preds, labels): + pred_flat = np.argmax(preds, axis=1).flatten() + labels_flat = labels.flatten() + + # accuracy_score(pred_flat, labels_flat) + return np.sum(pred_flat == labels_flat) / len(labels_flat) + +def flat_accuracy(preds, labels): + pred_flat = np.argmax(preds, axis=1).flatten() + labels_flat = labels.flatten() + + return f1_score(pred_flat, labels_flat, average='macro') + +def train_loop(model, optimizer, BATCH_SIZE, EPOCHS, PATIENCE): + + train_dataloader = DataLoader(train_dataset, sampler=RandomSampler(train_dataset), batch_size = BATCH_SIZE) + + # put device into GPU + model = model.to(device) + + scheduler = get_linear_schedule_with_warmup(optimizer, + num_warmup_steps=0, + num_training_steps=len(train_dataloader)*EPOCHS) + + last_loss = 100 + patience = 0 + for epoch in range(EPOCHS): + + # print out active_run + # print("Epoch: %s\n" % (epoch + 1)) + + model.train() + loss_train_total = 0 + acc_train_total = 0 + + loop = tqdm(enumerate(train_dataloader), leave=False, total=len(train_dataloader)) + for step, batch in loop: + + # clear previously calculated gradients (Zero the gradients to start fresh next time.) + optimizer.zero_grad() + + batch = [r.to(device) for r in batch] + input_ids, attention_mask, labels = batch + outputs = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels) + + # Calculate loss & backpropagation + loss = outputs[0] + loss_train_total += loss.item() + loss.backward() + + # Calculate accuracy + logits = outputs[1] + # print(logits) + classes = torch.argmax(logits, dim=1) + acc_train_total += torch.mean((classes == labels).float()) + + # Clip the norm of the gradients to 1.0. + # This is to help prevent the "exploding gradients" problem. + # torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) + + optimizer.step() + scheduler.step() + + # Show progress while training + loop.set_description(f'Epoch = {epoch+1}/{EPOCHS}, training_loss: {(loss.item()/len(batch)):.3f}') + + train_loss = loss_train_total / len(train_dataloader) + + if train_loss >= last_loss: + patience += 1 + + if patience == PATIENCE: + print("Early Stopping!\n") + with open("es-log.txt", "a+") as es: + es.write(f"{MODEL_NAME} - stopped at {epoch} epoch\n") + + return model + + else: + patience = 0 + + last_loss = train_loss + + + ## Validation + model.eval() + + val_dataloader = DataLoader(val_dataset, sampler = SequentialSampler(val_dataset), batch_size = 32) + + loss_val_total = 0 + total_eval_accuracy = 0 + predictions, true_vals = [], [] + + # print("\nValidating...") + for batch in tqdm(val_dataloader, total = len(val_dataloader), leave=False): + + batch = tuple(b.to(device) for b in batch) + + input_ids, attention_mask, labels = batch + + with torch.no_grad(): + outputs = model(input_ids, attention_mask, labels) + + loss = outputs[0] + logits = outputs[1] + loss_val_total += loss.item() + + logits = logits.detach().cpu().numpy() + label_ids = labels.cpu().numpy() + + total_eval_accuracy += flat_accuracy(logits, label_ids) + + if epoch == EPOCHS-1: + print(f'Training Loss: {train_loss: .3f}') + print(f'Train Acc.: {acc_train_total / len(train_dataloader)}') + + # Report the final accuracy for this validation run. + val_acc_avg = total_eval_accuracy / len(val_dataloader) + loss_val_avg = loss_val_total / len(val_dataloader) + + print('Val. Average loss: {:.3f}'.format(loss_val_avg)) + print('Val. Average Acc.: {:.3f}\n'.format(val_acc_avg)) + + return model + +def evaluate(model, test_dataset): + + model.eval() + + test_dataloader = DataLoader(test_dataset, + sampler = SequentialSampler(test_dataset), + batch_size = 32) + + loss_val_total = 0 + predictions, true_vals = [], [] + + for batch in tqdm(test_dataloader): + + batch = tuple(b.to(device) for b in batch) + + input_ids, attention_mask, labels = batch + + with torch.no_grad(): + outputs = model(input_ids, attention_mask, labels) + + loss = outputs[0] + logits = outputs[1] + loss_val_total += loss.item() + + logits = logits.detach().cpu().numpy() + label_ids = labels.cpu().numpy() + predictions.append(logits) + true_vals.append(label_ids) + + loss_val_avg = loss_val_total/len(test_dataloader) + + predictions = np.concatenate(predictions, axis=0) + preds_flat = np.argmax(predictions, axis=1).flatten() + + true_vals = np.concatenate(true_vals, axis=0) + labels_flat = true_vals.flatten() + + f1 = f1_score(preds_flat, labels_flat, average='macro') + acc = accuracy_score(preds_flat, labels_flat) + + return loss_val_avg, f1, acc + +class BertModel(torch.nn.Module): + def __init__(self, checkpoint, unique_labels): + super(BertModel, self).__init__() + self.bert = AutoModelForSequenceClassification.from_pretrained(checkpoint, + num_labels = len(unique_labels), + output_attentions=False, + output_hidden_states=False) + + def forward(self, input_ids, attention_mask, labels=None): + output = self.bert(input_ids=input_ids, attention_mask=attention_mask, labels=labels, return_dict=False) + return output + + def save(self, path="model"): + self.bert.save_pretrained(f"./{path}") + +import torch.optim as optim +def objective(trial): + gc.collect() + torch.cuda.empty_cache() + + raw_model = BertModel(MODEL_NAME, unique_labels) + print(f"{MODEL_NAME} - {trial.number} is training...") + + EPOCHS = trial.suggest_int("EPOCHS", low=4, high=7) + BATCH_SIZE = trial.suggest_categorical('BATCH_SIZE', [16, 32, 48, 64]) + LR = trial.suggest_categorical("LR", [1e-3, 3e-3, 3e-4, 1e-5, 3e-5, 5e-5]) + WD = trial.suggest_categorical("WD", [1e-4, 1e-5, 2e-5]) + OPT = trial.suggest_categorical("OPT", ["AdamW", "SGD", "RMSprop"]) + + optimizer = getattr(optim, OPT)(raw_model.parameters(), lr = LR, weight_decay = WD) + + parameters = { + "model": raw_model, + "optimizer" : optimizer, + "BATCH_SIZE" : BATCH_SIZE, + "EPOCHS" : EPOCHS, + "PATIENCE": 2 + } + + trained_model = train_loop(**parameters) + loss, f1, acc = evaluate(trained_model, test_dataset) + + if f1 > 0.63: + trained_model.save(f"./{MODEL_NAME}-{trial.number}") + + return f1 + +model_names = ["distilbert-base-uncased", "albert-base-v2", "huawei-noah/TinyBERT_General_6L_768D", "roberta-base", + "bert-base-uncased", "google/electra-base-discriminator", "YituTech/conv-bert-base"] + +for model in model_names[5:]: + MODEL_NAME = model + + tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME) + + # Create datasets For BERT + train_dataset = createBertDataset(df_train, tokenizer) + val_dataset = createBertDataset(df_val, tokenizer) + test_dataset = createBertDataset(df_test, tokenizer) + + # We want to maximize the f1 + study = optuna.create_study(study_name='airbert-hyperopt', + direction='maximize', + sampler=optuna.samplers.TPESampler(seed=rs)) + + # Optimize the objective using 50 different trials + study.optimize(objective, n_trials=50) + + with open("param_new.txt", "a+") as file: + trial = study.best_trial + file.write(f"Model Name: {MODEL_NAME}\n") + file.write(f"Best Score: {trial.value}\n") + file.write("Best Params: \n") + for key, value in trial.params.items(): + file.write(" {}: {}\n".format(key, value)) + file.write("*"*60) + file.write("\n") + + del train_dataset, val_dataset, test_dataset, tokenizer, MODEL_NAME + +"""- I realized in DistilBert training, Model overtfits the training data up to %93 accuracy score however it generalizes badly. +- Also, torch.clip_norm function demolishes the model success rate, it shows that additional alghoritmhs are unnecessar for bert base models. + +## Save model +""" + +# model.bert.save_pretrained("./f35-bert-uncased") + +tokenizer = AutoTokenizer.from_pretrained("YituTech/conv-bert-base") +test_dataset = createBertDataset(df_test, tokenizer) + +model_list = [dir for dir in os.listdir("/home/YituTech") if "bert" in dir] +model_list + +for mdl in model_list: + print(f"*** {mdl} ***") + load_model = BertModel("/home/YituTech/"+mdl, unique_labels) + load_model = load_model.to(device) + + test_loss, test_f1, test_acc = evaluate(load_model, test_dataset) + + print(f'Test loss: {test_loss}') + print(f'F1 Score (Weighted): {test_f1}') + print(f'Acc Score: {test_acc}') + print("-------------") + +# load_model = BertModel("bert-base-uncased-41", unique_labels) +# load_model = load_model.to(device) +# evaluate(load_model, test_dataset) + +# test_loss, test_f1, test_acc = evaluate(load_model, test_dataset) + +# print(f'Test loss: {test_loss}') +# print(f'F1 Score (Weighted): {test_f1}') +# print(f'Acc Score: {test_acc}') + diff --git a/results/acc-f1_scores.png b/results/acc-f1_scores.png new file mode 100644 index 0000000000000000000000000000000000000000..ca324d2aaf81fc188581fe480170170c8bc2aa75 GIT binary patch literal 26358 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 literal 0 HcmV?d00001 diff --git a/results/params.txt b/results/params.txt new file mode 100644 index 0000000..572b16d --- /dev/null +++ b/results/params.txt @@ -0,0 +1,63 @@ +Model Name: distilbert-base-uncased +Best Score: 0.6430863652840643 +Best Params: + EPOCHS: 5 + BATCH_SIZE: 32 + LR: 5e-05 + WD: 0.0001 + OPT: RMSprop +************************************************************ +Model Name: albert-base-v2 +Best Score: 0.6370035931881839 +Best Params: + EPOCHS: 5 + BATCH_SIZE: 48 + LR: 5e-05 + WD: 0.0001 + OPT: AdamW +************************************************************ +Model Name: huawei-noah/TinyBERT_General_6L_768D +Best Score: 0.6499193438968445 +Best Params: + EPOCHS: 7 + BATCH_SIZE: 16 + LR: 3e-05 + WD: 0.0001 + OPT: AdamW +************************************************************ +Model Name: roberta-base +Best Score: 0.6491600098598747 +Best Params: + EPOCHS: 5 + BATCH_SIZE: 48 + LR: 5e-05 + WD: 0.0001 + OPT: AdamW +************************************************************ +bert-base-uncased +Best Score: 0.6548374336934382 +Best Params: + EPOCHS: 5 + BATCH_SIZE: 16 + LR: 3e-05 + WD: 0.0001 + OPT: AdamW +************************************************************ +Model Name: google/electra-base-discriminator +Best Score: 0.6513194910894985 +Best Params: + EPOCHS: 7 + BATCH_SIZE: 64 + LR: 5e-05 + WD: 0.0001 + OPT: AdamW +************************************************************ +Model Name: YituTech/conv-bert-base +Best Score: 0.6431987265042431 +Best Params: + EPOCHS: 5 + BATCH_SIZE: 16 + LR: 5e-05 + WD: 0.0001 + OPT: AdamW +************************************************************