【AI 大模型】RAG 检索增强生成 ④ ( 向量相似度计算 | 余弦距离 | 欧式距离 | OpenAI 文本向量模型 | 手动实现的 余弦相似度 和 欧氏距离 函数计算 )


在这里插入图片描述

上一篇博客 【AI 大模型】RAG 检索增强生成 ③ ( 文本向量 | Word2Vec 词汇映射向量空间模型 - 算法原理、训练步骤、应用场景、实现细节 | Python 代码示例 ) 中 , 简单展示了 文本向量 的生成过程 和 表现形式 , 本篇博客中介绍 如何使用这些 文本向量 ;





一、向量相似度计算



向量相似度计算 :自然语言处理 ( NLP ) 和 机器学习 中 , 文本向量 相似度计算 是衡量两个文本语义相似性的核心任务 ;


常用的两种距离度量方法是

  • 余弦距离 ( Cosine Distance ) : 基于 向量夹角 的 余弦值 衡量相似性 ;
  • 欧氏距离 ( Euclidean Distance ) : 在 n 维向量空间 中两点之间的直线距离 ;

二者各有优缺点和适用场景 ;

在这里插入图片描述


场景余弦距离欧氏距离
文本相似度✔️ 更适合(高维稀疏,方向敏感)❌ 不适用(长度影响大)
推荐系统✔️ 更适合(用户兴趣方向)❌ 不适用(活跃度影响大)
高维稀疏数据✔️ 更适合(忽略零值维度)❌ 不适用(受噪声维度干扰)
图像处理❌ 不适用(像素值长度有意义)✔️ 更适合(绝对差异重要)
物理空间距离❌ 不适用(需要绝对距离)✔️ 更适合(直接反映距离)
低维稠密数据❌ 不适用(方向可能不显著)✔️ 更适合(全局差异重要)
异常检测❌ 不适用(需要绝对差异)✔️ 更适合(衡量偏差)




二、余弦距离




1、余弦距离 概念


余弦距离 ( Cosine Distance ) 是 基于 向量夹角 的 余弦值 衡量相似性 ;

  • 余弦相似度计算 : 余弦相似度 取值范围 [ -1 , 1 ] ;

C o s i n e S i m i l a r i t y = X ⋅ Y ∥ X ∥   ∥ Y ∥ \rm Cosine Similarity = \frac{X \cdot Y}{\|X\| \, \|Y\|} CosineSimilarity=∥X∥∥Y∥XY

  • 余弦距离计算 : 余弦距离 取值范围 [ 0 , 2 ] ;

C o s i n e D i s t a n c e = 1 − C o s i n e S i m i l a r i t y \rm Cosine Distance=1−Cosine Similarity CosineDistance=1CosineSimilarity


公式截图 : 防止 Latext 代码失效 ; ( Markdown 中的 Latext 代码仅在 CSDN 生效 )

在这里插入图片描述


上述公式中的 X 和 Y 各自都是一个向量空间中的向量 ;

  • X = ( x 1 , x 2 , ⋯   , x n ) X = (x_1 , x_2, \cdots , x_n) X=(x1,x2,,xn) 是 第一个向量点 , 每个向量的分量 如 x 1 , x 2 , ⋯   , x n x_1 , x_2, \cdots , x_n x1,x2,,xn 各自都是一个浮点值 ;
  • Y = ( y 1 , y 2 , ⋯   , y n ) Y = (y_1 , y_2, \cdots , y_n) Y=(y1,y2,,yn) 是 第二个向量点 , 每个向量的分量 如 y 1 , y 2 , ⋯   , y n y_1 , y_2, \cdots , y_n y1,y2,,yn 各自都是一个浮点值 ;

公式中的

X ⋅ Y = ∑ i = 1 n x i y i \rm X \cdot Y = \sum_{i=1}^{n} x_i y_i XY=i=1nxiyi

是两个向量 X = ( x 1 , x 2 , ⋯   , x n ) \rm X = (x_1 , x_2, \cdots , x_n) X=(x1,x2,,xn) Y = ( y 1 , y 2 , ⋯   , y n ) \rm Y = (y_1 , y_2, \cdots , y_n) Y=(y1,y2,,yn) 的 点积 ;

在这里插入图片描述

上述 X 和 Y 向量可参考如下值 , 每个向量都有 50 个浮点值确定 , 则这两个向量点就是 50 维向量空间中的点 ;

 Vector: [-0.00321157  0.03927787  0.00616916  0.02789649  0.02203173  0.03612738
  0.00637109  0.04316046 -0.049891    0.02915843 -0.00426264  0.02841807
  0.01823073  0.0149862  -0.02141328 -0.00687046  0.0535442   0.01235065
 -0.046329    0.00192757 -0.00424403  0.00364727  0.05790862  0.04215468
  0.04061833  0.03017248 -0.03808379  0.05979197  0.03251123 -0.01618787
 -0.05283526 -0.01509981  0.05030754 -0.03224825  0.05769876 -0.01519872
  0.02141866  0.01543435 -0.01191425 -0.00674526  0.00728445  0.04265702
  0.01254657  0.04424815 -0.05862596 -0.00738266  0.01891772  0.02471734
  0.01362135  0.02899224]

这是上一篇博客 【AI 大模型】RAG 检索增强生成 ③ ( 文本向量 | Word2Vec 词汇映射向量空间模型 - 算法原理、训练步骤、应用场景、实现细节 | Python 代码示例 ) 中 使用 tensorflow 中提供的 Word2Vec 模型 提取的 文本向量 ;


2、余弦距离 特点


余弦距离 特点 : 该类型距离 方向敏感 , 长度不敏感 , 仅关注向量的方向差异 , 忽略向量的大小 ( 模长 ) ;

余弦距离 示例 : 给出两个句子

  • “ 我喜欢机器学习 ”
  • “ 我热爱深度学习 ”

获取两个句子的 文本向量 , 这两个句子的方向接近 ,

但是 由于 词频差异 导致 长度可能不同 ,

其 余弦相似度 高 , 余弦距离 近 , 欧式距离 远 ;


3、余弦距离 适用场景


余弦距离 适用场景 : 余弦距离 通过 计算向量夹角的余弦值 来衡量相似性 , 关注向量的方向而非长度 ;

  • 文本相似度计算 : 文本向量 通常是 高维稀疏的 , 如 : TF-IDF、词袋模型、BERT Embedding , 余弦距离能有效捕捉语义方向 ;
    • 搜索引擎 : 查询 关键字 与 文档内容 的相似性 ;
    • 问答系统 : 匹配 用户问题 与 候选答案 ;
    • 文本聚类 : 将 语义相似 的文本进行聚类分组 ;
  • 推荐系统 : 用户 兴趣向量 的 方向 比 长度 更能反映 用户的个人偏好 ;
  • 高维稀疏数据 : 高维数据中 非零维度较少 , 余弦距离 能有效忽略零值维度的影响 ;
  • 向量长度不一致 : 向量长度差异较大 但 方向相似 时 , 余弦距离更合适 ;
    • 长短文本比较 : 长文本与短文本的相似性比较 ;
    • 用户活跃度不同但兴趣相似 ;

4、余弦距离 代码示例


代码示例 :

import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

# 定义两个向量
A = np.array([1, 2, 3])
B = np.array([4, 5, 6])

# 计算余弦相似度
cos_sim = cosine_similarity([A], [B])[0][0]  # 输出: Cosine Similarity: 0.9746318461970762
print("Cosine Similarity:", cos_sim)

# 计算余弦距离
cos_distance = 1 - cos_sim  # 输出: Cosine Distance: 0.025368153802923787
print("Cosine Distance:", cos_distance)

执行结果 :

Cosine Similarity: 0.9746318461970762
Cosine Distance: 0.025368153802923787

在这里插入图片描述





三、欧式距离




1、欧式距离 概念


欧氏距离 ( Euclidean Distance ) 是 在 n 维向量空间 中两点之间的直线距离 , 公式如下 :

E u c l i d e a n D i s t a n c e = d ( X , Y ) = ∑ i = 1 n ( x i − y i ) 2 \rm Euclidean Distance=d(X, Y) = \sqrt{\sum_{i=1}^{n} \left(x_i - y_i\right)^2} EuclideanDistance=d(X,Y)=i=1n(xiyi)2


公式截图 : 防止 Latext 代码失效 ;

在这里插入图片描述


上述公式中的

  • X = ( x 1 , x 2 , ⋯   , x n ) \rm X = (x_1 , x_2, \cdots , x_n) X=(x1,x2,,xn) 是 第一个向量点 , 每个向量的分量 如 x 1 , x 2 , ⋯   , x n x_1 , x_2, \cdots , x_n x1,x2,,xn 各自都是一个浮点值 ;
  • Y = ( y 1 , y 2 , ⋯   , y n ) \rm Y = (y_1 , y_2, \cdots , y_n) Y=(y1,y2,,yn) 是 第二个向量点 , 每个向量的分量 如 y 1 , y 2 , ⋯   , y n y_1 , y_2, \cdots , y_n y1,y2,,yn 各自都是一个浮点值 ;

欧氏距离 的 值是 非负数 , 值越小表示越相似 ;

在这里插入图片描述


2、欧式距离 特点


欧氏距离 特点 :

  • 对 绝对距离 敏感 , 同时考虑了 两个向量 的 方向和大小差异 ;
  • 对 向量归一化 敏感 , 如果向量未归一化 , 词频高 的 长文本 的 欧氏距离 会天然大于 短文本 , 可能掩盖语义相似性 ;
  • 欧氏距离 不适用于 高维稀疏文本向量 , 欧氏距离 容易受噪声维度影响 ;

3、欧式距离 适用场景


欧式距离 适用场景 : 欧氏距离通过 计算向量空间中两点的直线距离来衡量相似性 , 同时关注向量的方向和长度 ;

  • 物理空间距离计算 : 欧氏距离 直接反映 向量空间 中 两点之间的绝对距离 ;
    • 地理位置 : 计算两个地点之间的距离 ;
    • 传感器数据差异计算 : 测量设备之间的物理差异 ;
  • 图像处理 : 图像 像素值 向量的 长度和方向 都有意义 ;
    • 图像相似度计算 : 计算两幅图像的像素值差异 ;
    • 图像检索 : 基于内容的图像搜索 ;
  • 低维稠密数据 : 在低维数据中 , 所有维度都有意义 , 欧氏距离能捕捉全局差异 ;
    • 物理实验数据对比 : 如温度、压力等测量值 ;
    • 金融数据对比 : 如股票价格的时间序列 ;
  • 需要绝对差异度量的场景 : 欧氏距离更合适 需要绝对差异度量的场景 ;
    • 异常检测 : 检测与正常样本的偏差 ;
    • 聚类分析 : 基于绝对距离的分组 ;

4、欧式距离 代码示例


代码示例 :

import numpy as np
from sklearn.metrics.pairwise import euclidean_distances

# 定义两个向量
A = np.array([1, 2, 3])
B = np.array([4, 5, 6])

# 计算欧氏距离
euclidean_dist = euclidean_distances([A], [B])[0][0]  # 输出: Euclidean Distance: 5.196152422706632
print("Euclidean Distance:", euclidean_dist)

执行结果 :

Euclidean Distance: 5.196152422706632

在这里插入图片描述





四、OpenAI 文本向量模型




1、OpenAI 的 text-embedding-ada-002 文本向量模型


text-embedding-ada-002 是 OpenAI 发布的 文本嵌入 ( Embedding ) 模型 , 属于第二代嵌入模型系列 ;

  • 核心功能 : 将文本(单词、句子、段落)转换为高维向量(Embedding), 捕捉文本的语义信息 ;
  • 输出维度 : 生成 1536 维的浮点数向量 ;
  • 适用场景 : 语义搜索、文本相似度计算、聚类分析、分类任务等 ;

text-embedding-ada-002 适合快速构建语义相关的应用 , 如 : 搜索、推荐 ;

虽然存在领域和语言限制 , 但其低成本、易用性和高性能使其成为大多数场景的首选工具 ;

对于复杂需求 , 可结合本地模型或领域数据进行补充优化 ;


text-embedding-ada-002 模型 代码示例 : 下面代码的 api_key , 替换你自己的 api_key 和 接口 , 代码中的 api_key 删除了 ;

from openai import OpenAI

# 生成文本向量
# 这里替换你自己的 api_key 和 接口, 这里的 api_key 隐藏了
client = OpenAI(api_key="sk-i3dHq7757aF6", base_url="https://api.xiaoai.plus/v1")

# text-embedding-ada-002 模型是 OpenAI 提供的
def get_embedding(texts, model="text-embedding-ada-002"):
    '''封装 OpenAI 的 Embedding 模型接口'''
    data = client.embeddings.create(input=texts, model=model).data
    return [x.embedding for x in data]

# 计算相似度
text1 = "测试文本转向量"

# 计算出 文本向量
vec1 = get_embedding(text1)

# 打印文本向量
print(vec1)

执行结果如下 : 输出了 1536 个浮点数 , 就不在这里完整的贴出来了 ;

[[-0.009152066893875599, -0.008041816763579845, -0.00519117247313261, 0.014065677300095558, 0.0068490467965602875, 0.022430066019296646, -0.017283903434872627 ... ]]

在这里插入图片描述


2、使用 Scikit-learn 机器学习库中的函数计算文本向量距离


下面这段代码的主要功能是使用 OpenAI 的 text-embedding-ada-002 模型将文本转换为向量 , 并计算 Scikit-learn 机器学习库中的 余弦相似度 和 欧氏距离 函数 衡量查询文本与一组文档的语义相似性 ;


代码示例 : 下面代码的 api_key , 替换你自己的 api_key 和 接口 , 代码中的 api_key 删除了 ;

import numpy as np
from numpy import dot
from numpy.linalg import norm
from openai import OpenAI
from sklearn.metrics.pairwise import euclidean_distances
from sklearn.metrics.pairwise import cosine_similarity

# 这里替换你自己的 api_key 和 接口, 这里的 api_key 隐藏了
client = OpenAI(api_key="sk-i3dHqZ7757aF6", base_url="https://api.xiaoai.plus/v1")

# text-embedding-ada-002 模型是 OpenAI 提供的
def get_embeddings(texts, model="text-embedding-ada-002"):
    '''封装 OpenAI 的 Embedding 模型接口'''
    data = client.embeddings.create(input=texts, model=model).data
    return [x.embedding for x in data]

query = "国际争端新闻"

documents = [
    "李彦宏称大模型成本每年降低90%",
    "乌军大批直升机击落多架俄无人机",
    "王力宏回应是否想找新伴侣",
    "饺子不知道观众怎么想出的藕饼cp",
    "加沙停火协议关键时刻生变",
]

# 将 query = "国际争端新闻" 字符串转为 文本向量
query_vec = get_embeddings([query])[0]

# 将 documents 列表 中的每个文本 都转为 文本向量
documents_vecs = get_embeddings(documents)

print("余弦相似度: 相似度越大, 语义越接近")
for vec in documents_vecs:
    # 统计 "国际争端新闻" 与 documents 列表中的每个文本的语义相似度
    print(cosine_similarity([query_vec], [vec])[0][0])

print("\n欧氏距离: 距离越小, 语义越接近")
for vec in documents_vecs:
    # 统计 "国际争端新闻" 与 documents 列表中的每个文本的语义相似度
    print(euclidean_distances([query_vec], [vec])[0][0])

执行结果 :

余弦相似度: 相似度越大, 语义越接近
0.769241291292881
0.8078512251410452
0.7804568417556569
0.7423023140698245
0.8193178107256962

欧氏距离: 距离越小, 语义越接近
0.679350776164427
0.619917376411428
0.6626359259131844
0.7179104314580911
0.6011359204262787

在这里插入图片描述





五、手动实现的 余弦相似度 和 欧氏距离 函数计算




1、余弦距离计算


代码示例 :

  • 首先 , 计算两个向量的点积 np.dot(a, b)

  • 然后 , 计算每个向量的 L2 范数 , 也就是 模长 np.linalg.norm

  • 再后 , 计算余弦相似度 , 点积除以两个向量模长的乘积

  • 最后 , 计算 余弦距离:1 - 余弦相似度 ;

# 导入 numpy 库,用于数学计算
import numpy as np

# 定义余弦距离函数
def cosine_distance(a, b):
    """
    计算两个向量之间的余弦距离。

    参数:
    a (numpy.ndarray): 第一个向量。
    b (numpy.ndarray): 第二个向量。

    返回:
    float: 余弦距离,范围在 [0, 2] 之间。
    """
    # 计算向量 a 和向量 b 的点积(内积)
    dot_product = np.dot(a, b)

    # 计算向量 a 的 L2 范数(模长)
    norm_a = np.linalg.norm(a)

    # 计算向量 b 的 L2 范数(模长)
    norm_b = np.linalg.norm(b)

    # 计算余弦相似度:点积除以两个向量模长的乘积
    cos_sim = dot_product / (norm_a * norm_b)

    # 余弦距离 = 1 - 余弦相似度
    return 1 - cos_sim


# 示例向量
A = np.array([1, 2, 3])  # 向量 A
B = np.array([4, 5, 6])  # 向量 B

# 计算向量 A 和向量 B 之间的余弦距离
cos_dist = cosine_distance(A, B)  # 输出: 0.026

# 打印余弦距离结果
# Cosine Distance : 0.025368153802923787
print("Cosine Distance :", cos_dist)

执行结果 :

Cosine Distance : 0.025368153802923787

在这里插入图片描述


2、欧式距离计算


np.linalg.norm(a - b) 代码 是 计算的是L2 范数 ;

L2 范数(也叫 欧几里得范数,Euclidean Norm)是 向量的长度或模长,表示从原点到该点的欧几里得距离。

∥ X ∥ 2 = ∑ i = 1 n x i 2 \|X\|_2 = \sqrt{\sum_{i=1}^{n} x_i^2} X2=i=1nxi2

3 维向量 X = ( 3 , 4 , 12 ) X=(3,4,12) X=(3,4,12) 的 L2 范数计算 :

∥ X ∥ 2 = 3 2 + 4 2 + 1 2 2 = 169 = 13 \|X\|_2 = \sqrt{3^2 + 4^2 + 12^2} = \sqrt{169} = 13 X2=32+42+122 =169 =13


代码示例 :

# 导入 numpy 库,用于数学计算
import numpy as np

def euclidean_distance(a, b):
    """
    计算两个向量 a 和 b 之间的欧氏距离。

    参数:
    a -- 第一个向量(NumPy数组)
    b -- 第二个向量(NumPy数组)

    返回:
    两个向量之间的欧氏距离(标量值)
    """
    return np.linalg.norm(a - b)  # 使用 NumPy 的范数函数计算欧氏距离

# 示例向量
A = np.array([1, 2, 3])  # 向量 A
B = np.array([4, 5, 6])  # 向量 B

# 计算向量 A 和向量 B 之间的欧氏距离
ecul_dist = euclidean_distance(A, B)  # 输出: 0.026

# 打印余弦距离结果
# Euclidean Distance : 5.196152422706632
print("Euclidean Distance :", ecul_dist)

执行结果 :

Euclidean Distance : 5.196152422706632

在这里插入图片描述

评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值