用于显著提高检索速度和降低成本的二进制和标量嵌入量化

我们引入了嵌入量化的概念,并展示了它们对检索速度、内存使用、磁盘空间和成本的影响。我们将讨论理论上和实践中如何对嵌入进行量化,然后介绍一个 演示,展示了 4100 万维基百科文本的真实检索场景。

  • 演示地址https://hf.co/spaces/sentence-transformers/quantized-retrieval

为什么使用嵌入?

嵌入是自然语言处理中最多样化的工具之一,支持各种设置和使用场景。本质上,嵌入是对更复杂对象 (如文本、图像、音频等) 的数值表示。具体来说,这些对象被表示为 n 维向量。

在转换了复杂对象之后,你可以通过计算相应嵌入的相似性来确定它们的相似性!这对于许多使用场景至关重要: 它为推荐系统、检索、单次学习或少样本学习、异常检测、相似性搜索、释义检测、聚类、分类等提供了基础。

嵌入可能难以扩展

但是,当我们在实际应用中使用嵌入时,可能会遇到一些问题。比如,现在很多先进的模型产生的嵌入都是 1024 维的,每个维度需要 4 字节的空间来存储 (float 32 编码)。如果你要处理 2.5 亿个这样的向量,那就需要大约 1TB 的内存,这既花钱又可能导致处理速度变慢。

下表展示了一些不同的模型,它们的维度大小、需要的内存量以及相应的成本。成本是按照 AWS 上一种叫做 x2gd 的实例来估算的,大概每个月每 GB 需要 3.8 美元。

嵌入维数模型样例100M 嵌入250M 嵌入1B 嵌入
384all-MiniLM-L6-v2
bge-small-en-v1.5
143.05GB
$543 / mo
357.62GB
$1,358 / mo
1430.51GB
$5,435 / mo
768all-mpnet-base-v2
bge-base-en-v1.5
jina-embeddings-v2-base-en
nomic-embed-text-v1
286.10GB
$1,087 / mo
715.26GB
$2,717 / mo
2861.02GB
$10,871 / mo
1024bge-large-en-v1.5
mxbai-embed-large-v1
Cohere-embed-english-v3.0
381.46GB
$1,449 / mo
953.67GB
$3,623 / mo
3814.69GB
$14,495 / mo
1536OpenAI text-embedding-3-small572.20GB
$2,174 / mo
1430.51GB
$5,435 / mo
5722.04GB
$21,743 / mo
3072OpenAI text-embedding-3-large1144.40GB
$4,348 / mo
2861.02GB
$10,871 / mo
11444.09GB
$43,487 / mo
  • all-MiniLM-L6-v2https://hf.co/sentence-transformers/all-MiniLM-L6-v2

  • bge-small-en-v1.5https://hf.co/BAAI/bge-small-en-v1.5

  • all-mpnet-base-v2https://hf.co/sentence-transformers/all-mpnet-base-v2

  • bge-base-en-v1.5https://hf.co/BAAI/bge-base-en-v1.5

  • jina-embeddings-v2-base-enhttps://hf.co/jinaai/jina-embeddings-v2-base-en

  • nomic-embed-text-v1https://hf.co/nomic-ai/nomic-embed-text-v1

  • bge-large-en-v1.5https://huggingface.co/BAAI/bge-large-en-v1.5

  • mxbai-embed-large-v1https://hf.co/mixedbread-ai/mxbai-embed-large-v1

  • Cohere-embed-english-v3.0https://txt.cohere.com/introducing-embed-v3/

  • OpenAI text-embedding-3-smallhttps://openai.com/blog/new-embedding-models-and-api-updates

  • OpenAI text-embedding-3-largehttps://openai.com/blog/new-embedding-models-and-api-updates

提高可扩展性

有几种方法可以应对嵌入扩展的挑战。最常见的方法是降维,比如使用 主成分分析 (PCA)。然而,传统的降维方法——比如 PCA ——在处理嵌入时往往效果不佳。最近,有关于  Matryoshka 表征学习 (MRL) 的新闻 (博客),这种方法由 OpenAI 使用,允许更经济的嵌入。使用 MRL 时,只使用前 n 个嵌入维度。这种方法已经被一些开源模型采用,比如 nomic-ai/nomic-embed-text-v1.5 和 mixedbread-ai/mxbai-embed-2d-large-v1。对于 OpenAI 的 text-embedding-3-large 模型,我们看到在 12 倍压缩下性能保留了 93.1 %,而对于 nomic 的模型,在 3 倍压缩下保留了 95.8% 的性能,在 6 倍压缩下保留了 90% 的性能。

  • 主成分分析 (PCA)https://en.wikipedia.org/wiki/Principal_component_analysis

  • Matryoshka 表征学习https://arxiv.org/abs/2205.13147

  • 博客https://huggingface.co/blog/matryoshka

  • OpenAIhttps://openai.com/blog/new-embedding-models-and-api-updates

  • nomic-ai/nomic-embed-text-v1.5https://hf.co/nomic-ai/nomic-embed-text-v1.5

  • mixedbread-ai/mxbai-embed-2d-large-v1https://hf.co/mixedbread-ai/mxbai-embed-2d-large-v1

然而,还有一种新的方法可以在这个挑战上取得进展; 它不涉及降维,而是减少嵌入中每个个体值的尺寸大小: 量化。我们的量化实验将展示,我们可以在显著加快计算速度并节省内存、存储和成本的同时,保持大量的性能。让我们进一步了解一下吧!

二进制量化

与在模型中减少权重精度的量化不同,嵌入的量化是指对嵌入本身进行的一个后处理步骤。特别是,二进制量化指的是将嵌入中的 float32 值转换为 1 bit ,从而在内存和存储使用上实现 32 倍的减少。

要将 float32 嵌入量化为二进制,我们只需将归一化的嵌入在 0 处进行阈值处理:

如果如果

我们可以使用汉明距离来高效地检索这些二进制嵌入。汉明距离是指两个二进制嵌入在位上不同的位置数量。汉明距离越低,嵌入越接近; 因此,文档的相关性越高。汉明距离的一个巨大优势是它可以用 2 个 CPU 周期轻松计算,允许极快的性能。

Yamada 等人 (2021) 引入了一个重打分步骤,他们称之为 rerank ,以提高性能。他们提议可以使用点积将 float32 查询嵌入与二进制文档嵌入进行比较。在实践中,我们首先使用二进制查询嵌入和二进制文档嵌入检索 rescore_multiplier * top_k 的结果——即双二进制检索的前 k 个结果的列表——然后使用 float32 查询嵌入对这个二进制文档嵌入列表进行重打分。

  • Yamada 等人 (2021)https://arxiv.org/abs/2106.00882

通过应用这种新颖的重打分步骤,我们能够在减少内存和磁盘空间使用 32 倍的同时,保留高达 ~96% 的总检索性能,并使检索速度提高多达 32 倍。如果没有重打分,我们能够保留大约 ~92.5% 的总检索性能。

Sentence Transformers 中的二进制量化

将一个维度为 1024 的嵌入量化为二进制将得到 1024 比特。实际上,将比特存储为字节要常见得多,因此当我们量化为二进制嵌入时,我们使用 np.packbits 将比特打包成字节。

因此,将一个维度为 1024 的 float32 嵌入量化后,得到一个维度为 128 的 int8uint8 嵌入。下面是两种使用 Sentence Transformers 生成量化嵌入的方法:

  • Sentence Transformershttps://sbert.net/

from sentence_transformers import SentenceTransformer

# 1. Load an embedding model
model = SentenceTransformer("mixedbread-ai/mxbai-embed-large-v1")

# 2a. Encode some text using "binary" quantization
binary_embeddings = model.encode(
    ["I am driving to the lake.", "It is a beautiful day."],
    precision="binary",
)

或者

from sentence_transformers import SentenceTransformer
from sentence_transformers.quantization import quantize_embeddings

# 1. Load an embedding model
model = SentenceTransformer("mixedbread-ai/mxbai-embed-large-v1")

# 2b. or, encode some text without quantization & apply quantization afterwards
embeddings = model.encode(["I am driving to the lake.", "It is a beautiful day."])
binary_embeddings = quantize_embeddings(embeddings, precision="binary")

参考:

mixedbread-ai/mxbai-embed-large-v1SentenceTransformer.encodequantize_embeddings

在这里,你可以看到默认的 float32 嵌入和二进制嵌入在形状、大小和 numpy 数据类型方面的差异:

>>> embeddings.shape
(2, 1024)
>>> embeddings.nbytes
8192
>>> embeddings.dtype
float32
>>> binary_embeddings.shape
(2, 128)
>>> binary_embeddings.nbytes
256
>>> binary_embeddings.dtype
int8

请注意,你还可以选择 "ubinary" 来使用无符号的 uint8 数据格式将嵌入量化为二进制。这可能取决于你的向量库/数据库的要求。

向量数据库中的二进制量化
向量数据库是否支持
Faiss
USearch
Vespa AI
Milvus
Qdrant二进制量化
Weaviate二进制量化
  • Faisshttps://github.com/facebookresearch/faiss/wiki/Binary-indexes

  • USearchhttps://github.com/unum-cloud/usearch

  • Vespa AIhttps://docs.vespa.ai/en/reference/schema-reference.html

  • Milvushttps://milvus.io/docs/index.md

  • Qdrant 二进制量化https://qdrant.tech/documentation/guides/quantization/#binary-quantization

  • Weaviate 二进制量化https://weaviate.io/developers/weaviate/configuration/bq-compression

标量 (int8) 量化

我们使用标量量化过程将 float32 嵌入转换为 int8 。这涉及到将 float32 值的连续范围映射到可以表示 256 个不同级别 (从 -128 到 127) 的 int8 值的离散集合,如下面的图像所示。这是通过使用大量的嵌入校准数据集来完成的。我们计算这些嵌入的范围,即每个嵌入维度的 minmax 。从这里,我们计算将每个值分类的步骤 (桶)。

为了进一步提高检索性能,你可以可选地应用与二进制嵌入相同的重打分步骤。重要的是要注意,校准数据集极大地影响性能,因为它定义了量化桶。

e74d19b1ac10e78c025b45cf918fc426.png    Source: https://qdrant.tech/articles/scalar-quantization/

通过将标量量化为 int8 ,我们将原始 float32 嵌入的精度降低,使得每个值都用一个 8 位整数表示 (缩小 4 倍)。请注意,这与二进制量化情况不同,在二进制量化中,每个值由一个单比特表示 (缩小 32 倍)。

Sentence Transformers 中的标量量化

将一个维度为 1024 的嵌入量化为 int8 将得到 1024 字节。在实际应用中,我们可以选择 uint8int8 。这个选择通常取决于你的向量库/数据库支持哪种格式。

在实践中,建议为标量量化提供以下之一:

  1. 一大组嵌入,以便一次性全部量化,或者

  2. 每个嵌入维度的 minmax 范围,或者

  3. 一大组嵌入的校准数据集,从中可以计算 minmax 范围。

如果这些情况都不适用,你将收到如下警告:Computing int8 quantization buckets based on 2 embeddings. int8 quantization is more stable with 'ranges' calculated from more embeddings or a 'calibration_embeddings' that can be used to calculate the buckets.大意是如果你只使用很少量的嵌入 (在这个例子中是 2 个嵌入) 来计算这些量化桶,那么量化可能不会那么稳定或准确,因为少量的数据可能无法很好地代表整个数据分布。因此,如果你有一个很大的数据集来计算这些范围,或者有一个校准数据集,那么你可以得到更好的量化结果。

请看下面如何使用 Sentence Transformers 生成标量量化嵌入:

  • Sentence Transformershttps://sbert.net/

from sentence_transformers import SentenceTransformer
from sentence_transformers.quantization import quantize_embeddings
from datasets import load_dataset

# 1. Load an embedding model
model = SentenceTransformer("mixedbread-ai/mxbai-embed-large-v1")

# 2. Prepare an example calibration dataset
corpus = load_dataset("nq_open", split="train[:1000]")["question"]
calibration_embeddings = model.encode(corpus)

# 3. Encode some text without quantization & apply quantization afterwards
embeddings = model.encode(["I am driving to the lake.", "It is a beautiful day."])
int8_embeddings = quantize_embeddings(
    embeddings,
    precision="int8",
    calibration_embeddings=calibration_embeddings,
)

参考文献:

mixedbread-ai/mxbai-embed-large-v1SentenceTransformer.encodequantize_embeddings

在这里,你可以看到默认的 float32 嵌入和 int8 标量嵌入在形状、大小和 numpy 数据类型方面的差异:

>>> embeddings.shape
(2, 1024)
>>> embeddings.nbytes
8192
>>> embeddings.dtype
float32
>>> int8_embeddings.shape
(2, 1024)
>>> int8_embeddings.nbytes
2048
>>> int8_embeddings.dtype
int8
向量数据库中的标量量化
向量数据库是否支持标量量化
FaissIndexHNSWSQ
USearch
Vespa AI
OpenSearch
ElasticSearch
MilvusIVF_SQ8
QdrantScalar Quantization
  • Faiss: IndexHNSWSQhttps://faiss.ai/cpp_api/struct/structfaiss_1_1IndexHNSWSQ.html

  • USearchhttps://github.com/unum-cloud/usearch

  • Vespa AIhttps://docs.vespa.ai/en/reference/tensor.html

  • OpenSearchhttps://opensearch.org/docs/latest/field-types/supported-field-types/knn-vector

  • ElasticSearchhttps://www.elastic.co/de/blog/save-space-with-byte-sized-vectors

  • Milvus: IVF_SQ8https://milvus.io/docs/index.md

  • Qdrant: Scalar Quantizationhttps://qdrant.tech/documentation/guides/quantization/#scalar-quantization

结合二进制和标量量化

结合二进制和标量量化可以兼得两者的优点: 二进制嵌入的极快速度和标量嵌入在重打分后的优良性能的保留。请查看下面的演示,这是一个涉及维基百科 4100 万文本的真实实现。该设置的流程如下:

  1. 使用 mixedbread-ai/mxbai-embed-large-v1 SentenceTransformer 模型对查询进行嵌入。

  2. 使用 sentence-transformers 库中的 quantize_embeddings 函数将查询量化为二进制。

  3. 使用量化查询在二进制索引 (4100 万个二进制嵌入; 5.2GB 内存/磁盘空间) 中搜索前 40 个文档。

  4. 从磁盘上的 int8 索引 (4100 万个 int8 嵌入; 0 字节内存,47.5GB 磁盘空间) 动态加载前 40 个文档。

  5. 使用 float32 查询和 int8 嵌入对前 40 个文档进行重打分,以获得前 10 个文档。

  6. 按分数对前 10 个文档进行排序并显示。

  • mixedbread-ai/mxbai-embed-large-v1https://huggingface.co/mixedbread-ai/mxbai-embed-large-v1

通过这种方法,我们为索引使用了 5.2GB 内存和 52GB 磁盘空间。这比通常的检索所需的 200GB 内存和 200GB 磁盘空间要少得多。尤其是当你进一步扩展时,这将显著减少延迟和成本。

量化实验

我们在 MTEB 的检索子集上进行了实验,该子集包含 15 个基准测试。首先,我们使用 rescore_multiplier 为 4 来检索前 k (k=100) 个搜索结果。因此,我们总共检索了 400 个结果,并对这前 400 个结果进行了重打分。对于 int8 性能,我们直接使用了点积,而没有进行任何重打分。

  • MTEBhttps://huggingface.co/spaces/mteb/leaderboard

模型嵌入维度250M 嵌入MTEB 检索 (NDCG@10)默认性能的百分比
开源模型



mxbai-embed-large-v1: float321024953.67GB
$3623 / mo
54.39100%
mxbai-embed-large-v1: int81024238.41GB
$905 / mo
52.7997%
mxbai-embed-large-v1: binary102429.80GB
$113.25 / mo
52.4696.45%
e5-base-v2: float32768286.10GB
$1087 / mo
50.77100%
e5-base-v2: int8768178.81GB
$679 / mo
47.5494.68%
e5-base-v2: binary76822.35GB
$85 / mo
37.9674.77%
all-MiniLM-L6-v2: float32384357.62GB
$1358 / mo
41.66100%
all-MiniLM-L6-v2: int838489.40GB
$339 / mo
37.8290.79%
all-MiniLM-L6-v2: binary38411.18GB
$42 / mo
39.0793.79%
专有模型



Cohere-embed-english-v3.0: float321024953.67GB
$3623 / mo
55.0100%
Cohere-embed-english-v3.0: int81024238.41GB
$905 / mo
55.0100%
Cohere-embed-english-v3.0: binary102429.80GB
$113.25 / mo
52.394.6%
  • mxbai-embed-large-v1https://hf.co/mixedbread-ai/mxbai-embed-large-v1

  • e5-base-v2https://hf.co/intfloat/e5-base-v2

  • all-MiniLM-L6-v2https://hf.co/sentence-transformers/all-MiniLM-L6-v2

  • Cohere-embed-english-v3.0https://txt.cohere.com/introducing-embed-v3/

从我们的量化实验结果中,可以识别出几个关键趋势和好处。正如预期的那样,维度更高的嵌入模型通常每计算生成的存储成本更高,但能实现最佳性能。然而,令人惊讶的是,量化到 int8 已经帮助 mxbai-embed-large-v1Cohere-embed-english-v3.0 在存储使用低于较小维度基模型的情况下实现了更高的性能。

量化好处的显现,在查看二进制模型的结果时更为明显。在这种情况下,1024 维度的模型仍然优于现在存储需求高 10 倍的基模型,而 mxbai-embed-large-v1 在资源需求减少 32 倍后仍能保持超过 96% 的性能。从 int8 进一步量化到二进制的性能损失几乎可以忽略不计。

有趣的是,我们还可以看到 all-MiniLM-L6-v2 在二进制量化上的性能比 int8 量化更强。这可能的原因是校准数据的选择。在 e5-base-v2 上,我们观察到了 维度坍缩 效应,导致模型只使用潜在空间的子空间; 当进行量化时,整个空间进一步坍缩,导致性能损失很大。

  • 维度坍缩https://arxiv.org/abs/2110.09348

这表明量化并不适用于所有嵌入模型。考虑现有基准测试结果并开展实验以确定给定模型与量化的兼容性仍然至关重要。

重打分的影响

在本节中,我们探讨了重打分对检索性能的影响。我们基于 mxbai-embed-large-v1 评估了结果。

二进制重打分

使用二进制嵌入,mxbai-embed-large-v1 在 MTEB 检索上保留了 92.53% 的性能。仅进行重打分而无需检索更多样本,性能提升到了 96.45%。我们实验设置了 rescore_multiplier 从 1 到 10,但没有观察到进一步的性能提升。这表明 top_k 搜索已经检索到了最顶级的候选项,而重打分则正确地重新排列了这些好的候选项。

标量 (Int8) 重打分

我们还评估了 mxbai-embed-large-v1 模型与 int8 重打分,因为 Cohere 表明 Cohere-embed-english-v3.0 在 int8 量化后可以达到 float32 模型的 100% 性能。在这个实验中,我们将 rescore_multiplier 设置为 [1, 4, 10],并得到了以下结果:

dfe1a388b80e472758f1a114f988e8e3.png

从图表中我们可以看到,更高的重打分乘数意味着量化后性能的更好保留。从我们的结果推断,我们假设这种关系可能是双曲线的,随着重打分乘数的增加,性能接近 100%。使用 int8 时,重打分乘数为 4-5 已经导致令人瞩目的 99% 的性能保留。

检索速度

我们使用 Google Cloud Platform 的 a2-highgpu-4g 实例,在整个 MTEB 检索中测量了 mxbai-embed-large-v1 嵌入的检索速度,该嵌入的维度为 1024。对于 int8 ,我们使用了 USearch (版本 2.9.2) 和二进制量化 Faiss (版本 1.8.0)。所有计算都在 CPU 上使用精确搜索完成。

量化最小均值最大
float321x (baseline)1x (baseline)1x (baseline)
int82.99x speedup3.66x speedup4.8x speedup
binary15.05x speedup24.76x speedup45.8x speedup

如表中所示,应用 int8 标量量化相比全尺寸 float32 嵌入实现了平均速度提升 3.66 倍。此外,二进制量化实现了平均速度提升 24.76 倍。对于标量和二进制量化,即使在最坏的情况下,也实现了非常显著的速度提升。

性能汇总

量化在资源使用、检索速度和检索性能方面的实验结果和影响可以总结如下:


float32int8/uint8binary/ubinary
内存和索引空间节省1x精确 4x精确 32x
检索速度1x多达 4x多达 45x
默认性能百分比100%~99.3%~96%

演示

以下 演示 展示了通过结合二进制搜索和标量 ( int8 ) 重打分来提高检索效率。该解决方案需要 5GB 的内存用于二进制索引和 50GB 的磁盘空间用于二进制和标量索引,这比常规的 float32 检索所需的 200GB 内存和磁盘空间要少得多。此外,检索速度也更快。

  • 演示 Hugging Face Spacehttps://hf.co/spaces/sentence-transformers/quantized-retrieval

自己尝试

以下脚本可用于实验性地进行检索和其他用途的嵌入量化。它们分为三个类别:

  • 推荐检索:

    • semantic_search_recommended.py: 此脚本结合了二进制搜索和标量重打分,与上面的演示类似,以实现廉价、高效且性能良好的检索。

  • 使用:

    • semantic_search_faiss.py: 此脚本展示了使用 FAISS 的常规二进制或标量量化、检索和重打分的使用方式,通过使用 semantic_search_faiss 实用函数。

    • semantic_search_usearch.py: 此脚本展示了使用 USearch 的常规二进制或标量量化、检索和重打分的使用方式,通过使用 semantic_search_usearch 实用函数。

  • 基准测试:

    • semantic_search_faiss_benchmark.py: 此脚本包括了对 float32 检索、二进制检索加重打分和标量检索加重打分的检索速度基准测试,使用 FAISS。它使用了 semantic_search_faiss 实用函数。我们的基准测试特别显示了 ubinary 的速度提升。

    • semantic_search_usearch_benchmark.py: 此脚本包括了对 float32 检索、二进制检索加重打分和标量检索加重打分的检索速度基准测试,使用 USearch。它使用了 semantic_search_usearch 实用函数。我们的实验在新硬件上显示了巨大的速度提升,特别是对于 int8

未来工作

我们期待二进制量化技术的进一步发展。要提到的一些潜在改进,我们怀疑可能还有比 int8 更小的标量量化空间,即使用 128 或 64 个桶而不是 256 个。

此外,我们也很兴奋地发现,嵌入量化与 Matryoshka 表征学习 (MRL) 完全垂直。换句话说,可以将 MRL 嵌入从例如 1024 减少到 128 (通常与 2% 的性能降低相对应),然后应用二进制或标量量化。我们怀疑这可能会将检索速度提高多达 32 倍,质量降低约 3%,或者质量降低约 10% 时检索速度提高多达 256 倍。

最后,我们意识到,使用嵌入量化进行检索可以与一个独立的重新排序模型结合起来使用。我们设想了一个三步流水线: 首先进行二进制搜索,然后对结果进行标量 (int8) 重打分,最后使用交叉编码模型进行重新排序。这样的流水线可以实现高效的检索性能,同时降低延迟、内存使用、磁盘空间和成本。

致谢

这个项目得益于我们与 mixedbread.ai 的合作以及 SentenceTransformers 库,该库允许你轻松创建句子嵌入并进行量化。如果你想在你的项目中使用量化嵌入,你现在知道该怎么做了!

  • mixedbread.aihttps://mixedbread.ai

  • SentenceTransformershttps://www.sbert.net/

引用

@article{shakir2024quantization,
  author       = { Aamir Shakir and
                   Tom Aarsen and
                   Sean Lee
                 },
  title = { Binary and Scalar Embedding Quantization for Significantly Faster & Cheaper Retrieval },
  journal = {Hugging Face Blog},
  year = {2024},
  note = {https://huggingface.co/blog/embedding-quantization},
}

参考文献

mixedbread-ai/mxbai-embed-large-v1SentenceTransformer.encodequantize_embeddings

  • Sentence Transformers docs - Embedding Quantizationhttps://sbert.net/examples/applications/embedding-quantization/README.html

  • https://txt.cohere.com/int8-binary-embeddings/

  • https://qdrant.tech/documentation/guides/quantization

  • https://zilliz.com/learn/scalar-quantization-and-product-quantization


英文原文: https://hf.co/blog/embedding-quantization
原文作者: Aamir Shakir, Tom Aarsen, SeanLee
译者: innovation64

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言——贪吃蛇小游戏

目录 前言 一、贪吃蛇游戏 1.1 游戏背景 1.2 游戏功能 1.3 技术要点 二、Win32 API 2.1 控制台程序 2.2 控制台屏幕上的坐标COORD 2.3 GetStdHandle 2.4 GetConsoleCursorInfo 2.4 CONSOLE_CURSOR_INFO 2.5 SetConsoleCursorInfo 2.6 SetConsoleCursorPosition …

第十届蓝桥杯省赛真题(C/C++大学B组)

试题 A: 组队 答案&#xff1a;490 试题 B: 年号字串 #include <bits/stdc.h> using namespace std;int main() {//26进制数 int n;cin>>n;string s "111";for(int i s.length() - 1;i >0;i--){s[i] A - 1 n % 26;n / 26;}cout<<s<<…

交换机与路由器缓冲区:寻找完美大小

*本文系SDNLAB编译自瞻博网络技术专家兼高级工程总监Sharada Yeluri领英 在路由器和交换机中&#xff0c;缓冲区至关重要&#xff0c;可以防止网络拥塞期间的数据丢失。缓冲区到底要多大&#xff1f;这个问题在学术界和工业界一直备受争议。本文探讨了高端路由器中数据包缓冲的…

Matlab 实时读取串口并绘图

Matlab 实时读取串口并绘图 Vofa Vofa 是一个很好的跨平台上位机软件&#xff0c;但是它无法保存数据&#xff0c;而且作者也并没有要继续更新的意思&#xff0c;保存数据功能应该是遥遥无期了。因此本文使用 Matlab 实时读取串口数据&#xff0c;并使用 plot 函数绘制。 vo…

性能分析-nginx(tomcat、nginx【配置】、负载均衡)

tomcat 像kyj项目请求直接对接 tomcat&#xff0c;tomcat的连接池就会直接影响“并发用户数” 如果这种情况下做性能测试的时候&#xff0c;并发用户数不能满足要求&#xff0c;可以适当加大线程池的配置。 如&#xff1a;项目性能测试发现项目所在机器&#xff0c;资源利用率…

hexo接入github Discussions评论系统

评论存储仓 可以是你的博客项目的(github)仓库&#xff0c;也可以单独新建一个评论存储仓库。 我的博客项目在gitee上&#xff0c;就以新建存储仓为例&#xff1a; 使用Discussions评论系统必须开通Discussions模块&#xff01; 安装giscus插件 https://github.com/apps/…

书客、月影、欧普护眼大路灯哪款好?三款落地灯真实对比测评

作为在照明电器领域资深的评测员&#xff0c;我对市面上各种新颖的照明家电有着深入的探索和研究。大路灯能够提供舒适健康的照明光线&#xff0c;目前正受到许多用眼人群的广泛欢迎。&#xff0c;当然随着大路灯的普及&#xff0c;市场中也充斥着一些低劣的大路灯产品&#xf…

中国平安金融壹账通交付管理中心总经理崔羽先生受邀为第十三届中国PMO大会演讲嘉宾

全国PMO专业人士年度盛会 中国平安金融壹账通交付管理中心总经理崔羽先生受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾&#xff0c;演讲议题为“项目管理成与败&#xff0c;人才是第一要素”。大会将于5月25-26日在北京举办&#xff0c;敬请关注&#xff01; 议题简要…

消息队列之-----------------zookeeper机制

目录 一、ZooKeeper是什么 二、ZooKeeper的工作机制 三、ZooKeeper特点 四、ZooKeeper数据结构 五、ZooKeeper应用场景 5.1统一命名服务 5.2统一配置管理 5.3统一集群管理 5.4服务器动态上下线 5.5软负载均衡 六、ZooKeeper的选举机制 6.1第一次启动选举机制 6.2非…

Java中的TCP通信

TCP通信 TCP通信Socket客户端ServerSocket服务端 例子&#xff1a;一发一收例子&#xff1a;多发多收异常捕获 例子&#xff1a;服务器与多个客户端同时通信多客户端通信架构服务端代码ServerReaderThread 服务端读数据线程 TCP通信 特点&#xff1a;面向连接、可靠通信 通信双…

[C++][算法基础]树的重心(树图DFS)

给定一颗树&#xff0c;树中包含 n 个结点&#xff08;编号 1∼n&#xff09;和 n−1 条无向边。 请你找到树的重心&#xff0c;并输出将重心删除后&#xff0c;剩余各个连通块中点数的最大值。 重心定义&#xff1a;重心是指树中的一个结点&#xff0c;如果将这个点删除后&a…

为什么越来越多的网工运维转行网络安全?

最近越来越多的网工运维小伙伴都在吐槽&#xff1a;干网工、运维多年&#xff0c;薪资还是5.6K&#xff0c;技术也遇瓶颈上不去&#xff0c;考虑转岗或者转行。其中大部分的网工运维小伙伴们纷纷瞄准了高薪高前景的网络安全工程师岗位 网络安全是怎样的岗位&#xff1f; 人才…

星抖短剧养猪,闲鱼出售金币,日收益50-200+,零成本副业项目

自3月31日推出以来&#xff0c;“星斗短剧”平台迅速获得了众多团队的关注和推崇&#xff0c;用户数量持续增长。 目前&#xff0c;已有超过26万的用户群体活跃在平台上。用户数量的庞大直接映射了市场的广阔和需求的多样性&#xff0c;为我们提供了赚取收益的良机。 公 众号…

自然语言处理、大语言模型相关名词整理

自然语言处理相关名词整理 零样本学习&#xff08;zero-shot learning&#xff09;词嵌入&#xff08;Embedding&#xff09;为什么 Embedding 搜索比基于词频搜索效果好&#xff1f; Word2VecTransformer检索增强生成&#xff08;RAG&#xff09;幻觉采样温度Top-kTop-p奖励模…

HarmonyOS实战开发-WebSocket的使用。

介绍 本示例展示了WebSocket的使用&#xff0c;包括客户端与服务端的连接和断开以及客户端数据的接收和发送。 WebSocket连接&#xff1a;使用WebSocket建立服务器与客户端的双向连接&#xff0c;需要先通过createWebSocket方法创建WebSocket对象&#xff0c;然后通过connect…

node express 请求参数接收方式汇总

express 安装使用 express官网 express 是node.js 中写后端服务比较流行的框架。 安装express npm install -g express安装 express-generator 相当于vue的cli 用来快速生成express项目 npx express-generator生成项目mynode -e是使用ejs模版 express -e mynodeexpress生成器生…

TouchGFX 控件附加 ClickListener 功能的方法介绍

1. 引言 TouchGFX 是专用于 STM32 的图形界面设计软件&#xff0c;可用来低成本开发优秀的图形界面&#xff0c;TouchGFX 现已变的越来越流行。为了帮助客户更加深入地理解和使用 TouchGFX &#xff0c;本文介绍了 TouchGFX Designer 中的 Mixin 功能&#xff0c;从基础示例 B…

Docker核心特征

Docker的基本概念 Dockerfile&#xff1a;制作进行的文件&#xff0c;可以理解为制作镜像的一个清单。 镜像&#xff1a;用来创建容器的安装包&#xff0c;可以理解为给电脑安装操作系统的系统镜像。 容器&#xff1a;通过镜像来创建的一套运行环境&#xff0c;一个容器里可…

每日一题 — 将 x 减到 0 的最小操作数

思路&#xff1a; 题目要求是让我们从数组的最左端和最右端进行操作&#xff0c;这样的话解题的难度大大提升&#xff0c;我们可以用 正难则反 的思想&#xff1a; 题目中要求是减去数组中的数刚好等于X&#xff0c;我们可以转换成 数组中某一段的和等于 数组的总长减去X(sum -…

vue $set()使用复习总结

一维数据&#xff1a; this.$set(数组, 下标, 内容); this.$set(this.typeList, 1, 榴莲); 数组对象&#xff1a; this.$set( target要更改的数据源(可以是对象或者数组), key要更改的具体数据, value重新赋的值 ) 用法一&#xff1a; 循环外&#xff0c;单独使用 用法二 &…