语义是基于tex2vec文本向量化模型,通过计算文本向量之间的距离来实现的。向量搜索使用faiss来进行,搜索的结果通过设置相似度的阈值来判断是否属于某个意图,为了减少输出结果的错误率,建议把阈值尽量设置高一些,避免乱推荐/乱弹,但也不是越高越好,太高了就不出结果了,在严肃场景,当然也是可以不出结果的,这个需要根据具体的意图来进行设置。根据经验,通常建议设置阈值为0.9以上。
语义搜索基于faiss搜索来实现,通过sbert计算两个句子之间的相似度,用于识别意图。中文模型建议使用text2vec-base-chinese-sentence,英文模型建议使用distilbert-base-nli-mean-tokens,英文模型也支持中文,但效果不及专门的中文模型,同时英文模型也支持泰语、菲利宾语、阿拉伯语等各种语言,当然效果通常不及专门训练的对应语言的模型。
首先,创建faiss索引:
if language == "zh":
model = SentenceTransformer('text2vec-base-chinese-sentence')
elif language == "en":
model = SentenceTransformer('distilbert-base-nli-mean-tokens')
encoded_data = model.encode(data) #data 为你的数据list,如:相似问列表。
index = faiss.IndexIDMap(faiss.IndexFlatIP(768))
index.add_with_ids(encoded_data, np.array(range(0, len(data))))
faiss.write_index(index, f'data.{language}.index') # language为语言,如:zh/en。
其实,通过query进行搜索了:
query_vector = model.encode([query])
k = 5 #只搜索top_k = 5
index = faiss.read_index(f'data.{language}.index')
top_k = index.search(query_vector, k)
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), query, '搜索top_k={}用时: {}'.format(k,round(time.time()-t,4)))
results = [data[_id] for _id in top_k[1].tolist()[0]]
通过搜索,便获得了与query相似的句子。比如:query=番茄🍅。(假设data里面有“西红柿”),则得到的相似句子simq便是“西红柿”🍅。
然后,通过模型计算相似度。
res = []
for simq in results:
e_askq= model.encode([f'{query}'])
e_simq= model.encode([f'{simq}'])
sim = util.cos_sim(e_askq,e_simq).tolist()
sim = round(sim[0][0],4)
res.append([query, simq, sim])
以“番茄”和“西红柿”🍅为例,得到的相似度是:0.9634。