PyTorch深度学习CNN神经网络ResNet、DenseNet在CIFAR图像数据集分类应用与分析

全文链接:https://tecdat.cn/?p=38782

在当今深度学习领域,卷积神经网络(CNN)架构不断发展与创新,诸多先进的架构被提出并广泛应用。像GoogleNet(ILSVRC 2014获胜者)、ResNet(ILSVRC 2015获胜者)以及DenseNet(CVPR 2017最佳论文奖)等,它们在被提出时都处于当时的顶尖水平,且其核心思想也为如今众多先进架构奠定了基础。所以,深入理解这些架构并掌握如何实现它们是十分重要的点击文末“阅读原文”获取完整代码数据)。

基础库导入与环境设置
以下是关于路径和随机种子设置等相关代码:
# 数据集下载路径(例如CIFAR10数据集)
DATASET_PATH = "../data"
预训练模型与数据下载
import urllib.request
from urllib.error import HTTPError
# 如果检查点路径不存在则创建
os.makedirs(CHECKPOINT\_PATH, exist\_ok=True)
# 对每个文件,检查是否已存在,不存在则尝试下载
for file\_name in pretrained\_files:file\_path = os.path.join(CHECKPOINT\_PATH, file_name)if "/" in file_name:
CIFAR10数据集处理与分析
# 计算数据集的均值
DATA\_MEANS = (train\_dataset.data / 255.0).mean(axis=(0,1,2))
# 计算数据集的标准差
DATA_STD = (traint.data / 255.0).std(axis=(0,1,2))

利用上述计算得到的均值和标准差信息来对数据进行归一化处理,同时在训练过程中使用数据增强技术,以降低过拟合风险并提升模型的泛化能力。

为验证归一化是否有效,可输出单个批次数据的均值和标准差,理想情况下各通道均值接近0,标准差接近1。

c591d8914aec34e47d06c2953fb503ab.png

最后,可视化训练集中的部分图像以及经过随机数据增强后的样子

NUM_IMAGES = 4
images = \[train\_dataset\[idx\]\[0\] for idx in range(NUM\_IMAGES)\]plt.imshow(img_grid)
plt.axis('off')
plt.show()
plt.close()

26aa67e03869453abe771393d730a882.png


点击标题查阅往期内容

2995ad7f0b83e7b8c13a03904dc21b1a.jpeg

明星人脸识别基于VGG、MTCNN、RESNET深度学习卷积神经网络应用|附数据代码

outside_default.png

左右滑动查看更多

outside_default.png

01

3ffb5e2e25f157775a2c97823b7fb5bf.png

02

4810aa23ab1152670a84b432953d1f14.png

03

164416f39cb753f8f4d3ef7b26126b83.png

04

23e568c4da688217196a5bb8ba7342fe.png

PyTorch Lightning框架

PyTorch Lightning是一个能简化PyTorch中模型训练、评估和测试代码的框架,它还能自动将模型训练相关信息记录到TensorBoard中,并且用很少的代码就能自动保存模型检查点,方便我们将精力集中在实现不同模型架构上,减少代码编写的额外负担。
首先导入该库:

# 尝试导入PyTorch Lightning库
try:import pytorch_lightning as pl
except ModuleNotFoundError: # 如果Google Colab默认未安装,在此进行安装!pip install --quiet pytorch-lightning>=1.5import pytorch_lightning as pl

它自带了很多实用函数,比如设置种子的函数:

# 设置种子
pl.seed_everything(42)

在PyTorch Lightning中,通过定义pl.LightningModule(继承自torch.nn.Module)来将代码组织成5个主要部分:

  1. 初始化(__init__):创建所有必要的参数和模型。

  2. 优化器(configure_optimizers):创建优化器、学习率调度器等。

  3. 训练循环(training_step):只需定义单个批次的损失计算,优化器相关的梯度清零、反向传播和参数更新等操作以及日志记录、保存操作等都在后台自动完成。

  4. 验证循环(validation_step):与训练类似,只需定义每步要执行的操作。

  5. 测试循环(test_step):和验证类似,不过是针对测试集进行操作。
    以下是一个用于训练CNN的Lightning Module示例代码:

self.loss_module = nn.CrossEntropyLoss()# 用于在Tensorboard中可视化计算图的示例输入self.example\_input\_array = torch.zeros((1, 3, 32, 32), dtype=torch.float32)def forward(self, imgs):# 前向传播函数,在可视化计算图时运行return self.model(imgs)def configure_optimizers(self):# 支持Adam或SGD优化器if self.hparams.optimizer_name == "Adam":# AdamW是带有正确权重衰减实现的Adam(详见https://arxiv.org/pdf/1711.05101.pdf)optimizer = optim.AdamW(self.parameters(), **self.hparams.optimizer_hparams)elif self.hparams.optimizer_name == "SGD":optimizer = optim.SGD(self.parameters(), **self.hparams.optimizer_hparams)else:

最后,就可以聚焦于我们要实现的GoogleNet、ResNet和DenseNet等卷积神经网络了。

Inception与GoogleNet

在2014年被提出的GoogleNet凭借其Inception模块的应用赢得了ImageNet挑战赛。通常在本教程中,我们主要聚焦于Inception的概念,而非GoogleNet的具体细节,因为基于Inception诞生了众多后续工作(如Inception-v2、Inception-v3、Inception-v4、Inception-ResNet等),这些后续工作主要着重于提升效率以及构建更深的Inception网络。不过,若要从根本上理解,研究原始的Inception模块就足够了。
Inception模块会在同一个特征图上分别应用四个卷积块,分别是1x1、3x3、5x5的卷积以及一个最大池化操作。这样能让网络从不同感受野去审视相同的数据。理论上,仅学习5x5卷积可能功能会更强大,但这不仅计算量和内存占用更大,而且更容易出现过拟合现象。整体的Inception模块外观如下:
49ea40bd667ddcd1d5ad5b2ee318d2b1.png
在3x3和5x5卷积之前额外添加的1x1卷积用于降维。这一点尤为关键,因为后续所有分支的特征图会进行合并,我们不希望特征尺寸出现急剧膨胀。由于5x5卷积的计算量是1x1卷积的25倍,所以在大卷积之前进行降维能节省大量计算量和参数。

输入参数说明:c_in - 来自上一层的输入特征图数量c_red - 包含"3x3"和"5x5"键的字典,用于指定降维的1x1卷积输出c_out - 包含"1x1"、"3x3"、"5x5"和"max"键的字典act_fn - 激活函数类的构造器(例如nn.ReLU)"""super().\_\_init\_\_()# 1x1卷积分支self.conv_1x1 = nn.Sequential(nn.Conv2d(c\_in, c\_out\["1x1"\], kernel_size=1),nn.BatchNorm2d(c_out\["1x1"\]),act_fn())# 3x3卷积分支self.conv_3x3 = nn.Sequential(nn.Conv2d(c\_in, c\_red\["3x3"\], kernel_size=1),nn.BatchNorm2d(c_red\["3x3"\]),act_fn(),nn.Conv2d(c\_red\["3x3"\], c\_out\["3x3"\], kernel_size=3, padding=1),nn.BatchNorm2d(c_out\["3x3"\]),act_fn())# 5x5卷积分支self.conv_5x5 = nn.Sequential(nn.Conv2d(c\_in, c\_red\["5x5"\], kernel_size=1),nn.BatchNorm2d(c_red\["5x5"\]),act_fn(),

GoogleNet架构是由多个Inception模块堆叠而成,偶尔会使用最大池化来降低特征图的高度和宽度。原始的GoogleNet是为ImageNet图像尺寸(224x224像素)设计的,拥有近700万个参数。由于我们是在CIFAR10(图像尺寸为32x32)上进行训练,所以不需要如此复杂的架构,而是采用简化版本。降维和每个滤波器(1x1、3x3、5x5以及最大池化)的输出通道数量需要手动指定,如有兴趣也可进行更改。一般的思路是为3x3卷积设置最多的滤波器,因为它们功能足够强大,能考虑到上下文信息,同时所需参数仅约为5x5卷积的三分之一。

# 对原始图像进行初次卷积,以增加通道数量self.input_net = nn.Sequential(nn.Conv2d(3, 64, kernel_size=3, padding=1),nn.BatchNorm2d(64),self.hparams.act_fn())# 堆叠Inception模块self.inception_blocks = nn.Sequential(InceptionBlock(64, c\_red={"3x3": 32, "5x5": 16}, c\_out={"1x1": 16, "3x3": 32, "5x5": 8, "max": 8}, act\_fn=self.hparams.act\_fn),InceptionBlock(64, c\_red={"3x3": 32, "5x5": 16}, c\_out={"1x1": 24, "3x3": 48, "5x5": 12, "max": 12}, act\_fn=self.hparams.act\_fn),nn.MaxPool2d(3, stride=2, padding=1), # 32x32 => 16x16InceptionBlock(96, c\_red={"3x3": 32, "5x5": 16}, c\_out={"1x1": 24, "3x3": 48, "5x5": 12, "max": 12}, act\_fn=self.hparams.act\_fn),

现在,我们可以将模型整合到上面定义的模型字典中:

model_dict\["GoogleNet"\] = GoogleNet
Tensorboard日志

PyTorch Lightning的一个很棒的附加功能是能自动记录到TensorBoard中。为了让大家更好地了解TensorBoard的用途,我们可以查看在训练GoogleNet时PyTorch Lightning生成的面板。

18f5502ca7be1bbb9c15048b476e88ad.png
TensorBoard包含多个标签页。主标签页是标量标签页,我们可以在此记录单个数值的变化情况,例如训练损失、准确率、学习率等。如果查看训练或验证准确率,就能真切看到使用学习率调度器的影响。降低学习率能使模型的训练性能得到良好提升。同样,查看训练损失时,会发现此时损失会突然下降。不过,训练集上的数值高于验证集,这表明我们的模型存在过拟合现象,对于如此大型的网络来说,这是不可避免的。
TensorBoard中另一个有趣的标签页是图标签页,它展示了从输入到输出按模块构建的网络架构,基本呈现了CIFARModule前向传播步骤中的操作。双击模块可将其展开,大家可以从不同角度探索架构。图可视化通常有助于验证模型是否按预期运行,以及在计算图中是否遗漏了某些层。

ResNet

ResNet论文是被引用次数最多的人工智能论文之一,它为超过1000层的神经网络奠定了基础。尽管其原理简单,但残差连接的想法非常有效,因为它能支持网络中稳定的梯度传播。我们不是对 (x_{l+1}=F(x_{l})) 进行建模,而是对 (x_{l+1}=x_{l}+F(x_{l})) 建模,其中 (F) 是一个非线性映射(通常是一系列神经网络模块,如卷积、激活函数和归一化操作)。如果对此类残差连接进行反向传播,可得:
(\frac{\partial x_{l+1}}{\partial x_{l}} = \mathbf{I} + \frac{\partial F(x_{l})}{\partial x_{l}})
偏向于单位矩阵的特性保证了稳定的梯度传播,使其受 (F) 本身的影响更小。已经有许多ResNet的变体被提出,大多是关于函数 (F) 或者对求和结果所应用的操作。在本教程中,我们来看其中两种:原始的ResNet模块以及预激活ResNet模块。我们在下方直观对比这两种模块(图源 - He等人):
33145ed6a8b82aace4029f98d505f49e.png
原始的ResNet模块在跳跃连接之后应用非线性激活函数(通常是ReLU)。相反,预激活ResNet模块在 (F) 的开头就应用非线性操作。两者各有优劣。然而,对于非常深的网络,预激活ResNet表现更好,因为如上述计算所示,其梯度流能保证有单位矩阵的特性,并且不会受到应用于其上的非线性激活的影响。为了进行对比,我们将这两种ResNet类型都实现为较浅的网络。
先来看原始的ResNet模块。上面的示意图已经展示了 (F) 中包含哪些层。我们需要处理的一种特殊情况是,当想要降低图像的宽和高维度时,基本的ResNet模块要求 (F(x_{l})) 与 (x_{l}) 形状相同,所以在与 (F(x_{l})) 相加之前,也需要改变 (x_{l}) 的维度。原始实现使用步长为2的恒等映射,并将额外的特征维度用0填充。不过,更常用的实现是使用步长为2的1x1卷积,因为它能在改变特征维度的同时,在参数和计算成本方面更高效。ResNet模块的代码相对简单,如下所示:

"""输入参数说明:c_in - 输入特征数量act_fn - 激活函数类的构造器(例如nn.ReLU)subsample - 如果为True,我们要在模块内应用步长,将输出形状在高度和宽度上缩小2倍c\_out - 输出特征数量。注意,只有当subsample为True时,此参数才有意义,否则c\_out = c_in"""super().\_\_init\_\_()if not subsample:c\_out = c\_in# 代表F的网络self.net = nn.Sequential(nn.Conv2d(c\_in, c\_out, kernel_size=3, padding=1, stride=1 if not subsample else 2, bias=False), # 不需要偏置,因为批归一化会处理它nn.BatchNorm2d(c_out),act_fn(),

接下来实现预激活ResNet模块。为此,我们需要改变self.net中的层顺序,并且不在输出上应用激活函数。此外,下采样操作也需要应用非线性,因为输入 (x_l) 尚未经过非线性处理。

与模型选择类似,我们定义一个字典来创建从字符串到模块类的映射。我们将在模型中把字符串名称作为超参数值,用于在不同的ResNet模块之间进行选择。大家也可以自行实现其他类型的ResNet模块并添加进来。

整体的ResNet架构是由多个ResNet模块堆叠而成,其中一些模块会对输入进行下采样。当在整个网络中讨论ResNet模块时,我们通常按照相同的输出形状对它们进行分组。因此,如果说ResNet有[3,3,3]个模块,意思是我们有三组,每组包含3个ResNet模块,并且在第四和第七个模块处进行下采样。在CIFAR10上具有[3,3,3]个模块的ResNet可视化如下:
f70e98cc83a88077f3cee5070788d1de.png
这三组分别作用于分辨率为 (32×32)、(16×16) 和 (8×8) 的情况。

"""输入参数说明:num_classes - 分类输出的数量(CIFAR10为10)num_blocks - 包含ResNet模块数量的列表,每组的第一个模块(除了第一组的第一个)使用下采样c_hidden - 不同模块中的隐藏维度列表,通常随着深度增加而翻倍act\_fn\_name - 要使用的激活函数名称,从"act\_fn\_by_name"中查找block\_name - ResNet模块的名称,从"resnet\_blocks\_by\_name"中查找"""super().\_\_init\_\_()assert block\_name in resnet\_blocks\_by\_nameself.hparams = SimpleNamespace(num\_classes=num\_classes,c\_hidden=c\_hidden,num\_blocks=num\_blocks,act\_fn\_name=act\_fn\_name,act\_fn=act\_fn\_by\_name\[act\_fn\_name\],block\_class=resnet\_blocks\_by\_name\[block_name\])self.\_create\_network()self.\_init\_params()def \_create\_network(self):c\_hidden = self.hparams.c\_hidden# 对原始图像进行初次卷积,以增加通道数量if self.hparams.block_class == PreActResNetBlock: # => 不在输出上应用非线性self.input_net = nn.Sequential(nn.Conv2d(3, c\_hidden\[0\], kernel\_size=3, padding=1, bias=False))

最后,我们可以训练ResNet模型。与GoogleNet训练的一个不同之处在于,我们明确使用带动量的SGD作为优化器,而非Adam。在普通的浅层ResNets上,Adam往往会导致准确率稍差一些。目前还不完全清楚为什么Adam在这种情况下表现更差,一种可能的解释与ResNet的损失曲面有关。已有研究表明,ResNet比没有跳跃连接的网络能产生更平滑的损失曲面。有无跳跃连接的损失曲面的一种可能可视化如下:
2cadae76f47cea807a49763ab3baaedb.png
(x)轴和(y)轴展示了参数空间的投影,(z)轴展示了不同参数值所取得的损失值。在像右侧这样的平滑曲面上,我们可能不需要像Adam提供的那种自适应学习率。相反,Adam可能会陷入局部最优,而SGD能找到更宽泛的最小值,往往泛化能力更好。

下面我们使用SGD来训练模型:

resnet\_model, resnet\_results = train\_model(model\_name="ResNet",model\_hparams={"num\_classes": 10,"c_hidden": \[16,32,64\],"num_blocks": \[3,3,3\],"act\_fn\_name": "relu"},optimizer_name="SGD",optimizer_hparams={"lr": 0.1,"momentum": 0.9,"weight_decay": 1e-4})

Tensorboard日志

与GoogleNet模型类似,我们也有ResNet模型的TensorBoard日志。我们可以在下面打开它:

db4ecfb5f8313f0718758c1ae7171636.png
大家可以自行探索TensorBoard,包括计算图等内容。总体而言,我们可以看到,在训练的初期阶段,使用SGD的ResNet的训练损失比GoogleNet更高。不过在降低学习率之后,该模型能取得更高的验证准确率。我们会在笔记末尾对比具体的分数。

DenseNet网络架构分析

在深度学习领域,深度神经网络的架构不断演进,DenseNet 便是其中一种能够支持构建非常深层神经网络的架构。它对于残差连接有着独特的视角,与传统方式有所不同。传统做法往往聚焦于对各层之间差异进行建模,而 DenseNet 则将残差连接视为一种跨层复用特征的有效途径,如此一来,便无需再去学习那些冗余的特征图了。

当网络不断加深时,模型会学习抽象特征以识别各类模式。然而,一些复杂的模式其实是由抽象特征(比如手、脸等)以及低级特征(比如边缘、基础颜色等)共同组合而成的。在深层网络中,标准的卷积神经网络(CNN)若要找到这些低级特征,就不得不去重复学习这类特征图,这会造成大量参数资源的浪费。而 DenseNet 提供了一种高效的特征复用方式,它让每一次卷积操作都依赖于之前所有的输入特征,并且仅添加少量的滤波器,以此来避免上述的资源浪费情况,其原理可参考下图

1237e2ffe2b7cfe090dfa58228f30e85.png

在 DenseNet 中,最后一层被称作过渡层(TransitionLayer),它承担着降低特征图在高度、宽度以及通道尺寸方面维度的任务。尽管从技术层面来讲,这会在一定程度上打破恒等反向传播,但由于网络中此类过渡层数量较少,所以对整体的梯度流影响并不大。

DenseNet相关模块与整体架构

DenseLayer模块

在神经网络架构中,DenseLayer模块有着重要作用,以下是其具体的代码实现及相关解释。

class DenseLayer(nn.Module):def \_\_init\_\_(self, c\_in, bn\_size, growth\_rate, act\_fn):"""输入参数说明:c_in - 输入通道数量bn_size - 1x1卷积输出的瓶颈尺寸(增长率因子),通常取值在2到4之间。growth_rate - 3x3卷积的输出通道数量act_fn - 激活函数类的构造器(例如nn.ReLU)"""super().\_\_init\_\_()self.net = nn.Sequential(nn.BatchNorm2d(c_in),act_fn(),nn.Conv2d(c\_in, bn\_size * growth\_rate, kernel\_size=1, bias=False),nn.BatchNorm2d(bn\_size * growth\_rate),act_fn(),nn.Conv2d(bn\_size * growth\_rate, growth\_rate, kernel\_size=3, padding=1, bias=False))def forward(self, x):out = self.net(x)out = torch.cat(\[out, x\], dim=1)return out

这个DenseLayer模块的作用是,先对输入数据进行一系列的归一化、激活以及卷积操作,然后将处理后的结果与原始输入在通道维度上进行拼接,最后输出拼接后的结果。

DenseBlock模块

DenseBlock模块用于汇总按顺序应用的多个密集层:

在这个模块中,通过循环创建多个DenseLayer,并将它们按顺序组合起来,每个DenseLayer的输入通道数量会随着层数的增加而动态变化,它是原始输入通道加上前面各层生成的特征图数量,最终输出经过这些密集层处理后的结果。

TransitionLayer模块

TransitionLayer模块主要用于对输入(通常是一个密集块的最终输出)进行通道维度的降维处理:

该模块先对输入进行归一化和激活操作,接着通过1x1卷积来减少通道数量,然后采用核大小为2、步长为2的平均池化操作来降低高度和宽度维度,这样做相比ResNet中使用的一些方式更具参数效率,最后输出处理后的结果。

DenseNet整体架构

有了上述的基础模块,我们可以构建完整的DenseNet架构了:

DenseNet的构建过程中,首先确定了隐藏通道的初始数量,然后通过对原始图像进行初次卷积得到初始特征。接着,按照设定的层数列表循环创建密集块,并根据情况添加过渡层来逐步调整特征维度。最后,通过一系列操作将处理后的特征映射到分类输出,整个网络结构就这样搭建完成了。

模型训练与TensorBoard日志

与其他模型不同,在训练DenseNet时,它使用Adam优化器并不会出现像ResNet那样的问题,所以采用Adam来进行训练。这里选择的其他超参数使得构建出的网络在参数规模上与ResNet和GoogleNet相近。通常在设计非常深的网络时,DenseNet在参数利用效率方面比ResNet更有优势,而且能取得相近甚至更好的性能。

densenet\_model, densenet\_results = train\_model(model\_name="DenseNet",model\_hparams={"num\_classes": 10,"num_layers": \[6,6,6,6\],"bn_size": 2,"growth_rate": 16,"act\_fn\_name": "relu"},optimizer_name="Adam",optimizer_hparams={"lr": 1e-3,"weight_decay": 1e-4})

训练完成后,我们同样可以查看DenseNet训练的TensorBoard日志:

b275540621fc9492083135723c5fb011.png
从验证准确率和训练损失的整体变化过程来看,它与GoogleNet的训练情况比较相似,这也和使用Adam进行网络训练有关,大家可以自行去探索训练指标情况。

结论与对比

在分别讨论了各个模型,并对它们都进行训练之后,我们终于可以对它们进行对比了。首先,我们将所有模型的结果整理到一个表格中:

9f998a008ab06cc78d4cba6f3920fe50.png

首先,我们可以看到所有模型的表现都还算不错。大家自行实现的简单模型在实际应用中性能会低很多,这除了参数数量较少之外,也和架构设计的选择有关。GoogleNet在验证集和测试集上的性能是最低的,尽管它和DenseNet的差距比较小。如果对GoogleNet中所有通道尺寸进行合适的超参数搜索,可能会将模型的准确率提升到相近水平,但鉴于超参数数量众多,这样做的成本也比较高。ResNet在验证集上的性能比DenseNet和GoogleNet高出1%以上,而原始版本和预激活版本之间的差异较小。由此我们可以得出结论,对于浅层网络来说,激活函数的位置似乎并不是关键因素,尽管在一些论文中提到对于非常深的网络情况并非如此(例如He等人的相关研究)。

总体而言,我们可以认为ResNet是一种简单但功能强大的架构。如果将这些模型应用到更复杂的任务中,比如处理更大的图像以及网络内部层数更多的情况,我们可能会看到GoogleNet与像ResNet和DenseNet这样具有跳跃连接的架构之间出现更大的性能差距。在CIFAR10上与更深层模型的对比可参考此处。有趣的是,DenseNet在相关设置中性能优于原始的ResNet,但稍逊于预激活ResNet。而最佳模型,即双路径网络(Chen等人),实际上是ResNet和DenseNet的结合,这表明二者各有优势。

daa9817906f6eebe36d8ea0722e196ec.jpeg

本文中分析的数据、代码分享到会员群,扫描下面二维码即可加群! 

ccc37cced63284624672180072e1b26e.png


资料获取

在公众号后台回复“领资料”,可免费获取数据分析、机器学习、深度学习等学习资料。

50d11e030fdd2858c486005831003df4.jpeg

点击文末“阅读原文”

获取全文完整代码数据资料。

本文选自《PyTorch深度学习CNN神经网络ResNet、DenseNet在CIFAR图像数据集分类应用与分析》。

点击标题查阅往期内容

Python遗传算法GA对长短期记忆LSTM深度学习模型超参数调优分析司机数据|附数据代码

Python深度学习GRU、LSTM 、BiLSTM-CNN神经网络空气质量指数AQI时间序列预测及机器学习分析|数据分享

Python、R用深度学习神经网络组合预测优化能源消费总量时间序列预测及ARIMA、xgboost对比

R语言深度学习卷积神经网络 (CNN)对 CIFAR 图像进行分类:训练与结果评估可视化

R语言KERAS深度学习CNN卷积神经网络分类识别手写数字图像数据(MNIST)

R语言KERAS深度学习CNN卷积神经网络分类识别手写数字图像数据(MNIST)

Python深度强化学习对冲策略:衍生品投资组合套期保值Black-Scholes、Heston模型分析

MATLAB深度学习Transformer神经网络量化金融时间序列预测交易策略回测

【视频讲解】Python深度神经网络DNNs-K-Means(K-均值)聚类方法在MNIST等数据可视化对比分析

MATLAB用CNN-LSTM神经网络的语音情感分类深度学习研究

308ec7bc8f2095dee8d28f8b1adb5b4f.jpeg

91f95487824ce4e0d513ac92e9508039.png

d66b6641517648fc42975df93416e49f.png

9c8b966df9845b22e8ec417e76d6ec4c.jpeg

81147b18c91b9e9de3a5fe2a9af4233c.png

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

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

相关文章

word论文排版常见问题汇总

word论文排版常见问题汇总 常用快捷键: Alt F9 正常模式与域代码模式切换 Ctrl F9 插入域代码 F9 刷新域代码显示,要注意选定后刷新才会有效果 word中在当前列表的基础上修改列表 在使用word时,我们会定义一个列表,并将其链接…

【Rust】数据类型

目录 思维导图 1. 数据类型概述 1.1 标量类型 1.1.1 整数类型 1.1.2 浮点数类型 1.1.3 布尔类型 1.1.4 字符类型 1.2 复合类型 1.2.1 元组类型 1.2.2 数组类型 2. 类型注解与类型推断 3. 整数溢出处理 4. 数字运算 5. 示例 思维导图 1. 数据类型概述 Rust是一种静…

Proteus-8086调试汇编格式的一点心得

这阵子开始做汇编的微机实验(微机原理与接口技术题解及实验指导,吴宁版本13章),中间出了挺多问题,解决后记录下。 先上电路图 用子电路来仿真发现仿真的时候子电路这块根本没有高低电平输出,只好把子电路拿…

跨界融合:人工智能与区块链如何重新定义数据安全?

引言:数据安全的挑战与现状 在信息化驱动的数字化时代,数据已成为企业和个人最重要的资产之一。然而,随着网络技术的逐步优化和数据量的爆发式增长,数据安全问题也愈变突出。 数据安全现状:– 数据泄露驱动相关事件驱…

机器人碳钢去毛刺,用大扭去毛刺主轴可轻松去除

在碳钢精密加工的最后阶段,去除毛刺是确保产品质量的关键步骤。面对碳钢这种硬度较高的材料,采用大扭矩的SycoTec去毛刺主轴,成为了行业内的高效解决方案。SycoTec作为精密加工领域的领军品牌,其生产的高速电主轴以其卓越的性能&a…

大疆上云API连接遥控器和无人机

文章目录 1、部署大疆上云API关于如何连接我们自己部署的上云API2、开启无人机和遥控器并连接自己部署的上云API如果遥控器和无人机没有对频的情况下即只有遥控器没有无人机的情况下如果遥控器和无人机已经对频好了的情况下 4、订阅无人机或遥控器的主题信息4.1、订阅无人机实时…

[OPEN SQL] 限定选择行数

本次操作使用的数据库表为SCUSTOM&#xff0c;其字段内容如下所示 航班用户(SCUSTOM) 该数据库表中的部分值如下所示 指定查询多少行数据&#xff0c;我们可以使用语法UP TO n ROWS来实现对数据前n项的查询 语法格式 SELECT * FROM <dbtab> UP TO n ROWS 参数说明 db…

机器视觉3-线性分类器

机器视觉3-线性分类器 前言一、整体流程二、其他相关内容 图像的表示图像类型黑白图像灰度图像彩色图像 图像表示为向量一、基本概念二、表示方法三、优点四、局限性五、应用场景 线性分类器一、神经网络的层级结构形成非线性模型二、支撑向量机的高维映射形成非线性模型 线性分…

解决“无法定位程序输入点 av_buffer_create 于动态链接库 XXX\Obsidian.exe 上”问题

解决“无法定位程序输入点 av_buffer_create 于动态链接库 XXX\Obsidian.exe 上”问题 问题描述 本人在使用zotero中的zotero one&#xff08;青柠学术插件&#xff09;的时候&#xff0c;使用插件跳转obsidian中的对应笔记&#xff0c;出现上图情况。&#xff08;错误中提到的…

【数据结构高阶】B-树

目录 一、常见的搜索结构 二、B树 2.1 B树的概念 2.2 B树插入数据的分析 2.3 B树的性能分析 2.4 模拟实现B树 2.4.1 B树节点的定义 2.4.2 B树数据的查找 2.4.3 B树节点的数据插入 2.4.4 B树的遍历 2.4.5 模拟实现B树实现的完整代码 三、B树 3.1 B树的概念 3.2 B树…

《CPython Internals》阅读笔记:p97-p117

《CPython Internals》学习第 7 天&#xff0c;p97-p117 总结&#xff0c;总计 21 页。 一、技术总结 1.词法分析(lexical analysis) 根据《Compilers-Principles, Techniques, and Tools》(《编译原理》第2版)第 5 页&#xff1a;The first phase of a compiler is called …

2.两数相加--力扣

给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数都不会以 0 …

口碑很好的国产LDO芯片,有哪些?

在几乎任何一个电路设计中&#xff0c;都可能会使用LDO&#xff08;低压差线性稳压器&#xff09;这个器件。 虽然LDO不是什么高性能的IC&#xff0c;但LDO芯片市场竞争异常激烈。最近几年&#xff0c;诞生了越来越多的精品国产LDO&#xff0c;让人看得眼花缭乱。 业内人士曾经…

搜索引擎的设计与实现【源码+文档+部署讲解】

目 录 目 录 1 绪论 1.1 项目背景 1.2 国内外发展现状及分类 1.3 本论文组织结构介绍 2 相关技术介绍 2.1什么是搜索引擎 2.2 sqlserver数据库 2.3 Tomcat服务器 3 搜索引擎的基本原理 3.1搜索引擎的基本组成及其功能 3.2搜索引擎的详细工作流程 4 系统分析与…

计算机系统组成(计算机组成原理 基础)

文章目录&#xff1a; 一&#xff1a;体系结构 1.系统组成 1.1 硬件系统 1.2 软件系统 2.工作原理 2.1 冯诺依曼体系 2.2 指令和指令系统 3.性能指标 二&#xff1a;硬件系统 1.主机 1.1 CPU 1.2 内存 2.外设 2.1 外存 2.2 输入设备 2.3 输出设备 2.4 适配器 …

一些计算机零碎知识随写(25年1月)-1

我原以为世界上有技术的那批人不会那么闲&#xff0c;我错了&#xff0c;被脚本真实了。 今天正隔着画画呢&#xff0c;手机突然弹出几条安全告警通知。 急忙打开服务器&#xff0c;发现问题不简单&#xff0c;直接关服务器重装系统..... 首先&#xff0c;不要认为小网站&…

Go Ebiten小游戏开发:贪吃蛇

贪吃蛇是一款经典的小游戏&#xff0c;玩法简单却充满乐趣。本文将介绍如何使用 Go 语言和 Ebiten 游戏引擎开发一个简单的贪吃蛇游戏。通过这个项目&#xff0c;你可以学习到游戏开发的基本流程、Ebiten 的使用方法以及如何用 Go 实现游戏逻辑。 项目简介 贪吃蛇的核心玩法是…

FCPX插件:100组二维卡通动漫流体线条MG动画元素包 MotionVfx – mzap

mZap 是一款由 motionVFX 公司出品的 Final Cut Pro X 模板&#xff0c;提供 100 种卡通动漫流体 MG 动画元素和标题效果。这套模板专为视频制作者设计&#xff0c;添加流畅且生动的动画效果&#xff0c;提升视频的创意表现力。 丰富预设&#xff1a;提供 100 种卡通动漫流体 M…

linux下实现U盘和sd卡的自动挂载

linux下实现U盘和sd卡的自动挂载 Chapter0 linux下实现U盘和sd卡的自动挂载 Chapter0 linux下实现U盘和sd卡的自动挂载 原文链接&#xff1a;https://blog.csdn.net/EmSoftEn/article/details/45099699 目的&#xff1a;使U盘和SD卡在Linux系统中进行插入和拔除时能自动挂载和…

Taro+react 开发第一节创建 带有redux状态管理的项目

Taro 项目基于 node&#xff0c;请确保已具备较新的 node 环境&#xff08;>16.20.0&#xff09;&#xff0c;推荐使用 node 版本管理工具 nvm 来管理 node&#xff0c;这样不仅可以很方便地切换 node 版本&#xff0c;而且全局安装时候也不用加 sudo 了。 1.安装 npm inf…