Qwen2.5-14B-Instruct-epi
Qwen2.5-14B-Instruct-epi is a fine-tuned version of unsloth/Qwen2.5-14B-Instruct. It is specifically tailored for epidemiological text classification and structured information extraction regarding West Nile Virus (WNV).
The model classifies epidemiological reports into structured JSON formats containing metadata such as event dates, affected species, impacted countries, and specific alert classification levels.
Model details
- Base model:
unsloth/Qwen2.5-14B-Instruct - Fine-tuning framework: Unsloth &
TRL(SFTTrainer) - Optimization / quantization: Trained using 4-bit LoRA (QLoRA) adapters and pushed as merged 16-bit float (
save_method="merged_16bit"). - Target task: Fine-grained information extraction & classification of West Nile Virus news articles and surveillance reports into structured JSON.
- Output format: JSON.
Fine-tuning hyperparameters
- LoRA rank: 16
- LoRA alpha: 16
- LoRA target modules:
q_proj,k_proj,v_proj,o_proj,gate_proj,up_proj,down_proj - Max sequence length: 1024 tokens
- Epochs: 1
- Global batch size: 4 (per-device batch size 1 with gradient accumulation steps 4)
- Learning rate: 2e-4 (Linear scheduler, 5 warmup steps)
- Optimizer: 8-bit AdamW (
adamw_8bit) - Dataset size: 1,000 examples
Training results
The model was fine-tuned over 243 steps on a dataset of 1,000 samples. It demonstrated rapid convergence, hitting its optimal performance at step 207.
| Metric | Value |
|---|---|
| Initial training loss | 2.3895 |
| Best training loss | 0.0912 (Step 207) |
| Final training loss | 0.1506 |
| Total training steps | 243 |
Prompt template & task schema
The model uses a structured prompt to strictly enforce classification criteria, output schemas, and extraction rules.
instruction = """
You are an epidemiologist classifying West Nile virus articles.
Return ONE JSON object.
Article:
{article_text}
---
SCOPE RULE (VERY IMPORTANT):
Only consider West Nile virus (WNV).
If the article is about ANY other disease → classify as "other".
---
CLASSIFICATION RULES (apply in order):
1) If there are NO human or animal infections mentioned
(only mosquito traps/pools/surveillance, no infected humans/animals, research on climate change etc):
→ label = "other"
→ outbreak_detected = false
→ species_affected = []
→ STOP
2) If the article is a surveillance report, statistics table, or seasonal summary:
→ label = "epi_summary"
→ outbreak_detected = false
*CRITERIA*: This includes reports capturing multi-national data, seasonal comparisons, or tracking cumulative statistics across multiple countries.
*EXAMPLE*: "WNV in Europe 2022: EU countries reported 292 cases across Italy (228), Greece (59), and Austria (2)." This is an epi_summary
3) If there are confirmed or suspected active, localized spikes, unexpected cases, or emergency notifications:
→ label = "outbreak_alert"
→ outbreak_detected = true
*CRITERIA*: Tone features real-time concern, unexpected increases, or immediate localized threats in a country/region.
*EXAMPLE*: "In recent weeks, increasingly alarming news has spread about the increase in cases of West Nile Disease in our country. The cases reported in Italy by the National Reference Center for WND, at the Zooprophylactic Institute, have risen to 230..." This must be an outbreak_alert with outbreak_detected = true.
1) If there are NO human or animal infections mentioned
(only mosquito traps/pools/surveillance, no infected humans/animals):
→ classify = "other"
→ outbreak_detected = false
→ species_affected = []
→ STOP
2) If the article is a surveillance report, statistics, or seasonal summary:
→ classify = "epi_summary"
3) If there are confirmed or suspected human/animal cases:
→ classify = "outbreak_alert"
---
CRITICAL RULES:
- outbreak_detected = true ONLY if the text explicitly mentions cases, infections or outbreak.
- If only research, modelling, risk, or discussion → outbreak_detected = false
- Mosquito-only positivity WITHOUT human/animal cases is ALWAYS "other" → outbreak_detected = false
- ONLY extract information explicitly stated in the text.
- Do NOT infer, assume, or generalize.
- Do NOT guess countries or species if not explicitly mentioned.
- If unsure, return empty list [] and false.
- If no specific event date is mentioned in the text, set "event_date" to null.
- Reason must be maximum 10 words, do not exceed 10 words under any circumstance
Return ONLY valid JSON.
JSON:"""
Output JSON schema
{
"article_id": "string",
"label": "outbreak_alert" | "epi_summary" | "other",
"outbreak_detected": boolean,
"countries": ["string"],
"iso2_codes": ["string"],
"species_affected": ["human" | "equid" | "bird" | ...],
"event_date": "YYYY-MM-DD" | null,
"reasoning": "string (max 10 words)"
}
Usage
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id = "anjelinejeline/Qwen2.5-14B-Instruct-epi"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=torch.float16,
device_map="auto"
)
prompt_template = """
You are an epidemiologist classifying West Nile virus articles.
Return ONE JSON object.
Article:
{article_text}
---
SCOPE RULE (VERY IMPORTANT):
Only consider West Nile virus (WNV).
If the article is about ANY other disease → classify as "other".
---
CLASSIFICATION RULES (apply in order):
1) If there are NO human or animal infections mentioned
(only mosquito traps/pools/surveillance, no infected humans/animals, research on climate change etc):
→ label = "other"
→ outbreak_detected = false
→ species_affected = []
→ STOP
2) If the article is a surveillance report, statistics table, or seasonal summary:
→ label = "epi_summary"
→ outbreak_detected = false
*CRITERIA*: This includes reports capturing multi-national data, seasonal comparisons, or tracking cumulative statistics across multiple countries.
*EXAMPLE*: "WNV in Europe 2022: EU countries reported 292 cases across Italy (228), Greece (59), and Austria (2)." This is an epi_summary
3) If there are confirmed or suspected active, localized spikes, unexpected cases, or emergency notifications:
→ label = "outbreak_alert"
→ outbreak_detected = true
*CRITERIA*: Tone features real-time concern, unexpected increases, or immediate localized threats in a country/region.
*EXAMPLE*: "In recent weeks, increasingly alarming news has spread about the increase in cases of West Nile Disease in our country. The cases reported in Italy by the National Reference Center for WND, at the Zooprophylactic Institute, have risen to 230..." This must be an outbreak_alert with outbreak_detected = true.
1) If there are NO human or animal infections mentioned
(only mosquito traps/pools/surveillance, no infected humans/animals):
→ classify = "other"
→ outbreak_detected = false
→ species_affected = []
→ STOP
2) If the article is a surveillance report, statistics, or seasonal summary:
→ classify = "epi_summary"
3) If there are confirmed or suspected human/animal cases:
→ classify = "outbreak_alert"
---
CRITICAL RULES:
- outbreak_detected = true ONLY if the text explicitly mentions cases, infections or outbreak.
- If only research, modelling, risk, or discussion → outbreak_detected = false
- Mosquito-only positivity WITHOUT human/animal cases is ALWAYS "other" → outbreak_detected = false
- ONLY extract information explicitly stated in the text.
- Do NOT infer, assume, or generalize.
- Do NOT guess countries or species if not explicitly mentioned.
- If unsure, return empty list [] and false.
- If no specific event date is mentioned in the text, set "event_date" to null.
- Reason must be maximum 10 words, do not exceed 10 words under any circumstance
Return ONLY valid JSON.
JSON:"""
article = """
Seville, Spain - July 16, 2026. Health authorities in Andalusia have confirmed two new human cases of West Nile Virus in the province of Seville, resulting in one fatality. The regional health department reported that both individuals, residents of Coria del Río, were hospitalized last week after developing severe neurological symptoms. This brings the total number of localized infections in the province to three this month, sparking urgent vector control operations in the affected municipal zones.
"""
formatted_prompt = prompt_template.format(article_text=article)
inputs = tokenizer(formatted_prompt, return_tensors="pt").to("cuda")
outputs = model.generate(**inputs, max_new_tokens=150, temperature=0.1)
response = tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True)
print(response)
Expected output
{
"article_id": "spain_west_nile_2026",
"event_date": "2026-07-16",
"label": "outbreak_alert",
"outbreak_detected": true,
"countries": [
"Spain"
],
"iso2_codes": [
"ES"
],
"species_affected": [
"human"
],
"reasoning": "Human cases and death reported."
}
Uploaded fine-tuned model
- Developed by: Angela Fanelli
- Year: 2026
- License: apache-2.0
- Finetuned from model : unsloth/qwen2.5-14b-instruct-unsloth-bnb-4bit
This qwen2 model was trained 2x faster with Unsloth and Huggingface's TRL library.