Downloads · 30 days
0
kirilsss/Phishing_analyzer_LoRA
Phishing_analyzer_LoRA is a machine learning model from kirilsss. Use it for the machine learning task on the model card, and read the license before you ship it in a product.
QLoRA adapters for Qwen2.5-Instruct (3B and 7B variants) that classify emails as phishing or legitimate and return a structured threat analysis (threat type, risk level, indicators, mitigation recommendations) as JSON.
Downloads · 30 days
0
Access
Public
Updated Sep 4, 2026
Repo size
152 MB
Likes
0
Public
Click a slice to open those files.
.safetensors141 MB · 86%
From the Hugging Face model README
QLoRA adapters for Qwen2.5-Instruct (3B and 7B variants) that classify emails as phishing or legitimate and return a structured threat analysis (threat type, risk level, indicators, mitigation recommendations) as JSON.
This is a portfolio / learning project focused on practical LoRA fine-tuning skills, evaluated as rigorously as the available compute and sample sizes allow — see the Limitations section before drawing strong conclusions from any single number below.
.
├── 3b-adapter/
│ ├── adapter_config.json
│ ├── adapter_model.safetensors
│ ├── tokenizer.json
│ ├── tokenizer_config.json
│ └── chat_template.jinja
├── 7b-adapter/
│ ├── adapter_config.json
│ ├── adapter_model.safetensors
│ ├── tokenizer.json
│ ├── tokenizer_config.json
│ └── chat_template.jinja
├── assets/
│ ├── pooled_recall_base_vs_trained.png
│ ├── confusion_matrix_3b.png
│ └── confusion_matrix_7b.png
└── README.md
| 3B adapter | 7B adapter | |
|---|---|---|
| Base model | unsloth/Qwen2.5-3B-Instruct-bnb-4bit | unsloth/Qwen2.5-7B-Instruct-bnb-4bit |
| Adapter type | QLoRA (PEFT LORA) | QLoRA (PEFT LORA) |
| Rank (r) | 8 | 8 |
| Alpha | 16 | 16 |
| Dropout | 0 | 0 |
| Target modules | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj | same |
| Adapter file size | ~58 MB | ~77 MB |
| Trained with | Unsloth (QLoRA), Google Colab (T4) | Unsloth (QLoRA) |
| Epochs | 2 | 2 |
| Context length | 2048 | 2048 |
| Effective batch size | 8 | 8 |
| LR scheduler | cosine, warmup_ratio=0.03 | cosine, warmup_ratio=0.03 |
| Weight decay | 0.001 | 0.001 |
| Train/eval split | train_test_split(test_size=0.1, seed=3407) | same |
| PEFT version | 0.20.0 | 0.20.0 |
Note on chat template: chat_template.jinja is the unmodified Qwen2.5 ChatML template — the system prompt used during training/eval is not baked in and must be passed explicitly (see below).
datasetv3_2048.jsonl — 2,259 rows after cleaning.Four models were evaluated on the same two external (non-training-distribution) test sets, using an identical, paired evaluation harness:
58b9c22ff94898bc68df95722874547d), confirming the comparison is over the exact same items — this is what makes the paired McNemar test below valid.FAILURE_IS_WRONG = True: any parse failure on the base (no-adapter) models counts as an error rather than being excluded, so baseline numbers aren't artificially inflated.
| Model | Recall (Test B) | FPR (Test B) | Recall (Test C) | Pooled accuracy (n=75) |
|---|---|---|---|---|
| base 3B (no adapter) | 0.960 | 0.240 | 0.920 | 0.880 |
| 3B adapter | 0.960 | 0.000 | 0.880 | 0.947 |
| base 7B (no adapter) | 0.920 | 0.000 | 0.560 | 0.827 |
| 7B adapter | 1.000 | 0.080 | 0.880 | 0.933 |
The base 3B model misclassified 6 of 25 legitimate emails as phishing (FPR = 0.24) on Test B. After fine-tuning, FPR drops to 0. This is the single clearest, most consistent effect of the adapter across both model sizes.
| 3B adapter | 7B adapter |
|---|---|
![]() | ![]() |
| Comparison | Δ accuracy | 95% CI | p-value | Significant? |
|---|---|---|---|---|
| base 3B → 3B adapter (fine-tuning effect, 3B) | +6.7 pp | [−0.1, +13.4] pp | 0.125 | No |
| base 7B → 7B adapter (fine-tuning effect, 7B) | +10.7 pp | [+1.9, +19.4] pp | 0.039 | Yes (marginal) |
| base 3B → base 7B (size effect, no fine-tuning) | −5.3 pp | [−15.7, +5.1] pp | 0.455 | No |
| 3B adapter → 7B adapter (size effect, with fine-tuning) | −1.3 pp | [−8.2, +5.6] pp | 1.000 | No |
Honest read of these numbers, not a sales pitch:
Manual review of the discordant pairs identified four false negatives, broken down as:
Confidence scores on incorrect verdicts were observed to run high in some cases — i.e. the models are not well calibrated, and confidence should not be treated as a reliable proxy for correctness. Downstream use should not threshold purely on confidence_score without independent calibration.
from unsloth import FastLanguageModel
import torch, json
# Choose one:
BASE_MODEL = "unsloth/Qwen2.5-3B-Instruct-bnb-4bit" # or "unsloth/Qwen2.5-7B-Instruct-bnb-4bit"
ADAPTER_DIR = "3b-adapter" # or "7b-adapter"
model, tokenizer = FastLanguageModel.from_pretrained(
model_name=BASE_MODEL,
max_seq_length=2048,
load_in_4bit=True,
)
model.load_adapter(ADAPTER_DIR)
FastLanguageModel.for_inference(model)
messages = [
{
"role": "system",
"content": (
"You are an advanced AI security analyst specialized in email threat detection. "
"Analyze the provided email and respond with a JSON object containing: "
"is_phishing, confidence_score, threat_type, risk_level, indicators, "
"mitigation_recommendations, analysis_summary."
),
},
{"role": "user", "content": "<email text here>"},
]
inputs = tokenizer.apply_chat_template(
messages, tokenize=True, add_generation_prompt=True, return_tensors="pt"
).to(model.device)
outputs = model.generate(inputs, max_new_tokens=500, do_sample=False)
response = tokenizer.decode(outputs[0][inputs.shape[-1]:], skip_special_tokens=True)
print(json.loads(response))
Note: the system prompt above is not baked into chat_template.jinja — it must be passed explicitly, for both adapters. Production use should parse the model's JSON output defensively (regex fallback for malformed fields), rather than assuming json.loads() will always succeed on greedy-decoded output.
{
"is_phishing": true,
"confidence_score": 0.96,
"threat_type": "business_email_compromise_invoice_fraud",
"risk_level": "5",
"indicators": [
{"category": "...", "finding": "...", "severity": "4", "explanation": "..."}
],
"mitigation_recommendations": {
"immediate_actions": ["..."],
"preventive_measures": ["..."],
"reporting_guidance": "..."
},
"analysis_summary": "..."
}
Included: adapter weights (3B and 7B), tokenizer files, chat template, this README, evaluation charts.
Not included:
datasetv3_2048.jsonl (training data) — not redistributed here; see Training Data section for the CEAS-08 sourceAdapters released under Apache 2.0. This inherits the base model's license terms — verify the current Qwen2.5 license on Hugging Face before commercial use (see Limitations). The CEAS-08 source dataset's own license was not independently re-verified for this repo; check the linked source before relying on it.