神经网络-Inception

Inception网络是由Google开发的一种深度卷积神经网络架构,旨在解决计算机视觉领域中的图像分类和物体识别任务。

Inception网络最初在2014年被提出,并在ImageNet图像分类挑战赛上取得了很好的结果。其设计灵感来自于模块化的思想,将不同尺度和不同层级的滤波器并行应用于输入,然后将它们的输出在通道维度上拼接在一起,形成了一个多分支的结构。这种并行使用不同卷积核尺寸的方式可以捕捉到不同尺度的图像特征,提高了网络对输入图像的理解能力。

Inception网络的演变版本包括Inception-V2、Inception-V3、Inception-V4和Inception-ResNet等。这些版本在原始Inception网络的基础上进行了改进,提升了性能和效果。

Inception网络在计算机视觉领域广泛应用,被用于图像分类、目标检测、图像生成等任务。它的设计思想和结构对深度学习模型的发展和优化有着重要的影响和贡献。

Inception介绍

Inception模块是Inception架构的核心组件,它由多个并行的分支组成。每个分支都使用不同大小的卷积核进行卷积操作,例如1×1、3×3和5×5的卷积核。这样做的目的是让网络能够同时学习到局部和全局的特征,并且能够适应不同尺度的目标。此外,为了减少参数数量和计算复杂度,每个分支都会在输入前使用1×1的卷积核进行降维处理。

除了卷积层之外,Inception模块还包括池化层。池化层可以帮助减小特征图的空间尺寸,从而提高计算效率和减少过拟合的风险。作者建议在每个阶段中添加一个替代的并行池化路径,使得模型能够更好地捕捉空间信息。

整个Inception网络由多个堆叠的Inception模块构成,模块之间通过卷积层进行连接。最后的全局平均池化层将特征图转换为向量表示,并通过全连接层进行分类或回归等任务。

随着网络的深入,模型需要更多的感受野来理解更复杂的图像特征。较小的卷积核(如1×1和3×3)能够捕捉局部特征,而较大的卷积核(如5×5)则能够捕捉更广阔的上下文信息。因此,在高层次的特征表示中,作者提出使用更多的3×3和5×5卷积核来覆盖更大范围的特征,并适应数据中更高层次的抽象特征。这样做有助于提高网络对不同尺度和抽象级别的特征的表示能力。

下图是一个Inception结构拆解示意:

上图左侧是最原始的Inception结构,包含了1*1、3*3、5*5以及max pooling,使用多个5×5的卷积核可以捕捉到更广泛的特征,但是这会导致计算成本增加。特别是当在具有大量滤波器的卷积层上使用较多的5×5卷积时,计算量更加昂贵。

而且,一旦添加了池化单元,它们的输出滤波器数量与前一层的滤波器数量相等,这就意味着从卷积层到池化层的输出数量会增加。而当将池化层的输出与卷积层的输出合并时,会导致每个阶段之间输出数量的不可避免增加。

这种架构虽然可能能够覆盖最佳的稀疏结构,但是效率非常低下。随着网络的深入,输出数量会逐渐增加,从而导致计算量的剧增。这会对网络的计算性能和效率造成困扰,因为需要处理大量的输出数据

如何保证模型效果的同时,降低计算量?

为了降低计算量,我们引入了1×1卷积操作。1×1卷积是一种特殊的卷积操作,它使用只有一个像素大小的卷积核。与传统的卷积核相比,它的尺寸非常小。通过应用1×1卷积,我们可以将输入信号从高维空间投影到低维空间,即减少信号的维度。这样做可以减少计算量,因为在低维空间中进行卷积计算要比在高维空间中更快速。

在Inception方法中,1×1卷积操作被放置在耗时的3×3和5×5卷积操作之前。通过降低信号的维度,我们可以减少需要进行的计算量。此外,为了增强模型的表达能力,我们在降维卷积后引入修正线性激活函数。这个激活函数可以让模型更好地学习特征,在处理图像时取得更好的效果。(也就是上图的b)

总结起来,我们的方法利用1×1卷积操作将信号从高维空间投影到低维空间,以降低计算量。同时,我们引入修正线性激活函数增强模型表达能力。这样的设计策略可以提高计算效率,并在处理复杂图像任务时获得更好的结果。

总结

在Inception网络中,核心组件是称为Inception模块的构建块。一个Inception模块由多个并行的子路径组成,每个子路径具有不同大小的卷积核和不同的滤波器数量。这样可以让网络同时学习到不同尺度和层次的特征。例如,一个子路径可能使用小的卷积核来捕捉细节特征,而另一个子路径可能使用大的卷积核来捕捉整体结构。

为了提高计算效率,Inception模块还会使用降维操作,即先使用较少的滤波器数量进行卷积,然后再使用更多的滤波器进行卷积。这样可以减少网络的参数数量和计算量,同时保持较好的表达能力。

此外,Inception网络还会通过插入步长为2的最大池化层来减小输入数据的尺寸,从而进一步降低计算复杂度。最大池化层可以将输入数据划分为不重叠的区域,并从每个区域中选择最大值作为输出。这样可以降低数据的维度,同时保留重要的特征信息。

总体来说,Inception网络通过模块化的设计、不同尺度特征的并行处理和降维操作来提高图像处理任务的性能和效率。它能够从图像中学习到更丰富的特征表示,并在保持计算效率的同时提高准确性。

GoogLeNet

在GoogLeNet中,利用Inception结构进行了设计,下面我们将具体介绍,如何应用Inception:

在GooLeNet中,网络结构大致可以分为6个部分,其中第一部分、第二部分、第六部分是我们常见的卷积层等方法使用,第3~5,均是采用了上述介绍的Inception结构,每个部分中采用的数量不同,比如第三部分采用了2个Inception结构;第四部分采用了5个Inception结构;第五部分采用了2个Inception结构。

下图是GooLeNet整体的网络结构,下面我们将针对每部分进行介绍。

  • 第一部分、第二部分

    • 第一部分构成:conv 7*7 -》max pool 3*3 -》LRN

    • 第二部分构成:conv 1*1 -》 conv 3*3 -》 LRN -》 max pool 3*3

具体参数计算如下:

均属于常规网络设计。

  • 第三部分

    • 第三部分构成:Inception(3a)->Inception(3b)->max pool

  • 第四部分

    • 第四部分构成:Inception(4a)->Inception(4b)->Inception(4c)->Inception(4d)->Inception(4e)->MaxPool

其中在Inception(4b) 和Inception(4e) 又接了两个辅助分类器

  • 第五部分

    • 第五部分构成:Inception(5a)->Inception(5b)-average pool

  • 第六部分

    • 第六部分构成:FC->softmax

代码示例

根据上文介绍,Inception结构如下所示,根据下图我们进行网络定义。

 
import torch
import torch.nn as nn# 定义 Inception 模块
class Inception(nn.Module):def __init__(self, in_channels, ch1x1, ch3x3red, ch3x3, ch5x5red, ch5x5, pool_proj):super(Inception, self).__init__()# 1x1 卷积分支self.branch1 = nn.Sequential(nn.Conv2d(in_channels, ch1x1, kernel_size=1),nn.ReLU(inplace=True))# 1x1 卷积后接 3x3 卷积分支self.branch2 = nn.Sequential(nn.Conv2d(in_channels, ch3x3red, kernel_size=1),nn.ReLU(inplace=True),nn.Conv2d(ch3x3red, ch3x3, kernel_size=3, padding=1),nn.ReLU(inplace=True))# 1x1 卷积后接 5x5 卷积分支self.branch3 = nn.Sequential(nn.Conv2d(in_channels, ch5x5red, kernel_size=1),nn.ReLU(inplace=True),nn.Conv2d(ch5x5red, ch5x5, kernel_size=5, padding=2),nn.ReLU(inplace=True))# 3x3 最大池化后接 1x1 卷积分支self.branch4 = nn.Sequential(nn.MaxPool2d(kernel_size=3, stride=1, padding=1),nn.Conv2d(in_channels, pool_proj, kernel_size=1),nn.ReLU(inplace=True))def forward(self, x):branch1 = self.branch1(x)branch2 = self.branch2(x)branch3 = self.branch3(x)branch4 = self.branch4(x)outputs = [branch1, branch2, branch3, branch4]return torch.cat(outputs, 1)

  • 定义GoogleNet网络

# 定义 GoogleNet
class GoogleNet(nn.Module):def __init__(self, num_classes=1000):super(GoogleNet, self).__init__()# 第一个卷积和池化层self.conv1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),  # 输入通道数为3,输出通道数为64,卷积核大小为7x7,步长为2,填充为3nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2, padding=1)  # 池化层,使用最大池化,池化核大小为3x3,步长为2,填充为1)# 第二个卷积和池化层self.conv2 = nn.Sequential(nn.Conv2d(64, 64, kernel_size=1),  # 输入通道数为64,输出通道数为64,卷积核大小为1x1,不改变特征图的大小nn.ReLU(inplace=True),nn.Conv2d(64, 192, kernel_size=3, padding=1),  # 输入通道数为64,输出通道数为192,卷积核大小为3x3,填充为1nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2, padding=1)  # 池化层,使用最大池化,池化核大小为3x3,步长为2,填充为1)# Inception 模块self.inception3a = Inception(192, 64, 96, 128, 16, 32, 32)self.inception3b = Inception(256, 128, 128, 192, 32, 96, 64)self.inception4a = Inception(480, 192, 96, 208, 16, 48, 64)self.inception4b = Inception(512, 160, 112, 224, 24, 64, 64)self.inception4c = Inception(512, 128, 128, 256, 24, 64, 64)self.inception4d = Inception(512, 112, 144, 288, 32, 64, 64)self.inception4e = Inception(528, 256, 160, 320, 32, 128, 128)self.inception5a = Inception(832, 256, 160, 320, 32, 128, 128)self.inception5b = Inception(832, 384, 192, 384, 48, 128, 128)# 最后的全局平均池化、dropout、全连接层self.avgpool = nn.AdaptiveAvgPool2d((1, 1))  # 全局平均池化层,将特征图大小池化为1x1self.dropout = nn.Dropout(0.4)  # Dropout层,防止过拟合,丢弃概率为0.4self.fc = nn.Linear(1024, num_classes)  # 全连接层,输入大小为1024,输出大小为类别数def forward(self, x):x = self.conv1(x)  # 第一个卷积和池化层x = self.conv2(x)  # 第二个卷积和池化层x = self.inception3a(x)  # Inception 模块x = self.inception3b(x)  # Inception 模块x = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)(x)  # 池化层,使用最大池化,池化核大小为3x3,步长为2,填充为1x = self.inception4a(x)  # Inception 模块x = self.inception4b(x)  # Inception 模块x = self.inception4c(x)  # Inception 模块x = self.inception4d(x)  # Inception 模块x = self.inception4e(x)  # Inception 模块x = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)(x)  # 池化层,使用最大池化,池化核大小为3x3,步长为2,填充为1x = self.inception5a(x)  # Inception 模块x = self.inception5b(x)  # Inception 模块x = self.avgpool(x)  # 全局平均池化层x = torch.flatten(x, 1)  # 平铺特征图x = self.dropout(x)  # Dropout层x = self.fc(x)  # 全连接层return x

最终model输出如下:

GoogleNet((conv1): Sequential((0): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3))(1): ReLU(inplace=True)(2): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False))(conv2): Sequential((0): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(64, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace=True)(4): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False))(inception3a): Inception((branch1): Sequential((0): Conv2d(192, 64, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True))(branch2): Sequential((0): Conv2d(192, 96, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(96, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace=True))(branch3): Sequential((0): Conv2d(192, 16, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(16, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))(3): ReLU(inplace=True))(branch4): Sequential((0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)(1): Conv2d(192, 32, kernel_size=(1, 1), stride=(1, 1))(2): ReLU(inplace=True)))(inception3b): Inception((branch1): Sequential((0): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True))(branch2): Sequential((0): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(128, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace=True))(branch3): Sequential((0): Conv2d(256, 32, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(32, 96, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))(3): ReLU(inplace=True))(branch4): Sequential((0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)(1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1))(2): ReLU(inplace=True)))(inception4a): Inception((branch1): Sequential((0): Conv2d(480, 192, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True))(branch2): Sequential((0): Conv2d(480, 96, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(96, 208, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace=True))(branch3): Sequential((0): Conv2d(480, 16, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(16, 48, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))(3): ReLU(inplace=True))(branch4): Sequential((0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)(1): Conv2d(480, 64, kernel_size=(1, 1), stride=(1, 1))(2): ReLU(inplace=True)))(inception4b): Inception((branch1): Sequential((0): Conv2d(512, 160, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True))(branch2): Sequential((0): Conv2d(512, 112, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(112, 224, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace=True))(branch3): Sequential((0): Conv2d(512, 24, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(24, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))(3): ReLU(inplace=True))(branch4): Sequential((0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)(1): Conv2d(512, 64, kernel_size=(1, 1), stride=(1, 1))(2): ReLU(inplace=True)))(inception4c): Inception((branch1): Sequential((0): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True))(branch2): Sequential((0): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace=True))(branch3): Sequential((0): Conv2d(512, 24, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(24, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))(3): ReLU(inplace=True))(branch4): Sequential((0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)(1): Conv2d(512, 64, kernel_size=(1, 1), stride=(1, 1))(2): ReLU(inplace=True)))(inception4d): Inception((branch1): Sequential((0): Conv2d(512, 112, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True))(branch2): Sequential((0): Conv2d(512, 144, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(144, 288, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace=True))(branch3): Sequential((0): Conv2d(512, 32, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))(3): ReLU(inplace=True))(branch4): Sequential((0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)(1): Conv2d(512, 64, kernel_size=(1, 1), stride=(1, 1))(2): ReLU(inplace=True)))(inception4e): Inception((branch1): Sequential((0): Conv2d(528, 256, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True))(branch2): Sequential((0): Conv2d(528, 160, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(160, 320, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace=True))(branch3): Sequential((0): Conv2d(528, 32, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(32, 128, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))(3): ReLU(inplace=True))(branch4): Sequential((0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)(1): Conv2d(528, 128, kernel_size=(1, 1), stride=(1, 1))(2): ReLU(inplace=True)))(inception5a): Inception((branch1): Sequential((0): Conv2d(832, 256, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True))(branch2): Sequential((0): Conv2d(832, 160, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(160, 320, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace=True))(branch3): Sequential((0): Conv2d(832, 32, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(32, 128, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))(3): ReLU(inplace=True))(branch4): Sequential((0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)(1): Conv2d(832, 128, kernel_size=(1, 1), stride=(1, 1))(2): ReLU(inplace=True)))(inception5b): Inception((branch1): Sequential((0): Conv2d(832, 384, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True))(branch2): Sequential((0): Conv2d(832, 192, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace=True))(branch3): Sequential((0): Conv2d(832, 48, kernel_size=(1, 1), stride=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(48, 128, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))(3): ReLU(inplace=True))(branch4): Sequential((0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)(1): Conv2d(832, 128, kernel_size=(1, 1), stride=(1, 1))(2): ReLU(inplace=True)))(avgpool): AdaptiveAvgPool2d(output_size=(1, 1))(dropout): Dropout(p=0.4, inplace=False)(fc): Linear(in_features=1024, out_features=1000, bias=True)
)

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

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

相关文章

PyTorch Instance Normalization介绍

Instance Normalization(实例归一化) 是一种标准化技术,与 Batch Normalization 类似,但它对每个样本独立地对每个通道进行归一化,而不依赖于小批量数据的统计信息。这使得它非常适合小批量训练任务以及图像生成任务(如风格迁移)。 Instance Normalization 的原理 对每…

国内独立开发者案例及免费送独立开发蓝图书

独立开发者在国内越来越受到关注,他们追求的是一种自由且自给自足的工作状态。 送这个: 少楠light(Flomo、小报童、如果相机):他们是独立开发者的典范,不仅开发了多款产品,还坚信“剩者为王”…

【小程序】自定义组件的data、methods、properties

目录 自定义组件 - 数据、方法和属性 1. data 数据 2. methods 方法 3. properties 属性 4. data 和 properties 的区别 5. 使用 setData 修改 properties 的值 自定义组件 - 数据、方法和属性 1. data 数据 在小程序组件中,用于组件模板渲染的私有数据&…

MATLAB用find函数结合all,any函数高效解决问题

如本节中最后提到的问题,我们输出后还需要判断,不是特别的一目了然,这时候我们可以再加上 f i n d find find函数直接标记序号并输出。首先我们先来了解 f i n d find find的用法, f i n d ( a ) find(a) find(a)表示将矩阵或向量…

2022博客之星年度总评选开始了

作者简介:陶然同学 专注于Java领域开发 熟练掌握Java、js等语言的“Hello World” CSDN原力计划作者、CSDN内容合伙人、Java领域优质作者、Java领域新星作者、51CTO专家、华为云专家、阿里云专家等 🎬 陶然同学🎥 由 陶然同学 原创&#…

vue2 升级为 vite 打包

VUE2 中使用 Webpack 打包、开发,每次打包时间太久,尤其是在开发的过程中,本文记录一下 VUE2 升级Vite 步骤。 安装 Vue2 Vite 依赖 dev 依赖 vitejs/plugin-vue2": "^2.3.3 vitejs/plugin-vue2-jsx": "^1.1.1 vite&…

20241227在ubuntu20.04.6系统中,如何用watch命令每秒钟调用nvidia-smi来监控GPU

watch -n 1 nvidia-smi 20241227在ubuntu20.04.6系统中,如何用watch命令每秒钟调用nvidia-smi来监控GPU 2024/12/27 17:04 缘起:在ubuntu20.04.6系统中,使用M6000显卡来跑whisper,显存拉满/占用巨大,但是CPU占用比低&…

[江科大STM32] 第五集STM32工程模板——笔记

保存,进去选芯片型号,我们是F10C8T6 再添加一些文件,自己看路径 然后去 复习这三文件 打开KEIL add existing那个,添加已经存在的文件 还有5个.c.h文件也要添加进来 回到KEIL 点击旁边的settings 如果你用寄存器开发就建到这里就可…

Bitmap(BMP)图像信息分析主要说明带压缩的形式

文章目录 参考资料Bitmap图片结构Bitmap图片组成实例说明 参考资料 微软官方-位图存储 Bitmap图片结构 序号名称说明1Bitmap File HeaderBitmap文件头2Bitmap Info HeaderBitmap信息头3Color Palette Data调色板数据4Bitmap Image Data图像数据 说明 Bitmap文件头的大小为…

二分和离散化

为什么把二分和离散化放一起:因为离散化其实是一种二分整数的过程。 二分 相信大家都接触过二分查找(折半查找),这就是二分的思想。 二分通过每次舍弃一半并不存在答案的区间,进而快速锁定要求的答案(二…

ESP-IDF学习记录(2)ESP-IDF 扩展的简单使用

傻瓜式记录一个示例的打开,编译,运行。后面我再一个个运行简单分析每个demo的内容。 1.打开示例代码 2.选择项目,文件夹 3.选择串口 4.选择调试方式 5.根据硬件GPIO口配置menuconfig 6.构建项目 7.烧录设备,选择串口UART方式 运行…

SpringMVC学习(一)——请求与响应处理

目录 一、SpringMVC简介 二、RequestMapping:请求路径映射 三、RestController 四、请求限定 五、请求处理 1.使用普通变量,收集请求参数 2.使用RequestParam明确指定获取参数 3.目标方法参数是一个pojo 4.RequestHeader:获取请求…

数据分析的分类和EDIT思维框架

为了服务于企业不同层次的决策,商业数据分析过程需要提供相应的数据科学产出物。 一般而言,数据分析需要经历从需求层、数据层、分析层到输出层四个阶段。 第一个阶段是需求层——确定目标,具体目标需要依据具体的层次进行分析&#xff1a…

实验五 时序逻辑电路部件实验

一、实验目的 熟悉常用的时序逻辑电路功能部件,掌握计数器、了解寄存器的功能。 二、实验所用器件和仪表 1、双 D触发器 74LS74 2片 2、74LS162 1片 3、74194 1片 4、LH-D4实验仪 1台 1.双…

iOS 中的 nil、Nil、NULL、NSNull 僵尸对象和野指针

iOS 中的 nil、Nil、NULL、NSNull 僵尸对象和野指针-CSDN博客 类型含义使用场景示例nil表示一个指向 Objective - C 对象的空指针。在 Objective - C 和 Swift(与 Objective - C 交互时)中用于表示对象不存在。当一个对象变量没有指向任何有效的对象实例…

JS面试题|[2024-12-28]

1.JS的设计原理是什么? JS引擎 运行上下文 调用栈 事件循环 回调 执行流程: JS引擎将代码解析为电脑可以执行的代码,调用一些API(运行上下文)让浏览器执行 JS是单线程的,每次从调用栈里面取出来的代码进行调…

全面了解 SQL Server:功能、优势与最佳实践

SQL Server 是微软公司推出的一款关系型数据库管理系统(RDBMS),广泛应用于企业级数据存储、数据分析、应用开发等领域。作为全球最受欢迎的数据库管理系统之一,SQL Server 提供了强大的功能和工具,支持从小型应用到大型…

jdk动态代理和cglib动态代理对比

jdk动态代理和cglib动态代理对比: CGLIB 和 JDK 动态代理都可以用来在运行时生成代理对象 1. 基本概念 JDK 动态代理:只代理接口(interface),无法代理类。它使用 java.lang.reflect.Proxy 类和 java.lang.reflect.I…

攻破 Kioptix Level 1 靶机

找教程然后自己练习,论菜狗的自我修养 基本步骤 1.确定目标IP 2.扫描端口,服务,版本信息,漏洞信息 3.查找漏洞可利用脚本 4.运行脚步 一、信息获取 arp-scan -l nmap -sS -p- -sV -sC -A --min-rate5000 192.168.5.130 二、查…

b站ip属地评论和主页不一样怎么回事

在浏览B站时,细心的用户可能会发现一个有趣的现象:某些用户的评论IP属地与主页显示的IP属地并不一致。这种差异引发了用户的好奇和猜测,究竟是什么原因导致了这种情况的发生呢?本文将对此进行深入解析,帮助大家揭开这一…