用 Sentence Transformers v3 训练和微调嵌入模型

sentence,transformers,v3 · 浏览次数 : 0

小编点评

Sentence Transformers是一个Python库,用于使用和训练各种应用的嵌入模型,例如检索增强生成(RAG)、语义搜索、语义文本相似度、释义挖掘等。 更新亮点: - 引入新的训练方法 教程目标: - 如何使用Sentence Transformers来微调模型。 - 理解微调过程和相关组成部分。 微调原因: - 获取针对任务特定相似性的独特嵌入表示。 实现步骤: 1. 加载相应的数据集(训练和评估)。 2. 定义损失函数。 3. 可选:设置训练参数和学习率调度器。 4. 可选:选择评估器。 5. 创建训练器,整合模型、数据集、损失函数和评估器。 6. 开始训练过程。 7. 训练结束后,在测试集上评估模型性能。 注意事项: - 确保损失函数与数据格式兼容。 - 适当调整训练参数以获得更好的效果。 - 根据具体任务,考虑预处理或特征工程。 教程目的: 帮助读者理解如何使用Sentence Transformers进行特定任务的微调。

正文

Sentence Transformers 是一个 Python 库,用于使用和训练各种应用的嵌入模型,例如检索增强生成 (RAG)、语义搜索、语义文本相似度、释义挖掘 (paraphrase mining) 等等。其 3.0 版本的更新是该工程自创建以来最大的一次,引入了一种新的训练方法。在这篇博客中,我将向你展示如何使用它来微调 Sentence Transformer 模型,以提高它们在特定任务上的性能。你也可以使用这种方法从头开始训练新的 Sentence Transformer 模型。

现在,微调 Sentence Transformers 涉及几个组成部分,包括数据集、损失函数、训练参数、评估器以及新的训练器本身。我将详细讲解每个组成部分,并提供如何使用它们来训练有效模型的示例。

为什么进行微调?

微调 Sentence Transformer 模型可以显著提高它们在特定任务上的性能。这是因为每个任务都需要独特的相似性概念。让我们以几个新闻文章标题为例:

  • “Apple 发布新款 iPad”
  • “NVIDIA 正在为下一代 GPU 做准备 “

根据用例的不同,我们可能希望这些文本具有相似或不相似的嵌入。例如,一个针对新闻文章的分类模型可能会将这些文本视为相似,因为它们都属于技术类别。另一方面,一个语义文本相似度或检索模型应该将它们视为不相似,因为它们具有不同的含义。

训练组件

训练 Sentence Transformer 模型涉及以下组件:

  1. 数据集 : 用于训练和评估的数据。
  2. 损失函数 : 一个量化模型性能并指导优化过程的函数。
  3. 训练参数 (可选): 影响训练性能和跟踪/调试的参数。
  4. 评估器 (可选): 一个在训练前、中或后评估模型的工具。
  5. 训练器 : 将模型、数据集、损失函数和其他组件整合在一起进行训练。

现在,让我们更详细地了解这些组件。

数据集

SentenceTransformerTrainer 使用 datasets.Datasetdatasets.DatasetDict 实例进行训练和评估。你可以从 Hugging Face 数据集中心加载数据,或使用各种格式的本地数据,如 CSV、JSON、Parquet、Arrow 或 SQL。

注意: 许多开箱即用的 Sentence Transformers 的 Hugging Face 数据集已经标记为 sentence-transformers ,你可以通过浏览 https://huggingface.co/datasets?other=sentence-transformers 轻松找到它们。我们强烈建议你浏览这些数据集,以找到可能对你任务有用的训练数据集。

Hugging Face Hub 上的数据

要从 Hugging Face Hub 中的数据集加载数据,请使用 load_dataset 函数:

from datasets import load_dataset

train_dataset = load_dataset("sentence-transformers/all-nli", "pair-class", split="train")
eval_dataset = load_dataset("sentence-transformers/all-nli", "pair-class", split="dev")

print(train_dataset)
"""
Dataset({
    features: ['premise', 'hypothesis', 'label'],
    num_rows: 942069
})
"""

一些数据集,如 sentence-transformers/all-nli,具有多个子集,不同的数据格式。你需要指定子集名称以及数据集名称。

本地数据 (CSV, JSON, Parquet, Arrow, SQL)

如果你有常见文件格式的本地数据,你也可以使用 load_dataset 轻松加载:

from datasets import load_dataset

dataset = load_dataset("csv", data_files="my_file.csv")
# or
dataset = load_dataset("json", data_files="my_file.json")

需要预处理的本地数据

如果你的本地数据需要预处理,你可以使用 datasets.Dataset.from_dict 用列表字典初始化你的数据集:

from datasets import Dataset

anchors = []
positives = []
# Open a file, perform preprocessing, filtering, cleaning, etc.
# and append to the lists

dataset = Dataset.from_dict({
    "anchor": anchors,
    "positive": positives,
})

字典中的每个键都成为结果数据集中的列。

数据集格式

确保你的数据集格式与你选择的 损失函数 相匹配至关重要。这包括检查两件事:

  1. 如果你的损失函数需要 标签 (如 损失概览 表中所指示),你的数据集必须有一个名为“label” “score”的列。
  2. “label”“score” 之外的所有列都被视为 输入 (如 损失概览 表中所指示)。这些列的数量必须与你选择的损失函数的有效输入数量相匹配。列的名称无关紧要, 只有它们的顺序重要

例如,如果你的损失函数接受 (anchor, positive, negative) 三元组,那么你的数据集的第一、第二和第三列分别对应于 anchorpositivenegative 。这意味着你的第一和第二列必须包含应该紧密嵌入的文本,而你的第一和第三列必须包含应该远距离嵌入的文本。这就是为什么根据你的损失函数,你的数据集列顺序很重要的原因。
考虑一个带有 ["text1", "text2", "label"] 列的数据集,其中 "label" 列包含浮点数相似性得分。这个数据集可以用 CoSENTLossAnglELossCosineSimilarityLoss ,因为:

  1. 数据集有一个“label”列,这是这些损失函数所必需的。
  2. 数据集有 2 个非标签列,与这些损失函数所需的输入数量相匹配。

如果你的数据集中的列没有正确排序,请使用 Dataset.select_columns 来重新排序。此外,使用 Dataset.remove_columns 移除任何多余的列 (例如, sample_idmetadatasourcetype ),因为否则它们将被视为输入。

损失函数

损失函数衡量模型在给定数据批次上的表现,并指导优化过程。损失函数的选择取决于你可用的数据和目标任务。请参阅 损失概览 以获取完整的选择列表。

大多数损失函数可以使用你正在训练的 SentenceTransformer model 来初始化:

from datasets import load_dataset
from sentence_transformers import SentenceTransformer
from sentence_transformers.losses import CoSENTLoss

# Load a model to train/finetune
model = SentenceTransformer("FacebookAI/xlm-roberta-base")

# Initialize the CoSENTLoss
# This loss requires pairs of text and a floating point similarity score as a label
loss = CoSENTLoss(model)

# Load an example training dataset that works with our loss function:
train_dataset = load_dataset("sentence-transformers/all-nli", "pair-score", split="train")
"""
Dataset({
    features: ['sentence1', 'sentence2', 'label'],
    num_rows: 942069
})
"""

训练参数

SentenceTransformersTrainingArguments 类允许你指定影响训练性能和跟踪/调试的参数。虽然这些参数是可选的,但实验这些参数可以帮助提高训练效率,并为训练过程提供洞察。

在 Sentence Transformers 的文档中,我概述了一些最有用的训练参数。我建议你阅读 训练概览 > 训练参数 部分。

以下是如何初始化 SentenceTransformersTrainingArguments 的示例:

from sentence_transformers.training_args import SentenceTransformerTrainingArguments

args = SentenceTransformerTrainingArguments(
    # Required parameter:
    output_dir="models/mpnet-base-all-nli-triplet",
    # Optional training parameters:
    num_train_epochs=1,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=16,
    warmup_ratio=0.1,
    fp16=True, # Set to False if your GPU can't handle FP16
    bf16=False, # Set to True if your GPU supports BF16
    batch_sampler=BatchSamplers.NO_DUPLICATES, # Losses using "in-batch negatives" benefit from no duplicates
    # Optional tracking/debugging parameters:
    eval_strategy="steps",
    eval_steps=100,
    save_strategy="steps",
    save_steps=100,
    save_total_limit=2,
    logging_steps=100,
    run_name="mpnet-base-all-nli-triplet", # Used in W&B if `wandb` is installed
)

注意 eval_strategy 是在 transformers 版本 4.41.0 中引入的。之前的版本应该使用 evaluation_strategy 代替。

评估器

你可以为 SentenceTransformerTrainer 提供一个 eval_dataset 以便在训练过程中获取评估损失,但在训练过程中获取更具体的指标也可能很有用。为此,你可以使用评估器来在训练前、中或后评估模型的性能,并使用有用的指标。你可以同时使用 eval_dataset 和评估器,或者只使用其中一个,或者都不使用。它们根据 eval_strategyeval_steps 训练参数 进行评估。

以下是 Sentence Tranformers 随附的已实现的评估器:

评估器 所需数据
BinaryClassificationEvaluator 带有类别标签的句子对
EmbeddingSimilarityEvaluator 带有相似性得分的句子对
InformationRetrievalEvaluator 查询(qid => 问题),语料库 (cid => 文档),以及相关文档 (qid => 集合[cid])
MSEEvaluator 需要由教师模型嵌入的源句子和需要由学生模型嵌入的目标句子。可以是相同的文本。
ParaphraseMiningEvaluator ID 到句子的映射以及带有重复句子 ID 的句子对。
RerankingEvaluator {'query': '..', 'positive': [...], 'negative': [...]} 字典的列表。
TranslationEvaluator 两种不同语言的句子对。
TripletEvaluator (锚点,正面,负面) 三元组。

此外,你可以使用 SequentialEvaluator 将多个评估器组合成一个,然后将其传递给 SentenceTransformerTrainer

如果你没有必要的评估数据但仍然想跟踪模型在常见基准上的性能,你可以使用 Hugging Face 上的数据与这些评估器一起使用。

使用 STSb 的 Embedding Similarity Evaluator

STS 基准测试 (也称为 STSb) 是一种常用的基准数据集,用于衡量模型对短文本 (如 “A man is feeding a mouse to a snake.”) 的语义文本相似性的理解。

你可以自由浏览 Hugging Face 上的 sentence-transformers/stsb 数据集。

from datasets import load_dataset
from sentence_transformers.evaluation import EmbeddingSimilarityEvaluator, SimilarityFunction

# Load the STSB dataset
eval_dataset = load_dataset("sentence-transformers/stsb", split="validation")

# Initialize the evaluator
dev_evaluator = EmbeddingSimilarityEvaluator(
    sentences1=eval_dataset["sentence1"],
    sentences2=eval_dataset["sentence2"],
    scores=eval_dataset["score"],
    main_similarity=SimilarityFunction.COSINE,
    name="sts-dev",
)
# Run evaluation manually:
# print(dev_evaluator(model))

# Later, you can provide this evaluator to the trainer to get results during training

使用 AllNLI 的 Triplet Evaluator

AllNLI 是 SNLIMultiNLI 数据集的合并,这两个数据集都是用于自然语言推理的。这个任务的传统目的是确定两段文本是否是蕴含、矛盾还是两者都不是。它后来被采用用于训练嵌入模型,因为蕴含和矛盾的句子构成了有用的 (anchor, positive, negative) 三元组: 这是训练嵌入模型的一种常见格式。

在这个片段中,它被用来评估模型认为锚文本和蕴含文本比锚文本和矛盾文本更相似的频率。一个示例文本是 “An older man is drinking orange juice at a restaurant.”。

你可以自由浏览 Hugging Face 上的 sentence-transformers/all-nli 数据集。

from datasets import load_dataset
from sentence_transformers.evaluation import TripletEvaluator, SimilarityFunction

# Load triplets from the AllNLI dataset
max_samples = 1000
eval_dataset = load_dataset("sentence-transformers/all-nli", "triplet", split=f"dev[:{max_samples}]")

# Initialize the evaluator
dev_evaluator = TripletEvaluator(
    anchors=eval_dataset["anchor"],
    positives=eval_dataset["positive"],
    negatives=eval_dataset["negative"],
    main_distance_function=SimilarityFunction.COSINE,
    name=f"all-nli-{max_samples}-dev",
)
# Run evaluation manually:
# print(dev_evaluator(model))

# Later, you can provide this evaluator to the trainer to get results during training

训练器

SentenceTransformerTrainer 将模型、数据集、损失函数和其他组件整合在一起进行训练:

from datasets import load_dataset
from sentence_transformers import (
    SentenceTransformer,
    SentenceTransformerTrainer,
    SentenceTransformerTrainingArguments,
    SentenceTransformerModelCardData,
)
from sentence_transformers.losses import MultipleNegativesRankingLoss
from sentence_transformers.training_args import BatchSamplers
from sentence_transformers.evaluation import TripletEvaluator

# 1. Load a model to finetune with 2. (Optional) model card data
model = SentenceTransformer(
    "microsoft/mpnet-base",
    model_card_data=SentenceTransformerModelCardData(
        language="en",
        license="apache-2.0",
        model_name="MPNet base trained on AllNLI triplets",
    )
)

# 3. Load a dataset to finetune on
dataset = load_dataset("sentence-transformers/all-nli", "triplet")
train_dataset = dataset["train"].select(range(100_000))
eval_dataset = dataset["dev"]
test_dataset = dataset["test"]

# 4. Define a loss function
loss = MultipleNegativesRankingLoss(model)

# 5. (Optional) Specify training arguments
args = SentenceTransformerTrainingArguments(
    # Required parameter:
    output_dir="models/mpnet-base-all-nli-triplet",
    # Optional training parameters:
    num_train_epochs=1,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=16,
    warmup_ratio=0.1,
    fp16=True, # Set to False if GPU can't handle FP16
    bf16=False, # Set to True if GPU supports BF16
    batch_sampler=BatchSamplers.NO_DUPLICATES, # MultipleNegativesRankingLoss benefits from no duplicates
    # Optional tracking/debugging parameters:
    eval_strategy="steps",
    eval_steps=100,
    save_strategy="steps",
    save_steps=100,
    save_total_limit=2,
    logging_steps=100,
    run_name="mpnet-base-all-nli-triplet", # Used in W&B if `wandb` is installed
)

# 6. (Optional) Create an evaluator & evaluate the base model
dev_evaluator = TripletEvaluator(
    anchors=eval_dataset["anchor"],
    positives=eval_dataset["positive"],
    negatives=eval_dataset["negative"],
    name="all-nli-dev",
)
dev_evaluator(model)

# 7. Create a trainer & train
trainer = SentenceTransformerTrainer(
    model=model,
    args=args,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    loss=loss,
    evaluator=dev_evaluator,
)
trainer.train()

# (Optional) Evaluate the trained model on the test set, after training completes
test_evaluator = TripletEvaluator(
    anchors=test_dataset["anchor"],
    positives=test_dataset["positive"],
    negatives=test_dataset["negative"],
    name="all-nli-test",
)
test_evaluator(model)

# 8. Save the trained model
model.save_pretrained("models/mpnet-base-all-nli-triplet/final")

# 9. (Optional) Push it to the Hugging Face Hub
model.push_to_hub("mpnet-base-all-nli-triplet")

在这个示例中,我从一个尚未成为 Sentence Transformer 模型的基础模型 microsoft/mpnet-base 开始进行微调。这需要比微调现有的 Sentence Transformer 模型,如 all-mpnet-base-v2,更多的训练数据。

运行此脚本后,tomaarsen/mpnet-base-all-nli-triplet 模型被上传了。使用余弦相似度的三元组准确性,即 cosine_similarity(anchor, positive) > cosine_similarity(anchor, negative) 的百分比为开发集上的 90.04% 和测试集上的 91.5% !作为参考,microsoft/mpnet-base 模型在训练前在开发集上的得分为 68.32%。

所有这些信息都被自动生成的模型卡存储,包括基础模型、语言、许可证、评估结果、训练和评估数据集信息、超参数、训练日志等。无需任何努力,你上传的模型应该包含潜在用户判断你的模型是否适合他们的所有信息。

回调函数

Sentence Transformers 训练器支持各种 transformers.TrainerCallback 子类,包括:

这些回调函数会自动使用,无需你进行任何指定,只要安装了所需的依赖项即可。

有关这些回调函数的更多信息以及如何创建你自己的回调函数,请参阅 Transformers 回调文档

多数据集训练

通常情况下,表现最好的模型是通过同时使用多个数据集进行训练的。SentenceTransformerTrainer 通过允许你使用多个数据集进行训练,而不需要将它们转换为相同的格式,简化了这一过程。你甚至可以为每个数据集应用不同的损失函数。以下是多数据集训练的步骤:

  1. 使用一个 datasets.Dataset 实例的字典 (或 datasets.DatasetDict) 作为 train_dataseteval_dataset
  2. (可选) 如果你希望为不同的数据集使用不同的损失函数,请使用一个损失函数的字典,其中数据集名称映射到损失。

每个训练/评估批次将仅包含来自一个数据集的样本。从多个数据集中采样批次的顺序由 MultiDatasetBatchSamplers 枚举确定,该枚举可以通过 multi_dataset_batch_sampler 传递给 SentenceTransformersTrainingArguments。有效的选项包括:

  • MultiDatasetBatchSamplers.ROUND_ROBIN : 以轮询方式从每个数据集采样,直到一个数据集用尽。这种策略可能不会使用每个数据集中的所有样本,但它确保了每个数据集的平等采样。
  • MultiDatasetBatchSamplers.PROPORTIONAL (默认): 按比例从每个数据集采样。这种策略确保了每个数据集中的所有样本都被使用,并且较大的数据集被更频繁地采样。

多任务训练已被证明是高度有效的。例如,Huang et al. 2024 使用了 MultipleNegativesRankingLossCoSENTLossMultipleNegativesRankingLoss 的一个变体 (不包含批次内的负样本,仅包含硬负样本),以在中国取得最先进的表现。他们还应用了 MatryoshkaLoss 以使模型能够产生 Matryoshka Embeddings

以下是多数据集训练的一个示例:

from datasets import load_dataset
from sentence_transformers import SentenceTransformer, SentenceTransformerTrainer
from sentence_transformers.losses import CoSENTLoss, MultipleNegativesRankingLoss, SoftmaxLoss

# 1. Load a model to finetune
model = SentenceTransformer("bert-base-uncased")

# 2. Loadseveral Datasets to train with
# (anchor, positive)
all_nli_pair_train = load_dataset("sentence-transformers/all-nli", "pair", split="train[:10000]")
# (premise, hypothesis) + label
all_nli_pair_class_train = load_dataset("sentence-transformers/all-nli", "pair-class", split="train[:10000]")
# (sentence1, sentence2) + score
all_nli_pair_score_train = load_dataset("sentence-transformers/all-nli", "pair-score", split="train[:10000]")
# (anchor, positive, negative)
all_nli_triplet_train = load_dataset("sentence-transformers/all-nli", "triplet", split="train[:10000]")
# (sentence1, sentence2) + score
stsb_pair_score_train = load_dataset("sentence-transformers/stsb", split="train[:10000]")
# (anchor, positive)
quora_pair_train = load_dataset("sentence-transformers/quora-duplicates", "pair", split="train[:10000]")
# (query, answer)
natural_questions_train = load_dataset("sentence-transformers/natural-questions", split="train[:10000]")

# Combine all datasets into a dictionary with dataset names to datasets
train_dataset = {
    "all-nli-pair": all_nli_pair_train,
    "all-nli-pair-class": all_nli_pair_class_train,
    "all-nli-pair-score": all_nli_pair_score_train,
    "all-nli-triplet": all_nli_triplet_train,
    "stsb": stsb_pair_score_train,
    "quora": quora_pair_train,
    "natural-questions": natural_questions_train,
}

# 3. Load several Datasets to evaluate with
# (anchor, positive, negative)
all_nli_triplet_dev = load_dataset("sentence-transformers/all-nli", "triplet", split="dev")
# (sentence1, sentence2, score)
stsb_pair_score_dev = load_dataset("sentence-transformers/stsb", split="validation")
# (anchor, positive)
quora_pair_dev = load_dataset("sentence-transformers/quora-duplicates", "pair", split="train[10000:11000]")
# (query, answer)
natural_questions_dev = load_dataset("sentence-transformers/natural-questions", split="train[10000:11000]")

# Use a dictionary for the evaluation dataset too, or just use one dataset or none at all
eval_dataset = {
    "all-nli-triplet": all_nli_triplet_dev,
    "stsb": stsb_pair_score_dev,
    "quora": quora_pair_dev,
    "natural-questions": natural_questions_dev,
}

# 4. Load several loss functions to train with
# (anchor, positive), (anchor, positive, negative)
mnrl_loss = MultipleNegativesRankingLoss(model)
# (sentence_A, sentence_B) + class
softmax_loss = SoftmaxLoss(model)
# (sentence_A, sentence_B) + score
cosent_loss = CoSENTLoss(model)

# Create a mapping with dataset names to loss functions, so the trainer knows which loss to apply where
# Note: You can also just use one loss if all your training/evaluation datasets use the same loss
losses = {
    "all-nli-pair": mnrl_loss,
    "all-nli-pair-class": softmax_loss,
    "all-nli-pair-score": cosent_loss,
    "all-nli-triplet": mnrl_loss,
    "stsb": cosent_loss,
    "quora": mnrl_loss,
    "natural-questions": mnrl_loss,
}

# 5. Define a simple trainer, although it's recommended to use one with args & evaluators
trainer = SentenceTransformerTrainer(
    model=model,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    loss=losses,
)
trainer.train()

# 6. Save the trained model and optionally push it to the Hugging Face Hub
model.save_pretrained("bert-base-all-nli-stsb-quora-nq")
model.push_to_hub("bert-base-all-nli-stsb-quora-nq")

弃用

在 Sentence Transformer v3 发布之前,所有模型都会使用 SentenceTransformer.fit 方法进行训练。从 v3.0 开始,该方法将使用 SentenceTransformerTrainer 作为后端。这意味着你的旧训练代码仍然应该可以工作,甚至可以升级到新的特性,如多 GPU 训练、损失记录等。然而,新的训练方法更加强大,因此建议使用新的方法编写新的训练脚本。

附加资源

训练示例

以下页面包含带有解释的训练示例以及代码链接。我们建议你浏览这些页面以熟悉训练循环:

文档

此外,以下页面可能有助于你了解 Sentence Transformers 的更多信息:

最后,以下是一些高级页面,你可能会感兴趣:


英文原文: https://hf.co/blog/train-sentence-transformers

原文作者: Tom Aarsen

译者: innovation64

与用 Sentence Transformers v3 训练和微调嵌入模型相似的内容:

用 Sentence Transformers v3 训练和微调嵌入模型

Sentence Transformers 是一个 Python 库,用于使用和训练各种应用的嵌入模型,例如检索增强生成 (RAG)、语义搜索、语义文本相似度、释义挖掘 (paraphrase mining) 等等。其 3.0 版本的更新是该工程自创建以来最大的一次,引入了一种新的训练方法。在这篇博

用 KV 缓存量化解锁长文本生成

很高兴和大家分享 Hugging Face 的一项新功能: KV 缓存量化 ,它能够把你的语言模型的速度提升到一个新水平。 太长不看版: KV 缓存量化可在最小化对生成质量的影响的条件下,减少 LLM 在长文本生成场景下的内存使用量,从而在内存效率和生成速度之间提供可定制的权衡。 你是否曾尝试过用语

用Python脚本迁移MongoDB数据到金仓-kingbase数据库

1、首先需要明确MongoDB与kingbase的对应关系,collection相当于table,filed相当于字段,根据这个对应关系创建表; 此次迁移的MongoDB里的数据字段是:_id(自动生成的objectid),image(转成二进制存储的文档) 所以在金仓里创建表 create tab

用.NET代码生成JSON Schema 验证器

问题 对于验证复杂JSON数据是否合法的需求,通常的解决方式是标准JSON Schema,.Net下有对应的JSON Schema实现库。应用程序通常需要将标准JSON schema传入实现库,来做后续的数据验证。这里有一种情况,就是如果使用者不太了解标准JSON Schema格式,但又希望能在自己

用python字典统计CSV数据

1.用python字典统计CSV数据的步骤和代码示例 为了使用Python字典来统计CSV数据,我们可以使用内置的csv模块来读取CSV文件,并使用字典来存储统计信息。以下是一个详细的步骤和完整的代码示例: 1.1步骤 (1)导入csv模块。 (2)打开CSV文件并读取数据。 (3)初始化一个空字典

【ESP32】制作 Wi-fi 音箱(HTTP + I2S 协议)

用 Wifi 来传输音频数据,会比蓝牙更好。使用蓝牙方式,不管你用什么协议,都会对数据重新编码,说人话就是有损音质,虽然不至于全损。而使用 Wifi 就可以将 PCM 数据直接传输,无需再编码和压缩。在 ESP32 开发板上可以通过 I2S(IIS)向功放芯片发出音频数据。 关于 i2s 的时序,老

用STM32F4的DMA实现高速、实时的同步并行通信——以读取高速ADC为例[原创www.cnblogs.com/helesheng]

本文给出了一种利用STM32F4系列MCU的DMA功能,实现10MSPS数量级的同步并行数据通信的方法。并用控制高速流水线型的模数转换器AD9200读取作为实例,展示了该通行方法。本文最后总结了该方法的优点和问题,以及克服这些问题的思路。

用python用户注册和短信验证码逻辑实现案例

一.写代码前分析(逻辑分析OK了才可以顺利成章的敲代码): A、用户发送请求 1、注册账号(用户名不能重复)--按照需求进行判断 2、短信验证码(有效期5分钟)--对短信验证码进行保存 B、用户注册、短信验证用不同得函数封装实现 d_user={} #存放用户名和密码的数据字典 verificati

用 VS Code 搞 Qt6:让信号和槽自动建立连接

Qt 具备让某个对象的信号与符合要求的槽函数自动建立连接。弄起来也很简单,只要调用这个静态方法即可: QMetaObject::connectSlotsByName(...); connectSlotsByName 方法需要一个参数,此参数的指针指向一个实例,这个实例自身的信号,以及它的子级对象的信

用现代C++写一个python的简易型list

std::variant介绍:en.cppreference.com/w/cpp/utility/variant 通过泛型模板(仅提供了int, double, string三种类型的存储),实现了append, pop, front, back, size等方法,并且通过重载运算符实现了对负数索引