为什么在NLP里面使用FAISS的精度没有余弦高

        今天在做NLP意图识别测试的时候发现自己的FAISS识别的内容还没有余弦的高,感到很奇怪。代码如下

1、先加载向量模型

from sentence_transformers import SentenceTransformer
import os

os.environ['TRANSFORMERS_CACHE'] = 'D:/HuggingFace'  # 可选,指定模型缓存路径
os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'  # Hugging Face 镜像

# hf_hub_download.repo_url_prefix = "https://mirror.tuna.tsinghua.edu.cn/hugging-face-transformers"

# 加载预训练模型
model = SentenceTransformer('all-MiniLM-L6-v2',device="cpu")  # 小型模型,速度快,精度高

2、定义测试数据

intents = {
    "query_balance": ["查询余额", "余额查询", "查账户里的钱"],
    "query_wheather": ["天气怎么样", "查询天气"],
    "transfer_money": ["转账", "给别人汇款", "支付给对方"],
    "open_account": ["开户", "我要开账户", "申请银行账号"],
    "order_check": ["查订单", "订单查询", "订单状态"],
    "query_bill": ["账单查询", "查询账单", "账单怎么样"],
    "order_food": ["订餐", "我要订餐", "订餐服务"],
    "query_express": ["查快递", "快递查询", "查询快递状态"],   
    "query_stock": ["查股票", "股票查询", "查询股票价格"],
    "query_traffic": ["查交通", "交通查询", "查询交通状况"],
    "query_news": ["查新闻", "新闻查询", "查询新闻"],
    "query_calendar": ["查日历", "日历查询", "查询日历"],
    "query_map": ["查地图", "地图查询", "查询地图"],
    "query_movie": ["查电影", "电影查询", "查询电影"],
    "query_music": ["查音乐", "音乐查询", "查询音乐"], 
    "query_joke": ["查笑话", "笑话查询", "查询笑话"],
    "query_poem": ["查诗词", "诗词查询", "查询诗词"],
    "query_translation": ["查翻译", "翻译查询", "查询翻译"],
    "query_time": ["查时间", "时间查询", "查询时间"],
    "order_hotel": ["订酒店", "我要订酒店", "酒店预订","定房间","定大号房间","还有房间吗"],
}
# 计算每个意图分类的短句向量
intent_embeddings = {}
for intent, phrases in intents.items():
    intent_embeddings[intent] = model.encode(phrases)

3、使用传统的余弦计算距离

import numpy as np
from sentence_transformers import util

def find_best_intent(user_input):
    user_embedding = model.encode(user_input)
    best_intent, best_score = None, 0
    
    for intent, embeddings in intent_embeddings.items():
        # 计算与每个意图分类的最高相似度
        scores = util.cos_sim(user_embedding, embeddings).max()
        if scores > best_score:
            best_intent, best_score = intent, scores
    return best_intent, best_score

# 测试
user_input = "帮我查一下账户的余额"
intent, score = find_best_intent(user_input)
print(f"匹配意图: {intent}, 相似度: {score}")

  没有问题匹配意图: open_account, 相似度: 0.7169514298439026

4、使用FAISS

# 使用向量搜索不行,因为向量搜索只能找到最近的向量,不能找到最相似的向量
import faiss

# 构建向量索引
index = faiss.IndexFlatL2(384)  # 向量维度为 384
all_embeddings = []
intent_to_ids = {}

# 为每个意图分配 ID
id = 0
for intent, embeddings in intent_embeddings.items():
    for embedding in embeddings:
        all_embeddings.append(embedding)
        intent_to_ids[id] = intent
        id += 1
all_embeddings = np.array(all_embeddings).astype('float32')

# 添加到索引
index.add(all_embeddings)

# 用户输入匹配
def find_best_intent_faiss(user_input):
    user_embedding = model.encode([user_input]).astype('float32')
    distances, ids = index.search(user_embedding, 1)  # 检索最近的一个向量
    return intent_to_ids[ids[0][0]], distances[0][0]

# 测试
user_input = "我想查余额"
intent, distance = find_best_intent_faiss(user_input)
confidence = 1 - (distance/1.0)
print(f"匹配意图: {intent}, 距离: {distance} 相似度: {confidence}")

匹配意图: open_account, 距离: 3.0383210053788745e-13 相似度: 0.9999999999996961,这个没有问题

user_input = "我想查天气"
intent, distance = find_best_intent_faiss(user_input)
confidence = 1 - (distance/1.0)
print(f"匹配意图: {intent}, 距离: {distance} 相似度: {confidence}")

匹配意图: query_wheather, 距离: 0.2974719703197479 相似度: 0.7025280296802521,感觉也没有问题,下面的问题来了

user_input = "我要定一个房间"
intent, distance = find_best_intent_faiss(user_input)
confidence = 1-distance/1.0
print(f"向量匹配意图: {intent}, 距离: {distance} 相似度: {confidence}")
intent, score = find_best_intent(user_input)
print(f"最近距离匹配意图: {intent}, 相似度: {score}")

向量匹配意图: order_hotel, 距离: 0.49188053607940674 相似度: 0.5081194639205933 最近距离匹配意图: order_hotel, 相似度: 0.7540597915649414

只能查询AI信息

FAISS 默认使用的是 L2(欧几里得)距离,而余弦相似度更适合文本匹配任务,因此出现了这种相似度差异。

为什么 FAISS 的相似度较低?

  1. 默认 L2 距离计算方式

    • FAISS 主要用于高维向量的最近邻搜索,默认使用 L2(欧几里得)距离。
    • 由于 L2 距离受到向量长度的影响,可能导致不同长度的短句和长句的匹配效果不佳。
  2. 余弦相似度更适合文本

    • 余弦相似度计算的是向量方向,而非长度,因此对语义匹配更稳定。
    • 在 NLP 任务中,余弦相似度往往比 L2 距离更可靠。

5、使用 FAISS 余弦相似度

# 构建向量索引,Inner Product(内积),并归一化向量,使其等效于 余弦相似度
# 在NLP里面余弦相似度和内积相似度是等效的,计算的是两个向量的夹角
index = faiss.IndexFlatIP(384)  # 向量维度为 384,
all_embeddings = []
intent_to_ids = {}

# 为每个意图分配 ID
id = 0
for intent, embeddings in intent_embeddings.items():
    for embedding in embeddings:
        all_embeddings.append(embedding)
        intent_to_ids[id] = intent
        id += 1
all_embeddings = np.array(all_embeddings).astype('float32')

# 添加到索引
faiss.normalize_L2(embeddings)
index.add(all_embeddings)

向量匹配意图: order_hotel, 距离: 0.7540597319602966 相似度: 0.24594026803970337 最近距离匹配意图: order_hotel, 相似度: 0.7540597915649414

考虑到后续的扩展性,因此后续整个使用FAISS

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

livepy

老码农,赋闲在家要吃饭

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值