Skip to content

Commit f3f6502

Browse files
authored
Merge pull request #123 from Halukisan/dev
Dev
2 parents 3a5ab97 + 7c72cb1 commit f3f6502

7 files changed

Lines changed: 44 additions & 14 deletions

File tree

docs/Faiss/chapter3/FAISS核心功能进阶.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ COSINE 相似度用于衡量两个向量在方向上的一致性,公式如下
1818
$$
1919
\text{cosine}(a,b) = \frac{a \cdot b}{\|a\| \|b\|}
2020
$$
21-
其中,`a*bb`是向量 `a``b` 的内积,`|a|``|b|` 是向量 `a``b` 的 L2 范数(即向量的长度)。
21+
其中,`a*b`是向量 `a``b` 的内积,`|a|``|b|` 是向量 `a``b` 的 L2 范数(即向量的长度)。
2222

2323

2424
#### 1.1.1 L2 归一化对 COSINE 相似度的影响

docs/Faiss/chapter4/FAISS性能调优与评估.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,10 @@ for i, params in enumerate(random_params_list):
395395
# 输出随机搜索结果
396396
print("\n" + "="*30)
397397
if best_random_params is not None:
398+
# 重新评估最优参数以获取完整指标
399+
best_random_recall, _, best_random_build_time = evaluate_hnsw(best_random_params, xb, xq, I_gt, k)
398400
print(f"随机搜索最优参数:{best_random_params}")
399-
print(f"对应Recall@{k}: {recall_at_k(evaluate_hnsw(best_random_params, xb, xq, I_gt, k)[0], I_gt, k):.4f}")
401+
print(f"对应Recall@{k}: {best_random_recall:.4f}")
400402
print(f"对应QPS: {best_random_qps:.0f}")
401403
else:
402404
print("随机搜索中没有找到满足Recall≥0.9的参数组合")
@@ -445,8 +447,10 @@ for i, params in enumerate(grid_params_list):
445447
# 输出网格搜索结果
446448
print("\n" + "="*30)
447449
if best_grid_params is not None:
450+
# 重新评估最优参数以获取完整指标
451+
best_grid_recall, _, best_grid_build_time = evaluate_hnsw(best_grid_params, xb, xq, I_gt, k)
448452
print(f"网格搜索最优参数:{best_grid_params}")
449-
print(f"对应Recall@{k}: {recall_at_k(evaluate_hnsw(best_grid_params, xb, xq, I_gt, k)[0], I_gt, k):.4f}")
453+
print(f"对应Recall@{k}: {best_grid_recall:.4f}")
450454
print(f"对应QPS: {best_grid_qps:.0f}")
451455
else:
452456
print("网格搜索中没有找到满足Recall≥0.9的参数组合")

docs/base/chapter1/项目介绍.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@
2121

2222
### 1.1 技术概览
2323

24-
**向量数据库(Vector Database)** 是专为高维向量数据设计的新一代数据库系统。
25-
它通过将文本、图像、音频等非结构化数据转化为数学向量,并基于相似性度量实现高效语义检索。
26-
与传统关系型数据库的“精确匹配”不同,向量数据库通过 **嵌入模型(Embedding Model)** 将复杂的非结构化内容映射到高维向量空间中,再利用 **近似最近邻搜索(ANN, Approximate Nearest Neighbor)** 算法实现毫秒级相似度检索。
24+
**向量数据库(Vector Database)** 是专为高维向量设计的新一代数据库系统。 不同于传统数据库的“精确匹配”,它通过 **嵌入模型(Embedding Model)** 将文本、图像、音频等非结构化数据映射为高维向量,并利用**近似最近邻搜索(ANN)** 算法,实现海量数据下的毫秒级语义检索。
2725

2826
![alt text](/images/qianyan3.png)
2927

docs/more/chapter3/Limit基于嵌入检索的理论极限.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
### 问题背景
55
对于用户查询的向量嵌入问题,需要召回相关文档内容,尽管先前的研究指出了向量嵌入的理论局限性,但人们普遍认为这些困难是由于用户的不切实际的查询请求导致的,而对于那些切实的查询请求,通过更好的训练数据和更大的模型就能克服困难。这篇论文证明了在现实场景中,即便是极其简单的查询,也会遇到局限性,即:证明了对于给定的嵌入维度d,存在无法返回前k个文档组合————无论查询是什么,为了证明这一理论极限适用于任何检索模型或训练数据集,论文作者测试了一种场景:向量本身直接通过测试数据进行优化。这使我们能够通过实验证明嵌入维度如何助力解决检索任务。作者发现,对于每个嵌入维度\((d)\),**都存在一个关键点,超过该点后,文档数量过多,导致嵌入维度无法对所有组合进行编码**。随后,我们收集了不同维度d下的这些关键点,并证明这种关系可以通过多项式函数进行经验建模。
66

7-
总结:虽然先前的一些研究已经指出了向量嵌入的一些理论限制,但通常假设这些困难仅仅来源于不切实际的用户查询问题,或者可以通过更好的训练数据集和更大参数量的模型来客服。这篇论文的动机就是挑战这一假设,并证明即使在现实且简单的查询设置中,这些理论限制也可能出现。
7+
总结:虽然先前的一些研究已经指出了向量嵌入的一些理论限制,但通常假设这些困难仅仅来源于不切实际的用户查询问题,或者可以通过更好的训练数据集和更大参数量的模型来克服。这篇论文的动机就是挑战这一假设,并证明即使在现实且简单的查询设置中,这些理论限制也可能出现。
88
### 方法
99
在数学层面上,对于上面提到的问题进行一个证明:
1010

1111
参考论文3.3结论部分,简单的来说,3.3节提到的结论是关于向量嵌入模型表示能力的根本限制。它指出了:
1212
* **存在无法被d维嵌入捕获的检索任务**:对于任何固定的嵌入维度d,总会存在一些二进制相关性矩阵(你可以理解为一种用户的检索任务),是无法被d维嵌入模型精确表示的。这意味着,有些检索任务的难度太高,需要更高的嵌入维度才能被识别。
1313

1414
* **高签秩的检索任务更难**:检索任务的相关性矩阵如果具有较高的签秩,那么对于嵌入模型来说,他就更难被精确捕获,应为它需要更高的维度。
15-
* **签秩是衡量任务难度的指标**:签秩为我们提供了一个衡量检索任务的难度的理论机制。我们可以通过优化自由嵌入表示的梯度下降方法,为矩阵的签秩确定一个上线
15+
* **签秩是衡量任务难度的指标**:签秩为我们提供了一个衡量检索任务的难度的理论机制。我们可以通过优化自由嵌入表示的梯度下降方法,为矩阵的签秩确定一个上限
1616

1717
#### 用一个比喻来理解
1818
* **嵌入维度**: 就像你拥有的乐高积木的种类和数量

docs/more/chapter5/向量.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
4. **理论边界探索**:Meta论文对嵌入模型根本限制的分析
1010
5. **实践与应用**:( o=^•ェ•)o🍚
1111

12-
关于更多的基础知识(比如BERT),强烈推荐去看宋博大佬的[Happy-LLM教程](https://datawhalechina.github.io/happy-llm/#/./chapter1/%E7%AC%AC%E4%B8%80%E7%AB%A0%20NLP%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5)建议你看完这个hayyp-llm以及FusionANNS后再来看现在的这篇文章。
12+
关于更多的基础知识(比如BERT),强烈推荐去看宋博大佬的[Happy-LLM教程](https://datawhalechina.github.io/happy-llm/#/./chapter1/%E7%AC%AC%E4%B8%80%E7%AB%A0%20NLP%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5)建议你看完这个happy-llm以及FusionANNS后再来看现在的这篇文章。
1313

1414
## 向量数据库:从"数据存储"到"语义理解"的范式跃迁
1515

@@ -75,7 +75,6 @@ TF-IDF的计算通常由两个主要部分构成:
7575
TF(猫, d) = \frac{5}{1000} = 0.005
7676
$$
7777

78-
那么TF值为:5/1000=0.005,
7978

8079
**对数词频缩放**
8180
另一种常见的处理方式是对词频取对数,以减缓词频增长带来的权重增加。这意味着词语出现次数从10次到20次的影响,要比从1次到10次的影响小。
@@ -108,7 +107,7 @@ $$
108107
TF-IDF巧妙地平衡了“局部重要性”和“全局稀有性”,使其在信息检索和文本挖掘领域具有广泛的应用价值:
109108

110109
* **惩罚常见词**:像“的”、“是”这样的高频词在许多文档中都会出现,它们的DF值会非常高,导致IDF值接近于零,也就是非常小。因此即使这些词的TF很高,其最终的TF-IDF值也会很低,从而被有效的降权,这使得算法可以忽略这些词对文档的贡献,专注于那些更具信息量的词,比如说上文提到的“量子纠缠”。
111-
* **突出关键词**:那些在当前文档中频繁出现(高TF),但在整个文档集合中相对稀有(高IDF)的词会得到最高的TF-IDF分数,这些次雨往往是关键词,它们往往代表文档的主题或内容。例如,在一篇关于“量子计算”的论文中,“量子计算”的TF会很高,同时由于它不是所有文档都常见的词,IDF也会相对较高,最终导致TF-IDF值很高。
110+
* **突出关键词**:那些在当前文档中频繁出现(高TF),但在整个文档集合中相对稀有(高IDF)的词会得到最高的TF-IDF分数,这些词语往往是关键词,它们往往代表文档的主题或内容。例如,在一篇关于“量子计算”的论文中,“量子计算”的TF会很高,同时由于它不是所有文档都常见的词,IDF也会相对较高,最终导致TF-IDF值很高。
112111
* **提供可解释性**:每个词的重要性都有明确的数学依据和直观的解释。我们可以清楚地看到一个词为什么重要(因为它在这篇文章里多,在所有文章里少),这使得TF-IDF模型的结果比一些“黑箱”模型更容易理解和验证。
113112
* **基石作用**:用户输入查询词时,搜索引擎会计算查询词与每个文档的TF-IDF相似度。通常,这通过计算查询词向量和文档词向量的余弦相似度来实现,其中向量的每个维度代表一个词语的TF-IDF值。余弦相似度可以衡量两个向量方向的相似性,从而判断查询与文档内容的匹配程度。然后,系统会按相关性排序,将最匹配的文档呈现给用户。
114113

@@ -216,7 +215,7 @@ BM25和Milvus的混合搜索是工程实战中企业最可能选择并且效益
216215

217216
BM25是一种经典的文本相关性评分算法,广泛应用于信息检索系统中,它是TF-IDF的改进版本,并且具有以下优势:
218217
* **词频饱和:** 词频增长到一定程度后对分数的贡献递减,避免高频词汇过度影响结果
219-
* **文档长度归一化:** 避免长文档应为包含更多关键词而获得不公平的高分
218+
* **文档长度归一化:** 避免长文档因为包含更多关键词而获得不公平的高分
220219
* **参数可调:** 通过k1和b参数调节算法行为
221220

222221
**2. BM25在搜索中的作用**
@@ -556,15 +555,15 @@ splade 代码实践[点这里](./code/colBert/zzmilvus.ipynb)
556555
### 问题背景
557556
对于用户查询的向量嵌入问题,需要召回相关文档内容,尽管先前的研究指出了向量嵌入的理论局限性,但人们普遍认为这些困难是由于用户的不切实际的查询请求导致的,而对于那些切实的查询请求,通过更好的训练数据和更大的模型就能克服困难。这篇论文证明了在现实场景中,即便是极其简单的查询,也会遇到局限性,即:证明了对于给定的嵌入维度d,存在无法返回前k个文档组合————无论查询是什么,为了证明这一理论极限适用于任何检索模型或训练数据集,论文作者测试了一种场景:向量本身直接通过测试数据进行优化。这使我们能够通过实验证明嵌入维度如何助力解决检索任务。作者发现,对于每个嵌入维度\((d)\),**都存在一个关键点,超过该点后,文档数量过多,导致嵌入维度无法对所有组合进行编码**。随后,我们收集了不同维度d下的这些关键点,并证明这种关系可以通过多项式函数进行经验建模。
558557

559-
总结:虽然先前的一些研究已经指出了向量嵌入的一些理论限制,但通常假设这些困难仅仅来源于不切实际的用户查询问题,或者可以通过更好的训练数据集和更大参数量的模型来客服。这篇论文的动机就是挑战这一假设,并证明即使在现实且简单的查询设置中,这些理论限制也可能出现。
558+
总结:虽然先前的一些研究已经指出了向量嵌入的一些理论限制,但通常假设这些困难仅仅来源于不切实际的用户查询问题,或者可以通过更好的训练数据集和更大参数量的模型来克服。这篇论文的动机就是挑战这一假设,并证明即使在现实且简单的查询设置中,这些理论限制也可能出现。
560559
### 方法
561560
在数学层面上,对于上面提到的问题进行一个证明:
562561

563562
参考论文3.3结论部分,简单的来说,3.3节提到的结论是关于向量嵌入模型表示能力的根本限制。它指出了:
564563
* **存在无法被d维嵌入捕获的检索任务**:对于任何固定的嵌入维度d,总会存在一些二进制相关性矩阵(你可以理解为一种用户的检索任务),是无法被d维嵌入模型精确表示的。这意味着,有些检索任务的难度太高,需要更高的嵌入维度才能被识别。
565564

566565
* **高签秩的检索任务更难**:检索任务的相关性矩阵如果具有较高的签秩,那么对于嵌入模型来说,他就更难被精确捕获,应为它需要更高的维度。
567-
* **签秩是衡量任务难度的指标**:签秩为我们提供了一个衡量检索任务的难度的理论机制。我们可以通过优化自由嵌入表示的梯度下降方法,为矩阵的签秩确定一个上线
566+
* **签秩是衡量任务难度的指标**:签秩为我们提供了一个衡量检索任务的难度的理论机制。我们可以通过优化自由嵌入表示的梯度下降方法,为矩阵的签秩确定一个上限
568567

569568
#### 用一个比喻来理解
570569
* **嵌入维度**: 就像你拥有的乐高积木的种类和数量

docs/projects/project1/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,41 @@ trainer.fit(train_dl)
222222
训练完成后,使用模型分别推理出用户 Embedding 和物品 Embedding,然后用 Annoy 构建物品向量索引,实现高效的近似最近邻召回。
223223

224224
```python
225+
<<<<<<< HEAD
225226
# 推理 Embedding
226227
user_embedding = trainer.inference_embedding(model=model, mode="user", data_loader=test_dl, model_path=save_dir)
227228
item_embedding = trainer.inference_embedding(model=model, mode="item", data_loader=item_dl, model_path=save_dir)
228229

229230
# 使用 Annoy 构建索引并召回
230231
from torch_rechub.utils.match import Annoy
232+
=======
233+
class FaissVectorStore:
234+
def __init__(self, dimension: int):
235+
"""初始化 Faiss 向量数据库"""
236+
self.dimension = dimension
237+
self.texts = []
238+
self.embeddings = []
239+
self.metadata = []
240+
self.index = faiss.IndexFlatIP(dimension) # 使用内积 (Inner Product) 进行余弦相似度搜索
241+
242+
def add_vectors(self, embeddings: List[List[float]], texts: List[str], metadata: Optional[List[Dict[str, Any]]] = None):
243+
"""向数据库添加向量及其对应的文本内容,可选添加元数据"""
244+
embeddings_array = np.array(embeddings, dtype=np.float32)
245+
246+
# 归一化以支持余弦相似度
247+
norms = np.linalg.norm(embeddings_array, axis=1, keepdims=True)
248+
embeddings_array = embeddings_array / (norms + 1e-8) # 添加极小值防止除以零
249+
250+
self.index.add(embeddings_array)
251+
self.texts.extend(texts)
252+
self.embeddings.extend(embeddings)
253+
254+
# 添加元数据(如果未提供,则默认为空字典)
255+
if metadata:
256+
self.metadata.extend(metadata)
257+
else:
258+
self.metadata.extend([{} for _ in texts])
259+
>>>>>>> 2d971f1 (fix code)
231260

232261
annoy = Annoy(n_trees=10)
233262
annoy.fit(item_embedding)

docs/public/images/qianyan3.png

-1.05 MB
Loading

0 commit comments

Comments
 (0)