如何利用NLP技术判断词汇/语句与目标定义的相似性并得到预期分类结果?
嗨,我明白你的需求啦——你不是要单纯计算句子之间的语义相似度,而是要判断每个句子是否符合*「素食用户」*这个明确的定义,得到True/False的分类结果对吧?之前用SentenceTransformer算所有句子间的相似度肯定不对,因为那是在找句子之间的关联,不是做符合度判断。下面给你几个实用的方案,你可以根据自己的场景选择:
一、快速上手:基于关键词规则的方案
如果你的定义比较明确(比如这里的*「素食用户」就是不吃鸡、鱼等肉类,只吃植物类食物),直接写规则是最省心的。咱们可以设定正向关键词和反向关键词*,然后通过简单逻辑判断:
- 正向关键词:表示符合素食的表述,比如
vegetarian、only eats fruits - 反向关键词:表示不符合素食的食物,比如
chicken、fish
具体代码实现如下:
# 定义关键词规则 definition_rules = { "positive": {"vegetarian"}, "negative": {"chicken", "fish"} } sentences = [ 'vegetarian User', 'user sometimes eats chicken', 'user is vegetarian', 'user only eats fruits', 'user likes fish' ] results = [] for sent in sentences: lower_sent = sent.lower() # 检查是否包含正向关键词,或者是纯植物饮食表述 has_positive = any(word in lower_sent for word in definition_rules["positive"]) or "only eats fruits" in lower_sent # 检查是否包含非素食的反向关键词 has_negative = any(word in lower_sent for word in definition_rules["negative"]) # 逻辑:符合素食条件且没有非素食行为 is_vegetarian = has_positive and not has_negative results.append(is_vegetarian) print(results) # 输出: [True, False, True, True, False]
这个方案的优点是简单直接,容易调整规则;缺点是遇到复杂句子(比如「user doesn't eat chicken but eats fish」)时,需要细化规则。
二、更灵活:微调小模型做文本分类
如果需要处理更复杂的语义场景(比如遇到「user avoids all animal products」这种间接表述),咱们可以用预训练小模型做微调,把问题转成二分类任务(符合定义/不符合定义):
- 准备少量标注数据:把符合素食的句子标为1,不符合的标为0
- 用轻量级预训练模型(比如DistilBERT)做微调
- 用微调后的模型预测新句子的分类结果
简化版代码示例:
from transformers import DistilBertTokenizer, DistilBertForSequenceClassification, Trainer, TrainingArguments import torch # 准备标注训练数据 train_texts = [ 'vegetarian User', 'user is vegetarian', 'user only eats fruits', 'user sometimes eats chicken', 'user likes fish', 'user eats beef' ] train_labels = [1, 1, 1, 0, 0, 0] # 加载模型和分词器 tokenizer = DistilBertTokenizer.from_pretrained('distilbert-base-uncased') model = DistilBertForSequenceClassification.from_pretrained('distilbert-base-uncased', num_labels=2) # 自定义数据集类 class TextDataset(torch.utils.data.Dataset): def __init__(self, encodings, labels): self.encodings = encodings self.labels = labels def __getitem__(self, idx): item = {key: torch.tensor(val[idx]) for key, val in self.encodings.items()} item['labels'] = torch.tensor(self.labels[idx]) return item def __len__(self): return len(self.labels) # 预处理数据 train_encodings = tokenizer(train_texts, truncation=True, padding=True) train_dataset = TextDataset(train_encodings, train_labels) # 设置训练参数 training_args = TrainingArguments( output_dir='./model_results', num_train_epochs=3, per_device_train_batch_size=2, logging_dir='./training_logs', logging_steps=10 ) # 训练模型 trainer = Trainer( model=model, args=training_args, train_dataset=train_dataset ) trainer.train() # 预测目标句子 test_sentences = [ 'vegetarian User', 'user sometimes eats chicken', 'user is vegetarian', 'user only eats fruits', 'user likes fish' ] test_encodings = tokenizer(test_sentences, truncation=True, padding=True, return_tensors='pt') outputs = model(**test_encodings) predictions = torch.argmax(outputs.logits, dim=1) print([bool(pred) for pred in predictions]) # 输出符合预期的分类结果
这个方案能处理复杂语义,但需要准备少量标注数据,训练过程也需要一点时间。
三、改进你的SentenceTransformer方法
如果你还是想用相似度思路,别再计算所有句子之间的相似度了,应该聚焦每个句子和**目标定义「vegetarian User」**的相似度,然后设置一个阈值来判断True/False:
from sentence_transformers import SentenceTransformer, util model = SentenceTransformer("all-mpnet-base-v2") target_definition = "vegetarian User" sentences = [ 'vegetarian User', 'user sometimes eats chicken', 'user is vegetarian', 'user only eats fruits', 'user likes fish' ] # 编码目标定义和所有句子 def_embedding = model.encode(target_definition, convert_to_tensor=True) sent_embeddings = model.encode(sentences, convert_to_tensor=True) # 计算每个句子与定义的余弦相似度 similarities = util.cos_sim(def_embedding, sent_embeddings)[0] # 设置相似度阈值,比如0.7,超过则认为符合定义 threshold = 0.7 results = [sim > threshold for sim in similarities] print(results)
这里的关键是调整阈值,你可以根据实际输出的相似度得分来调整,直到得到你想要的结果。
总结一下:如果场景简单,规则方案足够用;如果需要处理复杂语义,微调模型是更好的选择;用SentenceTransformer的话,一定要聚焦和目标定义的单方向相似度,而不是所有句子间的相互相似度。
备注:内容来源于stack exchange,提问作者A3006

