神经网络的正则化(一)

目录

  • 摘要
  • Abstract
  • 1. 引言
  • 2. 参数范数惩罚
  • 3. 显式约束和重投影
    • 3.1 显式约束
    • 3.2 重投影
  • 4. 数据集增强
  • 5. 多任务学习
  • 6. 提前终止
  • 7. 参数绑定和共享
  • 8. 稀疏表示
  • 9. Bagging和其他集成方法
  • 10. 对抗训练
  • 参考
  • 总结

摘要

  本周,我学习了神经网络中的正则化方法。

Abstract

  This week, I studied regularization methods in neural networks.

1. 引言

  前面介绍了机器学习中的正则化,在机器学习正则化的基础上介绍深度学习的正则化。
  在探究正则化之前,需要说明的是在神经网络中参数包括每一层仿射变换的权重和偏置,通常只对权重正则化而不对偏置正则化。不对偏置进行正则化也不会导致太大的方差,相反正则化偏置可能导致欠拟合。
  在神经网络中希望对网络的每一层使用单独的惩罚,并分配不同的正则化系数。但是如果这样做的话,寻找多个合适超参数的代价很大,为了减少搜索空间,尽量在所有层使用相同的权重衰减。

2. 参数范数惩罚

  参数范数惩罚是一种通过在代价函数中增加额外项来限制模型复杂度的方法,从而防止过拟合。它通过对模型参数进行约束,鼓励模型在学习过程中保持简单,避免过多的自由度。常见的参数范数惩罚方法包括L1范数惩罚和L2范数惩罚。
  。L2正则化(也称为权重衰减)通过对权重矩阵的平方和进行惩罚,迫使权重变得尽可能小,从而避免模型的参数过大,避免过拟合。神经网络的所有参数为 θ \theta θ,损失函数为 L ( θ ) L(\theta) L(θ),所有层的权重为 W W W L 2 L^2 L2正则化后的损失函数为
J ( θ ) = L ( θ ) + λ ∥ W ∥ 2 2 . \Large J(\theta)=L(\theta)+\lambda\|W\|_2^2. J(θ)=L(θ)+λW22.
  L1正则化通过对参数的绝对值进行惩罚,鼓励模型的某些权重变为零,从而实现稀疏性。稀疏表示有助于特征选择,因为只有少数特征会对最终的预测产生重要影响。 L 1 L^1 L1正则化后的损失函数为
J ( θ ) = L ( θ ) + λ ∥ W ∥ 1 . \Large J(\theta)=L(\theta)+\lambda\|W\|_1. J(θ)=L(θ)+λW1.
  PyTorch中优化器实现了 L 2 L^2 L2正则化,只需要设置优化器的weight_decay参数即可,这个参数是正则化系数; L 1 L^1 L1正则化需要手动实现。

from torch import optimoptimizer = optim.SGD(lr=1e-2, momentum=0.9, weight_decay=0.5)

3. 显式约束和重投影

3.1 显式约束

  显式约束和重投影是一种对模型参数施加限制的方法,用于控制模型的训练过程和参数空间,以满足特定的条件或约束。这些技术主要用于提高模型的稳定性、泛化能力,或者让模型满足某些特定的结构化需求。
  带有参数范数约束 Ω \Omega Ω的损失函数为
J ( θ ) = L ( θ ) + λ ( Ω ( θ ) − k ) . \Large J(\theta)=L(\theta)+\lambda(\Omega(\theta)-k). J(θ)=L(θ)+λ(Ω(θ)k).
  显式约束可以确保模型的参数满足预定的结构或范围,有助于提高模型的解释性和稳定性。但是直接施加显式约束可能会影响模型的优化过程,尤其是在梯度下降时,强制性的约束可能会导致训练效率下降。这一问题可以重投影技术解决。

3.2 重投影

  2. 重投影(Reprojection)
重投影是一种优化方法,用于在训练过程中将不满足约束条件的模型参数投影回满足约束的可行域中。这种方法通常与显式约束结合使用,用于确保训练过程中参数始终满足约束条件。
  工作机制:假设在训练过程中,某些权重 W W W在更新后不满足给定的约束条件 C C C。此时,重投影步骤会将 W W W投影回满足 C C C的空间中: W ← P r o j C ( W ) W\leftarrow Proj_C(W) WProjC(W),其中 P r o j C Proj_C ProjC是投影操作,将 W W W调整到最近的满足 C C C的点。
  重投影方法确保了模型参数始终在可行域内,从而满足显式约束的要求,有助于提高模型的稳定性。但是重投影操作可能增加计算开销,尤其是在高维参数空间或复杂约束下,计算投影可能比较耗时。

4. 数据集增强

  让模型泛化得更好的最好方法是是使用更多的数据进行训练。在实践中,可获取的数据是有限的,解决这一问题的一种方法是创建假数据并添加到训练集中。
  对于分类任务来说这种方法最容易实现。分类器需要一个复杂的高维输入 x x x,并用单个类别标识 y y y概括 x x x,这意味着分类需要对各种各样的变换保持不变,因此可以通过转换训练集中的 x x x来生成新的 ( x , y ) (x, y) (x,y)对。对于图片分类任务来说,可以通过旋转图片等操作来增强数据集,但是如果增强操作会改变图片的类别,就不能使用这种增强操作。
  此外,数据集增强在语音识别任务也是有效的。这里不详细介绍各种领域都有哪些数据增强操作。

5. 多任务学习

  多任务学习是通过在一个模型中同时训练多个任务,以提高模型的泛化能力。与传统的单任务学习不同,多任务学习 将多个相关的任务联合学习,利用不同任务之间的共享信息和特征,从而提高每个任务的表现。
  特点:
  1. 共享表示:在多任务学习中,所有任务共享模型的某些参数(通常是网络的前几层),这样可以让模型在不同任务之间共享有用的信息。通过共享低层次特征,模型能够学到更加通用的表示。
  2. 同时训练多个任务:多个任务的损失函数被合并,模型在训练过程中同时优化这些任务的目标函数。通常,这些任务会有不同的权重来平衡每个任务的贡献。
  3. 提高泛化能力:通过学习多个相关任务,模型有可能避免过拟合,因为它被迫学会共享不同任务的知识,而不仅仅是针对某个任务优化。

6. 提前终止

  当训练有足够的表示能力甚至会过拟合的模型时,可以观察到训练误差随着时间的推移逐渐降低但验证集的误差会再次上升。这意味着只要返回使验证集误差最低的参数设置,就可以获得验证集误差最低的模型,使模型具备最好的泛化能力。这种策略就是提前终止,是深度学习中最常用的正则化形式。
  提前终止算法的过程:
p 为 p a t i e n c e , 观察到较坏的验证集表现 p 次后终止。 θ 0 为模型的初始参数。 θ = θ 0 i = 0 ( 训练轮数 ) j = 0 ( 坏验证集表现出现的次数 ) v = ∞ ( 评估的验证集表现 ) θ ∗ = θ ( 使验证集表现更好的参数 ) i ∗ = i ( 使验证集表现更好的步数 ) w h i l e j < p d o 训练算法在训练集上训练一遍 , 更新 θ 。 i = i + 1 v ′ = V a l i d a t i o n S e t E r r o r ( θ ) i f v ′ < v t h e n j = 0 θ ∗ = θ i ∗ = i v = v ′ e l s e j = j + 1 e n d i f e n d w h i l e 最佳参数为 θ ∗ , 最佳训练步数 ( 轮数 ) 为 i ∗ 。 \begin{aligned} &p为patience,观察到较坏的验证集表现p次后终止。\\ &\theta_0为模型的初始参数。\\ &\theta=\theta_0\\ &i=0(训练轮数)\\ &j=0(坏验证集表现出现的次数)\\ &v=\infty(评估的验证集表现)\\ &\theta^*=\theta(使验证集表现更好的参数)\\ &i^*=i(使验证集表现更好的步数)\\ &while \quad j \lt p \quad do\\ &\quad 训练算法在训练集上训练一遍,更新\theta。\\ &\quad i=i+1\\ &\quad v'=ValidationSetError(\theta)\\ &\quad if \quad v' \lt v \quad then\\ &\quad\quad j=0\\ &\quad\quad \theta^*=\theta\\ &\quad\quad i^*=i\\ &\quad\quad v=v'\\ &\quad else\\ &\quad\quad j=j+1\\ &\quad end\quad if\\ &end \quad while 最佳参数为\theta^*,最佳训练步数(轮数)为i^*。 \end{aligned} ppatience,观察到较坏的验证集表现p次后终止。θ0为模型的初始参数。θ=θ0i=0(训练轮数)j=0(坏验证集表现出现的次数)v=(评估的验证集表现)θ=θ(使验证集表现更好的参数)i=i(使验证集表现更好的步数)whilej<pdo训练算法在训练集上训练一遍,更新θi=i+1v=ValidationSetError(θ)ifv<vthenj=0θ=θi=iv=velsej=j+1endifendwhile最佳参数为θ,最佳训练步数(轮数)i
  提前终止需要验证集,这意味着某些训练数据不能被送到模型中。为了更好地利用这些额外的数据,可以在完成提前终止的某次训练后进行额外的训练。在第二轮中,所有的训练数据都被包括在内。
  额外训练有二种方式:1. 再次初始化模型,然后使用所有数据训练,训练步数为第一轮提前终止确定的最佳步数。2. 保存从第一轮训练获得的最佳参数,然后使用全部数据继续训练,直到在第一轮的验证集上的平均损失函数值低于第一轮提前终止时的值。
  下面给出模型训练过程中如何使用提前终止的例子(需要使用ignite)。

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from torchvision.models import resnet18
from torchvision.transforms.v2 import Compose, Normalize, ToImage, ToDtype
from ignite.engine import Engine, Events, create_supervised_trainer, create_supervised_evaluator
from ignite.metrics import Accuracy, Loss
from ignite.handlers import ModelCheckpoint, EarlyStopping
from ignite.contrib.handlers import TensorboardLogger, global_step_from_enginedevice = torch.device("cuda" if torch.cuda.is_available() else "cpu")class Net(nn.Module):def __init__(self):super(Net, self).__init__()self.model = resnet18(num_classes=10)self.model.conv1 = self.model.conv1 = nn.Conv2d(1, 64, kernel_size=3, padding=1, bias=False)def forward(self, x):return self.model(x)model = Net().to(device)data_transform = Compose([ToImage(),ToDtype(torch.float32, scale=True),Normalize((0.1307,), (0.3081,))
])
train_loader = DataLoader(MNIST(download=True, root=".", transform=data_transform, train=True), batch_size=128, shuffle=True
)
val_loader = DataLoader(MNIST(download=True, root=".", transform=data_transform, train=False), batch_size=256, shuffle=False
)optimizer = torch.optim.RMSprop(model.parameters(), lr=0.005)
criterion = nn.CrossEntropyLoss()
trainer = create_supervised_trainer(model, optimizer, criterion, device)
val_metrics = {"accuracy": Accuracy(),"loss": Loss(criterion)
}
train_evaluator = create_supervised_evaluator(model, metrics=val_metrics, device=device)
val_evaluator = create_supervised_evaluator(model, metrics=val_metrics, device=device)log_interval = 100@trainer.on(Events.ITERATION_COMPLETED(every=log_interval))
def log_training_loss(engine):print(f"Epoch[{engine.state.epoch}], Iter[{engine.state.iteration}] Loss: {engine.state.output:.2f}")@trainer.on(Events.EPOCH_COMPLETED)
def log_training_results(trainer):train_evaluator.run(train_loader)metrics = train_evaluator.state.metricsprint(f"Training Results - Epoch[{trainer.state.epoch}] Avg accuracy: {metrics['accuracy']:.2f} Avg loss: {metrics['loss']:.2f}")@trainer.on(Events.EPOCH_COMPLETED)
def log_validation_results(trainer):val_evaluator.run(val_loader)metrics = val_evaluator.state.metricsprint(f"Validation Results - Epoch[{trainer.state.epoch}] Avg accuracy: {metrics['accuracy']:.2f} Avg loss: {metrics['loss']:.2f}")def score_function(engine):return -engine.state.metrics["loss"]model_checkpoint = ModelCheckpoint("checkpoint",n_saved=1,filename_prefix="best",score_function=score_function, #默认是越大越好,因此需要添加负号score_name="val_loss",global_step_transform=global_step_from_engine(trainer),
)early_stopping = EarlyStopping(patience=5, score_function=score_function, trainer=trainer) #默认是越大越好
val_evaluator.add_event_handler(Events.COMPLETED, early_stopping)
val_evaluator.add_event_handler(Events.COMPLETED, model_checkpoint, {"model": model})trainer.run(train_loader, max_epochs=50)

7. 参数绑定和共享

  在神经网络中,参数绑定和共享可以帮助减少模型的复杂性、降低计算和存储成本,同时增加模型的泛化能力,防止过拟合。它们在不同的神经网络架构中被广泛使用,尤其是在卷积神经网络和递归神经网络中。
  在卷积神经网络中,所有卷积核在整个输入图像上共享相同的参数。在这种情况下,卷积层的参数在所有位置上都是相同的,这就是参数共享的一种形式。卷积操作通过滑动卷积核并对输入的不同区域应用相同的权重,来学习特征。

8. 稀疏表示

  在深度学习中,稀疏表示(Sparse Representation) 是一种将数据表示为在某个基下大部分系数为零或接近零的形式。简单来说,稀疏表示希望找到一种方式,使用少量的非零系数来近似或表示输入数据,尤其在高维数据处理(如图像、语音、文本等)中,这种表示方式能够显著减少数据的复杂性和冗余。
  稀疏表示的优势
  1. 降低计算复杂度:由于大多数系数为零,稀疏表示可以显著减少计算量,特别是在大规模数据处理时。
  2. 提高模型的解释性:稀疏表示有助于突出输入数据中最重要的特征,使模型的行为更具可解释性。
  3. 防止过拟合:通过减少冗余的参数和特征,稀疏表示有助于提高模型的泛化能力,避免过拟合。

9. Bagging和其他集成方法

  Bagging是通过结合几个模型降低泛化误差的技术,主要想法是分别训练几个不同的模型,然后让所有模型表决测试样例的输出。
  Bagging的过程:1. 从训练集 D D D中有放回抽样,生成 k k k个子集 D 1 D_1 D1 D 2 D_2 D2 ⋯ \cdots D k D_k Dk。2. 在每个训练子集 D i D_i Di上训练一个模型 h i h_i hi。3. 对于新样本,Bagging 将
k k k个模型的结果通过投票或平均进行融合,得到最终预测结果。
  还有其他集成方法如Boosting也可用于神经网络。
  下面给出使用Bagging进行预测的例子。

import torch
import numpy as np
from torch import nn, optim
from torch.utils.data import DataLoader, SubsetRandomSampler
from torchvision.datasets import MNIST
from torchvision.transforms.v2 import Compose, ToImage, ToDtype, Normalize
from ignite.engine import Events, create_supervised_trainer, create_supervised_evaluator
from ignite.metrics import Accuracy, Losstransform = Compose([ToImage(),ToDtype(torch.float32, scale=True),Normalize((0,5,), (0.5,))
])train_dataset = MNIST(root="data", train=True, download=True, transform=transform)
test_dataset = MNIST(root="data", train=False, download=True, transform=transform)class SimpleCNN(nn.Module):def __init__(self):super().__init__()self.conv1 = nn.Conv2d(2, 32, kernel_size=3, padding=1)self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)self.pool = nn.MaxPool2d(2, 2)self.fc1 = nn.Linear(64 * 7 * 7, 128)self.fc2 = nn.Linear(128, 10)def forward(self, x):x = self.pool(torch.relu(self.conv1(x)))x = self.pool(torch.relu(self.conv2(x)))x = x.view(-1, 64 * 7 * 7)  # Flatten layerx = torch.relu(self.fc1(x))x = self.fc2(x)return xdevice = "cuda"class BaggingModel:def __init__(self, model, num, batch_size, learning_rate, epochs):super().__init__()self.model = modelself.num = numself.batch_size = batch_sizeself.lr = learning_rateself.epochs = epochsself.models = nn.ModuleList()def train(self, train_dataset, valid_dataset):for i in range(self.num):model = self.model().to(device)criterion = nn.CrossEntropyLoss()optimizer = optim.Adam(model.parameters(), self.lr)indices = torch.randperm(len(train_dataset))subset_sampler = SubsetRandomSampler(indices[: len(train_dataset) // 2])train_loader = DataLoader(train_dataset, batch_size=self.batch_size, sampler=subset_sampler)valid_loader = DataLoader(valid_dataset, batch_size=self.batch_size, shuffle=False)trainer = create_supervised_trainer(model, optimizer, criterion, device)val_metrics = {"accuracy": Accuracy(), "loss": Loss(criterion)}train_evaluator = create_supervised_evaluator(model, metrics=val_metrics, device=device)val_evaluator = create_supervised_evaluator(model, metrics=val_metrics, device=device)log_interval = 100@trainer.on(Events.ITERATION_COMPLETED(every=log_interval))def log_training_loss(engine):print(f"Model[{i+1}], Epoch[{engine.state.epoch}], Iter[{engine.state.iteration}] Loss: {engine.state.output:.2f}")@trainer.on(Events.EPOCH_COMPLETED)def log_training_results(trainer):train_evaluator.run(train_loader)metrics = train_evaluator.state.metricsprint(f"Training Results of Model[{i+1}] - Epoch[{trainer.state.epoch}] Avg accuracy: {metrics['accuracy']:.2f} Avg loss: {metrics['loss']:.2f}")@trainer.on(Events.EPOCH_COMPLETED)def log_validation_results(trainer):val_evaluator.run(valid_loader)metrics = val_evaluator.state.metricsprint(f"Validation Results of Model[{i+1}] - Epoch[{trainer.state.epoch}] Avg accuracy: {metrics['accuracy']:.2f} Avg loss: {metrics['loss']:.2f}")trainer.run(train_loader, self.epochs)self.models.append(model)def predict(self, test_dataset):all_preds = []all_labels = []test_loader = DataLoader(test_dataset, batch_size=self.batch_size, shuffle=False)for X, y in test_loader:X, y = X.to(device), y.to(device)all_labels.append(y.cpu().numpy())pred = torch.zeros(X.shape[0], 10).to(device)for model in self.models:model.eval()with torch.no_grad():pred += nn.Softmax(dim=1)(model(X))pred /= self.numall_preds.append(torch.argmax(pred, dim=1).cpu().numpy())return np.concatenate(all_preds), np.concatenate(all_labels)def evaluate(self, test_dataset):y_pred, y_true = self.predict(test_dataset)accuracy = np.sum(y_pred == y_true) / len(y_pred)return accuracybagging_model = BaggingModel(SimpleCNN, 5, 64, 1e-2, 5)
bagging_model.train(train_dataset, test_dataset)
accuracy = bagging_model.evaluate(test_dataset)
print(f"Bagging模型的准确率: {accuracy:.4f}")

10. 对抗训练

  对抗训练是一种通过引入对抗样本来增强模型泛化能力的方法。对抗样本是通过对原始数据进行微小扰动(通常通过梯度下降等方法)而生成的,这些扰动足够小,以至于对人类来说仍然难以察觉,但却足以让机器学习模型产生错误预测。
  对抗训练的核心思想是在训练过程中,除了使用正常的数据样本,还要使用这些对抗样本来“挑战”模型。通过在训练集中加入对抗样本,模型不仅学习正常数据的特征,还学习如何应对由对抗样本引起的扰动,从而提升其对潜在攻击或不确定输入的鲁棒性。
  训练过程:
  1. 生成对抗样本:使用某种方法(如快速梯度符号法 FGSM、迭代法等)生成对抗样本。
  2. 结合对抗样本与正常样本进行训练:将这些对抗样本与原始样本一起输入到模型中,并计算总损失函数,优化模型的参数。

参考

[美]伊恩·古德费洛(lan Goodfellow)[加]约书亚·本吉奥(Yoshua Bengio)[加]亚伦·库维尔(Aaron Courville) 深度学习(中文翻译版)
PyTorch-Ignite Getting Started

总结

  本周,我学习了一部分神经网络中的正则化方法。
  下周,我将学习Dropout,BatchNormalization,LayerNormalization。

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

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

相关文章

普通用户切换到 root 用户不需要输入密码配置(Ubuntu20)

在 Ubuntu 系统中&#xff0c;允许一个普通用户切换到 root 用户而不需要输入密码&#xff0c;可以通过以下步骤配置 sudo 设置来实现。 步骤&#xff1a; 打开 sudoers 文件进行编辑&#xff1a; 在终端中&#xff0c;输入以下命令来编辑 sudoers 文件&#xff1a; sudo visu…

MySQL系统优化

文章目录 MySQL系统优化第一章&#xff1a;引言第二章&#xff1a;MySQL服务架构优化1. 读写分离2. 水平分区与垂直分区3. 缓存策略 第三章&#xff1a;MySQL配置优化1. 内存分配优化Buffer Pool 的优化查询缓存与表缓存Key Buffer 2. 连接优化最大连接数会话超时连接池 3. 日志…

菲涅耳全息图

菲涅耳全息图&#xff1a;记录介质在物光波场的菲涅耳衍射区(物体到记录介质表面的距离在菲涅耳衍射区内)。 一、点源全息图的记录和再现 1.1 记录 设物光波和参考光波是从点源O(xo, yo, zo)和点源 R(xr, yr, zr)发出的球面波, 波长为λ1, 全息底片位于z0 的平面上, 与两个点源…

多线程-阻塞队列

目录 阻塞队列 消息队列 阻塞队列用于生产者消费者模型 概念 实现原理 生产者消费者主要优势 缺陷 阻塞队列的实现 1.写一个普通队列 2.加上线程安全和阻塞等待 3.解决代码中的问题 阻塞队列 阻塞队列&#xff0c;是带有线程安全功能的队列&#xff0c;拥有队列先进…

css样式:flex布局

文章目录 简介简单使用直接使用一行放不下的换行水平方向上对齐方式竖直方向上对齐方式布局中排列顺序放大比例缩小比例单个元素与其他元素不同的对齐 文章目录 简介简单使用直接使用一行放不下的换行水平方向上对齐方式竖直方向上对齐方式布局中排列顺序放大比例缩小比例单个元…

MySQL LOAD DATA INFILE导入数据报错

1.导入命令 LOAD DATA INFILE "merge.csv" INTO TABLE 报名数据 FIELDS TERMINATED BY , ENCLOSED BY " LINES TERMINATED BY \n IGNORE 1 LINES; 2.表结构 CREATE TABLE IF NOT EXISTS 报名数据 ( pid VARCHAR(100) NOT NULL, 查询日期 VARCHAR(25) NO…

详解模版类pair

目录 一、pair简介 二、 pair的创建 三、pair的赋值 四、pair的排序 &#xff08;1&#xff09;用sort默认排序 &#xff08;2&#xff09;用sort中的自定义排序进行排序 五、pair的交换操作 一、pair简介 pair是一个模版类&#xff0c;可以存储两个值的键值对.first以…

C#从入门到放弃

C#和.NET的区别 C# C#是一个编程语言 .NET .NET是一个在window下创建程序的框架 .NET框架不仅局限于C#,它还可以支持很多语言 .NET包括了2个组件&#xff0c;一个叫CLR(通用语言运行时)&#xff0c;另一个是用来构建程序的类库 CLR 用C写一个程序&#xff0c;在一台8688的机器…

算法复杂度详解

目录 算法定义 复杂度概念 时间复杂度 大O的渐近表示法 空间复杂度 常见复杂度对比 算法定义 算法(Algorithm):就是定义良好的计算过程&#xff0c;他取一个或一组的值为输入&#xff0c;并产生出一个或一组值作为 输出。简单来说算法就是一系列的计算步骤&#xff0c;用来…

AI写作(十)发展趋势与展望(10/10)

一、AI 写作的崛起之势 在当今科技飞速发展的时代&#xff0c;AI 写作如同一颗耀眼的新星&#xff0c;迅速崛起并在多个领域展现出强大的力量。 随着人工智能技术的不断进步&#xff0c;AI 写作在内容创作领域发挥着越来越重要的作用。据统计&#xff0c;目前已有众多企业开始…

电子应用设计方案-12:智能窗帘系统方案设计

一、系统概述 本设计方案旨在打造便捷、高效的全自动智能窗帘系统。 二、硬件选择 1. 电机&#xff1a;选用低噪音、扭矩合适的智能电机&#xff0c;根据窗帘尺寸和重量确定电机功率&#xff0c;确保能平稳拉动窗帘。 2. 轨道&#xff1a;选择坚固、顺滑的铝合金轨道&…

数据结构《栈和队列》

文章目录 一、什么是栈&#xff1f;1.1 栈的模拟实现1.2 关于栈的例题 二、什么是队列&#xff1f;2.2 队列的模拟实现2.2 关于队列的例题 总结 提示&#xff1a;关于栈和队列的实现其实很简单&#xff0c;基本上是对之前的顺序表和链表的一种应用&#xff0c;代码部分也不难。…

从0-1训练自己的数据集实现火焰检测

随着工业、建筑、交通等领域的快速发展,火灾作为一种常见的灾难性事件,对生命财产安全造成了严重威胁。为了提高火灾的预警能力,减少火灾损失,火焰检测技术应运而生,成为火灾监控和预防的有效手段之一。 传统的火灾检测方法,如烟雾探测器、温度传感器等,存在响应时间慢…

WSL--无需安装虚拟机和docker可以直接在Windows操作系统上使用Linux操作系统

安装WSL命令 管理员打开PowerShell或Windows命令提示符&#xff0c;输入wsl --install&#xff0c;然后回车 注意&#xff1a;此命令将启用运行 WSL 和安装 Linux 的 Ubuntu 发行版所需的功能。 注意&#xff1a;默认安装最新的Ubuntu发行版。 注意&#xff1a;默认安装路径是…

云原生-docker安装与基础操作

一、云原生 Docker 介绍 Docker 在云原生中的优势 二、docker的安装 三、docker的基础命令 1. docker pull&#xff08;拉取镜像&#xff09; 2. docker images&#xff08;查看本地镜像&#xff09; 3. docker run&#xff08;创建并启动容器&#xff09; 4. docker ps…

@Autowired 和 @Resource思考(注入redisTemplate时发现一些奇怪的现象)

1. 前置知识 Configuration public class RedisConfig {Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template new RedisTemplate<>();template.setConnectionFactory(facto…

HarmonyOS ArkUI(基于ArkTS) 常用组件

一 Button 按钮 Button是按钮组件&#xff0c;通常用于响应用户的点击操作,可以加子组件 Button(我是button)Button(){Text(我是button)}type 按钮类型 Button有三种可选类型&#xff0c;分别为胶囊类型&#xff08;Capsule&#xff09;、圆形按钮&#xff08;Circle&#xf…

Jenkins + gitee 自动触发项目拉取部署(Webhook配置)

目录 前言 Generic Webhook Trigger 插件 下载插件 ​编辑 配置WebHook 生成tocken 总结 前言 前文简单介绍了Jenkins环境搭建&#xff0c;本文主要来介绍一下如何使用 WebHook 触发自动拉取构建项目&#xff1b; Generic Webhook Trigger 插件 实现代码推送后&#xff0c;触…

【插件】重复执行 pytest-repeat

安装 pip3 install pytest-repeat 用法 1.命令行 pytest --count num pytest --count 32.装饰器 pytest.mark.repeat(num) #num运行次数 pytest.mark.repeat(5)#执行结果如下&#xff1a;

软件测试 —— 自动化基础

目录 前言 一、Web 自动化测试 1.什么是 Web 自动化测试 2.驱动 3.安装驱动管理 二、Selenium 1.简单 web 自动化测试示例 2.工作原理 三、元素定位 1.cssSelector 2.XPath 四、操作测试对象 1.点击/提交对象 2.模拟按键输入 3.清除文本内容 4.获取文本信息 5.…