当前位置: 首页 > news >正文

构建大语言模型应用:句子转换器(Sentence Transformers)(第三部分)

本系列文章目录

  1. 简介
  2. 数据准备
  3. 句子转换器(本文)
  4. 向量数据库
  5. 搜索与检索
  6. 大语言模型
  7. 开源检索增强生成
  8. 评估
  9. 大语言模型服务
  10. 高级检索增强生成 RAG

在之前的博客中,我们学习了为RAG(检索增强生成,Retrieval Augmented Generation)进行数据准备,包括数据摄取(Data Ingestion)、数据预处理(Data Preparation)和分块(Chunking)。

由于在RAG过程中需要搜索相关的上下文块,我们必须将数据从文本格式转换为向量嵌入(vector embeddings)。因此,我们将探索通过句子转换器(Sentence Transformers)实现文本转换的最高效方法。

在这里插入图片描述

让我们从一些最常用的嵌入模型(embedding models)开始。

1. 嵌入模型(Embedding Models)

嵌入(Embeddings)是一种单词表示形式(通过数值向量),允许具有相似含义的单词具有相似的表示。

这些向量可以通过各种机器学习算法和大型文本数据集学习得到。词嵌入(word embeddings)的主要作用之一是为下游任务(如文本分类和信息检索)提供输入特征。

在这里插入图片描述

在过去十年中,已经提出了几种词嵌入方法,以下是其中一些:

在这里插入图片描述

1.1 上下文无关嵌入(Context-independent Embeddings)

上下文无关嵌入(Context-independent embeddings)重新定义了单词表示,无论上下文如何变化,都为每个单词分配唯一的向量。这种简洁的探索侧重于对同形异义词(homonym)消歧的影响。

  • 上下文无关模型为每个单词分配不同的向量,而不考虑上下文。
  • 像"duck"这样的同形异义词会获得单个向量,在没有上下文线索的情况下混合了多种含义。
  • 这种方法产生了一个全面的单词向量图,以固定表示形式捕捉多个含义。

在这里插入图片描述

上下文无关嵌入提供了效率,但在细微语言理解方面提出了挑战,特别是对于同形异义词。这种范式转变促使我们更仔细地研究自然语言处理中的权衡。

一些常见的基于频率的上下文无关嵌入:

词袋模型(Bag of Words)

词袋模型(Bag of Words)将创建一个包含所有句子中最常见单词的字典,然后对句子进行编码,如下所示。

在这里插入图片描述

TF-IDF

TF-IDF是一种从句子中查找特征的简单技术。在计数特征(Count features)中,我们计算文档中所有单词/ngrams的出现次数,而在TF-IDF中,我们只对重要单词提取特征。我们如何做到这一点?如果您考虑语料库中的一个文档,我们将关注该文档中任何单词的两个方面:

  • 词频(Term Frequency):单词在文档中的重要性如何?
    在这里插入图片描述

  • 逆文档频率(Inverse Document Frequency):该术语在整个语料库中的重要性如何?
    在这里插入图片描述

在这里插入图片描述

一些常见的基于预测的上下文无关嵌入:

Word2Vec:

Word2Vec中的词嵌入(word embeddings)是通过一个两层神经网络学习的,该网络在训练过程中无意中捕捉了语言上下文。这些嵌入作为算法主要目标的副产品展示,显示了这种方法的效率。Word2Vec通过两种不同的模型架构提供了灵活性:CBOW和连续skip-gram。

  • 连续词袋模型(Continuous Bag-of-Words, CBOW):
    • 从上下文单词的窗口中预测当前单词。
    • 强调上下文单词在预测目标单词时的协作影响。
  • 连续Skip-Gram:
    • 使用当前单词来预测上下文单词的窗口。
    • 侧重于目标单词在生成上下文单词时的预测能力。

在这里插入图片描述

Word2Vec的双模型架构在捕捉语言细微差别方面提供了多功能性,允许从业者根据其自然语言处理任务的具体要求在CBOW和连续skip-gram之间进行选择。理解这些架构之间的相互作用增强了Word2Vec在不同上下文中的应用。

在这里插入图片描述

GloVe(全局词向量表示,Global Vectors for Word Representation):

GloVe的优势在于其在训练过程中利用了从语料库中聚合的全局词-词共现统计信息。生成的表示不仅封装了语义关系,还揭示了词向量空间中有趣的线性子结构,为词嵌入的理解增添了深度。

FastText:

与GloVe相比,FastText采用了一种新颖的方法,将每个单词视为由字符n-gram组成。这一独特特性使FastText不仅能够学习罕见单词,还能优雅地处理词汇表外的单词(out-of-vocabulary words)。对字符级嵌入的强调使FastText能够捕捉形态学上的细微差别,提供了更全面的词汇表示。

1.2 上下文相关嵌入(Context-Dependent Embeddings)

上下文相关方法(Context-Dependent methods)根据上下文为同一个单词学习不同的嵌入。
在这里插入图片描述

基于RNN的模型:
  • ELMO(来自语言模型的嵌入,Embeddings from Language Model):基于具有基于字符的编码层和两个BiLSTM层的神经语言模型学习上下文相关的词表示。
  • CoVe(上下文相关的词向量,Contextualized Word Vectors):使用来自为机器翻译训练的注意力序列到序列模型的深度LSTM编码器来上下文化词向量。
基于Transformer的模型:
  • BERT(双向编码器表示来自Transformers,Bidirectional Encoder Representations from Transformers):基于Transformer的语言表示模型,在大型跨领域语料库上训练。应用掩码语言模型(masked language model)来预测序列中随机掩码的单词,随后是用于学习句子之间关联的下一句预测任务(next-sentence-prediction task)。
  • XLM(跨语言语言模型,Cross-lingual Language Model):这是一个使用下一词预测、类似BERT的掩码语言建模目标和翻译目标进行预训练的transformer。
  • RoBERTa(鲁棒优化的BERT预训练方法,Robustly Optimized BERT Pretraining Approach):它建立在BERT基础上,修改了关键超参数,移除了下一句预训练目标,并使用更大的小批次和学习率进行训练。
  • ALBERT(用于语言表示自监督学习的轻量级BERT,A Lite BERT for Self-supervised Learning of Language Representations):提出了参数减少技术,以降低内存消耗并提高BERT的训练速度。

2. BERT

BERT(Bidirectional Encoder Representations from Transformers)是由Google AI开发的自然语言处理领域的强大模型,重塑了语言模型的格局。本节将深入探讨其预训练方法和双向架构的复杂性。

  • 预训练(Pre-training):BERT通过两个无监督任务进行预训练——掩码语言建模(MLM,Masked Language Modeling)和下一句预测(NSP,Next Sentence Prediction)。在MLM任务中,系统会随机掩盖输入中15%的标记(tokens),目标是仅根据上下文预测被掩盖单词的原始词汇ID。

  • 除了掩码语言模型外,BERT还采用NSP任务联合预训练文本对表示。许多重要下游任务(如问答系统QA和自然语言推理NLI)都基于对两个句子关系的理解,而这是传统语言建模无法直接捕捉的。

  • 预训练数据(Pre-training data):预训练流程基本遵循语言模型预训练的现有文献规范。使用的预训练语料库包括:

    • BooksCorpus(8亿单词)
    • 英文维基百科(25亿单词)
  • 双向性(Bi-directional):与从左到右(left-to-right)的语言模型预训练不同,MLM目标使模型能够融合左右上下文信息,从而实现对深度双向Transformer的预训练。

BERT架构包含多个编码器层(encoder layers),每层对输入进行自注意力(self-attention)处理并传递到下一层。最小的BERT BASE变体包含:

  • 12个编码器层
  • 768个隐藏单元的FFNN块
  • 12个注意力头(attention heads)

在这里插入图片描述

2.1 输入表示(Input representations)

对于问答任务,BERT将由句子或句子对(例如,<问题,答案>)组成的序列作为输入,以一个标记(token)序列的形式输入。

在将输入序列输入到模型之前,会使用词块分词器(WordPiece Tokenizer)进行处理,该分词器的词表大小为30000个标记。它的工作方式是将一个单词拆分成几个子词(标记)。

特殊标记如下:

  • [CLS]:用作每个序列的第一个标记。与该标记对应的最终隐藏状态将用作分类任务的聚合序列表示。
  • [SEP]:句子对被打包成一个单一序列。我们通过两种方式区分句子。首先,我们使用一个特殊标记([SEP])将它们分开。其次,我们为每个标记添加一个已学习的嵌入,以指示它属于句子A还是句子B。
  • [PAD]:用于表示输入句子中的填充(空标记)。模型期望输入固定长度的句子。因此,根据数据集会固定一个最大长度。较短的句子会被填充,而较长的句子会被截断。为了明确区分真实标记和[PAD]标记,我们使用注意力掩码。

引入了段嵌入(Segmentation embedding)来指示给定标记属于第一个还是第二个句子。位置嵌入(Positional embedding)指示标记在句子中的位置。与原始的Transformer不同,BERT从绝对顺序位置学习位置嵌入,而不是使用三角函数。

对于给定的标记,其输入表示是通过将相应的标记嵌入、段嵌入和位置嵌入相加来构建的。

在这里插入图片描述

BERT输入表示:输入嵌入是标记嵌入、段嵌入和位置嵌入的总和。

在这里插入图片描述

使用BERT进行句子编码

为了获得标记嵌入,在嵌入层使用一个嵌入查找表(如上图所示),其中行表示词表中所有可能的标记ID(例如有30000行),列表示标记嵌入的维度。

2.2. 为什么选择句子BERT(S-BERT)而不是BERT?

到目前为止,一切都还不错,但这些Transformer模型在构建句子向量时存在一个问题:Transformer是使用词或标记级别的嵌入进行工作的,而不是句子级别的嵌入。

在句子Transformer出现之前,使用BERT计算准确句子相似度的方法是使用交叉编码器(cross-encoder)结构。这意味着我们会将两个句子输入到BERT中,在BERT的顶部添加一个分类头,然后使用它来输出一个相似度分数。

BERT交叉编码器架构由一个BERT模型组成,该模型处理句子A和句子B。两者都在同一个序列中进行处理,由一个[SEP]标记分隔。所有这些之后是一个前馈神经网络分类器,它输出一个相似度分数。

在这里插入图片描述

孪生(双编码器)架构在左侧显示,非孪生(交叉编码器)架构在右侧显示。主要区别在于左侧的模型同时接受两个输入。在右侧,模型并行接受两个输入,因此两个输出彼此不依赖。

在这里插入图片描述

交叉编码器(左)和双编码器(右)

交叉编码器网络确实能产生非常准确的相似度分数(比SBERT更好),但它不具有可扩展性。如果我们想要在一个包含10万个句子的小型数据集中进行相似度搜索,我们需要完成10万次交叉编码器推理计算。

为了对句子进行聚类,我们需要比较我们10万个句子数据集中的所有句子,这将导致接近5亿次比较——这根本不现实。

理想情况下,我们需要预先计算可以存储的句子向量,然后在需要时使用它们。如果这些向量表示良好,我们所需要做的就是计算它们之间的余弦相似度。使用原始的BERT(以及其他Transformer),我们可以通过对BERT输出的所有标记嵌入的值求平均来构建一个句子嵌入(如果我们输入512个标记,我们就会输出512个嵌入)。[方法一]

或者,我们可以使用第一个[CLS]标记的输出(一个特定于BERT的标记,其输出嵌入用于分类任务)。[方法二]

使用这两种方法中的任何一种都可以为我们提供句子嵌入,这些嵌入可以被存储并且比较速度要快得多,将搜索时间从65小时缩短到大约5秒。然而,准确性并不理想,甚至比使用平均的GloVe嵌入(2014年开发)还要差。

在这里插入图片描述

句子BERT(双编码器)

因此,使用BERT从1万个句子中找到最相似的句子对需要65个小时。使用SBERT,大约5秒内就能创建嵌入,并且使用余弦相似度进行比较大约只需0.01秒。

自从SBERT的论文发表以来,已经使用与训练原始SBERT类似的概念构建了更多的句子Transformer模型。它们都是在许多相似和不相似的句子对上进行训练的。

使用诸如softmax损失、多负例排名损失(multiple negatives ranking loss)或均方误差边际损失(MSE margin loss)等损失函数,这些模型被优化为对相似的句子生成相似的嵌入,对不相似的句子则生成不相似的嵌入。

推导独立的句子嵌入是BERT的主要问题之一。为了缓解这一方面的问题,开发了SBERT。

3. 句子Transformer

在这里插入图片描述

我们解释了使用BERT进行句子相似度计算的交叉编码器架构。SBERT与之类似,但去掉了最后的分类头,并且一次处理一个句子。然后,SBERT对最终输出层使用平均池化(mean pooling)操作来生成一个句子嵌入。

与BERT不同,SBERT使用孪生架构(siamese architecture)在句子对上进行微调。我们可以将其想象为有两个并行的相同BERT,它们共享完全相同的网络权重。

在这里插入图片描述

一个应用于句子对(句子A和句子B)的SBERT模型。请注意,BERT模型输出标记嵌入(由512个768维向量组成)。然后,我们使用一个池化函数将这些数据压缩成一个单一的768维句子向量。

实际上,我们使用的是单个BERT模型。然而,因为在训练期间我们将句子A和句子B作为对依次进行处理,所以将其想象为两个具有绑定权重的模型会更容易理解。

3.1. 孪生BERT预训练

在这里插入图片描述

训练句子Transformer有不同的方法。我们将描述原始SBERT论文中最突出的原始过程,该过程基于softmax损失进行优化。

softmax损失方法使用在斯坦福自然语言推理(Stanford Natural Language Inference,SNLI)和多体裁自然语言推理(Multi-Genre NLI,MNLI)语料库上微调的“孪生”架构。

SNLI包含57万个句子对,MNLI包含43万个句子对。这两个语料库中的句子对都包含一个前提和一个假设。每对句子被分配三个标签之一:

  • 0 — 蕴含(entailment),例如前提暗示了假设。
  • 1 — 中立(neutral),前提和假设都可能是真的,但它们不一定相关。
  • 2 — 矛盾(contradiction),前提和假设相互矛盾。

给定这些数据,我们将句子A(假设是前提)输入到孪生BERT A中,将句子B(假设是假设)输入到孪生BERT B中。

孪生BERT输出我们池化后的句子嵌入。在SBERT论文中有三种不同池化方法的结果。它们是平均池化(mean)、最大池化(max)和[CLS]池化。对于NLI和STSb数据集,平均池化方法的性能最佳。

现在有两个句子嵌入。我们将嵌入A称为u,嵌入B称为v。下一步是连接u和v。同样,测试了几种连接方法,但性能最高的是一个(u, v, |u-v|)操作:
在这里插入图片描述

我们连接嵌入u、v和|u — v|。

|u-v|是通过计算得到的,用于给出两个向量之间的元素级差异。除了原始的两个嵌入(u和v)之外,这些都被输入到一个具有三个输出的前馈神经网络(FFNN)中。

这三个输出与我们的NLI相似度标签0、1和2相对应。我们需要计算来自FFNN的softmax,这是在交叉熵损失函数中完成的。softmax和标签用于对这个“softmax损失”进行优化。

在这里插入图片描述

在训练期间对两个句子嵌入u和v执行这些操作。请注意,softmax损失指的是交叉熵损失(默认情况下包含一个softmax函数)。

这使得我们对于相似句子(标签0)的池化句子嵌入变得更加相似,对于不相似句子(标签2)的嵌入变得更加不相似。

记住我们使用的是孪生BERT,而不是双BERT。这意味着我们不使用两个独立的BERT模型,而是使用一个先处理句子A再处理句子B的单个BERT。

这意味着当我们优化模型权重时,它们会朝着一个方向调整,使得模型在看到蕴含标签时输出更相似的向量,在看到矛盾标签时输出更不相似的向量。

4. SBERT目标函数

通过使用这两个向量u和v,下面讨论了优化不同目标的三种方法。

4.1. 分类

将三个向量u、v和|u-v|连接起来,乘以一个可训练的权重矩阵W,然后将乘法结果输入到softmax分类器中,该分类器输出与不同类别相对应的句子的归一化概率。使用交叉熵损失函数来更新模型的权重。
在这里插入图片描述

用于分类目标的SBERT架构。参数n表示嵌入的维度(对于BERT基础模型,默认值为768),而k表示标签的数量。

4.2. 回归

在这种公式化方法中,在得到向量u和v之后,它们之间的相似度分数直接通过一个选定的相似度度量来计算。将预测的相似度分数与真实值进行比较,并使用均方误差(MSE)损失函数来更新模型。
在这里插入图片描述

用于回归目标的SBERT架构。参数n表示嵌入的维度(对于BERT基础模型,默认值为768)。

4.3. 三元组损失

三元组目标引入了一个三元组损失,它是在通常被称为锚点(anchor)、正例(positive)和负例(negative)的三个句子上计算的。假设锚点和正例句子彼此非常接近,而锚点和负例句子则非常不同。在训练过程中,模型评估(锚点,正例)对与(锚点,负例)对相比的接近程度。

在这里插入图片描述

三元组SBERT架构

目前,让我们看看如何初始化和使用这些句子Transformer模型。

5. 实践句子Transformer

开始使用句子Transformer的最快、最简单的方法是通过由SBERT的创建者开发的sentence-transformers库。我们可以使用pip安装它。

!pip install sentence-transformers

我们将从原始的SBERT模型bert-base-nli-mean-tokens开始。首先,我们下载并初始化该模型。

from sentence_transformers import SentenceTransformer
model = SentenceTransformer('bert-base-nli-mean-tokens')
model

输出:

SentenceTransformer((0): Transformer({'max_seq_length': 128, 'do_lower_case': False}) with Transformer model: BertModel (1): Pooling({'word_embedding_dimension': 768, 'pooling_mode_cls_token': False, 'pooling_mode_mean_tokens': True, 'pooling_mode_max_tokens': False, 'pooling_mode_mean_sqrt_len_tokens': False})
)

我们在这里看到的输出是SentenceTransformer对象,它包含三个组件:

  • Transformer本身,在这里我们可以看到最大序列长度为128个标记,以及是否将任何输入转换为小写(在这种情况下,模型不转换)。我们还可以看到模型类,BertModel
  • 池化操作,在这里我们可以看到我们正在生成一个768维的句子嵌入。我们使用的是平均池化方法。

一旦我们有了模型,使用encode方法可以快速构建句子嵌入。

sentences = ["the fifty mannequin heads floating in the pool kind of freaked them out","she swore she just saw her sushi move","he embraced his new life as an eggplant","my dentist tells me that chewing bricks is very bad for your teeth","the dental specialist recommended an immediate stop to flossing with construction materials"
]embeddings = model.encode(sentences)embeddings.shape

输出:

(5, 768)

6. 选择哪种嵌入模型?

然而,我们很快就会发现,目前使用的大多数嵌入模型都属于Transformer类别。这些模型由不同的提供商提供,有些是开源的,有些是专有的,每个模型都针对特定的目标进行了定制:

  • 有些最适合编码任务。
  • 有些专门为英语设计。
  • 还有一些嵌入模型在处理多语言数据集方面表现出色。

最简单的方法是利用现有的学术基准。然而,必须记住,这些基准可能无法全面反映人工智能应用中检索系统在现实世界中的使用情况。

或者,你可以使用各种嵌入模型进行测试,并编制一个最终的评估表,以确定最适合你特定用例的模型。我强烈建议在此过程中加入一个重排器(re-ranker),因为它可以显著提高检索器的性能,最终产生最佳结果。

为了简化你的决策过程,Hugging Face提供了卓越的大规模文本嵌入基准(Massive Text Embedding Benchmark,MTEB)排行榜。这个资源提供了关于所有可用嵌入模型及其在各种指标上的相应分数的全面信息:
在这里插入图片描述

如果你选择第二种方法,有一篇优秀的博客文章展示了如何利用LlamaIndex的检索评估模块。这个资源可以帮助你有效地评估和识别从初始模型列表中最适合的嵌入和重排器组合。
在这里插入图片描述

我相信,现在你在为你的RAG架构选择最合适的嵌入和重排模型时,能更好地做出明智的决策了!

结论

这篇博客探讨了用于生成文本向量表示的各种嵌入模型,包括词袋模型(Bag of Words,BoW)、词频-逆文档频率(TF-IDF)、Word2Vec、GloVe、FastText、ELMO、BERT等。它深入研究了BERT的架构和预训练,引入了用于高效句子嵌入的句子BERT(SBERT),并提供了一个使用sentence-transformers库的实践示例。结论强调了选择合适嵌入模型的挑战,并建议利用Hugging Face大规模文本嵌入基准(MTEB)排行榜等资源进行评估。

致谢

在这篇博客文章中,我们从各种来源收集了信息,包括研究论文、技术博客、官方文档、YouTube视频等。每个来源都在相应的图片下方进行了适当的标注,并提供了来源链接。

以下是参考资料的综合列表:

  • https://jina.ai/news/the-1950-2024-text-embeddings-evolution-poster/
  • https://partee.io/2022/08/11/vector-embeddings/
  • https://www.nlplanet.org/course-practical-nlp/01-intro-to-nlp/11-text-as-vectors-embeddings
  • https://www.deeplearning.ai/resources/natural-language-processing/
  • https://www.mygreatlearning.com/blog/word-embedding/#sh4
  • https://mlwhiz.com/blog/2019/02/08/deeplearning_nlp_conventional_methods/
  • https://vitalflux.com/bert-vs-gpt-differences-real-life-examples/
  • https://d3mlabs.de/?p=1169
  • https://www.linkedin.com/pulse/why-does-bert-stand-out-sea-sentence-embedding-models-bhaskar-t-bi6wc%3FtrackingId=RKK3MNdP8pugx6iyhwJ2hw%253D%253D/?trackingId=RKK3MNdP8pugx6iyhwJ2hw%3D%3D
  • https://www.amazon.science/blog/improving-unsupervised-sentence-pair-comparison
  • https://www.researchgate.net/figure/Sentence-BERT-model_fig3_360530243
  • https://www.youtube.com/watch?app=desktop&v=O3xbVmpdJwU
  • https://www.pinecone.io/learn/series/nlp/sentence-embeddings/
  • https://towardsdatascience.com/sbert-deb3d4aef8a4
  • https://huggingface.co/spaces/mteb/leaderboard
  • https://medium.com/@vipra_singh/building-llm-applications-sentence-transformers-part-3-a9e2529f99c1

相关文章:

构建大语言模型应用:句子转换器(Sentence Transformers)(第三部分)

本系列文章目录 简介数据准备句子转换器&#xff08;本文&#xff09;向量数据库搜索与检索大语言模型开源检索增强生成评估大语言模型服务高级检索增强生成 RAG 在之前的博客中&#xff0c;我们学习了为RAG&#xff08;检索增强生成&#xff0c;Retrieval Augmented Generati…...

新能源汽车空调系统(R134A)性能评估(一)

国内外主流空调系统厂家&#xff1a;贝尔、德尔福、空调国际、法雷奥、电装、松芝、杰信、新电、豫新等 泛亚汽车的空调电子部是比较优秀的整车空调研发团队。 空调系统综合试验台架是一套由试验室、风量测定装置、空气调和器、空气温度测定装置、湿度测定装置、加热器试验辅助…...

STRUCTBERT:将语言结构融入预训练以提升深度语言理解

【摘要】最近&#xff0c;预训练语言模型BERT&#xff08;及其经过稳健优化的版本RoBERTa&#xff09;在自然语言理解&#xff08;NLU&#xff09;领域引起了广泛关注&#xff0c;并在情感分类、自然语言推理、语义文本相似度和问答等各种NLU任务中达到了最先进的准确率。受到E…...

MCP协议的Streamable HTTP:革新数据传输的未来

引言 在数字化时代&#xff0c;数据传输的效率和稳定性是推动技术进步的关键。MCP&#xff08;Model Context Protocol&#xff09;作为AI生态系统中的重要一环&#xff0c;通过引入Streamable HTTP传输机制&#xff0c;为数据交互带来了革命性的变化。本文将深入解读MCP协议的…...

基于 RK3588 的 YOLO 多线程推理多级硬件加速引擎框架设计(代码框架和实现细节)

一、前言 接续上一篇文章&#xff0c;这个部分主要分析代码框架的实现细节和设计理念。 基于RK3588的YOLO多线程推理多级硬件加速引擎框架设计&#xff08;项目总览和加速效果&#xff09;-CSDN博客https://blog.csdn.net/plmm__/article/details/146542002?spm1001.2014.300…...

stm32 can 遥控帧的问题

STM32单片机使用CAN协议进行通信 引用这个博客的一段话 CAN的遥控帧&#xff08;Remote Frame&#xff09;的主要作用是请求其他节点发送具 有特定ID的数据帧。具体来说&#xff0c;当一个节点需要从另一个节点获取数 据时&#xff0c;它可以发送一个遥控帧&#xff0c;而不是…...

机器人基础知识-1

1.六轴机器人中的六轴是什么&#xff1f; 第一轴&#xff08;J1&#xff09;&#xff1a;底座旋转 控制机器人整体绕垂直轴旋转&#xff08;左右摆动&#xff09;&#xff0c;决定工作范围的水平方向。 第二轴&#xff08;J2&#xff09;&#xff1a;下臂前后摆动 驱动机器人的…...

JAVA- 锁机制介绍 进程锁

进程锁 基于文件的锁基于Socket的锁数据库锁分布式锁基于Redis的分布式锁基于ZooKeeper的分布式锁 实际工作中都是集群部署&#xff0c;通过负载均衡多台服务器工作&#xff0c;所以存在多个进程并发执行情况&#xff0c;而在每台服务器中又存在多个线程并发的情况&#xff0c;…...

如何在WordPress中强制用户使用强密码?

在如今网络安全备受关注的环境下&#xff0c;弱密码问题不容忽视。很多用户习惯在多个网站使用相同且简单的密码&#xff0c;这样一来&#xff0c;若不强制他们在 WordPress 网站上使用强密码&#xff0c;网站的安全性就会受到威胁。尤其对于在线商店、会员网站、多作者博客等站…...

鸿蒙NEXT开发Base64工具类(ArkTs)

import util from ohos.util;/*** Base64 工具类* author: 鸿蒙布道师* since: 2025/03/31*/ export class Base64Util {/*** 创建 Base64Helper 实例* returns Base64Helper 实例*/private static createBase64Helper(): util.Base64Helper {return new util.Base64Helper();}…...

基于HUTOOL实现RSA工具类

一、前言&#xff1a;用 Hutool 简化 RSA 加密开发&#xff0c;提升代码安全与效率 在当今数据安全至关重要的时代&#xff0c;RSA 非对称加密作为保护敏感信息的核心技术&#xff0c;广泛应用于通信加密、数字签名、密钥交换等场景。然而&#xff0c;手动实现 RSA 算法涉及复…...

flink 分组窗口聚合 与 窗口表值函数聚合 的区别

警告&#xff1a;分组窗口聚合已经过时。推荐使用更加强大和有效的窗口表值函数聚合。 参考官方文档 在 Apache Flink 中&#xff0c;分组窗口聚合&#xff08;Group Window Aggregation&#xff09; 和 窗口表值函数聚合&#xff08;Windowing TVF Aggregation&#xff09;…...

prompt_status:5: command not found: wc解决办法

问题出现背景 想配置uniapp的命令行&#xff0c;在.zprofile配置路径的时候PATH 前面少打了一个$&#xff0c;执行了 source&#xff0c;导致各种命令都失效。 解决办法 用fider 打开用户文件夹&#xff0c;Command Shift .显示隐藏文件&#xff0c;用文本编辑器修改一下&…...

《STL 六大组件之容器篇:简单了解 list》

目录 一、list 简介二、list 的常用接口1. 构造函数&#xff08;constructor &#xff09;2. 迭代器&#xff08;iterator&#xff09;3. 容量、修改和访问&#xff08;capacity 、modify and access&#xff09; 一、list 简介 简单来说&#xff0c;list 就是数据结构初阶中学…...

向量数据库学习笔记(2) —— pgvector 用法 与 最佳实践

关于向量的基础概念&#xff0c;可以参考&#xff1a;向量数据库学习笔记&#xff08;1&#xff09; —— 基础概念-CSDN博客 一、 pgvector简介 pgvector 是一款开源的、基于pg的、向量相似性搜索 插件&#xff0c;将您的向量数据与其他数据统一存储在pg中。支持功能包括&…...

TCP的连接建立

面向连接 定义&#xff1a;在发送数据之前&#xff0c;需要建立一条点到点的连接 &#xff08;参数协商的过程。因为tcp要保证可靠&#xff0c;所以tcp通信是发生在双方之间、两端之间的&#xff0c;两端在正式发送数据之前需要约定一些初始参数&#xff0c;这个过程就是面向连…...

如何让AI帮你做用户运营:用户消费偏好分层和洞察

随着deepseek的爆火&#xff0c;我一直在想能不能用AI来帮我做用户运营&#xff0c;目前deepseek只能提供框架层面的运营建议&#xff0c;还无法实现将订单数据给到它&#xff0c;能够自动化分析并将用户分层&#xff0c;并给出可视化的运营洞察报表。但是&#xff0c;我要告诉…...

二分答案-P8647 [蓝桥杯 2017 省 AB] 分巧克力

题解&#xff1a;P8647 [蓝桥杯 2017 省 AB] 分巧克力 题目传送门 题目链接 一、题目描述 小明有N块不同尺寸的巧克力&#xff0c;需要切出K块相同大小的正方形巧克力分给小朋友们。要求找到能满足条件的最大的正方形边长。 二、题目分析 我们需要从N块巧克力中切出K个相…...

搜广推校招面经六十一

美团推荐算法 一、ANN算法了解么&#xff1f;说几种你了解的ANN算法 ANN 近似最近邻搜索&#xff08;Approximate Nearest Neighbor Search&#xff09;算法 1.1. KD-Tree&#xff08;K-Dimensional Tree&#xff0c;K 维树&#xff09; 类型: 空间划分数据结构适用场景: 低…...

某地老旧房屋自动化监测项目

1. 项目简介 自从上个世纪90年代以来&#xff0c;我国经济发展迅猛&#xff0c;在此期间大量建筑平地而起&#xff0c;并且多为砖混结构的住房&#xff0c;使用寿命通常约为30-50年&#xff0c;钢筋混凝土结构&#xff0c;钢结构等高层建筑&#xff0c;这些建筑在一般情况下的…...

【第一节】Python爬虫基础-HTTP基本原理

目录 前言 一、URI和URL是什么 二、什么是超文本 三、HTTP和HTTPS的区别 四、HTTP请求过程 五、请求 六、响应 前言 在着手开发爬虫程序之前&#xff0c;我们需要先掌握一些基础概念。本节将详细讲解HTTP的基本工作原理&#xff0c;重点分析从浏览器输入网址到获取网页内…...

docker打包使用有头模式playwright

1.打包镜像 创建Dockerfile文件如下 # playywright 官方镜像 FROM mcr.microsoft.com/playwright:v1.37.0-jammy# 设置非交互式环境变量和时区 ENV DEBIAN_FRONTENDnoninteractive ENV TZEtc/UTC# 安装 Python 3.9 和 pip&#xff08;修复时区阻塞问题&#xff09; RUN apt-g…...

VuePress 和 Docusaurus的对比

VuePress 和 Docusaurus 是两个流行的现代静态网站生成器 vuepress:首页 | VuePress Docusaurus&#xff1a;Docusaurus 博客 | Docusaurus中文文档 | Docusaurus中文网 一、技术栈和设计理念 VuePress 技术栈&#xff1a;基于Vue.js&#xff0c;专为技术文档设计&#xff0c…...

JAVA数据库增删改查

格式 Main.java(测试类) package com.example;import com.example.dao.UserDao; import com.example.model.User;public class Main {public static void main(String[] args) {UserDao userDao new UserDao();// 测试添加用户System.out.println(" 添加用户 ");Us…...

MSTP多域生成树

协议信息 MSTP 兼容 STP 和 RSTP&#xff0c;既可以快速收敛&#xff0c;又提供了数据转发的多个冗余路径&#xff0c;在数据转发过程中实现 VLAN 数据的负载均衡。 MSTP 可以将一个或多个 VLAN 映射到一个 Instance&#xff08;实例&#xff09;&#xff08;一个或多个 VLAN…...

HashMap 在 JDK 1.7 和 JDK 1.8 有什么区别

HashMap 在 JDK 1.7 和 JDK 1.8 中的实现存在显著差异&#xff0c;主要体现在以下几个方面&#xff1a; 1. 数据结构的变化 • JDK 1.7&#xff1a;HashMap 的底层数据结构是数组 单向链表。当哈希冲突发生时&#xff0c;新的元素会插入到链表的头部&#xff08;头插法&#…...

Mysql忽略大小写

🚀欢迎来到我的【Mysql】专栏🚀 🙋我是小蜗,一名在职牛马。🐒我的博客主页​​​​​​ ➡️ ➡️ 小蜗向前冲的主页🙏🙏欢迎大家的关注,你们的关注是我创作的最大动力🙏🙏在 MySQL 中取消大小写区分主要涉及以下两个层面的配置,具体操作如下: 一、表名大…...

基于TradingView和CTPBee的自动化期货交易系统实现

引言 在量化交易领域&#xff0c;TradingView因其强大的技术分析工具和丰富的指标库而广受欢迎&#xff0c;但是其不支持国内期货自动化交易&#xff0c;CTPBee则是一个优秀的国产Python期货交易接口。本文将介绍如何将两者结合&#xff0c;实现一个完整的自动化交易系统。 本…...

昇腾CANN算子共建仓CANN-Ops正式上线Gitee,首批算子已合入

在人工智能技术呈指数级发展的今天&#xff0c;AI创新已走向更底层的算法创新&#xff0c;以DeepSeek为例&#xff0c;通过MoE模型架构和底层算法创新&#xff0c;不仅获取极佳的模型性能&#xff0c;又更大程度释放硬件性能&#xff0c;降低硬件使用成本。 算子&#xff0c;作…...

基于PyQt5的自动化任务管理软件:高效、智能的任务调度与执行管理

基于PyQt5的自动化任务管理软件&#xff1a;高效、智能的任务调度与执行管理 相关资源文件已经打包成EXE文件&#xff0c;可双击直接运行程序&#xff0c;且文章末尾已附上相关源码&#xff0c;以供大家学习交流&#xff0c;博主主页还有更多Python相关程序案例&#xff0c;秉着…...

Pycharm(八):字符串切片

一、字符串分片介绍 对操作的对象截取其中一部分的操作&#xff0c;比如想要获取字符串“888666qq.com前面的qq号的时候就可以用切片。 字符串、列表、元组都支持切片操作。 语法&#xff1a;字符串变量名 [起始:结束:步长] 口诀&#xff1a;切片其实很简单&#xff0c;只顾头来…...

C++编程学习笔记:函数相关特性、引用与编译流程

目录 一、函数的缺省参数 &#xff08;一&#xff09;全缺省参数 &#xff08;二&#xff09;半缺省参数 二、函数重载 &#xff08;一&#xff09;参数类型不同 &#xff08;二&#xff09;参数个数不同 &#xff08;三&#xff09;参数类型顺序不同 三、引用相关问题…...

Nginx 配置 HTTPS 与 WSS 完整指南

Nginx 配置 HTTPS 与 WSS 完整指南 本教程将手把手教你如何为网站配置 HTTPS 加密访问&#xff0c;并通过反向代理实现安全的 WebSocket&#xff08;WSS&#xff09;通信。以 https://www.zhegepai.cn 域名为例&#xff0c;完整流程约需 30 分钟完成。 一、前置准备 1.1 域名…...

链表基本操作

文章目录 1、单链表1.1 链表的创建1.2 链表的遍历1.3 链表的删除1.4 链表的插入1.5 链表和数组 2、双向链表2.1 双链表的创建2.2 双链表的删除2.3 双链表的插入2.4 双向循环链表2.5 双链表优缺点 1、单链表 链表是一种物理存储单元上非连续、非顺序的存储结构&#xff0c;插入…...

【huggingface 数据下载】ssh / https 不同的下载流程,hf 镜像下载注意事项

ssh 下载流程 在 linux 服务器上生成 ssh key将 pub key 放入 huggingface 的 setting 中通过 git lfs install 然后 git clone githf.co … 来下载数据 遇到的问题 一直卡在 Updating files 后 卡住的可能原因&#xff1a; 系统当前限制了允许监视的最大文件数&#xff1…...

简单版CentOS7配置haproxy

一、实验步骤 1、自行下载pes的tar包 然后解压到家目录下 tar -xzvf pes.tar.gz 2、创建一个目录 mkdir docker-compose-pes-lb2 3、在这个目录下写两个文件docker-compose.yml和haproxy.cfg docker-compose.yml version: 3 services: db: image: mysql:5.7.44 container…...

leetcode146.LRU缓存

思路源自 【面试高频】146. LRU 缓存 采用哈希表双向链表 put一个键值对时&#xff0c;采用头插法将缓存块置于等级较高的位置&#xff0c;如果put数量超出限制&#xff0c;那么就将尾部的缓存块删除&#xff0c;以此达到置换的一个效果 get一个键值对也是同样的思路&#xf…...

SpringIoC和DI

文章目录 OCP开闭原则DIP(依赖倒置原则)IOC(控制反转)依赖注入DI基于XML配置Beanset注入构造注入 使用注解存储beanController方法注解Bean扫描路径依赖注入三种注入方式优缺点分析 引入 当我们写了一个程序&#xff0c;遵循SpringMVC三层架构&#xff0c;表现层调用业务逻辑层…...

vue 路由

目录 一、路由的使用 二、声明式导航 2.1 声明式导航 2.2 声明式导航路由传参 2.2.1.字符串写法 2.2.2.对象写法 2.2.3 query 传参和 param 传参总结 2.3 命名路由 2.4 可选操作符 2.5 props 参数 三、编程式导航 3.1 replace 和 push 跳转…...

JAVA常见的 JVM 参数及其典型默认值

在 Java 线上应用中&#xff0c;JVM 参数的默认值取决于具体的 JVM 实现&#xff08;如 Oracle JDK、OpenJDK、Zulu 等&#xff09;、版本&#xff08;如 Java 8、11、17 等&#xff09;以及运行环境&#xff08;物理机、容器等&#xff09;。以下是常见的 JVM 参数及其典型默认…...

文件压缩与解压(zip4j)

maven依赖 <dependency><groupId>net.lingala.zip4j</groupId><artifactId>zip4j</artifactId><version>2.11.5</version></dependency>示例 //参数配置ZipParameters parameters new ZipParameters();parameters.setCompres…...

【操作系统】查内存泄漏方法

【操作系统】查内存泄漏方法 1. 通用检测方法1.1 代码审查1.2 运行时监测 2.Linux平台检测工具2.1 Valgrind工具套件2.2 AddressSanitizer (ASan)2.3 mtrace 3.Windows平台检测工具3.1 Visual Studio诊断工具3.2 CRT调试堆 4.嵌入式系统检测方法4.1 RT-Thread内存检测4.2 自定义…...

oracle常用sql

获取主键 1. 查询主键的两种常用方法 Oracle 的主键信息存储在以下两个视图中&#xff1a; USER_CONSTRAINTS&#xff1a;存储当前用户下所有表的约束信息&#xff08;如主键、外键等&#xff09;。 USER_CONS_COLUMNS&#xff1a;存储约束对应的列信息。 方法 1&#xff…...

【第十三届“泰迪杯”数据挖掘挑战赛】【2025泰迪杯】【思路篇】A题解题全流程(持续更新)

【第十三届“泰迪杯”数据挖掘挑战赛】【2025泰迪杯】A题解题全流程-思路&#xff08;持续更新&#xff09; 写在前面&#xff1a; 1、A题、C题将会持续更新&#xff0c;陆续更新发布文章 2、赛题交流咨询Q群&#xff1a;1037590285 3、全家桶依旧包含&#xff1a; 代码、…...

Qt 信号量使用方法

Qt 信号量使用方法 QSemaphore 类 常用函数介绍 函数名称函数功能QSemaphore()构造并初始化对象acquire()尝试获取n个资源&#xff0c;如果没有那么多资源&#xff0c;线程将阻塞直到有n个资源可用available()返回当前信号量可用的资源个数&#xff0c;这个数永远不可能为负…...

C++进阶——封装哈希表实现unordered_map/set

与红黑树封装map/set基本相似&#xff0c;只是unordered_map/set是单向迭代器&#xff0c;模板多传一个HashFunc。 目录 1、源码及框架分析 2、模拟实现unordered_map/set 2.1 复用的哈希表框架及Insert 2.2 iterator的实现 2.2.1 iteartor的核心源码 2.2.2 iterator的实…...

AI Agent 实战:搭建个人在线旅游助手

AI Agent 实战&#xff1a;搭建个人在线旅游助手 本次实验中&#xff0c;我们将继续探索 Agent 的提示词&#xff0c;学习更加规范的提示词撰写方法。 本实验中你将掌握的知识点 使用 Dify 构建 Agent 的方法结构化的提示词撰写技巧变量的使用方法 1. 准备 在新建 Agent 之…...

CSS中的overflow属性

在 CSS 中&#xff0c;overflow 属性用于控制当一个元素的内容溢出其指定的区域时&#xff0c;应该如何处理溢出的部分。通常用于盒模型&#xff08;如 div&#xff09;中&#xff0c;指定内容超出容器时的显示方式。 overflow 属性的常用值&#xff1a; 1. visible&#xff08…...

【Unity】处理文字显示不全的问题

1.选中字体文件&#xff0c;检查 MultiAtlasTeextures 是否勾选&#xff0c;未勾选的话&#xff0c;先勾选保存后查看是否显示正常 2.勾选后未正常显示&#xff0c;则在搜索框中输入未显示的文本&#xff0c;确认字体图集是否包含该文本&#xff0c;然后点击Update Atlas Textu…...

蓝桥备赛指南(11):递归简介

递归的介绍 概念&#xff1a;递归是指函数直接或间接调用自身的过程。 解释递归的两个关键要素&#xff1a; 基本情况&#xff08;递归终止条件&#xff09;&#xff1a;递归函数中的一个条件&#xff0c;当满足该条件时&#xff0c;递归终止&#xff0c;避免无限递归。可以…...