SPLADE 在稀疏向量搜索中的原理与应用详解

今天看到Sentence Transformers v5.0 集成了许多稀疏嵌入模型。为了搞清楚什么稀疏嵌入模型以及应用,查到了SPLADE,比较巧合的是在paper reading分享的时候看到有同学分享了一片ACL 2025的工作也是基于SPLADE去做的。下面结合一些资料分享关于SPLADE 在稀疏向量搜索中的原理以及应用。

主要内容来自:https://www.pinecone.io/learn/splade/

在现代向量搜索出现之前,我们主要采用“传统”的词袋模型( Bag of Words, BOW)方法。基于这些方法,我们将待检索的文档(例如谷歌的网页)转化为一个词集(即词袋),进而生成一个表示词频的稀疏向量。TF-IDF 和 BM25 是其中典型的算法。

稀疏向量因其高效性、可解释性和精确的词语匹配特性,在信息检索领域曾广受欢迎。然而,它们远非完美。

稀疏向量搜索的工作方式与人类的自然表达存在脱节。我们在搜索信息时,通常很难预测目标文档中会包含哪些确切的词语。

稠密嵌入模型(Dense Embedding Models)在这方面提供了一定的帮助。利用稠密模型,我们可以基于“语义含义”进行搜索,而非仅仅依赖于词语匹配。然而,这些模型仍然有不足之处。

稠密嵌入模型需要大量数据进行微调(fine-tune),否则其性能可能不如稀疏方法。这对于难以获取数据且领域特定术语很重要的小众领域来说,是一个棘手的问题。

过去曾涌现出各种临时性的补救方案来应对这些挑战,包括复杂且(仍然不完美)的两阶段检索系统,以及查询和文档扩展或改写方法(我们将在后文探讨)。然而,这些方案都未能提供真正鲁棒、持久的解决方案。

幸运的是,该领域已取得显著进展,有望结合两者的优势。通过混合搜索 (Hybrid Search)技术,稀疏和稠密检索得以融合;而可学习的稀疏嵌入 (Learnable Sparse Embeddings)则有助于克服传统稀疏检索的不足。

本文将深入探讨可学习稀疏嵌入领域的最新进展——SPLADE (Sparse Lexical and Expansion model)模型 [1]。


稀疏向量与稠密向量

在信息检索中,向量嵌入(Vector Embeddings)将文档和查询表示为数值向量格式。这种格式使得我们能够在向量数据库中通过计算相似度来检索相似的向量。

稀疏向量和稠密向量是向量表示的两种不同形式,各有优缺点。

稀疏向量包含很多零值,非零值比例非常小。

TF-IDF 或 BM25 等稀疏向量具有高维度,但包含的非零值非常少(因此得名“稀疏”)。稀疏向量已有数十年的研究历史,由此产生了紧凑的数据结构和许多专门针对这类向量设计的高效检索算法。

稠密向量维度较低,但包含丰富信息,大多数或全部维度都包含非零值。这些向量通常由神经网络模型(如 Transformer)构建,因此能够表示更抽象的信息,例如文本的语义含义

总的来说,这两种方法的优缺点可以概括如下表:

稀疏检索

优点缺点
通常检索速度更快性能无法相比基线显著提升
具有良好的基线性能性能无法相比基线显著提升
不需要模型微调存在词汇不匹配问题
词汇精确匹配

密集检索

优点缺点
通过微调可以超越稀疏检索性能需要训练数据,在低资源场景下较困难
可以搜索类似人类的抽象概念泛化能力不强,特别是对于细分术语
支持多模态(文本、图像、音频等)和跨模态搜索(如文本到图像)比稀疏检索需要更多计算和内存资源
无法精确匹配
不易解释

理想情况下,我们希望结合两者的优势,但这很难实现。

两阶段检索

一种常见的处理方法是实现两阶段检索和排序系统(Two-stage Retrieval and Ranking)。在这种方案中,系统使用两个不同的阶段来检索和排序与给定查询相关的文档。

在第一阶段,系统使用稀疏检索方法召回大量候选文档。然后,这些文档被传递到第二阶段,使用稠密模型根据它们与查询的相关性重新排序结果。

两阶段检索系统包含一个稀疏检索器和一个稠密重排序器。

这种方法有一些优点:(1)对完整的文档集应用稀疏模型进行召回更高效;(2)对召回后较小的文档集使用较慢的稠密模型进行重排序可以更准确。通过这种方式,我们可以向用户返回更相关的结果。另一个优点是,重排序阶段与检索系统是分离的,这对于多用途的检索系统很有帮助。

然而,它并非完美。两阶段的检索和重排序可能比使用近似搜索算法的单阶段系统要慢。拥有两个阶段会带来更高的工程复杂性。最后,系统的性能依赖于第一阶段检索器能否返回相关的结果;如果第一阶段未能召回有用的内容,第二阶段的重排序也无济于事。

改进单阶段系统

由于两阶段检索存在固有的不足,大量研究致力于改进单阶段检索系统

单阶段检索系统。注意,检索器可以是稀疏、稠密,甚至两者兼具。

这方面的研究成果之一就是更鲁棒、更可学习的稀疏嵌入模型——其中性能最优的模型之一就是 SPLADE。

SPLADE(SparseLexical and Expansion model)模型的理念是:一个预训练语言模型(如 BERT)可以识别词语/子词(在本文中称为“词片段”或“词项”)之间的联系,并利用这些知识来增强我们的稀疏向量嵌入。

这通过两种方式实现:它允许我们为不同词项赋予相关性权重(例如,“the”这样的词项权重较低,而“orangutan”等不常用词权重较高);同时,它支持词项扩展(Term Expansion):包含除原始文本中出现词项之外的、相关但不同的备选词项。

词项扩展允许我们识别相关但不同的词项,并在稀疏向量检索步骤中使用它们。

SPLADE 最显著的优势在于它能够学习词项扩展,而非仅仅执行词项扩展。传统方法需要基于规则进行词项扩展,这既耗时又本质受限。而 SPLADE可以利用最优秀的语言模型来学习词项扩展,甚至可以根据句子的上下文对其进行微调。

尽管查询和文档包含许多相关的词项,但由于它们不是“精确匹配”,因此未能被识别。

词项扩展对于缓解词汇不匹配问题至关重要——这是查询和相关文档之间典型缺乏词项重叠的现象。

通过对查询进行词项扩展,我们将获得更大的重叠度,因为现在能够识别相似的词语。

由于语言的复杂性以及描述同一事物的多种方式,相关文档与查询之间可能存在很少甚至没有词项重叠,这是可以预期的。词项扩展正是为了解决这一问题。

SPLADE 嵌入构建过程

SPLADE 构建稀疏嵌入的过程是易于理解的。我们首先使用一个带有**掩码语言模型( Masked-Language Modeling, MLM)**头的 Transformer 模型,例如 BERT。

MLM 是许多 Transformer 常用的预训练方法。我们可以直接使用一个现成的预训练 BERT 模型。### BERT 模型介绍

如前所述,我们将使用带有 MLM 头的 BERT 模型。如果您熟悉 BERT 和 MLM,那很好;如果不熟悉,下面我们将进行分解。

BERT 是一种流行的 Transformer 模型。与所有 Transformer 一样,其核心功能是生成信息丰富的词元嵌入(Token Embeddings)。这具体意味着什么呢?

我们以文本 "Orangutans are native to the rainforests of Indonesia and Malaysia"(猩猩原产于印度尼西亚和马来西亚的雨林)为例。首先,我们会将这段文本**词元化(tokenize)**为 BERT 特定的子词词元:

text = ("Orangutans are native tothe rainforests of ""Indonesia and Malaysia"
)# create the tokens that will be input into the model
tokens = tokenizer(text, returntensors="pt")
tokens
{'inputids': tensor([[  101,  2030,  5654, 13210,  3619,  2024,  3128,2000,  1996, 18951,\2015,  1997,  6239,  1998,  6027,   102]]), 'tokentypeids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0]]), 'attentionmask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1]])}
# we transform the inputids to human-readable tokens
tokenizer.convertidstotokens(tokens["inputids"][0])
['[CLS]',\'or',\'##ang',\'##uta',\'##ns',\'are',\'native',\'to',\'the',\'rainforest',\'##s',\'of',\'indonesia',\'and',\'malaysia',\'[SEP]']

词元 ID 被映射到嵌入矩阵中学习到的词元嵌入。

这些词元会与一个**“嵌入矩阵(EmbeddingMatrix)”**相匹配,嵌入矩阵是 BERT 模型的第一层。在这个嵌入矩阵中,我们可以找到学习到的“向量嵌入(Vector Embeddings)”,它们是这些词语/子词词元的“数值表示”。

嵌入矩阵中的向量在有意义的向量空间中分别代表一个词元。

接下来,原始文本的词元表示会通过多个**“编码器块(Encoder Blocks)”**。这些编码器块基于文本的其余上下文,将越来越多的上下文信息编码到每个向量嵌入中。

在此之后,我们就得到了 Transformer 的**“输出(Output)”**:信息丰富的向量嵌入。每个嵌入都代表了先前的词元,但融入了从原始句子中提取的其他词元向量嵌入中获取的信息。

通过多个注意力编码器块处理初始词元嵌入,可以编码更多上下文信息,从而生成信息丰富的嵌入。

这个过程是 BERT 和其他所有 Transformer 模型的核心。然而,Transformer 的强大之处在于,这些信息丰富的向量可以用于众多不同的任务。通常,我们会给 Transformer 添加一个任务特定的“头(Head)”,将这些向量转换为其他形式,例如预测结果或稀疏向量

掩码语言模型头 (MLM Head)

MLM 头 是 BERT 模型常用的众多“头”之一。与大多数头不同,MLM 头用于 BERT 的初始预训练阶段。

其工作原理是:输入一个句子,例如 "Orangutans are native to the rainforests of Indonesia and Malaysia"。我们将文本进行词元化,然后用特殊的 [MASK] 词元随机替换部分词元。

可以使用 [MASK] 词元屏蔽任何词语或子词词元。

这个经过掩码处理的词元序列作为输入传递给 BERT。在另一端,我们将原始句子提供给 MLM 头。然后,对 BERT 和 MLM 头进行优化,使其能够预测被 [MASK] 词元替换的原始词语/子词词元。

MLM 头从每个输出logits 生成一个概率分布。这些概率表示对词汇表中每个词元代表 [MASK] 的预测。

为实现这一功能,MLM 头为每个词元位置输出 30522 个值。这30522 个值代表 BERT 的词汇表大小,并构成一个在词汇表上的概率分布。激活度最高的值对应的词元,即为该词元位置的词元预测结果。

MLM与稀疏向量

这 30522 个概率分布 wijw{ij}wij​ 指示了词汇表 VVV 中哪些词语/词元 jjj 最为重要。MLM 头为模型输入的每个词元 iii 输出这些分布。

MLM 头为每个词元(无论是否被掩码)提供一个概率分布。这些分布被聚合起来,得到重要性估计。

SPLADE 将所有这些概率分布聚合成一个单一的分布,称为重要性估计(Importance Estimation) wjw\jwj​。这个重要性估计就是 SPLADE 生成的稀疏向量。我们可以将所有这些概率分布组合成一个单一的分布,它告诉我们词汇表中的每个词元与输入句子的相关性

其计算公式如下:

w j = ∑ i ∈ t log ⁡ ( 1 + ReLU ( w i j ) ) w_j = \sum_{i \in t} \log(1 + \text{ReLU}(w_{ij})) wj=itlog(1+ReLU(wij))

其中:

i ∈ t i \in t it:表示输入词元集合 t t t 中的每一个词元 i i i

w i j w_{ij} wij:表示对于每个词元 i i i,模型预测的词汇表 V V V 中所有词元 j j j 的权重值。

这使得我们能够识别输入句子中不存在但相关的词元。例如,如果我们掩码了词语 rainforest(雨林),模型可能会对 jungle(丛林)、land(土地)和 forest(森林)等词返回较高的预测概率 w j w_j wj。这些词语及其相关的概率随后会在 SPLADE 构建的稀疏向量中得到体现。

这种**“学习到的”查询/文档扩展能力,即包含其他相关词项的能力,是 SPLADE 相较于传统稀疏方法的一个关键优势**。它基于学习到的词项关系和上下文,帮助我们最大程度地缓解词汇不匹配问题。

查询中的词项扩展可以大大增加查询与相关文档之间的重叠度,从而帮助我们缓解词汇不匹配问题。

由于许多 Transformer 模型都使用 MLM 进行预训练,因此有大量模型在预训练阶段学习了 MLM 头的权重,这些权重可以用于后续的 SPLADE 微调。

SPLADE 的不足之处

SPLADE 是缓解稀疏向量方法常见词汇不匹配问题的一种优秀方法。然而,我们还需要考虑它的一些局限性。

相较于其他稀疏方法,使用SPLADE 进行检索速度相对较慢。这主要有三个原因:

  1. SPLADE 查询和文档向量中的非零值数量通常多于传统稀疏向量,而现有的稀疏检索系统并未针对这一点进行优化。
  2. 非零值的分布偏离了传统稀疏检索系统所预期的分布,这也会导致速度变慢。
  3. 大多数稀疏检索系统不原生支持 SPLADE 向量,这意味着我们必须执行多步预处理和后处理,例如权重离散化等。

幸运的是,所有这些问题都有解决方案。针对原因 (1),SPLADE 的作者在模型的后续版本 (SPLADEv2) 中解决了这个问题,该版本最小化了查询向量中的非零值数量 [2]。

减少查询向量中的非零值数量是通过两个步骤实现的。首先,通过对原始池化策略进行最大池化(Max Pooling)修改,提高了 SPLADE 文档编码的性能:

wj=maxi∈tlog(1+ReLU(wij))w\j = max{i \in t}log(1 + ReLU(w{ij}))wj​=maxi∈t​log(1+ReLU(wij​))

其次,将词项扩展仅限于文档编码。得益于改进后的文档编码性能,即使去掉了查询扩展,性能依然优于原始的 SPLADE 模型。

原因 (2) 和 (3) 则可以通过使用 Pinecone 向量数据库解决。(2) 的解决方案在于 Pinecone 的检索引擎从头设计时就不依赖数据分布。Pinecone 支持实数值的稀疏向量,这意味着 SPLADE 向量天然就能得到支持。

SPLADE 实现示例

实现 SPLADE 有两种选择:直接使用 Hugging Face 的 Transformer 和 PyTorch,或者使用封装程度更高的官方 SPLADE 库。我们将演示这两种方法,先从 Hugging Face 和 PyTorch 的实现开始,以便理解其内部工作原理。

使用Hugging Face 和 PyTorch

首先,安装所有必需的库:

!pip install -U transformers torch

然后,初始化 BERT 的分词器(Tokenizer)和带有掩码语言模型(MLM)头的 BERT 模型。我们加载 naver/splade-cocondenser-ensembledistil 中经过微调的 SPLADE 模型权重。

from transformers import AutoModelForMaskedLM, AutoTokenizermodelid = 'naver/splade-cocondenser-ensembledistil'tokenizer = AutoTokenizer.frompretrained(modelid)
model = AutoModelForMaskedLM.frompretrained(modelid)

接下来,我们可以创建一个输入文档文本 text,对其进行词元化,并通过 model 处理,以生成 MLM 头的输出 logits。

tokens = tokenizer(text, returntensors='pt')
output = model(**tokens)
output
MaskedLMOutput(loss=None, logits=tensor([[[ -6.9833,  -8.2131,  -8.1693,  ...,  -8.1552,  -7.8168,  -5.8152],\[-13.6888, -11.7828, -12.5595,  ..., -12.4415, -11.5789, -12.0632],\[ -8.7075,  -8.7019,  -9.0092,  ...,  -9.1933,  -8.4834,  -6.8165],\...,\[ -5.1051,  -7.7245,  -7.0402,  ...,-7.5713,  -6.9855,  -5.0462],\[-23.5020, -18.8779, -17.7931,  ..., -18.2811, -17.2806, -19.4826],\[-21.6329,-17.7142, -16.6525,  ..., -17.1870, -16.1865, -17.9581]]],gradfn=<ViewBackward0>), hiddenstates=None, attentions=None)
output.logits.shape
torch.Size([1, 91, 30522])

我们得到了 91 个概率分布,每个分布的维度是 30522。要将其转换为 SPLADE 稀疏向量,我们执行以下操作:

importtorchvec = torch.max(torch.log(1 + torch.relu(output.logits)) * tokens.attentionmask.unsqueeze(-1),
dim=1)[0].squeeze()vec.shape
torch.Size([30522])
vec
tensor([0., 0., 0.,  ..., 0.,0., 0.], gradfn=<SqueezeBackward0>)

由于我们的向量是稀疏的,我们可以将其转换为更紧凑的字典格式,只保留非零值的位置和权重。

cols = vec.nonzero().squeeze().cpu().tolist()
print(f"非零值数量: {len(cols)}")# extract the non-zero values
weights = vec[cols].cpu().tolist()
# use to create a dictionary of token ID to weight
sparsedict = dict(zip(cols, weights))
sparsedict
非零值数量: 174```

{1000: 0.6246446967124939,
1039: 0.45678916573524475,
1052: 0.3088974058628082,
1997: 0.15812619030475616,
1999: 0.07194626331329346,
2003: 0.6496524810791016,
2024: 0.9411943554878235,
…,
29215: 0.3594200909137726,
29278: 2.276832342147827}


这是稀疏向量的最终格式,但还不太易于解释。我们可以将词元 ID 键转换为人类可读的纯文本词元。操作如下:```python
# extract the ID position to text token mappings
idx2token = {idx: token for token, idx in tokenizer.getvocab().items()
}
# map tokenIDs to human-readable tokens
sparsedicttokens = {idx2token[idx]: round(weight, 2) for idx, weight in zip(cols, weights)
}
# sort so we cansee most relevant tokens first
sparsedicttokens = {k: v for k, v in sorted(sparsedicttokens.items(),key=lambda item: item[1],reverse=True)
}
sparsedicttokens
{'pc': 3.02,'lace': 2.95,'programmed': 2.36,'##for': 2.28,'madagascar': 2.26,'death': 1.96,'##d': 1.95,'lattice':1.81,...,'carter': 0.0,'reg': 0.0}

现在我们可以看到稀疏向量中得分最高的词元,包括一些重要的领域特定词项,如 programmed(编程的)、cell(细胞)、lattice(晶格)、regulated(被调节的)等等。

使用 Naver Labs SPLADE 库

另一个更高级的替代方案是直接使用 SPLADE 官方库。我们可以通过 pip 安装它:pip install git+https://github.com/naver/splade.git。然后使用以下代码初始化相同的模型和构建向量的步骤:


sparsemodelid = 'naver/splade-cocondenser-ensembledistil'sparsemodel = Splade(sparsemodelid, agg='max')
sparsemodel.eval()

我们仍然需要使用 Hugging Face 分词器对输入文本进行词元化以获取 tokens,然后使用以下代码创建稀疏向量:

    sparseemb = sparsemodel(dkwargs=tokens)['drep'].squeeze()
sparseemb.shape
torch.Size([30522])

这些嵌入可以像之前使用 Hugging Face 和 PyTorch 方法那样,被处理成一个更小的稀疏向量字典。最终得到的数据是相同的。

向量比较示例

让我们看看如何实际比较我们的稀疏向量。我们将定义三个短文本。

texts = [\"Programmed cell death (PCD) is the regulated death of cells within an organism",\"How is thescheduled death of cells within a living thing regulated?",\"Photosynthesis is the process of storing light energy as chemical energy in cells"\
]

像之前一样,我们使用 tokenizer 对所有文本进行编码,使用 model 生成输出 logits,并将词元级别的向量转换为单一的稀疏向量。

tokens = tokenizer(texts, returntensors='pt',padding=True, truncation=True
)output = model(**tokens)
# aggregate the token-level vecs and transform to sparse
vecs = torch.max(torch.log(1 + torch.relu(output.logits)) * tokens.attentionmask.unsqueeze(-1), dim=1
)[0].squeeze().detach().cpu().numpy()
vecs.shape
(3, 30522)

现在我们得到了三个30522 维的稀疏向量。为了比较它们,我们可以使用余弦相似度(Cosine Similarity)或点积(Dot Product)计算。使用余弦相似度,我们执行以下操作:

importnumpy as npsim = np.zeros((vecs.shape[0], vecs.shape[0]))for i, vec in enumerate(vecs):sim[i,:] = np.dot(vec, vecs.T) / (np.linalg.norm(vec) * np.linalg.norm(vecs, axis=1))
sim
array([[1.        , 0.54609376, 0.20535842],\[0.54609376, 0.99999988, 0.20411882],\[0.2053584 , 0.20411879, 1.]])

最终得到以下相似度矩阵:

使用上面计算出的相似度值生成的相似度热力图。句子 1 和句子 2 共享最高的相似度(对角线除外,它们代表每个句子与自身的比较)。

可以看到,两个内容相似的句子(句 1 和句 2)的相似度得分自然高于与第三个不相关句子(句 3)的相似度得分。

—以上便是对 SPLADE 学习型稀疏嵌入的介绍。通过 SPLADE,我们可以使用高效的稀疏向量嵌入来表示文本,有助于解决词汇不匹配问题,同时兼顾精确词语匹配的能力。

我们也探讨了 SPLADE 在传统检索系统中的局限性,以及 SPLADEv2 和 Pinecone 这类数据分布无关检索系统如何克服这些问题。

该领域仍有许多工作可以开展。更多的研究和近期成果表明,结合稠密和稀疏表示的混合搜索 (Hybrid Search)索引能带来更多优势。通过这些以及其他众多进展,我们可以看到向量搜索正变得越来越精确和易用。


参考文献

[1] T. Formal, B. Piwowarski, S. Clinchant, SPLADE: Sparse Lexical and Expansion Model for First Stage Ranking (2021), SIGIR 21

[2] T. Formal, C. Lassance, B. Piwowarski, S. Clinchant, SPLADE v2: Sparse Lexical and Expansion Model for Information Retrieval (2021)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/89580.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/89580.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wpf的Binding之UpdateSourceTrigger

前言 在wpf界面开发中&#xff0c;Binding的源和目标之间可以通过Mode来决定数据的传递方向&#xff0c;同时数据传递时的触发条件也是可以有多种情况&#xff0c;多种情况由UpdateSourceTrigger属性来控制&#xff0c;该属性有Default、Explicit、LostFocus、PropertyChanged…

突破性进展:超短等离子体脉冲实现单电子量子干涉,为飞行量子比特奠定基础

关键词&#xff1a;量子计算、电子干涉测量、等离子体脉冲、马赫-曾德尔干涉仪、非绝热量子操控 研究背景 在量子计算领域&#xff0c;飞行量子比特&#xff08;flying qubits&#xff09;因其动态传播特性和通过库仑相互作用直接纠缠的能力&#xff0c;成为替代光子量子比特的…

Java调用百度地图天气查询服务获取当前和未来天气-以贵州省榕江县为例

目录 前言 一、百度天气查询服务 1、天气查询服务 2、查询API简介 二、UniHttp集成天气查询服务 1、定义访问接口 2、业务集成调用 三、天气检索成果 1、IDE检索结果输出 2、互联网天气对比 四、总结 前言 天气与人们的生活息息相关&#xff0c;无论是日常出行、农业…

Windows Excel文档办公工作数据整理小工具

在现代办公环境中&#xff0c;Excel 是处理数据不可或缺的工具&#xff0c;而 “Excel 工作圈小工具” 则如同为 Excel 量软件下载地址安装包 身打造的超级增效器&#xff0c;它是一个集合了大量 Excel 功能的绿色工具软件&#xff0c;能够显著提升你的工作效率。 这款软件虽然…

Node.js v22.5+ 官方 SQLite 模块全解析:从入门到实战

在 Node.js v22.5.0 及更高版本中&#xff0c;node:sqlite 模块作为内置模块被引入&#xff0c;为开发者提供了与 SQLite 数据库交互的官方支持。以下是关于 node:sqlite 模块的详细介绍&#xff1a; 一、模块启用与导入 启用方式&#xff1a;node:sqlite 模块目前处于活跃开…

API接口安全-2:签名、时间戳与Token如何联手抵御攻击

在API接口通信中&#xff0c;数据传输的安全性至关重要。无论是前端与后端的交互&#xff0c;还是企业间的接口对接&#xff0c;一旦缺乏有效的安全校验&#xff0c;攻击者可能通过抓包篡改参数&#xff08;如修改订单金额&#xff09;、重放攻击&#xff08;重复提交支付请求&…

Pull Request记录与Git commit签名

Pull Request记录 好久没有pull request了&#xff0c;浅浅记录一下流程 &#xff1a;Fork 原项目&#xff08;如果你没有写权限&#xff09;&#xff1a;打开原项目主页&#xff08;例如&#xff1a;github.com/your-professor/research-topic&#xff09;&#xff0c;点击右…

如何在C++交易系统中集成高性能回测与模拟撮合

DolphinDB 的高性能行情回放与模拟撮合引擎插件&#xff0c;为量化交易者提供了低延迟、高吞吐量的策略验证解决方案。对于已构建 C 回测框架的机构而言&#xff0c;直接在现有系统中集成撮合引擎&#xff0c;既能复用既有基础设施&#xff0c;又能获得 DolphinDB 的极速计算优…

【Laravel】 Laravel 智能验证规则生成器

Laravel 智能验证规则生成器:企业级增强方案 <?phpnamespace App\Services\Validation;use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; use Illuminate\Validation\…

讲基于优化的 IMU 与视觉信息融合

目录 视觉 SLAM 里的 Bundle Adjustment 问题 最小二乘基础概念 迭代下降法求解:下降法 最速下降法和牛顿法 阻尼法 非线性最小二乘 Gauss-Newton 和 LM 鲁棒核函数的实现 VIO 残差函数的构建 视觉重投影误差 IMU 测量值积分 状态误差线性递推公式的推导 基于误差随时间变化的…

洛谷P1107 [BJWC2008] 雷涛的小猫

洛谷P1107 [BJWC2008] 雷涛的小猫 洛谷题目传送门 题目背景 原最大整数参见 P1012 题目描述 雷涛同学非常的有爱心&#xff0c;在他的宿舍里&#xff0c;养着一只因为受伤被救助的小猫&#xff08;当然&#xff0c;这样的行为是违反学生宿舍管理条例的&#xff09;。在他的…

ROS2---话题重映射

一、话题重映射的基本概念 在 ROS2&#xff08;Robot Operating System 2&#xff09;中&#xff0c;话题重映射&#xff08;Topic Remapping&#xff09; 是一种灵活的机制&#xff0c;允许用户在不修改代码的情况下&#xff0c;改变节点发布或订阅的话题名称。这一机制在多机…

IOday4——7.3

1.思维导图 2.创建一个分支线程&#xff0c;在主线程中拷贝文件的前一部分&#xff0c;主线程拷贝文件的后一部分。 3.解读代码 info1 from child process_1 info2 from child process_1 info1 from child process_2 info1 from parent process 4.解读代码&#xff0c;打印…

[特殊字符] Excel 提取+图片批量插入 | Python 自动化生成稽查报告 Word 模板

本篇教程展示如何利用 Python&#xff0c;实现从 Excel 中提取稽查问题数据&#xff0c;并将对应图片按顺序插入到 Word 模板表格里&#xff0c;最终生成一份图文并茂的稽查报告。 目录 &#x1f4dd; Step 1&#xff1a;从 Excel 提取稽查问题数据 &#x1f5bc; Step 2&am…

【libm】 7 双精度正弦函数 (k_sin.rs)

一、源码 这段代码实现了一个高精度的正弦函数计算核心&#xff08;kernel sin function&#xff09;&#xff0c;用于计算在区间约[-π/4, π/4]内的正弦值。 // origin: FreeBSD /usr/src/lib/msun/src/k_sin.c // // // Copyright (C) 1993 by Sun Microsystems, Inc. Al…

c++ 的标准库 --- std::

在 C 的标准库&#xff08;std&#xff09;里&#xff0c;除了 std::string&#xff0c;还有很多常用的类型和工具。下面列举一些最常用的&#xff1a; 常用的 std:: 标准库类型 1. 容器类&#xff08;用来存放一组数据&#xff09; std::vector  // 动态数组&#xff0c;类…

用 PyTorch 构建液态神经网络(LNN):下一代动态深度学习模型

引言 在深度学习领域&#xff0c;研究人员不断探索更接近生物神经系统工作方式的模型。液态神经网络(Liquid Neural Networks, LNN)正是这样一种受生物神经元动态特性启发的创新架构。本文将带你了解LNN的核心概念&#xff0c;并展示如何使用PyTorch实现这种前沿模型。 一、什…

取消latex Beamer 中,右下角的导航按钮

取消 Beamer 右下角的导航按钮 在 Beamer 中,右下角的导航按钮(如上一页、下一页、目录等)是由主题(如 Boadilla)自动添加的。要移除它们,可以通过以下方法实现: 方法 1:使用 \setbeamertemplate{navigation symbols}{}(推荐) 在导言区(\begin{document} 之前)添…

LLaMA-Factory 单卡后训练微调Qwen3完整脚本

LLaMA-Factory 单卡后训练微调Qwen3完整脚本 flyfish 使用说明 将下面代码保存为 train_single_gpu.sh 修改脚本中的以下参数&#xff1a; MODEL_PATH&#xff1a;模型路径 DS_CONFIG_PATH&#xff1a;DeepSpeed配置文件路径 OUTPUT_PATH&#xff1a;输出目录路径 --dataset…

AI自动化神器-DroidRun使用体验

引言 DroidRun 是一个强大的框架&#xff0c;用于通过 LLM 代理控制 Android 设备。它允许您使用自然语言命令自动化 Android 设备交互。 特点 使用自然语言命令控制 Android 设备 支持多个 LLM 提供商(OpenAI、Anthropic、Gemini) 易于使用的 CLI 用于自定义自动化的可扩…