SwarajSolanke-turtle commited on
Commit
ead1d01
·
verified ·
1 Parent(s): 3e94ed3

training script simcse

Browse files
Files changed (1) hide show
  1. 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()