Sentence Similarity
sentence-transformers
Safetensors
distilbert
feature-extraction
dense
Generated from Trainer
dataset_size:3810
loss:MultipleNegativesRankingLoss
Eval Results (legacy)
text-embeddings-inference
Instructions to use SwarajSolanke-turtle/make-model-SimCSE-embedding with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- sentence-transformers
How to use SwarajSolanke-turtle/make-model-SimCSE-embedding with sentence-transformers:
from sentence_transformers import SentenceTransformer model = SentenceTransformer("SwarajSolanke-turtle/make-model-SimCSE-embedding") sentences = [ "bmw ix", "bmw ix", "bmw x7", "bmw i5" ] embeddings = model.encode(sentences) similarities = model.similarity(embeddings, embeddings) print(similarities.shape) # [4, 4] - Notebooks
- Google Colab
- Kaggle
training script simcse
Browse files- train_simcse.py +132 -0
train_simcse.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Unsupervised SimCSE on the FW make/model strings.
|
| 2 |
+
|
| 3 |
+
This is the simcse_script.ipynb pipeline pointed at our own data instead of
|
| 4 |
+
wiki1m/stsb. SimCSE's positive pair is the *same* sentence encoded twice -- the
|
| 5 |
+
two views differ only through dropout -- and MultipleNegativesRankingLoss
|
| 6 |
+
supplies the negatives from the rest of the batch.
|
| 7 |
+
|
| 8 |
+
Run prepare_data.py first.
|
| 9 |
+
|
| 10 |
+
python simcse/train_simcse.py # defaults
|
| 11 |
+
python simcse/train_simcse.py --epochs 10 --batch-size 30
|
| 12 |
+
"""
|
| 13 |
+
|
| 14 |
+
import argparse
|
| 15 |
+
import json
|
| 16 |
+
import logging
|
| 17 |
+
from datetime import datetime
|
| 18 |
+
from pathlib import Path
|
| 19 |
+
from xml.parsers.expat import model
|
| 20 |
+
from datasets import Dataset
|
| 21 |
+
from sentence_transformers import SentenceTransformer
|
| 22 |
+
from sentence_transformers.evaluation import EmbeddingSimilarityEvaluator
|
| 23 |
+
from sentence_transformers.losses import MultipleNegativesRankingLoss
|
| 24 |
+
from sentence_transformers.models import Pooling, Transformer
|
| 25 |
+
from sentence_transformers.similarity_functions import SimilarityFunction
|
| 26 |
+
from sentence_transformers.trainer import SentenceTransformerTrainer
|
| 27 |
+
from sentence_transformers.training_args import SentenceTransformerTrainingArguments
|
| 28 |
+
|
| 29 |
+
HERE = Path(__file__).resolve().parent
|
| 30 |
+
DATA = HERE / "data"
|
| 31 |
+
|
| 32 |
+
logging.basicConfig(format="%(asctime)s - %(message)s", level=logging.INFO)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def read_jsonl(path: Path) -> list[dict]:
|
| 36 |
+
with path.open() as f:
|
| 37 |
+
return [json.loads(line) for line in f]
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def parse_args():
|
| 41 |
+
p = argparse.ArgumentParser()
|
| 42 |
+
p.add_argument("--model-name", default="distilbert/distilbert-base-uncased")
|
| 43 |
+
p.add_argument("--batch-size", type=int, default=30)
|
| 44 |
+
p.add_argument("--epochs", type=int, default=10)
|
| 45 |
+
# make/model strings are a handful of tokens; 32 is already generous
|
| 46 |
+
p.add_argument("--max-seq-length", type=int, default=32)
|
| 47 |
+
p.add_argument("--learning-rate", type=float, default=3e-5)
|
| 48 |
+
p.add_argument("--output-dir", default=None)
|
| 49 |
+
return p.parse_args()
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def main():
|
| 53 |
+
args = parse_args()
|
| 54 |
+
out = Path(args.output_dir) if args.output_dir else HERE / "output" / (
|
| 55 |
+
"simcse-make-model-{}-bs{}-{}".format(
|
| 56 |
+
args.model_name.split("/")[-1],
|
| 57 |
+
args.batch_size,
|
| 58 |
+
datetime.now().strftime("%Y-%m-%d-%H-%M-%S"),
|
| 59 |
+
)
|
| 60 |
+
)
|
| 61 |
+
|
| 62 |
+
# ---- model ----------------------------------------------------------
|
| 63 |
+
word_embedding_model = Transformer(args.model_name, max_seq_length=args.max_seq_length)
|
| 64 |
+
pooling_model = Pooling(word_embedding_model.get_sentence_embedding_dimension(), "mean")
|
| 65 |
+
model = SentenceTransformer(modules=[word_embedding_model, pooling_model])
|
| 66 |
+
|
| 67 |
+
# ---- data -----------------------------------------------------------
|
| 68 |
+
train_rows = read_jsonl(DATA / "train.jsonl")
|
| 69 |
+
train_dataset = Dataset.from_list(train_rows)
|
| 70 |
+
|
| 71 |
+
eval_rows = read_jsonl(DATA / "eval.jsonl")
|
| 72 |
+
|
| 73 |
+
evaluator = EmbeddingSimilarityEvaluator(
|
| 74 |
+
sentences1=[r["sentence1"] for r in eval_rows],
|
| 75 |
+
sentences2=[r["sentence2"] for r in eval_rows],
|
| 76 |
+
scores=[r["score"] for r in eval_rows],
|
| 77 |
+
main_similarity=SimilarityFunction.COSINE,
|
| 78 |
+
name="make-model-dev",
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
logging.info("train sentences=%d eval pairs=%d", len(train_dataset), len(eval_rows))
|
| 82 |
+
|
| 83 |
+
loss = MultipleNegativesRankingLoss(model)
|
| 84 |
+
|
| 85 |
+
logging.info("performance before training")
|
| 86 |
+
before = evaluator(model)
|
| 87 |
+
logging.info("%s", before)
|
| 88 |
+
|
| 89 |
+
# ---- train ----------------------------------------------------------
|
| 90 |
+
training_args = SentenceTransformerTrainingArguments(
|
| 91 |
+
output_dir=str(out),
|
| 92 |
+
num_train_epochs=args.epochs,
|
| 93 |
+
per_device_train_batch_size=args.batch_size,
|
| 94 |
+
warmup_ratio=0.1,
|
| 95 |
+
learning_rate=args.learning_rate,
|
| 96 |
+
eval_strategy="steps",
|
| 97 |
+
eval_steps=0.1,
|
| 98 |
+
logging_steps=0.05,
|
| 99 |
+
save_strategy="no",
|
| 100 |
+
fp16=True,
|
| 101 |
+
# identical strings in one batch become false negatives under MNRL
|
| 102 |
+
batch_sampler="no_duplicates",
|
| 103 |
+
report_to=[],
|
| 104 |
+
)
|
| 105 |
+
|
| 106 |
+
trainer = SentenceTransformerTrainer(
|
| 107 |
+
model=model,
|
| 108 |
+
args=training_args,
|
| 109 |
+
train_dataset=train_dataset,
|
| 110 |
+
evaluator=evaluator,
|
| 111 |
+
loss=loss,
|
| 112 |
+
)
|
| 113 |
+
trainer.train()
|
| 114 |
+
|
| 115 |
+
after = evaluator(model)
|
| 116 |
+
logging.info("performance after training")
|
| 117 |
+
logging.info("%s", after)
|
| 118 |
+
|
| 119 |
+
final = out.parent / (out.name + "-final")
|
| 120 |
+
model.save_pretrained(str(final))
|
| 121 |
+
logging.info("saved -> %s", final)
|
| 122 |
+
|
| 123 |
+
key = "make-model-dev_spearman_cosine"
|
| 124 |
+
print("\n=== dev spearman (cosine) ===")
|
| 125 |
+
print(f" before : {before.get(key):.4f}")
|
| 126 |
+
print(f" after : {after.get(key):.4f}")
|
| 127 |
+
print(f" model : {final}")
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
if __name__ == "__main__":
|
| 132 |
+
main()
|