SimCSE¶
Gao等人在SimCSE中提出了一种无需训练数据即可训练句子嵌入的简单方法。
其思路是对同一个句子进行两次编码。由于在变压器模型中使用了dropout,两个句子嵌入将位于稍微不同的位置。这些嵌入之间的距离将被最小化,而同一批次中其他句子嵌入的距离将被最大化(它们作为负样本)。
使用SentenceTransformers¶
SentenceTransformers实现了MultipleNegativesRankingLoss,这使得使用SimCSE进行训练变得简单:
from sentence_transformers import SentenceTransformer, InputExample
from sentence_transformers import models, losses
from torch.utils.data import DataLoader
# 使用CLS池化定义你的句子转换器模型
model_name = "distilroberta-base"
word_embedding_model = models.Transformer(model_name, max_seq_length=32)
pooling_model = models.Pooling(word_embedding_model.get_word_embedding_dimension())
model = SentenceTransformer(modules=[word_embedding_model, pooling_model])
# 定义一个包含句子的列表(1k - 100k个句子)
train_sentences = [
"你的句子集合",
"模型将自动添加噪声",
"并重新构建它",
"你应该至少提供1k个句子",
]
# 将训练句子转换为句子对
train_data = [InputExample(texts=[s, s]) for s in train_sentences]
# 数据加载器以批量处理你的数据
train_dataloader = DataLoader(train_data, batch_size=128, shuffle=True)
# 使用去噪自编码器损失
train_loss = losses.MultipleNegativesRankingLoss(model)
# 调用fit方法
model.fit(
train_objectives=[(train_dataloader, train_loss)], epochs=1, show_progress_bar=True
)
model.save("output/simcse-model")
从句子文件进行SimCSE训练¶
train_simcse_from_file.py 从提供的文本文件加载句子。预期文件中每行有一个句子。
SimCSE将使用这些句子进行训练。检查点每500步存储到输出文件夹。
训练示例¶
train_askubuntu_simcse.py - 展示了如何在AskUbuntu问题数据集上使用SimCSE进行训练的示例。
train_stsb_simcse.py - 此脚本使用100万个句子,并在STSbenchmark数据集上评估SimCSE。
消融研究¶
我们使用TSDAE论文中提出的评估设置。
使用mean pooling,max_seq_length=32,batch_size=128
基础模型 | AskUbuntu测试性能(MAP) |
---|---|
distilbert-base-uncased | 53.59 |
bert-base-uncased | 54.89 |
distilroberta-base | 56.16 |
roberta-base | 55.89 |
使用mean pooling,max_seq_length=32,distilroberta-base模型。
批次大小 | AskUbuntu测试性能(MAP) |
---|---|
128 | 56.16 |
256 | 56.63 |
512 | 56.69 |
使用max_seq_length=32,distilroberta-base模型,512批次大小。
池化模式 | AskUbuntu测试性能(MAP) |
---|---|
Mean pooling | 56.69 |
CLS pooling | 56.56 |
Max pooling | 52.91 |
注意: 这是在sentence-transformers中对SimCSE的重现。对于官方CT代码,请参见:princeton-nlp/SimCSE