- 导入需要的包:transformers、torch、sklearn等。
- 加载预训练的BERT模型和分词器。
- 定义计算相似度的similarity函数。
- 对两个文本分词,添加特殊标记,转换成索引列表。
- 将索引列表转换为张量输入到BERT中。
- 获取输入对应的词向量表示embeddings。
- 计算词向量的均值,获取句子embeddings。
- 使用cosine_similarity计算两个句子向量的余弦相似度。
- 返回相似度分数。
- 可以根据相似度分数对QA对话进行筛查
# -*- coding: utf-8 -*-
from transformers import BertTokenizer, BertModel
import torch
from sklearn.metrics.pairwise import cosine_similarity
import json
# 加载预训练的BERT模型和tokenizer
model_name = 'bert-base-chinese'
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertModel.from_pretrained(model_name)
# 输入文本
# 分词并添加特殊标记
"""
用模型对经过分词筛查之后的数据进行,语义相似度过滤,保存高于0.75的数据
"""
def similarity(text1,text2):
tokens1 = tokenizer.tokenize(text1)
tokens1 = ['[CLS]'] + tokens1 + ['[SEP]']
tokens2 = tokenizer.tokenize(text2)
tokens2 = ['[CLS]'] + tokens2 + ['[SEP]']
# 将分词转换为词汇表中的索引
input_ids1 = tokenizer.convert_tokens_to_ids(tokens1)
input_ids2 = tokenizer.convert_tokens_to_ids(tokens2)
# print(input_ids1)
# 将输入转换为PyTorch张量
input_tensor1 = torch.tensor([input_ids1])
input_tensor2 = torch.tensor([input_ids2])
# print(input_tensor1)
# 获取词向量
with torch.no_grad():
outputs1 = model(input_tensor1)
embeddings1 = outputs1[0][0]
outputs2 = model(input_tensor2)
embeddings2 = outputs2[0][0]
# 计算句子表示
sentence_embedding1 = torch.mean(embeddings1, dim=0)
sentence_embedding2 = torch.mean(embeddings2, dim=0)
# print(sentence_embedding1)
# 计算余弦相似度
similarity = cosine_similarity(sentence_embedding1.unsqueeze(0), sentence_embedding2.unsqueeze(0))
return similarity[0][0]
一句阈值筛查相关度低于阈值的数据:
total = 0
with open('你的待筛查的QA文件', 'r', encoding='utf-8') as f:
for line in f:
dataset = []
# print(line)
try:
data = json.loads(line)
except json.JSONDecodeError:
continue
#这里对文本长度进行限制,因为模型中的embedding为512,所以限制输入句子的长度
if (len(data['instruction'])>200 or len(data['output'])>300):
# with open('danlunduihua/0.72data.json', 'a', encoding='utf-8') as f:
# data = str(data).replace("'", "\"").replace(r"\n", "")
# f.write(str(data)+ '\n')
continue
#这里是取文本里面的QA数据,进行相似度判断
sentence_a = data['instruction']
sentence_b = data['output']
if similarity(sentence_a,sentence_b)>0.73:
# print(data)
# print(similarity(sentence_a,sentence_b))
with open('超过阈值的数据写入某个新文件', 'a', encoding='utf-8') as f:
data = str(data).replace("'", "\"").replace(r"\n", "")
json.dump(data + '\n', f)
f.close()
else:
total+=1
print(total)
print("低于0.73相似度的数据总数:",total)
使用预训练BERT提取文本语义特征向量,然后计算余弦相似度。相似度分数可以用来判断两篇文本,一段QA对话等的语义相关性,进行语义重复过滤等。
值得一提的是这个预训练的bert模型,在某些具体领域(比如医疗QA数据等),效果不是特别好,例如这个QA对话的相似度达到了0.8+,而实际这段对话无实际意义
{"instruction": "想得到怎样的帮助:应该怎么办", "output": "您好,根据您提供的信息,我了解到您在肝功能检查中发现了直接胆红素升高的情况。首先,我想告诉您不要过于担心,因为直接胆红素升高并不一定意味着您患有肝胆系统疾病。根据您提供的数据,您的直接胆红素结果在正常范围内,这可能是由于抽血环节出现问题导致的标本溶血引起的升高。为了更加准确地了解您的情况,我建议您进行肝胆B超检查,以排除肝胆系统疾病的可能性。同时,我建议您注意保持良好的饮食习惯和饮水习惯,避免过度劳累和饮食过于油腻的食物。如果您有任何不适或者检查结果出现异常,请及时就医。希望我的回答能够对您有所帮助,祝您身体健康!这是一个关于医疗的问题,模型生成的建议仅供参考,请咨询专业医生并遵循医嘱"}
相似度: 0.813937
因为模型没有专门训练医疗方面的数据所以,表现不好,可以用自己的部分数据先做训练,在进行相似度分析,效果会很好。
或者用实体抽取的方式,抽取前后文章中包含的实体,比较Q中抽取的实体是否包含在A中,把少量包含或者不包含的数据给筛出来。也是一个可行的办法。
# 导入THULAC
import thulac
import json
# 初始化THULAC对象,设置为进行词性标注
def shiti(text):
thu = thulac.thulac(seg_only=False)
# 对文本进行切词和词性标注
tagged_text = thu.cut(text)
# 初始化名词列表
nouns = []
# 遍历标注结果,抽取名词
for item in tagged_text:
if item[1].startswith('n'):
nouns.append(item[0])
return nouns
最好还是用bert训练自己的数据模型,这样效果最好,但工程量会比较大