【Transformer-Hugging Face 06/10】 数据预处理实例

目录

  • 一、说明
  • 二、自然语言处理
    • 2.1 Pad
    • 2.2 截断
    • 2.3 构建张量
  • 三、TensorFlow
  • 四、处理语音
  • 五、计算机视觉
  • 六、填充
  • 七、Multimodal

一、说明

   在数据集上训练模型之前,需要将其预处理为预期的模型输入格式。无论您的数据是文本、图像还是音频,都需要将它们转换并组装成批量张量。🤗 Transformers 提供了一组预处理类来帮助为模型准备数据。在本教程中,您将了解以下内容:

  • 文本,使用Tokenizer将文本转换为标记序列,创建标记的数字表示,并将它们组装成张量。
  • 语音和音频,使用特征提取器从音频波形中提取顺序特征并将其转换为张量。
  • 图像输入使用ImageProcessor将图像转换为张量。
  • 多模态输入,使用处理器来组合分词器和特征提取器或图像处理器。

   AutoProcessor 无论您使用分词器、图像处理器、特征提取器还是处理器,它始终有效并自动为您正在使用的模型选择正确的类。

   在开始之前,请安装 🤗 数据集,以便您可以加载一些数据集进行实验:

pip install datasets

二、自然语言处理

   预处理文本数据的主要工具是分词器。分词器根据一组规则将文本分割成标记。标记被转换为数字,然后是张量,成为模型输入。模型所需的任何额外输入均由分词器添加。

   如果您计划使用预训练模型,那么使用关联的预训练分词器非常重要。这确保了文本以与预训练语料库相同的方式进行分割,并在预训练期间使用相同的相应标记到索引(通常称为词汇)。

   首先使用AutoTokenizer.from_pretrained()方法加载预训练的分词器。这将下载模型预训练的词汇:

from transformers import AutoTokenizer 
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

   然后将您的文本传递给标记器:

encoded_input = tokenizer("Do not meddle in the affairs of wizards, for they are subtle and quick to anger.")
print(encoded_input)

{ ‘input_ids’ : [ 101 , 2079 , 2025 , 19960 , 10362 , 1999 , 1996 , 3821 , 1997 , 16657 , 1010 , 2005 , 2027 , 2024 , 11259 , 1998 , 4248 , 2000 , 4963 , 1012 , 102 ] ,
’ token_type_ids’ : [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
‘attention_mask’ : [ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ] }

   分词器返回一个包含三个重要项目的字典:

   input_ids是句子中每个标记对应的索引。

  •    Attention_mask指示是否应注意令牌。
  •    token_type_ids标识当存在多个序列时令牌属于哪一个序列。
  •    通过解码返回您的输入input_ids:
tokenizer.decode(encoded_input["input_ids"])

   '​​[CLS] 不要插手巫师的事务,因为他们很狡猾且容易生气。[九月]'正如您所看到的,分词器在句子中添加了两个特殊的标记 - CLSand SEP(分类器和分隔符)。并非所有模型都需要特殊标记,但如果需要,标记生成器会自动为您添加它们。

   如果您想要预处理多个句子,请将它们作为列表传递给分词器:

batch_sentences = ["But what about second breakfast?","Don't think he knows about second breakfast, Pip.","What about elevensies?",
]
encoded_inputs = tokenizer(batch_sentences)
print(encoded_inputs)

{ ‘input_ids’ : [[ 101 , 1252 , 1184 , 1164 , 1248 , 6462 , 136 , 102 ],
[ 101、1790、112、189、1341、1119、3520、1164、1248、6462、117、21902、1643、119、102 ] 、 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
[ 101 , 1327 , 1164 , 5450 , 23434 , 136 , 102 ]],
‘token_type_ids’ : [[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 ]],
‘attention_mask’ : [[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ],
[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ],
[ 1 , 1 , 1 , 1 , 1 , 1 , 1 ]]}

2.1 Pad

   句子的长度并不总是相同,这可能是一个问题,因为张量(模型输入)需要具有统一的形状。填充是一种通过向较短句子添加特殊填充标记来确保张量为矩形的策略。

   将参数设置padding为True以填充批次中的较短序列以匹配最长序列:

batch_sentences = ["But what about second breakfast?","Don't think he knows about second breakfast, Pip.","What about elevensies?",
]
encoded_input = tokenizer(batch_sentences, padding=True)
print(encoded_input)

{ ‘input_ids’ : [[ 101 , 1252 , 1184 , 1164 , 1248 , 6462 , 136 , 102 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 101、1790、112、189、1341、1119、3520、1164、1248、6462、117、21902、1643、119、102 ] 、 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
[ 101 , 1327 , 1164 , 5450 , 23434 , 136 , 102 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]],
‘token_type_ids’ : [[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]],
‘attention_mask’ : [[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ],
[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]]}

   第一个和第三个句子现在用0’ 填充,因为它们更短。

2.2 截断

另一方面,有时序列可能太长,模型无法处理。在这种情况下,您需要将序列截断为更短的长度。

将参数设置truncation为True将序列截断为模型接受的最大长度:

batch_sentences = ["But what about second breakfast?","Don't think he knows about second breakfast, Pip.","What about elevensies?",
]
encoded_input = tokenizer(batch_sentences, padding=True, truncation=True)
print(encoded_input)

{ ‘input_ids’ : [[ 101 , 1252 , 1184 , 1164 , 1248 , 6462 , 136 , 102 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 101、1790、112、189、1341、1119、3520、1164、1248、6462、117、21902、1643、119、102 ] 、 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
[ 101 , 1327 , 1164 , 5450 , 23434 , 136 , 102 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]],
‘token_type_ids’ : [[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]],
‘attention_mask’ : [[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ],
[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]]}

   查看填充和截断概念指南以了解更多不同的填充和截断参数。

2.3 构建张量

最后,您希望分词器返回输入模型的实际张量。

将return_tensors参数设置pt为 PyTorch 或tfTensorFlow:

batch_sentences = ["But what about second breakfast?","Don't think he knows about second breakfast, Pip.","What about elevensies?",
]
encoded_input = tokenizer(batch_sentences, padding=True, truncation=True, return_tensors="pt")
print(encoded_input)

{ ‘input_ids’ : 张量([[ 101 , 1252 , 1184 , 1164 , 1248 , 6462 , 136 , 102 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 101、1790、112、189、1341、1119、3520、1164、1248、6462、117、21902、1643、119、102 ] 、 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
[ 101 , 1327 , 1164 , 5450 , 23434 , 136 , 102 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]]),
‘token_type_ids’ : 张量([[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]]),
‘attention_mask’ : 张量([[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ],
[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]])}

三、TensorFlow

batch_sentences = ["But what about second breakfast?","Don't think he knows about second breakfast, Pip.","What about elevensies?",
]
encoded_input = tokenizer(batch_sentences, padding=True, truncation=True, return_tensors="tf")
print(encoded_input)

{ ‘input_ids’ : <tf.Tensor: shape=( 2 , 9 ), dtype=int32, numpy=
数组([[ 101 , 1252 , 1184 , 1164 , 1248 , 6462 , 136 , 102 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,
[ 101、1790、112、189、1341、1119、3520、1164、1248、6462、117、21902、1643、119、102 ] 、 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
[ 101 , 1327 , 1164 , 5450 , 23434 , 136 , 102 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]],
dtype=int32)>,
‘token_type_ids’ : <tf.Tensor: shape=( 2 , 9 ), dtype=int32, numpy=
数组([[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]], dtype=int32)>,
‘attention_mask’ : <tf.Tensor: shape= ( 2 , 9 ), dtype=int32, numpy=
数组([[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,
[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ],
[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]], dtype=int32)>}

   不同的管道在其“call()”中支持分词器参数的方式不同。“text-2-text- Generation”管道仅支持(即传递)“截断”。“文本生成”管道支持“max_length”、“truncation”、“padding”和“add_special_tokens”。在“fill-mask”管道中,分词器参数可以在“tokenizer_kwargs”参数(字典)中传递。

四、处理语音

   对于音频任务,您需要一个特征提取器来为模型准备数据集。特征提取器旨在从原始音频数据中提取特征,并将其转换为张量。

   加载MInDS-14数据集(有关如何加载数据集的更多详细信息,请参阅🤗数据集教程)以了解如何将特征提取器与音频数据集一起使用:

from datasets import load_dataset, Audio
dataset = load_dataset("PolyAI/minds14", name="en-US", split="train")

   访问该列的第一个元素audio以查看输入。调用该audio列会自动加载音频文件并重新采样:

 dataset[0]["audio"]

{ ‘数组’ : 数组([ 0. , 0.00024414 , - 0.00024414 , …, - 0.00024414 ,
0. , 0. ], dtype=float32),
‘路径’ : ‘/root/.cache/huggingface/datasets/下载/提取/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~JOINT_ACCOUNT/602ba55abb1e6d0fbce92065.wav’,‘sampling_rate’:8000 }
_

   这将返回三个项目:

  • array是作为一维数组加载并可能重新采样的语音信号。
  • path指向音频文件的位置。
  • sampling_rate指的是每秒测量语音信号中的多少个数据点。
       在本教程中,您将使用Wav2Vec2模型。查看模型卡,您将了解到 Wav2Vec2 是在 16kHz 采样语音音频上进行预训练的。音频数据的采样率与用于预训练模型的数据集的采样率相匹配非常重要。如果您的数据的采样率不相同,那么您需要对数据重新采样。
  1. 使用Datasets的cast_column方法将采样率上采样到16kHz:
dataset = dataset.cast_column("audio", Audio(sampling_rate=16_000))
  1. 其次调用该audio列以重新采样音频文件:
    dataset[0][“audio”]

{ ‘数组’ : 数组([ 2.3443763e-05 , 2.1729663e-04 , 2.2145823e-04 , …,
3.8356509e-05 , - 7.3497440e-06 , - 2.1754686e-05 ], dtype=float32),
‘路径’:‘/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~JOINT_ACCOUNT/602ba55abb1e6d0fbce92065.wav’ ,
‘采样率’ : 16000 }

   接下来,加载特征提取器以规范化并填充输入。填充文本数据时,0会添加 a 以表示较短的序列。同样的想法也适用于音频数据。特征提取器将0- 解释为静音 - 添加到array。

   使用AutoFeatureExtractor.from_pretrained()加载特征提取器:

from transformers import AutoFeatureExtractor
feature_extractor = AutoFeatureExtractor.from_pretrained("facebook/wav2vec2-base")

   将音频传递array到特征提取器。我们还建议sampling_rate在特征提取器中添加参数,以便更好地调试可能发生的任何静默错误。

audio_input = [dataset[0]["audio"]["array"]]
feature_extractor(audio_input, sampling_rate=16000)

{ ‘input_values’ : [array([ 3.8106556e-04 , 2.7506407e-03 , 2.8015103e-03 , …,
5.6335266e-04 , 4.6588284e-06 , - 1.7142107e-04 ], dtype=float32) ] }

   就像分词器一样,您可以应用填充或截断来处理批量中的变量序列。看一下这两个音频样本的序列长度:

dataset[0]["audio"]["array"].shapedataset[1]["audio"]["array"].shape

   创建一个函数来预处理数据集,使音频样本具有相同的长度。指定最大样本长度,特征提取器将填充或截断序列以匹配它:

def preprocess_function(examples):audio_arrays = [x["array"] for x in examples["audio"]]inputs = feature_extractor(audio_arrays,sampling_rate=16000,padding=True,max_length=100000,truncation=True,)return inputs

   将 应用于preprocess_function数据集中的前几个示例:

processed_dataset = preprocess_function(dataset[:5])

   样本长度现在相同并且与指定的最大长度匹配。您现在可以将处理后的数据集传递给模型!

processed_dataset["input_values"][0].shape
processed_dataset["input_values"][1].shape

五、计算机视觉

   对于计算机视觉任务,您需要一个图像处理器来为模型准备数据集。图像预处理由几个步骤组成,将图像转换为模型期望的输入。这些步骤包括但不限于调整大小、标准化、颜色通道校正以及将图像转换为张量。

   图像预处理通常遵循某种形式的图像增强。图像预处理和图像增强都对图像数据进行变换,但它们的目的不同:
  图像增强以有助于防止过度拟合并提高模型稳健性的方式改变图像。您可以在增强数据的方式上发挥创意 - 调整亮度和颜色、裁剪、旋转、调整大小、缩放等。但是,请注意不要通过增强来改变图像的含义。
  图像预处理可确保图像与模型的预期输入格式匹配。在微调计算机视觉模型时,必须与模型最初训练时完全一样地对图像进行预处理。
  您可以使用任何您喜欢的库来进行图像增强。对于图像预处理,使用ImageProcessor与模型关联的。

   加载food101数据集(有关如何加载数据集的更多详细信息,请参阅 🤗数据集教程)以了解如何将图像处理器与计算机视觉数据集结合使用:

   使用 🤗 Datasetssplit参数仅从训练分割中加载小样本,因为数据集非常大!

from datasets import load_dataset
dataset = load_dataset("food101", split="train[:100]")

接下来,使用 🤗 数据集功能查看图像Image:

dataset[0]["image"]

在这里插入图片描述

使用AutoImageProcessor.from_pretrained()加载图像处理器:

from transformers import AutoImageProcessor
image_processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224")

   首先,让我们添加一些图像增强。您可以使用您喜欢的任何库,但在本教程中,我们将使用 torchvision 的transforms模块。如果您有兴趣使用其他数据增强库,请在Albumentations或Kornia 笔记本中了解如何操作。

   1. 在这里,我们使用Compose将几个变换链接在一起 -RandomResizedCrop和ColorJitter。请注意,对于调整大小,我们可以从image_processor. 对于某些模型,需要精确的高度和宽度,而对于其他模型,仅shortest_edge定义了高度和宽度。

from torchvision.transforms import RandomResizedCrop, ColorJitter, Composesize = (image_processor.size["shortest_edge"]if "shortest_edge" in image_processor.sizeelse (image_processor.size["height"], image_processor.size["width"])
)_transforms = Compose([RandomResizedCrop(size), ColorJitter(brightness=0.5, hue=0.5)])

   2. 该模型接受pixel_values 作为其输入。ImageProcessor可以负责标准化图像并生成适当的张量。创建一个函数,将一批图像的图像增强和图像预处理相结合并生成pixel_values:

def transforms(examples):images = [_transforms(img.convert("RGB")) for img in examples["image"]]examples["pixel_values"] = image_processor(images, do_resize=False, return_tensors="pt")["pixel_values"]return examples

   在上面的示例中,我们进行设置do_resize=False是因为我们已经在图像增强变换中调整了图像的大小,并利用了size适当的image_processor. 如果在图像增强期间不调整图像大小,请忽略此参数。默认情况下,ImageProcessor将处理调整大小。

   如果您希望将图像标准化作为增强变换的一部分,请使用image_processor.image_mean, 和image_processor.image_std值。

   3. 然后使用 🤗 数据集set_transform动态应用转换:

dataset.set_transform(transforms)

   4. 现在,当您访问图像时,您会注意到图像处理器已添加pixel_values. 您现在可以将处理后的数据集传递给模型!

dataset[0].keys()

   这是应用变换后图像的样子。该图像已被随机裁剪,并且其颜色属性有所不同。

import numpy as np
import matplotlib.pyplot as pltimg = dataset[0]["pixel_values"]
plt.imshow(img.permute(1, 2, 0))

在这里插入图片描述

   对于对象检测、语义分割、实例分割和全景分割等任务,ImageProcessor 提供后处理方法。这些方法将模型的原始输出转换为有意义的预测,例如边界框或分割图。

六、填充

   在某些情况下,例如,在微调DETR时,模型会在训练时应用尺度增强。这可能会导致一批图像的尺寸不同。您可以使用DetrImageProcessor.pad() DetrImageProcessor并定义一个自定义来将collate_fn图像一起批处理。

def collate_fn(batch):pixel_values = [item["pixel_values"] for item in batch]encoding = image_processor.pad(pixel_values, return_tensors="pt")labels = [item["labels"] for item in batch]batch = {}batch["pixel_values"] = encoding["pixel_values"]batch["pixel_mask"] = encoding["pixel_mask"]batch["labels"] = labelsreturn batch

七、Multimodal

   对于涉及多模式输入的任务,您需要一个处理器来为模型准备数据集。处理器将两个处理对象耦合在一起,例如分词器和特征提取器。

   加载LJ 语音数据集(有关如何加载数据集的更多详细信息,请参阅 🤗数据集教程)以了解如何使用处理器进行自动语音识别 (ASR):

from datasets import load_dataset
lj_speech = load_dataset("lj_speech", split="train")

   对于 ASR,您主要关注的是audio,text因此您可以删除其他列:

lj_speech = lj_speech.map(remove_columns=["file", "id", "normalized_text"])

   现在看一下audio和text列:

lj_speech[0]["audio"]

{ ‘数组’ : 数组([- 7.3242188e-04 , - 7.6293945e-04 , - 6.4086914e-04 , …,
7.3242188e-04 , 2.1362305e-04 , 6.1035156e-05 ], dtype=float32) ,
‘路径’:‘/root/.cache/huggingface/datasets/downloads/extracted/917ece08c95cf0c4115e45294e3cd0dee724a1165b7fc11798369308a465bd26/LJSpeech-1.1/wavs/LJ001-0001.wav’,
‘放大率’:22050 }

lj_speech[0]["text"]

   ‘印刷,就我们目前所关心的唯一意义而言,与展览中展示的大多数艺术和手工艺不同,甚至是所有艺术和手工艺’
请记住,您应该始终对音频数据集的采样率进行重新采样,以匹配用于预训练模型的数据集的采样率!

lj_speech = lj_speech.cast_column("audio", Audio(sampling_rate=16_000))

   使用AutoProcessor.from_pretrained()加载处理器:

from transformers import AutoProcessor
processor = AutoProcessor.from_pretrained("facebook/wav2vec2-base-960h")

   1. 创建一个函数来将数组中包含的音频数据处理为 input_values,并将文本标记为标签。这些是模型的输入:

def prepare_dataset(example):audio = example["audio"]example.update(processor(audio=audio["array"], text=example["text"], sampling_rate=16000))return example

   2. 将prepare_dataset函数应用于样本:

prepare_dataset(lj_speech[0])

   处理器现已添加input_values和labels,并且采样率也已正确下采样至 16kHz。您现在可以将处理后的数据集传递给模型!

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

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

相关文章

Leetcode第383场周赛

Leetcode第383场周赛 本人水平有限&#xff0c;只做前3道。 一、边界上的蚂蚁 边界上有一只蚂蚁&#xff0c;它有时向 左 走&#xff0c;有时向 右 走。 给你一个 非零 整数数组 nums 。蚂蚁会按顺序读取 nums 中的元素&#xff0c;从第一个元素开始直到结束。每一步&#…

C#中实现串口通讯(使用SerialPort类)

仅作自己学习使用 1 准备部份 需要两个调试软件commix和Virtual Serial Port Driver&#xff0c;分别用于监视串口和创造虚拟串口。 第一个软件是这样的&#xff1a; 资源在这里&#xff1a;免费下载&#xff1a;Commix 也可以前往官网下载&#xff1a;Bwsensing— Attitude…

CSS综合案例4

CSS综合案例4 1. 综合案例 我们来做一个静态的轮播图。 2. 分析思路 首先需要加载一张背景图进去需要4个小圆点&#xff0c;设置样式&#xff0c;并用定位和平移调整位置添加两个箭头&#xff0c;也是需要用定位和位移进行调整位置 3. 代码演示 html文件 <!DOCTYPE htm…

几个好用的 iphone 手机模板贴图样机

整理了几个好用的 iphone 手机模板贴图&#xff0c;分享一下。 关注订阅号「设计师工作日常」&#xff0c;发送关键词 iphone mockup ,获取下载链接。 [1] 原文阅读 我是 Just&#xff0c;这里是「设计师工作日常」&#xff0c;求点赞求关注&#xff01;

MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(1)-后端项目框架搭建

前言&#xff1a; 前面的四个章节我们主要讲解了MongoDB的相关基础知识&#xff0c;接下来我们就开始进入使用.NET7操作MongoDB开发一个ToDoList系统实战教程。本章节主要介绍的是如何快熟搭建一个简单明了的后端项目框架。 MongoDB从入门到实战的相关教程 MongoDB从入门到实战…

RBAC权限控制系统-手撸RBAC

手撸RBAC 一、概述 1、什么是RBAC RBAC&#xff08;Role-Based Access Control&#xff09;是一种访问控制机制&#xff0c;它基于角色的概念&#xff0c;将权限授予特定的角色&#xff0c;而不是直接授予个体用户。 这种模型允许管理员根据用户的角色来管理他们的权限&…

服务器出现问题该怎么办?

在我们日常使用服务器的过程中&#xff0c;经常会有遇到服务器出现各种各样问题&#xff0c;服务器出错的原因有很多种&#xff0c;常见的包括系统问题、软件问题、硬件问题和网络问题。今天德迅云安全就来介绍几种比较常见的情况。 一、 服务器出现蓝屏、死机可能的原因&#…

Arcgis使用过程中常见问题解决方法

Arcgis无法连接数据库/数据库连接或创建失败解决方法 最近在使用arcgis过程中出现无法连接数据库或者是无法创建数据库。连接到数据库失败&#xff1b;无法创建新的数据库&#xff0c;权限被拒绝&#xff08;如下图&#xff09;。 出现这个原因是你所用的电脑系统文件dao360.…

C++多线程学习[六]: 多线程之间的同步

一、同步问题 实际开发场景中有很多需要同步的情况&#xff0c;例如&#xff0c;音频和视频的同步输出、或者通讯能够第一时间同步接受处理… 二、多线程同步demo 可以看到cond可以阻塞等待&#xff08;wait&#xff09;可以通知一个线程(notify_one)也可以通知所有的线程&am…

Kubernetes实战(二十六)-K8S 部署Dashboard UI

Kubernetes Dashboard是Kubernetes集群的通用、基于Web的UI。它允许用户管理集群中运行的应用程序并对其进行故障排除&#xff0c;以及管理集群本身。 访问到DashBoard有两种方式&#xff1a; 通过KubernetesAPI访问&#xff1a;Dashboard是Kubernetes的内置的UI插件&#xff…

C#(C Sharp)学习笔记_If条件判断语句【五】

前言&#xff1a; 本期学习的是编程语言中的主要语句&#xff1a;if-条件判断语句。在这里我们会学到&#xff1a;if语法&#xff0c;if-else&#xff0c;和if嵌套。话不多说&#xff0c;我们开始吧&#xff01; 什么是条件判断语句&#xff1f; 条件语句是用来判断给定的条件…

好看的安全跳转单页html源码

好看的安全跳转单页html源码,效果如下 代码如下&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <!--[if IE 8]><style>.ie8 .alert-circle,.ie8 .alert-footer{display:none}.ie8 .alert-box{padding-top:…

游戏服务器多少钱一台?腾讯云32元,阿里云26元

游戏服务器租用多少钱一年&#xff1f;1个月游戏服务器费用多少&#xff1f;阿里云游戏服务器26元1个月、腾讯云游戏服务器32元&#xff0c;游戏服务器配置从4核16G、4核32G、8核32G、16核64G等配置可选&#xff0c;可以选择轻量应用服务器和云服务器&#xff0c;阿腾云atengyu…

开启一个服务,将服务器指定的文件读取,传播到网上其他终端

from flask import Flask, render_template_string app Flask(__name__)app.route(/get-data) def get_data():# 读取data.txt文件的内容with open(r./2024/2/4/data.txt, r) as file:data file.read()print(data)# 返回数据的HTML表示return render_template_string(<div…

使用x86架构+Nvidia消费显卡12G显存,搭建智能终端,将大模型本地化部署,说不定是未来方向,开源交互机器人设计

1&#xff0c;大模型本地部署 视频说明地址&#xff1a; https://www.bilibili.com/video/BV1BF4m1u769/ 【创新思考】&#xff08;1&#xff09;&#xff1a;使用x86架构Nvidia消费显卡12G显存&#xff0c;搭建智能终端&#xff0c;将大模型本地化部署&#xff0c;语音交互机…

02 动力云客之登陆界面

1. 前端登录界面 需求样式: 1. 自定义登录页面装配到main.js src下新建一个文件夹view, view下新建一个Vue Component , 名为LoginView.vue , 并选择options API Composition API用于复杂页面. 生成的LoginView.vue文件 <script> export default {//组件的名字nam…

Compose | UI组件(十四) | Navigation-Data - 页面导航传递数据

文章目录 前言传参流程实例说明普通方式传值定义接受参数格式定义接受参数类型获取参数传入参数传参和接受参数效果图 结合 ViewModel 传递参数定义ViewModel在 navigation 定义 ViewModel 实例&#xff0c;并且传入 LoginScreen传入输入框中的值&#xff0c;并且跳转传值获取值…

架设游戏服务器租用价格?腾讯云和阿里云价格对比

游戏服务器租用多少钱一年&#xff1f;1个月游戏服务器费用多少&#xff1f;阿里云游戏服务器26元1个月、腾讯云游戏服务器32元&#xff0c;游戏服务器配置从4核16G、4核32G、8核32G、16核64G等配置可选&#xff0c;可以选择轻量应用服务器和云服务器&#xff0c;阿腾云atengyu…

Docker Compose实例

目录 一、前提说明 二、简单的Docker容器部署案例 1. Dockerfile 配置 2. docker-compose.yml 配置 3. application.properties 配置 4. pom.xml 配置 5. 上传文件 6. 创建基础Docker镜像 7. docker-compose.yml编排 8. 停止并删除容器编排 一、前提说明 在配置好Do…

rediss集群 三主三从集群模式

三主三从集群模式 1)、新建redis集群目录&#xff1a;7001~7006工作目录【/app/soft/redis-cluster/目下】 2&#xff09;、在7001~7006 目录下创建bin和conf 目录&#xff0c;然后将/app/soft/redis/bin目录下的文件分别拷贝到7001~7006 目录&#xff0c;然后在7001~7006 目…