如何使用BERT对相似句子进行聚类

对于ElMo、FastText和Word2Vec,我是通过平均句子内的词嵌入,并使用HDBSCAN/KMeans聚类来对相似句子进行分组的。

一个很好的实现示例可以在以下短文中看到:http://ai.intelligentonlinetools.com/ml/text-clustering-word-embedding-machine-learning/

我想使用BERT(使用来自hugging face的BERT Python包)做同样的事情,但我对如何提取原始的词/句向量以输入到聚类算法中不太熟悉。我知道BERT可以输出句子表示——那么我该如何实际从句子中提取原始向量呢?

任何信息都会有所帮助。


回答:

正如Subham Kumar 提到的,可以使用这个Python 3库来计算句子相似度:https://github.com/UKPLab/sentence-transformers

该库有几个代码示例来执行聚类:

fast_clustering.py

"""这是一个关于在大规模数据集上执行聚类的更复杂的示例。这个示例在一个大的句子集中找到局部社区,即高度相似的句子组。你可以自由配置什么被认为是相似的阈值。一个高的阈值只会找到极度相似的句子,一个较低的阈值会找到更多不太相似的句子。第二个参数是'min_community_size':只有至少包含一定数量句子的社区才会被返回。寻找社区的方法非常快,对于聚类50k个句子只需要5秒(加上嵌入计算)。在这个示例中,我们从Quora下载了一大组问题,然后在这个集合中找到相似的问句。"""from sentence_transformers import SentenceTransformer, utilimport osimport csvimport time# 用于计算句子嵌入的模型。我们使用一个为相似问题检测训练的模型model = SentenceTransformer('paraphrase-MiniLM-L6-v2')# 我们下载Quora重复问题数据集(https://www.quora.com/q/quoradata/First-Quora-Dataset-Release-Question-Pairs)# 并在其中找到相似的问句url = "http://qim.fs.quoracdn.net/quora_duplicate_questions.tsv"dataset_path = "quora_duplicate_questions.tsv"max_corpus_size = 50000 # 我们将我们的语料库限制为前50k个问题# 检查数据集是否存在。如果不存在,则下载并提取# 如有需要下载数据集if not os.path.exists(dataset_path):    print("下载数据集")    util.http_get(url, dataset_path)# 从文件中获取所有唯一句子corpus_sentences = set()with open(dataset_path, encoding='utf8') as fIn:    reader = csv.DictReader(fIn, delimiter='\t', quoting=csv.QUOTE_MINIMAL)    for row in reader:        corpus_sentences.add(row['question1'])        corpus_sentences.add(row['question2'])        if len(corpus_sentences) >= max_corpus_size:            breakcorpus_sentences = list(corpus_sentences)print("编码语料库。这可能需要一些时间")corpus_embeddings = model.encode(corpus_sentences, batch_size=64, show_progress_bar=True, convert_to_tensor=True)print("开始聚类")start_time = time.time()#两个参数需要调整:#min_cluster_size: 只考虑至少有25个元素的聚类#threshold: 考虑余弦相似度大于阈值的句子对为相似clusters = util.community_detection(corpus_embeddings, min_community_size=25, threshold=0.75)print("聚类完成,耗时 {:.2f} 秒".format(time.time() - start_time))#打印所有聚类的前3个和后3个元素for i, cluster in enumerate(clusters):    print("\n聚类 {}, #{} 个元素 ".format(i+1, len(cluster)))    for sentence_id in cluster[0:3]:        print("\t", corpus_sentences[sentence_id])    print("\t", "...")    for sentence_id in cluster[-3:]:        print("\t", corpus_sentences[sentence_id])

kmeans.py

"""这是一个关于句子嵌入的简单应用:聚类句子被映射到句子嵌入,然后应用k-means聚类。"""from sentence_transformers import SentenceTransformerfrom sklearn.cluster import KMeansembedder = SentenceTransformer('paraphrase-MiniLM-L6-v2')# 带有示例句子的语料库corpus = ['一个人在吃食物。',          '一个人在吃一块面包。',          '一个人在吃意大利面。',          '女孩在抱一个婴儿。',          '婴儿被女人抱起来',          '一个人在骑马。',          '一个人在骑一匹白马在一个封闭的场地上。',          '一只猴子在玩鼓。',          '有人穿着大猩猩服装在玩一套鼓。',          '一只猎豹在追赶它的猎物。',          '一只猎豹在田野上追赶猎物。'          ]corpus_embeddings = embedder.encode(corpus)# 执行kmeans聚类num_clusters = 5clustering_model = KMeans(n_clusters=num_clusters)clustering_model.fit(corpus_embeddings)cluster_assignment = clustering_model.labels_clustered_sentences = [[] for i in range(num_clusters)]for sentence_id, cluster_id in enumerate(cluster_assignment):    clustered_sentences[cluster_id].append(corpus[sentence_id])for i, cluster in enumerate(clustered_sentences):    print("聚类 ", i+1)    print(cluster)    print("")

agglomerative.py

"""这是一个关于句子嵌入的简单应用:聚类句子被映射到句子嵌入,然后应用带阈值的聚合聚类。"""from sentence_transformers import SentenceTransformerfrom sklearn.cluster import AgglomerativeClusteringimport numpy as npembedder = SentenceTransformer('paraphrase-MiniLM-L6-v2')# 带有示例句子的语料库corpus = ['一个人在吃食物。',          '一个人在吃一块面包。',          '一个人在吃意大利面。',          '女孩在抱一个婴儿。',          '婴儿被女人抱起来',          '一个人在骑马。',          '一个人在骑一匹白马在一个封闭的场地上。',          '一只猴子在玩鼓。',          '有人穿着大猩猩服装在玩一套鼓。',          '一只猎豹在追赶它的猎物。',          '一只猎豹在田野上追赶猎物。'          ]corpus_embeddings = embedder.encode(corpus)# 将嵌入标准化为单位长度corpus_embeddings = corpus_embeddings /  np.linalg.norm(corpus_embeddings, axis=1, keepdims=True)# 执行kmeans聚类clustering_model = AgglomerativeClustering(n_clusters=None, distance_threshold=1.5) #, affinity='cosine', linkage='average', distance_threshold=0.4)clustering_model.fit(corpus_embeddings)cluster_assignment = clustering_model.labels_clustered_sentences = {}for sentence_id, cluster_id in enumerate(cluster_assignment):    if cluster_id not in clustered_sentences:        clustered_sentences[cluster_id] = []    clustered_sentences[cluster_id].append(corpus[sentence_id])for i, cluster in clustered_sentences.items():    print("聚类 ", i+1)    print(cluster)    print("")

Related Posts

Keras Dense层输入未被展平

这是我的测试代码: from keras import…

无法将分类变量输入随机森林

我有10个分类变量和3个数值变量。我在分割后直接将它们…

如何在Keras中对每个输出应用Sigmoid函数?

这是我代码的一部分。 model = Sequenti…

如何选择类概率的最佳阈值?

我的神经网络输出是一个用于多标签分类的预测类概率表: …

在Keras中使用深度学习得到不同的结果

我按照一个教程使用Keras中的深度神经网络进行文本分…

‘MatMul’操作的输入’b’类型为float32,与参数’a’的类型float64不匹配

我写了一个简单的TensorFlow代码,但不断遇到T…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注