KingsGuard / scripts /train_l1.py
Abdulahad79's picture
Initial commit - KingsGuard Security Framework (Clean Build)
5846193
Raw
History Blame Contribute Delete
5.98 kB
"""
KingsGuard L1 Fine-Tuning Script
Trains a DeBERTa-v3-base model on MPDD.csv via LoRA/PEFT.
Splits data 90/10 β€” saves test split to MPDD_test.csv for benchmark use.
Output adapter: ./kingsguard_l1_final
"""
import json
import pandas as pd
import torch
from sklearn.model_selection import train_test_split
from datasets import Dataset
from transformers import (
AutoTokenizer,
AutoModelForSequenceClassification,
TrainingArguments,
Trainer,
DataCollatorWithPadding,
)
from peft import LoraConfig, get_peft_model, TaskType
import numpy as np
from sklearn.metrics import accuracy_score, f1_score
# ─────────────────────────────────────────────────────────────
# 1. Load & Split Dataset
# ─────────────────────────────────────────────────────────────
CSV_PATH = "injecagent_data/MPDD.csv"
TEST_CSV = "injecagent_data/MPDD_test.csv"
print(f"[Dataset] Loading {CSV_PATH} ...")
df = pd.read_csv(CSV_PATH, header=0, names=["text", "label"])
df = df.dropna(subset=["text", "label"])
df["text"] = df["text"].astype(str).str.strip()
df["label"] = df["label"].astype(int)
# 90 / 10 split β€” stratified to preserve class balance
train_df, test_df = train_test_split(
df, test_size=0.10, random_state=42, stratify=df["label"]
)
print(f"[Dataset] Train: {len(train_df)} | Test: {len(test_df)}")
print(f"[Dataset] Label distribution (train):\n{train_df['label'].value_counts()}")
# Save test split for benchmark use in app.py
test_df.to_csv(TEST_CSV, index=False)
print(f"[Dataset] Test split saved to {TEST_CSV}")
# ─────────────────────────────────────────────────────────────
# 2. Model & Tokeniser
# ─────────────────────────────────────────────────────────────
MODEL_ID = "microsoft/deberta-v3-base"
id2label = {0: "BENIGN", 1: "MALICIOUS"}
label2id = {"BENIGN": 0, "MALICIOUS": 1}
print(f"[Model] Loading tokeniser from {MODEL_ID} ...")
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
def tokenize(examples):
return tokenizer(
examples["text"],
truncation=True,
padding="max_length",
max_length=256,
)
train_ds = Dataset.from_pandas(train_df.reset_index(drop=True))
test_ds = Dataset.from_pandas(test_df.reset_index(drop=True))
print("[Dataset] Tokenising ...")
train_ds = train_ds.map(tokenize, batched=True)
test_ds = test_ds.map(tokenize, batched=True)
# ─────────────────────────────────────────────────────────────
# 3. Base Model + LoRA
# ─────────────────────────────────────────────────────────────
print("[Model] Loading base model ...")
model = AutoModelForSequenceClassification.from_pretrained(
MODEL_ID,
num_labels=2,
id2label=id2label,
label2id=label2id,
ignore_mismatched_sizes=True,
)
peft_config = LoraConfig(
task_type=TaskType.SEQ_CLS,
r=16,
lora_alpha=32,
lora_dropout=0.1,
target_modules=["query_proj", "value_proj"],
)
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()
# ─────────────────────────────────────────────────────────────
# 4. Training
# ─────────────────────────────────────────────────────────────
def compute_metrics(eval_pred):
logits, labels = eval_pred
preds = np.argmax(logits, axis=-1)
return {
"accuracy": accuracy_score(labels, preds),
"f1": f1_score(labels, preds, average="weighted"),
}
# DeBERTa + PEFT is incompatible with fp16 AMP (gradient scaler crashes on
# relative-position embeddings). Use bf16 on GPU instead β€” works on T4/V100/A100.
# Falls back to plain fp32 on CPU.
use_bf16 = torch.cuda.is_available() and torch.cuda.is_bf16_supported()
use_fp16 = torch.cuda.is_available() and not use_bf16
training_args = TrainingArguments(
output_dir="./kingsguard_l1_results",
learning_rate=2e-4,
per_device_train_batch_size=16,
per_device_eval_batch_size=32,
num_train_epochs=3,
weight_decay=0.01,
save_strategy="epoch",
eval_strategy="epoch",
load_best_model_at_end=True,
metric_for_best_model="f1",
fp16=use_fp16,
bf16=use_bf16,
logging_steps=200,
report_to="none",
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_ds,
eval_dataset=test_ds,
processing_class=tokenizer,
data_collator=DataCollatorWithPadding(tokenizer),
compute_metrics=compute_metrics,
)
print("[Training] Starting ...")
trainer.train()
# ─────────────────────────────────────────────────────────────
# 5. Save PEFT adapter
# ─────────────────────────────────────────────────────────────
ADAPTER_DIR = "./kingsguard_l1_final"
model.save_pretrained(ADAPTER_DIR)
tokenizer.save_pretrained(ADAPTER_DIR)
print(f"[Training] Adapter saved to {ADAPTER_DIR}")
print("[Training] Run merge_l1.py next to create the final merged model.")