| from cybersecurity_knowledge_graph.event_arg_role_dataloader import EventArgumentRoleDataset |
| from cybersecurity_knowledge_graph.utils import arg_2_role |
|
|
| import os |
| from transformers import AutoTokenizer |
| import optuna |
| from sklearn.model_selection import StratifiedKFold |
| from sklearn.model_selection import cross_val_score |
| from sklearn.metrics import make_scorer, f1_score |
| from sklearn.ensemble import VotingClassifier |
| from sklearn.linear_model import LogisticRegression |
| from sklearn.neural_network import MLPClassifier |
| from sklearn.svm import SVC |
| from joblib import dump, load |
| from sentence_transformers import SentenceTransformer |
| import numpy as np |
|
|
| embed_model = SentenceTransformer('all-MiniLM-L6-v2') |
|
|
| model_checkpoint = "ehsanaghaei/SecureBERT" |
|
|
| tokenizer = AutoTokenizer.from_pretrained(model_checkpoint, add_prefix_space=True) |
|
|
| classifiers = {} |
| folder_path = '/cybersecurity_knowledge_graph/arg_role_models' |
|
|
| for filename in os.listdir(os.getcwd() + folder_path): |
| if filename.endswith('.joblib'): |
| file_path = os.getcwd() + os.path.join(folder_path, filename) |
| clf = load(file_path) |
| arg = filename.split(".")[0] |
| classifiers[arg] = clf |
|
|
| """ |
| Function: fit() |
| Description: This function performs a machine learning task to train and evaluate classifiers for multiple argument roles. |
| It utilizes Optuna for hyperparameter optimization and creates a Voting Classifier. |
| The trained classifiers are saved as joblib files. |
| """ |
| def fit(): |
| for arg, roles in arg_2_role.items(): |
| if len(roles) > 1: |
|
|
| dataset = EventArgumentRoleDataset(path="./data/annotation/", tokenizer=tokenizer, arg=arg) |
| dataset.load_data() |
| dataset.train_val_test_split() |
|
|
|
|
| X = [datapoint["embedding"] for datapoint in dataset.data] |
| y = [roles.index(datapoint["label"]) for datapoint in dataset.data] |
|
|
|
|
| |
| |
| def objective(trial): |
|
|
| classifier_name = trial.suggest_categorical("classifier", ["voting"]) |
| if classifier_name == "voting": |
| svc_c = trial.suggest_float("svc_c", 1e-3, 1e3, log=True) |
| svc_kernel = trial.suggest_categorical("kernel", ['rbf']) |
| classifier_obj = VotingClassifier(estimators=[ |
| ('Logistic Regression', LogisticRegression()), |
| ('Neural Network', MLPClassifier(max_iter=500)), |
| ('Support Vector Machine', SVC(C=svc_c, kernel=svc_kernel)) |
| ], voting='hard') |
|
|
| f1_scorer = make_scorer(f1_score, average = "weighted") |
| stratified_kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) |
| cv_scores = cross_val_score(classifier_obj, X, y, cv=stratified_kfold, scoring=f1_scorer) |
| return cv_scores.mean() |
|
|
|
|
| study = optuna.create_study(direction="maximize") |
| study.optimize(objective, n_trials=20) |
| print(f"{arg} : {study.best_trial.values[0]}") |
|
|
| best_clf = VotingClassifier(estimators=[ |
| ('Logistic Regression', LogisticRegression()), |
| ('Neural Network', MLPClassifier(max_iter=500)), |
| ('Support Vector Machine', SVC(C=study.best_trial.params["svc_c"], kernel=study.best_trial.params["kernel"])) |
| ], voting='hard') |
|
|
| best_clf.fit(X, y) |
| dump(best_clf, f'{arg}.joblib') |
|
|
| """ |
| Function: get_arg_roles(event_args, doc) |
| Description: This function assigns argument roles to a list of event arguments within a document. |
| Inputs: |
| - event_args: A list of event argument dictionaries, each containing information about an argument. |
| - doc: A spaCy document representing the analyzed text. |
| Output: |
| - The input 'event_args' list with updated 'role' values assigned to each argument. |
| """ |
| def get_arg_roles(event_args, doc): |
| for arg in event_args: |
| if len(arg_2_role[arg["subtype"]]) > 1: |
| sent = next(filter(lambda x : arg["startOffset"] >= x.start_char and arg["endOffset"] <= x.end_char, doc.sents)) |
|
|
| sent_embed = embed_model.encode(sent.text) |
| arg_embed = embed_model.encode(arg["text"]) |
| embed = np.concatenate((sent_embed, arg_embed)) |
|
|
| arg_clf = classifiers[arg["subtype"]] |
| role_id = arg_clf.predict(embed.reshape(1, -1)) |
| role = arg_2_role[arg["subtype"]][role_id[0]] |
|
|
| arg["role"] = role |
| else: |
| arg["role"] = arg_2_role[arg["subtype"]][0] |
| return event_args |
|
|
|
|
|
|