claim-ai / src /train_multinli.py
MINOO LA
initial commit β€” clAIm v2.0 clean
cd91c77
Raw
History Blame Contribute Delete
4.85 kB
"""
train_multinli.py β€” v4 (clean fix)
Fine-tune DeBERTa-v3-base on MultiNLI.
Run on Google Colab T4 GPU.
"""
import numpy as np
from datasets import load_dataset
from transformers import (
AutoTokenizer,
AutoModelForSequenceClassification,
TrainingArguments,
Trainer,
)
from sklearn.metrics import f1_score
# ── Config ───────────────────────────────────────────────────────────────────
MODEL_NAME = "microsoft/deberta-v3-base"
OUTPUT_DIR = "content/drive/MyDrive/multinli_checkpoint"
MAX_LENGTH = 256
BATCH_SIZE = 16
EPOCHS = 3
LR = 1e-5
WARMUP_STEPS = 1000
LABEL2ID = {"entailment": 0, "neutral": 1, "contradiction": 2}
ID2LABEL = {v: k for k, v in LABEL2ID.items()}
# ── Load ─────────────────────────────────────────────────────────────────────
print("Loading MultiNLI...")
raw = load_dataset("multi_nli", split={
"train": "train",
"validation": "validation_matched",
})
print(f" Train : {len(raw['train'])} | Val : {len(raw['validation'])}")
# ── Tokenise ─────────────────────────────────────────────────────────────────
# KEY FIX: build labels inside tokenize AND use remove_columns to drop
# everything else β€” token_type_ids never enters the dataset this way.
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
def tokenize(batch):
enc = tokenizer(
batch["premise"],
batch["hypothesis"],
truncation=True,
max_length=MAX_LENGTH,
padding="max_length",
)
enc["labels"] = batch["label"] # carry label through
enc.pop("token_type_ids", None) # DeBERTa-v3 doesn't use this
return enc
print("Tokenising...")
dataset = raw.map(
tokenize,
batched=True,
batch_size=512,
remove_columns=raw["train"].column_names, # drops ALL original cols
)
dataset.set_format("torch", columns=["input_ids", "attention_mask", "labels"])
print(" Columns:", dataset["train"].column_names) # should be exactly 3
# ── Model ─────────────────────────────────────────────────────────────────────
print("Loading model...")
model = AutoModelForSequenceClassification.from_pretrained(
MODEL_NAME,
num_labels=3,
id2label=ID2LABEL,
label2id=LABEL2ID,
ignore_mismatched_sizes=True,
)
# ── Metrics ───────────────────────────────────────────────────────────────────
def compute_metrics(eval_pred):
logits, labels = eval_pred
preds = np.argmax(logits, axis=-1)
macro_f1 = f1_score(labels, preds, average="macro")
accuracy = (preds == labels).mean()
return {"macro_f1": macro_f1, "accuracy": accuracy}
# ── Training args ─────────────────────────────────────────────────────────────
training_args = TrainingArguments(
output_dir=OUTPUT_DIR,
num_train_epochs=EPOCHS,
per_device_train_batch_size=BATCH_SIZE,
per_device_eval_batch_size=BATCH_SIZE,
learning_rate=LR,
weight_decay=0.01,
warmup_steps=WARMUP_STEPS,
eval_strategy="epoch",
save_strategy="epoch",
load_best_model_at_end=True,
metric_for_best_model="macro_f1",
logging_steps=1000,
log_level="error",
log_level_replica="error",
fp16=True,
bf16=False,
report_to="none",
)
# ── Train ─────────────────────────────────────────────────────────────────────
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
eval_dataset=dataset["validation"],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
print("Starting training β€” ~2 hrs on Kaggle 2XT4 (fp16)...")
trainer.train()
# ── Save ──────────────────────────────────────────────────────────────────────
trainer.save_model(OUTPUT_DIR)
tokenizer.save_pretrained(OUTPUT_DIR)
print(f"\nDone! Checkpoint saved to {OUTPUT_DIR}")