
本文详解如何正确使用bert模型(特别是土耳其语预训练版本)计算1000个问题与1000个答案间的余弦相似度,解决因语言不匹配导致的相似度坍缩与准确率为0的问题,并提供可复现的评估流程与优化建议。
本文详解如何正确使用bert模型(特别是土耳其语预训练版本)计算1000个问题与1000个答案间的余弦相似度,解决因语言不匹配导致的相似度坍缩与准确率为0的问题,并提供可复现的评估流程与优化建议。
在使用BERT进行跨语言语义匹配时,模型的语言适配性是决定性前提。原代码中直接调用 bert-base-uncased(英文小写版),但示例问题“bir sunum oluşturmak için beş adım yazın.”(土耳其语:“请写出制作演示文稿的五个步骤”)表明数据集为土耳其语。由于BERT词表未覆盖土耳其语子词、且预训练语料中几乎不含土耳其语,导致所有输入被大量映射至 [UNK] 或低信息量的通用token,最终句向量丧失判别力——这正是余弦相似度趋近于0、Top-k准确率恒为0的根本原因。
✅ 正确做法:切换为土耳其语专用预训练模型
推荐使用 Hugging Face 上经过充分验证的 dbmdz/bert-base-turkish-cased(支持大小写敏感分词,更适配土耳其语形态变化):
from transformers import BertTokenizer, BertModel
import torch
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
# ✅ 使用土耳其语BERT
tokenizer = BertTokenizer.from_pretrained("dbmdz/bert-base-turkish-cased")
model = BertModel.from_pretrained("dbmdz/bert-base-turkish-cased").eval().to(device)
def get_sentence_embedding(text: str) -> torch.Tensor:
inputs = tokenizer(
text,
return_tensors="pt",
padding=True,
truncation=True,
max_length=128
).to(device)
with torch.no_grad():
outputs = model(**inputs)
# 使用[CLS] token embedding(比mean-pooling更稳定)
return outputs.last_hidden_state[:, 0, :].cpu() # shape: [1, 768]
# 批量编码(大幅提升效率,避免for循环逐条推理)
sample_questions = train_ds['questions'].sample(1000, random_state=42).tolist()
sample_answers = train_ds['answers'].sample(1000, random_state=42).tolist()
# 获取全部问题嵌入(以第一个问题为例)
question_emb = get_sentence_embedding(sample_questions[0])
# 批量编码答案(推荐使用DataLoader或分batch处理,此处简化为列表推导)
answer_embs = torch.cat([get_sentence_embedding(a) for a in sample_answers], dim=0) # [1000, 768]
# 向量化余弦相似度计算(无需循环)
similarities = cosine_similarity(question_emb.numpy(), answer_embs.numpy()).flatten() # [1000]
most_similar_indices = np.argsort(similarities)[-5:][::-1]
# ⚠️ 关键修正:ground_truth_idx 必须与 sample_answers 对齐!
# 原代码错误地从全量 train_ds 中取答案索引,但 sample_answers 是随机抽样,索引已失效
# 正确方式:记录原始问题在train_ds中的位置,并查找其对应答案在sample_answers中的相对索引
original_question_idx = 30574 # 示例中选定的问题在原始数据集中的位置
ground_truth_answer = train_ds['answers'].iloc[original_question_idx]
# 在sample_answers中查找该答案(需处理可能重复或未抽中情况)
try:
gt_in_sample_idx = sample_answers.index(ground_truth_answer)
except ValueError:
print("⚠️ Warning: Ground truth answer not found in sampled answers — skipping evaluation.")
gt_in_sample_idx = -1
top1_acc = 1 if (gt_in_sample_idx != -1 and most_similar_indices[0] == gt_in_sample_idx) else 0
top5_acc = 1 if (gt_in_sample_idx != -1 and gt_in_sample_idx in most_similar_indices) else 0? 重要注意事项与进阶建议:
-
评估指标需合理设计:Top-1/Top-5 准确率在仅抽样1000对且无答案重排时过于严苛。建议补充:
- Top-10 / Top-25 准确率观察趋势;
- Mean Reciprocal Rank (MRR):1 / (rank_of_ground_truth + 1),对部分匹配更鲁棒;
- Semantic Similarity Score Distribution:绘制相似度直方图,确认是否出现明显双峰(理想情况应有清晰高相似度簇)。
- 嵌入策略优化:优先使用 [CLS] 向量而非 mean(last_hidden_state),后者易受padding和短文本噪声干扰;若需更高精度,可尝试 sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2(专为多语言语义检索微调)。
- 性能提示:对1000×1000相似度矩阵,务必使用 torch.nn.functional.cosine_similarity 或 sklearn 的批处理接口,避免Python循环+单次cosine_similarity调用(后者内部仍为循环)。
通过语言模型对齐、嵌入方法修正与评估逻辑严谨化,可显著提升土耳其语问答检索的语义匹配质量,使相似度分数回归合理区间(如0.4–0.8),准确率具备真实区分度。

















