Skip to content

Commit 85dab5c

Browse files
chg: Add per-class metrics and best checkpoint selection to severity trainer, add source field to dataset
- Severity trainer: compute_metrics now reports per-class precision/recall/F1 for Low/Medium/High/Critical. Best model selected by accuracy instead of eval_loss, save_total_limit bumped to 3. - Dataset generation: add source field (cvelistv5, github, pysec, cnvd, csaf_*) to each vulnerability entry. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 47e82ea commit 85dab5c

2 files changed

Lines changed: 30 additions & 4 deletions

File tree

vulntrain/datasets/create_dataset.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ def __call__(self) -> Generator[dict[str, Any], None, None]:
210210
if not vuln_data.get("description"):
211211
continue
212212

213+
vuln_data["source"] = source
213214
yield vuln_data
214215

215216
count += 1

vulntrain/trainers/classify_severity.py

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import numpy as np
88
from codecarbon import EmissionsTracker
99
from datasets import load_dataset
10+
from sklearn.metrics import classification_report, f1_score
1011
from transformers import (
1112
AutoModelForSequenceClassification,
1213
AutoTokenizer,
@@ -30,12 +31,34 @@
3031
SEVERITY_MAPPING = {"Low": 0, "Medium": 1, "High": 2, "Critical": 3}
3132

3233

34+
ID2LABEL = {v: k for k, v in SEVERITY_MAPPING.items()}
35+
36+
3337
def compute_metrics(eval_pred):
34-
"""Compute accuracy and F1-score for model evaluation."""
35-
metric = evaluate.load("accuracy")
38+
"""Compute accuracy and per-class precision/recall/F1."""
39+
accuracy = evaluate.load("accuracy")
3640
logits, labels = eval_pred
3741
predictions = np.argmax(logits, axis=-1)
38-
return metric.compute(predictions=predictions, references=labels)
42+
43+
acc = accuracy.compute(predictions=predictions, references=labels)
44+
macro_f1 = f1_score(labels, predictions, average="macro", zero_division=0)
45+
46+
report = classification_report(
47+
labels,
48+
predictions,
49+
target_names=[ID2LABEL[i] for i in range(len(SEVERITY_MAPPING))],
50+
output_dict=True,
51+
zero_division=0,
52+
)
53+
54+
metrics = {**acc, "f1_macro": macro_f1}
55+
for label_name in SEVERITY_MAPPING:
56+
if label_name in report:
57+
metrics[f"{label_name}_precision"] = report[label_name]["precision"]
58+
metrics[f"{label_name}_recall"] = report[label_name]["recall"]
59+
metrics[f"{label_name}_f1"] = report[label_name]["f1-score"]
60+
61+
return metrics
3962

4063

4164
# Define severity mapping function
@@ -181,8 +204,10 @@ def tokenize_function(elem):
181204
weight_decay=0.01,
182205
logging_dir="./logs",
183206
logging_steps=10,
184-
save_total_limit=2,
207+
save_total_limit=3,
185208
load_best_model_at_end=True,
209+
metric_for_best_model="accuracy",
210+
greater_is_better=True,
186211
use_cache=use_cache,
187212
hub_model_id=repo_id,
188213
)

0 commit comments

Comments
 (0)