AgroChat / scripts /train_embedder.py
mutoni1923's picture
Deploy AgroChat without large model weights
ee140b6
Raw History Blame Contribute Delete
2.3 kB
"""Fine-tune a Sentence-Transformer on agriculture QA pairs.
Usage:
python scripts/train_embedder.py --output models/agri-minilm
MultipleNegativesRankingLoss treats every other answer in the batch as a
negative for the current question. No explicit negative sampling needed.
"""
from __future__ import annotations
import argparse
import csv
from pathlib import Path
from sentence_transformers import (
InputExample,
SentenceTransformer,
evaluation,
losses,
)
from torch.utils.data import DataLoader
BASE_DIR = Path(__file__).resolve().parent.parent
DATA = BASE_DIR / "data"
def load_pairs(path: Path) -> list[tuple[str, str]]:
with open(path, newline="", encoding="utf-8") as f:
rows = list(csv.DictReader(f))
return [(r["question"].strip(), r["answer"].strip()) for r in rows]
def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("--base_model",
default="sentence-transformers/all-MiniLM-L6-v2")
ap.add_argument("--epochs", type=int, default=3)
ap.add_argument("--batch_size", type=int, default=64)
ap.add_argument("--output", default=str(BASE_DIR / "models" / "agri-minilm"))
args = ap.parse_args()
train_pairs = load_pairs(DATA / "qa_train.csv")
val_pairs = load_pairs(DATA / "qa_val.csv")
print(f"[info] train={len(train_pairs)} val={len(val_pairs)}")
examples = [InputExample(texts=[q, a]) for q, a in train_pairs]
loader = DataLoader(examples, shuffle=True, batch_size=args.batch_size)
model = SentenceTransformer(args.base_model)
loss = losses.MultipleNegativesRankingLoss(model)
evaluator = evaluation.InformationRetrievalEvaluator(
queries={i: q for i, (q, _) in enumerate(val_pairs)},
corpus={i: a for i, (_, a) in enumerate(val_pairs)},
relevant_docs={i: {i} for i in range(len(val_pairs))},
name="agri-val",
)
steps = max(1, len(loader))
warmup = max(1, int(0.1 * steps * args.epochs))
model.fit(
train_objectives=[(loader, loss)],
evaluator=evaluator,
epochs=args.epochs,
warmup_steps=warmup,
output_path=args.output,
show_progress_bar=True,
)
print(f"[done] saved fine-tuned embedder to {args.output}")
if __name__ == "__main__":
main()