resnet与densenet的比较

news2025/3/28 8:52:32

一、 ResNet(残差网络)和 DenseNet(密集连接网络)

ResNet(残差网络)和 DenseNet(密集连接网络)都是深度学习中非常经典的卷积神经网络架构,它们在图像分类、目标检测等诸多视觉任务中表现出色。下面从多个方面对二者进行具体比较:

1. 网络结构

连接方式
  • ResNet:采用残差连接(shortcut connection),即通过跳跃连接将前一层的输出直接加到后面某一层的输出上。例如,在一个残差块中,输入 x 经过一系列卷积操作得到 \(F(x)\),最终输出为 \(y = F(x)+x\)。这种连接方式有效缓解了深度网络训练时的梯度消失和梯度爆炸问题,使得网络可以更深。
  • DenseNet:采用密集连接方式,网络中的每一层都与前面所有层相连。在一个密集块中,第 i 层的输入是前面 \(i - 1\) 层输出特征图在通道维度上的拼接。假设第 i 层之前的所有层输出特征图数量分别为 \(x_1,x_2,\cdots,x_{i - 1}\),那么第 i 层的输入为 \([x_1,x_2,\cdots,x_{i - 1}]\),这种连接方式能促进特征的重复利用和传播。
模块设计
  • ResNet:主要有两种基本模块,即用于较浅网络(如 ResNet18、ResNet34)的BasicBlock和用于更深网络(如 ResNet50、ResNet101、ResNet152)的BottleneckBasicBlock由两个 3x3 卷积层组成,Bottleneck则通过 1x1 卷积进行降维和升维,减少了参数数量和计算量。
  • DenseNet:基本模块是DenseBlockTransition层。DenseBlock由多个DenseLayer组成,每个DenseLayer通常包含批归一化(BN)、ReLU 激活函数和卷积层;Transition层用于在不同的DenseBlock之间进行下采样和通道数的缩减。

2. 性能表现

特征利用效率
  • ResNet:通过残差连接使得信息可以在不同层之间快速传递,但在特征的重复利用方面相对较弱。每一层主要学习当前层输入特征的残差信息,不同层之间的特征交互相对有限。
  • DenseNet:由于其密集连接的特性,能够充分利用前面所有层的特征信息,大大提高了特征的利用率。每一层都可以获取到之前所有层的特征,使得模型能够学习到更丰富的特征表示,尤其在小数据集上表现出色。
计算量与内存需求
  • ResNet:计算量和内存需求相对较为可控。特别是使用Bottleneck模块时,通过 1x1 卷积减少了中间层的通道数,从而降低了计算复杂度。因此,ResNet 在大规模数据集上训练时,能够在保证性能的同时,减少对计算资源的需求。
  • DenseNet:由于每一层的输入都包含了前面所有层的特征,导致特征图的通道数会随着网络深度的增加而快速增长,从而增加了计算量和内存需求。尤其是在深层网络中,这种问题更为明显。
泛化能力
  • ResNet:通过残差连接使得网络更容易训练,能够学习到更复杂的特征表示,从而在不同的数据集和任务上都具有较好的泛化能力。
  • DenseNet:由于其密集连接的方式,使得模型能够学习到更丰富的特征信息,增强了模型的泛化能力。在一些数据集上,DenseNet 能够取得比 ResNet 更好的分类准确率。

3. 训练与收敛

训练速度
  • ResNet:残差连接使得梯度能够更顺畅地传播,网络更容易收敛,训练速度相对较快。在大规模数据集上进行训练时,ResNet 能够更快地达到较好的性能。
  • DenseNet:由于其密集连接的特性,训练时需要处理更多的特征信息,计算量较大,因此训练速度相对较慢。尤其是在网络较深、数据集较大的情况下,训练时间会明显增加。
收敛稳定性
  • ResNet:残差连接有效缓解了梯度消失和梯度爆炸问题,使得网络在训练过程中更加稳定,收敛速度更快。即使在网络深度很大的情况下,也能保持较好的训练效果。
  • DenseNet:虽然密集连接也有助于梯度的传播,但由于特征图通道数的快速增长,可能会导致训练过程中的数值不稳定问题。在训练时,需要更加小心地调整学习率等超参数,以保证网络的收敛。

4. 实际应用场景

资源受限场景
  • ResNet:由于其计算量和内存需求相对较低,更适合在资源受限的设备上部署,如移动设备、嵌入式系统等。
  • DenseNet:由于其较高的计算量和内存需求,在资源受限的场景下应用可能会受到一定的限制。
小数据集场景
  • ResNet:在小数据集上也能取得较好的性能,但由于其特征利用效率相对较低,可能需要更多的训练数据来达到最佳效果。
  • DenseNet:由于其密集连接的方式能够充分利用特征信息,在小数据集上表现更优,能够通过较少的训练数据学习到更丰富的特征表示。
大数据集场景
  • ResNet:凭借其良好的训练速度和收敛稳定性,在大规模数据集上训练时具有明显优势,能够快速收敛并取得较好的性能。
  • DenseNet:虽然在大数据集上也能取得不错的效果,但由于其训练速度较慢,可能需要更多的时间和计算资源。

5.代码演示 

 ResNet(残差网络):

from torch import nn
from torchsummary import summary


class BasicBlock(nn.Module):
    expansion = 1

    def __init__(self, inplanes, planes, stride=1, downsample=None):
        super(BasicBlock, self).__init__()
        self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(planes)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(planes)
        self.downsample = downsample
        self.stride = stride

    def forward(self, x):
        residual = x
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)
        if self.downsample is not None:
            residual = self.downsample(x)
        out += residual
        return out


class Bottleneck(nn.Module):
    expansion = 4

    def __init__(self, inplanes, planes, stride=1, downsample=None):
        super(Bottleneck, self).__init__()
        self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
        self.bn1 = nn.BatchNorm2d(planes)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(planes)
        self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1, bias=False)
        self.bn3 = nn.BatchNorm2d(planes * self.expansion)
        self.downsample = downsample
        self.stride = stride

    def forward(self, x):
        residual = x
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu(out)
        out = self.conv3(out)
        out = self.bn3(out)
        if self.downsample is not None:
            residual = self.downsample(residual)
        out += residual
        out = self.relu(out)
        return out


class MyResNet(nn.Module):
    def __init__(self, block, layers, num_classes=1000):
        super(MyResNet, self).__init__()
        self.inplanes = 8
        self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3, bias=False)
        self.bn1 = nn.BatchNorm2d(self.inplanes)
        self.relu = nn.ReLU(inplace=True)
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        self.layer1 = self._make_layer(block, 8, layers[0], stride=1)
        self.layer2 = self._make_layer(block, 16, layers[1], stride=2)
        self.layer3 = self._make_layer(block, 32, layers[2], stride=2)
        self.layer4 = self._make_layer(block, 64, layers[3], stride=2)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.dropout = nn.Dropout(0.2)
        self.fc = nn.Linear(64 * block.expansion, num_classes)

    def _make_layer(self, block, planes, blocks, stride=1):
        downsample = None
        if stride != 1 or self.inplanes != planes * block.expansion:
            downsample = nn.Sequential(
                nn.Conv2d(self.inplanes, planes * block.expansion, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(planes * block.expansion),
            )
        layers = []
        layers.append(block(self.inplanes, planes, stride, downsample))
        self.inplanes = planes * block.expansion  # 在创建第一个残差块后更新 inplanes
        for i in range(1, blocks):
            layers.append(block(self.inplanes, planes))
        return nn.Sequential(*layers)

    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.maxpool(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        x = self.avgpool(x)
        x = x.view(x.size(0), -1)
        x = self.dropout(x)
        x = self.fc(x)
        return x

def myresnet18(num_classes=1000):
    model = MyResNet(BasicBlock, [2, 2, 2, 2], num_classes=num_classes)
    return model

def myresnet34(num_classes=1000):
    model = MyResNet(BasicBlock, [3, 4, 6, 3], num_classes=num_classes)
    return model

def myresnet50(num_classes=1000):
    model = MyResNet(Bottleneck, [3, 4, 6, 3], num_classes=num_classes)
    return model

def myresnet101(num_classes=1000):
    model = MyResNet(Bottleneck, [3, 4, 23, 3], num_classes=num_classes)
    return model

def myresnet152(num_classes=1000):
    model = MyResNet(Bottleneck, [3, 8, 36, 3], num_classes=num_classes)
    return model


if __name__ == '__main__':
    mynet = myresnet50(num_classes=2)
    print(summary(mynet, (3, 224, 224)))
    print(sum(p.numel() for p in mynet.parameters() if p.requires_grad))

 DenseNet(密集连接网络):

import torch
from torch import nn


class Bottleneck(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(Bottleneck, self).__init__()
        self.conv1 = nn.Sequential(
            nn.BatchNorm2d(in_channels),
            nn.ReLU(),
            nn.Conv2d(in_channels=in_channels, out_channels=4 * out_channels, kernel_size=1, stride=1, padding=0, bias=False)
        )
        self.conv2 = nn.Sequential(
            nn.BatchNorm2d(4 * out_channels),
            nn.ReLU(),
            nn.Conv2d(in_channels=4 * out_channels, out_channels=out_channels, kernel_size=3, stride=1, padding=1, bias=False)
        )

    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        return x


class DenseBlock(nn.Module):
    def __init__(self, in_channels, out_channels, num_bottleneck):
        super(DenseBlock, self).__init__()
        layers = []
        for i in range(num_bottleneck):
            layers.append(Bottleneck(in_channels + i * out_channels, out_channels))  # 拼接(理解困难点)
        self.layers = nn.ModuleList(layers)

    def forward(self, x):
        for layer in self.layers:
            x = torch.cat((x, layer(x)), dim=1)
        return x


class Transition(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(Transition, self).__init__()
        self.conv = nn.Sequential(
            nn.BatchNorm2d(in_channels),
            nn.ReLU(),
            nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=1, padding=0, bias=False),
            nn.AvgPool2d(kernel_size=2, stride=2)
        )

    def forward(self, x):
        x = self.conv(x)
        return x


class MyDenseNet(nn.Module):
    def __init__(self, block_config, num_classes=10, growth_rate=32, reduction=0.5):
        super(MyDenseNet, self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=64, kernel_size=7, stride=2, padding=3, bias=False),
            nn.BatchNorm2d(64),
            nn.ReLU()
        )
        self.pool1 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)

        in_channels = 64
        self.dense_blocks = nn.ModuleList()  # 存放DenseBlock
        self.transitions = nn.ModuleList()  # 存放Transition
        for i, block in enumerate(block_config):
            self.dense_blocks.append(DenseBlock(in_channels, growth_rate, block))
            in_channels += growth_rate * block

            if i != len(block_config) - 1:
                self.transitions.append(Transition(in_channels, int(in_channels * reduction)))
                in_channels = int(in_channels * reduction)

        self.bn2 = nn.BatchNorm2d(in_channels)
        self.pool2 = nn.AdaptiveAvgPool2d((1, 1))
        self.fc = nn.Linear(in_channels, num_classes)

    def forward(self, x):
        x = self.conv1(x)
        x = self.pool1(x)
        for i in range(len(self.dense_blocks)):
            x = self.dense_blocks[i](x)
            if i != len(self.dense_blocks) - 1:
                x = self.transitions[i](x)
        x = self.bn2(x)
        x = self.pool2(x)
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        return x


def densenet121(num_classes=10):
    return MyDenseNet([6, 12, 24, 16], num_classes=num_classes, growth_rate=32, reduction=0.5)


def densenet169(num_classes=10):
    return MyDenseNet([6, 12, 32, 32], num_classes=num_classes, growth_rate=32, reduction=0.5)


def densenet201(num_classes=10):
    return MyDenseNet([6, 12, 48, 32], num_classes=num_classes, growth_rate=32, reduction=0.5)


def densenet264(num_classes=10):
    return MyDenseNet([6, 12, 64, 48], num_classes=num_classes, growth_rate=32, reduction=0.5)


if __name__ == '__main__':
    model = densenet121()
    # 测试数据
    x = torch.randn(2, 3, 224, 224)
    y = model(x)
    print(y.shape)
    print(sum(p.numel() for p in model.parameters()))
    print(sum(p.numel() for p in model.parameters() if p.requires_grad))

 

二、补充(BN位置不同的差异) 

Batch Normalization(BN)是深度学习中常用的一种技术,用于加速网络训练和提高模型的稳定性。在池化层前后使用 BN 会产生不同的效果,下面从原理、对特征的影响以及实际应用等方面详细分析它们的区别。

1. 原理上的区别

  • 池化前使用 BN
    • 在池化操作之前应用 BN,BN 会对卷积层输出的特征图进行归一化处理。具体来说,对于输入的特征图 x_{ij}(其中 i 表示通道索引,j 表示特征图上的位置索引),BN 会计算每个通道的均值 \mu_i 和方差 \sigma_i^2,然后进行归一化: \hat{x}_{ij} = \frac{x_{ij}-\mu_i}{\sqrt{\sigma_i^2 + \epsilon}}) 其中 \epsilon 是一个很小的常数,用于保证分母不为零。接着,通过可学习的参数 \gamma_i 和 \beta_i 对归一化后的特征进行缩放和平移: y_{ij} = \gamma_i \hat{x}_{ij} + \beta_i
    • 这样做的目的是使得特征图在进入池化层之前具有稳定的分布,有助于梯度的传播,从而加速网络的训练。
  • 池化后使用 BN
    • 当在池化操作之后使用 BN 时,BN 处理的是经过池化后的特征图。池化操作(如最大池化或平均池化)会改变特征图的尺寸和数值分布。BN 同样会对池化后的特征图计算均值和方差,并进行归一化和缩放平移操作。由于池化后的特征图已经经过了下采样,其统计信息(均值和方差)与池化前不同,因此归一化的效果也会有所差异。

2. 对特征的影响

  • 池化前使用 BN
    • 特征分布调整:可以使卷积层输出的特征图在进入池化层之前具有更稳定的分布。这有助于缓解梯度消失或梯度爆炸问题,使得网络能够更有效地学习特征。例如,在卷积层中,不同通道的特征图可能具有不同的均值和方差,通过 BN 可以将它们拉到相似的分布上,避免某些通道的特征对后续层的影响过大。
    • 增强特征多样性:由于归一化操作会调整特征的数值范围,使得每个通道的特征都能在相对公平的环境下被池化层处理,从而增强了特征的多样性。这有助于模型学习到更丰富的特征表示。
  • 池化后使用 BN
    • 适应池化后的特征分布:池化操作会改变特征图的数值分布,在池化后使用 BN 可以对这种变化进行调整,使得后续层能够更好地处理池化后的特征。例如,最大池化会保留特征图中的最大值,而平均池化会计算平均值,这些操作都会导致特征图的分布发生变化,BN 可以对其进行归一化,使其更适合后续的处理。
    • 减少信息损失:池化操作会导致一定程度的信息损失,在池化后使用 BN 可以在一定程度上减少这种损失。通过调整特征的分布,BN 可以使得池化后的特征更具有代表性,从而提高模型的性能。

3. 实际应用中的区别

  • 计算效率
    • 池化前使用 BN:通常在池化前使用 BN 会增加一些计算量,因为需要对卷积层输出的较大尺寸的特征图进行归一化操作。但是,由于归一化后的特征图更易于后续处理,可能会减少整体的训练时间。
    • 池化后使用 BN:池化后的特征图尺寸通常较小,因此在池化后使用 BN 的计算量相对较小。这在处理大规模数据或计算资源有限的情况下可能更具优势。
  • 模型性能
    • 池化前使用 BN:在一些情况下,池化前使用 BN 可以提高模型的性能,特别是当卷积层输出的特征图分布差异较大时。通过归一化操作,可以使模型更好地学习到不同通道的特征,从而提高分类或回归的准确性。
    • 池化后使用 BN:在另一些情况下,池化后使用 BN 可能更合适。例如,当池化操作对特征图的分布影响较大时,在池化后进行归一化可以更好地适应这种变化,从而提高模型的性能。

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

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

相关文章

【算法day16】电话号码的字母组合

电话号码的字母组合 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 https://leetcode.cn/problems/letter-combinations…

软件工程之软件验证计划Software Verification Plan

个人主页:云纳星辰怀自在 座右铭:“所谓坚持,就是觉得还有希望!” 本文为基于ISO26262软件验证计划模板,仅供参考。 软件验证计划,包括: 1. 软件需求验证计划 2. 软件架构设计验证计划 3. 软件单…

Spring Cloud之负载均衡之LoadBalance

目录 负载均衡 问题 步骤 现象 什么是负载均衡? 负载均衡的一些实现 服务端负载均衡 客户端负载均衡 使用Spring Cloud LoadBalance实现负载均衡 负载均衡策略 ​编辑 ​编辑LoadBalancer原理 服务部署 准备环境和数据 服务构建打包 启动服务 上传J…

分布式任务调度

今天我们讲讲分布式定时任务调度—ElasticJob。 一、概述 1、什么是分布式任务调度 我们可以思考⼀下下⾯业务场景的解决⽅案: 某电商平台需要每天上午10点,下午3点,晚上8点发放⼀批优惠券 某银⾏系统需要在信⽤卡到期还款⽇的前三天进⾏短信提醒 某…

架构设计的灵魂交响曲:系统设计各维度的深度解析与实战指南

引言: 系统设计的背景与重要性 在快速变化的技术环境中,数字化转型成为企业生存与发展的核心驱动力。系统设计能力不仅是技术团队的核心竞争力,也是推动业务创新和提升整体效率的关键因素。根据Gartner的研究,超过70%的数字化转型项目未能实…

[贪心算法]买卖股票的最佳时机 买卖股票的最佳时机Ⅱ K次取反后最大化的数组和 按身高排序 优势洗牌(田忌赛马)

1.买卖股票的最佳时机 暴力解法就是两层循环&#xff0c;找出两个差值最大的即可。 优化&#xff1a;在找最小的时候不用每次都循环一遍&#xff0c;只要在i向后走的时候&#xff0c;每次记录一下最小的值即可 class Solution { public:int maxProfit(vector<int>& p…

【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring MVC 的核心组件:DispatcherServlet 的工作原理

<前文回顾> 点击此处查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12907601&sharereferPC&sharesourceFoyoDesigner&sharefromfrom_link <今日更新> 一、Dispat…

第J3周:DenseNet121算法实现01(Pytorch版)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 目标 具体实现 &#xff08;一&#xff09;环境 语言环境&#xff1a;Python 3.10 编 译 器: PyCharm 框 架: Pytorch &#xff08;二&#xff09;具体步骤…

webrtc3A算法

使用ubuntu18.04 选择webrtc_audio_processing v0.3 下载地址 https://gitlab.freedesktop.org/pulseaudio/webrtc-audio-processing/-/tree/master git clone 完 编译 # Initialise into the build/ directory, for a prefixed install into the # install/ directory meson …

让“树和二叉树”埋在记忆土壤中--性质和概念

Nice to meet your! 目录 树的介绍&#xff1a; 树的创建&#xff1a; 二叉树的概念和结构&#xff1a; 二叉树的存储结构&#xff1a; 树的介绍&#xff1a; 概念和结构&#xff1a; 不知你们是否在现实中看见过分为两个叉的枯树&#xff0c;大概长这样&#xff1a; 那…

Spring Boot整合SSE实现消息推送:跨域问题解决与前后端联调实战

摘要 本文记录了一次完整的Spring Boot整合Server-Sent Events&#xff08;SSE&#xff09;实现实时消息推送的开发过程&#xff0c;重点分析前后端联调时遇到的跨域问题及解决方案。通过CrossOrigin注解的实际应用案例&#xff0c;帮助开发者快速定位和解决类似问题。 一、项…

【工具分享】vscode+deepseek的接入与使用

目录 第一章 前言 第二章 获取Deepseek APIKEY 2.1 登录与充值 2.2 创建API key 第三章 vscode接入deepseek并使用 3.1 vscode接入deepseek 3.2 vscode使用deepseek 第一章 前言 deepseek刚出来时有一段时间余额无法充值&#xff0c;导致小编没法给大家发完整的流程&…

康谋方案 | AVM合成数据仿真验证方案

随着自动驾驶技术的快速发展&#xff0c;仿真软件在开发过程中扮演着越来越重要的角色。仿真传感器与环境不仅能够加速算法验证&#xff0c;还能在安全可控的条件下进行复杂场景的重复测试。 本文将分享如何利用自动驾驶仿真软件配置仿真传感器与搭建仿真环境&#xff0c;并对…

Linux内核IPv4路由选择子系统

一、基本知识 1.具体案例&#xff1a;直连路由 结构fib_nh表示下一跳&#xff0c;包含输出网络设备、外出接口索引等信息。 有两个以太网局域网 LAN1 和 LAN2&#xff0c;其中 LAN1 包含子网 192.168.1.0/24&#xff0c;而 LAN2 包含子网 192.168.2.0/24。在这两个 LAN 之…

NWAFU 生物统计实验二 R语言版

#1 setwd(修改为你的工作路径或桌面路径) feed_types <- c("A", "B", "C") weight_gain_means <- c(36.8, 34.9, 21.3) weight_gain_sds <- c(2.4, 2.7, 6.6) weight_gain <- rnorm(3, mean weight_gain_means, sd weight_gain_sd…

Thinkphp指纹识别

识别ThinkPHP框架(指纹) 1.ioc判断 /favicon.ico 2.报错 /1 然后使用工具梭哈

【AVRCP】蓝牙AVRCP协议中的L2CAP互操作性要求深度解析

目录 一、L2CAP互操作性要求&#xff08;针对AVRCP&#xff09; 1.1 核心概念 1.2 AVRCP对L2CAP的增强需求 1.3 关键机制解析 1.4 浏览通道优化配置 1.5 实际应用场景与解决方案 二、通道类型与配置 2.1. 通道类型限制 2.2 PSM字段规范 2.3. 实现意义 3.4. 实际应用…

剑指 Offer II 111. 计算除法

comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20111.%20%E8%AE%A1%E7%AE%97%E9%99%A4%E6%B3%95/README.md 剑指 Offer II 111. 计算除法 题目描述 给定一个变量对数组 equations 和一个实数值数组 values 作…

掌握 WRF/Chem 模式:突破大气环境研究技术瓶颈的关键

技术点目录 第一部分、WRF-Chem模式应用案例和理论基础第二部分、Linux环境配置及WRF-CHEM第三部分、WRF-Chem模式编译&#xff0c;排放源制作第四部分、WRF-Chem数据准备&#xff08;气象、排放、初边界条件等&#xff09;&#xff0c;案例实践第五部分、模拟结果提取、数据可…

linux性能监控的分布式集群 prometheus + grafana 监控体系搭建

prometheusgrafana分布式集群资源监控体系搭建 前言一、安装 prometheus二、在要监控的服务器上安装监听器三、prometheus服务器配置四、grafana配置大屏五、创建Linux监控看板五、监控windows服务器注意事项 前言 Prometheus 是一个开源的 ​分布式监控系统 和 ​时间序列数据…