Text Classification
setfit
Safetensors
sentence-transformers
mpnet
generated_from_setfit_trainer
text-embeddings-inference
Instructions to use peter2000/setfit-vulnerability-groups with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- setfit
How to use peter2000/setfit-vulnerability-groups with setfit:
from setfit import SetFitModel model = SetFitModel.from_pretrained("peter2000/setfit-vulnerability-groups") preds = model.predict(["i loved the spiderman movie!", "pineapple on pizza is the worst"]) print(preds) - sentence-transformers
How to use peter2000/setfit-vulnerability-groups with sentence-transformers:
from sentence_transformers import SentenceTransformer model = SentenceTransformer("peter2000/setfit-vulnerability-groups") sentences = [ "The weather is lovely today.", "It's so sunny outside!", "He drove to the stadium." ] embeddings = model.encode(sentences) similarities = model.similarity(embeddings, embeddings) print(similarities.shape) # [3, 3] - Notebooks
- Google Colab
- Kaggle
Add training script: SetFit one-vs-rest multi-label classifier on GIZ vulnerability data
Browse files- train_setfit.py +134 -0
train_setfit.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
os.environ.setdefault("USE_TF", "0")
|
| 3 |
+
os.environ.setdefault("USE_TORCH", "1")
|
| 4 |
+
os.environ.setdefault("TOKENIZERS_PARALLELISM", "false")
|
| 5 |
+
|
| 6 |
+
import json
|
| 7 |
+
import time
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
import pandas as pd
|
| 11 |
+
import trackio
|
| 12 |
+
|
| 13 |
+
def _trackio_safe(fn):
|
| 14 |
+
def wrapper(*a, **k):
|
| 15 |
+
try:
|
| 16 |
+
return fn(*a, **k)
|
| 17 |
+
except Exception as e:
|
| 18 |
+
print(f"trackio.{fn.__name__} failed (non-fatal): {e}")
|
| 19 |
+
return wrapper
|
| 20 |
+
trackio.log = _trackio_safe(trackio.log)
|
| 21 |
+
trackio.init = _trackio_safe(trackio.init)
|
| 22 |
+
trackio.finish = _trackio_safe(trackio.finish)
|
| 23 |
+
|
| 24 |
+
from datasets import Dataset
|
| 25 |
+
from huggingface_hub import HfApi
|
| 26 |
+
from sklearn.metrics import f1_score
|
| 27 |
+
from sklearn.model_selection import train_test_split
|
| 28 |
+
from setfit import SetFitModel, TrainingArguments, Trainer
|
| 29 |
+
|
| 30 |
+
SMOKE = os.environ.get("SMOKE", "0") == "1"
|
| 31 |
+
PARQUET_URL = "https://huggingface.co/datasets/GIZ/vulnerability_training_data_full/resolve/refs%2Fconvert%2Fparquet/default/train/0000.parquet"
|
| 32 |
+
LABELS = [
|
| 33 |
+
"Agricultural communities", "Coastal communities", "Ethnic, racial or other minorities",
|
| 34 |
+
"Fishery communities", "Informal sector workers", "Members of indigenous and local communities",
|
| 35 |
+
"Migrants and displaced persons", "Older persons", "Other", "Persons living in poverty",
|
| 36 |
+
"Persons with disabilities", "Persons with pre-existing health conditions",
|
| 37 |
+
"Residents of drought-prone regions", "Rural populations", "Sexual minorities (LGBTQI+)",
|
| 38 |
+
"Urban populations", "Women and other genders",
|
| 39 |
+
]
|
| 40 |
+
REPO_ID = "peter2000/setfit-vulnerability-groups"
|
| 41 |
+
|
| 42 |
+
def load_data():
|
| 43 |
+
df = pd.read_parquet(PARQUET_URL)
|
| 44 |
+
assert len(df) == 475, f"expected 475 rows, got {len(df)}"
|
| 45 |
+
Y = df[LABELS].values.astype(np.int64)
|
| 46 |
+
nlab = Y.sum(1)
|
| 47 |
+
idx_tr, idx_te = train_test_split(
|
| 48 |
+
np.arange(len(df)), test_size=0.2, random_state=42, stratify=np.minimum(nlab, 3)
|
| 49 |
+
)
|
| 50 |
+
return df, Y, np.asarray(idx_tr), np.asarray(idx_te)
|
| 51 |
+
|
| 52 |
+
def ece(conf, correct, n_bins=15):
|
| 53 |
+
conf = np.asarray(conf, dtype=np.float64)
|
| 54 |
+
corr = np.asarray(correct, dtype=np.float64)
|
| 55 |
+
bins = np.linspace(0.0, 1.0, n_bins + 1)
|
| 56 |
+
e = 0.0
|
| 57 |
+
for lo, hi in zip(bins[:-1], bins[1:]):
|
| 58 |
+
m = (conf > lo) & (conf <= hi)
|
| 59 |
+
if m.sum() > 0:
|
| 60 |
+
e += m.mean() * abs(corr[m].mean() - conf[m].mean())
|
| 61 |
+
return float(e)
|
| 62 |
+
|
| 63 |
+
def evaluate(Y_true, P_pred, threshold=0.5):
|
| 64 |
+
pred = (P_pred >= threshold).astype(int)
|
| 65 |
+
per_label = f1_score(Y_true, pred, average=None, zero_division=0)
|
| 66 |
+
macro = float(f1_score(Y_true, pred, average="macro", zero_division=0))
|
| 67 |
+
micro = float(f1_score(Y_true, pred, average="micro", zero_division=0))
|
| 68 |
+
conf = np.where(pred == 1, P_pred, 1.0 - P_pred)
|
| 69 |
+
corr = (pred == Y_true).astype(np.float64)
|
| 70 |
+
return {
|
| 71 |
+
"macro_f1": macro,
|
| 72 |
+
"micro_f1": micro,
|
| 73 |
+
"ece": ece(conf, corr),
|
| 74 |
+
"subset_accuracy": float(((pred == Y_true).all(axis=1)).mean()),
|
| 75 |
+
"per_label_f1": {LABELS[i]: round(float(per_label[i]), 4) for i in range(len(LABELS))},
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
def main():
|
| 79 |
+
df, Y, idx_tr, idx_te = load_data()
|
| 80 |
+
texts = df["text"].tolist()
|
| 81 |
+
X_tr = [texts[i] for i in idx_tr]
|
| 82 |
+
X_te = [texts[i] for i in idx_te]
|
| 83 |
+
Y_tr, Y_te = Y[idx_tr], Y[idx_te]
|
| 84 |
+
print(f"train={len(X_tr)} test={len(X_te)} labels={len(LABELS)}")
|
| 85 |
+
|
| 86 |
+
if SMOKE:
|
| 87 |
+
X_tr, Y_tr = X_tr[:40], Y_tr[:40]
|
| 88 |
+
X_te, Y_te = X_te[:10], Y_te[:10]
|
| 89 |
+
|
| 90 |
+
model = SetFitModel.from_pretrained(
|
| 91 |
+
"sentence-transformers/paraphrase-mpnet-base-v2",
|
| 92 |
+
multi_target_strategy="one-vs-rest",
|
| 93 |
+
labels=LABELS,
|
| 94 |
+
)
|
| 95 |
+
model.model_body.max_seq_length = 256
|
| 96 |
+
|
| 97 |
+
train_ds = Dataset.from_dict({
|
| 98 |
+
"text": X_tr,
|
| 99 |
+
"label": [list(map(int, y)) for y in Y_tr],
|
| 100 |
+
})
|
| 101 |
+
|
| 102 |
+
args = TrainingArguments(
|
| 103 |
+
batch_size=16,
|
| 104 |
+
num_epochs=1,
|
| 105 |
+
num_iterations=20 if not SMOKE else 2,
|
| 106 |
+
seed=42,
|
| 107 |
+
)
|
| 108 |
+
trainer = Trainer(model=model, args=args, train_dataset=train_ds)
|
| 109 |
+
trainer.train()
|
| 110 |
+
|
| 111 |
+
P_te = np.asarray(model.predict_proba(X_te))
|
| 112 |
+
metrics = evaluate(Y_te, P_te)
|
| 113 |
+
print(json.dumps(metrics, indent=2))
|
| 114 |
+
|
| 115 |
+
trackio.init(project="vulnerability-multilabel-classifier", space_id="peter2000/vulnerability-multilabel-classifier-trackio")
|
| 116 |
+
trackio.log({"setfit_macro_f1": metrics["macro_f1"], "setfit_micro_f1": metrics["micro_f1"], "setfit_ece": metrics["ece"]}, step=1)
|
| 117 |
+
trackio.log({f"setfit_f1/{k}": v for k, v in metrics["per_label_f1"].items()}, step=1)
|
| 118 |
+
|
| 119 |
+
trainer.push_to_hub(repo_id=REPO_ID)
|
| 120 |
+
api = HfApi(token=os.environ.get("HF_TOKEN"))
|
| 121 |
+
api.upload_file(
|
| 122 |
+
path_or_fileobj=json.dumps(metrics, indent=2).encode(),
|
| 123 |
+
path_in_repo="metrics.json",
|
| 124 |
+
repo_id=REPO_ID,
|
| 125 |
+
repo_type="model",
|
| 126 |
+
commit_message="Add evaluation metrics (macro-F1, micro-F1, per-label F1, ECE)",
|
| 127 |
+
)
|
| 128 |
+
trackio.finish()
|
| 129 |
+
print("DONE")
|
| 130 |
+
|
| 131 |
+
if __name__ == "__main__":
|
| 132 |
+
t0 = time.time()
|
| 133 |
+
main()
|
| 134 |
+
print(f"elapsed {time.time()-t0:.0f}s")
|