深度学习模型keras第二十五讲:使用KerasNLP从零开始预训练Transformer模型

1、KerasNPL预训练Transformer模型概念

使用KerasNLP来预训练一个Transformer模型涉及多个步骤。由于Keras本身并不直接提供NLP的预训练模型或工具集,我们通常需要结合像TensorFlow Hub、Hugging Face的Transformers库或自定义的Keras层来实现。

以下是一个简化的步骤概述,用于说明如何使用Keras和相关的NLP工具来预训练一个Transformer模型:

  • 环境准备

      - 安装TensorFlow和Keras。- 安装任何你需要的NLP相关库,如Hugging Face的Transformers。
    
  • 数据准备
    - 收集一个大型的无标签文本数据集,用于预训练。
    - 对文本进行预处理,包括分词、填充/截断、创建词汇表等。

  • 定义模型
    - 使用Keras的Sequential API或函数式API定义Transformer模型的架构。
    - 通常,你会需要实现Transformer的编码器层(包括自注意力机制和前馈神经网络)。
    - 你也可以考虑使用现有的Transformer实现作为起点,如Hugging Face的Transformers库中的BERT或GPT模型。

  • 编译和配置模型
    - 编译模型,设置损失函数(对于预训练,可能是掩码语言建模的损失或句子级别的损失)和优化器。
    - 配置模型训练的超参数,如学习率、批大小、训练轮数等。

  • 训练模型
    - 使用准备好的数据集训练模型。这可能需要很长时间,特别是当数据集很大时。
    - 监控训练过程中的损失和任何其他的评估指标。

  • 保存模型
    - 在训练完成后,保存模型的权重和架构。

  • (可选)微调
    - 如果你打算将预训练的Transformer模型用于特定的NLP任务,你可能需要在有标签的数据集上进行微调。

需要注意的是,预训练一个Transformer模型是一个复杂且资源密集的任务,通常需要大量的计算资源(如GPU或TPU)和时间。此外,由于Keras本身并不直接提供NLP的预训练功能,你可能需要深入了解Transformer架构和相关的NLP技术来实现这一目标。

如果你希望快速开始并使用预训练的Transformer模型,考虑使用Hugging Face的Transformers库,它提供了大量预训练的模型和方便的API来加载和使用这些模型。

KerasNLP旨在简化构建最先进的文本处理模型的过程。在本文中,我们将展示如何使用该库的组件来简化从头开始预训练和微调Transformer模型的流程。

  • 设置、任务定义和建立基线。
  • 预训练一个Transformer模型。
  • 在分类任务上微调Transformer模型。

2、KerasNLP预训练Transformer模型的步骤

2.1 设置

安装及导入

!pip install -q --upgrade keras-nlp
!pip install -q --upgrade keras  # Upgrade to Keras 3.
import osos.environ["KERAS_BACKEND"] = "jax"  # or "tensorflow" or "torch"import keras_nlp
import tensorflow as tf
import keras

下载数据集
接下来,我们可以下载两个数据集。

SST-2 是一个文本分类数据集,也是我们的“最终目标”。这个数据集经常被用来作为语言模型的基准测试。
WikiText-103:一个中等规模的英文维基百科精选文章集合,我们将用于预训练。
最后,我们将下载一个WordPiece词汇表,以便在后面的指南中进行子词分词。

# Download pretraining data.
keras.utils.get_file(origin="https://s3.amazonaws.com/research.metamind.io/wikitext/wikitext-103-raw-v1.zip",extract=True,
)
wiki_dir = os.path.expanduser("~/.keras/datasets/wikitext-103-raw/")# Download finetuning data.
keras.utils.get_file(origin="https://dl.fbaipublicfiles.com/glue/data/SST-2.zip",extract=True,
)
sst_dir = os.path.expanduser("~/.keras/datasets/SST-2/")# Download vocabulary data.
vocab_file = keras.utils.get_file(origin="https://storage.googleapis.com/tensorflow/keras-nlp/examples/bert/bert_vocab_uncased.txt",
)

定义参数
接下来,定义一些在训练过程中将使用的超参数。

# Preprocessing params.
PRETRAINING_BATCH_SIZE = 128
FINETUNING_BATCH_SIZE = 32
SEQ_LENGTH = 128
MASK_RATE = 0.25
PREDICTIONS_PER_SEQ = 32# Model params.
NUM_LAYERS = 3
MODEL_DIM = 256
INTERMEDIATE_DIM = 512
NUM_HEADS = 4
DROPOUT = 0.1
NORM_EPSILON = 1e-5# Training params.
PRETRAINING_LEARNING_RATE = 5e-4
PRETRAINING_EPOCHS = 8
FINETUNING_LEARNING_RATE = 5e-5
FINETUNING_EPOCHS = 3

2.2 加载数据

使用tf.data来加载我们的数据,这将允许我们定义用于分词和文本预处理的输入管道。

# Load SST-2.
sst_train_ds = tf.data.experimental.CsvDataset(sst_dir + "train.tsv", [tf.string, tf.int32], header=True, field_delim="\t"
).batch(FINETUNING_BATCH_SIZE)
sst_val_ds = tf.data.experimental.CsvDataset(sst_dir + "dev.tsv", [tf.string, tf.int32], header=True, field_delim="\t"
).batch(FINETUNING_BATCH_SIZE)# Load wikitext-103 and filter out short lines.
wiki_train_ds = (tf.data.TextLineDataset(wiki_dir + "wiki.train.raw").filter(lambda x: tf.strings.length(x) > 100).batch(PRETRAINING_BATCH_SIZE)
)
wiki_val_ds = (tf.data.TextLineDataset(wiki_dir + "wiki.valid.raw").filter(lambda x: tf.strings.length(x) > 100).batch(PRETRAINING_BATCH_SIZE)
)# Take a peak at the sst-2 dataset.
print(sst_train_ds.unbatch().batch(4).take(1).get_single_element())
(<tf.Tensor: shape=(4,), dtype=string, numpy=
array([b'hide new secretions from the parental units ',b'contains no wit , only labored gags ',b'that loves its characters and communicates something rather beautiful about human nature ',b'remains utterly satisfied to remain the same throughout '],dtype=object)>, <tf.Tensor: shape=(4,), dtype=int32, numpy=array([0, 0, 1, 0], dtype=int32)>)

程序员可以看到,我们的SST-2数据集包含相对较短的电影评论文本片段。我们的目标是预测这些片段的情感倾向。标签为1表示正面情感,标签为0表示负面情感。

2.3建立基线

作为第一步,我们将建立一个性能良好的基线。其实这一步并不需要KerasNLP,我们只需要使用Keras的核心层就可以了。

我们将训练一个简单的词袋模型,其中我们为每个词汇表中的单词学习一个正面或负面的权重。一个样本的分数仅仅是样本中所有单词的权重之和。

# This layer will turn our input sentence into a list of 1s and 0s the same size
# our vocabulary, indicating whether a word is present in absent.
multi_hot_layer = keras.layers.TextVectorization(max_tokens=4000, output_mode="multi_hot"
)
multi_hot_layer.adapt(sst_train_ds.map(lambda x, y: x))
multi_hot_ds = sst_train_ds.map(lambda x, y: (multi_hot_layer(x), y))
multi_hot_val_ds = sst_val_ds.map(lambda x, y: (multi_hot_layer(x), y))# We then learn a linear regression over that layer, and that's our entire
# baseline model!inputs = keras.Input(shape=(4000,), dtype="int32")
outputs = keras.layers.Dense(1, activation="sigmoid")(inputs)
baseline_model = keras.Model(inputs, outputs)
baseline_model.compile(loss="binary_crossentropy", metrics=["accuracy"])
baseline_model.fit(multi_hot_ds, validation_data=multi_hot_val_ds, epochs=5)

词袋方法可能既快速又出乎意料地强大,尤其是在输入示例包含大量单词时。但对于较短的序列,它可能会达到性能上限。

为了做得更好,我们希望构建一个能够评估上下文中的单词的模型。我们不能再将每个单词视为孤立的存在,而是需要利用输入中整个有序序列所包含的信息。

这就引出了一个问题。SST-2是一个非常小的数据集,没有足够的示例文本来尝试构建一个更大、参数更多的模型来学习序列。我们很快就会开始过拟合并记住训练集,而没有任何提高我们对未见示例的泛化能力。

这时,预训练就派上了用场,它允许我们在一个更大的语料库上进行学习,并将我们的知识转移到SST-2任务上。同时,KerasNLP的引入使我们能够轻松地预训练一个特别强大的模型——Transformer。

2.4预训练

为了超越我们的基线模型,我们将利用WikiText103数据集,这是一个比SST-2大得多的无标签维基百科文章集合。

我们将训练一个Transformer模型,这是一个高度表达性的模型,它将学习将输入中的每个单词嵌入为低维向量。由于我们的维基百科数据集没有标签,因此我们将使用一个无监督的训练目标,称为掩码语言建模(Masked Language Modeling,MaskedLM)。

基本上,我们将玩一个大型的“猜缺失单词”游戏。对于每个输入样本,我们将遮盖25%的输入数据,并训练我们的模型来预测我们遮盖的部分。

2.4.1为MaskedLM任务预处理数据

我们为MaskedLM任务进行的文本预处理将分为两个阶段。

  • 将输入文本分词为token id的整数序列。
  • 遮盖输入中的某些位置以进行预测。

为了进行分词,我们可以使用keras_nlp.tokenizers.Tokenizer——KerasNLP中将文本转换为整数token id序列的构建块。

特别是,我们将使用keras_nlp.tokenizers.WordPieceTokenizer进行子词分词。在大文本语料库上训练模型时,子词分词非常流行。基本上,它允许我们的模型从不常见的单词中学习,而不需要包含训练集中每个单词的庞大词汇表。

我们需要做的第二件事是为MaskedLM任务遮盖输入。为此,我们可以使用keras_nlp.layers.MaskedLMMaskGenerator,它将在每个输入中随机选择一组token并遮盖它们。

分词器和遮盖层都可以在tf.data.Dataset.map的调用中使用。我们可以使用tf.data在CPU上高效地预计算每个批次,而我们的GPU或TPU则处理前一个批次的训练。由于我们的遮盖层每次都会选择新的单词进行遮盖,因此每次遍历数据集时,我们都会获得一组全新的标签进行训练。

# Setting sequence_length will trim or pad the token outputs to shape
# (batch_size, SEQ_LENGTH).
tokenizer = keras_nlp.tokenizers.WordPieceTokenizer(vocabulary=vocab_file,sequence_length=SEQ_LENGTH,lowercase=True,strip_accents=True,
)
# Setting mask_selection_length will trim or pad the mask outputs to shape
# (batch_size, PREDICTIONS_PER_SEQ).
masker = keras_nlp.layers.MaskedLMMaskGenerator(vocabulary_size=tokenizer.vocabulary_size(),mask_selection_rate=MASK_RATE,mask_selection_length=PREDICTIONS_PER_SEQ,mask_token_id=tokenizer.token_to_id("[MASK]"),
)def preprocess(inputs):inputs = tokenizer(inputs)outputs = masker(inputs)# Split the masking layer outputs into a (features, labels, and weights)# tuple that we can use with keras.Model.fit().features = {"token_ids": outputs["token_ids"],"mask_positions": outputs["mask_positions"],}labels = outputs["mask_ids"]weights = outputs["mask_weights"]return features, labels, weights# We use prefetch() to pre-compute preprocessed batches on the fly on the CPU.
pretrain_ds = wiki_train_ds.map(preprocess, num_parallel_calls=tf.data.AUTOTUNE
).prefetch(tf.data.AUTOTUNE)
pretrain_val_ds = wiki_val_ds.map(preprocess, num_parallel_calls=tf.data.AUTOTUNE
).prefetch(tf.data.AUTOTUNE)# Preview a single input example.
# The masks will change each time you run the cell.
print(pretrain_val_ds.take(1).get_single_element())

上述部分将我们的数据集整理为一个(features, labels, weights)的元组,可以直接传递给keras.Model.fit()函数进行训练。

我们有两个特征:

  • “token_ids”,其中一些token已经被替换为我们的掩码token id。
  • “mask_positions”,跟踪我们遮盖了哪些token。

我们的标签就是我们遮盖掉的那些token的id。

由于不是所有序列的掩码数量都相同,我们还保留了一个sample_weight张量,通过给填充的标签零权重,来从我们的损失函数中移除它们。

2.4.2创建Transformer编码器

KerasNLP提供了所有构建块,可以快速构建一个Transformer编码器。

我们使用keras_nlp.layers.TokenAndPositionEmbedding首先将输入token id进行嵌入。这个层同时学习两种嵌入——一种是句子中单词的嵌入,另一种是句子中整数位置的嵌入。输出嵌入就是两者的和。

然后我们可以添加一系列的keras_nlp.layers.TransformerEncoder层。这些层是Transformer模型的核心,使用注意力机制来关注输入句子的不同部分,接着是一个多层感知机块。

这个模型的输出是每个输入token id的编码向量。与我们用作基线的词袋模型不同,这个模型在嵌入每个token时会考虑到它出现的上下文。

inputs = keras.Input(shape=(SEQ_LENGTH,), dtype="int32")# Embed our tokens with a positional embedding.
embedding_layer = keras_nlp.layers.TokenAndPositionEmbedding(vocabulary_size=tokenizer.vocabulary_size(),sequence_length=SEQ_LENGTH,embedding_dim=MODEL_DIM,
)
outputs = embedding_layer(inputs)# Apply layer normalization and dropout to the embedding.
outputs = keras.layers.LayerNormalization(epsilon=NORM_EPSILON)(outputs)
outputs = keras.layers.Dropout(rate=DROPOUT)(outputs)# Add a number of encoder blocks
for i in range(NUM_LAYERS):outputs = keras_nlp.layers.TransformerEncoder(intermediate_dim=INTERMEDIATE_DIM,num_heads=NUM_HEADS,dropout=DROPOUT,layer_norm_epsilon=NORM_EPSILON,)(outputs)encoder_model = keras.Model(inputs, outputs)
encoder_model.summary()
2.4.3预训练Transformer

你可以把encoder_model看作是一个模块化的单元,这是我们对下游任务真正感兴趣的部分。然而,我们仍然需要设置编码器以在MaskedLM任务上进行训练;为此,我们将添加一个keras_nlp.layers.MaskedLMHead层。

这个层将接收两个输入:一个是token的编码,另一个是我们在原始输入中遮盖的位置。它将收集我们遮盖的token编码,并将它们转换回对整个词汇表的预测。

有了这些,我们就可以编译并开始预训练了。如果你在一个Colab环境中运行这个,请注意这可能需要大约一个小时。训练Transformer是出了名的计算密集型,所以即使是这个相对较小的Transformer也需要一些时间。

# Create the pretraining model by attaching a masked language model head.
inputs = {"token_ids": keras.Input(shape=(SEQ_LENGTH,), dtype="int32", name="token_ids"),"mask_positions": keras.Input(shape=(PREDICTIONS_PER_SEQ,), dtype="int32", name="mask_positions"),
}# Encode the tokens.
encoded_tokens = encoder_model(inputs["token_ids"])# Predict an output word for each masked input token.
# We use the input token embedding to project from our encoded vectors to
# vocabulary logits, which has been shown to improve training efficiency.
outputs = keras_nlp.layers.MaskedLMHead(token_embedding=embedding_layer.token_embedding,activation="softmax",
)(encoded_tokens, mask_positions=inputs["mask_positions"])# Define and compile our pretraining model.
pretraining_model = keras.Model(inputs, outputs)
pretraining_model.compile(loss="sparse_categorical_crossentropy",optimizer=keras.optimizers.AdamW(PRETRAINING_LEARNING_RATE),weighted_metrics=["sparse_categorical_accuracy"],jit_compile=True,
)# Pretrain the model on our wiki text dataset.
pretraining_model.fit(pretrain_ds,validation_data=pretrain_val_ds,epochs=PRETRAINING_EPOCHS,
)# Save this base model for further finetuning.
encoder_model.save("encoder_model.keras")

2.5微调

预训练之后,我们现在可以在SST-2数据集上微调我们的模型。我们可以利用我们构建的编码器在上下文中预测单词的能力,以提高我们在下游任务上的性能。

2.5.1分类任务的数据预处理

对于微调任务的数据预处理比预训练的MaskedLM任务简单得多。我们只需要对输入句子进行分词,就可以开始训练了!

具体来说,对于SST-2这样的情感分类任务,我们可能需要执行以下步骤来准备数据:

  • 分词:使用与预训练时相同的分词器对文本进行分词,并转换为token IDs。

  • 填充和截断:由于模型期望接收固定长度的输入,我们需要将文本填充或截断到模型接受的长度。

  • 标签编码:将情感标签转换为数字形式,以便模型可以处理它们作为目标变量。

  • 划分数据集:将数据集划分为训练集、验证集(可选)和测试集。

  • 构建输入:将分词后的文本(token IDs)和对应的标签组合成训练所需的格式(例如,使用tf.data API构建输入管道)。

  • (可选)添加样本权重:如果数据集不平衡,我们可以考虑使用样本权重来平衡不同类别的贡献。

完成这些步骤后,我们就可以将预处理后的数据输入到预训练好的Transformer编码器中进行微调了。微调过程将调整模型的所有权重(或其中的一部分,如只调整顶部几层),以优化在SST-2数据集上的性能。

def preprocess(sentences, labels):return tokenizer(sentences), labels# We use prefetch() to pre-compute preprocessed batches on the fly on our CPU.
finetune_ds = sst_train_ds.map(preprocess, num_parallel_calls=tf.data.AUTOTUNE
).prefetch(tf.data.AUTOTUNE)
finetune_val_ds = sst_val_ds.map(preprocess, num_parallel_calls=tf.data.AUTOTUNE
).prefetch(tf.data.AUTOTUNE)# Preview a single input example.
print(finetune_val_ds.take(1).get_single_element())
2.5.2微调Transformer

要从编码后的token输出转换为分类预测,我们需要给我们的Transformer模型再添加一个“头”。在这里,我们可以简单地实现它。我们将编码后的token合并在一起(池化),并使用一个单独的密集层(全连接层)进行预测。

# Reload the encoder model from disk so we can restart fine-tuning from scratch.
encoder_model = keras.models.load_model("encoder_model.keras", compile=False)# Take as input the tokenized input.
inputs = keras.Input(shape=(SEQ_LENGTH,), dtype="int32")# Encode and pool the tokens.
encoded_tokens = encoder_model(inputs)
pooled_tokens = keras.layers.GlobalAveragePooling1D()(encoded_tokens[0])# Predict an output label.
outputs = keras.layers.Dense(1, activation="sigmoid")(pooled_tokens)# Define and compile our fine-tuning model.
finetuning_model = keras.Model(inputs, outputs)
finetuning_model.compile(loss="binary_crossentropy",optimizer=keras.optimizers.AdamW(FINETUNING_LEARNING_RATE),metrics=["accuracy"],
)# Finetune the model for the SST-2 task.
finetuning_model.fit(finetune_ds,validation_data=finetune_val_ds,epochs=FINETUNING_EPOCHS,
)

预训练已经将我们的性能提升到了84%,但这对于Transformer模型来说还远未达到上限。在预训练过程中,你可能已经注意到验证性能仍在稳步提高。我们的模型仍然远远没有训练充分。通过增加训练轮次、训练一个更大的Transformer模型,以及在更多的未标记文本上进行训练,都可以继续显著提高性能。

KerasNLP的关键目标之一是提供NLP模型构建的模块化方法。在这里,我们展示了构建Transformer模型的一种方法,但KerasNLP支持越来越多用于文本预处理和模型构建的组件。我们希望它能让您更容易地针对自然语言问题尝试不同的解决方案。

3、总结

本文的讨论主要涉及了Transformer模型的预训练和微调过程,以及如何使用KerasNLP库来构建和实验NLP模型。首先,提到了预训练Transformer模型对于提高下游任务性能的重要性,包括通过MaskedLM任务进行预训练。随后,介绍了在预训练之后,如何对Transformer模型进行微调以适应特定的分类任务(如SST-2情感分类),并强调了数据预处理的重要性。此外,还提到了预训练模型的性能可能远未达到上限,可以通过增加训练轮次、扩大模型规模以及在更多未标记文本上进行训练来进一步提高性能。最后,强调了KerasNLP库在NLP模型构建中的模块化方法,它支持各种用于文本预处理和模型构建的组件,使得实验和尝试不同的解决方案变得更加容易。整个讨论展示了Transformer模型在NLP任务中的强大潜力和灵活性,以及使用KerasNLP库进行NLP模型开发的优势。

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

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

相关文章

Android Baidu地图SDK只展示蓝背景,没有绘制内容问题解决

背景 项目里接入了Baidu地图SDK&#xff0c;用于展示信息、选点。 在一个新的Activity中&#xff0c;引入了TextureMapView&#xff0c;用于地图展示。 选点过程有两个页面。 A页面中有一个不能滑动的地图&#xff0c;只是用来展示&#xff0c;没有其他任何操作。 点击A页…

Plesk中如何移除之前添加的域名

我这边想要移除我之前绑定到主机的域名&#xff0c;但是不知道如何在主机上面进行移除&#xff0c;由于我使用的Hostease的Windows虚拟主机产品默认带普通用户权限的Plesk面板&#xff0c;但是不知道如何在Plesk上操作移除域名&#xff0c;因为也是对于Hostease主机产品不是很了…

java单元测试:JUnit断言库

JUnit断言库提供了一组用于验证测试结果的工具。这些断言方法帮助开发人员在单元测试中明确表达预期结果&#xff0c;并在实际结果与预期结果不符时报告失败。 1. JUnit中的断言 断言用于验证测试的预期结果。JUnit 5&#xff08;Jupiter&#xff09;提供了一组静态方法&…

获取和设置代理的动态IP的方式

引言 大家好&#xff0c;今天我来给大家分享一下如何通过编程技术来获取和设置代理的动态IP。在网络世界中&#xff0c;代理和动态IP是非常常见的概念&#xff0c;尤其对于需要大规模访问网站或者需要隐藏真实IP地址的应用程序来说&#xff0c;更是必不可少的工具。接下来&…

【精品】【算法实战】每日一题:如何用Python实现给定整数序列中寻找最小长度窗口以包含所有不同元素的算法?

问题&#xff1a; 如何用Python实现给定整数序列中寻找最小长度窗口以包含所有不同元素的算法&#xff1f; 核心思路 核心思路是利用双端队列&#xff08;作为滑动窗口&#xff09;来找到一个满足特定条件的最小长度子序列。算法遍历给定的序列&#xff0c;对于每个新数据点…

【Spring】Spring框架对RESTFul风格的支持

1、简介 Spring框架对RESTful风格的支持主要体现在Spring MVC和Spring Boot等模块中。RESTful&#xff08;Representational State Transfer&#xff0c;表述层资源状态转移&#xff09;是一种软件架构风格&#xff0c;它强调资源&#xff08;通常是网络上的信息&#xff09;的…

Java方法的基本用法

Java方法的基本用法 前言一、什么是方法方法存在的意义示例 二、方法定义语法基本语法代码示例注意事项 三、方法调用的执行过程基本规则代码示例计算两个整数相加计算 1! 2! 3! 4! 5! 四、实参和形参的关系代码示例交换两个整型变量原因分析解决办法 五、没有返回值的方法…

初识java——javaSE (6)接口的实现——比较器与深拷贝,浅拷贝

文章目录 前言一 比较器1.1 关于两个对象的比较1.2 Comparable接口&#xff1a;1.3 Arrays.sort方法的实现1.4 比较器的实现Comparator接口 二 深拷贝与浅拷贝2.1 浅拷贝&#xff1a;Cloneable接口&#xff1a;clone方法&#xff1a;实现拷贝&#xff1a;浅拷贝&#xff1a; 2.…

Python3 笔记:Python的所有关键字

查看Python的关键字首先需要用import导入keyword模块 import keyword # 查看Python的所有关键字&#xff0c;先用import导入keyword模块 print(keyword.kwlist) 运行结果&#xff1a; [False, None, True, and, as, assert, async, await, break, class, continue, def, …

MQ如何保证消息不丢失

MQ如何保证消息不丢失 问题分析具体分析及解决方案RabbitMQ生产者RabbitMQ配置消费者 KafkaKafka配置消费者 问题分析 从Kafka和RabbitMQ进行分析&#xff0c;MQ消息丢失的情况有生产者推送消息时数据丢失&#xff0c;MQ中间件宕机情况下数据丢失&#xff0c;消费者消费时消息…

GoLand map中的并发问题——为什么会造成并发问题?该怎么解决?

GoLand map中的并发问题——为什么会造成并发问题&#xff1f;该怎么解决&#xff1f; 问题提出原因解析具体原因竞态检测器 如何解决并发问题呢&#xff1f;方法一 &#xff1a; 使用sync.Mutex方法二&#xff1a; 使用sync.Map我们首先了解一下sync.Map的常用方法&#xff1a…

2024.5.24.python.exercise

# python文件操作 # f open("打字版.txt", "a", encoding"UTF-8") # writer input("请输入你想要写入到文件的内容") # f.write(writer) # f.flush() # f.close() # f open("打字版.txt", "r", encoding"…

代码随想录算法训练营第三十九天 | 738.单调递增的数字、968.监控二叉树 (可以跳过)

监控二叉树同样的等代码随想录刷完后&#xff0c;再回头来看&#xff0c;先跳过 738.单调递增的数字 代码随想录 解题思路 例如&#xff1a;98&#xff0c;一旦出现strNum[i - 1] > strNum[i]的情况&#xff08;非单调递增&#xff09;&#xff0c;首先想让strNum[i - 1]--…

游戏引擎支持脚本编程的好处

哈喽呀&#xff0c;大家好&#xff0c;淼淼又来和大家见面啦&#xff0c;咱们今天来聊聊游戏引擎&#xff0c;游戏引擎作为现代游戏开发的核心&#xff0c;它集成了图形渲染、物理模拟、音频处理、动画系统、输入输出控制等多种复杂技术于一体&#xff0c;为开发者提供了一个高…

ASP+ACCESS基于WEB网上留言板

摘要 本文概述了ACCESS数据库及其相关的一些知识&#xff0c;着重论述ACCESS数据库和ASP的中间技术&#xff0c;构建一个简单的留言板。具体的实现是构造一个留言板系统&#xff0c;能很方便的和同学沟通和交流。留言板具有功能强大、使用方便的特点。用户以个人的身份进入&am…

瑞芯微RV1126——人脸识别源码分析

本节内容主要分为3部分&#xff0c;第一部分是流程结构图;第二部分为人脸识别代码流程;第三部分为具体的代码分析。 1.流程结构图 2.人脸识别代码流程 1、人脸数据的初始化&#xff1a; init_all_rockx_face_data();init_face_data();2、创建rtsp会话&#xff0c;这里包括发…

一个典型的分布式缓存系统是什么样的?no.32

分布式 Redis 服务 由于本课程聚焦于缓存&#xff0c;接下来&#xff0c;我将以微博内的 分布式 Redis 服务系统为例&#xff0c;介绍一个典型的分布式缓存系统的组成。 微博的 Redis 服务内部也称为 RedisService。RedisService 的整体架构如图所示。主要分为Proxy、存储、集…

产品推荐 | 基于Xilinx XCKU115的半高PCIe x8 硬件加速卡

一、板卡概述 本板卡系我公司自主研发&#xff0c;采用Xilinx公司的XCKU115-3-FLVF1924-E芯片作为主处理器&#xff0c;主要用于FPGA硬件加速。板卡设计满足工业级要求。如下图所示&#xff1a; 二、功能和技术指标 板卡功能 参数内容 主处理器 XCKU115-3-FLVF1924-E 板卡…

UE4/UE5像素流送云推流:多人访问不稳定、画面糊、端口占用多等

UE4/UE5想要实现网页访问&#xff0c;很多工程师会选择guan方的像素流送。但这个技术要求在模型开发初期就接入。对于一些已有UE模型是无法进行流化的。虽然也可以解决新UE模型的网页访问问题&#xff0c;但在实际的应用中&#xff0c;点量云流也收到很多反馈说&#xff0c;使用…

netty-socketio 集群随记

实现netty-socketio集群的方式 代码实例 PostConstructpublic void subscribe() {pubSubStore.subscribe(PubSubType.DISPATCH, new PubSubListener<DispatchMessage>() {Overridepublic void onMessage(DispatchMessage message) {log.debug("subscribe: {}"…