如何评估用于语义搜索的AutoModelForQuestionAnswering模型?
基于AutoModelForQuestionAnswering的语义搜索模型评估方案
一、核心问题拆解
你当前用CamemBERT-base做的是抽取式问答(可适配语义搜索场景的评估逻辑),缺少标注数据(训练/测试集、真实答案)是评估的核心障碍,以下是无需大规模标注也能落地的评估思路:
二、无标注数据下的评估方法
1. 人工评估(最直接)
- 自己构造一批典型的
问题-文本对,手动写出预期答案 - 用你的模型生成答案后,从三个维度打分:
- 准确性:答案是否和真实信息匹配
- 完整性:是否覆盖了问题要求的全部要点
- 流畅性:拼接后的答案读起来是否通顺
- 统计所有样本的平均得分,作为模型性能的参考
2. 用公开数据集评估
直接用成熟的抽取式问答法语数据集(比如SQuAD法语版、MLQA法语子集,适配CamemBERT的语言特性):
- 加载数据集后,用模型批量预测答案
- 计算两个行业标准指标:
- Exact Match(EM):预测答案和真实答案完全一致的样本比例
- F1 Score:预测答案和真实答案的词级重叠率,数值越高匹配度越好
3. 自监督式评估(无标注数据也能用)
- 困惑度(Perplexity):计算模型在无标注文本上的预测困惑度,数值越低说明模型对文本的理解越到位
- 答案合理性校验:统计模型输出"No Answer"的比例,结合问题和文本的相关性判断是否合理(比如问题和文本完全无关时,模型应该输出"No Answer")
三、适配评估的代码调整建议
你的代码存在几个小问题,先修正再开展评估:
import torch from transformers import CamembertTokenizer, AutoModelForQuestionAnswering def load_model(): model_name = "camembert-base" tokenizer = CamembertTokenizer.from_pretrained(model_name) model = AutoModelForQuestionAnswering.from_pretrained(model_name) return model, tokenizer def get_answer(search, text, model, tokenizer): # 修正token_type_ids错误:encode_plus返回的token_type_ids是区分问题和上下文的标识,不能硬设为0 encoded_output = tokenizer.encode_plus(text=search, text_pair=text, padding=True, return_tensors="pt") # 直接用返回的tensor,无需手动转换 input_ids = encoded_output['input_ids'] attention_mask = encoded_output['attention_mask'] token_type_ids = encoded_output['token_type_ids'] tokens = tokenizer.convert_ids_to_tokens(input_ids[0]) # 切换到推理模式,禁用梯度计算节省资源 model.eval() with torch.no_grad(): output = model(input_ids=input_ids, token_type_ids=token_type_ids, attention_mask=attention_mask) # 获取答案区间 answer_start = torch.argmax(output.start_logits) answer_end = torch.argmax(output.end_logits) if answer_end >= answer_start: # 用tokenizer自带方法合并子词,避免手动拼接的混乱 answer = tokenizer.convert_tokens_to_string(tokens[answer_start:answer_end + 1]) else: answer = "No Answer" return answer # 使用示例 model, tokenizer = load_model() question = "Quelle est la capitale de la France ?" context = "La France est un pays d'Europe occidentale. Sa capitale est Paris." print(get_answer(question, context, model, tokenizer))
修正点说明:
- 移除手动tensor转换,用
encode_plus的return_tensors="pt"直接生成可用的张量 - 修复
token_type_ids的错误赋值,保证模型能区分问题和上下文 - 添加
model.eval()和torch.no_grad()优化推理效率 - 用
convert_tokens_to_string替代手动拼接,解决CamemBERT子词拆分的问题
四、评估指标计算示例(以SQuAD数据集为例)
假设你加载了SQuAD法语版数据集,计算EM和F1的代码逻辑如下:
def compute_em(pred_answer, true_answers): # 真实答案可能有多个候选,匹配任意一个就算EM pred_clean = pred_answer.strip().lower() for ans in true_answers: ans_clean = ans.strip().lower() if pred_clean == ans_clean: return 1 return 0 def compute_f1(pred_answer, true_answers): pred_tokens = pred_answer.strip().lower().split() max_f1 = 0 for ans in true_answers: true_tokens = ans.strip().lower().split() # 计算词的交集 common = set(pred_tokens) & set(true_tokens) if len(common) == 0: f1 = 0 else: precision = len(common) / len(pred_tokens) recall = len(common) / len(true_tokens) f1 = 2 * (precision * recall) / (precision + recall) if f1 > max_f1: max_f1 = f1 return max_f1 # 批量评估统计 total_em = 0 total_f1 = 0 data_samples = [...] # 替换为加载的数据集样本,每个样本包含question、context、true_answers for sample in data_samples: pred = get_answer(sample['question'], sample['context'], model, tokenizer) total_em += compute_em(pred, sample['true_answers']) total_f1 += compute_f1(pred, sample['true_answers']) avg_em = total_em / len(data_samples) avg_f1 = total_f1 / len(data_samples) print(f"Exact Match: {avg_em:.2f}, F1 Score: {avg_f1:.2f}")
内容的提问来源于stack exchange,提问作者Emna Talbi
相关产品推荐
相关产品推荐

