MobileNetV3详细原理(含torch源码)

news2025/1/19 23:14:43

作者:爱笑的男孩。

个人简介:打工人。

持续分享:机器学习、深度学习、python相关内容、日常BUG解决方法及Windows&Linux实践小技巧。

如发现文章有误,麻烦请指出,我会及时去纠正。有其他需要可以私信我或者发我邮箱:zhilong666@foxmail.com

目录

MobileNetV3原理

MobileNetV3创新点

MobileNetV3对比MobileNetV2

MobileNetV3源码(torch版)

MobileNetV3-large

MobileNetV3-small

训练10个epoch的效果


MobileNetV3原理

        MobileNetV3是Google在2019年提出的一款深度神经网络模型,其在移动端图像分类、目标检测、语义分割等任务上均取得了优秀的表现。MobileNetV3采用了很多新的技术,包括针对通道注意力的Squeeze-and-Excitation模块、NAS搜索方法等,这些方法都有利于进一步提升网络的性能。

        MobileNetV3的整体架构基本沿用了MobileNetV2的设计,采用了轻量级的深度可分离卷积和残差块等结构,依然是由多个模块组成,但是每个模块得到了优化和升级,包括瓶颈结构、SE模块和NL模块。

        首先是瓶颈结构,MobileNetV3中的瓶颈结构和MobileNetV2类似,但是在MobileNetV3中,每个瓶颈结构加入了一个关键的组件,即非线性激活函数。在MobileNetV2中,瓶颈中的Max-Pooling层只是一种简单的预处理方式,而MobileNetV3中引入了ReLU6非线性激活函数来激活瓶颈层,从而能够更好地提升模型的非线性表达能力。

        其次是Squeeze-and-Excitation模块,MobileNetV3引入了Squeeze-and-Excitation(SE)模块来有效地增强网络中的通道交互和上下文信息的传递。SE模块通过自适应地学习通道的处理权重,将通道之间的相关性进行特异性加强,进而提高特征图的鉴别力和语义表达能力。

        最后是NAS搜索方法,MobileNetV3可以采用神经结构搜索(NAS)方法,该方法能够根据数据集的特点,自动得到一种最优的网络架构。在MobileNetV3中,采用了一种基于RL策略的NAS搜索方法,使用强化学习策略来搜索网络的结构,从而能够自适应地预测最优网络架构。

        综合来说,MobileNetV3是一种高效、准确和灵活的深度学习模型,它适用于各种移动设备上的图像分类和识别任务。

MobileNetV3创新点

        MobileNetV3的主要创新在于使用了两个重要的组件:候选块和内积激活函数。

     1.候选块

        MobileNetV3使用候选块来替代基于固定卷积单元的基础框架。候选块是一个由若干个卷积层、批标准化层和激活函数组成的一个基本构建单元。候选块的输入和输出都是四维张量(n, h, w, c),其中n表示batch size,h和w表示图像的高度和宽度,c表示通道数。

        MobileNetV3提出了三种不同的候选块:小型、中型和大型。这三个候选块的结构相同,但是它们的通道数和宽度倍增的比例不同。这样可以在不增加运算量的情况下,提高模型的表现力。

     2.内积激活函数

        MobileNetV3使用了内积激活函数。内积激活函数将输入的特征图和可学习的参数进行内积运算,得到一个标量,然后将该标量通过非线性激活函数进行映射,从而得到特征图的输出。

        内积激活函数相比传统的卷积激活函数具有如下优点:

  1. 降低了计算量。内积运算可以使用点乘或卷积来实现,比起传统的卷积操作,计算量更小。
  2. 降低了内存占用。内积激活函数可以将输入特征图的通道数降低到1,从而减少存储和传输开销。
  3. 提高了模型表现力。内积激活函数可以使模型在特定的任务上获得更好的表现力。

        MobileNetV3在实验中证明了其在ImageNet上图像分类任务上的有效性,同时也在COCO数据集上进行了检测和分割等任务的实验,取得了较好的结果。

补充:

  1. Adaptive Inverted Residual Block(AIR Block):MobileNetV3首先引入了AIR Block来替代MobileNetV2中的Inverted Residual Block(IR Block)。AIR Block的特点是具有自适应的非线性结构,可以提高模型的表达能力和精度。同时,AIR Block引入了多步卷积结构,可以减少模型参数量和计算量,从而提升模型的运行速度。

  2. 激活函数优化:MobileNetV3中对ReLU6进行了优化,引入了Swish激活函数,可以有效提高模型的精度。 Swish激活函数是一种非常流行的激活函数,其具有类似于sigmoid激活函数的平滑曲线,可以在容易梯度消失的区域内提供更好的梯度。同时,Swish激活函数可以保持较高的计算效率。

  3. Hard-Sigmoid门控:MobileNetV3中提出了一种新的门控机制,即Hard-Sigmoid门控。 Hard-Sigmoid门控可以在保证计算效率的前提下,提高模型的表达能力,从而提高模型的精度。

  4. Network Architecture Search(NAS)技术:MobileNetV3采用了NAS技术进行模型搜索,可以自动化地发现适合移动端场景的网络结构,并自动优化其超参数。这一方法可以有效地降低模型的人工设计成本,并提高模型的精度和效率。

        MobileNetV3在神经网络结构设计、激活函数优化、门控机制提升以及NAS技术应用等方面都有比较明显的创新点,其提高了移动端神经网络模型的表达能力和计算效率,具有非常重要的应用价值。

MobileNetV3对比MobileNetV2

        MobileNetV3相较于MobileNetV2,主要有以下改进和优化:

  1. 更高的准确率:MobileNetV3在ImageNet数据集上的Top-1准确率达到了75.2%,比MobileNetV2的72.0%要高。

  2. 更快的推理速度:MobileNetV3通过增加Squeeze-and-Excitation模块和hard-swish非线性激活函数,提高了模型的计算效率,加快了推理速度。

  3. 更少的参数和计算量:MobileNetV3在保持准确率不变的情况下,参数数量和计算量比MobileNetV2都要少。

  4. 支持多种模型结构:MobileNetV3除了提供标准版模型外,还提供了Small模型和Large模型,可以根据不同的场景和需求选择合适的模型。

  5. 支持自适应网络:MobileNetV3加入了Squeeze-and-Excite模块和自适应网络结构,可以根据输入图像的尺寸和分辨率自适应地调整模型的结构和参数,从而实现更好的模型泛化能力和适应性。

  6. 支持权重重要性筛选:MobileNetV3提供了权重重要性筛选工具,可以定量地筛选出对模型性能影响最大的参数,从而实现更高效的模型压缩和优化。

        总的来说,MobileNetV3相对于MobileNetV2,在准确率、推理速度、参数数量、计算量、模型结构和适应性等方面都有了显著的提升和改进。

MobileNetV3源码(torch版)

MobileNetV3-large



from torch.utils.data import DataLoader
from torchvision.datasets import CIFAR10
from torchvision.transforms import transforms
from torch.autograd import Variable


import torch.nn as nn
import torch.nn.functional as F
import torch

class hswish(nn.Module):
    def __init__(self, inplace=True):
        super(hswish, self).__init__()
        self.inplace = inplace

    def forward(self, x):
        f = nn.functional.relu6(x + 3., inplace=self.inplace) / 6.
        return x * f

class hsigmoid(nn.Module):
    def __init__(self, inplace=True):
        super(hsigmoid, self).__init__()
        self.inplace = inplace

    def forward(self, x):
        f = nn.functional.relu6(x + 3., inplace=self.inplace) / 6.
        return f

class SeModule(nn.Module):
    def __init__(self, in_channels, se_ratio=0.25):
        super(SeModule, self).__init__()
        self.se_reduce = nn.Conv2d(in_channels, int(in_channels * se_ratio), kernel_size=1, stride=1, padding=0)
        self.se_expand = nn.Conv2d(int(in_channels * se_ratio), in_channels, kernel_size=1, stride=1, padding=0)

    def forward(self, x):
        s = nn.functional.adaptive_avg_pool2d(x, 1)
        s = self.se_expand(nn.functional.relu(self.se_reduce(s), inplace=True))
        return x * s.sigmoid()

class ConvBlock(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride, padding, groups=1):
        super(ConvBlock, self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, groups=groups, bias=False)
        self.bn = nn.BatchNorm2d(out_channels)
        self.act = hswish()

    def forward(self, x):
        return self.act(self.bn(self.conv(x)))

class SqueezeExcitation(nn.Module):
    def __init__(self, in_channel, out_channel, reduction=4):
        super(SqueezeExcitation, self).__init__()
        self.pool = nn.AdaptiveAvgPool2d(1)
        self.fc1 = nn.Conv2d(in_channel, out_channel // reduction, kernel_size=1, stride=1)
        self.relu = nn.ReLU(inplace=True)
        self.fc2 = nn.Conv2d(out_channel // reduction, out_channel, kernel_size=1, stride=1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        out = self.pool(x)
        out = self.fc1(out)
        out = self.relu(out)
        out = self.fc2(out)
        out = self.sigmoid(out)
        return out

class ResidualBlock(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride, use_se=True):
        super(ResidualBlock, self).__init__()
        self.conv1 = ConvBlock(in_channels, out_channels, kernel_size, stride, kernel_size//2)
        self.conv2 = ConvBlock(out_channels, out_channels, kernel_size, 1, kernel_size//2)
        self.use_se = use_se
        if use_se:
            self.se = SqueezeExcitation(out_channels, out_channels)
        self.shortcut = nn.Sequential()
        if stride != 1 or in_channels != out_channels:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(out_channels)
            )

    def forward(self, x):
        out = self.conv1(x)
        out = self.conv2(out)
        if self.use_se:
            out = out * self.se(out)
        out += self.shortcut(x)
        out = nn.functional.relu(out, inplace=True)
        return out

class MobileNetV3Large(nn.Module):
    def __init__(self, num_classes=1000):
        super(MobileNetV3Large, self).__init__()#

        self.conv1 = ConvBlock(3, 16, 3, 2, 1)     # 1/2
        self.bottlenecks = nn.Sequential(
            ResidualBlock(16, 16, 3, 1, False),
            ResidualBlock(16, 24, 3, 2, False),     # 1/4
            ResidualBlock(24, 24, 3, 1, False),
            ResidualBlock(24, 40, 5, 2, True),      # 1/8
            ResidualBlock(40, 40, 5, 1, True),
            ResidualBlock(40, 40, 5, 1, True),
            ResidualBlock(40, 80, 3, 2, False),     # 1/16
            ResidualBlock(80, 80, 3, 1, False),
            ResidualBlock(80, 80, 3, 1, False),
            ResidualBlock(80, 112, 5, 1, True),
            ResidualBlock(112, 112, 5, 1, True),
            ResidualBlock(112, 160, 5, 2, True),    # 1/32
            ResidualBlock(160, 160, 5, 1, True),
            ResidualBlock(160, 160, 5, 1, True)
        )
        self.conv2 = ConvBlock(160, 960, 1, 1, 0)
        self.pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Sequential(
            nn.Linear(960, 1280),
            nn.BatchNorm1d(1280),
            nn.Hardswish(inplace=True),
            nn.Linear(1280, num_classes),
        )

    def forward(self, x):
        out = self.conv1(x)
        out = self.bottlenecks(out)
        out = self.conv2(out)
        out = self.pool(out)
        out = out.reshape(out.size(0), -1)
        out = self.fc(out)
        return out

if __name__ == '__main__':
    train_data = CIFAR10('cifar', train=True, transform=transforms.ToTensor())
    data = DataLoader(train_data, batch_size=148, shuffle=True)
    device = torch.device('cuda')
    net = MobileNetV3Large(num_classes=10).to(device)
    print(net)
    cross = nn.CrossEntropyLoss().to(device)
    optimizer = torch.optim.Adam(net.parameters(), 0.001)
    for epoch in range(10):
        for img, label in data:
            img = Variable(img).to(device)
            label = Variable(label).to(device)
            output = net.forward(img)
            loss = cross(output, label)
            loss.backward()
            optimizer.zero_grad()
            optimizer.step()
            pre = torch.argmax(output, 1)
            num = (pre == label).sum().item()
            acc = num / img.shape[0]
        print("epoch:", epoch + 1)
        print("loss:", loss.item())
        print("Accuracy:", acc)

MobileNetV3-small



from torch.utils.data import DataLoader
from torchvision.datasets import CIFAR10
from torchvision.transforms import transforms
from torch.autograd import Variable


import torch.nn as nn
import torch.nn.functional as F
import torch


class hswish(nn.Module):
    def __init__(self, inplace=True):
        super(hswish, self).__init__()
        self.inplace = inplace

    def forward(self, x):
        f = nn.functional.relu6(x + 3., inplace=self.inplace) / 6.
        return x * f

class hsigmoid(nn.Module):
    def __init__(self, inplace=True):
        super(hsigmoid, self).__init__()
        self.inplace = inplace

    def forward(self, x):
        f = nn.functional.relu6(x + 3., inplace=self.inplace) / 6.
        return f

class SeModule(nn.Module):
    def __init__(self, in_channels, se_ratio=0.25):
        super(SeModule, self).__init__()
        self.se_reduce = nn.Conv2d(in_channels, int(in_channels * se_ratio), kernel_size=1, stride=1, padding=0)
        self.se_expand = nn.Conv2d(int(in_channels * se_ratio), in_channels, kernel_size=1, stride=1, padding=0)

    def forward(self, x):
        s = nn.functional.adaptive_avg_pool2d(x, 1)
        s = self.se_expand(nn.functional.relu(self.se_reduce(s), inplace=True))
        return x * s.sigmoid()

class ConvBlock(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride, padding, groups=1):
        super(ConvBlock, self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, groups=groups, bias=False)
        self.bn = nn.BatchNorm2d(out_channels)
        self.act = hswish()

    def forward(self, x):
        return self.act(self.bn(self.conv(x)))

class SqueezeExcitation(nn.Module):
    def __init__(self, in_channel, out_channel, reduction=4):
        super(SqueezeExcitation, self).__init__()
        self.pool = nn.AdaptiveAvgPool2d(1)
        self.fc1 = nn.Conv2d(in_channel, out_channel // reduction, kernel_size=1, stride=1)
        self.relu = nn.ReLU(inplace=True)
        self.fc2 = nn.Conv2d(out_channel // reduction, out_channel, kernel_size=1, stride=1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        out = self.pool(x)
        out = self.fc1(out)
        out = self.relu(out)
        out = self.fc2(out)
        out = self.sigmoid(out)
        return out

class ResidualBlock(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride, use_se=True):
        super(ResidualBlock, self).__init__()
        self.conv1 = ConvBlock(in_channels, out_channels, kernel_size, stride, kernel_size//2)
        self.conv2 = ConvBlock(out_channels, out_channels, kernel_size, 1, kernel_size//2)
        self.use_se = use_se
        if use_se:
            self.se = SqueezeExcitation(out_channels, out_channels)
        self.shortcut = nn.Sequential()
        if stride != 1 or in_channels != out_channels:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(out_channels)
            )

    def forward(self, x):
        out = self.conv1(x)
        out = self.conv2(out)
        if self.use_se:
            out = out * self.se(out)
        out += self.shortcut(x)
        out = nn.functional.relu(out, inplace=True)
        return out

class MobileNetV3Small(nn.Module):
    def __init__(self, num_classes=1000):
        super(MobileNetV3Small, self).__init__()

        self.conv1 = ConvBlock(3, 16, 3, 2, 1)     # 1/2
        self.bottlenecks = nn.Sequential(
            ResidualBlock(16, 16, 3, 2, False),     # 1/4
            ResidualBlock(16, 72, 3, 2, False),     # 1/8
            ResidualBlock(72, 72, 3, 1, False),
            ResidualBlock(72, 72, 3, 1, True),
            ResidualBlock(72, 96, 3, 2, True),      # 1/16
            ResidualBlock(96, 96, 3, 1, True),
            ResidualBlock(96, 96, 3, 1, True),
            ResidualBlock(96, 240, 5, 2, True),     # 1/32
            ResidualBlock(240, 240, 5, 1, True),
            ResidualBlock(240, 240, 5, 1, True),
            ResidualBlock(240, 480, 5, 1, True),
            ResidualBlock(480, 480, 5, 1, True),
            ResidualBlock(480, 480, 5, 1, True),
        )
        self.conv2 = ConvBlock(480, 576, 1, 1, 0, groups=2)
        self.conv3 = nn.Conv2d(576, 1024, kernel_size=1, stride=1, padding=0, bias=False)
        self.bn = nn.BatchNorm2d(1024)
        self.act = hswish()
        self.pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Linear(1024, num_classes)

    def forward(self, x):
        out = self.conv1(x)
        out = self.bottlenecks(out)
        out = self.conv2(out)
        out = self.conv3(out)
        out = self.bn(out)
        out = self.act(out)
        out = self.pool(out)
        out = out.reshape(out.size(0), -1)
        out = self.fc(out)
        return out




if __name__ == '__main__':
    train_data = CIFAR10('cifar', train=True, transform=transforms.ToTensor())
    data = DataLoader(train_data, batch_size=148, shuffle=True)

    device = torch.device("cuda")
    net = MobileNetV3Small(num_classes=10).to(device)
    print(net)
    cross = nn.CrossEntropyLoss().to(device)
    optimizer = torch.optim.Adam(net.parameters(), 0.01)
    for epoch in range(10):
        for img, label in data:
            img = Variable(img).to(device)
            label = Variable(label).to(device)
            output = net.forward(img)
            loss = cross(output, label)
            loss.backward()
            optimizer.zero_grad()
            optimizer.step()
            pre = torch.argmax(output, 1)
            num = (pre == label).sum().item()
            acc = num / img.shape[0]
        print("epoch:", epoch + 1)
        print("loss:", loss.item())
        print("Accuracy:", acc)

训练10个epoch的效果

 

 

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

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

相关文章

企业对外投资为何一定要申请境外投资备案?

随着贸易经济全球化的发展,国内外企业也纷纷把目标转向海外市场,尤其香港,日本,东南亚等地的投资有增无减。 境外投资备案,就是在中国境内设立的公司主体对中国以外的国家进行投资,需要在商务部和发改委进…

高级数据结构与算法 | 自适应基数树(Adaptive Radix Tree)

文章目录 AdaptiveRadixTree基本介绍自适应节点内部节点叶子节点 高度压缩Path CompressionLazy Expansion 算法SearchInsertDeleteBulk loading 并发乐观锁耦合读优化写排除(ROWEX)适配 ROWEX节点替换路径压缩 AdaptiveRadixTree 基本介绍 论文链接&am…

在win10中使用webdriver

一、察看并下载webdriver 查看 下载: 地址为: CNPM Binaries Mirror (npmmirror.com)https://registry.npmmirror.com/binary.html?pathchromedriver/ 找到对应的版本,最后面的数字不一定要完全相同 二、安装 参考: Python…

设计模式-工厂方法模式

大话设计模式这本书反反复复学过好多遍了,每一次学都会有不同的认识,接下来谈谈我最近学习工厂的一次感受; 发展: 一个计算器的例子从不使用工厂到分离出前端、后端,到使用简单工厂再到使用工厂方法,每一步…

第一性原理计算在材料分析中的应用及未来发展趋势

第一性原理计算是一种理论计算方法,能够基于量子力学原理对物质的性质进行高精度预测。它已经成为材料科学研究中不可或缺的工具,帮助我们了解材料的基本特性,优化材料的性能,并发现新的材料。 一、第一性原理计算的基本原理 第一…

zabbix故障排查

zabbix server服务问题可以查看server日志 tail -f /var/log/zabbix/zabbix_server.log 根据日志中的error报错提示分析原因 zabbix agent服务问题可以查看agent日志 tail -f /var/log/zabbix/zabbix_agentd.log 根据日志中的error报错提示分析原因 zabbix的nginx服务问题可…

Window下编译PJSIP,不编译Media模块

Windows系统下使用VS1027进行编译PJSIP。 下载地址 PJSIP的地址:https://github.com/pjsip/pjproject 在线clone太慢的话,可以直接在这里下载比clone会快很多: https://github.com/pjsip/pjproject/releases 安装OpenSSL 直接安装已经编译…

TitanIDE 新版本来袭,全新“效能看板”上线

TitanIDE产品团队于4月17日晚发布了TitanV2.6.3版本,作为一次重要的版本迭代,新版本主要增加/优化了以下重大功能: 全新效能看板上线,研发进度一目了然;新增代码拷贝、下载权限管理功能;项目启动提速&…

创客匠人视频号全域增长落地班成功举办

以专业赋能好老师,打造知识付费商业IP,借助视频号布局商业增长第二曲线。 4月15日-16日,泛知识场景数字化服务商创客匠人在厦门举办「视频号全域增长落地班」。 本次大会邀请到创客匠人CEO、中欧EMBA蒋洪波,福布斯环球联盟创新企业…

电脑开机进不了系统怎么办?电脑开机错误无法显示桌面解决方法

电脑开机进不了系统怎么办?很多用户都有遇到过电脑正常开机,但是无法进入到系统桌面的情况。其实遇到这个问题,大部分的原因都是因为系统出现了故障损坏,我们可以去通过U盘来重装系统的方法进行解决。一起来看看以下的具体操作方法…

jar包反编译工具(java-decompiler)

五种反编译工具 1.jd-gui 下载地址:http://java-decompiler.github.io/ 优点:反编译的源代码基本符合,没有乱七八糟新增的修饰符 缺点:反编译过程耗时较长(50MB需要10分钟左右) 无法还原内部类 可以查看对…

DDPG算法详解

DQN算法详解 一.概述 概括来说,RL要解决的问题是:让agent学习在一个环境中的如何行为动作(act), 从而获得最大的奖励值总和(total reward)。 这个奖励值一般与agent定义的任务目标关联。 agent需要的主要学习内容:第一是行为策略…

leetcode刷题(5)

各位朋友们,大家好,今天是我leedcode刷题的第五篇,我们一起来看看吧。 文章目录 栈的压入,弹出序列题目要求用例输入提示做题思路代码实现C语言代码实现Java代码实现 最小栈题目要求用例输入提示做题思路代码实现Java代码实现 栈的…

QML自定义模块及qmldir的使用

前言 在开发QtQuick项目中,当项目文件很多的情况下,可能会分成多级文件夹来进行分类,还有一些通用类型文件,如公共组件,通用配置等等,需要在各个不同的文件中进行调用,这种情况下,一…

04、Cadence使用记录之器件连接的连线、网络、总线、差分(OrCAD Capture CIS)

04、Cadence使用记录之器件连接的连线、页内网络、总线、跨页网络、差分、电源(OrCAD Capture CIS原理图) 前置教程: 01、Cadence使用记录之新建工程与基础操作(原理图绘制:OrCAD Capture CIS) 02、Cadenc…

操作系统原理 —— 操作系统的四个特征:并发、共享、虚拟、异步 (二)

本章我们来聊一下操作系统的四个特征 在我们的操作系统中有四个特征:并发、共享、虚拟、异步,我们结合每一个特征来进行讲解,我们先来看并发。 并发 这里所说的并发,最好不联想到并发编程。咱们就简简单单理解一下,…

浙工商机器学习课程论文+代码分享(含数据集)

文章目录 一、论文总览二、摘要 & 目录三、数据集的展示四、部分代码4.1 降低内存4.2 部分特征生成4.3 热力图分析4.4 变量分布图4.5 聚类算法4.6 聚类结果的展示(部分)4.7 聚类后的特征图 完整版的论文代码数据集地址: https://mbd.pub…

leetcode刷题(7)二叉树(1)

哈喽大家好,这是我leetcode刷题的第七篇,这两天我将更新leetcode上关于二叉树方面的题目,如果大家对这方面感兴趣的话,欢迎大家持续关注,谢谢大家。 那么我们就进入今天的主题。 文章目录 1.二叉树的前序遍历题目要求示…

优先级队列

目录 前言: 1、PriorityQueue的特性 .2 PriorityQueue常用接口介绍 Ⅰ、PriorityQueue常见的构造方法 Ⅱ、常用的方法 Ⅲ、PriorityQueue的扩容方式: 3、应用 前言: 普通的队列是一种 先进先出的数据结构,元素在队列尾追加&am…

RC专题:无源滤波电路和有源滤波电路

什么是无源滤波电路和有源滤波电路 仅由无源器件(电阻、电容、电感)构成的滤波电路 称为无源滤波电路。如下图所示。 由无源器件和有源器件(双极型管,单极型管,集成运放)构成的滤波电路 称为有源滤波电路。…