Views
No views yet
label: 1 = AI, 0 = Human) using microsoft/deberta-v3-large as the base model.microsoft/deberta-v3-largeBCEWithLogitsLosspeft)adapter/ – LoRA weights saved with peft_model.save_pretrained(...)merged_model/ – fully merged model (base + LoRA) for standalone usethreshold.json – chosen deployment threshold and validation F1calibration.json – temperature scaling parameters and calibration metricsresults.json – hyperparameters, validation threshold search, test metricstraining_log_history.csv – raw Trainer log historypredictions_calib.csv – calibration-set probabilities and labelspredictions_test.csv – test probabilities and labelsfigures/ – training and evaluation plotsREADME.md – this file| Metric | Value |
|---|---|
| AUROC | 0.9985 |
| Average Precision (AP) | 0.9985 |
| F1 | 0.9812 |
| Accuracy | 0.9814 |
| Precision (AI) | 0.9902 |
| Recall (AI) | 0.9724 |
| Precision (Human) | 0.9728 |
| Recall (Human) | 0.9904 |










1from transformers import AutoTokenizer, AutoModelForSequenceClassification
2from peft import PeftModel
3import torch
4import json
5
6base_model_id = "microsoft/deberta-v3-large"
7adapter_id = "stealthcode/ai-detection" # or local: "./adapter"
8
9tokenizer = AutoTokenizer.from_pretrained(base_model_id)
10
11base_model = AutoModelForSequenceClassification.from_pretrained(
12 base_model_id,
13 num_labels=1, # single logit for BCEWithLogitsLoss
14)
15model = PeftModel.from_pretrained(base_model, adapter_id)
16model.eval()1# load threshold
2with open("threshold.json") as f:
3 thr = json.load(f)["threshold"] # 0.8697
4
5def predict_proba(texts):
6 enc = tokenizer(
7 texts,
8 padding=True,
9 truncation=True,
10 max_length=512,
11 return_tensors="pt",
12 )
13 with torch.no_grad():
14 logits = model(**enc).logits.squeeze(-1)
15 probs = torch.sigmoid(logits)
16 return probs.cpu().numpy()
17
18def predict_label(texts, threshold=thr):
19 probs = predict_proba(texts)
20 return (probs >= threshold).astype(int)
21
22# example
23texts = ["Some example text to classify"]
24probs = predict_proba(texts)
25labels = predict_label(texts)
26print(probs, labels) # label 1 = AI, 0 = Human1from transformers import AutoTokenizer, AutoModelForSequenceClassification
2import torch, json
3
4model_dir = "./merged_model"
5tokenizer = AutoTokenizer.from_pretrained(model_dir)
6model = AutoModelForSequenceClassification.from_pretrained(model_dir)
7model.eval()
8
9with open("threshold.json") as f:
10 thr = json.load(f)["threshold"] # 0.8697
11
12def predict_proba(texts):
13 enc = tokenizer(texts, padding=True, truncation=True, max_length=512, return_tensors="pt")
14 with torch.no_grad():
15 logits = model(**enc).logits.squeeze(-1)
16 probs = torch.sigmoid(logits)
17 return probs.cpu().numpy()1import json
2with open("calibration.json") as f:
3 T = json.load(f)["temperature"] # e.g., 1.4437
4
5def predict_proba_calibrated(texts):
6 enc = tokenizer(texts, padding=True, truncation=True, max_length=512, return_tensors="pt")
7 with torch.no_grad():
8 logits = model(**enc).logits.squeeze(-1)
9 probs = torch.sigmoid(logits / T)
10 return probs.cpu().numpy()r=32, alpha=128, dropout=0.0query_proj, key_proj, value_projbf16=Trueoptim="adamw_torch_fused"lr_scheduler_type="cosine_with_restarts"num_train_epochs=2per_device_train_batch_size=8, gradient_accumulation_steps=4max_grad_norm=0.50.8697 was chosen as the max-F1 point on the calibration set.
You can adjust it if you prefer fewer false positives or fewer false negatives.