test / rmit_hackathon_2026 /predict.py
0ewik's picture
Upload folder using huggingface_hub
34e621c verified
Raw History Blame Contribute Delete
4.78 kB
"""
Script du doan (Inference) cho RMIT Hackathon 2026.
Chay tren test.csv (6,000 mau) bang cac fold models da luu va xuat submission.csv chuan.
"""
import os
import glob
import argparse
import numpy as np
import pandas as pd
import torch
from torch.utils.data import DataLoader
from transformers import AutoTokenizer, AutoModelForSequenceClassification, AutoConfig
from tqdm import tqdm
from src.dataset import PromptDataset
from src.preprocessing import clean_and_deobfuscate_text
ID2LABEL = {0: "BENIGN", 1: "JAILBREAK", 2: "PROMPT_INJECTION"}
def predict_2026(
models_dir: str = "../models_2026",
test_file: str = "./data/test.csv" if os.path.exists("./data/test.csv") else r"D:\Code\rmit\data\Data-rmit2026\test.csv",
output_file: str = "submission.csv",
batch_size: int = 32,
max_length: int = 256,
):
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"[Device] Dang su dung: {device}")
if not os.path.exists(test_file):
raise FileNotFoundError(f"Khong tim thay test.csv tai: {test_file}")
df_test = pd.read_csv(test_file)
print(f"[Data] So mau test: {len(df_test)}")
df_test["clean_text"] = df_test["text"].apply(clean_and_deobfuscate_text)
# Tim cac checkpoint .pt
ckpt_files = sorted(glob.glob(os.path.join(models_dir, "**", "*.pt"), recursive=True))
if not ckpt_files:
# Fallback tim trong ../models
ckpt_files = sorted(glob.glob(os.path.join("../models", "**", "*.pt"), recursive=True))
if not ckpt_files:
raise FileNotFoundError(f"Khong tim thay checkpoint .pt nao trong {models_dir}")
print(f"[Models] Tim thay {len(ckpt_files)} checkpoints:")
for f in ckpt_files:
print(f" - {os.path.basename(f)}")
# Lay tokenizer tu model dau tien hoac xlm-roberta-base / mdeberta
model_name = "FacebookAI/xlm-roberta-base" if "xlm" in ckpt_files[0].lower() else "microsoft/mdeberta-v3-base"
tokenizer = AutoTokenizer.from_pretrained(model_name)
test_ds = PromptDataset(df_test["clean_text"].values, tokenizer=tokenizer, max_length=max_length)
test_loader = DataLoader(test_ds, batch_size=batch_size, shuffle=False, num_workers=0)
all_fold_probs = []
for ckpt_path in ckpt_files:
fold_name = os.path.basename(ckpt_path)
print(f"\n[Inference] Dang suy luan checkpoint: {fold_name}...")
# Kiem tra so luong labels tu checkpoint state_dict
state_dict = torch.load(ckpt_path, map_location=device)
classifier_keys = [k for k in state_dict.keys() if "classifier.weight" in k or "classifier.out_proj.weight" in k]
num_labels = state_dict[classifier_keys[0]].shape[0] if classifier_keys else 3
config = AutoConfig.from_pretrained(model_name, num_labels=num_labels)
model = AutoModelForSequenceClassification.from_pretrained(model_name, config=config).to(device)
model.load_state_dict(state_dict)
model.eval()
fold_probs = []
with torch.no_grad():
for batch in tqdm(test_loader, desc=f" {fold_name}", leave=False):
logits = model(
batch["input_ids"].to(device),
attention_mask=batch["attention_mask"].to(device),
).logits
probs = torch.softmax(logits, dim=-1).cpu().numpy()
fold_probs.extend(probs)
all_fold_probs.append(np.array(fold_probs))
del model
torch.cuda.empty_cache()
# Ensemble
ensemble_probs = np.mean(all_fold_probs, axis=0)
if ensemble_probs.shape[1] == 3:
pred_indices = np.argmax(ensemble_probs, axis=1)
pred_labels = [ID2LABEL[idx] for idx in pred_indices]
else:
# 2 classes fallback
p_jailbreak = ensemble_probs[:, 1]
pred_labels = np.where(p_jailbreak >= 0.5, "JAILBREAK", "BENIGN")
sub = pd.DataFrame({
"id": df_test["id"],
"label": pred_labels
})
sub.to_csv(output_file, index=False)
print(f"\n[Done] Da tao file nop bai: {output_file} ({len(sub)} dong)")
print(f"[Done] Phan bo du doan:")
print(sub["label"].value_counts(normalize=True))
return sub
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="RMIT Hackathon 2026 -- Predict")
parser.add_argument("--models_dir", default="../models_2026")
parser.add_argument("--test_file", default=r"D:\Code\rmit\data\Data-rmit2026\test.csv")
parser.add_argument("--output", default="submission.csv")
parser.add_argument("--batch", type=int, default=32)
args = parser.parse_args()
predict_2026(
models_dir=args.models_dir,
test_file=args.test_file,
output_file=args.output,
batch_size=args.batch,
)